@sema-agent/core 7.15.0 → 7.17.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 +202 -0
- package/dist/agents/builtin-agents.d.ts +3 -3
- package/dist/agents/cross-session-envelope.d.ts +0 -1
- package/dist/agents/cross-session-envelope.js +0 -1
- package/dist/agents/peer-notices.d.ts +0 -9
- package/dist/agents/peer-notices.js +0 -63
- package/dist/agents/subagent.js +7 -15
- package/dist/brain/request-params.d.ts +2 -2
- package/dist/config/defaults.d.ts +0 -7
- package/dist/config/defaults.js +0 -2
- package/dist/core/artifact-host.d.ts +218 -0
- package/dist/core/artifact-host.js +92 -0
- package/dist/core/ask-origin.d.ts +29 -3
- package/dist/core/ask-origin.js +17 -9
- package/dist/core/ask-question.d.ts +25 -0
- package/dist/core/ask-question.js +4 -0
- package/dist/core/ask-unresolvable-notice.d.ts +30 -21
- package/dist/core/ask-unresolvable-notice.js +16 -8
- package/dist/core/auto-compaction.d.ts +10 -10
- package/dist/core/auto-mode-arming.d.ts +2 -2
- package/dist/core/background-agent-store.d.ts +5 -5
- package/dist/core/background-shell.d.ts +1 -1
- package/dist/core/checkpoint-execution-record.d.ts +0 -3
- package/dist/core/checkpoint-execution-record.js +0 -4
- package/dist/core/checkpoint-store.d.ts +71 -99
- package/dist/core/checkpoint-store.js +9 -16
- package/dist/core/context-edit.d.ts +36 -104
- package/dist/core/context-edit.js +37 -60
- package/dist/core/effective-path-target.d.ts +68 -8
- package/dist/core/effective-path-target.js +42 -30
- package/dist/core/engine-notice.d.ts +46 -32
- package/dist/core/env-budget.d.ts +31 -0
- package/dist/core/env-budget.js +39 -0
- package/dist/core/exec-output-tail.d.ts +5 -5
- package/dist/core/file-history-store.js +3 -6
- package/dist/core/fs-write-gate-policy.d.ts +1 -1
- package/dist/core/fs-write-gate-policy.js +3 -3
- package/dist/core/gate-lanes.js +9 -15
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +4 -0
- package/dist/core/hands-band.d.ts +1 -1
- package/dist/core/hooks.d.ts +18 -17
- package/dist/core/lsp-session.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/lsp.js +5 -4
- package/dist/core/mcp.d.ts +5 -5
- package/dist/core/mcp.js +4 -48
- package/dist/core/memory-engine/delegation-settlement.d.ts +37 -12
- package/dist/core/memory-engine/delegation-settlement.js +128 -39
- package/dist/core/memory-engine/engine.d.ts +9 -8
- package/dist/core/memory-engine/engine.js +115 -120
- package/dist/core/memory-engine/file-backend.d.ts +17 -5
- package/dist/core/memory-engine/file-backend.js +78 -34
- package/dist/core/memory-engine/index.d.ts +2 -2
- package/dist/core/memory-engine/index.js +2 -2
- package/dist/core/memory-engine/layout.d.ts +152 -54
- package/dist/core/memory-engine/layout.js +441 -104
- package/dist/core/memory-engine/types.d.ts +8 -3
- package/dist/core/memory-engine/types.js +5 -0
- package/dist/core/memory-recall.d.ts +0 -8
- package/dist/core/memory.d.ts +1 -1
- package/dist/core/oracle-isolation.js +2 -2
- package/dist/core/parent-spec-seat.d.ts +66 -0
- package/dist/core/parent-spec-seat.js +47 -0
- package/dist/core/permission-rule-model.d.ts +11 -6
- package/dist/core/permission-rule-model.js +53 -37
- package/dist/core/permission-rules.js +8 -3
- package/dist/core/protocol-naming.d.ts +2 -2
- package/dist/core/remote-env.d.ts +1 -1
- package/dist/core/retired-keys.d.ts +19 -0
- package/dist/core/retired-keys.js +15 -0
- package/dist/core/runner/abort-race.d.ts +3 -3
- package/dist/core/runner/active-skill-scope.d.ts +2 -2
- package/dist/core/runner/active-skill-scope.js +3 -3
- package/dist/core/runner/assemble-result.d.ts +42 -40
- package/dist/core/runner/assemble-result.js +5 -4
- package/dist/core/runner/checkpoint-scope.d.ts +4 -4
- package/dist/core/runner/clock-and-limits.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.d.ts +35 -99
- package/dist/core/runner/compaction-knobs.d.ts +4 -4
- package/dist/core/runner/compaction-seams.d.ts +5 -5
- package/dist/core/runner/contracts.d.ts +232 -233
- package/dist/core/runner/decide-continuation.d.ts +6 -6
- package/dist/core/runner/denial-limit-arms.d.ts +8 -8
- package/dist/core/runner/derived-route-fallback.d.ts +2 -2
- package/dist/core/runner/gate-exit.d.ts +6 -6
- package/dist/core/runner/gate-exit.js +15 -1
- package/dist/core/runner/git-status-frame.d.ts +7 -7
- package/dist/core/runner/halt-attribution.d.ts +35 -0
- package/dist/core/runner/halt-attribution.js +16 -0
- package/dist/core/runner/inherited-ask-grants.d.ts +6 -6
- package/dist/core/runner/memory-capture-optout.d.ts +1 -1
- package/dist/core/runner/memory-consolidation-driver.d.ts +4 -4
- package/dist/core/runner/memory-consolidation.d.ts +6 -8
- package/dist/core/runner/memory-consolidation.js +0 -1
- package/dist/core/runner/park-commit.d.ts +6 -6
- package/dist/core/runner/permission-rule-lanes.d.ts +19 -19
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +4 -4
- package/dist/core/runner/prepare-artifact.d.ts +53 -0
- package/dist/core/runner/prepare-artifact.js +77 -0
- package/dist/core/runner/prepare-ask-lane.d.ts +3 -3
- package/dist/core/runner/prepare-boundary-parks.d.ts +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +9 -7
- package/dist/core/runner/prepare-caps-and-workflow.js +2 -3
- package/dist/core/runner/prepare-config-doors.d.ts +24 -24
- package/dist/core/runner/prepare-config-doors.js +5 -2
- package/dist/core/runner/prepare-context-lane.d.ts +8 -8
- package/dist/core/runner/prepare-context-lane.js +2 -13
- package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
- package/dist/core/runner/prepare-file-history.d.ts +3 -3
- package/dist/core/runner/prepare-file-history.js +3 -52
- package/dist/core/runner/prepare-gate-stations.d.ts +5 -5
- package/dist/core/runner/prepare-hands-readface.d.ts +35 -38
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +9 -6
- package/dist/core/runner/prepare-inherited-gate.js +7 -8
- package/dist/core/runner/prepare-listings.d.ts +3 -3
- package/dist/core/runner/prepare-lsp.d.ts +3 -3
- package/dist/core/runner/prepare-memory-engine-session.d.ts +5 -5
- package/dist/core/runner/prepare-memory.d.ts +4 -6
- package/dist/core/runner/prepare-memory.js +10 -9
- package/dist/core/runner/prepare-offload-wrappers.d.ts +2 -2
- package/dist/core/runner/prepare-park-ask.d.ts +6 -6
- package/dist/core/runner/prepare-policy-chain.d.ts +7 -7
- package/dist/core/runner/prepare-policy-chain.js +15 -30
- package/dist/core/runner/prepare-prompt-assembly.js +1 -1
- package/dist/core/runner/prepare-prompt-inputs.d.ts +5 -5
- package/dist/core/runner/prepare-protocol-tools.d.ts +1 -1
- package/dist/core/runner/prepare-question-face.d.ts +4 -4
- package/dist/core/runner/prepare-run-refs.d.ts +11 -11
- package/dist/core/runner/prepare-safety-scan.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +4 -4
- package/dist/core/runner/prepare-suspend-saga.js +0 -2
- package/dist/core/runner/prepare-task.d.ts +12 -12
- package/dist/core/runner/prepare-task.js +10 -9
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +2 -3
- package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -4
- package/dist/core/runner/prepare-wiring-manifest.js +9 -7
- package/dist/core/runner/prepare-workspace-restore.d.ts +1 -1
- package/dist/core/runner/remote-env-retry.d.ts +3 -3
- package/dist/core/runner/resume-admission.d.ts +1 -1
- package/dist/core/runner/resume-admission.js +2 -1
- package/dist/core/runner/resume-claim.d.ts +1 -1
- package/dist/core/runner/resume-internals-and-config.d.ts +1 -1
- package/dist/core/runner/resume-internals-and-config.js +4 -0
- package/dist/core/runner/resume-policy-outcome.d.ts +1 -1
- package/dist/core/runner/resume-preflight.d.ts +1 -1
- package/dist/core/runner/resume-review-outcome.d.ts +1 -1
- package/dist/core/runner/retired-runner-deps.d.ts +3 -0
- package/dist/core/runner/retired-runner-deps.js +7 -0
- package/dist/core/runner/run-brain-sinks.d.ts +1 -1
- package/dist/core/runner/run-clock-and-content.d.ts +4 -4
- package/dist/core/runner/run-compaction-machinery.d.ts +3 -3
- package/dist/core/runner/run-git-lane.d.ts +1 -1
- package/dist/core/runner/run-harness-handlers.d.ts +2 -2
- package/dist/core/runner/run-harness-handlers.js +2 -3
- package/dist/core/runner/run-identity-wiring.d.ts +4 -4
- package/dist/core/runner/run-leg.d.ts +3 -3
- package/dist/core/runner/run-notification-lane.d.ts +2 -2
- package/dist/core/runner/run-reasoning-seat.d.ts +2 -2
- package/dist/core/runner/run-settle-and-teardown.d.ts +5 -5
- package/dist/core/runner/run-settle-and-teardown.js +3 -1
- package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +2 -2
- package/dist/core/runner/run-terminal-adoption.d.ts +5 -5
- package/dist/core/runner/runtask.d.ts +14 -14
- package/dist/core/runner/session-file-state-replay.d.ts +3 -3
- package/dist/core/runner/session-file-state-replay.js +3 -3
- package/dist/core/runner/session-rule-policy.d.ts +2 -2
- package/dist/core/runner/session-rule-policy.js +3 -4
- package/dist/core/runner/steer-admission.d.ts +2 -2
- package/dist/core/runner/stream-halt-verbs.d.ts +1 -1
- package/dist/core/runner/stream-halt-verbs.js +1 -1
- package/dist/core/runner/stream-reap.d.ts +1 -1
- package/dist/core/runner/stream-steer-verb.js +1 -4
- package/dist/core/runner/synthetic-tools.d.ts +8 -8
- package/dist/core/runner/teardown-bounded.d.ts +2 -2
- package/dist/core/runner/tool-defer-gate.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.d.ts +33 -33
- package/dist/core/runner/tool-end-body.d.ts +3 -3
- package/dist/core/runner/tool-face-overlay.d.ts +2 -2
- package/dist/core/runner/tool-output-projection.d.ts +2 -2
- package/dist/core/runner/turn-attachments.d.ts +53 -53
- package/dist/core/runner/usage-accounting.d.ts +4 -4
- package/dist/core/runner/workspace-path.d.ts +1 -1
- package/dist/core/runner/workspace-path.js +3 -0
- package/dist/core/runner-deps.d.ts +30 -49
- package/dist/core/safe-notify.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/sensitive-path-policy.js +4 -4
- package/dist/core/session.d.ts +2 -2
- package/dist/core/skill-tool-specifier.d.ts +1 -1
- package/dist/core/skills-directory.d.ts +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/strategy-store.d.ts +8 -11
- package/dist/core/task-event.d.ts +20 -17
- package/dist/core/task-limits.d.ts +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +5 -5
- package/dist/core/task-registry-monitor.d.ts +2 -2
- package/dist/core/task-registry-shared.d.ts +27 -27
- package/dist/core/task-registry-shared.js +3 -13
- package/dist/core/task-registry.d.ts +8 -8
- package/dist/core/task-result.d.ts +37 -37
- package/dist/core/task-spec.d.ts +5 -5
- package/dist/core/task-stream.d.ts +16 -11
- package/dist/core/tool-catalog-entries.d.ts +1 -0
- package/dist/core/tool-catalog-entries.js +5 -0
- package/dist/core/tool-conformance.d.ts +0 -2
- package/dist/core/tool-conformance.js +1 -3
- package/dist/core/tool-errors.d.ts +5 -0
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +51 -22
- package/dist/core/tool-policy.js +28 -5
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +11 -11
- package/dist/core/tool-spec.d.ts +34 -38
- package/dist/core/tools.d.ts +2 -2
- package/dist/core/trace.d.ts +12 -15
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +4 -3
- package/dist/core/workflow-journal-store.d.ts +11 -11
- package/dist/engine/execution-env/node-execution-env.d.ts +3 -2
- package/dist/engine/execution-env/node-execution-env.js +4 -2
- package/dist/engine/harness/agent-harness.d.ts +47 -4
- package/dist/engine/harness/agent-harness.js +52 -9
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +15 -8
- package/dist/engine/loop/types.d.ts +5 -0
- package/dist/index.d.ts +21 -16
- package/dist/index.js +17 -12
- package/dist/internal/harness.d.ts +1 -0
- package/dist/orchestration/run-spec.d.ts +3 -0
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +12 -6
- package/dist/orchestration/run-workflow-tool.js +23 -5
- package/dist/orchestration/workflow-primitives.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +1 -4
- package/dist/orchestration/workflow-types.d.ts +34 -4
- package/dist/orchestration/workflow-types.js +2 -0
- package/dist/orchestration/workflow.d.ts +39 -7
- package/dist/orchestration/workflow.js +234 -113
- package/dist/prompt-assembly/assemble.d.ts +2 -2
- package/dist/prompt-assembly/assemble.js +9 -9
- package/dist/prompt-assembly/composer.d.ts +6 -7
- package/dist/prompt-assembly/composer.js +10 -10
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.d.ts +0 -21
- package/dist/prompt-assembly/packs/sema-default.js +30 -30
- package/dist/prompt-assembly/types.d.ts +14 -14
- package/dist/prompts/coordinator.d.ts +0 -13
- package/dist/prompts/coordinator.js +0 -3
- package/dist/stores/file/checkpoint-store.js +1 -5
- package/dist/stores/file/file-history-store.js +2 -2
- package/dist/stores/file/permission-rule-store.d.ts +4 -35
- package/dist/stores/file/permission-rule-store.js +4 -148
- package/dist/tools/artifact/artifact-text.d.ts +62 -0
- package/dist/tools/artifact/artifact-text.js +68 -0
- package/dist/tools/artifact/artifact-tool.d.ts +52 -0
- package/dist/tools/artifact/artifact-tool.js +351 -0
- package/dist/tools/artifact/local-stub.d.ts +26 -0
- package/dist/tools/artifact/local-stub.js +296 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +114 -48
- package/dist/tools/fs/bash-readonly-classifier.js +171 -60
- package/dist/tools/fs/encoding.d.ts +31 -40
- package/dist/tools/fs/fs-bash.d.ts +49 -45
- package/dist/tools/fs/fs-bash.js +19 -27
- package/dist/tools/fs/fs-pdf.d.ts +8 -8
- package/dist/tools/fs/fs-search-tools.d.ts +4 -4
- package/dist/tools/fs/fs-search-tools.js +5 -2
- package/dist/tools/fs/fs-shared.d.ts +146 -158
- package/dist/tools/fs/fs-shared.js +3 -11
- package/dist/tools/fs/fs-write.d.ts +8 -8
- package/dist/tools/fs/gh-rate-limit.d.ts +13 -14
- package/dist/tools/fs/index.d.ts +78 -78
- package/dist/tools/fs/index.js +4 -1
- package/dist/tools/fs/notebook.d.ts +24 -25
- package/dist/tools/fs/pdf.d.ts +3 -3
- package/dist/tools/fs/read-deny.d.ts +22 -22
- package/dist/tools/fs/read-face.d.ts +21 -24
- package/dist/tools/fs/repo-map.d.ts +8 -8
- package/dist/tools/fs/safety.d.ts +233 -130
- package/dist/tools/fs/safety.js +131 -31
- package/dist/tools/fs/search.d.ts +63 -71
- package/dist/tools/fs/search.js +8 -6
- package/package.json +6 -2
- package/test/export-surface.snapshot.json +119 -39
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
2
|
import { protectivePathTargetOf, type ToolCallLike } from "../../core/tool-registry.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* CC parity: Read/Edit/Write take the file path as `file_path`. Read the target the same way
|
|
5
5
|
* EVERYWHERE the path is consumed from a tool-call's args — not just the tool body but ALSO every gate that
|
|
6
6
|
* extracts the write target to confine it (sensitive-path, skill allowPaths, session allowDirs). A gate that only
|
|
7
7
|
* read `args.path` would see `undefined` for a `file_path` call and either fail-OPEN (circumvent the guard — a real
|
|
8
8
|
* hole) or fail-closed (deny a legitimate write). Single source.
|
|
9
9
|
*
|
|
10
|
-
* The `path` arm is deliberately BROADER than what Read/Edit/Write accept
|
|
10
|
+
* The `path` arm is deliberately BROADER than what Read/Edit/Write accept: their schema requires
|
|
11
11
|
* `file_path` and rejects the retired `path` alias outright (fs-shared.ts FILE_PATH_PARAMS), but this reader is
|
|
12
12
|
* shared with gates that judge OTHER tool vocabularies — Glob's real `path` parameter, deployment-authored tools —
|
|
13
13
|
* and a gate must never see LESS than the tool it is confining might act on. So the asymmetry is the design: the
|
|
@@ -15,8 +15,8 @@ import { protectivePathTargetOf, type ToolCallLike } from "../../core/tool-regis
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function fileArgPath(args: unknown): string | undefined;
|
|
17
17
|
/**
|
|
18
|
-
* The WRITE TARGET of a path-confinable write call, tool-aware
|
|
19
|
-
*
|
|
18
|
+
* The WRITE TARGET of a path-confinable write call, tool-aware — single source for every gate that
|
|
19
|
+
* confines a write target, same discipline as {@link fileArgPath} above:
|
|
20
20
|
*
|
|
21
21
|
* · canonical `NotebookEdit` → `notebook_path` FIRST, `file_path`/`path` only as fallback. The tool
|
|
22
22
|
* itself writes `notebook_path`; its schema tolerates extra keys, so a stray/decoy `file_path` on a
|
|
@@ -25,30 +25,30 @@ export declare function fileArgPath(args: unknown): string | undefined;
|
|
|
25
25
|
* · every other tool → `file_path`/`path` first ({@link fileArgPath}), `notebook_path` as the
|
|
26
26
|
* historical fallback (unchanged behavior for the pre-existing gate callers).
|
|
27
27
|
*
|
|
28
|
-
* `canonicalName` is the tool name as mounted
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* `canonicalName` is the tool name as mounted, raw: there is no legacy normalizer, and this module
|
|
29
|
+
* stays dependency-free of the alias table — "NotebookEdit" is the canonical CC name and old→new
|
|
30
|
+
* normalization is identity for it.
|
|
31
31
|
*/
|
|
32
32
|
export declare function writeTargetPath(call: ToolCallLike, pt?: ReturnType<typeof protectivePathTargetOf>): string | undefined;
|
|
33
33
|
/**
|
|
34
|
-
* The "hand" file tools
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* this dir compose it. Per-task state and the execution env are passed in (factory-closure wiring,
|
|
38
|
-
*
|
|
34
|
+
* The "hand" file tools' safety invariants, ported from CC's `FileEditTool`: without these a weak
|
|
35
|
+
* model blind-edits / overwrites files (a safety property, not polish). This module is the
|
|
36
|
+
* pure/testable core (path resolution + the three edit invariants + content hashing); the tools in
|
|
37
|
+
* this dir compose it. Per-task state and the execution env are passed in (factory-closure wiring),
|
|
38
|
+
* never read from a shared/global.
|
|
39
39
|
*/
|
|
40
|
-
/** What we remember about a file the agent has read
|
|
40
|
+
/** What we remember about a file the agent has read. */
|
|
41
41
|
export interface ReadEntry {
|
|
42
42
|
/** SHA-256 of the content at read time. Staleness is detected by content hash, NOT mtime — mtime is
|
|
43
|
-
* unreliable across containers/volumes/NFS and across a
|
|
43
|
+
* unreliable across containers/volumes/NFS and across a suspend→resume on another replica. */
|
|
44
44
|
hash: string;
|
|
45
|
-
/** Total line count at read time, and whether the read was truncated (for the edit truncation hint
|
|
45
|
+
/** Total line count at read time, and whether the read was truncated (for the edit truncation hint). */
|
|
46
46
|
totalLines: number;
|
|
47
47
|
truncated: boolean;
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
48
|
+
/** CC `isPartialView` parity: set ONLY when the auto-pagination branch fires — the model asked for
|
|
49
|
+
* the file by DEFAULT (no explicit offset/limit) and the token cap truncated it anyway. An EXPLICIT
|
|
50
|
+
* offset/limit slice that fits under the cap is NEVER marked this way, even though it is equally
|
|
51
|
+
* "not the whole file". Deliberately narrower than {@link truncated} above,
|
|
52
52
|
* which also fires for a fully-intentional, successful slice read (`start>1 || end<total`) — folding
|
|
53
53
|
* THIS flag into that broader one would make {@link OVERSIZE_READ_ESCAPE_HINT}'s documented promise
|
|
54
54
|
* ("read it in slices with explicit offset/limit to satisfy the read-first rule") false: a model paging
|
|
@@ -56,51 +56,50 @@ export interface ReadEntry {
|
|
|
56
56
|
* additive: undefined on every non-Read write-back (Write/Edit re-record the file they just fully wrote)
|
|
57
57
|
* and on every seeded/attachment entry — those are never partial by construction. */
|
|
58
58
|
isPartialView?: boolean;
|
|
59
|
-
/** The line window actually served to the model on the last read (
|
|
59
|
+
/** The line window actually served to the model on the last read (the dedup stub's key). Lets
|
|
60
60
|
* read_file return a `file_unchanged` stub when the SAME window is re-requested and the content hash is
|
|
61
61
|
* unchanged — saving the re-transmitted body. Optional/additive: undefined (e.g. an entry seeded from an
|
|
62
|
-
* older
|
|
62
|
+
* older checkpoint) just means "no dedup", never a false hit. */
|
|
63
63
|
view?: {
|
|
64
64
|
start: number;
|
|
65
65
|
end: number;
|
|
66
66
|
};
|
|
67
|
-
/** Millisecond timestamp of the last read/write-back that recorded this entry
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* seeded from an older checkpoint) sorts last, never breaks. */
|
|
67
|
+
/** Millisecond timestamp of the last read/write-back that recorded this entry: the post-compaction
|
|
68
|
+
* attachment picks the most RECENTLY read files, the way CC sorts readFileState by timestamp.
|
|
69
|
+
* Optional/additive: undefined (an entry seeded from an older checkpoint) sorts last, never breaks. */
|
|
71
70
|
lastReadAt?: number;
|
|
72
|
-
/** CC 2.1.204 parity
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
71
|
+
/** CC 2.1.204 parity: TRUE when the Runner pre-seeded this entry because the file's FULL
|
|
72
|
+
* disk-verbatim text was injected into the model's context at startup
|
|
73
|
+
* (ProjectMemoryLoad.seededFiles — CC's own memory preload). A DEFAULT whole-file Read of an
|
|
74
|
+
* UNCHANGED seeded file
|
|
76
75
|
* answers with the already-in-context reminder instead of re-transmitting the body. Any real
|
|
77
76
|
* Read / edit write-back records a FRESH entry without this flag, so a file that changed on
|
|
78
77
|
* disk (hash mismatch) always serves real content and the dedup disarms permanently.
|
|
79
78
|
* Optional/additive: absent = normal entry. */
|
|
80
79
|
seededFromContext?: boolean;
|
|
81
80
|
}
|
|
82
|
-
/** Per-task record of which files have been read, keyed by canonical path
|
|
83
|
-
*
|
|
81
|
+
/** Per-task record of which files have been read, keyed by canonical path: owned by prepare-task,
|
|
82
|
+
* closure-captured by the tools, and serialized into the durable checkpoint. */
|
|
84
83
|
export type ReadFileState = Map<string, ReadEntry>;
|
|
85
|
-
/** SHA-256 hex of UTF-8 content — the staleness/identity key
|
|
84
|
+
/** SHA-256 hex of UTF-8 content — the staleness/identity key. */
|
|
86
85
|
export declare function sha256(content: string): string;
|
|
87
86
|
/** A failed path resolution / invariant check, surfaced to the model as a self-correctable tool error. */
|
|
88
87
|
export interface FsViolation {
|
|
89
88
|
code: "path_not_in_root" | "not_read" | "stale" | "ambiguous_edit" | "invalid" | "read_path_denied";
|
|
90
|
-
/**
|
|
89
|
+
/** Set on the `not_read` violation raised by an AUTO-TRUNCATED read
|
|
91
90
|
* ({@link ReadEntry.isPartialView}) rather than by a never-read file. Both carry the same CC-verbatim
|
|
92
91
|
* message; only this one needs {@link PARTIAL_VIEW_READ_ESCAPE_HINT} appended, because for it a plain
|
|
93
92
|
* re-read is a fixpoint. */
|
|
94
93
|
partialView?: true;
|
|
95
|
-
/**
|
|
94
|
+
/** Set on `path_not_in_root` and `read_path_denied` — the CANONICAL key the
|
|
96
95
|
* refused path resolved to (symlinks followed, tracked cwd applied), i.e. the value the fence
|
|
97
96
|
* actually judged. Rides into the tool result's `details` (see {@link violationDetails}) so a
|
|
98
97
|
* consumer can count/aggregate boundary refusals from fields instead of regexing the prose. */
|
|
99
98
|
target?: string;
|
|
100
|
-
/**
|
|
99
|
+
/** Set ONLY on `path_not_in_root` — the containment roots in effect (primary first,
|
|
101
100
|
* then additionalDirectories), canonical form. */
|
|
102
101
|
roots?: readonly string[];
|
|
103
|
-
/**
|
|
102
|
+
/** Set ONLY on `read_path_denied` — the deny-list pattern (verbatim entry text)
|
|
104
103
|
* the judged target matched. */
|
|
105
104
|
pattern?: string;
|
|
106
105
|
message: string;
|
|
@@ -108,21 +107,17 @@ export interface FsViolation {
|
|
|
108
107
|
/**
|
|
109
108
|
* Absolute in EITHER family: POSIX `/…` or drive-letter `C:\…`/`C:/…`.
|
|
110
109
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* carried a comment claiming the same philosophy as this file while keeping their own copy. The
|
|
115
|
-
* failure mode is not the duplication itself but the drift it invites: a family added at one
|
|
116
|
-
* coordinate leaves the other eight judging the same string differently, and this predicate gates a
|
|
110
|
+
* This is the ONE definition of "already absolute, therefore do not prepend a base". The failure mode
|
|
111
|
+
* of a private re-typing is not the duplication but the drift it invites: a family added at one
|
|
112
|
+
* coordinate leaves every other copy judging the same string differently, and this predicate gates a
|
|
117
113
|
* security fence (frozen-path deny, readonly-boundary containment) as well as URI key minting.
|
|
118
114
|
* Callers that need a family the predicate does not cover must widen it HERE, not locally.
|
|
119
115
|
*
|
|
120
|
-
* The UNC arm (`\\host\share\…`)
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* POSIX/drive root, i.e. it is a location the working directory does not contain.
|
|
116
|
+
* The UNC arm (`\\host\share\…`) is the shape that drift produced: held privately in one consumer, it
|
|
117
|
+
* made that consumer resolve a UNC path as absolute while a sibling prefixed it with the task root —
|
|
118
|
+
* two URI keys for one file. Folding it in here settles the disagreement in the direction the rest of
|
|
119
|
+
* this file takes: a literal `\\host\share\…` is win-form (see {@link isWinFormPath}) and `within()`
|
|
120
|
+
* lands it outside every POSIX/drive root, i.e. a location the working directory does not contain.
|
|
126
121
|
*/
|
|
127
122
|
export declare function isAbsolutePathForm(p: string): boolean;
|
|
128
123
|
/**
|
|
@@ -133,10 +128,10 @@ export declare function isAbsolutePathForm(p: string): boolean;
|
|
|
133
128
|
* contains a literal backslash (legal on POSIX), and `//host/share` is therefore POSIX-form too — which is
|
|
134
129
|
* the whole point: on POSIX that spelling is an ordinary absolute path, not a network share.
|
|
135
130
|
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
131
|
+
* This is the ONE definition of the win-family spelling; core/file-snapshot-store.ts conditions its
|
|
132
|
+
* manifest key / restore-target folds on this import rather than a private twin. core/ already depends
|
|
133
|
+
* on this module elsewhere, and this file's own imports are `node:crypto` plus a type, so there is no
|
|
134
|
+
* layering wall between them.
|
|
140
135
|
*/
|
|
141
136
|
export declare function isWinFormPath(p: string): boolean;
|
|
142
137
|
/**
|
|
@@ -153,7 +148,7 @@ export declare function isWinFormPath(p: string): boolean;
|
|
|
153
148
|
export declare function expandHomeTilde(p: string, home: string): string;
|
|
154
149
|
export declare function isBlockedDevicePath(key: string): boolean;
|
|
155
150
|
/**
|
|
156
|
-
*
|
|
151
|
+
* Purely LEXICAL path normalization: collapse repeated separators, drop `.` segments, and
|
|
157
152
|
* resolve `..` against the preceding segment. No filesystem access, no cwd: this is a spelling
|
|
158
153
|
* normalizer, not a resolver. (Deliberately NOT `canonicalizeNewPath`'s job — that one walks the real
|
|
159
154
|
* filesystem precisely because folding `..` lexically across a SYMLINKED parent is unsound. Use this one
|
|
@@ -164,9 +159,8 @@ export declare function isBlockedDevicePath(key: string): boolean;
|
|
|
164
159
|
* three different ways. Callers that match a device list against a raw argument must normalize first or
|
|
165
160
|
* the list is a spelling filter rather than a device filter.
|
|
166
161
|
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* covered between them is now the contract here:
|
|
162
|
+
* Coverage — the union of every fold the callers need, held once here rather than re-implemented per
|
|
163
|
+
* consumer:
|
|
170
164
|
* · POSIX absolute — `/a/./b` → `/a/b`; `/..` is `/`, matching the kernel.
|
|
171
165
|
* · drive-letter (`C:\a\..\b`) and UNC (`\\host\share\..\x`) — prefix preserved, folding applies
|
|
172
166
|
* to the tail only, and the REJOIN uses the path's own native separator so one file cannot acquire
|
|
@@ -175,14 +169,14 @@ export declare function isBlockedDevicePath(key: string): boolean;
|
|
|
175
169
|
* `dev/zero` under some other directory is an ordinary file), and a leading `..` is KEPT rather than
|
|
176
170
|
* popped into nothing — dropping it would move the path.
|
|
177
171
|
*
|
|
178
|
-
* FAMILY-awareness is the
|
|
179
|
-
* win-form path; in a POSIX path it is an ordinary filename character, and
|
|
180
|
-
*
|
|
181
|
-
*
|
|
172
|
+
* FAMILY-awareness is the part a private copy tends to get wrong. A backslash is a separator only in a
|
|
173
|
+
* win-form path; in a POSIX path it is an ordinary filename character, and an unconditional `\`→`/`
|
|
174
|
+
* fold rewrites a POSIX file literally named `a\..\b` into a different location before the boundary
|
|
175
|
+
* check ever sees it — in both directions: false refusal and false allow.
|
|
182
176
|
*/
|
|
183
177
|
export declare function normalizeAbsPathLexically(p: string): string;
|
|
184
178
|
/**
|
|
185
|
-
* The READ-leg fold
|
|
179
|
+
* The READ-leg fold: removes `.` segments and duplicate
|
|
186
180
|
* separators ONLY — transformations that name the SAME file on every real filesystem, symlinks
|
|
187
181
|
* included. `..` is deliberately KEPT: `a/../x` and `x` are different files when `a` is a symlink,
|
|
188
182
|
* and this function's callers go on to OPEN the result (fileInfo/readText), not just to mint a
|
|
@@ -197,7 +191,7 @@ export declare function hasBinaryExtension(path: string): boolean;
|
|
|
197
191
|
export declare function imageMimeForRead(path: string): string | undefined;
|
|
198
192
|
/** Verify the raw bytes actually ARE the image format the extension claims (magic-number sniff). Extension alone
|
|
199
193
|
* is forgeable: a `.png` holding text / an empty file / a truncated blob would otherwise become a malformed
|
|
200
|
-
* `ImageContent` that makes the NEXT provider request fail (400). Pure — no I/O.
|
|
194
|
+
* `ImageContent` that makes the NEXT provider request fail (400). Pure — no I/O. */
|
|
201
195
|
export declare function imageMagicMatches(bytes: Uint8Array, mimeType: string): boolean;
|
|
202
196
|
/** One contiguous byte pattern that must appear at a fixed offset for its signature to match. */
|
|
203
197
|
export interface BinaryMagicSegment {
|
|
@@ -216,11 +210,11 @@ export interface BinaryMagicSignature {
|
|
|
216
210
|
readonly segments: readonly BinaryMagicSegment[];
|
|
217
211
|
}
|
|
218
212
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* (
|
|
222
|
-
*
|
|
223
|
-
*
|
|
213
|
+
* Magic-byte criteria for the formats {@link hasBinaryExtension} names. That list carries 103
|
|
214
|
+
* extensions; without this table only PDF (`pdfMagicMatches`, in the PDF lane) and the four API image
|
|
215
|
+
* formats ({@link imageMagicMatches}) have a content criterion, so for every other listed format the
|
|
216
|
+
* NAME is the only evidence available. Where the content IS reachable that leaves identification to
|
|
217
|
+
* the statistical fallback ({@link isBinaryContent}),
|
|
224
218
|
* which samples the first 8192 decoded characters and passes anything whose control-character ratio
|
|
225
219
|
* stays under 10% — a short archive/executable header followed by printable payload clears that bar
|
|
226
220
|
* and gets delivered as text.
|
|
@@ -249,36 +243,147 @@ export declare const BINARY_MAGIC_SIGNATURES: readonly BinaryMagicSignature[];
|
|
|
249
243
|
*/
|
|
250
244
|
export declare function binaryMagicFormat(bytes: Uint8Array): string | undefined;
|
|
251
245
|
/**
|
|
252
|
-
* Content sniff for binary data (
|
|
246
|
+
* Content sniff for binary data (CC `isBinaryContent` parity): a NUL byte,
|
|
253
247
|
* or more than 10% non-printable characters in the sample, means binary. Second layer behind
|
|
254
248
|
* {@link hasBinaryExtension} — catches extension-less or mis-named binaries (a `Dockerfile` that is really
|
|
255
249
|
* a compiled blob) that would otherwise be read as mojibake. Plain text (incl. UTF-8, tabs/newlines) passes.
|
|
256
250
|
*/
|
|
257
251
|
export declare function isBinaryContent(sample: string): boolean;
|
|
258
252
|
/**
|
|
259
|
-
* CC's own UNC/network-path predicate, verbatim (
|
|
260
|
-
* `n.startsWith("\\\\") || n.startsWith("//")`). Pure.
|
|
253
|
+
* CC's own UNC/network-path predicate, verbatim (`n.startsWith("\\\\") || n.startsWith("//")`). Pure.
|
|
261
254
|
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* This function stays a pure spelling test with no verdict of its own.
|
|
255
|
+
* In CC this test is an EARLY ALLOW — it skips the binary-extension and device checks that follow it —
|
|
256
|
+
* and CC applies it to the NORMALIZED path, not the raw argument. See {@link canonicalizeTarget} for
|
|
257
|
+
* how sema mirrors that and for the two deliberate differences. This function stays a pure spelling
|
|
258
|
+
* test with no verdict of its own.
|
|
267
259
|
*/
|
|
268
260
|
export declare function isUncPath(path: string): boolean;
|
|
269
|
-
/**
|
|
270
|
-
*
|
|
271
|
-
|
|
261
|
+
/** The two spelling families a tree can be in. Read from the ROOT's spelling (the cwd's when a deployment
|
|
262
|
+
* supplies no root) — never from `process.platform`: the exec env may be remote and of the other family. */
|
|
263
|
+
export type PathFamily = "win" | "posix";
|
|
264
|
+
/** The family of a call's tree; `undefined` when the call declares neither root nor cwd (a treeless call
|
|
265
|
+
* gets no family invented for it — see {@link pathIdentityOf} for what it can still read). */
|
|
266
|
+
export declare function pathFamilyOf(bases: {
|
|
267
|
+
readonly root: string;
|
|
268
|
+
readonly cwd?: string | undefined;
|
|
269
|
+
}): PathFamily;
|
|
270
|
+
export declare function pathFamilyOf(bases: {
|
|
271
|
+
readonly root?: string | undefined;
|
|
272
|
+
readonly cwd: string;
|
|
273
|
+
}): PathFamily;
|
|
274
|
+
export declare function pathFamilyOf(bases: {
|
|
275
|
+
readonly root?: string | undefined;
|
|
276
|
+
readonly cwd?: string | undefined;
|
|
277
|
+
}): PathFamily | undefined;
|
|
278
|
+
/**
|
|
279
|
+
* FULLY QUALIFIED under the family. win: drive-rooted (`C:\`/`C:/`) or UNC — a `/x` / `\x` is rooted-not-
|
|
280
|
+
* qualified and joins the base's drive or share root ({@link joinForFamily}), a `C:rel` is drive-relative.
|
|
281
|
+
* posix: `/`-rooted. `undefined` (a treeless call): only the anchor-free `/`-rooted form, the one spelling
|
|
282
|
+
* that names a file without a tree.
|
|
283
|
+
*/
|
|
284
|
+
export declare function isAbsoluteForFamily(family: PathFamily | undefined, p: string): boolean;
|
|
285
|
+
/** The refusal words of {@link win32NamespaceScreen} — a closed set (docs/CLOSED-SETS.md). */
|
|
286
|
+
export declare const WIN32_NAMESPACE_REFUSALS: readonly ["device_namespace", "unmappable_namespace", "unc_on_posix_tree", "drive_relative"];
|
|
287
|
+
export type Win32NamespaceRefusal = (typeof WIN32_NAMESPACE_REFUSALS)[number];
|
|
288
|
+
/** What each refusal word says about the spelling (the message clause after `path "…" `). */
|
|
289
|
+
export declare const WIN32_NAMESPACE_REFUSAL_TEXT: {
|
|
290
|
+
readonly device_namespace: "is a Win32 device-namespace path (\\\\.\\ names a raw device object, not a file)";
|
|
291
|
+
readonly unmappable_namespace: "is a Win32 extended-length namespace path with no DOS-path equivalent (only \\\\?\\<drive>: and \\\\?\\UNC\\ forms name files)";
|
|
292
|
+
readonly unc_on_posix_tree: "is a UNC (\\\\host\\share) spelling, which names no file on a POSIX tree";
|
|
293
|
+
readonly drive_relative: "is drive-relative (a drive letter with no separator after the colon), a location no tree can locate";
|
|
294
|
+
};
|
|
295
|
+
/** The fence over the text table: `never` while every refusal word has a row. */
|
|
296
|
+
export type NamespaceRefusalTextCoversEveryWord = AssertAllKeysHandled<Exclude<Win32NamespaceRefusal, keyof typeof WIN32_NAMESPACE_REFUSAL_TEXT>>;
|
|
297
|
+
type AssertAllKeysHandled<T extends never> = T;
|
|
298
|
+
/**
|
|
299
|
+
* The Win32 namespace screen — run on every model-spelled target BEFORE the family join, at every site
|
|
300
|
+
* (the fs throat, the effective-target reader, the rule side, the glob splitter), so one spelling is
|
|
301
|
+
* refused with one word everywhere. `\\.\` ⇒ `device_namespace` (every family); `\\?\` mappable ⇒ the
|
|
302
|
+
* stripped spelling, which is screened ON (a `\\?\UNC\…` on a POSIX tree still refuses), unmappable ⇒
|
|
303
|
+
* `unmappable_namespace` (every family); a backslash UNC ⇒ passes under `win`, `unc_on_posix_tree` under
|
|
304
|
+
* `posix` (the canonicalizer's refusal boundary on POSIX trees is preserved: the family rule governs what
|
|
305
|
+
* is admitted, never what was already refused); `C:rel` under `win` ⇒ `drive_relative`. A treeless call
|
|
306
|
+
* passes a UNC spelling through — the identity then reads it as relative, as before.
|
|
307
|
+
*/
|
|
308
|
+
export declare function win32NamespaceScreen(spelled: string, family: PathFamily | undefined): {
|
|
309
|
+
readonly ok: true;
|
|
310
|
+
readonly spelled: string;
|
|
311
|
+
} | {
|
|
312
|
+
readonly ok: false;
|
|
313
|
+
readonly refuse: Win32NamespaceRefusal;
|
|
314
|
+
};
|
|
315
|
+
declare const PATH_IDENTITY: unique symbol;
|
|
316
|
+
/**
|
|
317
|
+
* The ONE comparison form of an absolute path (upstream's normal form): posix = the lexical-normal
|
|
318
|
+
* `/`-rooted path; win = `/c/rest` for a drive (letter lower-cased), `//host/share/rest` for UNC, `\`
|
|
319
|
+
* folded to `/`, `.`/`..` folded with the anchor preserved. A COMPARISON form — never a path to open, never
|
|
320
|
+
* compared against a native `C:\…` string. Branded: a spelling is not an identity until {@link pathIdentityOf}
|
|
321
|
+
* has read it.
|
|
322
|
+
*/
|
|
323
|
+
export type PathIdentity = string & {
|
|
324
|
+
readonly [PATH_IDENTITY]: true;
|
|
325
|
+
};
|
|
326
|
+
/** Why a spelling has no identity: a namespace refusal, `relative` (join it to a base first), or
|
|
327
|
+
* `unanchored` (a win `/x` with no tree root to take a drive from). */
|
|
328
|
+
export type PathIdentityRefusal = Win32NamespaceRefusal | "relative" | "unanchored";
|
|
329
|
+
export type PathIdentityReading = {
|
|
330
|
+
readonly ok: true;
|
|
331
|
+
readonly identity: PathIdentity;
|
|
332
|
+
} | {
|
|
333
|
+
readonly ok: false;
|
|
334
|
+
readonly reason: PathIdentityRefusal;
|
|
335
|
+
};
|
|
336
|
+
/**
|
|
337
|
+
* The identity of an ABSOLUTE spelling under the family ({@link PathIdentity}). `anchor` is the tree's root
|
|
338
|
+
* (or cwd) spelling: under `win` a `/`-rooted spelling whose first segment is not a drive letter
|
|
339
|
+
* (`/proj/x`) anchors on the root's drive or share, as `path.win32.resolve` anchors it on the current
|
|
340
|
+
* drive; `/c/x` and `/C:/x` are drive spellings (the cygdrive form and the rule grammar's `/`+body), and
|
|
341
|
+
* `/\\host\share\x` is the grammar's prefix before a UNC. A relative spelling is `relative` — callers join
|
|
342
|
+
* it to a base FIRST. A treeless call (`family` undefined) reads only the anchor-free `/`-rooted form, as
|
|
343
|
+
* the POSIX identity; every other spelling names nothing, which is what a missing base answered before.
|
|
344
|
+
*/
|
|
345
|
+
export declare function pathIdentityOf(spelled: string, family: PathFamily | undefined, anchor?: string): PathIdentityReading;
|
|
346
|
+
/** Is the identity a UNC one (`//host/share/…`)? Identities compare by anchor kind first: a UNC identity is
|
|
347
|
+
* never under a rooted one and vice versa (upstream's shape parity). */
|
|
348
|
+
export declare function isUncIdentity(identity: PathIdentity): boolean;
|
|
349
|
+
/** Is `s` already an identity under the family — the identity function is the identity on it? The
|
|
350
|
+
* runtime twin of the brand for values that arrive from outside the type system. */
|
|
351
|
+
export declare function isPathIdentity(s: string, family: PathFamily | undefined): s is PathIdentity;
|
|
352
|
+
/** Is the identity a DIRECTORY a rule may speak for — anything but the tree's bare root (`/`, a drive root
|
|
353
|
+
* `/c`, a share root `//host/share`), which admits nothing? */
|
|
354
|
+
export declare function isIdentityDir(identity: PathIdentity, family: PathFamily | undefined): boolean;
|
|
355
|
+
/** Does the spelling carry a `.` or `..` segment under the family's separators (a backslash is a name byte on
|
|
356
|
+
* POSIX)? A rule body with one admits nothing: folding it could make it name a second directory. */
|
|
357
|
+
export declare function carriesDotSegment(spelled: string, family: PathFamily | undefined): boolean;
|
|
358
|
+
/** A model-spelled path bounded for error text (the spelling is unbounded input). */
|
|
359
|
+
export declare function clipSpelling(spelled: string): string;
|
|
360
|
+
/** A ROOTED (not qualified) spelling handed to the SHELL on a win tree (`/d/x`, `/etc`, `\\x`) is the shell's to
|
|
361
|
+
* map — the win32 adapter runs Git Bash, where `/d/x` is drive D and `/etc` the MSYS root, neither the cwd's
|
|
362
|
+
* drive root — so no lexical reader may resolve it (fail-closed: the operand is unresolvable, the cd mints
|
|
363
|
+
* nothing). The ONE statement of that rule, for every shell-facing resolver. */
|
|
364
|
+
export declare function isShellRootedSpellingUnmapped(family: PathFamily | undefined, spelled: string): boolean;
|
|
365
|
+
/** The win family's native spelling of a UNC written with any leading-separator mix (`//host/share/x`, `\\/host/…`
|
|
366
|
+
* ⇒ `\\\\host\\share\\x`), for a lexical normalizer that recognises the backslash form only; every other spelling is
|
|
367
|
+
* returned as is. */
|
|
368
|
+
export declare function nativeUncSpellingOf(family: PathFamily | undefined, spelled: string): string;
|
|
369
|
+
/**
|
|
370
|
+
* Join a RELATIVE-OR-ROOTED spelling to a base under the family, without folding (`..` across a symlinked
|
|
371
|
+
* parent is the env's to resolve). win = `path.win32` semantics: `/x`/`\x` lands on the base's drive or
|
|
372
|
+
* share root, anything else under the base with the base's own separator. posix = `/`-join.
|
|
373
|
+
*/
|
|
374
|
+
export declare function joinForFamily(family: PathFamily, base: string, rel: string): string;
|
|
375
|
+
/** The family-aware LEXICAL view of a possibly-relative spelling against a resolution base (no I/O,
|
|
376
|
+
* `.`/`..` folded via {@link normalizeAbsPathLexically}): the SECOND deny-judgment view. It asks
|
|
377
|
+
* "does the NAME land on a guarded path", complementing the canonical
|
|
272
378
|
* view's "does the TARGET" — a symlink AT a guarded spelling resolves away from it canonically,
|
|
273
379
|
* and only this view still names it. */
|
|
274
380
|
export declare function lexicalViewOf(spelled: string, base: string): string;
|
|
275
381
|
/**
|
|
276
|
-
* Resolve a model-supplied path to a canonical key AND enforce rootPath containment
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* `executionEnv` — see design/44 §5.)
|
|
382
|
+
* Resolve a model-supplied path to a canonical key AND enforce rootPath containment. Existing paths
|
|
383
|
+
* use `canonicalPath` (resolves symlinks, so the same file cannot get two keys). New paths
|
|
384
|
+
* canonicalize the **deepest existing ancestor** then rejoin the missing tail — a symlinked parent
|
|
385
|
+
* therefore cannot land the target outside root. Returns the canonical key, or a `path_not_in_root`
|
|
386
|
+
* violation. Defense-in-depth at the tool layer; NOT a substitute for a sandboxed `executionEnv`.
|
|
282
387
|
*/
|
|
283
388
|
export declare function resolveKey(env: ExecutionEnv, rootCanonical: string, path: string, signal?: AbortSignal, baseCwd?: string, additionalRootsCanonical?: readonly string[], exactFileReadExemption?: (canonicalKey: string) => boolean, readDeny?: {
|
|
284
389
|
matchTarget(canonicalKey: string, lexicalView?: string, opts?: {
|
|
@@ -299,11 +404,11 @@ export declare function resolveKey(env: ExecutionEnv, rootCanonical: string, pat
|
|
|
299
404
|
* doesn't exist yet, the deepest EXISTING ancestor is canonicalized then the missing tail rejoined —
|
|
300
405
|
* so a symlinked parent cannot land the target elsewhere). NO containment check — this is the pure
|
|
301
406
|
* canonicalization shared by `resolveKey` (which adds rootPath containment) and
|
|
302
|
-
* `createSensitivePathPolicy` (
|
|
407
|
+
* `createSensitivePathPolicy` (which matches the real target against a guarded list).
|
|
303
408
|
* A single source of truth for symlink resolution: a sensitive-path policy that matched the raw path
|
|
304
|
-
* instead of the real target would compare against the spelling, not the destination
|
|
409
|
+
* instead of the real target would compare against the spelling, not the destination.
|
|
305
410
|
*/
|
|
306
|
-
export declare function canonicalizeTarget(env: ExecutionEnv, path: string, signal
|
|
411
|
+
export declare function canonicalizeTarget(env: ExecutionEnv, path: string, signal: AbortSignal | undefined, family: PathFamily, baseCwd?: string): Promise<{
|
|
307
412
|
ok: true;
|
|
308
413
|
key: string;
|
|
309
414
|
aliasResolved?: true;
|
|
@@ -311,20 +416,21 @@ export declare function canonicalizeTarget(env: ExecutionEnv, path: string, sign
|
|
|
311
416
|
ok: false;
|
|
312
417
|
message: string;
|
|
313
418
|
unresolvedSymlink?: true;
|
|
419
|
+
refused?: Win32NamespaceRefusal;
|
|
314
420
|
}>;
|
|
315
421
|
/** Render a `FsViolation` as the model-facing tool error text (returned, never thrown — model retries). */
|
|
316
422
|
export declare function violationText(toolName: string, v: FsViolation): string;
|
|
317
423
|
/**
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
424
|
+
* Structured `details` for a rendered violation: non-`undefined` ONLY for the two codes with
|
|
425
|
+
* per-refusal coordinates worth counting (which canonical target, against which roots or which deny
|
|
426
|
+
* pattern). Designed to be passed straight as `errorResult`'s second argument by every renderer of a
|
|
427
|
+
* {@link resolveKey} violation — `undefined` keeps the detail-less shape for all other violation
|
|
428
|
+
* codes.
|
|
323
429
|
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
* `tool_end.structured` and the "count from fields" promise above
|
|
327
|
-
* `code`
|
|
430
|
+
* `type` is the WIRE discriminator: the card projector (`createStructuredProjector`,
|
|
431
|
+
* tool-output-projection.ts) keys on `details.type`, so without it the card never reaches
|
|
432
|
+
* `tool_end.structured` and the "count from fields" promise above holds for in-process readers only.
|
|
433
|
+
* `code` carries the same value for consumers that read it.
|
|
328
434
|
*/
|
|
329
435
|
export declare function violationDetails(v: FsViolation): {
|
|
330
436
|
type: "path_not_in_root";
|
|
@@ -338,7 +444,7 @@ export declare function violationDetails(v: FsViolation): {
|
|
|
338
444
|
pattern: string;
|
|
339
445
|
} | undefined;
|
|
340
446
|
/**
|
|
341
|
-
*
|
|
447
|
+
* Does `p` sit inside ANY of the canonical containment roots? Exposed for the Bash
|
|
342
448
|
* tool's post-`cd` disclosure note (fs-bash.ts): the note reuses the SAME segment-aware `within`
|
|
343
449
|
* the fence itself uses, so the disclosure and the fence can never disagree about what counts as
|
|
344
450
|
* "inside". Pure/lexical — callers own any canonicalization of `p` (the tracked cwd stays raw by
|
|
@@ -346,37 +452,34 @@ export declare function violationDetails(v: FsViolation): {
|
|
|
346
452
|
*/
|
|
347
453
|
export declare function withinAnyRoot(rootsCanonical: readonly string[], p: string): boolean;
|
|
348
454
|
/**
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
455
|
+
* The escape-hatch tail for the `path_not_in_root` refusal: like its three sibling hints below, it
|
|
456
|
+
* names a sanctioned next step, so the model does not oscillate between "the boundary is hard" and
|
|
457
|
+
* hunting for a way around it.
|
|
352
458
|
*
|
|
353
459
|
* The card names the SANCTIONED way out and nothing else: widening the declaration
|
|
354
|
-
* (`additionalDirectories` / read-only `additionalReadDirectories
|
|
355
|
-
*
|
|
460
|
+
* (`additionalDirectories` / read-only `additionalReadDirectories`), or the deployment-level
|
|
461
|
+
* `readFace: "open"` for reads.
|
|
356
462
|
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
* fence, and every shell call still passes the deployment's approval policy); it is simply no longer
|
|
366
|
-
* handed to the model inside a denial. What the card says now: this is denied, and here is the
|
|
367
|
-
* sanctioned way to be allowed.
|
|
463
|
+
* It deliberately does NOT name the shell as unconfined by this fence, even though that is a true
|
|
464
|
+
* statement rather than a recommendation. A live retest settled the question: a refused agent read
|
|
465
|
+
* such a sentence as the next step, went to the shell, and rewrote through it the very file the fence
|
|
466
|
+
* had just protected. A refusal card is a PROMPT surface — naming, at the moment of denial, a second
|
|
467
|
+
* tool that does not enforce the boundary is a recipe whatever its grammar, and the model cannot be
|
|
468
|
+
* relied on to hear "fact, not advice". The underlying fact is documented where humans read it (the
|
|
469
|
+
* shell is deliberately unconfined by this fence, and every shell call still passes the deployment's
|
|
470
|
+
* approval policy); it is simply not handed to the model inside a denial.
|
|
368
471
|
*/
|
|
369
472
|
export declare const PATH_NOT_IN_ROOT_ESCAPE_HINT = "(This boundary applies to the structured file tools. If you genuinely need content outside the allowed root(s), ask for the directory to be added to the deployment's additionalDirectories \u2014 or additionalReadDirectories for read-only access; a deployment that wants reads open everywhere can declare readFace: \"open\" instead of listing directories.)";
|
|
370
473
|
/** inv 1 (read-before-edit): a file must have been read this task before it can be edited/overwritten.
|
|
371
474
|
* Message is CC 2.1.198 live-verbatim (all-tools-live-probe 2026-07-08 §2.1/§3.1/§5.1 — one message for
|
|
372
475
|
* Edit/Write/NotebookEdit: "before writing to it", not the old sema "before editing").
|
|
373
476
|
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
477
|
+
* CC parity (Edit and Write spell the read gate identically, `!p || p.isPartialView`): an
|
|
478
|
+
* AUTO-TRUNCATED read (the model asked for the file by default, no explicit offset/limit, and the token
|
|
479
|
+
* cap cut it anyway — {@link ReadEntry.isPartialView}) must NOT satisfy this gate. With `state.has(key)`
|
|
480
|
+
* alone as the whole check, the model could Write (full overwrite) or Edit a file having genuinely seen
|
|
481
|
+
* only its first page, silently destroying or blind-editing the unseen remainder. CC's own gate treats
|
|
482
|
+
* "never read" and "auto-truncated
|
|
380
483
|
* partial view" identically for BOTH tools — no softer rule for Edit (whose old_string match only touches
|
|
381
484
|
* a small snippet) versus Write (which replaces everything), so this doesn't carve one out either.
|
|
382
485
|
*
|
|
@@ -394,8 +497,7 @@ export declare function requireRead(state: ReadFileState, key: string): FsViolat
|
|
|
394
497
|
*/
|
|
395
498
|
export declare const OVERSIZE_READ_ESCAPE_HINT = "(This file is over the Read tool's whole-file byte cap, so a default Read is refused \u2014 read it in slices with explicit offset/limit to satisfy the read-first rule, or inspect/transform it with bash (e.g. `sed -n`, `grep`) instead.)";
|
|
396
499
|
/**
|
|
397
|
-
*
|
|
398
|
-
* the escape-hatch parenthetical for the OTHER shape of the read-before-edit refusal: the file was read,
|
|
500
|
+
* The escape-hatch parenthetical for the OTHER shape of the read-before-edit refusal: the file was read,
|
|
399
501
|
* but the read was AUTO-PAGINATED by the output token cap ({@link ReadEntry.isPartialView}), so only the
|
|
400
502
|
* first page was ever seen. The oversize branch above has named its escape route since the fidelity
|
|
401
503
|
* sweep; this branch named none — and it is the worse of the two, because the refusal's own advice
|
|
@@ -406,29 +508,29 @@ export declare const OVERSIZE_READ_ESCAPE_HINT = "(This file is over the Read to
|
|
|
406
508
|
*/
|
|
407
509
|
export declare const PARTIAL_VIEW_READ_ESCAPE_HINT = "(Your last Read of this file returned only a PARTIAL view \u2014 the output token cap paginated it, so a default Read will keep returning the same page. Re-read it with explicit offset/limit (start from the page marker's next-page hint) until you have seen the part you are about to change; an explicit slice that fits satisfies the read-first rule. Or inspect/transform it with bash (e.g. `sed -n`, `grep`) instead.)";
|
|
408
510
|
/**
|
|
409
|
-
*
|
|
410
|
-
*
|
|
511
|
+
* The escape-hatch parenthetical for the ONE shape of the read-first deadlock that nothing observable
|
|
512
|
+
* diagnoses: a file the Read tool REFUSES (binary /
|
|
411
513
|
* BOM-less UTF-16 / unknown encoding) can never satisfy read-before-write, and — unlike the oversize
|
|
412
514
|
* and partial-view shapes — leaves no trace the refusal renderer can stat for. It is therefore the
|
|
413
515
|
* renderer's FALLBACK hint (least specific, appended only when no sharper branch fired); appending it
|
|
414
516
|
* beside a sharper one would assert something false, since both of those shapes are files Read handled.
|
|
415
517
|
* Kept byte-identical to the sentence Write rendered inline before it moved here.
|
|
416
518
|
*
|
|
417
|
-
*
|
|
519
|
+
* The deadlock is a property of the READ GATE,
|
|
418
520
|
* not of Write — Edit and NotebookEdit hit the identical dead end and used to render the bare sentence
|
|
419
521
|
* with no way out named. All three now pass this one constant, which is why it is no longer named for
|
|
420
522
|
* the tool that happened to have it first: one sentence, three call sites, nothing to drift apart.
|
|
421
523
|
*/
|
|
422
524
|
export declare const READ_REFUSED_ESCAPE_HINT = "(If the Read tool refuses this file (binary/unknown encoding), overwrite or convert it with bash instead \u2014 e.g. `rm` + rewrite, or `iconv`.)";
|
|
423
525
|
/**
|
|
424
|
-
* Edit "no-op" guard (
|
|
526
|
+
* Edit "no-op" guard (CC FileEditTool parity): refuse an edit whose `old_string`
|
|
425
527
|
* equals `new_string` — without it the edit passes the match check and writes the file back unchanged (a
|
|
426
528
|
* silent no-op that wastes a turn and dirties mtime). Verbatim CC message so a CC-trained model recognizes it.
|
|
427
529
|
*/
|
|
428
530
|
export declare function checkNoChange(oldString: string, newString: string): FsViolation | undefined;
|
|
429
531
|
/** inv 2 (staleness): the file's current content hash must match what was recorded at read time.
|
|
430
532
|
*
|
|
431
|
-
*
|
|
533
|
+
* Takes `ReadEntry | undefined` and treats an ABSENT entry as stale (fail-closed). The three
|
|
432
534
|
* write-side callers prove the entry exists with `requireRead`, then re-read the file — an `await` — and
|
|
433
535
|
* only then reach here, so each was asserting a pre-await invariant across a suspension point with `!`.
|
|
434
536
|
* Nothing deletes read state mid-turn today (the compaction sweep runs at a turn boundary), so behaviour
|
|
@@ -441,7 +543,7 @@ export declare function countOccurrences(haystack: string, needle: string): numb
|
|
|
441
543
|
* Suggest a sibling filename for a missing path (CC `File does not exist… Did you mean X?` self-heal
|
|
442
544
|
* path, bundle :335883/:478419). Honest scope (1.253 双轨终审): this is the FALLBACK tier — an
|
|
443
545
|
* approximation of CC's Cxe same-directory scan plus a sema-added case-insensitive exact-name match
|
|
444
|
-
* (the case-typo class CC misses).
|
|
546
|
+
* (the case-typo class CC misses). Registered delta: CC's FIRST-tier suggester is a GATED
|
|
445
547
|
* sibling-tree REBASE (`join(cwd, relative(dirname(cwd), missing))`, only for a path under the cwd's
|
|
446
548
|
* parent but not under the cwd), NOT the "re-resolve the filename against cwd" this comment used to
|
|
447
549
|
* claim; the full geometry and the sema delta are recorded at the call site (fs-shared.ts
|
|
@@ -460,14 +562,14 @@ export declare function normalizeQuotes(s: string): string;
|
|
|
460
562
|
*/
|
|
461
563
|
export declare function resolveQuoteMatch(content: string, oldString: string): string | undefined;
|
|
462
564
|
/**
|
|
463
|
-
*
|
|
565
|
+
* CC's forgiving-match layers 3+4: resolve `oldString` against `content` across the
|
|
464
566
|
* escape/literal spelling boundary. Returns the ACTUAL span present in `content` (which is what must be
|
|
465
567
|
* replaced), or `undefined` when neither spelling is present. Pure — call only after an exact match and
|
|
466
568
|
* the curly-quote layer have both missed.
|
|
467
569
|
*/
|
|
468
570
|
export declare function resolveEscapeMatch(content: string, oldString: string): string | undefined;
|
|
469
571
|
/**
|
|
470
|
-
*
|
|
572
|
+
* CC `YZu` verbatim: rewrite `newString` into the SAME spelling the matched
|
|
471
573
|
* span uses. Without this, a match found through {@link resolveEscapeMatch} would replace an escaped
|
|
472
574
|
* span with a literal-character replacement (or vice versa) and silently change the file's encoding
|
|
473
575
|
* convention at that spot. Hex case follows what the file itself used, per-character where known and by
|
|
@@ -477,7 +579,7 @@ export declare function adaptNewStringEscapes(oldString: string, matchedOld: str
|
|
|
477
579
|
/** CC `KZu` (@366558): the old_string shapes for which the escape layers above were even attempted —
|
|
478
580
|
* gates the explanatory note appended to a no-match refusal so it is never a false claim. */
|
|
479
581
|
export declare function escapeMatchWasAttempted(oldString: string): boolean;
|
|
480
|
-
/**
|
|
582
|
+
/** CC `KZu`'s note, verbatim. */
|
|
481
583
|
export declare const ESCAPE_MATCH_MISS_NOTE = "\n(note: Edit also tried swapping \\uXXXX escapes and their characters; neither form matched, so the mismatch is likely elsewhere in old_string. Re-read the file and copy the exact surrounding text.)";
|
|
482
584
|
/**
|
|
483
585
|
* When the quote-forgiving match resolved to a curly-quoted file span, convert the straight quotes in
|
|
@@ -508,3 +610,4 @@ export declare function deletionOldString(content: string, oldString: string, ne
|
|
|
508
610
|
* matters most (and these refusals return as tool results, which do not pass the loop-level budget). */
|
|
509
611
|
export declare const EDIT_ECHO_MAX_CHARS = 200;
|
|
510
612
|
export declare function checkEditMatch(content: string, oldString: string, replaceAll: boolean, truncated: boolean): FsViolation | undefined;
|
|
613
|
+
export {};
|