@arnilo/prism-coding-agent 0.2.4 → 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.
Files changed (50) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +10 -0
  3. package/dist/coding-checkpoint.js +4 -0
  4. package/dist/diagnostics.d.ts +83 -0
  5. package/dist/diagnostics.js +179 -0
  6. package/dist/git.d.ts +27 -6
  7. package/dist/git.js +58 -1
  8. package/dist/index.d.ts +13 -4
  9. package/dist/index.js +13 -2
  10. package/dist/language/client.d.ts +25 -0
  11. package/dist/language/client.js +54 -0
  12. package/dist/language/framing.d.ts +9 -1
  13. package/dist/language/framing.js +89 -17
  14. package/dist/language/index.d.ts +1 -1
  15. package/dist/language/intelligence.js +58 -0
  16. package/dist/language/types.d.ts +32 -0
  17. package/dist/limits.d.ts +59 -0
  18. package/dist/limits.js +59 -0
  19. package/dist/process/index.d.ts +4 -1
  20. package/dist/process/index.js +1 -0
  21. package/dist/process/recovery.d.ts +174 -0
  22. package/dist/process/recovery.js +320 -0
  23. package/dist/process/sessions.js +714 -25
  24. package/dist/process/types.d.ts +128 -4
  25. package/dist/process/types.js +7 -1
  26. package/dist/repository/glob.d.ts +4 -0
  27. package/dist/repository/glob.js +143 -0
  28. package/dist/repository/indexed-search.d.ts +121 -0
  29. package/dist/repository/indexed-search.js +313 -0
  30. package/dist/repository/list.d.ts +3 -0
  31. package/dist/repository/list.js +119 -0
  32. package/dist/repository/operations.d.ts +5 -0
  33. package/dist/repository/operations.js +14 -0
  34. package/dist/repository/path.d.ts +18 -0
  35. package/dist/repository/path.js +91 -0
  36. package/dist/repository/search.d.ts +9 -0
  37. package/dist/repository/search.js +284 -0
  38. package/dist/repository/types.d.ts +138 -0
  39. package/dist/repository/types.js +31 -0
  40. package/dist/repository/walk.d.ts +22 -0
  41. package/dist/repository/walk.js +99 -0
  42. package/dist/repository.d.ts +11 -172
  43. package/dist/repository.js +11 -748
  44. package/dist/review.d.ts +150 -0
  45. package/dist/review.js +222 -0
  46. package/dist/search.d.ts +3 -1
  47. package/dist/search.js +42 -7
  48. package/dist/workspace-lifecycle.d.ts +153 -0
  49. package/dist/workspace-lifecycle.js +629 -0
  50. package/package.json +3 -3
