@oisincoveney/pipeline 2.0.1 → 2.1.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.
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: claude-code-opencode-execute
3
+ description: Use in Claude Code when executing Moka work locally through OpenCode; loads execute first, then spawns Claude Task agents that run opencode run with the correct MoKa agent prompts.
4
+ allowed-tools: Bash(opencode run *) Bash(pwd) Bash(git status *) Task
5
+ ---
6
+
7
+ # Claude Code OpenCode Execute
8
+
9
+ Use this skill when Claude Code is the interactive host, but the work should be executed by local OpenCode MoKa agents through `opencode run` subprocesses.
10
+
11
+ This skill is a host adapter. It does not replace [[execute]]. Load and follow [[execute]] first; use this skill only for the Claude Code dispatch mechanics.
12
+
13
+ ## Contract
14
+
15
+ 1. Load [[execute]] and let it classify the request, required companion skills, acceptance criteria, and verification path.
16
+ 2. Keep the execution doctrine from [[execute]]: vertical slices, test-first for behavior, root-cause fixes, fidelity checks, critique, and verification.
17
+ 3. Use Claude Code `Task` subagents as wrappers around local OpenCode subprocesses when work can be delegated.
18
+ 4. Each delegated Task agent should run exactly one MoKa-flavored OpenCode command and return the command, exit status, parsed evidence, touched files, and blockers.
19
+ 5. Batch independent nodes in parallel, wait at barriers, synthesize outputs, then decide the next batch.
20
+
21
+ ## OpenCode command shape
22
+
23
+ Task agents should run OpenCode with this shape from the repository root:
24
+
25
+ ```sh
26
+ opencode run --agent "<MoKa Agent Name>" --format json --dir "$PWD" '<node prompt>'
27
+ ```
28
+
29
+ Use `--format json` so the parent can inspect structured event output. If the output contains multiple assistant text candidates, prefer the latest candidate that satisfies the requested JSON or evidence contract.
30
+
31
+ Do not use `moka submit` for this local Claude Code adapter unless the user explicitly asks to submit an Argo Workflow. `moka submit` is the durable pipeline path; this skill is for interactive local orchestration through Claude Task agents and `opencode run`.
32
+
33
+ ## Agent Selection
34
+
35
+ Select the MoKa agent by the slice's role:
36
+
37
+ | Role | OpenCode agent |
38
+ | --- | --- |
39
+ | Intake, repository research, requirements clarification | `MoKa Researcher` |
40
+ | Read-only code inspection | `MoKa Inspector` |
41
+ | Schedule graph generation or schedule review | `MoKa Schedule Planner` |
42
+ | Focused failing tests | `MoKa Test Writer` |
43
+ | Production implementation | `MoKa Code Writer` |
44
+ | Acceptance criteria audit | `MoKa Acceptance Reviewer` |
45
+ | Final quality review | `MoKa Thermo Nuclear Reviewer` |
46
+ | Verification evidence and command checks | `MoKa Verifier` |
47
+ | Durable lessons after a completed run | `MoKa Learner` |
48
+
49
+ Do not delegate normal child work to `MoKa Orchestrator`; the Claude Code parent is the local orchestrator for this adapter.
50
+
51
+ ## Prompt Contract
52
+
53
+ Every `opencode run` prompt must include:
54
+
55
+ - The original user task.
56
+ - The current execution contract from [[execute]].
57
+ - The node id and role.
58
+ - The selected MoKa agent name and why it was selected.
59
+ - The exact files or modules in scope, or a read-only discovery scope.
60
+ - Dependency outputs from earlier nodes.
61
+ - The acceptance criteria this node owns.
62
+ - The output shape expected by the parent.
63
+
64
+ Use this template for delegated prompts:
65
+
66
+ ```text
67
+ You are running as <MoKa Agent Name> for a Claude Code local Moka execution.
68
+
69
+ Original task:
70
+ <user task>
71
+
72
+ Execution contract:
73
+ <contract produced by execute>
74
+
75
+ Node:
76
+ - id: <node id>
77
+ - role: <role>
78
+ - selected agent: <MoKa Agent Name>
79
+ - scope: <files/modules/commands>
80
+
81
+ Dependency outputs:
82
+ <summaries or "none">
83
+
84
+ Acceptance criteria owned by this node:
85
+ <criteria>
86
+
87
+ Instructions:
88
+ - Follow the skills and grants configured for this MoKa agent.
89
+ - Stay inside this node's scope.
90
+ - Do not claim completion without fresh evidence.
91
+ - Return only the requested output shape.
92
+
93
+ Output shape:
94
+ <JSON or concise evidence contract>
95
+ ```
96
+
97
+ ## Batching Rules
98
+
99
+ - Run read-only discovery agents in parallel when their scopes do not require a shared conclusion first.
100
+ - Run test-writing before production implementation for behavior changes.
101
+ - Run multiple `MoKa Code Writer` agents in the same batch only when [[execute]] has produced independent vertical slices with disjoint files or clearly isolated worktrees.
102
+ - Never let two write-capable agents edit the same file in the same batch.
103
+ - Run acceptance review, final quality review, and verifier after implementation outputs have been integrated.
104
+ - If any delegated command fails, stop the batch, read the output, classify the blocker, and return to [[execute]] routing instead of retrying blindly.
105
+
106
+ ## Parent Responsibilities
107
+
108
+ The Claude Code parent must:
109
+
110
+ - Inspect outputs before launching the next batch.
111
+ - Integrate or reconcile changes itself when multiple agents wrote code.
112
+ - Run the verification required by [[execute]] in the real repository context.
113
+ - Inspect the final diff for accidental edits, secrets, generated churn, and unrelated changes.
114
+ - Report partial verification honestly if the real command path cannot be exercised.
115
+
116
+ This skill is complete only when [[execute]] would allow the parent to claim completion.
@@ -64,7 +64,7 @@ ecosystem_code:
64
64
  package: oc-codex-multi-auth
