@kairyou/agent-tools 0.22.0 → 0.23.1
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/.claude-plugin/plugin.json +17 -0
- package/.codex-plugin/plugin.json +7 -0
- package/.zcode-plugin/plugin.json +17 -0
- package/README.md +28 -9
- package/README.zh-CN.md +26 -9
- package/capabilities/usage/lib/context.mjs +1 -0
- package/capabilities/vision/lib/tool-contract.mjs +14 -0
- package/capabilities/vision/mcp-server.mjs +5 -13
- package/capabilities/vision/pi-extension.mjs +77 -0
- package/dist/usage/core.mjs +1 -0
- package/dist/vision/mcp-server.mjs +471 -149
- package/dist/vision/pi-extension.mjs +6306 -0
- package/docs/en/extras.md +21 -21
- package/docs/en/repository-structure.md +3 -1
- package/docs/zh-CN/extras.md +19 -19
- package/docs/zh-CN/repository-structure.md +3 -1
- package/package.json +10 -5
- package/scripts/build.mjs +1 -0
- package/scripts/install.mjs +265 -10
- package/scripts/sync-plugin-version.mjs +22 -0
- package/skills/systems/at-zentao/SKILL.md +32 -11
- package/skills/systems/at-zentao/scripts/zentao-cli.mjs +48 -2
package/docs/en/extras.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Extras
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This page lists optional tools outside the day-to-day development workflow.
|
|
4
4
|
|
|
5
5
|
## at-self-eval
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
for
|
|
7
|
+
Turn Git commit history, a work log you provide, or both into a performance
|
|
8
|
+
self-evaluation for quarterly reviews, half-year reviews, or promotion materials.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
npx -y skills@latest add kairyou/agent-tools --skill at-self-eval -g -y
|
|
@@ -25,7 +25,7 @@ Review the generated result before use.
|
|
|
25
25
|
|
|
26
26
|
## at-daily-log
|
|
27
27
|
|
|
28
|
-
Distill each day's Git commits across projects into a work report
|
|
28
|
+
Distill each day's Git commits across projects into a work report.
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
npx -y skills@latest add kairyou/agent-tools --skill at-daily-log -g -y
|
|
@@ -35,12 +35,12 @@ Usage:
|
|
|
35
35
|
|
|
36
36
|
- `/at-daily-log` — print today's log
|
|
37
37
|
- `/at-daily-log 2026-07-31` — pick the date
|
|
38
|
-
- `/at-daily-log last week` / `/at-daily-log the last two weeks` — one
|
|
38
|
+
- `/at-daily-log last week` / `/at-daily-log the last two weeks` — one report per date with Git commits; dates without commits are skipped
|
|
39
39
|
- `/at-daily-log summarize today for C:\projects\project-a` — only that project
|
|
40
40
|
- `/at-daily-log also include C:\projects\project-c` — add to the default scope
|
|
41
41
|
- `/at-daily-log record the log` — record to the configured file; rerunning a day only refreshes the generated part
|
|
42
42
|
- `/at-daily-log record it to C:\logs\daily-log.md` — record to that file
|
|
43
|
-
- `/at-daily-log record daily at 18:00` — guides you through an OS scheduled task;
|
|
43
|
+
- `/at-daily-log record daily at 18:00` — guides you through an OS scheduled task; no report is written when the day has no Git commits
|
|
44
44
|
|
|
45
45
|
Recorded output example:
|
|
46
46
|
|
|
@@ -73,21 +73,6 @@ npx -y @kairyou/agent-tools@latest log -a claude codex opencode
|
|
|
73
73
|
- `format: "daily"`: writes to a single Markdown file grouped by date; each completed answer with substantive results is recorded as one line, while pending prompts are omitted; content may be truncated by the length limit, so use it only as a lightweight activity index
|
|
74
74
|
- Codex: run `/hooks` once after installing to approve it; opencode: restart after installing or updating
|
|
75
75
|
|
|
76
|
-
`daily` output example:
|
|
77
|
-
|
|
78
|
-
```markdown
|
|
79
|
-
+ 2026-08-03
|
|
80
|
-
<!-- log:2026-08-03:start -->
|
|
81
|
-
1. project-a: Found the cause of the login timeout: the renewal branch never updated the cache expiry, so the second request still read the old value. Patched session.ts and verified...
|
|
82
|
-
2. project-a: Fix is in, with 3 regression tests covering the renewal path; all passing.
|
|
83
|
-
3. project-b: Empty report exports came from an inverted permission filter, now corrected and confirmed working.
|
|
84
|
-
<!-- log:2026-08-03:end -->
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
One line per turn, taken verbatim from the closing text of that turn's AI reply
|
|
88
|
-
(truncated when long); no distilling, no cross-turn consolidation. Updates likewise
|
|
89
|
-
rewrite only what sits between the markers.
|
|
90
|
-
|
|
91
76
|
`detailed` output example (excerpt):
|
|
92
77
|
|
|
93
78
|
```markdown
|
|
@@ -114,6 +99,21 @@ Changes
|
|
|
114
99
|
- src/auth/session.ts | diff +42/-8 | 3 ops
|
|
115
100
|
```
|
|
116
101
|
|
|
102
|
+
`daily` output example:
|
|
103
|
+
|
|
104
|
+
```markdown
|
|
105
|
+
+ 2026-08-03
|
|
106
|
+
<!-- log:2026-08-03:start -->
|
|
107
|
+
1. project-a: Found the cause of the login timeout: the renewal branch never updated the cache expiry, so the second request still read the old value. Patched session.ts and verified...
|
|
108
|
+
2. project-a: Fix is in, with 3 regression tests covering the renewal path; all passing.
|
|
109
|
+
3. project-b: Empty report exports came from an inverted permission filter, now corrected and confirmed working.
|
|
110
|
+
<!-- log:2026-08-03:end -->
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
One line per turn, taken verbatim from the closing text of that turn's AI reply
|
|
114
|
+
(truncated when long); no distilling, no cross-turn consolidation. Updates likewise
|
|
115
|
+
rewrite only what sits between the markers.
|
|
116
|
+
|
|
117
117
|
## Configuration
|
|
118
118
|
|
|
119
119
|
All in `~/.agent-tools/config.jsonc`:
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
agent-tools/
|
|
5
5
|
├── .claude-plugin/ # Claude Code/plugin ecosystem manifest.
|
|
6
6
|
├── .codex-plugin/ # Codex plugin manifest.
|
|
7
|
+
├── .zcode-plugin/ # ZCode plugin manifest.
|
|
7
8
|
├── capabilities/ # Runtime capabilities, one directory each.
|
|
8
9
|
│ ├── statusline/ # Agent status line: branch, model, usage.
|
|
9
10
|
│ ├── usage/ # Provider balance / quota display.
|
|
10
|
-
│
|
|
11
|
+
│ ├── vision/ # Cross-model image understanding and host adapters.
|
|
12
|
+
│ └── log/ # Session work-log hooks and plugins.
|
|
11
13
|
├── skills/ # Reusable Agent Skills.
|
|
12
14
|
│ ├── workflow/ # Workflow-oriented skills.
|
|
13
15
|
│ │ ├── at-commit/ # Conventional Commit message skill.
|
package/docs/zh-CN/extras.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Extras
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
这里收录日常开发主流程之外的可选工具.
|
|
4
4
|
|
|
5
5
|
## at-self-eval
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
基于 Git 提交历史或你提供的工作日志生成绩效自评, 可用于季度总结, 半年总结及晋升材料撰写.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npx -y skills@latest add kairyou/agent-tools --skill at-self-eval -g -y
|
|
@@ -24,7 +24,7 @@ npx -y skills@latest add kairyou/agent-tools --skill at-self-eval -g -y
|
|
|
24
24
|
|
|
25
25
|
## at-daily-log
|
|
26
26
|
|
|
27
|
-
按天把各项目的 Git
|
|
27
|
+
按天把各项目的 Git 提交提炼成工作日报.
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
npx -y skills@latest add kairyou/agent-tools --skill at-daily-log -g -y
|
|
@@ -34,12 +34,12 @@ npx -y skills@latest add kairyou/agent-tools --skill at-daily-log -g -y
|
|
|
34
34
|
|
|
35
35
|
- `/at-daily-log` — 输出今天的日报
|
|
36
36
|
- `/at-daily-log 2026-07-31` — 指定日期
|
|
37
|
-
- `/at-daily-log 上周` / `/at-daily-log 最近两周` —
|
|
37
|
+
- `/at-daily-log 上周` / `/at-daily-log 最近两周` — 按日期生成日报, 跳过没有 Git 提交的日期
|
|
38
38
|
- `/at-daily-log 统计 C:\projects\project-a 今天的工作` — 只统计指定项目
|
|
39
39
|
- `/at-daily-log 另外包含 C:\projects\project-c` — 在默认范围上追加
|
|
40
40
|
- `/at-daily-log 记录日报` — 记录到配置的文件; 同一天重复执行只更新生成的部分
|
|
41
41
|
- `/at-daily-log 记录到 C:\logs\daily-log.md` — 记录到指定文件
|
|
42
|
-
- `/at-daily-log 每天 18:00 自动记录` — 引导搭建系统定时任务;
|
|
42
|
+
- `/at-daily-log 每天 18:00 自动记录` — 引导搭建系统定时任务; 当天没有 Git 提交时不写入日报
|
|
43
43
|
|
|
44
44
|
记录到文件的示例:
|
|
45
45
|
|
|
@@ -71,20 +71,6 @@ npx -y @kairyou/agent-tools@latest log -a claude codex opencode
|
|
|
71
71
|
- `format: "daily"`: 写入单个 Markdown 文件, 并按日期归档; 每个已完成且有实质结果的回答记录为一行, 不记录未完成的提问; 内容可能因长度限制被截断, 因此仅适合作为轻量活动索引
|
|
72
72
|
- Codex 安装后运行 `/hooks` 批准一次; opencode 安装或更新后需要重启
|
|
73
73
|
|
|
74
|
-
`daily` 输出示例:
|
|
75
|
-
|
|
76
|
-
```markdown
|
|
77
|
-
+ 2026-08-03
|
|
78
|
-
<!-- log:2026-08-03:start -->
|
|
79
|
-
1. project-a: 已定位登录超时的原因: 会话缓存在续期分支上没有更新过期时间, 第二次请求拿到的还是旧值。已经在 session.ts 补上续期并本地验证通过, 接下来...
|
|
80
|
-
2. project-a: 修复完成, 新增 3 个回归用例覆盖续期路径, 全部通过。
|
|
81
|
-
3. project-b: 报表导出为空定位到权限过滤条件写反, 已修正并确认导出恢复正常。
|
|
82
|
-
<!-- log:2026-08-03:end -->
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
每轮一行, 直接摘录那一轮 AI 回复的收尾内容(过长会截断), 不做提炼也不跨轮归纳;
|
|
86
|
-
同样只重写标记之间的部分, 文件里的其他内容不会被碰.
|
|
87
|
-
|
|
88
74
|
`detailed` 输出示例(节选):
|
|
89
75
|
|
|
90
76
|
```markdown
|
|
@@ -111,6 +97,20 @@ Changes
|
|
|
111
97
|
- src/auth/session.ts | 变更 +42/-8 | 操作 3 次
|
|
112
98
|
```
|
|
113
99
|
|
|
100
|
+
`daily` 输出示例:
|
|
101
|
+
|
|
102
|
+
```markdown
|
|
103
|
+
+ 2026-08-03
|
|
104
|
+
<!-- log:2026-08-03:start -->
|
|
105
|
+
1. project-a: 已定位登录超时的原因: 会话缓存在续期分支上没有更新过期时间, 第二次请求拿到的还是旧值. 已经在 session.ts 补上续期并本地验证通过, 接下来...
|
|
106
|
+
2. project-a: 修复完成, 新增 3 个回归用例覆盖续期路径, 全部通过.
|
|
107
|
+
3. project-b: 报表导出为空定位到权限过滤条件写反, 已修正并确认导出恢复正常.
|
|
108
|
+
<!-- log:2026-08-03:end -->
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
每轮一行, 直接摘录那一轮 AI 回复的收尾内容(过长会截断), 不做提炼也不跨轮归纳;
|
|
112
|
+
同样只重写标记之间的部分, 文件里的其他内容不会被碰.
|
|
113
|
+
|
|
114
114
|
## 配置
|
|
115
115
|
|
|
116
116
|
都在 `~/.agent-tools/config.jsonc`:
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
agent-tools/
|
|
5
5
|
├── .claude-plugin/ # Claude Code/plugin 生态的 manifest.
|
|
6
6
|
├── .codex-plugin/ # Codex plugin manifest.
|
|
7
|
+
├── .zcode-plugin/ # ZCode plugin manifest.
|
|
7
8
|
├── capabilities/ # Runtime capabilities, 一个一目录.
|
|
8
9
|
│ ├── statusline/ # Agent 状态栏: 分支, 模型, 用量.
|
|
9
10
|
│ ├── usage/ # Provider 余额/额度显示.
|
|
10
|
-
│
|
|
11
|
+
│ ├── vision/ # 跨模型识图与各 Agent adapter.
|
|
12
|
+
│ └── log/ # Session work log hooks 与 plugins.
|
|
11
13
|
├── skills/ # 可复用的 Agent Skills.
|
|
12
14
|
│ ├── workflow/ # 工作流类 skills.
|
|
13
15
|
│ │ ├── at-commit/ # 生成 Conventional Commits message.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kairyou/agent-tools",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Reusable Agent Skills
|
|
3
|
+
"version": "0.23.1",
|
|
4
|
+
"description": "Reusable Agent Skills plus per-agent runtime capabilities for compatible coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"config.default.jsonc",
|
|
18
|
+
".claude-plugin/",
|
|
19
|
+
".codex-plugin/",
|
|
20
|
+
".zcode-plugin/",
|
|
18
21
|
"docs/",
|
|
19
22
|
"dist/",
|
|
20
23
|
"capabilities/",
|
|
@@ -25,14 +28,16 @@
|
|
|
25
28
|
"jsonc-parser": "3.3.1"
|
|
26
29
|
},
|
|
27
30
|
"devDependencies": {
|
|
28
|
-
"@modelcontextprotocol/sdk": "1.
|
|
29
|
-
"esbuild": "0.28.
|
|
31
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
32
|
+
"esbuild": "0.28.2",
|
|
33
|
+
"typebox": "1.3.7",
|
|
30
34
|
"zod": "4.4.3"
|
|
31
35
|
},
|
|
32
36
|
"scripts": {
|
|
33
37
|
"build": "node scripts/build.mjs",
|
|
34
38
|
"prepare": "npm run build",
|
|
35
|
-
"test": "node --test tests/*.test.mjs",
|
|
39
|
+
"test": "node --test --test-concurrency=1 tests/*.test.mjs",
|
|
40
|
+
"version": "node scripts/sync-plugin-version.mjs",
|
|
36
41
|
"claude-skills:fetch": "node tools/claude-skill-sync/cli.mjs fetch",
|
|
37
42
|
"claude-skills:inspect": "node tools/claude-skill-sync/cli.mjs inspect",
|
|
38
43
|
"claude-skills:apply": "node tools/claude-skill-sync/cli.mjs apply",
|
package/scripts/build.mjs
CHANGED
|
@@ -33,6 +33,7 @@ const TARGETS = {
|
|
|
33
33
|
entryPoints: {
|
|
34
34
|
"mcp-server": path.join(ROOT, "capabilities", "vision", "mcp-server.mjs"),
|
|
35
35
|
cli: path.join(ROOT, "capabilities", "vision", "lib", "cli.mjs"),
|
|
36
|
+
"pi-extension": path.join(ROOT, "capabilities", "vision", "pi-extension.mjs"),
|
|
36
37
|
},
|
|
37
38
|
},
|
|
38
39
|
log: {
|
package/scripts/install.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// agent-tools installer: wires statusline / usage into each agent's config.
|
|
3
3
|
// Runtime-dependent skills are installed with their capability. Standalone
|
|
4
|
-
//
|
|
4
|
+
// skills are still handled by `npx skills add`.
|
|
5
5
|
//
|
|
6
6
|
// Capabilities (all global for now — they target the user-level config):
|
|
7
7
|
// statusline Claude Code statusLine script (claude only).
|
|
8
|
-
// usage Active API provider quota/balance (
|
|
9
|
-
// vision inspect_image
|
|
10
|
-
// log AI session work log via agent hooks (
|
|
8
|
+
// usage Active API provider quota/balance (Claude/Codex/OpenCode).
|
|
9
|
+
// vision inspect_image host adapter + at-vision skill.
|
|
10
|
+
// log AI session work log via agent hooks (Claude/Codex/OpenCode).
|
|
11
11
|
//
|
|
12
12
|
// Standalone commands (dispatched before capability parsing):
|
|
13
13
|
// inspect-image <path|url> --question "..." Human diagnostic for vision.
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
// ~/.codex/config.toml (vision MCP) + ~/.agents/skills (at-vision)
|
|
23
23
|
// opencode -> ~/.config/opencode/ (usage + log plugins,
|
|
24
24
|
// vision MCP in opencode.json + skills/at-vision)
|
|
25
|
+
// pi -> ~/.pi/agent/extensions/ (native vision tool)
|
|
26
|
+
// + ~/.pi/agent/skills/at-vision
|
|
27
|
+
// zcode -> ~/.zcode/cli/config.json (vision MCP)
|
|
28
|
+
// + ~/.zcode/skills/at-vision
|
|
29
|
+
// dsh -> ~/.dsh/cordis.patch.yml (official MCP client row)
|
|
30
|
+
// + ~/.dsh/skills/at-vision
|
|
25
31
|
// Runtime scripts are copied into ~/.agent-tools so this installer can be
|
|
26
32
|
// run via npx from GitHub without requiring a persistent local clone.
|
|
27
33
|
//
|
|
@@ -32,7 +38,7 @@
|
|
|
32
38
|
// agent-tools <capabilities> [options]
|
|
33
39
|
//
|
|
34
40
|
// Options:
|
|
35
|
-
// -a, --agent <names> Target agents: claude | codex | opencode.
|
|
41
|
+
// -a, --agent <names> Target agents: claude | codex | opencode | pi | zcode | dsh.
|
|
36
42
|
// Default: claude.
|
|
37
43
|
// --settings <path> Override the Claude settings.json (for testing).
|
|
38
44
|
// --codex-hooks <path> Override the Codex hooks.json (for testing).
|
|
@@ -41,6 +47,10 @@
|
|
|
41
47
|
// --claude-skills-dir <p> Override ~/.claude/skills (for testing).
|
|
42
48
|
// --codex-config <path> Override ~/.codex/config.toml (for testing).
|
|
43
49
|
// --codex-skills-dir <p> Override ~/.agents/skills (for testing).
|
|
50
|
+
// --pi-agent-dir <path> Override ~/.pi/agent (for testing).
|
|
51
|
+
// --zcode-config <path> Override ~/.zcode/cli/config.json (for testing).
|
|
52
|
+
// --zcode-skills-dir <path> Override ~/.zcode/skills (for testing).
|
|
53
|
+
// --dsh-home <path> Override ~/.dsh (for testing).
|
|
44
54
|
// --uninstall Remove what this installer added, restoring backups.
|
|
45
55
|
// --dry-run Print planned changes without writing anything.
|
|
46
56
|
// -h, --help Show this help.
|
|
@@ -92,11 +102,14 @@ const RUNTIME = {
|
|
|
92
102
|
opencodeUsageTui: path.join(INSTALL_ROOT, "dist", "usage", "opencode-tui.mjs"),
|
|
93
103
|
};
|
|
94
104
|
const ALL_CAPS = ["statusline", "usage", "vision", "log"];
|
|
95
|
-
const ALL_AGENTS = ["claude", "codex", "opencode"];
|
|
105
|
+
const ALL_AGENTS = ["claude", "codex", "opencode", "pi", "zcode", "dsh"];
|
|
96
106
|
const AGENT_CAPS = {
|
|
97
107
|
claude: ["statusline", "usage", "vision", "log"],
|
|
98
108
|
codex: ["usage", "vision", "log"],
|
|
99
109
|
opencode: ["usage", "vision", "log"],
|
|
110
|
+
pi: ["vision"],
|
|
111
|
+
zcode: ["vision"],
|
|
112
|
+
dsh: ["vision"],
|
|
100
113
|
};
|
|
101
114
|
const VISION_MCP_NAME = "agent-tools-vision";
|
|
102
115
|
const VISION_SKILL_NAME = "at-vision";
|
|
@@ -300,6 +313,10 @@ function parseArgs(argv) {
|
|
|
300
313
|
claudeSkillsDir: null,
|
|
301
314
|
codexConfig: null,
|
|
302
315
|
codexSkillsDir: null,
|
|
316
|
+
piAgentDir: null,
|
|
317
|
+
zcodeConfig: null,
|
|
318
|
+
zcodeSkillsDir: null,
|
|
319
|
+
dshHome: null,
|
|
303
320
|
uninstall: false,
|
|
304
321
|
dryRun: false,
|
|
305
322
|
help: false,
|
|
@@ -334,6 +351,10 @@ function parseArgs(argv) {
|
|
|
334
351
|
case "--claude-skills-dir": opts.claudeSkillsDir = argv[++i]; break;
|
|
335
352
|
case "--codex-config": opts.codexConfig = argv[++i]; break;
|
|
336
353
|
case "--codex-skills-dir": opts.codexSkillsDir = argv[++i]; break;
|
|
354
|
+
case "--pi-agent-dir": opts.piAgentDir = argv[++i]; break;
|
|
355
|
+
case "--zcode-config": opts.zcodeConfig = argv[++i]; break;
|
|
356
|
+
case "--zcode-skills-dir": opts.zcodeSkillsDir = argv[++i]; break;
|
|
357
|
+
case "--dsh-home": opts.dshHome = argv[++i]; break;
|
|
337
358
|
case "--uninstall": opts.uninstall = true; break;
|
|
338
359
|
case "--dry-run": opts.dryRun = true; break;
|
|
339
360
|
case "-h":
|
|
@@ -535,6 +556,7 @@ const VISION_RATE_LIMIT_STATE = path.join(INSTALL_ROOT, "cache", "vision-rate-li
|
|
|
535
556
|
const VISION_DIST_DIR = path.join(REPO_ROOT, "dist", "vision");
|
|
536
557
|
const VISION_RUNTIME_SERVER = path.join(VISION_RUNTIME_DIR, "mcp-server.mjs");
|
|
537
558
|
const VISION_RUNTIME_CLI = path.join(VISION_RUNTIME_DIR, "cli.mjs");
|
|
559
|
+
const VISION_RUNTIME_PI_EXTENSION = path.join(VISION_RUNTIME_DIR, "pi-extension.mjs");
|
|
538
560
|
const VISION_SKILL_IDENTITY = Object.freeze({
|
|
539
561
|
owner: "@kairyou/agent-tools",
|
|
540
562
|
capability: "vision",
|
|
@@ -545,7 +567,7 @@ const USAGE_SKILL_IDENTITY = Object.freeze({
|
|
|
545
567
|
capability: "usage",
|
|
546
568
|
artifact: "skill",
|
|
547
569
|
});
|
|
548
|
-
// Vision is bundled at release time. Install atomically swaps
|
|
570
|
+
// Vision is bundled at release time. Install atomically swaps self-contained
|
|
549
571
|
// entry files into ~/.agent-tools/dist/vision, so hosts never run npm and a
|
|
550
572
|
// failed update cannot destroy the previously working runtime.
|
|
551
573
|
function visionMcpCommand() {
|
|
@@ -591,6 +613,16 @@ function isOpenCodeVisionMcp(value, mcp = visionMcpCommand()) {
|
|
|
591
613
|
);
|
|
592
614
|
}
|
|
593
615
|
|
|
616
|
+
function isZcodeVisionMcp(value, mcp = visionMcpCommand()) {
|
|
617
|
+
return Boolean(
|
|
618
|
+
value &&
|
|
619
|
+
value.command === mcp.command &&
|
|
620
|
+
Array.isArray(value.args) &&
|
|
621
|
+
value.args.length === 1 &&
|
|
622
|
+
isVisionServerPath(value.args[0])
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
|
|
594
626
|
function installVisionRuntime(opts) {
|
|
595
627
|
if (opts.uninstall) return;
|
|
596
628
|
console.log(`vision runtime: ${VISION_RUNTIME_DIR}`);
|
|
@@ -598,7 +630,7 @@ function installVisionRuntime(opts) {
|
|
|
598
630
|
console.log(` [dry-run] would atomically install ${VISION_DIST_DIR} -> ${VISION_RUNTIME_DIR}`);
|
|
599
631
|
return;
|
|
600
632
|
}
|
|
601
|
-
for (const name of ["mcp-server.mjs", "cli.mjs"]) {
|
|
633
|
+
for (const name of ["mcp-server.mjs", "cli.mjs", "pi-extension.mjs"]) {
|
|
602
634
|
if (!fs.existsSync(path.join(VISION_DIST_DIR, name))) {
|
|
603
635
|
throw new Error(`Missing bundled vision runtime ${path.join(VISION_DIST_DIR, name)}. Run npm run build.`);
|
|
604
636
|
}
|
|
@@ -616,7 +648,7 @@ function installVisionRuntime(opts) {
|
|
|
616
648
|
JSON.stringify({ owner: "@kairyou/agent-tools", capability: "vision", version: 1 }, null, 2) + "\n",
|
|
617
649
|
false
|
|
618
650
|
);
|
|
619
|
-
for (const name of ["mcp-server.mjs", "cli.mjs"]) {
|
|
651
|
+
for (const name of ["mcp-server.mjs", "cli.mjs", "pi-extension.mjs"]) {
|
|
620
652
|
const check = spawnSync(process.execPath, ["--check", path.join(stage, name)], {
|
|
621
653
|
encoding: "utf8",
|
|
622
654
|
});
|
|
@@ -1123,6 +1155,192 @@ function runOpencode(opts) {
|
|
|
1123
1155
|
if (!opts.dryRun) console.log(" NOTE: restart opencode to load the agent-tools usage plugin.");
|
|
1124
1156
|
}
|
|
1125
1157
|
|
|
1158
|
+
// ---- Pi: native extension tool plus the capability-owned skill. ----
|
|
1159
|
+
|
|
1160
|
+
const PI_VISION_STUB_NAME = "agent-tools-vision.js";
|
|
1161
|
+
|
|
1162
|
+
function piAgentDir(opts) {
|
|
1163
|
+
return opts.piAgentDir || path.join(os.homedir(), ".pi", "agent");
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
function piVisionStubContents() {
|
|
1167
|
+
return (
|
|
1168
|
+
"// Generated by agent-tools installer; do not edit.\n" +
|
|
1169
|
+
`export { default } from ${JSON.stringify(pathToFileURL(VISION_RUNTIME_PI_EXTENSION).href)};\n`
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
function isManagedPiVisionStub(file) {
|
|
1174
|
+
return fs.existsSync(file) && fs.readFileSync(file, "utf8") === piVisionStubContents();
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
function runPi(opts) {
|
|
1178
|
+
if (!wants(opts, "vision")) return;
|
|
1179
|
+
const agentDir = piAgentDir(opts);
|
|
1180
|
+
const stub = path.join(agentDir, "extensions", PI_VISION_STUB_NAME);
|
|
1181
|
+
const skillsDir = path.join(agentDir, "skills");
|
|
1182
|
+
console.log(`pi vision: ${stub}`);
|
|
1183
|
+
|
|
1184
|
+
if (opts.uninstall) {
|
|
1185
|
+
if (isManagedPiVisionStub(stub)) removeFile(stub, opts.dryRun);
|
|
1186
|
+
else if (fs.existsSync(stub)) console.log(` kept unmanaged ${stub}`);
|
|
1187
|
+
else console.log(" no agent-tools vision extension found; nothing to remove.");
|
|
1188
|
+
installVisionSkillDir(skillsDir, { remove: true, dryRun: opts.dryRun });
|
|
1189
|
+
console.log(" - vision");
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
if (fs.existsSync(stub) && !isManagedPiVisionStub(stub)) {
|
|
1194
|
+
throw new Error(
|
|
1195
|
+
`Refusing to overwrite existing unmanaged Pi extension ${stub}. ` +
|
|
1196
|
+
"Move or remove it, then re-run the install."
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
writeText(stub, piVisionStubContents(), opts.dryRun);
|
|
1200
|
+
installVisionSkillDir(skillsDir, { remove: false, dryRun: opts.dryRun });
|
|
1201
|
+
console.log(" + vision (native inspect_image extension + at-vision skill)");
|
|
1202
|
+
if (!opts.dryRun) console.log(" NOTE: restart Pi or run /reload to load the agent-tools vision extension.");
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// ---- ZCode: native user MCP config plus the user-level skill. ----
|
|
1206
|
+
|
|
1207
|
+
function updateZcodeVisionMcp(file, { remove, dryRun, mcp }) {
|
|
1208
|
+
const exists = fs.existsSync(file);
|
|
1209
|
+
const currentText = exists ? fs.readFileSync(file, "utf8") : "{}\n";
|
|
1210
|
+
const errors = [];
|
|
1211
|
+
const current = parseJsonc(currentText, errors, { allowTrailingComma: true }) || {};
|
|
1212
|
+
if (errors.length > 0 || typeof current !== "object" || Array.isArray(current)) {
|
|
1213
|
+
throw new Error(`Cannot parse ${file} as JSONC`);
|
|
1214
|
+
}
|
|
1215
|
+
const existing = current.mcp?.servers?.[VISION_MCP_NAME];
|
|
1216
|
+
if (existing && !isZcodeVisionMcp(existing, mcp)) {
|
|
1217
|
+
if (remove) {
|
|
1218
|
+
console.log(` kept unmanaged ${VISION_MCP_NAME} entry in ${file}`);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
throw new Error(
|
|
1222
|
+
`Found an existing unmanaged ${VISION_MCP_NAME} entry in ${file}. ` +
|
|
1223
|
+
"Remove or rename it, then re-run the install."
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
const desired = remove ? undefined : { command: mcp.command, args: mcp.args, env: {} };
|
|
1227
|
+
if (JSON.stringify(existing) === JSON.stringify(desired)) {
|
|
1228
|
+
console.log(` kept existing ${file}`);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const eol = currentText.includes("\r\n") ? "\r\n" : "\n";
|
|
1232
|
+
const edits = modify(currentText, ["mcp", "servers", VISION_MCP_NAME], desired, {
|
|
1233
|
+
formattingOptions: { insertSpaces: true, tabSize: 2, eol },
|
|
1234
|
+
});
|
|
1235
|
+
const updated = applyEdits(currentText, edits).replace(/\s*$/, "") + eol;
|
|
1236
|
+
writeText(file, updated, dryRun);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
function runZcode(opts) {
|
|
1240
|
+
if (!wants(opts, "vision")) return;
|
|
1241
|
+
const file = opts.zcodeConfig || path.join(os.homedir(), ".zcode", "cli", "config.json");
|
|
1242
|
+
const skillsDir = opts.zcodeSkillsDir || path.join(os.homedir(), ".zcode", "skills");
|
|
1243
|
+
console.log(`zcode vision: ${file}`);
|
|
1244
|
+
updateZcodeVisionMcp(file, {
|
|
1245
|
+
remove: opts.uninstall,
|
|
1246
|
+
dryRun: opts.dryRun,
|
|
1247
|
+
mcp: visionMcpCommand(),
|
|
1248
|
+
});
|
|
1249
|
+
installVisionSkillDir(skillsDir, { remove: opts.uninstall, dryRun: opts.dryRun });
|
|
1250
|
+
console.log(opts.uninstall ? " - vision" : " + vision (inspect_image MCP + at-vision skill)");
|
|
1251
|
+
if (!opts.uninstall && !opts.dryRun) {
|
|
1252
|
+
console.log(" NOTE: start a new ZCode session to load the agent-tools vision MCP server.");
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
// ---- DeepSeek Harness: official MCP client row in the global Cordis patch. ----
|
|
1257
|
+
|
|
1258
|
+
const DSH_VISION_BEGIN = "# >>> agent-tools vision >>>";
|
|
1259
|
+
const DSH_VISION_END = "# <<< agent-tools vision <<<";
|
|
1260
|
+
const DSH_VISION_ROW_ID = "agent-tools-vision";
|
|
1261
|
+
|
|
1262
|
+
function dshHome(opts) {
|
|
1263
|
+
return opts.dshHome || process.env.DSH_HOME || path.join(os.homedir(), ".dsh");
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function dshVisionBlock(mcp) {
|
|
1267
|
+
return [
|
|
1268
|
+
DSH_VISION_BEGIN,
|
|
1269
|
+
"- insert:",
|
|
1270
|
+
` - id: ${DSH_VISION_ROW_ID}`,
|
|
1271
|
+
" name: '@deepseek-ai/dsh-mcp-client'",
|
|
1272
|
+
" config:",
|
|
1273
|
+
` serverName: ${DSH_VISION_ROW_ID}`,
|
|
1274
|
+
" transport: stdio",
|
|
1275
|
+
` command: ${JSON.stringify(mcp.command)}`,
|
|
1276
|
+
` args: [${mcp.args.map((arg) => JSON.stringify(arg)).join(", ")}]`,
|
|
1277
|
+
" env: {}",
|
|
1278
|
+
DSH_VISION_END,
|
|
1279
|
+
"",
|
|
1280
|
+
].join("\n");
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
function updateDshVisionPatch(file, { remove, dryRun, mcp }) {
|
|
1284
|
+
const current = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "[]\n";
|
|
1285
|
+
const escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1286
|
+
const blockRe = new RegExp(
|
|
1287
|
+
`\\r?\\n?${escape(DSH_VISION_BEGIN)}[\\s\\S]*?${escape(DSH_VISION_END)}\\r?\\n?`
|
|
1288
|
+
);
|
|
1289
|
+
const hadManagedBlock = blockRe.test(current);
|
|
1290
|
+
let base = current.replace(blockRe, "\n").trim();
|
|
1291
|
+
if (base !== "" && base !== "[]" && !base.startsWith("-")) {
|
|
1292
|
+
throw new Error(`Cannot update ${file}: the Cordis patch must be a top-level YAML array`);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
if (!remove && !hadManagedBlock) {
|
|
1296
|
+
const conflict = new RegExp(
|
|
1297
|
+
`^\\s*(?:-\\s*)?(?:id|serverName):\\s*['\"]?${escape(DSH_VISION_ROW_ID)}['\"]?\\s*$`,
|
|
1298
|
+
"m"
|
|
1299
|
+
);
|
|
1300
|
+
if (conflict.test(base)) {
|
|
1301
|
+
throw new Error(
|
|
1302
|
+
`Found an existing unmanaged ${DSH_VISION_ROW_ID} Cordis row in ${file}. ` +
|
|
1303
|
+
"Remove or rename it, then re-run the install."
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
let next;
|
|
1309
|
+
if (remove) {
|
|
1310
|
+
if (!hadManagedBlock) {
|
|
1311
|
+
console.log(` no managed ${DSH_VISION_ROW_ID} Cordis row found; nothing to remove.`);
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
next = base === "" ? "[]\n" : `${base}\n`;
|
|
1315
|
+
} else {
|
|
1316
|
+
const block = dshVisionBlock(mcp);
|
|
1317
|
+
next = base === "" || base === "[]" ? block : `${base}\n\n${block}`;
|
|
1318
|
+
}
|
|
1319
|
+
if (next === current) {
|
|
1320
|
+
console.log(` kept existing ${file}`);
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
writeText(file, next, dryRun);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
function runDsh(opts) {
|
|
1327
|
+
if (!wants(opts, "vision")) return;
|
|
1328
|
+
const home = dshHome(opts);
|
|
1329
|
+
const patchFile = path.join(home, "cordis.patch.yml");
|
|
1330
|
+
const skillsDir = path.join(home, "skills");
|
|
1331
|
+
console.log(`dsh vision: ${patchFile}`);
|
|
1332
|
+
updateDshVisionPatch(patchFile, {
|
|
1333
|
+
remove: opts.uninstall,
|
|
1334
|
+
dryRun: opts.dryRun,
|
|
1335
|
+
mcp: visionMcpCommand(),
|
|
1336
|
+
});
|
|
1337
|
+
installVisionSkillDir(skillsDir, { remove: opts.uninstall, dryRun: opts.dryRun });
|
|
1338
|
+
console.log(opts.uninstall ? " - vision" : " + vision (official MCP client row + at-vision skill)");
|
|
1339
|
+
if (!opts.uninstall && !opts.dryRun) {
|
|
1340
|
+
console.log(" NOTE: restart DSH and wait for mcp__agent-tools-vision__inspect_image to appear.");
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1126
1344
|
function visionRuntimeHasRemainingReference(opts) {
|
|
1127
1345
|
const removed = new Set(opts.agents);
|
|
1128
1346
|
if (!removed.has("claude")) {
|
|
@@ -1162,6 +1380,36 @@ function visionRuntimeHasRemainingReference(opts) {
|
|
|
1162
1380
|
return true;
|
|
1163
1381
|
}
|
|
1164
1382
|
}
|
|
1383
|
+
if (!removed.has("pi")) {
|
|
1384
|
+
const stub = path.join(piAgentDir(opts), "extensions", PI_VISION_STUB_NAME);
|
|
1385
|
+
try {
|
|
1386
|
+
if (isManagedPiVisionStub(stub)) return true;
|
|
1387
|
+
} catch {
|
|
1388
|
+
return true;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
if (!removed.has("zcode")) {
|
|
1392
|
+
const file = opts.zcodeConfig || path.join(os.homedir(), ".zcode", "cli", "config.json");
|
|
1393
|
+
try {
|
|
1394
|
+
if (isZcodeVisionMcp(readJsonc(file).mcp?.servers?.[VISION_MCP_NAME])) return true;
|
|
1395
|
+
} catch {
|
|
1396
|
+
return true;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
if (!removed.has("dsh")) {
|
|
1400
|
+
const file = path.join(dshHome(opts), "cordis.patch.yml");
|
|
1401
|
+
try {
|
|
1402
|
+
const text = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
|
|
1403
|
+
const start = text.indexOf(DSH_VISION_BEGIN);
|
|
1404
|
+
const end = text.indexOf(DSH_VISION_END, start + DSH_VISION_BEGIN.length);
|
|
1405
|
+
if (start !== -1 && end !== -1) {
|
|
1406
|
+
const block = text.slice(start, end);
|
|
1407
|
+
if (block.includes(fwd(VISION_RUNTIME_SERVER))) return true;
|
|
1408
|
+
}
|
|
1409
|
+
} catch {
|
|
1410
|
+
return true;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1165
1413
|
return false;
|
|
1166
1414
|
}
|
|
1167
1415
|
|
|
@@ -1187,7 +1435,14 @@ function cleanupVisionRuntimeIfUnused(opts) {
|
|
|
1187
1435
|
console.log(` removed unused vision runtime ${VISION_RUNTIME_DIR}`);
|
|
1188
1436
|
}
|
|
1189
1437
|
|
|
1190
|
-
const AGENTS = {
|
|
1438
|
+
const AGENTS = {
|
|
1439
|
+
claude: runClaude,
|
|
1440
|
+
codex: runCodex,
|
|
1441
|
+
opencode: runOpencode,
|
|
1442
|
+
pi: runPi,
|
|
1443
|
+
zcode: runZcode,
|
|
1444
|
+
dsh: runDsh,
|
|
1445
|
+
};
|
|
1191
1446
|
|
|
1192
1447
|
function main() {
|
|
1193
1448
|
const opts = parseArgs(process.argv.slice(2));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
8
|
+
const version = JSON.parse(fs.readFileSync(path.join(ROOT, "package.json"), "utf8")).version;
|
|
9
|
+
const targets = [
|
|
10
|
+
[".claude-plugin/plugin.json", []],
|
|
11
|
+
[".codex-plugin/plugin.json", []],
|
|
12
|
+
[".zcode-plugin/plugin.json", []],
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
for (const [relativePath, parentPath] of targets) {
|
|
16
|
+
const file = path.join(ROOT, relativePath);
|
|
17
|
+
const document = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
18
|
+
let target = document;
|
|
19
|
+
for (const key of parentPath) target = target[key];
|
|
20
|
+
target.version = version;
|
|
21
|
+
fs.writeFileSync(file, `${JSON.stringify(document, null, 2)}\n`);
|
|
22
|
+
}
|