@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
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Resolution of OMP's *shared* content-addressed blob store root, mirrored from the tagged
|
|
2
|
+
// v17.2.1 source (`packages/utils/src/dirs.ts`: `getBlobsDir()` / `DirResolver`) rather than
|
|
3
|
+
// invented by Zeroshot.
|
|
4
|
+
//
|
|
5
|
+
// Why this exists: OMP externalizes large payloads (images, provider data URLs) out of the session
|
|
6
|
+
// JSONL into `<blobsDir>/<sha256-hex>` and leaves a nested `blob:sha256:<hex>` reference string
|
|
7
|
+
// inside the JSONL record (`packages/coding-agent/src/session/blob-store.ts`). The store is shared
|
|
8
|
+
// by every session on the machine and lives at `~/.omp/agent/blobs` by default — nowhere near
|
|
9
|
+
// Zeroshot's per-task session partition. A resumed partition whose referenced blobs are missing is
|
|
10
|
+
// an invalid continuation, so verification has to resolve them at this real root; and because the
|
|
11
|
+
// root is shared, Zeroshot cleanup must never delete anything under it.
|
|
12
|
+
//
|
|
13
|
+
// Resolution order, exactly as `DirResolver`'s constructor computes it:
|
|
14
|
+
// profile = normalize(OMP_PROFILE ?? PI_PROFILE) // OMP_PROFILE wins; '' selects default
|
|
15
|
+
// configRoot = ~/${PI_CONFIG_DIR || '.omp'}[/profiles/<profile>]
|
|
16
|
+
// defaultAgent = <configRoot>/agent
|
|
17
|
+
// agentDir = profile ? defaultAgent : (resolve(PI_CODING_AGENT_DIR) || defaultAgent)
|
|
18
|
+
// dataBase = (linux|darwin) && agentDir === defaultAgent && $XDG_DATA_HOME/omp[/profiles/<p>]
|
|
19
|
+
// exists ? that : agentDir // XDG flattens the agent/ prefix
|
|
20
|
+
// blobsDir = <dataBase>/blobs
|
|
21
|
+
import * as fs from 'fs';
|
|
22
|
+
import * as os from 'os';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
|
|
25
|
+
type Environment = Readonly<Record<string, string | undefined>>;
|
|
26
|
+
|
|
27
|
+
interface OmpBlobsDirOptions {
|
|
28
|
+
readonly env?: Environment;
|
|
29
|
+
readonly homedir?: string;
|
|
30
|
+
readonly platform?: NodeJS.Platform;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const APP_NAME = 'omp';
|
|
34
|
+
const CONFIG_DIR_NAME = '.omp';
|
|
35
|
+
// dirs.ts PROFILE_NAME_RE / WINDOWS_RESERVED_BASENAME_RE.
|
|
36
|
+
const PROFILE_NAME_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
|
|
37
|
+
const WINDOWS_RESERVED_BASENAME_PATTERN = /^(?:CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(?:\..*)?$/iu;
|
|
38
|
+
|
|
39
|
+
/** dirs.ts normalizeProfileName, but total: an invalid name resolves to the default profile here
|
|
40
|
+
* instead of throwing. A resume against a profile OMP itself would reject cannot succeed anyway —
|
|
41
|
+
* the verifier will simply not find the referenced blobs and fail the continuation closed. */
|
|
42
|
+
function normalizeProfileName(profile: unknown): string | undefined {
|
|
43
|
+
const normalized = typeof profile === 'string' ? profile.trim() : '';
|
|
44
|
+
if (!normalized || normalized === 'default') return undefined;
|
|
45
|
+
if (
|
|
46
|
+
normalized === '.' ||
|
|
47
|
+
normalized === '..' ||
|
|
48
|
+
normalized.endsWith('.') ||
|
|
49
|
+
!PROFILE_NAME_PATTERN.test(normalized) ||
|
|
50
|
+
WINDOWS_RESERVED_BASENAME_PATTERN.test(normalized)
|
|
51
|
+
) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return normalized;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function activeProfile(env: Environment): string | undefined {
|
|
58
|
+
return normalizeProfileName(env.OMP_PROFILE !== undefined ? env.OMP_PROFILE : env.PI_PROFILE);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function directoryExists(candidate: string): boolean {
|
|
62
|
+
try {
|
|
63
|
+
return fs.statSync(candidate).isDirectory();
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Absolute path of the shared OMP blob store for the current environment.
|
|
71
|
+
* `env`/`homedir`/`platform` are injectable for tests only; production callers pass nothing.
|
|
72
|
+
*/
|
|
73
|
+
function resolveOmpBlobsDir({
|
|
74
|
+
env = process.env,
|
|
75
|
+
homedir = os.homedir(),
|
|
76
|
+
platform = process.platform,
|
|
77
|
+
}: OmpBlobsDirOptions = {}): string {
|
|
78
|
+
const profile = activeProfile(env);
|
|
79
|
+
const configDirName = env.PI_CONFIG_DIR || CONFIG_DIR_NAME;
|
|
80
|
+
const baseConfigRoot = path.join(homedir, configDirName);
|
|
81
|
+
const configRoot = profile ? path.join(baseConfigRoot, 'profiles', profile) : baseConfigRoot;
|
|
82
|
+
|
|
83
|
+
const defaultAgentDir = path.join(configRoot, 'agent');
|
|
84
|
+
// A named profile pins the agent dir to the profile root; PI_CODING_AGENT_DIR applies only in
|
|
85
|
+
// default mode (dirs.ts: `const agentDirOverride = profile ? undefined : options.agentDirOverride`).
|
|
86
|
+
const agentDirOverride = profile ? undefined : env.PI_CODING_AGENT_DIR;
|
|
87
|
+
const agentDir = agentDirOverride ? path.resolve(agentDirOverride) : defaultAgentDir;
|
|
88
|
+
|
|
89
|
+
let dataBase = agentDir;
|
|
90
|
+
if ((platform === 'linux' || platform === 'darwin') && agentDir === defaultAgentDir) {
|
|
91
|
+
const xdgDataHome = env.XDG_DATA_HOME;
|
|
92
|
+
if (xdgDataHome) {
|
|
93
|
+
const appRoot = path.join(xdgDataHome, APP_NAME);
|
|
94
|
+
const candidate = profile ? path.join(appRoot, 'profiles', profile) : appRoot;
|
|
95
|
+
if (directoryExists(candidate)) dataBase = candidate;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return path.join(dataBase, 'blobs');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** True when `candidate` is the shared blob root or anything inside it. Cleanup uses this as a
|
|
103
|
+
* hard stop: a Zeroshot partition must never resolve into OMP's shared, cross-session CAS. */
|
|
104
|
+
function isInsideOmpBlobsDir(candidate: string, options: OmpBlobsDirOptions = {}): boolean {
|
|
105
|
+
const blobsDir = resolveOmpBlobsDir(options);
|
|
106
|
+
const resolved = path.resolve(candidate);
|
|
107
|
+
return resolved === blobsDir || resolved.startsWith(blobsDir + path.sep);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export = {
|
|
111
|
+
APP_NAME,
|
|
112
|
+
CONFIG_DIR_NAME,
|
|
113
|
+
isInsideOmpBlobsDir,
|
|
114
|
+
normalizeProfileName,
|
|
115
|
+
resolveOmpBlobsDir,
|
|
116
|
+
};
|
|
@@ -1,13 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
const crypto_1 = require("crypto");
|
|
36
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
6
39
|
const OVERLAY_PREFIX = 'zeroshot-omp-config-';
|
|
7
40
|
const OMP_CONFIG_OVERLAY_DIR_PATTERN = /^zeroshot-omp-config-[A-Za-z0-9_-]+$/u;
|
|
8
|
-
const OMP_CONFIG_OVERLAY_FILE_PATTERN =
|
|
9
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.yml$/u;
|
|
10
|
-
|
|
41
|
+
const OMP_CONFIG_OVERLAY_FILE_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.yml$/u;
|
|
11
42
|
// Verified against tagged v17.2.1 source: packages/coding-agent/src/config/settings-schema.ts
|
|
12
43
|
// (key types/defaults) and packages/coding-agent/src/main.ts (HOST_DEFAULTED_SETTING_PATHS /
|
|
13
44
|
// RPC_BACKGROUND_DEFAULTED_SETTING_PATHS). RPC mode (docs/rpc.md) only re-applies its own
|
|
@@ -61,44 +92,40 @@ bash:
|
|
|
61
92
|
enabled: false
|
|
62
93
|
thresholdMs: 60000
|
|
63
94
|
`;
|
|
64
|
-
|
|
65
95
|
// Identity of the overlay *content*, not of any one temp file. A resumed session was produced
|
|
66
96
|
// under whatever workflow-altering defaults this body pinned; if the body changes (a Zeroshot
|
|
67
97
|
// upgrade retunes task.*/memory/advisor/async behaviour), continuing an old transcript under the
|
|
68
98
|
// new rules is execution drift, so this digest is part of the OMP execution fingerprint recorded
|
|
69
|
-
// with every resumable session (src/omp-execution-fingerprint.
|
|
70
|
-
const OMP_CONFIG_OVERLAY_DIGEST = `sha256:${createHash('sha256').update(OVERLAY_BODY, 'utf8').digest('hex')}`;
|
|
71
|
-
|
|
99
|
+
// with every resumable session (src/omp-execution-fingerprint.ts).
|
|
100
|
+
const OMP_CONFIG_OVERLAY_DIGEST = `sha256:${(0, crypto_1.createHash)('sha256').update(OVERLAY_BODY, 'utf8').digest('hex')}`;
|
|
72
101
|
function createOmpConfigOverlay() {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
const directoryOptions = { mode: 0o700 };
|
|
103
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), OVERLAY_PREFIX), directoryOptions);
|
|
104
|
+
try {
|
|
105
|
+
const file = path.join(dir, `${(0, crypto_1.randomUUID)()}.yml`);
|
|
106
|
+
fs.writeFileSync(file, OVERLAY_BODY, { flag: 'wx', mode: 0o600 });
|
|
107
|
+
if (process.platform !== 'win32') {
|
|
108
|
+
fs.chmodSync(dir, 0o700);
|
|
109
|
+
fs.chmodSync(file, 0o600);
|
|
110
|
+
}
|
|
111
|
+
return { dir, file };
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
115
|
+
throw error;
|
|
80
116
|
}
|
|
81
|
-
return { dir, file };
|
|
82
|
-
} catch (error) {
|
|
83
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
84
|
-
throw error;
|
|
85
|
-
}
|
|
86
117
|
}
|
|
87
|
-
|
|
88
118
|
function isCanonicalOmpConfigOverlayDirectory(overlayDir) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
OMP_CONFIG_OVERLAY_DIR_PATTERN.test(path.basename(overlayDir))
|
|
95
|
-
);
|
|
119
|
+
if (typeof overlayDir !== 'string' || !overlayDir || path.resolve(overlayDir) !== overlayDir) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return (path.dirname(overlayDir) === path.resolve(os.tmpdir()) &&
|
|
123
|
+
OMP_CONFIG_OVERLAY_DIR_PATTERN.test(path.basename(overlayDir)));
|
|
96
124
|
}
|
|
97
|
-
|
|
98
125
|
module.exports = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
126
|
+
OMP_CONFIG_OVERLAY_DIGEST,
|
|
127
|
+
OMP_CONFIG_OVERLAY_DIR_PATTERN,
|
|
128
|
+
OMP_CONFIG_OVERLAY_FILE_PATTERN,
|
|
129
|
+
createOmpConfigOverlay,
|
|
130
|
+
isCanonicalOmpConfigOverlayDirectory,
|
|
104
131
|
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'crypto';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
|
|
6
|
+
interface OmpConfigOverlay {
|
|
7
|
+
readonly dir: string;
|
|
8
|
+
readonly file: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const OVERLAY_PREFIX = 'zeroshot-omp-config-';
|
|
12
|
+
const OMP_CONFIG_OVERLAY_DIR_PATTERN = /^zeroshot-omp-config-[A-Za-z0-9_-]+$/u;
|
|
13
|
+
const OMP_CONFIG_OVERLAY_FILE_PATTERN =
|
|
14
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.yml$/u;
|
|
15
|
+
|
|
16
|
+
// Verified against tagged v17.2.1 source: packages/coding-agent/src/config/settings-schema.ts
|
|
17
|
+
// (key types/defaults) and packages/coding-agent/src/main.ts (HOST_DEFAULTED_SETTING_PATHS /
|
|
18
|
+
// RPC_BACKGROUND_DEFAULTED_SETTING_PATHS). RPC mode (docs/rpc.md) only re-applies its own
|
|
19
|
+
// neutral defaults for task.*/memory.backend/memories.enabled/advisor.*/tier.advisor/
|
|
20
|
+
// async.*/bash.autoBackground.* when a path is completely unconfigured at every settings
|
|
21
|
+
// layer; `todo.*` is explicitly caller-controlled and never host-defaulted in RPC mode
|
|
22
|
+
// (main.ts: "embedders need project-level opt-outs for reminder/prelude prompt injection").
|
|
23
|
+
// A host's ~/.omp/agent/config.yml or project .omp/config.yml can therefore change one of
|
|
24
|
+
// these workflow-altering namespaces out from under an unattended RPC worker. This overlay
|
|
25
|
+
// pins every one of them to its schema built-in default plus marketplace.autoUpdate off, so
|
|
26
|
+
// Zeroshot's worker behavior never depends on the host machine's OMP config. It deliberately
|
|
27
|
+
// never sets context/skills/rules/extensions/mcp keys, which keep flowing from native
|
|
28
|
+
// project/user config underneath this overlay.
|
|
29
|
+
const OVERLAY_BODY = `# Zeroshot-owned OMP safety overlay — do not add model/profile settings.
|
|
30
|
+
marketplace:
|
|
31
|
+
autoUpdate: "off"
|
|
32
|
+
todo:
|
|
33
|
+
enabled: true
|
|
34
|
+
reminders: true
|
|
35
|
+
remindersMax: 3
|
|
36
|
+
eager: "default"
|
|
37
|
+
task:
|
|
38
|
+
isolation:
|
|
39
|
+
mode: "none"
|
|
40
|
+
apply: true
|
|
41
|
+
merge: "patch"
|
|
42
|
+
commits: "generic"
|
|
43
|
+
eager: "default"
|
|
44
|
+
batch: true
|
|
45
|
+
maxConcurrency: 32
|
|
46
|
+
maxRecursionDepth: 2
|
|
47
|
+
disabledAgents: []
|
|
48
|
+
agentModelOverrides: {}
|
|
49
|
+
agentPrewalk: {}
|
|
50
|
+
memory:
|
|
51
|
+
backend: "off"
|
|
52
|
+
memories:
|
|
53
|
+
enabled: false
|
|
54
|
+
advisor:
|
|
55
|
+
enabled: false
|
|
56
|
+
subagents: false
|
|
57
|
+
syncBacklog: "off"
|
|
58
|
+
immuneTurns: 3
|
|
59
|
+
tier:
|
|
60
|
+
advisor: "none"
|
|
61
|
+
async:
|
|
62
|
+
enabled: true
|
|
63
|
+
maxJobs: 100
|
|
64
|
+
bash:
|
|
65
|
+
autoBackground:
|
|
66
|
+
enabled: false
|
|
67
|
+
thresholdMs: 60000
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
// Identity of the overlay *content*, not of any one temp file. A resumed session was produced
|
|
71
|
+
// under whatever workflow-altering defaults this body pinned; if the body changes (a Zeroshot
|
|
72
|
+
// upgrade retunes task.*/memory/advisor/async behaviour), continuing an old transcript under the
|
|
73
|
+
// new rules is execution drift, so this digest is part of the OMP execution fingerprint recorded
|
|
74
|
+
// with every resumable session (src/omp-execution-fingerprint.ts).
|
|
75
|
+
const OMP_CONFIG_OVERLAY_DIGEST = `sha256:${createHash('sha256').update(OVERLAY_BODY, 'utf8').digest('hex')}`;
|
|
76
|
+
|
|
77
|
+
function createOmpConfigOverlay(): OmpConfigOverlay {
|
|
78
|
+
const directoryOptions: fs.EncodingOption & { readonly mode: number } = { mode: 0o700 };
|
|
79
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), OVERLAY_PREFIX), directoryOptions);
|
|
80
|
+
try {
|
|
81
|
+
const file = path.join(dir, `${randomUUID()}.yml`);
|
|
82
|
+
fs.writeFileSync(file, OVERLAY_BODY, { flag: 'wx', mode: 0o600 });
|
|
83
|
+
if (process.platform !== 'win32') {
|
|
84
|
+
fs.chmodSync(dir, 0o700);
|
|
85
|
+
fs.chmodSync(file, 0o600);
|
|
86
|
+
}
|
|
87
|
+
return { dir, file };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isCanonicalOmpConfigOverlayDirectory(overlayDir: unknown): boolean {
|
|
95
|
+
if (typeof overlayDir !== 'string' || !overlayDir || path.resolve(overlayDir) !== overlayDir) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return (
|
|
99
|
+
path.dirname(overlayDir) === path.resolve(os.tmpdir()) &&
|
|
100
|
+
OMP_CONFIG_OVERLAY_DIR_PATTERN.test(path.basename(overlayDir))
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export = {
|
|
105
|
+
OMP_CONFIG_OVERLAY_DIGEST,
|
|
106
|
+
OMP_CONFIG_OVERLAY_DIR_PATTERN,
|
|
107
|
+
OMP_CONFIG_OVERLAY_FILE_PATTERN,
|
|
108
|
+
createOmpConfigOverlay,
|
|
109
|
+
isCanonicalOmpConfigOverlayDirectory,
|
|
110
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
// The `executionFingerprint` recorded with every resumable OMP session (issue #866).
|
|
2
3
|
//
|
|
3
4
|
// A session transcript is only safely continuable under the same execution contract that produced
|
|
@@ -7,56 +8,50 @@
|
|
|
7
8
|
// between the recording turn and a resume attempt — a Zeroshot upgrade that retunes the overlay, a
|
|
8
9
|
// changed level mapping, an alias resolving to a different concrete model, a different thinking
|
|
9
10
|
// level — makes the fingerprints differ, and the continuation is refused before the prompt.
|
|
10
|
-
const
|
|
11
|
+
const crypto_1 = require("crypto");
|
|
12
|
+
// The generated CommonJS module resolves the maintained overlay at the matching runtime path.
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
11
14
|
const { OMP_CONFIG_OVERLAY_DIGEST } = require('./omp-config-overlay');
|
|
12
|
-
|
|
13
15
|
/** Value of `--flag <value>` in an argv array, or '' when the flag is absent. */
|
|
14
16
|
function flagValue(args, flag) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if (!Array.isArray(args))
|
|
18
|
+
return '';
|
|
19
|
+
const index = args.indexOf(flag);
|
|
20
|
+
if (index < 0 || index + 1 >= args.length)
|
|
21
|
+
return '';
|
|
22
|
+
const value = args[index + 1];
|
|
23
|
+
return typeof value === 'string' ? value : '';
|
|
20
24
|
}
|
|
21
|
-
|
|
22
25
|
/** The Zeroshot-requested half of the contract, readable from the command spec alone. */
|
|
23
26
|
function requestedExecutionSelectors(commandSpec) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const args = commandSpec?.args;
|
|
28
|
+
return {
|
|
29
|
+
modelSelector: flagValue(args, '--model'),
|
|
30
|
+
thinkingSelector: flagValue(args, '--thinking'),
|
|
31
|
+
approvalMode: flagValue(args, '--approval-mode'),
|
|
32
|
+
};
|
|
30
33
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
observedProvider: String(evidence?.selectedProvider ?? ''),
|
|
51
|
-
observedModel: String(evidence?.selectedModel ?? ''),
|
|
52
|
-
observedThinkingLevel: String(evidence?.thinkingLevel ?? ''),
|
|
53
|
-
};
|
|
54
|
-
const stable = {};
|
|
55
|
-
for (const key of Object.keys(fields).sort()) stable[key] = fields[key];
|
|
56
|
-
return `sha256:${createHash('sha256').update(JSON.stringify(stable), 'utf8').digest('hex')}`;
|
|
34
|
+
/** Compute the deterministic digest for the requested and observed OMP execution contract. */
|
|
35
|
+
function computeOmpExecutionFingerprint({ expectedVersion, commandSpec, evidence, configOverlayDigest = OMP_CONFIG_OVERLAY_DIGEST, }) {
|
|
36
|
+
const fields = {
|
|
37
|
+
ompSupportedVersion: String(expectedVersion ?? ''),
|
|
38
|
+
configOverlayDigest: String(configOverlayDigest ?? ''),
|
|
39
|
+
...requestedExecutionSelectors(commandSpec),
|
|
40
|
+
observedProvider: String(evidence?.selectedProvider ?? ''),
|
|
41
|
+
observedModel: String(evidence?.selectedModel ?? ''),
|
|
42
|
+
observedThinkingLevel: String(evidence?.thinkingLevel ?? ''),
|
|
43
|
+
};
|
|
44
|
+
const stable = {};
|
|
45
|
+
// Fingerprints preserve ECMAScript's locale-independent UTF-16 code-unit ordering.
|
|
46
|
+
// eslint-disable-next-line sonarjs/no-alphabetical-sort
|
|
47
|
+
for (const key of Object.keys(fields).sort()) {
|
|
48
|
+
const value = fields[key];
|
|
49
|
+
if (value !== undefined)
|
|
50
|
+
stable[key] = value;
|
|
51
|
+
}
|
|
52
|
+
return `sha256:${(0, crypto_1.createHash)('sha256').update(JSON.stringify(stable), 'utf8').digest('hex')}`;
|
|
57
53
|
}
|
|
58
|
-
|
|
59
54
|
module.exports = {
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
computeOmpExecutionFingerprint,
|
|
56
|
+
requestedExecutionSelectors,
|
|
62
57
|
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// The `executionFingerprint` recorded with every resumable OMP session (issue #866).
|
|
2
|
+
//
|
|
3
|
+
// A session transcript is only safely continuable under the same execution contract that produced
|
|
4
|
+
// it. This digest binds that contract: the pinned OMP release, the Zeroshot config overlay's
|
|
5
|
+
// content, the requested Zeroshot selectors (`--model`, `--thinking`, `--approval-mode`), and the
|
|
6
|
+
// concrete provider/model/thinking level OMP actually reported for the turn. Any of those drifting
|
|
7
|
+
// between the recording turn and a resume attempt — a Zeroshot upgrade that retunes the overlay, a
|
|
8
|
+
// changed level mapping, an alias resolving to a different concrete model, a different thinking
|
|
9
|
+
// level — makes the fingerprints differ, and the continuation is refused before the prompt.
|
|
10
|
+
import { createHash } from 'crypto';
|
|
11
|
+
|
|
12
|
+
interface ConfigOverlayFacade {
|
|
13
|
+
readonly OMP_CONFIG_OVERLAY_DIGEST: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface CommandSpec {
|
|
17
|
+
readonly args?: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface OmpSessionEvidence {
|
|
21
|
+
readonly selectedProvider?: unknown;
|
|
22
|
+
readonly selectedModel?: unknown;
|
|
23
|
+
readonly thinkingLevel?: unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface FingerprintParams {
|
|
27
|
+
readonly expectedVersion: unknown;
|
|
28
|
+
readonly commandSpec: CommandSpec | null | undefined;
|
|
29
|
+
readonly evidence: OmpSessionEvidence | null | undefined;
|
|
30
|
+
readonly configOverlayDigest?: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface RequestedExecutionSelectors {
|
|
34
|
+
readonly modelSelector: string;
|
|
35
|
+
readonly thinkingSelector: string;
|
|
36
|
+
readonly approvalMode: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The generated CommonJS module resolves the maintained overlay at the matching runtime path.
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
41
|
+
const { OMP_CONFIG_OVERLAY_DIGEST }: ConfigOverlayFacade = require('./omp-config-overlay');
|
|
42
|
+
|
|
43
|
+
/** Value of `--flag <value>` in an argv array, or '' when the flag is absent. */
|
|
44
|
+
function flagValue(args: unknown, flag: string): string {
|
|
45
|
+
if (!Array.isArray(args)) return '';
|
|
46
|
+
const index = args.indexOf(flag);
|
|
47
|
+
if (index < 0 || index + 1 >= args.length) return '';
|
|
48
|
+
const value: unknown = args[index + 1];
|
|
49
|
+
return typeof value === 'string' ? value : '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The Zeroshot-requested half of the contract, readable from the command spec alone. */
|
|
53
|
+
function requestedExecutionSelectors(
|
|
54
|
+
commandSpec: CommandSpec | null | undefined
|
|
55
|
+
): RequestedExecutionSelectors {
|
|
56
|
+
const args = commandSpec?.args;
|
|
57
|
+
return {
|
|
58
|
+
modelSelector: flagValue(args, '--model'),
|
|
59
|
+
thinkingSelector: flagValue(args, '--thinking'),
|
|
60
|
+
approvalMode: flagValue(args, '--approval-mode'),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Compute the deterministic digest for the requested and observed OMP execution contract. */
|
|
65
|
+
function computeOmpExecutionFingerprint({
|
|
66
|
+
expectedVersion,
|
|
67
|
+
commandSpec,
|
|
68
|
+
evidence,
|
|
69
|
+
configOverlayDigest = OMP_CONFIG_OVERLAY_DIGEST,
|
|
70
|
+
}: FingerprintParams): string {
|
|
71
|
+
const fields: Record<string, string> = {
|
|
72
|
+
ompSupportedVersion: String(expectedVersion ?? ''),
|
|
73
|
+
configOverlayDigest: String(configOverlayDigest ?? ''),
|
|
74
|
+
...requestedExecutionSelectors(commandSpec),
|
|
75
|
+
observedProvider: String(evidence?.selectedProvider ?? ''),
|
|
76
|
+
observedModel: String(evidence?.selectedModel ?? ''),
|
|
77
|
+
observedThinkingLevel: String(evidence?.thinkingLevel ?? ''),
|
|
78
|
+
};
|
|
79
|
+
const stable: Record<string, string> = {};
|
|
80
|
+
// Fingerprints preserve ECMAScript's locale-independent UTF-16 code-unit ordering.
|
|
81
|
+
// eslint-disable-next-line sonarjs/no-alphabetical-sort
|
|
82
|
+
for (const key of Object.keys(fields).sort()) {
|
|
83
|
+
const value = fields[key];
|
|
84
|
+
if (value !== undefined) stable[key] = value;
|
|
85
|
+
}
|
|
86
|
+
return `sha256:${createHash('sha256').update(JSON.stringify(stable), 'utf8').digest('hex')}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export = {
|
|
90
|
+
computeOmpExecutionFingerprint,
|
|
91
|
+
requestedExecutionSelectors,
|
|
92
|
+
};
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
// Every value is pinned exactly as specified by issue #866; do not derive these from settings or
|
|
3
|
-
// environment — a configurable ceiling here would let a compromised/misbehaving OMP process (or a
|
|
4
|
-
// hostile resumed partition) negotiate its own verification budget.
|
|
1
|
+
"use strict";
|
|
5
2
|
const OMP_SESSION_LIMITS = Object.freeze({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
maxSessionBytes: 268435456,
|
|
4
|
+
maxSessionRecords: 1000000,
|
|
5
|
+
maxArtifactEntries: 4096,
|
|
6
|
+
maxArtifactDepth: 16,
|
|
7
|
+
maxRelativePathBytes: 4096,
|
|
8
|
+
maxArtifactFileBytes: 268435456,
|
|
9
|
+
maxArtifactAggregateBytes: 536870912,
|
|
10
|
+
maxBlobReferences: 4096,
|
|
11
|
+
maxReferencedBlobBytes: 67108864,
|
|
15
12
|
});
|
|
16
|
-
|
|
17
13
|
/**
|
|
18
14
|
* The largest single JSONL record the verifier will buffer, DERIVED from the constants above
|
|
19
15
|
* rather than chosen — it is `maxReferencedBlobBytes`, and it is not a new knob (there is nothing
|
|
@@ -37,5 +33,4 @@ const OMP_SESSION_LIMITS = Object.freeze({
|
|
|
37
33
|
* verifier accumulates session, artifact, or blob bytes.
|
|
38
34
|
*/
|
|
39
35
|
const MAX_SESSION_RECORD_BYTES = OMP_SESSION_LIMITS.maxReferencedBlobBytes;
|
|
40
|
-
|
|
41
36
|
module.exports = { OMP_SESSION_LIMITS, MAX_SESSION_RECORD_BYTES };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Non-configurable bounds for OMP session partition verification (src/omp-session-verifier.js).
|
|
2
|
+
// Every value is pinned exactly as specified by issue #866; do not derive these from settings or
|
|
3
|
+
// environment — a configurable ceiling here would let a compromised/misbehaving OMP process (or a
|
|
4
|
+
// hostile resumed partition) negotiate its own verification budget.
|
|
5
|
+
interface OmpSessionLimits {
|
|
6
|
+
readonly maxSessionBytes: number;
|
|
7
|
+
readonly maxSessionRecords: number;
|
|
8
|
+
readonly maxArtifactEntries: number;
|
|
9
|
+
readonly maxArtifactDepth: number;
|
|
10
|
+
readonly maxRelativePathBytes: number;
|
|
11
|
+
readonly maxArtifactFileBytes: number;
|
|
12
|
+
readonly maxArtifactAggregateBytes: number;
|
|
13
|
+
readonly maxBlobReferences: number;
|
|
14
|
+
readonly maxReferencedBlobBytes: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const OMP_SESSION_LIMITS: Readonly<OmpSessionLimits> = Object.freeze({
|
|
18
|
+
maxSessionBytes: 268435456,
|
|
19
|
+
maxSessionRecords: 1000000,
|
|
20
|
+
maxArtifactEntries: 4096,
|
|
21
|
+
maxArtifactDepth: 16,
|
|
22
|
+
maxRelativePathBytes: 4096,
|
|
23
|
+
maxArtifactFileBytes: 268435456,
|
|
24
|
+
maxArtifactAggregateBytes: 536870912,
|
|
25
|
+
maxBlobReferences: 4096,
|
|
26
|
+
maxReferencedBlobBytes: 67108864,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The largest single JSONL record the verifier will buffer, DERIVED from the constants above
|
|
31
|
+
* rather than chosen — it is `maxReferencedBlobBytes`, and it is not a new knob (there is nothing
|
|
32
|
+
* to configure and no caller may override it).
|
|
33
|
+
*
|
|
34
|
+
* Why a per-record bound is needed at all: `maxSessionBytes` bounds the *file*, not a line within
|
|
35
|
+
* it. A hostile 256 MiB session with no newline in it is one record, and buffering it would cost
|
|
36
|
+
* the raw bytes, a concatenated copy, a UTF-16 string for JSON.parse, and the parsed value — a
|
|
37
|
+
* multi-hundred-megabyte spike driven entirely by the attacker's choice of where to put newlines.
|
|
38
|
+
*
|
|
39
|
+
* Why this value: `maxReferencedBlobBytes` is the issue's own answer to "how large may one
|
|
40
|
+
* addressable unit of session content be". OMP externalizes anything bigger than a message to the
|
|
41
|
+
* shared CAS store (blob-store.ts) and leaves only a 76-byte `blob:sha256:<hex>` reference in the
|
|
42
|
+
* record, so a legitimate record is orders of magnitude smaller than this; the bound exists to cap
|
|
43
|
+
* the pathological case, not to constrain real transcripts.
|
|
44
|
+
*
|
|
45
|
+
* Remaining allocation, exactly: verification buffers at most MAX_SESSION_RECORD_BYTES of raw
|
|
46
|
+
* record bytes, and `JSON.parse` necessarily materializes that record as one UTF-16 string plus its
|
|
47
|
+
* parsed value. Peak per-record cost is therefore O(MAX_SESSION_RECORD_BYTES) and independent of
|
|
48
|
+
* `maxSessionBytes`, the record count, and the file's newline placement. Nothing else in the
|
|
49
|
+
* verifier accumulates session, artifact, or blob bytes.
|
|
50
|
+
*/
|
|
51
|
+
const MAX_SESSION_RECORD_BYTES = OMP_SESSION_LIMITS.maxReferencedBlobBytes;
|
|
52
|
+
|
|
53
|
+
export = { OMP_SESSION_LIMITS, MAX_SESSION_RECORD_BYTES };
|
|
@@ -5,9 +5,9 @@ const { isInsideOmpBlobsDir } = require('./omp-blob-root');
|
|
|
5
5
|
|
|
6
6
|
// Every OMP session partition lives under <storageRoot>/omp-sessions/<uuid>/. storageRoot is the
|
|
7
7
|
// owning cluster's storageDir for cluster-agent tasks or the standalone TASKS_DIR otherwise (see
|
|
8
|
-
// task-lib/omp-storage-root.
|
|
8
|
+
// task-lib/omp-storage-root.ts) — never derived from prompt text or cwd. The shared OMP CAS blob
|
|
9
9
|
// store is *not* under here at all (it is machine-wide, at pi-utils::getBlobsDir(); see
|
|
10
|
-
// src/omp-blob-root.
|
|
10
|
+
// src/omp-blob-root.ts), which is what makes per-task partition deletion safe.
|
|
11
11
|
const OMP_SESSIONS_SUBDIR = 'omp-sessions';
|
|
12
12
|
const PARTITION_ID_PATTERN =
|
|
13
13
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// CAS blobs are NOT part of the partition. OMP externalizes large payloads to a *shared*,
|
|
11
11
|
// machine-wide content-addressed store (`blob-store.ts`, rooted at `pi-utils::getBlobsDir()` —
|
|
12
12
|
// `~/.omp/agent/blobs` modulo OMP's config-root/profile/XDG semantics, mirrored in
|
|
13
|
-
// src/omp-blob-root.
|
|
13
|
+
// src/omp-blob-root.ts) and leaves a *nested* `blob:sha256:<64-lower-hex>` reference string inside
|
|
14
14
|
// the session JSONL records. So verification parses the JSONL, collects canonical nested refs, and
|
|
15
15
|
// checks the referenced blobs at that real shared root. Nothing here ever writes to or deletes
|
|
16
16
|
// from it (see src/omp-session-partition.js, which refuses any path resolving inside it).
|