65
65
  plugin:
66
66
  kind: npm
67
- package: oc-codex-multi-auth
67
+ package: oc-codex-multi-auth@6.3.2
68
68
  role: ChatGPT Plus/Pro OAuth with multi-account rotation, health checks, and Codex/GPT-5 routing for OpenCode
69
69
  default_stack: true
70
70
  source: https://github.com/ndycode/oc-codex-multi-auth
@@ -83,6 +83,56 @@ ecosystem_code:
83
83
  role: OpenCode policy enforcement through tool execution hooks
84
84
  default_stack: true
85
85
  source: https://cupcake.eqtylab.io/getting-started/usage/opencode/
86
+ provider_models:
87
+ # Reasoning-effort variant selectors for ChatGPT OAuth Codex routing.
88
+ # Each id must match the oc-codex-multi-auth MODEL_MAP exactly; the plugin
89
+ # normalizes the selector back to the base API model (gpt-5.5) and the
90
+ # reasoning effort is carried by the generated options.reasoningEffort.
91
+ - id: gpt-5.5-none
92
+ provider: openai
93
+ role: zero-reasoning GPT-5.5 selector for mechanical low-stakes work
94
+ options:
95
+ reasoningEffort: none
96
+ reasoningSummary: auto
97
+ textVerbosity: medium
98
+ include: [reasoning.encrypted_content]
99
+ store: false
100
+ - id: gpt-5.5-low
101
+ provider: openai
102
+ role: low-reasoning GPT-5.5 selector for cheap inspection and bookkeeping roles
103
+ options:
104
+ reasoningEffort: low
105
+ reasoningSummary: auto
106
+ textVerbosity: medium
107
+ include: [reasoning.encrypted_content]
108
+ store: false
109
+ - id: gpt-5.5-medium
110
+ provider: openai
111
+ role: default-reasoning GPT-5.5 selector for research and coverage roles
112
+ options:
113
+ reasoningEffort: medium
114
+ reasoningSummary: auto
115
+ textVerbosity: medium
116
+ include: [reasoning.encrypted_content]
117
+ store: false
118
+ - id: gpt-5.5-high
119
+ provider: openai
120
+ role: high-reasoning GPT-5.5 selector for implementation roles
121
+ options:
122
+ reasoningEffort: high
123
+ reasoningSummary: detailed
124
+ textVerbosity: medium
125
+ include: [reasoning.encrypted_content]
126
+ store: false
127
+ - id: gpt-5.5-xhigh
128
+ provider: openai
129
+ role: maximum-reasoning GPT-5.5 selector for schedule planning
130
+ options:
131
+ reasoningEffort: xhigh
132
+ reasoningSummary: detailed
133
+ textVerbosity: medium
134
+ include: [reasoning.encrypted_content]
135
+ store: false
86
136
  mcp_backends:
87
137
  - id: pipeline-gateway
88
138
  locality: project-remote
