@sakanano-moe/agenthelm 6.5.3 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -0
- package/README.zh-CN.md +28 -0
- package/bin/agenthelm.js +1 -1
- package/package.json +2 -2
- package/runtime/index.json +80 -0
- package/runtime/plugins/agent-pack/.codex-plugin/plugin.json +26 -0
- package/runtime/plugins/agent-pack/.mcp.json +12 -0
- package/runtime/plugins/agent-pack/hooks/hooks.json +16 -0
- package/runtime/plugins/agent-pack/mcp.json +14 -0
- package/runtime/plugins/agent-pack/plugin.json +20 -0
- package/runtime/plugins/agent-pack/references/capability-config.md +148 -0
- package/runtime/plugins/agent-pack/runtime/agent_pack_claude.py +448 -0
- package/runtime/{agent_pack_config.py → plugins/agent-pack/runtime/agent_pack_config.py} +178 -22
- package/runtime/{agenthelm.py → plugins/agent-pack/runtime/agenthelm.py} +42 -1
- package/runtime/plugins/agent-pack/runtime/agenthelm_runtime.py +388 -0
- package/runtime/{mcp_server.py → plugins/agent-pack/runtime/mcp_server.py} +30 -8
- package/runtime/plugins/agent-pack/skills/agent-pack/SKILL.md +46 -0
- package/runtime/plugins/agents-init/.codex-plugin/plugin.json +22 -0
- package/runtime/plugins/agents-init/content.json +31 -0
- package/runtime/plugins/agents-init/plugin.json +19 -0
- package/runtime/plugins/agents-init/skills/agents-init/AGENT.template.md +376 -0
- package/runtime/plugins/agents-init/skills/agents-init/SKILL.md +119 -0
- package/runtime/plugins/agents-init/skills/agents-init/index.html +357 -0
- package/runtime/plugins/agents-init/skills/agents-init/launcher.sh +93 -0
- package/runtime/plugins/agents-init/skills/agents-init/project.schema.json +171 -0
- package/runtime/plugins/agents-init/skills/agents-init/scripts/init_project.py +1190 -0
- package/runtime/plugins/agents-init/skills/agents-init/scripts/test_init_project.py +678 -0
- package/runtime/plugins/agents-init/skills/agents-init/skill.json +122 -0
- package/runtime/plugins/opinion-manager/.codex-plugin/plugin.json +26 -0
- package/runtime/plugins/opinion-manager/catalog/README.md +15 -0
- package/runtime/plugins/opinion-manager/catalog/rules/.gitkeep +0 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.align-requirements/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.assumptions-authority/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.batch-questions/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.bilingual-terms/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.calculations/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.chinese-response/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.clean-deliverable/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.complete-options/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.conclusion-first/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.concrete-titles/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.consistent-items/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.device-readable/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.editable-diagrams/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.evidence-inference/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.maintenance-chinese/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.maintenance-project-language/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.markdown-structure/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.portable-files/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.report-context/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.report-formats/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.report-review/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.response-brief/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.response-dense/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.rules-tools/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.semantic-wrap/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.solutions-proportional/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.solutions-three-level/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.tables-compact/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.tables-list-first/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.test-evidence/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/rules/om.versioned-files/versions/1.0.0.json +11 -0
- package/runtime/plugins/opinion-manager/catalog/templates/.gitkeep +0 -0
- package/runtime/plugins/opinion-manager/catalog/templates/delivery-standard/compact-tables/versions/1.0.0.json +21 -0
- package/runtime/plugins/opinion-manager/catalog/templates/delivery-standard/list-first/versions/1.0.0.json +21 -0
- package/runtime/plugins/opinion-manager/catalog/templates/development-standard/chinese-maintenance/versions/1.0.0.json +15 -0
- package/runtime/plugins/opinion-manager/catalog/templates/development-standard/project-language/versions/1.0.0.json +15 -0
- package/runtime/plugins/opinion-manager/catalog/templates/response-style/brief-chinese/versions/1.0.0.json +19 -0
- package/runtime/plugins/opinion-manager/catalog/templates/response-style/dense-chinese/versions/1.0.0.json +19 -0
- package/runtime/plugins/opinion-manager/catalog/templates/scenario/concise-project/versions/1.0.0.json +39 -0
- package/runtime/plugins/opinion-manager/catalog/templates/scenario/reviewed-project/versions/1.0.0.json +39 -0
- package/runtime/plugins/opinion-manager/catalog/templates/work-method/proportional/versions/1.0.0.json +20 -0
- package/runtime/plugins/opinion-manager/catalog/templates/work-method/three-level/versions/1.0.0.json +20 -0
- package/runtime/plugins/opinion-manager/content.json +63 -0
- package/runtime/plugins/opinion-manager/plugin.json +18 -0
- package/runtime/plugins/opinion-manager/references/lock.schema.json +14 -0
- package/runtime/plugins/opinion-manager/references/onboarding.md +57 -0
- package/runtime/plugins/opinion-manager/references/profile.schema.json +56 -0
- package/runtime/plugins/opinion-manager/references/rule.schema.json +16 -0
- package/runtime/plugins/opinion-manager/references/template.schema.json +71 -0
- package/runtime/plugins/opinion-manager/references/versioned-template.schema.json +19 -0
- package/runtime/plugins/opinion-manager/references/versioning.md +263 -0
- package/runtime/plugins/opinion-manager/runtime/constants.py +7 -0
- package/runtime/plugins/opinion-manager/runtime/context.py +180 -0
- package/runtime/plugins/opinion-manager/runtime/lifecycle.py +395 -0
- package/runtime/plugins/opinion-manager/runtime/opinion_manager.py +419 -0
- package/runtime/plugins/opinion-manager/runtime/versioned.py +705 -0
- package/runtime/plugins/opinion-manager/skills/opinion-manager/SKILL.md +62 -0
- package/runtime/plugins/opinion-manager/skills/opinion-manager/agents/openai.yaml +4 -0
- package/runtime/plugins/opinion-manager/templates/.gitkeep +1 -0
- package/runtime/plugins/project-orchestrator/.codex-plugin/plugin.json +24 -0
- package/runtime/plugins/project-orchestrator/content.json +37 -0
- package/runtime/plugins/project-orchestrator/plugin.json +19 -0
- package/runtime/plugins/project-orchestrator/references/asset-synonyms.example.json +8 -0
- package/runtime/plugins/project-orchestrator/references/case-workspaces.md +159 -0
- package/runtime/plugins/project-orchestrator/references/case.schema.json +31 -0
- package/runtime/plugins/project-orchestrator/runtime/assets.py +1288 -0
- package/runtime/plugins/project-orchestrator/runtime/case.py +557 -0
- package/runtime/plugins/project-orchestrator/runtime/case_workspace.py +350 -0
- package/runtime/plugins/project-orchestrator/runtime/memory.py +363 -0
- package/runtime/plugins/project-orchestrator/runtime/project_base.py +107 -0
- package/runtime/plugins/project-orchestrator/runtime/project_cli.py +599 -0
- package/runtime/plugins/project-orchestrator/runtime/project_demo.py +504 -0
- package/runtime/plugins/project-orchestrator/runtime/project_maintain.py +470 -0
- package/runtime/plugins/project-orchestrator/runtime/project_menu.py +394 -0
- package/runtime/plugins/project-orchestrator/runtime/project_real.py +522 -0
- package/runtime/plugins/project-orchestrator/runtime/project_write.py +329 -0
- package/runtime/plugins/project-orchestrator/runtime/wf.py +439 -0
- package/runtime/plugins/project-orchestrator/skills/project-orchestrator/SKILL.md +230 -0
- package/runtime/plugins/project-orchestrator/skills/project-orchestrator/agents/openai.yaml +4 -0
- package/runtime/plugins/project-orchestrator/templates/CASE.md +39 -0
- /package/runtime/{mcp_env_launcher.py → plugins/agent-pack/runtime/mcp_env_launcher.py} +0 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"""agenthelm 用户级运行时:把四个插件的确定性工具装进用户数据目录,日常只需要 Python 3.11+。
|
|
2
|
+
|
|
3
|
+
布局(``$XDG_DATA_HOME`` 缺省为 ``~/.local/share``)::
|
|
4
|
+
|
|
5
|
+
agenthelm/runtimes/<发布版本>/ index.json、plugins/<插件>/、bin/agenthelm、runtime.json
|
|
6
|
+
agenthelm/current -> runtimes/<发布版本>
|
|
7
|
+
|
|
8
|
+
项目根启动器先找 ``current/bin/agenthelm``,所以装好后打开菜单不联网、不经过 npx。
|
|
9
|
+
同一版本装好后不再改写;新版本装在旁边并切换 ``current``,旧版本保留,可用 ``use`` 切回。
|
|
10
|
+
来源三选一:本命令所在的发布内容(npm 包、发布包或仓库检出)、``--from-release``
|
|
11
|
+
(联网下载发布包并核对摘要)、``--source``(本地目录或 .tar.gz,离线用)。
|
|
12
|
+
写操作默认只预览,``--apply`` 才执行。只在 macOS 与 Linux 上验证过。
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import hashlib
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import shutil
|
|
21
|
+
import sys
|
|
22
|
+
import tempfile
|
|
23
|
+
from datetime import UTC, datetime
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
PLUGINS = ("agent-pack", "agents-init", "opinion-manager", "project-orchestrator")
|
|
28
|
+
SKIP_PARTS = {"tests", "__pycache__", ".DS_Store", "node_modules"}
|
|
29
|
+
MANIFEST = "runtime.json"
|
|
30
|
+
SHIM = """#!/bin/sh
|
|
31
|
+
# agenthelm 运行时 {version}(agenthelm runtime install 生成)。只需要 Python 3.11+,不需要 AI 客户端。
|
|
32
|
+
self=$0
|
|
33
|
+
while [ -L "$self" ]; do # a command link (--link-bin) points here; follow it to the runtime
|
|
34
|
+
link=$(readlink "$self")
|
|
35
|
+
case $link in /*) self=$link ;; *) self=$(dirname -- "$self")/$link ;; esac
|
|
36
|
+
done
|
|
37
|
+
here=$(CDPATH= cd -- "$(dirname -- "$self")/.." && pwd)
|
|
38
|
+
for candidate in "${{AGENTHELM_PYTHON:-}}" python3 python; do
|
|
39
|
+
[ -n "$candidate" ] || continue
|
|
40
|
+
command -v "$candidate" >/dev/null 2>&1 || continue
|
|
41
|
+
if "$candidate" -c 'import sys; sys.exit(0 if sys.version_info >= (3, 11) else 1)' >/dev/null 2>&1; then
|
|
42
|
+
exec "$candidate" "$here/plugins/agent-pack/runtime/agenthelm.py" "$@"
|
|
43
|
+
fi
|
|
44
|
+
done
|
|
45
|
+
echo "agenthelm 需要 Python 3.11 或更高版本:安装后重试,或设置 AGENTHELM_PYTHON。" >&2
|
|
46
|
+
exit 3
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class RuntimeInstallError(Exception):
|
|
51
|
+
def __init__(self, message: str, next_steps: list[str] | None = None) -> None:
|
|
52
|
+
super().__init__(message)
|
|
53
|
+
self.next_steps = next_steps or []
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ---------------------------------------------------------------- locations
|
|
57
|
+
|
|
58
|
+
def data_root(env: Any) -> Path:
|
|
59
|
+
base = env.get("XDG_DATA_HOME")
|
|
60
|
+
return (Path(base) if base else env.home / ".local" / "share") / "agenthelm"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def runtimes_dir(env: Any) -> Path:
|
|
64
|
+
return data_root(env) / "runtimes"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def current_link(env: Any) -> Path:
|
|
68
|
+
return data_root(env) / "current"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def bundled_root() -> Path | None:
|
|
72
|
+
"""The release content this file ships in: npm package, release tarball or checkout."""
|
|
73
|
+
root = Path(__file__).resolve().parents[3]
|
|
74
|
+
return root if _is_release_root(root) else None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _is_release_root(root: Path) -> bool:
|
|
78
|
+
return (root / "index.json").is_file() and all((root / "plugins" / name / "plugin.json").is_file()
|
|
79
|
+
for name in PLUGINS)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def running_from(env: Any) -> str:
|
|
83
|
+
here = Path(__file__).resolve()
|
|
84
|
+
try:
|
|
85
|
+
if data_root(env).resolve() in here.parents:
|
|
86
|
+
return "runtime"
|
|
87
|
+
except OSError:
|
|
88
|
+
pass
|
|
89
|
+
text = here.as_posix()
|
|
90
|
+
if "/plugins/cache/" in text or "/.cursor/plugins/" in text:
|
|
91
|
+
return "client-plugin"
|
|
92
|
+
if "/node_modules/" in text or "/_npx/" in text:
|
|
93
|
+
return "npm"
|
|
94
|
+
return "checkout"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------- source description
|
|
98
|
+
|
|
99
|
+
def _shipped_files(root: Path) -> list[Path]:
|
|
100
|
+
files = []
|
|
101
|
+
for name in PLUGINS:
|
|
102
|
+
base = root / "plugins" / name
|
|
103
|
+
for path in sorted(base.rglob("*")):
|
|
104
|
+
relative = path.relative_to(root)
|
|
105
|
+
if path.is_file() and not path.is_symlink() and not (set(relative.parts) & SKIP_PARTS) \
|
|
106
|
+
and path.suffix != ".pyc":
|
|
107
|
+
files.append(relative)
|
|
108
|
+
return files
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def describe(root: Path) -> dict:
|
|
112
|
+
if not _is_release_root(root):
|
|
113
|
+
raise RuntimeInstallError(f"{root} 不是 agenthelm 发布内容(缺少 index.json 或 plugins/<插件>)",
|
|
114
|
+
["--source 指向仓库检出、解压后的发布包目录或 .tar.gz 发布包"])
|
|
115
|
+
index = json.loads((root / "index.json").read_text(encoding="utf-8"))
|
|
116
|
+
version = str(index.get("plugin", {}).get("version") or "")
|
|
117
|
+
if not version:
|
|
118
|
+
raise RuntimeInstallError(f"{root}/index.json 没有发布版本号")
|
|
119
|
+
digest = hashlib.sha256()
|
|
120
|
+
files = _shipped_files(root)
|
|
121
|
+
for relative in files:
|
|
122
|
+
digest.update(relative.as_posix().encode("utf-8") + b"\0" + (root / relative).read_bytes() + b"\0")
|
|
123
|
+
plugins = {name: json.loads((root / "plugins" / name / "plugin.json").read_text(encoding="utf-8")).get("version")
|
|
124
|
+
for name in PLUGINS}
|
|
125
|
+
return {"version": version, "plugins": plugins, "digest": digest.hexdigest(), "files": len(files)}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _read_manifest(directory: Path) -> dict | None:
|
|
129
|
+
try:
|
|
130
|
+
data = json.loads((directory / MANIFEST).read_text(encoding="utf-8"))
|
|
131
|
+
except (OSError, ValueError):
|
|
132
|
+
return None
|
|
133
|
+
return data if isinstance(data, dict) else None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def installed(env: Any) -> list[dict]:
|
|
137
|
+
base = runtimes_dir(env)
|
|
138
|
+
found = []
|
|
139
|
+
if base.is_dir():
|
|
140
|
+
for directory in sorted(base.iterdir()):
|
|
141
|
+
manifest = _read_manifest(directory) if directory.is_dir() and not directory.name.startswith(".") else None
|
|
142
|
+
if manifest:
|
|
143
|
+
found.append({**manifest, "path": str(directory)})
|
|
144
|
+
return found
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def current(env: Any) -> dict | None:
|
|
148
|
+
link = current_link(env)
|
|
149
|
+
if not link.is_symlink():
|
|
150
|
+
return None
|
|
151
|
+
manifest = _read_manifest(link)
|
|
152
|
+
return {**manifest, "path": str(link.resolve())} if manifest else None
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def release_version(latest: dict | None) -> str | None:
|
|
156
|
+
tag = ((latest or {}).get("release") or {}).get("tag")
|
|
157
|
+
return tag[1:] if isinstance(tag, str) and tag.startswith("v") else tag
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def report(env: Any, latest: dict | None = None) -> dict:
|
|
161
|
+
active = current(env)
|
|
162
|
+
newest = release_version(latest)
|
|
163
|
+
return {"current": active, "installed": installed(env), "data_root": str(data_root(env)),
|
|
164
|
+
"running_from": running_from(env), "latest_release": newest,
|
|
165
|
+
"update_available": bool(active and newest and _newer(newest, active["version"]))}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _newer(candidate: str, existing: str) -> bool:
|
|
169
|
+
def key(value: str) -> tuple:
|
|
170
|
+
parts = value.split("-", 1)[0].split(".")
|
|
171
|
+
return tuple(int(part) if part.isdigit() else 0 for part in parts)
|
|
172
|
+
return key(candidate) > key(existing)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# ---------------------------------------------------------------- plan and apply
|
|
176
|
+
|
|
177
|
+
def plan(env: Any, root: Path, origin: str, *, link_bin: Path | None = None) -> dict:
|
|
178
|
+
info = describe(root)
|
|
179
|
+
target = runtimes_dir(env) / info["version"]
|
|
180
|
+
existing = _read_manifest(target)
|
|
181
|
+
active = current(env)
|
|
182
|
+
if existing and existing.get("digest") != info["digest"]:
|
|
183
|
+
raise RuntimeInstallError(f"运行时 {info['version']} 已安装,但内容与来源不同(来源:{origin})",
|
|
184
|
+
[f"已装:{target};同一版本不会被改写",
|
|
185
|
+
"确认要换掉时先手动移走该目录(例如移到 ~/.agent-pack/recovery/),再重新安装"])
|
|
186
|
+
writes = []
|
|
187
|
+
if not existing:
|
|
188
|
+
writes.append({"path": str(target), "scope": "用户数据目录(新版本,旧版本保留)"})
|
|
189
|
+
switch = not active or active.get("version") != info["version"]
|
|
190
|
+
if switch:
|
|
191
|
+
writes.append({"path": str(current_link(env)), "scope": f"切换当前版本 → {info['version']}"})
|
|
192
|
+
link = None
|
|
193
|
+
if link_bin is not None:
|
|
194
|
+
link = link_bin.expanduser() / "agenthelm"
|
|
195
|
+
expected = current_link(env) / "bin" / "agenthelm"
|
|
196
|
+
if link.is_symlink() and Path(os.readlink(link)) == expected:
|
|
197
|
+
link = None
|
|
198
|
+
elif link.exists() or link.is_symlink():
|
|
199
|
+
raise RuntimeInstallError(f"{link} 已存在且不是本运行时的链接,不会覆盖", ["换一个 --link-bin 目录,或手动处理该文件"])
|
|
200
|
+
else:
|
|
201
|
+
writes.append({"path": str(link), "scope": "命令链接(指向当前运行时)"})
|
|
202
|
+
return {"version": info["version"], "plugins": info["plugins"], "digest": info["digest"], "source": origin,
|
|
203
|
+
"target": str(target), "install": not existing, "switch": switch,
|
|
204
|
+
"previous": active.get("version") if active else None, "link": str(link) if link else None,
|
|
205
|
+
"writes": writes, "action": "install" if not existing else ("switch" if switch else "none")}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def apply(env: Any, planned: dict, root: Path) -> dict:
|
|
209
|
+
base = runtimes_dir(env)
|
|
210
|
+
base.mkdir(parents=True, exist_ok=True)
|
|
211
|
+
target = Path(planned["target"])
|
|
212
|
+
if planned["install"]:
|
|
213
|
+
staging = Path(tempfile.mkdtemp(prefix=f".{planned['version']}-", dir=base))
|
|
214
|
+
try:
|
|
215
|
+
for relative in _shipped_files(root):
|
|
216
|
+
destination = staging / relative
|
|
217
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
218
|
+
shutil.copy2(root / relative, destination)
|
|
219
|
+
shutil.copy2(root / "index.json", staging / "index.json")
|
|
220
|
+
if describe(staging)["digest"] != planned["digest"]:
|
|
221
|
+
raise RuntimeInstallError("复制后的内容与来源摘要不一致,已放弃安装")
|
|
222
|
+
shim = staging / "bin" / "agenthelm"
|
|
223
|
+
shim.parent.mkdir()
|
|
224
|
+
shim.write_text(SHIM.format(version=planned["version"]), encoding="utf-8")
|
|
225
|
+
shim.chmod(0o755)
|
|
226
|
+
manifest = {"schema_version": 1, "version": planned["version"], "plugins": planned["plugins"],
|
|
227
|
+
"digest": planned["digest"], "source": planned["source"],
|
|
228
|
+
"installed_at": datetime.now(UTC).replace(microsecond=0).isoformat()}
|
|
229
|
+
(staging / MANIFEST).write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
230
|
+
os.rename(staging, target)
|
|
231
|
+
except BaseException:
|
|
232
|
+
shutil.rmtree(staging, ignore_errors=True)
|
|
233
|
+
raise
|
|
234
|
+
if planned["switch"]:
|
|
235
|
+
_switch(env, target)
|
|
236
|
+
if planned["link"]:
|
|
237
|
+
link = Path(planned["link"])
|
|
238
|
+
link.parent.mkdir(parents=True, exist_ok=True)
|
|
239
|
+
link.symlink_to(current_link(env) / "bin" / "agenthelm")
|
|
240
|
+
active = current(env)
|
|
241
|
+
shim = current_link(env) / "bin" / "agenthelm"
|
|
242
|
+
verified = bool(active and active["version"] == planned["version"] and os.access(shim, os.X_OK))
|
|
243
|
+
return {"ok": verified, "version": planned["version"], "current": active,
|
|
244
|
+
"verify": (f"重新读取:当前运行时 {planned['version']},命令 {shim}" if verified
|
|
245
|
+
else "回读不一致:请运行 agenthelm runtime status 查看"),
|
|
246
|
+
"rollback": f"agenthelm runtime use {planned['previous']} --apply" if planned["previous"]
|
|
247
|
+
and planned["previous"] != planned["version"] else None}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _switch(env: Any, target: Path) -> None:
|
|
251
|
+
link = current_link(env)
|
|
252
|
+
temporary = link.with_name(f".current.{os.getpid()}")
|
|
253
|
+
if temporary.is_symlink() or temporary.exists():
|
|
254
|
+
temporary.unlink()
|
|
255
|
+
temporary.symlink_to(Path("runtimes") / target.name)
|
|
256
|
+
os.replace(temporary, link)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def use(env: Any, version: str, *, apply_change: bool) -> dict:
|
|
260
|
+
target = runtimes_dir(env) / version
|
|
261
|
+
if not _read_manifest(target):
|
|
262
|
+
versions = "、".join(item["version"] for item in installed(env)) or "(无)"
|
|
263
|
+
raise RuntimeInstallError(f"没有安装运行时 {version}", [f"已安装:{versions}"])
|
|
264
|
+
active = current(env)
|
|
265
|
+
result = {"version": version, "previous": active.get("version") if active else None, "applied": False}
|
|
266
|
+
if apply_change:
|
|
267
|
+
_switch(env, target)
|
|
268
|
+
result["applied"] = True
|
|
269
|
+
result["current"] = current(env)
|
|
270
|
+
return result
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# ---------------------------------------------------------------- sources
|
|
274
|
+
|
|
275
|
+
def resolve_source(host: Any, env: Any, args: argparse.Namespace, workdir: Path, *, prefer_release: bool) -> tuple[Path, str]:
|
|
276
|
+
if args.source is not None:
|
|
277
|
+
source = args.source.expanduser().resolve()
|
|
278
|
+
if source.is_file():
|
|
279
|
+
extracted = workdir / "source"
|
|
280
|
+
extracted.mkdir()
|
|
281
|
+
host._safe_extract(source, extracted)
|
|
282
|
+
roots = [path for path in extracted.iterdir() if path.is_dir()]
|
|
283
|
+
if len(roots) != 1:
|
|
284
|
+
raise RuntimeInstallError("发布包结构不符合预期")
|
|
285
|
+
return roots[0], f"本地发布包 {source.name}"
|
|
286
|
+
return source, f"本地目录 {source}"
|
|
287
|
+
bundled = bundled_root()
|
|
288
|
+
if bundled is not None and not prefer_release and not args.from_release:
|
|
289
|
+
return bundled, f"随附内容({running_from(env)})"
|
|
290
|
+
try:
|
|
291
|
+
latest, _ = host.load_latest(env, args.latest, max_age=0)
|
|
292
|
+
return host.release_source(latest, workdir), "GitHub Release(已核对摘要)"
|
|
293
|
+
except (host.CheckError, OSError, ValueError) as exc:
|
|
294
|
+
raise RuntimeInstallError(f"无法下载发布包:{exc}",
|
|
295
|
+
["离线时用 --source 指向发布包(.tar.gz)或仓库检出",
|
|
296
|
+
"下载地址见 https://github.com/lc4t/agenthelm/releases"]) from exc
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# ---------------------------------------------------------------- command line
|
|
300
|
+
|
|
301
|
+
def parser() -> argparse.ArgumentParser:
|
|
302
|
+
result = argparse.ArgumentParser(prog="agenthelm runtime", description=__doc__.split("\n\n")[0])
|
|
303
|
+
sub = result.add_subparsers(dest="action", required=True)
|
|
304
|
+
for name, text in (("status", "当前运行时、已装版本与可用更新"),
|
|
305
|
+
("install", "安装运行时(默认用本命令随附的内容;默认预览)"),
|
|
306
|
+
("update", "联网安装最新发布版本并切换(默认预览)"),
|
|
307
|
+
("use", "切换到已安装的某个版本(默认预览)")):
|
|
308
|
+
command = sub.add_parser(name, help=text)
|
|
309
|
+
command.add_argument("--output", choices=("text", "json"), default="text")
|
|
310
|
+
command.add_argument("--home", type=Path, help=argparse.SUPPRESS)
|
|
311
|
+
command.add_argument("--latest", help="latest.json 的 URL 或本地路径")
|
|
312
|
+
if name == "use":
|
|
313
|
+
command.add_argument("version")
|
|
314
|
+
if name in ("install", "update"):
|
|
315
|
+
command.add_argument("--source", type=Path, help="本地目录或 .tar.gz 发布包(离线安装)")
|
|
316
|
+
command.add_argument("--link-bin", type=Path, help="在这个目录建 agenthelm 命令链接(例如 ~/.local/bin)")
|
|
317
|
+
if name == "install":
|
|
318
|
+
command.add_argument("--from-release", action="store_true", help="联网下载发布包,而不用随附内容")
|
|
319
|
+
if name != "status":
|
|
320
|
+
command.add_argument("--apply", action="store_true")
|
|
321
|
+
if name == "status":
|
|
322
|
+
command.add_argument("--offline", action="store_true", help="只用缓存的版本信息")
|
|
323
|
+
return result
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _print(payload: dict, output: str, lines: list[str]) -> None:
|
|
327
|
+
if output == "json":
|
|
328
|
+
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
329
|
+
else:
|
|
330
|
+
print("\n".join(lines))
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def main(argv: list[str], host: Any) -> int:
|
|
334
|
+
args = parser().parse_args(argv)
|
|
335
|
+
env = host.current_env(args.home)
|
|
336
|
+
if sys.platform == "win32":
|
|
337
|
+
print("agenthelm runtime 目前只支持 macOS 与 Linux。", file=sys.stderr)
|
|
338
|
+
return 4
|
|
339
|
+
try:
|
|
340
|
+
if args.action == "status":
|
|
341
|
+
try:
|
|
342
|
+
latest, _ = host.load_latest(env, args.latest, offline=args.offline)
|
|
343
|
+
except (host.CheckError, OSError, ValueError):
|
|
344
|
+
latest = None
|
|
345
|
+
data = report(env, latest)
|
|
346
|
+
active = data["current"]
|
|
347
|
+
lines = [f"当前运行时:{active['version']}({active['path']})" if active else "当前运行时:未安装",
|
|
348
|
+
f"已安装:{'、'.join(item['version'] for item in data['installed']) or '(无)'}",
|
|
349
|
+
f"本次命令来自:{data['running_from']}"]
|
|
350
|
+
if data["update_available"]:
|
|
351
|
+
lines.append(f"有新版本 {data['latest_release']}:agenthelm runtime update 预览")
|
|
352
|
+
if not active:
|
|
353
|
+
lines.append("安装:agenthelm runtime install(预览)→ 加 --apply 执行")
|
|
354
|
+
_print({"ok": True, **data}, args.output, lines)
|
|
355
|
+
return 0
|
|
356
|
+
if args.action == "use":
|
|
357
|
+
result = use(env, args.version, apply_change=args.apply)
|
|
358
|
+
lines = [f"{'已切换' if result['applied'] else '将切换'}:{result['previous']} → {result['version']}"]
|
|
359
|
+
if not args.apply:
|
|
360
|
+
lines.append("以上为预览;加 --apply 执行。")
|
|
361
|
+
_print({"ok": True, **result}, args.output, lines)
|
|
362
|
+
return 0
|
|
363
|
+
with tempfile.TemporaryDirectory(prefix="agenthelm-runtime-") as temporary:
|
|
364
|
+
root, origin = resolve_source(host, env, args, Path(temporary), prefer_release=args.action == "update")
|
|
365
|
+
planned = plan(env, root, origin, link_bin=args.link_bin)
|
|
366
|
+
lines = [f"运行时 {planned['version']}(来源:{origin})"]
|
|
367
|
+
lines += [f" 将写入:{item['path']}({item['scope']})" for item in planned["writes"]] or [" 已是当前版本,无需改动。"]
|
|
368
|
+
if not args.apply or planned["action"] == "none" and not planned["link"]:
|
|
369
|
+
if args.apply is False and planned["writes"]:
|
|
370
|
+
lines.append("以上为预览;加 --apply 执行。")
|
|
371
|
+
_print({"ok": True, "applied": False, "plan": planned}, args.output, lines)
|
|
372
|
+
return 0
|
|
373
|
+
result = apply(env, planned, root)
|
|
374
|
+
lines.append((" " + result["verify"]))
|
|
375
|
+
if result["rollback"]:
|
|
376
|
+
lines.append(f" 回到旧版本:{result['rollback']}")
|
|
377
|
+
if not os.environ.get("PATH", "").count(str(current_link(env) / "bin")) and not planned["link"]:
|
|
378
|
+
lines.append(f" 直接用命令:把 {current_link(env) / 'bin'} 加入 PATH,或重新运行并加 --link-bin ~/.local/bin")
|
|
379
|
+
_print({"ok": result["ok"], "applied": True, "plan": planned, **result}, args.output, lines)
|
|
380
|
+
return 0 if result["ok"] else 6
|
|
381
|
+
except RuntimeInstallError as exc:
|
|
382
|
+
if args.output == "json":
|
|
383
|
+
print(json.dumps({"ok": False, "error": str(exc), "next": exc.next_steps}, ensure_ascii=False, indent=2))
|
|
384
|
+
else:
|
|
385
|
+
print(f"出错:{exc}", file=sys.stderr)
|
|
386
|
+
for step in exc.next_steps:
|
|
387
|
+
print(f" · {step}", file=sys.stderr)
|
|
388
|
+
return 4 if "无法下载" in str(exc) else 2
|
|
@@ -43,7 +43,7 @@ TOOLS = [
|
|
|
43
43
|
{
|
|
44
44
|
"name": "agent_pack_bootstrap",
|
|
45
45
|
"title": "Install Agent Plugin",
|
|
46
|
-
"description": "Dry-run or install a portable plugin, including agent-pack itself, into Codex, Cursor, or Claude Code without overwriting an existing package.",
|
|
46
|
+
"description": "Dry-run or install a portable plugin, including agent-pack itself, into Codex, Cursor, or Claude Code without overwriting an existing package. For Claude Code, skills / mcps limit the install to those components, and local credential values on MCP entries are kept unless resetOverrides.",
|
|
47
47
|
"inputSchema": {
|
|
48
48
|
"type": "object",
|
|
49
49
|
"properties": {
|
|
@@ -53,6 +53,9 @@ TOOLS = [
|
|
|
53
53
|
"apply": {"type": "boolean", "default": False},
|
|
54
54
|
"replace": {"type": "boolean", "default": False},
|
|
55
55
|
"recoveryRoot": {"type": "string"},
|
|
56
|
+
"skills": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
57
|
+
"mcps": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
58
|
+
"resetOverrides": {"type": "boolean", "default": False},
|
|
56
59
|
},
|
|
57
60
|
"required": ["plugin", "client"],
|
|
58
61
|
"additionalProperties": False,
|
|
@@ -62,12 +65,14 @@ TOOLS = [
|
|
|
62
65
|
{
|
|
63
66
|
"name": "agent_pack_reconcile",
|
|
64
67
|
"title": "Reconcile Project and Client Capabilities",
|
|
65
|
-
"description": "Classify capability drift, safely replace the managed project package, and archive explicitly selected legacy Skills or plugins with rollback. apply defaults to false.",
|
|
68
|
+
"description": "Classify capability drift, safely replace the managed project package, and archive explicitly selected legacy Skills or plugins with rollback. Claude Code gets its own package, MCP entries and Skill links; local credential values are kept unless resetOverrides. apply defaults to false.",
|
|
66
69
|
"inputSchema": {
|
|
67
70
|
"type": "object",
|
|
68
71
|
"properties": {
|
|
69
72
|
"project": {"type": "string"},
|
|
70
|
-
"client": {"type": "string", "enum": ["codex", "cursor"]},
|
|
73
|
+
"client": {"type": "string", "enum": ["codex", "cursor", "claude"]},
|
|
74
|
+
"replace": {"type": "boolean", "default": False},
|
|
75
|
+
"resetOverrides": {"type": "boolean", "default": False},
|
|
71
76
|
"home": {"type": "string"},
|
|
72
77
|
"retireSkills": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
73
78
|
"retirePlugins": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
@@ -97,10 +102,15 @@ TOOLS = [
|
|
|
97
102
|
{
|
|
98
103
|
"name": "agent_pack_doctor",
|
|
99
104
|
"title": "Validate Project Capabilities",
|
|
100
|
-
"description": "Validate an initialized project's Agent Plugin, Skill, MCP, duplicate-name, portability, and secret boundaries.",
|
|
105
|
+
"description": "Validate an initialized project's Agent Plugin, Skill, MCP, duplicate-name, portability, and secret boundaries. With clients, also report each client's missing, stale and different components and kept local overrides.",
|
|
101
106
|
"inputSchema": {
|
|
102
107
|
"type": "object",
|
|
103
|
-
"properties": {
|
|
108
|
+
"properties": {
|
|
109
|
+
"project": {"type": "string"},
|
|
110
|
+
"clients": {"type": "array", "items": {"type": "string", "enum": ["codex", "cursor", "claude"]},
|
|
111
|
+
"default": []},
|
|
112
|
+
"home": {"type": "string"},
|
|
113
|
+
},
|
|
104
114
|
"required": ["project"],
|
|
105
115
|
"additionalProperties": False,
|
|
106
116
|
},
|
|
@@ -127,14 +137,17 @@ TOOLS = [
|
|
|
127
137
|
{
|
|
128
138
|
"name": "agent_pack_sync",
|
|
129
139
|
"title": "Sync Project Capabilities to an Agent Client",
|
|
130
|
-
"description": "Dry-run or install a project's portable capability package into Codex or
|
|
140
|
+
"description": "Dry-run or install a project's portable capability package into Codex, Cursor or Claude Code. apply defaults to false; replaced content goes to the recovery directory. Claude Code keeps local credential values unless resetOverrides, and only replaces entries it did not install with replace.",
|
|
131
141
|
"inputSchema": {
|
|
132
142
|
"type": "object",
|
|
133
143
|
"properties": {
|
|
134
144
|
"project": {"type": "string"},
|
|
135
|
-
"client": {"type": "string", "enum": ["codex", "cursor"]},
|
|
145
|
+
"client": {"type": "string", "enum": ["codex", "cursor", "claude"]},
|
|
136
146
|
"home": {"type": "string"},
|
|
137
147
|
"apply": {"type": "boolean", "default": False},
|
|
148
|
+
"replace": {"type": "boolean", "default": False},
|
|
149
|
+
"resetOverrides": {"type": "boolean", "default": False},
|
|
150
|
+
"recoveryRoot": {"type": "string"},
|
|
138
151
|
},
|
|
139
152
|
"required": ["project", "client"],
|
|
140
153
|
"additionalProperties": False,
|
|
@@ -174,6 +187,9 @@ def _call(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
|
174
187
|
apply=bool(arguments.get("apply", False)),
|
|
175
188
|
replace=bool(arguments.get("replace", False)),
|
|
176
189
|
recovery_root=recovery,
|
|
190
|
+
skills=arguments.get("skills", []),
|
|
191
|
+
mcps=arguments.get("mcps", []),
|
|
192
|
+
reset_overrides=bool(arguments.get("resetOverrides", False)),
|
|
177
193
|
)
|
|
178
194
|
if name == "agent_pack_reconcile":
|
|
179
195
|
recovery_value = arguments.get("recoveryRoot")
|
|
@@ -187,6 +203,8 @@ def _call(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
|
187
203
|
recovery_root=recovery,
|
|
188
204
|
apply=bool(arguments.get("apply", False)),
|
|
189
205
|
retire_only=bool(arguments.get("retireOnly", False)),
|
|
206
|
+
replace=bool(arguments.get("replace", False)),
|
|
207
|
+
reset_overrides=bool(arguments.get("resetOverrides", False)),
|
|
190
208
|
)
|
|
191
209
|
if name == "agent_pack_inventory":
|
|
192
210
|
inventory = inventory_source(arguments["source"], home)
|
|
@@ -194,7 +212,7 @@ def _call(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
|
194
212
|
payload["ok"] = not payload["issues"]
|
|
195
213
|
return payload
|
|
196
214
|
if name == "agent_pack_doctor":
|
|
197
|
-
return doctor(Path(arguments["project"]))
|
|
215
|
+
return doctor(Path(arguments["project"]), arguments.get("clients", []), home)
|
|
198
216
|
if name == "agent_pack_transfer":
|
|
199
217
|
source = inventory_source(arguments["source"], home)
|
|
200
218
|
return transfer_to_project(
|
|
@@ -205,11 +223,15 @@ def _call(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
|
205
223
|
apply=bool(arguments.get("apply", False)),
|
|
206
224
|
)
|
|
207
225
|
if name == "agent_pack_sync":
|
|
226
|
+
recovery_value = arguments.get("recoveryRoot")
|
|
208
227
|
return sync_project(
|
|
209
228
|
Path(arguments["project"]),
|
|
210
229
|
arguments["client"],
|
|
211
230
|
home=home,
|
|
212
231
|
apply=bool(arguments.get("apply", False)),
|
|
232
|
+
replace=bool(arguments.get("replace", False)),
|
|
233
|
+
reset_overrides=bool(arguments.get("resetOverrides", False)),
|
|
234
|
+
recovery_root=Path(recovery_value) if isinstance(recovery_value, str) else None,
|
|
213
235
|
)
|
|
214
236
|
raise AgentPackError(f"unknown tool: {name}")
|
|
215
237
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-pack
|
|
3
|
+
description: Deterministically inventory, verify, install, sync, migrate and reconcile Agent Plugins, Skills and MCP servers across projects, plugin directories and clients such as Codex, Cursor and Claude. Use when discovering, importing, exporting, syncing or verifying Agent capabilities, or diagnosing extension drift on a machine. The project lifecycle (Task/Case/routing/verification/Git) is not part of this Skill; that is project-orchestrator. 中文:确定性地盘点、校验、安装、同步、迁移与对账 Agent Plugin、Skill 与 MCP server——在项目、插件目录与 Codex / Cursor / Claude 等客户端之间。当需要发现、导入、导出、同步或验证 Agent 能力,或诊断某台机器的扩展安装漂移时使用。项目生命周期(Task/Case/路由/验证/Git)不在本 Skill 内——那是 project-orchestrator。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent Pack(Agent 扩展能力管理)
|
|
7
|
+
|
|
8
|
+
## 定位
|
|
9
|
+
|
|
10
|
+
`agent-pack` 是**确定性工具**,不做生命周期决策。它只在项目、插件目录与已支持客户端之间 inventory / doctor / bootstrap / sync / transfer / reconcile。所有写操作默认 dry-run;重名、无效 manifest、外部 symlink、含疑似密钥的 MCP 条目一律失败关闭。
|
|
11
|
+
|
|
12
|
+
- 项目编排(选 Task/Case、路由、验证、Git 交付)归 **project-orchestrator**,不在本 Skill 内。
|
|
13
|
+
- 跨机整机恢复的**单一用户入口**是 `python3 tools/agent-bootstrap`(`doctor` / `install <client>` / `list`),它读取 `00-system/capabilities.json` 的 `agent_extensions` 契约并在内部调用本工具。日常先用它。
|
|
14
|
+
- 只有需要单组件级操作(transfer 某个 skill、reconcile 退役某个旧包、向另一个项目导出)时才直接用本工具。
|
|
15
|
+
|
|
16
|
+
## 入口
|
|
17
|
+
|
|
18
|
+
优先使用随附的 `agent-pack` MCP Tool(`agent_pack_inventory` / `agent_pack_doctor` / `agent_pack_bootstrap` / `agent_pack_sync` / `agent_pack_transfer` / `agent_pack_reconcile`);不可用时运行标准库 CLI `runtime/agent_pack_config.py`。执行能力管理前读取 [references/capability-config.md](../../references/capability-config.md)。
|
|
19
|
+
|
|
20
|
+
`runtime/agenthelm.py` 另有两个面向人的入口:`project` 转交 project-orchestrator 的项目入口(不需要 AI Agent);`runtime install|update|use|status` 管理用户级运行时(`~/.local/share/agenthelm/`,项目根目录的启动器优先使用它),写操作默认预览、`--apply` 才执行,新版本装在旁边、旧版本保留。
|
|
21
|
+
|
|
22
|
+
## 执行顺序
|
|
23
|
+
|
|
24
|
+
1. 盘点来源与目标(`inventory --source project:/path | plugin:/path | client:codex | client:cursor | client:claude`);
|
|
25
|
+
2. 把每个组件分类为 Agent Plugin、Skill 或 MCP server;
|
|
26
|
+
3. 拒绝重名、无效 manifest、外部 symlink 以及包含密钥的 MCP 配置;
|
|
27
|
+
4. 通过 dry-run 预览导入、导出与客户端同步;
|
|
28
|
+
5. 计划写入其他项目或用户级客户端时申请授权;
|
|
29
|
+
6. 只应用明确选择的组件;
|
|
30
|
+
7. 对目标运行 `doctor`。
|
|
31
|
+
|
|
32
|
+
目标客户端尚未安装某包时,从可信本地插件根目录使用 `bootstrap`。`bootstrap` 支持 `codex` / `cursor` / `claude`;Claude 端写入 `~/.claude/skills` 符号链接与 `~/.claude.json` user-scope MCP,可用 `--skill` / `--mcp` 只装选中的组件,本机认证值默认保留(`--reset-overrides` 才丢弃),装完需重启 Claude Code。把项目能力同步到 Claude 用 `sync --client claude`:它为 Claude 单独生成包,只增删改本包装过的条目,不要用 `bootstrap` 指向 Codex 的包。核对客户端是否与项目一致用 `doctor --client <客户端>`。处理已有客户端时优先使用 `reconcile`:审阅组件状态,明确列出要退役的旧 Skill/plugin,再执行应用。只退役、不安装项目包时加 `--retire-only`。用户验收迁移前,已退役或替换的内容必须保留在报告的恢复目录(`~/.agent-pack/recovery/`)中。
|
|
33
|
+
|
|
34
|
+
## 打包与协议
|
|
35
|
+
|
|
36
|
+
优先使用 Agent Plugins 1.0 作为可移植包格式:根目录 `plugin.json`、直接子目录 `skills/<name>/SKILL.md` 和根目录 `mcp.json`。客户端专属投影(`.codex-plugin/`、`.mcp.json`)只作为 adapter 保留,且其 `name` / `version` 由 `plugin.json` 生成,禁止手改。以 MCP 2026-07-28 为主要 wire revision;已安装客户端仍要求旧版本时保留兼容投影。
|
|
37
|
+
|
|
38
|
+
## 版本完整性
|
|
39
|
+
|
|
40
|
+
`plugin.json#version` 是唯一权威。`doctor` 对每个被盘点插件比对仓库 `plugin.json` 版本与其 `.codex-plugin/plugin.json` 适配器版本,不一致即报 issue(fail,不是 warning)。`~/.codex/plugins/cache/personal/` 是 Codex 自身的版本化缓存,滞后于 marketplace 源,须由 Codex 下次激活或重启刷新——这不是 `agent-pack` 能写的。
|
|
41
|
+
|
|
42
|
+
## 边界
|
|
43
|
+
|
|
44
|
+
- 不初始化项目、不创建骨架(那是 `agents-init`)。
|
|
45
|
+
- 不选择 Task/Case、不写项目进度、不做 Git 提交(那是 project-orchestrator)。
|
|
46
|
+
- 不把原生客户端 MCP 配置中的凭据复制进可移植包;含密钥条目保持 `blocked` 并留在客户端本地。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agents-init",
|
|
3
|
+
"version": "6.6.1",
|
|
4
|
+
"description": "Initialize or migrate an Agent project contract; ships with project-orchestrator, agent-pack and opinion-manager.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "lc4t"
|
|
7
|
+
},
|
|
8
|
+
"skills": "./skills/",
|
|
9
|
+
"interface": {
|
|
10
|
+
"displayName": "Agents Init",
|
|
11
|
+
"shortDescription": "Initialize or migrate the project skeleton and Project Profile",
|
|
12
|
+
"longDescription": "Use agents-init to create or migrate a portable project contract, including a root launcher that opens the project menu without any AI agent. project-orchestrator manages the project lifecycle, agent-pack manages Plugins/Skills/MCP, and opinion-manager manages behavior rules between the user and the Agent; all three ship alongside it as separate plugins. 中文:用 agents-init 创建或迁移可移植项目契约(含不需要 AI Agent 就能打开项目菜单的根目录启动器)。project-orchestrator 管理项目生命周期,agent-pack 管理 Plugin/Skill/MCP,opinion-manager 管理用户与 Agent 之间的行为规则;三者作为独立 Plugin 随同分发。",
|
|
13
|
+
"developerName": "lc4t",
|
|
14
|
+
"category": "Developer Tools",
|
|
15
|
+
"capabilities": [
|
|
16
|
+
"project-initialization",
|
|
17
|
+
"project-migration",
|
|
18
|
+
"opinion-configuration"
|
|
19
|
+
],
|
|
20
|
+
"defaultPrompt": "Use $agents-init to initialize or migrate this project, then use $opinion-manager to configure the Agent behavior rules for this environment."
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"packs": [
|
|
4
|
+
{
|
|
5
|
+
"id": "agents-init/project-contract",
|
|
6
|
+
"version": "1.1.0",
|
|
7
|
+
"kind": "template",
|
|
8
|
+
"title": "项目契约模板",
|
|
9
|
+
"description": "初始化时渲染为项目入口文件的中文模板与根目录启动器;更新后由用户逐文件选择是否重新渲染。",
|
|
10
|
+
"sources": [
|
|
11
|
+
"skills/agents-init/AGENT.template.md",
|
|
12
|
+
"skills/agents-init/launcher.sh"
|
|
13
|
+
],
|
|
14
|
+
"materializes": [
|
|
15
|
+
"AGENTS.md",
|
|
16
|
+
"AGENT.RULES.md",
|
|
17
|
+
"CLAUDE.md",
|
|
18
|
+
"AGENT.md",
|
|
19
|
+
"docs/refs/README.md"
|
|
20
|
+
],
|
|
21
|
+
"project_lock": "agenthelm",
|
|
22
|
+
"files": {
|
|
23
|
+
"skills/agents-init/AGENT.template.md": "cb35f9a20b845686f24823c03bc71c5b93683dc750b61bd4eae733da2085b056",
|
|
24
|
+
"skills/agents-init/launcher.sh": "cf27d6cca786905a192446ea4eefe5635942914c3358c78d12117af912107cad"
|
|
25
|
+
},
|
|
26
|
+
"materializes_from_profile": [
|
|
27
|
+
"entry.launcher"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "agents-init",
|
|
4
|
+
"version": "6.6.1",
|
|
5
|
+
"description": "Initialize or migrate an Agent project contract (AGENTS.md, Project Profile, root launcher); ships with project-orchestrator, agent-pack and opinion-manager.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "lc4t"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/lc4t/agenthelm",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"agents-init",
|
|
13
|
+
"project-orchestrator",
|
|
14
|
+
"agent-pack",
|
|
15
|
+
"opinion-manager",
|
|
16
|
+
"agent-skills",
|
|
17
|
+
"agent-plugins"
|
|
18
|
+
]
|
|
19
|
+
}
|