@oisincoveney/pipeline 3.15.5 → 3.16.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.
Files changed (60) hide show
  1. package/defaults/profiles.yaml +2 -2
  2. package/dist/argo-submit.d.ts +9 -5
  3. package/dist/argo-submit.js +5 -2
  4. package/dist/cli/program.js +1 -1
  5. package/dist/cli/run-commands.js +1 -1
  6. package/dist/cli/run-service.js +22 -21
  7. package/dist/cli/submit-options.js +1 -1
  8. package/dist/config/schemas.d.ts +1 -1
  9. package/dist/hooks.d.ts +1 -1
  10. package/dist/install-hooks.js +1 -1
  11. package/dist/install-rules.js +119 -40
  12. package/dist/moka-global-config.d.ts +11 -6
  13. package/dist/moka-global-config.js +25 -6
  14. package/dist/moka-submit.d.ts +22 -2
  15. package/dist/moka-submit.js +2 -0
  16. package/dist/pipeline-init.js +10 -6
  17. package/dist/pipeline-runtime.d.ts +40 -1
  18. package/dist/pipeline-runtime.js +60 -1
  19. package/dist/planning/generate.d.ts +6 -1
  20. package/dist/planning/generate.js +10 -3
  21. package/dist/remote/argo/model.d.ts +4 -0
  22. package/dist/remote/argo/model.js +12 -1
  23. package/dist/remote/argo/policy.js +8 -1
  24. package/dist/remote/submit/argo-submission.d.ts +4 -0
  25. package/dist/remote/submit/argo-submission.js +1 -0
  26. package/dist/remote/submit/compilation.d.ts +14 -3
  27. package/dist/remote/submit/compilation.js +3 -4
  28. package/dist/remote/submit/service.d.ts +12 -1
  29. package/dist/remote/submit/service.js +46 -6
  30. package/dist/run-control/contracts.d.ts +86 -1
  31. package/dist/run-control/logical-segment.js +2 -8
  32. package/dist/run-control/next-node.js +45 -49
  33. package/dist/run-control/postgres/postgres-run-control-store.js +4 -6
  34. package/dist/run-control/resume-command.js +42 -3
  35. package/dist/run-control/run-control-store.js +11 -35
  36. package/dist/run-control/run-record.js +35 -0
  37. package/dist/run-control/runtime-reporter.js +7 -4
  38. package/dist/run-control/store-fs-effects.js +3 -48
  39. package/dist/run-control/store-manifest.js +5 -72
  40. package/dist/run-control/store-paths.js +4 -28
  41. package/dist/run-control/store.js +9 -165
  42. package/dist/run-control/submit-result.js +6 -5
  43. package/dist/run-control/supervisor.js +1 -2
  44. package/dist/runner-command/lifecycle-context.js +7 -3
  45. package/dist/runner-command/lifecycle.js +56 -2
  46. package/dist/runner-command/run.js +165 -3
  47. package/dist/runner-command-contract.d.ts +2 -2
  48. package/dist/runner-event-schema.d.ts +2 -2
  49. package/dist/runtime/durable-store/acquisition.js +2 -3
  50. package/dist/runtime/durable-store/durable-store.d.ts +1 -0
  51. package/dist/runtime/durable-store/postgres/postgres-store.js +4 -14
  52. package/dist/runtime/journal-acquisition.js +1 -1
  53. package/dist/runtime/run-journal.js +23 -0
  54. package/dist/runtime/services/run-journal-file-service.js +20 -0
  55. package/dist/runtime/step/step-node.js +53 -0
  56. package/docs/moka-orchestrator-design.md +35 -4
  57. package/docs/operator-guide.md +50 -22
  58. package/docs/run-control.md +40 -0
  59. package/package.json +17 -5
  60. package/dist/runtime/durable-store/durable-store.js +0 -53
@@ -154,7 +154,7 @@ profiles:
154
154
  runner: opencode
155
155
  scheduling_roles: [implementation]
156
156
  description: Add focused failing tests for the requested behavior.
157
- timeout_ms: 900000
157
+ timeout_ms: 1800000
158
158
  instructions: { inline: "This scheduled node is already dispatched by Moka; do direct repository work inside the current workspace. Do not invoke `moka run`, `moka submit`, `$dispatch`, `$scope`, `$execute`, or any nested Moka/workflow supervisor from this node. 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/**. Tool findings about lint, types, complexity, or dead code must be resolved at source; comments must not hide them. If a gate flags your test, restructure the test (e.g. move restricted imports into shared support/fixture helpers). 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." }
159
159
  skills: [test]
160
160
  mcp_servers: [pipeline-gateway]
@@ -169,7 +169,7 @@ profiles:
169
169
  runner: opencode
170
170
  scheduling_roles: [implementation]
