@sema-agent/core 5.19.0 → 5.21.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/CHANGELOG.md +102 -4
- package/dist/agents/agent-definition.d.ts +7 -0
- package/dist/agents/agent-transcript-tool.d.ts +30 -0
- package/dist/agents/builtin-agents.d.ts +60 -0
- package/dist/agents/cascade.d.ts +107 -0
- package/dist/agents/cumulative-stats.d.ts +56 -0
- package/dist/agents/observer.d.ts +162 -0
- package/dist/agents/peer-admission.d.ts +95 -0
- package/dist/agents/repair-loop.d.ts +226 -0
- package/dist/agents/retain-ledger.d.ts +141 -0
- package/dist/agents/roster-store.d.ts +105 -0
- package/dist/agents/roster-store.js +3 -0
- package/dist/agents/send-message-tool.d.ts +92 -0
- package/dist/agents/session-util.d.ts +5 -0
- package/dist/agents/subagent-steps.d.ts +66 -0
- package/dist/agents/subagent.d.ts +600 -0
- package/dist/agents/suspend-guard.d.ts +29 -0
- package/dist/agents/teacher.d.ts +75 -0
- package/dist/agents/team.d.ts +120 -1
- package/dist/agents/tool-filter.d.ts +34 -0
- package/dist/agents/verify.d.ts +198 -0
- package/dist/bench/metrics.d.ts +455 -0
- package/dist/brain/anthropic.d.ts +30 -0
- package/dist/brain/circuit-breaker.d.ts +33 -0
- package/dist/brain/circuit-breaker.js +14 -3
- package/dist/brain/context-overflow.d.ts +60 -3
- package/dist/brain/degrading.d.ts +67 -0
- package/dist/brain/errors.d.ts +42 -0
- package/dist/brain/failover.d.ts +15 -0
- package/dist/brain/media-degrade.d.ts +39 -0
- package/dist/brain/model-presets.d.ts +31 -0
- package/dist/brain/open-responses.d.ts +19 -0
- package/dist/brain/openai.d.ts +46 -0
- package/dist/brain/reasoning.d.ts +106 -1
- package/dist/brain/repetition.d.ts +83 -0
- package/dist/brain/request-params.d.ts +56 -0
- package/dist/brain/retry.d.ts +46 -0
- package/dist/brain/routing.d.ts +12 -0
- package/dist/brain/status-sink.d.ts +30 -1
- package/dist/brain/stream-engine.d.ts +147 -0
- package/dist/brain/stream-shared.d.ts +34 -0
- package/dist/brain/terminal-cause.d.ts +31 -0
- package/dist/brain/timeout.d.ts +108 -0
- package/dist/brain/timeout.js +11 -0
- package/dist/brain/tool-call-id.d.ts +20 -0
- package/dist/brain/tool-call-repair.d.ts +13 -0
- package/dist/config/catalog.d.ts +47 -0
- package/dist/config/defaults.d.ts +33 -0
- package/dist/core/a2a-task-state.d.ts +53 -0
- package/dist/core/a2a.d.ts +51 -0
- package/dist/core/arg-summary.d.ts +62 -0
- package/dist/core/ask-question.d.ts +272 -2
- package/dist/core/auto-compaction.d.ts +467 -0
- package/dist/core/auto-compaction.js +20 -6
- package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
- package/dist/core/auto-mode-prompt.d.ts +27 -0
- package/dist/core/auto-mode.d.ts +54 -3
- package/dist/core/auto-promote.d.ts +100 -0
- package/dist/core/background-agent-store.d.ts +293 -0
- package/dist/core/background-agent-store.js +5 -0
- package/dist/core/background-shell.d.ts +110 -0
- package/dist/core/cache-break-detector.d.ts +34 -0
- package/dist/core/canonical-json.d.ts +57 -0
- package/dist/core/checkpoint-store.d.ts +1574 -16
- package/dist/core/compliance.d.ts +30 -0
- package/dist/core/consolidate-scope.d.ts +75 -0
- package/dist/core/context-edit.d.ts +99 -0
- package/dist/core/context-guard.d.ts +46 -0
- package/dist/core/exec-gate.d.ts +44 -0
- package/dist/core/exec-output-tail.d.ts +61 -0
- package/dist/core/file-snapshot-store.d.ts +104 -0
- package/dist/core/fs-write-gate-policy.d.ts +36 -0
- package/dist/core/git-worktree-env.d.ts +31 -0
- package/dist/core/governance-codes.d.ts +19 -0
- package/dist/core/hooks.d.ts +609 -1
- package/dist/core/human-input-projection.d.ts +37 -0
- package/dist/core/human-input-projection.js +13 -0
- package/dist/core/image-downsample.d.ts +74 -0
- package/dist/core/locked-config.d.ts +37 -0
- package/dist/core/lsp-diagnostics.d.ts +77 -0
- package/dist/core/lsp-protocol.d.ts +29 -0
- package/dist/core/lsp-session.d.ts +60 -1
- package/dist/core/lsp.d.ts +150 -1
- package/dist/core/mailbox-store.d.ts +57 -0
- package/dist/core/mailbox-store.js +2 -0
- package/dist/core/mcp.d.ts +385 -0
- package/dist/core/mcp.js +58 -11
- package/dist/core/media-byte-cap.d.ts +21 -0
- package/dist/core/memory-admission.d.ts +71 -0
- package/dist/core/memory-engine/content-origin.d.ts +64 -0
- package/dist/core/memory-engine/data-plane.d.ts +43 -0
- package/dist/core/memory-engine/dual-root.d.ts +24 -0
- package/dist/core/memory-engine/engine.d.ts +230 -0
- package/dist/core/memory-engine/engine.js +103 -35
- package/dist/core/memory-engine/file-backend.d.ts +155 -0
- package/dist/core/memory-engine/frontmatter.d.ts +16 -0
- package/dist/core/memory-engine/layout.d.ts +217 -0
- package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
- package/dist/core/memory-engine/migrate.d.ts +9 -0
- package/dist/core/memory-engine/scan.d.ts +12 -0
- package/dist/core/memory-engine/scope-contract.d.ts +61 -1
- package/dist/core/memory-engine/sync-client.d.ts +87 -0
- package/dist/core/memory-engine/sync.d.ts +60 -0
- package/dist/core/memory-engine/tools.d.ts +41 -0
- package/dist/core/memory-engine/types.d.ts +188 -0
- package/dist/core/memory-recall.d.ts +141 -0
- package/dist/core/memory-vector.d.ts +20 -0
- package/dist/core/memory.d.ts +458 -0
- package/dist/core/message-utils.d.ts +6 -0
- package/dist/core/oracle-isolation.d.ts +69 -0
- package/dist/core/permission-rule-consent.d.ts +138 -0
- package/dist/core/permission-rule-model.d.ts +122 -0
- package/dist/core/permission-rule-store.d.ts +119 -3
- package/dist/core/permission-rules.d.ts +87 -1
- package/dist/core/present-plan-tool.d.ts +20 -0
- package/dist/core/pricing.d.ts +26 -0
- package/dist/core/property-harness.d.ts +86 -0
- package/dist/core/protocol-naming.d.ts +38 -0
- package/dist/core/protocol-table.d.ts +61 -0
- package/dist/core/push-queue.d.ts +1 -0
- package/dist/core/remote-env.d.ts +383 -1
- package/dist/core/retention-policy.d.ts +40 -0
- package/dist/core/retention-policy.js +21 -0
- package/dist/core/retention.d.ts +51 -0
- package/dist/core/roles.d.ts +59 -0
- package/dist/core/runner/active-skill-scope.d.ts +34 -0
- package/dist/core/runner/assemble-result.d.ts +134 -0
- package/dist/core/runner/compaction-call-options.d.ts +97 -1
- package/dist/core/runner/grounding-signal.d.ts +10 -0
- package/dist/core/runner/image.d.ts +17 -0
- package/dist/core/runner/image.js +29 -15
- package/dist/core/runner/memory-consolidation.d.ts +60 -0
- package/dist/core/runner/prepare-memory.d.ts +59 -0
- package/dist/core/runner/prepare-task.d.ts +1011 -2
- package/dist/core/runner/prepare-task.js +51 -14
- package/dist/core/runner/prompt-suggestions.d.ts +7 -0
- package/dist/core/runner/runtask.d.ts +304 -3
- package/dist/core/runner/runtask.js +17 -2
- package/dist/core/runner/session-file-state-replay.d.ts +49 -0
- package/dist/core/runner/session-rule-policy.d.ts +58 -0
- package/dist/core/runner/strict-output-schema.d.ts +18 -3
- package/dist/core/runner/synthetic-tools.d.ts +113 -0
- package/dist/core/runner/teardown-bounded.d.ts +34 -0
- package/dist/core/runner/tool-disclosure.d.ts +227 -0
- package/dist/core/runner/tool-output-projection.d.ts +6 -0
- package/dist/core/runner/turn-attachments.d.ts +634 -0
- package/dist/core/runner/usage-accounting.d.ts +32 -0
- package/dist/core/runtime.d.ts +9 -0
- package/dist/core/safe-notify.d.ts +64 -0
- package/dist/core/safety-axis-vocab.d.ts +23 -0
- package/dist/core/safety-merge-corpus.d.ts +37 -0
- package/dist/core/scheduler.d.ts +121 -0
- package/dist/core/secret-env.d.ts +32 -0
- package/dist/core/select-model.d.ts +15 -0
- package/dist/core/sensitive-path-policy.d.ts +42 -0
- package/dist/core/session-policy-store.d.ts +94 -0
- package/dist/core/session-reconcile.d.ts +80 -0
- package/dist/core/session-store.d.ts +85 -0
- package/dist/core/session.d.ts +153 -0
- package/dist/core/shared-memory/contract.d.ts +22 -0
- package/dist/core/shared-memory/normalize.d.ts +123 -2
- package/dist/core/shared-memory/tools.d.ts +14 -0
- package/dist/core/shared-memory/types.d.ts +105 -0
- package/dist/core/shutdown-debug.d.ts +6 -0
- package/dist/core/side-query.d.ts +38 -0
- package/dist/core/side-query.js +6 -1
- package/dist/core/skill-tool-specifier.d.ts +72 -0
- package/dist/core/skills-directory.d.ts +100 -1
- package/dist/core/spec-contract.d.ts +89 -0
- package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
- package/dist/core/store-contracts/contract-harness.d.ts +20 -0
- package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
- package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
- package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
- package/dist/core/strategy-store.d.ts +37 -0
- package/dist/core/stub-env.d.ts +7 -0
- package/dist/core/surrogate-safe-slice.d.ts +35 -0
- package/dist/core/task-notification.d.ts +202 -0
- package/dist/core/task-outcome.d.ts +53 -0
- package/dist/core/task-registry-agent.d.ts +337 -1
- package/dist/core/task-registry-agent.js +2 -0
- package/dist/core/task-registry-monitor.d.ts +12 -0
- package/dist/core/task-registry-shared.d.ts +540 -0
- package/dist/core/task-registry.d.ts +343 -0
- package/dist/core/task-registry.js +13 -2
- package/dist/core/task-tool-shape.d.ts +44 -0
- package/dist/core/tighten-task-spec.d.ts +21 -0
- package/dist/core/tool-detach.d.ts +21 -0
- package/dist/core/tool-errors.d.ts +131 -0
- package/dist/core/tool-errors.js +4 -0
- package/dist/core/tool-name-aliases.d.ts +27 -0
- package/dist/core/tool-policy.d.ts +555 -0
- package/dist/core/tool-policy.js +3 -0
- package/dist/core/tool-result-budget.d.ts +32 -0
- package/dist/core/tool-result-store.d.ts +174 -1
- package/dist/core/tools.d.ts +45 -0
- package/dist/core/trace.d.ts +323 -0
- package/dist/core/types.d.ts +3859 -2
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-text.d.ts +156 -0
- package/dist/core/usage-window-store.d.ts +95 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/warm-resume.d.ts +17 -0
- package/dist/core/wiring-manifest.d.ts +169 -0
- package/dist/core/with-retry.d.ts +24 -0
- package/dist/core/workflow-journal-store.d.ts +160 -0
- package/dist/core/workflow-run-store-contract.d.ts +25 -0
- package/dist/core/workflow-run-store.d.ts +119 -0
- package/dist/core/workflow-run-store.js +2 -0
- package/dist/engine/compaction/compaction.d.ts +256 -1
- package/dist/engine/compaction/utils.d.ts +94 -0
- package/dist/engine/execution-env/kill-tree.d.ts +29 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
- package/dist/engine/harness/agent-harness.d.ts +116 -0
- package/dist/engine/harness/agent-harness.js +3 -14
- package/dist/engine/harness/messages.d.ts +15 -0
- package/dist/engine/harness/types.d.ts +464 -2
- package/dist/engine/llm/diagnostics.d.ts +4 -0
- package/dist/engine/llm/event-stream.d.ts +3 -0
- package/dist/engine/llm/index.d.ts +7 -0
- package/dist/engine/llm/types.d.ts +500 -3
- package/dist/engine/llm/validation.d.ts +3 -0
- package/dist/engine/loop/agent-loop.d.ts +87 -2
- package/dist/engine/loop/runtime-deps.d.ts +7 -0
- package/dist/engine/loop/types.d.ts +424 -0
- package/dist/engine/lsp/frame-decoder.d.ts +13 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
- package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
- package/dist/engine/session/import-validate.d.ts +27 -0
- package/dist/engine/session/log-digest.d.ts +93 -0
- package/dist/engine/session/memory-repo.d.ts +6 -0
- package/dist/engine/session/memory-storage.d.ts +2 -0
- package/dist/engine/session/session.d.ts +75 -0
- package/dist/engine/session/storage-base.d.ts +8 -0
- package/dist/fixtures/index.d.ts +36 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1 -2
- package/dist/internal/harness-types.d.ts +6 -0
- package/dist/internal/harness.d.ts +11 -0
- package/dist/internal/llm.d.ts +6 -0
- package/dist/orchestration/builtin-workflows.d.ts +53 -0
- package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
- package/dist/orchestration/goal.d.ts +57 -0
- package/dist/orchestration/goal.js +3 -0
- package/dist/orchestration/run-spec.d.ts +42 -0
- package/dist/orchestration/run-spec.js +4 -0
- package/dist/orchestration/run-workflow-tool.d.ts +169 -0
- package/dist/orchestration/workflow-governance.d.ts +61 -0
- package/dist/orchestration/workflow-meta.d.ts +28 -0
- package/dist/orchestration/workflow-observe.d.ts +60 -0
- package/dist/orchestration/workflow-primitives.d.ts +23 -1
- package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
- package/dist/orchestration/workflow-script-runner.d.ts +88 -0
- package/dist/orchestration/workflow-script-store.d.ts +98 -0
- package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
- package/dist/orchestration/workflow-types.d.ts +169 -2
- package/dist/orchestration/workflow.d.ts +358 -0
- package/dist/orchestration/workflow.js +13 -2
- package/dist/prompt-assembly/artifact-store.d.ts +33 -0
- package/dist/prompt-assembly/artifact.d.ts +25 -0
- package/dist/prompt-assembly/assemble.d.ts +20 -0
- package/dist/prompt-assembly/composer.d.ts +29 -0
- package/dist/prompt-assembly/epoch.d.ts +55 -1
- package/dist/prompt-assembly/event-registry.d.ts +35 -0
- package/dist/prompt-assembly/explain.d.ts +12 -0
- package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
- package/dist/prompt-assembly/types.d.ts +115 -0
- package/dist/prompts/coordinator.d.ts +27 -0
- package/dist/prompts/default.d.ts +539 -0
- package/dist/prompts/simple-sections.d.ts +45 -0
- package/dist/prompts/supervisor.d.ts +66 -0
- package/dist/scenarios/env.d.ts +28 -0
- package/dist/scenarios/full-body.d.ts +50 -0
- package/dist/scenarios/scenario-registry.d.ts +60 -0
- package/dist/scenarios/teacher-quickstart.d.ts +27 -0
- package/dist/server/http.d.ts +17 -0
- package/dist/stores/cc/lockfile.d.ts +6 -0
- package/dist/stores/cc/mailbox-store.d.ts +8 -0
- package/dist/stores/cc/roster-adapter.d.ts +4 -0
- package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
- package/dist/stores/file/background-agent-store.d.ts +24 -0
- package/dist/stores/file/background-agent-store.js +2 -1
- package/dist/stores/file/checkpoint-store.d.ts +38 -0
- package/dist/stores/file/file-snapshot-store.d.ts +25 -0
- package/dist/stores/file/fs-atomic.d.ts +155 -0
- package/dist/stores/file/index.d.ts +89 -0
- package/dist/stores/file/mailbox-store.d.ts +36 -0
- package/dist/stores/file/mailbox-store.js +2 -0
- package/dist/stores/file/memory-store.d.ts +82 -0
- package/dist/stores/file/permission-rule-store.d.ts +79 -0
- package/dist/stores/file/session-policy-store.d.ts +28 -0
- package/dist/stores/file/session-store.d.ts +40 -0
- package/dist/stores/file/shared-ledger.d.ts +83 -0
- package/dist/stores/file/tool-result-store.d.ts +11 -0
- package/dist/stores/file/usage-window-store.d.ts +18 -0
- package/dist/stores/file/workflow-journal-store.d.ts +100 -0
- package/dist/stores/file/workflow-run-store.d.ts +11 -0
- package/dist/stores/file/workflow-run-store.js +2 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
- package/dist/tools/fs/encoding.d.ts +60 -0
- package/dist/tools/fs/fs-bash.d.ts +133 -0
- package/dist/tools/fs/fs-pdf.d.ts +28 -0
- package/dist/tools/fs/fs-search-tools.d.ts +5 -0
- package/dist/tools/fs/fs-shared.d.ts +360 -0
- package/dist/tools/fs/fs-write.d.ts +16 -0
- package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
- package/dist/tools/fs/index.d.ts +79 -0
- package/dist/tools/fs/notebook.d.ts +56 -0
- package/dist/tools/fs/pdf.d.ts +70 -0
- package/dist/tools/fs/pdf.js +8 -2
- package/dist/tools/fs/repo-map.d.ts +10 -0
- package/dist/tools/fs/safety.d.ts +376 -0
- package/dist/tools/fs/search.d.ts +131 -0
- package/dist/tools/loop-tick.d.ts +24 -0
- package/dist/tools/monitor.d.ts +55 -0
- package/dist/tools/scheduler-tools.d.ts +51 -0
- package/dist/tools/sql-adapters.d.ts +18 -0
- package/dist/tools/sql.d.ts +25 -0
- package/dist/tools/task-list.d.ts +77 -0
- package/dist/tools/todo.d.ts +8 -0
- package/dist/tools/web.d.ts +184 -0
- package/dist/tools/web.js +32 -5
- package/dist/tools/worktree.d.ts +81 -0
- package/package.json +2 -2
- package/dist/tools/gitea-issue.d.ts +0 -13
- package/dist/tools/gitea-issue.js +0 -75
|
@@ -1,11 +1,41 @@
|
|
|
1
|
+
/** Closed compliance profile set (CC 2.1.221 policy-limits profiles). */
|
|
1
2
|
export type ComplianceProfile = "hipaa" | "zdr";
|
|
3
|
+
/** Closed capability set the ENGINE can veto end-to-end (see the module header for the entry-point
|
|
4
|
+
* map — a capability is admitted here only with its full interception story). */
|
|
2
5
|
export type ComplianceCapability = "mcp_servers" | "workflows" | "web_fetch" | "org_memory_mount";
|
|
6
|
+
/** Every member of {@link ComplianceCapability} — the fail-closed "deny everything managed" set used
|
|
7
|
+
* when the posture resolver itself fails. `satisfies` keeps it in lockstep with the union. */
|
|
3
8
|
export declare const COMPLIANCE_CAPABILITIES: readonly ["mcp_servers", "workflows", "web_fetch", "org_memory_mount"];
|
|
9
|
+
/**
|
|
10
|
+
* A principal's resolved compliance posture, supplied by the trusted deployment resolver. The
|
|
11
|
+
* effective deny set is `BUILTIN_COMPLIANCE_DENIES[profile] ∪ additionalDenies` — supply can only
|
|
12
|
+
* TIGHTEN a profile's builtin floor, never carve a builtin deny back out.
|
|
13
|
+
*/
|
|
4
14
|
export interface CompliancePosture {
|
|
5
15
|
profile: ComplianceProfile;
|
|
16
|
+
/** Extra denies on top of the profile's builtin floor (closed set; unknown values are refused). */
|
|
6
17
|
additionalDenies?: readonly ComplianceCapability[];
|
|
7
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Builtin per-profile deny floors, mapped from the CC 2.1.221 policy-limits pair table onto the
|
|
21
|
+
* capabilities this engine manages: hipaa denies `allow_web_fetch` ⇒ `web_fetch`. (CC's
|
|
22
|
+
* `allow_memory_sync` row maps onto the org-memory plane and joins this table together with the
|
|
23
|
+
* memory-admission seam; CC has no MCP/workflow rows — those stay reachable via `additionalDenies`.)
|
|
24
|
+
*/
|
|
8
25
|
export declare const BUILTIN_COMPLIANCE_DENIES: Record<ComplianceProfile, readonly ComplianceCapability[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a posture into its effective deny set. Fail-loud on any value outside the closed sets
|
|
28
|
+
* (`config.compliance_posture`): a posture that does not parse must be treated by the caller as a
|
|
29
|
+
* resolver FAULT (deny every managed capability), never as a partially-applied profile.
|
|
30
|
+
*/
|
|
9
31
|
export declare function resolveComplianceDenies(posture: CompliancePosture): ReadonlySet<ComplianceCapability>;
|
|
32
|
+
/** The core web-fetch tool face's canonical mounted name (`createWebFetchTool` in tools/web.ts). */
|
|
10
33
|
export declare const WEB_FETCH_TOOL_NAME = "WebFetch";
|
|
34
|
+
/**
|
|
35
|
+
* The CALL-TIME half of the `web_fetch` double point (CC form — mount check + call guard): given the
|
|
36
|
+
* run's frozen deny set and a tool-call name, return the refusal text when the call must be blocked,
|
|
37
|
+
* else `undefined`. Kept as a pure exported decision so the gate wiring and the tests hold ONE
|
|
38
|
+
* predicate; today every roster lane that can mint a `WebFetch`-named tool is already refused at
|
|
39
|
+
* prepare, so this is the standing second lock for any future dynamic roster lane.
|
|
40
|
+
*/
|
|
11
41
|
export declare function complianceCallDenial(denies: ReadonlySet<ComplianceCapability>, toolName: string): string | undefined;
|
|
@@ -1,18 +1,93 @@
|
|
|
1
1
|
import type { MemoryStore } from "./memory.js";
|
|
2
2
|
import { type ConsolidationLLM, type ConsolidationStats } from "./runner/memory-consolidation.js";
|
|
3
|
+
/**
|
|
4
|
+
* design/84 Seam B (M6+M10) — **cursor-incremental scope consolidation**. A thin function over the pure
|
|
5
|
+
* {@link runMemoryConsolidation}: it reads the scope's persisted cursor, feeds ONLY the notes appended
|
|
6
|
+
* AFTER it (the incremental batch) into one reconcile pass, then — IFF the whole pass succeeds — advances
|
|
7
|
+
* the cursor to the high-water mark it observed. This is the externally-triggerable periodic path (a
|
|
8
|
+
* deployment's timer / N-session gate fires it); the TRIGGER and any cross-process LOCK live OUTSIDE this
|
|
9
|
+
* function (the deployment shell's exec/persist axes — see {@link ConsolidateScopeOptions.acquire}).
|
|
10
|
+
*
|
|
11
|
+
* **Cursor marker semantics (no-miss / no-dup):** the cursor is an OPAQUE ordering marker the STORE defines
|
|
12
|
+
* (this core never parses it). In the three reference stores it is a note **id** — `uuidv7`, which is
|
|
13
|
+
* lexicographically time-sortable, so "after the cursor" is a string `>` comparison and the high-water mark
|
|
14
|
+
* is the lexicographic MAX. Each pass:
|
|
15
|
+
* - reads `cursor = getConsolidationCursor(scope)` (undefined ⇒ whole scope pending),
|
|
16
|
+
* - lists the scope's note headers (stable store ordering) and keeps those with `id > cursor` AND not
|
|
17
|
+
* already `consolidationGenerated` (a prior pass's own output — excluded so it is never re-merged),
|
|
18
|
+
* - reconciles that incremental batch via `runMemoryConsolidation` (which itself re-excludes
|
|
19
|
+
* `consolidationGenerated` + this-batch ids from each note's candidate set),
|
|
20
|
+
* - advances the cursor to the high-water mark of the fed batch ∪ `stats.addedIds`, but capped STRICTLY
|
|
21
|
+
* BELOW the smallest note this pass FAILED to process (`stats.failedIds`) — a contiguous successful-prefix
|
|
22
|
+
* marker, not the plain max (the MAJOR1 BLOCKER: a single max marker cannot keep a sub-max failed note
|
|
23
|
+
* pending; see {@link cappedHighWater}).
|
|
24
|
+
* No-dup: a note with `id <= cursor` is never re-fed. No-miss: a note appended after the advance, or one at/
|
|
25
|
+
* above a failure floor this pass, keeps `id > cursor` (uuidv7 monotonic) and is picked up by a later pass. A
|
|
26
|
+
* pass's own ADDs carry `consolidationGenerated:true` AND (when below the failure floor) are folded into the
|
|
27
|
+
* high-water mark, so they are excluded twice over.
|
|
28
|
+
*
|
|
29
|
+
* **Whole-pass advance (decision 3):** the cursor advances (up to the success boundary) ONLY when the pass
|
|
30
|
+
* returns (no throw). A pass that THROWS (LLM hard failure) does NOT advance at all — the batch is fully
|
|
31
|
+
* retried next time. A pass that returns with per-note failures advances only past the contiguous successful
|
|
32
|
+
* prefix below the smallest failure (fail-open: at worst a near-duplicate survives an extra pass, never data
|
|
33
|
+
* loss; consistent with the memory-store contract).
|
|
34
|
+
*
|
|
35
|
+
* **No-op safety (the BLOCKER §2 closes):** when the store lacks the cursor pair
|
|
36
|
+
* ({@link supportsPeriodicConsolidation} false) this is a NO-OP that calls `onWarn` — it NEVER degrades into a
|
|
37
|
+
* full re-consolidation of the whole scope (which would re-merge already-consolidated notes forever). It is
|
|
38
|
+
* also a no-op when the store can't consolidate at all ({@link supportsConsolidation} false) or the manifest
|
|
39
|
+
* read pair ({@link MemoryStore.listStructuredNotes} / {@link MemoryStore.getByIds}) is incomplete.
|
|
40
|
+
*/
|
|
3
41
|
export interface ConsolidateScopeDeps {
|
|
4
42
|
store: MemoryStore;
|
|
5
43
|
llm: ConsolidationLLM;
|
|
44
|
+
/** Routes diagnostics (skipped decisions, no-op-because-unsupported, lock-busy) — same sink as the Runner's
|
|
45
|
+
* `onError(phase:"memory")`. Never throws back into this function. */
|
|
6
46
|
onWarn?: (err: unknown) => void;
|
|
47
|
+
/**
|
|
48
|
+
* design/84 Seam B (TOC profile) — OPTIONAL cross-process consolidation lock. When provided,
|
|
49
|
+
* {@link consolidateScope} acquires it for `scope` before the pass and releases it after; a `release` of
|
|
50
|
+
* `undefined` (lock busy) makes the pass a NO-OP (another process is already consolidating this scope).
|
|
51
|
+
* The implementation (writeThenLink + stale-PID prune) lives in the deployment shell (`stores/file`), NOT
|
|
52
|
+
* core — core only DEFINES the injection point (the constitutional persist/exec-axis split).
|
|
53
|
+
*/
|
|
7
54
|
acquire?: (scope: string) => Promise<(() => void) | undefined> | (() => void) | undefined;
|
|
8
55
|
}
|
|
56
|
+
/** Tuning for one {@link consolidateScope} pass (mirrors the inline consolidation settings; all optional). */
|
|
9
57
|
export interface ConsolidateScopeOptions {
|
|
10
58
|
band?: {
|
|
11
59
|
lo: number;
|
|
12
60
|
hi: number;
|
|
13
61
|
};
|
|
14
62
|
searchLimit?: number;
|
|
63
|
+
/** Cap on notes fed into ONE pass (token bound). The cursor advances only past the contiguous SUCCESSFUL
|
|
64
|
+
* prefix of the FED batch (the first `maxNotes` pending) — never past the un-fed tail beyond the cap, and
|
|
65
|
+
* never past a note this pass FAILED to process — so a backlog larger than `maxNotes`, and any failed note,
|
|
66
|
+
* keep `id > cursor` and drain over successive passes without ever re-feeding the notes already handled. */
|
|
15
67
|
maxNotes?: number;
|
|
16
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Run ONE cursor-incremental consolidation pass for `scope` (design/84 Seam B). Returns the pass stats
|
|
71
|
+
* (or `undefined` when it was a no-op: unsupported store, empty incremental batch, or lock busy). Never
|
|
72
|
+
* throws for a no-op reason; a hard LLM failure inside `runMemoryConsolidation` propagates (the caller's
|
|
73
|
+
* fire-and-forget envelope catches it) and the cursor is left UN-advanced (the batch retries next pass).
|
|
74
|
+
*/
|
|
17
75
|
export declare function consolidateScope(scope: string, deps: ConsolidateScopeDeps, opts?: ConsolidateScopeOptions): Promise<ConsolidationStats | undefined>;
|
|
76
|
+
/**
|
|
77
|
+
* design/84 Seam B (切片 4) — advance ONLY the cursor after an INLINE (task-end) consolidation pass has
|
|
78
|
+
* already run, so a later periodic {@link consolidateScope} starts from the inline-processed high-water mark
|
|
79
|
+
* (it does NOT re-consolidate the notes the inline pass just handled). The inline path consolidates the
|
|
80
|
+
* notes the model saved THIS task (the newest, highest-id notes); advancing the cursor over the PROCESSED
|
|
81
|
+
* ids ∪ addedIds makes inline and periodic share ONE cursor.
|
|
82
|
+
*
|
|
83
|
+
* **MAJOR1 BLOCKER:** the advance caps STRICTLY BELOW the smallest FAILED note (`failedIds`). A single
|
|
84
|
+
* max-marker cursor cannot keep a sub-max failed note pending, so a low-id note whose handling failed must
|
|
85
|
+
* stop the cursor below it even when a higher-id sibling succeeded — otherwise the failed note (id <= the
|
|
86
|
+
* plain max) would lose `id > cursor` and be exiled from consolidation forever. Pass the pass's
|
|
87
|
+
* `stats.consolidatedIds` (processed), `stats.addedIds`, and `stats.failedIds`.
|
|
88
|
+
*
|
|
89
|
+
* No-op when the store lacks the cursor pair (back-compat: an old store keeps the pure-inline behavior).
|
|
90
|
+
* Never throws — a cursor-advance failure routes to `onWarn` (the inline notes are already durable; the
|
|
91
|
+
* worst case is the next periodic pass re-sees them, which `runMemoryConsolidation` handles idempotently).
|
|
92
|
+
*/
|
|
18
93
|
export declare function advanceCursorAfterInline(store: MemoryStore, scope: string, seenNoteIds: ReadonlyArray<string | undefined>, addedIds: ReadonlyArray<string>, failedIds?: ReadonlyArray<string>, onWarn?: (err: unknown) => void): Promise<void>;
|
|
@@ -1,20 +1,119 @@
|
|
|
1
1
|
import type { AgentMessage } from "../internal/harness.js";
|
|
2
2
|
import type { Model } from "../internal/llm.js";
|
|
3
|
+
/**
|
|
4
|
+
* Small-window FLOOR fraction of the clearStale/compaction frontier (see {@link contextEditFrontier},
|
|
5
|
+
* which is the single source for both the clearStale budget and the compaction-threshold clamp).
|
|
6
|
+
* CC's fixed-deduction trigger geometry only exists for ≥100k autocompact windows (its configured-
|
|
7
|
+
* window floor is 100000), and `W − 33000` goes degenerate below ~47k — small windows keep the
|
|
8
|
+
* historical fractional trigger instead.
|
|
9
|
+
*/
|
|
3
10
|
export declare const EDIT_FRACTION = 0.7;
|
|
11
|
+
/**
|
|
12
|
+
* CC-parity trigger geometry (verified against CC 2.1.207): the reactive autocompact trigger sits a
|
|
13
|
+
* FIXED DISTANCE below the window, not at a fixed fraction —
|
|
14
|
+
* effectiveWindow = autocompactWindow − min(maxOutputTokens, 20000) (CC `Nye`, cap `uMd`)
|
|
15
|
+
* trigger = effectiveWindow − 13000 (CC `dSo`, buffer `rMd`)
|
|
16
|
+
* i.e. trigger = W − 33000 for every model whose max output is ≥ 20k: a 200k window triggers at
|
|
17
|
+
* 167000 (83.5% of nominal), a 1M window at 967000. (CC additionally ships a sonnet-5-only 1M
|
|
18
|
+
* autocompact-window special of 967000 via dynamic config, making ITS 1M trigger 934000; that is a
|
|
19
|
+
* per-model config delivery, not geometry — an embedder reproduces it EXACTLY via
|
|
20
|
+
* `model.autoCompactTokens = 967000`, which lowers only this trigger-side window while the guard
|
|
21
|
+
* and physical request budgeting stay on the 1M window — CC's dual-window shape.) We take the
|
|
22
|
+
* 20000 cap branch unconditionally (flat 33000), i.e. the `min(maxOutputTokens, 20000)` branch is
|
|
23
|
+
* deliberately NOT ported: the deduction is exact parity only for models with max output ≥ 20k. A
|
|
24
|
+
* model with a smaller max output would deduct less in CC (trigger LATER); we deduct the full
|
|
25
|
+
* 20000 and so trigger EARLIER there — the conservative direction (early compaction is bounded
|
|
26
|
+
* cost; a late trigger risks the window). It also keeps the frontier a pure function of the
|
|
27
|
+
* window — single source for the death-band clamp below.
|
|
28
|
+
*/
|
|
4
29
|
export declare const CONTEXT_OUTPUT_RESERVE_TOKENS = 20000;
|
|
5
30
|
export declare const COMPACTION_TRIGGER_BUFFER_TOKENS = 13000;
|
|
31
|
+
/**
|
|
32
|
+
* The clearStale/compaction frontier for a window — SINGLE SOURCE for two coupled points
|
|
33
|
+
* (design/64 §26.4 fix 2): the budget at which the request-layer stale-result clearing engages
|
|
34
|
+
* ({@link editBudget}) AND the ceiling the compaction threshold is clamped to
|
|
35
|
+
* (`sanitizeCompactionSettings`). Deriving both from one function keeps `compaction ≡ clearStale`
|
|
36
|
+
* an invariant: a threshold above the clearing frontier would put every request between the two
|
|
37
|
+
* points on a moving clearing frontier that breaks the prefix cache (~frontier re-prefilled PER
|
|
38
|
+
* REQUEST — the "death band"). `max()` keeps the frontier monotonic in the window; exact
|
|
39
|
+
* crossover (integer domain, pinned by test): the fractional floor strictly wins through
|
|
40
|
+
* W = 109996, the two legs are EQUAL for W = 109997…110000 (floor(0.7W) meets W − 33000 there),
|
|
41
|
+
* and the fixed deduction strictly wins from W = 110001 up.
|
|
42
|
+
*/
|
|
6
43
|
export declare function contextEditFrontier(window: number): number;
|
|
44
|
+
/**
|
|
45
|
+
* checklist #54 (CC microCompact.ts:41-50 `COMPACTABLE_TOOLS` parity): the INCLUSION whitelist of
|
|
46
|
+
* tools whose results may be content-cleared by the stale-result pass. CC's set is exactly
|
|
47
|
+
* { Read, Bash, PowerShell (SHELL_TOOL_NAMES), Grep, Glob, WebSearch, WebFetch, Edit, Write } —
|
|
48
|
+
* cheap-to-regenerate I/O. Everything else is PRESERVED: expensive/decision-bearing results
|
|
49
|
+
* (Agent subagent reports, Task* registry state, TodoWrite acks, Monitor, MCP tools, custom
|
|
50
|
+
* ToolSpecs) survive to the harder defenses (compaction summarizes them instead of blanking them).
|
|
51
|
+
* PowerShell is kept for CC fidelity even though sema does not mount it. Overridable per call via
|
|
52
|
+
* {@link ContextEditOptions.compactableTools} for custom-tool-heavy embedders.
|
|
53
|
+
*/
|
|
7
54
|
export declare const COMPACTABLE_TOOLS: ReadonlySet<string>;
|
|
8
55
|
export interface ContextEditOptions {
|
|
56
|
+
/** Start clearing once estimated context tokens exceed this. */
|
|
9
57
|
budgetTokens: number;
|
|
58
|
+
/** Always keep the content of this many most-recent tool results. Default 3. */
|
|
10
59
|
keepRecentToolResults?: number;
|
|
60
|
+
/**
|
|
61
|
+
* roadmap #6② (CC contentReplacementState parity): when set, a result's FULL TEXT is offloaded to
|
|
62
|
+
* the store before its content is cleared, and the marker carries the ReadToolResult ref — a
|
|
63
|
+
* cleared result becomes pageable instead of gone-from-view. `persist` must be idempotent per ref
|
|
64
|
+
* (the store's write-once put) because clearing re-runs on every request build. Absent ⇒ the bare
|
|
65
|
+
* marker (pre-#6 behavior; the durable session still holds the full result either way).
|
|
66
|
+
*/
|
|
11
67
|
offload?: {
|
|
68
|
+
/** Write-once persist; the returned ref goes into the marker. Sync (in-memory) or async stores both fit. */
|
|
12
69
|
persist: (toolCallId: string, fullText: string) => string;
|
|
13
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* design/123 D3 (codex-B1 = fable-M5) — ANCHORED accounting start: `estimateContextTokens(messages,
|
|
73
|
+
* charsPerToken).tokens` for the SAME message array. When set, the trigger gate AND the internal
|
|
74
|
+
* bookkeeping start from this usage-anchored value instead of the pure structural sum (which
|
|
75
|
+
* underestimates code by ~25% and CJK by 60–75% — the defense would self-certify and pass
|
|
76
|
+
* over-window requests). Bookkeeping semantics (pinned): clearing a message AFTER the usage anchor
|
|
77
|
+
* decrements by its structural delta; clearing a message AT/BEFORE the anchor decrements ZERO —
|
|
78
|
+
* the anchor usage was billed with that content included and does not shrink on a request-view
|
|
79
|
+
* edit (the clear only pays off on the NEXT request, after a fresh anchor lands), so the defense
|
|
80
|
+
* keeps clearing deeper until the anchored total is met or nothing clearable remains.
|
|
81
|
+
* Absent ⇒ legacy structural gate + accounting (byte-identical behavior).
|
|
82
|
+
*/
|
|
14
83
|
anchoredTotalTokens?: number;
|
|
84
|
+
/** design/123 D2 — structural coefficient (`Model.charsPerToken`); default 4. */
|
|
15
85
|
charsPerToken?: number;
|
|
86
|
+
/**
|
|
87
|
+
* checklist #54 — which tools' results are clearable. Defaults to {@link COMPACTABLE_TOOLS}
|
|
88
|
+
* (CC microCompact.ts:41-50). A result whose `toolName` is not in the set is NEVER cleared by
|
|
89
|
+
* this pass, no matter how far over budget the request is — expensive subagent reports and
|
|
90
|
+
* registry state are compaction's job, not a blanking marker's.
|
|
91
|
+
*/
|
|
16
92
|
compactableTools?: ReadonlySet<string>;
|
|
17
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Context-editing (the lightest, safest compaction; Anthropic reports ~29% improvement alone):
|
|
96
|
+
* when context exceeds the budget, replace the CONTENT of older tool-result messages with a short
|
|
97
|
+
* marker, keeping the turn structure (tool_call/tool_result pairing) intact. The most recent
|
|
98
|
+
* `keepRecentToolResults` results are preserved.
|
|
99
|
+
*
|
|
100
|
+
* Request-only and non-destructive: returns a new array; the durable session keeps the full results.
|
|
101
|
+
* Older results are cleared first, stopping as soon as the budget is met.
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* audit A-1 (view-level heal for HISTORICAL pollution): drop synthetic EMPTY failure assistants —
|
|
105
|
+
* stopReason aborted/error with no tool calls and no non-whitespace text/thinking. Sessions persisted
|
|
106
|
+
* before 1.92.0 may carry one parked between an interrupted tool batch and its reconcile tool_results
|
|
107
|
+
* (`A(tu×3), TR1, TR2, A(aborted,""), TR3`) — an API-invalid sequence on strict providers, and
|
|
108
|
+
* append-only sessions cannot be rewritten. Dropping the junk from the REQUEST VIEW restores a legal
|
|
109
|
+
* transcript (TR3 rejoins its batch). Deterministic ⇒ byte-stable per request ⇒ prefix-cache safe.
|
|
110
|
+
* New sessions never contain these (the loop exits cleanly on abort; the harness skips persisting them).
|
|
111
|
+
*/
|
|
18
112
|
export declare function dropEmptyFailureAssistants(messages: AgentMessage[]): AgentMessage[];
|
|
19
113
|
export declare function clearStaleToolResults(messages: AgentMessage[], opts: ContextEditOptions): AgentMessage[];
|
|
114
|
+
/** The token budget at which context-editing begins for a model (below the harder guard trim).
|
|
115
|
+
* = {@link contextEditFrontier} of the model's AUTOCOMPACT window (CC-parity fixed deduction with
|
|
116
|
+
* a 0.7 small-window floor) — the same point the compaction threshold is clamped to. Dual-window
|
|
117
|
+
* semantics: `autoCompactTokens` (when declared) feeds this trigger-side geometry only; the guard
|
|
118
|
+
* trim (`guardBudget`) stays on the physical window. */
|
|
20
119
|
export declare function editBudget(model: Model): number;
|
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
import type { AgentMessage } from "../internal/harness.js";
|
|
2
2
|
import type { Model } from "../internal/llm.js";
|
|
3
|
+
/**
|
|
4
|
+
* Last-resort, in-task context trim. Proper compaction (LLM summary) runs *between* tasks;
|
|
5
|
+
* this prevents a single task whose internal tool-loop balloons from overflowing the window.
|
|
6
|
+
*
|
|
7
|
+
* Keeps all summary messages (compaction/branch) and the most recent messages that fit the
|
|
8
|
+
* budget, dropping older regular messages at a safe boundary (never starting on an orphan
|
|
9
|
+
* toolResult). Returns the original array when already within budget.
|
|
10
|
+
*
|
|
11
|
+
* design/123 D3 (codex-B1 = fable-M5) — anchored accounting: when `anchoredTotalTokens`
|
|
12
|
+
* (= `estimateContextTokens(messages, charsPerToken).tokens` for the SAME array) is provided, the
|
|
13
|
+
* trigger gate and the internal bookkeeping start from the usage-anchored value instead of the
|
|
14
|
+
* structural sum (which underestimates code/CJK and lets over-window requests through). Dropping a
|
|
15
|
+
* message AFTER the usage anchor reduces the accounted total by its structural estimate; dropping a
|
|
16
|
+
* message AT/BEFORE the anchor reduces it by ZERO (the anchor usage was billed with that content —
|
|
17
|
+
* a request-view drop only pays off on the NEXT request), so the trim keeps cutting deeper until
|
|
18
|
+
* the anchored total meets the budget or only the minimal tail is left. Absent ⇒ legacy structural
|
|
19
|
+
* behavior, byte-identical. `charsPerToken` (design/123 D2): structural coefficient, default 4.
|
|
20
|
+
*/
|
|
3
21
|
export declare function trimToBudget(messages: AgentMessage[], budgetTokens: number, anchoredTotalTokens?: number, charsPerToken?: number): AgentMessage[];
|
|
22
|
+
/**
|
|
23
|
+
* In-band notice for a request view whose oldest messages were dropped by the guard trim. Every
|
|
24
|
+
* other history-reducing pass in the pipeline announces itself to the model (compaction injects a
|
|
25
|
+
* summary); a silent trim leaves the model unaware that earlier instructions or constraints are no
|
|
26
|
+
* longer visible. MUST remain a single static string: the notice is re-inserted on every trimmed
|
|
27
|
+
* request, and a byte-identical prefix keeps provider prefix caching effective.
|
|
28
|
+
*/
|
|
4
29
|
export declare const CONTEXT_TRIM_NOTICE: string;
|
|
30
|
+
/**
|
|
31
|
+
* Insert the static trim notice ahead of the kept tail of a trimmed request view (after any
|
|
32
|
+
* always-kept summary messages, which lead the rebuilt array). Call ONLY when the trim actually
|
|
33
|
+
* dropped messages. Request-view only — the synthetic message is never persisted to the session
|
|
34
|
+
* (fixed timestamp keeps it fully deterministic).
|
|
35
|
+
*/
|
|
5
36
|
export declare function insertTrimNotice(trimmed: AgentMessage[]): AgentMessage[];
|
|
37
|
+
/**
|
|
38
|
+
* design/123 D3 belt (invariant-level, live-caught 16k 400s): the FINAL request view must never
|
|
39
|
+
* contain a toolResult whose tool-call assistant is absent — strict gateways hard-400 on it
|
|
40
|
+
* ("Messages with role 'tool' must be a response to a preceding message with 'tool_calls'"). Every
|
|
41
|
+
* individual producer is turn-aligned (findCutPoint never cuts on a toolResult; trimToBudget
|
|
42
|
+
* turn-aligns its floor), but NO pipeline combination may ship an orphan, so the prepare-task
|
|
43
|
+
* context hook sweeps its output through this last. Deterministic ⇒ byte-stable per request ⇒
|
|
44
|
+
* prefix-cache safe. Returns the SAME array when clean (zero-cost fast path); `dropped` carries a
|
|
45
|
+
* diagnostic per removed orphan (toolCallId + neighbor roles) for onError attribution.
|
|
46
|
+
*/
|
|
6
47
|
export declare function dropOrphanToolResults(messages: AgentMessage[]): {
|
|
7
48
|
messages: AgentMessage[];
|
|
8
49
|
dropped: Array<{
|
|
@@ -12,4 +53,9 @@ export declare function dropOrphanToolResults(messages: AgentMessage[]): {
|
|
|
12
53
|
nextRole: string;
|
|
13
54
|
}>;
|
|
14
55
|
};
|
|
56
|
+
/** Budget the in-task guard targets for a model — CC-aligned headroom numbers with a 0.85
|
|
57
|
+
* small-window floor, sema-owned drop-oldest action (see {@link GUARD_HEADROOM_TOKENS}); always
|
|
58
|
+
* above the compaction/clearStale frontier. Dual-window semantics: deliberately the PHYSICAL
|
|
59
|
+
* window (`contextTokens ?? contextWindow`), NOT `autoCompactTokens` — the guard protects the
|
|
60
|
+
* real request limit; a lowered autocompact window only moves the trigger-side geometry. */
|
|
15
61
|
export declare function guardBudget(model: Model): number;
|
package/dist/core/exec-gate.d.ts
CHANGED
|
@@ -1,29 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L2 mechanical verification gate (design/54) — the "verifiable outputs" exit oracle.
|
|
3
|
+
*
|
|
4
|
+
* Runs a TRUSTED, spec-derived suite of commands (build / type-check / test) in an {@link ExecutionEnv}
|
|
5
|
+
* and gates on the **real exit codes**: pass = every step exited 0. This is the mechanical half of
|
|
6
|
+
* verifiable outputs (design/54 §2); the de-correlated LLM-judge half is {@link runWithVerification}
|
|
7
|
+
* (L3). It catches what tests cover; service[33] measured L2 alone misses 50-100% of semantic/edge
|
|
8
|
+
* defects, which is why L3 runs on what passes L2.
|
|
9
|
+
*
|
|
10
|
+
* **It is a thin exit oracle, not a framework** — no model, no Runner, no agents dependency. It just runs
|
|
11
|
+
* commands and reports their exit truthfully, choosing the streaming `execStream` on a remote env (long
|
|
12
|
+
* builds, read-timeout, output cap) or the buffered `exec` on a base env. Which commands to run, and how
|
|
13
|
+
* to compose L2 with L3 / per-module sub-gates, is the caller's (profile's) job (design/54 §4).
|
|
14
|
+
*
|
|
15
|
+
* 🔴 SECURITY (design/53 §2.B, threat BUG8 — "L2 can be gamed"): `steps` MUST be a trusted, spec-derived
|
|
16
|
+
* suite — NOT test files an **untrusted worker** authored (a worker can write `assert(true)` / happy-path
|
|
17
|
+
* tests that pass while the code is broken, pushing all pressure onto an uncalibrated L3). This helper does
|
|
18
|
+
* not and cannot know which commands are trustworthy; the caller owns that. The gate's guarantee is narrow:
|
|
19
|
+
* "did these exact commands all exit 0 in this env" — nothing about whether the commands are meaningful,
|
|
20
|
+
* whether the env is isolated (design/53 §E = deployment), or the semantics of the change (that is L3).
|
|
21
|
+
*/
|
|
1
22
|
import type { ExecutionEnv } from "../internal/harness-types.js";
|
|
23
|
+
/** One command in an L2 suite. */
|
|
2
24
|
export interface ExecStep {
|
|
25
|
+
/** Shell command to run (e.g. `"npm test"`, `"tsc --noEmit"`, `"git diff"`). */
|
|
3
26
|
command: string;
|
|
27
|
+
/** Human label for reporting. Default: the command string. */
|
|
4
28
|
label?: string;
|
|
29
|
+
/** Working directory; relative paths resolve against the env root. Default: the env's cwd. */
|
|
5
30
|
cwd?: string;
|
|
31
|
+
/** Extra environment variables for this command. */
|
|
6
32
|
env?: Record<string, string>;
|
|
33
|
+
/** Per-step timeout (seconds). Default: none. */
|
|
7
34
|
timeoutSec?: number;
|
|
8
35
|
}
|
|
36
|
+
/** The outcome of a single {@link ExecStep}. */
|
|
9
37
|
export interface ExecStepResult {
|
|
10
38
|
label: string;
|
|
11
39
|
command: string;
|
|
40
|
+
/** The real exit code, or `null` when the command never produced one (transport error / timeout / abort). */
|
|
12
41
|
exitCode: number | null;
|
|
13
42
|
stdout: string;
|
|
14
43
|
stderr: string;
|
|
44
|
+
/** `exitCode === 0`. A `null` exit is **never** `ok` (we can't confirm success, so we don't pass it). */
|
|
15
45
|
ok: boolean;
|
|
46
|
+
/** Set when the step failed to RUN (an `ExecutionError`/`RemoteExecutionError` code) — distinct from a non-zero exit. */
|
|
16
47
|
errorCode?: string;
|
|
48
|
+
/** True when captured output was truncated at {@link ExecGateOptions.maxOutputBytes}. */
|
|
17
49
|
truncated?: boolean;
|
|
18
50
|
}
|
|
51
|
+
/** The L2 verdict over a whole suite. */
|
|
19
52
|
export interface ExecGateResult {
|
|
53
|
+
/** True iff there was ≥1 step AND every step ran and exited 0. An EMPTY suite is `false` (nothing was verified — not a vacuous pass). */
|
|
20
54
|
passed: boolean;
|
|
55
|
+
/** Per-step detail, in order. With `stopOnFailure` (default), steps after the first failure are absent. */
|
|
21
56
|
steps: ExecStepResult[];
|
|
22
57
|
}
|
|
58
|
+
/** Options for {@link runExecGate}. */
|
|
23
59
|
export interface ExecGateOptions {
|
|
60
|
+
/** Stop at the first failed/non-zero step (default `true` — a cheap CI-style short-circuit). */
|
|
24
61
|
stopOnFailure?: boolean;
|
|
62
|
+
/** Cap captured output **per step** in UTF-8 bytes (default 64 KiB) so a `find /` can't flood memory. */
|
|
25
63
|
maxOutputBytes?: number;
|
|
64
|
+
/** Idle read timeout (ms) for the streaming (remote) path; ignored on the buffered path. */
|
|
26
65
|
readTimeoutMs?: number;
|
|
66
|
+
/** Abort the whole gate (also forwarded to each command). */
|
|
27
67
|
signal?: AbortSignal;
|
|
28
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Run an L2 mechanical gate: execute `steps` in `env` and gate on real exit codes. See the file header for
|
|
71
|
+
* the security contract — `steps` must be a trusted, spec-derived suite, not worker-authored tests.
|
|
72
|
+
*/
|
|
29
73
|
export declare function runExecGate(env: ExecutionEnv, steps: ExecStep[], options?: ExecGateOptions): Promise<ExecGateResult>;
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded rolling-TAIL accumulator for streaming exec output (sema D2) — FIRST-PARTY, vendor-independent.
|
|
3
|
+
*
|
|
4
|
+
* A model-driven `yes` / `cat big.bin` over a 120s/600s shell can emit gigabytes; accumulating it unbounded OOMs
|
|
5
|
+
* a durable worker. We keep only the LAST `maxBytes` — the tail (errors + the exit code are at the end, which is
|
|
6
|
+
* what the model needs) — dropping the head as it overflows, plus a count of dropped bytes for a visible marker.
|
|
7
|
+
*
|
|
8
|
+
* This lives in `src/core/` — NOT `src/vendor/` — on purpose: it is OUR robustness invariant, shared by the
|
|
9
|
+
* (currently-vendored) NodeExecutionEnv AND a downstream exec adapter (service host/ssh/adb/docker/k8s, [267]).
|
|
10
|
+
* One implementation + ONE model-facing marker text = zero drift, and the public export points at a STABLE path
|
|
11
|
+
* that survives the planned de-vendoring (when NodeExecutionEnv is naturalized out of `src/vendor/`, nothing rebinds).
|
|
12
|
+
*/
|
|
1
13
|
import { StringDecoder } from "node:string_decoder";
|
|
2
14
|
export declare const MAX_EXEC_OUTPUT_BYTES: number;
|
|
15
|
+
/**
|
|
16
|
+
* Push-based bounded tail: feed it raw output chunks (Buffers); it retains only the last `maxBytes`, dropping the
|
|
17
|
+
* head incrementally so memory is O(maxBytes) regardless of total output. Byte-precise (the OOM bound is bytes).
|
|
18
|
+
*/
|
|
3
19
|
export declare class RollingTailBuffer {
|
|
4
20
|
private readonly maxBytes;
|
|
5
21
|
private readonly chunks;
|
|
@@ -7,26 +23,71 @@ export declare class RollingTailBuffer {
|
|
|
7
23
|
private headDropped;
|
|
8
24
|
private sourceSkipped;
|
|
9
25
|
constructor(maxBytes?: number);
|
|
26
|
+
/** Append a chunk; evict head bytes (whole or partial chunks) until within `maxBytes`. */
|
|
10
27
|
push(chunk: Buffer): void;
|
|
28
|
+
/** Account bytes that were dropped BEFORE ever reaching the buffer (e.g. a spool reader skipping
|
|
29
|
+
* un-retainable backlog at the source). They join `droppedBytes` so `markTruncated` discloses the
|
|
30
|
+
* TRUE number of missing bytes — recording them here instead of pushing keeps the drop O(1). */
|
|
11
31
|
recordSkippedBytes(n: number): void;
|
|
32
|
+
/** The retained tail decoded as UTF-8, plus how many bytes are missing in total (head evictions +
|
|
33
|
+
* source skips — the foreground `markTruncated` disclosure keeps the combined figure). */
|
|
12
34
|
result(): {
|
|
13
35
|
text: string;
|
|
14
36
|
droppedBytes: number;
|
|
15
37
|
};
|
|
38
|
+
/** RB-234 ([1937]): the retained window's RAW bytes — cursor slicing must happen in the byte domain
|
|
39
|
+
* (re-encoding a lossily-decoded string inflates every invalid byte to a 3-byte U+FFFD and lands
|
|
40
|
+
* byte cursors on the wrong offsets). */
|
|
16
41
|
bytes(): Buffer;
|
|
42
|
+
/** RB-234 ([1937]): head-eviction count ALONE — the retention window is [headDroppedBytes, pushed-total)
|
|
43
|
+
* in the accepted-byte domain; source skips must not shift this origin. */
|
|
17
44
|
headDroppedBytes(): number;
|
|
45
|
+
/** RB-234 ([1937]): source-skip count alone (see {@link recordSkippedBytes}) — poll disclosure reports
|
|
46
|
+
* the per-poll increment of this figure instead of silently absorbing it into the window origin. */
|
|
18
47
|
sourceSkippedBytes(): number;
|
|
19
48
|
}
|
|
49
|
+
/** RB-234 ([1937]): per-stream cursor state for incremental (poll-style) consumption of a
|
|
50
|
+
* {@link RollingTailBuffer}. All counters live in the ACCEPTED-byte domain (bytes actually pushed);
|
|
51
|
+
* source skips are tracked separately for disclosure. Module-level export (not on the package
|
|
52
|
+
* surface) so the slice arithmetic is unit-pinnable without an 8MB integration harness. */
|
|
20
53
|
export interface StreamCursorState {
|
|
21
54
|
tail: RollingTailBuffer;
|
|
55
|
+
/** Consumer position in the accepted-byte domain (bytes already delivered). */
|
|
22
56
|
cursorBytes: number;
|
|
57
|
+
/** Bytes actually pushed into `tail` (excludes source skips — those never had content to deliver). */
|
|
23
58
|
acceptedBytes: number;
|
|
59
|
+
/** `tail.sourceSkippedBytes()` as of the last slice — the delta is disclosed exactly once. */
|
|
24
60
|
disclosedSkippedBytes: number;
|
|
61
|
+
/** Incremental UTF-8 decoder (CC 2.1.220 shape: StringDecoder holds a split multi-byte char across
|
|
62
|
+
* reads instead of emitting replacement chars at every read boundary). */
|
|
25
63
|
decoder: StringDecoder;
|
|
26
64
|
}
|
|
65
|
+
/** Fresh cursor state over a new tail. */
|
|
27
66
|
export declare function newStreamCursorState(tail?: RollingTailBuffer): StreamCursorState;
|
|
67
|
+
/**
|
|
68
|
+
* RB-234 ([1937]): slice the undelivered increment out of a rolling tail — in the BYTE domain, decoded
|
|
69
|
+
* incrementally. Replaces the former decode→re-encode→byte-offset-subarray shape, which mixed two
|
|
70
|
+
* domains: byte cursors landed inside a re-encoded string whose length differs from the raw stream as
|
|
71
|
+
* soon as any invalid-UTF-8 byte sits in the window (each inflates to a 3-byte U+FFFD), making every
|
|
72
|
+
* later poll re-deliver the same trailing garbage forever (a sleeping process "producing" output).
|
|
73
|
+
*
|
|
74
|
+
* - Continuity: a multi-byte char split across two slices is held by the decoder and completed on the
|
|
75
|
+
* next slice — zero replacement chars, zero duplication.
|
|
76
|
+
* - Discontinuity (`droppedBeforeCursor > 0`): the decoder is rebuilt, so bytes on either side of a
|
|
77
|
+
* hole are never joined into a fake character.
|
|
78
|
+
* - `terminal`: flush the decoder (a trailing split char becomes one honest U+FFFD) — without this
|
|
79
|
+
* the last 1–3 bytes of a finished stream would never surface.
|
|
80
|
+
*
|
|
81
|
+
* `droppedBeforeCursor` = head-evicted bytes the cursor never got to + the NEW source-skip increment
|
|
82
|
+
* since the previous slice (formerly silent: skips shifted the window origin instead, re-delivering
|
|
83
|
+
* already-served bytes with `truncated` unset).
|
|
84
|
+
*/
|
|
28
85
|
export declare function sliceStreamIncrement(s: StreamCursorState, terminal: boolean): {
|
|
29
86
|
inc: string;
|
|
30
87
|
droppedBeforeCursor: number;
|
|
31
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* Prepend a model-visible marker when `droppedBytes > 0` (only the TAIL was kept). The SINGLE source of the
|
|
91
|
+
* marker wording so the engine and any downstream adapter show the model the SAME thing.
|
|
92
|
+
*/
|
|
32
93
|
export declare function markTruncated(text: string, droppedBytes: number): string;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
/** rel path of `child` under `root` in "/" form (win root) / verbatim form (posix root); null when not under.
|
|
2
|
+
* codex 1.237 F7: fold "\" only under a WIN-family root ({@link isWinFormPath}); a POSIX tree may legally
|
|
3
|
+
* contain literal backslashes in FILE NAMES, and folding them corrupted both the manifest key and the
|
|
4
|
+
* restore target. */
|
|
1
5
|
declare function relUnder(root: string, child: string): string | null;
|
|
6
|
+
/** Join root + a "/"-form relPath using the ROOT's native separator (keys stay family-consistent). */
|
|
2
7
|
declare function joinUnder(root: string, rel: string): string;
|
|
3
8
|
import type { ExecutionEnv } from "../internal/harness-types.js";
|
|
4
9
|
export interface FileSnapshotError {
|
|
10
|
+
/** `too_large` = the tree exceeded a bound (fail-CLOSED, NOT a silent partial snapshot); `not_found` = no
|
|
11
|
+
* snapshot for that key; `aborted` = the signal fired; the rest = an underlying fs op failed. */
|
|
5
12
|
code: "too_large" | "enumerate_failed" | "read_failed" | "restore_failed" | "not_found" | "aborted";
|
|
6
13
|
message: string;
|
|
7
14
|
}
|
|
@@ -11,23 +18,106 @@ export type FileSnapshotResult = {
|
|
|
11
18
|
ok: false;
|
|
12
19
|
error: FileSnapshotError;
|
|
13
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Capture/restore a working-tree file set keyed by `(scope, key)` — `scope` = sessionId, `key` =
|
|
23
|
+
* `SessionTreeEntry.id` (same anchor as E18 resume-at). All methods are best-effort and NEVER throw — failures
|
|
24
|
+
* are encoded in the returned {@link FileSnapshotResult} (mirrors the ExecutionEnv FileSystem contract).
|
|
25
|
+
*
|
|
26
|
+
* **v1 fidelity bounds (design/101 §defer):** files only — symlinks are NOT captured and are REMOVED by
|
|
27
|
+
* `restore` (they are a path-escape vector); empty directories are not tracked; `restore` re-enumerates under
|
|
28
|
+
* the SAME bounds, so a tree that grew past a bound since the snapshot cannot be rewound (fail-closed).
|
|
29
|
+
*/
|
|
14
30
|
export interface FileSnapshotStore {
|
|
31
|
+
/** Capture the tree under `root` for `(scope, key)`. CREATE-ONCE: a second call for an existing key is a
|
|
32
|
+
* no-op `{ok:true}` (a session entry id is immutable, so its tree state is too). */
|
|
15
33
|
snapshot(scope: string, key: string, env: ExecutionEnv, root: string, signal?: AbortSignal): Promise<FileSnapshotResult>;
|
|
34
|
+
/** Converge the tree under `root` back to the snapshot for `(scope, key)`: remove obstructions/strays
|
|
35
|
+
* (symlinks + files created since), then write every captured file — so the tree MATCHES the snapshot. */
|
|
16
36
|
restore(scope: string, key: string, env: ExecutionEnv, root: string, signal?: AbortSignal): Promise<FileSnapshotResult>;
|
|
37
|
+
/** Whether a snapshot exists for `(scope, key)`. */
|
|
17
38
|
has(scope: string, key: string): Promise<boolean>;
|
|
39
|
+
/** GC: drop every snapshot in `scope` whose key is NOT in `keepKeys` (e.g. unreachable branches). Returns the
|
|
40
|
+
* number of snapshots removed. */
|
|
18
41
|
reap(scope: string, keepKeys: string[]): Promise<number>;
|
|
42
|
+
/** Every snapshot key in `scope` (order unspecified). The enumeration counterpart of {@link reap} (which
|
|
43
|
+
* already iterates the same set internally) — exposed for a cross-backend session EXPORT (service 2c
|
|
44
|
+
* session-sync, [266]): list a session's snapshot keys to move its {entries + file snapshots} to another
|
|
45
|
+
* backend. A durable backend implements it as a `SELECT key WHERE scope = ?`. */
|
|
19
46
|
listKeys(scope: string): Promise<string[]>;
|
|
47
|
+
/**
|
|
48
|
+
* 2c session-sync ([271]): the manifest (`relPath → blobHash`) for `(scope, key)`, or `null` if absent — to
|
|
49
|
+
* EXPORT a snapshot's content to another backend. Pairs with {@link getBlob} for CONTENT-ADDRESSED (deduped)
|
|
50
|
+
* blob transfer: the caller fetches each distinct hash ONCE across all of a session's snapshots. Optional — a
|
|
51
|
+
* backend that supports cross-backend snapshot export implements it.
|
|
52
|
+
*/
|
|
20
53
|
exportManifest?(scope: string, key: string): Promise<Map<string, string> | null>;
|
|
54
|
+
/** 2c session-sync ([271]): the content-addressed bytes for `hash` (undefined if absent). */
|
|
21
55
|
getBlob?(hash: string): Promise<Uint8Array | undefined>;
|
|
56
|
+
/**
|
|
57
|
+
* 2c session-sync ([273]): STORE a snapshot INTO this store from another store's {@link exportManifest} +
|
|
58
|
+
* {@link getBlob} output — the import-side mirror that closes the cross-backend transfer loop. For each DISTINCT
|
|
59
|
+
* blob hash in `manifest`, fetch its bytes via `srcGetBlob`, VERIFY content-address integrity
|
|
60
|
+
* (`sha256(bytes) === hash`), and store it (content-addressed dedup); THEN record `(scope, key) → manifest`.
|
|
61
|
+
*
|
|
62
|
+
* - CREATE-ONCE: a second import for an existing key is a no-op `{ok:true}` (an entry id is immutable).
|
|
63
|
+
* - FAIL-CLOSED: a missing OR hash-mismatched source blob → `read_failed` and NO manifest is committed (never a
|
|
64
|
+
* partial snapshot that a later {@link restore} would silently truncate). The manifest's relPaths are NOT
|
|
65
|
+
* re-validated here — `restore` remains the path-escape gate (it already neutralizes unsafe relPaths).
|
|
66
|
+
* - Pure store→store: does NOT touch an `ExecutionEnv` (unlike `applyManifest`, which converges ONE snapshot to a
|
|
67
|
+
* working tree; import preserves ALL historical snapshots in the dst store so a later rewind-to-past finds them).
|
|
68
|
+
*
|
|
69
|
+
* Optional — a backend that supports cross-backend snapshot import implements it.
|
|
70
|
+
*/
|
|
22
71
|
importManifest?(scope: string, key: string, manifest: Map<string, string>, srcGetBlob: (hash: string) => Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
|
|
72
|
+
/**
|
|
73
|
+
* 2c session-sync ([277]): STORE a single content-addressed blob — the symmetric WRITE side of {@link getBlob},
|
|
74
|
+
* for a two-phase PUSH (upload blobs, THEN import the manifest that references them). VERIFIES content-address
|
|
75
|
+
* integrity (`sha256(bytes) === hash`) so a corrupt/mismatched upload can never poison the store (a later
|
|
76
|
+
* getBlob/restore would otherwise return wrong content); a mismatch → `read_failed`, nothing stored. IMMUTABLE +
|
|
77
|
+
* content-addressed: a repeat putBlob for the same hash is a no-op (the bytes are identical by definition).
|
|
78
|
+
* Returns a {@link FileSnapshotResult} (NOT void) so the integrity failure is encodable under the never-throw
|
|
79
|
+
* contract. Optional — a backend that supports a two-phase push implements it.
|
|
80
|
+
*
|
|
81
|
+
* ⚠️ ORCHESTRATION CAVEAT: a pushed blob is NOT yet referenced by any manifest (the matching
|
|
82
|
+
* {@link importManifest} runs LATER), so — unlike `snapshot`/`importManifest`, which hold their blobs in an
|
|
83
|
+
* `inFlight` live-set across the whole store-then-commit — a `putBlob`'d blob is reap-ELIGIBLE in the window
|
|
84
|
+
* before its manifest is imported. The two-phase pusher MUST NOT `reap` the scope between PUT and import (a
|
|
85
|
+
* grace-window). This is fail-closed, not corrupting: blobs are content-addressed (re-push is always safe) and
|
|
86
|
+
* `importManifest` re-verifies+stores every blob before committing, so a reaped blob → `read_failed` with NO
|
|
87
|
+
* dangling-reference manifest, never wrong content.
|
|
88
|
+
*/
|
|
23
89
|
putBlob?(hash: string, bytes: Uint8Array): Promise<FileSnapshotResult>;
|
|
24
90
|
}
|
|
91
|
+
/** Bounds for the reference enumerator — a deliberate, fail-CLOSED cost policy (NOT the grep walk's silent caps). */
|
|
25
92
|
export interface FileSnapshotBounds {
|
|
93
|
+
/** Hard cap on file count; exceeding it REFUSES the snapshot (`too_large`) rather than silently truncating. */
|
|
26
94
|
maxFiles: number;
|
|
95
|
+
/** Hard cap on total bytes; exceeding it REFUSES the snapshot. */
|
|
27
96
|
maxBytes: number;
|
|
97
|
+
/** Directory BASENAMES skipped anywhere in the tree (cost bound). Default `.git` + `node_modules`. */
|
|
28
98
|
ignoreDirs: Set<string>;
|
|
29
99
|
}
|
|
30
100
|
export declare const DEFAULT_SNAPSHOT_BOUNDS: FileSnapshotBounds;
|
|
101
|
+
/**
|
|
102
|
+
* Capture the working tree under `root` into a manifest `relPath → sha256`, handing each file's bytes to
|
|
103
|
+
* `putBlob` (the backend stores them content-addressed). **The env-operating + security-critical half a durable
|
|
104
|
+
* backend MUST reuse** (not re-implement — duplication risks re-introducing the symlink-escape / fail-closed
|
|
105
|
+
* bugs the dual-review fixed). Fail-CLOSED: an enumerate/read/bound failure returns an error and the caller must
|
|
106
|
+
* NOT persist a partial manifest. Never throws.
|
|
107
|
+
*
|
|
108
|
+
* [789] vanished-file tolerance: a file that DISAPPEARED between enumerate and read (`not_found`) is OMITTED
|
|
109
|
+
* from the manifest instead of failing the whole capture. This is semantically SAFE — the E19 snapshot runs
|
|
110
|
+
* concurrently with a live tree (the `done` frame is emitted BEFORE the snapshot, so shell-side per-turn
|
|
111
|
+
* markers, `.git/index.lock`, editor swap files etc. legitimately vanish mid-walk), and omitting a
|
|
112
|
+
* just-deleted file yields the CONSISTENT tree state of one instant later — NOT a partial snapshot (which
|
|
113
|
+
* would mean "captured bytes are missing for a file that exists"). No re-stat second check is needed:
|
|
114
|
+
* `not_found` is a stable backend-independent FileErrorCode (locally the SOLE mapping of ENOENT,
|
|
115
|
+
* node-execution-env.ts toFileError) — the read itself IS the authoritative existence probe at capture time,
|
|
116
|
+
* and a re-stat would only re-open the same race one window later. Every OTHER read error (permission_denied/
|
|
117
|
+
* EIO/unknown…) and any enumerate failure keeps the fail-closed whole-capture rejection: those mean "the file
|
|
118
|
+
* is still there but we could not capture it" — omitting it WOULD be a data-lossy partial snapshot.
|
|
119
|
+
* `skippedVanished` reports the count for observability/tests.
|
|
120
|
+
*/
|
|
31
121
|
export declare function captureManifest(env: ExecutionEnv, root: string, bounds: FileSnapshotBounds, signal: AbortSignal | undefined, putBlob: (hash: string, bytes: Uint8Array) => void | Promise<void>): Promise<{
|
|
32
122
|
ok: true;
|
|
33
123
|
value: Map<string, string>;
|
|
@@ -36,7 +126,19 @@ export declare function captureManifest(env: ExecutionEnv, root: string, bounds:
|
|
|
36
126
|
ok: false;
|
|
37
127
|
error: FileSnapshotError;
|
|
38
128
|
}>;
|
|
129
|
+
/**
|
|
130
|
+
* CONVERGE the tree under `root` to `manifest`, loading each captured file's bytes via `getBlob`. **The
|
|
131
|
+
* env-operating + security-critical half a durable backend MUST reuse.** Order is load-bearing (codex BLOCKER +
|
|
132
|
+
* Opus M1): PHASE 1 removes every current symlink (neutralizes a `dir -> /outside` ancestor that writeFile would
|
|
133
|
+
* otherwise follow OUT of root) + every file created since; PHASE 2 writes each captured file, clearing a
|
|
134
|
+
* directory that now occupies a file's path first. Never throws.
|
|
135
|
+
*/
|
|
39
136
|
export declare function applyManifest(env: ExecutionEnv, root: string, bounds: FileSnapshotBounds, signal: AbortSignal | undefined, manifest: Map<string, string>, getBlob: (hash: string) => Uint8Array | undefined | Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
|
|
137
|
+
/**
|
|
138
|
+
* In-memory, content-addressed reference {@link FileSnapshotStore}. Blobs are deduplicated by sha256 ACROSS all
|
|
139
|
+
* snapshots (a file unchanged between turns is stored once); each snapshot keeps a manifest `relPath → hash`.
|
|
140
|
+
* Single-process (the default-deps reference; a durable/file-backed impl mirrors `src/stores/file/`).
|
|
141
|
+
*/
|
|
40
142
|
export declare class InMemoryFileSnapshotStore implements FileSnapshotStore {
|
|
41
143
|
private readonly blobs;
|
|
42
144
|
private readonly manifests;
|
|
@@ -53,6 +155,8 @@ export declare class InMemoryFileSnapshotStore implements FileSnapshotStore {
|
|
|
53
155
|
importManifest(scope: string, key: string, manifest: Map<string, string>, srcGetBlob: (hash: string) => Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
|
|
54
156
|
reap(scope: string, keepKeys: string[]): Promise<number>;
|
|
55
157
|
}
|
|
158
|
+
/** Test-only window (REF-C2 class pins): pure path helpers whose family-awareness carries a fence/
|
|
159
|
+
* restore invariant. Not re-exported from src/index.ts. */
|
|
56
160
|
export declare const __testables: {
|
|
57
161
|
joinUnder: typeof joinUnder;
|
|
58
162
|
relUnder: typeof relUnder;
|