@oisincoveney/pipeline 1.27.18 → 1.27.19

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 CHANGED
@@ -241,7 +241,7 @@ runner.
241
241
 
242
242
  | Host | Generated files | Invocation |
243
243
  | --- | --- | --- |
244
- | OpenCode | `.opencode/commands/<entrypoint>.md`, `.opencode/agents/*.md`, `.opencode/plugins/*.ts`, `.opencode/opencode.json` | `/quick <task>`, `/execute <task>`, `/inspect <task>` |
244
+ | OpenCode | `.opencode/commands/moka-<entrypoint>.md`, `.opencode/agents/*.md`, `.opencode/plugins/*.ts`, `.opencode/opencode.json` | `/moka-quick <task>`, `/moka-execute <task>`, `/moka-inspect <task>` |
245
245
 
246
246
  The installer is idempotent, supports `--check` and `--dry-run`, and refuses to
247
247
  overwrite manually edited files unless `--force` is supplied.
@@ -11,6 +11,10 @@ const RUNNER_WORKFLOW_ENTRYPOINT = "pipeline";
11
11
  const RUNNER_WORKFLOW_PAYLOAD_PATH = "/etc/pipeline/payload.json";
12
12
  const RUNNER_WORKFLOW_SCHEDULE_PATH = "/etc/pipeline/schedule.yaml";
13
13
  const RUNNER_GIT_CREDENTIALS_PATH = "/etc/pipeline/git-credentials";
14
+ const RUNNER_OPENCODE_ENV = [{
15
+ name: "CODEX_AUTH_PER_PROJECT_ACCOUNTS",
16
+ value: "0"
17
+ }];
14
18
  const kubernetesNameSchema = z.string().min(1);
15
19
  const labelValueSchema = z.string().min(1);
16
20
  const stringMapSchema = z.record(z.string().min(1), z.string().min(1));
@@ -346,6 +350,7 @@ function runnerCommandTemplate(task, options, volumeMounts) {
346
350
  RUNNER_WORKFLOW_SCHEDULE_PATH
347
351
  ],
348
352
  command: ["moka"],
353
+ env: [...RUNNER_OPENCODE_ENV],
349
354
  image: options.image,
350
355
  imagePullPolicy: options.imagePullPolicy,
351
356
  name: "runner",
@@ -368,6 +373,7 @@ function runnerFinalizerTemplate(options, volumeMounts) {
368
373
  "{{workflow.status}}"
369
374
  ],
370
375
  command: ["moka"],
376
+ env: [...RUNNER_OPENCODE_ENV],
371
377
  image: options.image,
372
378
  imagePullPolicy: options.imagePullPolicy,
373
379
  name: "runner",
