mirror of
https://github.com/titanwings/colleague-skill.git
synced 2026-10-29 04:16:54 +08:00
* Share one host table, ship one payload, split optional deps - tools/hosts.json is the single host path table, read by bin/distilly.mjs and tools/hosts.py (install_distilly, install_generated_skill, install_claude_generated_skill, skill_writer). - package.json "files" is the single publish list; the npm CLI and the Python installer both derive the install payload from it, so the Python installer no longer copies docs/, tests/ or .github/ into skill dirs and now supports all eight hosts. - requirements.txt keeps only requests; collector extras move to requirements-optional.txt. - Ruff is pinned with an explicit rule set and blocks CI; fix its findings. - tests/_paths.py replaces the sys.path boilerplate in 11 test files. - Rename the cover image to docs/social-preview.png so redesigns stop adding versioned files. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014AQdagxHQtDiYDXHNMsRSK * Keep reinstalling from an installed copy working An installed copy has no package.json, so install_distilly.py copies it whole (minus caches) instead of failing to read the publish list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014AQdagxHQtDiYDXHNMsRSK * Allow running CI manually A stacked PR retargeted after its base merges gets no CI run until the next push; workflow_dispatch lets a maintainer start one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014AQdagxHQtDiYDXHNMsRSK --------- Co-authored-by: Claude <noreply@anthropic.com>
49 lines
1.4 KiB
Python
49 lines
1.4 KiB
Python
"""Host install paths, loaded from hosts.json (shared with bin/distilly.mjs)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from collections.abc import Mapping
|
|
from pathlib import Path
|
|
|
|
|
|
HOSTS_FILE = Path(__file__).resolve().with_name("hosts.json")
|
|
HOSTS: dict[str, dict] = json.loads(HOSTS_FILE.read_text(encoding="utf-8"))["hosts"]
|
|
|
|
|
|
def _resolve(
|
|
host: str,
|
|
key: str,
|
|
home: Path | None,
|
|
environ: Mapping[str, str] | None,
|
|
) -> Path:
|
|
try:
|
|
spec = HOSTS[host]
|
|
except KeyError as error:
|
|
raise ValueError(f"unsupported host: {host}") from error
|
|
parts = spec.get(key) or spec["skills_dir"]
|
|
environment = os.environ if environ is None else environ
|
|
home_env = spec.get("home_env")
|
|
if home_env and environment.get(home_env):
|
|
return Path(environment[home_env]).expanduser().joinpath(*parts[1:])
|
|
return (home or Path.home()).joinpath(*parts)
|
|
|
|
|
|
def skills_dir(
|
|
host: str,
|
|
home: Path | None = None,
|
|
environ: Mapping[str, str] | None = None,
|
|
) -> Path:
|
|
"""Return the host's skill root where Distilly itself is installed."""
|
|
return _resolve(host, "skills_dir", home, environ)
|
|
|
|
|
|
def generated_skills_dir(
|
|
host: str,
|
|
home: Path | None = None,
|
|
environ: Mapping[str, str] | None = None,
|
|
) -> Path:
|
|
"""Return the host's skill root for generated person skills."""
|
|
return _resolve(host, "generated_skills_dir", home, environ)
|