@oisincoveney/pipeline 3.24.2 → 4.0.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/README.md +14 -2
- package/defaults/pipeline.yaml +23 -5
- package/defaults/profiles.yaml +104 -21
- package/dist/argo-graph.js +90 -88
- package/dist/argo-submit.d.ts +110 -138
- package/dist/argo-submit.js +363 -378
- package/dist/argo-workflow.d.ts +156 -177
- package/dist/argo-workflow.js +96 -138
- package/dist/backlog.js +5 -4
- package/dist/bench/eval-report.js +21 -12
- package/dist/claude-settings-config.js +23 -31
- package/dist/claude-user-config.js +6 -16
- package/dist/cli/bootstrap-commands.js +3 -3
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.js +176 -171
- package/dist/cli/factory-commands.js +13 -13
- package/dist/cli/format.js +92 -86
- package/dist/cli/loop-commands.js +21 -21
- package/dist/cli/mcp-gateway-commands.js +12 -12
- package/dist/cli/plan-commands.js +85 -116
- package/dist/cli/program.d.ts +3 -3
- package/dist/cli/program.js +41 -43
- package/dist/cli/run-command.d.ts +1 -1
- package/dist/cli/run-command.js +25 -25
- package/dist/cli/run-commands.js +31 -29
- package/dist/cli/run-resolver.d.ts +1 -1
- package/dist/cli/run-resolver.js +30 -32
- package/dist/cli/run-service.d.ts +2 -3
- package/dist/cli/run-service.js +229 -239
- package/dist/cli/submit-options.js +85 -83
- package/dist/cluster-doctor.js +147 -175
- package/dist/codex-config.js +24 -30
- package/dist/commands/bench-command.js +9 -7
- package/dist/commands/coordinator-command.js +35 -0
- package/dist/commands/pipeline-command.js +13 -7
- package/dist/commands/runner-command-command.js +39 -24
- package/dist/commands/runner-node-command.js +31 -0
- package/dist/commands/ticket/complete.js +29 -33
- package/dist/commands/ticket/create.js +84 -82
- package/dist/commands/ticket/graph-check.js +11 -11
- package/dist/commands/ticket/next.js +36 -36
- package/dist/commands/ticket/sequence.js +11 -12
- package/dist/commands/ticket/shared.d.ts +5 -2
- package/dist/commands/ticket/shared.js +63 -66
- package/dist/commands/ticket/start.js +58 -67
- package/dist/commands/ticket-command.js +2 -2
- package/dist/config/defaults.d.ts +139 -140
- package/dist/config/defaults.js +81 -80
- package/dist/config/lint.js +52 -64
- package/dist/config/load.d.ts +4 -5
- package/dist/config/load.js +64 -74
- package/dist/config/schema/catalog.d.ts +2 -1
- package/dist/config/schema/catalog.js +3 -2
- package/dist/config/schema/mcp.js +46 -52
- package/dist/config/schemas.d.ts +382 -528
- package/dist/config/schemas.js +400 -398
- package/dist/config/validate.d.ts +1 -2
- package/dist/config/validate.js +236 -201
- package/dist/config.d.ts +2 -2
- package/dist/context/repo-map.js +105 -119
- package/dist/coordinator/composition.js +169 -0
- package/dist/coordinator/config.js +71 -0
- package/dist/coordinator/run-owner.js +64 -0
- package/dist/coordinator/wave-advance.js +148 -0
- package/dist/coordinator/wave-scheduler.js +50 -0
- package/dist/credentials/broker.d.ts +6 -8
- package/dist/credentials/broker.js +17 -16
- package/dist/credentials/codex-config.js +15 -19
- package/dist/credentials/file-targets.js +9 -15
- package/dist/credentials/local-codex-auth-sync.js +55 -58
- package/dist/credentials/opencode-config.js +28 -32
- package/dist/credentials/runner.js +13 -13
- package/dist/effect-sync-errors.js +28 -0
- package/dist/factory/create-experiment.js +285 -121
- package/dist/factory/exec.js +10 -12
- package/dist/factory/git-credentials.js +4 -4
- package/dist/factory/stamp-answers.js +10 -11
- package/dist/factory/template-update.js +65 -44
- package/dist/factory-lane.d.ts +26 -40
- package/dist/factory-lane.js +26 -25
- package/dist/gates.js +3 -3
- package/dist/git-remote-url.js +17 -19
- package/dist/hooks.d.ts +26 -26
- package/dist/hooks.js +20 -22
- package/dist/index.d.ts +4 -3
- package/dist/index.js +27 -36
- package/dist/install-commands/claude-code.js +100 -92
- package/dist/install-commands/host-selection.js +3 -6
- package/dist/install-commands/opencode.js +264 -259
- package/dist/install-commands/planner.js +163 -181
- package/dist/install-commands/result-format.js +1 -3
- package/dist/install-commands/shared.js +25 -42
- package/dist/install-commands/writer.js +22 -25
- package/dist/install-commands.js +8 -8
- package/dist/jscpd-output.js +29 -0
- package/dist/json-config-merge.js +14 -20
- package/dist/json-line-values.js +17 -6
- package/dist/loop/argo-poll.d.ts +0 -1
- package/dist/loop/argo-poll.js +15 -95
- package/dist/loop/backlog-records.js +1 -3
- package/dist/loop/controller-deps.js +150 -161
- package/dist/loop/controller.js +164 -186
- package/dist/loop/gh-checks.js +62 -61
- package/dist/loop/gh-runner.js +22 -25
- package/dist/loop/loop-command.js +66 -58
- package/dist/loop/loop-controller-entrypoint.js +29 -30
- package/dist/loop/merge.js +36 -40
- package/dist/loop/run-terminal-poll.js +69 -0
- package/dist/mcp/gateway-config.js +25 -29
- package/dist/mcp/gateway-doctor.js +77 -119
- package/dist/mcp/gateway-reconcile.js +17 -22
- package/dist/mcp/gateway-runtime.js +1 -3
- package/dist/mcp/host-config.js +37 -40
- package/dist/mcp/host-renderers.js +10 -18
- package/dist/mcp/repo-local-backends.js +51 -54
- package/dist/mcp/toolhive-vmcp.js +39 -39
- package/dist/model-resolver.js +29 -33
- package/dist/moka-global-config.d.ts +78 -55
- package/dist/moka-global-config.js +93 -92
- package/dist/moka-submit.d.ts +2179 -866
- package/dist/moka-submit.js +97 -99
- package/dist/opencode-project-config.js +34 -40
- package/dist/package-assets.js +1 -3
- package/dist/path-refs.js +2 -2
- package/dist/pipeline-init.js +25 -25
- package/dist/pipeline-runtime.d.ts +15 -14
- package/dist/pipeline-runtime.js +51 -50
- package/dist/planned-node.js +6 -3
- package/dist/planning/compile.d.ts +5 -5
- package/dist/planning/compile.js +140 -139
- package/dist/planning/dependency-refs.js +5 -5
- package/dist/planning/generate.d.ts +1296 -1296
- package/dist/planning/generate.js +307 -314
- package/dist/planning/graph.d.ts +0 -1
- package/dist/planning/graph.js +131 -149
- package/dist/remote/argo/model.d.ts +104 -122
- package/dist/remote/argo/model.js +205 -197
- package/dist/remote/argo/policy.js +39 -47
- package/dist/remote/argo/storage.js +81 -85
- package/dist/remote/jobs/execution-identity.js +70 -0
- package/dist/remote/jobs/job-outcome.js +108 -0
- package/dist/remote/jobs/manifest.js +96 -0
- package/dist/remote/jobs/model.d.ts +158 -0
- package/dist/remote/jobs/model.js +162 -0
- package/dist/remote/jobs/node-bootstrap.js +213 -0
- package/dist/remote/jobs/policy.js +123 -0
- package/dist/remote/jobs/reconcile.js +100 -0
- package/dist/remote/jobs/run-spec-client.js +64 -0
- package/dist/remote/jobs/run-spec-path.js +31 -0
- package/dist/remote/jobs/run-spec-server.d.ts +34 -0
- package/dist/remote/jobs/run-spec-server.js +116 -0
- package/dist/remote/jobs/submit.d.ts +23 -0
- package/dist/remote/jobs/submit.js +116 -0
- package/dist/remote/jobs/watch.js +59 -0
- package/dist/remote/submit/argo-submission.d.ts +3 -1
- package/dist/remote/submit/argo-submission.js +53 -58
- package/dist/remote/submit/compilation.d.ts +2 -0
- package/dist/remote/submit/compilation.js +46 -49
- package/dist/remote/submit/event-boundary.js +62 -76
- package/dist/remote/submit/hook-events.d.ts +6 -0
- package/dist/remote/submit/io.d.ts +7 -1
- package/dist/remote/submit/io.js +40 -43
- package/dist/remote/submit/jobs-submission.d.ts +59 -0
- package/dist/remote/submit/jobs-submission.js +97 -0
- package/dist/remote/submit/jobs-submit-result.d.ts +25 -0
- package/dist/remote/submit/jobs-submit-result.js +34 -0
- package/dist/remote/submit/options.d.ts +49 -0
- package/dist/remote/submit/options.js +27 -0
- package/dist/remote/submit/service.d.ts +40 -1
- package/dist/remote/submit/service.js +67 -49
- package/dist/run-control/command-context.js +6 -8
- package/dist/run-control/commands.js +10 -10
- package/dist/run-control/contracts.d.ts +52 -101
- package/dist/run-control/contracts.js +83 -69
- package/dist/run-control/detach.js +66 -72
- package/dist/run-control/execution-store.js +0 -0
- package/dist/run-control/file-errors.js +1 -3
- package/dist/run-control/logical-segment.js +3 -3
- package/dist/run-control/next-node.js +67 -78
- package/dist/run-control/postgres/postgres-run-control-store.js +196 -225
- package/dist/run-control/resume-command.js +34 -41
- package/dist/run-control/run-artifacts-command.js +84 -105
- package/dist/run-control/run-command-domain.js +7 -11
- package/dist/run-control/run-control-store.js +9 -9
- package/dist/run-control/run-query-command.js +73 -100
- package/dist/run-control/run-record.js +5 -3
- package/dist/run-control/run-state-lock.js +5 -5
- package/dist/run-control/runtime-event-projection.js +38 -50
- package/dist/run-control/runtime-reporter.js +86 -102
- package/dist/run-control/stop-command.js +42 -53
- package/dist/run-control/store-fs-effects.js +3 -1
- package/dist/run-control/store-manifest.js +38 -13
- package/dist/run-control/store-paths.js +3 -3
- package/dist/run-control/store.js +1 -1
- package/dist/run-control/submit-result.js +21 -21
- package/dist/run-control/supervisor.js +78 -68
- package/dist/run-control/workspace.js +2 -2
- package/dist/run-state/git-refs.js +258 -307
- package/dist/runner/opencode-excludes.js +4 -4
- package/dist/runner/subprocess-result.js +28 -37
- package/dist/runner/subprocess.js +41 -41
- package/dist/runner/timeouts.js +14 -13
- package/dist/runner-command/dynamic-command.js +46 -39
- package/dist/runner-command/environment-commands.js +91 -0
- package/dist/runner-command/finalize.js +174 -153
- package/dist/runner-command/lifecycle-context.js +115 -130
- package/dist/runner-command/lifecycle.js +78 -72
- package/dist/runner-command/pre-schedule.js +203 -223
- package/dist/runner-command/run.js +450 -448
- package/dist/runner-command/schedule-source-options.js +8 -10
- package/dist/runner-command/select-ready-wave.js +39 -30
- package/dist/runner-command/task-descriptor.js +11 -17
- package/dist/runner-command-contract.d.ts +147 -157
- package/dist/runner-command-contract.js +403 -411
- package/dist/runner-event-schema.d.ts +364 -505
- package/dist/runner-event-schema.js +187 -175
- package/dist/runner-event-sink.js +37 -43
- package/dist/runner-output.js +6 -6
- package/dist/runner.d.ts +57 -37
- package/dist/runner.js +176 -127
- package/dist/runtime/actor-ids.d.ts +1 -0
- package/dist/runtime/actor-ids.js +2 -2
- package/dist/runtime/agent-node/agent-node.js +99 -110
- package/dist/runtime/agent-node/handoff-finalization.js +23 -24
- package/dist/runtime/agent-node/model-selection.js +19 -22
- package/dist/runtime/agent-node/output-finalization.js +174 -204
- package/dist/runtime/agent-node/prompt-rendering.js +208 -251
- package/dist/runtime/agent-node/session-execution.js +43 -39
- package/dist/runtime/builtins/builtins.js +218 -284
- package/dist/runtime/changed-files/changed-files.js +29 -34
- package/dist/runtime/command-executor/command-executor.js +31 -23
- package/dist/runtime/config-error.js +1 -3
- package/dist/runtime/context/context.js +35 -37
- package/dist/runtime/contracts/contracts.d.ts +3 -0
- package/dist/runtime/contracts/index.d.ts +1 -1
- package/dist/runtime/detached-race.js +11 -14
- package/dist/runtime/drain-merge/drain-merge.js +139 -164
- package/dist/runtime/durable-store/acquisition.js +5 -3
- package/dist/runtime/durable-store/durable-store.d.ts +3 -1
- package/dist/runtime/durable-store/postgres/client.js +29 -0
- package/dist/runtime/durable-store/postgres/migrate-substrate.js +34 -29
- package/dist/runtime/durable-store/postgres/postgres-store.js +18 -20
- package/dist/runtime/events/events.js +273 -331
- package/dist/runtime/events/index.js +2 -2
- package/dist/runtime/execution-envelope.js +44 -0
- package/dist/runtime/gates/adjudication/llm-judge.js +21 -24
- package/dist/runtime/gates/adjudication/structured-claim.js +15 -16
- package/dist/runtime/gates/adjudicator/adjudicator.js +27 -27
- package/dist/runtime/gates/adjudicator/index.js +2 -2
- package/dist/runtime/gates/contract.js +5 -9
- package/dist/runtime/gates/gates.js +9 -8
- package/dist/runtime/gates/kinds/acceptance/acceptance.js +68 -71
- package/dist/runtime/gates/kinds/acceptance/index.js +2 -2
- package/dist/runtime/gates/kinds/artifact/artifact.js +4 -4
- package/dist/runtime/gates/kinds/artifact/index.js +2 -2
- package/dist/runtime/gates/kinds/builtin/builtin.js +4 -4
- package/dist/runtime/gates/kinds/builtin/index.js +2 -2
- package/dist/runtime/gates/kinds/changed-files/changed-files.js +31 -35
- package/dist/runtime/gates/kinds/changed-files/index.js +2 -2
- package/dist/runtime/gates/kinds/command/command.js +3 -3
- package/dist/runtime/gates/kinds/command/index.js +2 -2
- package/dist/runtime/gates/kinds/json-schema/index.js +2 -2
- package/dist/runtime/gates/kinds/json-schema/json-schema.js +7 -6
- package/dist/runtime/gates/kinds/verdict/index.js +2 -2
- package/dist/runtime/gates/kinds/verdict/verdict.js +3 -3
- package/dist/runtime/gates/orchestrator.js +72 -86
- package/dist/runtime/gates/registry.js +1 -3
- package/dist/runtime/handoff.d.ts +2 -1
- package/dist/runtime/handoff.js +43 -46
- package/dist/runtime/hooks/command-hook.js +57 -71
- package/dist/runtime/hooks/context.js +21 -25
- package/dist/runtime/hooks/events.js +84 -100
- package/dist/runtime/hooks/execution.js +6 -12
- package/dist/runtime/hooks/hooks.js +34 -23
- package/dist/runtime/hooks/invocation.js +23 -29
- package/dist/runtime/hooks/module-hook.js +36 -35
- package/dist/runtime/hooks/policy.js +32 -29
- package/dist/runtime/hooks/results.js +56 -66
- package/dist/runtime/journal-acquisition.d.ts +3 -2
- package/dist/runtime/journal-acquisition.js +14 -14
- package/dist/runtime/json-validation/json-validation.js +51 -72
- package/dist/runtime/launch-plan-args.js +39 -0
- package/dist/runtime/local-scheduler.js +46 -48
- package/dist/runtime/node-execution.js +376 -445
- package/dist/runtime/node-protocol/node-protocol.js +36 -79
- package/dist/runtime/node-state-store.d.ts +4 -1
- package/dist/runtime/node-state-store.js +13 -57
- package/dist/runtime/node-state-tracker.js +46 -54
- package/dist/runtime/open-pull-request/open-pull-request.js +201 -187
- package/dist/runtime/opencode-adapter.js +23 -24
- package/dist/runtime/opencode-agent-name.js +6 -6
- package/dist/runtime/opencode-runtime.js +115 -93
- package/dist/runtime/opencode-server.js +39 -53
- package/dist/runtime/opencode-session-executor.js +312 -344
- package/dist/runtime/parallel-node/parallel-node.js +123 -134
- package/dist/runtime/parallel-worktrees/parallel-worktrees.js +90 -73
- package/dist/runtime/protected-paths/protected-paths.js +70 -71
- package/dist/runtime/remediation/remediation.js +202 -231
- package/dist/runtime/retry.js +8 -10
- package/dist/runtime/run-journal.d.ts +2 -0
- package/dist/runtime/run-journal.js +7 -7
- package/dist/runtime/runtime-results.js +54 -69
- package/dist/runtime/scheduled-dependencies.d.ts +2 -1
- package/dist/runtime/scheduled-dependencies.js +61 -75
- package/dist/runtime/scheduler.js +179 -202
- package/dist/runtime/services/agent-node-runtime-service.js +3 -3
- package/dist/runtime/services/backlog-service.d.ts +1 -2
- package/dist/runtime/services/backlog-service.js +8 -14
- package/dist/runtime/services/command-executor-service.js +1 -1
- package/dist/runtime/services/config-io-service.js +24 -21
- package/dist/runtime/services/drain-merge-git-service.js +1 -1
- package/dist/runtime/services/file-system-service.js +9 -7
- package/dist/runtime/services/git-porcelain-service.js +6 -6
- package/dist/runtime/services/kubernetes-argo-service.d.ts +10 -3
- package/dist/runtime/services/kubernetes-argo-service.js +90 -84
- package/dist/runtime/services/kubernetes-jobs-read-service.js +115 -0
- package/dist/runtime/services/kubernetes-jobs-service.d.ts +37 -0
- package/dist/runtime/services/kubernetes-jobs-service.js +45 -0
- package/dist/runtime/services/kubernetes-jobs-watch-service.js +61 -0
- package/dist/runtime/services/kubernetes-lease-service.js +21 -0
- package/dist/runtime/services/mcp-gateway-service.js +143 -94
- package/dist/runtime/services/open-pull-request-git-service.js +1 -3
- package/dist/runtime/services/opencode-runtime-server-service.js +10 -12
- package/dist/runtime/services/opencode-sdk-service.js +7 -7
- package/dist/runtime/services/repo-io-service.js +10 -12
- package/dist/runtime/services/run-journal-file-service.js +2 -2
- package/dist/runtime/services/runner-command-io-service.js +48 -52
- package/dist/runtime/services/runner-event-sink-http-service.js +32 -39
- package/dist/runtime/step/step-node.js +15 -15
- package/dist/runtime/workflow-execution.js +56 -57
- package/dist/runtime/workflow-lifecycle.js +82 -101
- package/dist/runtime/yeet-event-record.js +104 -0
- package/dist/runtime/yeet-executor.js +184 -0
- package/dist/safe-json.js +16 -16
- package/dist/schedule/backlog-context.js +122 -116
- package/dist/schedule/baseline.js +249 -255
- package/dist/schedule/passes/coverage.js +63 -68
- package/dist/schedule/passes/drain-merge.js +34 -40
- package/dist/schedule/passes/ids.js +15 -17
- package/dist/schedule/passes/models.js +40 -37
- package/dist/schedule/passes/open-pull-request.js +16 -20
- package/dist/schedule/passes/references.js +18 -22
- package/dist/schedule/prompts.js +135 -141
- package/dist/schedule/scheduling-roles.js +8 -14
- package/dist/schema-boundary.d.ts +4 -0
- package/dist/schema-boundary.js +145 -0
- package/dist/serialized-write-queue.js +2 -2
- package/dist/standard-output-schemas.js +61 -59
- package/dist/strings.js +12 -12
- package/dist/task-ref.js +5 -5
- package/dist/tickets/apply-ticket-plan.js +52 -61
- package/dist/tickets/backlog-task-store.d.ts +15 -23
- package/dist/tickets/backlog-task-store.js +82 -94
- package/dist/tickets/completion/complete-ticket.js +53 -59
- package/dist/tickets/ticket-graph-dto.d.ts +24 -48
- package/dist/tickets/ticket-graph-dto.js +40 -40
- package/dist/tickets/ticket-graph.d.ts +7 -2
- package/dist/tickets/ticket-graph.js +36 -50
- package/dist/tickets/ticket-plan-command-args.js +6 -10
- package/dist/tickets/ticket-plan-render.js +10 -16
- package/dist/tickets/ticket-plan.d.ts +32 -41
- package/dist/tickets/ticket-plan.js +97 -77
- package/dist/tickets/ticket-selection.d.ts +3 -1
- package/dist/tickets/ticket-selection.js +37 -52
- package/dist/tickets/ticket-task-index.js +13 -17
- package/dist/tickets/validation-error-format.js +3 -10
- package/dist/token-estimator.js +12 -7
- package/dist/unknown-fields.js +21 -0
- package/dist/workflow-submit-contract.d.ts +9 -10
- package/dist/workflow-submit-contract.js +10 -9
- package/docs/adr-moka-postgres-schema-isolation.md +48 -0
- package/docs/adr-opencode-first-goal-loop-runtime.md +11 -11
- package/docs/config-architecture.md +13 -13
- package/docs/mcp-host-isolation.md +1 -0
- package/docs/moka-orchestrator-design.md +3 -3
- package/docs/operator-guide.md +1 -1
- package/docs/pipeline-console-runner-contract.md +10 -6
- package/docs/runtime-actor-model.md +18 -18
- package/docs/runtime-test-subsystems.md +200 -0
- package/docs/slash-command-adapter-contract.md +3 -3
- package/package.json +49 -85
- package/dist/config/schema/reference-validation.js +0 -83
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { booleanValue, mutableArray, numberValue, parseJsonWithSchema, requiredString, struct } from "../schema-boundary.js";
|
|
1
2
|
//#region src/bench/eval-report.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
3
|
+
const evalRunResultsSchema = mutableArray(struct({
|
|
4
|
+
costTokens: numberValue(),
|
|
5
|
+
resolved: booleanValue(),
|
|
6
|
+
task: requiredString,
|
|
7
|
+
variant: requiredString,
|
|
8
|
+
wallMs: numberValue()
|
|
9
|
+
}));
|
|
10
|
+
const parseEvalRunResultsJson = (source) => parseJsonWithSchema(evalRunResultsSchema, source);
|
|
11
|
+
const summarizeVariant = (variant, runs) => {
|
|
10
12
|
const resolved = runs.filter((r) => r.resolved).length;
|
|
11
13
|
const totalWall = runs.reduce((sum, r) => sum + r.wallMs, 0);
|
|
12
14
|
return {
|
|
@@ -17,11 +19,18 @@ function summarizeVariant(variant, runs) {
|
|
|
17
19
|
totalCostTokens: runs.reduce((sum, r) => sum + r.costTokens, 0),
|
|
18
20
|
variant
|
|
19
21
|
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
+
};
|
|
23
|
+
const buildEvalReport = (results) => {
|
|
24
|
+
const variants = [...new Set(results.map((r) => r.variant))].toSorted();
|
|
25
|
+
return {
|
|
26
|
+
tasks: new Set(results.map((r) => r.task)).size,
|
|
27
|
+
variants: variants.map((variant) => summarizeVariant(variant, results.filter((r) => r.variant === variant)))
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const renderEvalReport = (report) => {
|
|
22
31
|
const lines = [`Eval over ${report.tasks} task(s):`, "variant | resolved | rate | tokens | avg ms"];
|
|
23
32
|
for (const v of report.variants) lines.push(`${v.variant} | ${v.resolved}/${v.count} | ${(v.resolutionRate * 100).toFixed(0)}% | ${v.totalCostTokens} | ${v.avgWallMs}`);
|
|
24
33
|
return lines.join("\n");
|
|
25
|
-
}
|
|
34
|
+
};
|
|
26
35
|
//#endregion
|
|
27
|
-
export { buildEvalReport, renderEvalReport };
|
|
36
|
+
export { buildEvalReport, parseEvalRunResultsJson, renderEvalReport };
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { applyJsonEdit, ensureTrailingNewline, formatJson, isRecord, parseJsonRecord, setIfMissing } from "./json-config-merge.js";
|
|
2
2
|
//#region src/claude-settings-config.ts
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const applyMcpServersProjection = (content, parsed, projection) => Object.entries(projection.mcpServers ?? {}).reduce((nextContent, [name, server]) => setIfMissing(nextContent, parsed, ["mcpServers", name], server), content);
|
|
4
|
+
const projectedAllowList = (projection) => projection.permissions?.allow ?? [];
|
|
5
|
+
const unionPreservingOrder = (existing, extra) => {
|
|
6
|
+
const merged = [...existing];
|
|
7
|
+
for (const entry of extra) if (!merged.includes(entry)) merged.push(entry);
|
|
8
|
+
return merged;
|
|
9
|
+
};
|
|
10
|
+
const sameOrderedList = (a, b) => a.length === b.length && a.every((value, index) => value === b[index]);
|
|
11
|
+
const permissionAllowList = (parsed) => {
|
|
12
|
+
const { permissions } = parsed;
|
|
13
|
+
if (!isRecord(permissions)) return [];
|
|
14
|
+
const { allow } = permissions;
|
|
15
|
+
return Array.isArray(allow) ? allow.filter((entry) => typeof entry === "string") : [];
|
|
16
|
+
};
|
|
17
|
+
const applyPermissionsAllow = (content, parsed, projection) => {
|
|
18
|
+
const existing = permissionAllowList(parsed);
|
|
19
|
+
const merged = unionPreservingOrder(existing, projectedAllowList(projection));
|
|
20
|
+
return sameOrderedList(existing, merged) ? content : applyJsonEdit(content, ["permissions", "allow"], merged);
|
|
21
|
+
};
|
|
22
|
+
const applyClaudeProjection = (currentText, parsed, projection) => applyPermissionsAllow(applyMcpServersProjection(currentText, parsed, projection), parsed, projection);
|
|
23
|
+
const mergeClaudeSettings = (currentText = "", projection) => {
|
|
24
|
+
if (currentText === "") return {
|
|
5
25
|
content: formatJson(projection),
|
|
6
26
|
ok: true
|
|
7
27
|
};
|
|
@@ -11,34 +31,6 @@ function mergeClaudeSettings(currentText, projection) {
|
|
|
11
31
|
content: ensureTrailingNewline(applyClaudeProjection(currentText, parsed.value, projection)),
|
|
12
32
|
ok: true
|
|
13
33
|
};
|
|
14
|
-
}
|
|
15
|
-
function applyClaudeProjection(currentText, parsed, projection) {
|
|
16
|
-
return applyPermissionsAllow(applyMcpServersProjection(currentText, parsed, projection), parsed, projection);
|
|
17
|
-
}
|
|
18
|
-
function applyMcpServersProjection(content, parsed, projection) {
|
|
19
|
-
return Object.entries(projection.mcpServers ?? {}).reduce((nextContent, [name, server]) => setIfMissing(nextContent, parsed, ["mcpServers", name], server), content);
|
|
20
|
-
}
|
|
21
|
-
function applyPermissionsAllow(content, parsed, projection) {
|
|
22
|
-
const existing = permissionAllowList(parsed);
|
|
23
|
-
const merged = unionPreservingOrder(existing, projectedAllowList(projection));
|
|
24
|
-
return sameOrderedList(existing, merged) ? content : applyJsonEdit(content, ["permissions", "allow"], merged);
|
|
25
|
-
}
|
|
26
|
-
function projectedAllowList(projection) {
|
|
27
|
-
return projection.permissions?.allow ?? [];
|
|
28
|
-
}
|
|
29
|
-
function unionPreservingOrder(existing, extra) {
|
|
30
|
-
const merged = [...existing];
|
|
31
|
-
for (const entry of extra) if (!merged.includes(entry)) merged.push(entry);
|
|
32
|
-
return merged;
|
|
33
|
-
}
|
|
34
|
-
function sameOrderedList(a, b) {
|
|
35
|
-
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
36
|
-
}
|
|
37
|
-
function permissionAllowList(parsed) {
|
|
38
|
-
const permissions = parsed.permissions;
|
|
39
|
-
if (!isRecord(permissions)) return [];
|
|
40
|
-
const allow = permissions.allow;
|
|
41
|
-
return Array.isArray(allow) ? allow.filter((entry) => typeof entry === "string") : [];
|
|
42
|
-
}
|
|
34
|
+
};
|
|
43
35
|
//#endregion
|
|
44
36
|
export { mergeClaudeSettings };
|
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
import { applyJsonEdit, ensureTrailingNewline, formatJson, parseJsonRecord, setIfMissing } from "./json-config-merge.js";
|
|
2
2
|
//#region src/claude-user-config.ts
|
|
3
|
-
|
|
4
|
-
if (currentText ===
|
|
3
|
+
const mergeClaudeUserConfigWith = (projection, project, currentText = "") => {
|
|
4
|
+
if (currentText === "") return {
|
|
5
5
|
content: formatJson(projection),
|
|
6
6
|
ok: true
|
|
7
7
|
};
|
|
8
8
|
const parsed = parseJsonRecord(currentText);
|
|
9
9
|
if (!parsed.ok) return parsed;
|
|
10
10
|
return {
|
|
11
|
-
content: ensureTrailingNewline(
|
|
11
|
+
content: ensureTrailingNewline(project(currentText, parsed.value, projection)),
|
|
12
12
|
ok: true
|
|
13
13
|
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
content: formatJson(projection),
|
|
18
|
-
ok: true
|
|
19
|
-
};
|
|
20
|
-
const parsed = parseJsonRecord(currentText);
|
|
21
|
-
if (!parsed.ok) return parsed;
|
|
22
|
-
return {
|
|
23
|
-
content: ensureTrailingNewline(applyJsonEdit(currentText, ["mcpServers"], projection.mcpServers ?? {})),
|
|
24
|
-
ok: true
|
|
25
|
-
};
|
|
26
|
-
}
|
|
14
|
+
};
|
|
15
|
+
const mergeClaudeUserConfig = (projection, currentText = "") => mergeClaudeUserConfigWith(projection, (text, parsed, value) => Object.entries(value.mcpServers ?? {}).reduce((nextContent, [name, server]) => setIfMissing(nextContent, parsed, ["mcpServers", name], server), text), currentText);
|
|
16
|
+
const replaceClaudeUserMcpServers = (projection, currentText = "") => mergeClaudeUserConfigWith(projection, (text, _parsed, value) => applyJsonEdit(text, ["mcpServers"], value.mcpServers ?? {}), currentText);
|
|
27
17
|
//#endregion
|
|
28
18
|
export { mergeClaudeUserConfig, replaceClaudeUserMcpServers };
|
|
@@ -4,10 +4,10 @@ import { runDoctor } from "./doctor.js";
|
|
|
4
4
|
import { formatDoctorResult } from "./format.js";
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
//#region src/cli/bootstrap-commands.ts
|
|
7
|
-
|
|
7
|
+
const registerBootstrapCommands = (program) => {
|
|
8
8
|
program.command("doctor").description("Check local prerequisites for pipeline init and execution").option("--cluster [namespace]", "also check runner-job Kubernetes prerequisites").option("--json", "print machine-readable readiness results").option("--kube-context <context>", "kubectl context for cluster checks").option("--kubeconfig <path>", "kubeconfig path for cluster checks").action(async (flags) => {
|
|
9
9
|
const result = await runDoctor(process.env.PIPELINE_TARGET_PATH ?? process.cwd(), flags);
|
|
10
|
-
console.log(flags.json ? JSON.stringify(result) : formatDoctorResult(result));
|
|
10
|
+
console.log(flags.json === true ? JSON.stringify(result) : formatDoctorResult(result));
|
|
11
11
|
if (!result.passed) throw new Error("Doctor checks failed.");
|
|
12
12
|
});
|
|
13
13
|
program.command("init").description([
|
|
@@ -34,6 +34,6 @@ function registerBootstrapCommands(program) {
|
|
|
34
34
|
console.log(formatCodexAuthSyncResult(result));
|
|
35
35
|
if (!result.ok) process.exitCode = 1;
|
|
36
36
|
});
|
|
37
|
-
}
|
|
37
|
+
};
|
|
38
38
|
//#endregion
|
|
39
39
|
export { registerBootstrapCommands };
|
package/dist/cli/doctor.d.ts
CHANGED
|
@@ -16,6 +16,6 @@ interface DoctorFlags {
|
|
|
16
16
|
kubeContext?: string;
|
|
17
17
|
kubeconfig?: string;
|
|
18
18
|
}
|
|
19
|
-
declare
|
|
19
|
+
declare const runDoctor: (cwd: string, options?: DoctorFlags) => Promise<DoctorResult>;
|
|
20
20
|
//#endregion
|
|
21
21
|
export { DoctorCheck, DoctorFlags, DoctorResult, runDoctor };
|
package/dist/cli/doctor.js
CHANGED
|
@@ -2,6 +2,7 @@ import { PipelineConfigError } from "../config/schemas.js";
|
|
|
2
2
|
import { loadPipelineConfig } from "../config/load.js";
|
|
3
3
|
import "../config.js";
|
|
4
4
|
import { loadMokaGlobalConfig } from "../moka-global-config.js";
|
|
5
|
+
import { isRecord } from "../safe-json.js";
|
|
5
6
|
import { opencodeAgentName } from "../runtime/opencode-agent-name.js";
|
|
6
7
|
import { defaultClusterDoctorNamespace, runClusterDoctor } from "../cluster-doctor.js";
|
|
7
8
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
@@ -23,50 +24,123 @@ const OPENCODE_AGENT_LIST_ARGS = [
|
|
|
23
24
|
"list",
|
|
24
25
|
"--json"
|
|
25
26
|
];
|
|
26
|
-
const BULLET_PREFIX_RE = /^[-*]\s
|
|
27
|
-
const LINE_RE = /\r?\n
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
const BULLET_PREFIX_RE = /^[-*]\s+/u;
|
|
28
|
+
const LINE_RE = /\r?\n/u;
|
|
29
|
+
const clusterNamespace = (value, configuredNamespace) => typeof value === "string" && value.length > 0 ? value : configuredNamespace ?? defaultClusterDoctorNamespace();
|
|
30
|
+
const checkPipelineConfig = (cwd) => {
|
|
31
|
+
try {
|
|
32
|
+
loadPipelineConfig(cwd);
|
|
33
|
+
return {
|
|
34
|
+
detail: "valid",
|
|
35
|
+
name: "pipeline-config",
|
|
36
|
+
passed: true
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
let message = "invalid";
|
|
40
|
+
if (error instanceof PipelineConfigError) message = error.issues.map((issue) => issue.message).join("; ");
|
|
41
|
+
else if (error instanceof Error) message = error.message;
|
|
42
|
+
return {
|
|
43
|
+
detail: message || "missing or invalid",
|
|
44
|
+
name: "pipeline-config",
|
|
45
|
+
passed: false
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const skippedAgentVisibility = (detail) => ({
|
|
50
|
+
check: {
|
|
51
|
+
detail: "skipped because OpenCode agent listing is unavailable",
|
|
38
52
|
name: "moka-agents",
|
|
39
53
|
passed: true
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
},
|
|
55
|
+
warning: {
|
|
56
|
+
detail,
|
|
57
|
+
name: "moka-agents",
|
|
58
|
+
passed: true
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const expectedRunAgentNames = (config) => {
|
|
62
|
+
const profiles = /* @__PURE__ */ new Set();
|
|
63
|
+
for (const catalog of Object.values(config.scheduler.node_catalogs)) for (const node of Object.values(catalog.nodes)) if (RUN_READINESS_CATEGORIES.has(node.category)) profiles.add(node.profile);
|
|
64
|
+
return [...profiles].filter((profileId) => config.profiles[profileId]?.runner === "opencode").map(opencodeAgentName).toSorted((a, b) => a.localeCompare(b));
|
|
65
|
+
};
|
|
66
|
+
const collectAgentNames = (value, names, inAgentList) => {
|
|
67
|
+
if (typeof value === "string") {
|
|
68
|
+
if (inAgentList) names.add(value);
|
|
69
|
+
return inAgentList;
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
let recognized = inAgentList;
|
|
73
|
+
for (const item of value) recognized = collectAgentNames(item, names, inAgentList) || recognized;
|
|
74
|
+
return recognized;
|
|
75
|
+
}
|
|
76
|
+
if (!isRecord(value)) return false;
|
|
77
|
+
let recognized = false;
|
|
78
|
+
for (const key of [
|
|
79
|
+
"agent",
|
|
80
|
+
"id",
|
|
81
|
+
"name",
|
|
82
|
+
"subagent_type",
|
|
83
|
+
"title"
|
|
84
|
+
]) if (typeof value[key] === "string") {
|
|
85
|
+
names.add(value[key]);
|
|
86
|
+
recognized = true;
|
|
87
|
+
}
|
|
88
|
+
for (const key of [
|
|
89
|
+
"agents",
|
|
90
|
+
"data",
|
|
91
|
+
"items",
|
|
92
|
+
"result"
|
|
93
|
+
]) {
|
|
94
|
+
const item = value[key];
|
|
95
|
+
if (Array.isArray(item) || typeof item === "object" && item !== null) recognized = collectAgentNames(item, names, true) || recognized;
|
|
96
|
+
}
|
|
97
|
+
return recognized;
|
|
98
|
+
};
|
|
99
|
+
const visibleAgentNames = (stdout) => {
|
|
100
|
+
const names = /* @__PURE__ */ new Set();
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(stdout);
|
|
103
|
+
return {
|
|
104
|
+
ambiguous: false,
|
|
105
|
+
names,
|
|
106
|
+
recognized: collectAgentNames(parsed, names, Array.isArray(parsed))
|
|
107
|
+
};
|
|
108
|
+
} catch {
|
|
109
|
+
for (const line of stdout.split(LINE_RE)) {
|
|
110
|
+
const name = line.trim().replace(BULLET_PREFIX_RE, "");
|
|
111
|
+
if (name !== "") names.add(name);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
56
114
|
return {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
warnings
|
|
115
|
+
ambiguous: true,
|
|
116
|
+
names,
|
|
117
|
+
recognized: names.size > 0
|
|
61
118
|
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
|
|
119
|
+
};
|
|
120
|
+
const interactivePermissionPaths = (value, path = ["permission"]) => {
|
|
121
|
+
if (typeof value === "string") return HEADLESS_AGENT_PERMISSION_VALUES.has(value.toLowerCase()) ? [path.join(".")] : [];
|
|
122
|
+
if (Array.isArray(value)) return value.flatMap((item, index) => interactivePermissionPaths(item, [...path, String(index)]));
|
|
123
|
+
if (!isRecord(value)) return [];
|
|
124
|
+
return Object.entries(value).flatMap(([key, item]) => interactivePermissionPaths(item, [...path, key]));
|
|
125
|
+
};
|
|
126
|
+
const isHeadless = () => {
|
|
127
|
+
const ci = process.env.CI?.toLowerCase();
|
|
128
|
+
return ci !== void 0 && ci !== "" && ci !== "0" && ci !== "false" || !process.stdin.isTTY;
|
|
129
|
+
};
|
|
130
|
+
const stringField = (value, field) => {
|
|
131
|
+
if (typeof value !== "object" || value === null) return "";
|
|
132
|
+
const candidate = Reflect.get(value, field);
|
|
133
|
+
return typeof candidate === "string" ? candidate : "";
|
|
134
|
+
};
|
|
135
|
+
const commandErrorDetail = (err) => {
|
|
136
|
+
return ([
|
|
137
|
+
stringField(err, "shortMessage"),
|
|
138
|
+
stringField(err, "stderr"),
|
|
139
|
+
stringField(err, "message"),
|
|
140
|
+
String(err)
|
|
141
|
+
].find((candidate) => candidate.trim() !== "") ?? "not available").trim();
|
|
142
|
+
};
|
|
143
|
+
const checkCommandWithRunner = async (name, command, args, cwd) => {
|
|
70
144
|
try {
|
|
71
145
|
await execa(command, args, {
|
|
72
146
|
cwd,
|
|
@@ -77,34 +151,16 @@ async function checkCommandWithRunner(name, command, args, cwd) {
|
|
|
77
151
|
name,
|
|
78
152
|
passed: true
|
|
79
153
|
};
|
|
80
|
-
} catch (
|
|
154
|
+
} catch (error) {
|
|
81
155
|
return {
|
|
82
|
-
detail: commandErrorDetail(
|
|
156
|
+
detail: commandErrorDetail(error),
|
|
83
157
|
name,
|
|
84
158
|
passed: false
|
|
85
159
|
};
|
|
86
160
|
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
loadPipelineConfig(cwd);
|
|
91
|
-
return {
|
|
92
|
-
detail: "valid",
|
|
93
|
-
name: "pipeline-config",
|
|
94
|
-
passed: true
|
|
95
|
-
};
|
|
96
|
-
} catch (err) {
|
|
97
|
-
let message = "invalid";
|
|
98
|
-
if (err instanceof PipelineConfigError) message = err.issues.map((issue) => issue.message).join("; ");
|
|
99
|
-
else if (err instanceof Error) message = err.message;
|
|
100
|
-
return {
|
|
101
|
-
detail: message || "missing or invalid",
|
|
102
|
-
name: "pipeline-config",
|
|
103
|
-
passed: false
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async function checkOpenCodeSdk() {
|
|
161
|
+
};
|
|
162
|
+
const checkCommand = async (name, args, cwd) => await checkCommandWithRunner(name, name, args, cwd);
|
|
163
|
+
const checkOpenCodeSdk = async () => {
|
|
108
164
|
try {
|
|
109
165
|
if (typeof (await import("@opencode-ai/sdk")).createOpencodeClient !== "function") return {
|
|
110
166
|
detail: "@opencode-ai/sdk does not export createOpencodeClient",
|
|
@@ -116,15 +172,15 @@ async function checkOpenCodeSdk() {
|
|
|
116
172
|
name: "opencode-sdk",
|
|
117
173
|
passed: true
|
|
118
174
|
};
|
|
119
|
-
} catch (
|
|
175
|
+
} catch (error) {
|
|
120
176
|
return {
|
|
121
|
-
detail: commandErrorDetail(
|
|
177
|
+
detail: commandErrorDetail(error),
|
|
122
178
|
name: "opencode-sdk",
|
|
123
179
|
passed: false
|
|
124
180
|
};
|
|
125
181
|
}
|
|
126
|
-
}
|
|
127
|
-
async
|
|
182
|
+
};
|
|
183
|
+
const checkMokaAgents = async (cwd, config) => {
|
|
128
184
|
const expected = expectedRunAgentNames(config);
|
|
129
185
|
if (expected.length === 0) return { check: {
|
|
130
186
|
detail: "no configured MoKa run agents",
|
|
@@ -132,10 +188,11 @@ async function checkMokaAgents(cwd, config) {
|
|
|
132
188
|
passed: true
|
|
133
189
|
} };
|
|
134
190
|
try {
|
|
135
|
-
const
|
|
191
|
+
const result = await execa("opencode", OPENCODE_AGENT_LIST_ARGS, {
|
|
136
192
|
cwd,
|
|
137
193
|
stdin: "ignore"
|
|
138
|
-
})
|
|
194
|
+
});
|
|
195
|
+
const visible = visibleAgentNames(result.stdout);
|
|
139
196
|
if (!visible.recognized) return skippedAgentVisibility("OpenCode agent listing output was not recognized");
|
|
140
197
|
if (visible.ambiguous && expected.every((name) => !visible.names.has(name))) return skippedAgentVisibility("OpenCode agent listing output did not include recognizable MoKa agent names");
|
|
141
198
|
const missing = expected.filter((name) => !visible.names.has(name));
|
|
@@ -148,121 +205,69 @@ async function checkMokaAgents(cwd, config) {
|
|
|
148
205
|
name: "moka-agents",
|
|
149
206
|
passed: true
|
|
150
207
|
} };
|
|
151
|
-
} catch (
|
|
152
|
-
return skippedAgentVisibility(`Could not cheaply list OpenCode agents: ${commandErrorDetail(
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return skippedAgentVisibility(`Could not cheaply list OpenCode agents: ${commandErrorDetail(error)}`);
|
|
153
210
|
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
check: {
|
|
158
|
-
detail: "skipped because OpenCode agent listing is unavailable",
|
|
159
|
-
name: "moka-agents",
|
|
160
|
-
passed: true
|
|
161
|
-
},
|
|
162
|
-
warning: {
|
|
163
|
-
detail,
|
|
164
|
-
name: "moka-agents",
|
|
165
|
-
passed: true
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
function expectedRunAgentNames(config) {
|
|
170
|
-
const profiles = /* @__PURE__ */ new Set();
|
|
171
|
-
for (const catalog of Object.values(config.scheduler.node_catalogs)) for (const node of Object.values(catalog.nodes)) if (RUN_READINESS_CATEGORIES.has(node.category)) profiles.add(node.profile);
|
|
172
|
-
return [...profiles].filter((profileId) => config.profiles[profileId]?.runner === "opencode").map(opencodeAgentName).sort((a, b) => a.localeCompare(b));
|
|
173
|
-
}
|
|
174
|
-
function visibleAgentNames(stdout) {
|
|
175
|
-
const names = /* @__PURE__ */ new Set();
|
|
176
|
-
try {
|
|
177
|
-
const parsed = JSON.parse(stdout);
|
|
178
|
-
return {
|
|
179
|
-
ambiguous: false,
|
|
180
|
-
names,
|
|
181
|
-
recognized: collectAgentNames(parsed, names, Array.isArray(parsed))
|
|
182
|
-
};
|
|
183
|
-
} catch {
|
|
184
|
-
for (const line of stdout.split(LINE_RE)) {
|
|
185
|
-
const name = line.trim().replace(BULLET_PREFIX_RE, "");
|
|
186
|
-
if (name) names.add(name);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
ambiguous: true,
|
|
191
|
-
names,
|
|
192
|
-
recognized: names.size > 0
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
function collectAgentNames(value, names, inAgentList) {
|
|
196
|
-
if (typeof value === "string") {
|
|
197
|
-
if (inAgentList) names.add(value);
|
|
198
|
-
return inAgentList;
|
|
199
|
-
}
|
|
200
|
-
if (Array.isArray(value)) {
|
|
201
|
-
let recognized = inAgentList;
|
|
202
|
-
for (const item of value) recognized = collectAgentNames(item, names, inAgentList) || recognized;
|
|
203
|
-
return recognized;
|
|
204
|
-
}
|
|
205
|
-
if (!(value && typeof value === "object")) return false;
|
|
206
|
-
const record = value;
|
|
207
|
-
let recognized = false;
|
|
208
|
-
for (const key of [
|
|
209
|
-
"agent",
|
|
210
|
-
"id",
|
|
211
|
-
"name",
|
|
212
|
-
"subagent_type",
|
|
213
|
-
"title"
|
|
214
|
-
]) if (typeof record[key] === "string") {
|
|
215
|
-
names.add(record[key]);
|
|
216
|
-
recognized = true;
|
|
217
|
-
}
|
|
218
|
-
for (const key of [
|
|
219
|
-
"agents",
|
|
220
|
-
"data",
|
|
221
|
-
"items",
|
|
222
|
-
"result"
|
|
223
|
-
]) {
|
|
224
|
-
const item = record[key];
|
|
225
|
-
if (Array.isArray(item) || item && typeof item === "object") recognized = collectAgentNames(item, names, true) || recognized;
|
|
226
|
-
}
|
|
227
|
-
return recognized;
|
|
228
|
-
}
|
|
229
|
-
function headlessPermissionWarnings(cwd) {
|
|
230
|
-
if (!isHeadless()) return [];
|
|
231
|
-
const agentDir = join(cwd, ".opencode", "agents");
|
|
232
|
-
if (!existsSync(agentDir)) return [];
|
|
233
|
-
return readdirSync(agentDir).filter((entry) => entry.endsWith(".md")).flatMap((entry) => headlessPermissionWarning(join(agentDir, entry), entry));
|
|
234
|
-
}
|
|
235
|
-
function headlessPermissionWarning(path, entry) {
|
|
211
|
+
};
|
|
212
|
+
const headlessPermissionWarning = (path, entry) => {
|
|
236
213
|
try {
|
|
237
214
|
if (!statSync(path).isFile()) return [];
|
|
238
|
-
const
|
|
215
|
+
const parsed = matter(readFileSync(path, "utf-8"));
|
|
216
|
+
const risky = interactivePermissionPaths(parsed.data.permission);
|
|
239
217
|
if (risky.length === 0) return [];
|
|
240
218
|
return [{
|
|
241
219
|
detail: `${entry} requires interactive permission prompts at ${risky.join(", ")}; headless MoKa runs may block.`,
|
|
242
220
|
name: "headless-permissions",
|
|
243
221
|
passed: true
|
|
244
222
|
}];
|
|
245
|
-
} catch (
|
|
223
|
+
} catch (error) {
|
|
246
224
|
return [{
|
|
247
|
-
detail: `Could not inspect ${entry} for headless permission risks: ${commandErrorDetail(
|
|
225
|
+
detail: `Could not inspect ${entry} for headless permission risks: ${commandErrorDetail(error)}`,
|
|
248
226
|
name: "headless-permissions",
|
|
249
227
|
passed: true
|
|
250
228
|
}];
|
|
251
229
|
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
if (!(
|
|
257
|
-
return
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
230
|
+
};
|
|
231
|
+
const headlessPermissionWarnings = (cwd) => {
|
|
232
|
+
if (!isHeadless()) return [];
|
|
233
|
+
const agentDir = join(cwd, ".opencode", "agents");
|
|
234
|
+
if (!existsSync(agentDir)) return [];
|
|
235
|
+
return readdirSync(agentDir).filter((entry) => entry.endsWith(".md")).flatMap((entry) => headlessPermissionWarning(join(agentDir, entry), entry));
|
|
236
|
+
};
|
|
237
|
+
const runDoctor = async (cwd, options = {}) => {
|
|
238
|
+
const commandChecks = await Promise.all([
|
|
239
|
+
checkCommand("npx", ["--version"], cwd),
|
|
240
|
+
checkCommand("opencode", ["--version"], cwd),
|
|
241
|
+
checkCommand("fallow", ["--version"], cwd)
|
|
242
|
+
]);
|
|
243
|
+
const configCheck = checkPipelineConfig(cwd);
|
|
244
|
+
const config = configCheck.passed ? loadPipelineConfig(cwd) : null;
|
|
245
|
+
const [sdkCheck, agentVisibility] = await Promise.all([checkOpenCodeSdk(), config ? checkMokaAgents(cwd, config) : Promise.resolve({ check: {
|
|
246
|
+
detail: "skipped because pipeline config is invalid",
|
|
247
|
+
name: "moka-agents",
|
|
248
|
+
passed: true
|
|
249
|
+
} })]);
|
|
250
|
+
const globalConfig = loadMokaGlobalConfig();
|
|
251
|
+
const clusterResult = options.cluster !== void 0 && options.cluster !== false ? await runClusterDoctor({
|
|
252
|
+
kubeContext: options.kubeContext,
|
|
253
|
+
kubeconfigPath: options.kubeconfig ?? (globalConfig === null ? void 0 : globalConfig.momokaya.kubernetes.kubeconfig),
|
|
254
|
+
namespace: clusterNamespace(options.cluster, globalConfig === null ? void 0 : globalConfig.momokaya.kubernetes.namespace)
|
|
255
|
+
}) : { checks: [] };
|
|
256
|
+
const checks = [
|
|
257
|
+
...commandChecks,
|
|
258
|
+
configCheck,
|
|
259
|
+
sdkCheck,
|
|
260
|
+
agentVisibility.check,
|
|
261
|
+
...clusterResult.checks
|
|
262
|
+
];
|
|
263
|
+
const warnings = [...agentVisibility.warning ? [agentVisibility.warning] : [], ...headlessPermissionWarnings(cwd)];
|
|
264
|
+
const blockers = checks.filter((check) => !check.passed);
|
|
265
|
+
return {
|
|
266
|
+
blockers,
|
|
267
|
+
checks,
|
|
268
|
+
passed: blockers.length === 0,
|
|
269
|
+
warnings
|
|
270
|
+
};
|
|
271
|
+
};
|
|
267
272
|
//#endregion
|
|
268
273
|
export { runDoctor };
|
|
@@ -2,32 +2,32 @@ import { runCreateExperiment } from "../factory/create-experiment.js";
|
|
|
2
2
|
import { runTemplateUpdate, summarizeTemplateUpdate } from "../factory/template-update.js";
|
|
3
3
|
import { Option } from "commander";
|
|
4
4
|
//#region src/cli/factory-commands.ts
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const hasText = (value) => typeof value === "string" && value !== "";
|
|
6
|
+
const registerFactoryCommands = (program) => {
|
|
7
|
+
program.command("create-experiment").description("Birth a fleet experiment: copier-stamp momokaya-template, create+push the org repo, register it in infra's fleet registry").requiredOption("--name <name>", "app name (kebab-case)").addOption(new Option("--flavor <flavor>", "app flavor").choices(["web", "expo-web"]).default("web")).option("--no-db", "skip the database surface").option("--org <org>", "GitHub org for the new repo").option("--template-src <source>", "copier template source").option("--template-ref <ref>", "template tag/ref (default: latest tag)").option("--infra-repo-url <url>", "infra repo the registry entry lands in").action(async (flags) => {
|
|
7
8
|
const result = await runCreateExperiment({
|
|
8
9
|
db: flags.db,
|
|
9
10
|
flavor: flags.flavor,
|
|
10
|
-
...flags.infraRepoUrl ? { infraRepoUrl: flags.infraRepoUrl } : {},
|
|
11
|
+
...hasText(flags.infraRepoUrl) ? { infraRepoUrl: flags.infraRepoUrl } : {},
|
|
11
12
|
name: flags.name,
|
|
12
|
-
...flags.org ? { org: flags.org } : {},
|
|
13
|
-
|
|
14
|
-
...flags.
|
|
15
|
-
...flags.templateSrc ? { templateSource: flags.templateSrc } : {}
|
|
13
|
+
...hasText(flags.org) ? { org: flags.org } : {},
|
|
14
|
+
...hasText(flags.templateRef) ? { templateRef: flags.templateRef } : {},
|
|
15
|
+
...hasText(flags.templateSrc) ? { templateSource: flags.templateSrc } : {}
|
|
16
16
|
});
|
|
17
17
|
console.log(`Experiment born: ${result.repoUrl} (registry ${result.registryPath} @ infra ${result.infraCommitSha})`);
|
|
18
18
|
});
|
|
19
19
|
program.command("template-update").description("Fan copier-update PRs out across repos stamped from momokaya-template").option("--repos <repos>", "comma-separated repo list (skips fleet-registry discovery)").option("--org <org>", "GitHub org the stamped repos live in").option("--template-match <substring>", "answers-file _src_path filter for stamp detection").option("--template-ref <ref>", "template tag/ref (default: latest tag)").option("--infra-repo-url <url>", "infra repo used for discovery").action(async (flags) => {
|
|
20
20
|
const { results } = await runTemplateUpdate({
|
|
21
|
-
...flags.infraRepoUrl ? { infraRepoUrl: flags.infraRepoUrl } : {},
|
|
22
|
-
...flags.org ? { org: flags.org } : {},
|
|
23
|
-
...flags.repos ? { repos: flags.repos.split(",").map((repo) => repo.trim()).filter((repo) => repo.length > 0) } : {},
|
|
24
|
-
...flags.templateMatch ? { templateMatch: flags.templateMatch } : {},
|
|
25
|
-
...flags.templateRef ? { templateRef: flags.templateRef } : {}
|
|
21
|
+
...hasText(flags.infraRepoUrl) ? { infraRepoUrl: flags.infraRepoUrl } : {},
|
|
22
|
+
...hasText(flags.org) ? { org: flags.org } : {},
|
|
23
|
+
...hasText(flags.repos) ? { repos: flags.repos.split(",").map((repo) => repo.trim()).filter((repo) => repo.length > 0) } : {},
|
|
24
|
+
...hasText(flags.templateMatch) ? { templateMatch: flags.templateMatch } : {},
|
|
25
|
+
...hasText(flags.templateRef) ? { templateRef: flags.templateRef } : {}
|
|
26
26
|
});
|
|
27
27
|
const { failed, opened } = summarizeTemplateUpdate(results);
|
|
28
28
|
console.log(`template-update: ${opened} PR(s) opened, ${failed} error(s)`);
|
|
29
29
|
if (failed > 0) process.exitCode = 1;
|
|
30
30
|
});
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
32
|
//#endregion
|
|
33
33
|
export { registerFactoryCommands };
|