@wrongstack/core 0.296.4 → 0.298.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 (820) hide show
  1. package/dist/chronicle/index.js +126 -22
  2. package/dist/chronicle/project-server-client.d.ts +12 -0
  3. package/dist/chronicle/project-server-protocol.d.ts +22 -0
  4. package/dist/chronicle/project-server.js +1076 -283
  5. package/dist/coordination/agents/index.js +136 -1
  6. package/dist/coordination/agents/role-skills.d.ts +3 -2
  7. package/dist/coordination/brain-cache.d.ts +14 -0
  8. package/dist/coordination/brain-trace.d.ts +2 -1
  9. package/dist/coordination/director/director-task-registry.d.ts +12 -0
  10. package/dist/coordination/fleet-supervisor.d.ts +21 -0
  11. package/dist/coordination/index.d.ts +23 -21
  12. package/dist/coordination/index.js +16514 -15945
  13. package/dist/coordination/mail-tools.d.ts +3 -3
  14. package/dist/coordination/mailbox-credential-store.d.ts +22 -2
  15. package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
  16. package/dist/coordination/mailbox-http-router.d.ts +6 -0
  17. package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
  18. package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
  19. package/dist/coordination/mailbox-project-server.js +1270 -289
  20. package/dist/coordination/provider-status-tracker.d.ts +2 -0
  21. package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
  22. package/dist/coordination/remote-mailbox.d.ts +30 -4
  23. package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
  24. package/dist/core/context.d.ts +5 -5
  25. package/dist/core/fallback-profile-manager.d.ts +14 -0
  26. package/dist/core/index.js +624 -168
  27. package/dist/core/instruction-bundle.d.ts +12 -0
  28. package/dist/core/system-prompt-builder.d.ts +14 -0
  29. package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
  30. package/dist/core/system-prompt-skill-text.d.ts +1 -2
  31. package/dist/defaults/index.js +2393 -1302
  32. package/dist/design/index.js +47 -8
  33. package/dist/execution/design-materialize.d.ts +22 -0
  34. package/dist/execution/index.js +582 -285
  35. package/dist/execution/skill-loader.d.ts +10 -1
  36. package/dist/execution/tool-error-taxonomy.d.ts +31 -0
  37. package/dist/execution/tool-executor.d.ts +1 -0
  38. package/dist/goal/index.js +71 -17
  39. package/dist/goal/phase-store.d.ts +7 -0
  40. package/dist/hooks/index.js +5 -0
  41. package/dist/hq/auth-audit.d.ts +6 -0
  42. package/dist/hq/auth-store.d.ts +59 -3
  43. package/dist/hq/index.js +680 -163
  44. package/dist/hq/kanban-store.d.ts +3 -0
  45. package/dist/hq/persistence/event-log.d.ts +25 -0
  46. package/dist/hq/persistence.d.ts +1 -1
  47. package/dist/hq/protocol/browser.d.ts +2 -1
  48. package/dist/hq/protocol/client.d.ts +18 -1
  49. package/dist/hq/protocol/core.d.ts +5 -16
  50. package/dist/hq/protocol/envelope.d.ts +29 -0
  51. package/dist/hq/protocol/governance.d.ts +34 -0
  52. package/dist/hq/protocol/peer.d.ts +55 -0
  53. package/dist/hq/protocol/project.d.ts +3 -0
  54. package/dist/hq/protocol/resume.d.ts +56 -0
  55. package/dist/hq/protocol.d.ts +11 -8
  56. package/dist/hq/protocol.js +675 -0
  57. package/dist/hq/publisher.d.ts +31 -2
  58. package/dist/hq/session-bridge.d.ts +8 -0
  59. package/dist/index.js +7197 -4006
  60. package/dist/infrastructure/index.js +198 -101
  61. package/dist/kernel/events/session-events.d.ts +3 -0
  62. package/dist/kernel/events/tool-events.d.ts +3 -1
  63. package/dist/models/index.js +1 -1
  64. package/dist/observability/index.d.ts +1 -1
  65. package/dist/observability/index.js +103 -5
  66. package/dist/observability/metrics.d.ts +37 -0
  67. package/dist/observability/prometheus.d.ts +11 -0
  68. package/dist/plugin/index.d.ts +5 -1
  69. package/dist/plugin/index.js +965 -511
  70. package/dist/plugins/auto-review-plugin.d.ts +6 -0
  71. package/dist/plugins/review-store-maintenance.d.ts +26 -0
  72. package/dist/plugins/review-types.d.ts +6 -0
  73. package/dist/security/capabilities.d.ts +45 -1
  74. package/dist/security/error-sanitize.d.ts +49 -0
  75. package/dist/security/file-permissions.d.ts +41 -0
  76. package/dist/security/index.d.ts +9 -6
  77. package/dist/security/index.js +3007 -2032
  78. package/dist/security/permission-policy.d.ts +55 -3
  79. package/dist/security/secret-vault.d.ts +17 -0
  80. package/dist/security/totp.d.ts +86 -0
  81. package/dist/skills/frontmatter.d.ts +12 -1
  82. package/dist/skills/github-fetcher.d.ts +48 -0
  83. package/dist/skills/index.js +137 -26
  84. package/dist/skills/limits.d.ts +19 -0
  85. package/dist/skills/skill-installer.d.ts +13 -0
  86. package/dist/storage/file-session-writer.d.ts +23 -0
  87. package/dist/storage/index.js +1140 -905
  88. package/dist/storage/provider-config-watcher.d.ts +1 -0
  89. package/dist/storage/session-helpers.d.ts +1 -0
  90. package/dist/storage/session-reader.d.ts +0 -7
  91. package/dist/storage/session-store/types.d.ts +12 -1
  92. package/dist/storage/session-store.d.ts +11 -2
  93. package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
  94. package/dist/tools/fallback-manage-tools.d.ts +6 -0
  95. package/dist/tools/index.js +305 -133
  96. package/dist/tools/mcp-use.d.ts +1 -1
  97. package/dist/types/blocks.d.ts +7 -0
  98. package/dist/types/config/autonomy.d.ts +12 -3
  99. package/dist/types/config/mcp-features.d.ts +15 -1
  100. package/dist/types/config/root.d.ts +10 -4
  101. package/dist/types/context-window.d.ts +15 -0
  102. package/dist/types/index.d.ts +1 -1
  103. package/dist/types/observability.d.ts +13 -0
  104. package/dist/types/secret-vault.d.ts +8 -0
  105. package/dist/types/session.d.ts +42 -0
  106. package/dist/types/skill.d.ts +56 -0
  107. package/dist/types/tool-executor.d.ts +2 -0
  108. package/dist/utils/continuous-memory-profiler.d.ts +35 -0
  109. package/dist/utils/env-typed.d.ts +64 -0
  110. package/dist/utils/glob-match.d.ts +21 -1
  111. package/dist/utils/heap-watchdog-types.d.ts +62 -0
  112. package/dist/utils/heap-watchdog.d.ts +15 -34
  113. package/dist/utils/heap-watchdog.js +592 -18
  114. package/dist/utils/incoming-images.d.ts +19 -0
  115. package/dist/utils/index.d.ts +15 -11
  116. package/dist/utils/index.js +1425 -545
  117. package/dist/utils/memory-flight-recorder.d.ts +47 -0
  118. package/dist/utils/path-segment.d.ts +29 -0
  119. package/dist/utils/tool-name.d.ts +34 -0
  120. package/dist/utils/win32-cmd.d.ts +25 -0
  121. package/dist/worktree/index.js +5 -0
  122. package/package.json +11 -3
  123. package/skills/chimera/SKILL.md +16 -4
  124. package/skills/data-governance/SKILL.md +92 -0
  125. package/skills/wrongstack-kanban/SKILL.md +129 -0
  126. package/skills/wrongstack-kanban/agents/openai.yaml +4 -0
  127. package/skills/wrongstack-mailbox-mcp/SKILL.md +72 -0
  128. package/skills/wrongstack-mailbox-mcp/agents/openai.yaml +4 -0
  129. package/dist/agent-status-helpers.d.ts.map +0 -1
  130. package/dist/agent-status-tracker.d.ts.map +0 -1
  131. package/dist/boot.d.ts.map +0 -1
  132. package/dist/chronicle/context.d.ts.map +0 -1
  133. package/dist/chronicle/decision-adapter.d.ts.map +0 -1
  134. package/dist/chronicle/domain-adapter.d.ts.map +0 -1
  135. package/dist/chronicle/event-hash.d.ts.map +0 -1
  136. package/dist/chronicle/file-observer.d.ts.map +0 -1
  137. package/dist/chronicle/health-monitor.d.ts.map +0 -1
  138. package/dist/chronicle/identity.d.ts.map +0 -1
  139. package/dist/chronicle/index.d.ts.map +0 -1
  140. package/dist/chronicle/index.js.map +0 -7
  141. package/dist/chronicle/journal.d.ts.map +0 -1
  142. package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
  143. package/dist/chronicle/metrics-store.d.ts.map +0 -1
  144. package/dist/chronicle/partition-filename.d.ts.map +0 -1
  145. package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
  146. package/dist/chronicle/process-adapter.d.ts.map +0 -1
  147. package/dist/chronicle/project-access.d.ts.map +0 -1
  148. package/dist/chronicle/project-server-client.d.ts.map +0 -1
  149. package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
  150. package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
  151. package/dist/chronicle/project-server.d.ts.map +0 -1
  152. package/dist/chronicle/project-server.js.map +0 -7
  153. package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
  154. package/dist/chronicle/provider-adapter.d.ts.map +0 -1
  155. package/dist/chronicle/query.d.ts.map +0 -1
  156. package/dist/chronicle/review-adapter.d.ts.map +0 -1
  157. package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
  158. package/dist/chronicle/sink.d.ts.map +0 -1
  159. package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
  160. package/dist/chronicle/sqlite-query.d.ts.map +0 -1
  161. package/dist/chronicle/stream-adapter.d.ts.map +0 -1
  162. package/dist/chronicle/tool-adapter.d.ts.map +0 -1
  163. package/dist/chronicle/types.d.ts.map +0 -1
  164. package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
  165. package/dist/coordination/agent-bridge.d.ts.map +0 -1
  166. package/dist/coordination/agent-monitor.d.ts.map +0 -1
  167. package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
  168. package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
  169. package/dist/coordination/agents/index.d.ts.map +0 -1
  170. package/dist/coordination/agents/index.js.map +0 -7
  171. package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
  172. package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
  173. package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
  174. package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
  175. package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
  176. package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
  177. package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
  178. package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
  179. package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
  180. package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
  181. package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
  182. package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
  183. package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
  184. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
  185. package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
  186. package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
  187. package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
  188. package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
  189. package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
  190. package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
  191. package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
  192. package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
  193. package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
  194. package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
  195. package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
  196. package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
  197. package/dist/coordination/agents/role-skills.d.ts.map +0 -1
  198. package/dist/coordination/agents/types.d.ts.map +0 -1
  199. package/dist/coordination/agents.d.ts.map +0 -1
  200. package/dist/coordination/auto-extend.d.ts.map +0 -1
  201. package/dist/coordination/autonomous-brain.d.ts.map +0 -1
  202. package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
  203. package/dist/coordination/brain-cache.d.ts.map +0 -1
  204. package/dist/coordination/brain-heuristics.d.ts.map +0 -1
  205. package/dist/coordination/brain-ledger.d.ts.map +0 -1
  206. package/dist/coordination/brain-monitor.d.ts.map +0 -1
  207. package/dist/coordination/brain-rules.d.ts.map +0 -1
  208. package/dist/coordination/brain-telemetry.d.ts.map +0 -1
  209. package/dist/coordination/brain-trace.d.ts.map +0 -1
  210. package/dist/coordination/brain.d.ts.map +0 -1
  211. package/dist/coordination/change-manager.d.ts.map +0 -1
  212. package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
  213. package/dist/coordination/collab-bus.d.ts.map +0 -1
  214. package/dist/coordination/collab-debug-types.d.ts.map +0 -1
  215. package/dist/coordination/collab-debug.d.ts.map +0 -1
  216. package/dist/coordination/collab-director-host.d.ts.map +0 -1
  217. package/dist/coordination/commit-safety.d.ts.map +0 -1
  218. package/dist/coordination/consensus-protocol.d.ts.map +0 -1
  219. package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
  220. package/dist/coordination/delegate-tool.d.ts.map +0 -1
  221. package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
  222. package/dist/coordination/dep-watcher.d.ts.map +0 -1
  223. package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
  224. package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
  225. package/dist/coordination/director/director-collab.d.ts.map +0 -1
  226. package/dist/coordination/director/director-errors.d.ts.map +0 -1
  227. package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
  228. package/dist/coordination/director/director-toolset.d.ts.map +0 -1
  229. package/dist/coordination/director-basic-tools.d.ts.map +0 -1
  230. package/dist/coordination/director-collab-tools.d.ts.map +0 -1
  231. package/dist/coordination/director-host-contracts.d.ts.map +0 -1
  232. package/dist/coordination/director-input-helpers.d.ts.map +0 -1
  233. package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
  234. package/dist/coordination/director-options.d.ts.map +0 -1
  235. package/dist/coordination/director-prompts.d.ts.map +0 -1
  236. package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
  237. package/dist/coordination/director-session.d.ts.map +0 -1
  238. package/dist/coordination/director-spawn-model.d.ts.map +0 -1
  239. package/dist/coordination/director-tools.d.ts.map +0 -1
  240. package/dist/coordination/director.d.ts.map +0 -1
  241. package/dist/coordination/dispatcher.d.ts.map +0 -1
  242. package/dist/coordination/file-author-tracker.d.ts.map +0 -1
  243. package/dist/coordination/fleet-bus.d.ts.map +0 -1
  244. package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
  245. package/dist/coordination/fleet-manager.d.ts.map +0 -1
  246. package/dist/coordination/fleet-spawn.d.ts.map +0 -1
  247. package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
  248. package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
  249. package/dist/coordination/fleet.d.ts.map +0 -1
  250. package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
  251. package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
  252. package/dist/coordination/icoordinator.d.ts.map +0 -1
  253. package/dist/coordination/ifleet-manager.d.ts.map +0 -1
  254. package/dist/coordination/in-memory-transport.d.ts.map +0 -1
  255. package/dist/coordination/index.d.ts.map +0 -1
  256. package/dist/coordination/index.js.map +0 -7
  257. package/dist/coordination/knowledge-graph.d.ts.map +0 -1
  258. package/dist/coordination/large-answer-store.d.ts.map +0 -1
  259. package/dist/coordination/mail-tools.d.ts.map +0 -1
  260. package/dist/coordination/mailbox-actions.d.ts.map +0 -1
  261. package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
  262. package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
  263. package/dist/coordination/mailbox-constants.d.ts.map +0 -1
  264. package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
  265. package/dist/coordination/mailbox-events.d.ts.map +0 -1
  266. package/dist/coordination/mailbox-health.d.ts.map +0 -1
  267. package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
  268. package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
  269. package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
  270. package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
  271. package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
  272. package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
  273. package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
  274. package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
  275. package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
  276. package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
  277. package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
  278. package/dist/coordination/mailbox-project-server.js.map +0 -7
  279. package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
  280. package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
  281. package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
  282. package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
  283. package/dist/coordination/mailbox-tool.d.ts.map +0 -1
  284. package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
  285. package/dist/coordination/mailbox-types.d.ts.map +0 -1
  286. package/dist/coordination/model-matrix.d.ts.map +0 -1
  287. package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
  288. package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
  289. package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
  290. package/dist/coordination/package-author-tracker.d.ts.map +0 -1
  291. package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
  292. package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
  293. package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
  294. package/dist/coordination/remote-mailbox.d.ts.map +0 -1
  295. package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
  296. package/dist/coordination/spawn-budget.d.ts.map +0 -1
  297. package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
  298. package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
  299. package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
  300. package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
  301. package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
  302. package/dist/coordination/subagent-budget.d.ts.map +0 -1
  303. package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
  304. package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
  305. package/dist/coordination/task-auctioneer.d.ts.map +0 -1
  306. package/dist/coordination/task-dag.d.ts.map +0 -1
  307. package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
  308. package/dist/coordination/transport.d.ts.map +0 -1
  309. package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
  310. package/dist/core/agent-internals.d.ts.map +0 -1
  311. package/dist/core/agent-loop.d.ts.map +0 -1
  312. package/dist/core/agent-response.d.ts.map +0 -1
  313. package/dist/core/agent-tools.d.ts.map +0 -1
  314. package/dist/core/agent-types.d.ts.map +0 -1
  315. package/dist/core/agent.d.ts.map +0 -1
  316. package/dist/core/btw.d.ts.map +0 -1
  317. package/dist/core/context.d.ts.map +0 -1
  318. package/dist/core/continue-intent.d.ts.map +0 -1
  319. package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
  320. package/dist/core/conversation-state.d.ts.map +0 -1
  321. package/dist/core/fallback-model.d.ts.map +0 -1
  322. package/dist/core/fallback-profile-manager.d.ts.map +0 -1
  323. package/dist/core/fleet-pulse.d.ts.map +0 -1
  324. package/dist/core/index.d.ts.map +0 -1
  325. package/dist/core/index.js.map +0 -7
  326. package/dist/core/input-builder.d.ts.map +0 -1
  327. package/dist/core/instruction-bundle.d.ts.map +0 -1
  328. package/dist/core/iteration-limit.d.ts.map +0 -1
  329. package/dist/core/mailbox-loop.d.ts.map +0 -1
  330. package/dist/core/model-availability-calendar.d.ts.map +0 -1
  331. package/dist/core/model-ref.d.ts.map +0 -1
  332. package/dist/core/model-ref.js.map +0 -7
  333. package/dist/core/modes/brief.d.ts.map +0 -1
  334. package/dist/core/modes/default.d.ts.map +0 -1
  335. package/dist/core/modes/teach.d.ts.map +0 -1
  336. package/dist/core/provider-runner.d.ts.map +0 -1
  337. package/dist/core/queued-messages.d.ts.map +0 -1
  338. package/dist/core/request-provider-binding.d.ts.map +0 -1
  339. package/dist/core/run-env.d.ts.map +0 -1
  340. package/dist/core/streaming-response-builder.d.ts.map +0 -1
  341. package/dist/core/system-prompt-blocks.d.ts.map +0 -1
  342. package/dist/core/system-prompt-builder.d.ts.map +0 -1
  343. package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
  344. package/dist/core/system-prompt-environment.d.ts.map +0 -1
  345. package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
  346. package/dist/core/system-prompt-plan.d.ts.map +0 -1
  347. package/dist/core/system-prompt-shell.d.ts.map +0 -1
  348. package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
  349. package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
  350. package/dist/defaults/index.d.ts.map +0 -1
  351. package/dist/defaults/index.js.map +0 -7
  352. package/dist/design/index.d.ts.map +0 -1
  353. package/dist/design/index.js.map +0 -7
  354. package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
  355. package/dist/execution/autonomous-runner.d.ts.map +0 -1
  356. package/dist/execution/autonomy-brain.d.ts.map +0 -1
  357. package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
  358. package/dist/execution/brain-chain.d.ts.map +0 -1
  359. package/dist/execution/brain-circuit.d.ts.map +0 -1
  360. package/dist/execution/brain-evaluation.d.ts.map +0 -1
  361. package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
  362. package/dist/execution/brain-runtime.d.ts.map +0 -1
  363. package/dist/execution/compaction-core.d.ts.map +0 -1
  364. package/dist/execution/compaction-scoring.d.ts.map +0 -1
  365. package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
  366. package/dist/execution/compactor.d.ts.map +0 -1
  367. package/dist/execution/council-brain.d.ts.map +0 -1
  368. package/dist/execution/council-orchestrator.d.ts.map +0 -1
  369. package/dist/execution/council-personas.d.ts.map +0 -1
  370. package/dist/execution/council-profiles.d.ts.map +0 -1
  371. package/dist/execution/council-prompts.d.ts.map +0 -1
  372. package/dist/execution/council-resolution.d.ts.map +0 -1
  373. package/dist/execution/design-color.d.ts.map +0 -1
  374. package/dist/execution/design-detect.d.ts.map +0 -1
  375. package/dist/execution/design-kit-loader.d.ts.map +0 -1
  376. package/dist/execution/design-materialize.d.ts.map +0 -1
  377. package/dist/execution/design-project-store.d.ts.map +0 -1
  378. package/dist/execution/design-tune.d.ts.map +0 -1
  379. package/dist/execution/design-verify.d.ts.map +0 -1
  380. package/dist/execution/enhance-recovery.d.ts.map +0 -1
  381. package/dist/execution/error-handler.d.ts.map +0 -1
  382. package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
  383. package/dist/execution/eternal-autonomy.d.ts.map +0 -1
  384. package/dist/execution/goal-preamble.d.ts.map +0 -1
  385. package/dist/execution/index.d.ts.map +0 -1
  386. package/dist/execution/index.js.map +0 -7
  387. package/dist/execution/intelligent-compactor.d.ts.map +0 -1
  388. package/dist/execution/model-runtime.d.ts.map +0 -1
  389. package/dist/execution/one-shot-llm.d.ts.map +0 -1
  390. package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
  391. package/dist/execution/prompt-enhancer.d.ts.map +0 -1
  392. package/dist/execution/prompt-enhancer.js.map +0 -7
  393. package/dist/execution/prompt-loader.d.ts.map +0 -1
  394. package/dist/execution/provider-runner-impl.d.ts.map +0 -1
  395. package/dist/execution/regex-patterns.d.ts.map +0 -1
  396. package/dist/execution/retry-policy.d.ts.map +0 -1
  397. package/dist/execution/selective-compactor.d.ts.map +0 -1
  398. package/dist/execution/skill-loader.d.ts.map +0 -1
  399. package/dist/execution/strategy-compactor.d.ts.map +0 -1
  400. package/dist/execution/subagent-compaction.d.ts.map +0 -1
  401. package/dist/execution/tool-executor-logging.d.ts.map +0 -1
  402. package/dist/execution/tool-executor-results.d.ts.map +0 -1
  403. package/dist/execution/tool-executor-stream.d.ts.map +0 -1
  404. package/dist/execution/tool-executor-support.d.ts.map +0 -1
  405. package/dist/execution/tool-executor.d.ts.map +0 -1
  406. package/dist/extension/extension-points.d.ts.map +0 -1
  407. package/dist/extension/index.d.ts.map +0 -1
  408. package/dist/extension/index.js.map +0 -7
  409. package/dist/extension/registry.d.ts.map +0 -1
  410. package/dist/fleet-notifier.d.ts.map +0 -1
  411. package/dist/goal/checkpoint.d.ts.map +0 -1
  412. package/dist/goal/goal-assessor.d.ts.map +0 -1
  413. package/dist/goal/goal-planner.d.ts.map +0 -1
  414. package/dist/goal/goal-runner.d.ts.map +0 -1
  415. package/dist/goal/index.d.ts.map +0 -1
  416. package/dist/goal/index.js.map +0 -7
  417. package/dist/goal/phase-board-mutations.d.ts.map +0 -1
  418. package/dist/goal/phase-graph-builder.d.ts.map +0 -1
  419. package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
  420. package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
  421. package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
  422. package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
  423. package/dist/goal/phase-orchestrator.d.ts.map +0 -1
  424. package/dist/goal/phase-store.d.ts.map +0 -1
  425. package/dist/goal/types.d.ts.map +0 -1
  426. package/dist/hooks/http-executor.d.ts.map +0 -1
  427. package/dist/hooks/index.d.ts.map +0 -1
  428. package/dist/hooks/index.js.map +0 -7
  429. package/dist/hooks/registry.d.ts.map +0 -1
  430. package/dist/hooks/runner.d.ts.map +0 -1
  431. package/dist/hooks/shell-executor.d.ts.map +0 -1
  432. package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
  433. package/dist/hq/alerts.d.ts.map +0 -1
  434. package/dist/hq/auth-audit.d.ts.map +0 -1
  435. package/dist/hq/auth-store.d.ts.map +0 -1
  436. package/dist/hq/bootstrap-store.d.ts.map +0 -1
  437. package/dist/hq/brain-bridge.d.ts.map +0 -1
  438. package/dist/hq/bridge-context.d.ts.map +0 -1
  439. package/dist/hq/commands.d.ts.map +0 -1
  440. package/dist/hq/cost-bridge.d.ts.map +0 -1
  441. package/dist/hq/exposure.d.ts.map +0 -1
  442. package/dist/hq/factory.d.ts.map +0 -1
  443. package/dist/hq/fleet-bridge.d.ts.map +0 -1
  444. package/dist/hq/index.d.ts.map +0 -1
  445. package/dist/hq/index.js.map +0 -7
  446. package/dist/hq/kanban-store.d.ts.map +0 -1
  447. package/dist/hq/mailbox-mapper.d.ts.map +0 -1
  448. package/dist/hq/persistence/event-log.d.ts.map +0 -1
  449. package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
  450. package/dist/hq/persistence/simple-log.d.ts.map +0 -1
  451. package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
  452. package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
  453. package/dist/hq/persistence.d.ts.map +0 -1
  454. package/dist/hq/protocol/brain.d.ts.map +0 -1
  455. package/dist/hq/protocol/browser.d.ts.map +0 -1
  456. package/dist/hq/protocol/client.d.ts.map +0 -1
  457. package/dist/hq/protocol/core.d.ts.map +0 -1
  458. package/dist/hq/protocol/fleet.d.ts.map +0 -1
  459. package/dist/hq/protocol/kanban.d.ts.map +0 -1
  460. package/dist/hq/protocol/mailbox.d.ts.map +0 -1
  461. package/dist/hq/protocol/mcp.d.ts.map +0 -1
  462. package/dist/hq/protocol/project.d.ts.map +0 -1
  463. package/dist/hq/protocol/session.d.ts.map +0 -1
  464. package/dist/hq/protocol/tool.d.ts.map +0 -1
  465. package/dist/hq/protocol.d.ts.map +0 -1
  466. package/dist/hq/publisher.d.ts.map +0 -1
  467. package/dist/hq/redaction.d.ts.map +0 -1
  468. package/dist/hq/session-bridge.d.ts.map +0 -1
  469. package/dist/hq/tool-bridge.d.ts.map +0 -1
  470. package/dist/hq/transcript-mapper.d.ts.map +0 -1
  471. package/dist/hq/worktree-bridge.d.ts.map +0 -1
  472. package/dist/hq/write-queues.d.ts.map +0 -1
  473. package/dist/index.d.ts.map +0 -1
  474. package/dist/index.js.map +0 -7
  475. package/dist/infrastructure/context-manager.d.ts.map +0 -1
  476. package/dist/infrastructure/index.d.ts.map +0 -1
  477. package/dist/infrastructure/index.js.map +0 -7
  478. package/dist/infrastructure/logger.d.ts.map +0 -1
  479. package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
  480. package/dist/infrastructure/path-resolver.d.ts.map +0 -1
  481. package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
  482. package/dist/infrastructure/token-counter.d.ts.map +0 -1
  483. package/dist/kernel/container.d.ts.map +0 -1
  484. package/dist/kernel/events/agent-events.d.ts.map +0 -1
  485. package/dist/kernel/events/brain-events.d.ts.map +0 -1
  486. package/dist/kernel/events/file-events.d.ts.map +0 -1
  487. package/dist/kernel/events/fleet-events.d.ts.map +0 -1
  488. package/dist/kernel/events/memory-events.d.ts.map +0 -1
  489. package/dist/kernel/events/network-events.d.ts.map +0 -1
  490. package/dist/kernel/events/process-events.d.ts.map +0 -1
  491. package/dist/kernel/events/provider-events.d.ts.map +0 -1
  492. package/dist/kernel/events/sdd-events.d.ts.map +0 -1
  493. package/dist/kernel/events/session-events.d.ts.map +0 -1
  494. package/dist/kernel/events/tool-events.d.ts.map +0 -1
  495. package/dist/kernel/events/worktree-events.d.ts.map +0 -1
  496. package/dist/kernel/events.d.ts.map +0 -1
  497. package/dist/kernel/index.d.ts.map +0 -1
  498. package/dist/kernel/index.js.map +0 -7
  499. package/dist/kernel/pipeline.d.ts.map +0 -1
  500. package/dist/kernel/run-controller.d.ts.map +0 -1
  501. package/dist/kernel/tokens.d.ts.map +0 -1
  502. package/dist/mailbox-attach.d.ts.map +0 -1
  503. package/dist/middleware/collab-pause.d.ts.map +0 -1
  504. package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
  505. package/dist/models/codex-catalog.d.ts.map +0 -1
  506. package/dist/models/index.d.ts.map +0 -1
  507. package/dist/models/index.js.map +0 -7
  508. package/dist/models/llm-selector.d.ts.map +0 -1
  509. package/dist/models/mode-store.d.ts.map +0 -1
  510. package/dist/models/model-intelligence.d.ts.map +0 -1
  511. package/dist/models/model-router.d.ts.map +0 -1
  512. package/dist/models/models-registry.d.ts.map +0 -1
  513. package/dist/models/provider-model-resolve.d.ts.map +0 -1
  514. package/dist/notifications/index.d.ts.map +0 -1
  515. package/dist/notifications/index.js.map +0 -7
  516. package/dist/notifications/notifier-impl.d.ts.map +0 -1
  517. package/dist/notifications/notifier.d.ts.map +0 -1
  518. package/dist/notifications/types.d.ts.map +0 -1
  519. package/dist/observability/event-bridge.d.ts.map +0 -1
  520. package/dist/observability/health.d.ts.map +0 -1
  521. package/dist/observability/index.d.ts.map +0 -1
  522. package/dist/observability/index.js.map +0 -7
  523. package/dist/observability/metrics.d.ts.map +0 -1
  524. package/dist/observability/network-telemetry.d.ts.map +0 -1
  525. package/dist/observability/otel-tracer.d.ts.map +0 -1
  526. package/dist/observability/otlp-metrics.d.ts.map +0 -1
  527. package/dist/observability/otlp-traces.d.ts.map +0 -1
  528. package/dist/observability/process-telemetry.d.ts.map +0 -1
  529. package/dist/observability/prometheus.d.ts.map +0 -1
  530. package/dist/observability/redact-command.d.ts.map +0 -1
  531. package/dist/observability/tracer.d.ts.map +0 -1
  532. package/dist/plugin/api.d.ts.map +0 -1
  533. package/dist/plugin/config.d.ts.map +0 -1
  534. package/dist/plugin/index.d.ts.map +0 -1
  535. package/dist/plugin/index.js.map +0 -7
  536. package/dist/plugin/loader.d.ts.map +0 -1
  537. package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
  538. package/dist/plugins/chimera-plugin.d.ts.map +0 -1
  539. package/dist/plugins/prompts-plugin.d.ts.map +0 -1
  540. package/dist/plugins/review-claim-registry.d.ts.map +0 -1
  541. package/dist/plugins/review-context-builder.d.ts.map +0 -1
  542. package/dist/plugins/review-finding-commands.d.ts.map +0 -1
  543. package/dist/plugins/review-finding-integration.d.ts.map +0 -1
  544. package/dist/plugins/review-finding-parser.d.ts.map +0 -1
  545. package/dist/plugins/review-finding-store.d.ts.map +0 -1
  546. package/dist/plugins/review-finding-types.d.ts.map +0 -1
  547. package/dist/plugins/review-report-integration.d.ts.map +0 -1
  548. package/dist/plugins/review-report-store.d.ts.map +0 -1
  549. package/dist/plugins/review-report-types.d.ts.map +0 -1
  550. package/dist/plugins/review-types.d.ts.map +0 -1
  551. package/dist/plugins/skills-plugin.d.ts.map +0 -1
  552. package/dist/plugins/sync-plugin.d.ts.map +0 -1
  553. package/dist/prompts/index.d.ts.map +0 -1
  554. package/dist/prompts/prompt-installer.d.ts.map +0 -1
  555. package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
  556. package/dist/registry/index.d.ts.map +0 -1
  557. package/dist/registry/index.js.map +0 -7
  558. package/dist/registry/provider-registry.d.ts.map +0 -1
  559. package/dist/registry/slash-command-registry.d.ts.map +0 -1
  560. package/dist/registry/tool-registry.d.ts.map +0 -1
  561. package/dist/replay/hash.d.ts.map +0 -1
  562. package/dist/replay/index.d.ts.map +0 -1
  563. package/dist/replay/index.js.map +0 -7
  564. package/dist/replay/replay-provider-runner.d.ts.map +0 -1
  565. package/dist/security/capabilities.d.ts.map +0 -1
  566. package/dist/security/config-secrets.d.ts.map +0 -1
  567. package/dist/security/directory-permission-policy.d.ts.map +0 -1
  568. package/dist/security/directory-policy-schema.d.ts.map +0 -1
  569. package/dist/security/index.d.ts.map +0 -1
  570. package/dist/security/index.js.map +0 -7
  571. package/dist/security/kanban-boundary.d.ts.map +0 -1
  572. package/dist/security/permission-policy-schema.d.ts.map +0 -1
  573. package/dist/security/permission-policy.d.ts.map +0 -1
  574. package/dist/security/readonly-permission-policy.d.ts.map +0 -1
  575. package/dist/security/secret-scrubber.d.ts.map +0 -1
  576. package/dist/security/secret-vault.d.ts.map +0 -1
  577. package/dist/security/trust-boundary.d.ts.map +0 -1
  578. package/dist/security/yolo-risk.d.ts.map +0 -1
  579. package/dist/session-registry-atomic-file.d.ts.map +0 -1
  580. package/dist/session-registry-types.d.ts.map +0 -1
  581. package/dist/session-registry.d.ts.map +0 -1
  582. package/dist/skills/foreign-sources.d.ts.map +0 -1
  583. package/dist/skills/frontmatter.d.ts.map +0 -1
  584. package/dist/skills/github-fetcher.d.ts.map +0 -1
  585. package/dist/skills/index.d.ts.map +0 -1
  586. package/dist/skills/index.js.map +0 -7
  587. package/dist/skills/limits.d.ts.map +0 -1
  588. package/dist/skills/manifest-store.d.ts.map +0 -1
  589. package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
  590. package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
  591. package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
  592. package/dist/skills/skill-generator.d.ts.map +0 -1
  593. package/dist/skills/skill-installer.d.ts.map +0 -1
  594. package/dist/storage/annotations-store.d.ts.map +0 -1
  595. package/dist/storage/attachment-store.d.ts.map +0 -1
  596. package/dist/storage/cloud-sync.d.ts.map +0 -1
  597. package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
  598. package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
  599. package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
  600. package/dist/storage/config-loader/defaults.d.ts.map +0 -1
  601. package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
  602. package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
  603. package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
  604. package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
  605. package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
  606. package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
  607. package/dist/storage/config-loader/types.d.ts.map +0 -1
  608. package/dist/storage/config-loader/validation.d.ts.map +0 -1
  609. package/dist/storage/config-loader.d.ts.map +0 -1
  610. package/dist/storage/config-migration.d.ts.map +0 -1
  611. package/dist/storage/config-store.d.ts.map +0 -1
  612. package/dist/storage/director-state.d.ts.map +0 -1
  613. package/dist/storage/file-session-writer.d.ts.map +0 -1
  614. package/dist/storage/goal-coordination.d.ts.map +0 -1
  615. package/dist/storage/goal-kanban.d.ts.map +0 -1
  616. package/dist/storage/goal-store.d.ts.map +0 -1
  617. package/dist/storage/index.d.ts.map +0 -1
  618. package/dist/storage/index.js.map +0 -7
  619. package/dist/storage/input-history-store.d.ts.map +0 -1
  620. package/dist/storage/memory-backend.d.ts.map +0 -1
  621. package/dist/storage/memory-consolidator.d.ts.map +0 -1
  622. package/dist/storage/memory-graph-backend.d.ts.map +0 -1
  623. package/dist/storage/plan-store.d.ts.map +0 -1
  624. package/dist/storage/plan-templates.d.ts.map +0 -1
  625. package/dist/storage/prompt-store.d.ts.map +0 -1
  626. package/dist/storage/prompt-usage-store.d.ts.map +0 -1
  627. package/dist/storage/provider-config-watcher.d.ts.map +0 -1
  628. package/dist/storage/queue-store.d.ts.map +0 -1
  629. package/dist/storage/recovery-lock.d.ts.map +0 -1
  630. package/dist/storage/replay-log-store.d.ts.map +0 -1
  631. package/dist/storage/session-analyzer.d.ts.map +0 -1
  632. package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
  633. package/dist/storage/session-event-bridge.d.ts.map +0 -1
  634. package/dist/storage/session-helpers.d.ts.map +0 -1
  635. package/dist/storage/session-id-resolver.d.ts.map +0 -1
  636. package/dist/storage/session-id.d.ts.map +0 -1
  637. package/dist/storage/session-read-scrubber.d.ts.map +0 -1
  638. package/dist/storage/session-reader.d.ts.map +0 -1
  639. package/dist/storage/session-recovery.d.ts.map +0 -1
  640. package/dist/storage/session-resume-validation.d.ts.map +0 -1
  641. package/dist/storage/session-rewind-apply.d.ts.map +0 -1
  642. package/dist/storage/session-rewinder.d.ts.map +0 -1
  643. package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
  644. package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
  645. package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
  646. package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
  647. package/dist/storage/session-store/events.d.ts.map +0 -1
  648. package/dist/storage/session-store/fork-session.d.ts.map +0 -1
  649. package/dist/storage/session-store/index-reader.d.ts.map +0 -1
  650. package/dist/storage/session-store/load-cache.d.ts.map +0 -1
  651. package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
  652. package/dist/storage/session-store/paths.d.ts.map +0 -1
  653. package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
  654. package/dist/storage/session-store/replay.d.ts.map +0 -1
  655. package/dist/storage/session-store/search-events.d.ts.map +0 -1
  656. package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
  657. package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
  658. package/dist/storage/session-store/summary-header.d.ts.map +0 -1
  659. package/dist/storage/session-store/types.d.ts.map +0 -1
  660. package/dist/storage/session-store.d.ts.map +0 -1
  661. package/dist/storage/session-summary.d.ts.map +0 -1
  662. package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
  663. package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
  664. package/dist/storage/session-writer-truncate.d.ts.map +0 -1
  665. package/dist/storage/storage-concurrency.d.ts.map +0 -1
  666. package/dist/storage/task-store.d.ts.map +0 -1
  667. package/dist/storage/todos-checkpoint.d.ts.map +0 -1
  668. package/dist/storage/tool-audit-log.d.ts.map +0 -1
  669. package/dist/tasking/index.d.ts.map +0 -1
  670. package/dist/tasking/index.js.map +0 -7
  671. package/dist/tasking/task-store.d.ts.map +0 -1
  672. package/dist/tasking/task-tracker.d.ts.map +0 -1
  673. package/dist/tools/council-tool.d.ts.map +0 -1
  674. package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
  675. package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
  676. package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
  677. package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
  678. package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
  679. package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
  680. package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
  681. package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
  682. package/dist/tools/index.d.ts.map +0 -1
  683. package/dist/tools/index.js.map +0 -7
  684. package/dist/tools/mcp-control.d.ts.map +0 -1
  685. package/dist/tools/mcp-use.d.ts.map +0 -1
  686. package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
  687. package/dist/tools/plugin-manager.d.ts.map +0 -1
  688. package/dist/types/agent-bridge.d.ts.map +0 -1
  689. package/dist/types/attachment.d.ts.map +0 -1
  690. package/dist/types/autonomy.d.ts.map +0 -1
  691. package/dist/types/blocks.d.ts.map +0 -1
  692. package/dist/types/compactor.d.ts.map +0 -1
  693. package/dist/types/config/autonomy.d.ts.map +0 -1
  694. package/dist/types/config/context.d.ts.map +0 -1
  695. package/dist/types/config/fleet-chat.d.ts.map +0 -1
  696. package/dist/types/config/mcp-features.d.ts.map +0 -1
  697. package/dist/types/config/providers.d.ts.map +0 -1
  698. package/dist/types/config/root.d.ts.map +0 -1
  699. package/dist/types/config/runtime.d.ts.map +0 -1
  700. package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
  701. package/dist/types/config/tools.d.ts.map +0 -1
  702. package/dist/types/config.d.ts.map +0 -1
  703. package/dist/types/context-evidence.d.ts.map +0 -1
  704. package/dist/types/context-window.d.ts.map +0 -1
  705. package/dist/types/council.d.ts.map +0 -1
  706. package/dist/types/default-config.d.ts.map +0 -1
  707. package/dist/types/design-kit.d.ts.map +0 -1
  708. package/dist/types/error-handler.d.ts.map +0 -1
  709. package/dist/types/errors.d.ts.map +0 -1
  710. package/dist/types/file-event-record.d.ts.map +0 -1
  711. package/dist/types/hooks.d.ts.map +0 -1
  712. package/dist/types/index.d.ts.map +0 -1
  713. package/dist/types/index.js.map +0 -7
  714. package/dist/types/input-reader.d.ts.map +0 -1
  715. package/dist/types/logger.d.ts.map +0 -1
  716. package/dist/types/memory.d.ts.map +0 -1
  717. package/dist/types/messages.d.ts.map +0 -1
  718. package/dist/types/mode-prompts.d.ts.map +0 -1
  719. package/dist/types/mode.d.ts.map +0 -1
  720. package/dist/types/models-registry.d.ts.map +0 -1
  721. package/dist/types/multi-agent.d.ts.map +0 -1
  722. package/dist/types/observability.d.ts.map +0 -1
  723. package/dist/types/one-shot-llm.d.ts.map +0 -1
  724. package/dist/types/path-resolver.d.ts.map +0 -1
  725. package/dist/types/permission.d.ts.map +0 -1
  726. package/dist/types/plugin.d.ts.map +0 -1
  727. package/dist/types/prompt-registry.d.ts.map +0 -1
  728. package/dist/types/prompt.d.ts.map +0 -1
  729. package/dist/types/provider-runner.d.ts.map +0 -1
  730. package/dist/types/provider.d.ts.map +0 -1
  731. package/dist/types/quota-regex.d.ts.map +0 -1
  732. package/dist/types/renderer.d.ts.map +0 -1
  733. package/dist/types/retry-policy.d.ts.map +0 -1
  734. package/dist/types/secret-scrubber.d.ts.map +0 -1
  735. package/dist/types/secret-vault.d.ts.map +0 -1
  736. package/dist/types/selector.d.ts.map +0 -1
  737. package/dist/types/session-markers.d.ts.map +0 -1
  738. package/dist/types/session-markers.js.map +0 -7
  739. package/dist/types/session-reader.d.ts.map +0 -1
  740. package/dist/types/session-rewinder.d.ts.map +0 -1
  741. package/dist/types/session.d.ts.map +0 -1
  742. package/dist/types/side-effect.d.ts.map +0 -1
  743. package/dist/types/skill.d.ts.map +0 -1
  744. package/dist/types/slash-command.d.ts.map +0 -1
  745. package/dist/types/spec.d.ts.map +0 -1
  746. package/dist/types/system-prompt-contributor.d.ts.map +0 -1
  747. package/dist/types/system-prompt.d.ts.map +0 -1
  748. package/dist/types/task-graph.d.ts.map +0 -1
  749. package/dist/types/token-counter.d.ts.map +0 -1
  750. package/dist/types/tool-executor.d.ts.map +0 -1
  751. package/dist/types/tool-markers.d.ts.map +0 -1
  752. package/dist/types/tool.d.ts.map +0 -1
  753. package/dist/types/utility-types.d.ts.map +0 -1
  754. package/dist/utils/assert-never.d.ts.map +0 -1
  755. package/dist/utils/atomic-write.d.ts.map +0 -1
  756. package/dist/utils/cache-key.d.ts.map +0 -1
  757. package/dist/utils/child-env.d.ts.map +0 -1
  758. package/dist/utils/color.d.ts.map +0 -1
  759. package/dist/utils/compaction-preview.d.ts.map +0 -1
  760. package/dist/utils/config-backup.d.ts.map +0 -1
  761. package/dist/utils/config-json.d.ts.map +0 -1
  762. package/dist/utils/connectivity.d.ts.map +0 -1
  763. package/dist/utils/context-breakdown.d.ts.map +0 -1
  764. package/dist/utils/context-evidence.d.ts.map +0 -1
  765. package/dist/utils/crash-shield.d.ts.map +0 -1
  766. package/dist/utils/deep-merge.d.ts.map +0 -1
  767. package/dist/utils/diff.d.ts.map +0 -1
  768. package/dist/utils/error.d.ts.map +0 -1
  769. package/dist/utils/error.js.map +0 -7
  770. package/dist/utils/expect-defined.d.ts.map +0 -1
  771. package/dist/utils/expect-defined.js.map +0 -7
  772. package/dist/utils/glob-expand.d.ts.map +0 -1
  773. package/dist/utils/glob-match.d.ts.map +0 -1
  774. package/dist/utils/heap-watchdog.d.ts.map +0 -1
  775. package/dist/utils/heap-watchdog.js.map +0 -7
  776. package/dist/utils/incoming-images.d.ts.map +0 -1
  777. package/dist/utils/index.d.ts.map +0 -1
  778. package/dist/utils/index.js.map +0 -7
  779. package/dist/utils/instruction-file.d.ts.map +0 -1
  780. package/dist/utils/ip-guard.d.ts.map +0 -1
  781. package/dist/utils/json-repair.d.ts.map +0 -1
  782. package/dist/utils/json-schema-validate.d.ts.map +0 -1
  783. package/dist/utils/lru-cache.d.ts.map +0 -1
  784. package/dist/utils/merge-custom-models.d.ts.map +0 -1
  785. package/dist/utils/merge-models-payload.d.ts.map +0 -1
  786. package/dist/utils/message-invariants.d.ts.map +0 -1
  787. package/dist/utils/newline-normalize.d.ts.map +0 -1
  788. package/dist/utils/perf-profile.d.ts.map +0 -1
  789. package/dist/utils/pid.d.ts.map +0 -1
  790. package/dist/utils/project-identity.d.ts.map +0 -1
  791. package/dist/utils/project-watch.d.ts.map +0 -1
  792. package/dist/utils/regex-guard.d.ts.map +0 -1
  793. package/dist/utils/safe-json.d.ts.map +0 -1
  794. package/dist/utils/sage-output-block.d.ts.map +0 -1
  795. package/dist/utils/session-scoped-path.d.ts.map +0 -1
  796. package/dist/utils/sleep.d.ts.map +0 -1
  797. package/dist/utils/slug.d.ts.map +0 -1
  798. package/dist/utils/socket-path.d.ts.map +0 -1
  799. package/dist/utils/sqlite-warning.d.ts.map +0 -1
  800. package/dist/utils/string.d.ts.map +0 -1
  801. package/dist/utils/task-format.d.ts.map +0 -1
  802. package/dist/utils/term.d.ts.map +0 -1
  803. package/dist/utils/todos-format.d.ts.map +0 -1
  804. package/dist/utils/token-estimate.d.ts.map +0 -1
  805. package/dist/utils/tool-description-mode.d.ts.map +0 -1
  806. package/dist/utils/tool-output-serializer.d.ts.map +0 -1
  807. package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
  808. package/dist/utils/tool-subject.d.ts.map +0 -1
  809. package/dist/utils/tool-wire-compact.d.ts.map +0 -1
  810. package/dist/utils/tree-kill.d.ts.map +0 -1
  811. package/dist/utils/tree-kill.js.map +0 -7
  812. package/dist/utils/ulid.d.ts.map +0 -1
  813. package/dist/utils/walk-ignore.d.ts.map +0 -1
  814. package/dist/utils/wstack-paths.d.ts.map +0 -1
  815. package/dist/worktree/index.d.ts.map +0 -1
  816. package/dist/worktree/index.js.map +0 -7
  817. package/dist/worktree/worktree-git.d.ts.map +0 -1
  818. package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
  819. package/dist/worktree/worktree-manager.d.ts.map +0 -1
  820. package/dist/worktree/worktree-types.d.ts.map +0 -1
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/utils/pid.ts", "../../src/session-registry-atomic-file.ts", "../../src/session-registry.ts", "../../src/infrastructure/logger.ts", "../../src/utils/term.ts", "../../src/utils/color.ts", "../../src/infrastructure/path-resolver.ts", "../../src/infrastructure/token-counter.ts", "../../src/infrastructure/provider-cache-ledger.ts", "../../src/infrastructure/mcp-servers.ts", "../../src/utils/expect-defined.ts", "../../src/utils/message-invariants.ts", "../../src/utils/tool-wire-compact.ts", "../../src/utils/token-estimate.ts", "../../src/infrastructure/context-manager.ts", "../../src/boot.ts", "../../src/security/secret-vault.ts", "../../src/utils/error.ts", "../../src/types/errors.ts", "../../src/types/secret-vault.ts", "../../src/utils/atomic-write.ts", "../../src/security/config-secrets.ts", "../../src/utils/deep-merge.ts", "../../src/storage/config-loader.ts", "../../src/types/context-window.ts", "../../src/utils/config-backup.ts", "../../src/utils/safe-json.ts", "../../src/utils/wstack-paths.ts", "../../src/storage/config-loader/bootstrap.ts", "../../src/types/config/runtime.ts", "../../src/types/default-config.ts", "../../src/storage/config-loader/defaults.ts", "../../src/storage/config-loader/default-repair.ts", "../../src/storage/config-loader/diagnostics.ts", "../../src/storage/config-loader/env-overrides.ts", "../../src/storage/config-loader/in-project-policy.ts", "../../src/storage/config-loader/inline-provider-models.ts", "../../src/storage/config-loader/legacy-sage-migration.ts", "../../src/storage/config-loader/path-identity.ts", "../../src/utils/project-identity.ts", "../../src/utils/ulid.ts"],
4
- "sourcesContent": ["/**\n * Process-liveness probing.\n *\n * This predicate was copy-pasted across six subsystems (session registry, HQ\n * auth store, director state, fleet notifier, recovery lock, mailbox lock)\n * with four different semantics. The dangerous variant was `catch { return\n * false }`: on POSIX, `process.kill(pid, 0)` throws EPERM when the process\n * EXISTS but belongs to another user (or runs elevated), so a bare catch\n * reports a live process as dead. Callers then \"reclaim\" resources that are\n * still owned \u2014 the director-state lock would be stolen from a running\n * director, and live sessions were pruned from the registry.\n *\n * Everything that asks \"is this pid alive?\" must go through here.\n */\n\n/**\n * True iff `pid` names a live process.\n *\n * POSIX: `process.kill(pid, 0)` succeeds for our own processes, throws EPERM\n * for processes we may not signal (alive, just not ours), and throws ESRCH\n * once the pid is gone.\n * Windows (Node 22+): the same call succeeds when the process exists and\n * throws otherwise.\n *\n * Deliberately fails CLOSED on an unrecognized error code \u2014 reporting \"dead\"\n * for an unknown failure is the conservative answer for the pruning callers,\n * which is why lock owners that must not be displaced (see\n * `single-instance-mailbox`) layer a second, platform-specific check on top.\n */\nexport function isPidAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n /* v8 ignore next -- platform/permission-specific: EPERM means alive but owned by another user */\n if (code === 'EPERM') return true;\n return false;\n }\n}\n", "/**\n * Crash- and Windows-safe file primitives behind {@link SessionRegistry}.\n *\n * The registry is one JSON file written by every WrongStack process, so its\n * write path carries all the platform scar tissue: an advisory lock file that a\n * crashed owner can leave behind, a fsync-before-rename that a system crash\n * would otherwise turn into a zero-filled registry, a copyFile fallback for\n * Windows MoveFile sharing violations, and temp-file litter from any of the\n * above. All of that lives here; `session-registry.ts` keeps the state machine.\n *\n * Every function is keyed on the registry file path rather than the registry\n * instance \u2014 none of them need registry state.\n *\n * @module session-registry-atomic-file\n */\nimport { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { SessionRegistryEntry } from './session-registry-types.js';\nimport { isPidAlive } from './utils/pid.js';\n\n// A held lock is released within milliseconds; anything older is a crashed\n// owner's leftover and is safe to break so writes never wedge permanently.\nconst STALE_LOCK_MS = 10_000;\n/** Also the scan interval for {@link pruneStaleTempFiles} \u2014 see its caller. */\nexport const STALE_TMP_MS = 60_000;\nconst MAX_STALE_TMP_FILES = 20;\n\n/**\n * Break a contended lock if it is stale: the recorded owner pid is no longer\n * alive, or the lock is older than {@link STALE_LOCK_MS}. Returns true when the\n * lock was removed (caller should retry acquisition). Best-effort and\n * race-tolerant \u2014 a fresh lock (age ~0, live owner) is never broken, so the\n * common concurrent case self-heals on the next heartbeat.\n */\nexport async function breakStaleLock(lockPath: string): Promise<boolean> {\n try {\n const [stat, content] = await Promise.all([\n fs.stat(lockPath),\n /* v8 ignore start -- best-effort lock-content read; .catch only fires if the lock vanished */\n fs.readFile(lockPath, 'utf8').catch(() => ''),\n /* v8 ignore stop */\n ]);\n const ageMs = Date.now() - stat.mtimeMs;\n const ownerPid = Number.parseInt(content.trim(), 10);\n const ownerDead =\n Number.isInteger(ownerPid) &&\n ownerPid > 0 &&\n ownerPid !== process.pid &&\n !isPidAlive(ownerPid);\n if (ownerDead || ageMs > STALE_LOCK_MS) {\n /* v8 ignore start -- best-effort stale-lock removal; .catch only fires if the lock vanished */\n await fs.unlink(lockPath).catch(() => undefined);\n /* v8 ignore stop */\n return true;\n }\n return false;\n } catch {\n // stat failed \u2192 the lock vanished underneath us; let the caller retry.\n /* v8 ignore next -- defensive: a vanished lock between stat and read is fine */\n return true;\n }\n}\n\nexport async function writeAtomicFile(\n filePath: string,\n registry: Record<string, SessionRegistryEntry>,\n): Promise<void> {\n const tmp = path.join(\n path.dirname(filePath),\n `.${path.basename(filePath)}.${randomUUID().slice(0, 8)}.tmp`,\n );\n let tmpPersisted = false;\n try {\n // Write + fsync BEFORE the rename: without the fsync, a system crash\n // can journal the rename metadata while the data blocks were never\n // flushed, leaving a zero-filled (all-NUL) registry file on reboot.\n const handle = await fs.open(tmp, 'w');\n try {\n await handle.writeFile(JSON.stringify(registry, null, 2), 'utf8');\n await handle.sync().catch(() => undefined);\n } finally {\n await handle.close();\n }\n tmpPersisted = true;\n // Cross-platform atomic publish:\n // 1. POSIX: rename(2) is atomic; if the destination exists it is\n // replaced in one step.\n // 2. Windows (Node 22): fs.rename uses MoveFile, which fails with\n // EPERM/EBUSY when the destination is briefly held by an antivirus\n // scan, a peer process reading the file, or an indexer.\n // fs.copyFile uses CopyFileEx/CopyFile2 with REPLACE_EXISTING,\n // which DOES overwrite an existing destination and tolerates short\n // sharing-violation windows better than MoveFile. Doing copyFile\n // first, then fs.unlink(tmp), gives us \"best of both worlds\":\n // the published bytes are the freshly written + fsynced ones,\n // and the destination is replaced even when MoveFile refuses.\n // The publish is no longer strictly atomic across the OS boundary,\n // but the only readers (cross-process observers) re-read after a\n // brief settle, and we still hold the cross-process advisory lock\n // so no concurrent writer can interleave.\n try {\n await fs.rename(tmp, filePath);\n tmpPersisted = false;\n } catch (renameErr) {\n const code = (renameErr as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'EPERM' || code === 'EBUSY' || code === 'EACCES') {\n // Copy bytes to destination (REPLACE_EXISTING is the default for\n // fs.copyFile when COPYFILE_FAIL_IF_EXISTS is not set), fsync the\n // destination so readers don't see zero-filled data on a crash,\n // then drop the temp file.\n await fs.copyFile(tmp, filePath);\n try {\n const destHandle = await fs.open(filePath, 'r+');\n try {\n await destHandle.sync().catch(() => undefined);\n } finally {\n await destHandle.close();\n }\n } catch {\n // Best-effort fsync of the destination; failure is non-fatal\n // because we already wrote the bytes and the OS will flush.\n }\n await fs.unlink(tmp).catch(() => undefined);\n tmpPersisted = false;\n } else {\n throw renameErr;\n }\n }\n } catch (err) {\n /* v8 ignore start -- rename-failure cleanup: best-effort tmp unlink + rethrow (atomicUpdate swallows it) */\n if (tmpPersisted) await fs.unlink(tmp).catch(() => undefined);\n throw err;\n /* v8 ignore stop */\n }\n}\n\nexport async function pruneStaleTempFiles(filePath: string): Promise<void> {\n try {\n const dir = path.dirname(filePath);\n const base = path.basename(filePath);\n const now = Date.now();\n const stale: Array<{ name: string; mtimeMs: number }> = [];\n\n for (const name of await fs.readdir(dir)) {\n const isTemp =\n (name.startsWith(`${base}.`) || name.startsWith(`.${base}.`)) && name.endsWith('.tmp');\n if (!isTemp) continue;\n /* v8 ignore start -- best-effort temp stat; .catch(null)+continue only fire when the temp vanished */\n const stat = await fs.stat(path.join(dir, name)).catch(() => null);\n if (!stat) continue;\n /* v8 ignore stop */\n if (now - stat.mtimeMs > STALE_TMP_MS) stale.push({ name, mtimeMs: stat.mtimeMs });\n }\n\n stale.sort((a, b) => b.mtimeMs - a.mtimeMs);\n await Promise.all(\n stale.slice(MAX_STALE_TMP_FILES).map(async ({ name }) => {\n /* v8 ignore start -- best-effort temp removal; .catch only fires if the temp vanished */\n await fs.unlink(path.join(dir, name)).catch(() => undefined);\n /* v8 ignore stop */\n }),\n );\n } catch {\n // best-effort cleanup must not block registry heartbeats\n }\n}\n", "/**\n * SessionRegistry \u2014 cross-process session and agent tracker.\n *\n * Each WrongStack process registers its session on start and updates its\n * status periodically. The registry is a single JSON file at\n * `~/.wrongstack/session-registry.json`. Entries are keyed by session ID.\n *\n * Because multiple processes may write concurrently, every write is an\n * atomic read-modify-write protected by a per-file advisory lock (flock on\n * Unix, exclusive open on Windows). Stale entries (process no longer alive)\n * are pruned on every read.\n *\n * @module session-registry\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport {\n breakStaleLock,\n pruneStaleTempFiles,\n STALE_TMP_MS,\n writeAtomicFile,\n} from './session-registry-atomic-file.js';\nimport type {\n AgentEntry,\n SessionLiveStatus,\n SessionRegistryEntry,\n} from './session-registry-types.js';\nimport { isPidAlive } from './utils/pid.js';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// Re-exported so `session-registry.js` stays the single import site for these\n// record shapes across the workspace; the declarations live in their own module.\nexport type {\n AgentActivityTotals,\n AgentEntry,\n AgentLiveStatus,\n AgentRecentMail,\n AgentRecentTool,\n AgentTodoItem,\n SessionLiveStatus,\n SessionRegistryEntry,\n} from './session-registry-types.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst REGISTRY_FILE = 'session-registry.json';\nconst HEARTBEAT_INTERVAL_MS = 5_000;\nconst STALE_TIMEOUT_MS = 30_000; // entry considered stale after 30s without heartbeat\n// A live session heartbeats every HEARTBEAT_INTERVAL_MS, so two missed beats\n// already mean something is wrong \u2014 cheap enough to confirm with a PID probe\n// from then on, instead of waiting out the full stale window.\nconst PID_CHECK_AFTER_MS = HEARTBEAT_INTERVAL_MS * 2;\n// A session that announced `closing` (heartbeat stopped) is dropped this long\n// after its last heartbeat, so the fleet view doesn't keep a dead client around.\nconst CLOSING_GRACE_MS = 15_000;\n// A live PID with a missed heartbeat is marked lost but retained. Removing it\n// would let another process open the same journal while the original process\n// can still write. Operators must terminate the live owner before takeover.\n/** Subagents without any activity this long are not live, even if the owning session still heartbeats. */\nconst AGENT_STALE_MS = 5 * 60_000;\n// Ownership claims are rare and must survive ordinary Windows fsync/antivirus\n// latency plus a burst of simultaneous heartbeats from several clients.\n// Telemetry writes remain cheap/best-effort and keep the shorter budget.\nconst OWNERSHIP_LOCK_WAIT_MS = 8_000;\nconst OPTIONAL_LOCK_WAIT_MS = 750;\nconst LOCK_RETRY_MAX_MS = 100;\n// Agent snapshots arrive on every tool boundary \u2014 a busy agent can cross\n// several boundaries per second, and each write is a full temp+fsync+rename\n// under the advisory lock. Coalesce to at most one write per window; the\n// first call in a quiet window still writes immediately so status stays live.\nconst AGENTS_WRITE_THROTTLE_MS = 300;\n\n/** Conflict errors are the one registry-write failure callers must observe. */\nclass SessionOwnershipConflictError extends Error {}\nclass SessionRegistryWriteError extends Error {}\n// Directory enumeration and per-file stats are substantially more expensive\n// than the tiny registry write itself on networked/antivirus-scanned homes.\n// Temp files cannot become stale faster than STALE_TMP_MS, so scanning once in\n// that window is sufficient even though heartbeats write every five seconds.\nconst TEMP_PRUNE_INTERVAL_MS = STALE_TMP_MS;\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Liveness probe for registry entries. Delegates to the shared helper so this\n * module can't drift back to the bare-catch variant, which reported a live\n * but non-signalable process (EPERM) as dead and pruned its session.\n */\nconst pidAlive = isPidAlive;\n\nfunction sameOwner(\n entry: Pick<SessionRegistryEntry, 'pid' | 'startedAt'>,\n owner: Pick<SessionRegistryEntry, 'pid' | 'startedAt'>,\n): boolean {\n return entry.pid === owner.pid && entry.startedAt === owner.startedAt;\n}\n\n/**\n * Parse registry file contents, tolerating corruption. A system crash can\n * leave the file zero-filled (NTFS journals the rename metadata but the data\n * blocks were never flushed \u2014 the file is its full size of NUL bytes), or a\n * torn write can leave invalid JSON. Treat anything unparsable \u2014 or parsable\n * but not a plain object \u2014 as an empty registry so the next write heals the\n * file instead of wedging every future write forever.\n */\nfunction parseRegistry(raw: string): Record<string, SessionRegistryEntry> {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, SessionRegistryEntry>;\n }\n } catch {\n /* corrupt file \u2014 fall through to empty */\n }\n return {};\n}\n\n/** Derive the session-level status from the agent collective. */\nfunction deriveSessionStatus(agents: AgentEntry[]): SessionLiveStatus {\n const hasRunning = agents.some((a) => a.status === 'running' || a.status === 'streaming');\n const hasWaiting = agents.some((a) => a.status === 'waiting_user');\n const hasError = agents.some((a) => a.status === 'error');\n return hasRunning || hasWaiting || hasError ? 'active' : 'idle';\n}\n\n// \u2500\u2500 Registry class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class SessionRegistry {\n private readonly filePath: string;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private currentSessionId: string | null = null;\n private lastTempPruneAt = 0;\n private tempPrunePromise: Promise<void> | null = null;\n /** Latest agent snapshot not yet written; superseded by newer calls. */\n private pendingAgents: AgentEntry[] | null = null;\n /** Shared settle promise for all updateAgents calls coalesced into one trailing write. */\n private pendingAgentsFlush: Promise<void> | null = null;\n private pendingAgentsResolve: (() => void) | null = null;\n private agentsFlushTimer: ReturnType<typeof setTimeout> | null = null;\n private lastAgentsWriteAt = 0;\n /**\n * Last full entry this process registered. Kept so the heartbeat can\n * re-create our entry if it ever goes missing because the file was reset or\n * a reader pruned a stale snapshot.\n */\n private lastEntry: SessionRegistryEntry | null = null;\n private readonly ownershipLockWaitMs: number;\n\n constructor(globalRoot: string, options: { ownershipLockWaitMs?: number } = {}) {\n this.filePath = path.join(globalRoot, REGISTRY_FILE);\n this.ownershipLockWaitMs = Math.max(0, options.ownershipLockWaitMs ?? OWNERSHIP_LOCK_WAIT_MS);\n }\n\n // \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Register the current session. Call once on session start.\n * Starts the heartbeat timer.\n */\n async register(\n entry: Omit<SessionRegistryEntry, 'status' | 'lastHeartbeatAt' | 'agentCount' | 'agents'> & {\n agents?: AgentEntry[] | undefined;\n },\n ): Promise<void> {\n // Safe to call again on a project switch: the WebUI re-roots in place and\n // creates a fresh session id pointing at the new project. Clear the prior\n // heartbeat timer (otherwise each switch leaks a timer that keeps writing).\n // A process owns exactly one entry, so the same-pid dedup below drops our\n // own previous entry \u2014 the registry never carries a phantom session still\n // pointing at the old project's root/workingDir.\n const full: SessionRegistryEntry = {\n ...entry,\n status: 'active',\n lastHeartbeatAt: new Date().toISOString(),\n agentCount: entry.agents?.length ?? 0,\n agents: entry.agents ?? [],\n };\n // Fast pre-check for the common conflict path. The same check is repeated\n // under atomicUpdate's cross-process lock below to close the resume race.\n const existingRegistry = await this.readAndPrune();\n const currentOwner = existingRegistry[entry.sessionId];\n if (currentOwner && currentOwner.pid !== entry.pid && pidAlive(currentOwner.pid)) {\n throw new SessionOwnershipConflictError(\n `Session ${entry.sessionId} is already open in another running wstack (pid ${currentOwner.pid}).`,\n );\n }\n\n await this.atomicUpdate((registry) => {\n // Prune dead entries that haven't heartbeated recently.\n // A just-created entry has no heartbeat yet \u2014 don't prune it.\n const now = Date.now();\n for (const [id, existing] of Object.entries(registry)) {\n if (existing.pid === entry.pid) {\n // Our own process owns exactly one entry. When re-registering under\n // a new session id (project switch re-roots in place), drop the\n // stale same-pid entry so it doesn't linger pointing at the old\n // project's root/workingDir.\n if (id !== entry.sessionId) delete registry[id];\n continue;\n }\n const heartbeatAge = now - new Date(existing.lastHeartbeatAt).getTime();\n if (heartbeatAge > PID_CHECK_AFTER_MS && !pidAlive(existing.pid)) {\n delete registry[id];\n }\n }\n const lockedOwner = registry[entry.sessionId];\n if (lockedOwner && lockedOwner.pid !== entry.pid && pidAlive(lockedOwner.pid)) {\n throw new SessionOwnershipConflictError(\n `Session ${entry.sessionId} is already open in another running wstack (pid ${lockedOwner.pid}).`,\n );\n }\n registry[entry.sessionId] = full;\n }, true);\n // Only publish local ownership after the cross-process claim succeeds.\n // A failed duplicate-session claim must not make heartbeats overwrite the\n // real owner's registry entry.\n this.cancelPendingAgentsFlush();\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n this.lastAgentsWriteAt = 0;\n this.currentSessionId = entry.sessionId;\n this.lastEntry = full;\n\n // Start heartbeat\n /* v8 ignore start -- 5s heartbeat timer fires only in a live process, not under test */\n this.heartbeatTimer = setInterval(() => {\n void this.heartbeat();\n }, HEARTBEAT_INTERVAL_MS);\n /* v8 ignore stop */\n if (this.heartbeatTimer.unref) this.heartbeatTimer.unref();\n }\n\n /**\n * Update agent status for the current session. Call on every\n * significant status change (agent start, tool start, user wait, error).\n *\n * Writes are coalesced: the first call in a quiet window writes\n * immediately; calls arriving within {@link AGENTS_WRITE_THROTTLE_MS} of\n * the last write collapse into one trailing write carrying the newest\n * snapshot. The in-memory cache ({@link lastEntry}) is always updated\n * synchronously, so heartbeat re-inserts never carry stale agents.\n */\n async updateAgents(agents: AgentEntry[]): Promise<void> {\n if (!this.currentSessionId) return;\n this.pendingAgents = agents;\n\n // Keep the cached entry current so a heartbeat re-insert carries live agents.\n if (this.lastEntry) {\n this.lastEntry.agents = agents;\n this.lastEntry.agentCount = agents.length;\n this.lastEntry.status = deriveSessionStatus(agents);\n this.lastEntry.lastHeartbeatAt = new Date().toISOString();\n }\n\n const sinceLastWrite = Date.now() - this.lastAgentsWriteAt;\n if (!this.agentsFlushTimer && sinceLastWrite >= AGENTS_WRITE_THROTTLE_MS) {\n await this.writeAgentsSnapshot();\n return;\n }\n\n if (!this.agentsFlushTimer) {\n const delay = Math.max(0, AGENTS_WRITE_THROTTLE_MS - sinceLastWrite);\n this.pendingAgentsFlush = new Promise<void>((resolve, reject) => {\n this.pendingAgentsResolve = resolve;\n const timer = setTimeout(() => {\n this.agentsFlushTimer = null;\n this.pendingAgentsFlush = null;\n this.pendingAgentsResolve = null;\n this.writeAgentsSnapshot().then(resolve, reject);\n }, delay);\n if (typeof timer.unref === 'function') timer.unref();\n this.agentsFlushTimer = timer;\n });\n }\n await this.pendingAgentsFlush;\n }\n\n /** Write the newest pending agent snapshot to the registry file. */\n private async writeAgentsSnapshot(): Promise<void> {\n const agents = this.pendingAgents;\n const sessionId = this.currentSessionId;\n const owner = this.lastEntry;\n if (!agents || !sessionId || !owner || owner.sessionId !== sessionId) return;\n this.pendingAgents = null;\n this.lastAgentsWriteAt = Date.now();\n const status = deriveSessionStatus(agents);\n const nowIso = new Date().toISOString();\n\n await this.atomicUpdate((registry) => {\n if (this.currentSessionId !== sessionId || this.lastEntry !== owner) return;\n let entry = registry[sessionId];\n if (entry && !sameOwner(entry, owner)) return;\n if (!entry) {\n // Our entry vanished (dropped write / reset / pruned) \u2014 re-create it.\n entry = { ...owner };\n registry[sessionId] = entry;\n }\n entry.agents = agents;\n entry.agentCount = agents.length;\n entry.status = status;\n entry.lastHeartbeatAt = nowIso;\n });\n }\n\n /**\n * Cancel a scheduled trailing agents write (releasing any waiters). Used on\n * shutdown so a late timer can't resurrect an entry that markClosing() /\n * unregister() is about to finalize. Returns the snapshot that was pending.\n */\n private cancelPendingAgentsFlush(): AgentEntry[] | null {\n if (this.agentsFlushTimer) {\n clearTimeout(this.agentsFlushTimer);\n this.agentsFlushTimer = null;\n }\n this.pendingAgentsResolve?.();\n this.pendingAgentsResolve = null;\n this.pendingAgentsFlush = null;\n const pending = this.pendingAgents;\n this.pendingAgents = null;\n return pending;\n }\n\n /**\n * Mark the session as closing. Called during shutdown.\n * Stops the heartbeat timer.\n */\n async markClosing(): Promise<void> {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n if (!this.currentSessionId) return;\n const sessionId = this.currentSessionId;\n const owner = this.lastEntry;\n if (!owner) return;\n // Fold any coalesced-but-unwritten agent snapshot into this final write so\n // the trailing timer can't fire later and flip us back to active.\n const pendingAgents = this.cancelPendingAgentsFlush();\n await this.atomicUpdate((registry) => {\n const entry = registry[sessionId];\n if (!entry || !sameOwner(entry, owner)) return;\n if (pendingAgents) {\n entry.agents = pendingAgents;\n entry.agentCount = pendingAgents.length;\n }\n entry.status = 'closing';\n entry.lastHeartbeatAt = new Date().toISOString();\n });\n }\n\n /**\n * Remove the current session from the registry. Call on clean exit.\n */\n async unregister(): Promise<void> {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n if (!this.currentSessionId) return;\n // Drop any coalesced agent snapshot \u2014 the entry is being deleted, and a\n // late trailing write would resurrect it from lastEntry.\n this.cancelPendingAgentsFlush();\n const sid = this.currentSessionId;\n const owner = this.lastEntry;\n this.currentSessionId = null;\n this.lastEntry = null;\n await this.atomicUpdate((registry) => {\n const entry = registry[sid];\n if (owner && entry && sameOwner(entry, owner)) {\n delete registry[sid];\n }\n });\n }\n\n /**\n * List all non-stale sessions. Prunes stale entries automatically.\n */\n async list(): Promise<SessionRegistryEntry[]> {\n const registry = await this.readAndPrune();\n return Object.values(registry);\n }\n\n /**\n * Get a single session entry by ID. Returns undefined if not found or stale.\n */\n async get(sessionId: string): Promise<SessionRegistryEntry | undefined> {\n const registry = await this.readAndPrune();\n return registry[sessionId];\n }\n\n /**\n * List all sessions for a specific project (by slug).\n */\n async listByProject(projectSlug: string): Promise<SessionRegistryEntry[]> {\n const all = await this.list();\n return all.filter((e) => e.projectSlug === projectSlug);\n }\n\n /**\n * Return the registry file path. Useful for WebUI to watch/read.\n */\n get registryPath(): string {\n return this.filePath;\n }\n\n // \u2500\u2500 Internal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async heartbeat(): Promise<void> {\n if (!this.currentSessionId) return;\n try {\n const sessionId = this.currentSessionId;\n const owner = this.lastEntry;\n if (!owner || owner.sessionId !== sessionId) return;\n const nowIso = new Date().toISOString();\n await this.atomicUpdate((registry) => {\n if (this.currentSessionId !== sessionId || this.lastEntry !== owner) return;\n const entry = registry[sessionId];\n if (entry) {\n if (!sameOwner(entry, owner)) return;\n entry.lastHeartbeatAt = nowIso;\n // Status bound: if closing, don't revert\n if (entry.status !== 'closing') {\n const hasRunning = (entry.agents ?? []).some(\n (a) => a.status === 'running' || a.status === 'streaming',\n );\n entry.status = hasRunning ? 'active' : 'idle';\n }\n return;\n }\n // Our entry was externally removed/reset. Re-create it only while this\n // exact ownership generation is still current; a heartbeat queued\n // before a session switch must never resurrect the previous session.\n registry[sessionId] = { ...owner, lastHeartbeatAt: nowIso };\n });\n } catch {\n // Best-effort heartbeat \u2014 never throw\n }\n }\n\n private async readAndPrune(): Promise<Record<string, SessionRegistryEntry>> {\n try {\n const raw = await fs.readFile(this.filePath, 'utf8');\n const registry = parseRegistry(raw);\n const observed = new Map(\n Object.entries(registry).map(([id, entry]) => [\n id,\n { pid: entry.pid, lastHeartbeatAt: entry.lastHeartbeatAt },\n ]),\n );\n const now = Date.now();\n let pruned = false;\n\n for (const [id, entry] of Object.entries(registry)) {\n const heartbeatAt = Date.parse(entry.lastHeartbeatAt);\n if (!Number.isFinite(heartbeatAt)) {\n delete registry[id];\n pruned = true;\n continue;\n }\n const heartbeatAge = now - heartbeatAt;\n\n // A live session heartbeat does not prove every cached subagent still\n // exists. Keep the leader as the surface itself, but reap workers whose\n // activity stopped several minutes ago (the common shadow-agent ghost).\n const agents = Array.isArray(entry.agents) ? entry.agents : [];\n const liveAgents = agents.filter((agent) => {\n if (agent.id === 'leader') return true;\n const lastActivityAt = Date.parse(agent.lastActivityAt);\n return Number.isFinite(lastActivityAt) && now - lastActivityAt <= AGENT_STALE_MS;\n });\n if (liveAgents.length !== agents.length || entry.agentCount !== liveAgents.length) {\n entry.agents = liveAgents;\n entry.agentCount = liveAgents.length;\n pruned = true;\n }\n\n // A cleanly-closing session is removable after the grace only when its\n // process is actually gone. A hung cleanup can still hold the writer.\n if (entry.status === 'closing' && heartbeatAge > CLOSING_GRACE_MS) {\n if (!pidAlive(entry.pid)) {\n delete registry[id];\n pruned = true;\n }\n continue;\n }\n // A dead PID is definitive, and this probe used to sit behind the full\n // STALE_TIMEOUT_MS window. That meant a session killed without\n // `markClosing` (SIGKILL, taskkill /F, the rapid-Ctrl+C\n // `process.exit(130)` path) kept its last written status \u2014 for an idle\n // TUI, literally `'idle'` \u2014 so every reader showed a live-looking\n // session on a dead pid for up to 30s. Probing after two missed\n // heartbeats cuts that to ~10s while still leaving healthy entries\n // (which heartbeat every 5s) untouched on the hot read path.\n if (heartbeatAge > PID_CHECK_AFTER_MS && !pidAlive(entry.pid)) {\n delete registry[id];\n pruned = true;\n continue;\n }\n if (heartbeatAge <= STALE_TIMEOUT_MS) continue;\n\n // A live PID remains the owner even when its heartbeat is lost. It may\n // be wedged, but it can still hold and write the session journal.\n if (entry.status !== 'lost') {\n entry.status = 'lost';\n pruned = true;\n }\n }\n\n if (pruned) {\n // Merge the pruned snapshot under the same cross-process lock used by\n // registrations. Never rename an old full-file snapshot over a session\n // that another process registered after our read.\n await this.atomicUpdate((current) => {\n for (const [id, version] of observed) {\n const latest = current[id];\n if (\n !latest ||\n latest.pid !== version.pid ||\n latest.lastHeartbeatAt !== version.lastHeartbeatAt\n ) {\n continue;\n }\n const next = registry[id];\n if (next) current[id] = next;\n else delete current[id];\n }\n });\n /* v8 ignore stop */\n }\n\n return registry;\n } catch {\n return {};\n }\n }\n\n private async atomicUpdate(\n fn: (registry: Record<string, SessionRegistryEntry>) => void,\n required = false,\n ): Promise<void> {\n const lockPath = `${this.filePath}.lock`;\n const waitBudgetMs = required ? this.ownershipLockWaitMs : OPTIONAL_LOCK_WAIT_MS;\n const deadline = Date.now() + waitBudgetMs;\n let attempt = 0;\n\n try {\n await fs.mkdir(path.dirname(this.filePath), { recursive: true });\n // Directory scans are independent cleanup work and can be slow on\n // Windows/antivirus-scanned homes. Never hold the registry mutex while\n // pruning old temp files.\n await this.maybePruneStaleTempFiles();\n } catch (err) {\n if (required) {\n throw new SessionRegistryWriteError(\n `Session registry ownership update failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n return;\n }\n\n while (true) {\n try {\n // Acquire exclusive lock via O_CREAT | O_EXCL\n let lockHandle = await fs.open(lockPath, 'wx').catch(() => null);\n if (!lockHandle) {\n // Lock contended. A crashed process can leave its lock file behind\n // forever (the `finally` unlink never ran), which would wedge EVERY\n // future write \u2014 the registry silently stops updating. Break the lock\n // when its owner pid is dead or it has been held implausibly long\n // (legit holds are sub-millisecond), then retry the open once.\n if (await breakStaleLock(lockPath)) {\n /* v8 ignore start -- retry-open after breaking a stale lock; .catch only fires on contention */\n lockHandle = await fs.open(lockPath, 'wx').catch(() => null);\n /* v8 ignore stop */\n }\n if (!lockHandle) {\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) break;\n const retryDelayMs = Math.min(LOCK_RETRY_MAX_MS, 20 * (attempt + 1));\n await new Promise((resolve) =>\n setTimeout(resolve, Math.min(retryDelayMs, remainingMs)),\n );\n attempt += 1;\n continue;\n }\n }\n\n try {\n // Stamp the owner pid so other processes can detect a stale lock.\n /* v8 ignore start -- best-effort owner-pid stamp; .catch only fires on a write failure */\n await lockHandle.writeFile(String(process.pid)).catch(() => undefined);\n /* v8 ignore stop */\n const raw = await fs.readFile(this.filePath, 'utf8').catch(() => '{}');\n // Corruption-tolerant: a crash-zeroed or torn file must not abort\n // the write \u2014 starting from {} rewrites a healthy registry.\n const registry = parseRegistry(raw);\n fn(registry);\n // Windows writeAtomicFile can fail with EPERM/EBUSY/EACCES when the\n // destination file is momentarily held by an antivirus scan, a\n // coexisting watcher, or a peer that just opened the file for read.\n // The lock we hold here proves WE have exclusive write intent; the\n // brief contention on the data file is best handled by a tiny\n // bounded retry, NOT by escalating into a SessionRegistryWriteError\n // that aborts every ownership claim in the process.\n await this.writeAtomicWithRetry(registry);\n return; // success\n } finally {\n await lockHandle.close();\n /* v8 ignore start -- best-effort lock cleanup in finally; .catch only fires if the lock vanished */\n await fs.unlink(lockPath).catch(() => undefined);\n /* v8 ignore stop */\n }\n } catch (err) {\n if (err instanceof SessionOwnershipConflictError) throw err;\n if (required) {\n throw new SessionRegistryWriteError(\n `Session registry ownership update failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n // Telemetry/cleanup writes remain best-effort.\n return;\n }\n }\n if (required) {\n throw new SessionRegistryWriteError(\n `Session registry ownership update failed: lock remained busy for ${waitBudgetMs}ms at ${lockPath}`,\n );\n }\n // All retries exhausted \u2014 non-ownership telemetry update dropped.\n }\n\n private async writeAtomicLocked(registry: Record<string, SessionRegistryEntry>): Promise<void> {\n await this.writeAtomicFile(registry);\n }\n\n /**\n * Windows-safe wrapper around {@link writeAtomicLocked}. Retries on the small\n * set of transient OS errors that occur when an antivirus scan, an indexing\n * service, or a peer process opens the destination file for read at the\n * same instant rename/copy tries to land. Retries are short and bounded so\n * the heartbeat never wedges; the per-call cap is well below the 5 s\n * heartbeat interval.\n *\n * Errors that look persistent (ENOENT, JSON.parse-style, anything other than\n * the well-known transient codes) are rethrown immediately so the original\n * failure isn't masked.\n */\n private async writeAtomicWithRetry(\n registry: Record<string, SessionRegistryEntry>,\n ): Promise<void> {\n const transientCodes = new Set(['EPERM', 'EBUSY', 'EACCES', 'ETXTBSY', 'ENOTEMPTY']);\n const maxAttempts = 5;\n let lastErr: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n try {\n await this.writeAtomicLocked(registry);\n return;\n } catch (err) {\n lastErr = err;\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (!transientCodes.has(String(code ?? '')) || attempt === maxAttempts) {\n throw err;\n }\n // Tiny backoff with a 5 ms floor and 80 ms ceiling; combined with\n // maxAttempts=5 the worst-case wait is ~250 ms \u2014 acceptable for a\n // 5 s heartbeat and well under the cross-process lock budget.\n const delayMs = Math.min(80, 5 * attempt);\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));\n }\n\n private async maybePruneStaleTempFiles(): Promise<void> {\n if (this.tempPrunePromise) {\n await this.tempPrunePromise;\n return;\n }\n const now = Date.now();\n if (now - this.lastTempPruneAt < TEMP_PRUNE_INTERVAL_MS) return;\n\n this.lastTempPruneAt = now;\n this.tempPrunePromise = this.pruneStaleTempFiles();\n try {\n await this.tempPrunePromise;\n } finally {\n this.tempPrunePromise = null;\n }\n }\n\n private async writeAtomicFile(registry: Record<string, SessionRegistryEntry>): Promise<void> {\n await writeAtomicFile(this.filePath, registry);\n }\n\n private async pruneStaleTempFiles(): Promise<void> {\n await pruneStaleTempFiles(this.filePath);\n }\n}\n\n/** Singleton \u2014 created once per process. */\nlet _instance: SessionRegistry | null = null;\n\nexport function getSessionRegistry(globalRoot?: string): SessionRegistry {\n if (!_instance && globalRoot) {\n _instance = new SessionRegistry(globalRoot);\n }\n if (!_instance) {\n /* v8 ignore next -- the singleton is initialized by the first call in every test/process */\n throw new Error('SessionRegistry not initialized. Call getSessionRegistry(globalRoot) first.');\n }\n return _instance;\n}\n\nexport function hasSessionRegistry(): boolean {\n return _instance !== null;\n}\n", "import * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Logger, LogLevel } from '../types/logger.js';\nimport { color } from '../utils/color.js';\nimport { writeErr } from '../utils/term.js';\n\nconst LEVEL_RANK: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\nconst COLORS: Record<LogLevel, (s: string) => string> = {\n error: color.red,\n warn: color.yellow,\n info: color.cyan,\n debug: color.gray,\n trace: color.dim,\n};\n\nconst LOG_LEVELS = new Set<LogLevel>(['error', 'warn', 'info', 'debug', 'trace']);\nconst LOG_FORMATS = new Set<string>(['pretty', 'json']);\n\nexport type LogFormat = 'pretty' | 'json';\n\nexport interface DefaultLoggerOptions {\n level?: LogLevel | undefined;\n file?: string | undefined;\n /**\n * @deprecated Use `format: 'json'` instead. Kept for backward compat\n * with existing callers but has no effect on output \u2014 the `format`\n * option controls whether stderr receives pretty-printed or JSON lines.\n */\n pretty?: boolean | undefined;\n /** Output format for stderr. `pretty` (colored, human-readable) or `json` (machine-parseable). Defaults to `WRONGSTACK_LOG_FORMAT` env var, falling back to `pretty`. */\n format?: LogFormat | undefined;\n bindings?: Record<string, unknown>;\n /**\n * When false, suppress stderr output entirely \u2014 only write to the log\n * file (if configured). Use this in TUI mode so plugin/library log\n * messages don't interleave with Ink's terminal rendering.\n * Default: true (stderr output is enabled).\n */\n stderr?: boolean | undefined;\n /**\n * Rotate the log file once it exceeds this many bytes: the current file is\n * renamed to `<file>.1` (replacing any previous one) and a fresh file\n * starts. Bounds total disk to ~2\u00D7 this value. Default 10 MB.\n */\n maxFileBytes?: number | undefined;\n}\n\nexport class DefaultLogger implements Logger {\n /** How many file writes between rotation size checks (statSync is not free). */\n private static readonly ROTATE_CHECK_EVERY = 100;\n private static readonly MAX_PENDING_FILE_WRITES = 2_000;\n private static readonly MAX_PENDING_FILE_BYTES = 8 * 1024 * 1024;\n\n level: LogLevel;\n private file?: string | undefined;\n private bindings: Record<string, unknown>;\n private format: LogFormat;\n private stderr: boolean;\n private maxFileBytes: number;\n private writesSinceRotateCheck = 0;\n /**\n * Serialized async tail for file writes. Every appendFile (and any\n * chained rotation) is awaited through this promise so file I/O\n * never overlaps itself \u2014 preserving the per-line ordering the\n * sync version had, but without blocking the caller thread. Any\n * rejection is swallowed (`catch(() => {})`) because logging must\n * never crash the host.\n *\n * Children share the parent's tail: `child.tail === parent.tail`\n * for the lifetime of the chain. Read/write access goes through\n * `_tail` so that, when a child has been wired to a parent, both\n * `enqueueRotate` and `log` always observe the parent's current tail\n * rather than a stale snapshot taken at `child()` time.\n */\n private tail: Promise<void> = Promise.resolve();\n private parent: DefaultLogger | null = null;\n private pendingFileWrites = 0;\n private pendingFileBytes = 0;\n\n private get root(): DefaultLogger {\n return this.parent ? this.parent.root : this;\n }\n\n /**\n * Resolve the current tail. For the root logger this is the field;\n * for a child logger we always read through the parent so that a\n * child's appends land on the parent's most recent tail, and a\n * parent's `flush()` waits for everything the child chained.\n */\n private get _tail(): Promise<void> {\n return this.parent ? this.parent._tail : this.tail;\n }\n private set _tail(next: Promise<void>) {\n if (this.parent) this.parent.tail = next;\n else this.tail = next;\n }\n\n constructor(opts: DefaultLoggerOptions = {}) {\n this.level = opts.level ?? parseLogLevel(process.env.WRONGSTACK_LOG_LEVEL);\n this.file = opts.file;\n this.bindings = opts.bindings ?? {};\n this.format = opts.format ?? parseLogFormat(process.env.WRONGSTACK_LOG_FORMAT);\n this.stderr = opts.stderr !== false; // default true\n this.maxFileBytes = opts.maxFileBytes ?? 10 * 1024 * 1024;\n if (this.file) {\n // Chain mkdir onto the file-write tail so the first append can't\n // race a still-pending mkdir (especially under tests that call\n // `flush()` immediately after `info()`). mkdir is best-effort;\n // a rejection only blocks subsequent appends in the chain that\n // observed it via the rejected promise, which would skip the\n // append \u2014 that is acceptable because ENOENT/EEXIST/EPERM all\n // either are no-ops or indicate an unrecoverable environment.\n const dir = path.dirname(this.file);\n this._tail = this._tail\n .then(async () => {\n await fsp.mkdir(dir, { recursive: true });\n })\n .catch(() => undefined);\n }\n }\n\n error(msg: string, ctx?: unknown): void {\n this.log('error', msg, ctx);\n }\n warn(msg: string, ctx?: unknown): void {\n this.log('warn', msg, ctx);\n }\n info(msg: string, ctx?: unknown): void {\n this.log('info', msg, ctx);\n }\n debug(msg: string, ctx?: unknown): void {\n this.log('debug', msg, ctx);\n }\n trace(msg: string, ctx?: unknown): void {\n this.log('trace', msg, ctx);\n }\n\n child(bindings: Record<string, unknown>): Logger {\n // Construct without invoking the class constructor (which would mkdir\n // again and create a separate file-write tail). The parent and child\n // must share the same tail so `parent.flush()` waits for child\n // appends too \u2014 otherwise a test that flushes the parent after\n // `child.info(...)` would race the child append and observe an empty\n // file. Sharing the tail preserves the order the parent originally\n // had via its serialised file-write queue.\n const child = Object.create(DefaultLogger.prototype) as DefaultLogger;\n child.level = this.level;\n child.file = this.file;\n child.bindings = { ...this.bindings, ...bindings };\n child.format = this.format;\n child.stderr = this.stderr;\n child.maxFileBytes = this.maxFileBytes;\n child.parent = this;\n child.writesSinceRotateCheck = this.writesSinceRotateCheck;\n return child;\n }\n\n /**\n * Wait until all queued file writes (and any pending rotation) have\n * completed. `log()` is fire-and-forget by design \u2014 the caller never\n * blocks on disk \u2014 so tests, shutdown handlers, and processes that\n * need a deterministic \"everything is on disk now\" guarantee should\n * `await logger.flush()` before reading the file or exiting.\n */\n flush(): Promise<void> {\n return this._tail;\n }\n\n /**\n * Size-based rotation: when the file outgrows `maxFileBytes`, rename it to\n * `<file>.1` (dropping the previous `.1`) so the live file restarts empty.\n * Checked on the first write and every ROTATE_CHECK_EVERY writes after.\n * Best-effort: a rename can fail on Windows while another process holds\n * the file \u2014 the next check retries. Multiple processes appending to the\n * same log all run this check; whoever crosses the threshold first wins.\n *\n * Async: the rotation runs on the file-write tail (so its writes don't\n * interleave with the next append), and the caller never blocks on a\n * statSync / renameSync syscall on the hot log path.\n */\n private enqueueRotate(file: string): void {\n if (this.writesSinceRotateCheck++ % DefaultLogger.ROTATE_CHECK_EVERY !== 0) return;\n this._tail = this._tail\n .then(async () => {\n let st;\n try {\n st = await fsp.stat(file);\n } catch {\n return; // file missing \u2014 nothing to rotate\n }\n if (st.size < this.maxFileBytes) return;\n try {\n await fsp.rm(`${file}.1`, { force: true });\n await fsp.rename(file, `${file}.1`);\n } catch {\n // file locked, or raced by another process \u2014 ignore\n }\n })\n .catch(() => undefined);\n }\n\n private log(level: LogLevel, msg: string, ctx?: unknown): void {\n const r = LEVEL_RANK[level];\n const allowed = LEVEL_RANK[this.level];\n if (r > allowed) return;\n const ts = new Date().toISOString();\n const entry: Record<string, unknown> = { ts, level, msg, ...this.bindings };\n if (ctx !== undefined) {\n entry.ctx = ctx instanceof Error ? { message: ctx.message, stack: ctx.stack } : ctx;\n }\n // Disk: JSON line. Serialized through `_tail` so concurrent log\n // calls preserve per-line order without blocking the caller on\n // sync file I/O. Children route through their parent's tail, so\n // a parent's `flush()` waits for every chained child append.\n if (this.file) {\n const line = `${JSON.stringify(entry)}\\n`;\n const bytes = Buffer.byteLength(line, 'utf8');\n const root = this.root;\n if (\n root.pendingFileWrites < DefaultLogger.MAX_PENDING_FILE_WRITES &&\n bytes <= DefaultLogger.MAX_PENDING_FILE_BYTES &&\n root.pendingFileBytes + bytes <= DefaultLogger.MAX_PENDING_FILE_BYTES\n ) {\n root.pendingFileWrites += 1;\n root.pendingFileBytes += bytes;\n this.enqueueRotate(this.file);\n this._tail = this._tail\n .then(() => fsp.appendFile(this.file!, line))\n .catch(() => undefined)\n .finally(() => {\n root.pendingFileWrites = Math.max(0, root.pendingFileWrites - 1);\n root.pendingFileBytes = Math.max(0, root.pendingFileBytes - bytes);\n });\n }\n }\n // Stderr: pretty or json. Suppressed when this.stderr is false (TUI mode)\n // so plugin/library log messages don't interleave with Ink's rendering.\n if (!this.stderr) return;\n if (this.format === 'json') {\n writeErr(`${JSON.stringify(entry)}\\n`);\n } else {\n const head = `${color.dim(ts)} ${COLORS[level](level.toUpperCase().padEnd(5))} ${msg}`;\n if (ctx !== undefined) {\n writeErr(`${head} ${formatCtx(ctx)}\\n`);\n } else {\n writeErr(`${head}\\n`);\n }\n }\n }\n}\n\nfunction parseLogLevel(raw: string | undefined): LogLevel {\n return raw && LOG_LEVELS.has(raw as LogLevel) ? (raw as LogLevel) : 'info';\n}\n\nfunction parseLogFormat(raw: string | undefined): LogFormat {\n return raw && LOG_FORMATS.has(raw) ? (raw as LogFormat) : 'pretty';\n}\n\nfunction formatCtx(ctx: unknown): string {\n if (ctx instanceof Error) return color.dim(ctx.message);\n if (typeof ctx === 'string') return color.dim(ctx);\n try {\n return color.dim(JSON.stringify(ctx));\n } catch {\n return color.dim(String(ctx));\n }\n}\n\n/**\n * A logger that silently discards all messages. Used during boot before\n * the real logger is configured, and in test contexts where logging\n * would be noise.\n */\nexport const noOpLogger: Logger = {\n // 'error' is the quietest level the Logger contract offers; the methods\n // discard everything regardless, this only matters to level checks.\n level: 'error',\n error: () => {},\n warn: () => {},\n info: () => {},\n debug: () => {},\n trace: () => {},\n child: () => noOpLogger,\n};\n", "/**\n * TTY detection helpers \u2014 the single source of truth for \"is this process\n * running against a real terminal?\". Replaces ad-hoc `process.stdin.isTTY`\n * / `process.stdout.isTTY` checks scattered across the codebase so that:\n *\n * 1. test code can mock a single module instead of stubbing `isTTY` on\n * every ReadStream/WriteStream the test happens to touch;\n * 2. a future TTY-detection source (an env var override, a Windows\n * ConPTY workaround, \u2026) lands in one place;\n * 3. `isInteractive()` encodes the rule the project already used inline\n * (\"both streams are TTYs AND we're not running under CI\") in one\n * testable helper instead of the same 3-condition check in two\n * different files.\n *\n * Scope: detection only. Raw-mode control (`setRawMode`), resize\n * subscriptions, and write-injection belong to a future, larger TTY\n * abstraction; this module is the smallest pull that gives us a\n * testable seam and dedups 20+ call sites.\n */\n\nconst hasStdout = (): boolean => typeof process !== 'undefined' && !!process.stdout;\nconst hasStdin = (): boolean => typeof process !== 'undefined' && !!process.stdin;\n\n/** True when `process.stdout` is attached to a terminal (not a pipe/file). */\nexport function isStdoutTTY(): boolean {\n return hasStdout() && Boolean(process.stdout.isTTY);\n}\n\n/** True when `process.stdin` is attached to a terminal (not a pipe/file). */\nexport function isStdinTTY(): boolean {\n return hasStdin() && Boolean(process.stdin.isTTY);\n}\n\n/**\n * True when the current process is an interactive session: both stdin and\n * stdout are TTYs. Callers that also need a \"not a single-shot invocation\"\n * or \"not under CI\" check should layer that on top \u2014 keeping this helper\n * minimal preserves the original inline checks it replaces.\n */\nexport function isInteractive(): boolean {\n return isStdinTTY() && isStdoutTTY();\n}\n\n/** Current terminal size in characters, with a 24\u00D780 fallback for non-TTYs. */\nexport function getTermSize(): { rows: number; cols: number } {\n if (!hasStdout()) return { rows: 24, cols: 80 };\n return {\n rows: process.stdout.rows ?? 24,\n cols: process.stdout.columns ?? 80,\n };\n}\n\n/**\n * Subscribe to terminal resize events. `cb` is called with the new size each\n * time the underlying stream emits `resize`. Returns a cleanup function the\n * caller MUST call on dispose to remove the listener \u2014 leaving a stale\n * `resize` listener on a disposed component leaks the closure (and the\n * component itself, transitively) until the process exits.\n *\n * The stream argument defaults to `process.stdout`. Pass an explicit\n * `NodeJS.WriteStream` when the caller already owns one (e.g. a status line\n * that targets an injected `out` for testability). For non-TTY streams no\n * listener is registered and the returned cleanup is a no-op.\n */\nexport function onResize(\n cb: (size: { rows: number; cols: number }) => void,\n stream: NodeJS.WriteStream = process.stdout,\n): () => void {\n if (!stream || typeof stream.on !== 'function') return () => {};\n const handler = (): void => {\n cb({\n rows: stream.rows ?? 24,\n cols: stream.columns ?? 80,\n });\n };\n stream.on('resize', handler);\n return () => {\n stream.off('resize', handler);\n };\n}\n\n/**\n * Toggle raw mode on a TTY stdin stream. Returns `true` when the toggle was\n * applied, `false` when the stream is null, not a TTY, or doesn't expose\n * `setRawMode` (pipes, file descriptors, Windows ConPTY edge cases). Callers\n * that need to restore the previous mode should snapshot `input.isRaw`\n * BEFORE the call and pass the value to a second call to flip back.\n *\n * Use this helper to drop the now-redundant\n * `if (input.isTTY) input.setRawMode(...)` ceremony at every call site.\n */\nexport function setRawMode(input: NodeJS.ReadStream, mode: boolean): boolean {\n if (input?.isTTY !== true) return false;\n if (typeof input.setRawMode !== 'function') return false;\n input.setRawMode(mode);\n return true;\n}\n\n/**\n * Bracket installed by the interactive input reader while a `readline`\n * prompt is on screen. Out-of-band terminal writes \u2014 logger WARN/INFO\n * lines, async activity from the Telegram bridge, etc. \u2014 go to the same\n * physical terminal as the half-typed prompt but readline has no idea they\n * happened, so it never repaints. The result is the classic corruption the\n * user sees: every async line strands the in-progress draft as a fresh\n * scrollback row (sometimes with its cursor underline).\n *\n * The guard closes that gap. `suspend()` wipes the draft row so the message\n * prints clean; `resume()` repaints the prompt + draft (cursor preserved).\n * When no prompt is active the guard is `null` and writes pass straight\n * through \u2014 so agent-turn output (spinner, renderer) is untouched.\n */\nexport interface OutputLineGuard {\n /** Clear the current input row right before an out-of-band write. */\n suspend(): void;\n /** Repaint the prompt + in-progress draft right after the write. */\n resume(): void;\n}\n\nlet activeOutputGuard: OutputLineGuard | null = null;\n\n/**\n * Register (or clear, with `null`) the guard that brackets out-of-band\n * writes. Installed by {@link writeOut}/{@link writeErr} consumers \u2014 in\n * practice the CLI's readline input reader \u2014 only while a prompt is live.\n * Idempotent; the most recent caller wins.\n */\nexport function setOutputLineGuard(guard: OutputLineGuard | null): void {\n activeOutputGuard = guard;\n}\n\n/**\n * Stream-agnostic write primitive. Returns `false` when the stream is\n * missing or doesn't expose `write` so callers can degrade silently under\n * hostile host environments (closed pipe, mock injects `null`, test\n * replaces the stream with a stub).\n *\n * When an {@link OutputLineGuard} is installed (a readline prompt is on\n * screen) the write is bracketed by `suspend()`/`resume()` so the user's\n * half-typed input survives the interruption instead of being stranded in\n * scrollback. The guard's own redraw uses raw stream writes \u2014 never\n * `writeOut`/`writeErr` \u2014 so there is no re-entrancy here.\n *\n * **Not exported in the public API.** Exposed only inside `term.ts` for\n * `writeOut` / `writeErr` to share a single implementation. If a caller\n * needs to write to an arbitrary stream, they should call `writeOut` (or\n * `writeErr`) with an explicit `stream` argument \u2014 the named functions\n * are the public surface so the \"this is the standard error stream\"\n * intent stays visible at every call site.\n */\nfunction writeTo(\n s: string,\n stream: NodeJS.WriteStream | undefined,\n): boolean {\n if (!stream || typeof stream.write !== 'function') return false;\n const guard = activeOutputGuard;\n if (!guard) {\n stream.write(s);\n return true;\n }\n // A prompt is live \u2014 wipe the draft row, emit the message, repaint.\n guard.suspend();\n stream.write(s);\n guard.resume();\n return true;\n}\n\n/**\n * Write `s` to `stream` (defaults to `process.stdout`). Returns `false`\n * when the stream is missing or doesn't expose `write` so callers can\n * degrade silently under hostile host environments (closed pipe, mock\n * injects `null`, test replaces the stream with a stub).\n *\n * Why a helper:\n * 1. **Single seam for output capture in tests** \u2014 stub `writeOut` once\n * and assert on what the rest of the codebase intended to print,\n * without spying on `process.stdout.write` (which is brittle and\n * leaks across parallel test files).\n * 2. **Stream swap without grep** \u2014 routing the CLI's output to a\n * logger or `out.log` becomes a one-line change at process boot.\n * 3. **Defensive default** \u2014 closes the \"what if `process.stdout` is\n * `null`\" gap that currently exists at ~50 call sites that just\n * call `process.stdout.write(s)` and crash on certain Windows\n * redirect invocations.\n *\n * Call-site migration is staged: this commit introduces the helper, a\n * follow-up commit replaces the 50+ `process.stdout.write(...)` sites\n * with `writeOut(...)`. Until that migration lands, both forms coexist\n * and `writeOut` is the preferred form for new code.\n */\nexport function writeOut(\n s: string,\n stream: NodeJS.WriteStream = process.stdout,\n): boolean {\n return writeTo(s, stream);\n}\n\n/**\n * Symmetric partner of `writeOut` for the standard error stream. Same shape,\n * same defensive contract, same single-seam-for-tests story \u2014 just defaults to\n * `process.stderr` instead of `process.stdout`.\n *\n * Use this in code paths that emit error/diagnostic/warning text. Keeping\n * these two helpers split (rather than a single `writeTo(s, stream)`) means\n * the call site reads as a clear intent signal: \"I am writing an error\" vs.\n * \"I am writing a result\" \u2014 which matters for callers that decide between\n * stdout/stderr routing (e.g. `--quiet` flags, log-level filtering,\n * structured-log rewriters that fork on stream).\n *\n * Stderr writes from the core logger (see `infrastructure/logger.ts`) and from\n * the TUI guard (see `tui/run-tui.ts`) used to call `process.stderr.write`\n * directly. Routing them through this helper lets tests stub the stream at\n * one boundary and lets future logging middleware (e.g. a JSON-line rewriter)\n * swap the destination for the entire process in one place.\n */\nexport function writeErr(\n s: string,\n stream: NodeJS.WriteStream = process.stderr,\n): boolean {\n return writeTo(s, stream);\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// TerminalCapability \u2014 startup capability profile\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Color depth the terminal can render.\n *\n * 0 = no color (dumb, redirected, `TERM=dumb`)\n * 1 = 16 colors (basic ANSI)\n * 2 = 256 colors (ANSI 256 + bright variants)\n * 3 = 16.7M / 24-bit truecolor\n */\nexport type ColorDepth = 0 | 1 | 2 | 3;\n\n/**\n * Mouse tracking protocol the terminal speaks.\n *\n * 'none' \u2014 no mouse reporting\n * 'x10' \u2014 basic button press/release, capped at 223 columns\n * 'urxvt'\u2014 URXVT extension, supports >223 cols\n * 'sgr' \u2014 SGR extended mode, modern standard, no column cap\n */\nexport type MouseProtocol = 'none' | 'x10' | 'urxvt' | 'sgr';\n\n/**\n * A snapshot of the terminal's capabilities and identity, computed once at\n * startup. Call {@link detectTerminal} once and pass the result through your\n * app \u2014 never re-detect mid-session.\n *\n * Query once \u2192 adapt once. Re-querying on every render is wrong because\n * `$TERM` is static for the process lifetime and stdout.isTTY can only go\n * from true\u2192false (never the reverse), so a mid-session change means the\n * process was started in a terminal and then something went wrong.\n */\nexport interface TerminalCapability {\n /** True when both stdin and stdout are attached to a terminal. */\n isRealTTY: boolean;\n /**\n * Whether the terminal speaks color.\n *\n * Uses the industry-standard precedence:\n * `FORCE_COLOR=0` \u2192 0 (disabled)\n * `FORCE_COLOR` \u2192 3 (force truecolor)\n * `NO_COLOR=\u2026` \u2192 0 (opted out)\n * `COLORTERM=truecolor|24bit` \u2192 3\n * `TERM=\u2026truecolor|24bit` \u2192 3 (some emulators advertise it)\n * `TERM=\u2026256color` \u2192 2\n * fallback \u2192 1\n *\n * Note: `TERM=dumb` always produces 0 even if `COLORTERM=truecolor` is set \u2014\n * `dumb` terminals are non-interactive by definition.\n */\n colorDepth: ColorDepth;\n /**\n * Whether `stdout` can be written to. Determined once at startup from\n * `stdout?.isTTY ?? false`. Even when `isRealTTY` is true, `stdout` may be\n * writable=false (e.g. the terminal was closed mid-session).\n */\n stdoutWritable: boolean;\n /**\n * Best mouse protocol the terminal speaks. Progressive enhancement:\n * attempt SGR first, fall back to URXVT, then X10, then 'none'.\n *\n * The caller (typically the App component) decides whether to enable\n * tracking at all \u2014 this only reports what the terminal CAN understand.\n */\n mouseProtocol: MouseProtocol;\n /**\n * Whether the terminal title can be set via OSC 0 / OSC 2.\n * True when stdout is a TTY and `$TERM` is not `dumb`.\n */\n canSetTitle: boolean;\n /**\n * Whether the terminal understands the tmux DCS passthrough prefix.\n * Detected by seeing `$TERM=tmux*`. When true, escape sequences should be\n * wrapped: `\\x1bPtmux;\\x1b${seq}\\x1b\\\\`.\n */\n isTmux: boolean;\n /**\n * Whether the terminal is on Windows using the legacy conhost backend\n * (cmd.exe, PowerShell non-ConPTY) rather than ConPTY (Windows Terminal,\n * VS Code Integrated Terminal). Used to apply Windows-specific raw-mode\n * handoff logic.\n *\n * Detected by: platform === 'win32' AND `!process.stdout.getColorDepth?.()`\n * (ConPTY exposes color depth; conhost does not). Also false on non-Windows.\n */\n isWindowsConhost: boolean;\n}\n\n/**\n * Parse `process.env.TERM` into a color-depth guess.\n *\n * We intentionally do NOT use the `supports-color` npm package here because\n * (a) it adds a dependency, (b) it resolves at module-import time, and (c) we\n * need to factor in `FORCE_COLOR` / `NO_COLOR` which may be set after import.\n * This pure function is trivial to test and predictable regardless of import\n * order.\n */\nfunction parseColorDepth(env: { FORCE_COLOR?: string; NO_COLOR?: string; COLORTERM?: string; TERM?: string; }): ColorDepth {\n // `FORCE_COLOR=0` is an explicit opt-out, even when `COLORTERM=truecolor`.\n if (env.FORCE_COLOR === '0') return 0;\n // `FORCE_COLOR` with no value or any truthy value forces truecolor.\n if (env.FORCE_COLOR !== undefined) return 3;\n // Explicit user opt-out.\n if (typeof env.NO_COLOR === 'string' && env.NO_COLOR !== '') return 0;\n // Explicit terminal advertisement.\n const colorterm = (env.COLORTERM ?? '').toLowerCase();\n if (colorterm === 'truecolor' || colorterm === '24bit') return 3;\n // TERM strings that advertise rich color.\n const term = (env.TERM ?? '').toLowerCase();\n if (term.includes('truecolor') || term.includes('24bit')) return 3;\n if (term.includes('256color')) return 2;\n // TERM=dumb = no interactive capability at all.\n if (term === 'dumb') return 0;\n // Default to 16-color \u2014 the safest floor. Modern terminals all override this.\n return 1;\n}\n\n/**\n * Detect the best mouse protocol the terminal speaks.\n *\n * Uses the `$TERM` string as a proxy since Node.js has no runtime query for\n * mouse capability (DECSET 1000/1002/1003 responses are not standardized for\n * programmatic use). The approximation is:\n * - `tmux` + `screen` = SGR (they proxy it)\n * - `xterm*`, `rxvt*`, `konsole`, `gnome*` = SGR (post-2013)\n * - `linux`, `vt100`, `dumb` = none\n * - Everything else = URXVT / X10 (try SGR, fall back gracefully in mouse.ts)\n *\n * This is advisory only. The App component gates mouse tracking behind an\n * explicit user/setting opt-in; false positives just mean the tracking enable\n * sequence is ignored harmlessly.\n */\nfunction parseMouseProtocol(term: string): MouseProtocol {\n const t = term.toLowerCase();\n // Terminals that reliably support SGR (1006) mode.\n if (\n t.startsWith('xterm') ||\n t.startsWith('tmux') ||\n t.startsWith('screen') ||\n t.includes('rxvt-unicode') ||\n t.includes('urxvt') ||\n t.includes('konsole') ||\n t.includes('gnome') ||\n t.includes('foot') ||\n t.includes('alacritty') ||\n t.includes('wezterm') ||\n t.includes('kitty') ||\n t.includes('vscode') ||\n t.includes('Apple_Terminal')\n ) {\n return 'sgr';\n }\n // Known mouse-capable but older terminals.\n if (t.startsWith('rxvt') || t.startsWith('linux') || t.includes('Eterm')) {\n return 'urxvt';\n }\n // vt100 / dumb \u2014 no mouse.\n if (t === 'vt100' || t === 'dumb') return 'none';\n // Default: assume SGR is safe to try; mouse.ts falls back silently.\n return 'sgr';\n}\n\n/**\n * Detect the terminal's capabilities and identity at startup.\n *\n * Call once, early in process boot, before any event-loop async has had a\n * chance to corrupt the read of `process.stdout.isTTY`. Store the result and\n * pass it through the app \u2014 do NOT call this on every render.\n *\n * All `env` lookups default gracefully to safe values when the env var is\n * absent or empty, so the return value is deterministic regardless of what\n * the host's environment looks like.\n */\nexport function detectTerminal(\n opts: {\n stdin?: NodeJS.ReadStream | null;\n stdout?: NodeJS.WriteStream | null;\n env?: typeof process.env;\n } = {},\n): TerminalCapability {\n const stdin = opts.stdin ?? process.stdin;\n const stdout = opts.stdout ?? process.stdout;\n const env = opts.env ?? process.env;\n\n const isRealTTY = (stdin?.isTTY ?? false) && (stdout?.isTTY ?? false);\n const stdoutWritable = isRealTTY && typeof stdout?.write === 'function';\n const term = env.TERM ?? '';\n const isTmux = term.toLowerCase().startsWith('tmux');\n const isWindowsConhost = isRealTTY\n && process.platform === 'win32'\n && typeof (stdout as NodeJS.WriteStream & { getColorDepth?: unknown }).getColorDepth !== 'function';\n\n return {\n isRealTTY,\n colorDepth: isRealTTY ? parseColorDepth(env) : 0,\n stdoutWritable,\n mouseProtocol: parseMouseProtocol(term),\n canSetTitle: isRealTTY && term !== 'dumb',\n isTmux,\n isWindowsConhost,\n };\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// TerminalLifecycle \u2014 raw-mode lifecycle manager\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Lifecycle owner for the TTY stdin raw-mode state machine.\n *\n * Raw mode is the most dangerous primitive in TUI code. Getting it wrong leaves\n * the user's terminal in a broken state (line-buffered, no echo) that requires\n * closing and reopening the terminal to recover. This class enforces a strict\n * acquire \u2192 hold \u2192 release lifecycle:\n *\n * - `acquire()` may be called only once (idempotent \u2014 subsequent calls no-op).\n * - `release()` restores the previous mode exactly once.\n * - `release()` is called automatically on process `exit` and `beforeExit`.\n * - Any signal handler (SIGINT, SIGTERM, SIGHUP) that calls `release()` clears\n * its own registration so double-signals don't double-restore.\n *\n * Use this instead of calling `setRawMode()` directly at every call site. The\n * single instance lives at module scope in `run-tui.ts`; components that need\n * to signal \"TUI is shutting down\" call `terminalLifecycle.requestExit()` rather\n * than calling `release()` directly.\n */\nexport class TerminalLifecycle {\n private _active = false;\n\n /**\n * The stdin stream we took raw mode on. Set by `acquire()`; undefined before\n * first call. Used by `release()` and by the ConPTY race-closer in\n * `acquire()`.\n */\n private _stdin: NodeJS.ReadStream | undefined;\n\n /**\n * The `isRaw` snapshot captured before the first `acquire()` call, so\n * `release()` restores to the pre-TUI state rather than blindly disabling\n * raw mode. Null when `acquire()` has never been called.\n */\n private _wasRaw: boolean | null = null;\n\n /**\n * Whether stdin was paused before the TUI took ownership. Readline closes\n * its interface by pausing the shared process stream, so raw mode alone is\n * not enough to make Ink receive bytes during the boot-prompt -> TUI handoff.\n */\n private _wasPaused: boolean | null = null;\n\n /**\n * Request the process to exit. Set the flag, trigger any registered\n * `onRequestExit` callback (typically Ink's `unmount()`), and arm a\n * deadline timer. When the timer fires the process is hard-exited.\n *\n * Safe to call multiple times: subsequent calls no-op after the first.\n */\n requestExit: (exitCode?: number) => void;\n\n /**\n * Callback invoked when `requestExit` is called. Registered by the Ink\n * mount point so unmount() runs before the deadline timer fires.\n */\n onRequestExit: (() => void | Promise<void>) | null = null;\n\n constructor() {\n // Build the requestExit closure here so subclasses / tests can override\n // `requestExit` before calling `acquire()`.\n let exitCode = 0;\n let requested = false;\n this.requestExit = (code = 0) => {\n exitCode = code;\n if (requested) return;\n requested = true;\n // Let the Ink unmount handler run (if registered).\n try {\n this.onRequestExit?.();\n } catch {\n // unmount handler threw \u2014 proceed to hard exit.\n }\n // Hard-exit deadline. `unref()` so the timer doesn't keep the event\n // loop alive if everything else has settled.\n setTimeout(() => process.exit(exitCode), 5_000).unref();\n };\n }\n\n /** True while raw mode is held. */\n get active(): boolean {\n return this._active;\n }\n\n /**\n * Acquire raw mode on `stdin`. Idempotent \u2014 calling twice is safe; only the\n * first call has any effect.\n *\n * On Windows ConPTY, calls `setRawMode` twice: once immediately, then again\n * after the next event-loop tick. This closes the ConPTY race where\n * `readline`'s cleanup (registered before this class is constructed) can\n * restore the original cooked mode after we set raw mode but before Ink's\n * render loop takes over the stdin fd. The double-call ensures the last\n * writer wins.\n *\n * @param stdin - The stdin stream (defaults to `process.stdin`).\n * @returns `true` if raw mode was acquired; `false` if stdin is not a TTY\n * or already shut down.\n */\n acquire(stdin: NodeJS.ReadStream = process.stdin): boolean {\n if (this._active) return false;\n\n // Guard: must be a real TTY, must have setRawMode.\n if (stdin?.isTTY !== true) return false;\n if (typeof stdin.setRawMode !== 'function') return false;\n\n // Snapshot the pre-TUI raw state so release() restores correctly.\n this._wasRaw = stdin.isRaw ?? false;\n this._wasPaused = stdin.isPaused();\n this._stdin = stdin;\n\n stdin.setRawMode(true);\n // A preceding readline prompt normally leaves process.stdin paused.\n // Explicitly start the stream before Ink installs its input listener;\n // otherwise the UI can render perfectly while every key appears dead.\n stdin.resume();\n this._active = true;\n\n // Windows ConPTY double-acquire: schedule a second setRawMode on the next\n // tick so we win the race against readline's \"restore original mode\".\n // Safe on non-Windows (no-op: process.platform !== 'win32').\n if (process.platform === 'win32') {\n setImmediate(() => {\n if (this._active && this._stdin?.isTTY) {\n this._stdin.setRawMode?.(true);\n }\n });\n }\n\n return true;\n }\n\n /**\n * Release raw mode and restore the terminal to the state it was in before\n * `acquire()` was called. Idempotent \u2014 subsequent calls are no-ops.\n *\n * Call this on: SIGINT, SIGTERM, SIGHUP, SIGBREAK, and `process.exit`.\n *\n * \u26A0 **Windows caveat**: `setRawMode(false)` on ConPTY restores the original\n * console mode captured when the process started \u2014 not the mode captured by\n * `acquire()`. On ConPTY, the original mode was already raw (ConPTY starts\n * raw), so this call is typically a no-op on Windows Terminal. On conhost.exe\n * it may restore cooked mode, which is correct for that backend.\n */\n release(): void {\n if (!this._active) return;\n this._active = false;\n\n const stdin = this._stdin;\n if (stdin?.isTTY === true) {\n // Restore to pre-TUI state rather than blindly disabling raw mode.\n stdin.setRawMode?.(this._wasRaw ?? false);\n if (this._wasPaused) stdin.pause();\n }\n this._stdin = undefined;\n this._wasRaw = null;\n this._wasPaused = null;\n }\n\n /**\n * Synchronously reset all terminal state written by the TUI layer:\n * raw mode, SGR attributes, cursor visibility, and mouse tracking.\n *\n * Intended for the final `process.on('exit')` handler where async is\n * impossible. Uses `\\x1b[0m` (SGR reset), `\\x1b[?25h` (cursor show),\n * and `\\x1b[?9l` (mouse off) \u2014 all safe to emit even if the terminal does\n * not understand them (unknown CSI sequences are silently ignored).\n *\n * Safe to call multiple times from multiple exit paths because each write\n * is a constant-time synchronous stream write.\n *\n * @param stdout - Stream to reset (defaults to `process.stdout`).\n */\n reset(stdout: NodeJS.WriteStream = process.stdout): void {\n if (typeof stdout?.write !== 'function') return;\n // SGR reset \u2014 clears bold, color, underline, etc.\n stdout.write('\\x1b[0m');\n // Cursor show (in case Ink's unmount left it hidden).\n stdout.write('\\x1b[?25h');\n // Mouse tracking off (all three DECRST sequences \u2014 safe no-ops if never set).\n stdout.write('\\x1b[?1003l\\x1b[?1002l\\x1b[?1000l');\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// safeEscape \u2014 guarded escape-sequence emitter\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Result of emitting an escape sequence. Distinguishes the three distinct\n * failure modes so callers can degrade gracefully.\n */\nexport interface EscapeEmitResult {\n /** `true` when the sequence was written to the stream. */\n ok: boolean;\n /**\n * Human-readable reason when `ok` is `false`. One of:\n * `'not_a_tty'` \u2014 stdout is not a terminal (pipe / redirect / CI)\n * `'unwritable'` \u2014 stdout.write is missing or threw\n * `'empty'` \u2014 `sequence` was the empty string\n */\n reason: 'not_a_tty' | 'unwritable' | 'empty';\n}\n\n/**\n * A terminal escape sequence with its optional string terminator.\n *\n * OSC (title, color palette) sequences MUST be terminated with `BEL (\\x07)`\n * or `ST (\\x1b\\\\)` or the terminal stays in command mode and corrupts\n * subsequent output. CSI sequences (colors, cursor movement) are\n * self-terminating and do not need a terminator byte.\n */\nexport interface EscapeSequence {\n /** The raw sequence, e.g. `\\x1b[38;2;255;0;0m`. */\n raw: string;\n /**\n * Optional terminator byte required by OSC/DCS families.\n * `undefined` for CSI sequences; `\\x07` (BEL) for OSC; `\\x1b\\\\` (ST) for DCS.\n */\n terminator?: string;\n}\n\n/**\n * Shared OSC/DCS terminator bytes.\n *\n * BEL (`\\x07`) is understood by iTerm2, Konsole, mintty, foot, and\n * Windows Terminal. ST (`\\x1b\\\\`) is the strict DEC standard equivalent.\n * Prefer BEL for compatibility; fall back to ST if the terminal's response\n * to BEL is observed to be garbled.\n */\nexport const ESCAPE_TERMINATOR = Object.freeze({\n BEL: '\\x07', // OSC 0 / OSC 2 (title)\n ST: '\\x1b\\\\', // DCS / strict OSC\n});\n\n/**\n * Emit a terminal escape sequence safely.\n *\n * Rules enforced:\n * 1. Empty string \u2192 returns `ok: false, reason: 'empty'`, no write.\n * 2. Not a TTY \u2192 returns `ok: false, reason: 'not_a_tty'`, no write.\n * 3. Stream write throws \u2192 returns `ok: false, reason: 'unwritable'`.\n * 4. OSC/DCS sequences MUST have a terminator byte (guarded assertion).\n * A missing terminator on an OSC sequence corrupts output on terminals\n * that don't understand the sequence \u2014 this function refuses to emit it.\n *\n * @param sequence - The sequence to emit. CSI sequences need no terminator.\n * OSC/DCS sequences must carry `terminator: '\\x07'` or `'\\x1b\\\\'`.\n * @param stdout - Stream to write to (defaults to `process.stdout`).\n * @returns Result indicating success or the specific failure mode.\n */\nexport function safeEmit(\n sequence: EscapeSequence | string,\n stdout: NodeJS.WriteStream = process.stdout,\n): EscapeEmitResult {\n const raw = typeof sequence === 'string' ? sequence : sequence.raw;\n const term = typeof sequence === 'string' ? undefined : sequence.terminator;\n\n if (!raw) {\n return { ok: false, reason: 'empty' };\n }\n if (stdout?.isTTY !== true) {\n return { ok: false, reason: 'not_a_tty' };\n }\n\n // For OSC/DCS sequences (which include `[` or `]` in the body), verify a\n // terminator is present. CSI sequences start with `\\x1b[` and are\n // self-terminating; we treat any sequence that is not a known OSC/DCS\n // as CSI and allow through. OSC starts with `\\x1b]`; DCS with `\\x1bP`.\n if (raw.startsWith('\\x1b]') || raw.startsWith('\\x1bP')) {\n // Assertion: terminator must be provided. Belt-and-suspenders against\n // callers that forget to append `\\x07` \u2014 this prevents corrupted output.\n if (!term) {\n // Defensive: append BEL rather than crashing. This is the only case\n // where we mutate the sequence. The assert-then-fallback pattern is\n // intentional: we catch programmer error in development but degrade\n // safely in production rather than throwing.\n void term; // suppress unused-variable warning\n const safe = `${raw}\\x07`;\n try {\n stdout.write(safe);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' }; // reason field is ignored when ok=true\n }\n try {\n stdout.write(`${raw}${term}`);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' };\n }\n\n // CSI sequence \u2014 self-terminating.\n try {\n stdout.write(raw);\n } catch {\n return { ok: false, reason: 'unwritable' };\n }\n return { ok: true, reason: 'empty' };\n}\n\n/**\n * Build an OSC 0 / OSC 2 (window/tab title) sequence with a safe terminator.\n *\n * The terminator defaults to `BEL (\\x07)` for broad terminal compatibility.\n * Use `terminator: ESCAPE_TERMINATOR.ST` for stricter terminals that interpret\n * BEL as a beep.\n *\n * @param title - The title string. Embedded BEL bytes are stripped.\n * @param terminator - Defaults to `ESCAPE_TERMINATOR.BEL`.\n */\nexport function buildTitleSequence(\n title: string,\n terminator: string = ESCAPE_TERMINATOR.BEL,\n): EscapeSequence {\n return {\n raw: `\\x1b]0;${title.replace(/\\x07/g, '')}`,\n terminator,\n };\n}\n\n/**\n * Build an SGR (Select Graphic Rendition) color/style sequence.\n *\n * @param codes - SGR parameter list, e.g. `[31]` (red foreground),\n * `[1;32]` (bold green), `[38;2;255;128;0]` (truecolor orange).\n */\nexport function buildSgrSequence(...codes: number[]): EscapeSequence {\n return { raw: `\\x1b[${codes.join(';')}m` };\n}\n\n/**\n * Emit a title sequence. Convenience wrapper around `safeEmit` + `buildTitleSequence`.\n *\n * @param title - The title string.\n * @param stdout - Target stream.\n */\nexport function setTitle(\n title: string,\n stdout: NodeJS.WriteStream = process.stdout,\n): boolean {\n return safeEmit(buildTitleSequence(title), stdout).ok;\n}\n", "import { isStdoutTTY } from './term.js';\n\nconst isColorTty = (): boolean => {\n if (envFlag(process.env.NO_COLOR)) return false;\n if (envFlag(process.env.FORCE_COLOR)) return true;\n return isStdoutTTY();\n};\n\nfunction envFlag(value: string | undefined): boolean {\n if (value === undefined) return false;\n if (value.trim() === '') return false;\n return !/^(0|false|no|off)$/i.test(value.trim());\n}\n\nconst COLOR = isColorTty();\n\nconst wrap =\n (open: string, close: string) =>\n (s: string): string =>\n COLOR ? `\\x1b[${open}m${s}\\x1b[${close}m` : s;\n\nexport const color = {\n reset: wrap('0', '0'),\n bold: wrap('1', '22'),\n dim: wrap('2', '22'),\n italic: wrap('3', '23'),\n underline: wrap('4', '24'),\n red: wrap('31', '39'),\n green: wrap('32', '39'),\n yellow: wrap('33', '39'),\n blue: wrap('34', '39'),\n magenta: wrap('35', '39'),\n cyan: wrap('36', '39'),\n gray: wrap('90', '39'),\n amber: wrap('38;5;214', '39'),\n pink: wrap('38;5;205', '39'),\n bgRed: wrap('41', '49'),\n bgGreen: wrap('42', '49'),\n};\n\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*[A-Za-z]/g, '');\n}\n", "import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { PathResolver } from '../types/path-resolver.js';\n\nconst PROJECT_MARKERS = [\n '.git',\n 'package.json',\n 'pnpm-workspace.yaml',\n 'go.mod',\n 'Cargo.toml',\n 'pyproject.toml',\n // Use AGENTS.md, not the bare .wrongstack directory. A bare .wrongstack/\n // directory can be the global config directory (~/.wrongstack), which is\n // NOT a project marker. Only .wrongstack/AGENTS.md signals a real\n // WrongStack project.\n '.wrongstack/AGENTS.md',\n];\n\nexport class DefaultPathResolver implements PathResolver {\n readonly projectRoot: string;\n readonly cwd: string;\n\n constructor(cwd: string = process.cwd()) {\n this.cwd = path.resolve(cwd);\n this.projectRoot = this.detectProjectRoot(this.cwd);\n }\n\n detectProjectRoot(start: string): string {\n let dir = path.resolve(start);\n const root = path.parse(dir).root;\n const home = path.resolve(os.homedir());\n const startPath = path.resolve(start);\n while (dir !== root) {\n // Don't walk past the user home directory. Home often has stray\n // markers (.git for dotfile tracking, package.json from global\n // tooling) that are unrelated to the actual working directory.\n // When cwd IS home we still check markers there \u2014 this guard\n // only fires during the upward walk from a subdirectory.\n if (dir === home && dir !== startPath) {\n break;\n }\n for (const marker of PROJECT_MARKERS) {\n try {\n fs.accessSync(path.join(dir, marker));\n return dir;\n } catch {\n // continue\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startPath;\n }\n\n resolve(input: string): string {\n const abs = path.isAbsolute(input) ? input : path.resolve(this.cwd, input);\n let real: string;\n try {\n real = fs.realpathSync(abs);\n } catch {\n // path doesn't exist yet; normalize without resolving symlinks\n real = path.normalize(abs);\n }\n return real;\n }\n\n isInsideRoot(absPath: string): boolean {\n const normalized = path.normalize(absPath);\n const root = path.normalize(this.projectRoot);\n if (normalized === root) return true;\n const rel = path.relative(root, normalized);\n return !rel.startsWith('..') && !path.isAbsolute(rel);\n }\n\n ensureInsideRoot(absPath: string): string {\n const resolved = this.resolve(absPath);\n if (!this.isInsideRoot(resolved)) {\n // Render the input as a project-relative-looking string when possible\n // so the error message can flow through telemetry / LLM transcripts\n // without leaking the absolute project root layout.\n const display = path.isAbsolute(absPath) ? path.basename(absPath) : absPath;\n const err = new Error(`Path \"${display}\" resolves outside the project root`);\n // Keep the full information available to programmatic callers; only\n // the user-facing `message` is sanitized.\n (err as Error & { fullPath?: string | undefined; projectRoot?: string | undefined }).fullPath = absPath;\n (err as Error & { fullPath?: string | undefined; projectRoot?: string | undefined }).projectRoot = this.projectRoot;\n throw err;\n }\n return resolved;\n }\n}\n", "import type { EventBus } from '../kernel/events.js';\nimport type { ModelsRegistry, ResolvedModel } from '../types/models-registry.js';\nimport type { Usage } from '../types/provider.js';\nimport type { CacheStats, TokenCounter } from '../types/token-counter.js';\n\ninterface PriceEntry {\n input?: number | undefined;\n output?: number | undefined;\n cacheRead?: number | undefined;\n cacheWrite?: number | undefined;\n cacheWrite5m?: number | undefined;\n cacheWrite1h?: number | undefined;\n}\n\nconst PRICE_CACHE_MAX_SIZE = 100;\n\n/**\n * Token counter that derives pricing from the ModelsRegistry instead of a\n * hardcoded table. If a model is unknown to the registry (or the registry is\n * unavailable) the counter still tracks token totals but reports zero cost.\n */\nexport class DefaultTokenCounter implements TokenCounter {\n private input = 0;\n private output = 0;\n private cacheRead = 0;\n private cacheWrite = 0;\n private costInput = 0;\n private costOutput = 0;\n private cacheSaved = 0;\n private readonly registry?: ModelsRegistry | undefined;\n private readonly providerId?: string | (() => string | undefined) | undefined;\n private readonly events?: EventBus | undefined;\n private sessionId?: string | (() => string | undefined) | undefined;\n private priceCache = new Map<string, PriceEntry>();\n /** Most recently accounted request's tokens. Used for per-request context pressure. */\n private lastInput = 0;\n private lastCacheRead = 0;\n private lastCacheWrite = 0;\n\n constructor(\n opts: {\n registry?: ModelsRegistry | undefined;\n providerId?: string | (() => string | undefined) | undefined;\n events?: EventBus | undefined;\n sessionId?: string | (() => string | undefined) | undefined;\n } = {},\n ) {\n this.registry = opts.registry;\n this.providerId = opts.providerId;\n this.events = opts.events;\n this.sessionId = opts.sessionId;\n }\n\n setSessionId(sessionId: string | (() => string | undefined) | undefined): void {\n this.sessionId = sessionId;\n }\n\n account(usage: Usage, model?: string, providerId = this.currentProviderId()): void {\n const eventSessionId = this.currentSessionId();\n this.input += usage.input;\n this.output += usage.output;\n this.cacheRead += usage.cacheRead ?? 0;\n this.cacheWrite += usage.cacheWrite ?? 0;\n // Snapshot per-request tokens for context pressure tracking.\n this.lastInput = usage.input;\n this.lastCacheRead = usage.cacheRead ?? 0;\n this.lastCacheWrite = usage.cacheWrite ?? 0;\n\n const priceKey = providerId && model ? `${providerId}\\0${model}` : undefined;\n const price = priceKey ? this.priceCache.get(priceKey) : undefined;\n if (price) {\n this.applyPrice(usage, price);\n this.emitAccounted(eventSessionId, model, providerId, usage);\n return;\n }\n\n if (this.registry && providerId && model) {\n // Evict oldest entry when cache is full before async lookup.\n if (this.priceCache.size >= PRICE_CACHE_MAX_SIZE) {\n const keys = [...this.priceCache.keys()];\n this.priceCache.delete(keys[0] ?? '');\n }\n // Async lookup \u2014 populate cache, but don't block this call.\n void this.registry\n .getModel(providerId, model)\n .then((m) => {\n if (m) {\n const p = priceFromModel(m);\n this.priceCache.set(priceKey!, p);\n this.applyPrice(usage, p);\n }\n // Token totals are authoritative even when pricing is unresolved.\n // Emit after the lookup settles so live UIs update for unknown models\n // without double-emitting when pricing is resolved.\n this.emitAccounted(eventSessionId, model, providerId, usage);\n })\n .catch(() => {\n // Emit so observability tooling can detect unknown models.\n this.events?.emit('token.cost_estimate_unavailable', {\n ...(eventSessionId ? { sessionId: eventSessionId } : {}),\n model: model ?? '<unknown>',\n });\n this.emitAccounted(eventSessionId, model, providerId, usage);\n return undefined;\n });\n return;\n }\n\n // No pricing source exists. Still emit token totals so live UIs do not stay\n // at 0 just because cost cannot be estimated.\n this.emitAccounted(eventSessionId, model, providerId, usage);\n }\n\n /** Synchronous variant for code paths that have already resolved the model. */\n accountWithModel(usage: Usage, resolved: ResolvedModel): void {\n const eventSessionId = this.currentSessionId();\n this.input += usage.input;\n this.output += usage.output;\n this.cacheRead += usage.cacheRead ?? 0;\n this.cacheWrite += usage.cacheWrite ?? 0;\n // Snapshot per-request tokens for context pressure tracking.\n this.lastInput = usage.input;\n this.lastCacheRead = usage.cacheRead ?? 0;\n this.lastCacheWrite = usage.cacheWrite ?? 0;\n const price = priceFromModel(resolved);\n if (this.priceCache.size >= PRICE_CACHE_MAX_SIZE) {\n const keys = [...this.priceCache.keys()];\n this.priceCache.delete(keys[0] ?? '');\n }\n this.priceCache.set(`${resolved.providerId}\\0${resolved.modelId}`, price);\n this.applyPrice(usage, price);\n this.emitAccounted(eventSessionId, resolved.modelId, resolved.providerId, usage);\n }\n\n total(): Usage {\n return {\n input: this.input,\n output: this.output,\n cacheRead: this.cacheRead,\n cacheWrite: this.cacheWrite,\n };\n }\n\n currentRequestTokens(): { input: number; cacheRead: number; cacheWrite: number } {\n return { input: this.lastInput, cacheRead: this.lastCacheRead, cacheWrite: this.lastCacheWrite };\n }\n\n setCurrentRequestTokens(input: number, cacheRead?: number, cacheWrite?: number): void {\n this.lastInput = input;\n this.lastCacheRead = cacheRead ?? 0;\n this.lastCacheWrite = cacheWrite ?? 0;\n }\n\n estimateCost(): { input: number; output: number; total: number; currency: 'USD' } {\n return {\n input: round4(this.costInput),\n output: round4(this.costOutput),\n total: round4(this.costInput + this.costOutput),\n currency: 'USD',\n };\n }\n\n cacheStats(): CacheStats {\n // Hit ratio: cacheRead / (cacheRead + input). `input` from the provider\n // is the count of fresh-token reads, so this answers \"what fraction of\n // the prompt did we get for the cache price?\"\n const denom = this.cacheRead + this.input;\n return {\n readTokens: this.cacheRead,\n writeTokens: this.cacheWrite,\n hitRatio: denom === 0 ? 0 : this.cacheRead / denom,\n savedUsd: round4(this.cacheSaved),\n };\n }\n\n /** Invalidate cached prices so the next account() call fetches fresh data. */\n invalidateCache(): void {\n this.priceCache.clear();\n }\n\n private emitAccounted(\n sessionId = this.currentSessionId(),\n model?: string,\n providerId = this.currentProviderId(),\n deltaUsage?: Usage,\n ): void {\n this.events?.emit('token.accounted', {\n ...(sessionId ? { sessionId } : {}),\n usage: this.total(),\n ...(deltaUsage ? { deltaUsage: { ...deltaUsage } } : {}),\n cost: { input: this.costInput, output: this.costOutput, total: this.costInput + this.costOutput },\n ...(providerId ? { provider: providerId } : {}),\n ...(model ? { model } : {}),\n });\n }\n\n private currentSessionId(): string | undefined {\n const value = typeof this.sessionId === 'function' ? this.sessionId() : this.sessionId;\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n }\n\n private currentProviderId(): string | undefined {\n const value = typeof this.providerId === 'function' ? this.providerId() : this.providerId;\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n }\n\n reset(): void {\n this.input = 0;\n this.output = 0;\n this.cacheRead = 0;\n this.cacheWrite = 0;\n this.costInput = 0;\n this.costOutput = 0;\n this.cacheSaved = 0;\n this.lastInput = 0;\n this.lastCacheRead = 0;\n this.lastCacheWrite = 0;\n this.emitAccounted(undefined, undefined, undefined, {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n });\n }\n\n private applyPrice(usage: Usage, price: PriceEntry): void {\n if (price.input) this.costInput += (usage.input / 1_000_000) * price.input;\n if (price.output) this.costOutput += (usage.output / 1_000_000) * price.output;\n if (usage.cacheRead && price.cacheRead) {\n this.costInput += (usage.cacheRead / 1_000_000) * price.cacheRead;\n }\n // Gross read savings: what those cached tokens would have cost at the full\n // input rate, minus the discounted cache-read rate actually billed.\n if (usage.cacheRead && price.input !== undefined) {\n this.cacheSaved += (usage.cacheRead / 1_000_000) * (price.input - (price.cacheRead ?? 0));\n }\n const hasCacheWriteSplit = usage.cacheWrite5m !== undefined || usage.cacheWrite1h !== undefined;\n const cacheWrite5m = usage.cacheWrite5m ?? (hasCacheWriteSplit ? 0 : usage.cacheWrite);\n const cacheWrite1h = usage.cacheWrite1h ?? 0;\n if (cacheWrite5m && (price.cacheWrite5m ?? price.cacheWrite)) {\n this.costInput += (cacheWrite5m / 1_000_000) * (price.cacheWrite5m ?? price.cacheWrite ?? 0);\n }\n if (cacheWrite1h && (price.cacheWrite1h ?? price.cacheWrite)) {\n this.costInput += (cacheWrite1h / 1_000_000) * (price.cacheWrite1h ?? price.cacheWrite ?? 0);\n }\n }\n}\n\nfunction priceFromModel(m: ResolvedModel): PriceEntry {\n return {\n input: m.cost?.input,\n output: m.cost?.output,\n cacheRead: m.cost?.cache_read,\n cacheWrite: m.cost?.cache_write,\n cacheWrite5m: m.cost?.cache_write_5m ?? m.cost?.cache_write,\n cacheWrite1h: m.cost?.cache_write_1h ?? (m.cost?.input !== undefined ? m.cost.input * 2 : undefined),\n };\n}\n\nfunction round4(n: number): number {\n return Math.round(n * 10_000) / 10_000;\n}\n", "import type { EventBus } from '../kernel/events.js';\nimport type { Usage } from '../types/provider.js';\n\nexport interface ProviderCacheEntry {\n provider: string;\n input: number;\n cacheRead: number;\n cacheWrite: number;\n /** cacheRead / (cacheRead + input); 0 when nothing cached. */\n hitRatio: number;\n}\n\ninterface Accum {\n input: number;\n cacheRead: number;\n cacheWrite: number;\n}\n\n/**\n * Per-provider prompt-cache accounting for a session. `TokenCounter.cacheStats()`\n * blends every provider into one figure; this splits it so a session that\n * switched providers (fallback, `/model`) can show each provider's real\n * cache-hit ratio.\n *\n * New counters provide an exact per-call `deltaUsage`; older event producers\n * remain compatible through cumulative-snapshot differencing. The explicit\n * delta keeps attribution correct even when asynchronous price lookups settle\n * out of order after a provider switch.\n *\n * **LIFECYCLE WARNING:** The constructor subscribes to `events.on('token.accounted', \u2026)`,\n * creating a permanent listener on the shared EventBus. The **caller MUST invoke\n * `dispose()` on session teardown** (e.g. via the `detachTodosCheckpoint` chain\n * in `packages/cli/src/wiring/session.ts`). Failure to do so leaks the listener\n * across session restarts/resumes \u2014 every constructor invocation after the first\n * adds a permanent listener that accumulates unboundedly.\n */\nexport class ProviderCacheLedger {\n private readonly byProvider = new Map<string, Accum>();\n private last: Accum = { input: 0, cacheRead: 0, cacheWrite: 0 };\n private readonly off: () => void;\n\n constructor(events: EventBus) {\n this.off = events.on(\n 'token.accounted',\n (p: { usage: Usage; deltaUsage?: Usage | undefined; provider?: string | undefined }) => {\n this.record(p.usage, p.provider, p.deltaUsage);\n },\n );\n }\n\n private record(usage: Usage, provider?: string, deltaUsage?: Usage): void {\n const cur: Accum = {\n input: usage.input,\n cacheRead: usage.cacheRead ?? 0,\n cacheWrite: usage.cacheWrite ?? 0,\n };\n // Diff the cumulative snapshot to isolate this request's contribution.\n // Guard against non-monotonic input (a counter reset): treat a decrease as\n // a fresh baseline rather than a negative delta.\n const delta: Accum = deltaUsage\n ? {\n input: deltaUsage.input,\n cacheRead: deltaUsage.cacheRead ?? 0,\n cacheWrite: deltaUsage.cacheWrite ?? 0,\n }\n : {\n input: Math.max(0, cur.input - this.last.input),\n cacheRead: Math.max(0, cur.cacheRead - this.last.cacheRead),\n cacheWrite: Math.max(0, cur.cacheWrite - this.last.cacheWrite),\n };\n this.last = cur;\n\n const key = provider ?? 'unknown';\n const acc = this.byProvider.get(key) ?? { input: 0, cacheRead: 0, cacheWrite: 0 };\n acc.input += delta.input;\n acc.cacheRead += delta.cacheRead;\n acc.cacheWrite += delta.cacheWrite;\n this.byProvider.set(key, acc);\n }\n\n /** Distinct providers seen this session. */\n providers(): string[] {\n return [...this.byProvider.keys()];\n }\n\n /** Per-provider cache stats, most-cached first. */\n perProvider(): ProviderCacheEntry[] {\n const out: ProviderCacheEntry[] = [];\n for (const [provider, a] of this.byProvider) {\n const denom = a.cacheRead + a.input;\n out.push({\n provider,\n input: a.input,\n cacheRead: a.cacheRead,\n cacheWrite: a.cacheWrite,\n hitRatio: denom === 0 ? 0 : a.cacheRead / denom,\n });\n }\n return out.sort((x, y) => y.cacheRead - x.cacheRead);\n }\n\n /**\n * Unsubscribe from the event bus and release the per-session listener.\n *\n * **The caller MUST invoke `dispose()` on session teardown** \u2014 see the\n * constructor's lifecycle warning. Failure to call this method leaves a\n * permanent `token.accounted` listener on the shared EventBus that\n * accumulates unboundedly across session restarts/resumes.\n */\n dispose(): void {\n this.off();\n }\n}\n", "import type { MCPServerConfig } from '../types/config.js';\n\n/**\n * Built-in MCP server presets available to all WrongStack users out of the box.\n * These servers must be explicitly enabled in config (disabled by default).\n *\n * To enable: set `mcpServers: { serverName: { enabled: true } }` in your config.\n *\n * Some servers require environment variables or additional config \u2014 see notes below.\n *\n * Transport types:\n * stdio \u2014 spawns a local npm package binary via child_process\n * sse \u2014 HTTP SSE endpoint (client POSTs requests)\n * streamable-http \u2014 session-based HTTP with NDJSON responses\n */\n\n/** Filesystem access: read, write, list, search, tree. Good for exploring projects. */\nexport const filesystemServer = (): MCPServerConfig => ({\n name: 'filesystem',\n description: 'Read, write, and navigate the local filesystem (read-heavy tools)',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-filesystem', '.'],\n permission: 'confirm',\n});\n\n/** GitHub API: issues, PRs, repos, search, file operations. Requires GITHUB_PERSONAL_ACCESS_TOKEN. */\nexport const githubServer = (): MCPServerConfig => ({\n name: 'github',\n description:\n 'GitHub API \u2014 issues, PRs, repos, search, file ops (requires GITHUB_PERSONAL_ACCESS_TOKEN)',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-github'],\n passthroughEnv: ['GITHUB_PERSONAL_ACCESS_TOKEN', 'GITHUB_TOKEN'],\n permission: 'confirm',\n});\n\n/**\n * Context7 \u2014 codebase-aware documentation and Q&A using context from your code.\n * Live documentation for any library, grounded in your actual versions.\n */\nexport const context7Server = (): MCPServerConfig => ({\n name: 'context7',\n description: 'Codebase-aware documentation and Q&A (context7.ai)',\n transport: 'streamable-http',\n url: 'https://mcp.context7.com/mcp',\n permission: 'confirm',\n});\n\n/**\n * Brave Search \u2014 web search via Brave Browser's API.\n * Requires BRAVE_SEARCH_API_KEY. Free tier: 2,000 queries/month.\n * Sign up at https://api.search.brave.com/\n */\nexport const braveSearchServer = (): MCPServerConfig => ({\n name: 'brave-search',\n description: 'Web search (Brave). Requires BRAVE_SEARCH_API_KEY \u2014 free tier 2k queries/month',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-brave-search'],\n passthroughEnv: ['BRAVE_SEARCH_API_KEY'],\n permission: 'confirm',\n});\n\n/**\n * Block (Block, Inc.) \u2014 Postgres database access via SQL.\n * Useful for running queries against a connected database during development.\n */\nexport const blockServer = (): MCPServerConfig => ({\n name: 'block',\n description: 'Postgres database access via SQL (Block MCP server)',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-block'],\n permission: 'confirm',\n});\n\n/**\n * EverArt \u2014 AI image generation via various providers.\n * Requires EVERART_API_KEY.\n */\nexport const everArtServer = (): MCPServerConfig => ({\n name: 'everart',\n description: 'AI image generation (EverArt). Requires EVERART_API_KEY',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-everart'],\n passthroughEnv: ['EVERART_API_KEY'],\n permission: 'confirm',\n});\n\n/**\n * Slack \u2014 messaging, channels, search.\n * Requires SLACK_BOT_TOKEN and either SLACK_TEAM_ID or SLACK_USER_TOKEN.\n */\nexport const slackServer = (): MCPServerConfig => ({\n name: 'slack',\n description: 'Slack \u2014 messaging, channels, search. Requires SLACK_BOT_TOKEN + SLACK_TEAM_ID',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-slack'],\n passthroughEnv: ['SLACK_BOT_TOKEN', 'SLACK_TEAM_ID'],\n permission: 'confirm',\n});\n\n/**\n * AWS knowledge base \u2014 EC2, S3, Lambda, IAM, CloudFormation, cost management.\n * Requires AWS access key + secret in environment.\n */\nexport const awsServer = (): MCPServerConfig => ({\n name: 'aws',\n description: 'AWS \u2014 EC2, S3, Lambda, IAM, CloudFormation, costs. Requires AWS credentials',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-aws'],\n passthroughEnv: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_REGION', 'AWS_SESSION_TOKEN'],\n permission: 'confirm',\n});\n\n/**\n * Google Maps \u2014 directions, distance matrix, geocoding, places.\n * Requires GOOGLE_MAPS_API_KEY.\n */\nexport const googleMapsServer = (): MCPServerConfig => ({\n name: 'google-maps',\n description: 'Google Maps \u2014 directions, geocoding, places. Requires GOOGLE_MAPS_API_KEY',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-google-maps'],\n passthroughEnv: ['GOOGLE_MAPS_API_KEY'],\n permission: 'confirm',\n});\n\n/** Sentinel \u2014 security vulnerability scanning (sentinel-labs). */\nexport const sentinelServer = (): MCPServerConfig => ({\n name: 'sentinel',\n description: 'Security vulnerability scanning (Sentinel)',\n transport: 'streamable-http',\n url: 'https://mcp.sentinel.ai',\n permission: 'deny', // security tool \u2014 require explicit confirmation\n});\n\n/**\n * Z.AI Vision MCP \u2014 image understanding fallback for text-only models.\n * Requires Z_AI_API_KEY. Tools are read-only and safe to run automatically.\n */\nexport const zaiVisionServer = (): MCPServerConfig => ({\n name: 'zai-vision',\n description: 'Z.AI Vision MCP \u2014 image analysis and screenshot understanding',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@z_ai/mcp-server@latest'],\n env: { Z_AI_MODE: 'ZAI' },\n passthroughEnv: ['Z_AI_API_KEY'],\n allowedTools: [\n 'image_analysis',\n 'extract_text_from_screenshot',\n 'diagnose_error_screenshot',\n 'understand_technical_diagram',\n 'analyze_data_visualization',\n 'ui_diff_check',\n ],\n permission: 'auto',\n});\n\n/**\n * Playwright \u2014 browser automation: navigate, click, type, screenshot, evaluate JS.\n * Spawns a headless Chromium browser via @modelcontextprotocol/server-playwright.\n * Tools can read and interact with live web pages \u2014 permission defaults to\n * `confirm` because form submission / DOM mutation is possible.\n */\nexport const playwrightServer = (): MCPServerConfig => ({\n name: 'playwright',\n description:\n 'Browser automation \u2014 navigate, screenshot, click, type, evaluate JS (headless Chromium)',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-playwright'],\n permission: 'confirm',\n});\n\n/**\n * MiniMax Token Plan MCP \u2014 search + understand_image.\n * This preset exposes only the read-only image understanding tool by default.\n * Requires MINIMAX_API_KEY and uvx on PATH.\n */\nexport const miniMaxVisionServer = (): MCPServerConfig => ({\n name: 'minimax-vision',\n description: 'MiniMax MCP \u2014 image understanding via understand_image',\n transport: 'stdio',\n command: 'uvx',\n args: ['minimax-coding-plan-mcp', '-y'],\n env: {\n MINIMAX_MCP_BASE_PATH: './.wrongstack/minimax-output',\n MINIMAX_API_HOST: 'https://api.minimax.io',\n MINIMAX_API_RESOURCE_MODE: 'url',\n },\n passthroughEnv: ['MINIMAX_API_KEY'],\n allowedTools: ['understand_image'],\n permission: 'auto',\n});\n\n/**\n * SSH Manager \u2014 remote SSH execution, file transfer, tunnels, health checks, and deployment ops.\n * Server credentials are intentionally NOT embedded here. Configure hosts via mcp-ssh-manager's\n * env/TOML config (for example SSH_SERVER_<NAME>_HOST, USER, KEYPATH/PASSWORD) or ssh-agent.\n */\nexport const sshManagerServer = (): MCPServerConfig => ({\n name: 'ssh',\n description:\n 'Remote SSH management \u2014 execute commands, transfer files, tunnels, health checks (mcp-ssh-manager)',\n transport: 'stdio',\n command: 'npx',\n args: ['-y', 'mcp-ssh-manager'],\n env: {\n MCP_SSH_COMPACT_JSON: 'true',\n MCP_SSH_DEFAULT_TIMEOUT: '120000',\n },\n permission: 'confirm',\n requestTimeoutMs: 180_000,\n});\n\n/** Everything bundled \u2014 full set of built-in servers. Useful for `wstack mcp add --all`. */\nexport const allServers = (): Record<string, MCPServerConfig> => ({\n filesystem: { ...filesystemServer(), enabled: false },\n github: { ...githubServer(), enabled: false },\n context7: { ...context7Server(), enabled: false },\n 'brave-search': { ...braveSearchServer(), enabled: false },\n block: { ...blockServer(), enabled: false },\n everart: { ...everArtServer(), enabled: false },\n slack: { ...slackServer(), enabled: false },\n aws: { ...awsServer(), enabled: false },\n 'google-maps': { ...googleMapsServer(), enabled: false },\n sentinel: { ...sentinelServer(), enabled: false },\n 'zai-vision': { ...zaiVisionServer(), enabled: false },\n 'minimax-vision': { ...miniMaxVisionServer(), enabled: false },\n playwright: { ...playwrightServer(), enabled: false },\n ssh: { ...sshManagerServer(), enabled: false },\n});\n", "/** Assert a value is neither null nor undefined. Throws if it is.\n * Useful after optional chaining and indexed access when the\n * control flow guarantees the value exists but TypeScript can't\n * prove it (e.g. after a check on a related field). */\nexport function expectDefined<T>(value: T | null | undefined, label?: string): T {\n if (value === null || value === undefined) {\n const err = new Error(label ? `Expected ${label} to be defined` : 'Expected value to be defined');\n err.name = 'ExpectDefinedError';\n throw err;\n }\n return value;\n}\n", "import type { ContentBlock, ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Message } from '../types/messages.js';\nimport { expectDefined } from './expect-defined.js';\nexport interface MessageRepairReport {\n changed: boolean;\n removedToolUses: string[];\n removedToolResults: string[];\n removedMessages: number;\n}\n\nexport interface MessageRepairResult {\n messages: Message[];\n report: MessageRepairReport;\n}\n\n/**\n * Repair provider-level tool-call adjacency invariants.\n *\n * Anthropic requires every assistant `tool_use` block to have a matching\n * `tool_result` block in the immediately following user message. Manual\n * context surgery (summary/prune) can cut through the middle of such an\n * exchange. This function removes only the now-orphaned protocol blocks,\n * preserving surrounding text/images/thinking blocks where possible.\n */\nexport function repairToolUseAdjacency(messages: Message[]): MessageRepairResult {\n const removedToolUses: string[] = [];\n const removedToolResults: string[] = [];\n let removedMessages = 0;\n let changed = false;\n const out: Message[] = [];\n\n for (let i = 0; i < messages.length; i++) {\n const original = expectDefined(messages[i]);\n let msg = original;\n\n if (hasToolUse(msg)) {\n const nextIds = toolResultIds(messages[i + 1]);\n const filtered = mapContent(msg, (blocks) => {\n const next: ContentBlock[] = [];\n for (const block of blocks) {\n if (block.type === 'tool_use' && !nextIds.has(block.id)) {\n removedToolUses.push(block.id);\n changed = true;\n continue;\n }\n next.push(block);\n }\n return next;\n });\n msg = filtered ?? msg;\n }\n\n if (hasToolResult(msg)) {\n const allowed = toolUseIds(out[out.length - 1]);\n const filtered = mapContent(msg, (blocks) => {\n const next: ContentBlock[] = [];\n for (const block of blocks) {\n if (block.type === 'tool_result' && !allowed.has(block.tool_use_id)) {\n removedToolResults.push(block.tool_use_id);\n changed = true;\n continue;\n }\n next.push(block);\n }\n return next;\n });\n msg = filtered ?? msg;\n }\n\n if (isEmptyMessage(msg)) {\n removedMessages++;\n changed = true;\n continue;\n }\n out.push(msg);\n }\n\n return {\n messages: changed ? out : messages,\n report: { changed, removedToolUses, removedToolResults, removedMessages },\n };\n}\n\nfunction hasToolUse(msg: Message | undefined): boolean {\n return contentBlocks(msg).some((b): b is ToolUseBlock => b.type === 'tool_use');\n}\n\nfunction hasToolResult(msg: Message | undefined): boolean {\n return contentBlocks(msg).some((b): b is ToolResultBlock => b.type === 'tool_result');\n}\n\nfunction toolUseIds(msg: Message | undefined): Set<string> {\n const ids = new Set<string>();\n if (msg?.role !== 'assistant') return ids;\n for (const block of contentBlocks(msg)) {\n if (block.type === 'tool_use') ids.add(block.id);\n }\n return ids;\n}\n\nfunction toolResultIds(msg: Message | undefined): Set<string> {\n const ids = new Set<string>();\n if (msg?.role !== 'user') return ids;\n for (const block of contentBlocks(msg)) {\n if (block.type === 'tool_result') ids.add(block.tool_use_id);\n }\n return ids;\n}\n\nfunction contentBlocks(msg: Message | undefined): ContentBlock[] {\n return msg && Array.isArray(msg.content) ? msg.content : [];\n}\n\nfunction mapContent(msg: Message, fn: (blocks: ContentBlock[]) => ContentBlock[]): Message | null {\n if (!Array.isArray(msg.content)) return msg;\n const next = fn(msg.content);\n if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {\n return msg;\n }\n return { ...msg, content: next };\n}\n\n/**\n * True when a message content payload carries meaningful information for\n * the provider: non-whitespace text, a tool call/result, thinking with\n * text or a signature, or any other block type.\n *\n * False for empty strings/arrays and for arrays whose only blocks are\n * empty or whitespace-only text \u2014 the shape persisted when a stream is\n * interrupted before the first meaningful delta (issue #271). Strict\n * providers reject such assistant turns, so repair and replay paths must\n * treat them as empty.\n */\nexport function hasMeaningfulContent(content: Message['content']): boolean {\n if (typeof content === 'string') return content.trim().length > 0;\n for (const block of content) {\n if (block.type === 'text') {\n if (block.text.trim().length > 0) return true;\n continue;\n }\n if (block.type === 'thinking') {\n // Signature-only thinking blocks are valid and required for replay;\n // blocks with neither text nor signature are provider-rejected noise.\n if (block.thinking.trim().length > 0 || block.signature) return true;\n continue;\n }\n // tool_use, tool_result, image, redacted_thinking, \u2026 \u2014 always meaningful.\n return true;\n }\n return false;\n}\n\nfunction isEmptyMessage(msg: Message): boolean {\n return !hasMeaningfulContent(msg.content);\n}\n", "import type { JSONSchema } from '../types/tool.js';\n\nexport interface ToolWireDefinitionLike {\n name: string;\n description?: string | undefined;\n inputSchema: unknown;\n}\n\nexport interface CompactToolDefinitionForWireOptions {\n /** Top-level tool description budget. */\n descriptionMaxChars?: number | undefined;\n /** Per-JSON-Schema `description` annotation budget. */\n schemaDescriptionMaxChars?: number | undefined;\n}\n\nexport interface CompactWireToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\nconst TOOL_DESCRIPTION_MAX_CHARS = 400;\nconst SCHEMA_DESCRIPTION_MAX_CHARS = 120;\n\nconst compactCache = new WeakMap<object, CompactWireToolDefinition>();\n\n/**\n * Return the provider-wire version of a tool definition.\n *\n * Tool schemas remain structurally intact: validation keywords, property\n * names, required fields, enum values, and nested shapes are preserved. The\n * only reduction is on human prose annotations (`description`), which are the\n * largest repeated cost in provider tool declarations.\n */\nexport function compactToolDefinitionForWire(\n tool: ToolWireDefinitionLike,\n opts: CompactToolDefinitionForWireOptions = {},\n): CompactWireToolDefinition {\n const useDefaultOptions =\n opts.descriptionMaxChars === undefined && opts.schemaDescriptionMaxChars === undefined;\n if (useDefaultOptions && typeof tool === 'object' && tool !== null) {\n const cached = compactCache.get(tool);\n if (cached) return cached;\n }\n\n const compact: CompactWireToolDefinition = {\n name: tool.name,\n description: compactDescription(\n tool.description ?? '',\n opts.descriptionMaxChars ?? TOOL_DESCRIPTION_MAX_CHARS,\n ),\n inputSchema: normalizeTopLevelToolSchema(\n compactSchemaDescriptions(\n tool.inputSchema,\n opts.schemaDescriptionMaxChars ?? SCHEMA_DESCRIPTION_MAX_CHARS,\n ),\n ),\n };\n\n if (useDefaultOptions && typeof tool === 'object' && tool !== null) {\n compactCache.set(tool, compact);\n }\n return compact;\n}\n\n/**\n * Tool inputs are always JSON objects, but dynamically supplied MCP/plugin\n * schemas sometimes express that object as a top-level oneOf/anyOf/allOf.\n * Anthropic-family endpoints reject those combinators at the input_schema\n * root (including when reached through an OpenAI-compatible gateway such as\n * OmniRoute). Keep nested combinators intact and flatten only the root.\n * Runtime validation still uses the tool's original schema.\n */\nexport function normalizeTopLevelToolSchema(\n schema: Record<string, unknown>,\n): Record<string, unknown> {\n const combinators = (['oneOf', 'anyOf', 'allOf'] as const)\n .map((keyword) => ({ keyword, branches: schema[keyword] }))\n .filter((entry): entry is { keyword: 'oneOf' | 'anyOf' | 'allOf'; branches: unknown[] } =>\n Array.isArray(entry.branches),\n );\n if (combinators.length === 0) return schema;\n\n const out: Record<string, unknown> = { ...schema, type: 'object' };\n delete out['oneOf'];\n delete out['anyOf'];\n delete out['allOf'];\n\n const properties: Record<string, unknown> = isRecord(schema['properties'])\n ? { ...schema['properties'] }\n : {};\n let required = stringSet(schema['required']);\n\n for (const { keyword, branches } of combinators) {\n const objectBranches = branches.filter(isRecord);\n for (const branch of objectBranches) {\n if (isRecord(branch['properties'])) Object.assign(properties, branch['properties']);\n }\n\n const branchRequired = objectBranches.map((branch) => stringSet(branch['required']));\n if (keyword === 'allOf') {\n for (const fields of branchRequired) for (const field of fields) required.add(field);\n } else if (branchRequired.length > 0) {\n const common = new Set(\n [...branchRequired[0]!].filter((field) =>\n branchRequired.slice(1).every((fields) => fields.has(field)),\n ),\n );\n required = new Set([...required, ...common]);\n }\n }\n\n out['properties'] = properties;\n if (required.size > 0) out['required'] = [...required];\n else delete out['required'];\n return out;\n}\n\nfunction stringSet(value: unknown): Set<string> {\n return new Set(\n Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : [],\n );\n}\n\nexport function compactSchemaDescriptions(\n schema: unknown,\n maxDescriptionChars = SCHEMA_DESCRIPTION_MAX_CHARS,\n): Record<string, unknown> {\n const compact = compactSchemaNode(schema, maxDescriptionChars);\n return isRecord(compact) ? compact : { type: 'object', properties: {} };\n}\n\nfunction compactSchemaNode(node: unknown, maxDescriptionChars: number): unknown {\n if (Array.isArray(node)) {\n return node.map((item) => compactSchemaNode(item, maxDescriptionChars));\n }\n if (!isRecord(node)) return node;\n\n const out: JSONSchema = {};\n for (const [key, value] of Object.entries(node)) {\n if (key === 'description' && typeof value === 'string') {\n out[key] = compactDescription(value, maxDescriptionChars);\n } else {\n out[key] = compactSchemaNode(value, maxDescriptionChars);\n }\n }\n return out;\n}\n\nexport function compactDescription(text: string, maxChars: number): string {\n const normalized = text.replace(/\\s+/g, ' ').trim();\n if (normalized.length <= maxChars) return normalized;\n if (maxChars <= 20) return normalized.slice(0, maxChars);\n\n const hardLimit = maxChars - 12;\n const boundary = findSemanticBoundary(normalized, hardLimit);\n const head = normalized.slice(0, boundary > 0 ? boundary : hardLimit).trimEnd();\n return `${head} ...`;\n}\n\nexport function findSemanticBoundary(text: string, limit: number): number {\n const punctuation = Math.max(\n text.lastIndexOf('. ', limit),\n text.lastIndexOf('; ', limit),\n text.lastIndexOf(': ', limit),\n );\n if (punctuation >= Math.floor(limit * 0.45)) return punctuation + 1;\n\n const comma = text.lastIndexOf(', ', limit);\n if (comma >= Math.floor(limit * 0.6)) return comma + 1;\n\n const space = text.lastIndexOf(' ', limit);\n return space >= Math.floor(limit * 0.6) ? space : limit;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n", "import type { Message } from '../types/messages.js';\nimport { compactToolDefinitionForWire } from './tool-wire-compact.js';\n\n/**\n * Shared token estimation with JSON.stringify caching.\n * Avoids repeated stringification of tool input objects.\n *\n * ## Calibration\n *\n * `estimateRequestTokens` uses a fixed 3.5 chars/token heuristic \u2014 a\n * conservative overestimate that prevents underestimation but reduces\n * accuracy. After each API call, call `recordActualUsage()` with the\n * provider-authoritative effective prompt tokens (`input + cacheRead +\n * cacheWrite` after adapter normalization). The module maintains a rolling\n * average of `actual / estimated` ratio (EWM, \u03B1=0.3) and applies it to\n * subsequent calls via `estimateRequestTokensCalibrated`.\n *\n * Calibration is per-module (shared across all callers), which is\n * sufficient: the chars/token ratio is a property of the tokenizer,\n * not the model. Uncalibrated calls (before any samples, or when\n * `recordActualUsage` is not called) fall back to the uncalibrated\n * estimate so nothing breaks.\n */\n\nconst RoughTokenEstimate = (text: string, charsPerToken = 3.5): number =>\n Math.max(1, Math.ceil(text.length / charsPerToken));\n\n/** Calibration state: actual/estimated ratio via exponential weighted moving average. */\ninterface CalState {\n ratio: number; // current calibration multiplier (actual / estimated)\n count: number; // number of samples recorded\n prevEst: number; // estimated tokens from the most recent estimateRequestTokens call\n}\n\n/** EWM \u03B1 \u2014 higher = faster adaptation, more volatile. */\nconst CAL_ALPHA = 0.3;\n\n/**\n * Calibration is keyed so that, in a multi-agent / model-switching process,\n * each (provider, model) tokenizer gets its own ratio instead of all of them\n * collapsing onto one shared number. Callers that don't pass a key use the\n * shared `__global__` bucket \u2014 that preserves the original single-session\n * behavior and keeps all existing call sites working unchanged.\n */\nconst CALIBRATION_GLOBAL_KEY = '__global__';\nconst _cals = new Map<string, CalState>();\n\nfunction calState(key: string): CalState {\n let state = _cals.get(key);\n if (!state) {\n state = { ratio: 1.0, count: 0, prevEst: 0 };\n _cals.set(key, state);\n }\n return state;\n}\n\nconst MIN_SAMPLES_FOR_CALIBRATION = 3;\n\n/**\n * Fallback chars/token ratios per model family for providers that don't return\n * usage data. Used when `recordActualUsage` receives zero/negative tokens and\n * we have enough samples to trust the fallback. Keys are lowercase prefixes.\n */\nconst MODEL_FAMILY_RATIO: Record<string, number> = {\n // Anthropic: ~3.8-4.0 chars/token depending on model\n claude: 3.8,\n // OpenAI: ~4.0 chars/token\n 'gpt-4': 4.0,\n 'gpt-3.5': 4.0,\n // Google: ~3.5 chars/token\n gemini: 3.5,\n // DeepSeek: ~3.5 chars/token\n deepseek: 3.5,\n};\n\n/**\n * Cache of computed estimates keyed by a compact HASH of the stringified input \u2014\n * NOT the stringified input itself. The estimator is called per tool_use and per\n * tool_result on every context-window check, and the source strings are full tool\n * payloads (file reads, command output). Keying the Map by those strings meant the\n * cache retained up to 50 000 full payloads \u2014 hundreds of MB \u2014 for a value that is\n * a single number. We now key by `\"<len>:<djb2>\"` (\u224815 chars) and never retain the\n * payload. A hash collision (same length AND djb2) at worst returns a slightly-off\n * heuristic token estimate, which only nudges compaction timing \u2014 never correctness.\n */\nconst ESTIMATE_CACHE = new Map<string, number>();\n/** Insertion-order queue for O(1) LRU eviction: shift from front on overcapacity. */\nconst _estimateCacheOrder: string[] = [];\n\nconst ESTIMATE_CACHE_MAX_SIZE = 50_000;\n\n/** Compact collision-resistant key: length prefix + 32-bit DJB2 of the source. */\nfunction estimateCacheKey(source: string): string {\n let h = 5381;\n for (let i = 0; i < source.length; i++) {\n h = ((h << 5) + h + source.charCodeAt(i)) | 0;\n }\n return `${source.length}:${h >>> 0}`;\n}\n\nfunction getCachedEstimate(source: string, compute: (source: string) => number): number {\n const key = estimateCacheKey(source);\n const existing = ESTIMATE_CACHE.get(key);\n if (existing !== undefined) return existing;\n if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {\n // Evict oldest half \u2014 O(1) per eviction (array shift + Map.delete) instead\n // of O(n) iteration over all 50 000 keys in the Map.\n while (ESTIMATE_CACHE.size > Math.floor(ESTIMATE_CACHE_MAX_SIZE / 2)) {\n const oldest = _estimateCacheOrder.shift();\n if (oldest !== undefined) ESTIMATE_CACHE.delete(oldest);\n }\n }\n // Compute on the full source (never retained); only the hash key + number stay.\n const estimate = compute(source);\n ESTIMATE_CACHE.set(key, estimate);\n _estimateCacheOrder.push(key);\n return estimate;\n}\n\n/**\n * Estimate tokens for a tool_use block input.\n * Caches the stringified result keyed by the stable string representation\n * to avoid repeated JSON.stringify calls during context window checks.\n */\nexport function estimateToolInputTokens(input: unknown): number {\n if (typeof input === 'string') return RoughTokenEstimate(input);\n if (input === null || typeof input !== 'object') {\n return RoughTokenEstimate(String(input));\n }\n // JSON.stringify is called once to form the cache key; RoughTokenEstimate\n // is deferred only on cache miss (compute callback), not wrapped unnecessarily.\n return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));\n}\n\n/**\n * Estimate tokens for a tool_result content.\n */\nexport function estimateToolResultTokens(content: string | unknown): number {\n if (typeof content === 'string') return RoughTokenEstimate(content);\n return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));\n}\n\n/**\n * Estimate tokens for a text block.\n */\nexport function estimateTextTokens(text: string): number {\n return RoughTokenEstimate(text);\n}\n\n/**\n * Compute and cache the token estimate for a single message. This is the\n * canonical per-message estimator \u2014 called once by ConversationState on\n * append/replace so the O(n\u00B7m) content-block walk happens at mutation time,\n * not on every context-pressure check.\n */\nexport function computeMessageTokens(msg: Message): number {\n if (typeof msg.content === 'string') return estimateTextTokens(msg.content);\n let total = 0;\n for (const b of msg.content) {\n if (b.type === 'text') total += estimateTextTokens(b.text);\n else if (b.type === 'tool_use') total += estimateToolInputTokens(b.input);\n else if (b.type === 'tool_result') total += estimateToolResultTokens(b.content);\n else total += RoughTokenEstimate(JSON.stringify(b));\n }\n return total;\n}\n\n/**\n * Estimate tokens for an array of messages (text + tool I/O), using the shared\n * 3.5 chars/token basis. This is the single canonical message-array estimator \u2014\n * compactors, the context_manager tool, and the `/context` display all route\n * through it so the number a user sees matches the number compaction decides on.\n *\n * When a message carries a pre-computed `_estTokens` field (set by\n * ConversationState on append/replace), it is used directly instead of\n * re-walking the content blocks \u2014 turning the O(n\u00B7m) scan into an O(n)\n * sum for fully-cached arrays.\n */\nexport function estimateMessageTokens(messages: readonly Message[]): number {\n let total = 0;\n for (const m of messages) {\n if (typeof m._estTokens === 'number' && m._estTokens > 0) {\n total += m._estTokens;\n continue;\n }\n total += computeMessageTokens(m);\n }\n return total;\n}\n\n/**\n * Real-usage-anchored input-token count. Given the provider's authoritative\n * prompt-token count from the last response (`anchorTokens`, a REAL number) and\n * the `messages.length` of the request that produced it (`anchorMsgCount`),\n * returns `anchorTokens + estimate(messages appended since)` \u2014 so everything up\n * to the last turn is exact and only the newest, not-yet-sent messages are\n * estimated. This is deliberately NOT calibrated: the base is already real, and\n * on the next response the whole thing re-anchors to the new real count.\n *\n * Returns `null` when there is no usable anchor (no response yet, or the\n * message array shrank below the anchor \u2014 e.g. after compaction \u2014 in which case\n * the caller falls back to a full estimate until the next response re-anchors).\n */\nexport function realAnchoredInputTokens(\n messages: readonly Message[],\n anchorTokens: number | undefined,\n anchorMsgCount: number | undefined,\n): number | null {\n if (typeof anchorTokens !== 'number' || anchorTokens <= 0) return null;\n if (typeof anchorMsgCount !== 'number' || anchorMsgCount < 0) return null;\n if (messages.length < anchorMsgCount) return null;\n const delta = anchorMsgCount === messages.length ? 0 : estimateMessageTokens(messages.slice(anchorMsgCount));\n return anchorTokens + delta;\n}\n\n/**\n * Rough estimate of tokens in a tool definition (name + description + schema).\n * Accounts for the JSON-serialized inputSchema which is sent to the API\n * but NOT included in roughEstimate(content).\n */\nexport function estimateToolDefTokens(tool: {\n name: string;\n description?: string | undefined;\n inputSchema: unknown;\n}): number {\n // Fast path: pre-computed by ToolRegistry at registration time.\n const cached = (tool as { _estDefTokens?: number | undefined })._estDefTokens;\n if (typeof cached === 'number' && cached > 0) return cached;\n\n const compact = compactToolDefinitionForWire(tool);\n return (\n RoughTokenEstimate(tool.name) +\n RoughTokenEstimate(compact.description) +\n RoughTokenEstimate(JSON.stringify(compact.inputSchema))\n );\n}\n\n/**\n * Estimate the total API request token count: system prompt + tool definitions\n * + conversation messages. Use this for context-window bar calculations\n * instead of roughEstimate (which only counts messages).\n *\n * The overhead ratio (overhead / messages) varies by conversation length:\n * - Short conversations (< 10 messages): ~30-50% overhead (large system+tools)\n * - Medium (10-50 messages): ~15-30%\n * - Long (> 50 messages): ~5-15%\n *\n * Returns { messages, systemPrompt, tools, total } for debugging display.\n */\nexport interface RequestTokenBreakdown {\n messages: number;\n systemPrompt: number;\n tools: number;\n total: number;\n}\n\nexport function estimateRequestTokens(\n messages: unknown,\n systemPrompt: unknown,\n tools: { name: string; description?: string | undefined; inputSchema: unknown }[],\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): RequestTokenBreakdown {\n // Messages: apply the same logic as roughEstimate\n let messagesTokens = 0;\n if (typeof messages === 'string') {\n messagesTokens = RoughTokenEstimate(messages);\n } else if (Array.isArray(messages)) {\n for (const m of messages) {\n if (typeof m === 'object' && m !== null && 'content' in m) {\n // Fast path: pre-computed per-message token estimate (set by\n // ConversationState on append/replace). Skips the O(m) content-block\n // walk entirely for cached messages.\n const cached = (m as { _estTokens?: number | undefined })._estTokens;\n if (typeof cached === 'number' && cached > 0) {\n messagesTokens += cached;\n continue;\n }\n const content = (m as { content: unknown }).content;\n if (typeof content === 'string') {\n messagesTokens += RoughTokenEstimate(content);\n } else if (Array.isArray(content)) {\n for (const b of content) {\n if (typeof b === 'object' && b !== null) {\n if ((b as { type?: string | undefined }).type === 'text') {\n messagesTokens += RoughTokenEstimate((b as { text: string }).text);\n } else {\n messagesTokens += RoughTokenEstimate(JSON.stringify(b));\n }\n }\n }\n }\n }\n }\n }\n\n // System prompt\n let systemTokens = 0;\n if (typeof systemPrompt === 'string') {\n systemTokens = RoughTokenEstimate(systemPrompt);\n } else if (Array.isArray(systemPrompt)) {\n for (const b of systemPrompt) {\n if (\n typeof b === 'object' &&\n b !== null &&\n (b as { type?: string | undefined }).type === 'text'\n ) {\n systemTokens += RoughTokenEstimate((b as { text: string }).text);\n }\n }\n }\n\n // Tool definitions\n let toolsTokens = 0;\n for (const t of tools) {\n toolsTokens += estimateToolDefTokens(t);\n }\n\n const total = messagesTokens + systemTokens + toolsTokens;\n\n // Record the raw estimate for calibration: the next recordActualUsage()\n // call will pair this against the actual API usage so the rolling ratio\n // stays in sync with the real chars/token ratio of the content.\n calState(calibrationKey).prevEst = total;\n\n return {\n messages: messagesTokens,\n systemPrompt: systemTokens,\n tools: toolsTokens,\n total,\n };\n}\n\n/**\n * Record the actual API input token count after a provider call so\n * `estimateRequestTokensCalibrated` can self-correct on subsequent calls.\n *\n * Prefer passing `estimatedInputTokens` explicitly (the calibrated pre-flight\n * estimate from the middleware) \u2014 this avoids race conditions when other code\n * also calls `estimateRequestTokens` between the pre-flight and this call\n * (e.g. audit logging in agent.ts).\n *\n * When `estimatedInputTokens` is omitted, falls back to the keyed bucket's\n * `prevEst` for backward compatibility with callers that don't have the\n * pre-flight value. `calibrationKey` selects the per-(provider,model) bucket\n * (defaults to the shared global bucket).\n */\nexport function recordActualUsage(\n actualInputTokens: number,\n estimatedInputTokens?: number,\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): void {\n if (actualInputTokens <= 0) return;\n const cal = calState(calibrationKey);\n const est = estimatedInputTokens ?? cal.prevEst;\n if (est <= 0) return;\n\n const sampleRatio = actualInputTokens / est;\n if (cal.count === 0) {\n cal.ratio = sampleRatio;\n } else {\n // EWM: new = \u03B1 * sample + (1-\u03B1) * old \u2192 \u03B1=0.3 = fast initial converge\n cal.ratio = CAL_ALPHA * sampleRatio + (1 - CAL_ALPHA) * cal.ratio;\n }\n // Sanity bound: keep the rolling ratio within [0.5, 1.5] so a sequence\n // of bad samples can't blow up the calibration for everyone.\n cal.ratio = Math.min(1.5, Math.max(0.5, cal.ratio));\n cal.count++;\n}\n\n/**\n * Returns the current calibration state for a bucket. Exposed for debugging\n * and tests \u2014 not needed by normal callers.\n */\nexport function getCalibrationState(calibrationKey: string = CALIBRATION_GLOBAL_KEY): {\n ratio: number;\n count: number;\n calibrated: boolean;\n} {\n const cal = calState(calibrationKey);\n return {\n ratio: cal.ratio,\n count: cal.count,\n calibrated: cal.count >= MIN_SAMPLES_FOR_CALIBRATION,\n };\n}\n\n/**\n * Like `estimateRequestTokens` but applies the rolling calibration factor\n * so context pressure readings converge on reality within a few iterations.\n *\n * Before any `recordActualUsage` samples are collected, returns the same\n * result as `estimateRequestTokens` (ratio = 1.0, no distortion).\n * After `MIN_SAMPLES_FOR_CALIBRATION` samples, applies the calibrated\n * multiplier capped to the range [0.5, 1.5] as a sanity bound.\n */\nexport function estimateRequestTokensCalibrated(\n messages: unknown,\n systemPrompt: unknown,\n tools: { name: string; description?: string | undefined; inputSchema: unknown }[],\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): RequestTokenBreakdown {\n const result = estimateRequestTokens(messages, systemPrompt, tools, calibrationKey);\n const cal = calState(calibrationKey);\n\n if (cal.count >= MIN_SAMPLES_FOR_CALIBRATION) {\n const safeRatio = Math.min(1.5, Math.max(0.5, cal.ratio));\n return {\n messages: Math.round(result.messages * safeRatio),\n systemPrompt: Math.round(result.systemPrompt * safeRatio),\n tools: Math.round(result.tools * safeRatio),\n total: Math.round(result.total * safeRatio),\n };\n }\n\n // No calibration samples yet \u2014 fall back to model-family ratio if available,\n // otherwise use the uncalibrated estimate (ratio = 1.0).\n const fallbackRatio = getModelFamilyRatio(calibrationKey);\n if (fallbackRatio !== null) {\n return {\n messages: Math.round(result.messages * fallbackRatio),\n systemPrompt: Math.round(result.systemPrompt * fallbackRatio),\n tools: Math.round(result.tools * fallbackRatio),\n total: Math.round(result.total * fallbackRatio),\n };\n }\n\n return result;\n}\n\n/** Per-block sample cap for the density scan \u2014 bounds work on giant blocks. */\nconst DENSITY_SAMPLE_PER_BLOCK = 4_096;\n/** Hard cap on total sampled chars so the density scan stays cheap. */\nconst DENSITY_SAMPLE_TOTAL_CAP = 2_000_000;\n\n/**\n * Estimate a **token-density multiplier** for content that the flat 3.5\n * chars/token basis under-counts. The basis is tuned for ASCII English\n * (~4 chars/token); CJK, and other high-codepoint scripts tokenize at ~1.5-2\n * chars/token, so a message that is mostly CJK carries up to ~2.3\u00D7 the tokens\n * the flat basis predicts. Long unbroken ASCII runs (base64, minified blobs)\n * pack slightly denser too. This scans a bounded sample and returns a\n * multiplier in [1, 2.5] \u2014 always \u2265 1, so it can only push the estimate UP,\n * never down. Used only by the send-time overflow guard, never for display.\n */\nfunction textDensityMultiplier(messages: readonly Message[]): number {\n let sampled = 0;\n let nonAscii = 0;\n let maxRun = 0;\n const consider = (s: string): void => {\n const n = Math.min(s.length, DENSITY_SAMPLE_PER_BLOCK);\n let run = 0;\n for (let i = 0; i < n; i++) {\n const c = s.charCodeAt(i);\n if (c > 127) nonAscii++;\n if (c === 32 || c === 9 || c === 10 || c === 13) {\n if (run > maxRun) maxRun = run;\n run = 0;\n } else {\n run++;\n }\n }\n if (run > maxRun) maxRun = run;\n sampled += n;\n };\n\n for (const m of messages) {\n if (typeof m.content === 'string') {\n consider(m.content);\n } else if (Array.isArray(m.content)) {\n for (const b of m.content) {\n if (b.type === 'text') consider(b.text);\n else if (b.type === 'tool_result' && typeof b.content === 'string') consider(b.content);\n else if (b.type === 'thinking') consider(b.thinking);\n }\n }\n if (sampled >= DENSITY_SAMPLE_TOTAL_CAP) break;\n }\n\n if (sampled === 0) return 1;\n const nonAsciiRatio = nonAscii / sampled;\n // 3.5 chars/token at 0% non-ASCII \u2192 1.5 at 100% (heavy CJK).\n let charsPerToken = 3.5 - 2.0 * nonAsciiRatio;\n // A very long unbroken ASCII run (base64/minified) packs a little denser.\n if (maxRun > 2_000 && nonAsciiRatio < 0.1) charsPerToken = Math.min(charsPerToken, 3.0);\n const multiplier = 3.5 / Math.max(1.4, charsPerToken);\n return Math.min(2.5, Math.max(1, multiplier));\n}\n\n/**\n * Never-undercount upper bound for the request token total, for the **send\n * guard** only. Takes the flat estimate and scales it up by the greater of the\n * content-density multiplier and the calibration ceiling, so the guarded value\n * satisfies `real \u2264 upperBound`. The context bar and `/context` keep using the\n * calibrated estimate \u2014 this deliberately over-counts, which is only ever safe\n * for the \"must this be trimmed before sending?\" decision.\n */\nexport function estimateRequestTokensUpperBound(\n messages: unknown,\n systemPrompt: unknown,\n tools: { name: string; description?: string | undefined; inputSchema: unknown }[],\n calibrationKey: string = CALIBRATION_GLOBAL_KEY,\n): RequestTokenBreakdown {\n const base = estimateRequestTokens(messages, systemPrompt, tools, calibrationKey);\n const density = Array.isArray(messages)\n ? textDensityMultiplier(messages as readonly Message[])\n : 1;\n const cal = calState(calibrationKey);\n const calCeiling =\n cal.count >= MIN_SAMPLES_FOR_CALIBRATION ? Math.min(1.5, Math.max(1, cal.ratio)) : 1;\n const mult = Math.max(density, calCeiling);\n if (mult <= 1) return base;\n return {\n messages: Math.ceil(base.messages * mult),\n systemPrompt: Math.ceil(base.systemPrompt * mult),\n tools: Math.ceil(base.tools * mult),\n total: Math.ceil(base.total * mult),\n };\n}\n\n/** Look up the fallback chars/token ratio for a calibration key (e.g. \"provider/model\"). */\nfunction getModelFamilyRatio(calibrationKey: string): number | null {\n const lower = calibrationKey.toLowerCase();\n for (const [family, ratio] of Object.entries(MODEL_FAMILY_RATIO)) {\n if (lower.includes(family)) return ratio / 3.5; // MODEL_FAMILY_RATIO is chars/token, we need multiplier\n }\n return null;\n}\n\n/**\n * Resets calibration state. Primarily for tests that run in the same\n * process and need a clean slate between suites. With no argument it clears\n * every bucket (including the global one); pass a key to reset just that bucket.\n */\nexport function resetCalibration(calibrationKey?: string): void {\n if (calibrationKey === undefined) {\n _cals.clear();\n return;\n }\n _cals.delete(calibrationKey);\n}\n", "import type { Context } from '../core/context.js';\nimport type { Compactor } from '../types/compactor.js';\nimport type { Message } from '../types/messages.js';\nimport type { Tool } from '../types/tool.js';\nimport { repairToolUseAdjacency } from '../utils/message-invariants.js';\nimport { estimateMessageTokens, estimateRequestTokens } from '../utils/token-estimate.js';\n\n/**\n * Context introspection and management tool.\n * Allows the model to:\n * - \"check\" \u2192 see token budget and message counts\n * - \"summary\" \u2192 summarize and replace a range of messages\n * - \"prune\" \u2192 remove specific message indices\n * - \"add_note\" \u2192 inject a summary note at a specific point\n * - \"compact\" \u2192 run compaction via the injected compactor\n */\nexport const CONTEXT_MANAGER_TOOL_NAME = 'context_manager';\n\nexport type ContextManagerAction =\n | 'check'\n | 'summary'\n | 'prune'\n | 'add_note'\n | 'compact'\n | 'repair';\n\nexport interface ContextManagerInput {\n action: ContextManagerAction;\n /** 0-based message indices for prune/summary (inclusive). */\n from?: number | undefined;\n to?: number | undefined;\n /** Text for add_note / summary actions. For summary, this is the LLM-provided summary text. */\n text?: string | undefined;\n /** Inject after which index (for add_note). Defaults to prepend (0). */\n afterIndex?: number | undefined;\n /**\n * System prompt blocks for accurate total token estimation in check action.\n * When provided, check returns the full API request estimate\n * (messages + system + tools) instead of just message tokens.\n */\n systemPrompt?: unknown | undefined;\n /**\n * Registered tools for accurate total token estimation in check action.\n * Each tool's name + description + inputSchema is counted.\n */\n tools?: { name: string; description?: string | undefined; inputSchema: unknown }[];\n}\n\nexport interface ContextManagerResult {\n action: ContextManagerAction;\n beforeTokens: number;\n afterTokens?: number | undefined;\n removedCount?: number | undefined;\n messageCount: number;\n summary?: string | undefined;\n notes?: string | undefined;\n repaired?: {\n removedToolUses: string[];\n removedToolResults: string[];\n removedMessages: number;\n } | undefined;\n}\n\n/**\n * Options for creating a context manager tool.\n * `compactor` is required for the \"compact\" action; without it the action returns an error.\n */\nexport interface ContextManagerToolOptions {\n compactor?: Compactor | undefined;\n /**\n * Optional sub-LLM summarizer. When provided, the \"summary\" action calls this\n * to produce real summaries of message ranges instead of placeholder text.\n * (signature matches Provider.complete \u2014 return the summary text in result.content[0].text)\n */\n summarizer?: (((messages: Message[]) => Promise<string>)) | undefined;\n /**\n * Minimum full-request token count before the compact action is allowed to run.\n * Prevents unnecessary compaction calls when context is small.\n * Default: 0 (always allow). Set to ~5000 for meaningful compaction targets.\n */\n minCompactThreshold?: number | undefined;\n /**\n * Minimum token growth required before retrying after a NOOP compaction.\n * A NOOP is when compaction saved nothing (preserveK protects everything,\n * no oversized tool_results). Default: 2000.\n */\n noopRetryDeltaTokens?: number | undefined;\n /**\n * Provider's max context window in tokens. Used to compute a relative\n * threshold when `minCompactThreshold` is not set. Default: 128_000.\n */\n maxContext?: number | undefined;\n /**\n * Fraction of maxContext that triggers compaction. Only used when\n * `minCompactThreshold` is not set. Default: 0.5 (50% of maxContext).\n */\n compactThresholdFraction?: number | undefined;\n}\n\n/** Messages-only token estimate. Delegates to the canonical shared estimator\n * so the context_manager tool agrees with compaction and the `/context` bar. */\nfunction roughEstimate(messages: Message[]): number {\n return estimateMessageTokens(messages);\n}\n\nexport function createContextManagerTool(\n opts: ContextManagerToolOptions = {},\n): Tool<ContextManagerInput, ContextManagerResult> {\n const minCompactThreshold = opts.minCompactThreshold ?? 0;\n const noopRetryDeltaTokens = opts.noopRetryDeltaTokens ?? 1_000;\n /** Hard override for maxContext. When absent, the runtime value from ctx.provider is used. */\n const configuredMaxContext = opts.maxContext;\n const compactThresholdFraction = opts.compactThresholdFraction ?? 0.4;\n\n // Tracks the most recent NOOP attempt so we can skip retry until context grows.\n let lastNoopTokens = 0;\n\n return {\n name: CONTEXT_MANAGER_TOOL_NAME,\n description:\n 'Inspect or reorganize the conversation context window. ' +\n 'Use \"check\" to see token budget. ' +\n 'Use \"summary\" to collapse a message range into a concise note (provide \"text\" for custom summary). ' +\n 'Use \"prune\" to remove specific messages by index. ' +\n 'Use \"add_note\" to inject a summary note. ' +\n 'Use \"compact\" to run aggressive compaction. ' +\n 'Use \"repair\" to remove orphan tool_use/tool_result blocks after manual context surgery.',\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['check', 'summary', 'prune', 'add_note', 'compact', 'repair'],\n description: 'The context operation to perform.',\n },\n from: {\n type: 'number',\n description: 'Start index (inclusive) for summary/prune operations.',\n },\n to: {\n type: 'number',\n description: 'End index (inclusive) for summary/prune operations.',\n },\n text: {\n type: 'string',\n description:\n 'Summary or note text. For \"summary\": the model-provided summary of the removed range. ' +\n 'For \"add_note\": the note to inject.',\n },\n afterIndex: {\n type: 'number',\n description: 'Insert after this index (for add_note). Defaults to prepend (0).',\n },\n },\n required: ['action'],\n },\n permission: 'auto',\n // Mutates only the in-memory conversation context, like the todo tool.\n // It must stay auto-runnable so the model can inspect/repair/compact its\n // own context without hitting a permission prompt loop.\n mutating: false,\n\n async execute(input: ContextManagerInput, ctx: Context): Promise<ContextManagerResult> {\n const messages = ctx.messages;\n const beforeTokens = roughEstimate(messages);\n\n // When ctx.state is available, route mutations through the observer\n // layer so subscribers stay in sync. Fall back to direct mutation for\n // tests and environments that haven't wired ConversationState.\n const applyMessages = (next: Message[]) => {\n const repaired = repairToolUseAdjacency(next);\n const finalMessages = repaired.messages;\n // Skip if finalMessages === messages (no-op: repair returned the same array).\n // This also prevents the self-spread bug where spreading an array into\n // splice(0, 0, ...arr) on the same array reference empties it.\n if (finalMessages === messages) return repaired.report;\n if (ctx.state) {\n ctx.state.replaceMessages(finalMessages);\n } else {\n // push(...) is O(k) with no element shift, unlike splice(0, 0, ...) which\n // shifts all existing elements before inserting at position 0.\n messages.length = 0;\n messages.push(...finalMessages);\n }\n return repaired.report;\n };\n\n switch (input.action) {\n case 'check': {\n // Prefer the full API request estimate when systemPrompt + tools are available.\n // This is the accurate number for context-window bar display.\n // Falls back to roughEstimate (messages-only) for backward compat and test environments.\n const estimate = (input.systemPrompt != null && Array.isArray(input.tools))\n ? estimateRequestTokens(messages, input.systemPrompt, input.tools)\n : { total: beforeTokens, messages: beforeTokens, systemPrompt: 0, tools: 0 };\n return {\n action: 'check',\n beforeTokens: estimate.total,\n messageCount: messages.length,\n notes: JSON.stringify({\n messages: messages.length,\n tokens: estimate.total,\n msgTokens: estimate.messages,\n sysTokens: estimate.systemPrompt,\n toolTokens: estimate.tools,\n readFiles: ctx.readFiles.size,\n todos: ctx.todos.length,\n inProgress: ctx.todos.filter((t) => t.status === 'in_progress').length,\n }),\n };\n }\n\n case 'repair': {\n const repair = applyMessages([...messages]);\n const afterTokens = roughEstimate(ctx.messages);\n return {\n action: 'repair',\n beforeTokens,\n afterTokens,\n messageCount: ctx.messages.length,\n repaired: repair.changed\n ? {\n removedToolUses: repair.removedToolUses,\n removedToolResults: repair.removedToolResults,\n removedMessages: repair.removedMessages,\n }\n : undefined,\n notes: repair.changed\n ? 'Context tool-call adjacency repaired.'\n : 'Context tool-call adjacency already valid.',\n };\n }\n\n case 'compact': {\n if (!opts.compactor) {\n return {\n action: 'compact',\n beforeTokens,\n messageCount: messages.length,\n notes: 'No compactor registered. Use /compact aggressive via slash command instead.',\n };\n }\n // Compute full request tokens for threshold check.\n const fullEstimate = (input.systemPrompt != null && Array.isArray(input.tools))\n ? estimateRequestTokens(messages, input.systemPrompt, input.tools)\n : { total: beforeTokens, messages: beforeTokens, systemPrompt: 0, tools: 0 };\n const currentTokens = fullEstimate.total;\n\n // Resolve maxContext at execution time from the live provider capabilities.\n // This is the actual model limit \u2014 from models.dev catalog, provider config,\n // or explicit effectiveMaxContext override. Falls back to the creation-time\n // value only when no runtime value is available (e.g. in test environments).\n const runtimeMaxContext =\n configuredMaxContext ?? ctx.provider?.capabilities?.maxContext ?? 128_000;\n const runtimeThreshold = minCompactThreshold > 0\n ? minCompactThreshold\n : Math.floor(runtimeMaxContext * compactThresholdFraction);\n\n // NOOP retry prevention: skip if the previous compaction saved nothing\n // and context hasn't grown enough to make another attempt worthwhile.\n if (lastNoopTokens > 0) {\n const delta = currentTokens - lastNoopTokens;\n if (delta < noopRetryDeltaTokens) {\n return {\n action: 'compact',\n beforeTokens,\n afterTokens: beforeTokens,\n messageCount: messages.length,\n notes: `Compact is a NOOP retry: context grew only ${delta} tokens since the last no-op attempt (threshold: ${noopRetryDeltaTokens}). Skip until more content accumulates.`,\n };\n }\n }\n\n // Minimum threshold check: skip if context is too small to benefit.\n if (runtimeThreshold > 0 && currentTokens < runtimeThreshold) {\n return {\n action: 'compact',\n beforeTokens,\n afterTokens: beforeTokens,\n messageCount: messages.length,\n notes: `Context tokens (${currentTokens}) below compact threshold (${runtimeThreshold}, based on provider maxContext ${runtimeMaxContext}). Skipping.`,\n };\n }\n\n const report = await opts.compactor.compact(ctx);\n ctx.clearFileTracking();\n\n // When ctx.state is not wired, the compactor's replaceMessages calls are\n // no-ops \u2014 repairToolUseAdjacency was still called inside the compactor but\n // the result was never committed. Run repair once to commit via the fallback.\n // When ctx.state IS wired, the compactor already committed the repair.\n let repaired = report.repaired;\n let afterTokens: number;\n if (!ctx.state) {\n const repair = applyMessages([...ctx.messages]);\n repaired = report.repaired ?? (repair.changed ? repair : undefined);\n afterTokens = repair.changed ? roughEstimate(ctx.messages) : report.after;\n } else {\n afterTokens = report.after;\n }\n\n // Record NOOP state: did compaction actually reduce tokens?\n const reduced = report.fullRequestTokensBefore > report.fullRequestTokensAfter;\n const repairedSomething = !!report.repaired;\n if (reduced || repairedSomething) {\n lastNoopTokens = 0;\n } else {\n lastNoopTokens = currentTokens;\n }\n\n return {\n action: 'compact',\n beforeTokens,\n afterTokens,\n messageCount: ctx.messages.length,\n repaired: repaired\n ? {\n removedToolUses: repaired.removedToolUses,\n removedToolResults: repaired.removedToolResults,\n removedMessages: repaired.removedMessages,\n }\n : undefined,\n };\n }\n\n case 'prune': {\n const from = input.from ?? 0;\n const to = input.to ?? messages.length - 1;\n if (from < 0 || to >= messages.length || from > to) {\n return {\n action: 'prune',\n beforeTokens,\n messageCount: messages.length,\n notes: `Invalid range [${from}, ${to}] for ${messages.length} messages.`,\n };\n }\n const copy = [...messages];\n const removed = copy.splice(from, to - from + 1);\n ctx.clearFileTracking();\n const repair = applyMessages(copy);\n const afterTokens = roughEstimate(ctx.messages);\n return {\n action: 'prune',\n beforeTokens,\n afterTokens,\n messageCount: ctx.messages.length,\n removedCount: removed.length,\n repaired: repair.changed\n ? {\n removedToolUses: repair.removedToolUses,\n removedToolResults: repair.removedToolResults,\n removedMessages: repair.removedMessages,\n }\n : undefined,\n };\n }\n\n case 'add_note': {\n const noteText = input.text ?? '(no summary)';\n const afterIdx = Math.min(input.afterIndex ?? 0, messages.length);\n const noteMsg: Message = {\n role: 'system',\n content: `[note: ${noteText}]`,\n };\n const copy = [...messages];\n copy.splice(afterIdx, 0, noteMsg);\n const repair = applyMessages(copy);\n const afterTokens = roughEstimate(ctx.messages);\n return {\n action: 'add_note',\n beforeTokens,\n afterTokens,\n messageCount: ctx.messages.length,\n summary: noteText,\n repaired: repair.changed\n ? {\n removedToolUses: repair.removedToolUses,\n removedToolResults: repair.removedToolResults,\n removedMessages: repair.removedMessages,\n }\n : undefined,\n };\n }\n\n case 'summary': {\n const from = input.from ?? 0;\n const to = input.to ?? messages.length - 1;\n if (from < 0 || to >= messages.length || from > to) {\n return {\n action: 'summary',\n beforeTokens,\n messageCount: messages.length,\n notes: `Invalid range [${from}, ${to}] for ${messages.length} messages.`,\n };\n }\n const summaryText =\n input.text ?? '[summary placeholder \u2014 provide \"text\" to record the summary]';\n const summaryMsg: Message = {\n role: 'system',\n content: `[summary of messages ${from}\u2013${to}]: ${summaryText}`,\n };\n const copy = [...messages];\n copy.splice(from, to - from + 1, summaryMsg);\n ctx.clearFileTracking();\n const repair = applyMessages(copy);\n const afterTokens = roughEstimate(ctx.messages);\n return {\n action: 'summary',\n beforeTokens,\n afterTokens,\n messageCount: ctx.messages.length,\n summary: summaryText,\n repaired: repair.changed\n ? {\n removedToolUses: repair.removedToolUses,\n removedToolResults: repair.removedToolResults,\n removedMessages: repair.removedMessages,\n }\n : undefined,\n };\n }\n\n default:\n return {\n action: input.action,\n beforeTokens,\n messageCount: messages.length,\n notes: `Unknown action: ${input.action}`,\n };\n }\n },\n };\n}\n\n/** Pre-built instance with no compactor \u2014 compact action will return an error. */\nexport const contextManagerTool: Tool<ContextManagerInput, ContextManagerResult> =\n createContextManagerTool();\n", "import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { DefaultLogger, noOpLogger } from './infrastructure/logger.js';\nimport { DefaultPathResolver } from './infrastructure/path-resolver.js';\nimport type { EventBus } from './kernel/events.js';\nimport { DefaultSecretVault, migratePlaintextSecrets } from './security/secret-vault.js';\nimport { DefaultConfigLoader } from './storage/config-loader.js';\nimport { type Config, normalizeTokenSavingTier } from './types/config.js';\nimport { atomicWrite } from './utils/atomic-write.js';\nimport { toErrorMessage } from './utils/error.js';\nimport {\n ensureProjectGitignore,\n ensureProjectIdentity,\n readProjectIdentity,\n} from './utils/project-identity.js';\nimport { safeParse } from './utils/safe-json.js';\nimport { writeErr } from './utils/term.js';\nimport {\n canonicalProjectRoot,\n resolveWstackPaths,\n safeProfileName,\n type WstackPaths,\n} from './utils/wstack-paths.js';\n\n/**\n * Options for {@link bootConfig}. Both the CLI and the WebUI server boot the\n * same way; the only intentional differences are the label used in the\n * plaintext-secret migration notice and whether CLI flags are supplied.\n */\nexport interface BootConfigOptions {\n /**\n * Parsed CLI flags. `cwd` relocates path resolution; `provider`/`model`/\n * `log-level`/`verbose`/`trace`/`yolo`/`no-features` are patched into the\n * loaded config (see {@link flagsToConfigPatch}). Defaults to `{}` (the\n * WebUI server passes no flags).\n */\n flags?: Record<string, string | boolean>;\n /**\n * Label shown in the `[<label>] Encrypted N plaintext secret(s) in FILE`\n * stderr notice emitted when legacy plaintext secrets get auto-encrypted.\n * The CLI passes `wstack`; the WebUI server passes `WebUI`. Default\n * `wstack`.\n */\n appLabel?: string | undefined;\n /**\n * Load the active profile's `sync.json` and merge it into `config.sync` so the\n * ConfigStore starts with the correct CloudSync state. Default `true`.\n */\n loadSyncConfig?: boolean | undefined;\n /**\n * Skip the provider/model identity validation during config load. When\n * `true`, a missing provider or model in config does NOT throw \u2014 the\n * boot caller is responsible for handling the missing-provider case\n * (e.g. showing a setup screen). Used by `--webui` mode so the WebUI\n * can boot without a configured provider and show the setup screen.\n */\n skipIdentityValidation?: boolean | undefined;\n}\n\n/**\n * Everything the boot phase resolves before DI-container wiring. Superset of\n * what the CLI and WebUI server each consumed previously, so both can pick the\n * fields they need from a single canonical result.\n */\nexport interface BootConfigResult {\n cwd: string;\n projectRoot: string;\n userHome: string;\n wpaths: WstackPaths;\n pathResolver: DefaultPathResolver;\n config: Config;\n vault: DefaultSecretVault;\n logger: DefaultLogger;\n /** Convenience alias for `wpaths.globalConfig`. */\n globalConfigPath: string;\n}\n\n/**\n * Canonical boot routine shared by `@wrongstack/cli` and `@wrongstack/webui`.\n * Resolves paths, creates the real AES-GCM secret vault, migrates any\n * plaintext secrets, loads + merges config (with CLI-flag overrides and an\n * optional sync overlay), and builds a logger.\n *\n * The per-package `bootConfig()` wrappers re-shape this result into their own\n * legacy return types for backward compatibility \u2014 keep this the single source\n * of boot behavior so the two consumers can't drift.\n */\nexport async function bootConfig(options: BootConfigOptions = {}): Promise<BootConfigResult> {\n const {\n flags = {},\n appLabel = 'wstack',\n loadSyncConfig = true,\n skipIdentityValidation = false,\n } = options;\n\n const cwd = typeof flags['cwd'] === 'string' ? path.resolve(flags['cwd']) : process.cwd();\n const pathResolver = new DefaultPathResolver(cwd);\n const projectRoot = pathResolver.projectRoot;\n const projectIdentityRoot = canonicalProjectRoot(projectRoot);\n const userHome = os.homedir();\n // No explicit userHome here: that would defeat the WRONGSTACK_HOME env\n // override (tests / sandboxed runs redirect all global state through it).\n const wpaths = resolveWstackPaths({ projectRoot });\n\n // Refuse to treat WrongStack's own state directory as a project. Must run\n // BEFORE the mkdir/registerProjectInManifest block below, or the bogus\n // namespace gets materialized on disk before we can complain about it.\n assertProjectRootOutsideStateDir(projectRoot, wpaths.globalRoot);\n\n // Ensure the directories every consumer relies on exist. This is the union\n // of what the cli and webui boot paths created independently \u2014 creating all\n // three eagerly is harmless and removes the \"new wpath added to one copy\n // only\" drift hazard.\n await fs.mkdir(wpaths.globalRoot, { recursive: true });\n await fs.mkdir(wpaths.profilesDir, { recursive: true });\n await fs.mkdir(wpaths.projectDir, { recursive: true });\n await fs.mkdir(wpaths.projectSessions, { recursive: true });\n let registeredProjectId: string | undefined;\n try {\n registeredProjectId = (await readProjectIdentity(projectRoot))?.projectId;\n } catch {\n // Malformed identity is reported by the HQ publisher; boot registration\n // still falls back to its historical path-scoped metadata.\n }\n await writeProjectMeta(wpaths, projectIdentityRoot, registeredProjectId);\n await registerProjectInManifest(\n wpaths,\n projectIdentityRoot,\n undefined,\n cwd !== projectIdentityRoot ? cwd : undefined,\n registeredProjectId,\n );\n await ensureProjectGitignore(projectRoot).catch(() => undefined);\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Legacy config migration: move ~/.wrongstack/config.json content into\n // ~/.wrongstack/profiles/default/config.json BEFORE any config load.\n // Starting with 0.291.0 the root config is a thin bootstrap pointer\n // (version + activeProfile); all user settings live in the profile config.\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n await migrateLegacyConfig(wpaths);\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Profile-state migration: copy all legacy user-owned files/directories\n // from the global root into the active profile if missing there.\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n await migrateProfileFiles(wpaths);\n\n // Clean up stale project directories left behind by tests or deleted\n // working directories. Best-effort \u2014 never blocks boot.\n cleanupStaleProjects(wpaths).catch((err) => {\n noOpLogger.debug('cleanupStaleProjects failed', { err });\n });\n\n // Preliminary logger \u2014 created before config load so both the vault and\n // config loader have a structured Logger for their warnings. Uses the\n // env-level or 'info' (handled by DefaultLogger constructor); replaced\n // with the properly-configured logger once config is loaded.\n const bootLogger = new DefaultLogger({ stderr: true });\n\n // Vault must come first so the config loader can decrypt apiKey-like fields.\n // It lazily creates ~/.wrongstack/.key on first encrypt/decrypt.\n const vault = new DefaultSecretVault({ keyFile: wpaths.secretsKey, logger: bootLogger });\n\n // Auto-encrypt any plaintext secrets still sitting in config files (left\n // over from before the vault existed, or hand-written). Silent no-op for\n // already-encrypted configs; never blocks boot on migration issues.\n // Uses noOpLogger because the structured logger isn't built until after\n // config loads; migration is best-effort and the warning it would emit\n // (permission errors on restrictFilePermissions) is the same one the\n // main logger would surface on the next boot.\n // Also migrate secrets in the selected profile config.\n // Defensive: profileConfig may not be available in test mocks.\n const bootstrapProfilePath =\n typeof wpaths.profileConfig === 'function' ? wpaths.profileConfig(wpaths.profileName) : null;\n const secretFiles = [wpaths.projectLocalConfig].filter(Boolean) as string[];\n if (bootstrapProfilePath) secretFiles.push(bootstrapProfilePath);\n for (const file of secretFiles) {\n try {\n const { migrated } = await migratePlaintextSecrets(file, vault, noOpLogger);\n if (migrated > 0) {\n writeErr(`[${appLabel}] Encrypted ${migrated} plaintext secret(s) in ${file}\\n`);\n }\n } catch {\n // best-effort \u2014 never block boot on migration issues\n }\n }\n\n const configLoader = new DefaultConfigLoader({ paths: wpaths, vault, logger: bootLogger });\n let config: Config;\n try {\n config = await configLoader.load({ cliFlags: flagsToConfigPatch(flags) });\n } catch (err) {\n if (\n skipIdentityValidation &&\n err instanceof Error &&\n err.message.includes('no provider configured')\n ) {\n // --webui mode: boot without a configured provider. Do not inject\n // a provider/model identity here; downstream setup state must stay\n // visibly unconfigured until the user picks a real target.\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'boot.no_provider_configured',\n app: appLabel,\n message: 'No provider configured \u2014 setup screen will be shown',\n timestamp: new Date().toISOString(),\n }),\n );\n try {\n config = await configLoader.load({\n cliFlags: flagsToConfigPatch(flags),\n skipIdentityValidation: true,\n });\n } catch (fallbackErr) {\n // Best-effort: if even the skip-validation load fails (corrupt config,\n // FS error), create a minimal in-memory config so --webui can still show\n // the setup screen instead of crashing at boot.\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'boot.config_fallback',\n message: `Config load fallback triggered: ${toErrorMessage(fallbackErr)}`,\n timestamp: new Date().toISOString(),\n }),\n );\n config = Object.freeze({}) as Config;\n }\n } else {\n throw err;\n }\n }\n\n // Load and decrypt sync config from the active profile and merge it into\n // the main config so ConfigStore starts with the correct sync state.\n // `load()` returns a frozen Config, so rebuild a new frozen object rather\n // than mutating in place (a direct assignment throws \"Cannot add property\n // sync, object is not extensible\" once sync.json exists).\n if (loadSyncConfig) {\n const syncConfig = await configLoader.loadSyncConfig();\n if (syncConfig) {\n config = Object.freeze({ ...config, sync: syncConfig }) as Config;\n }\n }\n\n // A committed project identity lets independent clones and worktrees join\n // the same HQ project. Existing alias-based installations keep their legacy\n // identity until they explicitly initialize/rekey the repository.\n if (!config.hq?.projectAlias) {\n try {\n await ensureProjectIdentity(projectRoot);\n } catch (error) {\n bootLogger.warn?.('Could not initialize .wrongstack/project.json', {\n event: 'project.identity_init_failed',\n error: toErrorMessage(error),\n });\n }\n }\n\n let committedProjectId: string | undefined;\n try {\n committedProjectId = (await readProjectIdentity(projectRoot))?.projectId;\n } catch {\n // The HQ publisher reports malformed identity files when it tries to use\n // them. Local boot state remains available so the user can repair/rekey.\n }\n if (committedProjectId !== registeredProjectId) {\n await writeProjectMeta(wpaths, projectIdentityRoot, committedProjectId);\n await registerProjectInManifest(\n wpaths,\n projectIdentityRoot,\n undefined,\n cwd !== projectIdentityRoot ? cwd : undefined,\n committedProjectId,\n );\n }\n\n const logger = new DefaultLogger({ level: config.log?.level ?? 'info', file: wpaths.logFile });\n\n // Initialize the cross-process session registry so /sessions status works\n // and the agent status tracker can register entries later.\n try {\n const { getSessionRegistry } = await import('./session-registry.js');\n getSessionRegistry(wpaths.globalRoot);\n } catch {\n // Non-critical \u2014 session tracking degrades gracefully\n }\n\n return {\n cwd,\n projectRoot,\n userHome,\n wpaths,\n pathResolver,\n config,\n vault,\n logger,\n globalConfigPath: wpaths.globalConfig,\n };\n}\n\nfunction isEnabledFlag(value: string | boolean | undefined): boolean {\n if (value === true) return true;\n if (typeof value !== 'string') return false;\n const normalized = value.trim().toLowerCase();\n return normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on';\n}\n\n/**\n * Translate parsed CLI flags into a partial Config patch applied on top of the\n * file-loaded config. Explicit `--log-level` wins over `--verbose`/`--trace`.\n */\nexport function flagsToConfigPatch(flags: Record<string, string | boolean>): Partial<Config> {\n const patch: Partial<Config> = {};\n if (typeof flags['provider'] === 'string') patch.provider = flags['provider'];\n if (typeof flags['model'] === 'string') patch.model = flags['model'];\n if (typeof flags['fallback-model'] === 'string') {\n const list = flags['fallback-model']\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n if (list.length > 0) patch.fallbackModels = list;\n }\n if (typeof flags['cwd'] === 'string') patch.cwd = flags['cwd'];\n if (typeof flags['log-level'] === 'string') {\n patch.log = { level: flags['log-level'] as Config['log']['level'] };\n } else if (flags['verbose']) {\n patch.log = { level: 'debug' };\n } else if (flags['trace']) {\n patch.log = { level: 'trace' };\n }\n if (flags['no-yolo'] === true) patch.yolo = false;\n else if (flags['yolo']) patch.yolo = true;\n if (flags['no-features']) {\n patch.features = {\n mcp: false,\n plugins: false,\n memory: false,\n modelsRegistry: false,\n skills: false,\n };\n }\n if (flags['token-saving-mode']) {\n patch.features ??= {} as Config['features'];\n patch.features.tokenSavingMode = true;\n }\n if (isEnabledFlag(flags['system-pro']) || flags['system-prompt'] === 'pro') {\n patch.systemPrompt = { variant: 'pro' };\n } else if (isEnabledFlag(flags['system-lite']) || flags['system-prompt'] === 'lite') {\n patch.systemPrompt = { variant: 'lite' };\n } else if (flags['system-prompt'] === 'default') {\n patch.systemPrompt = { variant: 'default' };\n }\n // `--token-saving-tier <level>` takes precedence over `--token-saving-mode`.\n // Supported values: off, minimal, light, medium, aggressive.\n if (typeof flags['token-saving-tier'] === 'string') {\n patch.features ??= {} as Config['features'];\n patch.features.tokenSavingMode = normalizeTokenSavingTier(\n flags['token-saving-tier'] as 'off' | 'minimal' | 'light' | 'medium' | 'aggressive',\n );\n }\n return patch;\n}\n\n/**\n * Before 0.291.0, all config lived in ~/.wrongstack/config.json.\n * Starting with 0.291.0, the root config is a thin bootstrap (version +\n * activeProfile) and settings live in ~/.wrongstack/profiles/<name>/config.json.\n *\n * This function migrates a legacy flat config into the default profile config\n * BEFORE any config loader runs, so the loader always reads from the right place.\n *\n * Migration is allowed only when the selected profile file does not exist.\n * An existing empty or corrupt profile is still authoritative: root settings\n * must never be re-imported once profiles are in use.\n */\nasync function migrateLegacyConfig(wpaths: WstackPaths): Promise<void> {\n const rootFp = wpaths.globalConfig;\n\n // If legacy root doesn't exist, nothing to migrate.\n let legacyRaw: string;\n try {\n legacyRaw = await fs.readFile(rootFp, 'utf8');\n } catch {\n return; // ENOENT or other error \u2014 nothing to migrate\n }\n\n // Validate the legacy content is parseable JSON with actual settings.\n const result = safeParse<Record<string, unknown>>(legacyRaw);\n if (\n !result.ok ||\n !result.value ||\n typeof result.value !== 'object' ||\n Array.isArray(result.value)\n ) {\n return;\n }\n\n const activeProfile = safeProfileName(\n typeof result.value['activeProfile'] === 'string' ? result.value['activeProfile'] : undefined,\n );\n const profileFp = wpaths.profileConfig(activeProfile);\n\n // File existence, not content, is the boundary. Never recover settings from\n // root over an existing profile, even when that profile is empty or corrupt.\n try {\n await fs.access(profileFp);\n return;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') return;\n }\n\n await fs.mkdir(path.dirname(profileFp), { recursive: true });\n\n // Copy legacy content into the profile config, stripping bootstrap-only fields.\n const profileContent = { ...result.value };\n delete profileContent['activeProfile'];\n\n await atomicWrite(profileFp, JSON.stringify(profileContent, null, 2), { mode: 0o600 });\n\n // Write the root config as a thin bootstrap pointer.\n const bootstrap = { version: 1, activeProfile };\n\n try {\n await atomicWrite(rootFp, JSON.stringify(bootstrap, null, 2), { mode: 0o600 });\n } catch {\n // best-effort \u2014 profile already migrated\n }\n}\n\n/** Pairs of (legacy root source, profile destination) that need migration. */\nconst PROFILE_STATE_PAIRS: ReadonlyArray<{\n globalSrc: (wpaths: WstackPaths) => string;\n profileDst: (wpaths: WstackPaths, name: string) => string;\n}> = [\n {\n globalSrc: (w) => path.join(w.globalRoot, 'statusline.json'),\n profileDst: (w, n) => w.profileStatuslineConfig(n),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'mode.json'),\n profileDst: (w, n) => w.profileModeConfig(n),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'provider-status.json'),\n profileDst: (w, n) => w.profileProviderStatus(n),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'update-cache.json'),\n profileDst: (w, n) => w.profileUpdateCache(n),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'memory.md'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'memory.md'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'history'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'history'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'sync.json'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'sync.json'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'sync-state.json'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'sync-state.json'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'prompt-usage.json'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'prompt-usage.json'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'custom-context-modes.json'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'custom-context-modes.json'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'desktop.json'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'desktop.json'),\n },\n {\n globalSrc: (w) => path.join(w.globalRoot, 'installed-skills.json'),\n profileDst: (w, n) => path.join(w.profilesDir, n, 'installed-skills.json'),\n },\n ...['skills', 'prompts', 'instructions', 'design-kits', 'desktop', 'settings'].map(\n (directory) => ({\n globalSrc: (w: WstackPaths) => path.join(w.globalRoot, directory),\n profileDst: (w: WstackPaths, n: string) => path.join(w.profilesDir, n, directory),\n }),\n ),\n];\n\n/**\n * Migrate legacy profile-owned files and directories from the global root\n * into the active profile's directory. Runs after migrateLegacyConfig() so the\n * active profile name is resolved from the now-migrated root bootstrap.\n *\n * For each entry: if it exists in the profile directory, it's left untouched\n * (idempotent). If it's missing in the profile but exists at the global root,\n * it's copied into the profile. If neither exists, silently skipped.\n * Best-effort: failures never block boot.\n */\nasync function migrateProfileFiles(wpaths: WstackPaths): Promise<void> {\n // Read the active profile name from the bootstrap (already migrated by\n // migrateLegacyConfig above). Default to 'default' if unset.\n let profileName = wpaths.profileName;\n try {\n const raw = await fs.readFile(wpaths.globalConfig, 'utf8');\n const parsed = safeParse<Record<string, unknown>>(raw);\n if (parsed.ok && parsed.value && typeof parsed.value.activeProfile === 'string') {\n profileName = safeProfileName(parsed.value.activeProfile);\n }\n } catch {\n // best-effort \u2014 default profile\n }\n\n // Ensure the profile directory exists so the copy targets are writable.\n try {\n await fs.mkdir(path.join(wpaths.profilesDir, profileName), { recursive: true });\n } catch {\n return;\n }\n\n for (const pair of PROFILE_STATE_PAIRS) {\n const src = pair.globalSrc(wpaths);\n const dst = pair.profileDst(wpaths, profileName);\n\n // Confirm the global source exists and capture its type.\n let srcIsDir: boolean;\n try {\n srcIsDir = (await fs.stat(src)).isDirectory();\n } catch {\n continue; // no global source \u2014 nothing to migrate\n }\n\n // Skip if the profile already has this entry with the matching type\n // (idempotent). A type mismatch indicates corrupt partial state left by\n // a botched earlier migration (e.g. a file where a directory belongs);\n // remove the wrong-typed stub so the copy below can recover the tree.\n try {\n const dstStat = await fs.stat(dst);\n if (dstStat.isDirectory() === srcIsDir) {\n continue; // already migrated with the correct type\n }\n await fs.rm(dst, { recursive: true, force: true });\n } catch (err) {\n // Only proceed to copy when dst genuinely doesn't exist (ENOENT).\n // Other errors (EACCES, EMFILE, \u2026) mean we can't safely determine\n // dst state \u2014 skip this entry rather than risk a broken copy.\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n writeErr(`migrateProfileFiles: skipping ${dst} (stat error: ${code ?? 'unknown'})\\n`);\n continue;\n }\n }\n\n // Copy the global file/directory into the profile directory.\n try {\n if (srcIsDir) {\n await fs.cp(src, dst, { recursive: true, errorOnExist: false, force: false });\n } else {\n const content = await fs.readFile(src);\n await fs.writeFile(dst, content, { mode: 0o600 });\n }\n } catch {\n // best-effort \u2014 never block boot\n }\n }\n}\n\n/**\n * Refuse to boot when the resolved project root lives inside\n * `<globalRoot>/projects` \u2014 the per-project state namespace WrongStack itself\n * owns (`~/.wrongstack/projects/<slug>`, or under `WRONGSTACK_HOME`).\n *\n * When this happens it means a caller spawned a WrongStack process with a\n * state path as its cwd; `DefaultPathResolver` then finds no project marker,\n * walks up, hits the home-directory stop, and falls back to cwd \u2014 so the state\n * directory itself becomes the \"project\". Boot would go on to register a\n * nested slug (`<slug>-<hash>`) with its own `meta.json`, `projects.json`\n * entry, mailbox lock and token, splitting coordination state across two\n * namespaces \u2014 with the nested one always winning `lastSeen`.\n *\n * Deliberately scoped to `projects/` rather than all of `globalRoot`: a user\n * may legitimately point `WRONGSTACK_HOME` at a directory that also contains\n * real repositories (our own bridge tests do exactly this), and refusing those\n * would be a false positive. Nothing under `projects/` is ever a real repo, so\n * the narrow check has no such ambiguity.\n *\n * Loud on purpose \u2014 the symptom is far harder to diagnose than a refused boot\n * that names the offending directory.\n */\nexport function assertProjectRootOutsideStateDir(projectRoot: string, globalRoot: string): void {\n const stateNamespace = path.resolve(globalRoot, 'projects');\n const rel = path.relative(stateNamespace, path.resolve(projectRoot));\n // Outside \u2192 the relative path escapes upward, or is absolute (other drive).\n if (rel.startsWith('..') || path.isAbsolute(rel)) return;\n // `rel === ''` means projectRoot IS `projects/`; anything else is nested.\n throw new Error(\n `Refusing to start: the resolved project root is inside WrongStack's per-project ` +\n `state directory.\\n` +\n ` project root: ${projectRoot}\\n` +\n ` state dir: ${stateNamespace}\\n` +\n `This usually means a WrongStack process was spawned with a state path as its ` +\n `working directory. Start from a real project directory, or pass --cwd <path>.`,\n );\n}\n\nasync function writeProjectMeta(\n paths: WstackPaths,\n projectRoot: string,\n projectId?: string,\n): Promise<void> {\n try {\n await fs.mkdir(paths.projectDir, { recursive: true });\n const meta = {\n hash: paths.projectHash,\n slug: paths.projectSlug,\n root: projectRoot,\n ...(projectId ? { projectId } : {}),\n lastSeen: new Date().toISOString(),\n };\n await atomicWrite(paths.projectMeta, JSON.stringify(meta, null, 2));\n } catch {\n // best-effort\n }\n}\n\n/**\n * Register or update the current project in ~/.wrongstack/projects.json.\n * This is the central manifest that the /project command uses.\n */\nasync function registerProjectInManifest(\n paths: WstackPaths,\n projectRoot: string,\n events?: EventBus,\n /** Working directory when it differs from projectRoot (e.g. subdirectory launch). */\n workingDir?: string,\n /** Stable repo-committed identity shared by clones and worktrees. */\n projectId?: string,\n): Promise<void> {\n const manifestPath = path.join(paths.globalRoot, 'projects.json');\n\n // Read existing manifest (best-effort \u2014 missing or malformed file is treated as empty)\n try {\n const t0 = Date.now();\n const raw = await fs.readFile(manifestPath, 'utf8');\n events?.emit('storage.read', {\n sessionId: '~boot~',\n store: 'project',\n filePath: manifestPath,\n operation: 'manifest_read',\n outcome: 'success',\n durationMs: Date.now() - t0,\n });\n try {\n JSON.parse(raw); // validate\n } catch {\n // treat malformed JSON as empty manifest \u2014 will be overwritten\n }\n } catch (err) {\n events?.emit('storage.error', {\n sessionId: '~boot~',\n store: 'project',\n filePath: manifestPath,\n operation: 'manifest_read',\n error: toErrorMessage(err),\n recoverable: true,\n });\n }\n\n // Write updated manifest\n try {\n let manifest: {\n projects: Array<{\n name: string;\n root: string;\n slug: string;\n projectId?: string;\n lastSeen?: string;\n createdAt?: string;\n lastWorkingDir?: string;\n }>;\n };\n try {\n const raw = await fs.readFile(manifestPath, 'utf8');\n manifest = JSON.parse(raw);\n } catch {\n manifest = { projects: [] };\n }\n\n const now = new Date().toISOString();\n const existing = manifest.projects.find((p) => p.root === projectRoot);\n if (existing) {\n existing.lastSeen = now;\n if (projectId) existing.projectId = projectId;\n if (workingDir) existing.lastWorkingDir = workingDir;\n } else {\n const slug = paths.projectSlug;\n const name = path.basename(projectRoot);\n const entry: Record<string, string | undefined> = {\n name,\n root: projectRoot,\n slug,\n projectId,\n lastSeen: now,\n createdAt: now,\n };\n if (workingDir) entry.lastWorkingDir = workingDir;\n manifest.projects.push(entry as (typeof manifest.projects)[0]);\n }\n\n const writeT0 = Date.now();\n await atomicWrite(manifestPath, JSON.stringify(manifest, null, 2));\n events?.emit('storage.write', {\n sessionId: '~boot~',\n store: 'project',\n filePath: manifestPath,\n operation: 'manifest_write',\n outcome: 'success',\n durationMs: Date.now() - writeT0,\n });\n } catch (err) {\n events?.emit('storage.error', {\n sessionId: '~boot~',\n store: 'project',\n filePath: manifestPath,\n operation: 'manifest_write',\n error: toErrorMessage(err),\n recoverable: false,\n });\n // best-effort \u2014 never blocks boot\n }\n}\n\n/**\n * Remove project directories that can no longer describe a real project:\n * those whose original `root` is gone from disk (temp dirs from tests,\n * deleted working copies), and phantom *nested* projects whose `root` points\n * back inside the state namespace.\n *\n * The nested case is the residue of the bug `assertProjectRootOutsideStateDir`\n * now refuses at boot: a process started with a state path as its cwd\n * registered `<slug>-<hash>` whose `root` is `<globalRoot>/projects/<slug>`.\n * The guard stops new ones, but it cannot retire the ones already on disk \u2014\n * and the existing \"root is gone\" rule never matches them, because their root\n * is a directory that very much still exists. They therefore persisted\n * indefinitely, each one doubling a real project's footprint: its own\n * `meta.json`, mailbox lock, token, and \u2014 because callers enumerate this\n * directory \u2014 its own spawned daemon.\n *\n * Safe to delete unconditionally: nothing under `projects/` is ever a real\n * repository, which is the same reasoning that lets the boot guard scope\n * itself to that subtree.\n *\n * Runs as a fire-and-forget best-effort \u2014 failures are silently ignored.\n *\n * @internal Exported for tests: this recursively deletes directories, so its\n * keep/delete decision is worth pinning directly rather than through `boot()`.\n */\nexport async function cleanupStaleProjects(wpaths: WstackPaths): Promise<void> {\n const projectsRoot = path.dirname(wpaths.projectDir);\n let entries;\n try {\n entries = await fs.readdir(projectsRoot, { withFileTypes: true });\n } catch {\n return; // directory doesn't exist or can't be read\n }\n const stateNamespace = path.resolve(projectsRoot);\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const projectPath = path.join(projectsRoot, entry.name);\n const metaPath = path.join(projectPath, 'meta.json');\n try {\n const raw = await fs.readFile(metaPath, 'utf8');\n const meta = JSON.parse(raw) as { root?: string | undefined };\n if (typeof meta.root !== 'string') continue;\n const rel = path.relative(stateNamespace, path.resolve(meta.root));\n const nested = rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n if (nested) {\n // Phantom project registered from a state path \u2014 never legitimate.\n await fs.rm(projectPath, { recursive: true, force: true });\n continue;\n }\n try {\n await fs.access(meta.root);\n // root still exists \u2014 keep it\n } catch {\n // root gone \u2192 remove the entire project directory\n await fs.rm(projectPath, { recursive: true, force: true });\n }\n } catch {\n // no readable meta.json \u2192 leave it alone (don't nuke ambiguous dirs)\n }\n }\n}\n", "import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Logger } from '../types/logger.js';\nimport type { RotatableSecretVault, SecretVault } from '../types/secret-vault.js';\nimport { ConfigError, ERROR_CODES } from '../types/errors.js';\nimport {\n ENCRYPTED_PREFIX_PATTERN,\n encryptedPrefixForVersion,\n} from '../types/secret-vault.js';\nimport { atomicWrite } from '../utils/atomic-write.js';\nimport { encryptConfigSecrets, isSecretField } from './config-secrets.js';\n\nexport interface SecretVaultOptions {\n /** Absolute path to the key file. Created with mode 0o600 if missing. */\n keyFile: string;\n /** Logger for structured warnings. Falls back to console.warn when omitted. */\n logger?: Logger | undefined;\n}\n\nconst KEY_BYTES = 32;\nconst IV_BYTES = 12;\nconst TAG_BYTES = 16;\nconst ALGO = 'aes-256-gcm';\n// Desired file mode for the key file on POSIX systems.\nconst KEY_FILE_MODE = 0o600;\n\n/**\n * Key file format v2+: 4-byte magic + 1-byte version + 32-byte key = 37 bytes.\n * The magic header distinguishes versioned key files from legacy 32-byte raw keys.\n */\nconst KEY_FILE_MAGIC = Buffer.from('WSKV', 'ascii');\nconst VERSIONED_KEY_FILE_SIZE = KEY_FILE_MAGIC.length + 1 + KEY_BYTES; // 37 bytes\n\n// \u2500\u2500 WS-03: opt-in passphrase-wrapped key file (KEK) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// When WRONGSTACK_VAULT_PASSPHRASE is set, the data key is NOT stored in the\n// clear. Instead the key file holds the data key encrypted (AES-256-GCM) under\n// a key-encryption-key (KEK) derived from the passphrase with scrypt. This adds\n// at-rest protection beyond the file's 0o600 perms: an attacker who copies\n// ~/.wrongstack/.key + config.json off the disk still cannot decrypt without the\n// passphrase. When the env var is unset, behavior is byte-for-byte identical to\n// before (legacy raw / versioned formats) \u2014 this is purely additive and opt-in.\n//\n// Wrapped format v3: magic 'WSKW' (4) + keyVersion (1) + salt (16) + iv (12) +\n// tag (16) + ciphertext (32) = 81 bytes.\nconst KEK_MAGIC = Buffer.from('WSKW', 'ascii');\nconst KEK_SALT_BYTES = 16;\nconst WRAPPED_KEY_FILE_SIZE =\n KEK_MAGIC.length + 1 + KEK_SALT_BYTES + IV_BYTES + TAG_BYTES + KEY_BYTES; // 81 bytes\n// scrypt cost parameters. N=2^15 keeps derivation ~50-100ms \u2014 strong against\n// offline brute force while imperceptible for a one-time-per-process unlock.\nconst SCRYPT_N = 1 << 15;\nconst SCRYPT_R = 8;\nconst SCRYPT_P = 1;\nconst SCRYPT_MAXMEM = 64 * 1024 * 1024; // headroom above N*r*128 so derivation never throws\n\n/** Read the optional vault passphrase from the environment. Empty = unset. */\nfunction getVaultPassphrase(): string | undefined {\n const v = process.env['WRONGSTACK_VAULT_PASSPHRASE'];\n return v && v.length > 0 ? v : undefined;\n}\n\n/** True if `buf` is a passphrase-wrapped (v3) key file. */\nfunction isWrappedKeyFile(buf: Buffer): boolean {\n return buf.length === WRAPPED_KEY_FILE_SIZE && buf.subarray(0, KEK_MAGIC.length).equals(KEK_MAGIC);\n}\n\n/** Derive the 32-byte KEK from a passphrase + salt via scrypt. */\nfunction deriveKEK(passphrase: string, salt: Buffer): Buffer {\n return scryptSync(passphrase, salt, KEY_BYTES, {\n N: SCRYPT_N,\n r: SCRYPT_R,\n p: SCRYPT_P,\n maxmem: SCRYPT_MAXMEM,\n });\n}\n\n/** Serialize a data key into the wrapped (v3) on-disk format under `passphrase`. */\nfunction wrapDataKey(dataKey: Buffer, keyVersion: number, passphrase: string): Buffer {\n const salt = randomBytes(KEK_SALT_BYTES);\n const iv = randomBytes(IV_BYTES);\n const kek = deriveKEK(passphrase, salt);\n const cipher = createCipheriv(ALGO, kek, iv);\n const ct = Buffer.concat([cipher.update(dataKey), cipher.final()]);\n const tag = cipher.getAuthTag();\n const out = Buffer.alloc(WRAPPED_KEY_FILE_SIZE);\n let off = 0;\n KEK_MAGIC.copy(out, off); off += KEK_MAGIC.length;\n out[off] = keyVersion & 0xff; off += 1;\n salt.copy(out, off); off += KEK_SALT_BYTES;\n iv.copy(out, off); off += IV_BYTES;\n tag.copy(out, off); off += TAG_BYTES;\n ct.copy(out, off);\n return out;\n}\n\n/**\n * Parse a wrapped (v3) key file and return the data key + version. Throws a\n * clear ConfigError when the passphrase is missing or wrong (GCM auth failure).\n */\nfunction unwrapDataKey(buf: Buffer, keyFile: string): { key: Buffer; version: number } {\n const passphrase = getVaultPassphrase();\n if (!passphrase) {\n throw new ConfigError({\n message:\n `SecretVault: key file ${keyFile} is passphrase-protected \u2014 set the ` +\n `WRONGSTACK_VAULT_PASSPHRASE environment variable to unlock it.`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile },\n });\n }\n let off = KEK_MAGIC.length;\n const version = buf[off]!; off += 1;\n const salt = buf.subarray(off, off + KEK_SALT_BYTES); off += KEK_SALT_BYTES;\n const iv = buf.subarray(off, off + IV_BYTES); off += IV_BYTES;\n const tag = buf.subarray(off, off + TAG_BYTES); off += TAG_BYTES;\n const ct = buf.subarray(off, off + KEY_BYTES);\n const kek = deriveKEK(passphrase, salt);\n const decipher = createDecipheriv(ALGO, kek, iv);\n decipher.setAuthTag(tag);\n try {\n const key = Buffer.concat([decipher.update(ct), decipher.final()]);\n return { key: Buffer.from(key), version };\n } catch {\n throw new ConfigError({\n message:\n `SecretVault: failed to unlock key file ${keyFile} \u2014 wrong ` +\n `WRONGSTACK_VAULT_PASSPHRASE (key unwrap authentication failed).`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile },\n });\n }\n}\n\n/**\n * Check and warn if the key file has incorrect permissions on POSIX.\n * On Windows this is a no-op (mode bits don't apply).\n */\nfunction checkKeyFilePermissions(\n keyFile: string,\n opts?: { warn?: (msg: string) => void } | undefined,\n): void {\n if (process.platform === 'win32') return; // No mode bits on Windows\n const warn = opts?.warn ?? ((msg: string) => console.warn(msg));\n try {\n const stat = fs.statSync(keyFile);\n const actualMode = stat.mode & 0o777;\n if (actualMode !== KEY_FILE_MODE) {\n warn(\n `Key file ${keyFile} has mode ${actualMode.toString(8)} \u2014 expected ${KEY_FILE_MODE.toString(8)}. Run: chmod ${KEY_FILE_MODE.toString(8)} ${keyFile}`,\n );\n }\n } catch {\n // stat can fail for reasons other than the file not existing;\n // if it does, the ENOENT path handles it.\n }\n}\n\n/**\n * Crash-atomic synchronous key-file write: temp (0o600) + fsync + rename.\n * A plain writeFileSync torn by a crash would leave a corrupt key file \u2014\n * and a corrupt key file means every secret in the vault is unrecoverable.\n * Sync because the vault's rotate/migrate paths are synchronous; these run\n * rarely (rotation, at-rest upgrade), never on a hot path.\n */\nfunction writeKeyFileAtomicSync(keyFile: string, content: Buffer): void {\n const tmp = `${keyFile}.${randomBytes(4).toString('hex')}.tmp`;\n const fd = fs.openSync(tmp, 'w', 0o600);\n try {\n fs.writeFileSync(fd, content);\n try {\n fs.fsyncSync(fd);\n } catch {\n // Best-effort fsync \u2014 matches the async atomicWrite primitive.\n }\n } finally {\n fs.closeSync(fd);\n }\n try {\n fs.renameSync(tmp, keyFile);\n } catch (err) {\n try {\n fs.unlinkSync(tmp);\n } catch {\n /* best-effort cleanup */\n }\n throw err;\n }\n}\n\n/**\n * Default vault: AES-256-GCM with a key stored at `keyFile` (mode 0o600).\n * The key is loaded lazily on first encrypt/decrypt; if it does not exist,\n * a fresh one is generated. Decryption of plaintext values is a no-op so\n * legacy configs continue to work.\n *\n * Key file format:\n * - Legacy (v1): exactly 32 raw bytes\n * - Versioned (v2+): 4-byte magic `WSKV` + 1-byte version + 32-byte key (37 bytes)\n *\n * Encrypted value format: `enc:v<N>:<iv>:<tag>:<ciphertext>` where N is the\n * key version. After rotation, encrypt() emits the new version prefix.\n */\nexport class DefaultSecretVault implements RotatableSecretVault {\n private readonly keyFile: string;\n private readonly logger: Logger | undefined;\n private key?: Buffer | undefined;\n private _keyVersion: number = 1;\n\n constructor(opts: SecretVaultOptions) {\n this.keyFile = opts.keyFile;\n this.logger = opts.logger;\n }\n\n /**\n * Emit a structured warning. Uses the configured Logger when available;\n * falls back to console.warn(JSON) so warnings are never silently dropped\n * during early boot.\n */\n private logWarn(msg: string, ctx?: Record<string, unknown>): void {\n if (this.logger) {\n this.logger.warn(msg, ctx);\n } else {\n console.warn(JSON.stringify({ ...ctx, message: msg, timestamp: new Date().toISOString() }));\n }\n }\n\n /** Current key version. Starts at 1; incremented by rotateKey(). */\n get keyVersion(): number {\n // Ensure key is loaded so version is accurate\n if (!this.key) this.loadOrCreateKey();\n return this._keyVersion;\n }\n\n isEncrypted(value: string): boolean {\n return typeof value === 'string' && ENCRYPTED_PREFIX_PATTERN.test(value);\n }\n\n encrypt(plaintext: string): string {\n if (this.isEncrypted(plaintext)) return plaintext;\n const key = this.loadOrCreateKey();\n const iv = randomBytes(IV_BYTES);\n const cipher = createCipheriv(ALGO, key, iv);\n const ct = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n const prefix = encryptedPrefixForVersion(this._keyVersion);\n return `${prefix}${iv.toString('base64')}:${tag.toString('base64')}:${ct.toString('base64')}`;\n }\n\n decrypt(value: string): string {\n if (!this.isEncrypted(value)) return value;\n // Strip the versioned prefix (enc:v1:, enc:v2:, etc.)\n const prefixMatch = value.match(ENCRYPTED_PREFIX_PATTERN);\n if (!prefixMatch) {\n throw new ConfigError({\n message: 'SecretVault: malformed encrypted value',\n code: ERROR_CODES.CONFIG_PARSE_FAILED,\n context: { field: 'encrypted_value' },\n });\n }\n const rest = value.slice(prefixMatch[0].length);\n const parts = rest.split(':');\n if (parts.length !== 3) {\n throw new ConfigError({\n message: 'SecretVault: malformed encrypted value',\n code: ERROR_CODES.CONFIG_PARSE_FAILED,\n context: { field: 'encrypted_value' },\n });\n }\n const [ivB64, tagB64, ctB64] = parts as [string, string, string];\n const iv = Buffer.from(ivB64, 'base64');\n const tag = Buffer.from(tagB64, 'base64');\n const ct = Buffer.from(ctB64, 'base64');\n if (iv.length !== IV_BYTES) throw new ConfigError({\n message: 'SecretVault: bad IV length',\n code: ERROR_CODES.CONFIG_PARSE_FAILED,\n context: { expected: IV_BYTES, actual: iv.length },\n });\n if (tag.length !== TAG_BYTES) throw new ConfigError({\n message: 'SecretVault: bad tag length',\n code: ERROR_CODES.CONFIG_PARSE_FAILED,\n context: { expected: TAG_BYTES, actual: tag.length },\n });\n const key = this.loadOrCreateKey();\n const decipher = createDecipheriv(ALGO, key, iv);\n decipher.setAuthTag(tag);\n const pt = Buffer.concat([decipher.update(ct), decipher.final()]);\n return pt.toString('utf8');\n }\n\n /**\n * Generate a new encryption key, write it to disk, and increment the key version.\n * After rotation, encrypt() emits the new version prefix (e.g. enc:v2:).\n * The caller must re-encrypt existing config values (see rotateConfigKeys()).\n */\n rotateKey(): { oldVersion: number; newVersion: number } {\n const oldVersion = this._keyVersion;\n const newKey = randomBytes(KEY_BYTES);\n const newVersion = oldVersion + 1;\n\n fs.mkdirSync(path.dirname(this.keyFile), { recursive: true });\n const passphrase = getVaultPassphrase();\n if (passphrase) {\n // Keep the rotated key passphrase-wrapped (v3) so rotation never\n // downgrades a protected key file to plaintext.\n writeKeyFileAtomicSync(this.keyFile, wrapDataKey(newKey, newVersion, passphrase));\n } else {\n // Write versioned key file: WSKV + version byte + key\n const keyFileBuf = Buffer.alloc(VERSIONED_KEY_FILE_SIZE);\n KEY_FILE_MAGIC.copy(keyFileBuf, 0);\n keyFileBuf[KEY_FILE_MAGIC.length] = newVersion;\n newKey.copy(keyFileBuf, KEY_FILE_MAGIC.length + 1);\n writeKeyFileAtomicSync(this.keyFile, keyFileBuf);\n }\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n\n this.key = newKey;\n this._keyVersion = newVersion;\n return { oldVersion, newVersion };\n }\n\n /**\n * If WRONGSTACK_VAULT_PASSPHRASE is set but the key on disk is still stored\n * unwrapped (legacy v1 / versioned v2), re-write it in passphrase-wrapped (v3)\n * form. The data key is preserved, so all existing ciphertext keeps\n * decrypting. Best-effort: a write failure leaves the working unwrapped file\n * in place and is not fatal to load.\n */\n private migrateToWrappedIfPassphrase(): void {\n const passphrase = getVaultPassphrase();\n if (!passphrase || !this.key) return;\n try {\n writeKeyFileAtomicSync(this.keyFile, wrapDataKey(this.key, this._keyVersion, passphrase));\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n } catch {\n // Non-fatal: the at-rest upgrade failed, but the loaded key is valid.\n }\n }\n\n private loadOrCreateKey(): Buffer {\n // readFileSync blocks the event loop, but this is a one-time cost per\n // process: the key is cached after the first load and reused for every\n // subsequent encrypt/decrypt. For CLI usage (single run \u2192 exit) this is\n // negligible. For server contexts (eternal autonomy, MCP server mode),\n // the first encrypt/decrypt call causes a brief (<1ms) event loop stall.\n // Prefer calling vault.encrypt('') during boot to warm the cache if this\n // is a concern in your deployment.\n if (this.key) return this.key;\n try {\n const buf = fs.readFileSync(this.keyFile);\n\n // Passphrase-wrapped (v3): unwrap with WRONGSTACK_VAULT_PASSPHRASE.\n // Checked first because its size/magic are distinct from the others.\n if (isWrappedKeyFile(buf)) {\n const { key, version } = unwrapDataKey(buf, this.keyFile);\n this.key = key;\n this._keyVersion = version;\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n return this.key;\n }\n\n // Detect key file format:\n if (buf.length === KEY_BYTES) {\n // Legacy v1: raw 32-byte key\n this.key = buf;\n this._keyVersion = 1;\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n // Upgrade to passphrase-wrapped at rest if a passphrase is configured.\n this.migrateToWrappedIfPassphrase();\n return this.key;\n }\n\n if (buf.length === VERSIONED_KEY_FILE_SIZE) {\n // Versioned v2+: WSKV magic + version byte + 32-byte key\n const magic = buf.subarray(0, KEY_FILE_MAGIC.length);\n if (!magic.equals(KEY_FILE_MAGIC)) {\n throw new ConfigError({\n message: `SecretVault: key file ${this.keyFile} has invalid magic header`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile: this.keyFile },\n });\n }\n const version = buf[KEY_FILE_MAGIC.length]!;\n const key = buf.subarray(KEY_FILE_MAGIC.length + 1);\n if (key.length !== KEY_BYTES) {\n throw new ConfigError({\n message: `SecretVault: key file ${this.keyFile} has wrong key size (${key.length} bytes, expected ${KEY_BYTES})`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile: this.keyFile, expectedBytes: KEY_BYTES, actualBytes: key.length },\n });\n }\n this.key = Buffer.from(key);\n this._keyVersion = version;\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n // Upgrade to passphrase-wrapped at rest if a passphrase is configured.\n this.migrateToWrappedIfPassphrase();\n return this.key;\n }\n\n // Wrong size \u2014 neither legacy nor versioned format\n throw new ConfigError({\n message:\n `SecretVault: key file ${this.keyFile} is ${buf.length} bytes ` +\n `(expected ${KEY_BYTES} for v1 or ${VERSIONED_KEY_FILE_SIZE} for v2+). ` +\n `Remove it manually to generate a new key.`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile: this.keyFile, expectedBytes: KEY_BYTES, actualBytes: buf.length },\n });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n // Create a fresh key. Use sync APIs so the constructor-free getter\n // remains synchronous from the caller's perspective.\n fs.mkdirSync(path.dirname(this.keyFile), { recursive: true });\n const key = randomBytes(KEY_BYTES);\n // When a passphrase is configured, a brand-new key is written wrapped (v3)\n // from the start; otherwise the legacy raw-32-byte format is preserved.\n const passphrase = getVaultPassphrase();\n const initialBytes = passphrase ? wrapDataKey(key, 1, passphrase) : key;\n // Use exclusive-create flag 'wx' to prevent races: if two processes race\n // to create the key file, only one succeeds and the loser gets EEXIST.\n try {\n fs.writeFileSync(this.keyFile, initialBytes, { mode: 0o600, flag: 'wx' });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'EEXIST') throw err;\n // Another process won the race \u2014 re-read what they wrote.\n const buf = fs.readFileSync(this.keyFile);\n if (isWrappedKeyFile(buf)) {\n const { key: winnerKey, version } = unwrapDataKey(buf, this.keyFile);\n this.key = winnerKey;\n this._keyVersion = version;\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n return this.key;\n }\n if (buf.length === KEY_BYTES) {\n // Legacy v1 format\n this.key = buf;\n this._keyVersion = 1;\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n return this.key;\n }\n if (buf.length === VERSIONED_KEY_FILE_SIZE) {\n // Versioned format\n const magic = buf.subarray(0, KEY_FILE_MAGIC.length);\n if (!magic.equals(KEY_FILE_MAGIC)) {\n throw new ConfigError({\n message: `SecretVault: key file ${this.keyFile} has invalid magic header`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile: this.keyFile },\n });\n }\n const version = buf[KEY_FILE_MAGIC.length]!;\n const winnerKey = buf.subarray(KEY_FILE_MAGIC.length + 1);\n this.key = Buffer.from(winnerKey);\n this._keyVersion = version;\n checkKeyFilePermissions(this.keyFile, { warn: (msg) => this.logWarn(msg) });\n return this.key;\n }\n throw new ConfigError({\n message:\n `SecretVault: key file ${this.keyFile} is ${buf.length} bytes ` +\n `(expected ${KEY_BYTES} for v1 or ${VERSIONED_KEY_FILE_SIZE} for v2+). ` +\n `Remove it manually to generate a new key.`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { keyFile: this.keyFile, expectedBytes: KEY_BYTES, actualBytes: buf.length },\n });\n }\n this.key = key;\n this._keyVersion = 1;\n return key;\n }\n}\n\n// The config-walking helpers (decryptConfigSecrets, encryptConfigSecrets,\n// isSecretField) live in config-secrets.ts \u2014 a crypto-free module \u2014 so that\n// chunks which only walk configs don't bundle the AES-GCM vault. Re-exported\n// here to keep this module's historical public API intact.\nexport { decryptConfigSecrets, encryptConfigSecrets, isSecretField } from './config-secrets.js';\n\n/**\n * Re-write a profile config (or any path) with all secret-bearing\n * fields encrypted. Used by the `wstack auth` subcommand.\n */\nexport async function rewriteConfigEncrypted(\n configPath: string,\n vault: SecretVault,\n patch?: Record<string, unknown>,\n): Promise<void> {\n let current: Record<string, unknown> = {};\n try {\n const raw = await fsp.readFile(configPath, 'utf8');\n current = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // start from empty\n }\n const merged = deepMerge(current, patch ?? {});\n const encrypted = encryptConfigSecrets(merged, vault);\n await fsp.mkdir(path.dirname(configPath), { recursive: true });\n // atomicWrite: torn write here would erase every saved encrypted API key.\n await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n await restrictFilePermissions(configPath);\n}\n\n/**\n * Scan a config file on disk for plaintext secret-bearing fields and\n * rewrite the file with them encrypted in place. Returns a count of how\n * many fields were migrated. Idempotent \u2014 calling on a fully-encrypted\n * file is a no-op and writes nothing. Used by the CLI on every boot so\n * users who had plaintext keys before the vault landed are upgraded\n * transparently.\n */\nexport async function migratePlaintextSecrets(\n configPath: string,\n vault: SecretVault,\n logger?: Pick<Logger, 'warn'>,\n): Promise<{ migrated: number; file: string }> {\n let raw: string;\n try {\n raw = await fsp.readFile(configPath, 'utf8');\n } catch {\n return { migrated: 0, file: configPath };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { migrated: 0, file: configPath };\n }\n const counter = { n: 0 };\n const migrated = walkCount(parsed, vault, counter);\n if (counter.n === 0) return { migrated: 0, file: configPath };\n // atomicWrite: runs on every boot for legacy users \u2014 torn write = wipe.\n await atomicWrite(configPath, JSON.stringify(migrated, null, 2), { mode: 0o600 });\n await restrictFilePermissions(\n configPath,\n logger ? { warn: (msg) => logger.warn(msg) } : undefined,\n );\n return { migrated: counter.n, file: configPath };\n}\n\n/**\n * Rotate the vault's encryption key and re-encrypt all secret-bearing\n * fields in a config file. This is the atomic key rotation operation:\n *\n * 1. Read the config file\n * 2. Decrypt all encrypted values with the old key\n * 3. Generate a new key (vault.rotateKey())\n * 4. Re-encrypt all values with the new key (new version prefix)\n * 5. Write the config file atomically\n *\n * Returns the number of fields re-encrypted and the version transition.\n * If the config file doesn't exist or has no encrypted fields, returns\n * { rotated: 0 } without modifying the key.\n */\nexport async function rotateConfigKeys(\n configPath: string,\n vault: RotatableSecretVault,\n logger?: Pick<Logger, 'warn' | 'info'>,\n): Promise<{ rotated: number; oldVersion: number; newVersion: number; file: string }> {\n const log = logger?.info ?? (() => {});\n const warn = logger?.warn ?? ((msg: string) => console.warn(msg));\n\n // Read the config file\n let raw: string;\n try {\n raw = await fsp.readFile(configPath, 'utf8');\n } catch {\n // No config file \u2014 just rotate the key without re-encrypting anything\n const { oldVersion, newVersion } = vault.rotateKey();\n log(`[secret-vault] Key rotated (v${oldVersion} \u2192 v${newVersion}) \u2014 no config file to re-encrypt`);\n return { rotated: 0, oldVersion, newVersion, file: configPath };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n warn(`[secret-vault] Config file ${configPath} is not valid JSON \u2014 skipping rotation`);\n return { rotated: 0, oldVersion: vault.keyVersion, newVersion: vault.keyVersion, file: configPath };\n }\n\n // Count encrypted fields and decrypt them\n const counter = { n: 0, failed: [] as string[] };\n const decrypted = walkDecryptCount(parsed, vault, counter);\n\n // Abort BEFORE rotating if any encrypted field could not be decrypted with\n // the current key. Rotation would discard the old key while these fields\n // still hold old-key ciphertext, and walkReencrypt skips already-encrypted\n // values \u2014 so they would become permanently undecryptable. Surface the\n // corruption and leave the key intact for the operator to investigate.\n if (counter.failed.length > 0) {\n throw new Error(\n `[secret-vault] Aborting key rotation: ${counter.failed.length} field(s) could not be decrypted ` +\n `with the current key and would be permanently lost on rotation: ${counter.failed.join(', ')}. ` +\n `Restore or remove these fields before rotating.`,\n );\n }\n\n if (counter.n === 0) {\n // No encrypted fields \u2014 just rotate the key\n const { oldVersion, newVersion } = vault.rotateKey();\n log(`[secret-vault] Key rotated (v${oldVersion} \u2192 v${newVersion}) \u2014 no encrypted fields to re-encrypt`);\n return { rotated: 0, oldVersion, newVersion, file: configPath };\n }\n\n // Rotate the key (generates new key, increments version)\n const { oldVersion, newVersion } = vault.rotateKey();\n\n // Re-encrypt all secret fields with the new key\n const reencrypted = walkReencrypt(decrypted, vault);\n\n // Write the config file atomically\n await atomicWrite(configPath, JSON.stringify(reencrypted, null, 2), { mode: 0o600 });\n await restrictFilePermissions(configPath, { warn });\n\n log(`[secret-vault] Key rotated (v${oldVersion} \u2192 v${newVersion}) \u2014 re-encrypted ${counter.n} field(s)`);\n return { rotated: counter.n, oldVersion, newVersion, file: configPath };\n}\n\n/**\n * Walk a config object, decrypt all encrypted values, and count them.\n * Returns a new object with decrypted values.\n *\n * `counter.failed` collects the key paths of any field that is encrypted but\n * could NOT be decrypted with the current key. These are left as-is (old\n * ciphertext). The caller MUST treat a non-empty `failed` list as a hard stop\n * before rotating: rotation discards the old key, and `walkReencrypt` skips\n * already-encrypted values, so a retained old-key ciphertext would become\n * permanently undecryptable. Surfacing it is strictly safer than entombing it.\n */\nfunction walkDecryptCount<T>(\n node: T,\n vault: SecretVault,\n counter: { n: number; failed: string[] },\n pathPrefix = '',\n): T {\n if (node === null || node === undefined) return node;\n if (typeof node !== 'object') return node;\n if (Array.isArray(node)) {\n return node.map((item, i) =>\n walkDecryptCount(item, vault, counter, `${pathPrefix}[${i}]`),\n ) as never as T;\n }\n const out: Record<string, unknown> = Object.create(null);\n for (const [k, v] of Object.entries(node as Record<string, unknown>)) {\n const keyPath = pathPrefix ? `${pathPrefix}.${k}` : k;\n if (typeof v === 'string' && vault.isEncrypted(v)) {\n try {\n out[k] = vault.decrypt(v);\n counter.n++;\n } catch {\n // Decryption failed \u2014 record the path and keep the old ciphertext.\n // The caller aborts rotation when counter.failed is non-empty, so\n // the old key is never discarded while this value still depends on it.\n counter.failed.push(keyPath);\n out[k] = v;\n }\n } else if (typeof v === 'object' && v !== null) {\n out[k] = walkDecryptCount(v, vault, counter, keyPath);\n } else {\n out[k] = v;\n }\n }\n return out as T;\n}\n\n/**\n * Walk a config object and re-encrypt all secret-bearing fields.\n * Unlike encryptConfigSecrets, this encrypts ALL string values that\n * were previously decrypted (they're now plaintext), not just those\n * matching the secret field pattern. This ensures we re-encrypt values\n * that were successfully decrypted in walkDecryptCount.\n */\nfunction walkReencrypt<T>(node: T, vault: SecretVault): T {\n if (node === null || node === undefined) return node;\n if (typeof node !== 'object') return node;\n if (Array.isArray(node)) {\n return node.map((item) => walkReencrypt(item, vault)) as never as T;\n }\n const out: Record<string, unknown> = Object.create(null);\n for (const [k, v] of Object.entries(node as Record<string, unknown>)) {\n if (typeof v === 'string' && isSecretField(k) && v.length > 0 && !vault.isEncrypted(v)) {\n // This was a decrypted secret \u2014 re-encrypt it\n out[k] = vault.encrypt(v);\n } else if (typeof v === 'object' && v !== null) {\n out[k] = walkReencrypt(v, vault);\n } else {\n out[k] = v;\n }\n }\n return out as T;\n}\n\n/**\n * Restrict a file to owner-only access. On POSIX this is chmod 0o600.\n * On Windows, chmod is a no-op \u2014 we use icacls to remove inherited\n * permissions and grant only the current user. Failures are logged\n * but not thrown so callers are not blocked on unsupported platforms.\n */\nasync function restrictFilePermissions(\n filePath: string,\n opts?: { warn?: (msg: string) => void },\n): Promise<void> {\n const warn = opts?.warn ?? ((msg: string) => console.warn(msg));\n if (process.platform === 'win32') {\n try {\n const { execFile } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const execFileAsync = promisify(execFile);\n const user = windowsAccountName();\n if (!user) {\n warn(\n `[secret-vault] Could not determine the current Windows user for ${filePath}; skipping icacls hardening.`,\n );\n return;\n }\n // Remove inherited ACEs, grant full control only to current user.\n await execFileAsync('icacls', [filePath, '/inheritance:r', '/grant:r', `${user}:(F)`]);\n } catch {\n // Best-effort: icacls may not be available in all environments.\n warn(\n `[secret-vault] Could not restrict permissions on ${filePath} \u2014 config file may be readable by other users on this system.`,\n );\n }\n } else {\n try {\n await fsp.chmod(filePath, 0o600);\n } catch {\n // Best-effort\n }\n }\n}\n\nfunction windowsAccountName(): string | undefined {\n const username = process.env.USERNAME || process.env.USER;\n if (!username || username.includes('\\0')) return undefined;\n const domain = process.env.USERDOMAIN;\n if (domain && !domain.includes('\\0')) return `${domain}\\\\${username}`;\n return username;\n}\n\nfunction walkCount<T>(node: T, vault: SecretVault, counter: { n: number }): T {\n if (node === null || node === undefined) return node;\n if (typeof node !== 'object') return node;\n if (Array.isArray(node)) {\n return node.map((item) => walkCount(item, vault, counter)) as never as T;\n }\n const out: Record<string, unknown> = Object.create(null);\n for (const [k, v] of Object.entries(node as Record<string, unknown>)) {\n if (typeof v === 'string' && isSecretField(k) && !vault.isEncrypted(v) && v.length > 0) {\n out[k] = vault.encrypt(v);\n counter.n++;\n } else if (typeof v === 'object' && v !== null) {\n out[k] = walkCount(v, vault, counter);\n } else {\n out[k] = v;\n }\n }\n return out as T;\n}\n\n/** Keys that, when written into a plain object, can poison the prototype\n * chain. We never want user config to carry these. */\nimport { deepMerge } from '../utils/deep-merge.js';\n", "/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n", "import { toErrorMessage } from '../utils/error.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "/**\n * SecretVault encrypts secrets-at-rest in config files. The wire format is\n * `enc:v<N>:<base64-iv>:<base64-tag>:<base64-ciphertext>` where `<N>` is the\n * key version used for encryption. Plaintext strings (those that do not match\n * this prefix) are passed through unchanged so that existing configs and\n * env-var-derived values keep working.\n *\n * Key rotation produces a new key and re-encrypts all secrets under it.\n * After rotation, `encrypt()` emits the new version prefix (e.g. `enc:v2:`)\n * and `decrypt()` accepts any version prefix \u2014 it uses the current key\n * regardless, since rotation re-encrypts every value atomically.\n *\n * The vault is intentionally NOT designed to defeat a determined local\n * attacker who can read both the config file and the key file \u2014 that level\n * of secrecy needs the OS keychain. The goal is to keep keys from being\n * visible in screen shares, accidental log captures, and `cat config.json`\n * over someone's shoulder.\n */\nexport interface SecretVault {\n encrypt(plaintext: string): string;\n decrypt(value: string): string;\n isEncrypted(value: string): boolean;\n /** Current key version. Starts at 1; incremented by `rotateKey()`. */\n readonly keyVersion: number;\n}\n\n/**\n * RotatableSecretVault extends SecretVault with key rotation support.\n * `rotateKey()` generates a fresh key, writes it to disk, and increments\n * the key version. All subsequent `encrypt()` calls use the new version\n * prefix. The caller is responsible for re-encrypting existing config\n * values (see `rotateConfigKeys()`).\n */\nexport interface RotatableSecretVault extends SecretVault {\n rotateKey(): { oldVersion: number; newVersion: number };\n}\n\n/** Legacy v1 prefix \u2014 values encrypted before key rotation was introduced. */\nexport const ENCRYPTED_PREFIX = 'enc:v1:';\n\n/**\n * Match any versioned encrypted value prefix: `enc:v1:`, `enc:v2:`, etc.\n * Used by `isEncrypted()` and `decrypt()` to handle all versions uniformly.\n */\nexport const ENCRYPTED_PREFIX_PATTERN = /^enc:v(\\d+):/;\n\n/**\n * Return the encrypted prefix for a given key version.\n * @example encryptedPrefixForVersion(1) // 'enc:v1:'\n * @example encryptedPrefixForVersion(2) // 'enc:v2:'\n */\nexport function encryptedPrefixForVersion(version: number): string {\n return `enc:v${version}:`;\n}\n\n/**\n * Parse the key version from an encrypted value string.\n * Returns undefined if the string is not an encrypted value.\n */\nexport function parseEncryptedVersion(value: string): number | undefined {\n const match = value.match(ENCRYPTED_PREFIX_PATTERN);\n return match ? Number.parseInt(match[1]!, 10) : undefined;\n}\n\n/**\n * No-op SecretVault that passes values through unchanged.\n * Used in contexts where encryption is not needed \u2014 e.g. reading/writing\n * config sections that contain no secret fields (models, settings, etc.).\n */\nexport const noOpVault: SecretVault = {\n encrypt: (v) => v,\n decrypt: (v) => v,\n isEncrypted: () => false,\n keyVersion: 1,\n};\n", "import type { FileHandle } from 'node:fs/promises';\nimport {\n type AtomicWriteOptions,\n createPersistencePrimitives,\n type FileLockOptions,\n} from '@wrongstack/persistence';\nimport { FsError } from '../types/errors.js';\n\nexport type { AtomicWriteOptions, FileLockOptions } from '@wrongstack/persistence';\n\nconst primitives = createPersistencePrimitives({\n createLockTimeoutError: ({ targetPath, timeoutMs }) =>\n new FsError({\n message: `Timed out waiting for file lock: ${targetPath}`,\n code: 'FS_ATOMIC_WRITE_FAILED',\n path: targetPath,\n context: { timeoutMs },\n }),\n});\n\nexport const atomicWrite: (\n targetPath: string,\n content: string | Uint8Array,\n opts?: AtomicWriteOptions,\n) => Promise<void> = primitives.atomicWrite;\n/**\n * Atomic replace that streams its new contents instead of taking them as one\n * buffer. Use when the replacement is large enough that materializing it would\n * itself be the memory problem (log rotation, tail compaction).\n */\nexport const atomicReplaceWithWriter: <T>(\n targetPath: string,\n write: (handle: FileHandle) => Promise<T>,\n opts?: AtomicWriteOptions,\n) => Promise<T> = primitives.atomicReplaceWithWriter;\nexport const ensureDir: (dir: string) => Promise<void> = primitives.ensureDir;\nexport const withFileLock: <T>(\n targetPath: string,\n fn: () => Promise<T>,\n opts?: FileLockOptions,\n) => Promise<T> = primitives.withFileLock;\n", "import type { SecretVault } from '../types/secret-vault.js';\n\n/**\n * Config-walking secret helpers, split out of secret-vault.ts so that\n * consumers which only need the walk logic (config loader, provider-config\n * watcher) don't pull the AES-GCM vault implementation \u2014 and its node:crypto\n * imports \u2014 into their bundle chunk. Everything here operates purely through\n * the `SecretVault` interface.\n */\n\n/**\n * Walk a Config-shaped object and decrypt any apiKey-like fields in place,\n * returning a new object. Used by the config loader so the rest of the\n * system never has to know about the wire format.\n *\n * @param warn \u2014 callback for decryption warnings. Defaults to `console.warn`\n * for backward compatibility; pass `logger.warn` when a structured logger\n * is available (preferred in long-running/server contexts).\n */\nexport function decryptConfigSecrets<T>(\n cfg: T,\n vault: SecretVault,\n opts?: { warn?: (msg: string) => void },\n): T {\n const warn = opts?.warn ?? ((msg: string) => console.warn(msg));\n // A single corrupted/malformed encrypted field should not kill the entire\n // config load. Swallow per-field decrypt errors (zero the field so callers\n // see \"missing key\" instead of holding ciphertext) and surface a warning.\n return walk(cfg, vault, (v, key) => {\n try {\n return vault.decrypt(v);\n } catch (err) {\n warn(\n `[secret-vault] Failed to decrypt \"${key}\": ${err instanceof Error ? err.message : err}`,\n );\n return '';\n }\n });\n}\n\nexport function encryptConfigSecrets<T>(\n cfg: T,\n vault: SecretVault,\n _opts?: { warn?: (msg: string) => void },\n): T {\n return walk(cfg, vault, (v) => vault.encrypt(v));\n}\n\nfunction walk<T>(node: T, vault: SecretVault, transform: (s: string, key: string) => string): T {\n if (node === null || node === undefined) return node;\n if (typeof node !== 'object') return node;\n if (Array.isArray(node)) {\n return node.map((item) => walk(item, vault, transform)) as never as T;\n }\n const out: Record<string, unknown> = Object.create(null);\n for (const [k, v] of Object.entries(node as Record<string, unknown>)) {\n if (typeof v === 'string' && isSecretField(k)) {\n out[k] = transform(v, k);\n } else if (typeof v === 'object' && v !== null) {\n out[k] = walk(v, vault, transform);\n } else {\n out[k] = v;\n }\n }\n return out as T;\n}\n\n/**\n * A key is treated as secret-bearing if its name (case-insensitive) contains\n * one of these tokens. Captures common variants like `apiKey`, `authToken`,\n * `refreshToken`, `sessionKey`, `password`, `client_secret`, `bearer`, etc.\n * Use a named field with `isSecret: false` annotation if you must opt out \u2014\n * see `NON_SECRET_OVERRIDES` below.\n */\nconst SECRET_KEY_PATTERN =\n /(?:apikey|api_key|authtoken|auth_token|bearer|secret|password|passwd|pwd|refreshtoken|refresh_token|sessionkey|session_key|access[_-]?token|private[_-]?key|token\\b)/i;\n\n// Field names that contain the literal substring \"key\" but are not secrets.\n// Keep this list short; the substring rule itself is intentionally narrow.\nconst NON_SECRET_OVERRIDES = new Set(['publickey', 'public_key']);\n\nexport function isSecretField(name: string): boolean {\n const lc = name.toLowerCase();\n if (NON_SECRET_OVERRIDES.has(lc)) return false;\n return SECRET_KEY_PATTERN.test(lc);\n}\n", "/**\n * Deep merge utility \u2014 safely merges nested objects with configurable\n * conflict resolution, array merging, and prototype-pollution guarding.\n *\n * Used by:\n * - config-loader (config layer merging with primitive-array concatenation)\n * - secret-vault (config patching)\n * - json-path (json_merge tool with prefer-base / prefer-patch semantics)\n *\n * @module utils/deep-merge\n */\n\n// ---------------------------------------------------------------------------\n// Prototype-pollution guard \u2014 shared set of forbidden __proto__ keys\n// ---------------------------------------------------------------------------\n\nexport const FORBIDDEN_PROTO_KEYS = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n '__defineGetter__',\n '__defineSetter__',\n '__lookupGetter__',\n '__lookupSetter__',\n]);\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** True when every element is a primitive or null (no nested objects/arrays). */\nexport function isPrimitiveArray(a: unknown[]): boolean {\n return a.every((v) => v === null || (typeof v !== 'object' && typeof v !== 'function'));\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface DeepMergeOptions {\n /**\n * Which side wins on collision for scalars and arrays.\n *\n * - `'prefer-patch'` (default): patch value replaces base value.\n * - `'prefer-base'`: base value is kept, patch value is ignored.\n */\n conflictResolution?: 'prefer-base' | 'prefer-patch';\n\n /**\n * How to handle array values.\n *\n * - `'replace'` (default): patch array replaces base array entirely.\n * - `'concat-primitives'`: when both values are primitive arrays,\n * they are concatenated and deduped (via Set). Non-primitive\n * arrays still replace the base wholesale.\n */\n arrayMode?: 'replace' | 'concat-primitives';\n\n /**\n * Skip prototype-pollution keys (`__proto__`, `constructor`, etc.).\n * Enabled by default. Only disable when you control both inputs\n * and the keyset (e.g. when merging trusted JSON schemas).\n */\n protectProto?: boolean;\n\n /**\n * Optional callback fired when a non-primitive (object) array is\n * replaced wholesale (only relevant with `arrayMode: 'concat-primitives'`).\n * Receives the key name, existing array length, and patch array length.\n * Used by config-loader for debug logging.\n */\n onNonPrimitiveArrayReplace?: (\n key: string,\n existingLen: number,\n patchLen: number,\n ) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively merge `patch` into `base`, returning a new object.\n *\n * - Nested plain objects are merged recursively.\n * - Arrays are handled per `options.arrayMode`.\n * - Scalar collisions are resolved per `options.conflictResolution`.\n * - `null` and non-object values in `patch` replace the base value\n * (unless `conflictResolution` is `'prefer-base'`).\n * - Keys in `base` that are absent from `patch` are preserved.\n * - `FORBIDDEN_PROTO_KEYS` are skipped in the patch (unless\n * `options.protectProto` is set to `false`).\n *\n * The function is generic over `T extends Record<string, unknown>` for\n * callers that pass typed config objects, but the runtime signature\n * also accepts `unknown` inputs (used by the json-path plugin).\n */\nexport function deepMerge<T extends Record<string, unknown>>(\n base: T,\n patch: Record<string, unknown>,\n options?: DeepMergeOptions,\n): T;\n\nexport function deepMerge(\n base: unknown,\n patch: unknown,\n options?: DeepMergeOptions,\n): unknown;\n\nexport function deepMerge(\n base: unknown,\n patch: unknown,\n options: DeepMergeOptions = {},\n): unknown {\n const {\n conflictResolution = 'prefer-patch',\n arrayMode = 'replace',\n protectProto = true,\n onNonPrimitiveArrayReplace,\n } = options;\n\n // Non-object / null handling \u2014 delegate to conflict resolution.\n if (typeof base !== 'object' || base === null) {\n return conflictResolution === 'prefer-patch' ? patch : base;\n }\n if (typeof patch !== 'object' || patch === null) {\n return conflictResolution === 'prefer-patch' ? patch : base;\n }\n\n // Arrays \u2014 handled *before* the object merge so array-of-objects\n // aren't accidentally treated as plain records.\n if (Array.isArray(base) && Array.isArray(patch)) {\n if (\n arrayMode === 'concat-primitives' &&\n isPrimitiveArray(base) &&\n isPrimitiveArray(patch)\n ) {\n return [...new Set([...base, ...patch])];\n }\n return conflictResolution === 'prefer-patch' ? patch : base;\n }\n\n // If only one side is an array, treat as scalar collision.\n if (Array.isArray(base) || Array.isArray(patch)) {\n return conflictResolution === 'prefer-patch' ? patch : base;\n }\n\n // Plain object merge.\n const baseObj = base as Record<string, unknown>;\n const patchObj = patch as Record<string, unknown>;\n const out: Record<string, unknown> = { ...baseObj };\n\n for (const [k, v] of Object.entries(patchObj)) {\n if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;\n\n const existing = out[k];\n if (\n v !== null &&\n typeof v === 'object' &&\n !Array.isArray(v) &&\n existing !== null &&\n typeof existing === 'object' &&\n !Array.isArray(existing)\n ) {\n // Recursive merge for nested plain objects.\n out[k] = deepMerge(existing, v, options);\n } else if (Array.isArray(v) && Array.isArray(existing)) {\n // Delegate to top-level array handling so arrayMode\n // (e.g. 'concat-primitives') applies to nested arrays too.\n // Fire debug hook when a non-primitive array replaces an existing\n // array (for non-primitive arrays, concat-primitives is a no-op and\n // the result is always a wholesale replacement).\n if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {\n onNonPrimitiveArrayReplace(k, existing.length, v.length);\n }\n out[k] = deepMerge(existing, v, options);\n } else if (v !== undefined) {\n // Fire debug hook when a non-primitive (object) array replaces an\n // existing value in concat-primitives mode.\n if (\n onNonPrimitiveArrayReplace &&\n Array.isArray(v) &&\n !isPrimitiveArray(v)\n ) {\n const existingLen = Array.isArray(existing) ? existing.length : 0;\n onNonPrimitiveArrayReplace(k, existingLen, v.length);\n }\n out[k] = v;\n }\n // When v === undefined, leave the existing value untouched\n // (this matches config-loader's behaviour: undefined in patch\n // means \"don't change this key\").\n }\n\n return out;\n}\n", "import * as fs from 'node:fs/promises';\nimport type { EventBus } from '../kernel/events.js';\nimport { decryptConfigSecrets } from '../security/config-secrets.js';\nimport type { Config, ConfigLoader, SyncConfig } from '../types/config.js';\nimport {\n DEFAULT_CONTEXT_WINDOW_MODE_ID,\n isContextWindowModeSelectionId,\n listContextWindowModes,\n normalizeContextWindowModeId,\n} from '../types/context-window.js';\nimport { ConfigError, ERROR_CODES } from '../types/errors.js';\nimport type { Logger } from '../types/logger.js';\nimport type { SecretVault } from '../types/secret-vault.js';\nimport { atomicWrite, withFileLock } from '../utils/atomic-write.js';\nimport { backupConfigFile } from '../utils/config-backup.js';\nimport { type DeepMergeOptions, deepMerge as deepMergeCore } from '../utils/deep-merge.js';\nimport { toErrorMessage } from '../utils/error.js';\nimport { safeParse } from '../utils/safe-json.js';\nimport type { WstackPaths } from '../utils/wstack-paths.js';\nimport { safeProfileName } from '../utils/wstack-paths.js';\nimport { isBootstrapOnly } from './config-loader/bootstrap.js';\nimport { fillMissingDefaults, isPlainRecord } from './config-loader/default-repair.js';\nimport { CONFIG_BEHAVIOR_DEFAULTS } from './config-loader/defaults.js';\nimport { storageErrorString } from './config-loader/diagnostics.js';\nimport { ENV_MAP, envBoolOptional, type PartialConfig } from './config-loader/env-overrides.js';\nimport { stripUnsafeInProjectFields } from './config-loader/in-project-policy.js';\nimport { normalizeInlineProviderModels } from './config-loader/inline-provider-models.js';\nimport {\n migrateLegacySuperMemoryKey,\n removeLegacySageEngine,\n} from './config-loader/legacy-sage-migration.js';\nimport { samePath } from './config-loader/path-identity.js';\nimport type {\n ConfigLoaderOptions,\n ConfigSource,\n MemoizedConfigSource,\n} from './config-loader/types.js';\n\nexport {\n type ConfigDefaultRepair,\n type ConfigDefaultRepairReport,\n fillMissingDefaults,\n repairConfigDefaults,\n} from './config-loader/default-repair.js';\nexport { CONFIG_BEHAVIOR_DEFAULTS } from './config-loader/defaults.js';\nexport {\n assertInProjectAllowListComplete,\n stripUnsafeInProjectFields,\n} from './config-loader/in-project-policy.js';\nexport type {\n ConfigLoaderOptions,\n ConfigSource,\n MemoizedConfigSource,\n} from './config-loader/types.js';\n\n/**\n * Config-layer deep merge \u2014 delegates to the shared utility with\n * `arrayMode: 'concat-primitives'` and optional debug logging for\n * non-primitive array replacements.\n */\nfunction deepMerge<T, TPatch extends object>(base: T, patch: TPatch): T {\n const opts: DeepMergeOptions = { arrayMode: 'concat-primitives' };\n if (envBoolOptional(process.env.WRONGSTACK_DEBUG_CONFIG)) {\n opts.onNonPrimitiveArrayReplace = (key, existingLen, patchLen) => {\n console.warn(\n `[config] Non-primitive array for \"${key}\" replaced (global + local config merge). ` +\n `Global entries: ${existingLen}, local entries: ${patchLen}.`,\n );\n };\n }\n return deepMergeCore(\n base as Record<string, unknown>,\n patch as Record<string, unknown>,\n opts,\n ) as T;\n}\n\nexport class DefaultConfigLoader implements ConfigLoader {\n private readonly paths: WstackPaths;\n private readonly strict: boolean;\n private readonly vault: SecretVault | undefined;\n private readonly extraSources: ConfigSource[];\n private readonly events: EventBus | undefined;\n private readonly traceId: string | undefined;\n private readonly logger: Logger | undefined;\n private readonly jsonCache = new Map<string, MemoizedConfigSource>();\n\n constructor(opts: ConfigLoaderOptions) {\n this.paths = opts.paths;\n this.strict = opts.strict ?? false;\n this.vault = opts.vault;\n this.extraSources = opts.sources ?? [];\n this.events = opts.events;\n this.traceId = opts.traceId;\n this.logger = opts.logger;\n }\n\n /**\n * Emit a structured warning. Uses the configured Logger when available;\n * falls back to console.warn(JSON) so warnings are never silently dropped\n * during early boot (before a Logger is constructed).\n */\n private logWarn(msg: string, ctx?: Record<string, unknown>): void {\n if (this.logger) {\n this.logger.warn(msg, ctx);\n } else {\n console.warn(JSON.stringify({ ...ctx, message: msg, timestamp: new Date().toISOString() }));\n }\n }\n\n async load(\n opts: {\n cliFlags?: Partial<Config> | undefined;\n cwd?: string | undefined;\n skipIdentityValidation?: boolean;\n } = {},\n ): Promise<Config> {\n let cfg: PartialConfig = { ...CONFIG_BEHAVIOR_DEFAULTS } as PartialConfig;\n\n // Materialize behavior/settings defaults into the active profile before\n // env vars or CLI flags are applied. The root config remains bootstrap-only.\n await this.ensureGlobalDefaults();\n\n // Layer 2, 3 (profile), 4 & 4b: global bootstrap + profile + project-local +\n // in-project config. The global bootstrap (~/.wrongstack/config.json) is now\n // a thin file containing just version and activeProfile. User settings live in the\n // active profile's config: ~/.wrongstack/profiles/<name>/config.json.\n //\n // inProjectConfig (<project>/.wrongstack/config.json) merges AFTER\n // projectLocalConfig so it takes priority (user-intended > auto-cached).\n //\n // When the project root *is* the user's home (e.g. launching from `~`),\n // `<projectRoot>/.wrongstack/config.json` resolves to the very same file as\n // the trusted global bootstrap. Reading it again as the untrusted in-project\n // layer would strip `provider`/`apiKey`/\u2026 from the user's *own* file and\n // emit a spurious `config.in_project_unsafe_fields_ignored` warning \u2014 even\n // though the trusted global layer already merged those fields. Skip the\n // in-project read entirely on collision so trust isn't applied to a file\n // the user fully controls.\n const inProjectCollides =\n samePath(this.paths.inProjectConfig, this.paths.globalConfig) ||\n samePath(this.paths.inProjectConfig, this.paths.projectLocalConfig);\n const [bootstrap, local, inProject] = await Promise.all([\n this.readJson(this.paths.globalConfig),\n this.readJson(this.paths.projectLocalConfig),\n inProjectCollides\n ? Promise.resolve({} as PartialConfig)\n : this.readJson(this.paths.inProjectConfig),\n ]);\n // The root config is bootstrap metadata, never a settings layer. Even if\n // another process accidentally writes settings into it, only these two\n // keys may affect the runtime. Legacy settings are migrated separately,\n // and only while the selected profile file does not yet exist.\n const bootstrapMetadata = {\n ...(typeof (bootstrap as { version?: unknown }).version === 'number'\n ? { version: (bootstrap as { version: number }).version }\n : {}),\n ...(typeof (bootstrap as { activeProfile?: unknown }).activeProfile === 'string'\n ? { activeProfile: safeProfileName((bootstrap as { activeProfile: string }).activeProfile) }\n : {}),\n } as PartialConfig;\n cfg = deepMerge(cfg, bootstrapMetadata);\n\n // Layer 2b: active profile config.\n // Extract the active profile name from the bootstrap config (default: 'default').\n const profileName = safeProfileName(\n (bootstrap as { activeProfile?: string | undefined }).activeProfile,\n );\n const profileCfg = await this.readJson(this.paths.profileConfig(profileName));\n if (Object.keys(profileCfg).length > 0) {\n // Bootstrap metadata is authoritative only in the root config. Ignore\n // stale copies in profile files so a profile cannot select another profile.\n const profileSettings = { ...profileCfg } as Record<string, unknown>;\n delete profileSettings['version'];\n delete profileSettings['activeProfile'];\n cfg = deepMerge(cfg, profileSettings as PartialConfig);\n }\n\n // Bootstrap metadata is authoritative only in the root config. A stale\n // project-private override must not make later persistence target a\n // different profile than the one whose settings were loaded above.\n const localSettings = { ...local } as Record<string, unknown>;\n delete localSettings['version'];\n delete localSettings['activeProfile'];\n cfg = deepMerge(cfg, localSettings as PartialConfig);\n\n // The in-project config is repo-committed and therefore attacker-\n // controllable. Strip credential/endpoint/code-execution fields before\n // merging so a malicious repo cannot redirect the provider endpoint\n // (API-key exfiltration) or auto-run an MCP server / hook (RCE) on launch.\n cfg = deepMerge(\n cfg,\n stripUnsafeInProjectFields(\n inProject,\n this.paths.inProjectConfig,\n this.logger ? (msg: string) => this.logger!.warn(msg) : undefined,\n ),\n );\n\n // Layer 4: env vars\n for (const [key, fn] of Object.entries(ENV_MAP)) {\n const v = process.env[key];\n if (v) fn(cfg, v);\n }\n\n // Layer 5: extra sources \u2014 sorted by priority (lowest first).\n // When priorities tie, sort by name for deterministic order.\n const sorted = [...this.extraSources].sort((a, b) => {\n const pd = (a.priority ?? 50) - (b.priority ?? 50);\n if (pd !== 0) return pd;\n return a.name.localeCompare(b.name);\n });\n for (const src of sorted) {\n try {\n const patch = await src.read();\n if (patch && Object.keys(patch).length > 0) {\n cfg = deepMerge(cfg, patch);\n }\n } catch (err) {\n // Best-effort: skip failing sources so one bad source doesn't block boot.\n this.logWarn('Config source load failed', {\n event: 'config.source_load_failed',\n source: src.name,\n message: toErrorMessage(err),\n });\n }\n }\n\n // Layer 6: CLI flags\n if (opts.cliFlags) {\n cfg = deepMerge(cfg, opts.cliFlags);\n }\n\n // Normalize model.dev-style inline provider model objects only after all\n // config layers and CLI flags have merged. Downstream routing keeps its\n // canonical `models: string[]` contract; metadata lands in `customModels`.\n normalizeInlineProviderModels(cfg as Record<string, unknown>, (message, context) =>\n this.logWarn(message, context),\n );\n\n // Decrypt apiKey-like fields if a vault is configured.\n if (this.vault) {\n cfg = decryptConfigSecrets(cfg, this.vault);\n }\n\n // Multi-key resolution: when a provider has `apiKeys[]` configured,\n // mirror the active entry into `apiKey` so downstream construction\n // code (provider registry, wire adapters) needs no changes. Honors\n // `activeKey` (by label), else falls back to the first entry. A\n // pre-existing `apiKey` set by env/CLI flags wins so an explicit\n // override still beats the saved list.\n if (cfg.providers) {\n for (const pcfg of Object.values(cfg.providers)) {\n if (!pcfg || typeof pcfg !== 'object') continue;\n const rawKeys = (pcfg as { apiKeys?: unknown | undefined }).apiKeys;\n if (!Array.isArray(rawKeys) || rawKeys.length === 0) continue;\n // Each apiKeys entry came from arbitrary JSON. Filter to entries\n // that actually have a string apiKey + label so a malformed array\n // (null entry, missing field) doesn't crash the .find / chosen.apiKey\n // path below.\n const keys = rawKeys.filter(\n (k): k is { label: string; apiKey: string } =>\n !!k &&\n typeof k === 'object' &&\n typeof (k as { label?: unknown | undefined }).label === 'string' &&\n typeof (k as { apiKey?: unknown | undefined }).apiKey === 'string',\n );\n if (keys.length === 0) continue;\n const existing = (pcfg as { apiKey?: string | undefined }).apiKey;\n if (existing && existing.length > 0) continue;\n const activeLabel = (pcfg as { activeKey?: string | undefined }).activeKey;\n const chosen = activeLabel\n ? (keys.find((k) => k.label === activeLabel) ?? keys[0])\n : keys[0];\n if (chosen?.apiKey) {\n (pcfg as { apiKey?: string | undefined }).apiKey = chosen.apiKey;\n }\n }\n }\n\n // `Sage.storage.engine` used to select JSONL. SQLite is now the\n // sole backend, so ignore the retired key from every config layer.\n removeLegacySageEngine(cfg as Record<string, unknown>);\n this.validateBehavior(cfg);\n if (this.strict && !opts.skipIdentityValidation) {\n this.validateIdentity(cfg);\n }\n // In strict mode, validateIdentity has confirmed provider/model are set;\n // it's safe to assert the full Config contract. In non-strict mode the\n // caller (e.g. early-boot wizard) accepts a Partial and constructs the\n // provider later, so we deliberately return without the cast.\n return Object.freeze(cfg) as Config;\n }\n\n /** Check whether a config object contains only the two bootstrap keys. */\n private static isBootstrapOnly(config: Record<string, unknown>): boolean {\n return isBootstrapOnly(config);\n }\n\n private async ensureGlobalDefaults(): Promise<void> {\n const fp = this.paths.globalConfig;\n const t0 = Date.now();\n try {\n await withFileLock(fp, async () => {\n let parsed: Record<string, unknown>;\n let fileExisted = true;\n try {\n const raw = await fs.readFile(fp, 'utf8');\n const result = safeParse<unknown>(raw);\n if (!result.ok || !isPlainRecord(result.value)) {\n return;\n }\n parsed = result.value;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.events?.emit('storage.error', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'ensure_defaults',\n outcome: 'failure',\n error: storageErrorString(err),\n recoverable: false,\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n this.logWarn('Config defaults read failed', {\n event: 'config.defaults_read_failed',\n path: fp,\n message: toErrorMessage(err),\n });\n return;\n }\n fileExisted = false;\n parsed = {};\n }\n\n // Do not silently normalize an explicit unsupported bootstrap schema.\n // Leave it intact so load() can surface the version error to the user.\n if (parsed['version'] !== undefined && parsed['version'] !== 1) return;\n\n const rawProfileName = (parsed as { activeProfile?: string | undefined }).activeProfile;\n const profileName = safeProfileName(rawProfileName);\n const profileFp = this.paths.profileConfig(profileName);\n\n // Run before trimming so a genuinely legacy flat config can be moved\n // into a missing profile. Once a profile file exists, root-level\n // settings are ignored rather than merged into the active profile.\n await this.ensureProfileConfig(profileFp, parsed, fileExisted);\n\n // Bootstrap config now only stores version + activeProfile.\n // Full behavior defaults go into the profile config instead.\n const bootstrap: Record<string, unknown> = {\n version: 1,\n activeProfile: profileName,\n };\n\n let needsBootstrapWrite = false;\n // If version is missing or wrong, write the bootstrap.\n if ((parsed as { version?: number | undefined }).version !== 1) {\n needsBootstrapWrite = true;\n }\n // If activeProfile is missing from the existing parsed config, flag it.\n if (parsed.activeProfile === undefined || parsed.activeProfile !== profileName) {\n needsBootstrapWrite = true;\n }\n // If the bootstrap has extra keys beyond version+activeProfile, trim it.\n if (!DefaultConfigLoader.isBootstrapOnly(parsed)) {\n needsBootstrapWrite = true;\n }\n\n if (needsBootstrapWrite) {\n // Back up the current root config before overwriting\n await backupConfigFile(fp, this.paths);\n await atomicWrite(fp, JSON.stringify(bootstrap, null, 2), { mode: 0o600 });\n this.events?.emit('storage.write', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'ensure_defaults',\n outcome: 'success',\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n }\n });\n } catch (err) {\n this.events?.emit('storage.error', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'ensure_defaults',\n outcome: 'failure',\n error: storageErrorString(err),\n recoverable: false,\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n this.logWarn('Config defaults write failed', {\n event: 'config.defaults_write_failed',\n path: fp,\n message: toErrorMessage(err),\n });\n }\n }\n\n /**\n * Ensure a profile config file exists at the given path.\n * On first boot: migrate content from the old flat global config, or seed\n * with behavior defaults. Subsequent boots: fill any missing keys from\n * CONFIG_BEHAVIOR_DEFAULTS (keeping user settings intact).\n *\n * Once a profile file exists, settings found in the root bootstrap are\n * ignored. This prevents stale or accidentally-written root values from\n * becoming a hidden settings source alongside profiles.\n */\n private async ensureProfileConfig(\n profileFp: string,\n oldGlobalParsed: Record<string, unknown>,\n oldFileExisted: boolean,\n ): Promise<void> {\n const t0 = Date.now();\n\n // No nested file lock: the profile write is idempotent (same content from\n // all writers) and atomicWrite handles concurrent writes atomically on\n // every platform. Using withFileLock here caused a second lock acquisition\n // inside the outer ensureGlobalDefaults() lock \u2014 under high concurrency\n // (50+ peers) the nested lock could time out, silently aborting the\n // migration and leaving the bootstrap overstuffed forever.\n let parsed: Record<string, unknown>;\n let existed = true;\n try {\n const raw = await fs.readFile(profileFp, 'utf8');\n const result = safeParse<unknown>(raw);\n if (!result.ok || !isPlainRecord(result.value)) {\n this.logWarn('Profile config parse failed \u2014 falling back to defaults', {\n event: 'config.profile_parse_failed',\n path: profileFp,\n });\n parsed = {};\n } else {\n parsed = result.value;\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.logWarn('Profile config read failed', {\n event: 'config.profile_read_failed',\n path: profileFp,\n message: toErrorMessage(err),\n });\n return;\n }\n existed = false;\n parsed = {};\n }\n\n const removedLegacyEngine = removeLegacySageEngine(parsed);\n\n // Migration from old flat config to profile: If the old global config\n // existed and had any setting at all (can be just `version` + one user\n // setting like `mcpServers`), promote them into the new profile config.\n //\n let seed: Record<string, unknown>;\n if (!existed && oldFileExisted && Object.keys(oldGlobalParsed).length >= 1) {\n // Copy old global content into the profile, excluding bootstrap-only fields.\n seed = { ...oldGlobalParsed };\n delete seed['activeProfile'];\n removeLegacySageEngine(seed);\n // Fill in any missing behavior defaults.\n const filled = fillMissingDefaults(seed, CONFIG_BEHAVIOR_DEFAULTS as Record<string, unknown>);\n seed = filled.value;\n } else {\n // Normal boot: fill missing defaults on existing (or empty) profile.\n const filled = fillMissingDefaults(\n parsed,\n CONFIG_BEHAVIOR_DEFAULTS as Record<string, unknown>,\n );\n if (!filled.changed && !removedLegacyEngine) return; // Nothing to write\n seed = filled.value;\n }\n\n await backupConfigFile(profileFp, this.paths);\n await atomicWrite(profileFp, JSON.stringify(seed, null, 2), { mode: 0o600 });\n this.events?.emit('storage.write', {\n sessionId: '~config~',\n store: 'config',\n filePath: profileFp,\n operation: 'ensure_profile_defaults',\n outcome: 'success',\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n }\n\n /**\n * Persist sync config to the active profile's sync.json, with the token encrypted\n * by the vault (if provided). The file is isolated from the main config\n * hierarchy to prevent accidental commits.\n */\n async persistSyncConfig(cfg: SyncConfig): Promise<void> {\n let toWrite = { ...cfg };\n if (this.vault && toWrite.githubToken && !toWrite.githubToken.startsWith('enc:')) {\n // Re-encrypt if plaintext (e.g. came from in-memory configStore update\n // rather than direct /sync enable call). Idempotent for already-encrypted.\n toWrite = { ...toWrite, githubToken: this.vault.encrypt(toWrite.githubToken) };\n }\n const fp = this.paths.syncConfig;\n const t0 = Date.now();\n try {\n await atomicWrite(fp, JSON.stringify(toWrite, null, 2), { mode: 0o600 });\n this.events?.emit('storage.write', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'persist_sync',\n outcome: 'success',\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n } catch (err) {\n this.events?.emit('storage.error', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'persist_sync',\n outcome: 'failure',\n error: storageErrorString(err),\n recoverable: false,\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n throw err;\n }\n }\n\n /**\n * Read the active profile's sync.json (encrypted GitHub token storage) and decrypt\n * the token if a vault is available. Returns null if the file doesn't exist.\n * This is separate from main config loading because sync.json is intentionally\n * isolated \u2014 it should never be part of project-local or env-driven config.\n */\n async loadSyncConfig(): Promise<SyncConfig | null> {\n const fp = this.paths.syncConfig;\n const t0 = Date.now();\n try {\n const raw = await fs.readFile(fp, 'utf8');\n const parsed = safeParse<SyncConfig>(raw);\n if (!parsed.ok || !parsed.value) {\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'load_sync',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: 'parse error or empty file',\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n return null;\n }\n\n // Decrypt the token if vault is available (field name matches secret pattern)\n if (this.vault) {\n const decrypted = decryptConfigSecrets({ sync: parsed.value } as PartialConfig, this.vault);\n const result = (decrypted as { sync: SyncConfig }).sync ?? null;\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'load_sync',\n outcome: 'success',\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n return result;\n }\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'load_sync',\n outcome: 'success',\n durationMs: Date.now() - t0,\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n return parsed.value;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n // Non-ENOENT failures (EACCES, ENOSPC, etc.) \u2014 emit storage.read failure, then return null\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: fp,\n operation: 'load_sync',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: storageErrorString(err),\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n this.logWarn('Config sync load failed', {\n event: 'config.sync_load_failed',\n message: toErrorMessage(err),\n });\n return null;\n }\n }\n\n private async readJson(file: string): Promise<PartialConfig> {\n const t0 = Date.now();\n let mtimeMs: number | null = null;\n try {\n const stat = await fs.stat(file);\n mtimeMs = stat.mtimeMs;\n const cached = this.jsonCache.get(file);\n if (cached && cached.mtimeMs === mtimeMs) {\n return structuredClone(cached.value);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n this.jsonCache.set(file, { mtimeMs: null, value: {} });\n return {};\n }\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: file,\n operation: 'read_json',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: storageErrorString(err),\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n this.logWarn('Config read failed (stat)', {\n event: 'config.read_failed',\n path: file,\n message: toErrorMessage(err),\n });\n return {};\n }\n\n let raw: string;\n try {\n raw = await fs.readFile(file, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: file,\n operation: 'read_json',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: storageErrorString(err),\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n this.logWarn('Config read failed (read)', {\n event: 'config.read_failed',\n path: file,\n message: toErrorMessage(err),\n });\n }\n this.jsonCache.set(file, { mtimeMs: null, value: {} });\n return {};\n }\n const parsed = safeParse<PartialConfig>(raw);\n if (!parsed.ok || !parsed.value) {\n this.events?.emit('storage.read', {\n sessionId: '~config~',\n store: 'config',\n filePath: file,\n operation: 'read_json',\n outcome: 'failure',\n durationMs: Date.now() - t0,\n error: 'parse error or empty file',\n ...(this.traceId !== undefined ? { traceId: this.traceId } : {}),\n });\n this.logWarn('Config parse failed \u2014 falling back to defaults', {\n event: 'config.parse_failed',\n path: file,\n });\n return {};\n }\n // Migrate the pre-SAGE `superMemory` key per SOURCE, before the layered\n // merge: after merging, `Sage` always exists (behavior defaults), so a\n // post-merge migration could only ever see defaults win and would drop the\n // user's legacy settings.\n migrateLegacySuperMemoryKey(parsed.value as Record<string, unknown>);\n this.jsonCache.set(file, { mtimeMs, value: structuredClone(parsed.value) });\n return parsed.value;\n }\n\n private validateBehavior(cfg: PartialConfig): void {\n /* v8 ignore start -- defensive: config defaults always seed version:1 before validation */\n if (cfg.version === undefined)\n throw new ConfigError({\n message: 'Config: missing version field',\n code: ERROR_CODES.CONFIG_INVALID,\n context: { field: 'version' },\n });\n /* v8 ignore stop */\n if (cfg.version !== 1)\n throw new ConfigError({\n message: `Config: unsupported version ${cfg.version}`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { field: 'version', actual: cfg.version },\n });\n const c = cfg.context;\n if (!c)\n throw new ConfigError({\n message: 'Config: missing context section',\n code: ERROR_CODES.CONFIG_INVALID,\n context: { field: 'context' },\n });\n // A user-edited config.json can land strings here (\"0.6\") and slip past\n // truthiness checks; the `>=` comparison then coerces silently and the\n // threshold ordering check passes for nonsense values. Validate types\n // explicitly so misconfigs surface here, not as confusing failures deep\n // in the auto-compaction logic.\n const fields: Array<keyof typeof c> = ['warnThreshold', 'softThreshold', 'hardThreshold'];\n for (const f of fields) {\n const v = c[f];\n if (typeof v !== 'number' || !Number.isFinite(v)) {\n throw new ConfigError({\n message: `Config: context.${String(f)} must be a finite number (got ${typeof v})`,\n code: ERROR_CODES.CONFIG_INVALID,\n context: { field: `context.${String(f)}`, actualType: typeof v },\n });\n }\n }\n if (c.warnThreshold >= c.softThreshold || c.softThreshold >= c.hardThreshold) {\n throw new ConfigError({\n message: 'Config: context thresholds must satisfy warn < soft < hard',\n code: ERROR_CODES.CONFIG_INVALID,\n context: { warn: c.warnThreshold, soft: c.softThreshold, hard: c.hardThreshold },\n });\n }\n if (c.mode !== undefined && !isContextWindowModeSelectionId(c.mode)) {\n // An unknown mode (typo or value from an older/renamed scheme) should not\n // brick the CLI \u2014 unlike the numeric thresholds above there is a safe\n // default. Warn and fall back rather than throwing.\n const known = listContextWindowModes()\n .map((m) => m.id)\n .join(', ');\n this.logWarn(\n `Ignoring unknown context.mode \"${c.mode}\" \u2014 falling back to \"${DEFAULT_CONTEXT_WINDOW_MODE_ID}\"`,\n { event: 'config.unknown_context_mode', mode: c.mode, known },\n );\n c.mode = DEFAULT_CONTEXT_WINDOW_MODE_ID;\n } else if (c.mode !== undefined) {\n c.mode = normalizeContextWindowModeId(c.mode) ?? DEFAULT_CONTEXT_WINDOW_MODE_ID;\n }\n }\n\n private validateIdentity(cfg: PartialConfig): void {\n if (!cfg.provider) {\n throw new ConfigError({\n message: 'Config: no provider configured. Run `wstack init` or set WRONGSTACK_PROVIDER.',\n code: ERROR_CODES.CONFIG_INVALID,\n context: { field: 'provider' },\n });\n }\n if (!cfg.model) {\n throw new ConfigError({\n message: 'Config: no model configured. Run `wstack init` or set WRONGSTACK_MODEL.',\n code: ERROR_CODES.CONFIG_INVALID,\n context: { field: 'model' },\n });\n }\n }\n}\n", "import { expectDefined } from '../utils/expect-defined.js';\n\nexport type ContextWindowModeId = 'balanced' | 'frugal' | 'deep';\nexport type DeprecatedContextWindowModeId = 'archival';\nexport type ContextWindowModeSelectionId = ContextWindowModeId | DeprecatedContextWindowModeId;\n\nexport type ContextWindowAggressiveOn = 'hard' | 'soft' | 'warn';\n\nexport interface ContextWindowThresholds {\n warn: number;\n soft: number;\n hard: number;\n}\n\nexport interface ContextWindowMode {\n id: ContextWindowModeId;\n name: string;\n description: string;\n thresholds: ContextWindowThresholds;\n aggressiveOn: ContextWindowAggressiveOn;\n preserveK: number;\n eliseThreshold: number;\n targetLoad: number;\n}\n\nexport interface ContextWindowPolicy extends ContextWindowMode {}\n\nexport interface ContextWindowConfigLike {\n mode?: ContextWindowModeSelectionId | string | undefined;\n warnThreshold?: number | undefined;\n softThreshold?: number | undefined;\n hardThreshold?: number | undefined;\n preserveK?: number | undefined;\n eliseThreshold?: number | undefined;\n targetLoad?: number | undefined;\n}\n\nexport const DEFAULT_CONTEXT_WINDOW_MODE_ID: ContextWindowModeId = 'balanced';\n\nexport const DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES: Readonly<\n Record<DeprecatedContextWindowModeId, ContextWindowModeId>\n> = Object.freeze({\n archival: 'balanced',\n});\n\nexport const CONTEXT_WINDOW_MODES: readonly ContextWindowMode[] = Object.freeze([\n {\n id: 'balanced',\n name: 'Balanced',\n description: 'Default rolling compaction: recent work stays verbatim, old tool output is trimmed.',\n thresholds: { warn: 0.55, soft: 0.7, hard: 0.85 },\n aggressiveOn: 'soft',\n preserveK: 8,\n eliseThreshold: 1200,\n targetLoad: 0.65,\n },\n {\n id: 'frugal',\n name: 'Frugal',\n description: 'Token-saver mode: compacts early and keeps a tight verbatim tail.',\n thresholds: { warn: 0.4, soft: 0.55, hard: 0.7 },\n aggressiveOn: 'warn',\n preserveK: 4,\n eliseThreshold: 500,\n targetLoad: 0.45,\n },\n {\n id: 'deep',\n name: 'Deep',\n description: 'Long-reasoning mode: delays compaction and keeps more recent turns intact.',\n thresholds: { warn: 0.72, soft: 0.86, hard: 0.96 },\n aggressiveOn: 'hard',\n preserveK: 18,\n eliseThreshold: 5000,\n targetLoad: 0.82,\n },\n]);\n\nexport function listContextWindowModes(): ContextWindowMode[] {\n return CONTEXT_WINDOW_MODES.map((m) => ({ ...m, thresholds: { ...m.thresholds } }));\n}\n\nexport function normalizeContextWindowModeId(\n id: string | null | undefined,\n): ContextWindowModeId | null {\n if (!id) return null;\n if (isContextWindowModeId(id)) return id;\n return DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES[id as DeprecatedContextWindowModeId] ?? null;\n}\n\nexport function isDeprecatedContextWindowModeId(\n id: string,\n): id is DeprecatedContextWindowModeId {\n return Object.hasOwn(DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES, id);\n}\n\nexport function isContextWindowModeSelectionId(\n id: string,\n): id is ContextWindowModeSelectionId {\n return isContextWindowModeId(id) || isDeprecatedContextWindowModeId(id);\n}\n\nexport function getContextWindowMode(id: string | null | undefined): ContextWindowMode | null {\n const normalized = normalizeContextWindowModeId(id);\n if (!normalized) return null;\n const mode = CONTEXT_WINDOW_MODES.find((m) => m.id === normalized);\n return mode ? { ...mode, thresholds: { ...mode.thresholds } } : null;\n}\n\nexport function isContextWindowModeId(id: string): id is ContextWindowModeId {\n return CONTEXT_WINDOW_MODES.some((m) => m.id === id);\n}\n\nexport function resolveContextWindowPolicy(\n config: ContextWindowConfigLike = {},\n overrideMode?: string | null | undefined,\n): ContextWindowPolicy {\n const requested = overrideMode ?? config.mode ?? DEFAULT_CONTEXT_WINDOW_MODE_ID;\n const mode = getContextWindowMode(requested) ?? expectDefined(getContextWindowMode(DEFAULT_CONTEXT_WINDOW_MODE_ID));\n\n return {\n ...mode,\n thresholds: {\n warn: config.warnThreshold ?? mode.thresholds.warn,\n soft: config.softThreshold ?? mode.thresholds.soft,\n hard: config.hardThreshold ?? mode.thresholds.hard,\n },\n preserveK: config.preserveK ?? mode.preserveK,\n eliseThreshold: config.eliseThreshold ?? mode.eliseThreshold,\n targetLoad: config.targetLoad ?? mode.targetLoad,\n };\n}\n\nexport function formatContextWindowModeList(activeId?: string | null): string {\n const active = normalizeContextWindowModeId(activeId);\n return CONTEXT_WINDOW_MODES.map((m) => {\n const marker = m.id === active ? '*' : ' ';\n return `${marker} ${m.id.padEnd(9)} ${m.name} - ${m.description}`;\n }).join('\\n');\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * Minimal paths object needed for config backup \u2014 just the global root\n * from which we derive the backup history directory.\n */\nexport interface ConfigBackupPaths {\n globalRoot: string;\n}\n\n/**\n * Backup directory for config file history.\n * Every config write creates a timestamped snapshot here so the user can\n * recover from accidental changes. Backups are never cleaned up automatically.\n */\nexport function configHistoryDir(globalRoot: string): string {\n return path.join(globalRoot, 'config-history');\n}\n\n/**\n * Derive a human-readable slug for a config file path relative to the\n * ~/.wrongstack root. Examples:\n * config.json \u2192 config\n * profiles/default/config.json \u2192 profiles-default-config\n */\nfunction configSlug(absolutePath: string, globalRoot: string): string {\n const rel = path.relative(globalRoot, absolutePath);\n const normalized = rel.replace(/\\\\/g, '/').replace(/\\.json$/i, '');\n return normalized.replace(/\\//g, '-');\n}\n\n/**\n * Before overwriting a config file, save its current content to the\n * config-history directory with a timestamp. Best-effort: failures are\n * silently ignored so they never block the config write itself.\n */\nexport async function backupConfigFile(\n filePath: string,\n paths: ConfigBackupPaths,\n): Promise<void> {\n let currentContent: string;\n try {\n currentContent = await fs.readFile(filePath, 'utf8');\n if (!currentContent.trim()) return;\n } catch {\n return; // ENOENT or other error \u2014 no current content to back up\n }\n\n const now = new Date();\n const ts = now.toISOString()\n .replace(/[:.]/g, '-')\n .replace(/Z$/, '');\n const slug = configSlug(filePath, paths.globalRoot);\n const backupDir = configHistoryDir(paths.globalRoot);\n const backupFile = path.join(backupDir, `${slug}-${ts}.json`);\n\n try {\n await fs.mkdir(backupDir, { recursive: true });\n await fs.writeFile(backupFile, currentContent, { mode: 0o600, encoding: 'utf8' });\n } catch {\n // best-effort \u2014 never block the config write for a backup failure\n }\n}\n", "import { toErrorMessage } from './error.js';\n\nexport interface SafeParseResult<T> {\n ok: boolean;\n value?: T | undefined;\n error?: string | undefined;\n}\n\nexport function safeParse<T = unknown>(input: string, maxBytes = 5_000_000): SafeParseResult<T> {\n if (Buffer.byteLength(input, 'utf8') > maxBytes) {\n return { ok: false, error: `Input exceeds limit (${maxBytes} bytes)` };\n }\n try {\n return { ok: true, value: JSON.parse(input) as T };\n } catch (err) {\n return {\n ok: false,\n error: toErrorMessage(err),\n };\n }\n}\n\nexport function safeStringify(value: unknown, pretty = false): string {\n const seen = new WeakSet();\n const replacer = (_k: string, v: unknown): unknown => {\n if (typeof v === 'bigint') return v.toString();\n if (v instanceof Error) {\n return { name: v.name, message: v.message, stack: v.stack };\n }\n if (typeof v === 'object' && v !== null) {\n if (seen.has(v as object)) return '[Circular]';\n seen.add(v as object);\n }\n return v;\n };\n try {\n return JSON.stringify(value, replacer, pretty ? 2 : undefined) ?? 'null';\n } catch (err) {\n return JSON.stringify({\n __serialization_error: toErrorMessage(err),\n });\n }\n}\n\n/**\n * Attempt to parse JSON5-style input and return a valid JSON string.\n * Handles trailing commas, line/block comments, and unquoted keys\n * that are common in provider output.\n *\n * Returns the sanitized string if it parses successfully as JSON,\n * or `null` if the input cannot be made valid. Callers use this to\n * decide whether to proceed with the parsed result or fall back to\n * raw handling.\n */\nexport function sanitizeJsonString(s: string): string | null {\n let out = s.trim();\n\n // Stage 1: strip line and block comments outside JSON string values.\n out = stripJsonComments(out);\n\n // Stage 2: strip trailing commas before } or ]\n out = out.replace(/,(\\s*[}\\]])/g, '$1');\n\n // Stage 3: escape literal control characters that appear *inside* string\n // values. Models frequently emit raw newlines/tabs inside a code payload\n // (e.g. edit's old_string/new_string) instead of the required \\n / \\t, which\n // makes JSON.parse throw. This is the single most common malformed-args case.\n out = escapeControlCharsInStrings(out);\n\n // Stage 4: attempt full parse; return null if it fails so callers can\n // distinguish \"already valid JSON\" from \"unrecoverable\".\n try {\n JSON.parse(out);\n return out;\n } catch {\n return null; // stripped but still not valid JSON; caller handles it\n }\n}\n\n/**\n * Strip a Markdown code-fence wrapper from a payload.\n *\n * Models occasionally return tool-call arguments wrapped in ```json fences\n * (or embedded in prose around one) instead of bare JSON. Returns the inner\n * content when the input starts with a fence (closing fence optional, so a\n * truncated stream still unwraps) or contains one complete fenced block;\n * returns null when no fence is present. Callers should only invoke this\n * after a direct parse failed, so fences inside legitimate string values are\n * never touched.\n */\nexport function stripCodeFences(s: string): string | null {\n const trimmed = s.trim();\n // Whole-payload fence: ```lang? \u2026 ```? (closer optional for truncation)\n const opener = /^```[\\w+-]*[ \\t]*\\r?\\n?/.exec(trimmed);\n if (opener) {\n const inner = trimmed.slice(opener[0].length).replace(/(\\r?\\n)?[ \\t]*```[ \\t]*$/, '');\n return inner.trim();\n }\n // Fence embedded in prose: extract the first complete fenced block.\n const embedded = /```[\\w+-]*[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n[ \\t]*```/.exec(trimmed);\n if (embedded) return (embedded[1] ?? '').trim();\n return null;\n}\n\n/**\n * Walk the string tracking whether we are inside a JSON string literal and\n * replace raw control characters (U+0000\u2013U+001F) that appear inside strings\n * with their valid JSON escape sequences. Characters outside strings are left\n * untouched (insignificant whitespace stays as-is). Already-escaped sequences\n * are not double-escaped because we only act on *literal* control bytes.\n */\nfunction escapeControlCharsInStrings(s: string): string {\n let inString = false;\n let out = '';\n for (let i = 0; i < s.length; i++) {\n const c = s.charAt(i);\n if (c === '\"' && (i === 0 || s[i - 1] !== '\\\\')) {\n inString = !inString;\n out += c;\n continue;\n }\n const code = c.charCodeAt(0);\n if (inString && code < 0x20) {\n switch (c) {\n case '\\n':\n out += '\\\\n';\n break;\n case '\\r':\n out += '\\\\r';\n break;\n case '\\t':\n out += '\\\\t';\n break;\n case '\\b':\n out += '\\\\b';\n break;\n case '\\f':\n out += '\\\\f';\n break;\n default:\n out += `\\\\u${code.toString(16).padStart(4, '0')}`;\n }\n continue;\n }\n out += c;\n }\n return out;\n}\n\nfunction stripJsonComments(s: string): string {\n let inString = false;\n let escaped = false;\n const chars: string[] = [];\n let i = 0;\n\n while (i < s.length) {\n const c = s.charAt(i);\n\n if (inString) {\n chars.push(c);\n if (escaped) {\n escaped = false;\n } else if (c === '\\\\') {\n escaped = true;\n } else if (c === '\"') {\n inString = false;\n }\n i++;\n continue;\n }\n\n if (c === '\"') {\n inString = true;\n chars.push(c);\n i++;\n continue;\n }\n\n if (c === '/' && s.charAt(i + 1) === '/') {\n while (i < s.length && s.charAt(i) !== '\\n') i++;\n continue;\n }\n\n if (c === '/' && s.charAt(i + 1) === '*') {\n const end = s.indexOf('*/', i + 2);\n if (end === -1) {\n // Preserve an unterminated opener so the final JSON.parse rejects it.\n chars.push(s.slice(i));\n break;\n }\n i = end + 2;\n continue;\n }\n\n chars.push(c);\n i++;\n }\n\n return chars.join('');\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n/**\n * Path layout. All developer-level state lives in ~/.wrongstack/.\n * Per-project state is keyed by the canonical project root under\n * ~/.wrongstack/projects/<slug>/. Linked Git worktrees resolve to their main\n * checkout so coordination and durable state are shared across worktrees.\n *\n * The ONLY thing inside the project tree is the optional\n * .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).\n */\n\nexport interface WstackPaths {\n /** ~/.wrongstack \u2014 global root. */\n globalRoot: string;\n /** Active profile name resolved from the bootstrap config. */\n profileName: string;\n /** ~/.wrongstack/profiles/<activeProfile> \u2014 active user-profile root. */\n profileDir: string;\n /** Absolute project root. */\n projectRoot: string;\n /** Home directory (~) \u2014 base for foreign tool state (~/.codex, ~/.agents, \u2026). */\n homeDir: string;\n /**\n * ~/.wrongstack/profiles/<activeProfile> \u2014 directory for profile-scoped\n * user state (mode.json, statusline.json, custom-context-modes.json, \u2026).\n */\n configDir: string;\n /** ~/.wrongstack/config.json \u2014 bootstrap config (activeProfile + version). */\n globalConfig: string;\n /**\n * ~/.wrongstack/profiles \u2014 directory containing per-profile configs.\n * Each profile has its own subdirectory with a config.json.\n */\n profilesDir: string;\n /**\n * Resolve the config path for a named profile.\n * Returns ~/.wrongstack/profiles/<name>/config.json.\n */\n profileConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/statusline.json */\n profileStatuslineConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/mode.json */\n profileModeConfig: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/provider-status.json */\n profileProviderStatus: (name: string) => string;\n /** Resolve ~/.wrongstack/profiles/<name>/update-cache.json */\n profileUpdateCache: (name: string) => string;\n /** ~/.wrongstack/.key \u2014 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/profiles/<activeProfile>/memory.md \u2014 profile memory. */\n globalMemory: string;\n /** ~/.wrongstack/profiles/<activeProfile>/skills \u2014 profile skills. */\n globalSkills: string;\n /** ~/.claude/skills \u2014 user-global skills from foreign coding agents (Claude Code, Codex, \u2026). Read-only. */\n globalClaudeSkills: string;\n /** ~/.wrongstack/profiles/<activeProfile>/design-kits \u2014 profile Design Studio kits. */\n globalDesignKits: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompts \u2014 profile prompt library. */\n globalPrompts: string;\n /** ~/.wrongstack/profiles/<activeProfile>/instructions \u2014 profile instruction overrides. */\n globalInstructions: string;\n /** ~/.wrongstack/profiles/<activeProfile>/prompt-usage.json \u2014 prompt usage. */\n promptUsage: string;\n /** ~/.wrongstack/cache \u2014 fetched data (models.dev, etc.). */\n cacheDir: string;\n /** ~/.wrongstack/cache/models.dev.json */\n modelsCache: string;\n /** ~/.wrongstack/cache/models-overlay.json \u2014 cached curated overlay. */\n modelsOverlayCache: string;\n /**\n * Per-project codebase symbol index (SQLite). Lives under the global project\n * dir \u2014 NOT inside the repo \u2014 so it never clutters the working tree or needs\n * gitignoring. `~/.wrongstack/projects/<hash>/codebase-index`.\n */\n projectCodebaseIndex: string;\n /** ~/.wrongstack/profiles/<activeProfile>/history \u2014 REPL line history. */\n historyFile: string;\n /** ~/.wrongstack/logs/wrongstack.log */\n logFile: string;\n /** ~/.wrongstack/projects/<hash> */\n projectDir: string;\n /** ~/.wrongstack/projects/<hash>/memory.md */\n projectMemory: string;\n /** ~/.wrongstack/projects/<hash>/sessions */\n projectSessions: string;\n /** ~/.wrongstack/projects/<hash>/trust.json */\n projectTrust: string;\n /** ~/.wrongstack/projects/<hash>/meta.json */\n projectMeta: string;\n /** ~/.wrongstack/projects/<hash>/config.local.json \u2014 optional override */\n projectLocalConfig: string;\n /** <project>/.wrongstack/config.json \u2014 per-project settings (safe fields only).\n * This lives inside the project root so it can be gitignored or shared. */\n inProjectConfig: string;\n /** <project>/.wrongstack/AGENTS.md \u2014 committed project memory. */\n inProjectAgentsFile: string;\n /** <project>/.wrongstack/skills \u2014 committed project skills. */\n inProjectSkills: string;\n /** <project>/.claude/skills \u2014 project skills authored for foreign coding agents (Claude Code, \u2026). Read-only. */\n inProjectClaudeSkills: string;\n /** <project>/.wrongstack/prompts \u2014 committed project prompt library. */\n inProjectPrompts: string;\n /** <project>/.wrongstack/instructions \u2014 committed project instruction overrides. */\n inProjectInstructions: string;\n /** <project>/.wrongstack/design-kits \u2014 committed project Design Studio kits. */\n inProjectDesignKits: string;\n /** <project>/.wrongstack/worktrees \u2014 git worktrees for per-phase isolation (gitignored). */\n inProjectWorktrees: string;\n /** Stable hash for the canonical project root (shared by linked Git worktrees). */\n projectHash: string;\n /** Human-readable canonical project slug, shared by linked Git worktrees. */\n projectSlug: string;\n /** ~/.wrongstack/projects/<hash>/goal.json \u2014 goal persistence */\n projectGoal: string;\n /** ~/.wrongstack/projects/<hash>/input-history.json \u2014 TUI prompt input history */\n projectInputHistory: string;\n /** ~/.wrongstack/projects/<hash>/specs \u2014 SDD spec files */\n projectSpecs: string;\n /** ~/.wrongstack/projects/<hash>/task-graphs \u2014 SDD task graphs */\n projectTaskGraphs: string;\n /** ~/.wrongstack/projects/<hash>/sdd-session.json \u2014 SDD session state */\n projectSddSession: string;\n /** ~/.wrongstack/projects/<hash>/plan.json \u2014 plan persistence */\n projectPlan: string;\n /** ~/.wrongstack/projects/<hash>/autophase \u2014 Goal phase-graph JSON files (dir name kept for backward compat) */\n projectAutophase: string;\n /** ~/.wrongstack/projects/<hash>/sdd-boards \u2014 live SDD board snapshots + JSONL event logs */\n projectSddBoards: string;\n /** ~/.wrongstack/profiles/<activeProfile>/sync.json \u2014 CloudSync configuration */\n syncConfig: string;\n /** ~/.wrongstack/config-history \u2014 timestamped backups on every config write */\n configHistoryDir: string;\n /** Function to get the status.json path for a project given its hash. */\n projectStatus: (projectHash: string) => string;\n}\n\n/**\n * Resolve the stable project identity root used by global WrongStack state.\n *\n * A linked Git worktree has its own checkout path and a `.git` *file* that\n * points into `<main>/.git/worktrees/<name>`. Its `commondir` points back to\n * the main checkout's `.git` directory. Treating the linked checkout path as\n * the project identity would split one repository into multiple session,\n * registry, and mailbox directories \u2014 agents in different worktrees would be\n * unable to see or message each other.\n *\n * Project-local paths still use the caller's actual checkout. Only global\n * state identity is canonicalized. Non-Git projects, normal checkouts, Git\n * submodules, and separate-git-dir layouts keep their existing identity.\n */\nexport function canonicalProjectRoot(absRoot: string): string {\n const checkoutRoot = path.resolve(absRoot);\n const dotGit = path.join(checkoutRoot, '.git');\n\n try {\n if (!fs.statSync(dotGit).isFile()) return checkoutRoot;\n\n const gitDirLine = fs.readFileSync(dotGit, 'utf8').trim();\n const match = /^gitdir:\\s*(.+)$/i.exec(gitDirLine);\n if (!match?.[1]) return checkoutRoot;\n\n const gitDir = path.resolve(checkoutRoot, match[1].trim());\n const commonDirFile = path.join(gitDir, 'commondir');\n if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;\n\n const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, 'utf8').trim());\n // Linked worktrees created by Git share the main checkout's `.git` dir.\n // A submodule or --separate-git-dir layout may point elsewhere; do not\n // guess a working-tree root for those shapes.\n if (path.basename(commonDir).toLowerCase() !== '.git') return checkoutRoot;\n return path.dirname(commonDir);\n } catch {\n // Missing/malformed administrative files must never make path resolution\n // fail. Falling back preserves the pre-canonicalization behavior.\n return checkoutRoot;\n }\n}\n\nexport function projectHash(absRoot: string): string {\n return createHash('sha256').update(canonicalProjectRoot(absRoot)).digest('hex').slice(0, 12);\n}\n\n/**\n * Human-readable project directory name: slugified folder name + short hash\n * suffix for uniqueness. e.g. `wrongstack-a1b2c3` instead of `3024e5e6fa58`.\n */\nexport function projectSlug(absRoot: string): string {\n const identityRoot = canonicalProjectRoot(absRoot);\n const base = slugify(path.basename(identityRoot));\n const hash = createHash('sha256').update(identityRoot).digest('hex').slice(0, 6);\n return `${base}-${hash}`;\n}\n\n/** Turn a folder name into a filesystem-safe lowercase slug. */\nfunction slugify(name: string): string {\n return (\n name\n .toLowerCase()\n // Collapse any run of non-alphanumeric chars into a single hyphen.\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40) || 'project'\n );\n}\n\nexport interface WstackPathOptions {\n userHome?: string | undefined;\n projectRoot: string;\n /** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */\n globalRoot?: string | undefined;\n /** Explicit profile override. Otherwise read from the root bootstrap config. */\n profileName?: string | undefined;\n}\n\n/** Make an untrusted profile name safe for use as one path segment. */\nexport function safeProfileName(name: string | undefined): string {\n const safe = (name ?? '').replace(/[/\\\\:]/g, '_').replace(/\\.\\./g, '_').trim();\n return safe || 'default';\n}\n\n/**\n * Resolve the selected profile from ~/.wrongstack/config.json. The root file\n * is bootstrap metadata only; a missing/corrupt bootstrap selects `default`.\n */\nexport function activeProfileName(globalRoot: string): string {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, 'config.json'), 'utf8')) as {\n activeProfile?: unknown;\n };\n return safeProfileName(typeof parsed.activeProfile === 'string' ? parsed.activeProfile : undefined);\n } catch {\n return 'default';\n }\n}\n\n/**\n * The global `~/.wrongstack` root, honoring the `WRONGSTACK_HOME` env\n * override. The override exists so tests (and sandboxed runs) can redirect\n * ALL global state \u2014 config, secrets, logs, projects/, mailboxes \u2014 away from\n * the real user home. Before it existed, `pnpm test` booted runtimes against\n * the real `~/.wrongstack`: it read the user's real config.json (starting a\n * second live Telegram poller), appended to the real wrongstack.log, and left\n * ~20k orphaned fixture dirs under projects/.\n *\n * Every code path that wants the global dir must come through here (or\n * through `resolveWstackPaths`) instead of `path.join(os.homedir(), '.wrongstack')`.\n */\nexport function wstackGlobalRoot(): string {\n const fromEnv = process.env['WRONGSTACK_HOME'];\n if (fromEnv && fromEnv.trim().length > 0) return path.resolve(fromEnv);\n return path.join(os.homedir(), '.wrongstack');\n}\n\nexport function resolveWstackPaths(opts: WstackPathOptions): WstackPaths {\n // Precedence: explicit globalRoot > explicit userHome (callers/tests that\n // pass one expect paths under it) > WRONGSTACK_HOME env > real home dir.\n const globalRoot =\n opts.globalRoot ?? (opts.userHome ? path.join(opts.userHome, '.wrongstack') : wstackGlobalRoot());\n // Home dir for FOREIGN tool state (Claude Code's ~/.claude). Independent of\n // WRONGSTACK_HOME, which redirects only WrongStack state: a real user's\n // Claude skills live in their real home, but tests pass `userHome` to keep\n // both `.wrongstack` and `.claude` under a temp dir.\n const homeDir = opts.userHome ?? os.homedir();\n const profileName = safeProfileName(opts.profileName ?? activeProfileName(globalRoot));\n const profileDir = path.join(globalRoot, 'profiles', profileName);\n const hash = projectHash(opts.projectRoot);\n const slug = projectSlug(opts.projectRoot);\n const projectDir = path.join(globalRoot, 'projects', slug);\n return {\n globalRoot,\n profileName,\n profileDir,\n projectRoot: opts.projectRoot,\n homeDir,\n configDir: profileDir,\n globalConfig: path.join(globalRoot, 'config.json'),\n profilesDir: path.join(globalRoot, 'profiles'),\n profileConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'config.json');\n },\n profileStatuslineConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'statusline.json');\n },\n profileModeConfig: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'mode.json');\n },\n profileProviderStatus: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'provider-status.json');\n },\n profileUpdateCache: (name: string) => {\n return path.join(globalRoot, 'profiles', safeProfileName(name), 'update-cache.json');\n },\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(profileDir, 'memory.md'),\n globalSkills: path.join(profileDir, 'skills'),\n globalClaudeSkills: path.join(homeDir, '.claude', 'skills'),\n globalDesignKits: path.join(profileDir, 'design-kits'),\n globalPrompts: path.join(profileDir, 'prompts'),\n globalInstructions: path.join(profileDir, 'instructions'),\n promptUsage: path.join(profileDir, 'prompt-usage.json'),\n cacheDir: path.join(globalRoot, 'cache'),\n modelsCache: path.join(globalRoot, 'cache', 'models.dev.json'),\n modelsOverlayCache: path.join(globalRoot, 'cache', 'models-overlay.json'),\n historyFile: path.join(profileDir, 'history'),\n logFile: path.join(globalRoot, 'logs', 'wrongstack.log'),\n projectDir,\n projectCodebaseIndex: path.join(projectDir, 'codebase-index'),\n projectMemory: path.join(projectDir, 'memory.md'),\n projectSessions: path.join(projectDir, 'sessions'),\n projectTrust: path.join(projectDir, 'trust.json'),\n projectMeta: path.join(projectDir, 'meta.json'),\n projectLocalConfig: path.join(projectDir, 'config.local.json'),\n inProjectConfig: path.join(opts.projectRoot, '.wrongstack', 'config.json'),\n inProjectAgentsFile: path.join(opts.projectRoot, '.wrongstack', 'AGENTS.md'),\n inProjectSkills: path.join(opts.projectRoot, '.wrongstack', 'skills'),\n inProjectClaudeSkills: path.join(opts.projectRoot, '.claude', 'skills'),\n inProjectPrompts: path.join(opts.projectRoot, '.wrongstack', 'prompts'),\n inProjectInstructions: path.join(opts.projectRoot, '.wrongstack', 'instructions'),\n inProjectDesignKits: path.join(opts.projectRoot, '.wrongstack', 'design-kits'),\n inProjectWorktrees: path.join(opts.projectRoot, '.wrongstack', 'worktrees'),\n projectHash: hash,\n projectSlug: slug,\n projectGoal: path.join(projectDir, 'goal.json'),\n projectInputHistory: path.join(projectDir, 'input-history.json'),\n projectSpecs: path.join(projectDir, 'specs'),\n projectTaskGraphs: path.join(projectDir, 'task-graphs'),\n projectSddSession: path.join(projectDir, 'sdd-session.json'),\n projectPlan: path.join(projectDir, 'plan.json'),\n projectAutophase: path.join(projectDir, 'autophase'),\n projectSddBoards: path.join(projectDir, 'sdd-boards'),\n syncConfig: path.join(profileDir, 'sync.json'),\n configHistoryDir: path.join(globalRoot, 'config-history'),\n projectStatus: (projectHash: string) => path.join(globalRoot, 'projects', projectHash, 'status.json'),\n };\n}\n", "const BOOTSTRAP_KEYS = new Set(['version', 'activeProfile']);\n\nexport function isBootstrapOnly(config: Record<string, unknown>): boolean {\n return Object.keys(config).every((k) => BOOTSTRAP_KEYS.has(k));\n}\n", "import type { CacheTtl, ReasoningEffort } from '../provider.js';\n\nexport interface ModelRuntimeReasoningConfig {\n /**\n * Whether to send explicit reasoning enable/disable.\n * - 'auto' \u2192 do not send explicit fields; provider/model default wins\n * - 'on' \u2192 send `reasoning.enabled = true`\n * - 'off' \u2192 send `reasoning.enabled = false` only when the model supports disable\n */\n mode?: 'auto' | 'on' | 'off' | undefined;\n /** Reasoning effort. Only sent when the model advertises `effortSupported`. */\n effort?: ReasoningEffort | undefined;\n /** Preserve thinking across turns. Only sent when `preserveThinking !== 'unsupported'`. */\n preserve?: boolean | undefined;\n}\n\n/**\n * Runtime prompt-cache controls mapped into `Request.cache`. Currently only the\n * Anthropic TTL toggle (5m vs 1h) is exposed; other providers ignore it.\n */\nexport interface ModelRuntimeCacheConfig {\n ttl?: CacheTtl | undefined;\n /**\n * Opt-in explicit Gemini context caching. When true, the Google provider\n * creates a server-side `cachedContents` resource for the stable system\n * prefix (system instruction + tool defs) and references it by name instead\n * of resending it every turn. Default false: Gemini's automatic *implicit*\n * caching already covers a byte-stable prefix with no setup. Ignored by every\n * non-Google provider. Any failure in the create flow falls back to the\n * normal inline request, so enabling it can never break a request.\n */\n geminiExplicit?: boolean | undefined;\n}\n\n/**\n * Shared runtime controls applied to every provider request, regardless of host\n * (REPL / TUI / WebUI). The CLI installs a single request-pipeline middleware\n * that reads these and mutates the outgoing `Request`.\n */\nexport interface ModelRuntimeConfig {\n reasoning?: ModelRuntimeReasoningConfig | undefined;\n cache?: ModelRuntimeCacheConfig | undefined;\n /**\n * Generic generation parameters mapped directly onto `Request` fields.\n * Only sent when the active model's `Capabilities` advertise support.\n */\n parameters?: ModelRuntimeParametersConfig | undefined;\n}\n\n/**\n * Selects which built-in/base system identity prompt file is used when building\n * the host system prompt. Surfaces keep `default` unless explicitly told to use\n * the lite or pro prompt.\n */\nexport interface SystemPromptConfig {\n variant?: 'default' | 'lite' | 'pro' | undefined;\n}\n\n/**\n * Generic generation parameters the user can set per-session / per-project.\n * Each field maps to a `Request` field of the same name and is gated by the\n * corresponding `Capabilities` flag so unsupported models don't receive\n * parameters they'd reject.\n */\nexport interface ModelRuntimeParametersConfig {\n /** Top-K sampling (Anthropic, Gemini). Gated by `capabilities.topK`. */\n topK?: number | undefined;\n /** Frequency penalty (OpenAI, Gemini). Gated by `capabilities.frequencyPenalty`. */\n frequencyPenalty?: number | undefined;\n /** Presence penalty (OpenAI, Gemini). Gated by `capabilities.presencePenalty`. */\n presencePenalty?: number | undefined;\n /** Random seed (OpenAI, Gemini). Gated by `capabilities.seed`. */\n seed?: number | undefined;\n /** End-user identifier for abuse monitoring. */\n user?: string | undefined;\n /** Log probabilities (OpenAI, Gemini). Gated by `capabilities.logprobs`. */\n logprobs?: boolean | undefined;\n /** Number of top logprobs to return (OpenAI). Only when `logprobs` is true. */\n topLogprobs?: number | undefined;\n}\n\n/**\n * HQ client connection settings. Same-machine clients can auto-discover the\n * local HQ auth file; remote clients use this config-backed URL/token pair.\n */\nexport interface HqClientConfig {\n /** Enable HQ publishing. Env WRONGSTACK_HQ_ENABLED still overrides at runtime. */\n enabled?: boolean | undefined;\n /** HQ HTTP base URL, e.g. http://host:3499. */\n url?: string | undefined;\n /** Client token for /ws/client. Stored encrypted by SecretVault when persisted. */\n token?: string | undefined;\n /** Optional HQ data dir for same-machine auth.json discovery. */\n dataDir?: string | undefined;\n /** Send raw content previews to HQ instead of redacted previews. */\n rawContent?: boolean | undefined;\n /** Override project display name in HQ. */\n projectAlias?: string | undefined;\n}\n\n/**\n * Token-saving mode tier levels. Controls how aggressively the system prompt\n * is compacted to reduce per-request token consumption.\n *\n * - 'off' \u2014 Full prompt, all tools, complete guidance (no reduction)\n * - 'minimal' \u2014 TIER1 tools (13, including codebase index lifecycle), stripped guidance\n * - 'light' \u2014 Same Tier 1 tool surface, common patterns, minimal guidance\n * - 'medium' \u2014 TIER1 + TIER2 development tools, some guidance (default when `true`)\n * - 'aggressive' \u2014 Maximum savings before tools become unusable (~4-5k tokens saved)\n */\n/**\n * Prompt token-saving tiers. `'auto'` is an INPUT-only sentinel meaning \"pick a\n * concrete tier from the model's context window\" \u2014 it is resolved to one of the\n * concrete tiers by {@link resolveTokenSavingTier} before reaching the prompt\n * builder (which never sees `'auto'`; if it somehow does, it behaves as `'off'`,\n * i.e. the full prompt \u2014 the safe fallback).\n */\nexport type TokenSavingTier = 'off' | 'auto' | 'minimal' | 'light' | 'medium' | 'aggressive';\n\n/** Concrete tiers the prompt builder actually consumes ('auto' excluded). */\nexport type ConcreteTokenSavingTier = Exclude<TokenSavingTier, 'auto'>;\n\n/**\n * Normalize a TokenSavingTier value, handling backward-compatible boolean inputs.\n * - `true` \u2192 'medium' (existing behavior)\n * - `false` \u2192 'off'\n * - `'auto'` \u2192 `'off'` \u2014 the `'auto'` sentinel is window-dependent, so EVERY\n * consumer that isn't the prompt builder (tool selection, lazy-load gate, TUI\n * display) must treat it as the safe no-op `'off'`: it must NOT reduce the\n * registered tool set or enable lazy loading on its own. Only the prompt\n * builder expands `'auto'` \u2014 via {@link resolveTokenSavingTier} \u2014 and only for\n * the (cache-stable) prompt prose. This keeps auto-tiering capability-neutral.\n * - other valid strings are returned as-is; `undefined`/invalid \u2192 'off'\n */\nexport function normalizeTokenSavingTier(val?: TokenSavingTier | boolean): ConcreteTokenSavingTier {\n if (val === undefined) return 'off';\n if (typeof val === 'boolean') return val ? 'medium' : 'off';\n const validTiers = new Set<ConcreteTokenSavingTier>([\n 'off',\n 'minimal',\n 'light',\n 'medium',\n 'aggressive',\n ]);\n // 'auto' is deliberately absent \u2192 collapses to 'off' for non-prompt consumers.\n return validTiers.has(val as ConcreteTokenSavingTier) ? (val as ConcreteTokenSavingTier) : 'off';\n}\n\n/**\n * Resolve the effective (concrete) token-saving tier for the **prompt builder**,\n * expanding the `'auto'` sentinel from the model's context window. This is\n * **cache-safe**: the window is stable for a session, so it resolves to the same\n * tier every turn \u2014 the system-prompt prefix stays byte-stable and the provider\n * prompt cache is never busted by a shifting tier (unlike a per-turn\n * pressure-driven tier). It re-resolves only on `/model` switch, which busts the\n * cache anyway.\n *\n * Modern threshold mapping \u2014 the system prompt (~12K tokens) is roughly the same\n * size regardless of context window; paying full price for it on every turn when\n * there is abundant headroom is wasteful. The tiers apply minimal trimming first,\n * escalating only when the window is genuinely tight:\n * - `< 32k` \u2192 `'medium'` (tiny window: identity + tool prose is a big fraction)\n * - `< 128k` \u2192 `'light'` (tight window: GPT-4 base class models)\n * - `>= 128k` \u2192 `'minimal'` (modern models: GPT-4o, Sonnet, DeepSeek, Qwen 3, Gemini 1M, Qwen 1M)\n * - unknown window \u2192 `'off'` (never guess a lean prompt without evidence)\n *\n * Explicit concrete tiers (a user who set `'medium'`, `'off'`, \u2026) are always\n * respected verbatim \u2014 `'auto'` is the only value that consults the window.\n */\nexport function resolveTokenSavingTier(\n val: TokenSavingTier | boolean | undefined,\n maxContext: number | undefined,\n): ConcreteTokenSavingTier {\n if (val === 'auto') {\n if (typeof maxContext !== 'number' || !Number.isFinite(maxContext) || maxContext <= 0) {\n return 'off';\n }\n if (maxContext < 32_000) return 'medium';\n if (maxContext < 128_000) return 'light';\n return 'minimal';\n }\n return normalizeTokenSavingTier(val);\n}\n\n// FleetChatVerbosity, FLEET_CHAT_VERBOSITY_VALUES, and resolveFleetChatVerbosity\n// were moved to the dependency-free leaf module ./fleet-chat.ts to avoid a\n// type-level import cycle with ./autonomy.ts. They are surfaced through the\n// config barrel (../config.ts) which re-exports ./config/fleet-chat.js directly.\n\nexport const DEFAULT_TUI_THINKING_WORD = 'thinking';\nexport const MAX_TUI_THINKING_WORD_LENGTH = 16;\n\n/**\n * Normalize the configurable statusline word shown while the TUI is working.\n * The value must be a single short word; invalid values fall back to the default.\n */\nexport function normalizeTuiThinkingWord(value: unknown): string {\n if (typeof value !== 'string') return DEFAULT_TUI_THINKING_WORD;\n const word = value.trim();\n if (word.length === 0 || word.length > MAX_TUI_THINKING_WORD_LENGTH) {\n return DEFAULT_TUI_THINKING_WORD;\n }\n if (!/^[\\p{L}\\p{N}_-]+$/u.test(word)) return DEFAULT_TUI_THINKING_WORD;\n return word;\n}\n", "/**\n * Shared configuration constants used across execution, storage, CLI, and WebUI.\n * Centralized here to avoid cross-domain import cycles.\n */\n\n/** Default tools config \u2014 mirrors values baked into CONFIG_BEHAVIOR_DEFAULTS. */\nexport const DEFAULT_TOOLS_CONFIG = Object.freeze({\n defaultExecutionStrategy: 'smart',\n maxIterations: 100,\n iterationTimeoutMs: 300_000,\n maxToolTimeoutMs: 300_000,\n sessionTimeoutMs: 1_800_000,\n perIterationOutputCapBytes: 100_000,\n descriptionMode: Object.freeze({}) as Record<string, 'extend' | 'simple' | undefined>,\n disabledTools: Object.freeze([]) as readonly string[],\n autoExtendLimit: true,\n restrictToProjectRoot: true,\n loopDetection: Object.freeze({\n mode: 'steer-then-cut',\n steerThreshold: 3,\n cutThreshold: 5,\n windowSize: 12,\n callRepeatThreshold: 4,\n }) as Readonly<{\n mode: 'steer-then-cut' | 'cut' | 'off';\n steerThreshold: number;\n cutThreshold: number;\n windowSize: number;\n callRepeatThreshold: number;\n }>,\n});\n\n/** Default context config \u2014 mirrors CONFIG_BEHAVIOR_DEFAULTS.context. */\nexport const DEFAULT_CONTEXT_CONFIG = Object.freeze({\n warnThreshold: 0.55,\n softThreshold: 0.7,\n hardThreshold: 0.85,\n targetLoad: 0.65,\n preserveK: 8,\n eliseThreshold: 1200,\n});\n\n/** Default autonomy config \u2014 auto-proceed delay etc. */\nexport const DEFAULT_AUTONOMY_CONFIG = Object.freeze({\n autoProceedDelayMs: 45_000,\n});\n\n/**\n * Default process circuit-breaker config. Protection is OFF by default \u2014 the\n * breaker only gates `bash`/`exec` once the user opts in via `/settings breaker on`.\n * The auto kill/reset delay is only consulted when protection is enabled.\n */\nexport const DEFAULT_CIRCUIT_BREAKER_CONFIG = Object.freeze({\n enabled: false,\n autoKillResetMs: 60_000,\n});\n\n/** Default session logging / audit configuration. */\nexport const DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({\n auditLevel: 'standard' as const,\n sampling: {\n toolProgress: {\n sampleRate: 8,\n },\n },\n});\n\n/** Default retention window for local session pruning. */\nexport const DEFAULT_SESSION_PRUNE_DAYS = 30;\n", "import { DEFAULT_TUI_THINKING_WORD, type Config } from '../../types/config.js';\nimport { DEFAULT_CONTEXT_WINDOW_MODE_ID } from '../../types/context-window.js';\nimport {\n DEFAULT_AUTONOMY_CONFIG,\n DEFAULT_CIRCUIT_BREAKER_CONFIG,\n DEFAULT_CONTEXT_CONFIG,\n DEFAULT_SESSION_LOGGING_CONFIG,\n DEFAULT_TOOLS_CONFIG,\n} from '../../types/default-config.js';\n\n/**\n * Defaults express *behavior*, not identity. Provider and model are NOT\n * hardcoded \u2014 they must be resolved at runtime from config + env + the\n * ModelsRegistry. A bare Config returned by this loader will throw when\n * the agent tries to construct a provider, with a message that points\n * users at `wstack init`.\n */\nexport const CONFIG_BEHAVIOR_DEFAULTS: Omit<Config, 'provider' | 'model'> = {\n version: 1,\n context: {\n mode: DEFAULT_CONTEXT_WINDOW_MODE_ID,\n warnThreshold: DEFAULT_CONTEXT_CONFIG.warnThreshold,\n softThreshold: DEFAULT_CONTEXT_CONFIG.softThreshold,\n hardThreshold: DEFAULT_CONTEXT_CONFIG.hardThreshold,\n targetLoad: DEFAULT_CONTEXT_CONFIG.targetLoad,\n autoCompact: true,\n preserveK: DEFAULT_CONTEXT_CONFIG.preserveK,\n eliseThreshold: DEFAULT_CONTEXT_CONFIG.eliseThreshold,\n strategy: 'hybrid',\n },\n tools: {\n defaultExecutionStrategy: DEFAULT_TOOLS_CONFIG.defaultExecutionStrategy,\n maxIterations: DEFAULT_TOOLS_CONFIG.maxIterations,\n iterationTimeoutMs: DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,\n maxToolTimeoutMs: DEFAULT_TOOLS_CONFIG.maxToolTimeoutMs,\n sessionTimeoutMs: DEFAULT_TOOLS_CONFIG.sessionTimeoutMs,\n perIterationOutputCapBytes: DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,\n descriptionMode: DEFAULT_TOOLS_CONFIG.descriptionMode,\n disabledTools: DEFAULT_TOOLS_CONFIG.disabledTools as string[],\n autoExtendLimit: DEFAULT_TOOLS_CONFIG.autoExtendLimit,\n restrictToProjectRoot: DEFAULT_TOOLS_CONFIG.restrictToProjectRoot,\n loopDetection: DEFAULT_TOOLS_CONFIG.loopDetection,\n },\n log: { level: 'info' },\n features: {\n mcp: true,\n plugins: true,\n memory: true,\n modelsRegistry: true,\n skills: true,\n prompts: true,\n // 'auto' \u2192 resolveTokenSavingTier picks a concrete tier from the model's\n // context window ONCE per session (cache-safe): lean prompt on small\n // windows (<32k medium, <128k light) where the fixed identity+tool prose\n // is a big fraction; minimal trimming on >=128k so modern large-window\n // models still get cost savings without capability loss. Explicit tiers\n // are respected verbatim.\n tokenSavingMode: 'auto',\n allowOutsideProjectRoot: true,\n },\n Sage: {\n enabled: true,\n storage: {\n projectLocal: true,\n directory: '.wrongstack/memories',\n },\n inject: {\n // Keep the ordinary turn prompt clean. Project memory is surfaced\n // on-demand beside relevant tool results, where the path/query that\n // caused retrieval is known and the hint can be independently capped.\n turnContext: false,\n toolResults: true,\n // Off: task text searches for what the operator is doing, not for the\n // file the tool touched, and every match it adds is unrelated to the\n // result it lands on.\n taskAware: false,\n maxHintsPerTool: 8,\n maxCharsPerTool: 2800,\n maxTurnMemories: 8,\n maxCharsPerTurn: 2400,\n minScore: 0.72,\n minImportance: 0.5,\n // 0 = once per session. Re-showing a memory the model has already been\n // given spends context and adds nothing.\n repeatCooldownMs: 0,\n },\n hygiene: {\n autoAfterSession: true,\n autoOnFileChange: true,\n retentionDays: 90,\n archiveLowConfidenceAfterDays: 30,\n },\n embeddings: {\n enabled: false,\n },\n },\n skills: { readClaudeSkills: true },\n mcpServers: {},\n fallbackAuto: true,\n maxConcurrent: 4,\n // YOLO opt-in: users who want auto-approve behaviour set `yolo: true`.\n // Off by default so prompt injection in repository content, fetched\n // content, or mailbox messages cannot induce arbitrary shell calls or\n // write operations without human confirmation.\n yolo: false,\n nextPrediction: false,\n hints: true,\n debugStream: false,\n configScope: 'global',\n indexing: {\n onSessionStart: true,\n onEdit: true,\n watchExternal: true,\n debounceMs: 400,\n },\n session: { ...DEFAULT_SESSION_LOGGING_CONFIG },\n autonomy: {\n // 'auto' by default: the agent self-drives (picks the top next-step after\n // each turn). This is a startup default, not a runtime flip \u2014 the\n // autoProceedMaxIterations cap + autoProceedDelayMs cooldown + Ctrl+C /\n // [GOAL_COMPLETE] stops remain in force. Explicit 'off'\n // in a config file is preserved (opt-out respected).\n defaultMode: 'auto',\n autoProceedDelayMs: DEFAULT_AUTONOMY_CONFIG.autoProceedDelayMs,\n autoProceedMaxIterations: 50,\n autonomyNextPrompt: 'auto {{suggestion}}',\n terminalTitleAnimation: true,\n // Mirrored from the top-level yolo default so the autonomy subsystem\n // (which reads autonomy.yolo) stays consistent with config.yolo.\n yolo: false,\n fleetChatVerbosity: 'off',\n chime: false,\n confirmExit: true,\n mouseMode: false,\n enhance: true,\n enhanceDelayMs: 60_000,\n enhanceLanguage: 'original',\n statuslineMode: 'detailed',\n thinkingWord: DEFAULT_TUI_THINKING_WORD,\n showAgentSwarmPanel: true,\n },\n circuitBreaker: { ...DEFAULT_CIRCUIT_BREAKER_CONFIG },\n modelRuntime: {\n // `effort` is intentionally undefined by default. Leaving it unset lets\n // each model use its provider-recommended reasoning effort (or none at\n // all) instead of forcing an opinionated value that may be unsupported,\n // silently omitted, and surfaced as a per-request warning. Users who\n // want a specific effort can opt in via `/settings` or the WebUI panel.\n reasoning: { mode: 'auto' },\n cache: { ttl: '1h' },\n },\n systemPrompt: { variant: 'default' },\n};\n", "import { ConfigError, ERROR_CODES } from '../../types/errors.js';\nimport { CONFIG_BEHAVIOR_DEFAULTS } from './defaults.js';\n\nexport function isPlainRecord(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) === Object.prototype\n );\n}\n\nfunction cloneJsonValue<T>(value: T): T {\n return structuredClone(value);\n}\n\n/**\n * Add-only default filling: copies missing keys from `defaults` into `target`\n * without removing or replacing any existing values. Recursively fills nested\n * plain objects. Safe for the normal boot path where a user's explicit config\n * must never be overwritten.\n *\n * For the add+replace variant (which also replaces type-incompatible values)\n * see `repairConfigDefaults`.\n */\nexport function fillMissingDefaults(\n target: Record<string, unknown>,\n defaults: Record<string, unknown>,\n): { value: Record<string, unknown>; changed: boolean } {\n const value = cloneJsonValue(target);\n const changed = fillMissingDefaultsInPlace(value, defaults);\n return { value, changed };\n}\n\nfunction fillMissingDefaultsInPlace(\n target: Record<string, unknown>,\n defaults: Record<string, unknown>,\n): boolean {\n let changed = false;\n for (const [key, defaultValue] of Object.entries(defaults)) {\n if (!Object.hasOwn(target, key)) {\n target[key] = cloneJsonValue(defaultValue);\n changed = true;\n continue;\n }\n const current = target[key];\n if (isPlainRecord(current) && isPlainRecord(defaultValue)) {\n changed = fillMissingDefaultsInPlace(current, defaultValue) || changed;\n }\n }\n return changed;\n}\n\nexport interface ConfigDefaultRepair {\n path: string;\n action: 'added' | 'replaced';\n}\n\nexport interface ConfigDefaultRepairReport {\n fixed: Record<string, unknown>;\n changes: ConfigDefaultRepair[];\n changed: boolean;\n}\n\n/**\n * Materialize the canonical behavior defaults into a persisted profile config.\n * Add+replace variant: missing fields are added AND values whose JSON shape is\n * incompatible with the default are replaced (not just skipped). This is useful\n * for the config-doctor repair path where a user-edited file may have wrong\n * types. For the normal boot path (add-only) see `fillMissingDefaults`.\n *\n * Identity fields (`provider`, `model`) are intentionally not invented.\n *\n * NOTE: This function assumes JSON-roundtripped input. Non-JSON values such\n * as `Buffer` or `Uint8Array` are objects and may not be correctly detected\n * as type-incompatible with primitive defaults.\n */\nexport function repairConfigDefaults(input: Record<string, unknown>): ConfigDefaultRepairReport {\n const fixed = cloneJsonValue(input);\n const changes: ConfigDefaultRepair[] = [];\n\n const MAX_REPAIR_DEPTH = 20;\n\n const repair = (\n target: Record<string, unknown>,\n defaults: Record<string, unknown>,\n prefix: string,\n depth: number = 0,\n ): void => {\n if (depth > MAX_REPAIR_DEPTH) {\n throw new ConfigError({\n message:\n `Config repair exceeded maximum depth (${MAX_REPAIR_DEPTH}) at \"${prefix}\". ` +\n 'This likely indicates a circular reference or deeply nested user-provided config.',\n code: ERROR_CODES.CONFIG_INVALID,\n context: { depth, prefix },\n });\n }\n for (const [key, defaultValue] of Object.entries(defaults)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (!Object.hasOwn(target, key)) {\n target[key] = cloneJsonValue(defaultValue);\n changes.push({ path, action: 'added' });\n continue;\n }\n\n const current = target[key];\n if (isPlainRecord(defaultValue)) {\n if (isPlainRecord(current)) {\n repair(current, defaultValue, path, depth + 1);\n } else {\n target[key] = cloneJsonValue(defaultValue);\n changes.push({ path, action: 'replaced' });\n }\n continue;\n }\n\n const defaultIsArray = Array.isArray(defaultValue);\n // Array element shape is NOT validated here \u2014 if an array default's\n // element type changes in a future version, existing arrays with the\n // old element type will be kept even though their elements no longer\n // match the new default element type. This is acceptable because:\n // (a) config changes that widen element types are extremely rare, and\n // (b) the config-doctor is a best-effort repair, not a type checker.\n const compatible = defaultIsArray\n ? Array.isArray(current)\n : !Array.isArray(current) && typeof current === typeof defaultValue;\n if (!compatible) {\n target[key] = cloneJsonValue(defaultValue);\n changes.push({ path, action: 'replaced' });\n }\n }\n };\n\n repair(fixed, CONFIG_BEHAVIOR_DEFAULTS as Record<string, unknown>, '');\n return { fixed, changes, changed: changes.length > 0 };\n}\n", "/**\n * Surface the OS error code (EACCES, ENOSPC, ...) alongside the message in\n * storage.* event payloads. Codes are stable and locale-independent.\n */\nexport function storageErrorString(err: unknown): string {\n if (err instanceof Error) {\n const code = (err as NodeJS.ErrnoException).code;\n return code ? `${code}: ${err.message}` : err.message;\n }\n /* v8 ignore next -- defensive: callers only pass fs Error instances */\n return String(err);\n}\n", "import type { Config } from '../../types/config.js';\n\nfunction envBool(v: string): boolean {\n return !/^(0|false|no|off)$/i.test(v.trim());\n}\n\nexport function envBoolOptional(v: string | undefined): boolean {\n return v !== undefined && envBool(v);\n}\n\nconst LOG_LEVELS = new Set<Config['log']['level']>(['error', 'warn', 'info', 'debug', 'trace']);\n\nfunction envLogLevel(v: string): Config['log']['level'] {\n return LOG_LEVELS.has(v as Config['log']['level']) ? (v as Config['log']['level']) : 'info';\n}\n\nconst defaultIndexing = {\n onSessionStart: true,\n onEdit: true,\n watchExternal: true,\n debounceMs: 400,\n} as const;\n\nexport type PartialConfig = Partial<Config> & {\n providers?: Record<\n string,\n { apiKey?: string | undefined; baseUrl?: string | undefined; type?: string | undefined }\n >;\n /** Fields that came from environment variables - must not be persisted. */\n _envSource?: Set<string> | undefined;\n};\n\nexport const ENV_MAP: Record<string, (cfg: PartialConfig, val: string) => void> = {\n WRONGSTACK_PROVIDER: (c, v) => {\n c.provider = v;\n if (c._envSource === undefined) c._envSource = new Set();\n c._envSource.add('provider');\n },\n WRONGSTACK_MODEL: (c, v) => {\n c.model = v;\n if (c._envSource === undefined) c._envSource = new Set();\n c._envSource.add('model');\n },\n WRONGSTACK_API_KEY: (c, v) => {\n c.apiKey = v;\n if (c._envSource === undefined) c._envSource = new Set();\n c._envSource.add('apiKey');\n },\n WRONGSTACK_BASE_URL: (c, v) => {\n c.baseUrl = v;\n if (c._envSource === undefined) c._envSource = new Set();\n c._envSource.add('baseUrl');\n },\n WRONGSTACK_LOG_LEVEL: (c, v) => {\n /* v8 ignore next -- defensive: config defaults always seed c.log before env handlers run */\n if (!c.log) c.log = { level: 'info' };\n c.log.level = envLogLevel(v);\n },\n WRONGSTACK_INDEX_ON_START: (c, v) => {\n c.indexing = { ...defaultIndexing, ...c.indexing, onSessionStart: envBool(v) };\n },\n WRONGSTACK_INDEX_ON_EDIT: (c, v) => {\n c.indexing = { ...defaultIndexing, ...c.indexing, onEdit: envBool(v) };\n },\n WRONGSTACK_INDEX_WATCH: (c, v) => {\n c.indexing = { ...defaultIndexing, ...c.indexing, watchExternal: envBool(v) };\n },\n};\n", "import type { PartialConfig } from './env-overrides.js';\n\nconst IN_PROJECT_ALLOWED_KEYS: ReadonlySet<string> = new Set([\n 'version',\n 'model',\n 'cwd',\n 'context',\n 'tools',\n 'features',\n 'Sage',\n 'skills',\n 'autonomy',\n 'indexing',\n 'session',\n 'log',\n 'launch',\n 'nextPrediction',\n 'hints',\n 'debugStream',\n 'configScope',\n 'maxConcurrent',\n 'uiLocale',\n 'fallbackModels',\n 'fallbackProfiles',\n 'favoriteModels',\n 'favoriteModelsOnly',\n 'modelAvailabilitySchedule',\n 'fallbackAuto',\n 'fallbackStickiness',\n 'models',\n 'modelMatrix',\n 'circuitBreaker',\n 'adaptiveConcurrency',\n 'modelRuntime',\n]);\n\nconst KNOWN_DENIED_IN_PROJECT: ReadonlyArray<{ key: string; reason: string }> = [\n {\n key: 'activeProfile',\n reason: 'Only the trusted root bootstrap may select the active profile.',\n },\n { key: 'provider', reason: 'Provider id override; can intercept prompts/responses.' },\n { key: 'apiKey', reason: 'Overrides user API key; exfiltrates prompts.' },\n { key: 'baseUrl', reason: 'Redirects provider endpoint; leaks real API key.' },\n { key: 'providers', reason: 'Per-provider apiKey/baseUrl/oauthConfig; same redirect/exfil.' },\n { key: 'mcpServers', reason: 'Arbitrary command/args/env spawned at boot (RCE).' },\n { key: 'hooks', reason: 'Shell command arrays on lifecycle events (RCE).' },\n { key: 'plugins', reason: 'Dynamic npm package load at boot (RCE).' },\n {\n key: 'pluginManager',\n reason: 'Controls which plugin boot states the LLM may mutate; user-owned trust policy.',\n },\n { key: 'sync', reason: 'Carries githubToken credential and target repo.' },\n { key: 'yolo', reason: 'Disables all permission confirmation prompts.' },\n { key: 'extensions', reason: 'Per-plugin config can carry command/credential fields.' },\n { key: 'hq', reason: 'Carries HQ client token credential and endpoint URL.' },\n { key: 'acp', reason: 'Per-agent ACP command/args/env override \u2192 arbitrary command exec (RCE).' },\n {\n key: 'fleet',\n reason:\n 'Fleet supervision knobs: a repo-committed config could enable autonomous subagent spawning/steering/termination and mailbox traffic on the victim machine.',\n },\n {\n key: 'brain',\n reason:\n 'Brain decision-layer knobs: a repo-committed config could raise the autonomy risk ceiling, switch the Brain to headless (removing the human tier), or reroute Brain decisions to an attacker-chosen provider/model.',\n },\n {\n key: 'git',\n reason:\n \"Carries git.identity (GIT_AUTHOR_*/GIT_COMMITTER_* injection): a repo-committed config could spoof the author identity written into the victim's commit history (impersonation).\",\n },\n];\n\nconst KNOWN_CONFIG_TOP_LEVEL_KEYS: ReadonlySet<string> = new Set([\n 'version',\n 'activeProfile',\n 'provider',\n 'model',\n 'apiKey',\n 'baseUrl',\n 'maxConcurrent',\n 'uiLocale',\n 'providers',\n 'models',\n 'modelMatrix',\n 'context',\n 'tools',\n 'mcpServers',\n 'fallbackModels',\n 'fallbackProfiles',\n 'favoriteModels',\n 'favoriteModelsOnly',\n 'modelAvailabilitySchedule',\n 'fallbackAuto',\n 'fallbackStickiness',\n 'hooks',\n 'plugins',\n 'pluginManager',\n 'log',\n 'features',\n 'Sage',\n 'skills',\n 'yolo',\n 'nextPrediction',\n 'cwd',\n 'autonomy',\n 'hints',\n 'debugStream',\n 'configScope',\n 'indexing',\n 'circuitBreaker',\n 'adaptiveConcurrency',\n 'launch',\n 'session',\n 'modelRuntime',\n 'hq',\n 'sync',\n 'extensions',\n 'acp',\n 'fleet',\n 'brain',\n 'git',\n]);\n\nexport function assertInProjectAllowListComplete(): void {\n const missingFromBoth: string[] = [];\n for (const key of KNOWN_CONFIG_TOP_LEVEL_KEYS) {\n if (IN_PROJECT_ALLOWED_KEYS.has(key)) continue;\n const denied = KNOWN_DENIED_IN_PROJECT.find((d) => d.key === key);\n if (!denied) missingFromBoth.push(key);\n }\n const staleDenials = KNOWN_DENIED_IN_PROJECT.filter(\n (d) => !KNOWN_CONFIG_TOP_LEVEL_KEYS.has(d.key),\n ).map((d) => d.key);\n const duplicate = KNOWN_DENIED_IN_PROJECT.filter((d) => IN_PROJECT_ALLOWED_KEYS.has(d.key)).map(\n (d) => d.key,\n );\n\n const problems: string[] = [];\n if (missingFromBoth.length > 0) {\n problems.push(\n `new Config field(s) not classified as allowed or denied for in-project config: ` +\n missingFromBoth.join(', ') +\n '. Add each to IN_PROJECT_ALLOWED_KEYS (if safe) or KNOWN_DENIED_IN_PROJECT (with a reason).',\n );\n }\n if (staleDenials.length > 0) {\n problems.push(\n `KNOWN_DENIED_IN_PROJECT references keys that no longer exist on Config: ` +\n staleDenials.join(', ') +\n '. Remove them or restore the field on Config.',\n );\n }\n if (duplicate.length > 0) {\n problems.push(\n `field(s) appear in BOTH IN_PROJECT_ALLOWED_KEYS and KNOWN_DENIED_IN_PROJECT: ` +\n duplicate.join(', ') +\n '. The allow-list wins at runtime; remove from one of the two.',\n );\n }\n if (problems.length > 0) {\n throw new Error(\n `stripUnsafeInProjectFields drift check failed:\\n - ${problems.join('\\n - ')}`,\n );\n }\n}\n\nlet driftChecked = false;\n\nexport function stripUnsafeInProjectFields(\n inProject: PartialConfig,\n sourcePath: string,\n warn: (msg: string) => void = (msg) => console.warn(msg),\n): PartialConfig {\n if (!driftChecked) {\n assertInProjectAllowListComplete();\n driftChecked = true;\n }\n const stripped: string[] = [];\n const out: PartialConfig = {};\n for (const [k, v] of Object.entries(inProject)) {\n if (IN_PROJECT_ALLOWED_KEYS.has(k)) {\n (out as Record<string, unknown>)[k] = v;\n continue;\n }\n stripped.push(k);\n }\n\n const outTools = (out as Record<string, unknown>)['tools'];\n if (outTools && typeof outTools === 'object') {\n const execCfg = (outTools as Record<string, unknown>)['exec'];\n if (execCfg && typeof execCfg === 'object') {\n const hasAllow = 'allow' in (execCfg as Record<string, unknown>);\n const hasDanger = 'danger' in (execCfg as Record<string, unknown>);\n if (hasAllow || hasDanger) {\n const clonedExec: Record<string, unknown> = { ...(execCfg as Record<string, unknown>) };\n if (hasAllow) {\n delete clonedExec['allow'];\n stripped.push('tools.exec.allow');\n }\n if (hasDanger) {\n delete clonedExec['danger'];\n stripped.push('tools.exec.danger');\n }\n (out as Record<string, unknown>)['tools'] = {\n ...(outTools as Record<string, unknown>),\n exec: clonedExec,\n };\n }\n }\n }\n\n const outSkills = (out as Record<string, unknown>)['skills'];\n if (outSkills && typeof outSkills === 'object') {\n const skillsRec = outSkills as Record<string, unknown>;\n const needsClone = 'extraDirs' in skillsRec || 'registryUrl' in skillsRec;\n if (needsClone) {\n const clonedSkills = { ...skillsRec };\n if ('extraDirs' in clonedSkills) {\n delete clonedSkills['extraDirs'];\n stripped.push('skills.extraDirs');\n }\n if ('registryUrl' in clonedSkills) {\n delete clonedSkills['registryUrl'];\n stripped.push('skills.registryUrl');\n }\n (out as Record<string, unknown>)['skills'] = clonedSkills;\n }\n }\n\n const outSage = (out as Record<string, unknown>)['Sage'];\n if (outSage && typeof outSage === 'object') {\n const storage = (outSage as Record<string, unknown>)['storage'];\n if (\n storage &&\n typeof storage === 'object' &&\n 'directory' in (storage as Record<string, unknown>)\n ) {\n const clonedStorage = { ...(storage as Record<string, unknown>) };\n delete clonedStorage['directory'];\n (out as Record<string, unknown>)['Sage'] = {\n ...(outSage as Record<string, unknown>),\n storage: clonedStorage,\n };\n stripped.push('Sage.storage.directory');\n }\n }\n\n if (stripped.length > 0) {\n warn(\n JSON.stringify({\n level: 'warn',\n event: 'config.in_project_unsafe_fields_ignored',\n path: sourcePath,\n ignoredKeys: stripped,\n message:\n `Ignored ${stripped.length} field(s) from the repo-committed config ` +\n `\"${sourcePath}\": ${stripped.join(', ')}. ` +\n `Only a small allow-list of benign preferences (model, context, tools limits, ` +\n `features, \u2026) may be set by <project>/.wrongstack/config.json. ` +\n `Everything else must live in your active profile config.`,\n timestamp: new Date().toISOString(),\n }),\n );\n }\n return out;\n}\n", "import type { CustomModelDefinition } from '../../types/config.js';\nimport type { Capabilities } from '../../types/provider.js';\nimport { FORBIDDEN_PROTO_KEYS } from '../../utils/deep-merge.js';\n\nexport type InlineProviderModelWarning = (\n message: string,\n context?: Record<string, unknown>,\n) => void;\n\nconst BOOLEAN_CAPABILITIES = [\n 'tools',\n 'parallelTools',\n 'vision',\n 'streaming',\n 'promptCache',\n 'systemPrompt',\n 'jsonMode',\n 'reasoning',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n 'structuredOutput',\n 'logprobs',\n 'audio',\n 'multipleCompletions',\n] as const satisfies readonly (keyof Capabilities)[];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction positiveNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined;\n}\n\nfunction readCapabilities(model: Record<string, unknown>): Partial<Capabilities> | undefined {\n const raw = isRecord(model['capabilities']) ? model['capabilities'] : undefined;\n const capabilities: Partial<Capabilities> = {};\n\n if (raw) {\n for (const key of BOOLEAN_CAPABILITIES) {\n const value = raw[key];\n if (typeof value === 'boolean') capabilities[key] = value;\n }\n const cacheControl = raw['cacheControl'];\n if (cacheControl === 'native' || cacheControl === 'auto' || cacheControl === 'none') {\n capabilities.cacheControl = cacheControl;\n }\n }\n\n const limit = isRecord(model['limit']) ? model['limit'] : undefined;\n const maxContext =\n positiveNumber(raw?.['maxContext']) ??\n positiveNumber(model['maxContext']) ??\n positiveNumber(model['contextWindow']) ??\n positiveNumber(limit?.['context']);\n if (maxContext !== undefined) capabilities.maxContext = maxContext;\n\n const capabilityMaxOutput = positiveNumber(raw?.['maxOutput']);\n if (capabilityMaxOutput !== undefined) capabilities.maxOutput = capabilityMaxOutput;\n\n if (typeof model['tool_call'] === 'boolean' && capabilities.tools === undefined) {\n capabilities.tools = model['tool_call'];\n }\n if (typeof model['reasoning'] === 'boolean' && capabilities.reasoning === undefined) {\n capabilities.reasoning = model['reasoning'];\n }\n\n const modalities = isRecord(model['modalities']) ? model['modalities'] : undefined;\n const inputModalities = modalities?.['input'];\n if (Array.isArray(inputModalities) && capabilities.vision === undefined) {\n capabilities.vision = inputModalities.includes('image');\n }\n\n return Object.keys(capabilities).length > 0 ? capabilities : undefined;\n}\n\nfunction inlineDefinition(model: Record<string, unknown>): CustomModelDefinition {\n const definition: CustomModelDefinition = {};\n const name = model['name'];\n if (typeof name === 'string' && name.trim().length > 0) definition.name = name;\n\n const provider = model['provider'];\n if (typeof provider === 'string' && provider.trim().length > 0) {\n definition.provider = provider;\n }\n\n const limit = isRecord(model['limit']) ? model['limit'] : undefined;\n const maxOutput =\n positiveNumber(model['maxOutput']) ??\n positiveNumber(limit?.['output']) ??\n positiveNumber(\n isRecord(model['capabilities']) ? model['capabilities']['maxOutput'] : undefined,\n );\n if (maxOutput !== undefined) definition.maxOutput = maxOutput;\n\n const capabilities = readCapabilities(model);\n if (capabilities) definition.capabilities = capabilities;\n return definition;\n}\n\nfunction mergeDefinitions(\n base: CustomModelDefinition | undefined,\n patch: CustomModelDefinition,\n): CustomModelDefinition {\n return {\n ...base,\n ...patch,\n ...(base?.capabilities || patch.capabilities\n ? { capabilities: { ...base?.capabilities, ...patch.capabilities } }\n : {}),\n };\n}\n\n/**\n * Normalize model.dev-style objects accepted in `providers.<id>.models` into\n * the canonical runtime representation: a string model allowlist plus the\n * provider-local `customModels` metadata map.\n *\n * The function mutates only the provider entries it normalizes. Explicit\n * `customModels` values win field-by-field over metadata derived from inline\n * objects, preserving the existing configuration override contract.\n */\nexport function normalizeInlineProviderModels(\n config: Record<string, unknown>,\n warn?: InlineProviderModelWarning,\n): void {\n const providers = config['providers'];\n if (!isRecord(providers)) return;\n\n for (const [providerId, rawProvider] of Object.entries(providers)) {\n if (!isRecord(rawProvider) || !Array.isArray(rawProvider['models'])) continue;\n\n const ids: string[] = [];\n const seen = new Set<string>();\n const derived = new Map<string, CustomModelDefinition>();\n\n for (const [index, entry] of rawProvider['models'].entries()) {\n let id: string | undefined;\n let definition: CustomModelDefinition | undefined;\n\n if (typeof entry === 'string' && entry.length > 0) {\n id = entry;\n } else if (isRecord(entry)) {\n const rawId = entry['id'];\n if (typeof rawId === 'string' && rawId.trim().length > 0) {\n id = rawId.trim();\n if (!FORBIDDEN_PROTO_KEYS.has(id)) definition = inlineDefinition(entry);\n }\n }\n\n if (!id || FORBIDDEN_PROTO_KEYS.has(id)) {\n warn?.('Ignoring invalid inline provider model entry', {\n event: 'config.invalid_inline_provider_model',\n provider: providerId,\n index,\n });\n continue;\n }\n\n if (!seen.has(id)) {\n seen.add(id);\n ids.push(id);\n }\n if (definition) derived.set(id, mergeDefinitions(derived.get(id), definition));\n }\n\n rawProvider['models'] = ids;\n if (derived.size === 0) continue;\n\n const explicit = isRecord(rawProvider['customModels'])\n ? rawProvider['customModels']\n : undefined;\n const normalized: Record<string, CustomModelDefinition> = Object.create(null) as Record<\n string,\n CustomModelDefinition\n >;\n for (const [id, definition] of derived) normalized[id] = definition;\n if (explicit) {\n for (const [id, value] of Object.entries(explicit)) {\n if (FORBIDDEN_PROTO_KEYS.has(id) || !isRecord(value)) continue;\n normalized[id] = mergeDefinitions(normalized[id], value as CustomModelDefinition);\n }\n }\n rawProvider['customModels'] = normalized;\n }\n}\n", "import { isPlainRecord } from './default-repair.js';\n\n/**\n * Migrate the retired `superMemory` config key (pre-SAGE-rename user configs)\n * into `Sage`. Existing `Sage` values win on conflict; top-level sub-keys the\n * user only ever set under `superMemory` are preserved so a rename release\n * does not silently drop their storage/injection/hygiene settings.\n */\nexport function migrateLegacySuperMemoryKey(config: Record<string, unknown>): boolean {\n const legacy = config['superMemory'];\n if (legacy === undefined) return false;\n if (isPlainRecord(legacy)) {\n const current = config['Sage'];\n config['Sage'] = isPlainRecord(current) ? { ...legacy, ...current } : { ...legacy };\n }\n delete config['superMemory'];\n return true;\n}\n\n/** Remove the retired backend selector from legacy/user-supplied configs. */\nexport function removeLegacySageEngine(config: Record<string, unknown>): boolean {\n const migratedKey = migrateLegacySuperMemoryKey(config);\n const Sage = config['Sage'];\n if (!isPlainRecord(Sage)) return migratedKey;\n const storage = Sage['storage'];\n if (!isPlainRecord(storage) || !Object.hasOwn(storage, 'engine')) {\n return migratedKey;\n }\n delete storage['engine'];\n return true;\n}\n", "import * as path from 'node:path';\n\n/**\n * Compare two absolute filesystem paths for identity. Normalizes separators and\n * `.`/`..` segments via `path.resolve`, and folds case on win32 (and darwin,\n * whose default APFS/HFS+ volumes are case-insensitive) so the same file\n * reached through differently-cased drive/dir spellings still compares equal \u2014\n * the same Windows path-casing hazard that bit the core token symbols.\n */\nexport function samePath(a: string, b: string): boolean {\n let ra = path.resolve(a);\n let rb = path.resolve(b);\n if (process.platform === 'win32' || process.platform === 'darwin') {\n ra = ra.toLowerCase();\n rb = rb.toLowerCase();\n }\n return ra === rb;\n}\n", "import * as fs from 'node:fs';\nimport * as fsPromises from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite } from './atomic-write.js';\nimport { isUlid, ulid } from './ulid.js';\n\nexport const PROJECT_IDENTITY_VERSION = 1 as const;\nexport const PROJECT_ID_PREFIX = 'proj_';\nexport const PROJECT_IDENTITY_RELATIVE_PATH = path.join('.wrongstack', 'project.json');\n\nexport interface ProjectIdentityFile {\n version: typeof PROJECT_IDENTITY_VERSION;\n projectId: string;\n}\n\nexport interface EnsureProjectIdentityResult {\n identity: ProjectIdentityFile;\n created: boolean;\n}\n\nexport interface RekeyProjectIdentityResult {\n previous?: ProjectIdentityFile | undefined;\n identity: ProjectIdentityFile;\n}\n\nconst PROJECT_GITIGNORE_RULES = [\n '.wrongstack/',\n '!/.wrongstack/',\n '/.wrongstack/*',\n '!/.wrongstack/project.json',\n] as const;\n\nexport function projectIdentityPath(projectRoot: string): string {\n return path.join(projectRoot, PROJECT_IDENTITY_RELATIVE_PATH);\n}\n\nexport function createProjectId(seedTime: number = Date.now()): string {\n return `${PROJECT_ID_PREFIX}${ulid(seedTime)}`;\n}\n\nexport function isProjectId(value: string): boolean {\n return value.startsWith(PROJECT_ID_PREFIX) && isUlid(value.slice(PROJECT_ID_PREFIX.length));\n}\n\nexport function readProjectIdentitySync(projectRoot: string): ProjectIdentityFile | undefined {\n const filePath = projectIdentityPath(projectRoot);\n try {\n return parseProjectIdentity(fs.readFileSync(filePath, 'utf8'), filePath);\n } catch (error) {\n if (isMissingFileError(error)) return undefined;\n throw error;\n }\n}\n\nexport async function readProjectIdentity(\n projectRoot: string,\n): Promise<ProjectIdentityFile | undefined> {\n const filePath = projectIdentityPath(projectRoot);\n try {\n return parseProjectIdentity(await fsPromises.readFile(filePath, 'utf8'), filePath);\n } catch (error) {\n if (isMissingFileError(error)) return undefined;\n throw error;\n }\n}\n\nexport async function ensureProjectIdentity(\n projectRoot: string,\n idFactory: () => string = createProjectId,\n): Promise<EnsureProjectIdentityResult> {\n const existing = await readProjectIdentity(projectRoot);\n if (existing) return { identity: existing, created: false };\n\n const filePath = projectIdentityPath(projectRoot);\n const identity = makeIdentity(idFactory());\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n\n try {\n await fsPromises.writeFile(filePath, serializeProjectIdentity(identity), {\n encoding: 'utf8',\n flag: 'wx',\n });\n return { identity, created: true };\n } catch (error) {\n if (!isAlreadyExistsError(error)) throw error;\n const winner = await readProjectIdentity(projectRoot);\n if (!winner) throw error;\n return { identity: winner, created: false };\n }\n}\n\nexport async function rekeyProjectIdentity(\n projectRoot: string,\n idFactory: () => string = createProjectId,\n): Promise<RekeyProjectIdentityResult> {\n const previous = await readProjectIdentity(projectRoot);\n const identity = makeIdentity(idFactory());\n const filePath = projectIdentityPath(projectRoot);\n await fsPromises.mkdir(path.dirname(filePath), { recursive: true });\n await atomicWrite(filePath, serializeProjectIdentity(identity));\n return { previous, identity };\n}\n\n/**\n * Keep runtime state ignored while allowing the small, explicitly shared\n * WrongStack project contract to travel with the repository.\n */\nexport async function ensureProjectGitignore(projectRoot: string): Promise<void> {\n const filePath = path.join(projectRoot, '.gitignore');\n let content = '';\n try {\n content = await fsPromises.readFile(filePath, 'utf8');\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n }\n\n const hadTrailingNewline = content.endsWith('\\n');\n const lines = content.length === 0 ? [] : content.split(/\\r?\\n/);\n if (hadTrailingNewline) lines.pop();\n\n let changed = false;\n for (let index = 0; index < lines.length; index++) {\n if (lines[index]?.trim() === '.wrongstack/*') {\n lines[index] = '.wrongstack/';\n changed = true;\n }\n }\n\n for (const entry of PROJECT_GITIGNORE_RULES) {\n if (!lines.some((line) => line.trim() === entry)) {\n if (entry === '.wrongstack/' && lines.length > 0 && lines.at(-1) !== '') lines.push('');\n lines.push(entry);\n changed = true;\n }\n }\n\n if (!changed) return;\n await fsPromises.writeFile(filePath, `${lines.join('\\n')}\\n`, 'utf8');\n}\n\nfunction makeIdentity(projectId: string): ProjectIdentityFile {\n if (!isProjectId(projectId)) {\n throw new Error(`Invalid WrongStack project id: ${projectId}`);\n }\n return { version: PROJECT_IDENTITY_VERSION, projectId };\n}\n\nfunction parseProjectIdentity(raw: string, filePath: string): ProjectIdentityFile {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in WrongStack project identity file: ${filePath}`);\n }\n if (typeof value !== 'object' || value === null) {\n throw new Error(`Invalid WrongStack project identity file: ${filePath}`);\n }\n const record = value as Record<string, unknown>;\n if (record['version'] !== PROJECT_IDENTITY_VERSION) {\n throw new Error(`Unsupported WrongStack project identity version in ${filePath}`);\n }\n if (typeof record['projectId'] !== 'string' || !isProjectId(record['projectId'])) {\n throw new Error(`Invalid projectId in WrongStack project identity file: ${filePath}`);\n }\n return { version: PROJECT_IDENTITY_VERSION, projectId: record['projectId'] };\n}\n\nfunction serializeProjectIdentity(identity: ProjectIdentityFile): string {\n return `${JSON.stringify(identity, null, 2)}\\n`;\n}\n\nfunction isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT';\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === 'EEXIST';\n}\n", "import { randomBytes } from 'node:crypto';\n\n/**\n * Crockford base32 alphabet (excludes I, L, O, U to avoid ambiguity).\n */\nconst ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\nconst ENCODING_LEN = ENCODING.length;\nconst TIME_LEN = 10;\nconst RANDOM_LEN = 16;\n\nfunction encodeTime(now: number, len: number): string {\n let mod: number;\n let str = '';\n for (let i = len - 1; i >= 0; i--) {\n mod = now % ENCODING_LEN;\n str = ENCODING[mod] + str;\n now = (now - mod) / ENCODING_LEN;\n }\n return str;\n}\n\nfunction encodeRandom(len: number): string {\n const bytes = randomBytes(len);\n let str = '';\n for (let i = 0; i < len; i++) {\n str += ENCODING[(bytes[i] as number) % ENCODING_LEN];\n }\n return str;\n}\n\n/**\n * Generate a ULID \u2014 a 26-char Crockford-base32 identifier whose first 10 chars\n * encode the millisecond timestamp (so IDs sort lexicographically by creation\n * time) followed by 16 chars of randomness. Zero runtime dependencies.\n *\n * The codebase convention is \"IDs are ULIDs\"; use this for any new store key.\n */\nexport function ulid(seedTime: number = Date.now()): string {\n return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN);\n}\n\n/** True for a well-formed 26-char Crockford-base32 ULID. */\nexport function isUlid(value: string): boolean {\n if (value.length !== TIME_LEN + RANDOM_LEN) return false;\n for (const ch of value) {\n if (!ENCODING.includes(ch)) return false;\n }\n return true;\n}\n"],
5
- "mappings": "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",
6
- "names": ["fs", "path", "stat", "fs", "path", "resolve", "projectSlug", "open", "path", "fs", "os", "path", "fs", "fsp", "path", "stat", "key", "fs", "fs", "path", "fs", "os", "path", "projectHash", "LOG_LEVELS", "isRecord", "path", "deepMerge", "stat", "path", "randomBytes", "getSessionRegistry"]
7
- }