@@ -18,6 +18,10 @@ export class LspClient {
18
18
  capabilities = {};
19
19
  /** file URI → latest diagnostics payload from publishDiagnostics */
20
20
  diagnosticsByUri = new Map();
21
+ /** file URI → monotonic document version (didOpen=1, each didChange += 1) */
22
+ documentVersions = new Map();
23
+ /** file URI → last pull-diagnostic resultId (textDocument/diagnostic) */
24
+ pullResultIds = new Map();
21
25
  onUnexpectedExit;
22
26
  constructor(spec, limits, hooks) {
23
27
  this.spec = spec;
@@ -88,6 +92,55 @@ export class LspClient {
88
92
  return;
89
93
  this.write({ jsonrpc: "2.0", method, params });
90
94
  }
95
+ /**
96
+ * Full-content textDocument/didChange (LSP 3.17; protocol-valid, no diff
97
+ * engine needed). Monotonic version: didOpen stamps 1, each didChange
98
+ * increments. No-op when the document was never opened.
99
+ */
100
+ didChange(uri, text) {
101
+ const version = (this.documentVersions.get(uri) ?? 0) + 1;
102
+ this.documentVersions.set(uri, version);
103
+ this.notify("textDocument/didChange", {
104
+ textDocument: { uri, version },
105
+ contentChanges: [{ text }],
106
+ });
107
+ }
108
+ /** true when the server advertises textDocument/diagnostic (pull diagnostics). */
109
+ hasPullDiagnostics() {
110
+ const provider = this.capabilities.diagnosticProvider;
111
+ if (!provider || provider === false)
112
+ return false;
113
+ return true;
114
+ }
115
+ /**
116
+ * Pull diagnostics for one opened document (textDocument/diagnostic) with
117
+ * resultId reuse: `kind: "full"` replaces the set, `kind: "unchanged"`
118
+ * reuses the previous payload. Returns the version at request time so the
119
+ * caller can drop stale responses. Falls back to the push cache when the
120
+ * server has no pull support.
121
+ */
122
+ async pullDiagnostics(uri, signal) {
123
+ const version = this.documentVersions.get(uri) ?? 1;
124
+ if (!this.hasPullDiagnostics()) {
125
+ return { kind: "full", diagnostics: this.diagnosticsByUri.get(uri) ?? [], version };
126
+ }
127
+ const previousResultId = this.pullResultIds.get(uri);
128
+ const result = (await this.request("textDocument/diagnostic", { textDocument: { uri }, ...(previousResultId === undefined ? {} : { previousResultId }) }, signal));
129
+ if (!result || typeof result !== "object") {
130
+ return { kind: "full", diagnostics: this.diagnosticsByUri.get(uri) ?? [], version };
131
+ }
132
+ if (result.kind === "unchanged") {
133
+ const cached = this.diagnosticsByUri.get(uri) ?? [];
134
+ if (typeof result.resultId === "string")
135
+ this.pullResultIds.set(uri, result.resultId);
136
+ return { kind: "unchanged", diagnostics: cached, resultId: result.resultId, version };
137
+ }
138
+ const items = Array.isArray(result.items) ? result.items : [];
139
+ this.diagnosticsByUri.set(uri, items);
140
+ if (typeof result.resultId === "string")
141
+ this.pullResultIds.set(uri, result.resultId);
142
+ return { kind: "full", diagnostics: items, resultId: result.resultId, version };
143
+ }
91
144
  hasCapability(key) {
92
145
  return this.capabilities[key] !== undefined && this.capabilities[key] !== false;
93
146
  }
@@ -177,6 +230,7 @@ export class LspClient {
177
230
  textDocument: {
178
231
  hover: { contentFormat: ["plaintext", "markdown"] },
179
232
  publishDiagnostics: {},
233
+ diagnostic: { dynamicRegistration: false },
180
234
  },
181
235
  },
182
236
  workspaceFolders: [{ uri: this.spec.rootUri, name: "workspace" }],
@@ -14,10 +14,18 @@ export declare function encodeLspFrame(message: unknown): Buffer;
14
14
  * Rejects malformed headers, non-decimal Content-Length, and oversized bodies.
15
15
  */
16
16
  export declare class LspFrameReader {
17
- private buf;
17
+ private chunks;
18
+ private offset;
19
+ private retained;
20
+ private cachedBodyStart;
21
+ private cachedContentLength;
18
22
  private readonly maxMessageBytes;
19
23
  constructor(maxMessageBytes: number);
20
24
  /** Push stdout/stderr chunk; return complete parsed JSON values (order preserved). */
21
25
  push(chunk: Buffer): unknown[];
26
+ /** Copy `n` unconsumed bytes starting at absolute unconsumed offset `start` (no advance). */
27
+ private peekAt;
28
+ /** Advance the unconsumed cursor by `n` (drop fully-consumed chunks). */
29
+ private drop;
22
30
  private tryParseOne;
23
31
  }
@@ -21,7 +21,20 @@ export function encodeLspFrame(message) {
21
21
  * Rejects malformed headers, non-decimal Content-Length, and oversized bodies.
22
22
  */
23
23
  export class LspFrameReader {
24
- buf = Buffer.alloc(0);
24
+ // ponytail: chunk-array accumulator — O(1) append per push, no whole-buffer re-concat
25
+ // (the 0.2.4 `this.buf = Buffer.concat([this.buf, chunk])` was O(input * chunks)).
26
+ // A completed frame copies only its header+body region (bounded by maxMessageBytes),
27
+ // so total copying is O(input). The header separator scan peeks min(retained, 64KiB)
28
+ // per unparsed frame; for the rare many-frames-per-large-chunk case that is a 64KiB-
29
+ // per-frame copy (linear, 64x constant) — upgrade to a streaming separator search
30
+ // if pipelined-frame throughput matters. A separator beyond the 64KiB header bound
31
+ // is rejected (stricter DoS guard than 0.2.4, which accepted it; no test exercises
32
+ // >64KiB headers — the bound exists precisely to reject unbounded header growth).
33
+ chunks = [];
34
+ offset = 0; // consumed prefix bytes in chunks[0]
35
+ retained = 0; // total unconsumed bytes
36
+ cachedBodyStart = -1; // -1 = header not yet parsed; else body starts at this absolute unconsumed offset
37
+ cachedContentLength = 0;
25
38
  maxMessageBytes;
26
39
  constructor(maxMessageBytes) {
27
40
  this.maxMessageBytes = maxMessageBytes;
@@ -30,7 +43,8 @@ export class LspFrameReader {
30
43
  push(chunk) {
31
44
  if (chunk.length === 0)
32
45
  return [];
33
- this.buf = Buffer.concat([this.buf, chunk]);
46
+ this.chunks.push(chunk);
47
+ this.retained += chunk.length;
34
48
  const out = [];
35
49
  for (;;) {
36
50
  const parsed = this.tryParseOne();
@@ -40,26 +54,84 @@ export class LspFrameReader {
40
54
  }
41
55
  return out;
42
56
  }
57
+ /** Copy `n` unconsumed bytes starting at absolute unconsumed offset `start` (no advance). */
58
+ peekAt(start, n) {
59
+ const out = Buffer.allocUnsafe(n);
60
+ let written = 0;
61
+ let i = 0;
62
+ let off = this.offset;
63
+ let skip = start;
64
+ while (skip > 0) {
65
+ const c = this.chunks[i];
66
+ const avail = c.length - off;
67
+ if (skip >= avail) {
68
+ skip -= avail;
69
+ i++;
70
+ off = 0;
71
+ }
72
+ else {
73
+ off += skip;
74
+ skip = 0;
75
+ }
76
+ }
77
+ while (written < n) {
78
+ const c = this.chunks[i];
79
+ const take = Math.min(c.length - off, n - written);
80
+ c.copy(out, written, off, off + take);
81
+ written += take;
82
+ i++;
83
+ off = 0;
84
+ }
85
+ return out;
86
+ }
87
+ /** Advance the unconsumed cursor by `n` (drop fully-consumed chunks). */
88
+ drop(n) {
89
+ let remaining = n;
90
+ while (remaining > 0 && this.chunks.length > 0) {
91
+ const first = this.chunks[0];
92
+ const avail = first.length - this.offset;
93
+ if (remaining >= avail) {
94
+ remaining -= avail;
95
+ this.chunks.shift();
96
+ this.offset = 0;
97
+ }
98
+ else {
99
+ this.offset += remaining;
100
+ remaining = 0;
101
+ }
102
+ }
103
+ this.retained -= n;
104
+ }
43
105
  tryParseOne() {
44
- const sep = indexOfHeaderSep(this.buf);
45
- if (sep < 0) {
106
+ if (this.retained === 0)
107
+ return undefined;
108
+ const headerBound = Math.min(this.maxMessageBytes, 64 * 1024);
109
+ if (this.cachedBodyStart < 0) {
46
110
  // Bound header scan buffer so a missing separator cannot grow forever.
47
- if (this.buf.length > Math.min(this.maxMessageBytes, 64 * 1024)) {
48
- throw new LspFrameError("ERR_PRISM_LSP_FRAMING", "LSP header exceeds bound without separator");
111
+ const scanLen = Math.min(this.retained, headerBound);
112
+ const view = this.peekAt(0, scanLen);
113
+ const sep = indexOfHeaderSep(view);
114
+ if (sep < 0) {
115
+ if (this.retained > headerBound) {
116
+ throw new LspFrameError("ERR_PRISM_LSP_FRAMING", "LSP header exceeds bound without separator");
117
+ }
118
+ return undefined;
49
119
  }
50
- return undefined;
51
- }
52
- const headerText = this.buf.subarray(0, sep).toString("ascii");
53
- const contentLength = parseContentLength(headerText);
54
- if (contentLength > this.maxMessageBytes) {
55
- throw new LspFrameError("ERR_PRISM_LSP_LIMIT", `LSP message body ${contentLength} exceeds maxMessageBytes ${this.maxMessageBytes}`);
120
+ const headerText = view.subarray(0, sep).toString("ascii");
121
+ const contentLength = parseContentLength(headerText);
122
+ if (contentLength > this.maxMessageBytes) {
123
+ throw new LspFrameError("ERR_PRISM_LSP_LIMIT", `LSP message body ${contentLength} exceeds maxMessageBytes ${this.maxMessageBytes}`);
124
+ }
125
+ this.cachedBodyStart = sep + 4;
126
+ this.cachedContentLength = contentLength;
56
127
  }
57
- const bodyStart = sep + 4;
58
- const bodyEnd = bodyStart + contentLength;
59
- if (this.buf.length < bodyEnd)
128
+ const bodyEnd = this.cachedBodyStart + this.cachedContentLength;
129
+ if (this.retained < bodyEnd)
60
130
  return undefined;
61
- const body = this.buf.subarray(bodyStart, bodyEnd);
62
- this.buf = this.buf.subarray(bodyEnd);
131
+ const body = this.peekAt(this.cachedBodyStart, this.cachedContentLength);
132
+ this.drop(bodyEnd);
133
+ this.cachedBodyStart = -1;
134
+ this.cachedContentLength = 0;
63
135
  let value;
64
136
  try {
65
137
  value = JSON.parse(body.toString("utf8"));
@@ -1,4 +1,4 @@
1
1
  export { encodeLspFrame, LspFrameError, LspFrameReader } from "./framing.js";
2
2
  export { LspClient } from "./client.js";
3
3
  export { applyTextEdits, createLanguageIntelligence, LanguageIntelligenceError, resolveLanguageIntelligenceLimits, } from "./intelligence.js";
4
- export type { CreateLanguageIntelligenceOptions, LanguageDiagnostic, LanguageIntelligence, LanguageIntelligenceLimits, LanguageLocation, LanguageServerSpec, LanguageSymbol, LanguageTextEdit, LanguageWorkspaceEdit, } from "./types.js";
4
+ export type { CreateLanguageIntelligenceOptions, LanguageDiagnostic, LanguageDiagnosticDeltaRequest, LanguageDiagnosticDeltaResult, LanguageFileDiagnostics, LanguageIntelligence, LanguageIntelligenceLimits, LanguageLocation, LanguageServerSpec, LanguageSymbol, LanguageTextEdit, LanguageWorkspaceEdit, } from "./types.js";
@@ -7,6 +7,7 @@ import { extname, isAbsolute, relative, resolve } from "node:path";
7
7
  import { fileURLToPath, pathToFileURL } from "node:url";
8
8
  import { assertExecutionAllowed, ExecutionDeniedError } from "@arnilo/prism";
9
9
  import { atomicWriteUtf8File } from "../atomic-write.js";
10
+ import { diagnosticDelta } from "../diagnostics.js";
10
11
  import { withFileMutationQueue } from "../file-mutation-queue.js";
11
12
  import { resolveContainedMutationPath } from "../mutation-path.js";
12
13
  import { LspClient } from "./client.js";
@@ -126,6 +127,7 @@ export function createLanguageIntelligence(options) {
126
127
  client.notify("textDocument/didOpen", {
127
128
  textDocument: { uri, languageId, version: 1, text },
128
129
  });
130
+ client.documentVersions.set(uri, 1);
129
131
  set.add(uri);
130
132
  }
131
133
  async function ensureAllStarted(signal) {
@@ -212,6 +214,62 @@ export function createLanguageIntelligence(options) {
212
214
  const text = hoverToText(contents);
213
215
  return text === undefined ? undefined : { text };
214
216
  },
217
+ async syncDocument(file, opts) {
218
+ assertNotDisposed();
219
+ const { client, uri, abs } = await clientForFile(file, opts?.signal);
220
+ const text = await readFile(abs, "utf8");
221
+ if (opts?.signal?.aborted) {
222
+ throw new LanguageIntelligenceError("ERR_PRISM_LSP_TIMEOUT", "syncDocument aborted");
223
+ }
224
+ client.didChange(uri, text);
225
+ const version = client.documentVersions.get(uri) ?? 1;
226
+ return { version };
227
+ },
228
+ async diagnosticDelta(request, opts) {
229
+ assertNotDisposed();
230
+ if (!Array.isArray(request.files) || request.files.length === 0) {
231
+ throw new LanguageIntelligenceError("ERR_PRISM_LSP_UNSUPPORTED", "diagnosticDelta requires a non-empty files list");
232
+ }
233
+ if (request.files.length > limits.maxResultsPerQuery) {
234
+ throw new LanguageIntelligenceError("ERR_PRISM_LSP_LIMIT", `diagnosticDelta files exceed ${limits.maxResultsPerQuery}`);
235
+ }
236
+ const previous = request.previous ?? {};
237
+ const files = {};
238
+ let latestGeneration = 0;
239
+ for (const file of request.files) {
240
+ const { client, uri } = await clientForFile(file, opts?.signal);
241
+ const pulled = await client.pullDiagnostics(uri, opts?.signal);
242
+ // Stale-version guard: the pull result carries the version at request
243
+ // time; if the document advanced meanwhile, drop the response.
244
+ const currentVersion = client.documentVersions.get(uri) ?? 1;
245
+ if (pulled.version < currentVersion)
246
+ continue;
247
+ const generation = currentVersion;
248
+ latestGeneration = Math.max(latestGeneration, generation);
249
+ const prior = previous[file];
250
+ if (prior && prior.generation > generation)
251
+ continue; // stale previous view
252
+ const raw = normalizeDiagnostics(workspaceRoot, uri, pulled.diagnostics, limits.maxDiagnosticsPerFile);
253
+ const stamped = raw.map((diagnostic) => ({
254
+ file: diagnostic.file,
255
+ line: diagnostic.line,
256
+ character: diagnostic.character,
257
+ endLine: diagnostic.endLine,
258
+ endCharacter: diagnostic.endCharacter,
259
+ severity: diagnostic.severity,
260
+ message: diagnostic.message,
261
+ source: diagnostic.source ?? "lsp",
262
+ code: diagnostic.code,
263
+ generation,
264
+ }));
265
+ const delta = diagnosticDelta({
266
+ next: stamped,
267
+ previous: prior?.diagnostics,
268
+ });
269
+ files[file] = delta;
270
+ }
271
+ return { files, generation: latestGeneration };
272
+ },
215
273
  async rename(loc, opts) {
216
274
  if (!loc.newName || typeof loc.newName !== "string") {
217
275
  throw new LanguageIntelligenceError("ERR_PRISM_LSP_UNSUPPORTED", "newName is required");
@@ -96,8 +96,40 @@ export interface LanguageIntelligence {
96
96
  }, opts?: {
97
97
  signal?: AbortSignal;
98
98
  }): Promise<LanguageWorkspaceEdit>;
99
+ /**
100
+ * Re-sync one file after an external edit: full-content didChange with a
101
+ * monotonic version. No-op when no host server handles the file's language
102
+ * (throws ERR_PRISM_LSP_UNSUPPORTED only when servers exist but none match).
103
+ */
104
+ syncDocument(file: string, opts?: {
105
+ signal?: AbortSignal;
106
+ }): Promise<{
107
+ version: number;
108
+ }>;
109
+ /**
110
+ * Bounded push/pull diagnostic refresh for changed files. Generations are
111
+ * document versions; stale-version results never overwrite newer views.
112
+ */
113
+ diagnosticDelta(request: LanguageDiagnosticDeltaRequest, opts?: {
114
+ signal?: AbortSignal;
115
+ }): Promise<LanguageDiagnosticDeltaResult>;
99
116
  dispose(): Promise<void>;
100
117
  }
118
+ export interface LanguageDiagnosticDeltaRequest {
119
+ /** Workspace-relative files to refresh; bounded per request. */
120
+ readonly files: readonly string[];
121
+ /** Prior normalized view per file (generation + diagnostics); optional. */
122
+ readonly previous?: Readonly<Record<string, LanguageFileDiagnostics>>;
123
+ }
124
+ export interface LanguageFileDiagnostics {
125
+ readonly generation: number;
126
+ readonly diagnostics: readonly import("../diagnostics.js").NormalizedDiagnostic[];
127
+ }
128
+ export interface LanguageDiagnosticDeltaResult {
129
+ /** Per-file delta; stale files (previous generation >= new generation) are omitted. */
130
+ readonly files: Record<string, import("../diagnostics.js").DiagnosticDelta>;
131
+ readonly generation: number;
132
+ }
101
133
  export interface CreateLanguageIntelligenceOptions {
102
134
  readonly workspaceRoot: string;
103
135
  readonly servers: Readonly<Record<string, LanguageServerSpec>>;
package/dist/limits.d.ts CHANGED
@@ -122,6 +122,42 @@ export declare const HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES: number;
122
122
  /** Total output reuses existing accumulator ceilings (64 MiB / 1 GiB). */
123
123
  export declare const DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES: number;
124
124
  export declare const HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES: number;
125
+ /** Phase 26 Task 0 freeze: host-selected PTY terminal caps (interactive sessions). */
126
+ export declare const DEFAULT_MAX_TERMINAL_COLUMNS = 120;
127
+ export declare const HARD_MAX_TERMINAL_COLUMNS = 500;
128
+ export declare const DEFAULT_MAX_TERMINAL_ROWS = 40;
129
+ export declare const HARD_MAX_TERMINAL_ROWS = 200;
130
+ export declare const DEFAULT_MAX_TERMINAL_TERM_BYTES = 64;
131
+ export declare const HARD_MAX_TERMINAL_TERM_BYTES = 256;
132
+ export declare const DEFAULT_MAX_TERMINAL_RESIZES_PER_MINUTE = 60;
133
+ export declare const HARD_MAX_TERMINAL_RESIZES_PER_MINUTE = 600;
134
+ export declare const DEFAULT_MAX_PTY_ATTACH_TIMEOUT_MS = 30000;
135
+ export declare const HARD_MAX_PTY_ATTACH_TIMEOUT_MS = 120000;
136
+ export declare const DEFAULT_MAX_PTY_BACKEND_METADATA_BYTES: number;
137
+ export declare const HARD_MAX_PTY_BACKEND_METADATA_BYTES: number;
138
+ /** Phase 26 Task 0 freeze: host index caps (indexed_literal/semantic repo_search). */
139
+ export declare const DEFAULT_MAX_INDEX_UPDATE_FILES = 1000;
140
+ export declare const HARD_MAX_INDEX_UPDATE_FILES = 10000;
141
+ export declare const DEFAULT_MAX_INDEX_UPDATE_BYTES: number;
142
+ export declare const HARD_MAX_INDEX_UPDATE_BYTES: number;
143
+ /** Index result cap reuses the repository results caps (1000 / 10000). */
144
+ export declare const DEFAULT_MAX_INDEX_SNIPPET_BYTES: number;
145
+ export declare const HARD_MAX_INDEX_SNIPPET_BYTES: number;
146
+ export declare const DEFAULT_MAX_INDEX_STALE_MAX_AGE_MS = 60000;
147
+ export declare const HARD_MAX_INDEX_STALE_MAX_AGE_MS = 300000;
148
+ export declare const DEFAULT_MAX_INDEX_QUERY_TIMEOUT_MS = 30000;
149
+ export declare const HARD_MAX_INDEX_QUERY_TIMEOUT_MS = 120000;
150
+ /** Phase 26 Task 0 freeze: patch-review manifest and diagnostic delta caps. */
151
+ export declare const DEFAULT_MAX_REVIEW_REVISIONS = 8;
152
+ export declare const HARD_MAX_REVIEW_REVISIONS = 32;
153
+ export declare const DEFAULT_MAX_REVIEW_DIAGNOSTICS = 500;
154
+ export declare const HARD_MAX_REVIEW_DIAGNOSTICS = 5000;
155
+ export declare const DEFAULT_MAX_REVIEW_MANIFEST_BYTES: number;
156
+ export declare const HARD_MAX_REVIEW_MANIFEST_BYTES: number;
157
+ export declare const DEFAULT_MAX_REVIEW_DELTA_ENTRIES = 2000;
158
+ export declare const HARD_MAX_REVIEW_DELTA_ENTRIES = 10000;
159
+ export declare const DEFAULT_MAX_DIAGNOSTIC_MESSAGE_BYTES: number;
160
+ export declare const HARD_MAX_DIAGNOSTIC_MESSAGE_BYTES: number;
125
161
  /** Forge (GitHub adapter) defaults and hard caps (Phase 9 Task 5). */
126
162
  export declare const DEFAULT_MAX_FORGE_PAGES_PER_OPERATION = 10;
127
163
  export declare const HARD_MAX_FORGE_PAGES_PER_OPERATION = 100;
@@ -133,6 +169,29 @@ export declare const DEFAULT_MAX_FORGE_REQUEST_CONCURRENCY = 4;
133
169
  export declare const HARD_MAX_FORGE_REQUEST_CONCURRENCY = 8;
134
170
  export declare const DEFAULT_MAX_FORGE_REQUEST_TIMEOUT_MS = 30000;
135
171
  export declare const HARD_MAX_FORGE_REQUEST_TIMEOUT_MS = 120000;
172
+ /** Phase 26 Task 0 freeze: coding workspace lifecycle caps (multi-repo/worktree, plan 026 Task 3). */
173
+ export declare const DEFAULT_MAX_WORKSPACE_REPOSITORIES = 4;
174
+ export declare const HARD_MAX_WORKSPACE_REPOSITORIES = 16;
175
+ /** Worktree cap reuses the git worktree caps (4 / 16). */
176
+ export declare const DEFAULT_MAX_WORKSPACE_WORKTREES = 4;
177
+ export declare const HARD_MAX_WORKSPACE_WORKTREES = 16;
178
+ export declare const DEFAULT_MAX_WORKSPACE_RECORD_BYTES: number;
179
+ export declare const HARD_MAX_WORKSPACE_RECORD_BYTES: number;
180
+ export declare const DEFAULT_MAX_WORKSPACE_LEASE_TTL_MS = 30000;
181
+ export declare const HARD_MAX_WORKSPACE_LEASE_TTL_MS = 300000;
182
+ export declare const DEFAULT_MAX_WORKSPACE_CLEANUP_OPERATIONS = 100;
183
+ export declare const HARD_MAX_WORKSPACE_CLEANUP_OPERATIONS = 1000;
184
+ /** Plan 026 Task 5: durable process/ACP recovery caps (frozen in the phase26 manifest). */
185
+ export declare const DEFAULT_MAX_RECOVERY_RECORDS = 32;
186
+ export declare const HARD_MAX_RECOVERY_RECORDS = 128;
187
+ export declare const DEFAULT_MAX_RECOVERY_LEASE_TTL_MS = 30000;
188
+ export declare const HARD_MAX_RECOVERY_LEASE_TTL_MS = 300000;
189
+ export declare const DEFAULT_MAX_RECOVERY_ATTACH_TIMEOUT_MS = 30000;
190
+ export declare const HARD_MAX_RECOVERY_ATTACH_TIMEOUT_MS = 120000;
191
+ export declare const DEFAULT_MAX_RECOVERY_BACKEND_REF_BYTES = 1024;
192
+ export declare const HARD_MAX_RECOVERY_BACKEND_REF_BYTES: number;
193
+ export declare const DEFAULT_MAX_RECOVERY_RECORD_BYTES: number;
194
+ export declare const HARD_MAX_RECOVERY_RECORD_BYTES: number;
136
195
  /** Validate one configurable coding resource limit. Invalid values fail instead of clamping. */
137
196
  export declare function validateCodingLimit(name: string, value: number, hardCap: number): number;
138
197
  /** Validate a non-negative integer limit (0 allowed), still capped. */
package/dist/limits.js CHANGED
@@ -122,6 +122,42 @@ export const HARD_MAX_PROCESS_OUTPUT_CHUNK_BYTES = 1024 * 1024;
122
122
  /** Total output reuses existing accumulator ceilings (64 MiB / 1 GiB). */
123
123
  export const DEFAULT_MAX_PROCESS_TOTAL_OUTPUT_BYTES = DEFAULT_MAX_TOTAL_OUTPUT_BYTES;
124
124
  export const HARD_MAX_PROCESS_TOTAL_OUTPUT_BYTES = HARD_MAX_TOTAL_OUTPUT_BYTES;
125
+ /** Phase 26 Task 0 freeze: host-selected PTY terminal caps (interactive sessions). */
126
+ export const DEFAULT_MAX_TERMINAL_COLUMNS = 120;
127
+ export const HARD_MAX_TERMINAL_COLUMNS = 500;
128
+ export const DEFAULT_MAX_TERMINAL_ROWS = 40;
129
+ export const HARD_MAX_TERMINAL_ROWS = 200;
130
+ export const DEFAULT_MAX_TERMINAL_TERM_BYTES = 64;
131
+ export const HARD_MAX_TERMINAL_TERM_BYTES = 256;
132
+ export const DEFAULT_MAX_TERMINAL_RESIZES_PER_MINUTE = 60;
133
+ export const HARD_MAX_TERMINAL_RESIZES_PER_MINUTE = 600;
134
+ export const DEFAULT_MAX_PTY_ATTACH_TIMEOUT_MS = 30_000;
135
+ export const HARD_MAX_PTY_ATTACH_TIMEOUT_MS = 120_000;
136
+ export const DEFAULT_MAX_PTY_BACKEND_METADATA_BYTES = 4 * 1024;
137
+ export const HARD_MAX_PTY_BACKEND_METADATA_BYTES = 16 * 1024;
138
+ /** Phase 26 Task 0 freeze: host index caps (indexed_literal/semantic repo_search). */
139
+ export const DEFAULT_MAX_INDEX_UPDATE_FILES = 1_000;
140
+ export const HARD_MAX_INDEX_UPDATE_FILES = 10_000;
141
+ export const DEFAULT_MAX_INDEX_UPDATE_BYTES = 16 * 1024 * 1024;
142
+ export const HARD_MAX_INDEX_UPDATE_BYTES = 64 * 1024 * 1024;
143
+ /** Index result cap reuses the repository results caps (1000 / 10000). */
144
+ export const DEFAULT_MAX_INDEX_SNIPPET_BYTES = 4 * 1024;
145
+ export const HARD_MAX_INDEX_SNIPPET_BYTES = 16 * 1024;
146
+ export const DEFAULT_MAX_INDEX_STALE_MAX_AGE_MS = 60_000;
147
+ export const HARD_MAX_INDEX_STALE_MAX_AGE_MS = 300_000;
148
+ export const DEFAULT_MAX_INDEX_QUERY_TIMEOUT_MS = 30_000;
149
+ export const HARD_MAX_INDEX_QUERY_TIMEOUT_MS = 120_000;
150
+ /** Phase 26 Task 0 freeze: patch-review manifest and diagnostic delta caps. */
151
+ export const DEFAULT_MAX_REVIEW_REVISIONS = 8;
152
+ export const HARD_MAX_REVIEW_REVISIONS = 32;
153
+ export const DEFAULT_MAX_REVIEW_DIAGNOSTICS = 500;
154
+ export const HARD_MAX_REVIEW_DIAGNOSTICS = 5_000;
155
+ export const DEFAULT_MAX_REVIEW_MANIFEST_BYTES = 64 * 1024;
156
+ export const HARD_MAX_REVIEW_MANIFEST_BYTES = 256 * 1024;
157
+ export const DEFAULT_MAX_REVIEW_DELTA_ENTRIES = 2_000;
158
+ export const HARD_MAX_REVIEW_DELTA_ENTRIES = 10_000;
159
+ export const DEFAULT_MAX_DIAGNOSTIC_MESSAGE_BYTES = 4 * 1024;
160
+ export const HARD_MAX_DIAGNOSTIC_MESSAGE_BYTES = 16 * 1024;
125
161
  /** Forge (GitHub adapter) defaults and hard caps (Phase 9 Task 5). */
126
162
  export const DEFAULT_MAX_FORGE_PAGES_PER_OPERATION = 10;
127
163
  export const HARD_MAX_FORGE_PAGES_PER_OPERATION = 100;
@@ -133,6 +169,29 @@ export const DEFAULT_MAX_FORGE_REQUEST_CONCURRENCY = 4;
133
169
  export const HARD_MAX_FORGE_REQUEST_CONCURRENCY = 8;
134
170
  export const DEFAULT_MAX_FORGE_REQUEST_TIMEOUT_MS = 30_000;
135
171
  export const HARD_MAX_FORGE_REQUEST_TIMEOUT_MS = 120_000;
172
+ /** Phase 26 Task 0 freeze: coding workspace lifecycle caps (multi-repo/worktree, plan 026 Task 3). */
173
+ export const DEFAULT_MAX_WORKSPACE_REPOSITORIES = 4;
174
+ export const HARD_MAX_WORKSPACE_REPOSITORIES = 16;
175
+ /** Worktree cap reuses the git worktree caps (4 / 16). */
176
+ export const DEFAULT_MAX_WORKSPACE_WORKTREES = DEFAULT_MAX_GIT_WORKTREES;
177
+ export const HARD_MAX_WORKSPACE_WORKTREES = HARD_MAX_GIT_WORKTREES;
178
+ export const DEFAULT_MAX_WORKSPACE_RECORD_BYTES = 64 * 1024;
179
+ export const HARD_MAX_WORKSPACE_RECORD_BYTES = 256 * 1024;
180
+ export const DEFAULT_MAX_WORKSPACE_LEASE_TTL_MS = 30_000;
181
+ export const HARD_MAX_WORKSPACE_LEASE_TTL_MS = 300_000;
182
+ export const DEFAULT_MAX_WORKSPACE_CLEANUP_OPERATIONS = 100;
183
+ export const HARD_MAX_WORKSPACE_CLEANUP_OPERATIONS = 1_000;
184
+ /** Plan 026 Task 5: durable process/ACP recovery caps (frozen in the phase26 manifest). */
185
+ export const DEFAULT_MAX_RECOVERY_RECORDS = 32;
186
+ export const HARD_MAX_RECOVERY_RECORDS = 128;
187
+ export const DEFAULT_MAX_RECOVERY_LEASE_TTL_MS = 30_000;
188
+ export const HARD_MAX_RECOVERY_LEASE_TTL_MS = 300_000;
189
+ export const DEFAULT_MAX_RECOVERY_ATTACH_TIMEOUT_MS = 30_000;
190
+ export const HARD_MAX_RECOVERY_ATTACH_TIMEOUT_MS = 120_000;
191
+ export const DEFAULT_MAX_RECOVERY_BACKEND_REF_BYTES = 1024;
192
+ export const HARD_MAX_RECOVERY_BACKEND_REF_BYTES = 4 * 1024;
193
+ export const DEFAULT_MAX_RECOVERY_RECORD_BYTES = 64 * 1024;
194
+ export const HARD_MAX_RECOVERY_RECORD_BYTES = 256 * 1024;
136
195
  /** Validate one configurable coding resource limit. Invalid values fail instead of clamping. */
137
196
  export function validateCodingLimit(name, value, hardCap) {
138
197
  if (!Number.isSafeInteger(value) || value < 1 || value > hardCap) {
@@ -1,3 +1,6 @@
1
- export type { CodingProcessEvent, CreateProcessSessionsOptions, ProcessExitResult, ProcessOutputChunk, ProcessSandboxBackend, ProcessSandboxHandle, ProcessSandboxStartRequest, ProcessSession, ProcessSessionLimits, ProcessSessionMetadata, ProcessSessions, ProcessSessionState, ProcessStartRequest, ResolvedProcessSessionLimits, } from "./types.js";
1
+ export type { CodingProcessEvent, CreateProcessSessionsOptions, ProcessExitResult, ProcessOutputChunk, ProcessPtyBackend, ProcessPtyHandle, ProcessPtyStartRequest, ProcessSandboxBackend, ProcessSandboxHandle, ProcessSandboxStartRequest, ProcessSession, ProcessSessionLimits, ProcessSessionMetadata, ProcessSessions, ProcessSessionState, ProcessStartRequest, ProcessTerminalRequest, ProcessTerminalResize, ResolvedProcessSessionLimits, } from "./types.js";
2
2
  export { ProcessSessionError, resolveProcessSessionLimits } from "./types.js";
3
3
  export { createProcessSessions } from "./sessions.js";
4
+ export { PROCESS_RECOVERY_CATEGORY, PROCESS_RECOVERY_LEASE_NAMESPACE, PROCESS_RECOVERY_NAMESPACE, PROCESS_RECOVERY_SCHEMA_VERSION, ProcessRecoveryError, acquireRecordLease, attachWithTimeout, buildProcessRecoveryRecord, deleteProcessRecoveryRecord, isOwnershipConflict, loadProcessRecoveryRecord, loadProcessRecoveryRecords, releaseRecordLease, resolveProcessRecoveryLimits, saveProcessRecoveryRecord, validateBackendRef, validateProcessRecoveryRecord, } from "./recovery.js";
5
+ export type { ProcessRecoveryErrorCode, ProcessRecoveryLimits, ProcessRecoveryRecord, ProcessRecoveryRecordReport, ProcessRecoveryReport, ResolvedProcessRecoveryLimits, RecoveryRecordPage, } from "./recovery.js";
6
+ export type { ProcessRecoveryBackend, ProcessRecoveryOutcome } from "./recovery.js";
@@ -1,3 +1,4 @@
1
1
  export { ProcessSessionError, resolveProcessSessionLimits } from "./types.js";
2
2
  export { createProcessSessions } from "./sessions.js";
3
+ export { PROCESS_RECOVERY_CATEGORY, PROCESS_RECOVERY_LEASE_NAMESPACE, PROCESS_RECOVERY_NAMESPACE, PROCESS_RECOVERY_SCHEMA_VERSION, ProcessRecoveryError, acquireRecordLease, attachWithTimeout, buildProcessRecoveryRecord, deleteProcessRecoveryRecord, isOwnershipConflict, loadProcessRecoveryRecord, loadProcessRecoveryRecords, releaseRecordLease, resolveProcessRecoveryLimits, saveProcessRecoveryRecord, validateBackendRef, validateProcessRecoveryRecord, } from "./recovery.js";
3
4
  //# sourceMappingURL=index.js.map