@oisincoveney/pipeline 3.13.0 → 3.14.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/opencode-ecosystem.yaml +2 -12
- package/defaults/pipeline.yaml +0 -4
- package/dist/argo-submit.d.ts +2 -4
- package/dist/argo-submit.js +1 -5
- package/dist/argo-workflow.d.ts +2 -7
- package/dist/argo-workflow.js +16 -48
- package/dist/broker-auth.js +4 -3
- package/dist/cli/doctor.js +2 -2
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +58 -55
- package/dist/cli/submit-options.js +7 -4
- package/dist/cluster-doctor.js +4 -5
- package/dist/codex-auth-sync.js +16 -51
- package/dist/commands/ticket/complete.js +61 -0
- package/dist/commands/ticket/create.js +115 -0
- package/dist/commands/ticket/graph-check.js +16 -0
- package/dist/commands/ticket/next.js +43 -0
- package/dist/commands/ticket/sequence.js +18 -0
- package/dist/commands/ticket/shared.d.ts +14 -0
- package/dist/commands/ticket/shared.js +77 -0
- package/dist/commands/ticket/start.js +94 -0
- package/dist/commands/ticket-command.d.ts +2 -15
- package/dist/commands/ticket-command.js +14 -319
- package/dist/config/load.js +28 -7
- package/dist/config/schemas.d.ts +18 -21
- package/dist/config/schemas.js +2 -7
- package/dist/gates.js +1 -1
- package/dist/install-commands/claude-code.js +1 -1
- package/dist/install-commands/opencode.js +19 -1
- package/dist/install-commands.js +2 -2
- package/dist/install-hooks.js +1 -1
- package/dist/install-rules.js +1 -1
- package/dist/loop/controller-deps.js +1 -2
- package/dist/loop/loop-command.js +0 -2
- package/dist/loop/loop-controller-entrypoint.js +7 -4
- package/dist/moka-global-config.d.ts +19 -5
- package/dist/moka-global-config.js +43 -6
- package/dist/moka-submit.d.ts +12 -18
- package/dist/moka-submit.js +1 -5
- package/dist/pipeline-runtime.d.ts +22 -1
- package/dist/pipeline-runtime.js +38 -20
- package/dist/planning/generate.d.ts +20 -20
- package/dist/run-control/commands.js +78 -40
- package/dist/run-control/next-node.js +112 -0
- package/dist/run-control/postgres/postgres-run-control-store.js +243 -0
- package/dist/run-control/postgres/schema.js +52 -0
- package/dist/run-control/run-control-store.js +62 -0
- package/dist/run-control/runtime-reporter.js +10 -12
- package/dist/run-control/store.js +19 -8
- package/dist/run-control/submit-result.js +59 -0
- package/dist/run-control/supervisor.js +20 -16
- package/dist/run-state/opencode-accounts.js +8 -94
- package/dist/runner-command/run.js +29 -13
- package/dist/runner-command-contract.d.ts +2 -2
- package/dist/runner-event-schema.d.ts +10 -10
- package/dist/runner.d.ts +7 -0
- package/dist/runner.js +53 -19
- package/dist/runtime/contracts/contracts.d.ts +20 -1
- package/dist/runtime/contracts/index.d.ts +1 -1
- package/dist/runtime/durable-store/durable-store.js +53 -0
- package/dist/runtime/durable-store/postgres/postgres-store.js +133 -0
- package/dist/runtime/durable-store/postgres/schema.js +31 -0
- package/dist/runtime/events/events.js +1 -1
- package/dist/runtime/gates/adjudication/llm-judge.js +56 -0
- package/dist/runtime/gates/adjudication/structured-claim.js +52 -0
- package/dist/runtime/gates/adjudicator/adjudicator.js +69 -0
- package/dist/runtime/gates/adjudicator/index.js +39 -0
- package/dist/runtime/gates/contract.js +25 -0
- package/dist/runtime/gates/gates.js +15 -368
- package/dist/runtime/gates/index.js +3 -0
- package/dist/runtime/gates/kinds/acceptance/acceptance.js +109 -0
- package/dist/runtime/gates/kinds/acceptance/index.js +9 -0
- package/dist/runtime/gates/kinds/artifact/artifact.js +20 -0
- package/dist/runtime/gates/kinds/artifact/index.js +9 -0
- package/dist/runtime/gates/kinds/builtin/builtin.js +21 -0
- package/dist/runtime/gates/kinds/builtin/index.js +9 -0
- package/dist/runtime/gates/kinds/changed-files/changed-files.js +61 -0
- package/dist/runtime/gates/kinds/changed-files/index.js +9 -0
- package/dist/runtime/gates/kinds/command/command.js +21 -0
- package/dist/runtime/gates/kinds/command/index.js +9 -0
- package/dist/runtime/gates/kinds/json-schema/index.js +9 -0
- package/dist/runtime/gates/kinds/json-schema/json-schema.js +32 -0
- package/dist/runtime/gates/kinds/verdict/index.js +9 -0
- package/dist/runtime/gates/kinds/verdict/verdict.js +32 -0
- package/dist/runtime/gates/orchestrator.js +161 -0
- package/dist/runtime/gates/registry.js +47 -0
- package/dist/runtime/json-validation/json-validation.js +1 -1
- package/dist/runtime/node-protocol/node-protocol.js +83 -0
- package/dist/runtime/opencode-session-executor.js +48 -8
- package/dist/runtime/protected-paths/protected-paths.js +97 -0
- package/dist/runtime/run-journal.d.ts +21 -0
- package/dist/runtime/scheduler.js +13 -8
- package/dist/runtime/services/opencode-sdk-service.js +4 -0
- package/dist/runtime/services/repo-io-service.d.ts +2 -0
- package/dist/runtime/services/runner-command-io-service.js +1 -1
- package/dist/tickets/backlog-task-store.d.ts +2 -0
- package/dist/tickets/completion/complete-ticket.js +96 -0
- package/dist/tickets/ticket-graph.d.ts +2 -0
- package/dist/tickets/ticket-selection.d.ts +1 -0
- package/docs/mcp-gateway.md +6 -6
- package/docs/moka-orchestrator-design.md +79 -0
- package/docs/okteto-runner.md +1 -1
- package/docs/operator-guide.md +8 -5
- package/docs/pipeline-console-runner-contract.md +8 -7
- package/package.json +5 -2
- package/dist/runtime/run-journal.js +0 -28
- package/dist/runtime/services/run-journal-file-service.js +0 -20
|
@@ -59,15 +59,6 @@ ecosystem_code:
|
|
|
59
59
|
role: long-running goal mode with /goal slash command, persistent state, evidence-gated completion, and TUI sidebar
|
|
60
60
|
default_stack: true
|
|
61
61
|
source: https://www.npmjs.com/package/@prevalentware/opencode-goal-plugin
|
|
62
|
-
- id: oc-codex-multi-auth
|
|
63
|
-
name: oc-codex-multi-auth
|
|
64
|
-
package: oc-codex-multi-auth
|
|
65
|
-
plugin:
|
|
66
|
-
kind: npm
|
|
67
|
-
package: oc-codex-multi-auth@6.3.2
|
|
68
|
-
role: ChatGPT Plus/Pro OAuth with multi-account rotation, health checks, and Codex/GPT-5 routing for OpenCode
|
|
69
|
-
default_stack: true
|
|
70
|
-
source: https://github.com/ndycode/oc-codex-multi-auth
|
|
71
62
|
- id: opencode-snip
|
|
72
63
|
name: opencode-snip
|
|
73
64
|
role: prompt snippet and command-discipline helper patterns
|
|
@@ -86,9 +77,8 @@ ecosystem_code:
|
|
|
86
77
|
# Reasoning effort is no longer expressed as synthetic per-effort model ids.
|
|
87
78
|
# Pipeline config carries `reasoning_effort` as data on each node/profile and the
|
|
88
79
|
# runner applies it as the opencode model variant (`--variant` / prompt body
|
|
89
|
-
# `variant`) for the selected GPT-5 model.
|
|
90
|
-
#
|
|
91
|
-
# reasoning.encrypted_content), so moka registers no provider models here.
|
|
80
|
+
# `variant`) for the selected GPT-5 model. Broker auth owns Codex request
|
|
81
|
+
# options, so moka registers no provider models here.
|
|
92
82
|
mcp_backends:
|
|
93
83
|
- id: pipeline-gateway
|
|
94
84
|
locality: project-remote
|
package/defaults/pipeline.yaml
CHANGED
|
@@ -11,10 +11,6 @@ context_handoff:
|
|
|
11
11
|
# seeded by the node's task + handoff artifacts, within token_budget.
|
|
12
12
|
repo_map:
|
|
13
13
|
enabled: true
|
|
14
|
-
# durability: journal each terminal node result so a killed run resumes from the
|
|
15
|
-
# last passed node without re-running (or re-spending tokens on) finished work.
|
|
16
|
-
durability:
|
|
17
|
-
enabled: true
|
|
18
14
|
# parallel_worktrees: opt-in git-worktree isolation for parallel child nodes —
|
|
19
15
|
# each parallel child runs on its own branch with its own per-worktree opencode
|
|
20
16
|
# server so concurrent edits and sessions can't collide. OFF by default; enable
|
package/dist/argo-submit.d.ts
CHANGED
|
@@ -20,13 +20,11 @@ declare const submitRunnerArgoWorkflowOptionsSchema: z.ZodObject<{
|
|
|
20
20
|
kubeconfigPath: z.ZodOptional<z.ZodString>;
|
|
21
21
|
name: z.ZodOptional<z.ZodString>;
|
|
22
22
|
namespace: z.ZodString;
|
|
23
|
-
brokerAuth: z.
|
|
23
|
+
brokerAuth: z.ZodObject<{
|
|
24
24
|
secretKey: z.ZodDefault<z.ZodString>;
|
|
25
25
|
secretName: z.ZodString;
|
|
26
26
|
url: z.ZodDefault<z.ZodString>;
|
|
27
|
-
}, z.core.$strict
|
|
28
|
-
opencodeAuthSecretName: z.ZodOptional<z.ZodString>;
|
|
29
|
-
opencodeOpenaiAccountsSecretName: z.ZodOptional<z.ZodString>;
|
|
27
|
+
}, z.core.$strict>;
|
|
30
28
|
payloadJson: z.ZodString;
|
|
31
29
|
scheduleYaml: z.ZodString;
|
|
32
30
|
serviceAccountName: z.ZodOptional<z.ZodString>;
|
package/dist/argo-submit.js
CHANGED
|
@@ -39,9 +39,7 @@ const submitRunnerArgoWorkflowOptionsSchema = z.object({
|
|
|
39
39
|
kubeconfigPath: z.string().min(1).optional(),
|
|
40
40
|
name: z.string().min(1).optional(),
|
|
41
41
|
namespace: z.string().min(1),
|
|
42
|
-
brokerAuth: brokerAuthOptionSchema
|
|
43
|
-
opencodeAuthSecretName: z.string().min(1).optional(),
|
|
44
|
-
opencodeOpenaiAccountsSecretName: z.string().min(1).optional(),
|
|
42
|
+
brokerAuth: brokerAuthOptionSchema,
|
|
45
43
|
payloadJson: z.string().min(1),
|
|
46
44
|
scheduleYaml: z.string().min(1),
|
|
47
45
|
serviceAccountName: z.string().min(1).optional()
|
|
@@ -92,8 +90,6 @@ function submitRunnerArgoWorkflowEffect(rawOptions, dependencies) {
|
|
|
92
90
|
name: options.name,
|
|
93
91
|
namespace: options.namespace,
|
|
94
92
|
brokerAuth: options.brokerAuth,
|
|
95
|
-
opencodeAuthSecretName: options.opencodeAuthSecretName,
|
|
96
|
-
opencodeOpenaiAccountsSecret: options.opencodeOpenaiAccountsSecretName ? { name: options.opencodeOpenaiAccountsSecretName } : void 0,
|
|
97
93
|
payloadConfigMapName,
|
|
98
94
|
plan: compiled.plan,
|
|
99
95
|
scheduleConfigMapName: scheduleArtifactConfigMapName,
|
package/dist/argo-workflow.d.ts
CHANGED
|
@@ -145,16 +145,11 @@ declare const buildRunnerArgoWorkflowOptionsSchema: z.ZodObject<{
|
|
|
145
145
|
labels: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodString>>>;
|
|
146
146
|
name: z.ZodOptional<z.ZodString>;
|
|
147
147
|
namespace: z.ZodString;
|
|
148
|
-
brokerAuth: z.
|
|
148
|
+
brokerAuth: z.ZodObject<{
|
|
149
149
|
secretKey: z.ZodDefault<z.ZodString>;
|
|
150
150
|
secretName: z.ZodString;
|
|
151
151
|
url: z.ZodDefault<z.ZodString>;
|
|
152
|
-
}, z.core.$strict
|
|
153
|
-
opencodeAuthSecretName: z.ZodOptional<z.ZodString>;
|
|
154
|
-
opencodeOpenaiAccountsSecret: z.ZodOptional<z.ZodObject<{
|
|
155
|
-
key: z.ZodOptional<z.ZodString>;
|
|
156
|
-
name: z.ZodString;
|
|
157
|
-
}, z.core.$strict>>;
|
|
152
|
+
}, z.core.$strict>;
|
|
158
153
|
payloadConfigMapKey: z.ZodDefault<z.ZodString>;
|
|
159
154
|
payloadConfigMapName: z.ZodString;
|
|
160
155
|
resources: z.ZodOptional<z.ZodObject<{
|
package/dist/argo-workflow.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { compileArgoExecutionGraph } from "./argo-graph.js";
|
|
2
|
-
import { OPENCODE_AUTH_STAGING_DIR, OPENCODE_OPENAI_ACCOUNTS_STAGING_DIR } from "./run-state/opencode-accounts.js";
|
|
3
2
|
import { DEFAULT_RUNNER_TASK_DESCRIPTOR_PATH } from "./runner-command/task-descriptor.js";
|
|
4
3
|
import { stringify } from "yaml";
|
|
5
4
|
import { z } from "zod";
|
|
@@ -27,6 +26,10 @@ const RUNNER_OPENCODE_ENV = [
|
|
|
27
26
|
name: "PIPELINE_AGENT_TIMEOUT_MS",
|
|
28
27
|
value: "600000"
|
|
29
28
|
},
|
|
29
|
+
{
|
|
30
|
+
name: "PIPELINE_AGENT_IDLE_TIMEOUT_MS",
|
|
31
|
+
value: "180000"
|
|
32
|
+
},
|
|
30
33
|
{
|
|
31
34
|
name: "PIPELINE_DISABLED_MODELS",
|
|
32
35
|
value: "opencode-go/qwen3.7-max"
|
|
@@ -180,12 +183,7 @@ const buildRunnerArgoWorkflowOptionsSchema = z.object({
|
|
|
180
183
|
secretKey: z.string().min(1).default("api-key"),
|
|
181
184
|
secretName: kubernetesNameSchema,
|
|
182
185
|
url: z.string().min(1).default("https://cliproxy.momokaya.ee")
|
|
183
|
-
}).strict()
|
|
184
|
-
opencodeAuthSecretName: kubernetesNameSchema.optional(),
|
|
185
|
-
opencodeOpenaiAccountsSecret: z.object({
|
|
186
|
-
key: z.string().min(1).optional(),
|
|
187
|
-
name: kubernetesNameSchema
|
|
188
|
-
}).strict().optional(),
|
|
186
|
+
}).strict(),
|
|
189
187
|
payloadConfigMapKey: z.string().min(1).default("payload.json"),
|
|
190
188
|
payloadConfigMapName: kubernetesNameSchema,
|
|
191
189
|
resources: argoWorkflowResourceRequirementsSchema.optional(),
|
|
@@ -312,43 +310,6 @@ function runnerWorkflowStorage(options, tasks) {
|
|
|
312
310
|
readOnly: true
|
|
313
311
|
});
|
|
314
312
|
}
|
|
315
|
-
if (options.opencodeAuthSecretName) {
|
|
316
|
-
volumes.push({
|
|
317
|
-
name: "opencode-auth",
|
|
318
|
-
secret: {
|
|
319
|
-
defaultMode: 256,
|
|
320
|
-
items: [{
|
|
321
|
-
key: "auth.json",
|
|
322
|
-
path: "auth.json"
|
|
323
|
-
}],
|
|
324
|
-
secretName: options.opencodeAuthSecretName
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
volumeMounts.push({
|
|
328
|
-
mountPath: OPENCODE_AUTH_STAGING_DIR,
|
|
329
|
-
name: "opencode-auth",
|
|
330
|
-
readOnly: true
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
if (options.opencodeOpenaiAccountsSecret) {
|
|
334
|
-
const accountsKey = options.opencodeOpenaiAccountsSecret.key ?? "accounts.json";
|
|
335
|
-
volumes.push({
|
|
336
|
-
name: "opencode-openai-accounts",
|
|
337
|
-
secret: {
|
|
338
|
-
defaultMode: 256,
|
|
339
|
-
items: [{
|
|
340
|
-
key: accountsKey,
|
|
341
|
-
path: "accounts.json"
|
|
342
|
-
}],
|
|
343
|
-
secretName: options.opencodeOpenaiAccountsSecret.name
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
volumeMounts.push({
|
|
347
|
-
mountPath: OPENCODE_OPENAI_ACCOUNTS_STAGING_DIR,
|
|
348
|
-
name: "opencode-openai-accounts",
|
|
349
|
-
readOnly: true
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
313
|
if (options.gitCredentialsSecretName) {
|
|
353
314
|
volumes.push({
|
|
354
315
|
name: "runner-git-credentials",
|
|
@@ -387,18 +348,25 @@ function runnerWorkflowStorage(options, tasks) {
|
|
|
387
348
|
};
|
|
388
349
|
}
|
|
389
350
|
/**
|
|
390
|
-
* The runner container env:
|
|
391
|
-
*
|
|
392
|
-
*
|
|
351
|
+
* The runner container env: static opencode/agent tuning plus BROKER_URL
|
|
352
|
+
* (literal) and BROKER_API_KEY (sourced from the broker secret key, never
|
|
353
|
+
* inlined into the manifest).
|
|
393
354
|
*/
|
|
394
355
|
function runnerContainerEnv(options) {
|
|
395
|
-
if (!options.brokerAuth) return [...RUNNER_OPENCODE_ENV];
|
|
396
356
|
return [
|
|
397
357
|
...RUNNER_OPENCODE_ENV,
|
|
398
358
|
{
|
|
399
359
|
name: "BROKER_URL",
|
|
400
360
|
value: options.brokerAuth.url
|
|
401
361
|
},
|
|
362
|
+
{
|
|
363
|
+
name: "PIPELINE_BROKER_SECRET_NAME",
|
|
364
|
+
value: options.brokerAuth.secretName
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: "PIPELINE_BROKER_SECRET_KEY",
|
|
368
|
+
value: options.brokerAuth.secretKey
|
|
369
|
+
},
|
|
402
370
|
{
|
|
403
371
|
name: "BROKER_API_KEY",
|
|
404
372
|
valueFrom: { secretKeyRef: {
|
package/dist/broker-auth.js
CHANGED
|
@@ -39,9 +39,10 @@ const brokerAuthOptionSchema = z.object({
|
|
|
39
39
|
url: z.string().min(1).default(DEFAULT_BROKER_URL)
|
|
40
40
|
}).strict();
|
|
41
41
|
/**
|
|
42
|
-
* Resolve broker credentials from the environment, or `undefined` when
|
|
43
|
-
* runner
|
|
44
|
-
* `BROKER_URL` env is optional and defaults to the
|
|
42
|
+
* Resolve broker credentials from the environment, or `undefined` when a
|
|
43
|
+
* non-runner caller has not supplied broker auth. Remote runner manifests always
|
|
44
|
+
* inject BROKER_API_KEY. The `BROKER_URL` env is optional and defaults to the
|
|
45
|
+
* production broker origin.
|
|
45
46
|
*/
|
|
46
47
|
function resolveBrokerCredentials(env = process.env) {
|
|
47
48
|
const apiKey = env[BROKER_API_KEY_ENV];
|
package/dist/cli/doctor.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { PipelineConfigError } from "../config/schemas.js";
|
|
2
2
|
import { loadPipelineConfig } from "../config/load.js";
|
|
3
3
|
import "../config.js";
|
|
4
|
-
import { opencodeAgentName } from "../runtime/opencode-agent-name.js";
|
|
5
4
|
import { loadMokaGlobalConfig } from "../moka-global-config.js";
|
|
5
|
+
import { opencodeAgentName } from "../runtime/opencode-agent-name.js";
|
|
6
6
|
import { defaultClusterDoctorNamespace, runClusterDoctor } from "../cluster-doctor.js";
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
8
|
-
import { join } from "node:path";
|
|
9
8
|
import { execa } from "execa";
|
|
9
|
+
import { join } from "node:path";
|
|
10
10
|
import matter from "gray-matter";
|
|
11
11
|
//#region src/cli/doctor.ts
|
|
12
12
|
const HEADLESS_AGENT_PERMISSION_VALUES = new Set(["ask"]);
|
package/dist/cli/program.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RunEffort, RunMode, RunTarget } from "../run-control/contracts.js";
|
|
2
2
|
import { RunCommand } from "./run-command.js";
|
|
3
|
-
import { TicketCommandOptions } from "../commands/ticket
|
|
3
|
+
import { TicketCommandOptions } from "../commands/ticket/shared.js";
|
|
4
4
|
import { runPipelineFromConfig } from "../pipeline-runtime.js";
|
|
5
5
|
import { Effect } from "effect";
|
|
6
6
|
import { Command } from "commander";
|
package/dist/cli/program.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { loadPipelineConfig } from "../config/load.js";
|
|
2
2
|
import "../config.js";
|
|
3
|
+
import { loadMokaGlobalConfig } from "../moka-global-config.js";
|
|
3
4
|
import { flattenNodes } from "../planning/graph.js";
|
|
4
5
|
import { configureGatewayHosts, localGatewayStatus, reconcileGateway, renderGatewayConfig, runGatewayDoctor, startLocalGateway } from "../mcp/gateway.js";
|
|
5
6
|
import { createOrchestratorLaunchPlan, createRunnerLaunchPlan } from "../runner.js";
|
|
@@ -17,9 +18,8 @@ import { registerTicketCommand } from "../commands/ticket-command.js";
|
|
|
17
18
|
import { formatConfigLintWarning, lintPipelineConfig } from "../config/lint.js";
|
|
18
19
|
import { parseLoopFlags, runLoopSubmit } from "../loop/loop-command.js";
|
|
19
20
|
import { runLoopControllerEntrypoint } from "../loop/loop-controller-entrypoint.js";
|
|
20
|
-
import { loadMokaGlobalConfig } from "../moka-global-config.js";
|
|
21
21
|
import { formatPipelineInitResult, initPipelineProject } from "../pipeline-init.js";
|
|
22
|
-
import {
|
|
22
|
+
import { withRunControlStoreScoped } from "../run-control/run-control-store.js";
|
|
23
23
|
import { registerRunControlCommands } from "../run-control/commands.js";
|
|
24
24
|
import { startDetachedRunController } from "../run-control/detach.js";
|
|
25
25
|
import { createRunStoreRuntimeReporter } from "../run-control/runtime-reporter.js";
|
|
@@ -117,8 +117,14 @@ async function runConfiguredPipeline(rawInputs) {
|
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
async function runAndPrintPipeline(inputs) {
|
|
120
|
+
await Effect.runPromise(withRunControlStoreScoped(inputs.worktreePath, (store) => Effect.tryPromise({
|
|
121
|
+
catch: (error) => error,
|
|
122
|
+
try: () => runAndPrintPipelineWithStore(inputs, store)
|
|
123
|
+
})));
|
|
124
|
+
}
|
|
125
|
+
async function runAndPrintPipelineWithStore(inputs, store) {
|
|
120
126
|
const runner = inputs.pipelineRunner ?? runPipelineFromConfig;
|
|
121
|
-
const runStoreReporter = await createRunStoreReporter(inputs, createTerminalRuntimeReporter());
|
|
127
|
+
const runStoreReporter = await createRunStoreReporter(inputs, createTerminalRuntimeReporter(), store);
|
|
122
128
|
if (inputs.supervised) console.log(formatSupervisedRunFollowUp(requireRunId(inputs.runId)));
|
|
123
129
|
let result;
|
|
124
130
|
try {
|
|
@@ -144,27 +150,28 @@ async function runWithFlushedReporter(flush, run) {
|
|
|
144
150
|
await flush();
|
|
145
151
|
}
|
|
146
152
|
}
|
|
147
|
-
async function createLocalRunStoreRuntimeReporter(inputs, reporter) {
|
|
153
|
+
async function createLocalRunStoreRuntimeReporter(inputs, reporter, store) {
|
|
148
154
|
const runId = requireRunId(inputs.runId);
|
|
149
|
-
await createRun({
|
|
155
|
+
await Effect.runPromise(store.createRun({
|
|
150
156
|
...resolvedRunControlOptions(inputs.runControl),
|
|
151
157
|
nodeIds: plannedRunStoreNodeIds(inputs),
|
|
152
|
-
runId
|
|
153
|
-
|
|
154
|
-
});
|
|
158
|
+
runId
|
|
159
|
+
}));
|
|
155
160
|
return createRunStoreRuntimeReporter({
|
|
156
161
|
reporter,
|
|
157
162
|
runId,
|
|
163
|
+
store,
|
|
158
164
|
workspaceRoot: inputs.worktreePath
|
|
159
165
|
});
|
|
160
166
|
}
|
|
161
|
-
function createRunStoreReporter(inputs, reporter) {
|
|
167
|
+
function createRunStoreReporter(inputs, reporter, store) {
|
|
162
168
|
if (inputs.runStoreMode === "reuse") {
|
|
163
169
|
const runId = requireRunId(inputs.runId);
|
|
164
170
|
if (inputs.supervisor) {
|
|
165
171
|
const supervisor = createRunControlSupervisor({
|
|
166
172
|
reporter,
|
|
167
173
|
runId,
|
|
174
|
+
store,
|
|
168
175
|
workspaceRoot: inputs.worktreePath
|
|
169
176
|
});
|
|
170
177
|
supervisor.start();
|
|
@@ -176,10 +183,11 @@ function createRunStoreReporter(inputs, reporter) {
|
|
|
176
183
|
return createRunStoreRuntimeReporter({
|
|
177
184
|
reporter,
|
|
178
185
|
runId,
|
|
186
|
+
store,
|
|
179
187
|
workspaceRoot: inputs.worktreePath
|
|
180
188
|
});
|
|
181
189
|
}
|
|
182
|
-
return createLocalRunStoreRuntimeReporter(inputs, reporter);
|
|
190
|
+
return createLocalRunStoreRuntimeReporter(inputs, reporter, store);
|
|
183
191
|
}
|
|
184
192
|
function requireRunId(runId) {
|
|
185
193
|
if (!runId) throw new Error("Run id is required for local run-control persistence.");
|
|
@@ -343,7 +351,7 @@ function createCliProgram(options = {}) {
|
|
|
343
351
|
dryRun: flags.dryRun
|
|
344
352
|
}));
|
|
345
353
|
});
|
|
346
|
-
program.command("codex-auth").description("Manage local Codex
|
|
354
|
+
program.command("codex-auth").description("Manage local Codex broker auth integration").command("sync-local").description("Point local dev repos' opencode openai provider at the central CLIProxyAPI broker").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) => {
|
|
347
355
|
const result = syncLocalCodexAuth({
|
|
348
356
|
check: flags.check,
|
|
349
357
|
dryRun: flags.dryRun,
|
|
@@ -352,12 +360,7 @@ function createCliProgram(options = {}) {
|
|
|
352
360
|
console.log(formatCodexAuthSyncResult(result));
|
|
353
361
|
if (!result.ok) process.exitCode = 1;
|
|
354
362
|
});
|
|
355
|
-
addMokaSubmitOptions(program.command("submit").description([
|
|
356
|
-
"Submit work to Momokaya as an Argo Workflow.",
|
|
357
|
-
"Compatibility alias for `moka run \"<task>\" --target remote --effort thorough`.",
|
|
358
|
-
"Quick equivalent: `moka run \"<task>\" --target remote --effort quick`.",
|
|
359
|
-
"Command equivalent: `moka run --target remote --command -- <argv...>`."
|
|
360
|
-
].join("\n")).argument("[input...]", "task description, or command argv with --command")).action(async (input, flags) => {
|
|
363
|
+
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) => {
|
|
361
364
|
printMokaSubmitResult(await runMokaSubmitFromCli(input, flags));
|
|
362
365
|
});
|
|
363
366
|
registerLoopCommand(program);
|
|
@@ -407,7 +410,10 @@ function buildLoopSubmitInput(options) {
|
|
|
407
410
|
const cwd = process.env.PIPELINE_TARGET_PATH ?? process.cwd();
|
|
408
411
|
const config = loadPipelineConfig(cwd, { allowMissingLintFileReferences: true });
|
|
409
412
|
const momokaya = loadMokaGlobalConfig()?.momokaya;
|
|
413
|
+
const brokerAuth = momokaya?.submit.brokerAuth;
|
|
414
|
+
if (!brokerAuth) throw new Error("momokaya.submit.brokerAuth is required for moka loop submit");
|
|
410
415
|
return {
|
|
416
|
+
brokerAuth,
|
|
411
417
|
config,
|
|
412
418
|
eventUrl: momokaya?.submit.eventUrl,
|
|
413
419
|
flags: parseLoopFlags(options),
|
|
@@ -415,9 +421,6 @@ function buildLoopSubmitInput(options) {
|
|
|
415
421
|
githubAuthSecretName: momokaya?.submit.githubAuthSecretName,
|
|
416
422
|
kubeconfigPath: momokaya?.kubernetes.kubeconfig,
|
|
417
423
|
namespace: momokaya?.kubernetes.namespace,
|
|
418
|
-
brokerAuth: momokaya?.submit.brokerAuth,
|
|
419
|
-
opencodeAuthSecretName: momokaya?.submit.opencodeAuthSecretName,
|
|
420
|
-
opencodeOpenaiAccountsSecretName: momokaya?.submit.opencodeOpenaiAccountsSecretName,
|
|
421
424
|
serviceAccountName: momokaya?.submit.serviceAccountName,
|
|
422
425
|
worktreePath: cwd
|
|
423
426
|
};
|
|
@@ -441,43 +444,43 @@ async function runDetachedResolvedTask(task, execution, runControl) {
|
|
|
441
444
|
task,
|
|
442
445
|
worktreePath
|
|
443
446
|
});
|
|
444
|
-
await
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
runControl,
|
|
451
|
-
schedule: prepared.schedule,
|
|
452
|
-
task,
|
|
453
|
-
workflow: prepared.workflow,
|
|
454
|
-
worktreePath
|
|
455
|
-
}),
|
|
456
|
-
runId,
|
|
457
|
-
workspaceRoot: worktreePath
|
|
458
|
-
});
|
|
459
|
-
const launch = await startDetachedRunController({
|
|
460
|
-
entrypoint: prepared.entrypoint,
|
|
461
|
-
runId,
|
|
462
|
-
schedule: prepared.schedule,
|
|
463
|
-
task,
|
|
464
|
-
workflow: prepared.workflow,
|
|
465
|
-
workspaceRoot: worktreePath
|
|
466
|
-
});
|
|
467
|
-
await updateRunController({
|
|
468
|
-
controller: {
|
|
469
|
-
argv: launch.argv,
|
|
470
|
-
cwd: worktreePath,
|
|
471
|
-
paths: runControlStatusPaths({
|
|
447
|
+
await Effect.runPromise(withRunControlStoreScoped(worktreePath, (store) => Effect.gen(function* () {
|
|
448
|
+
yield* store.createRun({
|
|
449
|
+
...resolvedRunControlOptions(runControl),
|
|
450
|
+
nodeIds: plannedRunStoreNodeIds({
|
|
451
|
+
config: prepared.config,
|
|
452
|
+
entrypoint: prepared.entrypoint,
|
|
472
453
|
runId,
|
|
473
|
-
|
|
454
|
+
runControl,
|
|
455
|
+
schedule: prepared.schedule,
|
|
456
|
+
task,
|
|
457
|
+
workflow: prepared.workflow,
|
|
458
|
+
worktreePath
|
|
474
459
|
}),
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
460
|
+
runId
|
|
461
|
+
});
|
|
462
|
+
const launch = yield* Effect.tryPromise({
|
|
463
|
+
catch: (error) => error,
|
|
464
|
+
try: () => startDetachedRunController({
|
|
465
|
+
entrypoint: prepared.entrypoint,
|
|
466
|
+
runId,
|
|
467
|
+
schedule: prepared.schedule,
|
|
468
|
+
task,
|
|
469
|
+
workflow: prepared.workflow,
|
|
470
|
+
workspaceRoot: worktreePath
|
|
471
|
+
})
|
|
472
|
+
});
|
|
473
|
+
yield* store.updateRunController({
|
|
474
|
+
controller: {
|
|
475
|
+
argv: launch.argv,
|
|
476
|
+
cwd: worktreePath,
|
|
477
|
+
paths: store.statusPaths({ runId }),
|
|
478
|
+
pid: launch.pid,
|
|
479
|
+
startedAt: launch.startedAt
|
|
480
|
+
},
|
|
481
|
+
runId
|
|
482
|
+
});
|
|
483
|
+
})));
|
|
481
484
|
console.log(formatDetachedRunFollowUp(runId));
|
|
482
485
|
}
|
|
483
486
|
async function prepareDetachedRun(input) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { loadPipelineConfig } from "../config/load.js";
|
|
2
2
|
import "../config.js";
|
|
3
|
-
import { submitMoka } from "../moka-submit.js";
|
|
4
3
|
import { loadMokaGlobalConfig } from "../moka-global-config.js";
|
|
4
|
+
import { submitMoka } from "../moka-submit.js";
|
|
5
5
|
import { Option } from "commander";
|
|
6
6
|
//#region src/cli/submit-options.ts
|
|
7
7
|
function addMokaSubmitOptions(command) {
|
|
@@ -34,6 +34,7 @@ function resolveMokaEventUrl(flags, globalConfig) {
|
|
|
34
34
|
function mokaCommonSubmitOptions(input) {
|
|
35
35
|
const momokaya = input.globalConfig?.momokaya;
|
|
36
36
|
return {
|
|
37
|
+
brokerAuth: resolveMokaBrokerAuth(input.globalConfig),
|
|
37
38
|
config: input.config,
|
|
38
39
|
delivery: { pullRequest: input.flags.openPr === true },
|
|
39
40
|
eventUrl: input.eventUrl,
|
|
@@ -48,13 +49,15 @@ function mokaCommonSubmitOptions(input) {
|
|
|
48
49
|
kubeconfigPath: input.flags.kubeconfig ?? momokaya?.kubernetes.kubeconfig,
|
|
49
50
|
name: input.flags.name,
|
|
50
51
|
namespace: input.flags.namespace ?? momokaya?.kubernetes.namespace,
|
|
51
|
-
brokerAuth: momokaya?.submit.brokerAuth,
|
|
52
|
-
opencodeAuthSecretName: momokaya?.submit.opencodeAuthSecretName,
|
|
53
|
-
opencodeOpenaiAccountsSecretName: momokaya?.submit.opencodeOpenaiAccountsSecretName,
|
|
54
52
|
serviceAccountName: input.flags.serviceAccount ?? momokaya?.submit.serviceAccountName,
|
|
55
53
|
worktreePath: input.cwd
|
|
56
54
|
};
|
|
57
55
|
}
|
|
56
|
+
function resolveMokaBrokerAuth(globalConfig) {
|
|
57
|
+
const brokerAuth = globalConfig?.momokaya.submit.brokerAuth;
|
|
58
|
+
if (!brokerAuth) throw new Error("momokaya.submit.brokerAuth is required for remote submit");
|
|
59
|
+
return brokerAuth;
|
|
60
|
+
}
|
|
58
61
|
function submitMokaCommandInput(input, flags, commonOptions) {
|
|
59
62
|
if (flags.quick || flags.schedule) throw new Error("--command cannot be combined with --quick or --schedule");
|
|
60
63
|
if (input.length === 0) throw new Error("Command argv is required when --command is set");
|
package/dist/cluster-doctor.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { KubernetesArgoService, KubernetesArgoServiceLive } from "./runtime/services/kubernetes-argo-service.js";
|
|
2
1
|
import { loadMokaGlobalConfig } from "./moka-global-config.js";
|
|
2
|
+
import { KubernetesArgoService, KubernetesArgoServiceLive } from "./runtime/services/kubernetes-argo-service.js";
|
|
3
3
|
import { Effect } from "effect";
|
|
4
4
|
//#region src/cluster-doctor.ts
|
|
5
5
|
const DEFAULT_NAMESPACE = "momokaya-pipeline";
|
|
6
6
|
const DEFAULT_RESOURCES = {
|
|
7
|
+
brokerAuthSecretName: "broker-api-key",
|
|
7
8
|
eventAuthSecretName: "pipeline-runner-event-auth",
|
|
8
9
|
eventAuthExternalSecretName: "pipeline-runner-event-auth",
|
|
9
10
|
externalSecretRemoteRef: "agent-runtime/pipeline-runner/event-auth",
|
|
10
11
|
gitCredentialsSecretName: "oisin-bot-git-credentials",
|
|
11
12
|
githubAuthSecretName: "oisin-bot-github-auth",
|
|
12
13
|
imagePullSecretName: "ghcr-pull-secret",
|
|
13
|
-
opencodeAuthSecretName: "opencode-auth-1",
|
|
14
14
|
serviceAccountName: "pipeline-runner"
|
|
15
15
|
};
|
|
16
16
|
const FORBIDDEN_RE = /forbidden/i;
|
|
@@ -62,17 +62,16 @@ function clusterResources() {
|
|
|
62
62
|
const configured = loadMokaGlobalConfig()?.momokaya.submit;
|
|
63
63
|
return configured ? {
|
|
64
64
|
...DEFAULT_RESOURCES,
|
|
65
|
-
brokerAuthSecretName: configured.brokerAuth?.secretName,
|
|
65
|
+
brokerAuthSecretName: configured.brokerAuth?.secretName ?? DEFAULT_RESOURCES.brokerAuthSecretName,
|
|
66
66
|
eventAuthSecretName: configured.eventAuthSecretName,
|
|
67
67
|
gitCredentialsSecretName: configured.gitCredentialsSecretName,
|
|
68
68
|
githubAuthSecretName: configured.githubAuthSecretName,
|
|
69
69
|
imagePullSecretName: configured.imagePullSecretName,
|
|
70
|
-
opencodeAuthSecretName: configured.opencodeAuthSecretName ?? DEFAULT_RESOURCES.opencodeAuthSecretName,
|
|
71
70
|
serviceAccountName: configured.serviceAccountName
|
|
72
71
|
} : DEFAULT_RESOURCES;
|
|
73
72
|
}
|
|
74
73
|
function secretChecks(namespace, kubectlOptions, resources) {
|
|
75
|
-
const authSecretCheck =
|
|
74
|
+
const authSecretCheck = [resources.brokerAuthSecretName, `Secret ${resources.brokerAuthSecretName} missing in ${namespace}; expected broker api-key mount by name.`];
|
|
76
75
|
return [
|
|
77
76
|
[resources.eventAuthSecretName, eventAuthMissingDetail(namespace)],
|
|
78
77
|
[resources.imagePullSecretName, `Secret ${resources.imagePullSecretName} missing in ${namespace}; expected imagePullSecret for ghcr.io/oisin-ee/pipeline-runner.`],
|
package/dist/codex-auth-sync.js
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { applyOpencodeBrokerProvider, resolveBrokerCredentials } from "./broker-auth.js";
|
|
2
|
-
import { mergeOpenCodeProjectConfig } from "./opencode-project-config.js";
|
|
3
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
3
|
import { dirname, join } from "node:path";
|
|
6
|
-
import { parse } from "jsonc-parser";
|
|
7
4
|
//#region src/codex-auth-sync.ts
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Point each local dev repo's opencode openai provider at the central
|
|
7
|
+
* CLIProxyAPI broker. codex + opencode authenticate through the broker
|
|
8
|
+
* (which owns OAuth refresh / rotation / failover), so there is no per-project
|
|
9
|
+
* account pool to declare. Requires BROKER_API_KEY in the env (or an explicit
|
|
10
|
+
* `broker` override).
|
|
11
|
+
*/
|
|
10
12
|
function syncLocalCodexAuth(options) {
|
|
11
13
|
const broker = options.broker === void 0 ? resolveBrokerCredentials() : options.broker;
|
|
12
|
-
|
|
14
|
+
if (!broker) return {
|
|
15
|
+
items: [{
|
|
16
|
+
action: "error",
|
|
17
|
+
message: "BROKER_API_KEY is required: codex + opencode authenticate through the central CLIProxyAPI broker.",
|
|
18
|
+
path: options.root
|
|
19
|
+
}],
|
|
20
|
+
ok: false
|
|
21
|
+
};
|
|
22
|
+
const items = discoverGitRepositories(options.root).map((repo) => syncProjectBrokerConfig(repo, broker, options));
|
|
13
23
|
const hasRequiredChanges = items.some((item) => item.action === "create" || item.action === "update");
|
|
14
24
|
const hasErrors = items.some((item) => item.action === "error");
|
|
15
25
|
const checkFailed = options.check === true && hasRequiredChanges;
|
|
@@ -26,30 +36,6 @@ function formatCodexAuthSyncResult(result) {
|
|
|
26
36
|
if (!result.ok) lines.push("codex-auth sync-local check failed");
|
|
27
37
|
return lines.join("\n");
|
|
28
38
|
}
|
|
29
|
-
function syncGlobalPluginConfig(path, options) {
|
|
30
|
-
const currentText = existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
31
|
-
const parsed = parseJsonObject(currentText ?? "{}");
|
|
32
|
-
if (!parsed.ok) return {
|
|
33
|
-
action: "error",
|
|
34
|
-
message: formatParseErrors(parsed.errors),
|
|
35
|
-
path
|
|
36
|
-
};
|
|
37
|
-
return writeIfChanged(path, currentText, `${JSON.stringify({
|
|
38
|
-
...parsed.value,
|
|
39
|
-
perProjectAccounts: false
|
|
40
|
-
}, null, 2)}\n`, options);
|
|
41
|
-
}
|
|
42
|
-
function syncProjectOpenCodeConfig(repo, options) {
|
|
43
|
-
const path = join(repo, ".opencode/opencode.json");
|
|
44
|
-
const currentText = existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
45
|
-
const merged = mergeOpenCodeProjectConfig(currentText, { plugin: [CODEX_MULTI_AUTH_PLUGIN] });
|
|
46
|
-
if (!merged.ok) return {
|
|
47
|
-
action: "error",
|
|
48
|
-
message: formatParseErrors(merged.errors),
|
|
49
|
-
path
|
|
50
|
-
};
|
|
51
|
-
return writeIfChanged(path, currentText, merged.content, options);
|
|
52
|
-
}
|
|
53
39
|
function syncProjectBrokerConfig(repo, broker, options) {
|
|
54
40
|
const path = join(repo, ".opencode/opencode.json");
|
|
55
41
|
const currentText = existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
@@ -86,26 +72,5 @@ function isDirectory(path) {
|
|
|
86
72
|
return false;
|
|
87
73
|
}
|
|
88
74
|
}
|
|
89
|
-
function parseJsonObject(content) {
|
|
90
|
-
const errors = [];
|
|
91
|
-
const value = parse(content, errors, {
|
|
92
|
-
allowTrailingComma: true,
|
|
93
|
-
disallowComments: false
|
|
94
|
-
});
|
|
95
|
-
if (errors.length > 0 || !isRecord(value)) return {
|
|
96
|
-
errors,
|
|
97
|
-
ok: false
|
|
98
|
-
};
|
|
99
|
-
return {
|
|
100
|
-
ok: true,
|
|
101
|
-
value
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function formatParseErrors(errors) {
|
|
105
|
-
return errors.length > 0 ? `invalid JSONC (${errors.length} parse error${errors.length === 1 ? "" : "s"})` : "expected a JSON object";
|
|
106
|
-
}
|
|
107
|
-
function isRecord(value) {
|
|
108
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
109
|
-
}
|
|
110
75
|
//#endregion
|
|
111
76
|
export { formatCodexAuthSyncResult, syncLocalCodexAuth };
|