@@ -0,0 +1,98 @@
1
+ import { mergeOpenCodeProjectConfig } from "./opencode-project-config.js";
2
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ import { parse } from "jsonc-parser";
6
+ //#region src/codex-auth-sync.ts
7
+ const CODEX_MULTI_AUTH_PLUGIN = "oc-codex-multi-auth";
8
+ const GLOBAL_CODEX_AUTH_CONFIG_PATH = join(homedir(), ".opencode/openai-codex-auth-config.json");
9
+ function syncLocalCodexAuth(options) {
10
+ const items = [syncGlobalPluginConfig(options.globalConfigPath ?? GLOBAL_CODEX_AUTH_CONFIG_PATH, options), ...discoverGitRepositories(options.root).map((repo) => syncProjectOpenCodeConfig(repo, options))];
11
+ const hasRequiredChanges = items.some((item) => item.action === "create" || item.action === "update");
12
+ const hasErrors = items.some((item) => item.action === "error");
13
+ const checkFailed = options.check === true && hasRequiredChanges;
14
+ return {
15
+ items,
16
+ ok: !(hasErrors || checkFailed)
17
+ };
18
+ }
19
+ function formatCodexAuthSyncResult(result) {
20
+ const lines = result.items.map((item) => {
21
+ const suffix = item.message ? `: ${item.message}` : "";
22
+ return `${item.action} ${item.path}${suffix}`;
23
+ });
24
+ if (!result.ok) lines.push("codex-auth sync-local check failed");
25
+ return lines.join("\n");
26
+ }
27
+ function syncGlobalPluginConfig(path, options) {
28
+ const currentText = existsSync(path) ? readFileSync(path, "utf8") : void 0;
29
+ const parsed = parseJsonObject(currentText ?? "{}");
30
+ if (!parsed.ok) return {
31
+ action: "error",
32
+ message: formatParseErrors(parsed.errors),
33
+ path
34
+ };
35
+ return writeIfChanged(path, currentText, `${JSON.stringify({
36
+ ...parsed.value,
37
+ perProjectAccounts: false
38
+ }, null, 2)}\n`, options);
39
+ }
40
+ function syncProjectOpenCodeConfig(repo, options) {
41
+ const path = join(repo, ".opencode/opencode.json");
42
+ const currentText = existsSync(path) ? readFileSync(path, "utf8") : void 0;
43
+ const merged = mergeOpenCodeProjectConfig(currentText, { plugin: [CODEX_MULTI_AUTH_PLUGIN] });
44
+ if (!merged.ok) return {
45
+ action: "error",
46
+ message: formatParseErrors(merged.errors),
47
+ path
48
+ };
49
+ return writeIfChanged(path, currentText, merged.content, options);
50
+ }
51
+ function writeIfChanged(path, currentText, nextText, options) {
52
+ if (currentText === nextText) return {
53
+ action: "unchanged",
54
+ path
55
+ };
56
+ const action = currentText === void 0 ? "create" : "update";
57
+ if (!(options.check || options.dryRun)) {
58
+ mkdirSync(dirname(path), { recursive: true });
59
+ writeFileSync(path, nextText);
60
+ }
61
+ return {
62
+ action,
63
+ path
64
+ };
65
+ }
66
+ function discoverGitRepositories(root) {
67
+ return readdirSync(root).map((name) => join(root, name)).filter((path) => isDirectory(path) && existsSync(join(path, ".git"))).sort((a, b) => a.localeCompare(b));
68
+ }
69
+ function isDirectory(path) {
70
+ try {
71
+ return statSync(path).isDirectory();
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
76
+ function parseJsonObject(content) {
77
+ const errors = [];
78
+ const value = parse(content, errors, {
79
+ allowTrailingComma: true,
80
+ disallowComments: false
81
+ });
82
+ if (errors.length > 0 || !isRecord(value)) return {
83
+ errors,
84
+ ok: false
85
+ };
86
+ return {
87
+ ok: true,
88
+ value
89
+ };
90
+ }
91
+ function formatParseErrors(errors) {
92
+ return errors.length > 0 ? `invalid JSONC (${errors.length} parse error${errors.length === 1 ? "" : "s"})` : "expected a JSON object";
93
+ }
94
+ function isRecord(value) {
95
+ return typeof value === "object" && value !== null && !Array.isArray(value);
96
+ }
97
+ //#endregion
98
+ export { formatCodexAuthSyncResult, syncLocalCodexAuth };
package/dist/config.d.ts CHANGED
@@ -362,8 +362,8 @@ declare const configSchema: z.ZodObject<{
362
362
  policy: z.ZodOptional<z.ZodObject<{
363
363
  commands: z.ZodOptional<z.ZodEnum<{
364
364
  allow: "allow";
365
- deny: "deny";
366
365
  "trusted-only": "trusted-only";
366
+ deny: "deny";
367
367
  }>>;
368
368
  modules: z.ZodOptional<z.ZodEnum<{
369
369
  allow: "allow";
@@ -387,8 +387,8 @@ declare const configSchema: z.ZodObject<{
387
387
  }, z.core.$strict>>>;
388
388
  default_profile: z.ZodOptional<z.ZodString>;
389
389
  mode: z.ZodEnum<{
390
- local: "local";
391
390
  hosted: "hosted";
391
+ local: "local";
392
392
  }>;
393
393
  provider: z.ZodLiteral<"toolhive">;
394
394
  authorization_env: z.ZodDefault<z.ZodString>;
@@ -431,10 +431,10 @@ declare const configSchema: z.ZodObject<{
431
431
  }, z.core.$strict>>;
432
432
  output: z.ZodOptional<z.ZodObject<{
433
433
  format: z.ZodEnum<{
434
- json_schema: "json_schema";
435
434
  text: "text";
436
435
  json: "json";
437
436
  jsonl: "jsonl";
437
+ json_schema: "json_schema";
438
438
  }>;
439
439
  repair: z.ZodOptional<z.ZodObject<{
440
440
  enabled: z.ZodOptional<z.ZodBoolean>;
@@ -485,8 +485,8 @@ declare const configSchema: z.ZodObject<{
485
485
  rules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
486
486
  path: z.ZodString;
487
487
  source_root: z.ZodDefault<z.ZodEnum<{
488
- project: "project";
489
488
  package: "package";
489
+ project: "project";
490
490
  }>>;
491
491
  }, z.core.$strict>>>;
492
492
  runners: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -503,10 +503,10 @@ declare const configSchema: z.ZodObject<{
503
503
  disabled: "disabled";
504
504
  }>>>;
505
505
  output_formats: z.ZodOptional<z.ZodArray<z.ZodEnum<{
506
- json_schema: "json_schema";
507
506
  text: "text";
508
507
  json: "json";
509
508
  jsonl: "jsonl";
509
+ json_schema: "json_schema";
510
510
  }>>>;
511
511
  rules: z.ZodOptional<z.ZodBoolean>;
512
512
  skills: z.ZodOptional<z.ZodBoolean>;
@@ -613,8 +613,8 @@ declare const configSchema: z.ZodObject<{
613
613
  schedules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
614
614
  description: z.ZodOptional<z.ZodString>;
615
615
  baseline: z.ZodEnum<{
616
- quick: "quick";
617
616
  execute: "execute";
617
+ quick: "quick";
618
618
  }>;
619
619
  max_parallel_nodes: z.ZodOptional<z.ZodNumber>;
620
620
  node_catalog: z.ZodOptional<z.ZodString>;
@@ -626,8 +626,8 @@ declare const configSchema: z.ZodObject<{
626
626
  skills: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
627
627
  path: z.ZodString;
628
628
  source_root: z.ZodDefault<z.ZodEnum<{
629
- project: "project";
630
629
  package: "package";
630
+ project: "project";
631
631
  }>>;
632
632
  }, z.core.$strict>>>;
633
633
  task_context: z.ZodOptional<z.ZodObject<{
package/dist/config.js CHANGED
@@ -315,7 +315,7 @@ hooks:
315
315
  runner_command:
316
316
  environment:
317
317
  setup:
318
- - command: pnpm
318
+ - command: bun
319
319
  args: [install, --frozen-lockfile]
320
320
  scheduler:
321
321
  commands:
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>;
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { PipelineConfigError, loadPipelineConfig } from "./config.js";
4
4
  import { createOrchestratorLaunchPlan, createRunnerLaunchPlan } from "./runner.js";
5
5
  import { compileWorkflowPlan } from "./workflow-planner.js";
6
6
  import { compileScheduleArtifact, generateScheduleArtifact, parseScheduleArtifact } from "./schedule-planner.js";
7
+ import { formatCodexAuthSyncResult, syncLocalCodexAuth } from "./codex-auth-sync.js";
7
8
  import { BUILTIN_PIPE_COMMANDS, registerConfiguredEntrypointCommands } from "./commands/pipeline-command.js";
8
9
  import { configureGatewayHosts, localGatewayStatus, reconcileGateway, renderGatewayConfig, runGatewayDoctor, startLocalGateway } from "./mcp/gateway.js";
9
10
  import { resolvePackageAssetPath } from "./package-assets.js";
@@ -289,6 +290,15 @@ function createCliProgram() {
289
290
  });
290
291
  console.log(formatInstallCommandsResult(result));
291
292
  });
293
+ program.command("codex-auth").description("Manage local Codex multi-auth integration").command("sync-local").description("Use one local oc-codex account pool and declare the plugin in dev repos").option("--root <path>", "directory containing repositories to sync").option("--dry-run", "show planned changes without writing files").option("--check", "fail if local Codex auth config is not synced").action((flags) => {
294
+ const result = syncLocalCodexAuth({
295
+ check: flags.check,
296
+ dryRun: flags.dryRun,
297
+ root: resolve(flags.root ?? process.env.PIPELINE_TARGET_PATH ?? process.cwd())
298
+ });
299
+ console.log(formatCodexAuthSyncResult(result));
300
+ if (!result.ok) process.exitCode = 1;
301
+ });
292
302
  addMokaSubmitOptions(program.command("submit").description("Submit work to Momokaya as an Argo Workflow").argument("[input...]", "task description, or command argv with --command")).action(async (input, flags) => {
293
303
  const result = await runMokaSubmitFromCli(input, flags);
294
304
  console.log(`Workflow submitted: ${result.workflowName} in ${result.namespace}`);
@@ -1,8 +1,8 @@
1
1
  import { DEFAULT_OPENCODE_ECOSYSTEM_MANIFEST, loadPipelineConfig } from "./config.js";
2
2
  import { compileWorkflowPlan } from "./workflow-planner.js";
3
+ import { mergeOpenCodeProjectConfig } from "./opencode-project-config.js";
3
4
  import { renderOpenCodeGatewayConfig } from "./mcp/gateway.js";
4
5
  import { resolvePackageAssetPath } from "./package-assets.js";
5
- import { mergeOpenCodeProjectConfig } from "./opencode-project-config.js";
6
6
  import { existsSync, readFileSync, statSync } from "node:fs";
7
7
  import { basename, dirname, join, relative } from "node:path";
8
8
  import matter from "gray-matter";
@@ -18,7 +18,8 @@ const AGENTS_MD_START = "<!-- @oisincoveney/pipeline:agents:start -->";
18
18
  const AGENTS_MD_END = "<!-- @oisincoveney/pipeline:agents:end -->";
19
19
  const SINGLE_OPENCODE_PLUGIN_ARRAY_RE = /\n {2}"plugin": \[\n {4}("[^"]+")\n {2}\]/;
20
20
  const OPENCODE_PROJECT_CONFIG_PATH = ".opencode/opencode.json";
21
- const ENTRYPOINT_PATH_PATTERNS = { opencode: [/^\.opencode\/commands\/([^/]+)\.md$/] };
21
+ const OPENCODE_COMMAND_PREFIX = "moka-";
22
+ const ENTRYPOINT_PATH_PATTERNS = { opencode: [/^\.opencode\/commands\/(?:moka-)?([^/]+)\.md$/] };
22
23
  const COMMAND_HOSTS = ["opencode"];
23
24
  const OPENCODE_ORCHESTRATOR_AGENT_ID = "MoKa Orchestrator";
24
25
  const MOKA_PROFILE_PREFIX = "moka-";
@@ -334,7 +335,7 @@ function opencodeDefinitions(config, cwd) {
334
335
  ]).join("\n")),
335
336
  host: "opencode",
336
337
  invocation: invocationForHost("opencode", id),
337
- path: `.opencode/commands/${id}.md`
338
+ path: `.opencode/commands/${commandIdForHost("opencode", id)}.md`
338
339
  })),
339
340
  {
340
341
  content: renderOpenCodeProjectConfig(config),
@@ -401,7 +402,7 @@ function projectAgentsMdDefinition(cwd, host) {
401
402
  "",
402
403
  "This repository uses package-owned `@oisincoveney/pipeline` config.",
403
404
  "",
404
- "- Use `/quick`, `/execute`, or `/inspect` for OpenCode slash-command entrypoints when available.",
405
+ "- Use `/moka-quick`, `/moka-execute`, or `/moka-inspect` for OpenCode slash-command entrypoints when available.",
405
406
  "- Load and follow the relevant skill from `.agents/skills` before doing specialized work.",
406
407
  "- Prefer the package-defined pipeline profiles and generated command surfaces over ad hoc subagent prompts.",
407
408
  "",
@@ -485,7 +486,11 @@ function entrypointIdFromGeneratedPath(host, path) {
485
486
  }
486
487
  }
487
488
  function invocationForHost(host, entrypointId = "execute") {
488
- return `${{ opencode: "/" }[host]}${entrypointId} <task description>`;
489
+ return `${{ opencode: "/" }[host]}${commandIdForHost(host, entrypointId)} <task description>`;
490
+ }
491
+ function commandIdForHost(host, entrypointId) {
492
+ if (host === "opencode") return `${OPENCODE_COMMAND_PREFIX}${entrypointId}`;
493
+ return entrypointId;
489
494
  }
490
495
  function resolveDefinitionContent(definition, target) {
491
496
  if (definition.path !== OPENCODE_PROJECT_CONFIG_PATH || !existsSync(target)) return {
@@ -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
- full: "full";
165
164
  quick: "quick";
165
+ full: "full";
166
166
  }>;
167
167
  schedulePath: z.ZodOptional<z.ZodString>;
168
168
  scheduleYaml: z.ZodOptional<z.ZodString>;
@@ -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
- full: "full";
47
46
  quick: "quick";
47
+ full: "full";
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
- full: "full";
108
107
  quick: "quick";
108
+ full: "full";
109
109
  }>;
110
110
  }, z.core.$strict>, z.ZodObject<{
111
111
  argv: z.ZodArray<z.ZodString>;
@@ -287,13 +287,13 @@ Troubleshooting:
287
287
  Generated invocations include:
288
288
 
289
289
  ```text
290
- OpenCode: /quick, /execute, /inspect
290
+ OpenCode: /moka-quick, /moka-execute, /moka-inspect
291
291
  Codex: $quick, $execute, $inspect
292
292
  ```
293
293
 
294
294
  `moka init` and `moka install-commands --host opencode` generate:
295
295
 
296
- - `.opencode/commands/<entrypoint>.md` for `/quick`, `/execute`, and `/inspect`
296
+ - `.opencode/commands/moka-<entrypoint>.md` for `/moka-quick`, `/moka-execute`, and `/moka-inspect`
297
297
  - `.opencode/agents/*.md` for primary and subagent profiles with explicit
298
298
  `permission` maps, `task` grants, and denied ungranted tools
299
299
  - `.opencode/skills/*/SKILL.md` from `npx skills add`, not Moka generation
@@ -15,7 +15,7 @@ moka install-commands --host all --check
15
15
 
16
16
  | Host | Generated resources | Invocation | Mechanical path |
17
17
  | -------- | -------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------- |
18
- | OpenCode | `.opencode/commands/<entrypoint>.md`, `.opencode/agents/*.md`, `.opencode/opencode.json` | `/quick <task>`, `/execute <task>`, `/inspect <task>` | Project commands run a primary orchestrator and OpenCode native subagents with package-owned skill, MCP, permission, and LSP projection. |
18
+ | OpenCode | `.opencode/commands/moka-<entrypoint>.md`, `.opencode/agents/*.md`, `.opencode/opencode.json` | `/moka-quick <task>`, `/moka-execute <task>`, `/moka-inspect <task>` | Project commands run a primary orchestrator and OpenCode native subagents with package-owned skill, MCP, permission, and LSP projection. |
19
19
 
20
20
  ## Projection Rules
21
21
 
package/package.json CHANGED
@@ -122,7 +122,7 @@
122
122
  "prepack": "bun run build:cli"
123
123
  },
124
124
  "type": "module",
125
- "version": "1.27.18",
125
+ "version": "1.27.19",
126
126
  "description": "Config-driven multi-agent pipeline runner for repository work",
127
127
  "main": "./dist/index.js",
128
128
  "types": "./dist/index.d.ts",