@arnilo/prism-coding-agent 0.2.5 → 0.2.6

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.6] - unreleased
4
+
5
+ ### Added
6
+ - **Bounded patch review and diagnostics** (plan 026 Task 6): `createCodingPatchReviewManifest` builds a bounded manifest (repository/worktree identity, base/head, patch digest, changed paths, diffstat, check summaries, diagnostic summaries; caps revisions 8/32, diagnostics 500/5000, manifest 64 KiB/256 KiB) and a structural ArtifactService input embedding it in the artifact preview; `assertCodingPatchAccepted` derives pending/accepted/rejected/superseded bound to the exact artifact revision + digest + identity — any patch/repository/worktree/base/head change supersedes prior acceptance and stale acceptances are refused (newer revision attached after approval); acceptance never applies/commits/pushes/merges; raw patch bodies, commands, env, secrets never persisted (`ERR_PRISM_REVIEW_*`). `normalizeDiagnostics`/`diagnosticDelta` normalize host-parsed check diagnostics and LSP push/pull diagnostics into one bounded shape (`file:source:position:code` identity) with deterministic added/removed/unchanged deltas, per-file caps, containment, control-character stripping, and stale-version rejection. LSP stays opt-in: `LanguageIntelligence.syncDocument` (full-content didChange, monotonic versions) and `.diagnosticDelta` (resultId pull reuse, changed-files-only refresh) extend the standalone host-activated factory — no LSP server spawns from `createCodingTools`/`createAllTools` or any agent assembly.
7
+
8
+ ### Deferred
9
+ - **Forge breadth stays demand-gated** (plan 026 Task 4): no GitLab or Bitbucket adapter ships while no named consumer is recorded in the phase26 freeze manifest demand registry (`scripts/phase26-freeze-manifest.json`); `forge/gitlab.ts`/`bitbucket.ts` remain absent and the forge barrel exports no such adapter.
10
+
11
+ ### Added
12
+ - **Durable process recovery** (plan 026 Task 5): optional `checkpoints`/`leases`/`ownerId` (all three together, partial config fails closed) persist intent before spawn and CAS/fence-write every lifecycle transition under per-record leases (30 s/300 s TTL, monotonic fencing tokens, serialized per-record write chains). `recover()` is attach-if-attested via an optional host `recoveryBackend` (opaque non-secret `ref` on PTY/sandbox handles, bounded attach timeout 30 s/120 s); starting/running records otherwise atomically become `unknown` with exitCode null — no fabricated exit, no PID probing, no duplicate spawn. Two replicas cannot both own/attach/mutate a process (held-lease skip + CAS/fence rejection); `cancelOwned` after recovery reaches the attached backend or records unknown. Durable records (32/128 cap, oldest-terminal eviction) are metadata only — never a handle, output, env, token, or credential; corrupt/forbidden/cross-tenant records fail closed. New errors `ERR_PRISM_RECOVERY_*` (unsupported/limit/ownership/fence/unknown/untrusted/timeout).
13
+ - **Coding workspace lifecycle** (plan 026 Task 3): `createCodingWorkspaceLifecycle` registers host-approved repositories and creates/lists/locks/verifies/removes linked worktrees per task behind durable `CheckpointStore` CAS records (separate `prism.coding-agent.workspace.v1` namespace, schemaVersion 1, 64 KiB/256 KiB) and `LeaseStore` fencing (30 s/300 s TTL, monotonic fencing tokens; stale workers reject with `ERR_PRISM_WORKSPACE_FENCE`). Records carry credential-free remote fingerprints (redacted remote URL + default branch, sha256), base/head shas, worktree id/path, ownership scope, and artifact refs only. `verify` revalidates root/worktree containment, head, and fingerprints before reuse; cleanup refuses dirty/locked/unowned/missing/mismatched trees and the main worktree unless the host policy allows the documented action, persisting partial failure as `unknown` for reconciliation. `GitOperations.worktree` gains `lock`/`unlock` and porcelain `locked`/`lockReason`; new `fingerprint()` reports the redacted remote identity; new errors `ERR_PRISM_WORKSPACE_*` (unknown/limit/ownership/fence/dirty/locked/main/path-escape/fingerprint); caps 4/16 repositories and worktrees, 100/1000 cleanup operations.
14
+ - **Host-indexed repository search** (plan 026 Task 2): `createIndexedRepositoryOperations` composes a host-owned `RepositoryIndexBackend` (`update/remove/search/status/dispose`) with the literal fallback; `repo_search` gains explicit `indexed_literal`/`semantic` modes behind `createRepoSearchTool({ modes })` with literal staying the default. Stale/failed/unsupported indexes fail closed with `ERR_PRISM_INDEX_*` (no silent downgrade); results are containment-checked, score-validated, snippet/result-capped, and labeled `untrusted_index` with provenance/freshness metadata. Update caps 1000 changes / 16 MiB per batch (hard 10000 / 64 MiB), stale window 60 s (hard 300 s), query timeout 30 s (hard 120 s). Benchmark: 100000-file fixture, query p95 ≤ 250 ms, 1000-file update ≤ 1 s, heap +64 MiB.
15
+
16
+ ### Changed
17
+ - **host-selected PTY backend** (plan 026 Task 1): `createProcessSessions` gains an optional `ptyBackend` — `pty: true` delegates only to the host backend with bounded terminal geometry/TERM (120×40 default, hard 500×200), attach timeout (30 s / 120 s), resize rate limit (60/min / 600/min), and backend metadata caps (4 KiB / 16 KiB); absent or `startProcess`-less backends fail closed with `ERR_PRISM_PROCESS_PTY_UNSUPPORTED` before spawn; backend failures surface as `ERR_PRISM_PROCESS_PTY_BACKEND` without embedded backend error text; bounds overflow as `ERR_PRISM_PROCESS_PTY_LIMIT`. Non-PTY sessions are byte-compatible with 0.2.5.
18
+
3
19
  ## [0.1.6] - 2026-08-11
4
20
 
5
21
  ### Changed
