cyber-agentkit 0.0.0-stage → 0.7.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 +19 -0
- package/.codex-plugin/plugin.json +19 -0
- package/.cursor-plugin/plugin.json +19 -0
- package/LICENSE +21 -0
- package/bin/cyber-agentkit.mjs +10 -0
- package/dist/cli.js +14307 -0
- package/dist/commands.d.ts +149 -0
- package/dist/commands.js +984 -0
- package/dist/harness-id-BgKL-x6C.d.ts +11 -0
- package/dist/index.d.ts +724 -0
- package/dist/index.js +652 -0
- package/dist/reference-where-BhymfNgA.js +10195 -0
- package/dist/resolve-reference-Cis-Ye6T.d.ts +232 -0
- package/dist/worktrees.d.ts +690 -0
- package/dist/worktrees.js +1456 -0
- package/package.json +92 -5
- package/plugin.json +27 -0
- package/readme.md +423 -0
- package/references/plugin-dependencies.md +31 -0
- package/skills/reference/README.md +63 -0
- package/skills/reference/SKILL.md +109 -0
- package/skills/reference/references/create.md +71 -0
- package/skills/reference/references/load.md +80 -0
- package/skills/reference/scripts/reference.mjs +199 -0
- package/README.md +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,93 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "cyber-agentkit",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "An agent-harness-agnostic toolkit: the fundamental features agent tools need, working the same on every harness. Detect the running harness, check plugin dependencies, resolve layered reference documents, and lease git worktrees.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent-harness",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"cursor",
|
|
9
|
+
"codex",
|
|
10
|
+
"copilot-cli",
|
|
11
|
+
"opencode",
|
|
12
|
+
"kilo-code",
|
|
13
|
+
"gemini-cli",
|
|
14
|
+
"qwen-code",
|
|
15
|
+
"vscode",
|
|
16
|
+
"cline",
|
|
17
|
+
"crush",
|
|
18
|
+
"openhands",
|
|
19
|
+
"auggie"
|
|
20
|
+
],
|
|
21
|
+
"homepage": "https://cyber-uni.github.io/cyber-agentkit/",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/cyber-uni/cyber-agentkit/issues"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/cyber-uni/cyber-agentkit.git",
|
|
28
|
+
"directory": "packages/cyber-agentkit"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"author": "unional <homawong@gmail.com>",
|
|
32
|
+
"type": "module",
|
|
33
|
+
"sideEffects": [
|
|
34
|
+
"./bin/*.mjs",
|
|
35
|
+
"./dist/cli.js",
|
|
36
|
+
"./skills/*/scripts/*.mjs"
|
|
37
|
+
],
|
|
38
|
+
"exports": {
|
|
39
|
+
".": "./dist/index.js",
|
|
40
|
+
"./commands": "./dist/commands.js",
|
|
41
|
+
"./worktrees": "./dist/worktrees.js",
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"bin": {
|
|
45
|
+
"cyber-agentkit": "./bin/cyber-agentkit.mjs"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"LICENSE",
|
|
49
|
+
"bin",
|
|
50
|
+
"dist",
|
|
51
|
+
"skills",
|
|
52
|
+
"references",
|
|
53
|
+
"plugin.json",
|
|
54
|
+
".claude-plugin",
|
|
55
|
+
".cursor-plugin",
|
|
56
|
+
".codex-plugin"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsdown",
|
|
60
|
+
"generate:references": "tsx scripts/generate-references.ts",
|
|
61
|
+
"dev": "tsx src/index.ts",
|
|
62
|
+
"lint": "biome check .",
|
|
63
|
+
"prepack": "pnpm build",
|
|
64
|
+
"test": "pnpm build && vitest run src",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"verify": "pnpm typecheck && pnpm lint && pnpm test"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"clibuilder": "^12.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"clibuilder": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@types/node": "^24.10.1",
|
|
79
|
+
"clibuilder": "^12.0.0",
|
|
80
|
+
"tsdown": "^0.23.0",
|
|
81
|
+
"tsx": "^4.22.3",
|
|
82
|
+
"typescript": "^7.0.0",
|
|
83
|
+
"vitest": "^5.0.0",
|
|
84
|
+
"yaml": "^2.9.0"
|
|
85
|
+
},
|
|
86
|
+
"engines": {
|
|
87
|
+
"node": ">=22"
|
|
88
|
+
},
|
|
89
|
+
"publishConfig": {
|
|
90
|
+
"access": "public",
|
|
91
|
+
"provenance": true
|
|
92
|
+
}
|
|
93
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "cyber-agentkit",
|
|
4
|
+
"version": "0.7.1",
|
|
5
|
+
"description": "An agent-harness-agnostic toolkit: the fundamental features agent tools need, working the same on every harness. Detect the running harness, check plugin dependencies, resolve layered reference documents, and lease git worktrees.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "unional"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/cyber-uni/cyber-agentkit",
|
|
10
|
+
"repository": "https://github.com/cyber-uni/cyber-agentkit",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": ["agent-harness", "claude-code", "cursor", "codex", "copilot-cli"],
|
|
13
|
+
"extensions": {
|
|
14
|
+
"org.cyberuni.universal-plugin": {
|
|
15
|
+
"skills": "./skills/",
|
|
16
|
+
"harnesses": {
|
|
17
|
+
"claude-code": {},
|
|
18
|
+
"cursor": {},
|
|
19
|
+
"codex": {},
|
|
20
|
+
"copilot-cli": {}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"skills/reference/scripts/reference.mjs": "src/references/reference.skill-script.ts"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# cyber-agentkit
|
|
2
|
+
|
|
3
|
+
[](https://github.com/cyber-uni/cyber-agentkit/blob/main/LICENSE)
|
|
4
|
+
|
|
5
|
+
An agent-harness-agnostic toolkit. It provides the fundamental features agent tools need and makes
|
|
6
|
+
each one work the same way across harnesses:
|
|
7
|
+
|
|
8
|
+
- **Harness knowledge.** Detect which harness is running, and query what it holds: managed-policy
|
|
9
|
+
locations, plugin storage, installed and enabled plugins, skill naming and directories, and how to
|
|
10
|
+
run it headless.
|
|
11
|
+
- **Plugin dependencies.** Check which plugins another plugin needs against what the harness has.
|
|
12
|
+
- **Reference documents.** Resolve the named Markdown documents an agent reads on demand.
|
|
13
|
+
- **Worktrees.** Lease git worktrees to concurrent agent sessions.
|
|
14
|
+
|
|
15
|
+
It depends on no other agent tool, so any of them can build on it.
|
|
16
|
+
|
|
17
|
+
**Status: pre-release.** Every fact this library encodes rests on
|
|
18
|
+
[`.research/harness-detection`](https://github.com/cyber-uni/cyber-agentkit/tree/main/.research/harness-detection).
|
|
19
|
+
|
|
20
|
+
## Detect the harness
|
|
21
|
+
|
|
22
|
+
It detects Claude Code, Cursor, Codex, GitHub Copilot CLI, OpenCode, Kilo Code, Gemini CLI, Qwen
|
|
23
|
+
Code, GitHub Copilot in VS Code, Cline, Crush, OpenHands, and the Auggie CLI.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { detectHarness } from 'cyber-agentkit'
|
|
27
|
+
|
|
28
|
+
const result = detectHarness()
|
|
29
|
+
// {
|
|
30
|
+
// harness: 'claude-code',
|
|
31
|
+
// candidates: ['claude-code'],
|
|
32
|
+
// evidence: [
|
|
33
|
+
// { harness: 'claude-code', signal: 'CLAUDECODE', research: 'E-CC-D1', description: '…' },
|
|
34
|
+
// { harness: 'claude-code', signal: 'CLAUDE_CODE_CHILD_SESSION', research: 'E-CC-D3', description: '…' },
|
|
35
|
+
// ],
|
|
36
|
+
// }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Detection reads environment variables that each harness sets on the processes it spawns:
|
|
40
|
+
|
|
41
|
+
| Harness | Detected from |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Claude Code | `CLAUDECODE=1` with `CLAUDE_CODE_CHILD_SESSION=1` or `CLAUDE_CODE_SESSION_ID` |
|
|
44
|
+
| Cursor | `CURSOR_AGENT=1`, or `CURSOR_VERSION` with `CURSOR_PROJECT_DIR` in hooks |
|
|
45
|
+
| Codex | `CODEX_THREAD_ID` |
|
|
46
|
+
| GitHub Copilot CLI | `COPILOT_CLI=1`, `COPILOT_AGENT_SESSION_ID`, or `COPILOT_PLUGIN_ROOT` in hooks |
|
|
47
|
+
| OpenCode | `OPENCODE=1` with `OPENCODE_PID` |
|
|
48
|
+
| Kilo Code | `KILO=1` with `KILO_PID` |
|
|
49
|
+
| Gemini CLI | `GEMINI_CLI=1` |
|
|
50
|
+
| Qwen Code | `QWEN_CODE=1` |
|
|
51
|
+
| GitHub Copilot in VS Code | `COPILOT_AGENT=1` |
|
|
52
|
+
| Cline | `CLINE_ACTIVE=true`, set by the VS Code extension only |
|
|
53
|
+
| Crush | `CRUSH=1` |
|
|
54
|
+
| OpenHands | `AI_AGENT=openhands`, or `OPENHANDS_EVENT_TYPE` with `OPENHANDS_PROJECT_DIR` in hooks |
|
|
55
|
+
| Auggie CLI | `AUGMENT_HOOK_EVENT` with `AUGMENT_PROJECT_DIR`, in hooks only |
|
|
56
|
+
|
|
57
|
+
It reports `unknown` instead of guessing:
|
|
58
|
+
|
|
59
|
+
- when no harness matches, including `CLAUDECODE=1` on its own, which IDE extensions also set;
|
|
60
|
+
- when more than one harness matches, as when one harness runs inside another's shell. The matches
|
|
61
|
+
are listed in `candidates`;
|
|
62
|
+
- for `AGENT` and `AI_AGENT`, which several vendors set (only the exact value `AI_AGENT=openhands`
|
|
63
|
+
counts), and for `OPENCODE=1` alone, which Kilo Code, an OpenCode fork, also sets;
|
|
64
|
+
- in contexts where a harness sets nothing of its own: Codex, Gemini CLI, and Qwen Code hooks, Qwen
|
|
65
|
+
Code, Crush, OpenHands, and Auggie MCP servers, Auggie shell commands, OpenHands CLI 1.16.0 shell
|
|
66
|
+
commands (its SDK predates `AI_AGENT=openhands`), and the Cline CLI;
|
|
67
|
+
- for harnesses with no verified signal, such as Goose, Antigravity, Rovo Dev, Kiro, Amp, Factory
|
|
68
|
+
Droid, Devin Desktop, and Warp. The research records why for each one.
|
|
69
|
+
|
|
70
|
+
Pass `{ env }` to inspect an environment other than `process.env`.
|
|
71
|
+
|
|
72
|
+
## Managed policy
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { managedPolicyLocations } from 'cyber-agentkit'
|
|
76
|
+
|
|
77
|
+
managedPolicyLocations('claude-code', { platform: 'linux' })
|
|
78
|
+
// [
|
|
79
|
+
// { kind: 'server', location: 'claude.ai admin console or a self-hosted Claude apps gateway', … },
|
|
80
|
+
// { kind: 'file', location: '/etc/claude-code/managed-settings.json', … },
|
|
81
|
+
// { kind: 'directory', location: '/etc/claude-code/managed-settings.d', … },
|
|
82
|
+
// { kind: 'file', location: '/etc/claude-code/managed-mcp.json', … },
|
|
83
|
+
// ]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`kind` is `file` or `directory` for what a caller can read from disk, `macos-managed-preferences`
|
|
87
|
+
or `windows-registry` for MDM delivery, and `server` for policy held by the vendor or the
|
|
88
|
+
organization. A `server` entry means the local files are not the whole policy.
|
|
89
|
+
|
|
90
|
+
## Plugin storage
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { pluginStorage } from 'cyber-agentkit'
|
|
94
|
+
|
|
95
|
+
pluginStorage('codex')
|
|
96
|
+
// {
|
|
97
|
+
// harness: 'codex',
|
|
98
|
+
// configDir: '/home/me/.codex',
|
|
99
|
+
// locations: [
|
|
100
|
+
// { kind: 'plugin-cache', path: '/home/me/.codex/plugins/cache', … },
|
|
101
|
+
// { kind: 'enabled-record', path: '/home/me/.codex/config.toml', … },
|
|
102
|
+
// ],
|
|
103
|
+
// }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Paths are computed, not checked, so a location may not exist until the first plugin is installed.
|
|
107
|
+
Cursor has no `enabled-record`: no file records which of its plugins are enabled.
|
|
108
|
+
|
|
109
|
+
## Enabled plugins
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { enabledPlugins } from 'cyber-agentkit'
|
|
113
|
+
|
|
114
|
+
const result = await enabledPlugins('claude-code')
|
|
115
|
+
// {
|
|
116
|
+
// harness: 'claude-code',
|
|
117
|
+
// supported: true,
|
|
118
|
+
// plugins: [{ id: 'my-plugin@my-marketplace', enabled: true, scope: 'project', source: '/repo/.claude/settings.json' }],
|
|
119
|
+
// sources: [{ scope: 'managed', path: '/etc/claude-code/managed-settings.json', found: false }, …],
|
|
120
|
+
// unread: ['server-managed settings (claude.ai admin console or a self-hosted Claude apps gateway)', …],
|
|
121
|
+
// research: ['E-CC-P3', …],
|
|
122
|
+
// }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
| Harness | Files read, highest precedence first |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| Claude Code | managed `managed-settings.json`, `.claude/settings.local.json`, `.claude/settings.json`, `<config dir>/settings.json` |
|
|
128
|
+
| Codex | `<config dir>/config.toml` |
|
|
129
|
+
| GitHub Copilot CLI | managed `managed-settings.json`, `.github/copilot/settings.local.json`, `.github/copilot/settings.json`, `<config dir>/settings.json` |
|
|
130
|
+
| Cursor, OpenCode, Kilo Code, Gemini CLI, Qwen Code, Copilot in VS Code, Cline, Crush, OpenHands, Auggie CLI | none: `supported` is `false` |
|
|
131
|
+
|
|
132
|
+
Only plugins with an explicit entry are reported. A plugin with no entry falls back to a default
|
|
133
|
+
this package does not know. When `unread` is not empty, MDM or server-managed policy can still
|
|
134
|
+
override the answer.
|
|
135
|
+
|
|
136
|
+
## Installed plugins
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { enabledPlugins, installedPlugins } from 'cyber-agentkit'
|
|
140
|
+
|
|
141
|
+
const installed = await installedPlugins('claude-code')
|
|
142
|
+
// {
|
|
143
|
+
// harness: 'claude-code',
|
|
144
|
+
// supported: true,
|
|
145
|
+
// plugins: [{ id: 'my-plugin@my-marketplace', path: '/home/me/.claude/plugins/cache/my-marketplace/my-plugin/1.0.0', version: '1.0.0', scope: 'user', research: ['E-CC-P2'] }],
|
|
146
|
+
// unresolved: [],
|
|
147
|
+
// sources: [{ path: '/home/me/.claude/plugins/installed_plugins.json', found: true }],
|
|
148
|
+
// unread: [],
|
|
149
|
+
// research: ['E-CC-P2'],
|
|
150
|
+
// }
|
|
151
|
+
|
|
152
|
+
// The folder of each enabled plugin:
|
|
153
|
+
const enabled = new Set((await enabledPlugins('claude-code')).plugins.filter((p) => p.enabled).map((p) => p.id))
|
|
154
|
+
const folders = installed.plugins.filter((p) => enabled.has(p.id)).map((p) => p.path)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Harness | Read from | Folder |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| Claude Code | `<config dir>/plugins/installed_plugins.json` | `installPath`; one entry per scope a plugin is installed at |
|
|
160
|
+
| Codex | `<config dir>/plugins/cache/<marketplace>/<plugin>/` | `local` if present, else the highest version, as Codex picks it |
|
|
161
|
+
| GitHub Copilot CLI | `<config dir>/config.json` `installedPlugins` | `cache_path`; a direct install's `id` is its bare name |
|
|
162
|
+
| Cursor, OpenCode, Kilo Code, Gemini CLI, Qwen Code, Copilot in VS Code, Cline, Crush, OpenHands, Auggie CLI | none: `supported` is `false` | — |
|
|
163
|
+
|
|
164
|
+
`unresolved` lists Codex plugins whose cache mixes semver and non-semver version folders, where the
|
|
165
|
+
folder Codex picks depends on its sort. Copilot CLI loads plugins from a marketplace added by local
|
|
166
|
+
path in place, without an install record, so they appear in `unread` instead.
|
|
167
|
+
|
|
168
|
+
## Skill naming
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import { skillInvocation } from 'cyber-agentkit'
|
|
172
|
+
|
|
173
|
+
skillInvocation('claude-code', { plugin: 'my-plugin', skill: 'review' })?.text // '/my-plugin:review'
|
|
174
|
+
skillInvocation('copilot-cli', { plugin: 'my-plugin', skill: 'review' })?.text // '/review'
|
|
175
|
+
skillInvocation('codex', { plugin: 'my-plugin', skill: 'review' })?.text // '$my-plugin:review'
|
|
176
|
+
skillInvocation('gemini-cli', { plugin: 'my-plugin', skill: 'review' }) // undefined: the model loads skills itself
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Plugin dependencies
|
|
180
|
+
|
|
181
|
+
Only Claude Code's manifest declares dependencies, and only Claude Code installs the missing ones.
|
|
182
|
+
Every other harness ignores the field, so the plugin installs and fails later with nothing to say
|
|
183
|
+
why. This reads what a plugin declares, checks it against what the running harness has installed and
|
|
184
|
+
enabled, and returns the steps that settle the rest. It installs nothing and compares no versions.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { checkPluginDependencies, supportsPluginDependencies } from 'cyber-agentkit'
|
|
188
|
+
|
|
189
|
+
supportsPluginDependencies('claude-code') // true; false for the others
|
|
190
|
+
|
|
191
|
+
const check = await checkPluginDependencies('codex', { pluginRoot })
|
|
192
|
+
// {
|
|
193
|
+
// harness: 'codex',
|
|
194
|
+
// supported: false,
|
|
195
|
+
// autoResolved: false,
|
|
196
|
+
// dependencies: [{ name: 'my-dep', marketplace: 'my-marketplace', state: 'missing' }],
|
|
197
|
+
// steps: ['…'],
|
|
198
|
+
// research: ['E-DEP-2', …],
|
|
199
|
+
// }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`state` is `enabled`, `installed` (no explicit setting), `disabled`, `missing`, or `unknown` (the
|
|
203
|
+
harness keeps no readable install record). A dependency with no marketplace resolves only in the
|
|
204
|
+
declaring plugin's own marketplace, as Claude Code does, and is `unknown` when that marketplace
|
|
205
|
+
cannot be found.
|
|
206
|
+
|
|
207
|
+
`readPluginDependencies(pluginRoot)` reads the list from `extensions["org.spikyuni.plugin-manager"]`
|
|
208
|
+
(or the older `extensions["org.cyberuni.universal-plugin"]`) in the root `plugin.json`, then from
|
|
209
|
+
`.claude-plugin/plugin.json`. `declaredPluginDependencies(manifest)` parses a manifest you already
|
|
210
|
+
hold. The how-to for a person or agent, `plugin-dependencies`, ships as a
|
|
211
|
+
[reference](#reference-documents).
|
|
212
|
+
|
|
213
|
+
## Skill directories
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { skillsDirectories } from 'cyber-agentkit'
|
|
217
|
+
|
|
218
|
+
skillsDirectories('claude-code') // { project: ['.claude/skills'], user: ['.claude/skills'], research: ['E-CC-L1'] }
|
|
219
|
+
skillsDirectories('codex')?.project.includes('.agents/skills') // true
|
|
220
|
+
skillsDirectories('qwen-code') // undefined: not confirmed
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Project directories are relative to the project root, user directories to the home directory. Only
|
|
224
|
+
directories read by default are listed; admin, bundled, and plugin skills are left out.
|
|
225
|
+
|
|
226
|
+
## Headless runs
|
|
227
|
+
|
|
228
|
+
How to run a harness on one prompt with no user present: the command, the model and permission
|
|
229
|
+
flags, the output formats and where token usage and cost appear in them, the transcript location,
|
|
230
|
+
and the documented exit codes. The library only describes the run; starting the process is up to
|
|
231
|
+
you.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { headlessCommand, headlessInvocation } from 'cyber-agentkit'
|
|
235
|
+
|
|
236
|
+
headlessCommand('claude-code', {
|
|
237
|
+
prompt: 'Fix the failing test',
|
|
238
|
+
model: 'sonnet',
|
|
239
|
+
permission: 'unattended',
|
|
240
|
+
outputFormat: 'stream-json',
|
|
241
|
+
})
|
|
242
|
+
// { executable: 'claude', args: ['-p', '--model', 'sonnet', '--permission-mode', 'bypassPermissions',
|
|
243
|
+
// '--output-format', 'stream-json', '--verbose', 'Fix the failing test'] }
|
|
244
|
+
|
|
245
|
+
const codex = headlessInvocation('codex')
|
|
246
|
+
// codex.outputFormats[1]: { name: 'jsonl', args: ['--json'],
|
|
247
|
+
// usage: { event: 'turn.completed', tokens: 'usage', accumulate: 'sum' } } (no dollar cost)
|
|
248
|
+
|
|
249
|
+
headlessInvocation('vscode-copilot').supported // false: no headless mode
|
|
250
|
+
headlessInvocation('opencode').supported // 'unknown': a one-shot mode exists, but its flags are not verified
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Claude Code, Codex, Copilot CLI, Cursor, Gemini CLI, and Qwen Code are covered. `permission:
|
|
254
|
+
'unattended'` lets the run edit files and run commands without asking, so use it only in a
|
|
255
|
+
throwaway checkout. Exit codes are a weak signal: Claude Code documents only zero and non-zero, and
|
|
256
|
+
a run stopped by a turn or budget cap is told apart by the `result` message's `subtype`.
|
|
257
|
+
|
|
258
|
+
## Reference documents
|
|
259
|
+
|
|
260
|
+
A reference is a named Markdown document an agent reads on demand, such as a checklist or a set of
|
|
261
|
+
weights a skill applies. A plugin ships a contribution, a skill ships its default at
|
|
262
|
+
`<skill>/references/<name>.default.md`, and anyone can add their own without editing the plugin: a
|
|
263
|
+
project in `.agents/references/<name>.md`, a person in `~/.agents/references/<name>.md`.
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { loadReference } from 'cyber-agentkit'
|
|
267
|
+
|
|
268
|
+
const resolved = await loadReference('agent-readiness-weights', {
|
|
269
|
+
root: process.cwd(),
|
|
270
|
+
// The plugin calling the resolver: its own `references/` is the first plugin layer.
|
|
271
|
+
plugin: { name: 'my-plugin', root: pluginRoot },
|
|
272
|
+
// The skill loading the name: its `references/<name>.default.md` joins as the default tier.
|
|
273
|
+
defaultSkill: skillFolder,
|
|
274
|
+
})
|
|
275
|
+
if (resolved.status === 'found') console.log(resolved.content)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
`status` is `found`, `missing`, `ambiguous` (nothing orders the plugins holding the name; pick one
|
|
279
|
+
of `resolved.options`, such as `my-plugin/agent-readiness-weights`, or settle it with
|
|
280
|
+
`reference select`), or `invalid` (not a reference name). A name not found also has a `code`, such
|
|
281
|
+
as `reference-missing`. A library function never throws for a bad name. `warnings` holds each fault
|
|
282
|
+
as `{ code, message }`, and `trace` says how the document was built.
|
|
283
|
+
|
|
284
|
+
The tiers, highest first:
|
|
285
|
+
|
|
286
|
+
| Tier | Folders |
|
|
287
|
+
| --- | --- |
|
|
288
|
+
| managed | a `references/` beside each detected harness's managed-policy files |
|
|
289
|
+
| project | `.agents/references/` in the root and each folder above it, up to the repository root |
|
|
290
|
+
| user | `~/.agents/references/` |
|
|
291
|
+
| plugin | the calling plugin's `references/`, each plugin the harness has enabled, then each declared dependency that has a plugin manifest, named by that manifest |
|
|
292
|
+
| default | `<skill folder>/references/<name>.default.md` of the skill loading the name |
|
|
293
|
+
|
|
294
|
+
In each folder, only `<name>.md` and `<name>/README.md` answer a name, in that order.
|
|
295
|
+
|
|
296
|
+
Contributions apply bottom first: the plugins and the default, in the order `extends` gives them,
|
|
297
|
+
then user, project, and managed. Each applies over what is below it with its frontmatter `merge`:
|
|
298
|
+
|
|
299
|
+
- `patch` (the default): its sections replace the text they match by heading path, and the rest is
|
|
300
|
+
kept.
|
|
301
|
+
- `combine`: its sections' text is added after the text they match, lower first; where combined text
|
|
302
|
+
conflicts, the later text wins.
|
|
303
|
+
- `replace`: it replaces everything below.
|
|
304
|
+
- `remove`: it drops everything below.
|
|
305
|
+
|
|
306
|
+
A `<!-- merge: <operation> -->` marker under a heading applies an operation to that section alone.
|
|
307
|
+
Frontmatter `extends` lists what a contribution builds on, bottom first: plugins by their manifest
|
|
308
|
+
name, and `default`. The highest `extends` written in the managed, project, or user tier builds the
|
|
309
|
+
stack; without one, the plugins' own `extends` order them. `resolved.metadata` holds the composed
|
|
310
|
+
frontmatter, the higher contribution winning each key, without `merge` and `extends`. Frontmatter
|
|
311
|
+
that is not a YAML mapping is ignored with a warning.
|
|
312
|
+
|
|
313
|
+
| Function | Does |
|
|
314
|
+
| --- | --- |
|
|
315
|
+
| `loadReference(name, options)` | Resolves one name for a root, with every tier read |
|
|
316
|
+
| `referenceLayers(options)` | Builds the ordered layers, and finds the skills holding a default, to resolve several names against |
|
|
317
|
+
| `resolveReference(name, layers)` | Resolves a name against layers |
|
|
318
|
+
| `listReferences(layers)`, `referenceNames(layers)` | Every name the layers hold, one row each, and a row per layer holding it |
|
|
319
|
+
| `listReferences(layers, { pattern })` | Every reference by exact name pattern |
|
|
320
|
+
| `searchReferences(query, layers)` | Names matching a query by name, description, heading, or body |
|
|
321
|
+
| `whereReference(name, layers, options)` | The project and user files a customization is written to, and the heading paths below each |
|
|
322
|
+
| `projectReferencesDir()`, `userReferencesDir()`, `defaultLayer()` | Single folders and layers |
|
|
323
|
+
| `declaredDependencies()`, `packageDir()`, `pluginManifestName()` | A manifest's declared packages, where each is installed, and a plugin's manifest name |
|
|
324
|
+
| `harnessSkillFolders()`, `pluginSkillFolders()`, `skillsIn()` | The skill folders a harness reads, and the skills in them, known by their `SKILL.md` name |
|
|
325
|
+
| `referenceImplementations(id, layers)` | The implementations of an interface a consumer can load, and those left out with why |
|
|
326
|
+
| `checkReferences(layers, options)` | Checks interface documents and their implementations, each as `show` composes it |
|
|
327
|
+
|
|
328
|
+
### The reference command
|
|
329
|
+
|
|
330
|
+
The package ships a `reference` command with `show`, `list`, `search`, `where`, `implementations`,
|
|
331
|
+
`check`, `create`, `select`, and `delete` subcommands:
|
|
332
|
+
|
|
333
|
+
```sh
|
|
334
|
+
npx -y cyber-agentkit reference show <name>... --root <repository root> --default <skill folder>
|
|
335
|
+
npx -y cyber-agentkit reference list
|
|
336
|
+
npx -y cyber-agentkit reference list 'project-tracker.capabilities.*'
|
|
337
|
+
npx -y cyber-agentkit reference implementations <interface id> --accept 1,2
|
|
338
|
+
npx -y cyber-agentkit reference check
|
|
339
|
+
npx -y cyber-agentkit reference create <name> --merge combine
|
|
340
|
+
npx -y cyber-agentkit reference select <name> <plugin> --scope user
|
|
341
|
+
npx -y cyber-agentkit reference delete <name> --scope project --dry-run
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
`implementations` lists what a consumer can load for an interface (a `<id>.interface` document) with
|
|
345
|
+
each one's pin, description, and unsupported sections. `check` verifies interface documents and
|
|
346
|
+
their implementations, and exits 1 on any failure.
|
|
347
|
+
|
|
348
|
+
`create`, `select`, and `delete` act on `.agents/references/` (the project, the default) or
|
|
349
|
+
`~/.agents/references/` (`--scope user`). `create` and `delete` also take `--plugin <plugin folder>`
|
|
350
|
+
or `--default <skill folder>` for a plugin's or a skill's source in the repository. `delete` reports
|
|
351
|
+
what answers the name afterwards, and never deletes a managed contribution or an installed copy.
|
|
352
|
+
`select` writes the `extends` that picks what a name builds on, and `--clear` removes it.
|
|
353
|
+
|
|
354
|
+
Output is [TOON](https://github.com/toon-format/toon) by default, for an agent to parse; pass
|
|
355
|
+
`--format json` or `--format text` (`show`, `create`, `select`, and `delete` default to `text`).
|
|
356
|
+
Each command prints only the fields that answer it; on `show`, `--metadata` adds the status and the
|
|
357
|
+
composed frontmatter, and `--trace` adds how the document was built. Every warning carries a stable
|
|
358
|
+
`code`. The formats
|
|
359
|
+
follow [`clibuilder`](https://www.npmjs.com/package/clibuilder) 12, and any other value is a
|
|
360
|
+
usage error (exit code 2). A CLI built on clibuilder 12
|
|
361
|
+
can host the same command under its own plugin name, imported from the `./commands` subpath. `--format`
|
|
362
|
+
is the host's global option, so the host's `cli({ format })` sets the default for every subcommand;
|
|
363
|
+
the `text` default of `show`, `create`, `select`, and `delete` belongs to the `cyber-agentkit` CLI:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
import { createReferenceCommand } from 'cyber-agentkit/commands'
|
|
367
|
+
|
|
368
|
+
app.command(createReferenceCommand({ plugin: { name: 'my-plugin', root: pluginRoot } }))
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### The `reference` skill
|
|
372
|
+
|
|
373
|
+
The package is also an agent plugin, `cyber-agentkit`, that ships a `reference` skill. Type
|
|
374
|
+
`/reference` (`/cyber-agentkit:reference` in Claude Code) to load, create, update, delete, find, or
|
|
375
|
+
inspect a reference, or to wire a skill to load one. The skill writes or deletes a file only after
|
|
376
|
+
you approve it. It runs the command from its bundled `scripts/reference.mjs`, which needs no
|
|
377
|
+
`node_modules`.
|
|
378
|
+
|
|
379
|
+
```text
|
|
380
|
+
/plugin marketplace add cyberuni/cyberplace
|
|
381
|
+
/plugin install cyber-agentkit@cyberplace
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
A skill that needs a reference names it in one line, as the skill's
|
|
385
|
+
[`README.md`](https://github.com/cyber-uni/cyber-agentkit/blob/main/packages/cyber-agentkit/skills/reference/README.md)
|
|
386
|
+
shows:
|
|
387
|
+
|
|
388
|
+
```text
|
|
389
|
+
Load `skill-design` with the `reference` skill of `cyber-agentkit`.
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Worktrees
|
|
393
|
+
|
|
394
|
+
The `./worktrees` subpath leases git worktrees to concurrent agent sessions, so two agents never
|
|
395
|
+
share a checkout. It does not fetch and never kills a process.
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import { acquire, pruneWorktrees, release } from 'cyber-agentkit/worktrees'
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
| Function | Does |
|
|
402
|
+
| --- | --- |
|
|
403
|
+
| `acquire(options)` | Leases a worktree: recycles an idle one of its own, else creates one at the next free slot under `max` |
|
|
404
|
+
| `explain(options)` | Every worktree of the repository with the reason it cannot be reused, or none |
|
|
405
|
+
| `release()`, `claimLease()`, `holdsLease()` | The lease a holder takes on a worktree |
|
|
406
|
+
| `pruneWorktrees(options)` | Removes unleased, idle, clean, landed worktrees it owns. A dry run unless `apply` is set |
|
|
407
|
+
| `removeWorktree(options)` | Removes the one worktree you name, under the same safety checks |
|
|
408
|
+
| `seedWorktree(options)` | Copies the gitignored files a `.worktreeinclude` names into a new or recycled worktree |
|
|
409
|
+
| `listWorktrees()`, `occupants()`, `classifyOwner()` | The worktrees of a repository, the sessions working in each, and who owns each |
|
|
410
|
+
|
|
411
|
+
A worktree is skipped, with the reason in its verdict, when it is the primary checkout, owned by
|
|
412
|
+
another tool or person, leased, prunable, busy, dirty, or not yet landed on the default branch. The
|
|
413
|
+
checks fail closed: when git or the process probe cannot say, the worktree is left alone.
|
|
414
|
+
|
|
415
|
+
## Why this exists
|
|
416
|
+
|
|
417
|
+
`universal-plugin`, `buddy-agent-harness`, `repobuddy`, and `cyberlegion/cyber-mux` each need to know
|
|
418
|
+
which agent harness they are running under, and each was re-implementing that detection separately.
|
|
419
|
+
This package exists so they share one implementation instead.
|
|
420
|
+
|
|
421
|
+
## License
|
|
422
|
+
|
|
423
|
+
[MIT](https://github.com/cyber-uni/cyber-agentkit/blob/main/LICENSE)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to install the plugins another plugin depends on, for Claude Code and for every harness that has no dependency field.
|
|
3
|
+
tags: [plugin, dependencies, install]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## What a plugin declares
|
|
7
|
+
|
|
8
|
+
Only Claude Code's manifest declares dependencies: a `dependencies` array in `.claude-plugin/plugin.json` whose entries are `"name"`, `"name@marketplace"`, or `{ "name", "marketplace", "version" }` (E-DEP-1). A bare name resolves in the declaring plugin's own marketplace. A plugin can author the same list once in its root `plugin.json`, at `extensions["org.spikyuni.plugin-manager"].dependencies` or, in plugins built before that key, `extensions["org.cyberuni.universal-plugin"].dependencies` (E-DEP-6, E-DEP-7). Read it from there first, then from `.claude-plugin/plugin.json`, whichever harness you run on.
|
|
9
|
+
|
|
10
|
+
## Check what is missing
|
|
11
|
+
|
|
12
|
+
Run the library's `checkPluginDependencies(harness, { pluginRoot })`. It reports each dependency as `enabled`, `installed` (no explicit setting), `disabled`, `missing`, or `unknown` (the harness keeps no readable install record), and returns the steps below that apply. It installs nothing.
|
|
13
|
+
|
|
14
|
+
## Claude Code
|
|
15
|
+
|
|
16
|
+
Claude Code resolves dependencies itself. `claude plugin install`, `/reload-plugins`, auto-update, and `marketplace add` install the missing ones, and a plugin whose dependency is missing or disabled does not load (E-DEP-2).
|
|
17
|
+
|
|
18
|
+
1. For a missing dependency, run `claude plugin install <name>@<marketplace>`.
|
|
19
|
+
2. For a disabled dependency, set its `<name>@<marketplace>` key to `true` in `enabledPlugins`.
|
|
20
|
+
3. Run `/reload-plugins`.
|
|
21
|
+
|
|
22
|
+
A dependency in another marketplace is not installed unless the root marketplace lists it in `allowCrossMarketplaceDependenciesOn`, or you already have it enabled. Without that, the install completes and the plugin then fails to load (E-DEP-3).
|
|
23
|
+
|
|
24
|
+
## Every other harness
|
|
25
|
+
|
|
26
|
+
`cursor`, `codex`, `copilot-cli`, `opencode`, `kilo`, `gemini-cli`, `qwen-code`, `vscode-copilot`, `cline`, `crush`, `openhands`, `augment` have no dependency field (E-DEP-4, E-DEP-5, E-CC-X1). Nothing is resolved for you, and no install command is given because none has been verified.
|
|
27
|
+
|
|
28
|
+
1. Read the dependencies as above.
|
|
29
|
+
2. Tell the user which marketplace each one needs. You cannot tell whether the harness has that marketplace added, so ask the user to check, and to add it if it is not.
|
|
30
|
+
3. Install each one through the harness's own plugin install flow, from its marketplace when one is named.
|
|
31
|
+
4. Enable each one.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Reference
|
|
2
|
+
|
|
3
|
+
Loads, creates, updates, selects, deletes, and finds [references](https://cyber-uni.github.io/cyber-agentkit/concepts/reference-documents/): Markdown documents an agent reads on demand by name. It routes each request to the `reference` command, run from a launcher bundled in `scripts/`, and writes or deletes a reference only after the user approves it. Type `/reference` (`/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`) in Claude Code) to run it yourself.
|
|
4
|
+
|
|
5
|
+
| Mode | When |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Load | a skill's instructions name references, or an interface whose implementations, to load with this skill |
|
|
8
|
+
| Create | writing a new reference for a project, a user, a plugin (`<plugin name>.<reference>.md`), or a skill's default (`<name>.default.md`); an implementation of an interface is `<id>.<key>.md` |
|
|
9
|
+
| Update | changing a reference: the user's own in place, a plugin's by a customization that patches it |
|
|
10
|
+
| Select | choosing which plugins, or the skill's default, a name builds on, which settles an ambiguous name |
|
|
11
|
+
| Delete | removing a project or user contribution, saying first what answers the name afterwards |
|
|
12
|
+
| Find | `search` for a topic, `list` every reference, or `implementations` of an interface |
|
|
13
|
+
| Inspect | `show`; `show --trace` for how a name composed; `where` for the project and user files a customization goes to; `check` against an interface |
|
|
14
|
+
| Wire a skill | giving a skill the line below |
|
|
15
|
+
|
|
16
|
+
It ships in the `cyber-agentkit` plugin:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
/plugin marketplace add cyberuni/cyberplace
|
|
20
|
+
/plugin install cyber-agentkit@cyberplace
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Loading a reference from a skill
|
|
24
|
+
|
|
25
|
+
A calling skill names the references it needs in one line:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
Load `skill-design` and `agent-tool-output` with the `reference` skill of `cyber-agentkit`.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Name the package as well as the skill: an agent that does not have the skill can then tell the user what to install. Write the skill's name in words, as above. Every harness reads the words, but each types the skill differently, and where the typed form does not name the plugin, two plugins' skills of the same name collide.
|
|
32
|
+
|
|
33
|
+
A skill written for one harness only may add that harness's typed form after the skill's name, for example "with the `reference` skill (`/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`)) of `cyber-agentkit`" in Claude Code. Each harness names it this way:
|
|
34
|
+
|
|
35
|
+
<!-- generated: harness invocations -->
|
|
36
|
+
| Harness | Typed form | Names the plugin |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `claude-code` | `/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`) | yes |
|
|
39
|
+
| `cursor` | `/reference` | no |
|
|
40
|
+
| `codex` | `$cyber-agentkit:reference` | yes |
|
|
41
|
+
| `copilot-cli` | `/reference` | no |
|
|
42
|
+
| `opencode` | `/reference` | no |
|
|
43
|
+
| `kilo` | `/reference` | no |
|
|
44
|
+
| `gemini-cli` | no typed form recorded | — |
|
|
45
|
+
| `qwen-code` | no typed form recorded | — |
|
|
46
|
+
| `vscode-copilot` | `/cyber-agentkit:reference` (pnpm install: `pnpm-cyber-agentkit-reference`) | yes |
|
|
47
|
+
| `cline` | `/reference` | no |
|
|
48
|
+
| `crush` | no typed form recorded | — |
|
|
49
|
+
| `openhands` | no typed form recorded | — |
|
|
50
|
+
| `augment` | no typed form recorded | — |
|
|
51
|
+
<!-- /generated -->
|
|
52
|
+
|
|
53
|
+
A skill that consumes an [interface](https://cyber-uni.github.io/cyber-agentkit/concepts/reference-interfaces/) names the interface instead:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
Load the implementations of the `scaffold.recipe` interface with the `reference` skill of `cyber-agentkit`.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The skill runs `implementations <id>` and hands back each implementation's pin, which the calling skill loads by name.
|
|
60
|
+
|
|
61
|
+
A calling skill may ship its own default of a reference at `references/<name>.default.md`. Loading passes the calling skill's folder as `--default`, so the default sits below every plugin, user, project, and managed contribution, and anyone can customize it. The skill reads the default by itself only when the command cannot run. A copy at `references/<name>.md`, the old layout, is not read as a default.
|
|
62
|
+
|
|
63
|
+
`scripts/reference.mjs` is the package's `reference` command bundled into this folder. It ships through the npm package and runs with no `node_modules`. Loading never falls back to `npx` or the network; the other modes fall back to `pnpm exec cyber-agentkit`, or to `npx` pinned to this release's exact version, when the launcher is missing.
|