@rryando/arcs 3.1.2 → 3.2.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 +65 -40
- package/dist/cli/arg-parser.d.ts +3 -3
- package/dist/cli/arg-parser.d.ts.map +1 -1
- package/dist/cli/arg-parser.js +1 -1
- package/dist/cli/arg-parser.js.map +1 -1
- package/dist/cli/bundle-installer.d.ts +11 -0
- package/dist/cli/bundle-installer.d.ts.map +1 -1
- package/dist/cli/bundle-installer.js +14 -4
- package/dist/cli/bundle-installer.js.map +1 -1
- package/dist/cli/command-registry.d.ts +61 -6
- package/dist/cli/command-registry.d.ts.map +1 -1
- package/dist/cli/command-registry.js.map +1 -1
- package/dist/cli/commands/batch.js +17 -16
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/brief.js +71 -74
- package/dist/cli/commands/brief.js.map +1 -1
- package/dist/cli/commands/bundle.js +79 -31
- package/dist/cli/commands/bundle.js.map +1 -1
- package/dist/cli/commands/dependency.js +47 -43
- package/dist/cli/commands/dependency.js.map +1 -1
- package/dist/cli/commands/diagnostics.js.map +1 -1
- package/dist/cli/commands/diagram.js +39 -55
- package/dist/cli/commands/diagram.js.map +1 -1
- package/dist/cli/commands/done.js +19 -18
- package/dist/cli/commands/done.js.map +1 -1
- package/dist/cli/commands/graph.js +12 -10
- package/dist/cli/commands/graph.js.map +1 -1
- package/dist/cli/commands/knowledge-search.js +11 -12
- package/dist/cli/commands/knowledge-search.js.map +1 -1
- package/dist/cli/commands/knowledge.js +63 -56
- package/dist/cli/commands/knowledge.js.map +1 -1
- package/dist/cli/commands/loop.js +40 -36
- package/dist/cli/commands/loop.js.map +1 -1
- package/dist/cli/commands/maintenance.js +16 -13
- package/dist/cli/commands/maintenance.js.map +1 -1
- package/dist/cli/commands/next.js +9 -8
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/plan.js +61 -55
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/project-updates.js +37 -33
- package/dist/cli/commands/project-updates.js.map +1 -1
- package/dist/cli/commands/project.js +21 -17
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/remember.js +6 -6
- package/dist/cli/commands/remember.js.map +1 -1
- package/dist/cli/commands/status.js +9 -8
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/task.d.ts +1 -5
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +180 -248
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/utility.d.ts.map +1 -1
- package/dist/cli/commands/utility.js +39 -35
- package/dist/cli/commands/utility.js.map +1 -1
- package/dist/cli/dag-commands.js.map +1 -1
- package/dist/cli/help-generator.d.ts +3 -3
- package/dist/cli/help-generator.d.ts.map +1 -1
- package/dist/cli/help-generator.js +1 -1
- package/dist/cli/help-generator.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +235 -113
- package/dist/cli/setup.js.map +1 -1
- package/dist/utils/diagram-store.d.ts +45 -0
- package/dist/utils/diagram-store.d.ts.map +1 -0
- package/dist/utils/diagram-store.js +99 -0
- package/dist/utils/diagram-store.js.map +1 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/json-schemas.d.ts +7 -0
- package/dist/utils/json-schemas.d.ts.map +1 -1
- package/dist/utils/json-schemas.js +1 -0
- package/dist/utils/json-schemas.js.map +1 -1
- package/dist/utils/storage-utils.d.ts +1 -1
- package/dist/utils/storage-utils.d.ts.map +1 -1
- package/dist/utils/storage-utils.js +1 -1
- package/dist/utils/storage-utils.js.map +1 -1
- package/dist/utils/task-store.d.ts.map +1 -1
- package/dist/utils/task-store.js +6 -5
- package/dist/utils/task-store.js.map +1 -1
- package/dist/utils/toposort.d.ts +1 -1
- package/dist/utils/toposort.d.ts.map +1 -1
- package/dist/utils/toposort.js +5 -4
- package/dist/utils/toposort.js.map +1 -1
- package/dist/utils/workflow-policy.d.ts +1 -1
- package/dist/utils/workflow-policy.d.ts.map +1 -1
- package/dist/utils/workflow-policy.js +1 -1
- package/dist/utils/workflow-policy.js.map +1 -1
- package/opencode/arcs/manifest.json +47 -66
- package/package.json +1 -1
- package/scripts/deploy-claudecode-bundle.mjs +414 -0
|
@@ -44,11 +44,19 @@
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
"path": [
|
|
49
|
+
"lsp"
|
|
50
|
+
],
|
|
51
|
+
"value": true,
|
|
52
|
+
"mode": "if-absent"
|
|
53
|
+
},
|
|
47
54
|
{
|
|
48
55
|
"path": [
|
|
49
56
|
"model"
|
|
50
57
|
],
|
|
51
|
-
"value": "github-copilot/claude-sonnet-4.6"
|
|
58
|
+
"value": "github-copilot/claude-sonnet-4.6",
|
|
59
|
+
"mode": "if-absent"
|
|
52
60
|
},
|
|
53
61
|
{
|
|
54
62
|
"path": [
|
|
@@ -56,7 +64,8 @@
|
|
|
56
64
|
"build",
|
|
57
65
|
"model"
|
|
58
66
|
],
|
|
59
|
-
"value": "github-copilot/claude-sonnet-4.6"
|
|
67
|
+
"value": "github-copilot/claude-sonnet-4.6",
|
|
68
|
+
"mode": "if-absent"
|
|
60
69
|
},
|
|
61
70
|
{
|
|
62
71
|
"path": [
|
|
@@ -64,7 +73,8 @@
|
|
|
64
73
|
"plan",
|
|
65
74
|
"model"
|
|
66
75
|
],
|
|
67
|
-
"value": "github-copilot/claude-opus-4.6"
|
|
76
|
+
"value": "github-copilot/claude-opus-4.6",
|
|
77
|
+
"mode": "if-absent"
|
|
68
78
|
},
|
|
69
79
|
{
|
|
70
80
|
"path": [
|
|
@@ -72,7 +82,8 @@
|
|
|
72
82
|
"general",
|
|
73
83
|
"model"
|
|
74
84
|
],
|
|
75
|
-
"value": "github-copilot/claude-opus-4.6"
|
|
85
|
+
"value": "github-copilot/claude-opus-4.6",
|
|
86
|
+
"mode": "if-absent"
|
|
76
87
|
},
|
|
77
88
|
{
|
|
78
89
|
"path": [
|
|
@@ -80,7 +91,8 @@
|
|
|
80
91
|
"explore",
|
|
81
92
|
"model"
|
|
82
93
|
],
|
|
83
|
-
"value": "github-copilot/claude-haiku-4.5"
|
|
94
|
+
"value": "github-copilot/claude-haiku-4.5",
|
|
95
|
+
"mode": "if-absent"
|
|
84
96
|
},
|
|
85
97
|
{
|
|
86
98
|
"path": [
|
|
@@ -93,9 +105,11 @@
|
|
|
93
105
|
"model": "github-copilot/claude-haiku-4.5",
|
|
94
106
|
"prompt": "{file:./prompts/code-reviewer.txt}",
|
|
95
107
|
"permission": {
|
|
96
|
-
"edit": "
|
|
108
|
+
"edit": "allow",
|
|
97
109
|
"bash": "allow",
|
|
98
|
-
"webfetch": "
|
|
110
|
+
"webfetch": "allow",
|
|
111
|
+
"mcp": "allow",
|
|
112
|
+
"external_directory": { "*": "allow" }
|
|
99
113
|
}
|
|
100
114
|
}
|
|
101
115
|
},
|
|
@@ -109,15 +123,11 @@
|
|
|
109
123
|
"mode": "subagent",
|
|
110
124
|
"model": "github-copilot/claude-opus-4.6",
|
|
111
125
|
"permission": {
|
|
112
|
-
"edit": "
|
|
113
|
-
"bash": "
|
|
126
|
+
"edit": "allow",
|
|
127
|
+
"bash": "allow",
|
|
114
128
|
"webfetch": "allow",
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
"/tmp/**": "allow",
|
|
118
|
-
"~/.arcs": "allow",
|
|
119
|
-
"~/.arcs/**": "allow"
|
|
120
|
-
}
|
|
129
|
+
"mcp": "allow",
|
|
130
|
+
"external_directory": { "*": "allow" }
|
|
121
131
|
},
|
|
122
132
|
"prompt": "{file:./prompts/docs-researcher.txt}"
|
|
123
133
|
}
|
|
@@ -132,13 +142,11 @@
|
|
|
132
142
|
"mode": "subagent",
|
|
133
143
|
"model": "github-copilot/claude-haiku-4.5",
|
|
134
144
|
"permission": {
|
|
135
|
-
"edit": "
|
|
136
|
-
"bash": "
|
|
137
|
-
"webfetch": "
|
|
138
|
-
"
|
|
139
|
-
|
|
140
|
-
"~/.arcs/**": "allow"
|
|
141
|
-
}
|
|
145
|
+
"edit": "allow",
|
|
146
|
+
"bash": "allow",
|
|
147
|
+
"webfetch": "allow",
|
|
148
|
+
"mcp": "allow",
|
|
149
|
+
"external_directory": { "*": "allow" }
|
|
142
150
|
},
|
|
143
151
|
"prompt": "{file:./prompts/tech-architect.txt}"
|
|
144
152
|
}
|
|
@@ -155,14 +163,9 @@
|
|
|
155
163
|
"permission": {
|
|
156
164
|
"edit": "allow",
|
|
157
165
|
"bash": "allow",
|
|
158
|
-
"webfetch": "
|
|
166
|
+
"webfetch": "allow",
|
|
159
167
|
"mcp": "allow",
|
|
160
|
-
"external_directory": {
|
|
161
|
-
"/tmp": "allow",
|
|
162
|
-
"/tmp/**": "allow",
|
|
163
|
-
"~/.arcs": "allow",
|
|
164
|
-
"~/.arcs/**": "allow"
|
|
165
|
-
}
|
|
168
|
+
"external_directory": { "*": "allow" }
|
|
166
169
|
},
|
|
167
170
|
"prompt": "{file:./prompts/software-engineer.txt}"
|
|
168
171
|
}
|
|
@@ -179,16 +182,9 @@
|
|
|
179
182
|
"permission": {
|
|
180
183
|
"edit": "allow",
|
|
181
184
|
"bash": "allow",
|
|
182
|
-
"webfetch": "
|
|
185
|
+
"webfetch": "allow",
|
|
183
186
|
"mcp": "allow",
|
|
184
|
-
"external_directory": {
|
|
185
|
-
"/tmp": "allow",
|
|
186
|
-
"/tmp/**": "allow",
|
|
187
|
-
"~/.arcs": "allow",
|
|
188
|
-
"~/.arcs/**": "allow",
|
|
189
|
-
"~/.config/opencode": "allow",
|
|
190
|
-
"~/.config/opencode/**": "allow"
|
|
191
|
-
}
|
|
187
|
+
"external_directory": { "*": "allow" }
|
|
192
188
|
},
|
|
193
189
|
"prompt": "{file:./prompts/arcs-docs.txt}"
|
|
194
190
|
}
|
|
@@ -203,14 +199,11 @@
|
|
|
203
199
|
"mode": "subagent",
|
|
204
200
|
"model": "github-copilot/claude-haiku-4.5",
|
|
205
201
|
"permission": {
|
|
206
|
-
"edit": "
|
|
202
|
+
"edit": "allow",
|
|
207
203
|
"bash": "allow",
|
|
208
|
-
"webfetch": "
|
|
204
|
+
"webfetch": "allow",
|
|
209
205
|
"mcp": "allow",
|
|
210
|
-
"external_directory": {
|
|
211
|
-
"~/.arcs": "allow",
|
|
212
|
-
"~/.arcs/**": "allow"
|
|
213
|
-
}
|
|
206
|
+
"external_directory": { "*": "allow" }
|
|
214
207
|
},
|
|
215
208
|
"prompt": "{file:./prompts/qa-analyst.txt}"
|
|
216
209
|
}
|
|
@@ -225,16 +218,11 @@
|
|
|
225
218
|
"mode": "subagent",
|
|
226
219
|
"model": "github-copilot/claude-sonnet-4.6",
|
|
227
220
|
"permission": {
|
|
228
|
-
"edit": "
|
|
221
|
+
"edit": "allow",
|
|
229
222
|
"bash": "allow",
|
|
230
|
-
"webfetch": "
|
|
223
|
+
"webfetch": "allow",
|
|
231
224
|
"mcp": "allow",
|
|
232
|
-
"external_directory": {
|
|
233
|
-
"/tmp": "allow",
|
|
234
|
-
"/tmp/**": "allow",
|
|
235
|
-
"~/.arcs": "allow",
|
|
236
|
-
"~/.arcs/**": "allow"
|
|
237
|
-
}
|
|
225
|
+
"external_directory": { "*": "allow" }
|
|
238
226
|
},
|
|
239
227
|
"prompt": "{file:./prompts/devil-advocate.txt}"
|
|
240
228
|
}
|
|
@@ -249,16 +237,11 @@
|
|
|
249
237
|
"mode": "subagent",
|
|
250
238
|
"model": "github-copilot/claude-opus-4.6",
|
|
251
239
|
"permission": {
|
|
252
|
-
"edit": "
|
|
240
|
+
"edit": "allow",
|
|
253
241
|
"bash": "allow",
|
|
254
|
-
"webfetch": "
|
|
242
|
+
"webfetch": "allow",
|
|
255
243
|
"mcp": "allow",
|
|
256
|
-
"external_directory": {
|
|
257
|
-
"/tmp": "allow",
|
|
258
|
-
"/tmp/**": "allow",
|
|
259
|
-
"~/.arcs": "allow",
|
|
260
|
-
"~/.arcs/**": "allow"
|
|
261
|
-
}
|
|
244
|
+
"external_directory": { "*": "allow" }
|
|
262
245
|
},
|
|
263
246
|
"prompt": "{file:./prompts/oncall-ops.txt}"
|
|
264
247
|
}
|
|
@@ -273,14 +256,11 @@
|
|
|
273
256
|
"mode": "subagent",
|
|
274
257
|
"model": "github-copilot/claude-opus-4.6",
|
|
275
258
|
"permission": {
|
|
276
|
-
"edit": "
|
|
259
|
+
"edit": "allow",
|
|
277
260
|
"bash": "allow",
|
|
278
261
|
"webfetch": "allow",
|
|
279
262
|
"mcp": "allow",
|
|
280
|
-
"external_directory": {
|
|
281
|
-
"~/.arcs": "allow",
|
|
282
|
-
"~/.arcs/**": "allow"
|
|
283
|
-
}
|
|
263
|
+
"external_directory": { "*": "allow" }
|
|
284
264
|
},
|
|
285
265
|
"prompt": "{file:./prompts/system-architect.txt}"
|
|
286
266
|
}
|
|
@@ -289,7 +269,8 @@
|
|
|
289
269
|
"path": [
|
|
290
270
|
"small_model"
|
|
291
271
|
],
|
|
292
|
-
"value": "github-copilot/claude-haiku-4.5"
|
|
272
|
+
"value": "github-copilot/claude-haiku-4.5",
|
|
273
|
+
"mode": "if-absent"
|
|
293
274
|
}
|
|
294
275
|
]
|
|
295
276
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Deploy claudecode ARCS bundle from repo to Claude Code config.
|
|
3
|
+
//
|
|
4
|
+
// Direction: repo → config ONLY. Never writes config → repo.
|
|
5
|
+
//
|
|
6
|
+
// What gets deployed:
|
|
7
|
+
// 1. Sub-agent prompts → <destination>/agents/<stem>.md
|
|
8
|
+
// 2. Skills tree → <destination>/skills/arcs-<name>/...
|
|
9
|
+
// (Claude Code skills must be flat under skills/; we use the `arcs-`
|
|
10
|
+
// prefix as a namespace so orphan pruning never touches user skills.)
|
|
11
|
+
// 3. Default agent → settings.json `agent` field set to "arcs-orchestrate"
|
|
12
|
+
//
|
|
13
|
+
// Env vars:
|
|
14
|
+
// DEPLOY_BUNDLE_ROOT — override bundle root (default: opencode/arcs)
|
|
15
|
+
// DEPLOY_CONFIG_ROOT — override config root (default: ~/.claude)
|
|
16
|
+
// DEPLOY_PROJECT_ROOT — override project root (default: repository root)
|
|
17
|
+
// DEPLOY_SCOPE — `global` or `project` (default: `global`)
|
|
18
|
+
// DEPLOY_DRY_RUN — "false" to actually write; anything else = dry-run (default: dry-run)
|
|
19
|
+
//
|
|
20
|
+
// Outputs JSON to stdout: DeployResult
|
|
21
|
+
// Exit code: 0 on success, 1 on error.
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
existsSync,
|
|
25
|
+
mkdirSync,
|
|
26
|
+
readdirSync,
|
|
27
|
+
readFileSync,
|
|
28
|
+
rmSync,
|
|
29
|
+
statSync,
|
|
30
|
+
writeFileSync,
|
|
31
|
+
} from "node:fs";
|
|
32
|
+
import { homedir } from "node:os";
|
|
33
|
+
import { dirname, relative, resolve } from "node:path";
|
|
34
|
+
|
|
35
|
+
const repoRoot = resolve(import.meta.dirname, "..");
|
|
36
|
+
const defaultBundleRoot = resolve(repoRoot, "opencode/arcs");
|
|
37
|
+
const defaultConfigRoot = resolve(homedir(), ".claude");
|
|
38
|
+
const defaultProjectRoot = repoRoot;
|
|
39
|
+
|
|
40
|
+
const bundleRoot = process.env.DEPLOY_BUNDLE_ROOT
|
|
41
|
+
? resolve(repoRoot, process.env.DEPLOY_BUNDLE_ROOT)
|
|
42
|
+
: defaultBundleRoot;
|
|
43
|
+
|
|
44
|
+
let configRoot;
|
|
45
|
+
if (process.env.DEPLOY_CONFIG_ROOT) {
|
|
46
|
+
const rawPath = process.env.DEPLOY_CONFIG_ROOT;
|
|
47
|
+
if (rawPath.startsWith("~/")) {
|
|
48
|
+
configRoot = resolve(homedir(), rawPath.slice(2));
|
|
49
|
+
} else if (rawPath === "~") {
|
|
50
|
+
configRoot = homedir();
|
|
51
|
+
} else {
|
|
52
|
+
configRoot = resolve(homedir(), rawPath);
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
configRoot = defaultConfigRoot;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const projectRoot = process.env.DEPLOY_PROJECT_ROOT
|
|
59
|
+
? resolve(repoRoot, process.env.DEPLOY_PROJECT_ROOT)
|
|
60
|
+
: defaultProjectRoot;
|
|
61
|
+
|
|
62
|
+
const scope = process.env.DEPLOY_SCOPE === "project" ? "project" : "global";
|
|
63
|
+
const dryRun = process.env.DEPLOY_DRY_RUN !== "false";
|
|
64
|
+
|
|
65
|
+
const destination = scope === "project" ? projectRoot : configRoot;
|
|
66
|
+
|
|
67
|
+
const DEFAULT_AGENT = "arcs-orchestrate";
|
|
68
|
+
const SKILL_PREFIX = "arcs-";
|
|
69
|
+
|
|
70
|
+
const agentMetadata = {
|
|
71
|
+
"software-engineer": {
|
|
72
|
+
name: "Software Engineer",
|
|
73
|
+
description: "Implementation specialist. Writes code, runs tests, and ships features.",
|
|
74
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
75
|
+
model: "inherit",
|
|
76
|
+
},
|
|
77
|
+
"devil-advocate": {
|
|
78
|
+
name: "Devil's Advocate",
|
|
79
|
+
description: "Adversarial phase-gate agent. Checks work using KISS/YAGNI/DRY principles.",
|
|
80
|
+
tools: "Read, Glob, Grep, Bash",
|
|
81
|
+
model: "inherit",
|
|
82
|
+
},
|
|
83
|
+
"tech-architect": {
|
|
84
|
+
name: "Technical Architect",
|
|
85
|
+
description:
|
|
86
|
+
"Architecture and analysis specialist. Deep structural reasoning and trade-off evaluation.",
|
|
87
|
+
tools: "Read, Glob, Grep, Bash",
|
|
88
|
+
model: "inherit",
|
|
89
|
+
},
|
|
90
|
+
"code-reviewer": {
|
|
91
|
+
name: "Code Reviewer",
|
|
92
|
+
description: "Reviews code changes for correctness, maintainability, and testing issues.",
|
|
93
|
+
tools: "Read, Glob, Grep, Bash",
|
|
94
|
+
model: "inherit",
|
|
95
|
+
},
|
|
96
|
+
"qa-analyst": {
|
|
97
|
+
name: "QA Analyst",
|
|
98
|
+
description: "Quality enforcement specialist. Proactive code audits and convention compliance.",
|
|
99
|
+
tools: "Read, Glob, Grep, Bash",
|
|
100
|
+
model: "inherit",
|
|
101
|
+
},
|
|
102
|
+
"system-architect": {
|
|
103
|
+
name: "System Architect",
|
|
104
|
+
description:
|
|
105
|
+
"Architecture and design specialist. Module boundaries, dependency graphs, and design decisions.",
|
|
106
|
+
tools: "Read, Glob, Grep, Bash",
|
|
107
|
+
model: "inherit",
|
|
108
|
+
},
|
|
109
|
+
"arcs-docs": {
|
|
110
|
+
name: "ARCS Docs Specialist",
|
|
111
|
+
description:
|
|
112
|
+
"Documentation specialist. Manages plans, knowledge entries, diagrams, and DAG health.",
|
|
113
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
114
|
+
model: "inherit",
|
|
115
|
+
},
|
|
116
|
+
"docs-researcher": {
|
|
117
|
+
name: "Docs Researcher",
|
|
118
|
+
description: "Handles documentation writing, research synthesis, and document-heavy analysis.",
|
|
119
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
120
|
+
model: "inherit",
|
|
121
|
+
},
|
|
122
|
+
"oncall-ops": {
|
|
123
|
+
name: "On-Call Ops",
|
|
124
|
+
description:
|
|
125
|
+
"Debugging and diagnosis specialist. Finds root causes through systematic investigation.",
|
|
126
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
127
|
+
model: "inherit",
|
|
128
|
+
},
|
|
129
|
+
"arcs-orchestrate": {
|
|
130
|
+
name: "ARCS Orchestrator",
|
|
131
|
+
description:
|
|
132
|
+
"The central coordinator for executing plans, managing agent dispatch, and handling DAG workflows.",
|
|
133
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
134
|
+
model: "inherit",
|
|
135
|
+
},
|
|
136
|
+
"arcs-orchestrate-caveman": {
|
|
137
|
+
name: "ARCS Orchestrator (Caveman)",
|
|
138
|
+
description:
|
|
139
|
+
"A terse, high-efficiency orchestrator that drives tasks without extra commentary.",
|
|
140
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
141
|
+
model: "inherit",
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
function ensureParentDir(filePath) {
|
|
146
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function configRelativePath(suffix) {
|
|
150
|
+
return scope === "project" ? `.claude/${suffix}` : suffix;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function walkFiles(dir) {
|
|
154
|
+
const out = [];
|
|
155
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
156
|
+
const full = resolve(dir, entry.name);
|
|
157
|
+
if (entry.isDirectory()) {
|
|
158
|
+
out.push(...walkFiles(full));
|
|
159
|
+
} else if (entry.isFile()) {
|
|
160
|
+
out.push(full);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// 1. Compile sub-agent prompts
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
function buildAgentSources() {
|
|
171
|
+
const promptsDir = resolve(bundleRoot, "prompts");
|
|
172
|
+
if (!existsSync(promptsDir)) {
|
|
173
|
+
throw new Error(`Prompts directory not found at ${promptsDir}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const promptFiles = readdirSync(promptsDir).filter((f) => f.endsWith(".txt"));
|
|
177
|
+
const sources = [];
|
|
178
|
+
|
|
179
|
+
for (const file of promptFiles) {
|
|
180
|
+
const stem = file.slice(0, -4);
|
|
181
|
+
const sourcePath = resolve(promptsDir, file);
|
|
182
|
+
const promptContent = readFileSync(sourcePath, "utf-8");
|
|
183
|
+
|
|
184
|
+
const meta = agentMetadata[stem] || {
|
|
185
|
+
name: stem
|
|
186
|
+
.split("-")
|
|
187
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
188
|
+
.join(" "),
|
|
189
|
+
description: `ARCS ${stem} agent.`,
|
|
190
|
+
tools: "Read, Write, Edit, Glob, Grep, Bash",
|
|
191
|
+
model: "inherit",
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const toolsArray = meta.tools.split(",").map((t) => t.trim());
|
|
195
|
+
const toolsYaml = `[${toolsArray.map((t) => `"${t}"`).join(", ")}]`;
|
|
196
|
+
|
|
197
|
+
const compiledContent = [
|
|
198
|
+
"---",
|
|
199
|
+
`name: ${meta.name}`,
|
|
200
|
+
`description: ${meta.description}`,
|
|
201
|
+
`model: ${meta.model}`,
|
|
202
|
+
`tools: ${toolsYaml}`,
|
|
203
|
+
"---",
|
|
204
|
+
"",
|
|
205
|
+
promptContent,
|
|
206
|
+
].join("\n");
|
|
207
|
+
|
|
208
|
+
sources.push({
|
|
209
|
+
stem,
|
|
210
|
+
compiledContent,
|
|
211
|
+
configRelative: configRelativePath(`agents/${stem}.md`),
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return sources;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// 2. Walk skills tree
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
function buildSkillSources() {
|
|
223
|
+
const skillsDir = resolve(bundleRoot, "skills");
|
|
224
|
+
if (!existsSync(skillsDir)) return { skillNames: [], files: [] };
|
|
225
|
+
|
|
226
|
+
const skillNames = readdirSync(skillsDir, { withFileTypes: true })
|
|
227
|
+
.filter((e) => e.isDirectory())
|
|
228
|
+
.map((e) => e.name);
|
|
229
|
+
|
|
230
|
+
const files = [];
|
|
231
|
+
for (const skillName of skillNames) {
|
|
232
|
+
const skillRoot = resolve(skillsDir, skillName);
|
|
233
|
+
for (const absPath of walkFiles(skillRoot)) {
|
|
234
|
+
const rel = relative(skillRoot, absPath).split(/[\\/]/).join("/");
|
|
235
|
+
files.push({
|
|
236
|
+
skillName,
|
|
237
|
+
absSource: absPath,
|
|
238
|
+
configRelative: configRelativePath(`skills/${SKILL_PREFIX}${skillName}/${rel}`),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { skillNames, files };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// 3. settings.json merge — set default agent
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
|
|
250
|
+
function planSettingsUpdate() {
|
|
251
|
+
const settingsConfigRelative = configRelativePath("settings.json");
|
|
252
|
+
const settingsAbsolute = resolve(destination, settingsConfigRelative);
|
|
253
|
+
|
|
254
|
+
let existing = null;
|
|
255
|
+
let parsed = {};
|
|
256
|
+
if (existsSync(settingsAbsolute)) {
|
|
257
|
+
existing = readFileSync(settingsAbsolute, "utf-8");
|
|
258
|
+
try {
|
|
259
|
+
parsed = JSON.parse(existing);
|
|
260
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
261
|
+
parsed = {};
|
|
262
|
+
}
|
|
263
|
+
} catch {
|
|
264
|
+
// Malformed JSON — preserve as-is by skipping the merge.
|
|
265
|
+
return { settingsConfigRelative, settingsAbsolute, status: "skipped-malformed" };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const merged = { ...parsed, agent: DEFAULT_AGENT };
|
|
270
|
+
const serialized = `${JSON.stringify(merged, null, 2)}\n`;
|
|
271
|
+
|
|
272
|
+
let status;
|
|
273
|
+
if (existing === null) {
|
|
274
|
+
status = "added";
|
|
275
|
+
} else if (existing === serialized) {
|
|
276
|
+
status = "unchanged";
|
|
277
|
+
} else {
|
|
278
|
+
status = "changed";
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return { settingsConfigRelative, settingsAbsolute, status, serialized };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
// Main
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
function main() {
|
|
289
|
+
const agentSources = buildAgentSources();
|
|
290
|
+
const skillSources = buildSkillSources();
|
|
291
|
+
const settingsPlan = planSettingsUpdate();
|
|
292
|
+
|
|
293
|
+
// Pass 1: Classify add/change/unchanged for every planned write
|
|
294
|
+
const filesAdded = [];
|
|
295
|
+
const filesChanged = [];
|
|
296
|
+
const filesUnchanged = [];
|
|
297
|
+
|
|
298
|
+
for (const { compiledContent, configRelative } of agentSources) {
|
|
299
|
+
const abs = resolve(destination, configRelative);
|
|
300
|
+
if (!existsSync(abs)) {
|
|
301
|
+
filesAdded.push(configRelative);
|
|
302
|
+
} else if (readFileSync(abs, "utf-8") !== compiledContent) {
|
|
303
|
+
filesChanged.push(configRelative);
|
|
304
|
+
} else {
|
|
305
|
+
filesUnchanged.push(configRelative);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
for (const { absSource, configRelative } of skillSources.files) {
|
|
310
|
+
const abs = resolve(destination, configRelative);
|
|
311
|
+
const sourceContent = readFileSync(absSource);
|
|
312
|
+
if (!existsSync(abs)) {
|
|
313
|
+
filesAdded.push(configRelative);
|
|
314
|
+
} else {
|
|
315
|
+
const existing = readFileSync(abs);
|
|
316
|
+
if (Buffer.compare(existing, sourceContent) !== 0) {
|
|
317
|
+
filesChanged.push(configRelative);
|
|
318
|
+
} else {
|
|
319
|
+
filesUnchanged.push(configRelative);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (settingsPlan.status === "added") {
|
|
325
|
+
filesAdded.push(settingsPlan.settingsConfigRelative);
|
|
326
|
+
} else if (settingsPlan.status === "changed") {
|
|
327
|
+
filesChanged.push(settingsPlan.settingsConfigRelative);
|
|
328
|
+
} else if (settingsPlan.status === "unchanged") {
|
|
329
|
+
filesUnchanged.push(settingsPlan.settingsConfigRelative);
|
|
330
|
+
}
|
|
331
|
+
// status "skipped-malformed" intentionally omitted from all lists
|
|
332
|
+
|
|
333
|
+
// Orphans
|
|
334
|
+
const filesRemoved = [];
|
|
335
|
+
|
|
336
|
+
// Agent orphans — only `.md` files whose stem we recognize from agentMetadata
|
|
337
|
+
const agentsTargetDir = resolve(destination, configRelativePath("agents"));
|
|
338
|
+
const activeAgentStems = new Set(agentSources.map((f) => f.stem));
|
|
339
|
+
if (existsSync(agentsTargetDir)) {
|
|
340
|
+
for (const entry of readdirSync(agentsTargetDir, { withFileTypes: true })) {
|
|
341
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
342
|
+
const stem = entry.name.slice(0, -3);
|
|
343
|
+
if (agentMetadata[stem] && !activeAgentStems.has(stem)) {
|
|
344
|
+
filesRemoved.push(configRelativePath(`agents/${entry.name}`));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Skill orphans — only `arcs-*/` directories that aren't in current source.
|
|
351
|
+
// The prefix gives us a safe namespace; foreign user skills are never touched.
|
|
352
|
+
const skillsTargetDir = resolve(destination, configRelativePath("skills"));
|
|
353
|
+
const activeSkillDirs = new Set(skillSources.skillNames.map((n) => `${SKILL_PREFIX}${n}`));
|
|
354
|
+
const orphanSkillDirs = [];
|
|
355
|
+
if (existsSync(skillsTargetDir)) {
|
|
356
|
+
for (const entry of readdirSync(skillsTargetDir, { withFileTypes: true })) {
|
|
357
|
+
if (entry.isDirectory() && entry.name.startsWith(SKILL_PREFIX)) {
|
|
358
|
+
if (!activeSkillDirs.has(entry.name)) {
|
|
359
|
+
orphanSkillDirs.push(entry.name);
|
|
360
|
+
filesRemoved.push(configRelativePath(`skills/${entry.name}`));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Pass 2: Write if not dry-run
|
|
367
|
+
if (!dryRun) {
|
|
368
|
+
for (const { compiledContent, configRelative } of agentSources) {
|
|
369
|
+
const abs = resolve(destination, configRelative);
|
|
370
|
+
ensureParentDir(abs);
|
|
371
|
+
writeFileSync(abs, compiledContent, "utf-8");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
for (const { absSource, configRelative } of skillSources.files) {
|
|
375
|
+
const abs = resolve(destination, configRelative);
|
|
376
|
+
ensureParentDir(abs);
|
|
377
|
+
writeFileSync(abs, readFileSync(absSource));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (settingsPlan.serialized) {
|
|
381
|
+
ensureParentDir(settingsPlan.settingsAbsolute);
|
|
382
|
+
writeFileSync(settingsPlan.settingsAbsolute, settingsPlan.serialized, "utf-8");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (const fileToRemove of filesRemoved) {
|
|
386
|
+
const abs = resolve(destination, fileToRemove);
|
|
387
|
+
if (existsSync(abs)) {
|
|
388
|
+
// Could be a file (agent orphan) or directory (skill orphan)
|
|
389
|
+
const isDir = statSync(abs).isDirectory();
|
|
390
|
+
rmSync(abs, { recursive: isDir, force: true });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const result = {
|
|
396
|
+
dryRun,
|
|
397
|
+
source: bundleRoot,
|
|
398
|
+
destination,
|
|
399
|
+
filesAdded,
|
|
400
|
+
filesChanged,
|
|
401
|
+
filesRemoved,
|
|
402
|
+
filesUnchanged,
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
main();
|
|
410
|
+
} catch (error) {
|
|
411
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
412
|
+
process.stderr.write(`${message}\n`);
|
|
413
|
+
process.exitCode = 1;
|
|
414
|
+
}
|