@wrongstack/core 0.297.0 → 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 (800) 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 +238 -157
  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-trace.d.ts +2 -1
  8. package/dist/coordination/director/director-task-registry.d.ts +12 -0
  9. package/dist/coordination/fleet-supervisor.d.ts +21 -0
  10. package/dist/coordination/index.d.ts +23 -21
  11. package/dist/coordination/index.js +16493 -16068
  12. package/dist/coordination/mail-tools.d.ts +3 -3
  13. package/dist/coordination/mailbox-credential-store.d.ts +22 -2
  14. package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
  15. package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
  16. package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
  17. package/dist/coordination/mailbox-project-server.js +508 -253
  18. package/dist/coordination/provider-status-tracker.d.ts +2 -0
  19. package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
  20. package/dist/coordination/remote-mailbox.d.ts +8 -4
  21. package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
  22. package/dist/core/fallback-profile-manager.d.ts +14 -0
  23. package/dist/core/index.js +451 -137
  24. package/dist/core/instruction-bundle.d.ts +12 -0
  25. package/dist/core/system-prompt-builder.d.ts +14 -0
  26. package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
  27. package/dist/core/system-prompt-skill-text.d.ts +1 -2
  28. package/dist/defaults/index.js +2081 -1102
  29. package/dist/design/index.js +47 -8
  30. package/dist/execution/design-materialize.d.ts +22 -0
  31. package/dist/execution/index.js +495 -248
  32. package/dist/execution/skill-loader.d.ts +10 -1
  33. package/dist/execution/tool-error-taxonomy.d.ts +31 -0
  34. package/dist/execution/tool-executor.d.ts +1 -0
  35. package/dist/goal/index.js +3 -1
  36. package/dist/hooks/index.js +5 -0
  37. package/dist/hq/auth-audit.d.ts +6 -0
  38. package/dist/hq/auth-store.d.ts +59 -3
  39. package/dist/hq/index.js +401 -101
  40. package/dist/hq/kanban-store.d.ts +3 -0
  41. package/dist/hq/protocol/core.d.ts +3 -15
  42. package/dist/hq/protocol/envelope.d.ts +29 -0
  43. package/dist/hq/protocol/governance.d.ts +34 -0
  44. package/dist/hq/protocol/project.d.ts +3 -0
  45. package/dist/hq/protocol/resume.d.ts +1 -1
  46. package/dist/hq/protocol.d.ts +9 -8
  47. package/dist/hq/protocol.js +675 -0
  48. package/dist/index.js +8518 -6416
  49. package/dist/infrastructure/index.js +198 -101
  50. package/dist/kernel/events/session-events.d.ts +3 -0
  51. package/dist/kernel/events/tool-events.d.ts +3 -1
  52. package/dist/models/index.js +1 -1
  53. package/dist/observability/index.js +27 -0
  54. package/dist/observability/prometheus.d.ts +11 -0
  55. package/dist/plugin/index.d.ts +5 -1
  56. package/dist/plugin/index.js +950 -509
  57. package/dist/plugins/review-store-maintenance.d.ts +26 -0
  58. package/dist/plugins/review-types.d.ts +6 -0
  59. package/dist/security/capabilities.d.ts +45 -1
  60. package/dist/security/error-sanitize.d.ts +49 -0
  61. package/dist/security/file-permissions.d.ts +41 -0
  62. package/dist/security/index.d.ts +9 -6
  63. package/dist/security/index.js +3007 -2032
  64. package/dist/security/permission-policy.d.ts +55 -3
  65. package/dist/security/secret-vault.d.ts +17 -0
  66. package/dist/security/totp.d.ts +86 -0
  67. package/dist/skills/frontmatter.d.ts +12 -1
  68. package/dist/skills/github-fetcher.d.ts +48 -0
  69. package/dist/skills/index.js +137 -26
  70. package/dist/skills/limits.d.ts +19 -0
  71. package/dist/skills/skill-installer.d.ts +13 -0
  72. package/dist/storage/index.js +928 -732
  73. package/dist/storage/provider-config-watcher.d.ts +1 -0
  74. package/dist/storage/session-helpers.d.ts +1 -0
  75. package/dist/storage/session-store.d.ts +9 -2
  76. package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
  77. package/dist/tools/fallback-manage-tools.d.ts +6 -0
  78. package/dist/tools/index.js +287 -131
  79. package/dist/tools/mcp-use.d.ts +1 -1
  80. package/dist/types/blocks.d.ts +7 -0
  81. package/dist/types/config/autonomy.d.ts +12 -3
  82. package/dist/types/config/mcp-features.d.ts +9 -1
  83. package/dist/types/config/root.d.ts +10 -4
  84. package/dist/types/context-window.d.ts +15 -0
  85. package/dist/types/index.d.ts +1 -1
  86. package/dist/types/secret-vault.d.ts +8 -0
  87. package/dist/types/session.d.ts +2 -0
  88. package/dist/types/skill.d.ts +56 -0
  89. package/dist/types/tool-executor.d.ts +2 -0
  90. package/dist/utils/env-typed.d.ts +64 -0
  91. package/dist/utils/glob-match.d.ts +21 -1
  92. package/dist/utils/heap-watchdog.js +1 -1
  93. package/dist/utils/incoming-images.d.ts +19 -0
  94. package/dist/utils/index.d.ts +15 -12
  95. package/dist/utils/index.js +3083 -2801
  96. package/dist/utils/path-segment.d.ts +29 -0
  97. package/dist/utils/win32-cmd.d.ts +25 -0
  98. package/dist/worktree/index.js +5 -0
  99. package/package.json +8 -3
  100. package/skills/chimera/SKILL.md +16 -4
  101. package/skills/data-governance/SKILL.md +92 -0
  102. package/skills/wrongstack-kanban/SKILL.md +125 -64
  103. package/dist/agent-status-helpers.d.ts.map +0 -1
  104. package/dist/agent-status-tracker.d.ts.map +0 -1
  105. package/dist/boot.d.ts.map +0 -1
  106. package/dist/chronicle/context.d.ts.map +0 -1
  107. package/dist/chronicle/decision-adapter.d.ts.map +0 -1
  108. package/dist/chronicle/domain-adapter.d.ts.map +0 -1
  109. package/dist/chronicle/event-hash.d.ts.map +0 -1
  110. package/dist/chronicle/file-observer.d.ts.map +0 -1
  111. package/dist/chronicle/health-monitor.d.ts.map +0 -1
  112. package/dist/chronicle/identity.d.ts.map +0 -1
  113. package/dist/chronicle/index.d.ts.map +0 -1
  114. package/dist/chronicle/index.js.map +0 -7
  115. package/dist/chronicle/journal.d.ts.map +0 -1
  116. package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
  117. package/dist/chronicle/metrics-store.d.ts.map +0 -1
  118. package/dist/chronicle/partition-filename.d.ts.map +0 -1
  119. package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
  120. package/dist/chronicle/process-adapter.d.ts.map +0 -1
  121. package/dist/chronicle/project-access.d.ts.map +0 -1
  122. package/dist/chronicle/project-server-client.d.ts.map +0 -1
  123. package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
  124. package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
  125. package/dist/chronicle/project-server.d.ts.map +0 -1
  126. package/dist/chronicle/project-server.js.map +0 -7
  127. package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
  128. package/dist/chronicle/provider-adapter.d.ts.map +0 -1
  129. package/dist/chronicle/query.d.ts.map +0 -1
  130. package/dist/chronicle/review-adapter.d.ts.map +0 -1
  131. package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
  132. package/dist/chronicle/sink.d.ts.map +0 -1
  133. package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
  134. package/dist/chronicle/sqlite-query.d.ts.map +0 -1
  135. package/dist/chronicle/stream-adapter.d.ts.map +0 -1
  136. package/dist/chronicle/tool-adapter.d.ts.map +0 -1
  137. package/dist/chronicle/types.d.ts.map +0 -1
  138. package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
  139. package/dist/coordination/agent-bridge.d.ts.map +0 -1
  140. package/dist/coordination/agent-monitor.d.ts.map +0 -1
  141. package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
  142. package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
  143. package/dist/coordination/agents/index.d.ts.map +0 -1
  144. package/dist/coordination/agents/index.js.map +0 -7
  145. package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
  146. package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
  147. package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
  148. package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
  149. package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
  150. package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
  151. package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
  152. package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
  153. package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
  154. package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
  155. package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
  156. package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
  157. package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
  158. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
  159. package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
  160. package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
  161. package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
  162. package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
  163. package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
  164. package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
  165. package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
  166. package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
  167. package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
  168. package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
  169. package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
  170. package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
  171. package/dist/coordination/agents/role-skills.d.ts.map +0 -1
  172. package/dist/coordination/agents/types.d.ts.map +0 -1
  173. package/dist/coordination/agents.d.ts.map +0 -1
  174. package/dist/coordination/auto-extend.d.ts.map +0 -1
  175. package/dist/coordination/autonomous-brain.d.ts.map +0 -1
  176. package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
  177. package/dist/coordination/brain-cache.d.ts.map +0 -1
  178. package/dist/coordination/brain-heuristics.d.ts.map +0 -1
  179. package/dist/coordination/brain-ledger.d.ts.map +0 -1
  180. package/dist/coordination/brain-monitor.d.ts.map +0 -1
  181. package/dist/coordination/brain-rules.d.ts.map +0 -1
  182. package/dist/coordination/brain-telemetry.d.ts.map +0 -1
  183. package/dist/coordination/brain-trace.d.ts.map +0 -1
  184. package/dist/coordination/brain.d.ts.map +0 -1
  185. package/dist/coordination/change-manager.d.ts.map +0 -1
  186. package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
  187. package/dist/coordination/collab-bus.d.ts.map +0 -1
  188. package/dist/coordination/collab-debug-types.d.ts.map +0 -1
  189. package/dist/coordination/collab-debug.d.ts.map +0 -1
  190. package/dist/coordination/collab-director-host.d.ts.map +0 -1
  191. package/dist/coordination/commit-safety.d.ts.map +0 -1
  192. package/dist/coordination/consensus-protocol.d.ts.map +0 -1
  193. package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
  194. package/dist/coordination/delegate-tool.d.ts.map +0 -1
  195. package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
  196. package/dist/coordination/dep-watcher.d.ts.map +0 -1
  197. package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
  198. package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
  199. package/dist/coordination/director/director-collab.d.ts.map +0 -1
  200. package/dist/coordination/director/director-errors.d.ts.map +0 -1
  201. package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
  202. package/dist/coordination/director/director-toolset.d.ts.map +0 -1
  203. package/dist/coordination/director-basic-tools.d.ts.map +0 -1
  204. package/dist/coordination/director-collab-tools.d.ts.map +0 -1
  205. package/dist/coordination/director-host-contracts.d.ts.map +0 -1
  206. package/dist/coordination/director-input-helpers.d.ts.map +0 -1
  207. package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
  208. package/dist/coordination/director-options.d.ts.map +0 -1
  209. package/dist/coordination/director-prompts.d.ts.map +0 -1
  210. package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
  211. package/dist/coordination/director-session.d.ts.map +0 -1
  212. package/dist/coordination/director-spawn-model.d.ts.map +0 -1
  213. package/dist/coordination/director-tools.d.ts.map +0 -1
  214. package/dist/coordination/director.d.ts.map +0 -1
  215. package/dist/coordination/dispatcher.d.ts.map +0 -1
  216. package/dist/coordination/file-author-tracker.d.ts.map +0 -1
  217. package/dist/coordination/fleet-bus.d.ts.map +0 -1
  218. package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
  219. package/dist/coordination/fleet-manager.d.ts.map +0 -1
  220. package/dist/coordination/fleet-spawn.d.ts.map +0 -1
  221. package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
  222. package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
  223. package/dist/coordination/fleet.d.ts.map +0 -1
  224. package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
  225. package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
  226. package/dist/coordination/icoordinator.d.ts.map +0 -1
  227. package/dist/coordination/ifleet-manager.d.ts.map +0 -1
  228. package/dist/coordination/in-memory-transport.d.ts.map +0 -1
  229. package/dist/coordination/index.d.ts.map +0 -1
  230. package/dist/coordination/index.js.map +0 -7
  231. package/dist/coordination/knowledge-graph.d.ts.map +0 -1
  232. package/dist/coordination/large-answer-store.d.ts.map +0 -1
  233. package/dist/coordination/mail-tools.d.ts.map +0 -1
  234. package/dist/coordination/mailbox-actions.d.ts.map +0 -1
  235. package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
  236. package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
  237. package/dist/coordination/mailbox-constants.d.ts.map +0 -1
  238. package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
  239. package/dist/coordination/mailbox-events.d.ts.map +0 -1
  240. package/dist/coordination/mailbox-health.d.ts.map +0 -1
  241. package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
  242. package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
  243. package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
  244. package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
  245. package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
  246. package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
  247. package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
  248. package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
  249. package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
  250. package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
  251. package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
  252. package/dist/coordination/mailbox-project-server.js.map +0 -7
  253. package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
  254. package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
  255. package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
  256. package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
  257. package/dist/coordination/mailbox-tool.d.ts.map +0 -1
  258. package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
  259. package/dist/coordination/mailbox-types.d.ts.map +0 -1
  260. package/dist/coordination/model-matrix.d.ts.map +0 -1
  261. package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
  262. package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
  263. package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
  264. package/dist/coordination/package-author-tracker.d.ts.map +0 -1
  265. package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
  266. package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
  267. package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
  268. package/dist/coordination/remote-mailbox.d.ts.map +0 -1
  269. package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
  270. package/dist/coordination/spawn-budget.d.ts.map +0 -1
  271. package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
  272. package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
  273. package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
  274. package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
  275. package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
  276. package/dist/coordination/subagent-budget.d.ts.map +0 -1
  277. package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
  278. package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
  279. package/dist/coordination/task-auctioneer.d.ts.map +0 -1
  280. package/dist/coordination/task-dag.d.ts.map +0 -1
  281. package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
  282. package/dist/coordination/transport.d.ts.map +0 -1
  283. package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
  284. package/dist/core/agent-internals.d.ts.map +0 -1
  285. package/dist/core/agent-loop.d.ts.map +0 -1
  286. package/dist/core/agent-response.d.ts.map +0 -1
  287. package/dist/core/agent-tools.d.ts.map +0 -1
  288. package/dist/core/agent-types.d.ts.map +0 -1
  289. package/dist/core/agent.d.ts.map +0 -1
  290. package/dist/core/btw.d.ts.map +0 -1
  291. package/dist/core/context.d.ts.map +0 -1
  292. package/dist/core/continue-intent.d.ts.map +0 -1
  293. package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
  294. package/dist/core/conversation-state.d.ts.map +0 -1
  295. package/dist/core/fallback-model.d.ts.map +0 -1
  296. package/dist/core/fallback-profile-manager.d.ts.map +0 -1
  297. package/dist/core/fleet-pulse.d.ts.map +0 -1
  298. package/dist/core/index.d.ts.map +0 -1
  299. package/dist/core/index.js.map +0 -7
  300. package/dist/core/input-builder.d.ts.map +0 -1
  301. package/dist/core/instruction-bundle.d.ts.map +0 -1
  302. package/dist/core/iteration-limit.d.ts.map +0 -1
  303. package/dist/core/mailbox-loop.d.ts.map +0 -1
  304. package/dist/core/model-availability-calendar.d.ts.map +0 -1
  305. package/dist/core/model-ref.d.ts.map +0 -1
  306. package/dist/core/model-ref.js.map +0 -7
  307. package/dist/core/modes/brief.d.ts.map +0 -1
  308. package/dist/core/modes/default.d.ts.map +0 -1
  309. package/dist/core/modes/teach.d.ts.map +0 -1
  310. package/dist/core/provider-runner.d.ts.map +0 -1
  311. package/dist/core/queued-messages.d.ts.map +0 -1
  312. package/dist/core/request-provider-binding.d.ts.map +0 -1
  313. package/dist/core/run-env.d.ts.map +0 -1
  314. package/dist/core/streaming-response-builder.d.ts.map +0 -1
  315. package/dist/core/system-prompt-blocks.d.ts.map +0 -1
  316. package/dist/core/system-prompt-builder.d.ts.map +0 -1
  317. package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
  318. package/dist/core/system-prompt-environment.d.ts.map +0 -1
  319. package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
  320. package/dist/core/system-prompt-plan.d.ts.map +0 -1
  321. package/dist/core/system-prompt-shell.d.ts.map +0 -1
  322. package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
  323. package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
  324. package/dist/defaults/index.d.ts.map +0 -1
  325. package/dist/defaults/index.js.map +0 -7
  326. package/dist/design/index.d.ts.map +0 -1
  327. package/dist/design/index.js.map +0 -7
  328. package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
  329. package/dist/execution/autonomous-runner.d.ts.map +0 -1
  330. package/dist/execution/autonomy-brain.d.ts.map +0 -1
  331. package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
  332. package/dist/execution/brain-chain.d.ts.map +0 -1
  333. package/dist/execution/brain-circuit.d.ts.map +0 -1
  334. package/dist/execution/brain-evaluation.d.ts.map +0 -1
  335. package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
  336. package/dist/execution/brain-runtime.d.ts.map +0 -1
  337. package/dist/execution/compaction-core.d.ts.map +0 -1
  338. package/dist/execution/compaction-scoring.d.ts.map +0 -1
  339. package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
  340. package/dist/execution/compactor.d.ts.map +0 -1
  341. package/dist/execution/council-brain.d.ts.map +0 -1
  342. package/dist/execution/council-orchestrator.d.ts.map +0 -1
  343. package/dist/execution/council-personas.d.ts.map +0 -1
  344. package/dist/execution/council-profiles.d.ts.map +0 -1
  345. package/dist/execution/council-prompts.d.ts.map +0 -1
  346. package/dist/execution/council-resolution.d.ts.map +0 -1
  347. package/dist/execution/design-color.d.ts.map +0 -1
  348. package/dist/execution/design-detect.d.ts.map +0 -1
  349. package/dist/execution/design-kit-loader.d.ts.map +0 -1
  350. package/dist/execution/design-materialize.d.ts.map +0 -1
  351. package/dist/execution/design-project-store.d.ts.map +0 -1
  352. package/dist/execution/design-tune.d.ts.map +0 -1
  353. package/dist/execution/design-verify.d.ts.map +0 -1
  354. package/dist/execution/enhance-recovery.d.ts.map +0 -1
  355. package/dist/execution/error-handler.d.ts.map +0 -1
  356. package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
  357. package/dist/execution/eternal-autonomy.d.ts.map +0 -1
  358. package/dist/execution/goal-preamble.d.ts.map +0 -1
  359. package/dist/execution/index.d.ts.map +0 -1
  360. package/dist/execution/index.js.map +0 -7
  361. package/dist/execution/intelligent-compactor.d.ts.map +0 -1
  362. package/dist/execution/model-runtime.d.ts.map +0 -1
  363. package/dist/execution/one-shot-llm.d.ts.map +0 -1
  364. package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
  365. package/dist/execution/prompt-enhancer.d.ts.map +0 -1
  366. package/dist/execution/prompt-enhancer.js.map +0 -7
  367. package/dist/execution/prompt-loader.d.ts.map +0 -1
  368. package/dist/execution/provider-runner-impl.d.ts.map +0 -1
  369. package/dist/execution/regex-patterns.d.ts.map +0 -1
  370. package/dist/execution/retry-policy.d.ts.map +0 -1
  371. package/dist/execution/selective-compactor.d.ts.map +0 -1
  372. package/dist/execution/skill-loader.d.ts.map +0 -1
  373. package/dist/execution/strategy-compactor.d.ts.map +0 -1
  374. package/dist/execution/subagent-compaction.d.ts.map +0 -1
  375. package/dist/execution/tool-executor-logging.d.ts.map +0 -1
  376. package/dist/execution/tool-executor-results.d.ts.map +0 -1
  377. package/dist/execution/tool-executor-stream.d.ts.map +0 -1
  378. package/dist/execution/tool-executor-support.d.ts.map +0 -1
  379. package/dist/execution/tool-executor.d.ts.map +0 -1
  380. package/dist/extension/extension-points.d.ts.map +0 -1
  381. package/dist/extension/index.d.ts.map +0 -1
  382. package/dist/extension/index.js.map +0 -7
  383. package/dist/extension/registry.d.ts.map +0 -1
  384. package/dist/fleet-notifier.d.ts.map +0 -1
  385. package/dist/goal/checkpoint.d.ts.map +0 -1
  386. package/dist/goal/goal-assessor.d.ts.map +0 -1
  387. package/dist/goal/goal-planner.d.ts.map +0 -1
  388. package/dist/goal/goal-runner.d.ts.map +0 -1
  389. package/dist/goal/index.d.ts.map +0 -1
  390. package/dist/goal/index.js.map +0 -7
  391. package/dist/goal/phase-board-mutations.d.ts.map +0 -1
  392. package/dist/goal/phase-graph-builder.d.ts.map +0 -1
  393. package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
  394. package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
  395. package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
  396. package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
  397. package/dist/goal/phase-orchestrator.d.ts.map +0 -1
  398. package/dist/goal/phase-store.d.ts.map +0 -1
  399. package/dist/goal/types.d.ts.map +0 -1
  400. package/dist/hooks/http-executor.d.ts.map +0 -1
  401. package/dist/hooks/index.d.ts.map +0 -1
  402. package/dist/hooks/index.js.map +0 -7
  403. package/dist/hooks/registry.d.ts.map +0 -1
  404. package/dist/hooks/runner.d.ts.map +0 -1
  405. package/dist/hooks/shell-executor.d.ts.map +0 -1
  406. package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
  407. package/dist/hq/alerts.d.ts.map +0 -1
  408. package/dist/hq/auth-audit.d.ts.map +0 -1
  409. package/dist/hq/auth-store.d.ts.map +0 -1
  410. package/dist/hq/bootstrap-store.d.ts.map +0 -1
  411. package/dist/hq/brain-bridge.d.ts.map +0 -1
  412. package/dist/hq/bridge-context.d.ts.map +0 -1
  413. package/dist/hq/commands.d.ts.map +0 -1
  414. package/dist/hq/cost-bridge.d.ts.map +0 -1
  415. package/dist/hq/exposure.d.ts.map +0 -1
  416. package/dist/hq/factory.d.ts.map +0 -1
  417. package/dist/hq/fleet-bridge.d.ts.map +0 -1
  418. package/dist/hq/index.d.ts.map +0 -1
  419. package/dist/hq/index.js.map +0 -7
  420. package/dist/hq/kanban-store.d.ts.map +0 -1
  421. package/dist/hq/mailbox-mapper.d.ts.map +0 -1
  422. package/dist/hq/persistence/event-log.d.ts.map +0 -1
  423. package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
  424. package/dist/hq/persistence/simple-log.d.ts.map +0 -1
  425. package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
  426. package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
  427. package/dist/hq/persistence.d.ts.map +0 -1
  428. package/dist/hq/protocol/brain.d.ts.map +0 -1
  429. package/dist/hq/protocol/browser.d.ts.map +0 -1
  430. package/dist/hq/protocol/client.d.ts.map +0 -1
  431. package/dist/hq/protocol/core.d.ts.map +0 -1
  432. package/dist/hq/protocol/fleet.d.ts.map +0 -1
  433. package/dist/hq/protocol/kanban.d.ts.map +0 -1
  434. package/dist/hq/protocol/mailbox.d.ts.map +0 -1
  435. package/dist/hq/protocol/mcp.d.ts.map +0 -1
  436. package/dist/hq/protocol/peer.d.ts.map +0 -1
  437. package/dist/hq/protocol/project.d.ts.map +0 -1
  438. package/dist/hq/protocol/resume.d.ts.map +0 -1
  439. package/dist/hq/protocol/session.d.ts.map +0 -1
  440. package/dist/hq/protocol/tool.d.ts.map +0 -1
  441. package/dist/hq/protocol.d.ts.map +0 -1
  442. package/dist/hq/publisher.d.ts.map +0 -1
  443. package/dist/hq/redaction.d.ts.map +0 -1
  444. package/dist/hq/session-bridge.d.ts.map +0 -1
  445. package/dist/hq/tool-bridge.d.ts.map +0 -1
  446. package/dist/hq/transcript-mapper.d.ts.map +0 -1
  447. package/dist/hq/worktree-bridge.d.ts.map +0 -1
  448. package/dist/hq/write-queues.d.ts.map +0 -1
  449. package/dist/index.d.ts.map +0 -1
  450. package/dist/index.js.map +0 -7
  451. package/dist/infrastructure/context-manager.d.ts.map +0 -1
  452. package/dist/infrastructure/index.d.ts.map +0 -1
  453. package/dist/infrastructure/index.js.map +0 -7
  454. package/dist/infrastructure/logger.d.ts.map +0 -1
  455. package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
  456. package/dist/infrastructure/path-resolver.d.ts.map +0 -1
  457. package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
  458. package/dist/infrastructure/token-counter.d.ts.map +0 -1
  459. package/dist/kernel/container.d.ts.map +0 -1
  460. package/dist/kernel/events/agent-events.d.ts.map +0 -1
  461. package/dist/kernel/events/brain-events.d.ts.map +0 -1
  462. package/dist/kernel/events/file-events.d.ts.map +0 -1
  463. package/dist/kernel/events/fleet-events.d.ts.map +0 -1
  464. package/dist/kernel/events/memory-events.d.ts.map +0 -1
  465. package/dist/kernel/events/network-events.d.ts.map +0 -1
  466. package/dist/kernel/events/process-events.d.ts.map +0 -1
  467. package/dist/kernel/events/provider-events.d.ts.map +0 -1
  468. package/dist/kernel/events/sdd-events.d.ts.map +0 -1
  469. package/dist/kernel/events/session-events.d.ts.map +0 -1
  470. package/dist/kernel/events/tool-events.d.ts.map +0 -1
  471. package/dist/kernel/events/worktree-events.d.ts.map +0 -1
  472. package/dist/kernel/events.d.ts.map +0 -1
  473. package/dist/kernel/index.d.ts.map +0 -1
  474. package/dist/kernel/index.js.map +0 -7
  475. package/dist/kernel/pipeline.d.ts.map +0 -1
  476. package/dist/kernel/run-controller.d.ts.map +0 -1
  477. package/dist/kernel/tokens.d.ts.map +0 -1
  478. package/dist/mailbox-attach.d.ts.map +0 -1
  479. package/dist/middleware/collab-pause.d.ts.map +0 -1
  480. package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
  481. package/dist/models/codex-catalog.d.ts.map +0 -1
  482. package/dist/models/index.d.ts.map +0 -1
  483. package/dist/models/index.js.map +0 -7
  484. package/dist/models/llm-selector.d.ts.map +0 -1
  485. package/dist/models/mode-store.d.ts.map +0 -1
  486. package/dist/models/model-intelligence.d.ts.map +0 -1
  487. package/dist/models/model-router.d.ts.map +0 -1
  488. package/dist/models/models-registry.d.ts.map +0 -1
  489. package/dist/models/provider-model-resolve.d.ts.map +0 -1
  490. package/dist/notifications/index.d.ts.map +0 -1
  491. package/dist/notifications/index.js.map +0 -7
  492. package/dist/notifications/notifier-impl.d.ts.map +0 -1
  493. package/dist/notifications/notifier.d.ts.map +0 -1
  494. package/dist/notifications/types.d.ts.map +0 -1
  495. package/dist/observability/event-bridge.d.ts.map +0 -1
  496. package/dist/observability/health.d.ts.map +0 -1
  497. package/dist/observability/index.d.ts.map +0 -1
  498. package/dist/observability/index.js.map +0 -7
  499. package/dist/observability/metrics.d.ts.map +0 -1
  500. package/dist/observability/network-telemetry.d.ts.map +0 -1
  501. package/dist/observability/otel-tracer.d.ts.map +0 -1
  502. package/dist/observability/otlp-metrics.d.ts.map +0 -1
  503. package/dist/observability/otlp-traces.d.ts.map +0 -1
  504. package/dist/observability/process-telemetry.d.ts.map +0 -1
  505. package/dist/observability/prometheus.d.ts.map +0 -1
  506. package/dist/observability/redact-command.d.ts.map +0 -1
  507. package/dist/observability/tracer.d.ts.map +0 -1
  508. package/dist/plugin/api.d.ts.map +0 -1
  509. package/dist/plugin/config.d.ts.map +0 -1
  510. package/dist/plugin/index.d.ts.map +0 -1
  511. package/dist/plugin/index.js.map +0 -7
  512. package/dist/plugin/loader.d.ts.map +0 -1
  513. package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
  514. package/dist/plugins/chimera-plugin.d.ts.map +0 -1
  515. package/dist/plugins/prompts-plugin.d.ts.map +0 -1
  516. package/dist/plugins/review-claim-registry.d.ts.map +0 -1
  517. package/dist/plugins/review-context-builder.d.ts.map +0 -1
  518. package/dist/plugins/review-finding-commands.d.ts.map +0 -1
  519. package/dist/plugins/review-finding-integration.d.ts.map +0 -1
  520. package/dist/plugins/review-finding-parser.d.ts.map +0 -1
  521. package/dist/plugins/review-finding-store.d.ts.map +0 -1
  522. package/dist/plugins/review-finding-types.d.ts.map +0 -1
  523. package/dist/plugins/review-report-integration.d.ts.map +0 -1
  524. package/dist/plugins/review-report-store.d.ts.map +0 -1
  525. package/dist/plugins/review-report-types.d.ts.map +0 -1
  526. package/dist/plugins/review-types.d.ts.map +0 -1
  527. package/dist/plugins/skills-plugin.d.ts.map +0 -1
  528. package/dist/plugins/sync-plugin.d.ts.map +0 -1
  529. package/dist/prompts/index.d.ts.map +0 -1
  530. package/dist/prompts/prompt-installer.d.ts.map +0 -1
  531. package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
  532. package/dist/registry/index.d.ts.map +0 -1
  533. package/dist/registry/index.js.map +0 -7
  534. package/dist/registry/provider-registry.d.ts.map +0 -1
  535. package/dist/registry/slash-command-registry.d.ts.map +0 -1
  536. package/dist/registry/tool-registry.d.ts.map +0 -1
  537. package/dist/replay/hash.d.ts.map +0 -1
  538. package/dist/replay/index.d.ts.map +0 -1
  539. package/dist/replay/index.js.map +0 -7
  540. package/dist/replay/replay-provider-runner.d.ts.map +0 -1
  541. package/dist/security/capabilities.d.ts.map +0 -1
  542. package/dist/security/config-secrets.d.ts.map +0 -1
  543. package/dist/security/directory-permission-policy.d.ts.map +0 -1
  544. package/dist/security/directory-policy-schema.d.ts.map +0 -1
  545. package/dist/security/index.d.ts.map +0 -1
  546. package/dist/security/index.js.map +0 -7
  547. package/dist/security/kanban-boundary.d.ts.map +0 -1
  548. package/dist/security/permission-policy-schema.d.ts.map +0 -1
  549. package/dist/security/permission-policy.d.ts.map +0 -1
  550. package/dist/security/readonly-permission-policy.d.ts.map +0 -1
  551. package/dist/security/secret-scrubber.d.ts.map +0 -1
  552. package/dist/security/secret-vault.d.ts.map +0 -1
  553. package/dist/security/trust-boundary.d.ts.map +0 -1
  554. package/dist/security/yolo-risk.d.ts.map +0 -1
  555. package/dist/session-registry-atomic-file.d.ts.map +0 -1
  556. package/dist/session-registry-types.d.ts.map +0 -1
  557. package/dist/session-registry.d.ts.map +0 -1
  558. package/dist/skills/foreign-sources.d.ts.map +0 -1
  559. package/dist/skills/frontmatter.d.ts.map +0 -1
  560. package/dist/skills/github-fetcher.d.ts.map +0 -1
  561. package/dist/skills/index.d.ts.map +0 -1
  562. package/dist/skills/index.js.map +0 -7
  563. package/dist/skills/limits.d.ts.map +0 -1
  564. package/dist/skills/manifest-store.d.ts.map +0 -1
  565. package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
  566. package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
  567. package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
  568. package/dist/skills/skill-generator.d.ts.map +0 -1
  569. package/dist/skills/skill-installer.d.ts.map +0 -1
  570. package/dist/storage/annotations-store.d.ts.map +0 -1
  571. package/dist/storage/attachment-store.d.ts.map +0 -1
  572. package/dist/storage/cloud-sync.d.ts.map +0 -1
  573. package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
  574. package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
  575. package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
  576. package/dist/storage/config-loader/defaults.d.ts.map +0 -1
  577. package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
  578. package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
  579. package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
  580. package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
  581. package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
  582. package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
  583. package/dist/storage/config-loader/types.d.ts.map +0 -1
  584. package/dist/storage/config-loader/validation.d.ts.map +0 -1
  585. package/dist/storage/config-loader.d.ts.map +0 -1
  586. package/dist/storage/config-migration.d.ts.map +0 -1
  587. package/dist/storage/config-store.d.ts.map +0 -1
  588. package/dist/storage/director-state.d.ts.map +0 -1
  589. package/dist/storage/file-session-writer.d.ts.map +0 -1
  590. package/dist/storage/goal-coordination.d.ts.map +0 -1
  591. package/dist/storage/goal-kanban.d.ts.map +0 -1
  592. package/dist/storage/goal-store.d.ts.map +0 -1
  593. package/dist/storage/index.d.ts.map +0 -1
  594. package/dist/storage/index.js.map +0 -7
  595. package/dist/storage/input-history-store.d.ts.map +0 -1
  596. package/dist/storage/memory-backend.d.ts.map +0 -1
  597. package/dist/storage/memory-consolidator.d.ts.map +0 -1
  598. package/dist/storage/memory-graph-backend.d.ts.map +0 -1
  599. package/dist/storage/plan-store.d.ts.map +0 -1
  600. package/dist/storage/plan-templates.d.ts.map +0 -1
  601. package/dist/storage/prompt-store.d.ts.map +0 -1
  602. package/dist/storage/prompt-usage-store.d.ts.map +0 -1
  603. package/dist/storage/provider-config-watcher.d.ts.map +0 -1
  604. package/dist/storage/queue-store.d.ts.map +0 -1
  605. package/dist/storage/recovery-lock.d.ts.map +0 -1
  606. package/dist/storage/replay-log-store.d.ts.map +0 -1
  607. package/dist/storage/session-analyzer.d.ts.map +0 -1
  608. package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
  609. package/dist/storage/session-event-bridge.d.ts.map +0 -1
  610. package/dist/storage/session-helpers.d.ts.map +0 -1
  611. package/dist/storage/session-id-resolver.d.ts.map +0 -1
  612. package/dist/storage/session-id.d.ts.map +0 -1
  613. package/dist/storage/session-read-scrubber.d.ts.map +0 -1
  614. package/dist/storage/session-reader.d.ts.map +0 -1
  615. package/dist/storage/session-recovery.d.ts.map +0 -1
  616. package/dist/storage/session-resume-validation.d.ts.map +0 -1
  617. package/dist/storage/session-rewind-apply.d.ts.map +0 -1
  618. package/dist/storage/session-rewinder.d.ts.map +0 -1
  619. package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
  620. package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
  621. package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
  622. package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
  623. package/dist/storage/session-store/events.d.ts.map +0 -1
  624. package/dist/storage/session-store/fork-session.d.ts.map +0 -1
  625. package/dist/storage/session-store/index-reader.d.ts.map +0 -1
  626. package/dist/storage/session-store/load-cache.d.ts.map +0 -1
  627. package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
  628. package/dist/storage/session-store/paths.d.ts.map +0 -1
  629. package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
  630. package/dist/storage/session-store/replay.d.ts.map +0 -1
  631. package/dist/storage/session-store/search-events.d.ts.map +0 -1
  632. package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
  633. package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
  634. package/dist/storage/session-store/summary-header.d.ts.map +0 -1
  635. package/dist/storage/session-store/types.d.ts.map +0 -1
  636. package/dist/storage/session-store.d.ts.map +0 -1
  637. package/dist/storage/session-summary.d.ts.map +0 -1
  638. package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
  639. package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
  640. package/dist/storage/session-writer-truncate.d.ts.map +0 -1
  641. package/dist/storage/storage-concurrency.d.ts.map +0 -1
  642. package/dist/storage/task-store.d.ts.map +0 -1
  643. package/dist/storage/todos-checkpoint.d.ts.map +0 -1
  644. package/dist/storage/tool-audit-log.d.ts.map +0 -1
  645. package/dist/tasking/index.d.ts.map +0 -1
  646. package/dist/tasking/index.js.map +0 -7
  647. package/dist/tasking/task-store.d.ts.map +0 -1
  648. package/dist/tasking/task-tracker.d.ts.map +0 -1
  649. package/dist/tools/council-tool.d.ts.map +0 -1
  650. package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
  651. package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
  652. package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
  653. package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
  654. package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
  655. package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
  656. package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
  657. package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
  658. package/dist/tools/index.d.ts.map +0 -1
  659. package/dist/tools/index.js.map +0 -7
  660. package/dist/tools/mcp-control.d.ts.map +0 -1
  661. package/dist/tools/mcp-use.d.ts.map +0 -1
  662. package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
  663. package/dist/tools/plugin-manager.d.ts.map +0 -1
  664. package/dist/types/agent-bridge.d.ts.map +0 -1
  665. package/dist/types/attachment.d.ts.map +0 -1
  666. package/dist/types/autonomy.d.ts.map +0 -1
  667. package/dist/types/blocks.d.ts.map +0 -1
  668. package/dist/types/compactor.d.ts.map +0 -1
  669. package/dist/types/config/autonomy.d.ts.map +0 -1
  670. package/dist/types/config/context.d.ts.map +0 -1
  671. package/dist/types/config/fleet-chat.d.ts.map +0 -1
  672. package/dist/types/config/mcp-features.d.ts.map +0 -1
  673. package/dist/types/config/providers.d.ts.map +0 -1
  674. package/dist/types/config/root.d.ts.map +0 -1
  675. package/dist/types/config/runtime.d.ts.map +0 -1
  676. package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
  677. package/dist/types/config/tools.d.ts.map +0 -1
  678. package/dist/types/config.d.ts.map +0 -1
  679. package/dist/types/context-evidence.d.ts.map +0 -1
  680. package/dist/types/context-window.d.ts.map +0 -1
  681. package/dist/types/council.d.ts.map +0 -1
  682. package/dist/types/default-config.d.ts.map +0 -1
  683. package/dist/types/design-kit.d.ts.map +0 -1
  684. package/dist/types/error-handler.d.ts.map +0 -1
  685. package/dist/types/errors.d.ts.map +0 -1
  686. package/dist/types/file-event-record.d.ts.map +0 -1
  687. package/dist/types/hooks.d.ts.map +0 -1
  688. package/dist/types/index.d.ts.map +0 -1
  689. package/dist/types/index.js.map +0 -7
  690. package/dist/types/input-reader.d.ts.map +0 -1
  691. package/dist/types/logger.d.ts.map +0 -1
  692. package/dist/types/memory.d.ts.map +0 -1
  693. package/dist/types/messages.d.ts.map +0 -1
  694. package/dist/types/mode-prompts.d.ts.map +0 -1
  695. package/dist/types/mode.d.ts.map +0 -1
  696. package/dist/types/models-registry.d.ts.map +0 -1
  697. package/dist/types/multi-agent.d.ts.map +0 -1
  698. package/dist/types/observability.d.ts.map +0 -1
  699. package/dist/types/one-shot-llm.d.ts.map +0 -1
  700. package/dist/types/path-resolver.d.ts.map +0 -1
  701. package/dist/types/permission.d.ts.map +0 -1
  702. package/dist/types/plugin.d.ts.map +0 -1
  703. package/dist/types/prompt-registry.d.ts.map +0 -1
  704. package/dist/types/prompt.d.ts.map +0 -1
  705. package/dist/types/provider-runner.d.ts.map +0 -1
  706. package/dist/types/provider.d.ts.map +0 -1
  707. package/dist/types/quota-regex.d.ts.map +0 -1
  708. package/dist/types/renderer.d.ts.map +0 -1
  709. package/dist/types/retry-policy.d.ts.map +0 -1
  710. package/dist/types/secret-scrubber.d.ts.map +0 -1
  711. package/dist/types/secret-vault.d.ts.map +0 -1
  712. package/dist/types/selector.d.ts.map +0 -1
  713. package/dist/types/session-markers.d.ts.map +0 -1
  714. package/dist/types/session-markers.js.map +0 -7
  715. package/dist/types/session-reader.d.ts.map +0 -1
  716. package/dist/types/session-rewinder.d.ts.map +0 -1
  717. package/dist/types/session.d.ts.map +0 -1
  718. package/dist/types/side-effect.d.ts.map +0 -1
  719. package/dist/types/skill.d.ts.map +0 -1
  720. package/dist/types/slash-command.d.ts.map +0 -1
  721. package/dist/types/spec.d.ts.map +0 -1
  722. package/dist/types/system-prompt-contributor.d.ts.map +0 -1
  723. package/dist/types/system-prompt.d.ts.map +0 -1
  724. package/dist/types/task-graph.d.ts.map +0 -1
  725. package/dist/types/token-counter.d.ts.map +0 -1
  726. package/dist/types/tool-executor.d.ts.map +0 -1
  727. package/dist/types/tool-markers.d.ts.map +0 -1
  728. package/dist/types/tool.d.ts.map +0 -1
  729. package/dist/types/utility-types.d.ts.map +0 -1
  730. package/dist/utils/assert-never.d.ts.map +0 -1
  731. package/dist/utils/atomic-write.d.ts.map +0 -1
  732. package/dist/utils/cache-key.d.ts.map +0 -1
  733. package/dist/utils/child-env.d.ts.map +0 -1
  734. package/dist/utils/color.d.ts.map +0 -1
  735. package/dist/utils/compaction-preview.d.ts.map +0 -1
  736. package/dist/utils/config-backup.d.ts.map +0 -1
  737. package/dist/utils/config-json.d.ts.map +0 -1
  738. package/dist/utils/connectivity.d.ts.map +0 -1
  739. package/dist/utils/context-breakdown.d.ts.map +0 -1
  740. package/dist/utils/context-evidence.d.ts.map +0 -1
  741. package/dist/utils/continuous-memory-profiler.d.ts.map +0 -1
  742. package/dist/utils/crash-shield.d.ts.map +0 -1
  743. package/dist/utils/deep-merge.d.ts.map +0 -1
  744. package/dist/utils/diff.d.ts.map +0 -1
  745. package/dist/utils/error.d.ts.map +0 -1
  746. package/dist/utils/error.js.map +0 -7
  747. package/dist/utils/expect-defined.d.ts.map +0 -1
  748. package/dist/utils/expect-defined.js.map +0 -7
  749. package/dist/utils/glob-expand.d.ts.map +0 -1
  750. package/dist/utils/glob-match.d.ts.map +0 -1
  751. package/dist/utils/heap-watchdog-types.d.ts.map +0 -1
  752. package/dist/utils/heap-watchdog.d.ts.map +0 -1
  753. package/dist/utils/heap-watchdog.js.map +0 -7
  754. package/dist/utils/incoming-images.d.ts.map +0 -1
  755. package/dist/utils/index.d.ts.map +0 -1
  756. package/dist/utils/index.js.map +0 -7
  757. package/dist/utils/instruction-file.d.ts.map +0 -1
  758. package/dist/utils/ip-guard.d.ts.map +0 -1
  759. package/dist/utils/json-repair.d.ts.map +0 -1
  760. package/dist/utils/json-schema-validate.d.ts.map +0 -1
  761. package/dist/utils/lru-cache.d.ts.map +0 -1
  762. package/dist/utils/memory-flight-recorder.d.ts.map +0 -1
  763. package/dist/utils/merge-custom-models.d.ts.map +0 -1
  764. package/dist/utils/merge-models-payload.d.ts.map +0 -1
  765. package/dist/utils/message-invariants.d.ts.map +0 -1
  766. package/dist/utils/newline-normalize.d.ts.map +0 -1
  767. package/dist/utils/perf-profile.d.ts.map +0 -1
  768. package/dist/utils/pid.d.ts.map +0 -1
  769. package/dist/utils/project-identity.d.ts.map +0 -1
  770. package/dist/utils/project-watch.d.ts.map +0 -1
  771. package/dist/utils/regex-guard.d.ts.map +0 -1
  772. package/dist/utils/safe-json.d.ts.map +0 -1
  773. package/dist/utils/sage-output-block.d.ts.map +0 -1
  774. package/dist/utils/session-scoped-path.d.ts.map +0 -1
  775. package/dist/utils/sleep.d.ts.map +0 -1
  776. package/dist/utils/slug.d.ts.map +0 -1
  777. package/dist/utils/socket-path.d.ts.map +0 -1
  778. package/dist/utils/sqlite-warning.d.ts.map +0 -1
  779. package/dist/utils/string.d.ts.map +0 -1
  780. package/dist/utils/task-format.d.ts.map +0 -1
  781. package/dist/utils/term.d.ts.map +0 -1
  782. package/dist/utils/todos-format.d.ts.map +0 -1
  783. package/dist/utils/token-estimate.d.ts.map +0 -1
  784. package/dist/utils/tool-description-mode.d.ts.map +0 -1
  785. package/dist/utils/tool-name.d.ts.map +0 -1
  786. package/dist/utils/tool-output-serializer.d.ts.map +0 -1
  787. package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
  788. package/dist/utils/tool-subject.d.ts.map +0 -1
  789. package/dist/utils/tool-wire-compact.d.ts.map +0 -1
  790. package/dist/utils/tree-kill.d.ts.map +0 -1
  791. package/dist/utils/tree-kill.js.map +0 -7
  792. package/dist/utils/ulid.d.ts.map +0 -1
  793. package/dist/utils/walk-ignore.d.ts.map +0 -1
  794. package/dist/utils/wstack-paths.d.ts.map +0 -1
  795. package/dist/worktree/index.d.ts.map +0 -1
  796. package/dist/worktree/index.js.map +0 -7
  797. package/dist/worktree/worktree-git.d.ts.map +0 -1
  798. package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
  799. package/dist/worktree/worktree-manager.d.ts.map +0 -1
  800. package/dist/worktree/worktree-types.d.ts.map +0 -1
