@arnilo/prism-coding-agent 0.0.15 → 0.0.17

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,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.17] - 2026-07-29
4
+
5
+ ### Added
6
+ - `ShellToolOptions.envAllowlist` restricts the environment the spawn hook and child process see (secret scrubbing without re-implementing the hook).
7
+
8
+ ### Changed
9
+ - Released with exact 0.0.17 graph.
10
+
11
+ ## [0.0.16] - 2026-07-26
12
+
13
+ ### Changed
14
+ - Released with exact 0.0.16 graph.
15
+
3
16
  ## [0.0.15] - 2026-07-26
4
17
 
5
18
  ## [0.0.14] - 2026-07-26
@@ -210,7 +210,7 @@ export function createAskUserDecisionTool(options) {
210
210
  selectionMode: {
211
211
  type: "string",
212
212
  enum: ["single", "multiple"],
213
- description: 'single (default) or multiple selection',
213
+ description: "single (default) or multiple selection",
214
214
  },
215
215
  allowCustom: {
216
216
  type: "boolean",
@@ -387,11 +387,7 @@ export function askUserDecisionResumeSchema(request) {
387
387
  maxLength: DEFAULT_MAX_ASK_USER_DECISION_CUSTOM_BYTES,
388
388
  },
389
389
  },
390
- anyOf: [
391
- { required: ["selectedId"] },
392
- { required: ["selectedIds"] },
393
- { required: ["customText"] },
394
- ],
390
+ anyOf: [{ required: ["selectedId"] }, { required: ["selectedIds"] }, { required: ["customText"] }],
395
391
  };
396
392
  }