package/README.md CHANGED
@@ -111,6 +111,16 @@ Factories: `createShellTool`, `createReadTool`, `createWriteTool`, `createEditTo
111
111
 
112
112
  Helpers: `detectSupportedImageMimeType`, `detectSupportedImageMimeTypeFromFile`, `getShellConfig`, `killProcessTree`, `waitForChildProcess`, `withFileMutationQueue`, `resolveRepositoryLimits`, `matchGlobPattern`, `validateGlobPattern`, `writeCodingPlanFile`, `readCodingPlanFile`, `buildCodingCheckpointMetadata`, `validateCodingCheckpointMetadata`, `assertCodingResumeAllowed`, `fingerprintJson`, `runCodingGoalVerify`, `createCodingGoalVerifyWorkflow`, `suspendAskUserDecision`, `createAskUserDecisionResumeValidator`, `validateAskUserDecisionResume`, `validateAskUserDecisionAgentResume`. Default/hard coding, repository, Git, and plan/checkpoint limit constants are exported for host configuration.
113
113
 
114
+ Interactive terminals (0.2.6, plan 026): `createProcessSessions` takes an optional host-selected PTY `ptyBackend` — `pty: true` delegates only to it (bounded geometry/TERM, attach timeout, resize rate limit, backend metadata caps; `ERR_PRISM_PROCESS_PTY_*`); without a backend, PTY fails closed as unsupported before spawn and the non-PTY path is unchanged.
115
+
116
+ Host-indexed search (0.2.6, plan 026): `createIndexedRepositoryOperations` composes a host index with the literal fallback; `indexed_literal`/`semantic` modes are explicit, stale/failed/unsupported indexes fail closed with `ERR_PRISM_INDEX_*` (no silent downgrade), and results are containment-checked and labeled `untrusted_index`. See docs/indexed-code-search.md.
117
+
118
+ Durable workspace lifecycle (0.2.6, plan 026): `createCodingWorkspaceLifecycle` registers host repositories and creates/locks/verifies/removes linked worktrees per task, with CheckpointStore CAS records, LeaseStore fencing, credential-free remote fingerprints, and a cleanup policy refusing dirty/locked/unowned/mismatched trees unless allowed. See docs/coding-workspaces.md.
119
+
120
+ Bounded patch review and diagnostics (0.2.6, plan 026): `createCodingPatchReviewManifest` + `assertCodingPatchAccepted` bind review decisions to patch digest + artifact revision + repository/worktree/base/head identity (pending/accepted/rejected/superseded, composed over the server ArtifactService, never applying or committing automatically); `normalizeDiagnostics`/`diagnosticDelta` normalize host-parsed check output and LSP push/pull results into one bounded shape with deterministic added/removed/unchanged deltas; `LanguageIntelligence.syncDocument`/`diagnosticDelta` stay opt-in (standalone factory, never baked into tool construction). See docs/coding-review-and-diagnostics.md.
121
+
122
+ Durable process recovery (0.2.6, plan 026): with `checkpoints` + `leases` + `ownerId`, `createProcessSessions` persists intent before spawn and CAS/fence-writes every transition; `recover()` is attach-if-attested via a host `recoveryBackend`, otherwise starting/running records atomically become `unknown` — no fabricated exit, no PID probing, replica-fenced so two replicas cannot both own a process. See docs/process-sessions.md.
123
+
114
124
  Option/operation types: `ToolsOptions`, `ShellToolOptions`/`BashOperations`, `ReadToolOptions`/`ReadOperations`/`ReadTextOptions`/`ReadTextResult`, `WriteToolOptions`/`WriteOperations`, `EditToolOptions`/`EditOperations`/`EditToolDetails`, `DeleteToolOptions`/`DeleteOperations`, `MoveToolOptions`/`MoveOperations`, `GlobToolOptions`, `ReadPathSet`.
115
125
 
116
126
  Text reads stop after one page or `maxScanBytes` instead of loading the file. Custom `ReadOperations` must implement bounded `readText` and `statFile`; custom `EditOperations` must implement `statFile` and honor the supplied read cap/signal. Successful truncated shell output is retained in an exclusive Unix `0600` temp file owned by the host; timeout, abort, output-limit, and spill failures remove unpublished spill files. Hosts should delete published `metadata.fullOutputPath` files after use.
@@ -178,6 +178,10 @@ export async function readCodingPlanFile(input) {
178
178
  };
179
179
  }
180
180
  export function buildCodingCheckpointMetadata(input) {
181
+ // Durable multi-repository workspace identity (worktree paths, heads,
182
+ // remote fingerprints, lease fencing) lives in the versioned
183
+ // CodingWorkspaceRecord (plan 026 Task 3, workspace-lifecycle.ts), not in
184
+ // this v1 metadata; resume revalidates that workspace before reuse.
181
185
  const metadata = {
182
186
  schemaVersion: CODING_CHECKPOINT_SCHEMA_VERSION,
183
187
  taskId: input.taskId,
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Bounded normalization of host-parsed check diagnostics and deterministic
3
+ * added/removed/unchanged deltas between generations. No language/tool-
4
+ * specific parser catalog: hosts parse check output into RawDiagnostic and
5
+ * this module validates, bounds, and fingerprints it.
6
+ */
7
+ export interface ResolvedDiagnosticsLimits {
8
+ readonly maxDiagnosticsPerFile: number;
9
+ readonly maxMessageBytes: number;
10
+ }
11
+ export declare function resolveDiagnosticsLimits(options?: {
12
+ readonly maxDiagnosticsPerFile?: number;
13
+ readonly maxMessageBytes?: number;
14
+ }): ResolvedDiagnosticsLimits;
15
+ export type DiagnosticSeverity = "error" | "warning" | "info" | "hint";
16
+ export interface RawDiagnostic {
17
+ readonly file: string;
18
+ readonly line?: number;
19
+ readonly character?: number;
20
+ readonly endLine?: number;
21
+ readonly endCharacter?: number;
22
+ readonly severity?: DiagnosticSeverity;
23
+ readonly message: string;
24
+ readonly source?: string;
25
+ readonly code?: string | number;
26
+ }
27
+ /** Normalized diagnostic: workspace-relative file, bounded fields, generation tag. */
28
+ export interface NormalizedDiagnostic {
29
+ readonly file: string;
30
+ readonly line: number;
31
+ readonly character: number;
32
+ readonly endLine: number;
33
+ readonly endCharacter: number;
34
+ readonly severity: DiagnosticSeverity;
35
+ readonly message: string;
36
+ readonly source: string;
37
+ readonly code?: string | number;
38
+ /** Monotonic producer generation (document version for LSP, host counter for checks). */
39
+ readonly generation: number;
40
+ }
41
+ export interface NormalizeDiagnosticsOptions {
42
+ /** Workspace root for containment; host-supplied, absolute. */
43
+ readonly workspaceRoot: string;
44
+ /** Diagnostics per file cap (default/hard 500/5000). */
45
+ readonly maxDiagnosticsPerFile?: number;
46
+ /** Message byte cap (default/hard 4096/16384). */
47
+ readonly maxMessageBytes?: number;
48
+ /** Generation stamped onto every normalized diagnostic. */
49
+ readonly generation: number;
50
+ }
51
+ export interface DiagnosticDelta {
52
+ readonly generation: number;
53
+ readonly added: readonly NormalizedDiagnostic[];
54
+ readonly removed: readonly NormalizedDiagnostic[];
55
+ readonly unchanged: readonly NormalizedDiagnostic[];
56
+ /** True when every input was deduplicated/truncated to the caps. */
57
+ readonly truncated: boolean;
58
+ }
59
+ export interface DiagnosticDeltaRequest {
60
+ /** Newest diagnostics, already normalized (generation must be >= previous). */
61
+ readonly next: readonly NormalizedDiagnostic[];
62
+ /** Prior generation view; entries older than next's generation are stale. */
63
+ readonly previous?: readonly NormalizedDiagnostic[];
64
+ /** Deterministic identity: file:source:line:character:code (default) or custom key. */
65
+ readonly identity?: (diagnostic: NormalizedDiagnostic) => string;
66
+ }
67
+ /** Stable identity key; the delta treats two diagnostics with the same key as one item. */
68
+ export declare function diagnosticIdentity(diagnostic: NormalizedDiagnostic): string;
69
+ /**
70
+ * Validate and bound host-parsed diagnostics. Throws nothing on malformed
71
+ * entries: each is dropped fail-closed (never partially normalized).
72
+ * Out-of-workspace paths, control characters, and non-finite positions are
73
+ * rejected per entry; overflow charges the per-file cap.
74
+ */
75
+ export declare function normalizeDiagnostics(raw: readonly RawDiagnostic[], options: NormalizeDiagnosticsOptions): readonly NormalizedDiagnostic[];
76
+ /**
77
+ * Deterministic added/removed/unchanged delta between two diagnostic
78
+ * generations. Identity is `diagnosticIdentity` (file:source:position:code);
79
+ * message/severity changes keep the same identity and count as unchanged —
80
+ * the delta tracks presence, not content edits (hosts diff content on demand).
81
+ * Stale previous entries (generation >= next's generation) are ignored.
82
+ */
83
+ export declare function diagnosticDelta(request: DiagnosticDeltaRequest): DiagnosticDelta;
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Bounded normalization of host-parsed check diagnostics and deterministic
3
+ * added/removed/unchanged deltas between generations. No language/tool-
4
+ * specific parser catalog: hosts parse check output into RawDiagnostic and
5
+ * this module validates, bounds, and fingerprints it.
6
+ */
7
+ import { isAbsolute, relative, resolve } from "node:path";
8
+ import { DEFAULT_MAX_DIAGNOSTIC_MESSAGE_BYTES, DEFAULT_MAX_REVIEW_DIAGNOSTICS, HARD_MAX_DIAGNOSTIC_MESSAGE_BYTES, HARD_MAX_REVIEW_DIAGNOSTICS, validateCodingLimit, } from "./limits.js";
9
+ export function resolveDiagnosticsLimits(options) {
10
+ return {
11
+ maxDiagnosticsPerFile: validateCodingLimit("maxDiagnosticsPerFile", options?.maxDiagnosticsPerFile ?? DEFAULT_MAX_REVIEW_DIAGNOSTICS, HARD_MAX_REVIEW_DIAGNOSTICS),
12
+ maxMessageBytes: validateCodingLimit("maxMessageBytes", options?.maxMessageBytes ?? DEFAULT_MAX_DIAGNOSTIC_MESSAGE_BYTES, HARD_MAX_DIAGNOSTIC_MESSAGE_BYTES),
13
+ };
14
+ }
15
+ const CONTROL_PATTERN = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g;
16
+ const TRUNCATE_SUFFIX = "…";
17
+ /** Stable identity key; the delta treats two diagnostics with the same key as one item. */
18
+ export function diagnosticIdentity(diagnostic) {
19
+ const code = diagnostic.code === undefined ? "" : String(diagnostic.code);
20
+ return `${diagnostic.file}:${diagnostic.source}:${diagnostic.line}:${diagnostic.character}:${code}`;
21
+ }
22
+ /**
23
+ * Validate and bound host-parsed diagnostics. Throws nothing on malformed
24
+ * entries: each is dropped fail-closed (never partially normalized).
25
+ * Out-of-workspace paths, control characters, and non-finite positions are
26
+ * rejected per entry; overflow charges the per-file cap.
27
+ */
28
+ export function normalizeDiagnostics(raw, options) {
29
+ const limits = resolveDiagnosticsLimits({
30
+ maxDiagnosticsPerFile: options.maxDiagnosticsPerFile,
31
+ maxMessageBytes: options.maxMessageBytes,
32
+ });
33
+ const root = resolve(options.workspaceRoot);
34
+ const perFileCounts = {};
35
+ const out = [];
36
+ for (const entry of raw) {
37
+ if (!entry || typeof entry !== "object") {
38
+ continue;
39
+ }
40
+ const file = normalizeFile(root, entry.file);
41
+ if (!file) {
42
+ continue;
43
+ }
44
+ if (typeof entry.message !== "string" || entry.message.length === 0) {
45
+ continue;
46
+ }
47
+ const severity = entry.severity ?? "error";
48
+ if (severity !== "error" && severity !== "warning" && severity !== "info" && severity !== "hint") {
49
+ continue;
50
+ }
51
+ const line = finiteInt(entry.line, 0);
52
+ const character = finiteInt(entry.character, 0);
53
+ const endLine = finiteInt(entry.endLine, line);
54
+ const endCharacter = finiteInt(entry.endCharacter, character);
55
+ // negative or non-finite positions are rejected, never clamped
56
+ if (!Number.isSafeInteger(line) ||
57
+ !Number.isSafeInteger(character) ||
58
+ !Number.isSafeInteger(endLine) ||
59
+ !Number.isSafeInteger(endCharacter)) {
60
+ continue;
61
+ }
62
+ if (endLine < line || (endLine === line && endCharacter < character)) {
63
+ continue;
64
+ }
65
+ const message = truncateUtf8(entry.message.replace(CONTROL_PATTERN, ""), limits.maxMessageBytes);
66
+ if (message.length === 0) {
67
+ continue;
68
+ }
69
+ const code = validCode(entry.code) ? entry.code : undefined;
70
+ const source = truncateUtf8(String(entry.source ?? "check"), limits.maxMessageBytes);
71
+ const diagnostic = {
72
+ file,
73
+ line,
74
+ character,
75
+ endLine,
76
+ endCharacter,
77
+ severity,
78
+ message,
79
+ source,
80
+ code,
81
+ generation: options.generation,
82
+ };
83
+ const count = perFileCounts[file] ?? 0;
84
+ if (count >= limits.maxDiagnosticsPerFile) {
85
+ continue;
86
+ }
87
+ perFileCounts[file] = count + 1;
88
+ out.push(diagnostic);
89
+ }
90
+ return out;
91
+ }
92
+ /**
93
+ * Deterministic added/removed/unchanged delta between two diagnostic
94
+ * generations. Identity is `diagnosticIdentity` (file:source:position:code);
95
+ * message/severity changes keep the same identity and count as unchanged —
96
+ * the delta tracks presence, not content edits (hosts diff content on demand).
97
+ * Stale previous entries (generation >= next's generation) are ignored.
98
+ */
99
+ export function diagnosticDelta(request) {
100
+ const identity = request.identity ?? diagnosticIdentity;
101
+ const nextGeneration = request.next[0]?.generation ?? 0;
102
+ const nextKeys = new Map();
103
+ const previousKeys = new Map();
104
+ let truncated = false;
105
+ for (const d of request.next) {
106
+ if (!d || typeof d !== "object") {
107
+ truncated = true;
108
+ continue;
109
+ }
110
+ const key = identity(d);
111
+ if (nextKeys.has(key)) {
112
+ truncated = true;
113
+ continue;
114
+ }
115
+ nextKeys.set(key, d);
116
+ }
117
+ for (const d of request.previous ?? []) {
118
+ if (!d || typeof d !== "object")
119
+ continue;
120
+ if (d.generation > nextGeneration)
121
+ continue; // stale: newer than the new view
122
+ const key = identity(d);
123
+ if (!previousKeys.has(key))
124
+ previousKeys.set(key, d);
125
+ }
126
+ const added = [];
127
+ const unchanged = [];
128
+ for (const d of nextKeys.values()) {
129
+ (previousKeys.has(identity(d)) ? unchanged : added).push(d);
130
+ }
131
+ const removed = [];
132
+ for (const d of previousKeys.values()) {
133
+ if (!nextKeys.has(identity(d)))
134
+ removed.push(d);
135
+ }
136
+ return { generation: nextGeneration, added, removed, unchanged, truncated };
137
+ }
138
+ function normalizeFile(root, file) {
139
+ if (typeof file !== "string" || file.length === 0)
140
+ return undefined;
141
+ if (file.includes("\0"))
142
+ return undefined;
143
+ if (isAbsolute(file)) {
144
+ const rel = relative(root, file);
145
+ if (rel.startsWith("..") || isAbsolute(rel))
146
+ return undefined;
147
+ return rel.split("\\").join("/");
148
+ }
149
+ const abs = resolve(root, file);
150
+ const rel = relative(root, abs);
151
+ if (rel.startsWith("..") || isAbsolute(rel))
152
+ return undefined;
153
+ return rel.split("\\").join("/");
154
+ }
155
+ function finiteInt(value, fallback) {
156
+ if (value === undefined)
157
+ return fallback; // absent position defaults
158
+ if (typeof value !== "number" || !Number.isFinite(value))
159
+ return Number.NaN; // malformed rejected
160
+ const floored = Math.floor(value);
161
+ if (floored < 0)
162
+ return Number.NaN; // negative positions rejected
163
+ return floored;
164
+ }
165
+ function validCode(value) {
166
+ return typeof value === "string" || (typeof value === "number" && Number.isFinite(value));
167
+ }
168
+ function truncateUtf8(text, maxBytes) {
169
+ let bytes = Buffer.byteLength(text, "utf8");
170
+ if (bytes <= maxBytes)
171
+ return text;
172
+ let result = text;
173
+ while (bytes > maxBytes && result.length > 0) {
174
+ result = result.slice(0, result.length - 1);
175
+ bytes = Buffer.byteLength(result, "utf8");
176
+ }
177
+ return result + TRUNCATE_SUFFIX;
178
+ }
179
+ //# sourceMappingURL=diagnostics.js.map
package/dist/git.d.ts CHANGED
@@ -52,6 +52,21 @@ export interface PrHandoff {
52
52
  }[];
53
53
  readonly artifact?: ArtifactReference;
54
54
  }
55
+ /** One entry from `git worktree list --porcelain -z` (plan 026 Task 3). */
56
+ export interface GitWorktreeEntry {
57
+ path: string;
58
+ head?: string;
59
+ branch?: string;
60
+ /** Porcelain `locked` record present. */
61
+ locked?: boolean;
62
+ /** Lock reason text when the porcelain record carries one. */
63
+ lockReason?: string;
64
+ }
65
+ export interface GitFingerprint {
66
+ /** SHA-256 of the credential-free remote URL plus default branch; never the URL itself. */
67
+ readonly remoteFingerprint: string;
68
+ readonly defaultBranch?: string;
69
+ }
55
70
  export interface GitOperations {
56
71
  status(options?: {
57
72
  includeIgnored?: boolean;
@@ -78,19 +93,23 @@ export interface GitOperations {
78
93
  checkpoint?: string;
79
94
  }>;
80
95
  worktree(options: {
81
- action: "list" | "add" | "remove";
96
+ action: "list" | "add" | "remove" | "lock" | "unlock";
82
97
  path?: string;
83
98
  branch?: string;
84
99
  force?: boolean;
100
+ reason?: string;
85
101
  signal?: AbortSignal;
86
102
  }): Promise<{
87
- worktrees: readonly {
88
- path: string;
89
- head?: string;
90
- branch?: string;
91
- }[];
103
+ worktrees: readonly GitWorktreeEntry[];
92
104
  path?: string;
93
105
  }>;
106
+ /**
107
+ * Repository identity for durable correlation: credential-free remote
108
+ * fingerprint plus default branch. Runs bounded read-only git queries only.
109
+ */
110
+ fingerprint(options?: {
111
+ signal?: AbortSignal;
112
+ }): Promise<GitFingerprint>;
94
113
  apply(options: {
95
114
  patch: string;
96
115
  action: "check" | "apply" | "reverse";
@@ -133,6 +152,8 @@ export interface CreateGitOperationsOptions extends CreateGitRunnerOptions, GitL
133
152
  };
134
153
  }
135
154
  export declare function createGitOperations(options: CreateGitOperationsOptions): Promise<GitOperations>;
155
+ /** Strip credentials from a remote URL, keeping scheme and host/path (plan 026 Task 3). */
156
+ export declare function redactRemoteUrl(url: string): string;
136
157
  export type { BoundGitRunner, CreateGitRunnerOptions, GitExecRequest, GitExecResult, GitRunner } from "./git-exec.js";
137
158
  export { createBoundGitRunner, GitError, runGitCli, SAFE_GIT_CONFIG_ARGS, SAFE_GIT_ENV, } from "./git-exec.js";
138
159
  export type { GitStatusBranch, GitStatusEntry, GitStatusEntryKind, GitStatusResult } from "./git-status.js";
package/dist/git.js CHANGED
@@ -8,6 +8,7 @@
8
8
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
9
9
  import { tmpdir } from "node:os";
10
10
  import { join } from "node:path";
11
+ import { sha256Hex } from "./artifacts.js";
11
12
  import { createBoundGitRunner, GitError, gitRequireOk, gitText, } from "./git-exec.js";
12
13
  import { parsePorcelainV2 } from "./git-status.js";
13
14
  import { DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_BYTES, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_WORKTREES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_BYTES, validateCodingLimit, } from "./limits.js";
@@ -227,6 +228,12 @@ export async function createGitOperations(options) {
227
228
  else if (current && record.startsWith("branch ")) {
228
229
  current.branch = record.slice("branch ".length);
229
230
  }
231
+ else if (current && record.startsWith("locked")) {
232
+ current.locked = true;
233
+ const reason = record.slice("locked".length).trim();
234
+ if (reason)
235
+ current.lockReason = reason;
236
+ }
230
237
  }
231
238
  if (current)
232
239
  worktrees.push(current);
@@ -235,6 +242,23 @@ export async function createGitOperations(options) {
235
242
  }
236
243
  return { worktrees };
237
244
  }
245
+ if (request.action === "lock" || request.action === "unlock") {
246
+ if (!request.path)
247
+ throw new GitError("worktree path is required");
248
+ if (request.path.includes("\0") || request.path.startsWith("-")) {
249
+ throw new GitError("worktree path must not start with '-' or contain NUL");
250
+ }
251
+ const args = ["worktree", request.action];
252
+ if (request.action === "lock" && request.reason) {
253
+ if (request.reason.includes("\0") || Buffer.byteLength(request.reason, "utf8") > 1024) {
254
+ throw new GitError("worktree lock reason must be bounded and NUL-free");
255
+ }
256
+ args.push("--reason", request.reason);
257
+ }
258
+ args.push("--", request.path);
259
+ await gitRequireOk(runner, { args, cwd, signal: request.signal, maxOutputBytes: limits.maxOutputBytes }, `git worktree ${request.action}`);
260
+ return { worktrees: (await worktree({ action: "list", signal: request.signal })).worktrees, path: request.path };
261
+ }
238
262
  if (request.action === "add") {
239
263
  const existing = await worktree({ action: "list", signal: request.signal });
240
264
  if (existing.worktrees.length >= limits.maxWorktrees) {
@@ -264,6 +288,22 @@ export async function createGitOperations(options) {
264
288
  await gitRequireOk(runner, { args, cwd, signal: request.signal, maxOutputBytes: limits.maxOutputBytes }, "git worktree remove");
265
289
  return { worktrees: (await worktree({ action: "list", signal: request.signal })).worktrees, path: request.path };
266
290
  }
291
+ async function fingerprint(options) {
292
+ const optional = async (args) => {
293
+ const result = await runner.exec({ args, cwd, signal: options?.signal, maxOutputBytes: 64 * 1024 });
294
+ if (result.exitCode !== 0)
295
+ return undefined;
296
+ const text = gitText(result).trim();
297
+ return text.length > 0 ? text : undefined;
298
+ };
299
+ const remoteUrl = await optional(["config", "--get", "remote.origin.url"]);
300
+ const originHead = await optional(["symbolic-ref", "-q", "--short", "refs/remotes/origin/HEAD"]);
301
+ const initDefault = await optional(["config", "--get", "init.defaultBranch"]);
302
+ const defaultBranch = originHead ? originHead.replace(/^origin\//, "") : initDefault;
303
+ const redacted = redactRemoteUrl(remoteUrl ?? "");
304
+ const fingerprintSource = Buffer.from(`${redacted}\0${defaultBranch ?? ""}`, "utf8");
305
+ return { remoteFingerprint: sha256Hex(fingerprintSource), defaultBranch };
306
+ }
267
307
  async function apply(request) {
268
308
  if (typeof request.patch !== "string")
269
309
  throw new GitError("patch must be a string");
@@ -488,7 +528,24 @@ export async function createGitOperations(options) {
488
528
  }
489
529
  return handoff;
490
530
  }
491
- return { status, diff, branch, worktree, apply, commit, prHandoff };
531
+ return { status, diff, branch, worktree, fingerprint, apply, commit, prHandoff };
532
+ }
533
+ /** Strip credentials from a remote URL, keeping scheme and host/path (plan 026 Task 3). */
534
+ export function redactRemoteUrl(url) {
535
+ if (typeof url !== "string" || url.length === 0)
536
+ return "";
537
+ let rest = url;
538
+ let scheme = "";
539
+ const schemeMatch = /^([a-z][a-z0-9+.-]*:\/\/)/i.exec(url);
540
+ if (schemeMatch) {
541
+ scheme = schemeMatch[1];
542
+ rest = url.slice(scheme.length);
543
+ }
544
+ const at = rest.lastIndexOf("@");
545
+ const slash = rest.indexOf("/");
546
+ if (at >= 0 && (slash < 0 || at < slash))
547
+ rest = rest.slice(at + 1);
548
+ return scheme + rest;
492
549
  }
493
550
  export { createBoundGitRunner, GitError, runGitCli, SAFE_GIT_CONFIG_ARGS, SAFE_GIT_ENV, } from "./git-exec.js";
494
551
  export { parsePorcelainV2 } from "./git-status.js";
package/dist/index.d.ts CHANGED
@@ -30,17 +30,26 @@ export type { ReadOperations, ReadTextOptions, ReadTextResult, ReadToolOptions,
30
30
  export { createReadTool, DEFAULT_MAX_IMAGE_BYTES, detectSupportedImageMimeType, detectSupportedImageMimeTypeFromFile, } from "./read.js";
31
31
  export type { ReadPathSet } from "./read-path-set.js";
32
32
  export { createReadPathSet, createReadPathSetPersistence, DEFAULT_MAX_PERSISTED_READ_PATHS, DEFAULT_MAX_PERSISTED_READ_PATH_CHARS, READ_PATH_SET_NAMESPACE, } from "./read-path-set.js";
33
- export type { RepoEntryKind, RepoListEntry, RepositoryGlobRequest, RepositoryGlobResult, RepositoryLimitOptions, RepositoryListRequest, RepositoryListResult, RepositoryOperations, RepoSearchOutputMode, RepositorySearchMatch, RepositorySearchRequest, RepositorySearchResult, ResolvedRepositoryLimits, RepositoryWalk, RepositoryWalkEvent, RepositoryWalkLimits, } from "./repository.js";
34
- export { compileSearchPattern, createLocalRepositoryOperations, DEFAULT_REPO_EXCLUDE, isBinaryBuffer, RepositoryError, resolveRepoPath, resolveRepositoryLimits, toRepoRelative, } from "./repository.js";
33
+ export type { RepoEntryKind, RepoListEntry, RepoSearchMode, IndexFileChange, IndexFacade, IndexLimitOptions, IndexResourceDiagnostics, IndexSearchHit, IndexState, IndexedRepositoryOptions, RepositoryGlobRequest, RepositoryGlobResult, RepositoryIndexBackend, RepositoryIndexQueryRequest, RepositoryIndexQueryResult, RepositoryIndexRemoveRequest, RepositoryIndexStatus, RepositoryIndexUpdateRequest, RepositoryLimitOptions, RepositoryListRequest, RepositoryListResult, RepositoryOperations, RepoSearchOutputMode, RepositorySearchMatch, RepositorySearchRequest, RepositorySearchResult, ResolvedIndexLimits, ResolvedRepositoryLimits, RepositoryWalk, RepositoryWalkEvent, RepositoryWalkLimits, } from "./repository.js";
34
+ export { compileSearchPattern, createLocalRepositoryOperations, DEFAULT_REPO_EXCLUDE, IndexError, isBinaryBuffer, RepositoryError, resolveRepoPath, resolveRepositoryLimits, toRepoRelative, } from "./repository.js";
35
+ export { createIndexedRepositoryOperations, resolveIndexLimits } from "./repository.js";
35
36
  export type { GitAwareRepositoryOptions } from "./git-aware-repository.js";
36
37
  export { createGitAwareRepositoryOperations, parseGitLsFilesZ } from "./git-aware-repository.js";
38
+ export { createCodingWorkspaceLifecycle, resolveWorkspaceLimits, WORKSPACE_LOCK_REASON_PREFIX, WORKSPACE_NAMESPACE, WORKSPACE_SCHEMA_VERSION, WORKSPACE_STATES, WorkspaceError, } from "./workspace-lifecycle.js";
39
+ export type { CodingWorkspaceLifecycle, CodingWorkspaceRecord, CreateCodingWorkspaceLifecycleOptions, ResolvedWorkspaceLimits, WorkspaceCleanupPolicy, WorkspaceCreateRequest, WorkspaceErrorCode, WorkspaceLimitOptions, WorkspaceRepositoryRecord, WorkspaceRepositoryRegistration, WorkspaceRepositoryState, WorkspaceState, } from "./workspace-lifecycle.js";
37
40
  export type { CreateLanguageIntelligenceOptions, LanguageDiagnostic, LanguageIntelligence, LanguageIntelligenceLimits, LanguageLocation, LanguageServerSpec, LanguageSymbol, LanguageTextEdit, LanguageWorkspaceEdit, } from "./language/index.js";
38
41
  export { applyTextEdits, createLanguageIntelligence, encodeLspFrame, LanguageIntelligenceError, LspFrameError, LspFrameReader, resolveLanguageIntelligenceLimits, } from "./language/index.js";
39
42
  export type { CreateGitHubForgeOptions, ForgeCheck, ForgeCredential, ForgeCredentialResolver, ForgeCredentialResolverSource, ForgeErrorCode, ForgeHandoffReport, ForgeIssueContext, ForgeLimits, ForgeOperations, ForgePullRequest, ResolvedForgeLimits, } from "./forge/index.js";
40
43
  export { createGitHubForge, ForgeError, resolveForgeLimits } from "./forge/index.js";
41
- export type { CodingProcessEvent, CreateProcessSessionsOptions, ProcessExitResult, ProcessOutputChunk, ProcessSandboxBackend, ProcessSandboxHandle, ProcessSandboxStartRequest, ProcessSession, ProcessSessionLimits, ProcessSessionMetadata, ProcessSessions, ProcessSessionState, ProcessStartRequest, ResolvedProcessSessionLimits, } from "./process/index.js";
44
+ export type { CodingProcessEvent, CreateProcessSessionsOptions, ProcessExitResult, ProcessOutputChunk, ProcessPtyBackend, ProcessPtyHandle, ProcessPtyStartRequest, ProcessSandboxBackend, ProcessSandboxHandle, ProcessSandboxStartRequest, ProcessSession, ProcessSessionLimits, ProcessSessionMetadata, ProcessSessions, ProcessSessionState, ProcessStartRequest, ProcessTerminalRequest, ProcessTerminalResize, ResolvedProcessSessionLimits, } from "./process/index.js";
42
45
  export { createProcessSessions, ProcessSessionError, resolveProcessSessionLimits, } from "./process/index.js";
46
+ export { PROCESS_RECOVERY_CATEGORY, PROCESS_RECOVERY_LEASE_NAMESPACE, PROCESS_RECOVERY_NAMESPACE, PROCESS_RECOVERY_SCHEMA_VERSION, ProcessRecoveryError, resolveProcessRecoveryLimits, validateBackendRef, validateProcessRecoveryRecord, } from "./process/index.js";
47
+ export type { ProcessRecoveryBackend, ProcessRecoveryErrorCode, ProcessRecoveryLimits, ProcessRecoveryOutcome, ProcessRecoveryRecord, ProcessRecoveryRecordReport, ProcessRecoveryReport, ResolvedProcessRecoveryLimits, } from "./process/index.js";
43
48
  export type { SearchToolOptions } from "./search.js";
49
+ export { CodingPatchReviewError, assertCodingPatchAccepted, createCodingPatchReviewManifest, resolveCodingReviewLimits, } from "./review.js";
50
+ export type { AssertCodingPatchAcceptedInput, AssertCodingPatchAcceptedResult, CodingPatchReview, CodingPatchReviewCheckSummary, CodingPatchReviewDiagnosticSummary, CodingPatchReviewDiffstatEntry, CodingPatchReviewErrorCode, CodingPatchReviewIdentity, CodingPatchReviewState, CodingReviewArtifactInput, CodingReviewLimits, CreateCodingPatchReviewInput, ResolvedCodingReviewLimits, ReviewDiagnosticSeverity, } from "./review.js";
51
+ export { diagnosticDelta, diagnosticIdentity, normalizeDiagnostics, resolveDiagnosticsLimits } from "./diagnostics.js";
52
+ export type { DiagnosticDelta, DiagnosticDeltaRequest, DiagnosticSeverity, NormalizeDiagnosticsOptions, NormalizedDiagnostic, RawDiagnostic, ResolvedDiagnosticsLimits, } from "./diagnostics.js";
44
53
  export { createRepoSearchTool } from "./search.js";
45
54
  export type { BashExecOptions, BashOperations, BashSpawnContext, BashSpawnHook, ShellConfig, ShellToolOptions, } from "./shell.js";
46
55
  export { createLocalBashOperations, createShellTool, getShellConfig, killProcessTree, waitForChildProcess, } from "./shell.js";
@@ -48,7 +57,7 @@ export type { WriteOperations, WriteToolOptions } from "./write.js";
48
57
  export { createWriteTool } from "./write.js";
49
58
  export { enforceExecutionPolicy } from "./execution-policy.js";
50
59
  export { withFileMutationQueue } from "./file-mutation-queue.js";
51
- export { DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_BYTES, DEFAULT_MAX_CHECK_CONCURRENCY, DEFAULT_MAX_CHECK_DIAGNOSTIC_LINES, DEFAULT_MAX_CHECK_NAMES, DEFAULT_MAX_CHECK_OUTPUT_BYTES, DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, DEFAULT_MAX_FORGE_COMMENTS_PER_REVIEW, DEFAULT_MAX_FORGE_PAGES_PER_OPERATION, DEFAULT_MAX_FORGE_PAYLOAD_BYTES, DEFAULT_MAX_FORGE_REQUEST_CONCURRENCY, DEFAULT_MAX_FORGE_REQUEST_TIMEOUT_MS, DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_LS_FILES_OUTPUT_BYTES, DEFAULT_MAX_LSP_DIAGNOSTICS_PER_FILE, DEFAULT_MAX_LSP_MESSAGE_BYTES, DEFAULT_MAX_LSP_PENDING_REQUESTS, DEFAULT_MAX_LSP_RESULTS_PER_QUERY, DEFAULT_MAX_LSP_SERVERS, DEFAULT_MAX_LSP_TIMEOUT_MS, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_MAX_LINES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_BYTES, DEFAULT_MAX_PROCESS_INPUT_BYTES, DEFAULT_MAX_PROCESS_LIFETIME_MS, DEFAULT_MAX_PROCESS_OUTPUT_CHUNK_BYTES, DEFAULT_MAX_PROCESS_SESSIONS, DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_REPO_CONCURRENCY, DEFAULT_MAX_REPO_DEPTH, DEFAULT_MAX_REPO_ENTRIES, DEFAULT_MAX_REPO_FILES, DEFAULT_MAX_REPO_RESULTS, DEFAULT_MAX_SEARCH_CONTEXT_LINES, DEFAULT_MAX_SEARCH_FILE_BYTES, DEFAULT_MAX_SEARCH_LINE_BYTES, DEFAULT_MAX_SEARCH_MATCHES, DEFAULT_MAX_SEARCH_PATTERN_BYTES, DEFAULT_MAX_SEARCH_SCAN_BYTES, DEFAULT_MAX_SEARCH_TIME_MS, DEFAULT_MAX_TEXT_SCAN_BYTES, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_TODOS, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_WRITE_BYTES, DEFAULT_SHELL_TIMEOUT_SECONDS, HARD_CHECK_TIMEOUT_MS, HARD_GIT_TIMEOUT_MS, HARD_MAX_BYTES, HARD_MAX_CHECK_CONCURRENCY, HARD_MAX_CHECK_DIAGNOSTIC_LINES, HARD_MAX_CHECK_NAMES, HARD_MAX_CHECK_OUTPUT_BYTES, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, HARD_MAX_FORGE_COMMENTS_PER_REVIEW, HARD_MAX_FORGE_PAGES_PER_OPERATION, HARD_MAX_FORGE_PAYLOAD_BYTES, HARD_MAX_FORGE_REQUEST_CONCURRENCY, HARD_MAX_FORGE_REQUEST_TIMEOUT_MS, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_LS_FILES_OUTPUT_BYTES, HARD_MAX_LSP_DIAGNOSTICS_PER_FILE, HARD_MAX_LSP_MESSAGE_BYTES, HARD_MAX_LSP_PENDING_REQUESTS, HARD_MAX_LSP_RESULTS_PER_QUERY, HARD_MAX_LSP_SERVERS, HARD_MAX_LSP_TIMEOUT_MS, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_WORKTREES, HARD_MAX_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_PLAN_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_BYTES, HARD_MAX_PROCESS_INPUT_BYTES, HARD_MAX_PROCESS_LIFETIME_MS, HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES, HARD_MAX_PROCESS_SESSIONS, HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES, HARD_MAX_REPO_CONCURRENCY, HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_ENTRIES, HARD_MAX_REPO_FILES, HARD_MAX_REPO_RESULTS, HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_FILE_BYTES, HARD_MAX_SEARCH_LINE_BYTES, HARD_MAX_SEARCH_MATCHES, HARD_MAX_SEARCH_PATTERN_BYTES, HARD_MAX_SEARCH_SCAN_BYTES, HARD_MAX_SEARCH_TIME_MS, HARD_MAX_TEXT_SCAN_BYTES, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_TODOS, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_MAX_WRITE_BYTES, HARD_SHELL_TIMEOUT_SECONDS, LSP_RESTARTS_PER_SERVER, } from "./limits.js";
60
+ export { DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_BYTES, DEFAULT_MAX_CHECK_CONCURRENCY, DEFAULT_MAX_CHECK_DIAGNOSTIC_LINES, DEFAULT_MAX_CHECK_NAMES, DEFAULT_MAX_CHECK_OUTPUT_BYTES, DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, DEFAULT_MAX_FORGE_COMMENTS_PER_REVIEW, DEFAULT_MAX_FORGE_PAGES_PER_OPERATION, DEFAULT_MAX_FORGE_PAYLOAD_BYTES, DEFAULT_MAX_FORGE_REQUEST_CONCURRENCY, DEFAULT_MAX_FORGE_REQUEST_TIMEOUT_MS, DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_LS_FILES_OUTPUT_BYTES, DEFAULT_MAX_LSP_DIAGNOSTICS_PER_FILE, DEFAULT_MAX_LSP_MESSAGE_BYTES, DEFAULT_MAX_LSP_PENDING_REQUESTS, DEFAULT_MAX_LSP_RESULTS_PER_QUERY, DEFAULT_MAX_LSP_SERVERS, DEFAULT_MAX_LSP_TIMEOUT_MS, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_MAX_LINES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_BYTES, DEFAULT_MAX_PROCESS_INPUT_BYTES, DEFAULT_MAX_PROCESS_LIFETIME_MS, DEFAULT_MAX_PROCESS_OUTPUT_CHUNK_BYTES, DEFAULT_MAX_PROCESS_SESSIONS, DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_PTY_ATTACH_TIMEOUT_MS, DEFAULT_MAX_PTY_BACKEND_METADATA_BYTES, DEFAULT_MAX_REPO_CONCURRENCY, DEFAULT_MAX_REPO_DEPTH, DEFAULT_MAX_REPO_ENTRIES, DEFAULT_MAX_REPO_FILES, DEFAULT_MAX_REPO_RESULTS, DEFAULT_MAX_SEARCH_CONTEXT_LINES, DEFAULT_MAX_SEARCH_FILE_BYTES, DEFAULT_MAX_SEARCH_LINE_BYTES, DEFAULT_MAX_SEARCH_MATCHES, DEFAULT_MAX_SEARCH_PATTERN_BYTES, DEFAULT_MAX_SEARCH_SCAN_BYTES, DEFAULT_MAX_SEARCH_TIME_MS, DEFAULT_MAX_TEXT_SCAN_BYTES, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_TODOS, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_TERMINAL_COLUMNS, DEFAULT_MAX_TERMINAL_RESIZES_PER_MINUTE, DEFAULT_MAX_TERMINAL_ROWS, DEFAULT_MAX_TERMINAL_TERM_BYTES, DEFAULT_MAX_WRITE_BYTES, DEFAULT_SHELL_TIMEOUT_SECONDS, HARD_CHECK_TIMEOUT_MS, HARD_GIT_TIMEOUT_MS, HARD_MAX_BYTES, HARD_MAX_CHECK_CONCURRENCY, HARD_MAX_CHECK_DIAGNOSTIC_LINES, HARD_MAX_CHECK_NAMES, HARD_MAX_CHECK_OUTPUT_BYTES, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, HARD_MAX_FORGE_COMMENTS_PER_REVIEW, HARD_MAX_FORGE_PAGES_PER_OPERATION, HARD_MAX_FORGE_PAYLOAD_BYTES, HARD_MAX_FORGE_REQUEST_CONCURRENCY, HARD_MAX_FORGE_REQUEST_TIMEOUT_MS, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_LS_FILES_OUTPUT_BYTES, HARD_MAX_LSP_DIAGNOSTICS_PER_FILE, HARD_MAX_LSP_MESSAGE_BYTES, HARD_MAX_LSP_PENDING_REQUESTS, HARD_MAX_LSP_RESULTS_PER_QUERY, HARD_MAX_LSP_SERVERS, HARD_MAX_LSP_TIMEOUT_MS, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_WORKTREES, HARD_MAX_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_PLAN_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_BYTES, HARD_MAX_PROCESS_INPUT_BYTES, HARD_MAX_PROCESS_LIFETIME_MS, HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES, HARD_MAX_PROCESS_SESSIONS, HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES, HARD_MAX_PTY_ATTACH_TIMEOUT_MS, HARD_MAX_PTY_BACKEND_METADATA_BYTES, HARD_MAX_REPO_CONCURRENCY, HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_ENTRIES, HARD_MAX_REPO_FILES, HARD_MAX_REPO_RESULTS, HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_FILE_BYTES, HARD_MAX_SEARCH_LINE_BYTES, HARD_MAX_SEARCH_MATCHES, HARD_MAX_SEARCH_PATTERN_BYTES, HARD_MAX_SEARCH_SCAN_BYTES, HARD_MAX_SEARCH_TIME_MS, HARD_MAX_TEXT_SCAN_BYTES, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_TODOS, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_MAX_TERMINAL_COLUMNS, HARD_MAX_TERMINAL_RESIZES_PER_MINUTE, HARD_MAX_TERMINAL_ROWS, HARD_MAX_TERMINAL_TERM_BYTES, HARD_MAX_WRITE_BYTES, HARD_SHELL_TIMEOUT_SECONDS, LSP_RESTARTS_PER_SERVER, } from "./limits.js";
52
61
  import type { ExecutionPolicy, ToolDefinition } from "@arnilo/prism";
53
62
  import type { DeleteToolOptions } from "./delete.js";
54
63
  import type { EditToolOptions } from "./edit.js";
package/dist/index.js CHANGED
@@ -21,18 +21,29 @@ export { createRepoListTool } from "./list.js";
21
21
  export { createMoveTool } from "./move.js";
22
22
  export { createReadTool, DEFAULT_MAX_IMAGE_BYTES, detectSupportedImageMimeType, detectSupportedImageMimeTypeFromFile, } from "./read.js";
23
23
  export { createReadPathSet, createReadPathSetPersistence, DEFAULT_MAX_PERSISTED_READ_PATHS, DEFAULT_MAX_PERSISTED_READ_PATH_CHARS, READ_PATH_SET_NAMESPACE, } from "./read-path-set.js";
24
- export { compileSearchPattern, createLocalRepositoryOperations, DEFAULT_REPO_EXCLUDE, isBinaryBuffer, RepositoryError, resolveRepoPath, resolveRepositoryLimits, toRepoRelative, } from "./repository.js";
24
+ export { compileSearchPattern, createLocalRepositoryOperations, DEFAULT_REPO_EXCLUDE, IndexError, isBinaryBuffer, RepositoryError, resolveRepoPath, resolveRepositoryLimits, toRepoRelative, } from "./repository.js";
25
+ // host-indexed search seam (plan 026 Task 2): compose a host index with the
26
+ // literal fallback; indexed_literal/semantic never fall back silently
27
+ export { createIndexedRepositoryOperations, resolveIndexLimits } from "./repository.js";
25
28
  export { createGitAwareRepositoryOperations, parseGitLsFilesZ } from "./git-aware-repository.js";
29
+ export { createCodingWorkspaceLifecycle, resolveWorkspaceLimits, WORKSPACE_LOCK_REASON_PREFIX, WORKSPACE_NAMESPACE, WORKSPACE_SCHEMA_VERSION, WORKSPACE_STATES, WorkspaceError, } from "./workspace-lifecycle.js";
26
30
  export { applyTextEdits, createLanguageIntelligence, encodeLspFrame, LanguageIntelligenceError, LspFrameError, LspFrameReader, resolveLanguageIntelligenceLimits, } from "./language/index.js";
27
31
  export { createGitHubForge, ForgeError, resolveForgeLimits } from "./forge/index.js";
28
32
  export { createProcessSessions, ProcessSessionError, resolveProcessSessionLimits, } from "./process/index.js";
33
+ // durable process/ACP recovery seam (plan 026 Task 5): recover() is
34
+ // attach-if-attested and never fabricates an exit code; exports below
35
+ export { PROCESS_RECOVERY_CATEGORY, PROCESS_RECOVERY_LEASE_NAMESPACE, PROCESS_RECOVERY_NAMESPACE, PROCESS_RECOVERY_SCHEMA_VERSION, ProcessRecoveryError, resolveProcessRecoveryLimits, validateBackendRef, validateProcessRecoveryRecord, } from "./process/index.js";
36
+ // bounded patch review (plan 026 Task 6): createCodingPatchReviewManifest +
37
+ // assertCodingPatchAccepted bind decisions to digest + revision + identity
38
+ export { CodingPatchReviewError, assertCodingPatchAccepted, createCodingPatchReviewManifest, resolveCodingReviewLimits, } from "./review.js";
39
+ export { diagnosticDelta, diagnosticIdentity, normalizeDiagnostics, resolveDiagnosticsLimits } from "./diagnostics.js";
29
40
  export { createRepoSearchTool } from "./search.js";
30
41
  export { createLocalBashOperations, createShellTool, getShellConfig, killProcessTree, waitForChildProcess, } from "./shell.js";
31
42
  export { createWriteTool } from "./write.js";
32
43
  // --- generic primitives (re-exported for hosts that want them) ---
33
44
  export { enforceExecutionPolicy } from "./execution-policy.js";
34
45
  export { withFileMutationQueue } from "./file-mutation-queue.js";
35
- export { DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_BYTES, DEFAULT_MAX_CHECK_CONCURRENCY, DEFAULT_MAX_CHECK_DIAGNOSTIC_LINES, DEFAULT_MAX_CHECK_NAMES, DEFAULT_MAX_CHECK_OUTPUT_BYTES, DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, DEFAULT_MAX_FORGE_COMMENTS_PER_REVIEW, DEFAULT_MAX_FORGE_PAGES_PER_OPERATION, DEFAULT_MAX_FORGE_PAYLOAD_BYTES, DEFAULT_MAX_FORGE_REQUEST_CONCURRENCY, DEFAULT_MAX_FORGE_REQUEST_TIMEOUT_MS, DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_LS_FILES_OUTPUT_BYTES, DEFAULT_MAX_LSP_DIAGNOSTICS_PER_FILE, DEFAULT_MAX_LSP_MESSAGE_BYTES, DEFAULT_MAX_LSP_PENDING_REQUESTS, DEFAULT_MAX_LSP_RESULTS_PER_QUERY, DEFAULT_MAX_LSP_SERVERS, DEFAULT_MAX_LSP_TIMEOUT_MS, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_MAX_LINES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_BYTES, DEFAULT_MAX_PROCESS_INPUT_BYTES, DEFAULT_MAX_PROCESS_LIFETIME_MS, DEFAULT_MAX_PROCESS_OUTPUT_CHUNK_BYTES, DEFAULT_MAX_PROCESS_SESSIONS, DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_REPO_CONCURRENCY, DEFAULT_MAX_REPO_DEPTH, DEFAULT_MAX_REPO_ENTRIES, DEFAULT_MAX_REPO_FILES, DEFAULT_MAX_REPO_RESULTS, DEFAULT_MAX_SEARCH_CONTEXT_LINES, DEFAULT_MAX_SEARCH_FILE_BYTES, DEFAULT_MAX_SEARCH_LINE_BYTES, DEFAULT_MAX_SEARCH_MATCHES, DEFAULT_MAX_SEARCH_PATTERN_BYTES, DEFAULT_MAX_SEARCH_SCAN_BYTES, DEFAULT_MAX_SEARCH_TIME_MS, DEFAULT_MAX_TEXT_SCAN_BYTES, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_TODOS, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_WRITE_BYTES, DEFAULT_SHELL_TIMEOUT_SECONDS, HARD_CHECK_TIMEOUT_MS, HARD_GIT_TIMEOUT_MS, HARD_MAX_BYTES, HARD_MAX_CHECK_CONCURRENCY, HARD_MAX_CHECK_DIAGNOSTIC_LINES, HARD_MAX_CHECK_NAMES, HARD_MAX_CHECK_OUTPUT_BYTES, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, HARD_MAX_FORGE_COMMENTS_PER_REVIEW, HARD_MAX_FORGE_PAGES_PER_OPERATION, HARD_MAX_FORGE_PAYLOAD_BYTES, HARD_MAX_FORGE_REQUEST_CONCURRENCY, HARD_MAX_FORGE_REQUEST_TIMEOUT_MS, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_LS_FILES_OUTPUT_BYTES, HARD_MAX_LSP_DIAGNOSTICS_PER_FILE, HARD_MAX_LSP_MESSAGE_BYTES, HARD_MAX_LSP_PENDING_REQUESTS, HARD_MAX_LSP_RESULTS_PER_QUERY, HARD_MAX_LSP_SERVERS, HARD_MAX_LSP_TIMEOUT_MS, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_WORKTREES, HARD_MAX_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_PLAN_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_BYTES, HARD_MAX_PROCESS_INPUT_BYTES, HARD_MAX_PROCESS_LIFETIME_MS, HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES, HARD_MAX_PROCESS_SESSIONS, HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES, HARD_MAX_REPO_CONCURRENCY, HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_ENTRIES, HARD_MAX_REPO_FILES, HARD_MAX_REPO_RESULTS, HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_FILE_BYTES, HARD_MAX_SEARCH_LINE_BYTES, HARD_MAX_SEARCH_MATCHES, HARD_MAX_SEARCH_PATTERN_BYTES, HARD_MAX_SEARCH_SCAN_BYTES, HARD_MAX_SEARCH_TIME_MS, HARD_MAX_TEXT_SCAN_BYTES, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_TODOS, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_MAX_WRITE_BYTES, HARD_SHELL_TIMEOUT_SECONDS, LSP_RESTARTS_PER_SERVER, } from "./limits.js";
46
+ export { DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_BYTES, DEFAULT_MAX_CHECK_CONCURRENCY, DEFAULT_MAX_CHECK_DIAGNOSTIC_LINES, DEFAULT_MAX_CHECK_NAMES, DEFAULT_MAX_CHECK_OUTPUT_BYTES, DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, DEFAULT_MAX_FORGE_COMMENTS_PER_REVIEW, DEFAULT_MAX_FORGE_PAGES_PER_OPERATION, DEFAULT_MAX_FORGE_PAYLOAD_BYTES, DEFAULT_MAX_FORGE_REQUEST_CONCURRENCY, DEFAULT_MAX_FORGE_REQUEST_TIMEOUT_MS, DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_LS_FILES_OUTPUT_BYTES, DEFAULT_MAX_LSP_DIAGNOSTICS_PER_FILE, DEFAULT_MAX_LSP_MESSAGE_BYTES, DEFAULT_MAX_LSP_PENDING_REQUESTS, DEFAULT_MAX_LSP_RESULTS_PER_QUERY, DEFAULT_MAX_LSP_SERVERS, DEFAULT_MAX_LSP_TIMEOUT_MS, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_MAX_LINES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_BYTES, DEFAULT_MAX_PROCESS_INPUT_BYTES, DEFAULT_MAX_PROCESS_LIFETIME_MS, DEFAULT_MAX_PROCESS_OUTPUT_CHUNK_BYTES, DEFAULT_MAX_PROCESS_SESSIONS, DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_PTY_ATTACH_TIMEOUT_MS, DEFAULT_MAX_PTY_BACKEND_METADATA_BYTES, DEFAULT_MAX_REPO_CONCURRENCY, DEFAULT_MAX_REPO_DEPTH, DEFAULT_MAX_REPO_ENTRIES, DEFAULT_MAX_REPO_FILES, DEFAULT_MAX_REPO_RESULTS, DEFAULT_MAX_SEARCH_CONTEXT_LINES, DEFAULT_MAX_SEARCH_FILE_BYTES, DEFAULT_MAX_SEARCH_LINE_BYTES, DEFAULT_MAX_SEARCH_MATCHES, DEFAULT_MAX_SEARCH_PATTERN_BYTES, DEFAULT_MAX_SEARCH_SCAN_BYTES, DEFAULT_MAX_SEARCH_TIME_MS, DEFAULT_MAX_TEXT_SCAN_BYTES, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_TODOS, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_TERMINAL_COLUMNS, DEFAULT_MAX_TERMINAL_RESIZES_PER_MINUTE, DEFAULT_MAX_TERMINAL_ROWS, DEFAULT_MAX_TERMINAL_TERM_BYTES, DEFAULT_MAX_WRITE_BYTES, DEFAULT_SHELL_TIMEOUT_SECONDS, HARD_CHECK_TIMEOUT_MS, HARD_GIT_TIMEOUT_MS, HARD_MAX_BYTES, HARD_MAX_CHECK_CONCURRENCY, HARD_MAX_CHECK_DIAGNOSTIC_LINES, HARD_MAX_CHECK_NAMES, HARD_MAX_CHECK_OUTPUT_BYTES, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, HARD_MAX_FORGE_COMMENTS_PER_REVIEW, HARD_MAX_FORGE_PAGES_PER_OPERATION, HARD_MAX_FORGE_PAYLOAD_BYTES, HARD_MAX_FORGE_REQUEST_CONCURRENCY, HARD_MAX_FORGE_REQUEST_TIMEOUT_MS, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_LS_FILES_OUTPUT_BYTES, HARD_MAX_LSP_DIAGNOSTICS_PER_FILE, HARD_MAX_LSP_MESSAGE_BYTES, HARD_MAX_LSP_PENDING_REQUESTS, HARD_MAX_LSP_RESULTS_PER_QUERY, HARD_MAX_LSP_SERVERS, HARD_MAX_LSP_TIMEOUT_MS, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_WORKTREES, HARD_MAX_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_PLAN_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_BYTES, HARD_MAX_PROCESS_INPUT_BYTES, HARD_MAX_PROCESS_LIFETIME_MS, HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES, HARD_MAX_PROCESS_SESSIONS, HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES, HARD_MAX_PTY_ATTACH_TIMEOUT_MS, HARD_MAX_PTY_BACKEND_METADATA_BYTES, HARD_MAX_REPO_CONCURRENCY, HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_ENTRIES, HARD_MAX_REPO_FILES, HARD_MAX_REPO_RESULTS, HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_FILE_BYTES, HARD_MAX_SEARCH_LINE_BYTES, HARD_MAX_SEARCH_MATCHES, HARD_MAX_SEARCH_PATTERN_BYTES, HARD_MAX_SEARCH_SCAN_BYTES, HARD_MAX_SEARCH_TIME_MS, HARD_MAX_TEXT_SCAN_BYTES, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_TODOS, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_MAX_TERMINAL_COLUMNS, HARD_MAX_TERMINAL_RESIZES_PER_MINUTE, HARD_MAX_TERMINAL_ROWS, HARD_MAX_TERMINAL_TERM_BYTES, HARD_MAX_WRITE_BYTES, HARD_SHELL_TIMEOUT_SECONDS, LSP_RESTARTS_PER_SERVER, } from "./limits.js";
36
47
  import { createDeleteTool } from "./delete.js";
37
48
  import { createEditTool } from "./edit.js";
38
49
  import { createGlobTool } from "./glob.js";
@@ -24,6 +24,10 @@ export declare class LspClient {
24
24
  private capabilities;
25
25
  /** file URI → latest diagnostics payload from publishDiagnostics */
26
26
  readonly diagnosticsByUri: Map<string, unknown>;
27
+ /** file URI → monotonic document version (didOpen=1, each didChange += 1) */
28
+ readonly documentVersions: Map<string, number>;
29
+ /** file URI → last pull-diagnostic resultId (textDocument/diagnostic) */
30
+ readonly pullResultIds: Map<string, string>;
27
31
  private readonly onUnexpectedExit;
28
32
  constructor(spec: LspServerSpec, limits: ResolvedLanguageIntelligenceLimits, hooks?: {
29
33
  onUnexpectedExit?: () => void;
@@ -32,6 +36,27 @@ export declare class LspClient {
32
36
  ensureStarted(signal?: AbortSignal): Promise<void>;
33
37
  request(method: string, params: unknown, signal?: AbortSignal): Promise<unknown>;
34
38
  notify(method: string, params: unknown): void;
39
+ /**
40
+ * Full-content textDocument/didChange (LSP 3.17; protocol-valid, no diff
41
+ * engine needed). Monotonic version: didOpen stamps 1, each didChange
42
+ * increments. No-op when the document was never opened.
43
+ */
44
+ didChange(uri: string, text: string): void;
45
+ /** true when the server advertises textDocument/diagnostic (pull diagnostics). */
46
+ hasPullDiagnostics(): boolean;
47
+ /**
48
+ * Pull diagnostics for one opened document (textDocument/diagnostic) with
49
+ * resultId reuse: `kind: "full"` replaces the set, `kind: "unchanged"`
50
+ * reuses the previous payload. Returns the version at request time so the
51
+ * caller can drop stale responses. Falls back to the push cache when the
52
+ * server has no pull support.
53
+ */
54
+ pullDiagnostics(uri: string, signal?: AbortSignal): Promise<{
55
+ kind: "full" | "unchanged";
56
+ diagnostics: unknown;
57
+ resultId?: string;
58
+ version: number;
59
+ }>;
35
60
  hasCapability(key: string): boolean;
36
61
  dispose(): Promise<void>;
37
62
  private write;