@sema-agent/core 5.20.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 +9 -0
- 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/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/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 +107 -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 +292 -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 +608 -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/mcp.d.ts +381 -0
- 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 +33 -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 +12 -11
- package/dist/core/runner/prompt-suggestions.d.ts +7 -0
- package/dist/core/runner/runtask.d.ts +304 -3
- 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-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-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/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 +16 -1
- package/dist/index.js +0 -1
- 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-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/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/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/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/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/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,47 +1,263 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* batch-B (CC 2.1.187 parity): Read/Edit/Write take the file path as `file_path`. Read the target the same way
|
|
4
|
+
* EVERYWHERE the path is consumed from a tool-call's args — not just the tool body but ALSO every gate that
|
|
5
|
+
* extracts the write target to confine it (sensitive-path, skill allowPaths, session allowDirs). A gate that only
|
|
6
|
+
* read `args.path` would see `undefined` for a `file_path` call and either fail-OPEN (bypass the guard — a real
|
|
7
|
+
* hole) or fail-closed (deny a legitimate write). Single source.
|
|
8
|
+
*
|
|
9
|
+
* The `path` arm is deliberately BROADER than what Read/Edit/Write accept (ruled 2026-08-03): their schema requires
|
|
10
|
+
* `file_path` and rejects the retired `path` alias outright (fs-shared.ts FILE_PATH_PARAMS), but this reader is
|
|
11
|
+
* shared with gates that judge OTHER tool vocabularies — Glob's real `path` parameter, deployment-authored tools —
|
|
12
|
+
* and a gate must never see LESS than the tool it is confining might act on. So the asymmetry is the design: the
|
|
13
|
+
* schema decides what a caller may send, this decides what gets judged, and this side over-reads on purpose.
|
|
14
|
+
*/
|
|
2
15
|
export declare function fileArgPath(args: unknown): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* The WRITE TARGET of a path-confinable write call, tool-aware ([886]①a/b — single source for every
|
|
18
|
+
* gate that confines a write target, same discipline as {@link fileArgPath} above):
|
|
19
|
+
*
|
|
20
|
+
* · canonical `NotebookEdit` → `notebook_path` FIRST, `file_path`/`path` only as fallback. The tool
|
|
21
|
+
* itself writes `notebook_path`; its schema tolerates extra keys, so a stray/decoy `file_path` on a
|
|
22
|
+
* NotebookEdit call must never become the judged target while the real write lands elsewhere
|
|
23
|
+
* (a gate that read `file_path` first would confine the decoy — the [886]①b hole).
|
|
24
|
+
* · every other tool → `file_path`/`path` first ({@link fileArgPath}), `notebook_path` as the
|
|
25
|
+
* historical fallback (unchanged behavior for the pre-existing gate callers).
|
|
26
|
+
*
|
|
27
|
+
* `canonicalName` is the tool name as mounted (RB-476-A: raw — the legacy normalizer is retired;
|
|
28
|
+
* this module stays dependency-free of the alias table — "NotebookEdit" is the canonical CC name and
|
|
29
|
+
* old→new normalization is identity for it).
|
|
30
|
+
*/
|
|
3
31
|
export declare function writeTargetPath(canonicalName: string, args: unknown): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* The "hand" file tools (design/44) — safety invariants ported from CC's `FileEditTool` (design/43 Rule
|
|
34
|
+
* 7): without these a weak model blind-edits / overwrites files (P0 safety, not polish). This module is
|
|
35
|
+
* the pure/testable core (path resolution + the three edit invariants + content hashing); the tools in
|
|
36
|
+
* this dir compose it. Per-task state and the execution env are passed in (factory-closure wiring,
|
|
37
|
+
* design/44 §11 ruling A), never read from a shared/global.
|
|
38
|
+
*/
|
|
39
|
+
/** What we remember about a file the agent has read (design/44 §4). */
|
|
4
40
|
export interface ReadEntry {
|
|
41
|
+
/** SHA-256 of the content at read time. Staleness is detected by content hash, NOT mtime — mtime is
|
|
42
|
+
* unreliable across containers/volumes/NFS and across a design/45 suspend→resume on another replica. */
|
|
5
43
|
hash: string;
|
|
44
|
+
/** Total line count at read time, and whether the read was truncated (for the edit truncation hint, S2). */
|
|
6
45
|
totalLines: number;
|
|
7
46
|
truncated: boolean;
|
|
47
|
+
/** RB-200 F2 — CC `isPartialView` parity (220 @515151 sets it only when the auto-pagination catch branch
|
|
48
|
+
* fires, i.e. the model asked for the file by DEFAULT — no explicit offset/limit — and the token cap
|
|
49
|
+
* truncated it anyway; an EXPLICIT offset/limit slice that fits under the cap is NEVER marked this way,
|
|
50
|
+
* even though it's equally "not the whole file"). Deliberately narrower than {@link truncated} above,
|
|
51
|
+
* which also fires for a fully-intentional, successful slice read (`start>1 || end<total`) — folding
|
|
52
|
+
* THIS flag into that broader one would make {@link OVERSIZE_READ_ESCAPE_HINT}'s documented promise
|
|
53
|
+
* ("read it in slices with explicit offset/limit to satisfy the read-first rule") false: a model paging
|
|
54
|
+
* through an oversized file on purpose would never be able to satisfy {@link requireRead} again. Optional/
|
|
55
|
+
* additive: undefined on every non-Read write-back (Write/Edit re-record the file they just fully wrote)
|
|
56
|
+
* and on every seeded/attachment entry — those are never partial by construction. */
|
|
8
57
|
isPartialView?: boolean;
|
|
58
|
+
/** The line window actually served to the model on the last read (design/64 §7.2(6) dedup stub). Lets
|
|
59
|
+
* read_file return a `file_unchanged` stub when the SAME window is re-requested and the content hash is
|
|
60
|
+
* unchanged — saving the re-transmitted body. Optional/additive: undefined (e.g. an entry seeded from an
|
|
61
|
+
* older design/45 checkpoint) just means "no dedup", never a false hit. */
|
|
9
62
|
view?: {
|
|
10
63
|
start: number;
|
|
11
64
|
end: number;
|
|
12
65
|
};
|
|
66
|
+
/** Millisecond timestamp of the last read/write-back that recorded this entry (blackboard
|
|
67
|
+
* 2026-07-03, compact re-read parity: the post-compaction attachment picks the most RECENTLY
|
|
68
|
+
* read files — CC sorts readFileState by timestamp). Optional/additive: undefined (an entry
|
|
69
|
+
* seeded from an older checkpoint) sorts last, never breaks. */
|
|
13
70
|
lastReadAt?: number;
|
|
71
|
+
/** CC 2.1.204 parity (`seededFromContext`, cc204-bundle @17889409 / seeding @17917159; 198 zero
|
|
72
|
+
* hits): TRUE when the Runner pre-seeded this entry because the file's FULL disk-verbatim text
|
|
73
|
+
* was injected into the model's context at startup (ProjectMemoryLoad.seededFiles — CC's
|
|
74
|
+
* CLAUDE.md/nested-memory seeding). A DEFAULT whole-file Read of an UNCHANGED seeded file
|
|
75
|
+
* answers with the already-in-context reminder instead of re-transmitting the body. Any real
|
|
76
|
+
* Read / edit write-back records a FRESH entry without this flag, so a file that changed on
|
|
77
|
+
* disk (hash mismatch) always serves real content and the dedup disarms permanently.
|
|
78
|
+
* Optional/additive: absent = normal entry. */
|
|
14
79
|
seededFromContext?: boolean;
|
|
15
80
|
}
|
|
81
|
+
/** Per-task record of which files have been read, keyed by canonical path (design/44 §4, §11 ruling A:
|
|
82
|
+
* owned by prepare-task, closure-captured by the tools; serialized into a design/45 Checkpoint later). */
|
|
16
83
|
export type ReadFileState = Map<string, ReadEntry>;
|
|
84
|
+
/** SHA-256 hex of UTF-8 content — the staleness/identity key (design/44 §4 inv 2, jury M1). */
|
|
17
85
|
export declare function sha256(content: string): string;
|
|
86
|
+
/** A failed path resolution / invariant check, surfaced to the model as a self-correctable tool error. */
|
|
18
87
|
export interface FsViolation {
|
|
19
88
|
code: "path_not_in_root" | "not_read" | "stale" | "ambiguous_edit" | "invalid";
|
|
89
|
+
/** RB-264 N1: set on the `not_read` violation raised by an AUTO-TRUNCATED read
|
|
90
|
+
* ({@link ReadEntry.isPartialView}) rather than by a never-read file. Both carry the same CC-verbatim
|
|
91
|
+
* message; only this one needs {@link PARTIAL_VIEW_READ_ESCAPE_HINT} appended, because for it a plain
|
|
92
|
+
* re-read is a fixpoint. */
|
|
20
93
|
partialView?: true;
|
|
94
|
+
/** RB-371 ④: set ONLY on `path_not_in_root` — the CANONICAL key the refused path resolved to
|
|
95
|
+
* (symlinks followed, tracked cwd applied), i.e. the value the fence actually judged. Rides into
|
|
96
|
+
* the tool result's `details` (see {@link violationDetails}) so a consumer can count/aggregate
|
|
97
|
+
* boundary refusals from fields instead of regexing the prose. */
|
|
21
98
|
target?: string;
|
|
99
|
+
/** RB-371 ④: set ONLY on `path_not_in_root` — the containment roots in effect (primary first,
|
|
100
|
+
* then additionalDirectories), canonical form. */
|
|
22
101
|
roots?: readonly string[];
|
|
23
102
|
message: string;
|
|
24
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Absolute in EITHER family: POSIX `/…` or drive-letter `C:\…`/`C:/…`.
|
|
106
|
+
*
|
|
107
|
+
* REF-C1 — this is the ONE definition of "already absolute, therefore do not prepend a base". It was
|
|
108
|
+
* independently re-typed at nine coordinates (search.ts ×4, bash-readonly-classifier.ts,
|
|
109
|
+
* core/lsp.ts, core/runner/prepare-task.ts, orchestration/run-spec.ts and here), three of which
|
|
110
|
+
* carried a comment claiming the same philosophy as this file while keeping their own copy. The
|
|
111
|
+
* failure mode is not the duplication itself but the drift it invites: a family added at one
|
|
112
|
+
* coordinate leaves the other eight judging the same string differently, and this predicate gates a
|
|
113
|
+
* security fence (frozen-path deny, readonly-boundary containment) as well as URI key minting.
|
|
114
|
+
* Callers that need a family the predicate does not cover must widen it HERE, not locally.
|
|
115
|
+
*
|
|
116
|
+
* The UNC arm (`\\host\share\…`) was exactly that drift, found already in flight: core/lsp.ts carried it
|
|
117
|
+
* privately while the other eight coordinates did not, so the LSP tool leg resolved a UNC path as
|
|
118
|
+
* absolute while the edit-nudge leg prefixed it with the task root — two URI keys for one file. Folding
|
|
119
|
+
* it in here settles the disagreement in the direction the rest of this file already takes: a literal
|
|
120
|
+
* `\\host\share\…` is win-form (see {@link isWinFormPath}) and `within()` lands it outside every
|
|
121
|
+
* POSIX/drive root, i.e. it is a location the working directory does not contain.
|
|
122
|
+
*/
|
|
25
123
|
export declare function isAbsolutePathForm(p: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Windows-FAMILY spelling of a path (codex 1.237 F6, extracted here so {@link canonicalizeTarget} judges
|
|
126
|
+
* the UNC family by the same rule): drive-rooted (`C:\…`/`C:/…`), UNC-backslash (`\\host\share`), or a
|
|
127
|
+
* RELATIVE path using `\` as its separator. Never keyed on `process.platform` — the exec env may be remote
|
|
128
|
+
* and of the other family than the host. A `/`-rooted path is POSIX-form even when a file NAME inside it
|
|
129
|
+
* contains a literal backslash (legal on POSIX), and `//host/share` is therefore POSIX-form too — which is
|
|
130
|
+
* the whole point: on POSIX that spelling is an ordinary absolute path, not a network share.
|
|
131
|
+
*
|
|
132
|
+
* REF-C2 — this is the ONE definition of the win-family spelling. core/file-snapshot-store.ts held a
|
|
133
|
+
* byte-identical private twin (its manifest key/restore-target folds are conditioned on it) and now
|
|
134
|
+
* imports this one; core/ already depends on this module at seven other coordinates, and this file's own
|
|
135
|
+
* imports are `node:crypto` plus a type, so there is no layering wall between them.
|
|
136
|
+
*/
|
|
26
137
|
export declare function isWinFormPath(p: string): boolean;
|
|
27
138
|
export declare function isBlockedDevicePath(key: string): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* RB-153 — purely LEXICAL path normalization: collapse repeated separators, drop `.` segments, and
|
|
141
|
+
* resolve `..` against the preceding segment. No filesystem access, no cwd: this is a spelling
|
|
142
|
+
* normalizer, not a resolver. (Deliberately NOT `canonicalizeNewPath`'s job — that one walks the real
|
|
143
|
+
* filesystem precisely because folding `..` lexically across a SYMLINKED parent is unsound. Use this one
|
|
144
|
+
* only where the question is "are these two strings the same name", never "which file is this".)
|
|
145
|
+
*
|
|
146
|
+
* It exists because {@link isBlockedDevicePath} is an exact-string membership test, and `//dev/zero`,
|
|
147
|
+
* `/dev/./zero` and `/dev/../dev/zero` all name the device `/dev/zero` to the kernel while spelling it
|
|
148
|
+
* three different ways. Callers that match a device list against a raw argument must normalize first or
|
|
149
|
+
* the list is a spelling filter rather than a device filter.
|
|
150
|
+
*
|
|
151
|
+
* REF-C3 — coverage, after folding in the two private re-implementations that had grown around this one
|
|
152
|
+
* (the bash classifier's drive-aware wrapper and prepare-task's `normalizeSegments`). The union they
|
|
153
|
+
* covered between them is now the contract here:
|
|
154
|
+
* · POSIX absolute — `/a/./b` → `/a/b`; `/..` is `/`, matching the kernel.
|
|
155
|
+
* · drive-letter (`C:\a\..\b`) and UNC (`\\host\share\..\x`) — prefix preserved, folding applies
|
|
156
|
+
* to the tail only, and the REJOIN uses the path's own native separator so one file cannot acquire
|
|
157
|
+
* two keys by separator form.
|
|
158
|
+
* · RELATIVE — stays relative (`dev/zero` therefore still never matches an absolute device entry:
|
|
159
|
+
* `dev/zero` under some other directory is an ordinary file), and a leading `..` is KEPT rather than
|
|
160
|
+
* popped into nothing — dropping it would move the path.
|
|
161
|
+
*
|
|
162
|
+
* FAMILY-awareness is the one thing none of the three had right. A backslash is a separator only in a
|
|
163
|
+
* win-form path; in a POSIX path it is an ordinary filename character, and the classifier's old
|
|
164
|
+
* unconditional `\`→`/` fold rewrote a POSIX file literally named `a\..\b` into a different location
|
|
165
|
+
* before the boundary check ever saw it (both directions: false refusal and false allow).
|
|
166
|
+
*/
|
|
28
167
|
export declare function normalizeAbsPathLexically(p: string): string;
|
|
168
|
+
/**
|
|
169
|
+
* The READ-leg fold (REF-C3 receipt, R1 verify ISSUE-1): removes `.` segments and duplicate
|
|
170
|
+
* separators ONLY — transformations that name the SAME file on every real filesystem, symlinks
|
|
171
|
+
* included. `..` is deliberately KEPT: `a/../x` and `x` are different files when `a` is a symlink,
|
|
172
|
+
* and this function's callers go on to OPEN the result (fileInfo/readText), not just to mint a
|
|
173
|
+
* comparison key. Ask "which file is this" here; ask "are these two strings the same name" with
|
|
174
|
+
* {@link normalizeAbsPathLexically}.
|
|
175
|
+
*/
|
|
29
176
|
export declare function foldRedundantPathSegments(p: string): string;
|
|
177
|
+
/** True if `path`'s extension is a known binary format (pure check — no I/O). Used by read_file and grep. */
|
|
30
178
|
export declare function hasBinaryExtension(path: string): boolean;
|
|
179
|
+
/** The MIME type to return an image file AS (a visual `ImageContent` block), or `undefined` if `path` is not a
|
|
180
|
+
* Read-supported image. Pure — no I/O. */
|
|
31
181
|
export declare function imageMimeForRead(path: string): string | undefined;
|
|
182
|
+
/** Verify the raw bytes actually ARE the image format the extension claims (magic-number sniff). Extension alone
|
|
183
|
+
* is forgeable: a `.png` holding text / an empty file / a truncated blob would otherwise become a malformed
|
|
184
|
+
* `ImageContent` that makes the NEXT provider request fail (400). Pure — no I/O. (batch-C, codex review.) */
|
|
32
185
|
export declare function imageMagicMatches(bytes: Uint8Array, mimeType: string): boolean;
|
|
186
|
+
/** One contiguous byte pattern that must appear at a fixed offset for its signature to match. */
|
|
33
187
|
export interface BinaryMagicSegment {
|
|
188
|
+
/** Byte offset the pattern starts at — 0 for a leading signature, 257 for tar's `ustar`, and so on. */
|
|
34
189
|
readonly offset: number;
|
|
190
|
+
/** The exact bytes that must appear there. */
|
|
35
191
|
readonly bytes: readonly number[];
|
|
36
192
|
}
|
|
193
|
+
/** A file-format signature: EVERY segment must match for the format to be claimed. */
|
|
37
194
|
export interface BinaryMagicSignature {
|
|
195
|
+
/** Human-readable format label. It lands verbatim in the Read refusal, so it names what the file IS,
|
|
196
|
+
* never the extension it happened to be carrying. */
|
|
38
197
|
readonly format: string;
|
|
198
|
+
/** All segments must match. A second segment exists only to disambiguate a prefix that also spells
|
|
199
|
+
* plausible text (`BM`, `RIFF`, `FORM`): the payload word at the later offset is what decides. */
|
|
39
200
|
readonly segments: readonly BinaryMagicSegment[];
|
|
40
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* ANG-5 (external black-box re-review, ruled 2026-08-03) — magic-byte criteria for the formats
|
|
204
|
+
* {@link hasBinaryExtension} names. That list carries 103 extensions; before this table only PDF
|
|
205
|
+
* (`pdfMagicMatches`, in the PDF lane) and the four API image formats ({@link imageMagicMatches}) had a
|
|
206
|
+
* content criterion, so for every other listed format the NAME was the only evidence available. Where the
|
|
207
|
+
* content IS reachable that left identification to the statistical fallback ({@link isBinaryContent}),
|
|
208
|
+
* which samples the first 8192 decoded characters and passes anything whose control-character ratio
|
|
209
|
+
* stays under 10% — a short archive/executable header followed by printable payload clears that bar
|
|
210
|
+
* and gets delivered as text.
|
|
211
|
+
*
|
|
212
|
+
* Shape: pure data, one table, `offset + bytes`. Adding a format is a row; the matcher
|
|
213
|
+
* ({@link binaryMagicFormat}) never changes. Rows are grouped by family so the next diff stays readable.
|
|
214
|
+
*
|
|
215
|
+
* Admission rule — a row exists only where the signature is DECIDABLE. A short ASCII prefix that also
|
|
216
|
+
* opens ordinary prose is admitted only with a disambiguating second segment (`BM` + the zeroed
|
|
217
|
+
* reserved fields, `RIFF`/`FORM` + the payload word); formats whose only fixed marker is such a prefix
|
|
218
|
+
* are deliberately absent, because a false positive here makes a real text file unreadable — the exact
|
|
219
|
+
* harm the name-only refusal was retired for. Absent on that ground: DOS/PE (`MZ`, with the PE header
|
|
220
|
+
* at a variable offset), SWF (`FWS`/`CWS` + a wide version byte), Blender (`BLENDER`), `.pyc` (a
|
|
221
|
+
* per-release magic), and PostScript/EPS (genuinely text). They stay covered by the statistical sniff.
|
|
222
|
+
*
|
|
223
|
+
* Converged consumer: the WebFetch lane (`tools/web.ts`'s `sniffBinarySignature`) used to carry its own
|
|
224
|
+
* private eight-format if-chain for HTTP bodies; it now reads this table via {@link binaryMagicFormat}
|
|
225
|
+
* (PDF handled the same way this table's own callers handle it — via `pdfMagicMatches`, not a row here).
|
|
226
|
+
*/
|
|
41
227
|
export declare const BINARY_MAGIC_SIGNATURES: readonly BinaryMagicSignature[];
|
|
228
|
+
/**
|
|
229
|
+
* Identify `bytes` by its file signature — the format label, or `undefined` when no row in
|
|
230
|
+
* {@link BINARY_MAGIC_SIGNATURES} matches. Pure — no I/O, and name-blind by construction (nothing here
|
|
231
|
+
* looks at a path), so it can be asked in either direction: a mis-named binary is caught, and a listed
|
|
232
|
+
* extension holding real text is NOT claimed.
|
|
233
|
+
*/
|
|
42
234
|
export declare function binaryMagicFormat(bytes: Uint8Array): string | undefined;
|
|
235
|
+
/**
|
|
236
|
+
* Content sniff for binary data (design/64 §17.1, CC `constants/files.ts` `isBinaryContent`): a NUL byte,
|
|
237
|
+
* or more than 10% non-printable characters in the sample, means binary. Second layer behind
|
|
238
|
+
* {@link hasBinaryExtension} — catches extension-less or mis-named binaries (a `Dockerfile` that is really
|
|
239
|
+
* a compiled blob) that would otherwise be read as mojibake. Plain text (incl. UTF-8, tabs/newlines) passes.
|
|
240
|
+
*/
|
|
43
241
|
export declare function isBinaryContent(sample: string): boolean;
|
|
242
|
+
/**
|
|
243
|
+
* CC's own UNC/network-path predicate, verbatim (220 @515523:
|
|
244
|
+
* `n.startsWith("\\\\") || n.startsWith("//")`). Pure.
|
|
245
|
+
*
|
|
246
|
+
* RB-279: the predicate is CC's, but CC's POLARITY is the opposite of what sema used it for. In CC this
|
|
247
|
+
* test is an EARLY ALLOW — `return { result: !0 }`, skipping the binary-extension and device checks that
|
|
248
|
+
* follow it — and CC applies it to the NORMALIZED path (`Li` ⇒ `path.normalize`), not the raw argument.
|
|
249
|
+
* See {@link canonicalizeTarget} for how sema now mirrors that (and for the two deliberate differences).
|
|
250
|
+
* This function stays a pure spelling test with no verdict of its own.
|
|
251
|
+
*/
|
|
44
252
|
export declare function isUncPath(path: string): boolean;
|
|
253
|
+
/**
|
|
254
|
+
* Resolve a model-supplied path to a canonical key AND enforce rootPath containment (design/44 §4
|
|
255
|
+
* inv 5/6/7). Existing paths use `canonicalPath` (resolves symlinks, so the same file can't get two
|
|
256
|
+
* keys). New paths canonicalize the **deepest existing ancestor** then rejoin the missing tail — a
|
|
257
|
+
* symlinked parent therefore cannot land the target outside root. Returns the canonical key, or a
|
|
258
|
+
* `path_not_in_root` violation. (Defense-in-depth at the tool layer; NOT a substitute for a sandboxed
|
|
259
|
+
* `executionEnv` — see design/44 §5.)
|
|
260
|
+
*/
|
|
45
261
|
export declare function resolveKey(env: ExecutionEnv, rootCanonical: string, path: string, signal?: AbortSignal, baseCwd?: string, additionalRootsCanonical?: readonly string[], exactFileReadExemption?: (canonicalKey: string) => boolean): Promise<{
|
|
46
262
|
ok: true;
|
|
47
263
|
key: string;
|
|
@@ -49,6 +265,15 @@ export declare function resolveKey(env: ExecutionEnv, rootCanonical: string, pat
|
|
|
49
265
|
ok: false;
|
|
50
266
|
violation: FsViolation;
|
|
51
267
|
}>;
|
|
268
|
+
/**
|
|
269
|
+
* Canonicalize a model-supplied path to its real on-disk target (symlinks resolved; for a path that
|
|
270
|
+
* doesn't exist yet, the deepest EXISTING ancestor is canonicalized then the missing tail rejoined —
|
|
271
|
+
* so a symlinked parent cannot land the target elsewhere). NO containment check — this is the pure
|
|
272
|
+
* canonicalization shared by `resolveKey` (which adds rootPath containment) and
|
|
273
|
+
* `createSensitivePathPolicy` (design/72 §2.1, which matches the real target against a guarded list).
|
|
274
|
+
* A single source of truth for symlink resolution: a sensitive-path policy that matched the raw path
|
|
275
|
+
* instead of the real target would compare against the spelling, not the destination (§2.1).
|
|
276
|
+
*/
|
|
52
277
|
export declare function canonicalizeTarget(env: ExecutionEnv, path: string, signal?: AbortSignal, baseCwd?: string): Promise<{
|
|
53
278
|
ok: true;
|
|
54
279
|
key: string;
|
|
@@ -57,30 +282,181 @@ export declare function canonicalizeTarget(env: ExecutionEnv, path: string, sign
|
|
|
57
282
|
message: string;
|
|
58
283
|
unresolvedSymlink?: true;
|
|
59
284
|
}>;
|
|
285
|
+
/** Render a `FsViolation` as the model-facing tool error text (returned, never thrown — model retries). */
|
|
60
286
|
export declare function violationText(toolName: string, v: FsViolation): string;
|
|
287
|
+
/**
|
|
288
|
+
* RB-371 ④ — structured `details` for a rendered violation: non-`undefined` ONLY for
|
|
289
|
+
* `path_not_in_root`, the one code with per-refusal coordinates worth counting (which canonical
|
|
290
|
+
* target, against which roots). Designed to be passed straight as `errorResult`'s second argument by
|
|
291
|
+
* every renderer of a {@link resolveKey} violation — `undefined` keeps the pre-existing detail-less
|
|
292
|
+
* shape for all other violation codes, so nothing else changes byte-wise.
|
|
293
|
+
*
|
|
294
|
+
* RB-397-c (回溯复查批): `type` is the WIRE discriminator — `structuredFrom`'s `CC_DETAIL_TYPES` gate
|
|
295
|
+
* (tool-output-projection.ts) keys on `details.type`, so without it the card never reached
|
|
296
|
+
* `tool_end.structured` and the "count from fields" promise above held for in-process readers only.
|
|
297
|
+
* `code` stays as-is for the existing RB-371 consumers — the new key is strictly additive.
|
|
298
|
+
*/
|
|
61
299
|
export declare function violationDetails(v: FsViolation): {
|
|
62
300
|
type: "path_not_in_root";
|
|
63
301
|
code: "path_not_in_root";
|
|
64
302
|
target: string;
|
|
65
303
|
roots: readonly string[];
|
|
66
304
|
} | undefined;
|
|
305
|
+
/**
|
|
306
|
+
* RB-371 ② — does `p` sit inside ANY of the canonical containment roots? Exposed for the Bash
|
|
307
|
+
* tool's post-`cd` disclosure note (fs-bash.ts): the note reuses the SAME segment-aware `within`
|
|
308
|
+
* the fence itself uses, so the disclosure and the fence can never disagree about what counts as
|
|
309
|
+
* "inside". Pure/lexical — callers own any canonicalization of `p` (the tracked cwd stays raw by
|
|
310
|
+
* design; fs-bash canonical-confirms before claiming "outside").
|
|
311
|
+
*/
|
|
67
312
|
export declare function withinAnyRoot(rootsCanonical: readonly string[], p: string): boolean;
|
|
313
|
+
/**
|
|
314
|
+
* RB-371 ① — the escape-hatch tail for the `path_not_in_root` refusal: its three sibling hints
|
|
315
|
+
* below each name a sanctioned next step; this refusal named none, leaving the model to oscillate
|
|
316
|
+
* between "the boundary is hard" and discovering by trial that bash is not confined by it. Both
|
|
317
|
+
* stated ways out are consistent with the Bash tool's own card (the shell is deliberately NOT
|
|
318
|
+
* sandboxed by this fence — design/44 §5 — and every call still passes the deployment's approval
|
|
319
|
+
* policy) and with the deployment-side widening knob (`additionalDirectories`, design/119).
|
|
320
|
+
*/
|
|
68
321
|
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) and the deployment permits it, use the Bash tool \u2014 it is not confined by this fence, though every call remains subject to the deployment's approval policy. Or ask for the directory to be added to additionalDirectories.)";
|
|
322
|
+
/** inv 1 (read-before-edit): a file must have been read this task before it can be edited/overwritten.
|
|
323
|
+
* Message is CC 2.1.198 live-verbatim (all-tools-live-probe 2026-07-08 §2.1/§3.1/§5.1 — one message for
|
|
324
|
+
* Edit/Write/NotebookEdit: "before writing to it", not the old sema "before editing").
|
|
325
|
+
*
|
|
326
|
+
* RB-200 F2(形态一,CC 220 语料证实,@367198/@367671 — Edit/Write 两处读门的判据字面完全相同,
|
|
327
|
+
* `!p || p.isPartialView`,两个工具用的是同一个条件): an AUTO-TRUNCATED read (the model asked for the
|
|
328
|
+
* file by default, no explicit offset/limit, and the token cap cut it anyway — {@link ReadEntry.isPartialView})
|
|
329
|
+
* used to satisfy this gate exactly like a full read (`state.has(key)` alone was the whole check) — the
|
|
330
|
+
* model could Write (full overwrite) or Edit a file having genuinely seen only its first page, silently
|
|
331
|
+
* destroying or blind-editing the unseen remainder. CC's own gate treats "never read" and "auto-truncated
|
|
332
|
+
* partial view" identically for BOTH tools — no softer rule for Edit (whose old_string match only touches
|
|
333
|
+
* a small snippet) versus Write (which replaces everything), so this doesn't carve one out either.
|
|
334
|
+
*
|
|
335
|
+
* Deliberately checks `isPartialView`, NOT the broader {@link ReadEntry.truncated} (which also fires for a
|
|
336
|
+
* fully-intentional, successful EXPLICIT offset/limit slice read) — CC's own `isPartialView` is scoped the
|
|
337
|
+
* same narrow way (only the auto-pagination case, never an explicit range that fit), and gating on the
|
|
338
|
+
* broader flag would make {@link OVERSIZE_READ_ESCAPE_HINT}'s documented promise false: a model deliberately
|
|
339
|
+
* paging through an oversized file via offset/limit would never be able to satisfy this gate again. */
|
|
69
340
|
export declare function requireRead(state: ReadFileState, key: string): FsViolation | undefined;
|
|
341
|
+
/**
|
|
342
|
+
* Escape-hatch parenthetical appended to the read-before-edit refusal when the target file is over
|
|
343
|
+
* the Read tool's whole-file byte cap: a bare "read it first" would be un-followable there (a default
|
|
344
|
+
* whole-file Read refuses such files → refusal loop). Same parenthetical pattern as the Write tool's
|
|
345
|
+
* encoding-deadlock hint; the CC-verbatim sentence stays untouched for the normal-size case.
|
|
346
|
+
*/
|
|
70
347
|
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.)";
|
|
348
|
+
/**
|
|
349
|
+
* RB-264 N1 ([1963] test AI 复验残留, repro `notebookedit-tool-read-gate-deadlock` assertion A.c2) —
|
|
350
|
+
* the escape-hatch parenthetical for the OTHER shape of the read-before-edit refusal: the file was read,
|
|
351
|
+
* but the read was AUTO-PAGINATED by the output token cap ({@link ReadEntry.isPartialView}), so only the
|
|
352
|
+
* first page was ever seen. The oversize branch above has named its escape route since the fidelity
|
|
353
|
+
* sweep; this branch named none — and it is the worse of the two, because the refusal's own advice
|
|
354
|
+
* ("Read it first") is a FIXPOINT here: the file is UNDER the byte cap, so a default Read succeeds and
|
|
355
|
+
* auto-paginates identically, and Read's unchanged-since-last-read dedup then short-circuits before the
|
|
356
|
+
* state is rewritten. The gate is `isPartialView`, not the file size, so ANY explicit offset/limit slice
|
|
357
|
+
* that fits clears it — stated explicitly because nothing else in the transcript says so.
|
|
358
|
+
*/
|
|
71
359
|
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.)";
|
|
360
|
+
/**
|
|
361
|
+
* RB-264 ⑥W1 ([1963] test AI 复验残留) — the escape-hatch parenthetical for the ONE shape of the
|
|
362
|
+
* read-first deadlock that nothing observable diagnoses: a file the Read tool REFUSES (binary /
|
|
363
|
+
* BOM-less UTF-16 / unknown encoding) can never satisfy read-before-write, and — unlike the oversize
|
|
364
|
+
* and partial-view shapes — leaves no trace the refusal renderer can stat for. It is therefore the
|
|
365
|
+
* renderer's FALLBACK hint (least specific, appended only when no sharper branch fired); appending it
|
|
366
|
+
* beside a sharper one would assert something false, since both of those shapes are files Read handled.
|
|
367
|
+
* Kept byte-identical to the sentence Write rendered inline before it moved here.
|
|
368
|
+
*
|
|
369
|
+
* ANG-6 (external black-box re-review, ruled 2026-08-03): the deadlock is a property of the READ GATE,
|
|
370
|
+
* not of Write — Edit and NotebookEdit hit the identical dead end and used to render the bare sentence
|
|
371
|
+
* with no way out named. All three now pass this one constant, which is why it is no longer named for
|
|
372
|
+
* the tool that happened to have it first: one sentence, three call sites, nothing to drift apart.
|
|
373
|
+
*/
|
|
72
374
|
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`.)";
|
|
375
|
+
/**
|
|
376
|
+
* Edit "no-op" guard (design/64 §7.2(4), CC `FileEditTool:148-153`): refuse an edit whose `old_string`
|
|
377
|
+
* equals `new_string` — without it the edit passes the match check and writes the file back unchanged (a
|
|
378
|
+
* silent no-op that wastes a turn and dirties mtime). Verbatim CC message so a CC-trained model recognizes it.
|
|
379
|
+
*/
|
|
73
380
|
export declare function checkNoChange(oldString: string, newString: string): FsViolation | undefined;
|
|
381
|
+
/** inv 2 (staleness): the file's current content hash must match what was recorded at read time.
|
|
382
|
+
*
|
|
383
|
+
* RB-436-g: takes `ReadEntry | undefined` and treats an ABSENT entry as stale (fail-closed). The three
|
|
384
|
+
* write-side callers prove the entry exists with `requireRead`, then re-read the file — an `await` — and
|
|
385
|
+
* only then reach here, so each was asserting a pre-await invariant across a suspension point with `!`.
|
|
386
|
+
* Nothing deletes read state mid-turn today (the compaction sweep runs at a turn boundary), so behaviour
|
|
387
|
+
* is unchanged; if that ever stops holding, the caller gets this tool's designed "read it again" refusal
|
|
388
|
+
* instead of a TypeError thrown from inside the tool. */
|
|
74
389
|
export declare function checkStale(entry: ReadEntry | undefined, currentHash: string): FsViolation | undefined;
|
|
390
|
+
/** Count non-overlapping occurrences of `needle` in `haystack` (`needle` must be non-empty). */
|
|
75
391
|
export declare function countOccurrences(haystack: string, needle: string): number;
|
|
392
|
+
/**
|
|
393
|
+
* Suggest a sibling filename for a missing path (CC `File does not exist… Did you mean X?` self-heal
|
|
394
|
+
* path, bundle :335883/:478419). Honest scope (1.253 双轨终审): this is the FALLBACK tier — an
|
|
395
|
+
* approximation of CC's Cxe same-directory scan plus a sema-added case-insensitive exact-name match
|
|
396
|
+
* (the case-typo class CC misses). RB-285 (归因更正): CC's FIRST-tier suggester is `G_e` — a GATED
|
|
397
|
+
* sibling-tree REBASE (`join(cwd, relative(dirname(cwd), missing))`, only for a path under the cwd's
|
|
398
|
+
* parent but not under the cwd), NOT the "re-resolve the filename against cwd" this comment used to
|
|
399
|
+
* claim; the full geometry and the sema delta are recorded at the call site (fs-shared.ts
|
|
400
|
+
* `enoentMessage`), which is where the env probing lives. This function stays pure over a listed
|
|
401
|
+
* sibling set and corresponds to CC's SECOND tier (`Yrt`/findSimilarFile). (a) CC's findSimilarFile
|
|
402
|
+
* rule — same stem, different extension/name in the same directory; (b) the case-insensitive
|
|
403
|
+
* exact-name match (sema addition). Returns the suggested NAME (not a full path), or undefined.
|
|
404
|
+
*/
|
|
76
405
|
export declare function similarNameSuggestion(siblingNames: readonly string[], missingName: string): string | undefined;
|
|
406
|
+
/** Replace curly single/double quotes with their straight ASCII forms (CC qDa, 1:1 char mapping). */
|
|
77
407
|
export declare function normalizeQuotes(s: string): string;
|
|
408
|
+
/**
|
|
409
|
+
* Resolve `oldString` against `content` with the CC quote-forgiveness layer: exact match first; on a
|
|
410
|
+
* miss, match in the curly→straight normalized coordinate and return the ACTUAL file substring at
|
|
411
|
+
* that span (CC kOe). Returns undefined when even the normalized form does not appear.
|
|
412
|
+
*/
|
|
78
413
|
export declare function resolveQuoteMatch(content: string, oldString: string): string | undefined;
|
|
414
|
+
/**
|
|
415
|
+
* RB-285 M9 (CC `Pdt` layers 3+4, @366594-366600): resolve `oldString` against `content` across the
|
|
416
|
+
* escape/literal spelling boundary. Returns the ACTUAL span present in `content` (which is what must be
|
|
417
|
+
* replaced), or `undefined` when neither spelling is present. Pure — call only after an exact match and
|
|
418
|
+
* the curly-quote layer have both missed.
|
|
419
|
+
*/
|
|
79
420
|
export declare function resolveEscapeMatch(content: string, oldString: string): string | undefined;
|
|
421
|
+
/**
|
|
422
|
+
* RB-285 M9 (CC `YZu` verbatim, @366561-366587): rewrite `newString` into the SAME spelling the matched
|
|
423
|
+
* span uses. Without this, a match found through {@link resolveEscapeMatch} would replace an escaped
|
|
424
|
+
* span with a literal-character replacement (or vice versa) and silently change the file's encoding
|
|
425
|
+
* convention at that spot. Hex case follows what the file itself used, per-character where known and by
|
|
426
|
+
* majority vote otherwise — CC's own rule, and the reason it counts upper/lower while walking the span.
|
|
427
|
+
*/
|
|
80
428
|
export declare function adaptNewStringEscapes(oldString: string, matchedOld: string, newString: string): string;
|
|
429
|
+
/** CC `KZu` (@366558): the old_string shapes for which the escape layers above were even attempted —
|
|
430
|
+
* gates the explanatory note appended to a no-match refusal so it is never a false claim. */
|
|
81
431
|
export declare function escapeMatchWasAttempted(oldString: string): boolean;
|
|
432
|
+
/** RB-285 M9 — CC `KZu`'s note (@367245-367248) verbatim. */
|
|
82
433
|
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.)";
|
|
434
|
+
/**
|
|
435
|
+
* When the quote-forgiving match resolved to a curly-quoted file span, convert the straight quotes in
|
|
436
|
+
* `newString` to the matching curly forms so the replacement stays style-consistent with the file
|
|
437
|
+
* (CC Dmt/yPp/TPp: openers vs closers by preceding char; a letter-adjacent single quote is an
|
|
438
|
+
* apostrophe U+2019). Call ONLY when the matched span differs from the model's old_string.
|
|
439
|
+
*/
|
|
83
440
|
export declare function adaptNewStringQuotes(matchedOld: string, newString: string): string;
|
|
441
|
+
/**
|
|
442
|
+
* The effective old_string a DELETION should replace: `oldString + "\n"` when new_string is empty,
|
|
443
|
+
* old_string doesn't already end with a newline, and the newline-suffixed form exists in the content;
|
|
444
|
+
* otherwise old_string unchanged (CC KDa parity). SINGLE (non-replace_all) edits only: a widened
|
|
445
|
+
* needle under replace_all would miss occurrences not followed by a newline and desync the
|
|
446
|
+
* replacement count — the Edit tool restricts the widening to single edits (1.253 双轨终审 MED).
|
|
447
|
+
*/
|
|
84
448
|
export declare function deletionOldString(content: string, oldString: string, newString: string): string;
|
|
449
|
+
/**
|
|
450
|
+
* inv 3 (edit uniqueness): `oldString` must match exactly once unless `replaceAll`. Zero → not found;
|
|
451
|
+
* >1 without replaceAll → ambiguous. `truncated` adds a hint that unseen content may hold more matches (S2).
|
|
452
|
+
* Messages are CC 2.1.198 live-verbatim (all-tools-live-probe 2026-07-08 §2.1): first sentence(s) byte-exact,
|
|
453
|
+
* then a `String: <needle>` echo line (CC form). The sema truncated-read hint survives as a parenthetical
|
|
454
|
+
* appended to the sentence (probe verdict: "truncated 提示可并入括注保留").
|
|
455
|
+
*/
|
|
456
|
+
/** How much of the needle a failed-match refusal spells back. The echo identifies WHICH string was
|
|
457
|
+
* searched for; the caller still holds the whole thing in the tool call above, so a prefix does the job
|
|
458
|
+
* a full copy was doing at any length the caller chose. Both arms use it — the not-found arm is the more
|
|
459
|
+
* common failure, so bounding only the multi-match arm would leave the stated bound defeated where it
|
|
460
|
+
* matters most (and these refusals return as tool results, which do not pass the loop-level budget). */
|
|
85
461
|
export declare const EDIT_ECHO_MAX_CHARS = 200;
|
|
86
462
|
export declare function checkEditMatch(content: string, oldString: string, replaceAll: boolean, truncated: boolean): FsViolation | undefined;
|