@oisincoveney/pipeline 2.1.0 → 2.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/defaults/pipeline.yaml +111 -0
- package/defaults/profiles.yaml +212 -0
- package/defaults/runners.yaml +24 -0
- package/dist/argo-graph.js +59 -27
- package/dist/argo-submit.js +28 -4
- package/dist/claude-settings-config.js +44 -0
- package/dist/cli/program.js +1 -1
- package/dist/config/defaults.js +7 -353
- package/dist/git-remote-url.js +30 -0
- package/dist/hooks.d.ts +1 -1
- package/dist/install-commands/claude-code.js +153 -17
- package/dist/install-commands/opencode.js +37 -33
- package/dist/install-commands/shared.js +27 -6
- package/dist/install-commands.js +26 -22
- package/dist/json-config-merge.js +47 -0
- package/dist/mcp/gateway.js +9 -1
- package/dist/moka-submit.d.ts +6 -6
- package/dist/moka-submit.js +4 -3
- package/dist/opencode-project-config.js +2 -45
- package/dist/pipeline-runtime.js +50 -8
- package/dist/runner-event-schema.d.ts +349 -0
- package/dist/runner-event-schema.js +185 -0
- package/dist/runner-output.js +2 -2
- package/dist/runner.d.ts +2 -0
- package/dist/runtime/agent-node/agent-node.js +1 -0
- package/dist/runtime/contracts/contracts.d.ts +2 -0
- package/dist/runtime/node-state-store.js +7 -0
- package/dist/runtime/opencode-adapter.js +28 -8
- package/dist/runtime/opencode-agent-name.js +18 -0
- package/dist/runtime/opencode-runtime.js +62 -0
- package/dist/runtime/opencode-server.js +67 -0
- package/dist/runtime/opencode-session-executor.js +206 -0
- package/docs/adr-opencode-first-goal-loop-runtime.md +1 -1
- package/docs/config-architecture.md +11 -6
- package/docs/mcp-gateway.md +4 -4
- package/docs/operator-guide.md +7 -5
- package/docs/slash-command-adapter-contract.md +1 -0
- package/package.json +6 -1
- package/.agents/skills/claude-code-opencode-execute/SKILL.md +0 -116
package/dist/config/defaults.js
CHANGED
|
@@ -7,359 +7,13 @@ const PIPELINE_CONFIG_PATH = ".pipeline/pipeline.yaml";
|
|
|
7
7
|
const RUNNERS_CONFIG_PATH = ".pipeline/runners.yaml";
|
|
8
8
|
const PROFILES_CONFIG_PATH = ".pipeline/profiles.yaml";
|
|
9
9
|
const OPENCODE_ECOSYSTEM_MANIFEST_PATH = "defaults/opencode-ecosystem.yaml";
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
skills: true
|
|
18
|
-
mcp_servers: true
|
|
19
|
-
tools: [read, list, grep, glob, bash, edit, write]
|
|
20
|
-
filesystem: [read-only, workspace-write]
|
|
21
|
-
network: [inherit, disabled]
|
|
22
|
-
output_formats: [text, json, jsonl, json_schema]
|
|
23
|
-
command:
|
|
24
|
-
type: command
|
|
25
|
-
capabilities:
|
|
26
|
-
native_subagents: false
|
|
27
|
-
rules: false
|
|
28
|
-
skills: false
|
|
29
|
-
mcp_servers: false
|
|
30
|
-
tools: [bash]
|
|
31
|
-
filesystem: [read-only, workspace-write]
|
|
32
|
-
network: [inherit, disabled]
|
|
33
|
-
output_formats: [text, json]
|
|
34
|
-
`;
|
|
35
|
-
const PACKAGE_DEFAULT_PROFILES_YAML = `version: 1
|
|
36
|
-
mcp_gateway:
|
|
37
|
-
provider: toolhive
|
|
38
|
-
mode: local
|
|
39
|
-
url: https://pipeline-mcp.momokaya.ee/mcp/
|
|
40
|
-
url_env: PIPELINE_MCP_GATEWAY_URL
|
|
41
|
-
authorization_env: PIPELINE_MCP_GATEWAY_AUTHORIZATION
|
|
42
|
-
default_profile: default
|
|
43
|
-
backends:
|
|
44
|
-
context7:
|
|
45
|
-
locality: shared-remote
|
|
46
|
-
tool_prefixes: [context7]
|
|
47
|
-
uidotsh:
|
|
48
|
-
locality: shared-remote
|
|
49
|
-
tool_prefixes: [uidotsh]
|
|
50
|
-
qdrant:
|
|
51
|
-
locality: repo-scoped-remote
|
|
52
|
-
tool_prefixes: [qdrant]
|
|
53
|
-
fallow:
|
|
54
|
-
locality: repo-local
|
|
55
|
-
workspace_path_source: PIPELINE_TARGET_PATH
|
|
56
|
-
required: false
|
|
57
|
-
tool_prefixes: [fallow]
|
|
58
|
-
serena:
|
|
59
|
-
locality: repo-local
|
|
60
|
-
workspace_path_source: PIPELINE_TARGET_PATH
|
|
61
|
-
tool_prefixes: [serena]
|
|
62
|
-
backlog:
|
|
63
|
-
locality: repo-local
|
|
64
|
-
workspace_path_source: PIPELINE_TARGET_PATH
|
|
65
|
-
tool_prefixes: [backlog]
|
|
66
|
-
skills:
|
|
67
|
-
execute:
|
|
68
|
-
path: .agents/skills/execute/SKILL.md
|
|
69
|
-
source_root: package
|
|
70
|
-
inspect:
|
|
71
|
-
path: .agents/skills/inspect/SKILL.md
|
|
72
|
-
source_root: package
|
|
73
|
-
quick:
|
|
74
|
-
path: .agents/skills/quick/SKILL.md
|
|
75
|
-
source_root: package
|
|
76
|
-
claude-code-opencode-execute:
|
|
77
|
-
path: .agents/skills/claude-code-opencode-execute/SKILL.md
|
|
78
|
-
source_root: package
|
|
79
|
-
critique:
|
|
80
|
-
path: .agents/skills/critique/SKILL.md
|
|
81
|
-
source_root: package
|
|
82
|
-
doubt:
|
|
83
|
-
path: .agents/skills/doubt/SKILL.md
|
|
84
|
-
source_root: package
|
|
85
|
-
fix:
|
|
86
|
-
path: .agents/skills/fix/SKILL.md
|
|
87
|
-
source_root: package
|
|
88
|
-
library-first-development:
|
|
89
|
-
path: .agents/skills/library-first-development/SKILL.md
|
|
90
|
-
source_root: package
|
|
91
|
-
migrate:
|
|
92
|
-
path: .agents/skills/migrate/SKILL.md
|
|
93
|
-
source_root: package
|
|
94
|
-
optimize:
|
|
95
|
-
path: .agents/skills/optimize/SKILL.md
|
|
96
|
-
source_root: package
|
|
97
|
-
research:
|
|
98
|
-
path: .agents/skills/research/SKILL.md
|
|
99
|
-
source_root: package
|
|
100
|
-
schedule-graph-shaping:
|
|
101
|
-
path: .agents/skills/schedule-graph-shaping/SKILL.md
|
|
102
|
-
source_root: package
|
|
103
|
-
scope:
|
|
104
|
-
path: .agents/skills/scope/SKILL.md
|
|
105
|
-
source_root: package
|
|
106
|
-
secure:
|
|
107
|
-
path: .agents/skills/secure/SKILL.md
|
|
108
|
-
source_root: package
|
|
109
|
-
spec:
|
|
110
|
-
path: .agents/skills/spec/SKILL.md
|
|
111
|
-
source_root: package
|
|
112
|
-
test:
|
|
113
|
-
path: .agents/skills/test/SKILL.md
|
|
114
|
-
source_root: package
|
|
115
|
-
trace:
|
|
116
|
-
path: .agents/skills/trace/SKILL.md
|
|
117
|
-
source_root: package
|
|
118
|
-
verify:
|
|
119
|
-
path: .agents/skills/verify/SKILL.md
|
|
120
|
-
source_root: package
|
|
121
|
-
profiles:
|
|
122
|
-
moka-orchestrator:
|
|
123
|
-
runner: opencode
|
|
124
|
-
description: Orchestrate the configured pipeline and enforce gates.
|
|
125
|
-
instructions: { inline: "Orchestrate the configured pipeline through package-defined entrypoints, native agents, and gates. Do not bypass configured runner subprocesses or package-configured gates." }
|
|
126
|
-
skills: [execute, quick, inspect]
|
|
127
|
-
mcp_servers: [pipeline-gateway]
|
|
128
|
-
tools: [read, list, grep, glob, bash]
|
|
129
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
130
|
-
network: { mode: inherit }
|
|
131
|
-
moka-researcher:
|
|
132
|
-
runner: opencode
|
|
133
|
-
description: Research the requested task and produce structured findings.
|
|
134
|
-
instructions: { inline: "Inspect first-party source, tests, docs, and task context for the current task only. Produce concise findings with file references and stop; do not perform open-ended repository exploration." }
|
|
135
|
-
timeout_ms: 900000
|
|
136
|
-
skills: [research, spec, scope]
|
|
137
|
-
mcp_servers: [pipeline-gateway]
|
|
138
|
-
tools: [read, list, grep, glob, bash]
|
|
139
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
140
|
-
network: { mode: inherit }
|
|
141
|
-
output:
|
|
142
|
-
format: json_schema
|
|
143
|
-
schema_path: .pipeline/schemas/research.schema.json
|
|
144
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
145
|
-
moka-inspector:
|
|
146
|
-
runner: opencode
|
|
147
|
-
model: openai/gpt-5.5-low
|
|
148
|
-
description: Inspect the repository without modifying files.
|
|
149
|
-
instructions: { inline: "Inspect the repository without modifying files." }
|
|
150
|
-
skills: [research]
|
|
151
|
-
mcp_servers: [pipeline-gateway]
|
|
152
|
-
tools: [read, list, grep, glob, bash]
|
|
153
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
154
|
-
network: { mode: inherit }
|
|
155
|
-
moka-schedule-planner:
|
|
156
|
-
runner: opencode
|
|
157
|
-
model: openai/gpt-5.5-xhigh
|
|
158
|
-
description: Refine a baseline schedule into a specialized approved-plan artifact.
|
|
159
|
-
instructions: { inline: "Generate exactly one workflow named root as an explicit schedule graph. Return YAML only." }
|
|
160
|
-
timeout_ms: 300000
|
|
161
|
-
skills: [schedule-graph-shaping]
|
|
162
|
-
mcp_servers: [pipeline-gateway]
|
|
163
|
-
tools: [read, list, grep, glob, bash]
|
|
164
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
165
|
-
network: { mode: inherit }
|
|
166
|
-
moka-test-writer:
|
|
167
|
-
runner: opencode
|
|
168
|
-
scheduling_roles: [implementation]
|
|
169
|
-
description: Add focused failing tests for the requested behavior.
|
|
170
|
-
instructions: { inline: "Add focused failing tests for the requested behavior only. Do not change production code. Only edit files matching test paths such as **/*.test.*, **/*.spec.*, **/*_test.*, **/__tests__/**, test/**, or tests/**. Return only valid JSON with top-level changes and verification. Every changes entry must include summary, why, and files. Include risks, followups, and lessons when present. Do not use Markdown fences or prose outside the JSON object." }
|
|
171
|
-
skills: [test]
|
|
172
|
-
mcp_servers: [pipeline-gateway]
|
|
173
|
-
tools: [read, list, grep, glob, bash, edit, write]
|
|
174
|
-
filesystem: { mode: workspace-write, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
175
|
-
network: { mode: inherit }
|
|
176
|
-
output:
|
|
177
|
-
format: json_schema
|
|
178
|
-
schema_path: .pipeline/schemas/implementation.schema.json
|
|
179
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
180
|
-
moka-code-writer:
|
|
181
|
-
runner: opencode
|
|
182
|
-
scheduling_roles: [implementation]
|
|
183
|
-
description: Implement production code until the failing tests pass.
|
|
184
|
-
instructions: { inline: "Implement the smallest production change that satisfies the failing tests. Return only valid JSON with top-level changes and verification. Every changes entry must include summary, why, and files. Include risks, followups, and lessons when present. Do not use Markdown fences or prose outside the JSON object." }
|
|
185
|
-
skills: [trace, test, fix, library-first-development]
|
|
186
|
-
mcp_servers: [pipeline-gateway]
|
|
187
|
-
tools: [read, list, grep, glob, bash, edit, write]
|
|
188
|
-
filesystem: { mode: workspace-write, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
189
|
-
network: { mode: inherit }
|
|
190
|
-
output:
|
|
191
|
-
format: json_schema
|
|
192
|
-
schema_path: .pipeline/schemas/implementation.schema.json
|
|
193
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
194
|
-
moka-acceptance-reviewer:
|
|
195
|
-
runner: opencode
|
|
196
|
-
scheduling_roles: [coverage]
|
|
197
|
-
description: Audit the finished change against every acceptance criterion.
|
|
198
|
-
instructions: { inline: 'Audit the completed change against each canonical acceptance criterion independently. Return only valid JSON with top-level "verdict", "evidence", "acceptance", and optional "violations". Each "acceptance" entry must include "id", "verdict", and non-empty "evidence". Do not use Markdown fences or prose outside the JSON object.' }
|
|
199
|
-
skills: [critique, doubt]
|
|
200
|
-
mcp_servers: [pipeline-gateway]
|
|
201
|
-
tools: [read, list, grep, glob, bash]
|
|
202
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
203
|
-
network: { mode: inherit }
|
|
204
|
-
output:
|
|
205
|
-
format: json_schema
|
|
206
|
-
schema_path: .pipeline/schemas/acceptance.schema.json
|
|
207
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
208
|
-
moka-thermo-nuclear-reviewer:
|
|
209
|
-
runner: opencode
|
|
210
|
-
scheduling_roles: [coverage]
|
|
211
|
-
description: Perform the final thermo-nuclear code quality review of the integration branch.
|
|
212
|
-
instructions: { inline: "Perform the final code quality review of the integration branch." }
|
|
213
|
-
skills: [critique]
|
|
214
|
-
mcp_servers: [pipeline-gateway]
|
|
215
|
-
tools: [read, list, grep, glob, bash]
|
|
216
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
217
|
-
network: { mode: inherit }
|
|
218
|
-
output:
|
|
219
|
-
format: json_schema
|
|
220
|
-
schema_path: .pipeline/schemas/review.schema.json
|
|
221
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
222
|
-
moka-verifier:
|
|
223
|
-
runner: opencode
|
|
224
|
-
scheduling_roles: [coverage]
|
|
225
|
-
description: Verify checks, implementation fit, and final evidence.
|
|
226
|
-
instructions: { inline: 'Verify checks, implementation fit, and final evidence. Return only valid JSON with top-level "verdict", "evidence", and optional "violations". Do not use Markdown fences or prose outside the JSON object.' }
|
|
227
|
-
skills: [verify, critique, secure, optimize]
|
|
228
|
-
mcp_servers: [pipeline-gateway]
|
|
229
|
-
tools: [read, list, grep, glob, bash]
|
|
230
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
231
|
-
network: { mode: inherit }
|
|
232
|
-
output:
|
|
233
|
-
format: json_schema
|
|
234
|
-
schema_path: .pipeline/schemas/verify.schema.json
|
|
235
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
236
|
-
moka-learner:
|
|
237
|
-
runner: opencode
|
|
238
|
-
model: openai/gpt-5.5-low
|
|
239
|
-
description: Store durable lessons from the completed run.
|
|
240
|
-
instructions: { inline: "Store durable lessons from the completed run when useful." }
|
|
241
|
-
skills: [migrate]
|
|
242
|
-
mcp_servers: [pipeline-gateway]
|
|
243
|
-
tools: [read, list, grep, glob, bash]
|
|
244
|
-
filesystem: { mode: read-only, allow: ["**/*"], deny: ["node_modules/**", "dist/**", ".git/**"] }
|
|
245
|
-
network: { mode: inherit }
|
|
246
|
-
output:
|
|
247
|
-
format: json_schema
|
|
248
|
-
schema_path: .pipeline/schemas/learn.schema.json
|
|
249
|
-
repair: { enabled: true, max_attempts: 1 }
|
|
250
|
-
`;
|
|
251
|
-
const PACKAGE_DEFAULT_PIPELINE_YAML = `version: 1
|
|
252
|
-
default_workflow: inspect
|
|
253
|
-
orchestrator:
|
|
254
|
-
profile: moka-orchestrator
|
|
255
|
-
entrypoints:
|
|
256
|
-
quick:
|
|
257
|
-
schedule: quick-schedule
|
|
258
|
-
description: Compact planner-generated pipeline for small work
|
|
259
|
-
execute:
|
|
260
|
-
schedule: execute-schedule
|
|
261
|
-
description: Full planner-generated pipeline for repository work
|
|
262
|
-
inspect:
|
|
263
|
-
workflow: inspect
|
|
264
|
-
description: Read-only repository inspection
|
|
265
|
-
hooks:
|
|
266
|
-
functions:
|
|
267
|
-
generated-defaults-audit:
|
|
268
|
-
kind: command
|
|
269
|
-
command: [node, -e, "const fs=require('node:fs'); fs.writeFileSync(process.env.PIPELINE_HOOK_RESULT, JSON.stringify({status:'pass',summary:'Generated defaults audit passed'}));"]
|
|
270
|
-
trusted: true
|
|
271
|
-
timeout_ms: 5000
|
|
272
|
-
output_limit_bytes: 4096
|
|
273
|
-
on:
|
|
274
|
-
workflow.start:
|
|
275
|
-
- id: generated-defaults-audit
|
|
276
|
-
function: generated-defaults-audit
|
|
277
|
-
failure: fail
|
|
278
|
-
runner_command:
|
|
279
|
-
environment:
|
|
280
|
-
setup:
|
|
281
|
-
- command: bun
|
|
282
|
-
args: [install, --frozen-lockfile]
|
|
283
|
-
scheduler:
|
|
284
|
-
commands:
|
|
285
|
-
quick:
|
|
286
|
-
schedule: quick-schedule
|
|
287
|
-
catalog: quick
|
|
288
|
-
execute:
|
|
289
|
-
schedule: execute-schedule
|
|
290
|
-
catalog: execute
|
|
291
|
-
node_catalogs:
|
|
292
|
-
quick:
|
|
293
|
-
required_categories: [intake, red, green, mechanical, verification]
|
|
294
|
-
nodes:
|
|
295
|
-
backlog-intake:
|
|
296
|
-
category: intake
|
|
297
|
-
profile: moka-researcher
|
|
298
|
-
models: [openai/gpt-5.5-medium]
|
|
299
|
-
red-tests:
|
|
300
|
-
category: red
|
|
301
|
-
profile: moka-test-writer
|
|
302
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/kimi-k2-thinking]
|
|
303
|
-
green-implementation:
|
|
304
|
-
category: green
|
|
305
|
-
profile: moka-code-writer
|
|
306
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
|
|
307
|
-
verification:
|
|
308
|
-
category: verification
|
|
309
|
-
profile: moka-verifier
|
|
310
|
-
models: [openai/gpt-5.5-medium]
|
|
311
|
-
execute:
|
|
312
|
-
required_categories: [intake, research, red, green, mechanical, acceptance, verification, learn]
|
|
313
|
-
nodes:
|
|
314
|
-
backlog-intake:
|
|
315
|
-
category: intake
|
|
316
|
-
profile: moka-researcher
|
|
317
|
-
models: [openai/gpt-5.5-medium]
|
|
318
|
-
research:
|
|
319
|
-
category: research
|
|
320
|
-
profile: moka-researcher
|
|
321
|
-
models: [openai/gpt-5.5-medium, kimi-for-coding/k2p6]
|
|
322
|
-
red-tests:
|
|
323
|
-
category: red
|
|
324
|
-
profile: moka-test-writer
|
|
325
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/kimi-k2-thinking]
|
|
326
|
-
green-backend:
|
|
327
|
-
category: green
|
|
328
|
-
profile: moka-code-writer
|
|
329
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
|
|
330
|
-
green-frontend:
|
|
331
|
-
category: green
|
|
332
|
-
profile: moka-code-writer
|
|
333
|
-
models: [openai/gpt-5.5-high, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
|
|
334
|
-
acceptance-review:
|
|
335
|
-
category: acceptance
|
|
336
|
-
profile: moka-acceptance-reviewer
|
|
337
|
-
models: [openai/gpt-5.5-medium]
|
|
338
|
-
verification:
|
|
339
|
-
category: verification
|
|
340
|
-
profile: moka-verifier
|
|
341
|
-
models: [openai/gpt-5.5-medium]
|
|
342
|
-
learn:
|
|
343
|
-
category: learn
|
|
344
|
-
profile: moka-learner
|
|
345
|
-
models: [openai/gpt-5.5-low]
|
|
346
|
-
schedules:
|
|
347
|
-
quick-schedule:
|
|
348
|
-
baseline: quick
|
|
349
|
-
planner_profile: moka-schedule-planner
|
|
350
|
-
node_catalog: quick
|
|
351
|
-
execute-schedule:
|
|
352
|
-
baseline: execute
|
|
353
|
-
planner_profile: moka-schedule-planner
|
|
354
|
-
node_catalog: execute
|
|
355
|
-
workflows:
|
|
356
|
-
inspect:
|
|
357
|
-
description: Read-only repository inspection workflow.
|
|
358
|
-
nodes:
|
|
359
|
-
- id: inspect
|
|
360
|
-
kind: agent
|
|
361
|
-
profile: moka-inspector
|
|
362
|
-
`;
|
|
10
|
+
const DEFAULT_PACKAGE_DEFAULTS_ROOT = new URL("../../defaults/", import.meta.url);
|
|
11
|
+
function loadDefaultYaml(filename) {
|
|
12
|
+
return readFileSync(new URL(filename, DEFAULT_PACKAGE_DEFAULTS_ROOT), "utf8");
|
|
13
|
+
}
|
|
14
|
+
const PACKAGE_DEFAULT_RUNNERS_YAML = loadDefaultYaml("runners.yaml");
|
|
15
|
+
const PACKAGE_DEFAULT_PROFILES_YAML = loadDefaultYaml("profiles.yaml");
|
|
16
|
+
const PACKAGE_DEFAULT_PIPELINE_YAML = loadDefaultYaml("pipeline.yaml");
|
|
363
17
|
const DEFAULT_OPENCODE_ECOSYSTEM_MANIFEST_URL = new URL(`../../${OPENCODE_ECOSYSTEM_MANIFEST_PATH}`, import.meta.url);
|
|
364
18
|
const ecosystemStringArraySchema = z.array(z.string().min(1));
|
|
365
19
|
const ecosystemRuntimeSchema = z.object({
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import parseGitUrl from "git-url-parse";
|
|
2
|
+
//#region src/git-remote-url.ts
|
|
3
|
+
const GITHUB_SOURCE = "github.com";
|
|
4
|
+
function normalizeRunnerRepositoryForSubmit(repository) {
|
|
5
|
+
const url = normalizeRepositoryUrlForSubmit(repository.url);
|
|
6
|
+
if (url === repository.url) return repository;
|
|
7
|
+
return {
|
|
8
|
+
...repository,
|
|
9
|
+
url
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function normalizeRepositoryUrlForSubmit(remoteUrl) {
|
|
13
|
+
const parsed = parseGitUrl(remoteUrl);
|
|
14
|
+
if (!isSshRemote(parsed)) return remoteUrl;
|
|
15
|
+
if (parsed.source !== GITHUB_SOURCE) throw new Error(`SSH git remote ${remoteUrl} is not supported for moka submit; use an HTTPS GitHub remote`);
|
|
16
|
+
return `https://${GITHUB_SOURCE}/${gitHubRepositoryPath(parsed, remoteUrl)}`;
|
|
17
|
+
}
|
|
18
|
+
function gitHubRepositoryPath(parsed, remoteUrl) {
|
|
19
|
+
return `${requiredGitHubPathSegment(parsed.owner, remoteUrl)}/${requiredGitHubPathSegment(parsed.name, remoteUrl)}.git`;
|
|
20
|
+
}
|
|
21
|
+
function requiredGitHubPathSegment(value, remoteUrl) {
|
|
22
|
+
const segment = value.trim();
|
|
23
|
+
if (segment.length > 0) return segment;
|
|
24
|
+
throw new Error(`GitHub SSH git remote ${remoteUrl} must include an owner and repository name`);
|
|
25
|
+
}
|
|
26
|
+
function isSshRemote(parsed) {
|
|
27
|
+
return parsed.protocols.includes("ssh");
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { normalizeRunnerRepositoryForSubmit };
|
package/dist/hooks.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ declare const hookResultSchema: z.ZodObject<{
|
|
|
13
13
|
taskContext: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
14
14
|
}, z.core.$strict>>;
|
|
15
15
|
status: z.ZodEnum<{
|
|
16
|
-
pass: "pass";
|
|
17
16
|
fail: "fail";
|
|
17
|
+
pass: "pass";
|
|
18
18
|
skip: "skip";
|
|
19
19
|
}>;
|
|
20
20
|
summary: z.ZodOptional<z.ZodString>;
|
|
@@ -1,24 +1,160 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { renderClaudeGatewayMcpServers } from "../mcp/gateway.js";
|
|
2
|
+
import { opencodeAgentName } from "../runtime/opencode-agent-name.js";
|
|
3
|
+
import { mergeClaudeSettings } from "../claude-settings-config.js";
|
|
4
|
+
import { CLAUDE_PROJECT_CONFIG_PATH, commandIdForHost, compactLines, entrypointDescription, entrypointEntries, instructionsPointer, invocationForHost } from "./shared.js";
|
|
5
|
+
import { agentDispatchRoutes, entrypointDispatchBlock, grants, header, markdown, projectAgentsMdDefinition, resolvedHostModel, scheduledEntrypointK8sNote } from "./opencode.js";
|
|
4
6
|
//#region src/install-commands/claude-code.ts
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const CLAUDE_CODE_HOST = "claude-code";
|
|
8
|
+
const CLAUDE_ALLOWED_TOOLS = "Task, Bash(opencode run *)";
|
|
9
|
+
const CLAUDE_AGENT_TOOLS = "Bash, Read";
|
|
10
|
+
const MOKA_PROFILE_PREFIX = "moka-";
|
|
11
|
+
function claudeAgentNameForProfile(profileId) {
|
|
12
|
+
return profileId.startsWith(MOKA_PROFILE_PREFIX) ? profileId : `${MOKA_PROFILE_PREFIX}${profileId}`;
|
|
13
|
+
}
|
|
14
|
+
function cliRoutesForConfig(config) {
|
|
15
|
+
return entrypointEntries(config).flatMap(([, entrypoint]) => "workflow" in entrypoint ? agentDispatchRoutes(CLAUDE_CODE_HOST, config, entrypoint.workflow) : []);
|
|
16
|
+
}
|
|
17
|
+
function distinctCliProfiles(config) {
|
|
18
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19
|
+
const profiles = [];
|
|
20
|
+
for (const route of cliRoutesForConfig(config)) {
|
|
21
|
+
if (route.kind !== "cli" || seen.has(route.profileId)) continue;
|
|
22
|
+
seen.add(route.profileId);
|
|
23
|
+
profiles.push(route);
|
|
24
|
+
}
|
|
25
|
+
return profiles.sort((a, b) => a.profileId.localeCompare(b.profileId));
|
|
26
|
+
}
|
|
27
|
+
function commandDispatchBody(config, id, entrypoint) {
|
|
28
|
+
if (!("workflow" in entrypoint)) return entrypointDispatchBlock(CLAUDE_CODE_HOST, config, id, entrypoint) ?? "";
|
|
29
|
+
const routes = agentDispatchRoutes(CLAUDE_CODE_HOST, config, entrypoint.workflow);
|
|
30
|
+
return [
|
|
31
|
+
`Run workflow \`${entrypoint.workflow}\` for the user task.`,
|
|
32
|
+
"",
|
|
33
|
+
"Delegate each agent node to a Claude Code `Task` subagent that wraps a local `opencode run` subprocess.",
|
|
34
|
+
"Spawn one node at a time respecting `needs`; run nodes whose dependencies are satisfied in parallel.",
|
|
35
|
+
"",
|
|
36
|
+
"Node routes:",
|
|
37
|
+
...routes.map(claudeNodeRouteLine),
|
|
38
|
+
"",
|
|
39
|
+
"For each node prompt include:",
|
|
40
|
+
"- user task",
|
|
41
|
+
`- workflow id: ${entrypoint.workflow}`,
|
|
42
|
+
"- node id",
|
|
43
|
+
"- profile id",
|
|
44
|
+
"- profile instructions reference",
|
|
45
|
+
"- profile grants",
|
|
46
|
+
"- dependency outputs",
|
|
11
47
|
"",
|
|
12
|
-
"
|
|
13
|
-
|
|
48
|
+
"Only package-configured gates are blocking. Do not invent RED, GREEN, full-suite, typecheck, or unrelated-drift gates.",
|
|
49
|
+
"If a node returns targeted evidence and has no configured blocking gate, advance to the next node.",
|
|
50
|
+
"The Task subagents wrap `opencode run` subprocesses; do not claim these worker nodes are Claude Code native agents."
|
|
51
|
+
].join("\n");
|
|
14
52
|
}
|
|
15
|
-
function
|
|
53
|
+
function claudeNodeRouteLine(route) {
|
|
54
|
+
const needs = route.needs.length > 0 ? route.needs.join(",") : "none";
|
|
55
|
+
return `- ${route.nodeId}: Task subagent_type=${claudeAgentNameForProfile(route.profileId)} runner=${route.runnerId} agent="${opencodeAgentName(route.profileId)}" needs=${needs}`;
|
|
56
|
+
}
|
|
57
|
+
function commandDefinitions(config) {
|
|
58
|
+
return entrypointEntries(config).map(([id, entrypoint]) => ({
|
|
59
|
+
content: markdown({
|
|
60
|
+
"argument-hint": "<task description>",
|
|
61
|
+
"allowed-tools": CLAUDE_ALLOWED_TOOLS,
|
|
62
|
+
description: entrypointDescription(id, entrypoint)
|
|
63
|
+
}, compactLines([
|
|
64
|
+
header(CLAUDE_CODE_HOST).trimEnd(),
|
|
65
|
+
"",
|
|
66
|
+
`Invoke this command with \`${invocationForHost(CLAUDE_CODE_HOST, id)}\`.`,
|
|
67
|
+
"",
|
|
68
|
+
"Load and follow the `execute` skill for the execution doctrine before dispatching work.",
|
|
69
|
+
"",
|
|
70
|
+
scheduledEntrypointK8sNote(entrypoint),
|
|
71
|
+
scheduledEntrypointK8sNote(entrypoint) ? "" : void 0,
|
|
72
|
+
commandDispatchBody(config, id, entrypoint)
|
|
73
|
+
]).join("\n")),
|
|
74
|
+
host: CLAUDE_CODE_HOST,
|
|
75
|
+
invocation: invocationForHost(CLAUDE_CODE_HOST, id),
|
|
76
|
+
path: `.claude/commands/${commandIdForHost(CLAUDE_CODE_HOST, id)}.md`
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
function agentModelProjection(config, profile) {
|
|
80
|
+
const model = resolvedHostModel(config, CLAUDE_CODE_HOST, profile);
|
|
81
|
+
return model ? { model } : {};
|
|
82
|
+
}
|
|
83
|
+
function agentDefinitions(config) {
|
|
84
|
+
return distinctCliProfiles(config).map((route) => {
|
|
85
|
+
const profile = route.profile;
|
|
86
|
+
const agentName = claudeAgentNameForProfile(route.profileId);
|
|
87
|
+
const displayName = opencodeAgentName(route.profileId);
|
|
88
|
+
return {
|
|
89
|
+
content: markdown({
|
|
90
|
+
name: agentName,
|
|
91
|
+
description: profile.description ?? route.profileId,
|
|
92
|
+
tools: CLAUDE_AGENT_TOOLS,
|
|
93
|
+
...agentModelProjection(config, profile)
|
|
94
|
+
}, [
|
|
95
|
+
header(CLAUDE_CODE_HOST).trimEnd(),
|
|
96
|
+
"",
|
|
97
|
+
profile.description ?? route.profileId,
|
|
98
|
+
"",
|
|
99
|
+
`Run EXACTLY ONE \`opencode run --agent "${displayName}" --format json --dir "$PWD" '<node prompt>'\` subprocess for this node.`,
|
|
100
|
+
"Stay inside this node's scope and do not branch into adjacent nodes.",
|
|
101
|
+
"Do not claim completion without fresh evidence from the subprocess output.",
|
|
102
|
+
"Return only: { command, exit status, parsed evidence, touched files, blockers }.",
|
|
103
|
+
"",
|
|
104
|
+
"Configured grants:",
|
|
105
|
+
grants(profile),
|
|
106
|
+
"",
|
|
107
|
+
instructionsPointer(profile)
|
|
108
|
+
].join("\n")),
|
|
109
|
+
host: CLAUDE_CODE_HOST,
|
|
110
|
+
invocation: invocationForHost(CLAUDE_CODE_HOST),
|
|
111
|
+
path: `.claude/agents/${agentName}.md`
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function settingsDefinition(config) {
|
|
116
|
+
const settings = { permissions: { allow: ["Task", "Bash(opencode run *)"] } };
|
|
117
|
+
if (config.mcp_gateway) settings.mcpServers = renderClaudeGatewayMcpServers(config);
|
|
16
118
|
return [{
|
|
17
|
-
content:
|
|
18
|
-
host:
|
|
19
|
-
invocation: invocationForHost(
|
|
20
|
-
path:
|
|
119
|
+
content: `${JSON.stringify(settings, null, 2)}\n`,
|
|
120
|
+
host: CLAUDE_CODE_HOST,
|
|
121
|
+
invocation: invocationForHost(CLAUDE_CODE_HOST),
|
|
122
|
+
path: CLAUDE_PROJECT_CONFIG_PATH
|
|
21
123
|
}];
|
|
22
124
|
}
|
|
125
|
+
function claudeCodeDefinitions(config, cwd) {
|
|
126
|
+
return [
|
|
127
|
+
...commandDefinitions(config),
|
|
128
|
+
...agentDefinitions(config),
|
|
129
|
+
...settingsDefinition(config),
|
|
130
|
+
projectAgentsMdDefinition(cwd, CLAUDE_CODE_HOST)
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The claude-code HostAdapter. Encapsulates all Claude Code-specific command
|
|
135
|
+
* generation, resource roots, and settings-merge behaviour.
|
|
136
|
+
*/
|
|
137
|
+
const claudeCodeAdapter = {
|
|
138
|
+
host: "claude-code",
|
|
139
|
+
resourceRoots: [".claude/commands", ".claude/agents"],
|
|
140
|
+
definitions(config, cwd) {
|
|
141
|
+
return claudeCodeDefinitions(config, cwd);
|
|
142
|
+
},
|
|
143
|
+
mergeDefinition(definition, existingContent) {
|
|
144
|
+
if (definition.path !== ".claude/settings.json") return;
|
|
145
|
+
const merged = mergeClaudeSettings(existingContent, JSON.parse(definition.content));
|
|
146
|
+
if (!merged.ok) return {
|
|
147
|
+
ok: false,
|
|
148
|
+
content: definition.content
|
|
149
|
+
};
|
|
150
|
+
return {
|
|
151
|
+
ok: true,
|
|
152
|
+
content: merged.content
|
|
153
|
+
};
|
|
154
|
+
},
|
|
155
|
+
isAlwaysForced(definition) {
|
|
156
|
+
return definition.path === CLAUDE_PROJECT_CONFIG_PATH;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
23
159
|
//#endregion
|
|
24
|
-
export {
|
|
160
|
+
export { claudeCodeAdapter };
|