@letrquan/book 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/CHANGELOG.md +2504 -0
  2. package/LICENSE +123 -0
  3. package/README.md +1383 -0
  4. package/dist/app-MOXXWEOY.js +18945 -0
  5. package/dist/app-MOXXWEOY.js.map +1 -0
  6. package/dist/chunk-24AXE6SP.js +12 -0
  7. package/dist/chunk-24AXE6SP.js.map +1 -0
  8. package/dist/chunk-3U5IBM24.js +213 -0
  9. package/dist/chunk-3U5IBM24.js.map +1 -0
  10. package/dist/chunk-574C6MQR.js +743 -0
  11. package/dist/chunk-574C6MQR.js.map +1 -0
  12. package/dist/chunk-5GDZ22YP.js +449 -0
  13. package/dist/chunk-5GDZ22YP.js.map +1 -0
  14. package/dist/chunk-5KLVH3PY.js +167 -0
  15. package/dist/chunk-5KLVH3PY.js.map +1 -0
  16. package/dist/chunk-5RDRAO4B.js +92 -0
  17. package/dist/chunk-5RDRAO4B.js.map +1 -0
  18. package/dist/chunk-7N4J557C.js +10 -0
  19. package/dist/chunk-7N4J557C.js.map +1 -0
  20. package/dist/chunk-A7JLBK2Y.js +3506 -0
  21. package/dist/chunk-A7JLBK2Y.js.map +1 -0
  22. package/dist/chunk-ANSJPYGI.js +84 -0
  23. package/dist/chunk-ANSJPYGI.js.map +1 -0
  24. package/dist/chunk-BTZZUCLI.js +264 -0
  25. package/dist/chunk-BTZZUCLI.js.map +1 -0
  26. package/dist/chunk-C7D4NJ2D.js +217 -0
  27. package/dist/chunk-C7D4NJ2D.js.map +1 -0
  28. package/dist/chunk-CAGOB2N4.js +208 -0
  29. package/dist/chunk-CAGOB2N4.js.map +1 -0
  30. package/dist/chunk-DGMQEI6Y.js +98 -0
  31. package/dist/chunk-DGMQEI6Y.js.map +1 -0
  32. package/dist/chunk-E75IPST5.js +289 -0
  33. package/dist/chunk-E75IPST5.js.map +1 -0
  34. package/dist/chunk-EYGD6X2T.js +180 -0
  35. package/dist/chunk-EYGD6X2T.js.map +1 -0
  36. package/dist/chunk-GTVB4HEM.js +765 -0
  37. package/dist/chunk-GTVB4HEM.js.map +1 -0
  38. package/dist/chunk-J7MIZ5CA.js +1907 -0
  39. package/dist/chunk-J7MIZ5CA.js.map +1 -0
  40. package/dist/chunk-KWHQ2XXL.js +626 -0
  41. package/dist/chunk-KWHQ2XXL.js.map +1 -0
  42. package/dist/chunk-L6LK2QIQ.js +657 -0
  43. package/dist/chunk-L6LK2QIQ.js.map +1 -0
  44. package/dist/chunk-MAQXCUR4.js +1007 -0
  45. package/dist/chunk-MAQXCUR4.js.map +1 -0
  46. package/dist/chunk-S4XL7HOM.js +402 -0
  47. package/dist/chunk-S4XL7HOM.js.map +1 -0
  48. package/dist/chunk-URLQAXTR.js +60 -0
  49. package/dist/chunk-URLQAXTR.js.map +1 -0
  50. package/dist/chunk-V4BOYR52.js +3504 -0
  51. package/dist/chunk-V4BOYR52.js.map +1 -0
  52. package/dist/chunk-VZQXX3WW.js +210 -0
  53. package/dist/chunk-VZQXX3WW.js.map +1 -0
  54. package/dist/chunk-WKBO5R4O.js +34 -0
  55. package/dist/chunk-WKBO5R4O.js.map +1 -0
  56. package/dist/chunk-XIFFTATU.js +15753 -0
  57. package/dist/chunk-XIFFTATU.js.map +1 -0
  58. package/dist/command-approvals-6Y57VCWZ.js +28 -0
  59. package/dist/command-approvals-6Y57VCWZ.js.map +1 -0
  60. package/dist/context-ZC5IFEAX.js +25 -0
  61. package/dist/context-ZC5IFEAX.js.map +1 -0
  62. package/dist/hook-approvals-CTUFKEJT.js +22 -0
  63. package/dist/hook-approvals-CTUFKEJT.js.map +1 -0
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.js +2582 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/interactive-assets-CCAAWVKH.js +31 -0
  68. package/dist/interactive-assets-CCAAWVKH.js.map +1 -0
  69. package/dist/job-runner.d.ts +2 -0
  70. package/dist/job-runner.js +235 -0
  71. package/dist/job-runner.js.map +1 -0
  72. package/dist/loader-4IDS2RIE.js +15 -0
  73. package/dist/loader-4IDS2RIE.js.map +1 -0
  74. package/dist/mcp-approvals-WNPH65BK.js +18 -0
  75. package/dist/mcp-approvals-WNPH65BK.js.map +1 -0
  76. package/dist/mcp-config-YIJIES2C.js +16 -0
  77. package/dist/mcp-config-YIJIES2C.js.map +1 -0
  78. package/dist/model-window-store-YFVNXCIP.js +27 -0
  79. package/dist/model-window-store-YFVNXCIP.js.map +1 -0
  80. package/dist/openai-compatible-RHZUBHV6.js +10 -0
  81. package/dist/openai-compatible-RHZUBHV6.js.map +1 -0
  82. package/dist/permission-approvals-76PVREFD.js +14 -0
  83. package/dist/permission-approvals-76PVREFD.js.map +1 -0
  84. package/dist/permissions-CHCKTFQQ.js +28 -0
  85. package/dist/permissions-CHCKTFQQ.js.map +1 -0
  86. package/dist/sandbox-CNVAQDA7.js +23 -0
  87. package/dist/sandbox-CNVAQDA7.js.map +1 -0
  88. package/dist/scrollback-LUKLIBVI.js +136 -0
  89. package/dist/scrollback-LUKLIBVI.js.map +1 -0
  90. package/dist/sdk.d.ts +4574 -0
  91. package/dist/sdk.js +665 -0
  92. package/dist/sdk.js.map +1 -0
  93. package/dist/settings-loader-M2QP5TX2.js +21 -0
  94. package/dist/settings-loader-M2QP5TX2.js.map +1 -0
  95. package/dist/settings-removed-JWWPT4WA.js +19 -0
  96. package/dist/settings-removed-JWWPT4WA.js.map +1 -0
  97. package/dist/shell-selection-V6QAYXPX.js +17 -0
  98. package/dist/shell-selection-V6QAYXPX.js.map +1 -0
  99. package/package.json +143 -0
  100. package/patches/ink+6.8.0.patch +13 -0
  101. package/scripts/apply-ink-patch.mjs +29 -0
  102. package/scripts/ink-patch.mjs +59 -0
  103. package/scripts/verify-ink-patch.mjs +11 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/settings.ts","../src/settings-repository.ts","../src/cli/utils.ts","../src/settings-redaction.ts"],"sourcesContent":["import { z } from 'zod';\r\n\r\n/**\r\n * Permission rule: \"Tool\" or \"Tool(specifier)\" where specifier is a glob pattern\r\n * matched against the tool's primary argument (e.g. bash command, file path).\r\n */\r\nexport const permissionRuleSchema = z.string().min(1);\r\n\r\n/**\r\n * Bash sandbox configuration (matches CC's sandbox.* keys).\r\n */\r\nexport const sandboxSchema = z.object({\r\n enabled: z.boolean().default(false),\r\n failIfUnavailable: z.boolean().default(false),\r\n autoAllowBashIfSandboxed: z.boolean().default(true),\r\n excludedCommands: z.array(z.string()).default([]),\r\n allowUnsandboxedCommands: z.boolean().default(true),\r\n filesystem: z\r\n .object({\r\n allowWrite: z.array(z.string()).default([]),\r\n denyWrite: z.array(z.string()).default([]),\r\n denyRead: z.array(z.string()).default([]),\r\n })\r\n .default({}),\r\n network: z\r\n .object({\r\n allowedDomains: z.array(z.string()).default([]),\r\n deniedDomains: z.array(z.string()).default([]),\r\n })\r\n .default({}),\r\n});\r\n\r\n/**\r\n * Permission configuration (matches CC's permissions key).\r\n */\r\n/**\r\n * Per-rule trust decisions for `permissions.allow` entries declared by the\r\n * checked-in project layer.\r\n *\r\n * Unlike an MCP server, a permission rule *is* its own identity: change the\r\n * rule and it is a different key, so no fingerprint is needed to detect drift.\r\n * Decisions are stored per workspace in `.book/settings.local.json`, which the\r\n * repository cannot write.\r\n */\r\nexport const projectAllowRuleChoiceSchema = z.enum(['approved', 'rejected']);\r\n\r\nexport type ProjectAllowRuleChoice = z.infer<typeof projectAllowRuleChoiceSchema>;\r\n\r\nexport const permissionsSchema = z.object({\r\n allow: z.array(permissionRuleSchema).default([]),\r\n ask: z.array(permissionRuleSchema).default([]),\r\n deny: z.array(permissionRuleSchema).default([]),\r\n /**\r\n * Decisions about `allow` rules the project layer declared. A project rule\r\n * with no `approved` entry here never reaches the resolved allow list.\r\n */\r\n projectAllowRules: z.record(projectAllowRuleChoiceSchema).default({}),\r\n});\r\n\r\n/**\r\n * Hook entry: a shell command that runs at a lifecycle event.\r\n * Matches Claude Code's hook configuration format.\r\n */\r\nexport const hookEntrySchema = z.object({\r\n /** Tool(specifier) pattern to filter which events trigger this hook. */\r\n matcher: z.string().optional(),\r\n /** Shell command to run (passed through system shell). */\r\n command: z.string().min(1),\r\n /** Extra environment variables for this hook. */\r\n env: z.record(z.string()).default({}),\r\n});\r\n\r\nexport type HookEntry = z.infer<typeof hookEntrySchema>;\r\n\r\n/**\r\n * Per-entry trust decisions for hook entries declared by the checked-in project\r\n * layer, keyed by a fingerprint of `{ event, matcher, command, env }`.\r\n *\r\n * A hook is a shell command Book executes at lifecycle events, so a project\r\n * hook with no `approved` entry here never reaches the resolved hooks. Unlike\r\n * an MCP server record, a hook carries no name — the fingerprint is the key.\r\n */\r\nexport const projectHookChoiceSchema = z.enum(['approved', 'rejected']);\r\n\r\nexport type ProjectHookChoice = z.infer<typeof projectHookChoiceSchema>;\r\n\r\n/** Hook events supported by book. */\r\nexport const HOOK_EVENTS = [\r\n 'SessionStart',\r\n 'SessionEnd',\r\n 'UserPromptSubmit',\r\n 'PreToolUse',\r\n 'PostToolUse',\r\n 'Stop',\r\n 'PreCompact',\r\n 'PostCompact',\r\n 'SubagentStart',\r\n 'SubagentStop',\r\n /**\r\n * Something a human should know about while nobody is watching: a run parked on\r\n * a rejected credential, a budget crossing its ceiling, a refused spawn because\r\n * the disk is nearly full. Wire ntfy/Slack/SMS here as an ordinary shell hook.\r\n *\r\n * Only `severity: 'alarm'` is meant to wake anyone; everything else is a line to\r\n * tail. `hooksSchema` is generated from this array, so the schema cost is one\r\n * entry.\r\n */\r\n 'Notification',\r\n] as const;\r\n\r\nexport type HookEvent = (typeof HOOK_EVENTS)[number];\r\n\r\n/**\r\n * Hooks configuration — a map from event name to an array of hook entries.\r\n */\r\nexport const hooksSchema = z.object({\r\n ...(Object.fromEntries(HOOK_EVENTS.map((e) => [e, z.array(hookEntrySchema).default([])])) as {\r\n [K in HookEvent]: z.ZodDefault<z.ZodArray<typeof hookEntrySchema>>;\r\n }),\r\n /**\r\n * Decisions about hook entries the checked-in project layer declared. An\r\n * entry whose fingerprint has no `approved` record here never reaches the\r\n * resolved hooks.\r\n */\r\n projectEntries: z.record(projectHookChoiceSchema).default({}),\r\n});\r\n\r\nexport type HooksConfig = z.infer<typeof hooksSchema>;\r\n\r\n/**\r\n * Retry configuration schema — mirrors Claude Code's retry tunables.\r\n */\r\nexport const retrySettingsSchema = z.object({\r\n maxAttempts: z.number().int().min(0).max(15).default(10),\r\n baseDelayMs: z.number().int().min(100).max(60000).default(1000),\r\n maxDelayMs: z.number().int().min(100).max(300000).default(30000),\r\n totalBudgetMs: z.number().int().min(0).max(600000).default(0),\r\n requestTimeoutMs: z.number().int().min(5000).max(600000).default(600000),\r\n streamStallTimeoutMs: z.number().int().min(5000).max(120000).default(20000),\r\n /**\r\n * Stall ceiling while the model is thinking, which is a different regime.\r\n *\r\n * `streamStallTimeoutMs` is tuned for a chat: 20s of silence means something\r\n * broke. But with adaptive thinking on — the default for every Opus and Sonnet\r\n * model here, at `high` effort unless told otherwise — a long quiet stretch\r\n * before the first token is the model working, not a fault. Applying the chat\r\n * timeout to it cancels a healthy request and reports `stream_stall`.\r\n */\r\n thinkingStallTimeoutMs: z.number().int().min(10_000).max(1_800_000).default(900_000),\r\n toolRetries: z.number().int().min(0).max(3).default(1),\r\n watchdog: z.boolean().default(false),\r\n /**\r\n * How many times a turn may be re-sent after a transport fault that left the\r\n * work intact — a stalled stream, a dropped socket.\r\n *\r\n * `maxAttempts` covers connection setup only; once a 200 response is streaming\r\n * it is out of scope, so without this a single 20-second provider silence ended\r\n * the run. Set to 0 to restore that behavior exactly.\r\n */\r\n streamReissueAttempts: z.number().int().min(0).max(10).default(3),\r\n /**\r\n * Separate allowance for continuing after the provider's output cap. A large\r\n * generated file legitimately hits the cap on consecutive turns, and sharing\r\n * the transport budget would leave nothing for a real socket drop afterwards.\r\n */\r\n outputCapContinuations: z.number().int().min(0).max(50).default(10),\r\n});\r\n\r\nexport type RetrySettings = z.infer<typeof retrySettingsSchema>;\r\n\r\nexport const effortLevelSchema = z.enum(['low', 'medium', 'high', 'xhigh', 'max']);\r\n\r\nexport const providerModelSchema = z.object({\r\n label: z.string().optional(),\r\n contextWindow: z.number().int().positive().optional(),\r\n maxOutputTokens: z.number().int().positive().optional(),\r\n /** Whether this model accepts image input. Unknown models remain optimistic. */\r\n vision: z.boolean().optional(),\r\n /**\r\n * Entered by hand rather than returned by the endpoint's model-list API.\r\n * Refreshing the catalog keeps these, since they exist precisely because\r\n * discovery does not list them.\r\n */\r\n manual: z.boolean().optional(),\r\n /** Mutation-tool preference for this model; defaults to a family-level prior. */\r\n editFormat: z.enum(['patch', 'replace', 'whole']).optional(),\r\n effort: z\r\n .union([\r\n z.literal(false),\r\n z.object({\r\n default: effortLevelSchema.optional(),\r\n levels: z.array(effortLevelSchema).optional(),\r\n }),\r\n ])\r\n .optional(),\r\n});\r\n\r\nexport const providerConfigSchema = z.object({\r\n type: z.enum(['openai', 'anthropic']).default('openai'),\r\n baseURL: z.string().min(1).optional(),\r\n baseUrl: z.string().min(1).optional(),\r\n apiKey: z.string().min(1).optional(),\r\n models: z.record(providerModelSchema).default({}),\r\n});\r\n\r\n/**\r\n * Continuation: whether a turn that stops with no tool calls may be re-driven.\r\n *\r\n * `runAgentLoop` ends as soon as a turn produces no tool calls, so one user\r\n * message is the whole run and a model that writes \"I've finished\" stops there.\r\n * Enabling this lets the loop append a host-authored user turn and keep going\r\n * while there is demonstrably work left.\r\n *\r\n * Off by default: it changes when a run ends, and continuation without the\r\n * no-progress brake below would let a stalled run spin and bill silently, where\r\n * today it stops and a human notices.\r\n */\r\nexport const continuationSettingsSchema = z.object({\r\n enabled: z.boolean().default(false),\r\n /** Consecutive host-authored continuations before the run stops regardless. */\r\n maxConsecutive: z.number().int().min(1).max(1000).default(50),\r\n /**\r\n * Identical progress witnesses in a row before the run stops as no-progress.\r\n * Minimum 1: a 0 here would fire on the first boundary, before any witness\r\n * exists, and label a run that never got a chance to spin as spinning.\r\n */\r\n noProgressLimit: z.number().int().min(1).max(20).default(3),\r\n /**\r\n * Consecutive turns in which EVERY tool call was refused before the run stops.\r\n *\r\n * Enforced even when `enabled` is false, deliberately. The spin it catches\r\n * predates continuation and needs no continuation to happen: a headless run in\r\n * the default permission mode answers every prompt `deny`, so the model can\r\n * re-issue a refused call forever while `toolCalls.length > 0` keeps the\r\n * turn-end gate from ever firing. None of the existing anti-loop signals see it\r\n * either — the repeated-failure breaker ignores anything that is not `error`,\r\n * and `toolCallStats.failures` excludes `blocked` by construction.\r\n *\r\n * 0 disables the guard.\r\n */\r\n blockedToolTurnLimit: z.number().int().min(0).max(100).default(3),\r\n /** Turns between host-authored work-state messages; 0 disables them. */\r\n planRefreshTurns: z.number().int().min(0).max(500).default(25),\r\n /** Wall-clock ceiling for one continued run; 0 means no ceiling. */\r\n maxWallClockMs: z.number().int().min(0).default(0),\r\n});\r\n\r\nexport type ContinuationSettings = z.infer<typeof continuationSettingsSchema>;\r\n\r\nexport const memorySettingsSchema = z.object({\r\n enabled: z.boolean().default(true),\r\n autoSave: z.boolean().default(true),\r\n requireApproval: z.boolean().default(true),\r\n});\r\n\r\nexport const agentSettingsSchema = z.object({\r\n mode: z.enum(['adaptive', 'manual', 'off']).default('adaptive'),\r\n maxConcurrent: z.number().int().min(1).max(16).default(3),\r\n maxSpawned: z.number().int().min(1).max(64).default(8),\r\n maxDepth: z.literal(1).default(1),\r\n persist: z.boolean().default(true),\r\n includeUntrackedInSnapshot: z.boolean().default(true),\r\n telemetry: z.boolean().default(true),\r\n retentionDays: z.number().int().min(1).max(3650).default(30),\r\n checks: z.record(z.union([z.string().min(1), z.array(z.string().min(1)).min(1)])).default({}),\r\n /**\r\n * Wall-clock ceiling for one `Check` run. The 120s default suits a focused\r\n * suite; a full `npm test` on a large repository routinely exceeds it, and a\r\n * check that always times out is worse than no check because the timeout was\r\n * reported as a failing suite. Raise it per project rather than per invocation.\r\n */\r\n checkTimeoutMs: z.number().int().min(1_000).max(7_200_000).default(120_000),\r\n /**\r\n * Simultaneous agent worktrees per repository; 0 disables the check.\r\n *\r\n * Nothing reclaims a worktree automatically outside the TUI, and the store's\r\n * retention sweep runs once at startup with a 30-day default — so on a long\r\n * unattended run the count only grows. Sized above `maxConcurrent` so ordinary\r\n * fan-out is unaffected and only accumulation trips it.\r\n */\r\n maxWorktrees: z.number().int().min(0).max(256).default(24),\r\n /**\r\n * Re-drive agents that were interrupted by process death on the next start.\r\n *\r\n * A restart otherwise converts the whole pending backlog into terminal records\r\n * nothing picks up, silently losing hours of child work on a wide fan-out. The\r\n * re-drive is contained: explorers are read-only and patchers/validators run in\r\n * their own worktree, so nothing reaches the parent workspace without the usual\r\n * evidence gate. Only `process_exit` interruptions qualify — a user stop stays\r\n * stopped.\r\n */\r\n resumeInterrupted: z.boolean().default(true),\r\n /**\r\n * Refuse a new worktree when free disk would fall below this; 0 disables.\r\n * Worktrees share the filesystem with the workspace, so exhausting it breaks\r\n * the root agent's own Edit and Bash, not just the child's.\r\n */\r\n minFreeDiskBytes: z\r\n .number()\r\n .int()\r\n .min(0)\r\n .default(2 * 1024 * 1024 * 1024),\r\n profiles: z\r\n .record(\r\n z.object({\r\n model: z.string().min(1).optional(),\r\n effort: effortLevelSchema.optional(),\r\n maxTurns: z.number().int().min(1).optional(),\r\n color: z.string().optional(),\r\n }),\r\n )\r\n .default({}),\r\n ui: z.object({ enabled: z.boolean().default(true) }).default({}),\r\n routing: z\r\n .object({\r\n inlineSearchBudget: z.number().int().min(1).max(20).default(3),\r\n exploreReminder: z.boolean().default(true),\r\n })\r\n .default({}),\r\n forwardTextEvents: z.boolean().default(false),\r\n});\r\n\r\nexport const toolDiscoverySettingsSchema = z.object({\r\n mode: z.enum(['auto', 'eager', 'deferred']).default('auto'),\r\n eagerToolCount: z.number().int().min(1).max(100).default(10),\r\n schemaTokenBudget: z.number().int().min(1000).max(100000).default(8000),\r\n maxLoadedTools: z.number().int().min(1).max(100).default(15),\r\n searchLimit: z.number().int().min(1).max(5).default(5),\r\n});\r\n\r\nexport type ToolDiscoverySettings = z.infer<typeof toolDiscoverySettingsSchema>;\r\n\r\nexport const toolExecutionSettingsSchema = z.object({\r\n /** Shared across the root loop and managed children for parallel-safe tools. */\r\n maxConcurrent: z.number().int().min(1).max(8).default(4),\r\n});\r\n\r\nexport type ToolExecutionSettings = z.infer<typeof toolExecutionSettingsSchema>;\r\n\r\nexport const observabilitySettingsSchema = z.object({\r\n /** Persist a per-tool-call JSONL record for `book tool-stats`. */\r\n toolTelemetry: z.boolean().default(true),\r\n /**\r\n * Default reporting window (in days) for `book tool-stats` and the target for\r\n * `book tool-stats --prune`. Disk use is bounded by size-based log rotation;\r\n * records are only deleted when they rotate out or are explicitly pruned.\r\n */\r\n toolTelemetryRetentionDays: z.number().int().min(1).max(3650).default(30),\r\n});\r\n\r\nexport type ObservabilitySettings = z.infer<typeof observabilitySettingsSchema>;\r\n\r\nexport const mcpProjectServerChoiceSchema = z.object({\r\n /** Hash of the server's command/args/env at decision time; a mismatch re-prompts. */\r\n fingerprint: z.string().min(1),\r\n choice: z.enum(['approved', 'rejected']),\r\n});\r\n\r\nexport type McpProjectServerChoice = z.infer<typeof mcpProjectServerChoiceSchema>;\r\n\r\nexport const mcpSettingsSchema = z.object({\r\n /**\r\n * Per-server trust decisions for workspace `.mcp.json` declarations.\r\n * User-global servers (<BOOK_HOME>/.book/mcp.json) never require approval.\r\n */\r\n projectServers: z.record(mcpProjectServerChoiceSchema).default({}),\r\n});\r\n\r\nexport type McpSettings = z.infer<typeof mcpSettingsSchema>;\r\n\r\nexport const projectCommandChoiceSchema = z.object({\r\n /** Digest of the shell the body substitutes at decision time; a mismatch re-prompts. */\r\n fingerprint: z.string().min(1),\r\n choice: z.enum(['approved', 'rejected']),\r\n});\r\n\r\nexport type ProjectCommandChoice = z.infer<typeof projectCommandChoiceSchema>;\r\n\r\nexport const commandSettingsSchema = z.object({\r\n /**\r\n * Per-command trust decisions for `<workspace>/.book/commands/*.md` files\r\n * that substitute shell into their prompt. That substitution runs outside the\r\n * permission system and outside the sandbox, so a repository-controlled file\r\n * needs a decision before it runs. User-global commands\r\n * (<BOOK_HOME>/commands) were written by the user and never require one.\r\n */\r\n projectCommands: z.record(projectCommandChoiceSchema).default({}),\r\n});\r\n\r\nexport type CommandSettings = z.infer<typeof commandSettingsSchema>;\r\n\r\nexport const uiSettingsSchema = z.object({\r\n /** Show provider-native and embedded model reasoning in the interactive transcript. */\r\n showThinking: z.boolean().default(true),\r\n /** Play the full-screen fire sequence on a newly created interactive startup session. */\r\n startupAnimation: z.boolean().default(true),\r\n});\r\n\r\nexport type UiSettings = z.infer<typeof uiSettingsSchema>;\r\n\r\nexport const skillActivationSchema = z.enum(['auto', 'name-only', 'manual', 'off']);\r\nexport type SkillActivation = z.infer<typeof skillActivationSchema>;\r\n\r\nexport const skillExecutionSchema = z.enum(['inherit', 'ask', 'deny']);\r\nexport type SkillExecution = z.infer<typeof skillExecutionSchema>;\r\n\r\nexport const skillSettingsSchema = z.object({\r\n /** Emergency switch that removes skill prompt and runtime effects without deleting packages. */\r\n enabled: z.boolean().default(true),\r\n /** Per-skill visibility overrides keyed by the skill's declared name. */\r\n overrides: z.record(skillActivationSchema).default({}),\r\n /** Per-skill activation consent policy. Tool calls still use the normal permission system. */\r\n execution: z.record(skillExecutionSchema).default({}),\r\n});\r\n\r\nexport type SkillSettings = z.infer<typeof skillSettingsSchema>;\r\n\r\nexport type ProviderModelConfig = z.infer<typeof providerModelSchema>;\r\nexport type ProviderConfig = z.infer<typeof providerConfigSchema>;\r\n\r\n/** The supported production strategy. */\r\nexport const compactStrategySchema = z.literal('summary');\r\nexport type CompactStrategy = z.infer<typeof compactStrategySchema>;\r\n\r\n/**\r\n * Full settings.json schema — all keys that book supports.\r\n * New keys added in later milestones extend this schema.\r\n */\r\nexport const bookSettingsSchema = z.object({\r\n model: z.string().optional(),\r\n /** Default strategy used to reduce historical conversation context. */\r\n compactStrategy: compactStrategySchema.optional(),\r\n /** Optional model used only to generate historical conversation checkpoints. */\r\n compactModel: z.string().min(1).optional(),\r\n /** Max agent turns per user message. Omit for unlimited. */\r\n maxTurns: z.number().int().min(1).optional(),\r\n maxTokens: z.number().int().min(1000).optional(),\r\n effort: effortLevelSchema.optional(),\r\n /** TUI color theme: apple (default), dark, light, auto, a bundled palette, or a custom theme filename. */\r\n theme: z.string().min(1).optional(),\r\n /**\r\n * The shell the Bash tool spawns: `bash`, `pwsh`, `powershell`, `cmd`, `sh`,\r\n * or an executable path. Honoured from the user-global layer, an explicit\r\n * `--settings` document, or `BOOK_SHELL` only: a workspace file cannot pick\r\n * the program every command is handed to.\r\n */\r\n shell: z.string().min(1).optional(),\r\n ui: uiSettingsSchema.default({}),\r\n skills: skillSettingsSchema.default({}),\r\n autoCompactEnabled: z.boolean().optional(),\r\n /** Permission mode used by each host when no invocation-specific mode is supplied. */\r\n defaultMode: z\r\n .enum(['default', 'acceptEdits', 'plan', 'auto', 'dontAsk', 'bypassPermissions'])\r\n .optional(),\r\n disableBypassPermissionsMode: z.boolean().optional(),\r\n additionalDirectories: z.array(z.string()).default([]),\r\n env: z.record(z.string()).default({}),\r\n provider: z.record(providerConfigSchema).default({}),\r\n permissions: permissionsSchema.default({}),\r\n sandbox: sandboxSchema.default({}),\r\n hooks: hooksSchema.default({}),\r\n retry: retrySettingsSchema.default({}),\r\n memory: memorySettingsSchema.default({}),\r\n continuation: continuationSettingsSchema.default({}),\r\n agents: agentSettingsSchema.default({}),\r\n toolDiscovery: toolDiscoverySettingsSchema.default({}),\r\n toolExecution: toolExecutionSettingsSchema.default({}),\r\n observability: observabilitySettingsSchema.default({}),\r\n mcp: mcpSettingsSchema.default({}),\r\n commands: commandSettingsSchema.default({}),\r\n});\r\n\r\nexport type BookSettings = z.infer<typeof bookSettingsSchema>;\r\n\r\n/**\r\n * Resolved settings after layering (all defaults filled).\r\n */\r\nexport type ResolvedSettings = Required<\r\n Omit<\r\n BookSettings,\r\n | 'model'\r\n | 'compactModel'\r\n | 'maxTurns'\r\n | 'maxTokens'\r\n | 'effort'\r\n | 'theme'\r\n | 'shell'\r\n | 'autoCompactEnabled'\r\n | 'defaultMode'\r\n | 'disableBypassPermissionsMode'\r\n >\r\n> &\r\n Pick<\r\n BookSettings,\r\n | 'model'\r\n | 'compactModel'\r\n | 'maxTurns'\r\n | 'maxTokens'\r\n | 'effort'\r\n | 'theme'\r\n | 'shell'\r\n | 'autoCompactEnabled'\r\n | 'defaultMode'\r\n | 'disableBypassPermissionsMode'\r\n >;\r\n\r\n/**\r\n * Default settings used as the base layer before user/project/local override.\r\n */\r\nexport const DEFAULT_SETTINGS: ResolvedSettings = {\r\n compactStrategy: 'summary',\r\n permissions: { allow: [], ask: [], deny: [], projectAllowRules: {} },\r\n sandbox: {\r\n enabled: false,\r\n failIfUnavailable: false,\r\n autoAllowBashIfSandboxed: true,\r\n excludedCommands: [],\r\n allowUnsandboxedCommands: true,\r\n filesystem: { allowWrite: [], denyWrite: [], denyRead: [] },\r\n network: { allowedDomains: [], deniedDomains: [] },\r\n },\r\n hooks: {\r\n SessionStart: [],\r\n SessionEnd: [],\r\n UserPromptSubmit: [],\r\n PreToolUse: [],\r\n PostToolUse: [],\r\n Stop: [],\r\n PreCompact: [],\r\n PostCompact: [],\r\n SubagentStart: [],\r\n SubagentStop: [],\r\n Notification: [],\r\n projectEntries: {},\r\n },\r\n additionalDirectories: [],\r\n env: {},\r\n provider: {},\r\n ui: { showThinking: true, startupAnimation: true },\r\n skills: { enabled: true, overrides: {}, execution: {} },\r\n retry: {\r\n maxAttempts: 10,\r\n baseDelayMs: 1000,\r\n maxDelayMs: 30000,\r\n totalBudgetMs: 0,\r\n requestTimeoutMs: 600000,\r\n streamStallTimeoutMs: 20000,\r\n thinkingStallTimeoutMs: 900_000,\r\n toolRetries: 1,\r\n watchdog: false,\r\n streamReissueAttempts: 3,\r\n outputCapContinuations: 10,\r\n },\r\n continuation: {\r\n enabled: false,\r\n maxConsecutive: 50,\r\n noProgressLimit: 3,\r\n blockedToolTurnLimit: 3,\r\n planRefreshTurns: 25,\r\n maxWallClockMs: 0,\r\n },\r\n memory: {\r\n enabled: true,\r\n autoSave: true,\r\n requireApproval: true,\r\n },\r\n agents: {\r\n mode: 'adaptive',\r\n maxConcurrent: 3,\r\n maxSpawned: 8,\r\n maxDepth: 1,\r\n persist: true,\r\n includeUntrackedInSnapshot: true,\r\n telemetry: true,\r\n retentionDays: 30,\r\n checks: {},\r\n checkTimeoutMs: 120_000,\r\n maxWorktrees: 24,\r\n resumeInterrupted: true,\r\n minFreeDiskBytes: 2 * 1024 * 1024 * 1024,\r\n profiles: {},\r\n ui: { enabled: true },\r\n routing: { inlineSearchBudget: 3, exploreReminder: true },\r\n forwardTextEvents: false,\r\n },\r\n toolDiscovery: {\r\n mode: 'auto',\r\n eagerToolCount: 10,\r\n schemaTokenBudget: 8000,\r\n maxLoadedTools: 15,\r\n searchLimit: 5,\r\n },\r\n toolExecution: {\r\n maxConcurrent: 4,\r\n },\r\n observability: {\r\n toolTelemetry: true,\r\n toolTelemetryRetentionDays: 30,\r\n },\r\n mcp: {\r\n projectServers: {},\r\n },\r\n commands: {\r\n projectCommands: {},\r\n },\r\n};\r\n","import {\r\n closeSync,\r\n existsSync,\r\n fsyncSync,\r\n mkdirSync,\r\n openSync,\r\n readFileSync,\r\n renameSync,\r\n statSync,\r\n unlinkSync,\r\n writeSync,\r\n} from 'fs';\r\nimport { basename, dirname, join } from 'path';\r\nimport type { ZodIssue } from 'zod';\r\nimport { deleteNestedValue, setNestedValue } from './cli/utils.js';\r\nimport { bookSettingsSchema } from './settings.js';\r\nimport { redactSettingValue } from './settings-redaction.js';\r\n\r\nexport type SettingsDocumentReadResult =\r\n | { status: 'absent'; path: string }\r\n | { status: 'valid'; path: string; document: Record<string, unknown> }\r\n | { status: 'malformed'; path: string; error: string }\r\n | { status: 'non-object'; path: string; error: string };\r\n\r\nexport interface SettingsDiagnostic {\r\n path: string;\r\n issuePath?: string;\r\n message: string;\r\n}\r\n\r\nexport type SettingsMutationResult =\r\n | {\r\n ok: true;\r\n path: string;\r\n document: Record<string, unknown>;\r\n values: Record<string, unknown>;\r\n changed: boolean;\r\n }\r\n | { ok: false; path: string; diagnostics: SettingsDiagnostic[] };\r\n\r\nexport interface SettingsRepositoryOptions {\r\n writeAtomic?: (path: string, contents: string) => void;\r\n}\r\n\r\nexport const SETTINGS_TOP_LEVEL_KEYS = Object.freeze(Object.keys(bookSettingsSchema.shape).sort());\r\n\r\nexport function formatSettingsKeyHelp(heading = 'Supported top-level settings:'): string {\r\n return `${heading}\\n${SETTINGS_TOP_LEVEL_KEYS.map((key) => ` ${key}`).join('\\n')}`;\r\n}\r\n\r\nfunction issueDiagnostic(path: string, issue: ZodIssue): SettingsDiagnostic {\r\n return {\r\n path,\r\n issuePath: issue.path.join('.'),\r\n message: issue.message,\r\n };\r\n}\r\n\r\nfunction safeMessage(error: unknown): string {\r\n return error instanceof Error ? error.message : String(error);\r\n}\r\n\r\nexport function readSettingsDocument(path: string): SettingsDocumentReadResult {\r\n if (!existsSync(path)) return { status: 'absent', path };\r\n\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(readFileSync(path, 'utf-8'));\r\n } catch (error) {\r\n return { status: 'malformed', path, error: safeMessage(error) };\r\n }\r\n\r\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\r\n return { status: 'non-object', path, error: 'Settings must contain a JSON object.' };\r\n }\r\n\r\n return { status: 'valid', path, document: parsed as Record<string, unknown> };\r\n}\r\n\r\nexport function writeFileAtomic(path: string, contents: string): void {\r\n const directory = dirname(path);\r\n mkdirSync(directory, { recursive: true });\r\n const temporaryPath = join(\r\n directory,\r\n `.${basename(path)}.${process.pid}.${crypto.randomUUID()}.tmp`,\r\n );\r\n let descriptor: number | undefined;\r\n\r\n try {\r\n descriptor = openSync(temporaryPath, 'wx', 0o600);\r\n writeSync(descriptor, contents, undefined, 'utf-8');\r\n fsyncSync(descriptor);\r\n closeSync(descriptor);\r\n descriptor = undefined;\r\n renameSync(temporaryPath, path);\r\n } catch (error) {\r\n if (descriptor !== undefined) closeSync(descriptor);\r\n try {\r\n unlinkSync(temporaryPath);\r\n } catch {\r\n // The temporary file may not have been created.\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\nfunction validateTopLevelKeys(\r\n path: string,\r\n document: Record<string, unknown>,\r\n): SettingsDiagnostic[] {\r\n const supported = new Set(SETTINGS_TOP_LEVEL_KEYS);\r\n return Object.keys(document)\r\n .filter((key) => !supported.has(key))\r\n .map((key) => ({\r\n path,\r\n issuePath: key,\r\n message: `Unknown top-level setting. Supported keys: ${SETTINGS_TOP_LEVEL_KEYS.join(', ')}`,\r\n }));\r\n}\r\n\r\nexport class SettingsRepository {\r\n private readonly writeAtomic: (path: string, contents: string) => void;\r\n\r\n constructor(\r\n readonly path: string,\r\n options: SettingsRepositoryOptions = {},\r\n ) {\r\n this.writeAtomic = options.writeAtomic ?? writeFileAtomic;\r\n }\r\n\r\n read(): SettingsDocumentReadResult {\r\n return readSettingsDocument(this.path);\r\n }\r\n\r\n set(values: Record<string, unknown>): SettingsMutationResult {\r\n return this.mutate((candidate) => {\r\n for (const [key, value] of Object.entries(values)) setNestedValue(candidate, key, value);\r\n }, values);\r\n }\r\n\r\n remove(paths: string[]): SettingsMutationResult {\r\n return this.mutate((candidate) => {\r\n for (const path of paths) deleteNestedValue(candidate, path.split('.'));\r\n }, {});\r\n }\r\n\r\n update(\r\n mutation: (candidate: Record<string, unknown>) => void,\r\n displayValues: Record<string, unknown> = {},\r\n ): SettingsMutationResult {\r\n return this.mutate(mutation, displayValues);\r\n }\r\n\r\n private mutate(\r\n mutation: (candidate: Record<string, unknown>) => void,\r\n values: Record<string, unknown>,\r\n ): SettingsMutationResult {\r\n let lock: number | undefined;\r\n try {\r\n lock = this.acquireLock();\r\n return this.mutateLocked(mutation, values);\r\n } catch (error) {\r\n return {\r\n ok: false,\r\n path: this.path,\r\n diagnostics: [{ path: this.path, message: safeMessage(error) }],\r\n };\r\n } finally {\r\n if (lock !== undefined) this.releaseLock(lock);\r\n }\r\n }\r\n\r\n private acquireLock(): number {\r\n mkdirSync(dirname(this.path), { recursive: true });\r\n const lockPath = `${this.path}.lock`;\r\n for (let attempt = 0; attempt < 50; attempt++) {\r\n try {\r\n return openSync(lockPath, 'wx', 0o600);\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\r\n try {\r\n if (Date.now() - statSync(lockPath).mtimeMs > 10_000) unlinkSync(lockPath);\r\n } catch {\r\n // Another process may have released or replaced the lock.\r\n }\r\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);\r\n }\r\n }\r\n throw new Error(`Timed out waiting for settings lock: ${lockPath}`);\r\n }\r\n\r\n private releaseLock(descriptor: number): void {\r\n closeSync(descriptor);\r\n try {\r\n unlinkSync(`${this.path}.lock`);\r\n } catch {\r\n // A stale-lock recovery may already have removed it.\r\n }\r\n }\r\n\r\n private mutateLocked(\r\n mutation: (candidate: Record<string, unknown>) => void,\r\n values: Record<string, unknown>,\r\n ): SettingsMutationResult {\r\n const source = this.read();\r\n if (source.status === 'malformed' || source.status === 'non-object') {\r\n return {\r\n ok: false,\r\n path: this.path,\r\n diagnostics: [{ path: this.path, message: source.error }],\r\n };\r\n }\r\n\r\n const candidate = structuredClone(source.status === 'valid' ? source.document : {});\r\n try {\r\n mutation(candidate);\r\n } catch (error) {\r\n return {\r\n ok: false,\r\n path: this.path,\r\n diagnostics: [{ path: this.path, message: safeMessage(error) }],\r\n };\r\n }\r\n\r\n const keyDiagnostics = validateTopLevelKeys(this.path, candidate);\r\n const validation = bookSettingsSchema.safeParse(candidate);\r\n const diagnostics = [\r\n ...keyDiagnostics,\r\n ...(validation.success\r\n ? []\r\n : validation.error.issues.map((issue) => issueDiagnostic(this.path, issue))),\r\n ];\r\n if (diagnostics.length > 0) return { ok: false, path: this.path, diagnostics };\r\n\r\n try {\r\n const changed =\r\n source.status !== 'valid' || JSON.stringify(source.document) !== JSON.stringify(candidate);\r\n if (changed) this.writeAtomic(this.path, JSON.stringify(candidate, null, 2) + '\\n');\r\n return {\r\n ok: true,\r\n path: this.path,\r\n document: candidate,\r\n changed,\r\n values: Object.fromEntries(\r\n Object.entries(values).map(([key, value]) => [key, redactSettingValue(key, value)]),\r\n ),\r\n };\r\n } catch (error) {\r\n return {\r\n ok: false,\r\n path: this.path,\r\n diagnostics: [{ path: this.path, message: safeMessage(error) }],\r\n };\r\n }\r\n }\r\n}\r\n\r\nexport function formatSettingsDiagnostics(diagnostics: SettingsDiagnostic[]): string {\r\n return diagnostics\r\n .map((diagnostic) => {\r\n const location = diagnostic.issuePath\r\n ? `${diagnostic.path} (${diagnostic.issuePath})`\r\n : diagnostic.path;\r\n return `${location}: ${diagnostic.message}`;\r\n })\r\n .join('\\n');\r\n}\r\n","/** Deeply nested value access by dot-separated key path. */\r\nexport function getNestedValue(obj: Record<string, unknown>, path: string): unknown {\r\n const parts = path.split('.');\r\n let current: unknown = obj;\r\n for (const part of parts) {\r\n if (current === null || current === undefined || typeof current !== 'object') return undefined;\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n return current;\r\n}\r\n\r\n/** Deeply nested value setter, creating intermediate objects as needed. */\r\nexport function setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\r\n const parts = path.split('.');\r\n let current = obj;\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n if (\r\n !(parts[i] in current) ||\r\n typeof current[parts[i]] !== 'object' ||\r\n current[parts[i]] === null\r\n ) {\r\n current[parts[i]] = {};\r\n }\r\n current = current[parts[i]] as Record<string, unknown>;\r\n }\r\n current[parts[parts.length - 1]] = value;\r\n}\r\n\r\n/** Delete a dot-path and prune only empty ancestor objects on that path. */\r\nexport function deleteNestedValue(\r\n obj: Record<string, unknown>,\r\n path: string | readonly string[],\r\n): boolean {\r\n const parts = typeof path === 'string' ? path.split('.') : [...path];\r\n const ancestors: Array<{ parent: Record<string, unknown>; key: string }> = [];\r\n let current = obj;\r\n\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n const key = parts[i];\r\n if (!Object.prototype.hasOwnProperty.call(current, key)) return false;\r\n const next = current[key];\r\n if (typeof next !== 'object' || next === null || Array.isArray(next)) return false;\r\n ancestors.push({ parent: current, key });\r\n current = next as Record<string, unknown>;\r\n }\r\n\r\n const leaf = parts[parts.length - 1];\r\n if (!Object.prototype.hasOwnProperty.call(current, leaf)) return false;\r\n delete current[leaf];\r\n\r\n for (let i = ancestors.length - 1; i >= 0; i--) {\r\n const { parent, key } = ancestors[i];\r\n const child = parent[key];\r\n if (\r\n typeof child === 'object' &&\r\n child !== null &&\r\n !Array.isArray(child) &&\r\n Object.keys(child).length === 0\r\n ) {\r\n delete parent[key];\r\n } else {\r\n break;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Parse a numeric CLI flag, refusing anything that is not a usable number.\r\n *\r\n * `parseInt('none', 10)` is `NaN`, and the old guard was truthiness — `'none'` is\r\n * truthy, so the typo sailed through. Downstream, `NaN` loses every comparison it\r\n * takes part in, which is the worst possible failure for a limit: `--max-turns`\r\n * ran zero turns and reported `completed`, and `--max-budget-usd` read as\r\n * *configured* while permitting unbounded spend. Reject it at the boundary, and\r\n * test presence with `!== undefined` so an explicit `0` is a real zero rather than\r\n * a missing flag.\r\n */\r\nexport function parseNumericFlag(\r\n raw: unknown,\r\n flag: string,\r\n opts: { integer?: boolean; min?: number } = {},\r\n): number | undefined {\r\n if (raw === undefined || raw === null || raw === '') return undefined;\r\n const text = String(raw).trim();\r\n const value = opts.integer ? Number.parseInt(text, 10) : Number.parseFloat(text);\r\n // Number.parse* stops at the first bad character, so '12abc' would otherwise\r\n // silently become 12.\r\n if (!Number.isFinite(value) || !/^[+-]?(\\d+\\.?\\d*|\\.\\d+)$/.test(text)) {\r\n throw new Error(`${flag} expects a number, but received \"${text}\".`);\r\n }\r\n // `Number.parseInt('2.5', 10)` is 2, so testing the parsed value would never\r\n // catch a fractional input for an integer flag - it would silently truncate.\r\n if (opts.integer && text.includes('.')) {\r\n throw new Error(`${flag} expects a whole number, but received \"${text}\".`);\r\n }\r\n const min = opts.min ?? 0;\r\n if (value < min) {\r\n throw new Error(`${flag} must be at least ${min}, but received \"${text}\".`);\r\n }\r\n return value;\r\n}\r\n","const REDACTED_SECRET = '*** (stored)';\r\n\r\nfunction redactProviderRecord(value: unknown): unknown {\r\n if (!value || typeof value !== 'object' || Array.isArray(value)) return value;\r\n const clone = structuredClone(value) as Record<string, unknown>;\r\n if ('apiKey' in clone) clone.apiKey = REDACTED_SECRET;\r\n return clone;\r\n}\r\n\r\nfunction redactProviderMap(value: unknown): unknown {\r\n if (!value || typeof value !== 'object' || Array.isArray(value)) return value;\r\n const clone = structuredClone(value) as Record<string, unknown>;\r\n for (const [id, provider] of Object.entries(clone)) clone[id] = redactProviderRecord(provider);\r\n return clone;\r\n}\r\n\r\n/**\r\n * Removed blocks that may still carry a credential in a real settings file.\r\n *\r\n * Subscription authentication is gone, but `auth.profiles.<id>.clientSecret`\r\n * and the free-form `headers` that rode along with the bearer token are still\r\n * on disk wherever it was configured — and `book config list` prints the *raw*\r\n * document, not the validated one, so those keys survive into terminal\r\n * scrollback and pasted bug reports. Validation discarding a block is not the\r\n * same as a display path being safe, so the whole subtree is masked rather than\r\n * its individual leaves: nothing reads it any more, so there is nothing in it\r\n * worth showing.\r\n */\r\nconst REMOVED_SECRET_BEARING_BLOCKS = ['auth'];\r\n\r\nexport function redactSettingValue(path: string, value: unknown): unknown {\r\n const parts = path.split('.');\r\n if (parts[0] && REMOVED_SECRET_BEARING_BLOCKS.includes(parts[0])) return REDACTED_SECRET;\r\n if (parts[0] !== 'provider') return value;\r\n if (parts.length === 1) return redactProviderMap(value);\r\n if (parts.length === 2) return redactProviderRecord(value);\r\n return parts[parts.length - 1] === 'apiKey' ? REDACTED_SECRET : value;\r\n}\r\n\r\nexport function redactSettingsForDisplay<T>(value: T): T {\r\n if (!value || typeof value !== 'object') return value;\r\n const clone = structuredClone(value) as Record<string, unknown>;\r\n clone.provider = redactProviderMap(clone.provider);\r\n for (const key of REMOVED_SECRET_BEARING_BLOCKS) {\r\n if (clone[key] !== undefined) clone[key] = REDACTED_SECRET;\r\n }\r\n return clone as T;\r\n}\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,449 @@
1
+ import {
2
+ resolveBookHome
3
+ } from "./chunk-24AXE6SP.js";
4
+
5
+ // src/tools/aliases.ts
6
+ var TOOL_ALIASES = {
7
+ read_file: "Read",
8
+ write_file: "Write",
9
+ edit_file: "Edit",
10
+ multi_edit: "MultiEdit",
11
+ apply_patch: "ApplyPatch",
12
+ glob: "Glob",
13
+ glob_files: "Glob",
14
+ grep: "Grep",
15
+ bash: "Bash",
16
+ // Legacy snake_case git tool names — backward compatible.
17
+ git_status: "GitStatus",
18
+ git_diff: "GitDiff",
19
+ git_log: "GitLog",
20
+ git_commit: "GitCommit",
21
+ git_branch: "GitBranch"
22
+ };
23
+ function canonicalToolName(name) {
24
+ return TOOL_ALIASES[name] ?? name;
25
+ }
26
+
27
+ // src/tools/primary-arg.ts
28
+ function getPrimaryArg(args) {
29
+ if (typeof args.command === "string") return args.command.split("\n")[0];
30
+ if (typeof args.shell_id === "string") return args.shell_id;
31
+ if (typeof args.shellId === "string") return args.shellId;
32
+ if (typeof args.taskId === "string") return args.taskId;
33
+ if (typeof args.task_id === "string") return args.task_id;
34
+ if (typeof args.filePath === "string") return args.filePath;
35
+ if (typeof args.file_path === "string") return args.file_path;
36
+ if (typeof args.patch === "string") {
37
+ const match = args.patch.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/m);
38
+ if (match) return match[1].trim();
39
+ }
40
+ if (typeof args.notebook_path === "string") return args.notebook_path;
41
+ if (typeof args.pattern === "string") return args.pattern;
42
+ if (typeof args.path === "string") return args.path;
43
+ if (typeof args.agent === "string") return args.agent;
44
+ if (typeof args.skill === "string") return args.skill;
45
+ if (typeof args.message === "string") return args.message;
46
+ if (typeof args.url === "string") return args.url;
47
+ if (typeof args.query === "string") return args.query;
48
+ if (typeof args.subject === "string") return args.subject;
49
+ if (typeof args.old_string === "string") return args.old_string.slice(0, 60);
50
+ const keys = Object.keys(args);
51
+ if (keys.length > 0) {
52
+ const v = args[keys[0]];
53
+ return typeof v === "string" ? v : "";
54
+ }
55
+ return "";
56
+ }
57
+
58
+ // src/tools/result.ts
59
+ import { mkdir, writeFile } from "fs/promises";
60
+ import { dirname, join } from "path";
61
+
62
+ // src/tools/tool-capabilities.ts
63
+ var FILE_MUTATING_TOOLS = /* @__PURE__ */ new Set([
64
+ "ApplyPatch",
65
+ "Write",
66
+ "Edit",
67
+ "MultiEdit",
68
+ "NotebookEdit"
69
+ ]);
70
+ function isFileMutatingTool(canonicalName) {
71
+ return FILE_MUTATING_TOOLS.has(canonicalName);
72
+ }
73
+
74
+ // src/tools/result.ts
75
+ var TOOL_RESULT_MAX_BYTES = 50 * 1024;
76
+ var TOOL_OUTPUT_DIRECTORY = join(resolveBookHome(), "tool-output");
77
+ function presentationFor(content, override) {
78
+ return {
79
+ kind: override?.kind ?? "text",
80
+ summary: override?.summary ?? content.split("\n")[0]?.trim() ?? "",
81
+ details: override?.details ?? content,
82
+ metadata: override?.metadata,
83
+ target: override?.target
84
+ };
85
+ }
86
+ function toolSuccess(content, options = {}) {
87
+ return {
88
+ version: 2,
89
+ toolCallId: options.toolCallId ?? "",
90
+ status: "success",
91
+ content,
92
+ data: options.data,
93
+ presentation: options.presentation ? presentationFor(content, options.presentation) : void 0,
94
+ artifacts: options.artifacts,
95
+ pagination: options.pagination
96
+ };
97
+ }
98
+ function toolFailure(message, options = {}) {
99
+ const error = {
100
+ code: options.code ?? "tool_error",
101
+ message,
102
+ retryable: options.retryable ?? false,
103
+ remediation: options.remediation,
104
+ details: options.details
105
+ };
106
+ const content = options.content ?? "";
107
+ return {
108
+ version: 2,
109
+ toolCallId: options.toolCallId ?? "",
110
+ status: options.status ?? "error",
111
+ content,
112
+ data: options.data,
113
+ structuredError: error,
114
+ presentation: options.presentation ? presentationFor(message, {
115
+ summary: message.split("\n")[0]?.trim(),
116
+ details: message,
117
+ ...options.presentation
118
+ }) : void 0,
119
+ artifacts: options.artifacts,
120
+ pagination: options.pagination
121
+ };
122
+ }
123
+ function toolResultSucceeded(result) {
124
+ return result.status === "success";
125
+ }
126
+ function toolResultErrorMessage(result) {
127
+ return result.structuredError?.message;
128
+ }
129
+ function rawToolResultModelContent(result) {
130
+ const content = result.content;
131
+ if (toolResultSucceeded(result)) return content;
132
+ const remediation = result.structuredError?.remediation;
133
+ const fix = remediation ? `
134
+ Fix: ${remediation}` : "";
135
+ const detail = content ? `
136
+ ${content}` : "";
137
+ return `ERROR [${result.structuredError?.code ?? result.status}]: ${toolResultErrorMessage(result) ?? "tool failed"}${fix}${detail}`;
138
+ }
139
+ function toolResultModelContent(result) {
140
+ const raw = rawToolResultModelContent(result);
141
+ if (Buffer.byteLength(raw) <= TOOL_RESULT_MAX_BYTES) return raw;
142
+ if (result.status === "timed_out") {
143
+ return tailPreview(
144
+ rawToolResultModelContent({ ...result, content: "" }),
145
+ result.content,
146
+ result.artifacts?.outputPath,
147
+ TOOL_RESULT_MAX_BYTES
148
+ );
149
+ }
150
+ return clippedOutputPreview(raw, result.artifacts?.outputPath, TOOL_RESULT_MAX_BYTES);
151
+ }
152
+ function utf8Prefix(text, maxBytes) {
153
+ if (maxBytes <= 0) return "";
154
+ const bytes = Buffer.from(text);
155
+ if (bytes.byteLength <= maxBytes) return text;
156
+ return bytes.subarray(0, maxBytes).toString("utf8").replace(/\uFFFD$/u, "");
157
+ }
158
+ function utf8Suffix(text, maxBytes) {
159
+ if (maxBytes <= 0) return "";
160
+ const bytes = Buffer.from(text);
161
+ if (bytes.byteLength <= maxBytes) return text;
162
+ let start = bytes.byteLength - maxBytes;
163
+ while (start < bytes.byteLength && (bytes[start] & 192) === 128) start++;
164
+ return bytes.subarray(start).toString("utf8");
165
+ }
166
+ function tailPreview(head, content, outputPath, maxBytes) {
167
+ const notice = outputPath ? `
168
+ [Earlier output truncated at ${maxBytes} bytes. Full output: ${outputPath}]
169
+ ` : `
170
+ [Earlier output truncated at ${maxBytes} bytes. Full output unavailable.]
171
+ `;
172
+ const noticeBytes = Buffer.byteLength(notice);
173
+ if (Buffer.byteLength(head) + noticeBytes >= maxBytes) {
174
+ return `${utf8Prefix(head, Math.max(0, maxBytes - noticeBytes)).trimEnd()}${notice}`;
175
+ }
176
+ const budget = maxBytes - Buffer.byteLength(head) - noticeBytes;
177
+ return `${head}${notice}${utf8Suffix(content, budget).trimStart()}`;
178
+ }
179
+ function clippedOutputPreview(content, outputPath, maxBytes) {
180
+ const notice = outputPath ? `
181
+
182
+ [Output truncated at ${maxBytes} bytes. Full output: ${outputPath}]` : `
183
+
184
+ [Output truncated at ${maxBytes} bytes. Full output unavailable.]`;
185
+ const previewBudget = Math.max(0, maxBytes - Buffer.byteLength(notice));
186
+ return `${utf8Prefix(content, previewBudget).trimEnd()}${notice}`;
187
+ }
188
+ async function boundToolResultOutput(input, _workspaceRoot, maxBytes = TOOL_RESULT_MAX_BYTES, artifactRoot = TOOL_OUTPUT_DIRECTORY) {
189
+ const result = normalizeToolResult(input);
190
+ const modelContent = rawToolResultModelContent(result);
191
+ const modelContentBytes = Buffer.byteLength(modelContent);
192
+ const contentBytes = Buffer.byteLength(result.content);
193
+ const details = result.presentation?.details;
194
+ const detailsBytes = details === void 0 ? 0 : Buffer.byteLength(details);
195
+ if (modelContentBytes <= maxBytes && detailsBytes <= maxBytes) return result;
196
+ let outputPath = result.artifacts?.outputPath;
197
+ if (!outputPath) {
198
+ const outputFile = join(artifactRoot, `${crypto.randomUUID()}.txt`);
199
+ try {
200
+ await mkdir(dirname(outputFile), { recursive: true });
201
+ await writeFile(
202
+ outputFile,
203
+ detailsBytes > modelContentBytes && details ? details : modelContent,
204
+ "utf8"
205
+ );
206
+ outputPath = outputFile.replace(/\\/g, "/");
207
+ } catch {
208
+ }
209
+ }
210
+ const modelOverflow = modelContentBytes > maxBytes;
211
+ const content = toolResultSucceeded(result) ? contentBytes > maxBytes ? clippedOutputPreview(result.content, outputPath, maxBytes) : result.content : modelOverflow ? "" : result.content;
212
+ const errorPrefix = `ERROR [${result.structuredError?.code ?? result.status}]: `;
213
+ const errorSource = `${toolResultErrorMessage(result) ?? "tool failed"}${result.content ? `
214
+ ${result.content}` : ""}`;
215
+ const fixReserve = result.structuredError?.remediation ? Buffer.byteLength(`
216
+ Fix: ${result.structuredError.remediation}`) : 0;
217
+ const errorBudget = Math.max(1, maxBytes - Buffer.byteLength(errorPrefix) - fixReserve);
218
+ const structuredError = result.structuredError ? {
219
+ ...result.structuredError,
220
+ message: modelOverflow ? (
221
+ // A killed command's output is folded into the message here, so this
222
+ // is the clip that decides what the model reads. Keeping the head
223
+ // hands back install and compile noise and drops the step the
224
+ // command died on, which is the whole point of the report.
225
+ result.status === "timed_out" ? tailPreview(result.structuredError.message, result.content, outputPath, errorBudget) : clippedOutputPreview(errorSource, outputPath, errorBudget)
226
+ ) : result.structuredError.message
227
+ } : result.structuredError;
228
+ const clippedDetails = details ? detailsBytes > maxBytes ? (
229
+ // The transcript row reads the same way the model does: for a killed
230
+ // command that means the tail it died on, not the head it started with.
231
+ result.status === "timed_out" ? tailPreview("", details, outputPath, maxBytes) : clippedOutputPreview(details, outputPath, maxBytes)
232
+ ) : details : toolResultSucceeded(result) ? content : structuredError?.message;
233
+ return {
234
+ ...result,
235
+ content,
236
+ structuredError,
237
+ presentation: result.presentation ? { ...result.presentation, details: clippedDetails } : result.presentation,
238
+ artifacts: outputPath ? { ...result.artifacts, outputPath } : result.artifacts,
239
+ pagination: {
240
+ ...result.pagination,
241
+ truncated: true,
242
+ omittedBytes: Math.max(
243
+ result.pagination?.omittedBytes ?? 0,
244
+ Math.max(modelContentBytes, contentBytes, detailsBytes) - maxBytes
245
+ )
246
+ }
247
+ };
248
+ }
249
+ function replaceToolResult(result, patch) {
250
+ const status = patch.status ?? result.status;
251
+ const content = patch.content ?? result.content;
252
+ return {
253
+ ...result,
254
+ status,
255
+ content,
256
+ structuredError: patch.error ?? (status === "success" ? void 0 : result.structuredError),
257
+ presentation: result.presentation || patch.presentation ? presentationFor(content, {
258
+ ...result.presentation,
259
+ ...patch.presentation
260
+ }) : void 0
261
+ };
262
+ }
263
+ function normalizeToolResult(result) {
264
+ const legacy = result;
265
+ const legacySuccess = legacy.success;
266
+ const legacyError = typeof legacy.error === "string" ? legacy.error : void 0;
267
+ const status = result.status ? result.status : legacySuccess ? "success" : legacyError?.startsWith("SKIPPED") ? "blocked" : legacyError?.startsWith("CANCELLED") ? "cancelled" : legacyError?.startsWith("Tool timeout") ? "timed_out" : "error";
268
+ const content = result.content ?? legacy.output ?? "";
269
+ const error = status === "success" ? void 0 : {
270
+ ...result.structuredError ?? {},
271
+ code: result.structuredError?.code ?? (status === "blocked" ? "blocked" : status),
272
+ message: legacyError ?? result.structuredError?.message ?? "Tool failed",
273
+ retryable: result.structuredError?.retryable ?? status === "timed_out"
274
+ };
275
+ const artifacts = result.artifacts ?? (legacy.fileMutation || legacy.fileMutations || legacy.fileObservations || legacy.eventRef || legacy.outputPath ? {
276
+ fileMutation: legacy.fileMutation,
277
+ fileMutations: legacy.fileMutations,
278
+ fileObservations: legacy.fileObservations,
279
+ eventRef: legacy.eventRef,
280
+ outputPath: legacy.outputPath
281
+ } : void 0);
282
+ const metrics = result.metrics ?? (legacy.durationMs !== void 0 || legacy.retryAttempt !== void 0 ? { durationMs: legacy.durationMs, retryAttempt: legacy.retryAttempt } : void 0);
283
+ return {
284
+ version: 2,
285
+ toolCallId: result.toolCallId,
286
+ status,
287
+ content,
288
+ data: result.data,
289
+ structuredError: error,
290
+ presentation: result.presentation,
291
+ artifacts,
292
+ metrics,
293
+ pagination: result.pagination
294
+ };
295
+ }
296
+ function nonEmptyLines(content) {
297
+ return content.split("\n").filter((line) => line.trim()).length;
298
+ }
299
+ function enrichToolResultPresentation(input, toolName, args) {
300
+ const result = normalizeToolResult(input);
301
+ const name = canonicalToolName(toolName);
302
+ const content = result.content;
303
+ const explicitPresentation = result.presentation;
304
+ const target = explicitPresentation?.target ?? (getPrimaryArg(args) || void 0);
305
+ const metadata = explicitPresentation?.metadata ? [...explicitPresentation.metadata] : [];
306
+ const inferKind = explicitPresentation?.kind === void 0;
307
+ const inferSummary = explicitPresentation?.summary === void 0;
308
+ const inferMetadata = explicitPresentation?.metadata === void 0;
309
+ let kind = explicitPresentation?.kind ?? "text";
310
+ let summary = explicitPresentation?.summary ?? content.split("\n")[0]?.trim() ?? "";
311
+ if (isFileMutatingTool(name)) {
312
+ if (inferKind) {
313
+ kind = result.artifacts?.fileMutation ? "file" : /^@@/m.test(content) ? "diff" : "file";
314
+ }
315
+ const mutation = result.artifacts?.fileMutation ?? result.artifacts?.fileMutations?.[0];
316
+ if (mutation) {
317
+ if (inferMetadata) {
318
+ if (mutation.addedLines) metadata.push(`+${mutation.addedLines}`);
319
+ if (mutation.removedLines) metadata.push(`-${mutation.removedLines}`);
320
+ if (!mutation.addedLines && !mutation.removedLines) metadata.push("no changes");
321
+ }
322
+ if (inferSummary) {
323
+ summary = `${mutation.kind === "create" ? "Created" : mutation.kind === "delete" ? "Deleted" : "Updated"} ${mutation.filePath}`;
324
+ }
325
+ }
326
+ } else if (name === "Read") {
327
+ if (inferKind) kind = "file";
328
+ const lines = content ? content.split("\n").length : 0;
329
+ if (inferMetadata) metadata.push(lines === 1 ? "1 line" : `${lines} lines`);
330
+ if (inferSummary) summary = target ? `Read ${target}` : summary;
331
+ } else if (name === "Glob") {
332
+ if (inferKind) kind = "search";
333
+ const count = /^(?:No files found|No matches found)$/i.test(content.trim()) ? 0 : nonEmptyLines(content.replace(/\n\.\.\. \(truncated[\s\S]*$/, ""));
334
+ if (inferMetadata) metadata.push(`${count} ${count === 1 ? "file" : "files"}`);
335
+ if (inferSummary) summary = `Found ${count} ${count === 1 ? "file" : "files"}`;
336
+ } else if (name === "Grep") {
337
+ if (inferKind) kind = "search";
338
+ const count = /^No matches found$/i.test(content.trim()) ? 0 : content.split("\n").filter((line) => /:\d+:/.test(line)).length || nonEmptyLines(content);
339
+ if (inferMetadata) metadata.push(`${count} ${count === 1 ? "match" : "matches"}`);
340
+ if (inferSummary) summary = `Found ${count} ${count === 1 ? "match" : "matches"}`;
341
+ } else if (name === "Bash" || name === "BashOutput" || name === "KillShell") {
342
+ if (inferKind) kind = "command";
343
+ if (inferSummary) summary = target ? `${name}: ${target}` : summary;
344
+ } else if (name === "GitDiff") {
345
+ if (inferKind) kind = "diff";
346
+ } else if (name.startsWith("Web") || name === "ToolSearch" || name.startsWith("SessionHistory")) {
347
+ if (inferKind) kind = name === "ToolSearch" ? "search" : "markdown";
348
+ } else if (name.startsWith("Task") || name === "TodoWrite") {
349
+ if (inferKind) kind = "task";
350
+ } else if (name.startsWith("Agent") || name.startsWith("Evidence")) {
351
+ if (inferKind) kind = "agent";
352
+ }
353
+ return {
354
+ ...result,
355
+ presentation: {
356
+ kind,
357
+ summary,
358
+ details: explicitPresentation?.details ?? content,
359
+ metadata,
360
+ target: explicitPresentation?.target ?? result.artifacts?.fileMutation?.filePath ?? target
361
+ }
362
+ };
363
+ }
364
+
365
+ // src/tools/file-provenance.ts
366
+ import { createHash } from "crypto";
367
+ import { readFile, stat } from "fs/promises";
368
+ import { normalize, relative, resolve } from "path";
369
+ function workspaceIdentity(workspaceRoot) {
370
+ const root = normalize(resolve(workspaceRoot));
371
+ const stable = process.platform === "win32" ? root.toLowerCase() : root;
372
+ return createHash("sha256").update(stable).digest("hex").slice(0, 24);
373
+ }
374
+ function observationKey(workspaceId, path) {
375
+ const normalized = path.replace(/\\/g, "/");
376
+ return `${workspaceId}:${process.platform === "win32" ? normalized.toLowerCase() : normalized}`;
377
+ }
378
+ async function observeFile(ctx, absolutePath, operation, coverage) {
379
+ const bytes = await readFile(absolutePath);
380
+ const workspaceId = workspaceIdentity(ctx.workspaceRoot);
381
+ const path = relative(resolve(ctx.workspaceRoot), absolutePath).replace(/\\/g, "/");
382
+ const observation = {
383
+ path,
384
+ workspaceId,
385
+ sha256: createHash("sha256").update(bytes).digest("hex"),
386
+ byteSize: bytes.byteLength,
387
+ lineStart: coverage?.lineStart,
388
+ lineEnd: coverage?.lineEnd,
389
+ operation,
390
+ sourceRef: ctx.currentToolTraceId ?? "runtime-tool",
391
+ timestamp: Date.now()
392
+ };
393
+ ctx.fileObservationLedger?.set(observationKey(workspaceId, path), observation);
394
+ return observation;
395
+ }
396
+ async function requireFreshObservation(ctx, absolutePath, relativePath) {
397
+ const workspaceId = workspaceIdentity(ctx.workspaceRoot);
398
+ const normalizedPath = relativePath.replace(/\\/g, "/");
399
+ const remembered = ctx.fileObservationLedger?.get(observationKey(workspaceId, normalizedPath));
400
+ if (!remembered) return void 0;
401
+ try {
402
+ const info = await stat(absolutePath);
403
+ if (!info.isFile()) return staleMessage(normalizedPath);
404
+ const bytes = await readFile(absolutePath);
405
+ const currentHash = createHash("sha256").update(bytes).digest("hex");
406
+ return currentHash === remembered.sha256 ? void 0 : staleMessage(normalizedPath);
407
+ } catch {
408
+ return staleMessage(normalizedPath);
409
+ }
410
+ }
411
+ function staleMessage(path) {
412
+ return `SKIPPED: ${path} changed or disappeared since it was last shown to the model. Call Read (or mention the file again) before modifying it.`;
413
+ }
414
+ function requireObservationForMutation(ctx, relativePath, retryVerb) {
415
+ const ledger = ctx.fileObservationLedger;
416
+ if (!ledger) return void 0;
417
+ const workspaceId = workspaceIdentity(ctx.workspaceRoot);
418
+ const normalizedPath = relativePath.replace(/\\/g, "/");
419
+ if (ledger.has(observationKey(workspaceId, normalizedPath))) return void 0;
420
+ return toolFailure(
421
+ `SKIPPED: ${normalizedPath} has not been read in this session. Call Read (or mention the file) before modifying it.`,
422
+ {
423
+ code: "file_not_observed",
424
+ remediation: `Read the file first, then retry the ${retryVerb}.`
425
+ }
426
+ );
427
+ }
428
+
429
+ export {
430
+ TOOL_ALIASES,
431
+ canonicalToolName,
432
+ getPrimaryArg,
433
+ isFileMutatingTool,
434
+ toolSuccess,
435
+ toolFailure,
436
+ toolResultSucceeded,
437
+ toolResultErrorMessage,
438
+ toolResultModelContent,
439
+ boundToolResultOutput,
440
+ replaceToolResult,
441
+ normalizeToolResult,
442
+ enrichToolResultPresentation,
443
+ workspaceIdentity,
444
+ observationKey,
445
+ observeFile,
446
+ requireFreshObservation,
447
+ requireObservationForMutation
448
+ };
449
+ //# sourceMappingURL=chunk-5GDZ22YP.js.map