@@ -179,6 +179,15 @@ var init_errors = __esm({
179
179
  }
180
180
  });
181
181
 
182
+ // src/security/file-permissions.ts
183
+ var SECRET_FILE_MODE;
184
+ var init_file_permissions = __esm({
185
+ "src/security/file-permissions.ts"() {
186
+ "use strict";
187
+ SECRET_FILE_MODE = 384;
188
+ }
189
+ });
190
+
182
191
  // src/utils/atomic-write.ts
183
192
  import {
184
193
  createPersistencePrimitives
@@ -278,6 +287,7 @@ var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT
278
287
  var init_review_finding_store = __esm({
279
288
  "src/plugins/review-finding-store.ts"() {
280
289
  "use strict";
290
+ init_file_permissions();
281
291
  init_atomic_write();
282
292
  init_review_finding_types();
283
293
  FINDING_RESOLVED_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -298,33 +308,49 @@ var init_review_finding_store = __esm({
298
308
  async upsert(newFindings, context) {
299
309
  if (newFindings.length === 0) return { created: 0, relinked: 0, reopened: 0 };
300
310
  const result = { created: 0, relinked: 0, reopened: 0 };
301
- const existing = await this._readAll();
302
311
  return withFileLock(this.filePath, async () => {
312
+ const existing = await this._readAll();
303
313
  for (const finding of newFindings) {
304
314
  const match = existing.find((e) => e.finding.fingerprint === finding.fingerprint);
305
315
  if (match) {
306
316
  const materialized = this._materialize(match);
307
317
  if (materialized.status === "resolved" || materialized.status === "ignored") {
308
- const reopenEvent = this._makeEvent(match.finding.id, "reopened", materialized.status, "active", context);
318
+ const reopenEvent = this._makeEvent(
319
+ match.finding.id,
320
+ "reopened",
321
+ materialized.status,
322
+ "active",
323
+ context
324
+ );
309
325
  match.finding.status = "active";
310
326
  match.finding.resolution = void 0;
311
327
  const updatedRecord = { __finding: 1, data: match.finding };
312
328
  await fsp2.appendFile(
313
329
  this.filePath,
314
330
  JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: reopenEvent }) + LINE_SEPARATOR,
315
- "utf8"
331
+ { encoding: "utf8", mode: SECRET_FILE_MODE }
316
332
  );
317
333
  result.reopened++;
318
334
  } else {
319
- const relinkEvent = this._makeEvent(match.finding.id, "relinked", match.finding.status, match.finding.status, context);
320
- await fsp2.appendFile(this.filePath, JSON.stringify({ __findingEvent: 1, data: relinkEvent }) + LINE_SEPARATOR, "utf8");
335
+ const relinkEvent = this._makeEvent(
336
+ match.finding.id,
337
+ "relinked",
338
+ match.finding.status,
339
+ match.finding.status,
340
+ context
341
+ );
342
+ await fsp2.appendFile(
343
+ this.filePath,
344
+ JSON.stringify({ __findingEvent: 1, data: relinkEvent }) + LINE_SEPARATOR,
345
+ { encoding: "utf8", mode: SECRET_FILE_MODE }
346
+ );
321
347
  result.relinked++;
322
348
  }
323
349
  } else {
324
350
  const record = { __finding: 1, data: finding };
325
351
  const createdEvent = this._makeEvent(finding.id, "created", null, "active", context);
326
352
  const lines = JSON.stringify(record) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: createdEvent }) + LINE_SEPARATOR;
327
- await fsp2.appendFile(this.filePath, lines, "utf8");
353
+ await fsp2.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
328
354
  result.created++;
329
355
  }
330
356
  }
@@ -332,39 +358,41 @@ var init_review_finding_store = __esm({
332
358
  });
333
359
  }
334
360
  async transition(findingId, to, actor, opts) {
335
- const all = await this._readAll();
336
- const entry = all.find((e) => e.finding.id === findingId);
337
- if (!entry) throw new Error(`Finding not found: ${findingId}`);
338
- const from = entry.finding.status;
339
- validateTransition(from, to);
340
- validateResolution(to, opts?.outcome);
341
- const event = {
342
- id: randomUUID3(),
343
- findingId,
344
- eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
345
- fromStatus: from,
346
- toStatus: to,
347
- actorId: actor.id,
348
- actorKind: actor.kind,
349
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
350
- reason: opts?.reason
351
- };
352
- entry.finding.status = to;
353
- if (to === "resolved" && opts?.outcome) {
354
- entry.finding.resolution = {
355
- outcome: opts.outcome,
356
- resolvedAt: event.timestamp,
357
- resolvedBy: actor.id,
358
- notes: opts.reason
361
+ return withFileLock(this.filePath, async () => {
362
+ const all = await this._readAll();
363
+ const entry = all.find((e) => e.finding.id === findingId);
364
+ if (!entry) throw new Error(`Finding not found: ${findingId}`);
365
+ const from = this._materialize(entry).status;
366
+ validateTransition(from, to);
367
+ validateResolution(to, opts?.outcome);
368
+ const event = {
369
+ id: randomUUID3(),
370
+ findingId,
371
+ eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
372
+ fromStatus: from,
373
+ toStatus: to,
374
+ actorId: actor.id,
375
+ actorKind: actor.kind,
376
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
377
+ reason: opts?.reason
359
378
  };
360
- }
361
- const updatedRecord = { __finding: 1, data: entry.finding };
362
- await fsp2.appendFile(
363
- this.filePath,
364
- JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: event }) + LINE_SEPARATOR,
365
- "utf8"
366
- );
367
- return { ...entry.finding };
379
+ entry.finding.status = to;
380
+ if (to === "resolved" && opts?.outcome) {
381
+ entry.finding.resolution = {
382
+ outcome: opts.outcome,
383
+ resolvedAt: event.timestamp,
384
+ resolvedBy: actor.id,
385
+ notes: opts.reason
386
+ };
387
+ }
388
+ const updatedRecord = { __finding: 1, data: entry.finding };
389
+ await fsp2.appendFile(
390
+ this.filePath,
391
+ JSON.stringify(updatedRecord) + LINE_SEPARATOR + JSON.stringify({ __findingEvent: 1, data: event }) + LINE_SEPARATOR,
392
+ { encoding: "utf8", mode: SECRET_FILE_MODE }
393
+ );
394
+ return { ...entry.finding };
395
+ });
368
396
  }
369
397
  async list(opts) {
370
398
  const all = await this._readAll();
@@ -384,7 +412,12 @@ var init_review_finding_store = __esm({
384
412
  if (opts?.reportId) {
385
413
  findings = findings.filter((f) => f.originReport.reportId === opts.reportId);
386
414
  }
387
- const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
415
+ const severityRank = {
416
+ critical: 0,
417
+ high: 1,
418
+ medium: 2,
419
+ low: 3
420
+ };
388
421
  findings.sort((a, b) => {
389
422
  const sa = severityRank[a.severity] - severityRank[b.severity];
390
423
  if (sa !== 0) return sa;
@@ -415,46 +448,57 @@ var init_review_finding_store = __esm({
415
448
  return events.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
416
449
  }
417
450
  async compact(opts) {
418
- const resolvedMaxAge = opts?.resolvedMaxAgeMs ?? FINDING_RESOLVED_RETENTION_MS;
419
- const ignoredMaxAge = opts?.ignoredMaxAgeMs ?? FINDING_IGNORED_RETENTION_MS;
420
- const now = Date.now();
421
- const all = await this._readAll();
422
- const kept = [];
423
- let removed = 0;
424
- let eventsFolded = 0;
425
- for (const entry of all) {
426
- const age = now - new Date(entry.finding.createdAt).getTime();
427
- const isResolved = entry.finding.status === "resolved";
428
- const isIgnored = entry.finding.status === "ignored";
429
- const maxAge = isResolved ? resolvedMaxAge : isIgnored ? ignoredMaxAge : Infinity;
430
- if (age > maxAge && (isResolved || isIgnored)) {
431
- removed++;
432
- eventsFolded += entry.events.length;
433
- continue;
434
- }
435
- const oldEvents = entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() > maxAge);
436
- if (oldEvents.length > 1) {
437
- eventsFolded += oldEvents.length - 1;
438
- const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
439
- entry.events = [newestOld, ...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)];
451
+ return withFileLock(this.filePath, async () => {
452
+ const resolvedMaxAge = opts?.resolvedMaxAgeMs ?? FINDING_RESOLVED_RETENTION_MS;
453
+ const ignoredMaxAge = opts?.ignoredMaxAgeMs ?? FINDING_IGNORED_RETENTION_MS;
454
+ const now = Date.now();
455
+ const all = await this._readAll();
456
+ const kept = [];
457
+ let removed = 0;
458
+ let eventsFolded = 0;
459
+ for (const entry of all) {
460
+ const age = now - new Date(entry.finding.createdAt).getTime();
461
+ const isResolved = entry.finding.status === "resolved";
462
+ const isIgnored = entry.finding.status === "ignored";
463
+ const maxAge = isResolved ? resolvedMaxAge : isIgnored ? ignoredMaxAge : Infinity;
464
+ if (age > maxAge && (isResolved || isIgnored)) {
465
+ removed++;
466
+ eventsFolded += entry.events.length;
467
+ continue;
468
+ }
469
+ const oldEvents = entry.events.filter(
470
+ (ev) => now - new Date(ev.timestamp).getTime() > maxAge
471
+ );
472
+ if (oldEvents.length > 1) {
473
+ eventsFolded += oldEvents.length - 1;
474
+ const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
475
+ entry.events = [
476
+ newestOld,
477
+ ...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
478
+ ];
479
+ }
480
+ kept.push({ record: { __finding: 1, data: entry.finding }, events: entry.events });
440
481
  }
441
- kept.push({ record: { __finding: 1, data: entry.finding }, events: entry.events });
442
- }
443
- const lines = [];
444
- for (const { record, events } of kept) {
445
- if (record) lines.push(JSON.stringify(record));
446
- for (const ev of events) {
447
- lines.push(JSON.stringify({ __findingEvent: 1, data: ev }));
482
+ const lines = [];
483
+ for (const { record, events } of kept) {
484
+ if (record) lines.push(JSON.stringify(record));
485
+ for (const ev of events) {
486
+ lines.push(JSON.stringify({ __findingEvent: 1, data: ev }));
487
+ }
448
488
  }
449
- }
450
- lines.push(JSON.stringify({
451
- __findingCompact: 1,
452
- compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
453
- removedFindings: removed,
454
- foldedEvents: eventsFolded
455
- }));
456
- await atomicWrite(this.filePath, lines.join(LINE_SEPARATOR) + LINE_SEPARATOR, { mode: 384 });
457
- return { removed, eventsFolded };
489
+ lines.push(
490
+ JSON.stringify({
491
+ __findingCompact: 1,
492
+ compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
493
+ removedFindings: removed,
494
+ foldedEvents: eventsFolded
495
+ })
496
+ );
497
+ await atomicWrite(this.filePath, lines.join(LINE_SEPARATOR) + LINE_SEPARATOR, {
498
+ mode: 384
499
+ });
500
+ return { removed, eventsFolded };
501
+ });
458
502
  }
459
503
  // ── Private helpers ──────────────────────────────────────────────
460
504
  async _readAllLines() {
@@ -600,6 +644,7 @@ var REPORT_RETENTION_MS, REPORT_DEFAULT_PAGE_SIZE, NL2, REPORT_STORE_FILE, Jsonl
600
644
  var init_review_report_store = __esm({
601
645
  "src/plugins/review-report-store.ts"() {
602
646
  "use strict";
647
+ init_file_permissions();
603
648
  init_atomic_write();
604
649
  init_review_report_types();
605
650
  REPORT_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
@@ -628,11 +673,10 @@ var init_review_report_store = __esm({
628
673
  rawText: input.rawText || existing.rawText,
629
674
  files: input.files.length > 0 ? input.files : existing.files
630
675
  };
631
- await fsp3.appendFile(
632
- this.filePath,
633
- JSON.stringify({ __report: 1, data: updated }) + NL2,
634
- "utf8"
635
- );
676
+ await fsp3.appendFile(this.filePath, JSON.stringify({ __report: 1, data: updated }) + NL2, {
677
+ encoding: "utf8",
678
+ mode: SECRET_FILE_MODE
679
+ });
636
680
  return updated;
637
681
  }
638
682
  const report = {
@@ -663,57 +707,60 @@ var init_review_report_store = __esm({
663
707
  timestamp: report.reviewedAt
664
708
  };
665
709
  const lines = JSON.stringify({ __report: 1, data: report }) + NL2 + JSON.stringify({ __reportEvent: 1, data: createdEvent }) + NL2;
666
- await fsp3.appendFile(this.filePath, lines, "utf8");
710
+ await fsp3.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
667
711
  return report;
668
712
  });
669
713
  }
670
714
  // ── Lifecycle transitions ────────────────────────────────────────
671
715
  async transition(reportId, to, actor, opts) {
672
- const all = await this._readAll();
673
- const entry = all.find((e) => e.report.id === reportId);
674
- if (!entry) throw new Error(`Review report not found: ${reportId}`);
675
- const from = this._materialize(entry).lifecycle;
676
- validateReportTransition(from, to);
677
- const event = {
678
- id: randomUUID5(),
679
- reportId,
680
- eventType: reportEventTypeFor(to),
681
- fromLifecycle: from,
682
- toLifecycle: to,
683
- actorId: actor.id,
684
- actorKind: actor.kind,
685
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
686
- reason: opts?.reason
687
- };
688
- entry.report.lifecycle = to;
689
- await fsp3.appendFile(
690
- this.filePath,
691
- JSON.stringify({ __reportEvent: 1, data: event }) + NL2,
692
- "utf8"
693
- );
694
- return { ...entry.report };
716
+ return withFileLock(this.filePath, async () => {
717
+ const all = await this._readAll();
718
+ const entry = all.find((e) => e.report.id === reportId);
719
+ if (!entry) throw new Error(`Review report not found: ${reportId}`);
720
+ const from = this._materialize(entry).lifecycle;
721
+ validateReportTransition(from, to);
722
+ const event = {
723
+ id: randomUUID5(),
724
+ reportId,
725
+ eventType: reportEventTypeFor(to),
726
+ fromLifecycle: from,
727
+ toLifecycle: to,
728
+ actorId: actor.id,
729
+ actorKind: actor.kind,
730
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
731
+ reason: opts?.reason
732
+ };
733
+ entry.report.lifecycle = to;
734
+ await fsp3.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL2, {
735
+ encoding: "utf8",
736
+ mode: SECRET_FILE_MODE
737
+ });
738
+ return { ...entry.report };
739
+ });
695
740
  }
696
741
  async addNote(reportId, actor, note) {
697
- const all = await this._readAll();
698
- const entry = all.find((e) => e.report.id === reportId);
699
- if (!entry) throw new Error(`Review report not found: ${reportId}`);
700
- const event = {
701
- id: randomUUID5(),
702
- reportId,
703
- eventType: "note_added",
704
- fromLifecycle: entry.report.lifecycle,
705
- toLifecycle: entry.report.lifecycle,
706
- actorId: actor.id,
707
- actorKind: actor.kind,
708
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
709
- reason: note
710
- };
711
- await fsp3.appendFile(
712
- this.filePath,
713
- JSON.stringify({ __reportEvent: 1, data: event }) + NL2,
714
- "utf8"
715
- );
716
- return { ...entry.report };
742
+ return withFileLock(this.filePath, async () => {
743
+ const all = await this._readAll();
744
+ const entry = all.find((e) => e.report.id === reportId);
745
+ if (!entry) throw new Error(`Review report not found: ${reportId}`);
746
+ const materialized = this._materialize(entry);
747
+ const event = {
748
+ id: randomUUID5(),
749
+ reportId,
750
+ eventType: "note_added",
751
+ fromLifecycle: materialized.lifecycle,
752
+ toLifecycle: materialized.lifecycle,
753
+ actorId: actor.id,
754
+ actorKind: actor.kind,
755
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
756
+ reason: note
757
+ };
758
+ await fsp3.appendFile(this.filePath, JSON.stringify({ __reportEvent: 1, data: event }) + NL2, {
759
+ encoding: "utf8",
760
+ mode: SECRET_FILE_MODE
761
+ });
762
+ return materialized;
763
+ });
717
764
  }
718
765
  // ── Query ────────────────────────────────────────────────────────
719
766
  async list(opts) {
@@ -752,44 +799,53 @@ var init_review_report_store = __esm({
752
799
  }
753
800
  // ── Compaction ───────────────────────────────────────────────────
754
801
  async compact(opts) {
755
- const maxAge = opts?.maxAgeMs ?? REPORT_RETENTION_MS;
756
- const now = Date.now();
757
- const all = await this._readAll();
758
- const kept = [];
759
- let removed = 0;
760
- let eventsFolded = 0;
761
- for (const entry of all) {
762
- const age = now - new Date(entry.report.reviewedAt).getTime();
763
- const materialized = this._materialize(entry);
764
- const isTerminal = materialized.lifecycle === "completed" || materialized.lifecycle === "skipped";
765
- if (isTerminal && age > maxAge) {
766
- removed++;
767
- eventsFolded += entry.events.length;
768
- continue;
769
- }
770
- const oldEvents = entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() > maxAge);
771
- if (oldEvents.length > 1) {
772
- eventsFolded += oldEvents.length - 1;
773
- const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
774
- entry.events = [newestOld, ...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)];
802
+ return withFileLock(this.filePath, async () => {
803
+ const maxAge = opts?.maxAgeMs ?? REPORT_RETENTION_MS;
804
+ const now = Date.now();
805
+ const all = await this._readAll();
806
+ const kept = [];
807
+ let removed = 0;
808
+ let eventsFolded = 0;
809
+ for (const entry of all) {
810
+ const age = now - new Date(entry.report.reviewedAt).getTime();
811
+ const materialized = this._materialize(entry);
812
+ const isTerminal = materialized.lifecycle === "completed" || materialized.lifecycle === "skipped";
813
+ if (isTerminal && age > maxAge) {
814
+ removed++;
815
+ eventsFolded += entry.events.length;
816
+ continue;
817
+ }
818
+ const oldEvents = entry.events.filter(
819
+ (ev) => now - new Date(ev.timestamp).getTime() > maxAge
820
+ );
821
+ if (oldEvents.length > 1) {
822
+ eventsFolded += oldEvents.length - 1;
823
+ const newestOld = oldEvents.sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
824
+ entry.events = [
825
+ newestOld,
826
+ ...entry.events.filter((ev) => now - new Date(ev.timestamp).getTime() <= maxAge)
827
+ ];
828
+ }
829
+ kept.push({ record: { __report: 1, data: entry.report }, events: entry.events });
775
830
  }
776
- kept.push({ record: { __report: 1, data: entry.report }, events: entry.events });
777
- }
778
- const lines = [];
779
- for (const { record, events } of kept) {
780
- if (record) lines.push(JSON.stringify(record));
781
- for (const ev of events) {
782
- lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));
831
+ const lines = [];
832
+ for (const { record, events } of kept) {
833
+ if (record) lines.push(JSON.stringify(record));
834
+ for (const ev of events) {
835
+ lines.push(JSON.stringify({ __reportEvent: 1, data: ev }));
836
+ }
783
837
  }
784
- }
785
- lines.push(JSON.stringify({
786
- __reportCompact: 1,
787
- compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
788
- removedReports: removed,
789
- foldedEvents: eventsFolded
790
- }));
791
- await atomicWrite(this.filePath, lines.join(NL2) + NL2, { mode: 384 });
792
- return { removed, eventsFolded };
838
+ lines.push(
839
+ JSON.stringify({
840
+ __reportCompact: 1,
841
+ compactedAt: (/* @__PURE__ */ new Date()).toISOString(),
842
+ removedReports: removed,
843
+ foldedEvents: eventsFolded
844
+ })
845
+ );
846
+ await atomicWrite(this.filePath, lines.join(NL2) + NL2, { mode: 384 });
847
+ return { removed, eventsFolded };
848
+ });
793
849
  }
794
850
  // ── Private helpers ──────────────────────────────────────────────
795
851
  async _readAllLines() {
@@ -1079,10 +1135,10 @@ function validateAgainstSchema(value, schema) {
1079
1135
  return { ok: errors.length === 0, errors };
1080
1136
  }
1081
1137
  var MAX_SCHEMA_DEPTH = 64;
1082
- function walk(value, schema, path28, errors, depth) {
1138
+ function walk(value, schema, path29, errors, depth) {
1083
1139
  if (depth > MAX_SCHEMA_DEPTH) {
1084
1140
  errors.push({
1085
- path: path28 || "<root>",
1141
+ path: path29 || "<root>",
1086
1142
  message: `schema nesting exceeds maximum depth (${MAX_SCHEMA_DEPTH})`
1087
1143
  });
1088
1144
  return;
@@ -1090,7 +1146,7 @@ function walk(value, schema, path28, errors, depth) {
1090
1146
  if (schema.enum !== void 0) {
1091
1147
  if (!enumIncludes(schema.enum, value)) {
1092
1148
  errors.push({
1093
- path: path28 || "<root>",
1149
+ path: path29 || "<root>",
1094
1150
  message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
1095
1151
  });
1096
1152
  return;
@@ -1099,7 +1155,7 @@ function walk(value, schema, path28, errors, depth) {
1099
1155
  if (typeof schema.type === "string") {
1100
1156
  if (!checkType(value, schema.type)) {
1101
1157
  errors.push({
1102
- path: path28 || "<root>",
1158
+ path: path29 || "<root>",
1103
1159
  message: `expected ${schema.type}, got ${describeType(value)} (${previewValue(value)})`
1104
1160
  });
1105
1161
  return;
@@ -1111,7 +1167,7 @@ function walk(value, schema, path28, errors, depth) {
1111
1167
  if (!(req in obj)) {
1112
1168
  const expected = schema.properties?.[req]?.type;
1113
1169
  errors.push({
1114
- path: joinPath(path28, req),
1170
+ path: joinPath(path29, req),
1115
1171
  message: `required property missing${typeof expected === "string" ? ` (expected ${expected})` : ""}`
1116
1172
  });
1117
1173
  }
@@ -1119,14 +1175,14 @@ function walk(value, schema, path28, errors, depth) {
1119
1175
  if (schema.properties) {
1120
1176
  for (const [key, subSchema] of Object.entries(schema.properties)) {
1121
1177
  if (key in obj) {
1122
- walk(obj[key], subSchema, joinPath(path28, key), errors, depth + 1);
1178
+ walk(obj[key], subSchema, joinPath(path29, key), errors, depth + 1);
1123
1179
  }
1124
1180
  }
1125
1181
  }
1126
1182
  }
1127
1183
  if (schema.type === "array" && Array.isArray(value) && schema.items) {
1128
1184
  for (let i = 0; i < value.length; i++) {
1129
- walk(value[i], schema.items, `${path28}[${i}]`, errors, depth + 1);
1185
+ walk(value[i], schema.items, `${path29}[${i}]`, errors, depth + 1);
1130
1186
  }
1131
1187
  }
1132
1188
  }
@@ -2054,23 +2110,6 @@ import { createHash as createHash7 } from "node:crypto";
2054
2110
  import * as fsp from "node:fs/promises";
2055
2111
  import * as path14 from "node:path";
2056
2112
 
2057
- // src/core/model-ref.ts
2058
- function parseModelRef(ref) {
2059
- const trimmed = ref.trim();
2060
- const slash = trimmed.indexOf("/");
2061
- if (slash !== -1) {
2062
- return {
2063
- provider: trimmed.slice(0, slash) || void 0,
2064
- model: trimmed.slice(slash + 1).trim()
2065
- };
2066
- }
2067
- const parts = trimmed.split(/\s+/);
2068
- if (parts.length >= 2) {
2069
- return { provider: parts[0], model: parts.slice(1).join(" ") };
2070
- }
2071
- return { model: trimmed };
2072
- }
2073
-
2074
2113
  // src/core/model-availability-calendar.ts
2075
2114
  function logicalCalendarTarget(providerId, model) {
2076
2115
  if (providerId !== "omniroute") return { providerId, model };
@@ -2149,6 +2188,23 @@ function evaluateModelCalendar(rules, providerId, model, at = /* @__PURE__ */ ne
2149
2188
  return { allowed: true };
2150
2189
  }
2151
2190
 
2191
+ // src/core/model-ref.ts
2192
+ function parseModelRef(ref) {
2193
+ const trimmed = ref.trim();
2194
+ const slash = trimmed.indexOf("/");
2195
+ if (slash !== -1) {
2196
+ return {
2197
+ provider: trimmed.slice(0, slash) || void 0,
2198
+ model: trimmed.slice(slash + 1).trim()
2199
+ };
2200
+ }
2201
+ const parts = trimmed.split(/\s+/);
2202
+ if (parts.length >= 2) {
2203
+ return { provider: parts[0], model: parts.slice(1).join(" ") };
2204
+ }
2205
+ return { model: trimmed };
2206
+ }
2207
+
2152
2208
  // src/core/fallback-profile-manager.ts
2153
2209
  function hasText(value) {
2154
2210
  return typeof value === "string" && value.trim().length > 0;
@@ -2249,18 +2305,42 @@ var FallbackProfileManager = class {
2249
2305
  * Mirrors the previous `effectiveFallbackChain()` logic but centralized.
2250
2306
  */
2251
2307
  resolveEffective(opts = {}) {
2308
+ const bridge = this.resolveBridge(opts.exclude);
2309
+ let selected = FREEZER_EMPTY;
2252
2310
  if (opts.fallbackModels && opts.fallbackModels.length > 0) {
2253
2311
  const resolved = this.resolveRefs(opts.fallbackModels, opts.exclude);
2254
- if (resolved.length > 0) return resolved;
2312
+ if (resolved.length > 0) selected = resolved;
2255
2313
  }
2256
- if (opts.fallbackProfile) {
2314
+ if (selected.length === 0 && opts.fallbackProfile) {
2257
2315
  const resolved = this.resolve(opts.fallbackProfile, { exclude: opts.exclude });
2258
- if (resolved.length > 0) return resolved;
2316
+ if (resolved.length > 0) selected = resolved;
2259
2317
  }
2260
- if (opts.fallbackAuto !== false) {
2261
- return this.smartDefault(opts.exclude);
2318
+ if (selected.length === 0 && opts.fallbackAuto !== false) {
2319
+ selected = this.smartDefault(opts.exclude);
2262
2320
  }
2263
- return FREEZER_EMPTY;
2321
+ if (bridge.length === 0) return selected;
2322
+ if (selected.length === 0) return bridge;
2323
+ const seen = new Set(bridge.map((entry) => `${entry.providerId}/${entry.model}`));
2324
+ return Object.freeze([
2325
+ ...bridge,
2326
+ ...selected.filter((entry) => !seen.has(`${entry.providerId}/${entry.model}`))
2327
+ ]);
2328
+ }
2329
+ /** Resolve the optional, fully-qualified emergency continuity route. */
2330
+ resolveBridge(exclude) {
2331
+ const ref = this.config.fallbackBridge?.trim();
2332
+ if (!ref) return FREEZER_EMPTY;
2333
+ const parsed = parseModelRef(ref);
2334
+ if (!parsed.provider || !parsed.model) return FREEZER_EMPTY;
2335
+ return this.resolveRefs([ref], exclude);
2336
+ }
2337
+ /**
2338
+ * Resolve every usable configured target as an uncapped last-resort chain.
2339
+ * Normal smart defaults stay bounded; callers append this only after the
2340
+ * preferred chain and only when automatic fallback is enabled.
2341
+ */
2342
+ resolveAllConfigured(exclude) {
2343
+ return this.smartDefault(exclude, Number.POSITIVE_INFINITY);
2264
2344
  }
2265
2345
  // ── Provider availability (read-only) ──────────────────────────────────
2266
2346
  checkProvider(providerId) {
@@ -2319,7 +2399,7 @@ var FallbackProfileManager = class {
2319
2399
  * explicit is set. Same-provider alternatives first, then cross-provider.
2320
2400
  * Limited to 4 entries to avoid burning through models on a transient blip.
2321
2401
  */
2322
- smartDefault(exclude) {
2402
+ smartDefault(exclude, maxCandidates = 4) {
2323
2403
  const leaderProvider = this.config.provider;
2324
2404
  const leaderModel = this.config.model;
2325
2405
  const providers = this.config.providers ?? {};
@@ -2360,8 +2440,18 @@ var FallbackProfileManager = class {
2360
2440
  (id === leaderProvider ? sameProvider : crossProvider).push(ref);
2361
2441
  }
2362
2442
  }
2363
- const MAX = 4;
2364
- const all = [...favorites, ...sameProvider, ...crossProvider].slice(0, MAX);
2443
+ const ordered = [...favorites, ...sameProvider, ...crossProvider];
2444
+ const all = Number.isFinite(maxCandidates) ? ordered.slice(0, Math.max(0, maxCandidates)) : [...ordered];
2445
+ const firstCrossProvider = ordered.find((ref) => {
2446
+ const parsed = parseModelRef(ref);
2447
+ return (parsed.provider ?? leaderProvider) !== leaderProvider;
2448
+ });
2449
+ if (all.length > 0 && firstCrossProvider && !all.some((ref) => {
2450
+ const parsed = parseModelRef(ref);
2451
+ return (parsed.provider ?? leaderProvider) !== leaderProvider;
2452
+ })) {
2453
+ all[all.length - 1] = firstCrossProvider;
2454
+ }
2365
2455
  return Object.freeze(
2366
2456
  all.map((ref) => {
2367
2457
  const p = parseModelRef(ref);
@@ -2618,6 +2708,7 @@ function stableId(prefix, value) {
2618
2708
  }
2619
2709
 
2620
2710
  // src/chronicle/journal.ts
2711
+ init_file_permissions();
2621
2712
  init_atomic_write();
2622
2713
  import { randomUUID } from "node:crypto";
2623
2714
  import { createReadStream } from "node:fs";
@@ -2682,7 +2773,16 @@ var ChronicleJournal = class {
2682
2773
  drainPromise;
2683
2774
  drainScheduled = false;
2684
2775
  drainTimer;
2685
- counters = { acceptedEvents: 0, persistedEvents: 0, rejectedEvents: 0, failedEvents: 0, batches: 0, maxObservedPending: 0, largestBatch: 0, partitionRolls: 0 };
2776
+ counters = {
2777
+ acceptedEvents: 0,
2778
+ persistedEvents: 0,
2779
+ rejectedEvents: 0,
2780
+ failedEvents: 0,
2781
+ batches: 0,
2782
+ maxObservedPending: 0,
2783
+ largestBatch: 0,
2784
+ partitionRolls: 0
2785
+ };
2686
2786
  lastBatchDurationMs;
2687
2787
  partitionIndex = 0;
2688
2788
  partitionStartedAt;
@@ -2708,18 +2808,27 @@ var ChronicleJournal = class {
2708
2808
  return this.partitionIndex === 0 ? this.basePath : rotatedPath(this.basePath, this.partitionIndex);
2709
2809
  }
2710
2810
  stats() {
2711
- return { ...this.counters, pendingEvents: this.pending.length, ...this.lastBatchDurationMs !== void 0 ? { lastBatchDurationMs: this.lastBatchDurationMs } : {} };
2811
+ return {
2812
+ ...this.counters,
2813
+ pendingEvents: this.pending.length,
2814
+ ...this.lastBatchDurationMs !== void 0 ? { lastBatchDurationMs: this.lastBatchDurationMs } : {}
2815
+ };
2712
2816
  }
2713
2817
  append(input) {
2714
2818
  if (this.pending.length >= this.maxPending) {
2715
2819
  this.counters.rejectedEvents++;
2716
- return Promise.reject(new Error(`Chronicle backpressure limit reached (${this.maxPending} pending events)`));
2820
+ return Promise.reject(
2821
+ new Error(`Chronicle backpressure limit reached (${this.maxPending} pending events)`)
2822
+ );
2717
2823
  }
2718
2824
  const promise = new Promise((resolve16, reject) => {
2719
2825
  this.pending.push({ input, resolve: resolve16, reject });
2720
2826
  });
2721
2827
  this.counters.acceptedEvents++;
2722
- this.counters.maxObservedPending = Math.max(this.counters.maxObservedPending, this.pending.length);
2828
+ this.counters.maxObservedPending = Math.max(
2829
+ this.counters.maxObservedPending,
2830
+ this.pending.length
2831
+ );
2723
2832
  this.scheduleDrain();
2724
2833
  return promise;
2725
2834
  }
@@ -2745,7 +2854,8 @@ var ChronicleJournal = class {
2745
2854
  await this.flush();
2746
2855
  const files = await collectPartitions(this.basePath);
2747
2856
  const checkpointResult = await readRetentionCheckpoint(this.basePath);
2748
- if (checkpointResult.error) return { ok: false, entries: 0, brokenAt: 0, reason: checkpointResult.error };
2857
+ if (checkpointResult.error)
2858
+ return { ok: false, entries: 0, brokenAt: 0, reason: checkpointResult.error };
2749
2859
  return verifyPartitionFiles(files, checkpointResult.checkpoint);
2750
2860
  }
2751
2861
  async purge(options) {
@@ -2763,7 +2873,10 @@ var ChronicleJournal = class {
2763
2873
  for (const suppliedPath of new Set(suppliedFiles)) {
2764
2874
  const file = path4.resolve(suppliedPath);
2765
2875
  if (!isJournalPartition(file, path4.dirname(this.basePath), this.basePath)) {
2766
- errors.push({ file: suppliedPath, reason: "not a Chronicle journal partition in this journal directory" });
2876
+ errors.push({
2877
+ file: suppliedPath,
2878
+ reason: "not a Chronicle journal partition in this journal directory"
2879
+ });
2767
2880
  sc++;
2768
2881
  continue;
2769
2882
  }
@@ -2812,8 +2925,12 @@ var ChronicleJournal = class {
2812
2925
  const checkpointResult = await readRetentionCheckpoint(familyBase);
2813
2926
  if (checkpointResult.error) throw new Error(checkpointResult.error);
2814
2927
  const checkpoint = checkpointResult.checkpoint;
2815
- const nextCheckpoint = await verifyRetainedPrefix(streamEntriesStrict(file), checkpoint);
2816
- if (!nextCheckpoint) throw new Error("partition does not extend the trusted Chronicle chain");
2928
+ const nextCheckpoint = await verifyRetainedPrefix(
2929
+ streamEntriesStrict(file),
2930
+ checkpoint
2931
+ );
2932
+ if (!nextCheckpoint)
2933
+ throw new Error("partition does not extend the trusted Chronicle chain");
2817
2934
  if (nextCheckpoint.sequence > (checkpoint?.sequence ?? 0)) {
2818
2935
  await writeRetentionCheckpoint(familyBase, nextCheckpoint);
2819
2936
  }
@@ -2833,7 +2950,13 @@ var ChronicleJournal = class {
2833
2950
  }
2834
2951
  }
2835
2952
  }
2836
- return { deletedCount: dc, deletedBytes: db, skippedCount: sc, errors, ...options.dryRun ? { candidates } : {} };
2953
+ return {
2954
+ deletedCount: dc,
2955
+ deletedBytes: db,
2956
+ skippedCount: sc,
2957
+ errors,
2958
+ ...options.dryRun ? { candidates } : {}
2959
+ };
2837
2960
  }
2838
2961
  async maybeAutoPurge() {
2839
2962
  if (this.retentionDays <= 0) return;
@@ -2909,7 +3032,8 @@ var ChronicleJournal = class {
2909
3032
  this.rotate();
2910
3033
  return;
2911
3034
  }
2912
- if (Number.isFinite(this.maxPartitionSizeBytes) && this.partitionSizeBytes >= this.maxPartitionSizeBytes) this.rotate();
3035
+ if (Number.isFinite(this.maxPartitionSizeBytes) && this.partitionSizeBytes >= this.maxPartitionSizeBytes)
3036
+ this.rotate();
2913
3037
  }
2914
3038
  rotate() {
2915
3039
  this.partitionIndex++;
@@ -2930,13 +3054,23 @@ var ChronicleJournal = class {
2930
3054
  let prev = this.lastSequence > 0 ? { sequence: this.lastSequence, hash: this.lastHash } : void 0;
2931
3055
  recorded = batch.map(({ input }) => {
2932
3056
  const instant = this.now().toISOString();
2933
- const uh = { ...input, occurredAt: input.occurredAt ?? instant, monotonicNs: input.monotonicNs ?? this.monotonicNow().toString(), schemaVersion: CHRONICLE_SCHEMA_VERSION, eventId: this.idFactory(), observedAt: instant, persistedAt: instant, sequence: (prev?.sequence ?? 0) + 1, previousHash: prev?.hash ?? GENESIS_HASH };
3057
+ const uh = {
3058
+ ...input,
3059
+ occurredAt: input.occurredAt ?? instant,
3060
+ monotonicNs: input.monotonicNs ?? this.monotonicNow().toString(),
3061
+ schemaVersion: CHRONICLE_SCHEMA_VERSION,
3062
+ eventId: this.idFactory(),
3063
+ observedAt: instant,
3064
+ persistedAt: instant,
3065
+ sequence: (prev?.sequence ?? 0) + 1,
3066
+ previousHash: prev?.hash ?? GENESIS_HASH
3067
+ };
2934
3068
  const event = { ...uh, hash: hashValue(uh) };
2935
3069
  prev = event;
2936
3070
  return event;
2937
3071
  });
2938
3072
  const serialized = recorded.map((e) => JSON.stringify(e)).join("\n") + "\n";
2939
- await fs2.appendFile(cp, serialized, "utf8");
3073
+ await fs2.appendFile(cp, serialized, { encoding: "utf8", mode: SECRET_FILE_MODE });
2940
3074
  this.partitionSizeBytes += Buffer.byteLength(serialized);
2941
3075
  });
2942
3076
  const last = recorded[recorded.length - 1];
@@ -2972,7 +3106,8 @@ async function collectPartitions(basePath) {
2972
3106
  const result = [];
2973
3107
  try {
2974
3108
  const entries = await fs2.readdir(dir, { withFileTypes: true });
2975
- for (const entry of entries) if (entry.isFile() && pattern.test(entry.name)) result.push(path4.join(dir, entry.name));
3109
+ for (const entry of entries)
3110
+ if (entry.isFile() && pattern.test(entry.name)) result.push(path4.join(dir, entry.name));
2976
3111
  } catch {
2977
3112
  }
2978
3113
  const baseFile = path4.join(dir, base + ext);
@@ -3047,23 +3182,42 @@ async function verifyPartitionFiles(files, checkpoint) {
3047
3182
  for await (const entry of streamEntriesStrict(file)) {
3048
3183
  const { hash: recordedHash, ...content } = entry;
3049
3184
  if (entry.sequence <= checkpointSequence) {
3050
- if (hashValue(content) !== recordedHash) return { ok: false, entries, brokenAt: entries, reason: "entry hash mismatch" };
3185
+ if (hashValue(content) !== recordedHash)
3186
+ return { ok: false, entries, brokenAt: entries, reason: "entry hash mismatch" };
3051
3187
  if (coveredPrevious && entry.sequence !== coveredPrevious.sequence + 1) {
3052
- return { ok: false, entries, brokenAt: entries, reason: `sequence ${entry.sequence} is not ${coveredPrevious.sequence + 1}` };
3188
+ return {
3189
+ ok: false,
3190
+ entries,
3191
+ brokenAt: entries,
3192
+ reason: `sequence ${entry.sequence} is not ${coveredPrevious.sequence + 1}`
3193
+ };
3053
3194
  }
3054
3195
  if (coveredPrevious && entry.previousHash !== coveredPrevious.hash) {
3055
3196
  return { ok: false, entries, brokenAt: entries, reason: "previous hash mismatch" };
3056
3197
  }
3057
3198
  if (entry.sequence === checkpointSequence && recordedHash !== checkpoint?.hash) {
3058
- return { ok: false, entries, brokenAt: entries, reason: "retention checkpoint hash mismatch" };
3199
+ return {
3200
+ ok: false,
3201
+ entries,
3202
+ brokenAt: entries,
3203
+ reason: "retention checkpoint hash mismatch"
3204
+ };
3059
3205
  }
3060
3206
  coveredPrevious = entry;
3061
3207
  continue;
3062
3208
  }
3063
3209
  const index = entries++;
3064
- if (entry.sequence !== lastSequence + 1) return { ok: false, entries, brokenAt: index, reason: `sequence ${entry.sequence} is not ${lastSequence + 1}` };
3065
- if (entry.previousHash !== previousHash) return { ok: false, entries, brokenAt: index, reason: "previous hash mismatch" };
3066
- if (hashValue(content) !== recordedHash) return { ok: false, entries, brokenAt: index, reason: "entry hash mismatch" };
3210
+ if (entry.sequence !== lastSequence + 1)
3211
+ return {
3212
+ ok: false,
3213
+ entries,
3214
+ brokenAt: index,
3215
+ reason: `sequence ${entry.sequence} is not ${lastSequence + 1}`
3216
+ };
3217
+ if (entry.previousHash !== previousHash)
3218
+ return { ok: false, entries, brokenAt: index, reason: "previous hash mismatch" };
3219
+ if (hashValue(content) !== recordedHash)
3220
+ return { ok: false, entries, brokenAt: index, reason: "entry hash mismatch" };
3067
3221
  previousHash = recordedHash;
3068
3222
  lastSequence = entry.sequence;
3069
3223
  }
@@ -3096,7 +3250,9 @@ async function readRetentionCheckpoint(basePath) {
3096
3250
  }
3097
3251
  async function writeRetentionCheckpoint(basePath, checkpoint) {
3098
3252
  await atomicWrite(retentionCheckpointPath(basePath), `${JSON.stringify(checkpoint)}
3099
- `, { mode: 384 });
3253
+ `, {
3254
+ mode: 384
3255
+ });
3100
3256
  }
3101
3257
  function isHash(value) {
3102
3258
  return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
@@ -3121,8 +3277,8 @@ async function readLastEntryState(filePath) {
3121
3277
  throw error;
3122
3278
  }
3123
3279
  try {
3124
- const stat6 = await handle.stat();
3125
- const size = stat6.size;
3280
+ const stat7 = await handle.stat();
3281
+ const size = stat7.size;
3126
3282
  let position = size, suffix = "";
3127
3283
  while (position > 0) {
3128
3284
  const length = Math.min(65536, position);
@@ -3136,13 +3292,17 @@ async function readLastEntryState(filePath) {
3136
3292
  const trimmed = lines[i].trim();
3137
3293
  if (!trimmed) continue;
3138
3294
  try {
3139
- return { entry: JSON.parse(trimmed), size, birthtimeMs: stat6.birthtimeMs };
3295
+ return {
3296
+ entry: JSON.parse(trimmed),
3297
+ size,
3298
+ birthtimeMs: stat7.birthtimeMs
3299
+ };
3140
3300
  } catch {
3141
3301
  }
3142
3302
  }
3143
3303
  suffix = lines[0] ?? "";
3144
3304
  }
3145
- return { size, birthtimeMs: stat6.birthtimeMs };
3305
+ return { size, birthtimeMs: stat7.birthtimeMs };
3146
3306
  } finally {
3147
3307
  await handle.close();
3148
3308
  }
@@ -3561,8 +3721,8 @@ async function* reverseLines(filePath, maxBytes) {
3561
3721
  return;
3562
3722
  }
3563
3723
  try {
3564
- const fileSize = (await handle.stat()).size;
3565
- const size = Math.min(fileSize, maxBytes ?? fileSize);
3724
+ const fileSize2 = (await handle.stat()).size;
3725
+ const size = Math.min(fileSize2, maxBytes ?? fileSize2);
3566
3726
  let position = size;
3567
3727
  let suffix = Buffer.alloc(0);
3568
3728
  while (position > 0) {
@@ -4925,6 +5085,14 @@ var SKILL_LIMITS = {
4925
5085
  * Consumer: `downloadGitHubTarball`.
4926
5086
  */
4927
5087
  MAX_TARBALL_SIZE: 50 * 1024 * 1024,
5088
+ /**
5089
+ * Maximum size of a GitHub skill tarball after gzip decompression. The
5090
+ * compressed download limit alone does not protect against highly
5091
+ * compressible archives expanding until the process runs out of memory.
5092
+ *
5093
+ * Consumer: `downloadGitHubTarball`.
5094
+ */
5095
+ MAX_UNCOMPRESSED_TARBALL_SIZE: 64 * 1024 * 1024,
4928
5096
  /**
4929
5097
  * Default total char budget for skill bodies injected in eager mode when
4930
5098
  * `config.skills.eagerMaxChars` is unset. ~6k tokens. Skills are injected
@@ -4936,6 +5104,17 @@ var SKILL_LIMITS = {
4936
5104
  * `skillEagerMaxChars`).
4937
5105
  */
4938
5106
  EAGER_DEFAULT_MAX_CHARS: 24e3,
5107
+ /**
5108
+ * Default total char budget for compact (token-saving) skill bodies injected
5109
+ * by `buildCompactSkillBodiesText`. Mirrors the eager ceiling so compact mode
5110
+ * can never inject more total skill text than eager mode. Before this bound
5111
+ * existed, compact mode injected EVERY skill's compact body with no cap, so
5112
+ * the section grew linearly with the number of installed skills. Skills past
5113
+ * the budget overflow to a name list the agent loads via the `skill` tool.
5114
+ *
5115
+ * Consumer: `buildCompactSkillBodiesText` (default for its `budget` param).
5116
+ */
5117
+ COMPACT_DEFAULT_MAX_CHARS: 24e3,
4939
5118
  /**
4940
5119
  * Auto-compact body limits (the token-saving fallback used when a skill has
4941
5120
  * no hand-crafted `SKILL.save.md`). The Overview and Rules sections are
@@ -4964,34 +5143,148 @@ var SKILL_LIMITS = {
4964
5143
  SKILL_BODY_LINE_LIMIT: 500
4965
5144
  };
4966
5145
 
4967
- // src/utils/instruction-file.ts
4968
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
4969
- import * as path9 from "node:path";
4970
- import { fileURLToPath } from "node:url";
4971
- var textCache = /* @__PURE__ */ new Map();
4972
- var rootCandidates;
4973
- function readBundledInstructionText(relativePath) {
4974
- const cached = textCache.get(relativePath);
4975
- if (cached !== void 0) return cached;
4976
- let resolved = "";
4977
- for (const root of instructionRootCandidates()) {
4978
- try {
4979
- resolved = readFileSync2(path9.join(root, relativePath), "utf8").trimEnd();
4980
- break;
4981
- } catch {
5146
+ // src/skills/frontmatter.ts
5147
+ var SCALAR_KEYS = /* @__PURE__ */ new Set(["name", "description", "trigger", "version", "license", "compatibility"]);
5148
+ function parseSkillFrontmatter(raw) {
5149
+ const text = normalizeLineEndings(raw);
5150
+ if (!text.startsWith("---")) return {};
5151
+ const end = text.indexOf("\n---", 4);
5152
+ if (end === -1) return {};
5153
+ return parseFrontmatterBlock(text.slice(4, end));
5154
+ }
5155
+ function stripFrontmatter(raw) {
5156
+ const text = normalizeLineEndings(raw);
5157
+ if (!text.startsWith("---")) return text;
5158
+ const end = text.indexOf("\n---", 4);
5159
+ if (end === -1) return text;
5160
+ let body = text.slice(end + 4);
5161
+ if (body.startsWith("\n")) body = body.slice(1);
5162
+ return body;
5163
+ }
5164
+ function normalizeLineEndings(s) {
5165
+ return s.replace(/\r\n?/g, "\n");
5166
+ }
5167
+ function parseFrontmatterBlock(block) {
5168
+ const out = {};
5169
+ const lines = block.split("\n");
5170
+ let i = 0;
5171
+ while (i < lines.length) {
5172
+ const line = lines[i] ?? "";
5173
+ const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
5174
+ if (!m) {
5175
+ i++;
5176
+ continue;
5177
+ }
5178
+ const key = m[1] ?? "";
5179
+ const rest = (m[2] ?? "").trim();
5180
+ if (key === "metadata") {
5181
+ const map = {};
5182
+ i++;
5183
+ while (i < lines.length) {
5184
+ const sub = lines[i] ?? "";
5185
+ const sm = /^\s+([a-zA-Z0-9_.-]+):\s*(.*)$/.exec(sub);
5186
+ if (!sm) break;
5187
+ map[sm[1] ?? ""] = unquote((sm[2] ?? "").trim());
5188
+ i++;
5189
+ }
5190
+ if (Object.keys(map).length > 0) out.metadata = map;
5191
+ continue;
5192
+ }
5193
+ if (rest === "|" || rest === ">") {
5194
+ const collected = [];
5195
+ i++;
5196
+ while (i < lines.length) {
5197
+ const sub = lines[i] ?? "";
5198
+ if (sub === "" || sub.startsWith(" ") || sub.startsWith(" ")) {
5199
+ collected.push(sub.replace(/^\s+/, ""));
5200
+ i++;
5201
+ } else break;
5202
+ }
5203
+ out[normalizeKey2(key)] = collected.join("\n").trim();
5204
+ continue;
5205
+ }
5206
+ if (key === "allowed-tools" || key === "allowedTools") {
5207
+ out.allowedTools = rest.split(/[\s,]+/).filter(Boolean);
5208
+ i++;
5209
+ continue;
5210
+ }
5211
+ if (SCALAR_KEYS.has(key)) {
5212
+ out[key] = unquote(rest);
5213
+ i++;
5214
+ continue;
4982
5215
  }
5216
+ i++;
4983
5217
  }
4984
- textCache.set(relativePath, resolved);
4985
- return resolved;
5218
+ return out;
4986
5219
  }
4987
- function renderInstructionTemplate(template, values) {
4988
- return template.replace(
4989
- /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g,
4990
- (match, key) => Object.hasOwn(values, key) ? values[key] ?? "" : match
4991
- );
5220
+ function normalizeKey2(key) {
5221
+ return key === "allowed-tools" ? "allowedTools" : key;
4992
5222
  }
4993
- function instructionRootCandidates() {
4994
- if (rootCandidates !== void 0) return rootCandidates;
5223
+ function unquote(s) {
5224
+ if (s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"))) {
5225
+ return s.slice(1, -1);
5226
+ }
5227
+ return s;
5228
+ }
5229
+ function isValidSkillNameFormat(name) {
5230
+ return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
5231
+ }
5232
+ function validateSkillName(name, parentDirName) {
5233
+ const errors = [];
5234
+ if (!name || name.trim().length === 0) {
5235
+ errors.push("name is empty");
5236
+ return errors;
5237
+ }
5238
+ if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);
5239
+ if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
5240
+ errors.push(
5241
+ "name must be lowercase letters, digits, and single hyphens only (no leading/trailing/consecutive hyphens)"
5242
+ );
5243
+ }
5244
+ if (parentDirName !== void 0 && name !== parentDirName) {
5245
+ errors.push(`name "${name}" must match its parent directory "${parentDirName}"`);
5246
+ }
5247
+ return errors;
5248
+ }
5249
+
5250
+ // src/core/system-prompt-skill-text.ts
5251
+ function capSkillBody(body) {
5252
+ const max = SKILL_LIMITS.MAX_SKILL_BODY_CHARS;
5253
+ if (body.length <= max) return body;
5254
+ const budget = max - 1;
5255
+ const cut = body.lastIndexOf("\n\n", budget);
5256
+ const truncated = cut > budget / 2 ? body.slice(0, cut) : body.slice(0, budget);
5257
+ return truncated + "\u2026";
5258
+ }
5259
+
5260
+ // src/utils/instruction-file.ts
5261
+ import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
5262
+ import * as path9 from "node:path";
5263
+ import { fileURLToPath } from "node:url";
5264
+ var textCache = /* @__PURE__ */ new Map();
5265
+ var rootCandidates;
5266
+ function readBundledInstructionText(relativePath) {
5267
+ const cached = textCache.get(relativePath);
5268
+ if (cached !== void 0) return cached;
5269
+ let resolved = "";
5270
+ for (const root of instructionRootCandidates()) {
5271
+ try {
5272
+ resolved = readFileSync2(path9.join(root, relativePath), "utf8").trimEnd();
5273
+ break;
5274
+ } catch {
5275
+ }
5276
+ }
5277
+ textCache.set(relativePath, resolved);
5278
+ return resolved;
5279
+ }
5280
+ function renderInstructionTemplate(template, values) {
5281
+ return template.replace(
5282
+ /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g,
5283
+ (match, key) => Object.hasOwn(values, key) ? values[key] ?? "" : match
5284
+ );
5285
+ }
5286
+ function instructionRootCandidates() {
5287
+ if (rootCandidates !== void 0) return rootCandidates;
4995
5288
  const here = path9.dirname(fileURLToPath(import.meta.url));
4996
5289
  const candidates = [
4997
5290
  path9.resolve(here, "../../instructions"),
@@ -5786,6 +6079,7 @@ function encodeChronicleProjectServerMessage(message) {
5786
6079
  }
5787
6080
 
5788
6081
  // src/chronicle/project-server-endpoint.ts
6082
+ var CHRONICLE_PROJECT_SERVER_METADATA_FILE = "server.json";
5789
6083
  function normalizedPath(value) {
5790
6084
  const resolved = path11.resolve(value);
5791
6085
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
@@ -5804,6 +6098,9 @@ function chronicleProjectServerEndpoint(projectDir) {
5804
6098
  `${key}.sock`
5805
6099
  );
5806
6100
  }
6101
+ function chronicleProjectServerMetadataPath(projectDir) {
6102
+ return path11.join(projectDir, "chronicle", CHRONICLE_PROJECT_SERVER_METADATA_FILE);
6103
+ }
5807
6104
 
5808
6105
  // src/chronicle/project-server-client.ts
5809
6106
  var CONNECT_ATTEMPT_TIMEOUT_MS = 750;
@@ -5858,6 +6155,8 @@ var ChronicleProjectServerClient = class {
5858
6155
  connectResolve = null;
5859
6156
  connectReject = null;
5860
6157
  nextId = 1;
6158
+ /** WS-027: read from the owner-only metadata file — see currentAuthToken. */
6159
+ authToken;
5861
6160
  pending = /* @__PURE__ */ new Map();
5862
6161
  async call(op, args, options = {}) {
5863
6162
  await this.ensureConnected(true);
@@ -5940,6 +6239,7 @@ var ChronicleProjectServerClient = class {
5940
6239
  connectOnce() {
5941
6240
  this.socket?.destroy();
5942
6241
  this.socket = null;
6242
+ this.authToken = void 0;
5943
6243
  this.info = null;
5944
6244
  this.buffer = "";
5945
6245
  return new Promise((resolve16, reject) => {
@@ -5970,13 +6270,42 @@ var ChronicleProjectServerClient = class {
5970
6270
  socket.on("close", () => this.onClose(socket));
5971
6271
  });
5972
6272
  }
6273
+ /**
6274
+ * WS-027: the per-process token, read from the daemon's owner-only metadata
6275
+ * file — never from the `hello` frame, which the daemon sends to every
6276
+ * socket that connects (the mistake WS-028 found in the SAGE daemon).
6277
+ *
6278
+ * Read lazily and re-read while unknown: the daemon starts listening before
6279
+ * it writes metadata (endpoint ownership has to be won first), and a
6280
+ * respawned daemon mints a new token, so a cached wrong one would be sticky.
6281
+ */
6282
+ currentAuthToken() {
6283
+ if (this.authToken === void 0) {
6284
+ try {
6285
+ const raw = fs7.readFileSync(
6286
+ chronicleProjectServerMetadataPath(this.options.projectDir),
6287
+ "utf8"
6288
+ );
6289
+ const parsed = JSON.parse(raw);
6290
+ if (typeof parsed.authToken === "string" && parsed.authToken.length > 0) {
6291
+ this.authToken = parsed.authToken;
6292
+ }
6293
+ } catch {
6294
+ }
6295
+ }
6296
+ return this.authToken;
6297
+ }
5973
6298
  request(message, timeoutMs) {
5974
6299
  const socket = this.socket;
5975
6300
  if (!socket || socket.destroyed) {
5976
6301
  return Promise.reject(new Error("Chronicle project server connection is unavailable"));
5977
6302
  }
5978
6303
  const id = this.nextId++;
5979
- const encoded = encodeChronicleProjectServerMessage({ ...message, id });
6304
+ const encoded = encodeChronicleProjectServerMessage({
6305
+ ...message,
6306
+ id,
6307
+ authToken: this.currentAuthToken()
6308
+ });
5980
6309
  if (encoded.length > CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS) {
5981
6310
  return Promise.reject(new Error("Chronicle project server request exceeded frame limit"));
5982
6311
  }
@@ -6554,7 +6883,12 @@ function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "",
6554
6883
  }
6555
6884
  function resolveAutoReviewConfig(cfg, sessionConfig) {
6556
6885
  const mgr = new FallbackProfileManager(sessionConfig);
6557
- const chain = cfg.fallbackProfile ? mgr.resolve(cfg.fallbackProfile) : mgr.resolveEffective({ fallbackAuto: true });
6886
+ const chain = mgr.resolveEffective({
6887
+ ...cfg.fallbackProfile ? { fallbackProfile: cfg.fallbackProfile, fallbackAuto: false } : {
6888
+ fallbackModels: sessionConfig.fallbackModels,
6889
+ fallbackAuto: sessionConfig.fallbackAuto
6890
+ }
6891
+ });
6558
6892
  const rawProvider = cfg.provider?.trim();
6559
6893
  const rawModel = cfg.model?.trim();
6560
6894
  const resolvedProvider = rawProvider || (chain.length > 0 ? chain[0].providerId : sessionConfig.provider);
@@ -6698,8 +7032,8 @@ async function snapshotChangedFiles(cwd) {
6698
7032
  if (file.path.startsWith(".wrongstack/")) continue;
6699
7033
  if (budget <= 0) break;
6700
7034
  try {
6701
- const stat6 = await fsp.stat(path14.join(cwd, file.path));
6702
- if (!stat6.isFile() || stat6.size > MAX_SNAPSHOT_FILE_BYTES) continue;
7035
+ const stat7 = await fsp.stat(path14.join(cwd, file.path));
7036
+ if (!stat7.isFile() || stat7.size > MAX_SNAPSHOT_FILE_BYTES) continue;
6703
7037
  const content = await fsp.readFile(path14.join(cwd, file.path), "utf8");
6704
7038
  budget -= content.length;
6705
7039
  snapshots.push({
@@ -7157,7 +7491,6 @@ function createAutoReviewPlugin() {
7157
7491
 
7158
7492
  // src/plugins/chimera-plugin.ts
7159
7493
  init_error();
7160
- import { randomUUID as randomUUID6 } from "node:crypto";
7161
7494
  import { spawn as spawn4 } from "node:child_process";
7162
7495
  import * as fsp4 from "node:fs/promises";
7163
7496
  import * as os5 from "node:os";
@@ -7233,10 +7566,20 @@ function parseFindingSegment(segment, severity, context) {
7233
7566
  if (tagMatch) {
7234
7567
  remaining = content.slice(tagMatch[0].length).trim();
7235
7568
  }
7569
+ const citationMatch = remaining.match(
7570
+ /^(`+)([a-zA-Z_./\\:][^`]*[a-zA-Z0-9_./\\:])\1(?=\s*[—–-]|\s*$)/
7571
+ );
7572
+ if (citationMatch) {
7573
+ const inner = citationMatch[2];
7574
+ const afterCitation = remaining.slice(citationMatch[0].length);
7575
+ remaining = `${inner}${afterCitation}`;
7576
+ }
7236
7577
  let file;
7237
7578
  let line;
7238
7579
  let desc = remaining;
7239
- const refMatch = remaining.match(/^(.+?)(?::(\d+))?\s*[—–-]\s*(.+)$/);
7580
+ const refMatch = remaining.match(
7581
+ /^([a-zA-Z_./\\][a-zA-Z0-9_./\\-]*\.\w+)(?::(\d+))?\s+(?:[—–]|-)\s+(.+)$/
7582
+ );
7240
7583
  if (refMatch) {
7241
7584
  file = refMatch[1].trim();
7242
7585
  if (refMatch[2] !== void 0) {
@@ -7334,12 +7677,26 @@ async function persistReviewReport(payload, reportId, projectDir) {
7334
7677
  ...cascadeDepth !== void 0 ? { cascadeDepth } : {}
7335
7678
  };
7336
7679
  await store.persist(input);
7680
+ if (reviewStatus === "success" && parsed.findings.length === 0 && parsed.unparseableCount === 0 && isExplicitAllClearReview(payload.reviewText)) {
7681
+ await store.transition(
7682
+ reportId,
7683
+ "completed",
7684
+ { id: "chimera", kind: "system" },
7685
+ {
7686
+ reason: "Successful Chimera review produced no actionable findings"
7687
+ }
7688
+ );
7689
+ }
7337
7690
  return {
7338
7691
  reportId,
7339
7692
  created: !existed,
7340
7693
  totalFindings: parsed.findings.length
7341
7694
  };
7342
7695
  }
7696
+ function isExplicitAllClearReview(text) {
7697
+ const normalized = text.trim().toLowerCase();
7698
+ return normalized.startsWith("## \u{1F982} chimera review \u2014 all clear") || normalized.includes("chimera review: all clear");
7699
+ }
7343
7700
  async function syncReportCompletion(reportId, projectDir, actor) {
7344
7701
  const reportStore = new JsonlReportStore(projectDir);
7345
7702
  const findingStore = new JsonlFindingStore(projectDir);
@@ -7812,49 +8169,6 @@ async function showStatus(ctx) {
7812
8169
  ].join("\n");
7813
8170
  }
7814
8171
 
7815
- // src/plugins/review-finding-integration.ts
7816
- init_review_finding_store();
7817
- async function integrateFindings(payload, projectDir, reportId) {
7818
- if (!payload.reviewText || payload.reviewText.trim().length === 0) {
7819
- return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
7820
- }
7821
- const store = new JsonlFindingStore(projectDir);
7822
- const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
7823
- const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
7824
- const sessionId = payload.sessionId ?? payload.cwd;
7825
- const model = payload.bundle.config.model;
7826
- const parsed = parseChimeraReviewReport(payload.reviewText, {
7827
- sessionId,
7828
- agentId,
7829
- reviewerModel: model,
7830
- reviewType: source,
7831
- reportId
7832
- });
7833
- if (parsed.findings.length === 0) {
7834
- return {
7835
- created: 0,
7836
- relinked: 0,
7837
- reopened: 0,
7838
- totalFindings: 0,
7839
- unparseableCount: parsed.unparseableCount
7840
- };
7841
- }
7842
- const result = await store.upsert(parsed.findings, {
7843
- sessionId,
7844
- reportId,
7845
- agentId,
7846
- model
7847
- });
7848
- return {
7849
- created: result.created,
7850
- relinked: result.relinked,
7851
- reopened: result.reopened,
7852
- reportId,
7853
- totalFindings: parsed.findings.length,
7854
- unparseableCount: parsed.unparseableCount
7855
- };
7856
- }
7857
-
7858
8172
  // src/plugins/chimera-plugin.ts
7859
8173
  var DEFAULT_MAX_FILES = 15;
7860
8174
  var DEFAULT_CASCADE_ON = "off";
@@ -8010,18 +8324,6 @@ function buildReviewCommand(_getConfig) {
8010
8324
  }
8011
8325
  };
8012
8326
  }
8013
- async function tryPersistFindings(payload) {
8014
- if (!payload || typeof payload !== "object") return;
8015
- const p = payload;
8016
- const cwd = p.cwd ?? p.bundle?.cwd;
8017
- if (!cwd) return;
8018
- const slug = projectSlug(cwd);
8019
- const globalRoot = path17.join(os5.homedir(), ".wrongstack");
8020
- const projectDir = path17.join(globalRoot, "projects", slug);
8021
- const reportId = randomUUID6();
8022
- await persistReviewReport(payload, reportId, projectDir);
8023
- await integrateFindings(payload, projectDir, reportId);
8024
- }
8025
8327
  function createChimeraPlugin() {
8026
8328
  return {
8027
8329
  name: "wstack-chimera",
@@ -8050,9 +8352,6 @@ function createChimeraPlugin() {
8050
8352
  });
8051
8353
  api.onPattern("chimera.review_complete", (_event, payload) => {
8052
8354
  recordCompletedReview(api.events, payload);
8053
- tryPersistFindings(payload).catch((err) => {
8054
- api.log.warn(`[review-finding] failed to persist findings: ${toErrorMessage(err)}`);
8055
- });
8056
8355
  });
8057
8356
  if (!resolved.enabled) {
8058
8357
  api.log.info("[chimera] disabled by config");
@@ -8634,8 +8933,8 @@ var PromptUsageStore = class {
8634
8933
  }
8635
8934
  async fileSignature() {
8636
8935
  try {
8637
- const stat6 = await fs10.stat(this.file);
8638
- return { size: stat6.size, mtimeMs: stat6.mtimeMs, ctimeMs: stat6.ctimeMs };
8936
+ const stat7 = await fs10.stat(this.file);
8937
+ return { size: stat7.size, mtimeMs: stat7.mtimeMs, ctimeMs: stat7.ctimeMs };
8639
8938
  } catch {
8640
8939
  return null;
8641
8940
  }
@@ -9045,12 +9344,12 @@ function parseFlags(input) {
9045
9344
  while (s.startsWith("--") && (m = flagRe.exec(s))) {
9046
9345
  const name = expectDefined(m[1]);
9047
9346
  const rawVal = m[2] ?? m[3] ?? "true";
9048
- flags[name] = unquote(rawVal);
9347
+ flags[name] = unquote2(rawVal);
9049
9348
  s = s.slice(m[0].length);
9050
9349
  }
9051
9350
  return { flags, positional: s.trim() };
9052
9351
  }
9053
- function unquote(v) {
9352
+ function unquote2(v) {
9054
9353
  if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
9055
9354
  return v.slice(1, -1);
9056
9355
  }
@@ -9089,7 +9388,7 @@ function parseKeyValues(kvs) {
9089
9388
  const out = {};
9090
9389
  for (const kv of kvs) {
9091
9390
  const eq = kv.indexOf("=");
9092
- if (eq > 0) out[kv.slice(0, eq)] = unquote(kv.slice(eq + 1));
9391
+ if (eq > 0) out[kv.slice(0, eq)] = unquote2(kv.slice(eq + 1));
9093
9392
  }
9094
9393
  return out;
9095
9394
  }
@@ -9109,9 +9408,123 @@ function dim(s) {
9109
9408
  return `\x1B[2m${s}\x1B[0m`;
9110
9409
  }
9111
9410
 
9411
+ // src/plugins/review-finding-integration.ts
9412
+ init_review_finding_store();
9413
+ async function integrateFindings(payload, projectDir, reportId) {
9414
+ if (!payload.reviewText || payload.reviewText.trim().length === 0) {
9415
+ return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
9416
+ }
9417
+ const store = new JsonlFindingStore(projectDir);
9418
+ const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
9419
+ const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
9420
+ const sessionId = payload.sessionId ?? payload.cwd;
9421
+ const model = payload.bundle.config.model;
9422
+ const parsed = parseChimeraReviewReport(payload.reviewText, {
9423
+ sessionId,
9424
+ agentId,
9425
+ reviewerModel: model,
9426
+ reviewType: source,
9427
+ reportId
9428
+ });
9429
+ if (parsed.findings.length === 0) {
9430
+ return {
9431
+ created: 0,
9432
+ relinked: 0,
9433
+ reopened: 0,
9434
+ totalFindings: 0,
9435
+ unparseableCount: parsed.unparseableCount
9436
+ };
9437
+ }
9438
+ const result = await store.upsert(parsed.findings, {
9439
+ sessionId,
9440
+ reportId,
9441
+ agentId,
9442
+ model
9443
+ });
9444
+ return {
9445
+ created: result.created,
9446
+ relinked: result.relinked,
9447
+ reopened: result.reopened,
9448
+ reportId,
9449
+ totalFindings: parsed.findings.length,
9450
+ unparseableCount: parsed.unparseableCount
9451
+ };
9452
+ }
9453
+
9454
+ // src/plugins/review-store-maintenance.ts
9455
+ init_atomic_write();
9456
+ init_review_finding_store();
9457
+ init_review_report_store();
9458
+ import * as fsp5 from "node:fs/promises";
9459
+ import * as path21 from "node:path";
9460
+ var REVIEW_STORE_COMPACTION_THRESHOLD_BYTES = 8 * 1024 * 1024;
9461
+ var REVIEW_STORE_COMPACTION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
9462
+ var REVIEW_STORE_MAINTENANCE_FILE = ".review-store-maintenance.json";
9463
+ async function maybeCompactReviewStores(projectDir, opts = {}) {
9464
+ const thresholdBytes = opts.thresholdBytes ?? REVIEW_STORE_COMPACTION_THRESHOLD_BYTES;
9465
+ const intervalMs = opts.intervalMs ?? REVIEW_STORE_COMPACTION_INTERVAL_MS;
9466
+ const now = opts.now ?? Date.now();
9467
+ const maintenancePath = path21.join(projectDir, REVIEW_STORE_MAINTENANCE_FILE);
9468
+ return withFileLock(maintenancePath, async () => {
9469
+ const totalBytes = await fileSize(resolveReportStorePath(projectDir)) + await fileSize(resolveFindingStorePath(projectDir));
9470
+ if (totalBytes < thresholdBytes) {
9471
+ return emptyResult("below_threshold", totalBytes);
9472
+ }
9473
+ const state = await readMaintenanceState(maintenancePath);
9474
+ if (state && now - new Date(state.compactedAt).getTime() < intervalMs) {
9475
+ return emptyResult("interval", totalBytes);
9476
+ }
9477
+ const reportResult = await new JsonlReportStore(projectDir).compact();
9478
+ const findingResult = await new JsonlFindingStore(projectDir).compact();
9479
+ const nextState = {
9480
+ compactedAt: new Date(now).toISOString(),
9481
+ totalBytesBefore: totalBytes
9482
+ };
9483
+ await atomicWrite(maintenancePath, `${JSON.stringify(nextState)}
9484
+ `, { mode: 384 });
9485
+ return {
9486
+ compacted: true,
9487
+ totalBytes,
9488
+ reason: "compacted",
9489
+ removedReports: reportResult.removed,
9490
+ removedFindings: findingResult.removed,
9491
+ eventsFolded: reportResult.eventsFolded + findingResult.eventsFolded
9492
+ };
9493
+ });
9494
+ }
9495
+ function emptyResult(reason, totalBytes) {
9496
+ return {
9497
+ compacted: false,
9498
+ totalBytes,
9499
+ reason,
9500
+ removedReports: 0,
9501
+ removedFindings: 0,
9502
+ eventsFolded: 0
9503
+ };
9504
+ }
9505
+ async function fileSize(filePath) {
9506
+ try {
9507
+ return (await fsp5.stat(filePath)).size;
9508
+ } catch (error) {
9509
+ if (error.code === "ENOENT") return 0;
9510
+ throw error;
9511
+ }
9512
+ }
9513
+ async function readMaintenanceState(filePath) {
9514
+ try {
9515
+ const parsed = JSON.parse(await fsp5.readFile(filePath, "utf8"));
9516
+ return typeof parsed.compactedAt === "string" && Number.isFinite(parsed.totalBytesBefore) ? parsed : null;
9517
+ } catch (error) {
9518
+ if (error.code === "ENOENT" || error instanceof SyntaxError) {
9519
+ return null;
9520
+ }
9521
+ throw error;
9522
+ }
9523
+ }
9524
+
9112
9525
  // src/plugins/skills-plugin.ts
9113
9526
  import * as os7 from "node:os";
9114
- import * as path25 from "node:path";
9527
+ import * as path26 from "node:path";
9115
9528
 
9116
9529
  // src/skills/foreign-sources.ts
9117
9530
  var FOREIGN_SKILL_TOOLS = [
@@ -9294,104 +9707,7 @@ function numField(rec, key) {
9294
9707
  init_errors();
9295
9708
  import { spawn as spawn5 } from "node:child_process";
9296
9709
  import * as fs12 from "node:fs/promises";
9297
- import * as path21 from "node:path";
9298
-
9299
- // src/skills/frontmatter.ts
9300
- var SCALAR_KEYS = /* @__PURE__ */ new Set(["name", "description", "version", "license", "compatibility"]);
9301
- function parseSkillFrontmatter(raw) {
9302
- const text = normalizeLineEndings(raw);
9303
- if (!text.startsWith("---")) return {};
9304
- const end = text.indexOf("\n---", 4);
9305
- if (end === -1) return {};
9306
- return parseFrontmatterBlock(text.slice(4, end));
9307
- }
9308
- function normalizeLineEndings(s) {
9309
- return s.replace(/\r\n?/g, "\n");
9310
- }
9311
- function parseFrontmatterBlock(block) {
9312
- const out = {};
9313
- const lines = block.split("\n");
9314
- let i = 0;
9315
- while (i < lines.length) {
9316
- const line = lines[i] ?? "";
9317
- const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
9318
- if (!m) {
9319
- i++;
9320
- continue;
9321
- }
9322
- const key = m[1] ?? "";
9323
- const rest = (m[2] ?? "").trim();
9324
- if (key === "metadata") {
9325
- const map = {};
9326
- i++;
9327
- while (i < lines.length) {
9328
- const sub = lines[i] ?? "";
9329
- const sm = /^\s+([a-zA-Z0-9_.-]+):\s*(.*)$/.exec(sub);
9330
- if (!sm) break;
9331
- map[sm[1] ?? ""] = unquote2((sm[2] ?? "").trim());
9332
- i++;
9333
- }
9334
- if (Object.keys(map).length > 0) out.metadata = map;
9335
- continue;
9336
- }
9337
- if (rest === "|" || rest === ">") {
9338
- const collected = [];
9339
- i++;
9340
- while (i < lines.length) {
9341
- const sub = lines[i] ?? "";
9342
- if (sub === "" || sub.startsWith(" ") || sub.startsWith(" ")) {
9343
- collected.push(sub.replace(/^\s+/, ""));
9344
- i++;
9345
- } else break;
9346
- }
9347
- out[normalizeKey2(key)] = collected.join("\n").trim();
9348
- continue;
9349
- }
9350
- if (key === "allowed-tools" || key === "allowedTools") {
9351
- out.allowedTools = rest.split(/[\s,]+/).filter(Boolean);
9352
- i++;
9353
- continue;
9354
- }
9355
- if (SCALAR_KEYS.has(key)) {
9356
- out[key] = unquote2(rest);
9357
- i++;
9358
- continue;
9359
- }
9360
- i++;
9361
- }
9362
- return out;
9363
- }
9364
- function normalizeKey2(key) {
9365
- return key === "allowed-tools" ? "allowedTools" : key;
9366
- }
9367
- function unquote2(s) {
9368
- if (s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"))) {
9369
- return s.slice(1, -1);
9370
- }
9371
- return s;
9372
- }
9373
- function isValidSkillNameFormat(name) {
9374
- return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
9375
- }
9376
- function validateSkillName(name, parentDirName) {
9377
- const errors = [];
9378
- if (!name || name.trim().length === 0) {
9379
- errors.push("name is empty");
9380
- return errors;
9381
- }
9382
- if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);
9383
- if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
9384
- errors.push(
9385
- "name must be lowercase letters, digits, and single hyphens only (no leading/trailing/consecutive hyphens)"
9386
- );
9387
- }
9388
- if (parentDirName !== void 0 && name !== parentDirName) {
9389
- errors.push(`name "${name}" must match its parent directory "${parentDirName}"`);
9390
- }
9391
- return errors;
9392
- }
9393
-
9394
- // src/skills/skill-generator.ts
9710
+ import * as path22 from "node:path";
9395
9711
  async function validateSkillNameAvailable(name, loader) {
9396
9712
  const formatViolations = validateSkillName(name);
9397
9713
  const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
@@ -9510,8 +9826,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
9510
9826
  subsystem: "general"
9511
9827
  });
9512
9828
  }
9513
- const skillDir = path21.join(skillsDir, name);
9514
- const skillFile = path21.join(skillDir, "SKILL.md");
9829
+ const skillDir = path22.join(skillsDir, name);
9830
+ const skillFile = path22.join(skillDir, "SKILL.md");
9515
9831
  if (!opts.overwrite) {
9516
9832
  try {
9517
9833
  await fs12.access(skillFile);
@@ -9570,13 +9886,14 @@ function defaultEditor() {
9570
9886
  init_errors();
9571
9887
  init_error();
9572
9888
  import * as fs15 from "node:fs/promises";
9573
- import * as path24 from "node:path";
9889
+ import * as path25 from "node:path";
9574
9890
 
9575
9891
  // src/skills/github-fetcher.ts
9576
9892
  init_errors();
9893
+ import { createWriteStream } from "node:fs";
9577
9894
  import * as fs13 from "node:fs/promises";
9578
9895
  import * as os6 from "node:os";
9579
- import * as path22 from "node:path";
9896
+ import * as path23 from "node:path";
9580
9897
  import { Readable } from "node:stream";
9581
9898
  import { pipeline } from "node:stream/promises";
9582
9899
  import { createGunzip } from "node:zlib";
@@ -9603,6 +9920,46 @@ function parseSkillRef(input) {
9603
9920
  }
9604
9921
  return { owner: expectDefined(parts[0]), repo: expectDefined(parts[1]), ref };
9605
9922
  }
9923
+ async function writeBoundedGzipStream(source, outputPath, maxBytes, maxCompressedBytes = SKILL_LIMITS.MAX_TARBALL_SIZE) {
9924
+ let compressedBytes = 0;
9925
+ let writtenBytes = 0;
9926
+ await pipeline(
9927
+ source,
9928
+ async function* (chunks) {
9929
+ for await (const chunk of chunks) {
9930
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9931
+ compressedBytes += buffer.byteLength;
9932
+ if (compressedBytes > maxCompressedBytes) {
9933
+ throw new WrongStackError({
9934
+ message: `Compressed tarball too large. Max: ${maxCompressedBytes / 1024 / 1024}MB`,
9935
+ code: ERROR_CODES.UNKNOWN,
9936
+ subsystem: "general",
9937
+ context: { compressedBytes, maxBytes: maxCompressedBytes }
9938
+ });
9939
+ }
9940
+ yield buffer;
9941
+ }
9942
+ },
9943
+ createGunzip(),
9944
+ async function* (chunks) {
9945
+ for await (const chunk of chunks) {
9946
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9947
+ writtenBytes += buffer.byteLength;
9948
+ if (writtenBytes > maxBytes) {
9949
+ throw new WrongStackError({
9950
+ message: `Uncompressed tarball too large. Max: ${maxBytes / 1024 / 1024}MB`,
9951
+ code: ERROR_CODES.UNKNOWN,
9952
+ subsystem: "general",
9953
+ context: { uncompressedBytes: writtenBytes, maxBytes }
9954
+ });
9955
+ }
9956
+ yield buffer;
9957
+ }
9958
+ },
9959
+ createWriteStream(outputPath, { flags: "wx" })
9960
+ );
9961
+ return writtenBytes;
9962
+ }
9606
9963
  function resolveGitHubToken(env = process.env) {
9607
9964
  const raw = env["WRONGSTACK_GITHUB_TOKEN"] ?? env["GITHUB_TOKEN"] ?? env["GH_TOKEN"];
9608
9965
  if (!raw) return void 0;
@@ -9678,7 +10035,7 @@ async function downloadGitHubTarball(parsed) {
9678
10035
  }
9679
10036
  });
9680
10037
  }
9681
- const tempDir = await fs13.mkdtemp(path22.join(os6.tmpdir(), "wskill-"));
10038
+ const tempDir = await fs13.mkdtemp(path23.join(os6.tmpdir(), "wskill-"));
9682
10039
  try {
9683
10040
  if (!response.body) {
9684
10041
  throw new WrongStackError({
@@ -9689,15 +10046,14 @@ async function downloadGitHubTarball(parsed) {
9689
10046
  });
9690
10047
  }
9691
10048
  const nodeStream = Readable.fromWeb(response.body);
9692
- const gunzip = createGunzip();
9693
- const chunks = [];
9694
- await pipeline(nodeStream, gunzip, async (source) => {
9695
- for await (const chunk of source) {
9696
- chunks.push(Buffer.from(chunk));
9697
- }
9698
- });
9699
- const tarBuf = Buffer.concat(chunks);
9700
- await extractTar(tarBuf, tempDir);
10049
+ const tarPath = path23.join(tempDir, ".wrongstack-download.tar");
10050
+ await writeBoundedGzipStream(nodeStream, tarPath, SKILL_LIMITS.MAX_UNCOMPRESSED_TARBALL_SIZE);
10051
+ const tarBuf = await fs13.readFile(tarPath);
10052
+ try {
10053
+ await extractTar(tarBuf, tempDir);
10054
+ } finally {
10055
+ await fs13.rm(tarPath, { force: true });
10056
+ }
9701
10057
  return { tempDir };
9702
10058
  } catch (err) {
9703
10059
  await fs13.rm(tempDir, { recursive: true, force: true }).catch(() => {
@@ -9705,6 +10061,44 @@ async function downloadGitHubTarball(parsed) {
9705
10061
  throw err;
9706
10062
  }
9707
10063
  }
10064
+ function readTarSize(buf, start) {
10065
+ const first = buf[start] ?? 0;
10066
+ if ((first & 128) !== 0) {
10067
+ if (first === 255) {
10068
+ throw new Error("tar: negative base-256 size field");
10069
+ }
10070
+ let value = first & 127;
10071
+ for (let i = start + 1; i < start + 12; i++) {
10072
+ value = value * 256 + (buf[i] ?? 0);
10073
+ if (!Number.isSafeInteger(value)) {
10074
+ throw new Error("tar: base-256 size exceeds the safe integer range");
10075
+ }
10076
+ }
10077
+ return value;
10078
+ }
10079
+ const text = readTarString(buf, start, 12).trim();
10080
+ if (text === "") return 0;
10081
+ if (!/^[0-7]+$/.test(text)) {
10082
+ throw new Error(`tar: unparseable size field ${JSON.stringify(text)}`);
10083
+ }
10084
+ const parsed = Number.parseInt(text, 8);
10085
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
10086
+ throw new Error("tar: size field out of range");
10087
+ }
10088
+ return parsed;
10089
+ }
10090
+ function readTarString(buf, start, maxLen) {
10091
+ let end = start;
10092
+ while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
10093
+ end++;
10094
+ }
10095
+ return buf.subarray(start, end).toString("utf8");
10096
+ }
10097
+ function stripTopDir(p) {
10098
+ const idx = p.indexOf("/");
10099
+ if (idx === -1) return "";
10100
+ return p.slice(idx + 1);
10101
+ }
9708
10102
  async function extractTar(buf, destDir) {
9709
10103
  let offset = 0;
9710
10104
  while (offset + 512 <= buf.length) {
@@ -9712,15 +10106,15 @@ async function extractTar(buf, destDir) {
9712
10106
  if (header.every((b) => b === 0)) break;
9713
10107
  const name = readTarString(buf, offset, 100);
9714
10108
  const prefix = readTarString(buf, offset + 345, 155);
9715
- const size = Number.parseInt(readTarString(buf, offset + 124, 12).trim(), 8) || 0;
10109
+ const size = readTarSize(buf, offset + 124);
9716
10110
  const typeflag = buf[offset + 156] ?? 0;
9717
10111
  const fullPath = prefix ? `${prefix}/${name}` : name;
9718
10112
  const relPath = stripTopDir(fullPath);
9719
10113
  if (relPath && relPath !== "." && relPath !== "..") {
9720
- const destPath = path22.join(destDir, relPath);
9721
- const resolvedDest = path22.resolve(destPath);
9722
- const resolvedRoot = path22.resolve(destDir);
9723
- if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path22.sep)) {
10114
+ const destPath = path23.join(destDir, relPath);
10115
+ const resolvedDest = path23.resolve(destPath);
10116
+ const resolvedRoot = path23.resolve(destDir);
10117
+ if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path23.sep)) {
9724
10118
  offset += 512 + Math.ceil(size / 512) * 512;
9725
10119
  continue;
9726
10120
  }
@@ -9730,7 +10124,7 @@ async function extractTar(buf, destDir) {
9730
10124
  }
9731
10125
  }
9732
10126
  if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
9733
- const dir = path22.dirname(destPath);
10127
+ const dir = path23.dirname(destPath);
9734
10128
  await fs13.mkdir(dir, { recursive: true });
9735
10129
  const dataStart = offset + 512;
9736
10130
  const dataEnd = dataStart + size;
@@ -9741,23 +10135,11 @@ async function extractTar(buf, destDir) {
9741
10135
  offset += 512 + Math.ceil(size / 512) * 512;
9742
10136
  }
9743
10137
  }
9744
- function readTarString(buf, start, maxLen) {
9745
- let end = start;
9746
- while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
9747
- end++;
9748
- }
9749
- return buf.subarray(start, end).toString("utf8");
9750
- }
9751
- function stripTopDir(p) {
9752
- const idx = p.indexOf("/");
9753
- if (idx === -1) return "";
9754
- return p.slice(idx + 1);
9755
- }
9756
10138
 
9757
10139
  // src/skills/manifest-store.ts
9758
10140
  init_atomic_write();
9759
10141
  import * as fs14 from "node:fs/promises";
9760
- import * as path23 from "node:path";
10142
+ import * as path24 from "node:path";
9761
10143
  var SkillManifestStore = class {
9762
10144
  manifestPath;
9763
10145
  cache;
@@ -9780,7 +10162,7 @@ var SkillManifestStore = class {
9780
10162
  return this.cache;
9781
10163
  }
9782
10164
  async write(data) {
9783
- const dir = path23.dirname(this.manifestPath);
10165
+ const dir = path24.dirname(this.manifestPath);
9784
10166
  await fs14.mkdir(dir, { recursive: true });
9785
10167
  await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
9786
10168
  this.cache = data;
@@ -9818,6 +10200,10 @@ var SkillManifestStore = class {
9818
10200
  };
9819
10201
 
9820
10202
  // src/skills/skill-installer.ts
10203
+ function isInside(resolved, destDir) {
10204
+ const root = path25.resolve(destDir);
10205
+ return resolved === root || resolved.startsWith(root + path25.sep);
10206
+ }
9821
10207
  var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
9822
10208
  var SkillInstaller = class {
9823
10209
  opts;
@@ -9871,14 +10257,14 @@ var SkillInstaller = class {
9871
10257
  this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
9872
10258
  await this.removeSkillFiles(skill.name, scope);
9873
10259
  }
9874
- const destDir = path24.join(targetDir, skill.name);
10260
+ const destDir = path25.join(targetDir, skill.name);
9875
10261
  await fs15.mkdir(destDir, { recursive: true });
9876
10262
  const copiedFiles = [];
9877
10263
  for (const file of skill.files) {
9878
- const srcPath = path24.join(skill.baseDir, file);
9879
- const destPath = path24.join(destDir, file);
9880
- const resolved2 = path24.resolve(destPath);
9881
- if (!resolved2.startsWith(path24.resolve(destDir))) {
10264
+ const srcPath = path25.join(skill.baseDir, file);
10265
+ const destPath = path25.join(destDir, file);
10266
+ const resolved2 = path25.resolve(destPath);
10267
+ if (!isInside(resolved2, destDir)) {
9882
10268
  throw new FsError({
9883
10269
  message: `Path traversal detected in skill file: ${file}`,
9884
10270
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -9886,16 +10272,16 @@ var SkillInstaller = class {
9886
10272
  context: { reason: "path_traversal", skillName: skill.name }
9887
10273
  });
9888
10274
  }
9889
- const stat6 = await fs15.stat(srcPath);
9890
- if (stat6.size > MAX_SKILL_FILE_SIZE) {
10275
+ const stat7 = await fs15.stat(srcPath);
10276
+ if (stat7.size > MAX_SKILL_FILE_SIZE) {
9891
10277
  throw new FsError({
9892
- message: `Skill file "${file}" is too large (${(stat6.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
10278
+ message: `Skill file "${file}" is too large (${(stat7.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
9893
10279
  code: ERROR_CODES.FS_WRITE_FAILED,
9894
10280
  path: srcPath,
9895
- context: { skillName: skill.name, fileSize: stat6.size, maxSize: MAX_SKILL_FILE_SIZE }
10281
+ context: { skillName: skill.name, fileSize: stat7.size, maxSize: MAX_SKILL_FILE_SIZE }
9896
10282
  });
9897
10283
  }
9898
- await fs15.mkdir(path24.dirname(destPath), { recursive: true });
10284
+ await fs15.mkdir(path25.dirname(destPath), { recursive: true });
9899
10285
  await fs15.copyFile(srcPath, destPath);
9900
10286
  copiedFiles.push(file);
9901
10287
  }
@@ -9953,7 +10339,7 @@ var SkillInstaller = class {
9953
10339
  const results = [];
9954
10340
  for (const e of entries) {
9955
10341
  if (!await entryIsDirectory(srcDir, e)) continue;
9956
- const skillMdPath = path24.join(srcDir, e.name, "SKILL.md");
10342
+ const skillMdPath = path25.join(srcDir, e.name, "SKILL.md");
9957
10343
  let content;
9958
10344
  try {
9959
10345
  content = await fs15.readFile(skillMdPath, "utf8");
@@ -9966,16 +10352,16 @@ var SkillInstaller = class {
9966
10352
  if (existing.find((x) => x.scope === scope)) {
9967
10353
  await this.removeSkillFiles(fm.name, scope);
9968
10354
  }
9969
- const destDir = path24.join(targetDir, fm.name);
10355
+ const destDir = path25.join(targetDir, fm.name);
9970
10356
  await fs15.mkdir(destDir, { recursive: true });
9971
- const srcSkillDir = path24.join(srcDir, e.name);
10357
+ const srcSkillDir = path25.join(srcDir, e.name);
9972
10358
  const files = await collectFiles(srcSkillDir, srcSkillDir);
9973
10359
  const copiedFiles = [];
9974
10360
  for (const file of files) {
9975
- const srcPath = path24.join(srcSkillDir, file);
9976
- const destPath = path24.join(destDir, file);
9977
- const resolved = path24.resolve(destPath);
9978
- if (!resolved.startsWith(path24.resolve(destDir))) {
10361
+ const srcPath = path25.join(srcSkillDir, file);
10362
+ const destPath = path25.join(destDir, file);
10363
+ const resolved = path25.resolve(destPath);
10364
+ if (!isInside(resolved, destDir)) {
9979
10365
  throw new FsError({
9980
10366
  message: `Path traversal detected in skill file: ${file}`,
9981
10367
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -9983,7 +10369,7 @@ var SkillInstaller = class {
9983
10369
  context: { reason: "path_traversal", skillName: fm.name }
9984
10370
  });
9985
10371
  }
9986
- await fs15.mkdir(path24.dirname(destPath), { recursive: true });
10372
+ await fs15.mkdir(path25.dirname(destPath), { recursive: true });
9987
10373
  if (opts?.link) {
9988
10374
  try {
9989
10375
  await fs15.symlink(srcPath, destPath);
@@ -10146,7 +10532,7 @@ var SkillInstaller = class {
10146
10532
  */
10147
10533
  async detectSkills(baseDir) {
10148
10534
  const results = [];
10149
- const rootSkillMd = path24.join(baseDir, "SKILL.md");
10535
+ const rootSkillMd = path25.join(baseDir, "SKILL.md");
10150
10536
  try {
10151
10537
  await fs15.access(rootSkillMd);
10152
10538
  const content = await fs15.readFile(rootSkillMd, "utf8");
@@ -10161,17 +10547,17 @@ var SkillInstaller = class {
10161
10547
  }
10162
10548
  } catch {
10163
10549
  }
10164
- const skillsDir = path24.join(baseDir, "skills");
10550
+ const skillsDir = path25.join(baseDir, "skills");
10165
10551
  try {
10166
10552
  const entries = await fs15.readdir(skillsDir, { withFileTypes: true });
10167
10553
  for (const entry of entries) {
10168
10554
  if (!entry.isDirectory()) continue;
10169
- const skillFile = path24.join(skillsDir, entry.name, "SKILL.md");
10555
+ const skillFile = path25.join(skillsDir, entry.name, "SKILL.md");
10170
10556
  try {
10171
10557
  const content = await fs15.readFile(skillFile, "utf8");
10172
10558
  const fm = parseSkillFrontmatter(content);
10173
10559
  if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
10174
- const skillDir = path24.join(skillsDir, entry.name);
10560
+ const skillDir = path25.join(skillsDir, entry.name);
10175
10561
  const files = await collectFiles(skillDir, skillDir);
10176
10562
  results.push({
10177
10563
  name: fm.name,
@@ -10189,9 +10575,31 @@ var SkillInstaller = class {
10189
10575
  /**
10190
10576
  * Remove all files for an installed skill.
10191
10577
  */
10578
+ /**
10579
+ * Delete an installed skill's directory.
10580
+ *
10581
+ * The containment check is not ceremonial: this is a `recursive: true,
10582
+ * force: true` delete whose target is built from a skill NAME taken from
10583
+ * manifest frontmatter. `path.join` normalises `..`, so a crafted name
10584
+ * escapes `targetDir` and takes the recursive delete with it. This file
10585
+ * already had `isInside` and applied it on the copy path but not here.
10586
+ *
10587
+ * The strict-subdirectory requirement matters separately: `isInside` allows
10588
+ * equality by design, and an empty or `.` name resolves `skillDir` to
10589
+ * `targetDir` itself — deleting every installed skill (WS-097).
10590
+ */
10192
10591
  async removeSkillFiles(name, scope) {
10193
10592
  const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
10194
- const skillDir = path24.join(targetDir, name);
10593
+ const root = path25.resolve(targetDir);
10594
+ const skillDir = path25.resolve(path25.join(targetDir, name));
10595
+ if (skillDir === root || !isInside(skillDir, root)) {
10596
+ throw new FsError({
10597
+ message: `Refusing to delete skill files outside the skills directory: ${name}`,
10598
+ code: ERROR_CODES.FS_DELETE_FAILED,
10599
+ path: skillDir,
10600
+ context: { reason: "path_traversal", skillName: name, scope }
10601
+ });
10602
+ }
10195
10603
  await fs15.rm(skillDir, { recursive: true, force: true });
10196
10604
  }
10197
10605
  /**
@@ -10227,7 +10635,7 @@ async function entryIsDirectory(dir, entry) {
10227
10635
  if (entry.isDirectory()) return true;
10228
10636
  if (entry.isSymbolicLink()) {
10229
10637
  try {
10230
- return (await fs15.stat(path24.join(dir, entry.name))).isDirectory();
10638
+ return (await fs15.stat(path25.join(dir, entry.name))).isDirectory();
10231
10639
  } catch {
10232
10640
  return false;
10233
10641
  }
@@ -10238,8 +10646,8 @@ async function collectFiles(dir, baseDir) {
10238
10646
  const results = [];
10239
10647
  const entries = await fs15.readdir(dir, { withFileTypes: true });
10240
10648
  for (const entry of entries) {
10241
- const fullPath = path24.join(dir, entry.name);
10242
- const relPath = path24.relative(baseDir, fullPath);
10649
+ const fullPath = path25.join(dir, entry.name);
10650
+ const relPath = path25.relative(baseDir, fullPath);
10243
10651
  if (entry.isDirectory()) {
10244
10652
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
10245
10653
  results.push(...await collectFiles(fullPath, baseDir));
@@ -10318,7 +10726,7 @@ function createSkillsPlugin(opts) {
10318
10726
  function makeInstaller(skillLoader, projectRoot, registryAdapters) {
10319
10727
  const paths = resolveWstackPaths({ projectRoot });
10320
10728
  return new SkillInstaller({
10321
- manifestPath: path25.join(paths.configDir, "installed-skills.json"),
10729
+ manifestPath: path26.join(paths.configDir, "installed-skills.json"),
10322
10730
  projectSkillsDir: paths.inProjectSkills,
10323
10731
  globalSkillsDir: paths.globalSkills,
10324
10732
  projectHash: paths.projectHash,
@@ -10346,7 +10754,8 @@ ${lines.join("\n\n")}
10346
10754
  }
10347
10755
  const skill = await skillLoader.find(args.trim());
10348
10756
  if (!skill) return { message: `Skill "${args.trim()}" not found.` };
10349
- return { message: await skillLoader.readBody(skill.name) };
10757
+ const body = capSkillBody(stripFrontmatter(await skillLoader.readBody(skill.name)));
10758
+ return { message: body };
10350
10759
  }
10351
10760
  };
10352
10761
  }
@@ -10385,9 +10794,32 @@ function buildSkillGeneratorCommand(skillLoader) {
10385
10794
  return ` ${src} ${e.name}
10386
10795
  ${e.trigger}`;
10387
10796
  });
10388
- return { message: `Available Skills:
10797
+ let message = `Available Skills:
10389
10798
  ${lines.join("\n\n")}
10390
- ` };
10799
+ `;
10800
+ const diag = skillLoader.diagnostics?.();
10801
+ if (diag && (diag.shadowed.length > 0 || diag.skipped.length > 0)) {
10802
+ const notes = [];
10803
+ if (diag.shadowed.length > 0) {
10804
+ notes.push(color.dim("Shadowed (hidden by a higher-priority layer):"));
10805
+ for (const s of diag.shadowed) {
10806
+ notes.push(
10807
+ color.dim(` \u26A0 ${s.name} (${s.source}) \u2190 overridden by ${s.shadowedBy}`)
10808
+ );
10809
+ }
10810
+ }
10811
+ if (diag.skipped.length > 0) {
10812
+ notes.push(color.dim("Skipped (malformed SKILL.md):"));
10813
+ for (const k of diag.skipped) {
10814
+ const name = k.name ? ` "${k.name}"` : "";
10815
+ notes.push(color.dim(` \u2717 ${k.entry}${name} \u2014 ${k.reason}`));
10816
+ }
10817
+ }
10818
+ message += `
10819
+ ${notes.join("\n")}
10820
+ `;
10821
+ }
10822
+ return { message };
10391
10823
  }
10392
10824
  if (sub === "validate") {
10393
10825
  const name = rest[0];
@@ -10444,7 +10876,10 @@ ${lines.join("\n\n")}
10444
10876
  if (!skill) return { message: `Skill "${skillName}" not found.` };
10445
10877
  try {
10446
10878
  await openInEditor(skill.path);
10447
- return { message: `Opening ${skill.path} in your editor\u2026` };
10879
+ skillLoader.invalidateCache();
10880
+ return {
10881
+ message: `Opening ${skill.path} in your editor\u2026 (skill cache cleared \u2014 changes load on next use)`
10882
+ };
10448
10883
  } catch (err) {
10449
10884
  return { message: `\u2717 ${toErrorMessage(err)}` };
10450
10885
  }
@@ -10670,7 +11105,7 @@ function resolveImportSourceDir(tool, opts) {
10670
11105
  const entry = IMPORT_SOURCE_TOOLS.find((t) => t.id === tool);
10671
11106
  if (!entry) return void 0;
10672
11107
  const base = opts.global ? opts.homeDir ?? os7.homedir() : opts.projectRoot;
10673
- return path25.join(base, "." + entry.id, entry.subdir);
11108
+ return path26.join(base, "." + entry.id, entry.subdir);
10674
11109
  }
10675
11110
  function buildSkillImportCommand(skillLoader) {
10676
11111
  return {
@@ -10711,7 +11146,7 @@ function buildSkillImportCommand(skillLoader) {
10711
11146
  };
10712
11147
  }
10713
11148
  } else if (positional) {
10714
- srcDir = path25.resolve(ctx.projectRoot, positional);
11149
+ srcDir = path26.resolve(ctx.projectRoot, positional);
10715
11150
  } else {
10716
11151
  return {
10717
11152
  message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
@@ -10838,14 +11273,14 @@ function truncate(s, max) {
10838
11273
  }
10839
11274
 
10840
11275
  // src/plugins/sync-plugin.ts
10841
- import * as path27 from "node:path";
11276
+ import * as path28 from "node:path";
10842
11277
  init_error();
10843
11278
 
10844
11279
  // src/storage/cloud-sync.ts
10845
11280
  init_atomic_write();
10846
11281
  init_errors();
10847
11282
  import * as fs16 from "node:fs/promises";
10848
- import * as path26 from "node:path";
11283
+ import * as path27 from "node:path";
10849
11284
  import { createHash as createHash9 } from "node:crypto";
10850
11285
  var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
10851
11286
  var CloudSync = class {
@@ -10853,8 +11288,8 @@ var CloudSync = class {
10853
11288
  this.paths = paths;
10854
11289
  this.getConfig = getConfig;
10855
11290
  this.setConfig = setConfig;
10856
- this.statePath = path26.join(paths.configDir, "sync-state.json");
10857
- this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path26.join(this.paths.configDir, "config.json"));
11291
+ this.statePath = path27.join(paths.configDir, "sync-state.json");
11292
+ this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path27.join(this.paths.configDir, "config.json"));
10858
11293
  }
10859
11294
  paths;
10860
11295
  getConfig;
@@ -11134,13 +11569,13 @@ var CloudSync = class {
11134
11569
  const localPath = this.categoryToPath(cat);
11135
11570
  if (!localPath) continue;
11136
11571
  try {
11137
- const stat6 = await fs16.lstat(localPath);
11138
- if (stat6.isSymbolicLink()) continue;
11139
- if (stat6.isDirectory()) {
11572
+ const stat7 = await fs16.lstat(localPath);
11573
+ if (stat7.isSymbolicLink()) continue;
11574
+ if (stat7.isDirectory()) {
11140
11575
  const files = await this.walkDir(localPath, localPath);
11141
11576
  for (const file of files) {
11142
11577
  const content = await fs16.readFile(file, "utf8");
11143
- const rel = path26.relative(localPath, file).replace(/\\/g, "/");
11578
+ const rel = path27.relative(localPath, file).replace(/\\/g, "/");
11144
11579
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
11145
11580
  hashes.push(`${cat}/${rel}\0${content}`);
11146
11581
  }
@@ -11161,13 +11596,13 @@ var CloudSync = class {
11161
11596
  const localPath = this.categoryToPath(cat);
11162
11597
  if (!localPath) continue;
11163
11598
  try {
11164
- const stat6 = await fs16.lstat(localPath);
11165
- if (stat6.isSymbolicLink()) continue;
11166
- if (stat6.isDirectory()) {
11599
+ const stat7 = await fs16.lstat(localPath);
11600
+ if (stat7.isSymbolicLink()) continue;
11601
+ if (stat7.isDirectory()) {
11167
11602
  const files = await this.walkDir(localPath, localPath);
11168
11603
  for (const file of files) {
11169
11604
  const content = await fs16.readFile(file, "utf8");
11170
- const rel = path26.relative(localPath, file).replace(/\\/g, "/");
11605
+ const rel = path27.relative(localPath, file).replace(/\\/g, "/");
11171
11606
  hashes.push(`${cat}/${rel}\0${content}`);
11172
11607
  }
11173
11608
  } else {
@@ -11201,7 +11636,7 @@ var CloudSync = class {
11201
11636
  const entries = await fs16.readdir(dir, { withFileTypes: true });
11202
11637
  entries.sort((a, b) => a.name.localeCompare(b.name));
11203
11638
  for (const entry of entries) {
11204
- const full = path26.join(dir, entry.name);
11639
+ const full = path27.join(dir, entry.name);
11205
11640
  if (entry.isSymbolicLink()) continue;
11206
11641
  if (entry.isDirectory()) {
11207
11642
  results.push(...await this.walkDir(full, base));
@@ -11214,25 +11649,25 @@ var CloudSync = class {
11214
11649
  };
11215
11650
  async function preparePulledDestination(cat, localPath, destPath, remotePath) {
11216
11651
  const directoryBacked = cat === "skills" || cat === "prompts";
11217
- const rootPath = directoryBacked ? localPath : path26.dirname(localPath);
11652
+ const rootPath = directoryBacked ? localPath : path27.dirname(localPath);
11218
11653
  const rootStat = await lstatIfExists(rootPath);
11219
11654
  if (rootStat?.isSymbolicLink()) {
11220
11655
  throw unsafePulledSymlinkError(remotePath, rootPath);
11221
11656
  }
11222
11657
  if (directoryBacked) {
11223
- const relativeParent = path26.relative(rootPath, path26.dirname(destPath));
11658
+ const relativeParent = path27.relative(rootPath, path27.dirname(destPath));
11224
11659
  let cursor = rootPath;
11225
11660
  if (relativeParent) {
11226
- for (const segment of relativeParent.split(path26.sep)) {
11227
- cursor = path26.join(cursor, segment);
11228
- const stat6 = await lstatIfExists(cursor);
11229
- if (stat6?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
11661
+ for (const segment of relativeParent.split(path27.sep)) {
11662
+ cursor = path27.join(cursor, segment);
11663
+ const stat7 = await lstatIfExists(cursor);
11664
+ if (stat7?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
11230
11665
  }
11231
11666
  }
11232
11667
  }
11233
11668
  const destStat = await lstatIfExists(destPath);
11234
11669
  if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
11235
- await fs16.mkdir(path26.dirname(destPath), { recursive: true });
11670
+ await fs16.mkdir(path27.dirname(destPath), { recursive: true });
11236
11671
  }
11237
11672
  async function lstatIfExists(filePath) {
11238
11673
  try {
@@ -11262,9 +11697,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
11262
11697
  return localPath;
11263
11698
  }
11264
11699
  if (!rel) return localPath;
11265
- const normalizedRel = path26.normalize(rel);
11266
- const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path26.sep}`);
11267
- if (path26.isAbsolute(normalizedRel) || traversesUp) {
11700
+ const normalizedRel = path27.normalize(rel);
11701
+ const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path27.sep}`);
11702
+ if (path27.isAbsolute(normalizedRel) || traversesUp) {
11268
11703
  throw new FsError({
11269
11704
  message: `Refusing CloudSync path traversal: ${remotePath}`,
11270
11705
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -11272,10 +11707,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
11272
11707
  context: { reason: "path_traversal", normalizedRel }
11273
11708
  });
11274
11709
  }
11275
- const dest = path26.resolve(localPath, normalizedRel);
11276
- const root = path26.resolve(localPath);
11277
- const relative5 = path26.relative(root, dest);
11278
- if (relative5.startsWith("..") || path26.isAbsolute(relative5)) {
11710
+ const dest = path27.resolve(localPath, normalizedRel);
11711
+ const root = path27.resolve(localPath);
11712
+ const relative5 = path27.relative(root, dest);
11713
+ if (relative5.startsWith("..") || path27.isAbsolute(relative5)) {
11279
11714
  throw new FsError({
11280
11715
  message: `Refusing CloudSync path outside category root: ${remotePath}`,
11281
11716
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -11318,7 +11753,7 @@ function createSyncPlugin(opts) {
11318
11753
  api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
11319
11754
  return;
11320
11755
  }
11321
- const syncConfigPath = paths.syncConfig ?? path27.join(paths.configDir, "sync.json");
11756
+ const syncConfigPath = paths.syncConfig ?? path28.join(paths.configDir, "sync.json");
11322
11757
  cloud = new CloudSync(
11323
11758
  paths,
11324
11759
  () => {
@@ -11329,7 +11764,7 @@ function createSyncPlugin(opts) {
11329
11764
  await persistSyncConfig(syncConfigPath, cfg, vault);
11330
11765
  configStore?.update({ sync: cfg });
11331
11766
  },
11332
- () => path27.join(paths.configDir, "config.json")
11767
+ () => path28.join(paths.configDir, "config.json")
11333
11768
  );
11334
11769
  void cloud.loadState();
11335
11770
  api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
@@ -11532,8 +11967,14 @@ export {
11532
11967
  definePlugin,
11533
11968
  diffPluginConfig,
11534
11969
  emitReviewIfChanged,
11970
+ integrateFindings,
11535
11971
  loadPlugins,
11972
+ maybeCompactReviewStores,
11973
+ parseChimeraReviewReport,
11536
11974
  parseReviewSeverity,
11975
+ persistReviewReport,
11976
+ recordCompletedReview,
11977
+ recordStartedReview,
11537
11978
  redactPluginConfig,
11538
11979
  resolvePluginConfig,
11539
11980
  resolvePluginManifestConfig,