@the-open-engine/zeroshot 6.38.0 → 6.39.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/cli/event-copy.js +8 -7
- package/cli/event-copy.ts +12 -0
- package/cli/index.js +7 -31
- package/cli/json-export.js +61 -64
- package/cli/json-export.ts +112 -0
- package/cli/message-formatter-utils.js +68 -56
- package/cli/message-formatter-utils.ts +121 -0
- package/cli/message-formatters-normal.js +124 -259
- package/cli/message-formatters-normal.ts +250 -0
- package/cli/message-formatters-watch.js +81 -84
- package/cli/message-formatters-watch.ts +189 -0
- package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +3 -1
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/cluster/generated/protocol-schema.cjs +1 -1
- package/lib/cluster/generated/protocol-schema.mjs +1 -1
- package/lib/cluster/generated/protocol.d.cts +8 -0
- package/lib/cluster/generated/protocol.d.mts +8 -0
- package/lib/cluster/generated/protocol.d.ts +8 -0
- package/lib/clusters-registry.d.ts +23 -0
- package/lib/clusters-registry.js +17 -29
- package/lib/completion.d.ts +12 -0
- package/lib/completion.js +84 -94
- package/lib/compose-utils.d.ts +32 -0
- package/lib/compose-utils.js +57 -72
- package/lib/detached-startup.d.ts +83 -0
- package/lib/detached-startup.js +231 -302
- package/lib/docker-config.d.ts +43 -0
- package/lib/docker-config.js +150 -325
- package/lib/docker-env-auth.d.ts +17 -0
- package/lib/docker-env-auth.js +75 -0
- package/lib/git-remote-utils.d.ts +48 -0
- package/lib/git-remote-utils.js +147 -213
- package/lib/id-detector.d.ts +15 -0
- package/lib/id-detector.js +37 -41
- package/lib/path-check.d.ts +30 -0
- package/lib/path-check.js +42 -45
- package/lib/process-liveness.d.ts +16 -0
- package/lib/process-liveness.js +19 -12
- package/lib/provider-credential-path.d.ts +16 -0
- package/lib/provider-credential-path.js +31 -29
- package/lib/provider-defaults.d.ts +30 -0
- package/lib/provider-defaults.js +47 -42
- package/lib/provider-detection.d.ts +11 -0
- package/lib/provider-detection.js +91 -54
- package/lib/provider-names.d.ts +38 -0
- package/lib/provider-names.js +56 -64
- package/lib/repo-settings.d.ts +28 -0
- package/lib/repo-settings.js +83 -59
- package/lib/run-mode.d.ts +21 -0
- package/lib/run-mode.js +21 -20
- package/lib/run-plan.d.ts +28 -0
- package/lib/run-plan.js +17 -16
- package/lib/settings/claude-auth.d.ts +35 -0
- package/lib/settings/claude-auth.js +30 -47
- package/lib/settings-defaults.d.ts +20 -0
- package/lib/settings-defaults.js +149 -0
- package/lib/settings-error.d.ts +7 -0
- package/lib/settings-error.js +8 -0
- package/lib/settings-issue-providers.d.ts +10 -0
- package/lib/settings-issue-providers.js +12 -0
- package/lib/settings-models.d.ts +22 -0
- package/lib/settings-models.js +93 -0
- package/lib/settings-storage.d.ts +23 -0
- package/lib/settings-storage.js +205 -0
- package/lib/settings-validation.d.ts +7 -0
- package/lib/settings-validation.js +182 -0
- package/lib/settings.d.ts +29 -0
- package/lib/settings.js +41 -736
- package/lib/setup-apply-types.d.ts +66 -0
- package/lib/setup-apply-types.js +2 -0
- package/lib/setup-apply.d.ts +39 -0
- package/lib/setup-apply.js +267 -264
- package/lib/setup-journal.d.ts +41 -0
- package/lib/setup-journal.js +119 -76
- package/lib/setup-plan-types.d.ts +102 -0
- package/lib/setup-plan-types.js +2 -0
- package/lib/setup-plan.d.ts +30 -0
- package/lib/setup-plan.js +300 -324
- package/lib/setup-undo.d.ts +44 -0
- package/lib/setup-undo.js +61 -74
- package/lib/start-cluster-config.d.ts +26 -0
- package/lib/start-cluster-config.js +56 -0
- package/lib/start-cluster-environment.d.ts +40 -0
- package/lib/start-cluster-environment.js +134 -0
- package/lib/start-cluster-run-options.d.ts +53 -0
- package/lib/start-cluster-run-options.js +147 -0
- package/lib/start-cluster.d.ts +64 -0
- package/lib/start-cluster.js +98 -454
- package/lib/stream-json-parser.d.ts +17 -0
- package/lib/stream-json-parser.js +51 -52
- package/npm-shrinkwrap.json +2 -2
- package/package.json +12 -6
- package/scripts/postinstall.js +27 -0
- package/scripts/rust-distribution.js +23 -14
- package/src/agent/agent-command-proofs-context.js +35 -45
- package/src/agent/agent-command-proofs-context.ts +87 -0
- package/src/agent/agent-config-settings.js +19 -0
- package/src/agent/agent-config-settings.ts +41 -0
- package/src/agent/agent-config.js +122 -231
- package/src/agent/agent-config.ts +285 -0
- package/src/agent/agent-context-builder.js +38 -273
- package/src/agent/agent-context-builder.ts +51 -0
- package/src/agent/agent-context-environment-sections.js +105 -0
- package/src/agent/agent-context-environment-sections.ts +134 -0
- package/src/agent/agent-context-packs.js +165 -0
- package/src/agent/agent-context-packs.ts +296 -0
- package/src/agent/agent-context-prompt-sections.js +100 -0
- package/src/agent/agent-context-prompt-sections.ts +148 -0
- package/src/agent/agent-context-sections.js +25 -334
- package/src/agent/agent-context-sections.ts +36 -0
- package/src/agent/agent-context-sources.js +96 -149
- package/src/agent/agent-context-sources.ts +253 -0
- package/src/agent/agent-context-types.js +2 -0
- package/src/agent/agent-context-types.ts +132 -0
- package/src/agent/agent-context-validation-sections.js +73 -0
- package/src/agent/agent-context-validation-sections.ts +129 -0
- package/src/agent/agent-input-injector.js +99 -118
- package/src/agent/agent-input-injector.ts +195 -0
- package/src/agent/agent-liveness-poll.js +74 -78
- package/src/agent/agent-liveness-poll.ts +163 -0
- package/src/agent/agent-quality-gate-schema.js +77 -86
- package/src/agent/agent-quality-gate-schema.ts +135 -0
- package/src/agent/agent-quality-gates-context.js +44 -50
- package/src/agent/agent-quality-gates-context.ts +91 -0
- package/src/agent/agent-stuck-detector.js +171 -239
- package/src/agent/agent-stuck-detector.ts +288 -0
- package/src/agent/agent-trigger-evaluator.js +29 -46
- package/src/agent/agent-trigger-evaluator.ts +98 -0
- package/src/agent/context-metrics.js +110 -141
- package/src/agent/context-metrics.ts +261 -0
- package/src/agent/context-pack-builder.js +72 -358
- package/src/agent/context-pack-builder.ts +105 -0
- package/src/agent/context-pack-core.js +70 -0
- package/src/agent/context-pack-core.ts +96 -0
- package/src/agent/context-pack-selection.js +119 -0
- package/src/agent/context-pack-selection.ts +187 -0
- package/src/agent/context-pack-truncation.js +139 -0
- package/src/agent/context-pack-truncation.ts +208 -0
- package/src/agent/context-pack-types.js +2 -0
- package/src/agent/context-pack-types.ts +98 -0
- package/src/agent/context-replay-policy.js +30 -39
- package/src/agent/context-replay-policy.ts +71 -0
- package/src/agent/critical-agent-policy.js +6 -10
- package/src/agent/critical-agent-policy.ts +20 -0
- package/src/agent/guidance-queue.js +74 -87
- package/src/agent/guidance-queue.ts +166 -0
- package/src/agent/output-extraction-error-detail.js +45 -0
- package/src/agent/output-extraction-error-detail.ts +49 -0
- package/src/agent/output-extraction-failures.js +125 -0
- package/src/agent/output-extraction-failures.ts +149 -0
- package/src/agent/output-extraction-json.js +234 -0
- package/src/agent/output-extraction-json.ts +235 -0
- package/src/agent/output-extraction-pi.js +124 -0
- package/src/agent/output-extraction-pi.ts +137 -0
- package/src/agent/output-extraction-types.js +2 -0
- package/src/agent/output-extraction-types.ts +49 -0
- package/src/agent/output-extraction.js +17 -617
- package/src/agent/output-extraction.ts +30 -0
- package/src/agent/output-reformatter-errors.js +83 -0
- package/src/agent/output-reformatter-errors.ts +106 -0
- package/src/agent/output-reformatter-types.js +2 -0
- package/src/agent/output-reformatter-types.ts +86 -0
- package/src/agent/output-reformatter.js +140 -185
- package/src/agent/output-reformatter.ts +238 -0
- package/src/agent/pi-terminal-lifecycle-types.js +2 -0
- package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
- package/src/agent/pi-terminal-lifecycle.js +186 -206
- package/src/agent/pi-terminal-lifecycle.ts +297 -0
- package/src/agent/provider-control-plane.js +22 -21
- package/src/agent/provider-control-plane.ts +52 -0
- package/src/agent/provider-terminal-failure-types.js +2 -0
- package/src/agent/provider-terminal-failure-types.ts +60 -0
- package/src/agent/provider-terminal-failure.js +194 -191
- package/src/agent/provider-terminal-failure.ts +262 -0
- package/src/agent/rate-limit-backoff.js +31 -74
- package/src/agent/rate-limit-backoff.ts +71 -0
- package/src/agent/schema-utils.js +85 -125
- package/src/agent/schema-utils.ts +148 -0
- package/src/agent/structured-output-error.js +34 -33
- package/src/agent/structured-output-error.ts +105 -0
- package/src/agent/validation-platform.js +27 -27
- package/src/agent/validation-platform.ts +49 -0
- package/src/agent-cli-provider/adapters/codex.ts +3 -1
- package/src/attach/attach-client.js +232 -405
- package/src/attach/attach-client.ts +300 -0
- package/src/attach/attach-server-cleanup.js +43 -0
- package/src/attach/attach-server-cleanup.ts +39 -0
- package/src/attach/attach-server-clients.js +117 -0
- package/src/attach/attach-server-clients.ts +122 -0
- package/src/attach/attach-server-events.js +38 -0
- package/src/attach/attach-server-events.ts +36 -0
- package/src/attach/attach-server-pty.js +45 -0
- package/src/attach/attach-server-pty.ts +64 -0
- package/src/attach/attach-server-runtime.js +73 -0
- package/src/attach/attach-server-runtime.ts +62 -0
- package/src/attach/attach-server-socket.js +28 -0
- package/src/attach/attach-server-socket.ts +23 -0
- package/src/attach/attach-server-types.js +2 -0
- package/src/attach/attach-server-types.ts +82 -0
- package/src/attach/attach-server.js +106 -523
- package/src/attach/attach-server.ts +158 -0
- package/src/attach/index.js +18 -35
- package/src/attach/index.ts +18 -0
- package/src/attach/protocol.js +95 -184
- package/src/attach/protocol.ts +181 -0
- package/src/attach/ring-buffer.js +76 -102
- package/src/attach/ring-buffer.ts +109 -0
- package/src/attach/send-input.js +64 -75
- package/src/attach/send-input.ts +94 -0
- package/src/attach/socket-discovery.js +164 -218
- package/src/attach/socket-discovery.ts +230 -0
- package/src/attach/socket-paths.js +42 -61
- package/src/attach/socket-paths.ts +81 -0
- package/src/claude-credentials.js +51 -54
- package/src/claude-credentials.ts +89 -0
- package/src/cluster/generated/protocol-schema.ts +1 -1
- package/src/cluster/generated/protocol.ts +2 -1
- package/src/command-proofs.js +110 -141
- package/src/command-proofs.ts +216 -0
- package/src/config-router.js +81 -73
- package/src/config-router.ts +131 -0
- package/src/copy-worker.js +53 -29
- package/src/copy-worker.ts +75 -0
- package/src/darwin-keychain-boundary.js +80 -111
- package/src/darwin-keychain-boundary.ts +148 -0
- package/src/guidance-topics.js +4 -5
- package/src/guidance-topics.ts +10 -0
- package/src/input-helpers.js +33 -54
- package/src/input-helpers.ts +58 -0
- package/src/ledger-sequence.js +45 -48
- package/src/ledger-sequence.ts +63 -0
- package/src/legacy-lib/clusters-registry.ts +40 -0
- package/src/legacy-lib/completion.ts +148 -0
- package/src/legacy-lib/compose-utils.ts +102 -0
- package/src/legacy-lib/detached-startup.ts +449 -0
- package/src/legacy-lib/docker-config.ts +282 -0
- package/src/legacy-lib/docker-env-auth.ts +116 -0
- package/src/legacy-lib/git-remote-utils.ts +244 -0
- package/src/legacy-lib/id-detector.ts +57 -0
- package/src/legacy-lib/js-yaml.d.ts +3 -0
- package/src/legacy-lib/omelette.d.ts +15 -0
- package/src/legacy-lib/path-check.ts +89 -0
- package/src/legacy-lib/process-liveness.ts +36 -0
- package/src/legacy-lib/provider-credential-path.ts +57 -0
- package/src/legacy-lib/provider-defaults.ts +114 -0
- package/src/legacy-lib/provider-detection.ts +67 -0
- package/src/legacy-lib/provider-names.ts +126 -0
- package/src/legacy-lib/repo-settings.ts +88 -0
- package/src/legacy-lib/run-mode.ts +58 -0
- package/src/legacy-lib/run-plan.ts +49 -0
- package/src/legacy-lib/settings/claude-auth.ts +80 -0
- package/src/legacy-lib/settings-defaults.ts +212 -0
- package/src/legacy-lib/settings-error.ts +8 -0
- package/src/legacy-lib/settings-issue-providers.ts +18 -0
- package/src/legacy-lib/settings-models.ts +124 -0
- package/src/legacy-lib/settings-storage.ts +277 -0
- package/src/legacy-lib/settings-validation.ts +220 -0
- package/src/legacy-lib/settings.ts +87 -0
- package/src/legacy-lib/setup-apply-types.ts +70 -0
- package/src/legacy-lib/setup-apply.ts +456 -0
- package/src/legacy-lib/setup-journal.ts +185 -0
- package/src/legacy-lib/setup-plan-types.ts +96 -0
- package/src/legacy-lib/setup-plan.ts +500 -0
- package/src/legacy-lib/setup-undo.ts +142 -0
- package/src/legacy-lib/start-cluster-config.ts +124 -0
- package/src/legacy-lib/start-cluster-environment.ts +165 -0
- package/src/legacy-lib/start-cluster-run-options.ts +279 -0
- package/src/legacy-lib/start-cluster.ts +237 -0
- package/src/legacy-lib/stream-json-parser.ts +88 -0
- package/src/message-buffer.js +55 -71
- package/src/message-buffer.ts +107 -0
- package/src/message-bus-bridge.js +92 -133
- package/src/message-bus-bridge.ts +149 -0
- package/src/name-generator-shared.js +220 -0
- package/src/name-generator-shared.ts +231 -0
- package/src/name-generator.js +8 -217
- package/src/name-generator.ts +27 -0
- package/src/omp-blob-root.js +83 -64
- package/src/omp-blob-root.ts +116 -0
- package/src/omp-config-overlay.js +65 -38
- package/src/omp-config-overlay.ts +110 -0
- package/src/omp-execution-fingerprint.js +38 -43
- package/src/omp-execution-fingerprint.ts +92 -0
- package/src/omp-session-limits.js +10 -15
- package/src/omp-session-limits.ts +53 -0
- package/src/omp-session-partition.js +2 -2
- package/src/omp-session-verifier.js +1 -1
- package/src/orchestrator.js +19 -4
- package/src/providers/anthropic/index.js +3 -1
- package/src/providers/anthropic/index.ts +13 -0
- package/src/providers/capabilities.js +19 -27
- package/src/providers/capabilities.ts +44 -0
- package/src/providers/google/index.js +3 -1
- package/src/providers/google/index.ts +13 -0
- package/src/providers/openai/index.js +3 -1
- package/src/providers/openai/index.ts +13 -0
- package/src/providers/opencode/index.js +3 -1
- package/src/providers/opencode/index.ts +13 -0
- package/src/quality-gates.js +67 -127
- package/src/quality-gates.ts +149 -0
- package/src/repo-settings-access.js +40 -0
- package/src/repo-settings-access.ts +64 -0
- package/src/schemas/sub-cluster.js +127 -183
- package/src/schemas/sub-cluster.ts +238 -0
- package/src/state-snapshot-normalization.js +224 -0
- package/src/state-snapshot-normalization.ts +222 -0
- package/src/state-snapshot.js +192 -359
- package/src/state-snapshot.ts +291 -0
- package/src/state-snapshotter.js +118 -130
- package/src/state-snapshotter.ts +167 -0
- package/src/sub-cluster-wrapper.js +4 -13
- package/src/task-run-model-args.js +87 -124
- package/src/task-run-model-args.ts +204 -0
- package/src/task-runner.js +5 -25
- package/src/task-runner.ts +28 -0
- package/src/task-startup-error.js +73 -58
- package/src/task-startup-error.ts +126 -0
- package/src/template-validation/consensus-gate-contracts.js +2 -0
- package/src/template-validation/consensus-gate-contracts.ts +70 -0
- package/src/template-validation/consensus-gate-scenarios.js +76 -0
- package/src/template-validation/consensus-gate-scenarios.ts +130 -0
- package/src/template-validation/consensus-gate-stage.js +34 -0
- package/src/template-validation/consensus-gate-stage.ts +56 -0
- package/src/template-validation/random-topology-contracts.js +2 -0
- package/src/template-validation/random-topology-contracts.ts +54 -0
- package/src/template-validation/random-topology-dispatch.js +25 -0
- package/src/template-validation/random-topology-dispatch.ts +33 -0
- package/src/template-validation/random-topology-message-loop.js +53 -0
- package/src/template-validation/random-topology-message-loop.ts +73 -0
- package/src/template-validation/random-topology-operations.js +79 -0
- package/src/template-validation/random-topology-operations.ts +101 -0
- package/src/template-validation/random-topology-runtime.js +25 -0
- package/src/template-validation/random-topology-runtime.ts +43 -0
- package/src/template-validation/random-topology-scenario.js +52 -0
- package/src/template-validation/random-topology-scenario.ts +57 -0
- package/src/template-validation/random-topology-schema.js +159 -0
- package/src/template-validation/random-topology-schema.ts +190 -0
- package/src/template-validation/random-topology-state.js +28 -0
- package/src/template-validation/random-topology-state.ts +30 -0
- package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
- package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
- package/src/template-validation/random-topology-trigger.js +75 -0
- package/src/template-validation/random-topology-trigger.ts +88 -0
- package/src/template-validation/report-formatter.js +40 -46
- package/src/template-validation/report-formatter.ts +101 -0
- package/src/template-validation/simulate-consensus-gates.js +111 -302
- package/src/template-validation/simulate-consensus-gates.ts +196 -0
- package/src/template-validation/simulate-random-topology.js +26 -519
- package/src/template-validation/simulate-random-topology.ts +57 -0
- package/src/template-validation/simulate-two-stage-validation.js +41 -265
- package/src/template-validation/simulate-two-stage-validation.ts +55 -0
- package/src/template-validation/simulation-agent-runtime.js +25 -0
- package/src/template-validation/simulation-agent-runtime.ts +40 -0
- package/src/template-validation/simulation-agent.js +29 -0
- package/src/template-validation/simulation-agent.ts +73 -0
- package/src/template-validation/simulation-runtime.js +34 -0
- package/src/template-validation/simulation-runtime.ts +72 -0
- package/src/template-validation/two-stage-contracts.js +2 -0
- package/src/template-validation/two-stage-contracts.ts +41 -0
- package/src/template-validation/two-stage-inputs.js +21 -0
- package/src/template-validation/two-stage-inputs.ts +29 -0
- package/src/template-validation/two-stage-results.js +30 -0
- package/src/template-validation/two-stage-results.ts +40 -0
- package/src/template-validation/two-stage-scenario.js +86 -0
- package/src/template-validation/two-stage-scenario.ts +120 -0
- package/src/worktree-claude-config.js +182 -220
- package/src/worktree-claude-config.ts +272 -0
- package/src/worktree-tooling-env.js +103 -125
- package/src/worktree-tooling-env.ts +142 -0
- package/task-lib/completion.js +2 -3
- package/task-lib/completion.ts +9 -0
- package/task-lib/config.js +1 -4
- package/task-lib/config.ts +11 -0
- package/task-lib/name-generator.js +4 -226
- package/task-lib/name-generator.ts +11 -0
- package/task-lib/omp-session-cleanup.js +1 -1
- package/task-lib/omp-storage-root.js +8 -12
- package/task-lib/omp-storage-root.ts +62 -0
- package/task-lib/process-termination.js +143 -166
- package/task-lib/process-termination.ts +268 -0
package/lib/settings.js
CHANGED
|
@@ -1,741 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
class SettingsValidationError extends Error {
|
|
25
|
-
constructor(message) {
|
|
26
|
-
super(message);
|
|
27
|
-
this.name = 'SettingsValidationError';
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Lazy-loaded to avoid circular dependency (issue-providers → settings → issue-providers)
|
|
32
|
-
let _issueProviderFns = null;
|
|
33
|
-
function getIssueProviderFns() {
|
|
34
|
-
if (!_issueProviderFns) {
|
|
35
|
-
_issueProviderFns = require('../src/issue-providers');
|
|
36
|
-
}
|
|
37
|
-
return _issueProviderFns;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Get settings file path (dynamically reads env var for testing)
|
|
42
|
-
* Using a getter ensures tests can override the path at runtime
|
|
43
|
-
* @returns {string}
|
|
44
|
-
*/
|
|
45
|
-
function getSettingsFile() {
|
|
46
|
-
return (
|
|
47
|
-
process.env.ZEROSHOT_SETTINGS_FILE || path.join(os.homedir(), '.zeroshot', 'settings.json')
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Whether the global settings file exists on disk (vs. running on defaults).
|
|
53
|
-
* @returns {boolean}
|
|
54
|
-
*/
|
|
55
|
-
function settingsFileExists() {
|
|
56
|
-
return fs.existsSync(getSettingsFile());
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Import provider defaults from separate module to avoid circular dependency
|
|
60
|
-
const { getProviderDefaults, clearProviderDefaultsCache } = require('./provider-defaults');
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Model hierarchy for cost ceiling validation
|
|
64
|
-
* Higher number = more expensive/capable model
|
|
65
|
-
*/
|
|
66
|
-
const MODEL_HIERARCHY = {
|
|
67
|
-
opus: 3,
|
|
68
|
-
fable: 3,
|
|
69
|
-
sonnet: 2,
|
|
70
|
-
haiku: 1,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const VALID_MODELS = Object.keys(MODEL_HIERARCHY);
|
|
74
|
-
const LEVEL_RANKS = { level1: 1, level2: 2, level3: 3 };
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Validate a requested model against the maxModel ceiling and minModel floor
|
|
78
|
-
* @param {string} requestedModel - Model the agent wants to use
|
|
79
|
-
* @param {string} maxModel - Maximum allowed model (cost ceiling)
|
|
80
|
-
* @param {string|null} minModel - Minimum required model (cost floor)
|
|
81
|
-
* @returns {string} The validated model
|
|
82
|
-
* @throws {Error} If requested model exceeds ceiling or falls below floor
|
|
83
|
-
*/
|
|
84
|
-
function validateModelAgainstMax(requestedModel, maxModel, minModel = null) {
|
|
85
|
-
if (!requestedModel) return maxModel; // Default to ceiling if unspecified
|
|
86
|
-
|
|
87
|
-
if (!VALID_MODELS.includes(requestedModel)) {
|
|
88
|
-
throw new Error(`Invalid model "${requestedModel}". Valid: ${VALID_MODELS.join(', ')}`);
|
|
89
|
-
}
|
|
90
|
-
if (!VALID_MODELS.includes(maxModel)) {
|
|
91
|
-
throw new Error(`Invalid maxModel "${maxModel}". Valid: ${VALID_MODELS.join(', ')}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (MODEL_HIERARCHY[requestedModel] > MODEL_HIERARCHY[maxModel]) {
|
|
95
|
-
throw new Error(
|
|
96
|
-
`Agent requests "${requestedModel}" but maxModel is "${maxModel}". ` +
|
|
97
|
-
`Either lower agent's model or raise maxModel.`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (minModel) {
|
|
102
|
-
if (!VALID_MODELS.includes(minModel)) {
|
|
103
|
-
throw new Error(`Invalid minModel "${minModel}". Valid: ${VALID_MODELS.join(', ')}`);
|
|
104
|
-
}
|
|
105
|
-
if (MODEL_HIERARCHY[minModel] > MODEL_HIERARCHY[maxModel]) {
|
|
106
|
-
throw new Error(`minModel "${minModel}" cannot be higher than maxModel "${maxModel}".`);
|
|
107
|
-
}
|
|
108
|
-
if (MODEL_HIERARCHY[requestedModel] < MODEL_HIERARCHY[minModel]) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
`Agent requests "${requestedModel}" but minModel is "${minModel}". ` +
|
|
111
|
-
`Either raise agent's model or lower minModel.`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return requestedModel;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Default settings (base - without issue provider settings which are added dynamically)
|
|
120
|
-
const DEFAULT_SETTINGS_BASE = {
|
|
121
|
-
maxModel: 'opus', // Cost ceiling - agents cannot use models above this
|
|
122
|
-
minModel: null, // Cost floor - agents cannot use models below this (null = no minimum)
|
|
123
|
-
defaultProvider: getDefaultProviderId(),
|
|
124
|
-
get providerSettings() {
|
|
125
|
-
// Dynamically build from providers on first access
|
|
126
|
-
return getProviderDefaults();
|
|
127
|
-
},
|
|
128
|
-
defaultConfig: 'conductor-bootstrap',
|
|
129
|
-
defaultIsolation: 'none', // 'none' | 'worktree' | 'docker'
|
|
130
|
-
defaultDelivery: 'none', // 'none' | 'pr' | 'ship'
|
|
131
|
-
setupVersion: null, // Internal marker written only after guided setup succeeds.
|
|
132
|
-
strictSchema: true, // true = reliable json output (default), false = live streaming (may crash - see bold-meadow-11)
|
|
133
|
-
logLevel: 'normal',
|
|
134
|
-
// Automatic update notification cache
|
|
135
|
-
autoCheckUpdates: true, // Check npm registry for newer versions
|
|
136
|
-
lastUpdateCheckAt: null, // Unix timestamp of last automatic attempt (null = never checked)
|
|
137
|
-
lastSeenVersion: null, // Compatibility key containing the cached valid npm-latest version
|
|
138
|
-
lastUpdateCheckClaim: null, // Opaque ownership token for an in-flight automatic refresh
|
|
139
|
-
// Claude command - customize how to invoke Claude CLI (default: 'claude')
|
|
140
|
-
// Example: 'ccr code' for claude-code-router integration
|
|
141
|
-
claudeCommand: 'claude',
|
|
142
|
-
// Docker isolation mounts - preset names or {host, container, readonly?} objects
|
|
143
|
-
// Valid presets: infrastructure presets plus provider ids from the provider registry
|
|
144
|
-
dockerMounts: ['gh', 'git', 'ssh'],
|
|
145
|
-
// Extra env vars to pass to Docker container (in addition to preset-implied ones)
|
|
146
|
-
// Supports: VAR (if set), VAR_* (pattern), VAR=value (forced), VAR= (empty)
|
|
147
|
-
dockerEnvPassthrough: [],
|
|
148
|
-
// Container home directory - where $HOME resolves in container paths
|
|
149
|
-
// Default: /home/node (matches zeroshot-cluster-base image)
|
|
150
|
-
dockerContainerHome: '/home/node',
|
|
151
|
-
// Retry/restart robustness defaults
|
|
152
|
-
maxRetries: 3, // Agent task retries (per execution) for retryable errors
|
|
153
|
-
maxRestartAttempts: 3, // Agent restarts since last TASK_COMPLETED
|
|
154
|
-
maxTotalRestarts: 10, // Safety valve (never resets)
|
|
155
|
-
staleWarningsBeforeKill: 2, // Consecutive stale warnings before restart
|
|
156
|
-
backoffBaseMs: 2000, // Initial retry backoff
|
|
157
|
-
backoffMaxMs: 30000, // Max retry backoff
|
|
158
|
-
jitterFactor: 0.2, // Random jitter ±20%
|
|
159
|
-
// Issue provider settings - defaultIssueSource is here, others come from providers
|
|
160
|
-
defaultIssueSource: 'github', // 'github' | 'gitlab' | 'jira' | 'azure-devops'
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
// Cache for merged defaults (base + issue provider settings)
|
|
164
|
-
let _defaultSettingsCache = null;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Get DEFAULT_SETTINGS with issue provider settings merged in
|
|
168
|
-
* Lazy-loaded to avoid circular dependency at module load time
|
|
169
|
-
*/
|
|
170
|
-
function getDefaultSettings() {
|
|
171
|
-
if (!_defaultSettingsCache) {
|
|
172
|
-
const issueProviderDefaults = getIssueProviderFns().getIssueProviderSettingsDefaults();
|
|
173
|
-
_defaultSettingsCache = {
|
|
174
|
-
...DEFAULT_SETTINGS_BASE,
|
|
175
|
-
...issueProviderDefaults,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
return _defaultSettingsCache;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// For backward compatibility, export DEFAULT_SETTINGS as a getter
|
|
182
|
-
const DEFAULT_SETTINGS = new Proxy(DEFAULT_SETTINGS_BASE, {
|
|
183
|
-
get(target, prop) {
|
|
184
|
-
// For known base properties, return from base
|
|
185
|
-
if (prop in target) {
|
|
186
|
-
return target[prop];
|
|
187
|
-
}
|
|
188
|
-
// For issue provider settings, get from merged defaults
|
|
189
|
-
const merged = getDefaultSettings();
|
|
190
|
-
return merged[prop];
|
|
191
|
-
},
|
|
192
|
-
has(target, prop) {
|
|
193
|
-
if (prop in target) return true;
|
|
194
|
-
const merged = getDefaultSettings();
|
|
195
|
-
return prop in merged;
|
|
196
|
-
},
|
|
197
|
-
ownKeys() {
|
|
198
|
-
const merged = getDefaultSettings();
|
|
199
|
-
return Object.keys(merged);
|
|
200
|
-
},
|
|
201
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
202
|
-
const merged = getDefaultSettings();
|
|
203
|
-
if (prop in merged) {
|
|
204
|
-
return { enumerable: true, configurable: true, value: merged[prop] };
|
|
205
|
-
}
|
|
206
|
-
return undefined;
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
function mapLegacyModelToLevel(model) {
|
|
211
|
-
switch (model) {
|
|
212
|
-
case 'haiku':
|
|
213
|
-
return 'level1';
|
|
214
|
-
case 'sonnet':
|
|
215
|
-
return 'level2';
|
|
216
|
-
case 'opus':
|
|
217
|
-
return 'level3';
|
|
218
|
-
default:
|
|
219
|
-
return null;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function mergeProviderSettings(current, overrides) {
|
|
224
|
-
// Ensure current has all providers with their defaults
|
|
225
|
-
const providerDefaults = getProviderDefaults();
|
|
226
|
-
const merged = {};
|
|
227
|
-
|
|
228
|
-
for (const provider of VALID_PROVIDERS) {
|
|
229
|
-
merged[provider] = {
|
|
230
|
-
...(providerDefaults[provider] || {}),
|
|
231
|
-
...(current[provider] || {}),
|
|
232
|
-
...(overrides?.[provider] || {}),
|
|
233
|
-
};
|
|
234
|
-
if (!merged[provider].levelOverrides) {
|
|
235
|
-
merged[provider].levelOverrides = {};
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return merged;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function applyLegacyModelBounds(settings) {
|
|
242
|
-
if (!settings.providerSettings) return settings;
|
|
243
|
-
const claude = settings.providerSettings.claude || {};
|
|
244
|
-
const legacyMaxLevel = mapLegacyModelToLevel(settings.maxModel);
|
|
245
|
-
const legacyMinLevel = mapLegacyModelToLevel(settings.minModel);
|
|
246
|
-
|
|
247
|
-
if (legacyMaxLevel) {
|
|
248
|
-
claude.maxLevel = legacyMaxLevel;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (legacyMinLevel) {
|
|
252
|
-
claude.minLevel = legacyMinLevel;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const minRank = LEVEL_RANKS[claude.minLevel] || LEVEL_RANKS.level1;
|
|
256
|
-
const maxRank = LEVEL_RANKS[claude.maxLevel] || LEVEL_RANKS.level3;
|
|
257
|
-
const defaultRank = LEVEL_RANKS[claude.defaultLevel] || LEVEL_RANKS.level2;
|
|
258
|
-
|
|
259
|
-
if (minRank > maxRank) {
|
|
260
|
-
claude.minLevel = 'level1';
|
|
261
|
-
claude.maxLevel = 'level3';
|
|
262
|
-
} else if (defaultRank < minRank) {
|
|
263
|
-
claude.defaultLevel = claude.minLevel;
|
|
264
|
-
} else if (defaultRank > maxRank) {
|
|
265
|
-
claude.defaultLevel = claude.maxLevel;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
settings.providerSettings.claude = claude;
|
|
269
|
-
return settings;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function normalizeLoadedSettings(parsed) {
|
|
273
|
-
const normalized = { ...parsed };
|
|
274
|
-
if (!Object.hasOwn(parsed, 'defaultIsolation') && typeof parsed.defaultDocker === 'boolean') {
|
|
275
|
-
normalized.defaultIsolation = parsed.defaultDocker ? 'docker' : 'none';
|
|
276
|
-
}
|
|
277
|
-
delete normalized.defaultDocker;
|
|
278
|
-
if (parsed.defaultProvider) {
|
|
279
|
-
normalized.defaultProvider = normalizeProviderName(parsed.defaultProvider);
|
|
280
|
-
}
|
|
281
|
-
if (parsed.providerSettings) {
|
|
282
|
-
normalized.providerSettings = normalizeProviderSettings(parsed.providerSettings);
|
|
283
|
-
}
|
|
284
|
-
if (
|
|
285
|
-
normalized.autoCheckUpdates === false ||
|
|
286
|
-
typeof normalized.lastUpdateCheckClaim !== 'string' ||
|
|
287
|
-
normalized.lastUpdateCheckClaim.trim().length === 0
|
|
288
|
-
) {
|
|
289
|
-
normalized.lastUpdateCheckClaim = null;
|
|
290
|
-
}
|
|
291
|
-
return normalized;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function resolvedDefaultSettings() {
|
|
295
|
-
return {
|
|
296
|
-
...DEFAULT_SETTINGS,
|
|
297
|
-
providerSettings: mergeProviderSettings(getProviderDefaults()),
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function mergeLoadedSettings(parsed) {
|
|
302
|
-
const normalized = normalizeLoadedSettings(parsed);
|
|
303
|
-
const merged = { ...resolvedDefaultSettings(), ...normalized };
|
|
304
|
-
merged.defaultProvider =
|
|
305
|
-
normalizeProviderName(merged.defaultProvider) || DEFAULT_SETTINGS.defaultProvider;
|
|
306
|
-
merged.providerSettings = mergeProviderSettings(
|
|
307
|
-
getProviderDefaults(),
|
|
308
|
-
normalized.providerSettings
|
|
309
|
-
);
|
|
310
|
-
if (
|
|
311
|
-
merged.autoCheckUpdates === false ||
|
|
312
|
-
typeof merged.lastUpdateCheckClaim !== 'string' ||
|
|
313
|
-
merged.lastUpdateCheckClaim.trim().length === 0
|
|
314
|
-
) {
|
|
315
|
-
merged.lastUpdateCheckClaim = null;
|
|
316
|
-
}
|
|
317
|
-
return applyLegacyModelBounds(merged);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Load settings from disk, merging with defaults
|
|
322
|
-
*/
|
|
323
|
-
function loadSettings(options = {}) {
|
|
324
|
-
const settingsFile = getSettingsFile();
|
|
325
|
-
if (!fs.existsSync(settingsFile)) {
|
|
326
|
-
return resolvedDefaultSettings();
|
|
327
|
-
}
|
|
328
|
-
try {
|
|
329
|
-
return mergeLoadedSettings(JSON.parse(fs.readFileSync(settingsFile, 'utf8')));
|
|
330
|
-
} catch {
|
|
331
|
-
if (!options.silent) console.error('Warning: Could not load settings, using defaults');
|
|
332
|
-
return resolvedDefaultSettings();
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function readSettingsForMutation(settingsFile) {
|
|
337
|
-
if (!fs.existsSync(settingsFile)) {
|
|
338
|
-
return {
|
|
339
|
-
settings: resolvedDefaultSettings(),
|
|
340
|
-
requiresClaimInvalidation: false,
|
|
341
|
-
requiresRecovery: false,
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
let parsed;
|
|
345
|
-
try {
|
|
346
|
-
parsed = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
|
|
347
|
-
} catch (error) {
|
|
348
|
-
if (!(error instanceof SyntaxError)) throw error;
|
|
349
|
-
return {
|
|
350
|
-
settings: resolvedDefaultSettings(),
|
|
351
|
-
requiresClaimInvalidation: false,
|
|
352
|
-
requiresRecovery: true,
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
1
|
+
"use strict";
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
3
|
+
const storage = require('./settings-storage');
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
5
|
+
const validation = require('./settings-validation');
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
7
|
+
const models = require('./settings-models');
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
9
|
+
const defaults = require('./settings-defaults');
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
11
|
+
const providerDefaults = require('./provider-defaults');
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
13
|
+
const { SettingsValidationError } = require('./settings-error');
|
|
14
|
+
const { loadSettings, mutateSettings, getSettingsFile, settingsFileExists } = storage;
|
|
15
|
+
const { validateSetting, coerceValue } = validation;
|
|
16
|
+
const { MODEL_HIERARCHY, VALID_MODELS, validateModelAgainstMax, mapLegacyModelToLevel } = models;
|
|
17
|
+
const { DEFAULT_SETTINGS } = defaults;
|
|
18
|
+
const { clearProviderDefaultsCache } = providerDefaults;
|
|
19
|
+
function getClaudeCommand() {
|
|
20
|
+
const settings = loadSettings();
|
|
21
|
+
const raw = process.env.ZEROSHOT_CLAUDE_COMMAND || settings.claudeCommand || 'claude';
|
|
22
|
+
const parts = raw.trim().split(/\s+/);
|
|
356
23
|
return {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
requiresRecovery: true,
|
|
24
|
+
command: parts[0],
|
|
25
|
+
args: parts.slice(1),
|
|
360
26
|
};
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const updatesDisabled = parsed.autoCheckUpdates === false || parsed.updatePolicy === 'off';
|
|
364
|
-
return {
|
|
365
|
-
settings: mergeLoadedSettings(parsed),
|
|
366
|
-
requiresClaimInvalidation: updatesDisabled && parsed.lastUpdateCheckClaim !== null,
|
|
367
|
-
requiresRecovery: false,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function getAtomicSettingsMode(settingsFile) {
|
|
372
|
-
try {
|
|
373
|
-
return fs.statSync(settingsFile).mode & 0o600;
|
|
374
|
-
} catch (error) {
|
|
375
|
-
if (error.code === 'ENOENT') return 0o600;
|
|
376
|
-
throw error;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function atomicWriteSettings(settingsFile, settings) {
|
|
381
|
-
const dir = path.dirname(settingsFile);
|
|
382
|
-
const temporaryFile = path.join(
|
|
383
|
-
dir,
|
|
384
|
-
`.${path.basename(settingsFile)}.${process.pid}.${crypto.randomUUID()}.tmp`
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
let operationError;
|
|
388
|
-
try {
|
|
389
|
-
fs.writeFileSync(temporaryFile, JSON.stringify(settings, null, 2), {
|
|
390
|
-
encoding: 'utf8',
|
|
391
|
-
flag: 'wx',
|
|
392
|
-
mode: getAtomicSettingsMode(settingsFile),
|
|
393
|
-
});
|
|
394
|
-
fs.renameSync(temporaryFile, settingsFile);
|
|
395
|
-
} catch (error) {
|
|
396
|
-
operationError = error;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
try {
|
|
400
|
-
fs.unlinkSync(temporaryFile);
|
|
401
|
-
} catch (error) {
|
|
402
|
-
if (error.code !== 'ENOENT' && !operationError) operationError = error;
|
|
403
|
-
}
|
|
404
|
-
if (operationError) throw operationError;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function acquireSettingsLock(settingsFile, lockfilePath, timeoutMs) {
|
|
408
|
-
const deadline = Date.now() + timeoutMs;
|
|
409
|
-
while (true) {
|
|
410
|
-
try {
|
|
411
|
-
return lockfile.lockSync(settingsFile, {
|
|
412
|
-
lockfilePath,
|
|
413
|
-
realpath: false,
|
|
414
|
-
stale: SETTINGS_LOCK_STALE_MS,
|
|
415
|
-
});
|
|
416
|
-
} catch (error) {
|
|
417
|
-
if (error.code !== 'ELOCKED' || Date.now() >= deadline) throw error;
|
|
418
|
-
Atomics.wait(SETTINGS_LOCK_SLEEP, 0, 0, SETTINGS_LOCK_RETRY_MS);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Atomically mutate global settings under the process-shared settings lock.
|
|
425
|
-
* The mutator receives only the freshly re-read, normalized state.
|
|
426
|
-
*
|
|
427
|
-
* @param {(settings: object) => any} mutator
|
|
428
|
-
* @param {object} [options]
|
|
429
|
-
* @returns {any} the mutator's return value
|
|
430
|
-
*/
|
|
431
|
-
function mutateSettings(mutator, options = {}) {
|
|
432
|
-
if (typeof mutator !== 'function') {
|
|
433
|
-
throw new TypeError('Global settings mutation requires a callback');
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const settingsFile = getSettingsFile();
|
|
437
|
-
const dir = path.dirname(settingsFile);
|
|
438
|
-
const lockfilePath = `${settingsFile}.lock`;
|
|
439
|
-
let release;
|
|
440
|
-
let result;
|
|
441
|
-
let mutationError;
|
|
442
|
-
|
|
443
|
-
try {
|
|
444
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
445
|
-
release = acquireSettingsLock(
|
|
446
|
-
settingsFile,
|
|
447
|
-
lockfilePath,
|
|
448
|
-
options.lockTimeoutMs ?? SETTINGS_LOCK_TIMEOUT_MS
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
const { settings, requiresClaimInvalidation, requiresRecovery } =
|
|
452
|
-
readSettingsForMutation(settingsFile);
|
|
453
|
-
const before = JSON.stringify(settings);
|
|
454
|
-
result = mutator(settings);
|
|
455
|
-
if (result && typeof result.then === 'function') {
|
|
456
|
-
throw new TypeError('Global settings mutations must be synchronous');
|
|
457
|
-
}
|
|
458
|
-
if (settings.autoCheckUpdates === false || settings.updatePolicy === 'off') {
|
|
459
|
-
settings.lastUpdateCheckClaim = null;
|
|
460
|
-
}
|
|
461
|
-
if (requiresRecovery || requiresClaimInvalidation || JSON.stringify(settings) !== before) {
|
|
462
|
-
atomicWriteSettings(settingsFile, settings);
|
|
463
|
-
}
|
|
464
|
-
} catch (error) {
|
|
465
|
-
mutationError =
|
|
466
|
-
error instanceof SettingsValidationError
|
|
467
|
-
? error
|
|
468
|
-
: new Error(`Unable to persist global settings: ${error.message}`, { cause: error });
|
|
469
|
-
} finally {
|
|
470
|
-
if (release) {
|
|
471
|
-
try {
|
|
472
|
-
release();
|
|
473
|
-
} catch (error) {
|
|
474
|
-
if (!mutationError) {
|
|
475
|
-
mutationError = new Error(`Unable to release global settings lock: ${error.message}`, {
|
|
476
|
-
cause: error,
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
if (mutationError) throw mutationError;
|
|
483
|
-
return result;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Validate claudeCommand setting
|
|
488
|
-
* @returns {string|null} Error message if invalid, null if valid
|
|
489
|
-
*/
|
|
490
|
-
function validateClaudeCommand(value) {
|
|
491
|
-
if (typeof value !== 'string') {
|
|
492
|
-
return 'claudeCommand must be a string';
|
|
493
|
-
}
|
|
494
|
-
if (value.trim().length === 0) {
|
|
495
|
-
return 'claudeCommand cannot be empty';
|
|
496
|
-
}
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
* Validate providerSettings structure by delegating to provider implementations
|
|
502
|
-
* @returns {string|null} Error message if invalid, null if valid
|
|
503
|
-
*/
|
|
504
|
-
function validateProviderSettings(value) {
|
|
505
|
-
const normalizedSettings = normalizeProviderSettings(value);
|
|
506
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
507
|
-
return 'providerSettings must be an object';
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// Lazy require to avoid circular dependency
|
|
511
|
-
const { getProvider } = require('../src/providers');
|
|
512
|
-
|
|
513
|
-
for (const [providerName, settings] of Object.entries(normalizedSettings || {})) {
|
|
514
|
-
if (!VALID_PROVIDERS.includes(providerName)) {
|
|
515
|
-
return `Unknown provider in providerSettings: ${providerName}. Valid providers: ${VALID_PROVIDERS.join(', ')}`;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Delegate validation to the provider
|
|
519
|
-
try {
|
|
520
|
-
const provider = getProvider(providerName);
|
|
521
|
-
const error = provider.validateSettings(settings);
|
|
522
|
-
if (error) return error;
|
|
523
|
-
} catch (err) {
|
|
524
|
-
return `Failed to validate ${providerName} settings: ${err.message}`;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Validate a setting value
|
|
533
|
-
* @returns {string|null} Error message if invalid, null if valid
|
|
534
|
-
*/
|
|
535
|
-
function validateSetting(key, value) {
|
|
536
|
-
if (!(key in DEFAULT_SETTINGS)) {
|
|
537
|
-
return `Unknown setting: ${key}`;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
if (
|
|
541
|
-
[
|
|
542
|
-
'maxRetries',
|
|
543
|
-
'maxRestartAttempts',
|
|
544
|
-
'maxTotalRestarts',
|
|
545
|
-
'staleWarningsBeforeKill',
|
|
546
|
-
'backoffBaseMs',
|
|
547
|
-
'backoffMaxMs',
|
|
548
|
-
].includes(key)
|
|
549
|
-
) {
|
|
550
|
-
if (!Number.isFinite(value)) {
|
|
551
|
-
return `${key} must be a number`;
|
|
552
|
-
}
|
|
553
|
-
if (!Number.isInteger(value)) {
|
|
554
|
-
return `${key} must be an integer`;
|
|
555
|
-
}
|
|
556
|
-
const min = ['backoffBaseMs', 'backoffMaxMs'].includes(key) ? 0 : 1;
|
|
557
|
-
if (value < min) {
|
|
558
|
-
return `${key} must be >= ${min}`;
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
if (key === 'jitterFactor') {
|
|
563
|
-
if (!Number.isFinite(value)) {
|
|
564
|
-
return 'jitterFactor must be a number';
|
|
565
|
-
}
|
|
566
|
-
if (value < 0 || value > 1) {
|
|
567
|
-
return 'jitterFactor must be between 0 and 1';
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (key === 'maxModel' && !VALID_MODELS.includes(value)) {
|
|
572
|
-
return `Invalid model: ${value}. Valid models: ${VALID_MODELS.join(', ')}`;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
if (key === 'minModel' && value !== null && !VALID_MODELS.includes(value)) {
|
|
576
|
-
return `Invalid model: ${value}. Valid models: ${VALID_MODELS.join(', ')}, null`;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
if (key === 'logLevel' && !['quiet', 'normal', 'verbose'].includes(value)) {
|
|
580
|
-
return `Invalid log level: ${value}. Valid levels: quiet, normal, verbose`;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (key === 'defaultDelivery' && !['none', 'pr', 'ship'].includes(value)) {
|
|
584
|
-
return `Invalid defaultDelivery: ${value}. Valid: none, pr, ship`;
|
|
585
|
-
}
|
|
586
|
-
if (key === 'defaultIsolation' && !['none', 'worktree', 'docker'].includes(value)) {
|
|
587
|
-
return `Invalid defaultIsolation: ${value}. Valid: none, worktree, docker`;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (key === 'claudeCommand') {
|
|
591
|
-
return validateClaudeCommand(value);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
if (key === 'defaultProvider') {
|
|
595
|
-
const normalized = normalizeProviderName(value);
|
|
596
|
-
if (!VALID_PROVIDERS.includes(normalized)) {
|
|
597
|
-
return `Invalid provider: ${value}. Valid providers: ${VALID_PROVIDERS.join(', ')}`;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
if (key === 'providerSettings') {
|
|
602
|
-
return validateProviderSettings(value);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
if (key === 'dockerMounts') {
|
|
606
|
-
return validateMountConfig(value);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
if (key === 'dockerEnvPassthrough') {
|
|
610
|
-
return validateEnvPassthrough(value);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// Issue source settings validation (grouped for maintainability)
|
|
614
|
-
const issueSourceError = validateIssueSourceSetting(key, value);
|
|
615
|
-
if (issueSourceError !== undefined) {
|
|
616
|
-
return issueSourceError;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return null;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/**
|
|
623
|
-
* Validate issue source related settings
|
|
624
|
-
* Delegates to issue providers for provider-specific settings
|
|
625
|
-
* @param {string} key - Setting key
|
|
626
|
-
* @param {any} value - Setting value
|
|
627
|
-
* @returns {string|null|undefined} Error message, null if valid, undefined if not an issue source setting
|
|
628
|
-
*/
|
|
629
|
-
function validateIssueSourceSetting(key, value) {
|
|
630
|
-
// defaultIssueSource is handled here (not provider-specific)
|
|
631
|
-
if (key === 'defaultIssueSource') {
|
|
632
|
-
const { listProviders } = getIssueProviderFns();
|
|
633
|
-
const validSources = listProviders();
|
|
634
|
-
if (!validSources.includes(value)) {
|
|
635
|
-
return `Invalid issue source: ${value}. Valid: ${validSources.join(', ')}`;
|
|
636
|
-
}
|
|
637
|
-
return null;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// Delegate to issue providers for provider-specific settings
|
|
641
|
-
const { validateIssueProviderSetting } = getIssueProviderFns();
|
|
642
|
-
return validateIssueProviderSetting(key, value);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
/**
|
|
646
|
-
* Coerce value to correct type based on default value type
|
|
647
|
-
*/
|
|
648
|
-
function coerceValue(key, value) {
|
|
649
|
-
const defaultValue = DEFAULT_SETTINGS[key];
|
|
650
|
-
|
|
651
|
-
// Handle null values for minModel
|
|
652
|
-
if (key === 'minModel' && (value === 'null' || value === null)) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (typeof defaultValue === 'boolean') {
|
|
657
|
-
return value === 'true' || value === '1' || value === 'yes' || value === true;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
if (typeof defaultValue === 'number') {
|
|
661
|
-
const parsed = parseFloat(value);
|
|
662
|
-
if (isNaN(parsed)) {
|
|
663
|
-
throw new Error(`Invalid number: ${value}`);
|
|
664
|
-
}
|
|
665
|
-
return parsed;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
// Handle array settings (dockerMounts, dockerEnvPassthrough)
|
|
669
|
-
if (Array.isArray(defaultValue)) {
|
|
670
|
-
if (typeof value === 'string') {
|
|
671
|
-
try {
|
|
672
|
-
const parsed = JSON.parse(value);
|
|
673
|
-
if (!Array.isArray(parsed)) {
|
|
674
|
-
throw new Error(`${key} must be an array`);
|
|
675
|
-
}
|
|
676
|
-
return parsed;
|
|
677
|
-
} catch (e) {
|
|
678
|
-
if (e instanceof SyntaxError) {
|
|
679
|
-
throw new Error(`Invalid JSON for ${key}: ${value}`);
|
|
680
|
-
}
|
|
681
|
-
throw e;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
return value;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
if (key === 'providerSettings') {
|
|
688
|
-
if (typeof value === 'string') {
|
|
689
|
-
try {
|
|
690
|
-
return normalizeProviderSettings(JSON.parse(value));
|
|
691
|
-
} catch {
|
|
692
|
-
throw new Error(`Invalid JSON for providerSettings: ${value}`);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
return normalizeProviderSettings(value);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
if (key === 'defaultProvider') {
|
|
699
|
-
return normalizeProviderName(value);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
return value;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Get parsed Claude command from settings/env
|
|
707
|
-
* Supports space-separated commands like 'ccr code'
|
|
708
|
-
* @returns {{ command: string, args: string[] }}
|
|
709
|
-
*/
|
|
710
|
-
function getClaudeCommand() {
|
|
711
|
-
const settings = loadSettings();
|
|
712
|
-
const raw = process.env.ZEROSHOT_CLAUDE_COMMAND || settings.claudeCommand || 'claude';
|
|
713
|
-
const parts = raw.trim().split(/\s+/);
|
|
714
|
-
return {
|
|
715
|
-
command: parts[0],
|
|
716
|
-
args: parts.slice(1),
|
|
717
|
-
};
|
|
718
27
|
}
|
|
719
|
-
|
|
720
28
|
module.exports = {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
get SETTINGS_FILE() {
|
|
739
|
-
return getSettingsFile();
|
|
740
|
-
},
|
|
29
|
+
loadSettings,
|
|
30
|
+
mutateSettings,
|
|
31
|
+
validateSetting,
|
|
32
|
+
coerceValue,
|
|
33
|
+
SettingsValidationError,
|
|
34
|
+
DEFAULT_SETTINGS,
|
|
35
|
+
getSettingsFile,
|
|
36
|
+
settingsFileExists,
|
|
37
|
+
getClaudeCommand,
|
|
38
|
+
MODEL_HIERARCHY,
|
|
39
|
+
VALID_MODELS,
|
|
40
|
+
validateModelAgainstMax,
|
|
41
|
+
clearProviderDefaultsCache,
|
|
42
|
+
mapLegacyModelToLevel,
|
|
43
|
+
get SETTINGS_FILE() {
|
|
44
|
+
return getSettingsFile();
|
|
45
|
+
},
|
|
741
46
|
};
|