171
171
  description: Implement production code until the failing tests pass.
172
- timeout_ms: 900000
172
+ timeout_ms: 1800000
173
173
  instructions: { inline: "This scheduled node is already dispatched by Moka; do direct repository work inside the current workspace. Do not invoke `moka run`, `moka submit`, `$dispatch`, `$scope`, `$execute`, or any nested Moka/workflow supervisor from this node. Implement the smallest production change that makes the failing tests pass. Tool findings about lint, types, complexity, or dead code must be resolved at source; comments must not hide them. Reduce complexity by extracting helpers, remove genuinely dead code, and migrate off deprecated APIs rather than hiding the warning. 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." }
174
174
  skills: [trace, test, fix, library-first-development]
175
175
  mcp_servers: [pipeline-gateway]
@@ -5,6 +5,15 @@ import { z } from "zod";
5
5
 
6
6
  //#region src/argo-submit.d.ts
7
7
  declare const submitRunnerArgoWorkflowOptionsSchema: z.ZodObject<{
8
+ brokerAuth: z.ZodObject<{
9
+ secretKey: z.ZodDefault<z.ZodString>;
10
+ secretName: z.ZodString;
11
+ url: z.ZodDefault<z.ZodString>;
12
+ }, z.core.$strict>;
13
+ dbAuth: z.ZodOptional<z.ZodObject<{
14
+ secretKey: z.ZodDefault<z.ZodString>;
15
+ secretName: z.ZodString;
16
+ }, z.core.$strict>>;
8
17
  eventAuthSecretKey: z.ZodOptional<z.ZodString>;
9
18
  eventAuthSecretName: z.ZodOptional<z.ZodString>;
10
19
  generateName: z.ZodOptional<z.ZodString>;
@@ -20,11 +29,6 @@ declare const submitRunnerArgoWorkflowOptionsSchema: z.ZodObject<{
20
29
  kubeconfigPath: z.ZodOptional<z.ZodString>;
21
30
  name: z.ZodOptional<z.ZodString>;
22
31
  namespace: z.ZodString;
23
- brokerAuth: z.ZodObject<{
24
- secretKey: z.ZodDefault<z.ZodString>;
25
- secretName: z.ZodString;
26
- url: z.ZodDefault<z.ZodString>;
27
- }, z.core.$strict>;
28
32
  payloadJson: z.ZodString;
29
33
  scheduleYaml: z.ZodString;
30
34
  serviceAccountName: z.ZodOptional<z.ZodString>;
@@ -1,4 +1,5 @@
1
1
  import { ArgoGraphCompilerError, compileArgoExecutionGraph } from "./argo-graph.js";
2
+ import { dbAuthOptionSchema } from "./remote/argo/model.js";
2
3
  import { brokerAuthOptionSchema } from "./credentials/broker.js";
3
4
  import { compileScheduleArtifact, parseScheduleArtifact } from "./planning/generate.js";
4
5
  import { parseRunnerCommandPayload, runnerCommandPayloadSchema } from "./runner-command-contract.js";
@@ -24,6 +25,8 @@ const configMapSchema = z.object({
24
25
  }).strict()
25
26
  }).strict();