397
393
  export function toAskUserDecisionSuspendData(request) {
@@ -409,10 +405,10 @@ function isAskUserDecisionSuspendData(value) {
409
405
  if (!value || typeof value !== "object" || Array.isArray(value))
410
406
  return false;
411
407
  const row = value;
412
- return (typeof row.question === "string"
413
- && Array.isArray(row.options)
414
- && (row.selectionMode === "single" || row.selectionMode === "multiple")
415
- && typeof row.allowCustom === "boolean");
408
+ return (typeof row.question === "string" &&
409
+ Array.isArray(row.options) &&
410
+ (row.selectionMode === "single" || row.selectionMode === "multiple") &&
411
+ typeof row.allowCustom === "boolean");
416
412
  }
417
413
  /**
418
414
  * Return from a workflow node to pause for a user decision (opt-in durable path).
@@ -441,7 +437,10 @@ export function validateAskUserDecisionResume(request, value, limits) {
441
437
  throw new Error("resume input must be an ask_user_decision answer object");
442
438
  }
443
439
  const maxCustomTextBytes = limits?.maxCustomTextBytes ?? DEFAULT_MAX_ASK_USER_DECISION_CUSTOM_BYTES;
444
- return resolveAskUserDecisionAnswer(value, request.selectionMode, request.options, { allowCustom: request.allowCustom, maxCustomTextBytes });
440
+ return resolveAskUserDecisionAnswer(value, request.selectionMode, request.options, {
441
+ allowCustom: request.allowCustom,
442
+ maxCustomTextBytes,
443
+ });
445
444
  }
446
445
  /**
447
446
  * Workflow `validateResume` adapter. Reads durable request from `suspension.data`
@@ -464,8 +463,6 @@ export function createAskUserDecisionResumeValidator(limits) {
464
463
  * unchanged in 0.0.12). Call after operator supplies an answer.
465
464
  */
466
465
  export function validateAskUserDecisionAgentResume(input) {
467
- return validateAskUserDecisionResume(input.request, input.answer, input.maxCustomTextBytes === undefined
468
- ? undefined
469
- : { maxCustomTextBytes: input.maxCustomTextBytes });
466
+ return validateAskUserDecisionResume(input.request, input.answer, input.maxCustomTextBytes === undefined ? undefined : { maxCustomTextBytes: input.maxCustomTextBytes });
470
467
  }
471
468
  //# sourceMappingURL=ask-user-decision.js.map
package/dist/checks.js CHANGED
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Named check tool: host declares fixed executable+args; model selects only a name.
3
+ */
1
4
  import { spawn } from "node:child_process";
2
5
  import { rm } from "node:fs/promises";
3
6
  import { isAbsolute } from "node:path";
@@ -8,8 +8,8 @@
8
8
  import { createHash } from "node:crypto";
9
9
  import { mkdir, readFile, writeFile } from "node:fs/promises";
10
10
  import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
11
- import { DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_TODOS, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_PLAN_BYTES, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_TODOS, validateCodingLimit, } from "./limits.js";
12
11
  import { sha256Hex } from "./artifacts.js";
12
+ import { DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_TODOS, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_PLAN_BYTES, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_TODOS, validateCodingLimit, } from "./limits.js";
13
13
  export const CODING_CHECKPOINT_SCHEMA_VERSION = 1;
14
14
  /** Workflow shared-state key that holds coding checkpoint metadata. */
15
15
  export const CODING_STATE_KEY = "coding";
@@ -217,9 +217,7 @@ export function validateCodingCheckpointMetadata(value, limits) {
217
217
  const planPath = requireRelativePath(value.planPath, "planPath");
218
218
  const plan = validateArtifactRef(value.plan, resolved, { requireKind: "plan" });
219
219
  const worktreePath = value.worktreePath === undefined ? undefined : requireAbsolutePath(value.worktreePath, "worktreePath");
220
- const workspaceExport = value.workspaceExport === undefined
221
- ? undefined
222
- : validateArtifactRef(value.workspaceExport, resolved);
220
+ const workspaceExport = value.workspaceExport === undefined ? undefined : validateArtifactRef(value.workspaceExport, resolved);
223
221
  const artifacts = requireArray(value.artifacts, "artifacts").map((item, index) => validateArtifactRef(item, resolved, { label: `artifacts[${index}]` }));
224
222
  if (artifacts.length > resolved.maxArtifacts) {
225
223
  throw new CodingCheckpointError(`Coding checkpoint exceeds ${resolved.maxArtifacts} artifact references`);
@@ -270,8 +268,7 @@ export function validateCodingCheckpointMetadata(value, limits) {
270
268
  export function assertCodingResumeAllowed(input) {
271
269
  const metadata = validateCodingCheckpointMetadata(input.metadata, input.limits);
272
270
  assertFingerprintsMatch(metadata.fingerprints, input.expected);
273
- if (input.expectedWorkspaceRoot !== undefined &&
274
- resolve(input.expectedWorkspaceRoot) !== resolve(metadata.workspaceRoot)) {
271
+ if (input.expectedWorkspaceRoot !== undefined && resolve(input.expectedWorkspaceRoot) !== resolve(metadata.workspaceRoot)) {
275
272
  throw new CodingCheckpointError("Workspace root mismatch on coding resume");
276
273
  }
277
274
  if (input.expectedBaseBranch !== undefined && input.expectedBaseBranch !== metadata.baseBranch) {
@@ -326,12 +323,8 @@ function validateFingerprints(value) {
326
323
  const workflowRevision = requireString(value.workflowRevision, "fingerprints.workflowRevision");
327
324
  const toolFingerprint = requireFingerprint(value.toolFingerprint, "fingerprints.toolFingerprint");
328
325
  const policyFingerprint = requireFingerprint(value.policyFingerprint, "fingerprints.policyFingerprint");
329
- const definitionHash = value.definitionHash === undefined
330
- ? undefined
331
- : requireFingerprint(value.definitionHash, "fingerprints.definitionHash");
332
- const imageDigest = value.imageDigest === undefined
333
- ? undefined
334
- : requireString(value.imageDigest, "fingerprints.imageDigest");
326
+ const definitionHash = value.definitionHash === undefined ? undefined : requireFingerprint(value.definitionHash, "fingerprints.definitionHash");
327
+ const imageDigest = value.imageDigest === undefined ? undefined : requireString(value.imageDigest, "fingerprints.imageDigest");
335
328
  if (imageDigest !== undefined && !/sha256:[a-f0-9]{64}/.test(imageDigest) && !SHA256_HEX.test(imageDigest)) {
336
329
  // Allow either raw hex or docker digest form.
337
330
  if (!imageDigest.includes("@sha256:") && !imageDigest.startsWith("sha256:")) {
@@ -421,9 +414,7 @@ function validateHandoffSummary(value, limits) {
421
414
  if (changedPathCount < 0 || checkCount < 0) {
422
415
  throw new CodingCheckpointError("handoff counts must be non-negative");
423
416
  }
424
- const artifact = value.artifact === undefined
425
- ? undefined
426
- : validateArtifactRef(value.artifact, limits, { label: "handoff.artifact" });
417
+ const artifact = value.artifact === undefined ? undefined : validateArtifactRef(value.artifact, limits, { label: "handoff.artifact" });
427
418
  return { base, head, changedPathCount, checkCount, artifact };
428
419
  }
429
420
  function requireStatus(value) {
package/dist/edit-diff.js CHANGED
@@ -88,10 +88,7 @@ function applyReplacements(content, replacements, offset = 0) {
88
88
  for (let i = replacements.length - 1; i >= 0; i--) {
89
89
  const replacement = replacements[i];
90
90
  const matchIndex = replacement.matchIndex - offset;
91
- result =
92
- result.substring(0, matchIndex) +
93
- replacement.newText +
94
- result.substring(matchIndex + replacement.matchLength);
91
+ result = result.substring(0, matchIndex) + replacement.newText + result.substring(matchIndex + replacement.matchLength);
95
92
  }
96
93
  return result;
97
94
  }
package/dist/edit.js CHANGED
@@ -20,14 +20,14 @@
20
20
  * completed, the edit is real and is reported as success rather than a misleading "aborted".
21
21
  */
22
22
  import { Buffer } from "node:buffer";
23
- import { access as fsAccess, stat as fsStat, writeFile as fsWriteFile, } from "node:fs/promises";
24
23
  import { constants } from "node:fs";
24
+ import { access as fsAccess, stat as fsStat, writeFile as fsWriteFile } from "node:fs/promises";
25
25
  import { readFileBounded } from "./bounded-file.js";
26
+ import { applyEditsToNormalizedContent, detectLineEnding, generateDiffString, generateUnifiedPatch, normalizeToLF, restoreLineEndings, stripBom, } from "./edit-diff.js";
26
27
  import { enforceExecutionPolicy } from "./execution-policy.js";
27
- import { resolveToCwd } from "./path-utils.js";
28
28
  import { withFileMutationQueue } from "./file-mutation-queue.js";
29
29
  import { DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, validateCodingLimit, } from "./limits.js";
30
- import { applyEditsToNormalizedContent, detectLineEnding, generateDiffString, generateUnifiedPatch, normalizeToLF, restoreLineEndings, stripBom, } from "./edit-diff.js";
30
+ import { resolveToCwd } from "./path-utils.js";
31
31
  const defaultEditOperations = {
32
32
  readFile: (path, options) => readFileBounded(path, options.maxBytes, options.signal),
33
33
  writeFile: (path, content, options) => fsWriteFile(path, content, { encoding: "utf-8", signal: options?.signal }),
@@ -196,9 +196,7 @@ export function createEditTool(cwd, options) {
196
196
  return {
197
197
  toolCallId,
198
198
  name: "edit",
199
- content: [
200
- { type: "text", text: `Successfully replaced ${edits.length} block(s) in ${prepared.path}.` },
201
- ],
199
+ content: [{ type: "text", text: `Successfully replaced ${edits.length} block(s) in ${prepared.path}.` }],
202
200
  metadata: {
203
201
  diff: diffResult.diff,
204
202
  patch,
@@ -1,5 +1,4 @@
1
- import type { ExecutionAction, ExecutionPolicy } from "@arnilo/prism";
2
- import type { ToolResult } from "@arnilo/prism";
1
+ import type { ExecutionAction, ExecutionPolicy, ToolResult } from "@arnilo/prism";
3
2
  export declare function enforceExecutionPolicy(policy: ExecutionPolicy | undefined, action: ExecutionAction, toolCallId: string, toolName: string): Promise<{
4
3
  allowed: true;
5
4
  action: ExecutionAction;
@@ -8,7 +8,7 @@ export async function enforceExecutionPolicy(policy, action, toolCallId, toolNam
8
8
  }
9
9
  catch (error) {
10
10
  const message = error instanceof ExecutionDeniedError
11
- ? error.decision.reason ?? error.message
11
+ ? (error.decision.reason ?? error.message)
12
12
  : error instanceof Error
13
13
  ? error.message
14
14
  : String(error);
@@ -19,8 +19,7 @@ function isMissingPathError(error) {
19
19
  return (typeof error === "object" &&
20
20
  error !== null &&
21
21
  "code" in error &&
22
- (error.code === "ENOENT" ||
23
- error.code === "ENOTDIR"));
22
+ (error.code === "ENOENT" || error.code === "ENOTDIR"));
24
23
  }
25
24
  async function getMutationQueueKey(filePath) {
26
25
  const resolvedPath = resolve(filePath);
package/dist/git-exec.js CHANGED
@@ -6,8 +6,8 @@
6
6
  * runner (for example a sandbox `execFile` adapter) without changing tool code.
7
7
  */
8
8
  import { spawn } from "node:child_process";
9
- import { access } from "node:fs/promises";
10
9
  import { constants as fsConstants } from "node:fs";
10
+ import { access } from "node:fs/promises";
11
11
  import { isAbsolute } from "node:path";
12
12
  import { DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_GIT_OUTPUT_BYTES, HARD_GIT_TIMEOUT_MS, HARD_MAX_GIT_OUTPUT_BYTES, validateCodingLimit, } from "./limits.js";
13
13
  export class GitError extends Error {
@@ -5,8 +5,8 @@
5
5
  * Shell is never used internally; all Git invocations go through typed arg arrays.
6
6
  */
7
7
  import type { ExecutionPolicy, ToolDefinition } from "@arnilo/prism";
8
- import { type ArtifactWriter, type CreateGitOperationsOptions, type GitOperations } from "./git.js";
9
8
  import { type CodingCheckToolOptions, type NamedCheckDefinition } from "./checks.js";
9
+ import { type ArtifactWriter, type CreateGitOperationsOptions, type GitOperations } from "./git.js";
10
10
  export interface GitToolsOptions {
11
11
  readonly executionPolicy?: ExecutionPolicy;
12
12
  readonly gitPath?: string;
package/dist/git-tools.js CHANGED
@@ -1,6 +1,6 @@
1
+ import { createCodingCheckTool } from "./checks.js";
1
2
  import { enforceExecutionPolicy } from "./execution-policy.js";
2
3
  import { createGitOperations, GitError, } from "./git.js";
3
- import { createCodingCheckTool } from "./checks.js";
4
4
  function errorResult(toolName, toolCallId, message) {
5
5
  return {
6
6
  toolCallId,
@@ -250,8 +250,7 @@ export function createGitWorktreeTool(cwd, options) {
250
250
  signal: context.signal,
251
251
  });
252
252
  const text = action === "list"
253
- ? result.worktrees.map((w) => `${w.path}\t${w.branch ?? ""}\t${w.head ?? ""}`).join("\n") ||
254
- "(no worktrees)"
253
+ ? result.worktrees.map((w) => `${w.path}\t${w.branch ?? ""}\t${w.head ?? ""}`).join("\n") || "(no worktrees)"
255
254
  : `ok action=${action} path=${result.path ?? ""}`;
256
255
  return {
257
256
  toolCallId,
@@ -430,9 +429,7 @@ export function createGitPrHandoffTool(cwd, options) {
430
429
  const base = typeof args.base === "string" ? args.base : "";
431
430
  const head = typeof args.head === "string" ? args.head : undefined;
432
431
  const includeBundle = args.includeBundle === true;
433
- const checks = Array.isArray(args.checks)
434
- ? args.checks
435
- : undefined;
432
+ const checks = Array.isArray(args.checks) ? args.checks : undefined;
436
433
  const policy = await enforceExecutionPolicy(options?.executionPolicy, {
437
434
  kind: "git",
438
435
  operation: "pr_handoff",
package/dist/git.d.ts CHANGED
@@ -133,7 +133,7 @@ export interface CreateGitOperationsOptions extends CreateGitRunnerOptions, GitL
133
133
  };
134
134
  }
135
135
  export declare function createGitOperations(options: CreateGitOperationsOptions): Promise<GitOperations>;
136
+ export type { BoundGitRunner, CreateGitRunnerOptions, GitExecRequest, GitExecResult, GitRunner } from "./git-exec.js";
137
+ export { createBoundGitRunner, GitError, runGitCli, SAFE_GIT_CONFIG_ARGS, SAFE_GIT_ENV, } from "./git-exec.js";
138
+ export type { GitStatusBranch, GitStatusEntry, GitStatusEntryKind, GitStatusResult } from "./git-status.js";
136
139
  export { parsePorcelainV2 } from "./git-status.js";
137
- export type { GitStatusResult, GitStatusEntry, GitStatusBranch, GitStatusEntryKind } from "./git-status.js";
138
- export { GitError, SAFE_GIT_ENV, SAFE_GIT_CONFIG_ARGS, createBoundGitRunner, runGitCli, } from "./git-exec.js";
139
- export type { GitRunner, GitExecRequest, GitExecResult, BoundGitRunner, CreateGitRunnerOptions } from "./git-exec.js";
package/dist/git.js CHANGED
@@ -5,12 +5,12 @@
5
5
  * `git check-ref-format` for refs, and safe config that disables hooks,
6
6
  * external diff/textconv, pagers, and credential prompts by default.
7
7
  */
8
- import { mkdtemp, writeFile, rm } from "node:fs/promises";
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 { 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";
12
11
  import { createBoundGitRunner, GitError, gitRequireOk, gitText, } from "./git-exec.js";
13
12
  import { parsePorcelainV2 } from "./git-status.js";
13
+ 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";
14
14
  import { resolveToCwd } from "./path-utils.js";
15
15
  export function resolveGitLimits(options) {
16
16
  return {
@@ -77,7 +77,7 @@ function truncateLines(text, maxLines) {
77
77
  const lineCount = lines.length;
78
78
  if (lineCount <= maxLines)
79
79
  return { text, truncated: false, lineCount };
80
- const kept = lines.slice(0, maxLines).join("\n") + "\n";
80
+ const kept = `${lines.slice(0, maxLines).join("\n")}\n`;
81
81
  return { text: kept, truncated: true, lineCount };
82
82
  }
83
83
  async function withTempFile(prefix, contents, fn) {
@@ -292,9 +292,7 @@ export async function createGitOperations(options) {
292
292
  ? await ensureCleanOrCheckpoint(request.createCheckpoint, request.signal, `git apply ${request.action}`)
293
293
  : undefined;
294
294
  // Always check first for apply/reverse.
295
- const checkArgs = request.action === "reverse"
296
- ? ["apply", "--reverse", "--check"]
297
- : ["apply", "--check"];
295
+ const checkArgs = request.action === "reverse" ? ["apply", "--reverse", "--check"] : ["apply", "--check"];
298
296
  const check = await runApply(checkArgs, filePath);
299
297
  if (check.exitCode !== 0) {
300
298
  const output = (gitText(check, "stderr") || gitText(check)).trim();
@@ -302,9 +300,7 @@ export async function createGitOperations(options) {
302
300
  await restoreCheckpoint(checkpoint, request.signal).catch(() => undefined);
303
301
  return { ok: false, checkpoint, restored: Boolean(checkpoint), output: output || "patch check failed" };
304
302
  }
305
- const applyArgs = request.action === "reverse"
306
- ? ["apply", "--reverse"]
307
- : ["apply"];
303
+ const applyArgs = request.action === "reverse" ? ["apply", "--reverse"] : ["apply"];
308
304
  const result = await runApply(applyArgs, filePath);
309
305
  if (result.exitCode !== 0) {
310
306
  const output = (gitText(result, "stderr") || gitText(result)).trim();
@@ -314,12 +310,14 @@ export async function createGitOperations(options) {
314
310
  }
315
311
  else {
316
312
  // Best-effort restore of tracked files when no checkpoint was taken (clean tree).
317
- await runner.exec({
313
+ await runner
314
+ .exec({
318
315
  args: ["checkout", "--", "."],
319
316
  cwd,
320
317
  signal: request.signal,
321
318
  maxOutputBytes: limits.maxOutputBytes,
322
- }).catch(() => undefined);
319
+ })
320
+ .catch(() => undefined);
323
321
  restored = true;
324
322
  }
325
323
  return { ok: false, checkpoint, restored, output: output || `apply failed with exit ${result.exitCode}` };
@@ -378,12 +376,14 @@ export async function createGitOperations(options) {
378
376
  }
379
377
  catch (error) {
380
378
  // Reset index for the attempted paths; never drop pre-existing dirty work unless checkpointed.
381
- await runner.exec({
379
+ await runner
380
+ .exec({
382
381
  args: ["reset", "-q", "HEAD", "--", ...paths],
383
382
  cwd,
384
383
  signal: request.signal,
385
384
  maxOutputBytes: limits.maxOutputBytes,
386
- }).catch(() => undefined);
385
+ })
386
+ .catch(() => undefined);
387
387
  if (checkpoint)
388
388
  await restoreCheckpoint(checkpoint, request.signal).catch(() => undefined);
389
389
  throw error;
@@ -490,6 +490,6 @@ export async function createGitOperations(options) {
490
490
  }
491
491
  return { status, diff, branch, worktree, apply, commit, prHandoff };
492
492
  }
493
+ export { createBoundGitRunner, GitError, runGitCli, SAFE_GIT_CONFIG_ARGS, SAFE_GIT_ENV, } from "./git-exec.js";
493
494
  export { parsePorcelainV2 } from "./git-status.js";
494
- export { GitError, SAFE_GIT_ENV, SAFE_GIT_CONFIG_ARGS, createBoundGitRunner, runGitCli, } from "./git-exec.js";
495
495
  //# sourceMappingURL=git.js.map
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import type { OwnershipScope, SecretRedactor } from "@arnilo/prism";
6
6
  import { type WorkflowCheckpointAdapter, type WorkflowEvent, type WorkflowResumeValidator, type WorkflowRunResult } from "@arnilo/prism-workflows";
7
- import { type CodingCheckSummary, type CodingCheckpointMetadata, type CodingHandoffSummary } from "./coding-checkpoint.js";
7
+ import { type CodingCheckpointMetadata, type CodingCheckSummary, type CodingHandoffSummary } from "./coding-checkpoint.js";
8
8
  export declare const CODING_GOAL_VERIFY_WORKFLOW_ID: "coding-goal-verify";
9
9
  export declare const CODING_GOAL_VERIFY_REVISION: "1";
10
10
  export declare const CODING_GOAL_VERIFY_SUSPEND_REASON: "approve-coding-goal-verify";
@@ -1,5 +1,5 @@
1
1
  import { defineWorkflow, functionNode, resumeWorkflow, runWorkflow, suspend, } from "@arnilo/prism-workflows";
2
- import { CODING_STATE_KEY, assertCodingResumeAllowed, buildCodingCheckpointMetadata, codingCheckpointStatePatch, codingPlanPathForTask, createCodingPlanMarkdown, fingerprintJson, parseCodingPlanTodos, readCodingCheckpointFromState, readCodingPlanFile, writeCodingPlanFile, } from "./coding-checkpoint.js";
2
+ import { assertCodingResumeAllowed, buildCodingCheckpointMetadata, CODING_STATE_KEY, codingCheckpointStatePatch, codingPlanPathForTask, createCodingPlanMarkdown, fingerprintJson, parseCodingPlanTodos, readCodingCheckpointFromState, readCodingPlanFile, writeCodingPlanFile, } from "./coding-checkpoint.js";
3
3
  import { DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_PR_HANDOFF_BYTES } from "./limits.js";
4
4
  export const CODING_GOAL_VERIFY_WORKFLOW_ID = "coding-goal-verify";
5
5
  export const CODING_GOAL_VERIFY_REVISION = "1";
@@ -93,10 +93,7 @@ export function createCodingGoalVerifyWorkflow(options) {
93
93
  const coding = requireCoding(ctx.state);
94
94
  const checks = normalizeChecks(await Promise.all(options.checks.map((name) => options.runCheck(name))));
95
95
  const failed = checks.some((check) => check.exitCode !== 0);
96
- const done = new Set([
97
- "plan",
98
- ...options.checks.map((name) => `check-${name}`),
99
- ]);
96
+ const done = new Set(["plan", ...options.checks.map((name) => `check-${name}`)]);
100
97
  const todos = markTodos(coding.todos.length ? coding.todos : defaultTodos(options.checks), done);
101
98
  const markdown = createCodingPlanMarkdown({
102
99
  title: options.title,
package/dist/index.d.ts CHANGED
@@ -1,41 +1,41 @@
1
- export { createShellTool, createLocalBashOperations, getShellConfig, killProcessTree, waitForChildProcess, } from "./shell.js";
2
- export type { ShellToolOptions, ShellConfig, BashOperations, BashExecOptions, BashSpawnContext, BashSpawnHook, } from "./shell.js";
3
- export { createReadTool, detectSupportedImageMimeType, detectSupportedImageMimeTypeFromFile, DEFAULT_MAX_IMAGE_BYTES, } from "./read.js";
4
- export type { ReadToolOptions, ReadOperations, ReadTextOptions, ReadTextResult, TransformImage, TransformImageInput, } from "./read.js";
5
- export { createWriteTool } from "./write.js";
6
- export type { WriteToolOptions, WriteOperations } from "./write.js";
1
+ export { createDirectoryArtifactWriter, createTempArtifactWriter, sha256Hex } from "./artifacts.js";
2
+ export type { AskUserDecisionAnswer, AskUserDecisionHandler, AskUserDecisionOption, AskUserDecisionRequest, AskUserDecisionSelectionMode, AskUserDecisionSuspendData, AskUserDecisionToolOptions, ResolvedAskUserDecisionAnswer, ResolvedAskUserDecisionLimits, SuspendAskUserDecisionOptions, } from "./ask-user-decision.js";
3
+ export { ASK_USER_DECISION_RATIONALE_COUNT, ASK_USER_DECISION_SUSPEND_REASON, ASK_USER_DECISION_TOOL_NAME, askUserDecisionResumeSchema, createAskUserDecisionResumeValidator, createAskUserDecisionTool, DEFAULT_MAX_ASK_USER_DECISION_BULLET_BYTES, DEFAULT_MAX_ASK_USER_DECISION_CUSTOM_BYTES, DEFAULT_MAX_ASK_USER_DECISION_LABEL_BYTES, DEFAULT_MAX_ASK_USER_DECISION_OPTIONS, DEFAULT_MAX_ASK_USER_DECISION_QUESTION_BYTES, HARD_MAX_ASK_USER_DECISION_BULLET_BYTES, HARD_MAX_ASK_USER_DECISION_CUSTOM_BYTES, HARD_MAX_ASK_USER_DECISION_LABEL_BYTES, HARD_MAX_ASK_USER_DECISION_OPTIONS, HARD_MAX_ASK_USER_DECISION_QUESTION_BYTES, parseAskUserDecisionArgs, resolveAskUserDecisionAnswer, resolveAskUserDecisionLimits, suspendAskUserDecision, toAskUserDecisionSuspendData, validateAskUserDecisionAgentResume, validateAskUserDecisionResume, } from "./ask-user-decision.js";
4
+ export type { CodingCheckToolOptions, NamedCheckDefinition } from "./checks.js";
5
+ export { createCodingCheckTool } from "./checks.js";
6
+ export type { CodingArtifactKind, CodingArtifactRef, CodingCheckpointLimitOptions, CodingCheckpointMetadata, CodingCheckSummary, CodingFingerprints, CodingHandoffSummary, CodingTaskStatus, CodingTodoItem, ResolvedCodingCheckpointLimits, } from "./coding-checkpoint.js";
7
+ export { assertCodingResumeAllowed, buildCodingCheckpointMetadata, CODING_CHECKPOINT_SCHEMA_VERSION, CODING_STATE_KEY, CodingCheckpointError, codingCheckpointStatePatch, codingPlanPathForTask, createCodingArtifactRef, createCodingPlanMarkdown, fingerprintJson, parseCodingPlanTodos, readCodingCheckpointFromState, readCodingPlanFile, resolveCodingCheckpointLimits, validateCodingCheckpointMetadata, verifyCodingArtifactBytes, writeCodingPlanFile, } from "./coding-checkpoint.js";
8
+ export type { Edit, EditOperations, EditToolDetails, EditToolOptions } from "./edit.js";
7
9
  export { createEditTool } from "./edit.js";
8
- export type { EditToolOptions, EditOperations, EditToolDetails, Edit } from "./edit.js";
9
- export { createRepoListTool } from "./list.js";
10
- export type { ListToolOptions } from "./list.js";
11
- export { createRepoSearchTool } from "./search.js";
12
- export type { SearchToolOptions } from "./search.js";
13
- export { createLocalRepositoryOperations, resolveRepositoryLimits, compileSearchPattern, isBinaryBuffer, resolveRepoPath, toRepoRelative, RepositoryError, DEFAULT_REPO_EXCLUDE, } from "./repository.js";
14
- export type { RepoEntryKind, RepoListEntry, RepositoryListRequest, RepositoryListResult, RepositorySearchMatch, RepositorySearchRequest, RepositorySearchResult, RepositoryOperations, RepositoryLimitOptions, ResolvedRepositoryLimits, } from "./repository.js";
15
- export { createGitOperations, resolveGitLimits, parsePorcelainV2, GitError, SAFE_GIT_ENV, SAFE_GIT_CONFIG_ARGS, createBoundGitRunner, runGitCli, } from "./git.js";
16
- export type { GitOperations, GitLimitOptions, ResolvedGitLimits, ArtifactReference, ArtifactWriter, PrHandoff, CreateGitOperationsOptions, GitStatusResult, GitStatusEntry, GitStatusBranch, GitStatusEntryKind, GitRunner, GitExecRequest, GitExecResult, BoundGitRunner, CreateGitRunnerOptions, } from "./git.js";
17
- export { createGitTools, createGitStatusTool, createGitDiffTool, createGitBranchTool, createGitWorktreeTool, createGitApplyTool, createGitCommitTool, createGitPrHandoffTool, } from "./git-tools.js";
10
+ export type { ArtifactReference, ArtifactWriter, BoundGitRunner, CreateGitOperationsOptions, CreateGitRunnerOptions, GitExecRequest, GitExecResult, GitLimitOptions, GitOperations, GitRunner, GitStatusBranch, GitStatusEntry, GitStatusEntryKind, GitStatusResult, PrHandoff, ResolvedGitLimits, } from "./git.js";
11
+ export { createBoundGitRunner, createGitOperations, GitError, parsePorcelainV2, resolveGitLimits, runGitCli, SAFE_GIT_CONFIG_ARGS, SAFE_GIT_ENV, } from "./git.js";
18
12
  export type { GitToolsOptions } from "./git-tools.js";
19
- export { createCodingCheckTool } from "./checks.js";
20
- export type { CodingCheckToolOptions, NamedCheckDefinition } from "./checks.js";
21
- export { ASK_USER_DECISION_RATIONALE_COUNT, ASK_USER_DECISION_SUSPEND_REASON, ASK_USER_DECISION_TOOL_NAME, DEFAULT_MAX_ASK_USER_DECISION_BULLET_BYTES, DEFAULT_MAX_ASK_USER_DECISION_CUSTOM_BYTES, DEFAULT_MAX_ASK_USER_DECISION_LABEL_BYTES, DEFAULT_MAX_ASK_USER_DECISION_OPTIONS, DEFAULT_MAX_ASK_USER_DECISION_QUESTION_BYTES, HARD_MAX_ASK_USER_DECISION_BULLET_BYTES, HARD_MAX_ASK_USER_DECISION_CUSTOM_BYTES, HARD_MAX_ASK_USER_DECISION_LABEL_BYTES, HARD_MAX_ASK_USER_DECISION_OPTIONS, HARD_MAX_ASK_USER_DECISION_QUESTION_BYTES, askUserDecisionResumeSchema, createAskUserDecisionResumeValidator, createAskUserDecisionTool, parseAskUserDecisionArgs, resolveAskUserDecisionAnswer, resolveAskUserDecisionLimits, suspendAskUserDecision, toAskUserDecisionSuspendData, validateAskUserDecisionAgentResume, validateAskUserDecisionResume, } from "./ask-user-decision.js";
22
- export type { AskUserDecisionAnswer, AskUserDecisionHandler, AskUserDecisionOption, AskUserDecisionRequest, AskUserDecisionSelectionMode, AskUserDecisionSuspendData, AskUserDecisionToolOptions, ResolvedAskUserDecisionAnswer, ResolvedAskUserDecisionLimits, SuspendAskUserDecisionOptions, } from "./ask-user-decision.js";
23
- export { createDirectoryArtifactWriter, createTempArtifactWriter, sha256Hex } from "./artifacts.js";
24
- export { CODING_CHECKPOINT_SCHEMA_VERSION, CODING_STATE_KEY, CodingCheckpointError, assertCodingResumeAllowed, buildCodingCheckpointMetadata, codingCheckpointStatePatch, codingPlanPathForTask, createCodingArtifactRef, createCodingPlanMarkdown, fingerprintJson, parseCodingPlanTodos, readCodingCheckpointFromState, readCodingPlanFile, resolveCodingCheckpointLimits, validateCodingCheckpointMetadata, verifyCodingArtifactBytes, writeCodingPlanFile, } from "./coding-checkpoint.js";
25
- export type { CodingArtifactKind, CodingArtifactRef, CodingCheckSummary, CodingCheckpointLimitOptions, CodingCheckpointMetadata, CodingFingerprints, CodingHandoffSummary, CodingTaskStatus, CodingTodoItem, ResolvedCodingCheckpointLimits, } from "./coding-checkpoint.js";
26
- export { CODING_GOAL_VERIFY_REVISION, CODING_GOAL_VERIFY_SUSPEND_REASON, CODING_GOAL_VERIFY_WORKFLOW_ID, CodingGoalVerifyError, createCodingGoalVerifyWorkflow, runCodingGoalVerify, } from "./goal-verify.js";
13
+ export { createGitApplyTool, createGitBranchTool, createGitCommitTool, createGitDiffTool, createGitPrHandoffTool, createGitStatusTool, createGitTools, createGitWorktreeTool, } from "./git-tools.js";
27
14
  export type { CodingGoalVerifyApproval, RunCodingGoalVerifyOptions, } from "./goal-verify.js";
28
- export { withFileMutationQueue } from "./file-mutation-queue.js";
15
+ export { CODING_GOAL_VERIFY_REVISION, CODING_GOAL_VERIFY_SUSPEND_REASON, CODING_GOAL_VERIFY_WORKFLOW_ID, CodingGoalVerifyError, createCodingGoalVerifyWorkflow, runCodingGoalVerify, } from "./goal-verify.js";
16
+ export type { ListToolOptions } from "./list.js";
17
+ export { createRepoListTool } from "./list.js";
18
+ export type { ReadOperations, ReadTextOptions, ReadTextResult, ReadToolOptions, TransformImage, TransformImageInput, } from "./read.js";
19
+ export { createReadTool, DEFAULT_MAX_IMAGE_BYTES, detectSupportedImageMimeType, detectSupportedImageMimeTypeFromFile, } from "./read.js";
20
+ export type { RepoEntryKind, RepoListEntry, RepositoryLimitOptions, RepositoryListRequest, RepositoryListResult, RepositoryOperations, RepositorySearchMatch, RepositorySearchRequest, RepositorySearchResult, ResolvedRepositoryLimits, } from "./repository.js";
21
+ export { compileSearchPattern, createLocalRepositoryOperations, DEFAULT_REPO_EXCLUDE, isBinaryBuffer, RepositoryError, resolveRepoPath, resolveRepositoryLimits, toRepoRelative, } from "./repository.js";
22
+ export type { SearchToolOptions } from "./search.js";
23
+ export { createRepoSearchTool } from "./search.js";
24
+ export type { BashExecOptions, BashOperations, BashSpawnContext, BashSpawnHook, ShellConfig, ShellToolOptions, } from "./shell.js";
25
+ export { createLocalBashOperations, createShellTool, getShellConfig, killProcessTree, waitForChildProcess, } from "./shell.js";
26
+ export type { WriteOperations, WriteToolOptions } from "./write.js";
27
+ export { createWriteTool } from "./write.js";
29
28
  export { enforceExecutionPolicy } from "./execution-policy.js";
30
- export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_MAX_TEXT_SCAN_BYTES, DEFAULT_MAX_WRITE_BYTES, DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, DEFAULT_SHELL_TIMEOUT_SECONDS, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_REPO_DEPTH, DEFAULT_MAX_REPO_ENTRIES, DEFAULT_MAX_REPO_FILES, DEFAULT_MAX_REPO_RESULTS, DEFAULT_MAX_REPO_CONCURRENCY, DEFAULT_MAX_SEARCH_SCAN_BYTES, DEFAULT_MAX_SEARCH_FILE_BYTES, DEFAULT_MAX_SEARCH_MATCHES, DEFAULT_MAX_SEARCH_PATTERN_BYTES, DEFAULT_MAX_SEARCH_LINE_BYTES, DEFAULT_MAX_SEARCH_CONTEXT_LINES, DEFAULT_MAX_SEARCH_TIME_MS, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_CHECK_NAMES, DEFAULT_MAX_CHECK_CONCURRENCY, DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_MAX_CHECK_DIAGNOSTIC_LINES, DEFAULT_MAX_CHECK_OUTPUT_BYTES, DEFAULT_MAX_PR_HANDOFF_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_TODOS, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_BYTES, HARD_MAX_LINES, HARD_MAX_TEXT_SCAN_BYTES, HARD_MAX_IMAGE_BYTES, HARD_MAX_WRITE_BYTES, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, HARD_SHELL_TIMEOUT_SECONDS, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_ENTRIES, HARD_MAX_REPO_FILES, HARD_MAX_REPO_RESULTS, HARD_MAX_REPO_CONCURRENCY, HARD_MAX_SEARCH_SCAN_BYTES, HARD_MAX_SEARCH_FILE_BYTES, HARD_MAX_SEARCH_MATCHES, HARD_MAX_SEARCH_PATTERN_BYTES, HARD_MAX_SEARCH_LINE_BYTES, HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_TIME_MS, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_WORKTREES, HARD_GIT_TIMEOUT_MS, HARD_MAX_CHECK_NAMES, HARD_MAX_CHECK_CONCURRENCY, HARD_CHECK_TIMEOUT_MS, HARD_MAX_CHECK_DIAGNOSTIC_LINES, HARD_MAX_CHECK_OUTPUT_BYTES, HARD_MAX_PR_HANDOFF_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PLAN_BYTES, HARD_MAX_TODOS, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_CHECKPOINT_BYTES, } from "./limits.js";
29
+ export { withFileMutationQueue } from "./file-mutation-queue.js";
30
+ 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_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_LINES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_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_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_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_PLAN_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_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, } from "./limits.js";
31
31
  import type { ExecutionPolicy, ToolDefinition } from "@arnilo/prism";
32
- import type { ShellToolOptions } from "./shell.js";
33
- import type { ReadToolOptions } from "./read.js";
34
- import type { WriteToolOptions } from "./write.js";
35
32
  import type { EditToolOptions } from "./edit.js";
36
33
  import type { ListToolOptions } from "./list.js";
37
- import type { SearchToolOptions } from "./search.js";
34
+ import type { ReadToolOptions } from "./read.js";
38
35
  import type { RepositoryLimitOptions, RepositoryOperations } from "./repository.js";
36
+ import type { SearchToolOptions } from "./search.js";
37
+ import type { ShellToolOptions } from "./shell.js";
38
+ import type { WriteToolOptions } from "./write.js";
39
39
  /** Per-tool options combined for the aggregator factories. */
40
40
  export interface ToolsOptions {
41
41
  /** Shared execution policy applied to every coding tool unless overridden per tool. */
package/dist/index.js CHANGED
@@ -4,30 +4,30 @@
4
4
  // `ToolDefinition`s that hosts register into a `ToolRegistry` (e.g.
5
5
  // `createToolRegistry(createCodingTools(cwd))`). No tools are auto-registered — import what you need.
6
6
  // --- per-tool factories & types ---
7
- export { createShellTool, createLocalBashOperations, getShellConfig, killProcessTree, waitForChildProcess, } from "./shell.js";
8
- export { createReadTool, detectSupportedImageMimeType, detectSupportedImageMimeTypeFromFile, DEFAULT_MAX_IMAGE_BYTES, } from "./read.js";
9
- export { createWriteTool } from "./write.js";
7
+ export { createDirectoryArtifactWriter, createTempArtifactWriter, sha256Hex } from "./artifacts.js";
8
+ export { ASK_USER_DECISION_RATIONALE_COUNT, ASK_USER_DECISION_SUSPEND_REASON, ASK_USER_DECISION_TOOL_NAME, askUserDecisionResumeSchema, createAskUserDecisionResumeValidator, createAskUserDecisionTool, DEFAULT_MAX_ASK_USER_DECISION_BULLET_BYTES, DEFAULT_MAX_ASK_USER_DECISION_CUSTOM_BYTES, DEFAULT_MAX_ASK_USER_DECISION_LABEL_BYTES, DEFAULT_MAX_ASK_USER_DECISION_OPTIONS, DEFAULT_MAX_ASK_USER_DECISION_QUESTION_BYTES, HARD_MAX_ASK_USER_DECISION_BULLET_BYTES, HARD_MAX_ASK_USER_DECISION_CUSTOM_BYTES, HARD_MAX_ASK_USER_DECISION_LABEL_BYTES, HARD_MAX_ASK_USER_DECISION_OPTIONS, HARD_MAX_ASK_USER_DECISION_QUESTION_BYTES, parseAskUserDecisionArgs, resolveAskUserDecisionAnswer, resolveAskUserDecisionLimits, suspendAskUserDecision, toAskUserDecisionSuspendData, validateAskUserDecisionAgentResume, validateAskUserDecisionResume, } from "./ask-user-decision.js";
9
+ export { createCodingCheckTool } from "./checks.js";
10
+ export { assertCodingResumeAllowed, buildCodingCheckpointMetadata, CODING_CHECKPOINT_SCHEMA_VERSION, CODING_STATE_KEY, CodingCheckpointError, codingCheckpointStatePatch, codingPlanPathForTask, createCodingArtifactRef, createCodingPlanMarkdown, fingerprintJson, parseCodingPlanTodos, readCodingCheckpointFromState, readCodingPlanFile, resolveCodingCheckpointLimits, validateCodingCheckpointMetadata, verifyCodingArtifactBytes, writeCodingPlanFile, } from "./coding-checkpoint.js";
10
11
  export { createEditTool } from "./edit.js";
12
+ export { createBoundGitRunner, createGitOperations, GitError, parsePorcelainV2, resolveGitLimits, runGitCli, SAFE_GIT_CONFIG_ARGS, SAFE_GIT_ENV, } from "./git.js";
13
+ export { createGitApplyTool, createGitBranchTool, createGitCommitTool, createGitDiffTool, createGitPrHandoffTool, createGitStatusTool, createGitTools, createGitWorktreeTool, } from "./git-tools.js";
14
+ export { CODING_GOAL_VERIFY_REVISION, CODING_GOAL_VERIFY_SUSPEND_REASON, CODING_GOAL_VERIFY_WORKFLOW_ID, CodingGoalVerifyError, createCodingGoalVerifyWorkflow, runCodingGoalVerify, } from "./goal-verify.js";
11
15
  export { createRepoListTool } from "./list.js";
16
+ export { createReadTool, DEFAULT_MAX_IMAGE_BYTES, detectSupportedImageMimeType, detectSupportedImageMimeTypeFromFile, } from "./read.js";
17
+ export { compileSearchPattern, createLocalRepositoryOperations, DEFAULT_REPO_EXCLUDE, isBinaryBuffer, RepositoryError, resolveRepoPath, resolveRepositoryLimits, toRepoRelative, } from "./repository.js";
12
18
  export { createRepoSearchTool } from "./search.js";
13
- export { createLocalRepositoryOperations, resolveRepositoryLimits, compileSearchPattern, isBinaryBuffer, resolveRepoPath, toRepoRelative, RepositoryError, DEFAULT_REPO_EXCLUDE, } from "./repository.js";
14
- export { createGitOperations, resolveGitLimits, parsePorcelainV2, GitError, SAFE_GIT_ENV, SAFE_GIT_CONFIG_ARGS, createBoundGitRunner, runGitCli, } from "./git.js";
15
- export { createGitTools, createGitStatusTool, createGitDiffTool, createGitBranchTool, createGitWorktreeTool, createGitApplyTool, createGitCommitTool, createGitPrHandoffTool, } from "./git-tools.js";
16
- export { createCodingCheckTool } from "./checks.js";
17
- export { ASK_USER_DECISION_RATIONALE_COUNT, ASK_USER_DECISION_SUSPEND_REASON, ASK_USER_DECISION_TOOL_NAME, DEFAULT_MAX_ASK_USER_DECISION_BULLET_BYTES, DEFAULT_MAX_ASK_USER_DECISION_CUSTOM_BYTES, DEFAULT_MAX_ASK_USER_DECISION_LABEL_BYTES, DEFAULT_MAX_ASK_USER_DECISION_OPTIONS, DEFAULT_MAX_ASK_USER_DECISION_QUESTION_BYTES, HARD_MAX_ASK_USER_DECISION_BULLET_BYTES, HARD_MAX_ASK_USER_DECISION_CUSTOM_BYTES, HARD_MAX_ASK_USER_DECISION_LABEL_BYTES, HARD_MAX_ASK_USER_DECISION_OPTIONS, HARD_MAX_ASK_USER_DECISION_QUESTION_BYTES, askUserDecisionResumeSchema, createAskUserDecisionResumeValidator, createAskUserDecisionTool, parseAskUserDecisionArgs, resolveAskUserDecisionAnswer, resolveAskUserDecisionLimits, suspendAskUserDecision, toAskUserDecisionSuspendData, validateAskUserDecisionAgentResume, validateAskUserDecisionResume, } from "./ask-user-decision.js";
18
- export { createDirectoryArtifactWriter, createTempArtifactWriter, sha256Hex } from "./artifacts.js";
19
- export { CODING_CHECKPOINT_SCHEMA_VERSION, CODING_STATE_KEY, CodingCheckpointError, assertCodingResumeAllowed, buildCodingCheckpointMetadata, codingCheckpointStatePatch, codingPlanPathForTask, createCodingArtifactRef, createCodingPlanMarkdown, fingerprintJson, parseCodingPlanTodos, readCodingCheckpointFromState, readCodingPlanFile, resolveCodingCheckpointLimits, validateCodingCheckpointMetadata, verifyCodingArtifactBytes, writeCodingPlanFile, } from "./coding-checkpoint.js";
20
- export { CODING_GOAL_VERIFY_REVISION, CODING_GOAL_VERIFY_SUSPEND_REASON, CODING_GOAL_VERIFY_WORKFLOW_ID, CodingGoalVerifyError, createCodingGoalVerifyWorkflow, runCodingGoalVerify, } from "./goal-verify.js";
19
+ export { createLocalBashOperations, createShellTool, getShellConfig, killProcessTree, waitForChildProcess, } from "./shell.js";
20
+ export { createWriteTool } from "./write.js";
21
21
  // --- generic primitives (re-exported for hosts that want them) ---
22
- export { withFileMutationQueue } from "./file-mutation-queue.js";
23
22
  export { enforceExecutionPolicy } from "./execution-policy.js";
24
- export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_MAX_TEXT_SCAN_BYTES, DEFAULT_MAX_WRITE_BYTES, DEFAULT_MAX_EDIT_FILE_BYTES, DEFAULT_MAX_EDIT_INPUT_BYTES, DEFAULT_MAX_EDITS, DEFAULT_SHELL_TIMEOUT_SECONDS, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_MAX_REPO_DEPTH, DEFAULT_MAX_REPO_ENTRIES, DEFAULT_MAX_REPO_FILES, DEFAULT_MAX_REPO_RESULTS, DEFAULT_MAX_REPO_CONCURRENCY, DEFAULT_MAX_SEARCH_SCAN_BYTES, DEFAULT_MAX_SEARCH_FILE_BYTES, DEFAULT_MAX_SEARCH_MATCHES, DEFAULT_MAX_SEARCH_PATTERN_BYTES, DEFAULT_MAX_SEARCH_LINE_BYTES, DEFAULT_MAX_SEARCH_CONTEXT_LINES, DEFAULT_MAX_SEARCH_TIME_MS, DEFAULT_MAX_GIT_PATHS, DEFAULT_MAX_GIT_REF_BYTES, DEFAULT_MAX_GIT_MESSAGE_BYTES, DEFAULT_MAX_GIT_OUTPUT_BYTES, DEFAULT_MAX_GIT_DIFF_LINES, DEFAULT_MAX_GIT_CHANGED_FILES, DEFAULT_MAX_GIT_PATCH_BYTES, DEFAULT_MAX_GIT_WORKTREES, DEFAULT_GIT_TIMEOUT_MS, DEFAULT_MAX_CHECK_NAMES, DEFAULT_MAX_CHECK_CONCURRENCY, DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_MAX_CHECK_DIAGNOSTIC_LINES, DEFAULT_MAX_CHECK_OUTPUT_BYTES, DEFAULT_MAX_PR_HANDOFF_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_TODOS, DEFAULT_MAX_TODO_TEXT_BYTES, DEFAULT_MAX_CODING_ARTIFACTS, DEFAULT_MAX_CODING_ARTIFACT_BYTES, DEFAULT_MAX_CHECK_SUMMARY_BYTES, DEFAULT_MAX_CODING_CHECKPOINT_BYTES, HARD_MAX_BYTES, HARD_MAX_LINES, HARD_MAX_TEXT_SCAN_BYTES, HARD_MAX_IMAGE_BYTES, HARD_MAX_WRITE_BYTES, HARD_MAX_EDIT_FILE_BYTES, HARD_MAX_EDIT_INPUT_BYTES, HARD_MAX_EDITS, HARD_SHELL_TIMEOUT_SECONDS, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_ENTRIES, HARD_MAX_REPO_FILES, HARD_MAX_REPO_RESULTS, HARD_MAX_REPO_CONCURRENCY, HARD_MAX_SEARCH_SCAN_BYTES, HARD_MAX_SEARCH_FILE_BYTES, HARD_MAX_SEARCH_MATCHES, HARD_MAX_SEARCH_PATTERN_BYTES, HARD_MAX_SEARCH_LINE_BYTES, HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_TIME_MS, HARD_MAX_GIT_PATHS, HARD_MAX_GIT_REF_BYTES, HARD_MAX_GIT_MESSAGE_BYTES, HARD_MAX_GIT_OUTPUT_BYTES, HARD_MAX_GIT_DIFF_LINES, HARD_MAX_GIT_CHANGED_FILES, HARD_MAX_GIT_PATCH_BYTES, HARD_MAX_GIT_WORKTREES, HARD_GIT_TIMEOUT_MS, HARD_MAX_CHECK_NAMES, HARD_MAX_CHECK_CONCURRENCY, HARD_CHECK_TIMEOUT_MS, HARD_MAX_CHECK_DIAGNOSTIC_LINES, HARD_MAX_CHECK_OUTPUT_BYTES, HARD_MAX_PR_HANDOFF_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PLAN_BYTES, HARD_MAX_TODOS, HARD_MAX_TODO_TEXT_BYTES, HARD_MAX_CODING_ARTIFACTS, HARD_MAX_CODING_ARTIFACT_BYTES, HARD_MAX_CHECK_SUMMARY_BYTES, HARD_MAX_CODING_CHECKPOINT_BYTES, } from "./limits.js";
25
- import { createShellTool } from "./shell.js";
26
- import { createReadTool } from "./read.js";
27
- import { createWriteTool } from "./write.js";
23
+ export { withFileMutationQueue } from "./file-mutation-queue.js";
24
+ 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_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_LINES, DEFAULT_MAX_PLAN_BYTES, DEFAULT_MAX_PR_COMMITS, DEFAULT_MAX_PR_HANDOFF_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_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_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_PLAN_BYTES, HARD_MAX_PR_COMMITS, HARD_MAX_PR_HANDOFF_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, } from "./limits.js";
28
25
  import { createEditTool } from "./edit.js";
29
26
  import { createRepoListTool } from "./list.js";
27
+ import { createReadTool } from "./read.js";
30
28
  import { createRepoSearchTool } from "./search.js";
29
+ import { createShellTool } from "./shell.js";
30
+ import { createWriteTool } from "./write.js";
31
31
  function withSharedExecutionPolicy(toolOptions, shared) {
32
32
  if (!shared)
33
33
  return (toolOptions ?? {});
package/dist/list.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { enforceExecutionPolicy } from "./execution-policy.js";
2
- import { createLocalRepositoryOperations, resolveRepositoryLimits, RepositoryError, } from "./repository.js";
3
2
  import { HARD_MAX_REPO_DEPTH, HARD_MAX_REPO_RESULTS, validateCodingLimit, validateCodingLimitAllowZero } from "./limits.js";
3
+ import { createLocalRepositoryOperations, RepositoryError, resolveRepositoryLimits, } from "./repository.js";
4
4
  function errorResult(toolCallId, message) {
5
5
  return {
6
6
  toolCallId,
@@ -11,9 +11,7 @@ function errorResult(toolCallId, message) {
11
11
  }
12
12
  function formatListText(result) {
13
13
  if (result.entries.length === 0) {
14
- return result.truncated
15
- ? `[truncated by ${result.truncatedBy ?? "limit"} before any entries]`
16
- : "(no entries)";
14
+ return result.truncated ? `[truncated by ${result.truncatedBy ?? "limit"} before any entries]` : "(no entries)";
17
15
  }
18
16
  const lines = result.entries.map((entry) => {
19
17
  const size = entry.size !== undefined ? `\t${entry.size}` : "";
@@ -131,11 +129,7 @@ export function createRepoListTool(cwd, options) {
131
129
  };
132
130
  }
133
131
  catch (error) {
134
- const message = error instanceof RepositoryError
135
- ? error.message
136
- : error instanceof Error
137
- ? error.message
138
- : String(error);
132
+ const message = error instanceof RepositoryError ? error.message : error instanceof Error ? error.message : String(error);
139
133
  return errorResult(toolCallId, message);
140
134
  }
141
135
  },
@@ -98,7 +98,7 @@ export function resolveReadPath(filePath, cwd) {
98
98
  }
99
99
  export async function resolveReadPathAsync(filePath, cwd) {
100
100
  const resolved = resolveToCwd(filePath, cwd);
101
- if ((await pathExists(resolved)))
101
+ if (await pathExists(resolved))
102
102
  return resolved;
103
103
  const amPmVariant = tryMacOSScreenshotPath(resolved);
104
104
  if (amPmVariant !== resolved && (await pathExists(amPmVariant)))
package/dist/read.js CHANGED
@@ -21,11 +21,11 @@
21
21
  */
22
22
  import { Buffer } from "node:buffer";
23
23
  import { constants } from "node:fs";
24
- import { access as fsAccess, open, stat as fsStat } from "node:fs/promises";
24
+ import { access as fsAccess, stat as fsStat, open } from "node:fs/promises";
25
25
  import { readFileBounded } from "./bounded-file.js";
26
26
  import { enforceExecutionPolicy } from "./execution-policy.js";
27
- import { resolveReadPathAsync } from "./path-utils.js";
28
27
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_IMAGE_BYTES, DEFAULT_MAX_LINES, DEFAULT_MAX_TEXT_SCAN_BYTES, HARD_MAX_BYTES, HARD_MAX_IMAGE_BYTES, HARD_MAX_LINES, HARD_MAX_TEXT_SCAN_BYTES, validateCodingLimit, } from "./limits.js";
28
+ import { resolveReadPathAsync } from "./path-utils.js";
29
29
  import { formatSize } from "./truncate.js";
30
30
  // --- magic-byte image MIME detection (faithful port of pi utils/mime.js, pure JS, no deps) ---
31
31
  const IMAGE_TYPE_SNIFF_BYTES = 4100;
@@ -64,9 +64,7 @@ export async function detectSupportedImageMimeTypeFromFile(filePath) {
64
64
  }
65
65
  function isPng(buffer) {
66
66
  // First chunk after the 8-byte signature must be a 13-byte IHDR.
67
- return (buffer.length >= 16 &&
68
- readUint32BE(buffer, PNG_SIGNATURE.length) === 13 &&
69
- startsWithAscii(buffer, 12, "IHDR"));
67
+ return buffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, "IHDR");
70
68
  }
71
69
  function isAnimatedPng(buffer) {
72
70
  // Walk PNG chunks; an acTL chunk before the first IDAT marks an animated (APNG) image.
@@ -118,16 +116,10 @@ function readUint16LE(buffer, offset) {
118
116
  return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);
119
117
  }
120
118
  function readUint32BE(buffer, offset) {
121
- return ((buffer[offset] ?? 0) * 0x1000000 +
122
- ((buffer[offset + 1] ?? 0) << 16) +
123
- ((buffer[offset + 2] ?? 0) << 8) +
124
- (buffer[offset + 3] ?? 0));
119
+ return ((buffer[offset] ?? 0) * 0x1000000 + ((buffer[offset + 1] ?? 0) << 16) + ((buffer[offset + 2] ?? 0) << 8) + (buffer[offset + 3] ?? 0));
125
120
  }
126
121
  function readUint32LE(buffer, offset) {
127
- return ((buffer[offset] ?? 0) +
128
- ((buffer[offset + 1] ?? 0) << 8) +
129
- ((buffer[offset + 2] ?? 0) << 16) +
130
- (buffer[offset + 3] ?? 0) * 0x1000000);
122
+ return ((buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8) + ((buffer[offset + 2] ?? 0) << 16) + (buffer[offset + 3] ?? 0) * 0x1000000);
131
123
  }
132
124
  function startsWith(buffer, bytes) {
133
125
  if (buffer.length < bytes.length)
@@ -339,9 +331,7 @@ export function createReadTool(cwd, options) {
339
331
  }
340
332
  try {
341
333
  const startLine = validateCodingLimit("offset", offset ?? 1, Number.MAX_SAFE_INTEGER);
342
- const requestedLines = limit === undefined
343
- ? undefined
344
- : validateCodingLimit("limit", limit, HARD_MAX_LINES);
334
+ const requestedLines = limit === undefined ? undefined : validateCodingLimit("limit", limit, HARD_MAX_LINES);
345
335
  const absolutePath = await resolveReadPathAsync(path, cwd);
346
336
  const policyCheck = await enforceExecutionPolicy(options?.executionPolicy, {
347
337
  kind: "read",
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Bounded repository walk primitives for list/search tools.
3
+ *
4
+ * Streams the tree with Node `opendir` / `lstat`; never follows symlink escapes,
5
+ * rejects devices/FIFOs/sockets for descent, and charges finite depth/entry/file
6
+ * limits before retaining the next result. No glob/index/watcher dependency.
7
+ */
1
8
  export type RepoEntryKind = "file" | "directory" | "symlink" | "other";
2
9
  export interface RepoListEntry {
3
10
  readonly path: string;
@@ -5,7 +5,7 @@
5
5
  * rejects devices/FIFOs/sockets for descent, and charges finite depth/entry/file
6
6
  * limits before retaining the next result. No glob/index/watcher dependency.
7
7
  */
8
- import { open, opendir, lstat, realpath } from "node:fs/promises";
8
+ import { lstat, open, opendir, realpath } from "node:fs/promises";
9
9
  import { isAbsolute, join, relative, resolve, sep } from "node:path";
10
10
  import { DEFAULT_BINARY_SNIFF_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, 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, validateCodingLimit, validateCodingLimitAllowZero, } from "./limits.js";
11
11
  import { resolveToCwd } from "./path-utils.js";
@@ -278,9 +278,7 @@ async function listLocal(request, defaults) {
278
278
  kind = "symlink";
279
279
  else if (startStat.isFile())
280
280
  kind = "file";
281
- const entry = kind === "file"
282
- ? { path: resolved.relative, kind, size: startStat.size }
283
- : { path: resolved.relative, kind };
281
+ const entry = kind === "file" ? { path: resolved.relative, kind, size: startStat.size } : { path: resolved.relative, kind };
284
282
  scannedEntries = 1;
285
283
  scannedFiles = kind === "file" ? 1 : 0;
286
284
  if (offset === 0 && maxResults > 0)
package/dist/search.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { enforceExecutionPolicy } from "./execution-policy.js";
2
- import { HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_MATCHES, validateCodingLimit, validateCodingLimitAllowZero, } from "./limits.js";
3
- import { createLocalRepositoryOperations, resolveRepositoryLimits, RepositoryError, } from "./repository.js";
2
+ import { HARD_MAX_SEARCH_CONTEXT_LINES, HARD_MAX_SEARCH_MATCHES, validateCodingLimit, validateCodingLimitAllowZero } from "./limits.js";
3
+ import { createLocalRepositoryOperations, RepositoryError, resolveRepositoryLimits, } from "./repository.js";
4
4
  import { truncateLine } from "./truncate.js";
5
5
  function errorResult(toolCallId, message) {
6
6
  return {
@@ -26,9 +26,7 @@ function formatMatch(match) {
26
26
  }
27
27
  function formatSearchText(result) {
28
28
  if (result.matches.length === 0) {
29
- return result.truncated
30
- ? `[truncated by ${result.truncatedBy ?? "limit"} before any matches]`
31
- : "(no matches)";
29
+ return result.truncated ? `[truncated by ${result.truncatedBy ?? "limit"} before any matches]` : "(no matches)";
32
30
  }
33
31
  const body = result.matches.map(formatMatch).join("\n");
34
32
  if (!result.truncated)
@@ -153,11 +151,7 @@ export function createRepoSearchTool(cwd, options) {
153
151
  };
154
152
  }
155
153
  catch (error) {
156
- const message = error instanceof RepositoryError
157
- ? error.message
158
- : error instanceof Error
159
- ? error.message
160
- : String(error);
154
+ const message = error instanceof RepositoryError ? error.message : error instanceof Error ? error.message : String(error);
161
155
  return errorResult(toolCallId, message);
162
156
  }
163
157
  },
package/dist/shell.d.ts CHANGED
@@ -55,6 +55,9 @@ export interface ShellToolOptions {
55
55
  shellPath?: string;
56
56
  /** Hook to adjust command, cwd, or env before execution. */
57
57
  spawnHook?: BashSpawnHook;
58
+ /** Restrict the process environment cloned for the spawn hook / child process to these
59
+ * names (e.g. scrub secrets). Unset keeps the full `process.env` clone. */
60
+ envAllowlist?: readonly string[];
58
61
  /** Max lines kept in the tail snapshot (default 2000). */
59
62
  maxLines?: number;
60
63
  /** Max bytes kept in the tail snapshot (default 50KB). */
package/dist/shell.js CHANGED
@@ -24,11 +24,23 @@ import { spawn } from "node:child_process";
24
24
  import { constants, existsSync } from "node:fs";
25
25
  import { access as fsAccess } from "node:fs/promises";
26
26
  import { enforceExecutionPolicy } from "./execution-policy.js";
27
- import { OutputAccumulator } from "./output-accumulator.js";
28
27
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_MAX_TOTAL_OUTPUT_BYTES, DEFAULT_SHELL_TIMEOUT_SECONDS, HARD_MAX_BYTES, HARD_MAX_LINES, HARD_MAX_TOTAL_OUTPUT_BYTES, HARD_SHELL_TIMEOUT_SECONDS, validateCodingLimit, } from "./limits.js";
28
+ import { OutputAccumulator } from "./output-accumulator.js";
29
29
  import { formatSize } from "./truncate.js";
30
30
  const EXIT_STDIO_GRACE_MS = 100;
31
31
  // --- spawn internals (re-ported from pi utils/shell.js + utils/child-process.js) ---
32
+ /** Clone the process environment, optionally restricted to an allowlist of names. */
33
+ function pickSpawnEnv(allowlist) {
34
+ if (!allowlist)
35
+ return { ...process.env };
36
+ const env = {};
37
+ for (const name of allowlist) {
38
+ const value = process.env[name];
39
+ if (value !== undefined)
40
+ env[name] = value;
41
+ }
42
+ return env;
43
+ }
32
44
  /** Resolve the shell binary + args. shellPath → SHELL env → /bin/bash → sh. */
33
45
  export function getShellConfig(customShellPath) {
34
46
  if (customShellPath) {
@@ -284,9 +296,10 @@ export function createShellTool(cwd, options) {
284
296
  return { toolCallId, name: "shell", content: [{ type: "text", text: message }], error: { message } };
285
297
  }
286
298
  const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
299
+ const baseEnv = pickSpawnEnv(options?.envAllowlist);
287
300
  let spawnContext = spawnHook
288
- ? spawnHook({ command: resolvedCommand, cwd, env: { ...process.env } })
289
- : { command: resolvedCommand, cwd, env: { ...process.env } };
301
+ ? spawnHook({ command: resolvedCommand, cwd, env: baseEnv })
302
+ : { command: resolvedCommand, cwd, env: baseEnv };
290
303
  const policyCheck = await enforceExecutionPolicy(options?.executionPolicy, {
291
304
  kind: "shell",
292
305
  operation: "execute",
@@ -309,9 +322,7 @@ export function createShellTool(cwd, options) {
309
322
  onLimit: () => outputAbort.abort("output-limit"),
310
323
  onStorageError: () => outputAbort.abort("output-storage-error"),
311
324
  });
312
- const signal = context.signal
313
- ? AbortSignal.any([context.signal, outputAbort.signal])
314
- : outputAbort.signal;
325
+ const signal = context.signal ? AbortSignal.any([context.signal, outputAbort.signal]) : outputAbort.signal;
315
326
  let acceptingOutput = true;
316
327
  const handleData = (data) => {
317
328
  if (acceptingOutput)
@@ -399,7 +410,9 @@ export function createShellTool(cwd, options) {
399
410
  try {
400
411
  await output.cleanupTempFile();
401
412
  }
402
- catch { /* retain primary error */ }
413
+ catch {
414
+ /* retain primary error */
415
+ }
403
416
  const message = err instanceof Error ? err.message : String(err);
404
417
  return { toolCallId, name: "shell", content: [{ type: "text", text: message }], error: { message } };
405
418
  }
package/dist/truncate.js CHANGED
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * Never returns partial lines (except the documented tail single-line edge case).
11
11
  */
12
- import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, HARD_MAX_BYTES, HARD_MAX_LINES, validateCodingLimit, } from "./limits.js";
12
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, HARD_MAX_BYTES, HARD_MAX_LINES, validateCodingLimit } from "./limits.js";
13
13
  export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "./limits.js";
14
14
  /**
15
15
  * Default char cap for {@link truncateLine}. pi names this GREP_MAX_LINE_LENGTH
package/dist/write.js CHANGED
@@ -18,9 +18,9 @@ import { Buffer } from "node:buffer";
18
18
  import { mkdir as fsMkdir, writeFile as fsWriteFile } from "node:fs/promises";
19
19
  import { dirname } from "node:path";
20
20
  import { enforceExecutionPolicy } from "./execution-policy.js";
21
- import { resolveToCwd } from "./path-utils.js";
22
21
  import { withFileMutationQueue } from "./file-mutation-queue.js";
23
- import { DEFAULT_MAX_WRITE_BYTES, HARD_MAX_WRITE_BYTES, validateCodingLimit, } from "./limits.js";
22
+ import { DEFAULT_MAX_WRITE_BYTES, HARD_MAX_WRITE_BYTES, validateCodingLimit } from "./limits.js";
23
+ import { resolveToCwd } from "./path-utils.js";
24
24
  const defaultWriteOperations = {
25
25
  writeFile: (path, content, options) => fsWriteFile(path, content, { encoding: "utf-8", signal: options?.signal }),
26
26
  mkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => { }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism-coding-agent",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Optional coding-agent tools (shell, read, write, edit, repo_list, repo_search, opt-in Git/check/ask-user-decision, and durable plan/checkpoint helpers) package for Prism.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,8 +28,8 @@
28
28
  "diff": "^9.0.0"
29
29
  },
30
30
  "peerDependencies": {
31
- "@arnilo/prism": "0.0.15",
32
- "@arnilo/prism-workflows": "0.0.15"
31
+ "@arnilo/prism": "0.0.17",
32
+ "@arnilo/prism-workflows": "0.0.17"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@arnilo/prism": "file:../..",