@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.
Files changed (312) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/agents/agent-definition.d.ts +7 -0
  3. package/dist/agents/agent-transcript-tool.d.ts +30 -0
  4. package/dist/agents/builtin-agents.d.ts +60 -0
  5. package/dist/agents/cascade.d.ts +107 -0
  6. package/dist/agents/cumulative-stats.d.ts +56 -0
  7. package/dist/agents/observer.d.ts +162 -0
  8. package/dist/agents/peer-admission.d.ts +95 -0
  9. package/dist/agents/repair-loop.d.ts +226 -0
  10. package/dist/agents/retain-ledger.d.ts +141 -0
  11. package/dist/agents/roster-store.d.ts +105 -0
  12. package/dist/agents/send-message-tool.d.ts +92 -0
  13. package/dist/agents/session-util.d.ts +5 -0
  14. package/dist/agents/subagent-steps.d.ts +66 -0
  15. package/dist/agents/subagent.d.ts +600 -0
  16. package/dist/agents/suspend-guard.d.ts +29 -0
  17. package/dist/agents/teacher.d.ts +75 -0
  18. package/dist/agents/team.d.ts +120 -1
  19. package/dist/agents/tool-filter.d.ts +34 -0
  20. package/dist/agents/verify.d.ts +198 -0
  21. package/dist/bench/metrics.d.ts +455 -0
  22. package/dist/brain/anthropic.d.ts +30 -0
  23. package/dist/brain/circuit-breaker.d.ts +33 -0
  24. package/dist/brain/context-overflow.d.ts +60 -3
  25. package/dist/brain/degrading.d.ts +67 -0
  26. package/dist/brain/errors.d.ts +42 -0
  27. package/dist/brain/failover.d.ts +15 -0
  28. package/dist/brain/media-degrade.d.ts +39 -0
  29. package/dist/brain/model-presets.d.ts +31 -0
  30. package/dist/brain/open-responses.d.ts +19 -0
  31. package/dist/brain/openai.d.ts +46 -0
  32. package/dist/brain/reasoning.d.ts +106 -1
  33. package/dist/brain/repetition.d.ts +83 -0
  34. package/dist/brain/request-params.d.ts +56 -0
  35. package/dist/brain/retry.d.ts +46 -0
  36. package/dist/brain/routing.d.ts +12 -0
  37. package/dist/brain/status-sink.d.ts +30 -1
  38. package/dist/brain/stream-engine.d.ts +147 -0
  39. package/dist/brain/stream-shared.d.ts +34 -0
  40. package/dist/brain/terminal-cause.d.ts +31 -0
  41. package/dist/brain/timeout.d.ts +107 -0
  42. package/dist/brain/tool-call-id.d.ts +20 -0
  43. package/dist/brain/tool-call-repair.d.ts +13 -0
  44. package/dist/config/catalog.d.ts +47 -0
  45. package/dist/config/defaults.d.ts +33 -0
  46. package/dist/core/a2a-task-state.d.ts +53 -0
  47. package/dist/core/a2a.d.ts +51 -0
  48. package/dist/core/arg-summary.d.ts +62 -0
  49. package/dist/core/ask-question.d.ts +272 -2
  50. package/dist/core/auto-compaction.d.ts +467 -0
  51. package/dist/core/auto-compaction.js +20 -6
  52. package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
  53. package/dist/core/auto-mode-prompt.d.ts +27 -0
  54. package/dist/core/auto-mode.d.ts +54 -3
  55. package/dist/core/auto-promote.d.ts +100 -0
  56. package/dist/core/background-agent-store.d.ts +292 -0
  57. package/dist/core/background-shell.d.ts +110 -0
  58. package/dist/core/cache-break-detector.d.ts +34 -0
  59. package/dist/core/canonical-json.d.ts +57 -0
  60. package/dist/core/checkpoint-store.d.ts +1574 -16
  61. package/dist/core/compliance.d.ts +30 -0
  62. package/dist/core/consolidate-scope.d.ts +75 -0
  63. package/dist/core/context-edit.d.ts +99 -0
  64. package/dist/core/context-guard.d.ts +46 -0
  65. package/dist/core/exec-gate.d.ts +44 -0
  66. package/dist/core/exec-output-tail.d.ts +61 -0
  67. package/dist/core/file-snapshot-store.d.ts +104 -0
  68. package/dist/core/fs-write-gate-policy.d.ts +36 -0
  69. package/dist/core/git-worktree-env.d.ts +31 -0
  70. package/dist/core/governance-codes.d.ts +19 -0
  71. package/dist/core/hooks.d.ts +608 -1
  72. package/dist/core/human-input-projection.d.ts +37 -0
  73. package/dist/core/human-input-projection.js +13 -0
  74. package/dist/core/image-downsample.d.ts +74 -0
  75. package/dist/core/locked-config.d.ts +37 -0
  76. package/dist/core/lsp-diagnostics.d.ts +77 -0
  77. package/dist/core/lsp-protocol.d.ts +29 -0
  78. package/dist/core/lsp-session.d.ts +60 -1
  79. package/dist/core/lsp.d.ts +150 -1
  80. package/dist/core/mailbox-store.d.ts +57 -0
  81. package/dist/core/mcp.d.ts +381 -0
  82. package/dist/core/media-byte-cap.d.ts +21 -0
  83. package/dist/core/memory-admission.d.ts +71 -0
  84. package/dist/core/memory-engine/content-origin.d.ts +64 -0
  85. package/dist/core/memory-engine/data-plane.d.ts +43 -0
  86. package/dist/core/memory-engine/dual-root.d.ts +24 -0
  87. package/dist/core/memory-engine/engine.d.ts +230 -0
  88. package/dist/core/memory-engine/engine.js +103 -35
  89. package/dist/core/memory-engine/file-backend.d.ts +155 -0
  90. package/dist/core/memory-engine/frontmatter.d.ts +16 -0
  91. package/dist/core/memory-engine/layout.d.ts +217 -0
  92. package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
  93. package/dist/core/memory-engine/migrate.d.ts +9 -0
  94. package/dist/core/memory-engine/scan.d.ts +12 -0
  95. package/dist/core/memory-engine/scope-contract.d.ts +61 -1
  96. package/dist/core/memory-engine/sync-client.d.ts +87 -0
  97. package/dist/core/memory-engine/sync.d.ts +60 -0
  98. package/dist/core/memory-engine/tools.d.ts +41 -0
  99. package/dist/core/memory-engine/types.d.ts +188 -0
  100. package/dist/core/memory-recall.d.ts +141 -0
  101. package/dist/core/memory-vector.d.ts +20 -0
  102. package/dist/core/memory.d.ts +458 -0
  103. package/dist/core/message-utils.d.ts +6 -0
  104. package/dist/core/oracle-isolation.d.ts +69 -0
  105. package/dist/core/permission-rule-consent.d.ts +138 -0
  106. package/dist/core/permission-rule-model.d.ts +122 -0
  107. package/dist/core/permission-rule-store.d.ts +119 -3
  108. package/dist/core/permission-rules.d.ts +87 -1
  109. package/dist/core/present-plan-tool.d.ts +20 -0
  110. package/dist/core/pricing.d.ts +26 -0
  111. package/dist/core/property-harness.d.ts +86 -0
  112. package/dist/core/protocol-naming.d.ts +38 -0
  113. package/dist/core/protocol-table.d.ts +61 -0
  114. package/dist/core/push-queue.d.ts +1 -0
  115. package/dist/core/remote-env.d.ts +383 -1
  116. package/dist/core/retention-policy.d.ts +33 -0
  117. package/dist/core/retention.d.ts +51 -0
  118. package/dist/core/roles.d.ts +59 -0
  119. package/dist/core/runner/active-skill-scope.d.ts +34 -0
  120. package/dist/core/runner/assemble-result.d.ts +134 -0
  121. package/dist/core/runner/compaction-call-options.d.ts +97 -1
  122. package/dist/core/runner/grounding-signal.d.ts +10 -0
  123. package/dist/core/runner/image.d.ts +17 -0
  124. package/dist/core/runner/image.js +29 -15
  125. package/dist/core/runner/memory-consolidation.d.ts +60 -0
  126. package/dist/core/runner/prepare-memory.d.ts +59 -0
  127. package/dist/core/runner/prepare-task.d.ts +1011 -2
  128. package/dist/core/runner/prepare-task.js +12 -11
  129. package/dist/core/runner/prompt-suggestions.d.ts +7 -0
  130. package/dist/core/runner/runtask.d.ts +304 -3
  131. package/dist/core/runner/session-file-state-replay.d.ts +49 -0
  132. package/dist/core/runner/session-rule-policy.d.ts +58 -0
  133. package/dist/core/runner/strict-output-schema.d.ts +18 -3
  134. package/dist/core/runner/synthetic-tools.d.ts +113 -0
  135. package/dist/core/runner/teardown-bounded.d.ts +34 -0
  136. package/dist/core/runner/tool-disclosure.d.ts +227 -0
  137. package/dist/core/runner/tool-output-projection.d.ts +6 -0
  138. package/dist/core/runner/turn-attachments.d.ts +634 -0
  139. package/dist/core/runner/usage-accounting.d.ts +32 -0
  140. package/dist/core/runtime.d.ts +9 -0
  141. package/dist/core/safe-notify.d.ts +64 -0
  142. package/dist/core/safety-axis-vocab.d.ts +23 -0
  143. package/dist/core/safety-merge-corpus.d.ts +37 -0
  144. package/dist/core/scheduler.d.ts +121 -0
  145. package/dist/core/secret-env.d.ts +32 -0
  146. package/dist/core/select-model.d.ts +15 -0
  147. package/dist/core/sensitive-path-policy.d.ts +42 -0
  148. package/dist/core/session-policy-store.d.ts +94 -0
  149. package/dist/core/session-reconcile.d.ts +80 -0
  150. package/dist/core/session-store.d.ts +85 -0
  151. package/dist/core/session.d.ts +153 -0
  152. package/dist/core/shared-memory/contract.d.ts +22 -0
  153. package/dist/core/shared-memory/normalize.d.ts +123 -2
  154. package/dist/core/shared-memory/tools.d.ts +14 -0
  155. package/dist/core/shared-memory/types.d.ts +105 -0
  156. package/dist/core/shutdown-debug.d.ts +6 -0
  157. package/dist/core/side-query.d.ts +38 -0
  158. package/dist/core/side-query.js +6 -1
  159. package/dist/core/skill-tool-specifier.d.ts +72 -0
  160. package/dist/core/skills-directory.d.ts +100 -1
  161. package/dist/core/spec-contract.d.ts +89 -0
  162. package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
  163. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
  164. package/dist/core/store-contracts/contract-harness.d.ts +20 -0
  165. package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
  166. package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
  167. package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
  168. package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
  169. package/dist/core/strategy-store.d.ts +37 -0
  170. package/dist/core/stub-env.d.ts +7 -0
  171. package/dist/core/surrogate-safe-slice.d.ts +35 -0
  172. package/dist/core/task-notification.d.ts +202 -0
  173. package/dist/core/task-outcome.d.ts +53 -0
  174. package/dist/core/task-registry-agent.d.ts +337 -1
  175. package/dist/core/task-registry-monitor.d.ts +12 -0
  176. package/dist/core/task-registry-shared.d.ts +540 -0
  177. package/dist/core/task-registry.d.ts +343 -0
  178. package/dist/core/task-registry.js +13 -2
  179. package/dist/core/task-tool-shape.d.ts +44 -0
  180. package/dist/core/tighten-task-spec.d.ts +21 -0
  181. package/dist/core/tool-detach.d.ts +21 -0
  182. package/dist/core/tool-errors.d.ts +131 -0
  183. package/dist/core/tool-errors.js +4 -0
  184. package/dist/core/tool-name-aliases.d.ts +27 -0
  185. package/dist/core/tool-policy.d.ts +555 -0
  186. package/dist/core/tool-result-budget.d.ts +32 -0
  187. package/dist/core/tool-result-store.d.ts +174 -1
  188. package/dist/core/tools.d.ts +45 -0
  189. package/dist/core/trace.d.ts +323 -0
  190. package/dist/core/types.d.ts +3859 -2
  191. package/dist/core/untrusted-egress.d.ts +8 -0
  192. package/dist/core/untrusted-text.d.ts +156 -0
  193. package/dist/core/usage-window-store.d.ts +95 -0
  194. package/dist/core/version.d.ts +1 -0
  195. package/dist/core/warm-resume.d.ts +17 -0
  196. package/dist/core/wiring-manifest.d.ts +169 -0
  197. package/dist/core/with-retry.d.ts +24 -0
  198. package/dist/core/workflow-journal-store.d.ts +160 -0
  199. package/dist/core/workflow-run-store-contract.d.ts +25 -0
  200. package/dist/core/workflow-run-store.d.ts +119 -0
  201. package/dist/engine/compaction/compaction.d.ts +256 -1
  202. package/dist/engine/compaction/utils.d.ts +94 -0
  203. package/dist/engine/execution-env/kill-tree.d.ts +29 -0
  204. package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
  205. package/dist/engine/harness/agent-harness.d.ts +116 -0
  206. package/dist/engine/harness/agent-harness.js +3 -14
  207. package/dist/engine/harness/messages.d.ts +15 -0
  208. package/dist/engine/harness/types.d.ts +464 -2
  209. package/dist/engine/llm/diagnostics.d.ts +4 -0
  210. package/dist/engine/llm/event-stream.d.ts +3 -0
  211. package/dist/engine/llm/index.d.ts +7 -0
  212. package/dist/engine/llm/types.d.ts +500 -3
  213. package/dist/engine/llm/validation.d.ts +3 -0
  214. package/dist/engine/loop/agent-loop.d.ts +87 -2
  215. package/dist/engine/loop/runtime-deps.d.ts +7 -0
  216. package/dist/engine/loop/types.d.ts +424 -0
  217. package/dist/engine/lsp/frame-decoder.d.ts +13 -0
  218. package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
  219. package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
  220. package/dist/engine/session/import-validate.d.ts +27 -0
  221. package/dist/engine/session/log-digest.d.ts +93 -0
  222. package/dist/engine/session/memory-repo.d.ts +6 -0
  223. package/dist/engine/session/memory-storage.d.ts +2 -0
  224. package/dist/engine/session/session.d.ts +75 -0
  225. package/dist/engine/session/storage-base.d.ts +8 -0
  226. package/dist/fixtures/index.d.ts +36 -0
  227. package/dist/index.d.ts +16 -1
  228. package/dist/index.js +0 -1
  229. package/dist/internal/harness-types.d.ts +6 -0
  230. package/dist/internal/harness.d.ts +11 -0
  231. package/dist/internal/llm.d.ts +6 -0
  232. package/dist/orchestration/builtin-workflows.d.ts +53 -0
  233. package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
  234. package/dist/orchestration/goal.d.ts +57 -0
  235. package/dist/orchestration/goal.js +3 -0
  236. package/dist/orchestration/run-spec.d.ts +42 -0
  237. package/dist/orchestration/run-workflow-tool.d.ts +169 -0
  238. package/dist/orchestration/workflow-governance.d.ts +61 -0
  239. package/dist/orchestration/workflow-meta.d.ts +28 -0
  240. package/dist/orchestration/workflow-observe.d.ts +60 -0
  241. package/dist/orchestration/workflow-primitives.d.ts +23 -1
  242. package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
  243. package/dist/orchestration/workflow-script-runner.d.ts +88 -0
  244. package/dist/orchestration/workflow-script-store.d.ts +98 -0
  245. package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
  246. package/dist/orchestration/workflow-types.d.ts +169 -2
  247. package/dist/orchestration/workflow.d.ts +358 -0
  248. package/dist/prompt-assembly/artifact-store.d.ts +33 -0
  249. package/dist/prompt-assembly/artifact.d.ts +25 -0
  250. package/dist/prompt-assembly/assemble.d.ts +20 -0
  251. package/dist/prompt-assembly/composer.d.ts +29 -0
  252. package/dist/prompt-assembly/epoch.d.ts +55 -1
  253. package/dist/prompt-assembly/event-registry.d.ts +35 -0
  254. package/dist/prompt-assembly/explain.d.ts +12 -0
  255. package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
  256. package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
  257. package/dist/prompt-assembly/types.d.ts +115 -0
  258. package/dist/prompts/coordinator.d.ts +27 -0
  259. package/dist/prompts/default.d.ts +539 -0
  260. package/dist/prompts/simple-sections.d.ts +45 -0
  261. package/dist/prompts/supervisor.d.ts +66 -0
  262. package/dist/scenarios/env.d.ts +28 -0
  263. package/dist/scenarios/full-body.d.ts +50 -0
  264. package/dist/scenarios/scenario-registry.d.ts +60 -0
  265. package/dist/scenarios/teacher-quickstart.d.ts +27 -0
  266. package/dist/server/http.d.ts +17 -0
  267. package/dist/stores/cc/lockfile.d.ts +6 -0
  268. package/dist/stores/cc/mailbox-store.d.ts +8 -0
  269. package/dist/stores/cc/roster-adapter.d.ts +4 -0
  270. package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
  271. package/dist/stores/file/background-agent-store.d.ts +24 -0
  272. package/dist/stores/file/checkpoint-store.d.ts +38 -0
  273. package/dist/stores/file/file-snapshot-store.d.ts +25 -0
  274. package/dist/stores/file/fs-atomic.d.ts +155 -0
  275. package/dist/stores/file/index.d.ts +89 -0
  276. package/dist/stores/file/mailbox-store.d.ts +36 -0
  277. package/dist/stores/file/memory-store.d.ts +82 -0
  278. package/dist/stores/file/permission-rule-store.d.ts +79 -0
  279. package/dist/stores/file/session-policy-store.d.ts +28 -0
  280. package/dist/stores/file/session-store.d.ts +40 -0
  281. package/dist/stores/file/shared-ledger.d.ts +83 -0
  282. package/dist/stores/file/tool-result-store.d.ts +11 -0
  283. package/dist/stores/file/usage-window-store.d.ts +18 -0
  284. package/dist/stores/file/workflow-journal-store.d.ts +100 -0
  285. package/dist/stores/file/workflow-run-store.d.ts +11 -0
  286. package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
  287. package/dist/tools/fs/encoding.d.ts +60 -0
  288. package/dist/tools/fs/fs-bash.d.ts +133 -0
  289. package/dist/tools/fs/fs-pdf.d.ts +28 -0
  290. package/dist/tools/fs/fs-search-tools.d.ts +5 -0
  291. package/dist/tools/fs/fs-shared.d.ts +360 -0
  292. package/dist/tools/fs/fs-write.d.ts +16 -0
  293. package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
  294. package/dist/tools/fs/index.d.ts +79 -0
  295. package/dist/tools/fs/notebook.d.ts +56 -0
  296. package/dist/tools/fs/pdf.d.ts +70 -0
  297. package/dist/tools/fs/pdf.js +8 -2
  298. package/dist/tools/fs/repo-map.d.ts +10 -0
  299. package/dist/tools/fs/safety.d.ts +376 -0
  300. package/dist/tools/fs/search.d.ts +131 -0
  301. package/dist/tools/loop-tick.d.ts +24 -0
  302. package/dist/tools/monitor.d.ts +55 -0
  303. package/dist/tools/scheduler-tools.d.ts +51 -0
  304. package/dist/tools/sql-adapters.d.ts +18 -0
  305. package/dist/tools/sql.d.ts +25 -0
  306. package/dist/tools/task-list.d.ts +77 -0
  307. package/dist/tools/todo.d.ts +8 -0
  308. package/dist/tools/web.d.ts +184 -0
  309. package/dist/tools/worktree.d.ts +81 -0
  310. package/package.json +2 -2
  311. package/dist/tools/gitea-issue.d.ts +0 -13
  312. 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;