26
27
  const submitRunnerArgoWorkflowOptionsSchema = z.object({
28
+ brokerAuth: brokerAuthOptionSchema,
29
+ dbAuth: dbAuthOptionSchema.optional(),
27
30
  eventAuthSecretKey: z.string().min(1).optional(),
28
31
  eventAuthSecretName: z.string().min(1).optional(),
29
32
  generateName: z.string().min(1).optional(),
@@ -39,7 +42,6 @@ const submitRunnerArgoWorkflowOptionsSchema = z.object({
39
42
  kubeconfigPath: z.string().min(1).optional(),
40
43
  name: z.string().min(1).optional(),
41
44
  namespace: z.string().min(1),
42
- brokerAuth: brokerAuthOptionSchema,
43
45
  payloadJson: z.string().min(1),
44
46
  scheduleYaml: z.string().min(1),
45
47
  serviceAccountName: z.string().min(1).optional()
@@ -78,6 +80,8 @@ function submitRunnerArgoWorkflowEffect(rawOptions, dependencies) {
78
80
  "pipeline.oisin.dev/ticket-project": payload.run.project,
79
81
  "pipeline.oisin.dev/ticket-title": payload.task.title
80
82
  } : {},
83
+ brokerAuth: options.brokerAuth,
84
+ dbAuth: options.dbAuth,
81
85
  eventAuthSecretKey: options.eventAuthSecretKey,
82
86
  eventAuthSecretName: options.eventAuthSecretName,
83
87
  generateName: options.generateName,
@@ -89,7 +93,6 @@ function submitRunnerArgoWorkflowEffect(rawOptions, dependencies) {
89
93
  labels,
90
94
  name: options.name,
91
95
  namespace: options.namespace,
92
- brokerAuth: options.brokerAuth,
93
96
  payloadConfigMapName,
94
97
  plan: compiled.plan,
95
98
  scheduleConfigMapName: scheduleArtifactConfigMapName,
@@ -4,13 +4,13 @@ import { registerBenchCommand } from "../commands/bench-command.js";
4
4
  import { registerConfiguredEntrypointCommands } from "../commands/pipeline-command.js";
5
5
  import { registerRunnerCommandCommand } from "../commands/runner-command-command.js";
6
6
  import { registerTicketCommand } from "../commands/ticket-command.js";
7
+ import { addMokaSubmitOptions, runMokaSubmitFromCli } from "./submit-options.js";
7
8
  import { registerRunControlCommands } from "../run-control/commands.js";
8
9
  import { registerBootstrapCommands } from "./bootstrap-commands.js";
9
10
  import { registerLoopCommand } from "./loop-commands.js";
10
11
  import { registerMcpGatewayCommands } from "./mcp-gateway-commands.js";
11
12
  import { registerPlanCommands } from "./plan-commands.js";
12
13
  import { execute } from "./run-service.js";
13
- import { addMokaSubmitOptions, runMokaSubmitFromCli } from "./submit-options.js";
14
14
  import { printMokaSubmitResult, registerRunCommands } from "./run-commands.js";
15
15
  import { Effect } from "effect";
16
16
  import { readFileSync } from "node:fs";
@@ -1,7 +1,7 @@
1
1
  import { MOKA_RUN_EFFORTS, MOKA_RUN_TARGETS, resolveMokaRun } from "./run-resolver.js";
2
+ import { runMokaSubmitFromCli } from "./submit-options.js";
2
3
  import { dispatchMokaRunCommand } from "./run-command.js";
3
4
  import { execute, runDetachedResolvedTask, runLocalResolvedTask } from "./run-service.js";
4
- import { runMokaSubmitFromCli } from "./submit-options.js";
5
5
  import { Option } from "commander";
6
6
  //#region src/cli/run-commands.ts
7
7
  function registerRunCommands(program, options = {}) {
@@ -1,15 +1,15 @@
1
1
  import { flattenNodes } from "../planning/graph.js";
2
2
  import { loadPipelineConfig } from "../config/load.js";
3
3
  import "../config.js";
4
+ import { withRunControlStoreScoped } from "../run-control/run-control-store.js";
4
5
  import { compileWorkflowPlan } from "../planning/compile.js";
5
6
  import { generateRuntimeRunId, resolveWorkflowSelection } from "../runtime/context/context.js";
6
7
  import "../runtime/context/index.js";
7
- import { compileScheduleArtifact, generateScheduleArtifact, parseScheduleArtifact } from "../planning/generate.js";
8
- import { withRunControlStoreScoped } from "../run-control/run-control-store.js";
8
+ import { compileScheduleArtifact, generateScheduleArtifactInMemory, parseScheduleArtifact } from "../planning/generate.js";
9
9
  import { runPipelineFromConfig } from "../pipeline-runtime.js";
10
+ import { createRunStoreRuntimeReporter } from "../run-control/runtime-reporter.js";
10
11
  import { createTerminalRuntimeReporter, formatRuntimeFailure, formatRuntimeResult } from "./format.js";
11
12
  import { startDetachedRunController } from "../run-control/detach.js";
12
- import { createRunStoreRuntimeReporter } from "../run-control/runtime-reporter.js";
13
13
  import { createRunControlSupervisor } from "../run-control/supervisor.js";
14
14
  import { Effect } from "effect";
15
15
  import { readFileSync } from "node:fs";
@@ -82,14 +82,7 @@ function persistDetachedRunController(input) {
82
82
  yield* store.createRun(detachedRunRecord(input));
83
83
  const launch = yield* Effect.tryPromise({
84
84
  catch: (error) => error,
85
- try: () => startDetachedRunController({
86
- entrypoint: input.prepared.entrypoint,
87
- runId: input.runId,
88
- schedule: input.prepared.schedule,
89
- task: input.task,
90
- workflow: input.prepared.workflow,
91
- workspaceRoot: input.worktreePath
92
- })
85
+ try: () => startDetachedRunController(detachedRunControllerInput(input))
93
86
  });
94
87
  yield* store.updateRunController({
95
88
  controller: {
@@ -103,6 +96,16 @@ function persistDetachedRunController(input) {
103
96
  });
104
97
  })));
105
98
  }
99
+ function detachedRunControllerInput(input) {
100
+ return {
101
+ entrypoint: input.prepared.entrypoint,
102
+ runId: input.runId,
103
+ ...input.prepared.schedule ? { schedule: input.prepared.schedule } : {},
104
+ task: input.task,
105
+ workflow: input.prepared.workflow,
106
+ workspaceRoot: input.worktreePath
107
+ };
108
+ }
106
109
  function detachedRunRecord(input) {
107
110
  return {
108
111
  ...resolvedRunControlOptions(input.runControl),
@@ -149,16 +152,16 @@ async function runConfiguredPipeline(rawInputs) {
149
152
  });
150
153
  return;
151
154
  }
152
- const result = await generateScheduleArtifact({
155
+ const result = await generateScheduleArtifactInMemory({
153
156
  config,
154
157
  entrypointId: scheduledEntrypoint,
155
158
  runId: inputs.runId,
156
159
  task: inputs.task,
157
160
  worktreePath: inputs.worktreePath
158
161
  });
159
- console.log(`Schedule generated: ${result.path}`);
160
- const scheduleYaml = readFileSync(resolve(inputs.worktreePath, result.path), "utf8");
161
- const compiled = compileScheduleArtifact(config, parseScheduleArtifact(scheduleYaml, result.path), inputs.worktreePath);
162
+ console.log("Schedule generated in memory");
163
+ const scheduleYaml = result.yaml;
164
+ const compiled = compileScheduleArtifact(config, parseScheduleArtifact(scheduleYaml, "schedule.yaml"), inputs.worktreePath);
162
165
  await runAndPrintPipeline({
163
166
  ...inputs,
164
167
  config: compiled.config,
@@ -327,20 +330,18 @@ async function prepareDetachedRun(input) {
327
330
  entrypoint: input.execution.entrypoint,
328
331
  workflow: input.execution.workflow
329
332
  };
330
- const result = await generateScheduleArtifact({
333
+ const result = await generateScheduleArtifactInMemory({
331
334
  config: input.config,
332
335
  entrypointId: scheduledEntrypoint,
333
336
  runId: input.runId,
334
337
  task: input.task,
335
338
  worktreePath: input.worktreePath
336
339
  });
337
- console.log(`Schedule generated: ${result.path}`);
338
- const schedule = resolve(input.worktreePath, result.path);
339
- const scheduleYaml = readFileSync(schedule, "utf8");
340
- const compiled = compileScheduleArtifact(input.config, parseScheduleArtifact(scheduleYaml, result.path), input.worktreePath);
340
+ console.log("Schedule generated in memory");
341
+ const scheduleYaml = result.yaml;
342
+ const compiled = compileScheduleArtifact(input.config, parseScheduleArtifact(scheduleYaml, "schedule.yaml"), input.worktreePath);
341
343
  return {
342
344
  config: compiled.config,
343
- schedule,
344
345
  scheduleArtifact: scheduleYaml,
345
346
  workflow: compiled.workflowId
346
347
  };
@@ -93,4 +93,4 @@ function parseImagePullPolicy(value) {
93
93
  return "Always";
94
94
  }
95
95
  //#endregion
96
- export { addMokaSubmitOptions, runMokaSubmitFromCli };
96
+ export { addMokaSubmitOptions, buildMokaSubmitInputFromCli, runMokaSubmitFromCli };
@@ -503,8 +503,8 @@ declare const configSchema: z.ZodObject<{
503
503
  schedules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
504
504
  description: z.ZodOptional<z.ZodString>;
505
505
  baseline: z.ZodEnum<{
506
- execute: "execute";
507
506
  quick: "quick";
507
+ execute: "execute";
508
508
  }>;
509
509
  max_parallel_nodes: z.ZodOptional<z.ZodNumber>;
510
510
  node_catalog: z.ZodOptional<z.ZodString>;
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>;
@@ -5,8 +5,8 @@ import { existsSync, readFileSync, statSync } from "node:fs";
5
5
  import { execa } from "execa";
6
6
  import { tmpdir } from "node:os";
7
7
  import { dirname, join, relative } from "node:path";
8
- import { createHash } from "node:crypto";
9
8
  import { mkdir, mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
9
+ import { createHash } from "node:crypto";
10
10
  //#region src/install-hooks.ts
11
11
  const DEFAULT_HOOK_INSTALL_SOURCE = AGENT_ASSET_SOURCE;
12
12
  const HOOK_HOSTS = [
@@ -1,7 +1,8 @@
1
+ import { resolveHarnessTarget } from "./install-commands/shared.js";
1
2
  import { AGENT_ASSET_SOURCE, AGENT_RULES_DIR } from "./agent-assets.js";
2
3
  import { execa } from "execa";
3
- import { homedir, tmpdir } from "node:os";
4
- import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { dirname, join } from "node:path";
5
6
  import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
6
7
  //#region src/install-rules.ts
7
8
  const DEFAULT_RULES_INSTALL_SOURCE = AGENT_ASSET_SOURCE;
@@ -12,6 +13,24 @@ const RULESYNC_TARGETS = [
12
13
  "geminicli",
13
14
  "opencode"
14
15
  ];
16
+ const RULE_OUTPUTS = [
17
+ {
18
+ generatedPath: ".claude/CLAUDE.md",
19
+ targetPath: ".claude/CLAUDE.md"
20
+ },
21
+ {
22
+ generatedPath: ".codex/AGENTS.md",
23
+ targetPath: ".codex/AGENTS.md"
24
+ },
25
+ {
26
+ generatedPath: ".gemini/GEMINI.md",
27
+ targetPath: ".gemini/GEMINI.md"
28
+ },
29
+ {
30
+ generatedPath: ".config/opencode/AGENTS.md",
31
+ targetPath: ".opencode/AGENTS.md"
32
+ }
33
+ ];
15
34
  async function cloneRulesRepository(targetDir) {
16
35
  await execa("gh", [
17
36
  "repo",
@@ -71,50 +90,110 @@ ${(await Promise.all(entries.map(async (name) => {
71
90
  await mkdir(rulesyncRulesDir, { recursive: true });
72
91
  await writeFile(join(rulesyncRulesDir, "_root.md"), rootContent);
73
92
  }
93
+ async function withRulesyncHome(useHome) {
94
+ const home = await mkdtemp(join(tmpdir(), "moka-rules-home-"));
95
+ try {
96
+ return await useHome(home);
97
+ } finally {
98
+ await rm(home, {
99
+ force: true,
100
+ recursive: true
101
+ });
102
+ }
103
+ }
104
+ function rulesyncArgs(options) {
105
+ const args = [
106
+ "generate",
107
+ "-t",
108
+ RULESYNC_TARGETS.join(","),
109
+ "-f",
110
+ "rules",
111
+ "--delete",
112
+ "--global"
113
+ ];
114
+ if (options.dryRun) args.push("--dry-run");
115
+ if (options.silent) args.push("--silent");
116
+ return args;
117
+ }
118
+ async function runRulesyncGenerate(input) {
119
+ await input.runner(rulesyncArgs(input), {
120
+ cwd: input.source,
121
+ env: {
122
+ ...process.env,
123
+ HOME_DIR: input.home
124
+ }
125
+ });
126
+ }
127
+ function ruleItems(action) {
128
+ return RULE_OUTPUTS.map((output) => ({
129
+ action,
130
+ path: resolveHarnessTarget(output.targetPath)
131
+ }));
132
+ }
133
+ function readGeneratedRuleFiles(home) {
134
+ return Promise.all(RULE_OUTPUTS.map(async (output) => ({
135
+ content: await readFile(join(home, output.generatedPath), "utf8"),
136
+ path: resolveHarnessTarget(output.targetPath)
137
+ })));
138
+ }
139
+ async function writeGeneratedRuleFiles(files) {
140
+ for (const file of files) {
141
+ await mkdir(dirname(file.path), { recursive: true });
142
+ await writeFile(file.path, file.content);
143
+ }
144
+ }
145
+ async function installedRuleAction(file) {
146
+ try {
147
+ return await readFile(file.path, "utf8") === file.content ? "unchanged" : "update";
148
+ } catch {
149
+ return "create";
150
+ }
151
+ }
152
+ async function assertInstalledRulesCurrent(files) {
153
+ const changed = (await Promise.all(files.map(async (file) => ({
154
+ action: await installedRuleAction(file),
155
+ path: file.path
156
+ })))).filter((item) => item.action !== "unchanged");
157
+ if (changed.length === 0) return;
158
+ throw new Error(["Installed rule files are not up to date.", ...changed.map((item) => `- ${item.path}: ${item.action}`)].join("\n"));
159
+ }
74
160
  function installRules(options = {}) {
75
161
  const runner = options.rulesyncRunner ?? defaultRulesyncRunner;
76
162
  return withRulesSource(options.sourceOverride, async (source) => {
77
163
  await buildRootRule(source);
78
- const home = process.env.HOME_DIR ?? homedir();
79
- const args = [
80
- "generate",
81
- "-t",
82
- RULESYNC_TARGETS.join(","),
83
- "-f",
84
- "rules",
85
- "--delete"
86
- ];
87
- if (options.dryRun) args.push("--dry-run");
88
- if (options.check) args.push("--check");
89
- await runner(args, {
90
- cwd: source,
91
- env: {
92
- ...process.env,
93
- HOME_DIR: home
164
+ return withRulesyncHome(async (home) => {
165
+ if (options.dryRun) {
166
+ await runRulesyncGenerate({
167
+ dryRun: true,
168
+ home,
169
+ runner,
170
+ source
171
+ });
172
+ return {
173
+ items: ruleItems("skip"),
174
+ source: DEFAULT_RULES_INSTALL_SOURCE
175
+ };
176
+ }
177
+ await runRulesyncGenerate({
178
+ home,
179
+ runner,
180
+ silent: options.check,
181
+ source
182
+ });
183
+ const files = await readGeneratedRuleFiles(home);
184
+ if (options.check) {
185
+ await assertInstalledRulesCurrent(files);
186
+ return {
187
+ items: ruleItems("skip"),
188
+ source: DEFAULT_RULES_INSTALL_SOURCE
189
+ };
94
190
  }
191
+ await writeGeneratedRuleFiles(files);
192
+ return {
193
+ items: ruleItems("generate"),
194
+ source: DEFAULT_RULES_INSTALL_SOURCE
195
+ };
95
196
  });
96
- const action = options.dryRun ?? options.check ? "skip" : "generate";
97
- return {
98
- items: [
99
- {
100
- action,
101
- path: join(home, ".claude/CLAUDE.md")
102
- },
103
- {
104
- action,
105
- path: join(home, ".codex/AGENTS.md")
106
- },
107
- {
108
- action,
109
- path: join(home, ".gemini/GEMINI.md")
110
- },
111
- {
112
- action,
113
- path: join(home, ".config/opencode/AGENTS.md")
114
- }
115
- ],
116
- source: DEFAULT_RULES_INSTALL_SOURCE
117
- };
118
197
  });
119
198
  }
120
199
  //#endregion
@@ -1,3 +1,4 @@
1
+ import { Effect } from "effect";
1
2
  import { z } from "zod";
2
3
 
3
4
  //#region src/moka-global-config.d.ts
@@ -29,20 +30,24 @@ declare const mokaGlobalConfigSchema: z.ZodObject<{
29
30
  }, z.core.$strict>;
30
31
  type MokaGlobalConfig = z.infer<typeof mokaGlobalConfigSchema>;
31
32
  declare function mokaGlobalConfigPath(homeDir?: string): string;
33
+ declare class MokaDbUrlRequiredError extends Error {
34
+ readonly code = "db.url-required";
35
+ constructor();
36
+ }
37
+ declare function requireMokaDbUrl(dbUrl: string | undefined): Effect.Effect<string, MokaDbUrlRequiredError>;
32
38
  /**
33
39
  * Resolve the durable-substrate `db.url` toggle for run-control store selection.
34
40
  *
35
- * Returns the configured Postgres url, or `undefined` for the defined default
36
- * (filesystem store) when the global config is absent or carries no `db.url`.
41
+ * Returns the configured Postgres url, or `undefined` when the global config is
42
+ * absent or carries no `db.url`.
37
43
  * The whole `momokaya` schema is deliberately NOT validated — only the `db`
38
44
  * section is — so an unrelated invalid/missing field never breaks run-control
39
45
  * reads. A genuine load fault (corrupt YAML, a malformed `db.url`) is surfaced
40
- * to stderr and falls back to the filesystem store rather than crashing the
41
- * command; this is the presence-toggle's resilience, not silent error-swallowing
42
- * (the fault is always logged).
46
+ * to stderr and returns `undefined`; the required-DB policy then fails at the
47
+ * runtime-state boundary with `db.url-required`.
43
48
  */
44
49
  declare function loadMokaDbUrl(): string | undefined;
45
50
  declare function loadMokaGlobalConfig(): MokaGlobalConfig | null;
46
51
  declare function parseMokaGlobalConfig(source: string, sourcePath: string): MokaGlobalConfig;
47
52
  //#endregion
48
- export { MOKA_GLOBAL_CONFIG_PATH, MokaGlobalConfig, loadMokaDbUrl, loadMokaGlobalConfig, mokaGlobalConfigPath, mokaGlobalConfigSchema, parseMokaGlobalConfig };
53
+ export { MOKA_GLOBAL_CONFIG_PATH, MokaDbUrlRequiredError, MokaGlobalConfig, loadMokaDbUrl, loadMokaGlobalConfig, mokaGlobalConfigPath, mokaGlobalConfigSchema, parseMokaGlobalConfig, requireMokaDbUrl };
@@ -37,20 +37,39 @@ const mokaGlobalConfigSchema = z.object({ momokaya: z.object({
37
37
  function mokaGlobalConfigPath(homeDir = homedir()) {
38
38
  return join(homeDir, MOKA_GLOBAL_CONFIG_PATH);
39
39
  }
40
+ var MokaDbUrlRequiredError = class extends Error {
41
+ code = "db.url-required";
42
+ constructor() {
43
+ super(`db.url-required: momokaya.db.url is required for Moka run-control runtime state. Configure momokaya.db.url in ${MOKA_GLOBAL_CONFIG_PATH}.`);
44
+ this.name = "MokaDbUrlRequiredError";
45
+ }
46
+ };
47
+ function requireMokaDbUrl(dbUrl) {
48
+ if (dbUrl === void 0) return Effect.fail(new MokaDbUrlRequiredError());
49
+ return Effect.succeed(dbUrl);
50
+ }
40
51
  const mokaDbUrlReadSchema = z.object({ momokaya: z.object({ db: mokaDbGlobalConfigSchema.optional() }).optional() });
41
52
  /**
42
53
  * Resolve the durable-substrate `db.url` toggle for run-control store selection.
43
54
  *
44
- * Returns the configured Postgres url, or `undefined` for the defined default
45
- * (filesystem store) when the global config is absent or carries no `db.url`.
55
+ * Returns the configured Postgres url, or `undefined` when the global config is
56
+ * absent or carries no `db.url`.
46
57
  * The whole `momokaya` schema is deliberately NOT validated — only the `db`
47
58
  * section is — so an unrelated invalid/missing field never breaks run-control
48
59
  * reads. A genuine load fault (corrupt YAML, a malformed `db.url`) is surfaced
49
- * to stderr and falls back to the filesystem store rather than crashing the
50
- * command; this is the presence-toggle's resilience, not silent error-swallowing
51
- * (the fault is always logged).
60
+ * to stderr and returns `undefined`; the required-DB policy then fails at the
61
+ * runtime-state boundary with `db.url-required`.
52
62
  */
53
63
  function loadMokaDbUrl() {
64
+ const envUrl = process.env.MOKA_DB_URL;
65
+ if (envUrl !== void 0) {
66
+ const parsed = mokaDbGlobalConfigSchema.safeParse({ url: envUrl });
67
+ if (!parsed.success) {
68
+ process.stderr.write(`run-control: MOKA_DB_URL is invalid: ${parsed.error.message}\n`);
69
+ return;
70
+ }
71
+ return parsed.data.url;
72
+ }
54
73
  const configPath = mokaGlobalConfigPath();
55
74
  const program = Effect.gen(function* () {
56
75
  const configIo = yield* ConfigIoService;
@@ -93,4 +112,4 @@ function parseMokaGlobalConfigEffect(source, sourcePath) {
93
112
  });
94
113
  }
95
114
  //#endregion
96
- export { MOKA_GLOBAL_CONFIG_PATH, loadMokaDbUrl, loadMokaGlobalConfig, mokaGlobalConfigPath, mokaGlobalConfigSchema, parseMokaGlobalConfig };
115
+ export { MOKA_GLOBAL_CONFIG_PATH, MokaDbUrlRequiredError, loadMokaDbUrl, loadMokaGlobalConfig, mokaGlobalConfigPath, mokaGlobalConfigSchema, parseMokaGlobalConfig, requireMokaDbUrl };
@@ -106,6 +106,10 @@ declare const mokaSubmitBaseOptionsSchema: z.ZodObject<{
106
106
  secretName: z.ZodString;
107
107
  url: z.ZodDefault<z.ZodString>;
108
108
  }, z.core.$strict>;
109
+ dbAuth: z.ZodOptional<z.ZodObject<{
110
+ secretKey: z.ZodDefault<z.ZodString>;
111
+ secretName: z.ZodString;
112
+ }, z.core.$strict>>;
109
113
  delivery: z.ZodDefault<z.ZodObject<{
110
114
  mode: z.ZodDefault<z.ZodEnum<{
111
115
  "create-new-pr": "create-new-pr";
@@ -211,6 +215,10 @@ declare const mokaGraphSubmitOptionsSchema: z.ZodObject<{
211
215
  secretName: z.ZodString;
212
216
  url: z.ZodDefault<z.ZodString>;
213
217
  }, z.core.$strict>;
218
+ dbAuth: z.ZodOptional<z.ZodObject<{
219
+ secretKey: z.ZodDefault<z.ZodString>;
220
+ secretName: z.ZodString;
221
+ }, z.core.$strict>>;
214
222
  delivery: z.ZodDefault<z.ZodObject<{
215
223
  mode: z.ZodDefault<z.ZodEnum<{
216
224
  "create-new-pr": "create-new-pr";
@@ -310,8 +318,8 @@ declare const mokaGraphSubmitOptionsSchema: z.ZodObject<{
310
318
  }, z.core.$strict>>;
311
319
  serviceAccountName: z.ZodOptional<z.ZodString>;
312
320
  mode: z.ZodEnum<{
313
- quick: "quick";
314
321
  full: "full";
322
+ quick: "quick";
315
323
  }>;
316
324
  schedulePath: z.ZodOptional<z.ZodString>;
317
325
  scheduleYaml: z.ZodOptional<z.ZodString>;
@@ -333,6 +341,10 @@ declare const mokaCommandSubmitOptionsSchema: z.ZodObject<{
333
341
  secretName: z.ZodString;
334
342
  url: z.ZodDefault<z.ZodString>;
335
343
  }, z.core.$strict>;
344
+ dbAuth: z.ZodOptional<z.ZodObject<{
345
+ secretKey: z.ZodDefault<z.ZodString>;
346
+ secretName: z.ZodString;
347
+ }, z.core.$strict>>;
336
348
  delivery: z.ZodDefault<z.ZodObject<{
337
349
  mode: z.ZodDefault<z.ZodEnum<{
338
350
  "create-new-pr": "create-new-pr";
@@ -450,6 +462,10 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
450
462
  secretName: z.ZodString;
451
463
  url: z.ZodDefault<z.ZodString>;
452
464
  }, z.core.$strict>;
465
+ dbAuth: z.ZodOptional<z.ZodObject<{
466
+ secretKey: z.ZodDefault<z.ZodString>;
467
+ secretName: z.ZodString;
468
+ }, z.core.$strict>>;
453
469
  delivery: z.ZodDefault<z.ZodObject<{
454
470
  mode: z.ZodDefault<z.ZodEnum<{
455
471
  "create-new-pr": "create-new-pr";
@@ -549,8 +565,8 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
549
565
  }, z.core.$strict>>;
550
566
  serviceAccountName: z.ZodOptional<z.ZodString>;
551
567
  mode: z.ZodEnum<{
552
- quick: "quick";
553
568
  full: "full";
569
+ quick: "quick";
554
570
  }>;
555
571
  schedulePath: z.ZodOptional<z.ZodString>;
556
572
  scheduleYaml: z.ZodOptional<z.ZodString>;
@@ -571,6 +587,10 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
571
587
  secretName: z.ZodString;
572
588
  url: z.ZodDefault<z.ZodString>;
573
589
  }, z.core.$strict>;
590
+ dbAuth: z.ZodOptional<z.ZodObject<{
591
+ secretKey: z.ZodDefault<z.ZodString>;
592
+ secretName: z.ZodString;
593
+ }, z.core.$strict>>;
574
594
  delivery: z.ZodDefault<z.ZodObject<{
575
595
  mode: z.ZodDefault<z.ZodEnum<{
576
596
  "create-new-pr": "create-new-pr";
@@ -1,3 +1,4 @@
1
+ import { dbAuthOptionSchema } from "./remote/argo/model.js";
1
2
  import { brokerAuthOptionSchema } from "./credentials/broker.js";
2
3
  import { runnerDeliverySchema, runnerHookPolicySchema, runnerRepositoryContextSchema, runnerRunIdentitySchema, runnerTaskSchema } from "./runner-command-contract.js";
3
4
  import { workflowSubmitResultSchema } from "./workflow-submit-contract.js";
@@ -46,6 +47,7 @@ const mokaSubmitHookPolicySchema = runnerHookPolicySchema;
46
47
  const mokaSubmitResultSchema = workflowSubmitResultSchema;
47
48
  const mokaSubmitBaseOptionsSchema = z.object({
48
49
  brokerAuth: brokerAuthOptionSchema,
50
+ dbAuth: dbAuthOptionSchema.optional(),
49
51
  delivery: runnerDeliverySchema.default({
50
52
  mode: "create-new-pr",
51
53
  pullRequest: false
@@ -39,12 +39,8 @@ function hookInstallerFiles(result) {
39
39
  }
40
40
  async function initPipelineProject(options = {}) {
41
41
  const cwd = options.cwd ?? process.cwd();
42
- const { check, dryRun, force } = options;
43
- const installerFlags = {
44
- check,
45
- dryRun,
46
- force
47
- };
42
+ const { check, dryRun } = options;
43
+ const installerFlags = initInstallerFlags(options);
48
44
  if (!(check || dryRun)) await (options.skillInstaller ?? installDefaultSkills)(cwd);
49
45
  const result = await installCommands({
50
46
  cwd,
@@ -59,6 +55,14 @@ async function initPipelineProject(options = {}) {
59
55
  ...rulesResult.items.map((item) => item.path)
60
56
  ] };
61
57
  }
58
+ function initInstallerFlags(options) {
59
+ const { check, dryRun } = options;
60
+ return {
61
+ check,
62
+ dryRun,
63
+ force: options.force ?? !(check || dryRun)
64
+ };
65
+ }
62
66
  const INIT_RESULT_COPY = {
63
67
  install: {
64
68
  headline: "Initialized package-owned pipeline support:",