@@ -150,7 +150,7 @@ function createCliProgram() {
150
150
  const config = loadPipelineConfig(process.env.PIPELINE_TARGET_PATH ?? process.cwd(), { allowMissingLintFileReferences: true });
151
151
  console.log(renderGatewayConfig(config));
152
152
  });
153
- gatewayCommand.command("configure-host").description("Rewrite host MCP config to the singleton pipeline gateway").addOption(new Option("--host <host>", "host config to update").choices(["all", "opencode"]).default("all").argParser(parseCommandHost)).addOption(new Option("--scope <scope>", "config scope to update").choices(["project", "global"]).default("project").argParser(parseGatewayHostScope)).action((flags) => {
153
+ gatewayCommand.command("configure-host").description("Rewrite host MCP config to the singleton pipeline gateway").addOption(new Option("--host <host>", "host config to update").choices(["all", "opencode"]).default("all").argParser(parseGatewayHost)).addOption(new Option("--scope <scope>", "config scope to update").choices(["project", "global"]).default("project").argParser(parseGatewayHostScope)).action((flags) => {
154
154
  const cwd = process.env.PIPELINE_TARGET_PATH ?? process.cwd();
155
155
  const result = configureGatewayHosts(loadPipelineConfig(cwd, { allowMissingLintFileReferences: true }), {
156
156
  cwd,
@@ -182,7 +182,11 @@ function createCliProgram() {
182
182
  const result = await initPipelineProject({ cwd: process.env.PIPELINE_TARGET_PATH ?? process.cwd() });
183
183
  console.log(formatPipelineInitResult(result));
184
184
  });
185
- program.command("install-commands").description("Install generated slash-command adapters into this repository").addOption(new Option("--host <host>", "host command set to install").choices(["all", "opencode"]).default("all").argParser(parseCommandHost)).option("--dry-run", "show planned changes without writing files").option("--check", "fail if generated command files are missing or stale").option("--force", "overwrite manually edited command files").action(async (flags) => {
185
+ program.command("install-commands").description("Install generated slash-command adapters into this repository").addOption(new Option("--host <host>", "host command set to install").choices([
186
+ "all",
187
+ "opencode",
188
+ "claude-code"
189
+ ]).default("all").argParser(parseCommandHost)).option("--dry-run", "show planned changes without writing files").option("--check", "fail if generated command files are missing or stale").option("--force", "overwrite manually edited command files").action(async (flags) => {
186
190
  const result = await installCommands({
187
191
  ...flags,
188
192
  cwd: process.env.PIPELINE_TARGET_PATH ?? process.cwd()
@@ -232,6 +236,10 @@ function parseGatewayHostScope(value) {
232
236
  if (value === "project" || value === "global") return value;
233
237
  throw new Error("scope must be project or global");
234
238
  }
239
+ function parseGatewayHost(value) {
240
+ if (value === "all" || value === "opencode") return value;
241
+ throw new Error(`Unsupported gateway host "${value}"`);
242
+ }
235
243
  async function runCli(argv) {
236
244
  await createCliProgram().parseAsync(argv, { from: "node" });
237
245
  }
@@ -4,7 +4,7 @@ import { dirname, join } from "node:path";
4
4
  import { homedir } from "node:os";
5
5
  import { parse } from "jsonc-parser";
6
6
  //#region src/codex-auth-sync.ts
7
- const CODEX_MULTI_AUTH_PLUGIN = "oc-codex-multi-auth";
7
+ const CODEX_MULTI_AUTH_PLUGIN = "oc-codex-multi-auth@6.3.2";
8
8
  const GLOBAL_CODEX_AUTH_CONFIG_PATH = join(homedir(), ".opencode/openai-codex-auth-config.json");
9
9
  function syncLocalCodexAuth(options) {
10
10
  const items = [syncGlobalPluginConfig(options.globalConfigPath ?? GLOBAL_CODEX_AUTH_CONFIG_PATH, options), ...discoverGitRepositories(options.root).map((repo) => syncProjectOpenCodeConfig(repo, options))];
@@ -55,6 +55,31 @@ declare const openCodeEcosystemManifestSchema: z.ZodObject<{
55
55
  source: z.ZodOptional<z.ZodString>;
56
56
  used_by: z.ZodArray<z.ZodString>;
57
57
  }, z.core.$strict>>;
58
+ provider_models: z.ZodArray<z.ZodObject<{
59
+ id: z.ZodString;
60
+ options: z.ZodObject<{
61
+ include: z.ZodArray<z.ZodString>;
62
+ reasoningEffort: z.ZodEnum<{
63
+ none: "none";
64
+ low: "low";
65
+ medium: "medium";
66
+ high: "high";
67
+ xhigh: "xhigh";
68
+ }>;
69
+ reasoningSummary: z.ZodEnum<{
70
+ auto: "auto";
71
+ detailed: "detailed";
72
+ }>;
73
+ store: z.ZodLiteral<false>;
74
+ textVerbosity: z.ZodEnum<{
75
+ low: "low";
76
+ medium: "medium";
77
+ high: "high";
78
+ }>;
79
+ }, z.core.$strict>;
80
+ provider: z.ZodString;
81
+ role: z.ZodString;
82
+ }, z.core.$strict>>;
58
83
  runtime: z.ZodObject<{
59
84
  compatibility_runners: z.ZodArray<z.ZodString>;
60
85
  default_runner: z.ZodLiteral<"opencode">;
@@ -125,6 +150,18 @@ declare const DEFAULT_OPENCODE_ECOSYSTEM_MANIFEST: {
125
150
  path?: string | undefined;
126
151
  source?: string | undefined;
127
152
  }[];
153
+ provider_models: {
154
+ id: string;
155
+ options: {
156
+ include: string[];
157
+ reasoningEffort: "none" | "low" | "medium" | "high" | "xhigh";
158
+ reasoningSummary: "auto" | "detailed";
159
+ store: false;
160
+ textVerbosity: "low" | "medium" | "high";
161
+ };
162
+ provider: string;
163
+ role: string;
164
+ }[];
128
165
  runtime: {
129
166
  compatibility_runners: string[];
130
167
  default_runner: "opencode";
@@ -73,6 +73,9 @@ skills:
73
73
  quick:
74
74
  path: .agents/skills/quick/SKILL.md
75
75
  source_root: package
76
+ claude-code-opencode-execute:
77
+ path: .agents/skills/claude-code-opencode-execute/SKILL.md
78
+ source_root: package
76
79
  critique:
77
80
  path: .agents/skills/critique/SKILL.md
78
81
  source_root: package
@@ -141,6 +144,7 @@ profiles:
141
144
  repair: { enabled: true, max_attempts: 1 }
142
145
  moka-inspector:
143
146
  runner: opencode
147
+ model: openai/gpt-5.5-low
144
148
  description: Inspect the repository without modifying files.
145
149
  instructions: { inline: "Inspect the repository without modifying files." }
146
150
  skills: [research]
@@ -150,6 +154,7 @@ profiles:
150
154
  network: { mode: inherit }
151
155
  moka-schedule-planner:
152
156
  runner: opencode
157
+ model: openai/gpt-5.5-xhigh
153
158
  description: Refine a baseline schedule into a specialized approved-plan artifact.
154
159
  instructions: { inline: "Generate exactly one workflow named root as an explicit schedule graph. Return YAML only." }
155
160
  timeout_ms: 300000
@@ -230,6 +235,7 @@ profiles:
230
235
  repair: { enabled: true, max_attempts: 1 }
231
236
  moka-learner:
232
237
  runner: opencode
238
+ model: openai/gpt-5.5-low
233
239
  description: Store durable lessons from the completed run.
234
240
  instructions: { inline: "Store durable lessons from the completed run when useful." }
235
241
  skills: [migrate]
@@ -289,54 +295,54 @@ scheduler:
289
295
  backlog-intake:
290
296
  category: intake
291
297
  profile: moka-researcher
292
- models: [openai/gpt-5.5-fast]
298
+ models: [openai/gpt-5.5-medium]
293
299
  red-tests:
294
300
  category: red
295
301
  profile: moka-test-writer
296
- models: [openai/gpt-5.5, kimi-for-coding/kimi-k2-thinking]
302
+ models: [openai/gpt-5.5-high, kimi-for-coding/kimi-k2-thinking]
297
303
  green-implementation:
298
304
  category: green
299
305
  profile: moka-code-writer
300
- models: [openai/gpt-5.5, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
306
+ models: [openai/gpt-5.5-high, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
301
307
  verification:
302
308
  category: verification
303
309
  profile: moka-verifier
304
- models: [openai/gpt-5.5]
310
+ models: [openai/gpt-5.5-medium]
305
311
  execute:
306
312
  required_categories: [intake, research, red, green, mechanical, acceptance, verification, learn]
307
313
  nodes:
308
314
  backlog-intake:
309
315
  category: intake
310
316
  profile: moka-researcher
311
- models: [openai/gpt-5.5-fast]
317
+ models: [openai/gpt-5.5-medium]
312
318
  research:
313
319
  category: research
314
320
  profile: moka-researcher
315
- models: [openai/gpt-5.5-fast, kimi-for-coding/k2p6]
321
+ models: [openai/gpt-5.5-medium, kimi-for-coding/k2p6]
316
322
  red-tests:
317
323
  category: red
318
324
  profile: moka-test-writer
319
- models: [openai/gpt-5.5, kimi-for-coding/kimi-k2-thinking]
325
+ models: [openai/gpt-5.5-high, kimi-for-coding/kimi-k2-thinking]
320
326
  green-backend:
321
327
  category: green
322
328
  profile: moka-code-writer
323
- models: [openai/gpt-5.5, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
329
+ models: [openai/gpt-5.5-high, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
324
330
  green-frontend:
325
331
  category: green
326
332
  profile: moka-code-writer
327
- models: [openai/gpt-5.5, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
333
+ models: [openai/gpt-5.5-high, kimi-for-coding/k2p6, opencode-go/qwen3.7-max]
328
334
  acceptance-review:
329
335
  category: acceptance
330
336
  profile: moka-acceptance-reviewer
331
- models: [openai/gpt-5.5]
337
+ models: [openai/gpt-5.5-medium]
332
338
  verification:
333
339
  category: verification
334
340
  profile: moka-verifier
335
- models: [openai/gpt-5.5]
341
+ models: [openai/gpt-5.5-medium]
336
342
  learn:
337
343
  category: learn
338
344
  profile: moka-learner
339
- models: [openai/gpt-5.5-fast]
345
+ models: [openai/gpt-5.5-low]
340
346
  schedules:
341
347
  quick-schedule:
342
348
  baseline: quick
@@ -385,6 +391,29 @@ const ecosystemCodeSchema = z.object({
385
391
  role: z.string().min(1),
386
392
  source: z.string().url()
387
393
  }).strict();
394
+ const ecosystemProviderModelOptionsSchema = z.object({
395
+ include: ecosystemStringArraySchema,
396
+ reasoningEffort: z.enum([
397
+ "none",
398
+ "low",
399
+ "medium",
400
+ "high",
401
+ "xhigh"
402
+ ]),
403
+ reasoningSummary: z.enum(["auto", "detailed"]),
404
+ store: z.literal(false),
405
+ textVerbosity: z.enum([
406
+ "low",
407
+ "medium",
408
+ "high"
409
+ ])
410
+ }).strict();
411
+ const ecosystemProviderModelSchema = z.object({
412
+ id: z.string().min(1),
413
+ options: ecosystemProviderModelOptionsSchema,
414
+ provider: z.string().min(1),
415
+ role: z.string().min(1)
416
+ }).strict();
388
417
  const ecosystemMcpBackendSchema = z.object({
389
418
  credentials: ecosystemStringArraySchema,
390
419
  id: z.string().min(1),
@@ -421,6 +450,7 @@ const openCodeEcosystemManifestSchema = z.object({
421
450
  mcp_backends: z.array(ecosystemMcpBackendSchema).min(1),
422
451
  official_dependencies: z.array(ecosystemDependencySchema).min(1),
423
452
  prompts: z.array(ecosystemProfileResourceSchema).min(1),
453
+ provider_models: z.array(ecosystemProviderModelSchema).min(1),
424
454
  runtime: ecosystemRuntimeSchema,
425
455
  skills: z.array(ecosystemProfileResourceSchema).min(1),
426
456
  sources: z.array(ecosystemSourceSchema).min(1),
@@ -343,8 +343,8 @@ declare const configSchema: z.ZodObject<{
343
343
  rules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
344
344
  path: z.ZodString;
345
345
  source_root: z.ZodDefault<z.ZodEnum<{
346
- package: "package";
347
346
  project: "project";
347
+ package: "package";
348
348
  }>>;
349
349
  }, z.core.$strict>>>;
350
350
  runners: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -471,8 +471,8 @@ declare const configSchema: z.ZodObject<{
471
471
  schedules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
472
472
  description: z.ZodOptional<z.ZodString>;
473
473
  baseline: z.ZodEnum<{
474
- execute: "execute";
475
474
  quick: "quick";
475
+ execute: "execute";
476
476
  }>;
477
477
  max_parallel_nodes: z.ZodOptional<z.ZodNumber>;
478
478
  node_catalog: z.ZodOptional<z.ZodString>;
@@ -484,8 +484,8 @@ declare const configSchema: z.ZodObject<{
484
484
  skills: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
485
485
  path: z.ZodString;
486
486
  source_root: z.ZodDefault<z.ZodEnum<{
487
- package: "package";
488
487
  project: "project";
488
+ package: "package";
489
489
  }>>;
490
490
  }, z.core.$strict>>>;
491
491
  task_context: z.ZodOptional<z.ZodObject<{
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
- fail: "fail";
17
16
  pass: "pass";
17
+ fail: "fail";
18
18
  skip: "skip";
19
19
  }>;
20
20
  summary: z.ZodOptional<z.ZodString>;
@@ -0,0 +1,24 @@
1
+ import { resolvePackageAssetPath } from "../package-assets.js";
2
+ import { GENERATED_MARKER, OWNER_MARKER_PREFIX, invocationForHost } from "./shared.js";
3
+ import { readFileSync } from "node:fs";
4
+ //#region src/install-commands/claude-code.ts
5
+ const CLAUDE_CODE_OPENCODE_EXECUTE_SKILL = "claude-code-opencode-execute";
6
+ const PACKAGE_SKILL_PATH = `.agents/skills/${CLAUDE_CODE_OPENCODE_EXECUTE_SKILL}/SKILL.md`;
7
+ function generatedClaudeSkillContent() {
8
+ return readFileSync(resolvePackageAssetPath(PACKAGE_SKILL_PATH), "utf8").replace("# Claude Code OpenCode Execute", [
9
+ GENERATED_MARKER,
10
+ `${OWNER_MARKER_PREFIX}host=claude-code -->`,
11
+ "",
12
+ "# Claude Code OpenCode Execute"
13
+ ].join("\n"));
14
+ }
15
+ function claudeCodeDefinitions() {
16
+ return [{
17
+ content: generatedClaudeSkillContent(),
18
+ host: "claude-code",
19
+ invocation: invocationForHost("claude-code", CLAUDE_CODE_OPENCODE_EXECUTE_SKILL),
20
+ path: `.claude/skills/${CLAUDE_CODE_OPENCODE_EXECUTE_SKILL}/SKILL.md`
21
+ }];
22
+ }
23
+ //#endregion
24
+ export { claudeCodeDefinitions };
@@ -222,7 +222,10 @@ function hostSpecificDispatchGuard(host, nativeRoutes, cliRoutes) {
222
222
  if (cliRoutes.length > 0 && nativeRoutes.length === 0) return `Do not claim these nodes are ${hostDisplayName(host)} subagents.`;
223
223
  }
224
224
  function hostDisplayName(host) {
225
- return { opencode: "OpenCode" }[host];
225
+ return {
226
+ "claude-code": "Claude Code",
227
+ opencode: "OpenCode"
228
+ }[host];
226
229
  }
227
230
  function needsSummary(needs) {
228
231
  return needs.length > 0 ? needs.join(",") : "none";
@@ -271,9 +274,18 @@ function renderOpenCodeProjectConfig(config) {
271
274
  return formatOpenCodeProjectJson({
272
275
  ...config.mcp_gateway ? JSON.parse(renderOpenCodeGatewayConfig(config)) : { $schema: "https://opencode.ai/config.json" },
273
276
  lsp: true,
274
- ...opencodePluginConfig()
277
+ ...opencodePluginConfig(),
278
+ ...opencodeProviderConfig()
275
279
  });
276
280
  }
281
+ function opencodeProviderConfig() {
282
+ const provider = {};
283
+ for (const model of DEFAULT_OPENCODE_ECOSYSTEM_MANIFEST.provider_models) {
284
+ provider[model.provider] ??= { models: {} };
285
+ provider[model.provider].models[model.id] = { options: model.options };
286
+ }
287
+ return Object.keys(provider).length > 0 ? { provider } : {};
288
+ }
277
289
  function opencodePluginConfig() {
278
290
  const plugins = DEFAULT_OPENCODE_ECOSYSTEM_MANIFEST.ecosystem_code.flatMap((item) => npmPluginPackage(item)).sort((a, b) => a.localeCompare(b));
279
291
  return plugins.length > 0 ? { plugin: plugins } : {};
@@ -10,10 +10,16 @@ const AGENTS_MD_END = "<!-- @oisincoveney/pipeline:agents:end -->";
10
10
  const SINGLE_OPENCODE_PLUGIN_ARRAY_RE = /\n {2}"plugin": \[\n {4}("[^"]+")\n {2}\]/;
11
11
  const OPENCODE_PROJECT_CONFIG_PATH = ".opencode/opencode.json";
12
12
  const OPENCODE_COMMAND_PREFIX = "moka-";
13
- const ENTRYPOINT_PATH_PATTERNS = { opencode: [/^\.opencode\/commands\/(?:moka-)?([^/]+)\.md$/] };
14
- const COMMAND_HOSTS = ["opencode"];
13
+ const ENTRYPOINT_PATH_PATTERNS = {
14
+ "claude-code": [],
15
+ opencode: [/^\.opencode\/commands\/(?:moka-)?([^/]+)\.md$/]
16
+ };
17
+ const COMMAND_HOSTS = ["opencode", "claude-code"];
15
18
  function invocationForHost(host, entrypointId = "execute") {
16
- return `${{ opencode: "/" }[host]}${commandIdForHost(host, entrypointId)} <task description>`;
19
+ return `${{
20
+ "claude-code": "/",
21
+ opencode: "/"
22
+ }[host]}${commandIdForHost(host, entrypointId)} <task description>`;
17
23
  }
18
24
  function commandIdForHost(host, entrypointId) {
19
25
  if (host === "opencode") return `${OPENCODE_COMMAND_PREFIX}${entrypointId}`;
@@ -2,13 +2,17 @@ import { loadPipelineConfig } from "./config/load.js";
2
2
  import "./config.js";
3
3
  import { mergeOpenCodeProjectConfig } from "./opencode-project-config.js";
4
4
  import { COMMAND_HOSTS, ENTRYPOINT_PATH_PATTERNS, invocationForHost } from "./install-commands/shared.js";
5
+ import { claudeCodeDefinitions } from "./install-commands/claude-code.js";
5
6
  import { opencodeDefinitions } from "./install-commands/opencode.js";
6
7
  import { existsSync, readFileSync, statSync } from "node:fs";
7
8
  import { dirname, join, relative } from "node:path";
8
9
  import { mkdir, readdir, rm, writeFile } from "node:fs/promises";
9
10
  //#region src/install-commands.ts
10
11
  function definitionsFor(host, config, cwd) {
11
- const definitions = { opencode: () => opencodeDefinitions(config, cwd) };
12
+ const definitions = {
13
+ "claude-code": () => claudeCodeDefinitions(),
14
+ opencode: () => opencodeDefinitions(config, cwd)
15
+ };
12
16
  return dedupeDefinitionsByPath((host === "all" ? COMMAND_HOSTS : [host]).flatMap((name) => definitions[name]()));
13
17
  }
14
18
  function dedupeDefinitionsByPath(definitions) {
@@ -21,12 +25,15 @@ function dedupeDefinitionsByPath(definitions) {
21
25
  function selectedHosts(host) {
22
26
  return host === "all" ? [...COMMAND_HOSTS] : [host];
23
27
  }
24
- const GENERATED_RESOURCE_ROOTS = { opencode: [
25
- ".opencode/commands",
26
- ".opencode/agents",
27
- ".opencode/plugins",
28
- ".opencode/skills"
29
- ] };
28
+ const GENERATED_RESOURCE_ROOTS = {
29
+ "claude-code": [".claude/skills"],
30
+ opencode: [
31
+ ".opencode/commands",
32
+ ".opencode/agents",
33
+ ".opencode/plugins",
34
+ ".opencode/skills"
35
+ ]
36
+ };
30
37
  async function listFiles(root) {
31
38
  if (!existsSync(root)) return [];
32
39
  if (statSync(root).isFile()) return [root];
@@ -161,8 +161,8 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
161
161
  }, z.core.$strict>>;
162
162
  serviceAccountName: z.ZodOptional<z.ZodString>;
163
163
  mode: z.ZodEnum<{
164
- quick: "quick";
165
164
  full: "full";
165
+ quick: "quick";
166
166
  }>;
167
167
  schedulePath: z.ZodOptional<z.ZodString>;
168
168
  scheduleYaml: z.ZodOptional<z.ZodString>;
@@ -32,7 +32,15 @@ function parseOpenCodeProjectConfig(currentText) {
32
32
  };
33
33
  }
34
34
  function applyOpenCodeProjection(currentText, parsed, projection) {
35
- return applyPluginProjection(applyMcpProjection(setIfMissing(setIfMissing(currentText, parsed, ["$schema"], projection.$schema), parsed, ["lsp"], projection.lsp), parsed, projection), parsed, projection);
35
+ return applyProviderProjection(applyPluginProjection(applyMcpProjection(setIfMissing(setIfMissing(currentText, parsed, ["$schema"], projection.$schema), parsed, ["lsp"], projection.lsp), parsed, projection), parsed, projection), parsed, projection);
36
+ }
37
+ function applyProviderProjection(content, parsed, projection) {
38
+ return Object.entries(projection.provider ?? {}).reduce((providerContent, [providerId, provider]) => Object.entries(provider.models ?? {}).reduce((modelContent, [modelId, model]) => setIfMissing(modelContent, parsed, [
39
+ "provider",
40
+ providerId,
41
+ "models",
42
+ modelId
43
+ ], model), providerContent), content);
36
44
  }
37
45
  function applyMcpProjection(content, parsed, projection) {
38
46
  return Object.entries(projection.mcp ?? {}).reduce((nextContent, [name, server]) => setIfMissing(nextContent, parsed, ["mcp", name], server), content);
@@ -54,8 +62,14 @@ function hasPath(value, path) {
54
62
  return true;
55
63
  }
56
64
  function mergePluginEntries(existing, projected) {
57
- const merged = Array.isArray(existing) ? [...existing] : [];
58
- const seen = new Set(merged.map(pluginKey));
65
+ const projectedByKey = new Map(projected.map((plugin) => [pluginKey(plugin), plugin]));
66
+ const merged = [];
67
+ const seen = /* @__PURE__ */ new Set();
68
+ for (const plugin of Array.isArray(existing) ? existing : []) {
69
+ const key = pluginKey(plugin);
70
+ merged.push(projectedByKey.get(key) ?? plugin);
71
+ seen.add(key);
72
+ }
59
73
  for (const plugin of projected) {
60
74
  const key = pluginKey(plugin);
61
75
  if (seen.has(key)) continue;
@@ -65,8 +79,12 @@ function mergePluginEntries(existing, projected) {
65
79
  return merged;
66
80
  }
67
81
  function pluginKey(value) {
68
- if (Array.isArray(value)) return typeof value[0] === "string" ? value[0] : JSON.stringify(value);
69
- return typeof value === "string" ? value : JSON.stringify(value);
82
+ if (Array.isArray(value)) return typeof value[0] === "string" ? pluginName(value[0]) : JSON.stringify(value);
83
+ return typeof value === "string" ? pluginName(value) : JSON.stringify(value);
84
+ }
85
+ function pluginName(specifier) {
86
+ const versionSeparator = specifier.indexOf("@", 1);
87
+ return versionSeparator === -1 ? specifier : specifier.slice(0, versionSeparator);
70
88
  }
71
89
  function applyJsonEdit(content, path, value) {
72
90
  return applyEdits(content, modify(content, path, value, { formattingOptions: JSON_FORMAT_OPTIONS }));
@@ -43,8 +43,8 @@ declare const runnerDeliverySchema: z.ZodObject<{
43
43
  declare const mokaSubmissionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
44
44
  kind: z.ZodLiteral<"graph">;
45
45
  mode: z.ZodEnum<{
46
- quick: "quick";
47
46
  full: "full";
47
+ quick: "quick";
48
48
  }>;
49
49
  }, z.core.$strict>, z.ZodObject<{
50
50
  argv: z.ZodArray<z.ZodString>;
@@ -104,8 +104,8 @@ declare const runnerCommandPayloadSchema: z.ZodObject<{
104
104
  submission: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
105
105
  kind: z.ZodLiteral<"graph">;
106
106
  mode: z.ZodEnum<{
107
- quick: "quick";
108
107
  full: "full";
108
+ quick: "quick";
109
109
  }>;
110
110
  }, z.core.$strict>, z.ZodObject<{
111
111
  argv: z.ZodArray<z.ZodString>;
package/package.json CHANGED
@@ -115,7 +115,7 @@
115
115
  "prepack": "bun run build:cli"
116
116
  },
117
117
  "type": "module",
118
- "version": "2.0.1",
118
+ "version": "2.1.0",
119
119
  "description": "Config-driven multi-agent pipeline runner for repository work",
120
120
  "main": "./dist/index.js",
121
121
  "types": "./dist/index.d.ts",