@wrongstack/core 0.297.0 → 0.298.1

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 (806) 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 +2191 -1208
  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 +9012 -6916
  49. package/dist/infrastructure/index.js +199 -102
  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 +988 -558
  57. package/dist/plugins/auto-review-plugin.d.ts +1 -11
  58. package/dist/plugins/review-store-maintenance.d.ts +26 -0
  59. package/dist/plugins/review-types.d.ts +6 -0
  60. package/dist/security/auto-approve-policy.d.ts +37 -0
  61. package/dist/security/capabilities.d.ts +45 -1
  62. package/dist/security/error-sanitize.d.ts +49 -0
  63. package/dist/security/file-permissions.d.ts +41 -0
  64. package/dist/security/index.d.ts +9 -6
  65. package/dist/security/index.js +3008 -2029
  66. package/dist/security/permission-helpers.d.ts +93 -0
  67. package/dist/security/permission-policy.d.ts +37 -35
  68. package/dist/security/secret-vault.d.ts +17 -0
  69. package/dist/security/totp.d.ts +86 -0
  70. package/dist/skills/frontmatter.d.ts +12 -1
  71. package/dist/skills/github-fetcher.d.ts +48 -0
  72. package/dist/skills/index.js +137 -26
  73. package/dist/skills/limits.d.ts +19 -0
  74. package/dist/skills/skill-installer.d.ts +13 -0
  75. package/dist/storage/index.js +929 -733
  76. package/dist/storage/provider-config-watcher.d.ts +1 -0
  77. package/dist/storage/session-helpers.d.ts +1 -0
  78. package/dist/storage/session-store.d.ts +9 -2
  79. package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
  80. package/dist/tools/fallback-manage-tools.d.ts +6 -0
  81. package/dist/tools/index.js +287 -131
  82. package/dist/tools/mcp-use.d.ts +1 -1
  83. package/dist/types/blocks.d.ts +7 -0
  84. package/dist/types/config/autonomy.d.ts +15 -7
  85. package/dist/types/config/mcp-features.d.ts +9 -1
  86. package/dist/types/config/root.d.ts +10 -4
  87. package/dist/types/context-window.d.ts +15 -0
  88. package/dist/types/index.d.ts +1 -1
  89. package/dist/types/secret-vault.d.ts +8 -0
  90. package/dist/types/session.d.ts +2 -0
  91. package/dist/types/skill.d.ts +56 -0
  92. package/dist/types/tool-executor.d.ts +2 -0
  93. package/dist/utils/env-typed.d.ts +64 -0
  94. package/dist/utils/glob-match.d.ts +21 -1
  95. package/dist/utils/heap-watchdog.js +1 -1
  96. package/dist/utils/incoming-images.d.ts +19 -0
  97. package/dist/utils/index.d.ts +16 -12
  98. package/dist/utils/index.js +3128 -2800
  99. package/dist/utils/path-segment.d.ts +29 -0
  100. package/dist/utils/sage-output-block.js +48 -0
  101. package/dist/utils/win32-cmd.d.ts +25 -0
  102. package/dist/worktree/index.js +5 -0
  103. package/instructions/llm/chimera-review.md +4 -6
  104. package/package.json +13 -4
  105. package/skills/auto-review/SKILL.md +11 -76
  106. package/skills/chimera/SKILL.md +31 -49
  107. package/skills/data-governance/SKILL.md +92 -0
  108. package/skills/wrongstack-kanban/SKILL.md +125 -64
  109. package/dist/agent-status-helpers.d.ts.map +0 -1
  110. package/dist/agent-status-tracker.d.ts.map +0 -1
  111. package/dist/boot.d.ts.map +0 -1
  112. package/dist/chronicle/context.d.ts.map +0 -1
  113. package/dist/chronicle/decision-adapter.d.ts.map +0 -1
  114. package/dist/chronicle/domain-adapter.d.ts.map +0 -1
  115. package/dist/chronicle/event-hash.d.ts.map +0 -1
  116. package/dist/chronicle/file-observer.d.ts.map +0 -1
  117. package/dist/chronicle/health-monitor.d.ts.map +0 -1
  118. package/dist/chronicle/identity.d.ts.map +0 -1
  119. package/dist/chronicle/index.d.ts.map +0 -1
  120. package/dist/chronicle/index.js.map +0 -7
  121. package/dist/chronicle/journal.d.ts.map +0 -1
  122. package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
  123. package/dist/chronicle/metrics-store.d.ts.map +0 -1
  124. package/dist/chronicle/partition-filename.d.ts.map +0 -1
  125. package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
  126. package/dist/chronicle/process-adapter.d.ts.map +0 -1
  127. package/dist/chronicle/project-access.d.ts.map +0 -1
  128. package/dist/chronicle/project-server-client.d.ts.map +0 -1
  129. package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
  130. package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
  131. package/dist/chronicle/project-server.d.ts.map +0 -1
  132. package/dist/chronicle/project-server.js.map +0 -7
  133. package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
  134. package/dist/chronicle/provider-adapter.d.ts.map +0 -1
  135. package/dist/chronicle/query.d.ts.map +0 -1
  136. package/dist/chronicle/review-adapter.d.ts.map +0 -1
  137. package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
  138. package/dist/chronicle/sink.d.ts.map +0 -1
  139. package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
  140. package/dist/chronicle/sqlite-query.d.ts.map +0 -1
  141. package/dist/chronicle/stream-adapter.d.ts.map +0 -1
  142. package/dist/chronicle/tool-adapter.d.ts.map +0 -1
  143. package/dist/chronicle/types.d.ts.map +0 -1
  144. package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
  145. package/dist/coordination/agent-bridge.d.ts.map +0 -1
  146. package/dist/coordination/agent-monitor.d.ts.map +0 -1
  147. package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
  148. package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
  149. package/dist/coordination/agents/index.d.ts.map +0 -1
  150. package/dist/coordination/agents/index.js.map +0 -7
  151. package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
  152. package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
  153. package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
  154. package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
  155. package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
  156. package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
  157. package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
  158. package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
  159. package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
  160. package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
  161. package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
  162. package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
  163. package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
  164. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
  165. package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
  166. package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
  167. package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
  168. package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
  169. package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
  170. package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
  171. package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
  172. package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
  173. package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
  174. package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
  175. package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
  176. package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
  177. package/dist/coordination/agents/role-skills.d.ts.map +0 -1
  178. package/dist/coordination/agents/types.d.ts.map +0 -1
  179. package/dist/coordination/agents.d.ts.map +0 -1
  180. package/dist/coordination/auto-extend.d.ts.map +0 -1
  181. package/dist/coordination/autonomous-brain.d.ts.map +0 -1
  182. package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
  183. package/dist/coordination/brain-cache.d.ts.map +0 -1
  184. package/dist/coordination/brain-heuristics.d.ts.map +0 -1
  185. package/dist/coordination/brain-ledger.d.ts.map +0 -1
  186. package/dist/coordination/brain-monitor.d.ts.map +0 -1
  187. package/dist/coordination/brain-rules.d.ts.map +0 -1
  188. package/dist/coordination/brain-telemetry.d.ts.map +0 -1
  189. package/dist/coordination/brain-trace.d.ts.map +0 -1
  190. package/dist/coordination/brain.d.ts.map +0 -1
  191. package/dist/coordination/change-manager.d.ts.map +0 -1
  192. package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
  193. package/dist/coordination/collab-bus.d.ts.map +0 -1
  194. package/dist/coordination/collab-debug-types.d.ts.map +0 -1
  195. package/dist/coordination/collab-debug.d.ts.map +0 -1
  196. package/dist/coordination/collab-director-host.d.ts.map +0 -1
  197. package/dist/coordination/commit-safety.d.ts.map +0 -1
  198. package/dist/coordination/consensus-protocol.d.ts.map +0 -1
  199. package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
  200. package/dist/coordination/delegate-tool.d.ts.map +0 -1
  201. package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
  202. package/dist/coordination/dep-watcher.d.ts.map +0 -1
  203. package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
  204. package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
  205. package/dist/coordination/director/director-collab.d.ts.map +0 -1
  206. package/dist/coordination/director/director-errors.d.ts.map +0 -1
  207. package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
  208. package/dist/coordination/director/director-toolset.d.ts.map +0 -1
  209. package/dist/coordination/director-basic-tools.d.ts.map +0 -1
  210. package/dist/coordination/director-collab-tools.d.ts.map +0 -1
  211. package/dist/coordination/director-host-contracts.d.ts.map +0 -1
  212. package/dist/coordination/director-input-helpers.d.ts.map +0 -1
  213. package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
  214. package/dist/coordination/director-options.d.ts.map +0 -1
  215. package/dist/coordination/director-prompts.d.ts.map +0 -1
  216. package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
  217. package/dist/coordination/director-session.d.ts.map +0 -1
  218. package/dist/coordination/director-spawn-model.d.ts.map +0 -1
  219. package/dist/coordination/director-tools.d.ts.map +0 -1
  220. package/dist/coordination/director.d.ts.map +0 -1
  221. package/dist/coordination/dispatcher.d.ts.map +0 -1
  222. package/dist/coordination/file-author-tracker.d.ts.map +0 -1
  223. package/dist/coordination/fleet-bus.d.ts.map +0 -1
  224. package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
  225. package/dist/coordination/fleet-manager.d.ts.map +0 -1
  226. package/dist/coordination/fleet-spawn.d.ts.map +0 -1
  227. package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
  228. package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
  229. package/dist/coordination/fleet.d.ts.map +0 -1
  230. package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
  231. package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
  232. package/dist/coordination/icoordinator.d.ts.map +0 -1
  233. package/dist/coordination/ifleet-manager.d.ts.map +0 -1
  234. package/dist/coordination/in-memory-transport.d.ts.map +0 -1
  235. package/dist/coordination/index.d.ts.map +0 -1
  236. package/dist/coordination/index.js.map +0 -7
  237. package/dist/coordination/knowledge-graph.d.ts.map +0 -1
  238. package/dist/coordination/large-answer-store.d.ts.map +0 -1
  239. package/dist/coordination/mail-tools.d.ts.map +0 -1
  240. package/dist/coordination/mailbox-actions.d.ts.map +0 -1
  241. package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
  242. package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
  243. package/dist/coordination/mailbox-constants.d.ts.map +0 -1
  244. package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
  245. package/dist/coordination/mailbox-events.d.ts.map +0 -1
  246. package/dist/coordination/mailbox-health.d.ts.map +0 -1
  247. package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
  248. package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
  249. package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
  250. package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
  251. package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
  252. package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
  253. package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
  254. package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
  255. package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
  256. package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
  257. package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
  258. package/dist/coordination/mailbox-project-server.js.map +0 -7
  259. package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
  260. package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
  261. package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
  262. package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
  263. package/dist/coordination/mailbox-tool.d.ts.map +0 -1
  264. package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
  265. package/dist/coordination/mailbox-types.d.ts.map +0 -1
  266. package/dist/coordination/model-matrix.d.ts.map +0 -1
  267. package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
  268. package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
  269. package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
  270. package/dist/coordination/package-author-tracker.d.ts.map +0 -1
  271. package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
  272. package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
  273. package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
  274. package/dist/coordination/remote-mailbox.d.ts.map +0 -1
  275. package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
  276. package/dist/coordination/spawn-budget.d.ts.map +0 -1
  277. package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
  278. package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
  279. package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
  280. package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
  281. package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
  282. package/dist/coordination/subagent-budget.d.ts.map +0 -1
  283. package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
  284. package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
  285. package/dist/coordination/task-auctioneer.d.ts.map +0 -1
  286. package/dist/coordination/task-dag.d.ts.map +0 -1
  287. package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
  288. package/dist/coordination/transport.d.ts.map +0 -1
  289. package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
  290. package/dist/core/agent-internals.d.ts.map +0 -1
  291. package/dist/core/agent-loop.d.ts.map +0 -1
  292. package/dist/core/agent-response.d.ts.map +0 -1
  293. package/dist/core/agent-tools.d.ts.map +0 -1
  294. package/dist/core/agent-types.d.ts.map +0 -1
  295. package/dist/core/agent.d.ts.map +0 -1
  296. package/dist/core/btw.d.ts.map +0 -1
  297. package/dist/core/context.d.ts.map +0 -1
  298. package/dist/core/continue-intent.d.ts.map +0 -1
  299. package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
  300. package/dist/core/conversation-state.d.ts.map +0 -1
  301. package/dist/core/fallback-model.d.ts.map +0 -1
  302. package/dist/core/fallback-profile-manager.d.ts.map +0 -1
  303. package/dist/core/fleet-pulse.d.ts.map +0 -1
  304. package/dist/core/index.d.ts.map +0 -1
  305. package/dist/core/index.js.map +0 -7
  306. package/dist/core/input-builder.d.ts.map +0 -1
  307. package/dist/core/instruction-bundle.d.ts.map +0 -1
  308. package/dist/core/iteration-limit.d.ts.map +0 -1
  309. package/dist/core/mailbox-loop.d.ts.map +0 -1
  310. package/dist/core/model-availability-calendar.d.ts.map +0 -1
  311. package/dist/core/model-ref.d.ts.map +0 -1
  312. package/dist/core/model-ref.js.map +0 -7
  313. package/dist/core/modes/brief.d.ts.map +0 -1
  314. package/dist/core/modes/default.d.ts.map +0 -1
  315. package/dist/core/modes/teach.d.ts.map +0 -1
  316. package/dist/core/provider-runner.d.ts.map +0 -1
  317. package/dist/core/queued-messages.d.ts.map +0 -1
  318. package/dist/core/request-provider-binding.d.ts.map +0 -1
  319. package/dist/core/run-env.d.ts.map +0 -1
  320. package/dist/core/streaming-response-builder.d.ts.map +0 -1
  321. package/dist/core/system-prompt-blocks.d.ts.map +0 -1
  322. package/dist/core/system-prompt-builder.d.ts.map +0 -1
  323. package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
  324. package/dist/core/system-prompt-environment.d.ts.map +0 -1
  325. package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
  326. package/dist/core/system-prompt-plan.d.ts.map +0 -1
  327. package/dist/core/system-prompt-shell.d.ts.map +0 -1
  328. package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
  329. package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
  330. package/dist/defaults/index.d.ts.map +0 -1
  331. package/dist/defaults/index.js.map +0 -7
  332. package/dist/design/index.d.ts.map +0 -1
  333. package/dist/design/index.js.map +0 -7
  334. package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
  335. package/dist/execution/autonomous-runner.d.ts.map +0 -1
  336. package/dist/execution/autonomy-brain.d.ts.map +0 -1
  337. package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
  338. package/dist/execution/brain-chain.d.ts.map +0 -1
  339. package/dist/execution/brain-circuit.d.ts.map +0 -1
  340. package/dist/execution/brain-evaluation.d.ts.map +0 -1
  341. package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
  342. package/dist/execution/brain-runtime.d.ts.map +0 -1
  343. package/dist/execution/compaction-core.d.ts.map +0 -1
  344. package/dist/execution/compaction-scoring.d.ts.map +0 -1
  345. package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
  346. package/dist/execution/compactor.d.ts.map +0 -1
  347. package/dist/execution/council-brain.d.ts.map +0 -1
  348. package/dist/execution/council-orchestrator.d.ts.map +0 -1
  349. package/dist/execution/council-personas.d.ts.map +0 -1
  350. package/dist/execution/council-profiles.d.ts.map +0 -1
  351. package/dist/execution/council-prompts.d.ts.map +0 -1
  352. package/dist/execution/council-resolution.d.ts.map +0 -1
  353. package/dist/execution/design-color.d.ts.map +0 -1
  354. package/dist/execution/design-detect.d.ts.map +0 -1
  355. package/dist/execution/design-kit-loader.d.ts.map +0 -1
  356. package/dist/execution/design-materialize.d.ts.map +0 -1
  357. package/dist/execution/design-project-store.d.ts.map +0 -1
  358. package/dist/execution/design-tune.d.ts.map +0 -1
  359. package/dist/execution/design-verify.d.ts.map +0 -1
  360. package/dist/execution/enhance-recovery.d.ts.map +0 -1
  361. package/dist/execution/error-handler.d.ts.map +0 -1
  362. package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
  363. package/dist/execution/eternal-autonomy.d.ts.map +0 -1
  364. package/dist/execution/goal-preamble.d.ts.map +0 -1
  365. package/dist/execution/index.d.ts.map +0 -1
  366. package/dist/execution/index.js.map +0 -7
  367. package/dist/execution/intelligent-compactor.d.ts.map +0 -1
  368. package/dist/execution/model-runtime.d.ts.map +0 -1
  369. package/dist/execution/one-shot-llm.d.ts.map +0 -1
  370. package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
  371. package/dist/execution/prompt-enhancer.d.ts.map +0 -1
  372. package/dist/execution/prompt-enhancer.js.map +0 -7
  373. package/dist/execution/prompt-loader.d.ts.map +0 -1
  374. package/dist/execution/provider-runner-impl.d.ts.map +0 -1
  375. package/dist/execution/regex-patterns.d.ts.map +0 -1
  376. package/dist/execution/retry-policy.d.ts.map +0 -1
  377. package/dist/execution/selective-compactor.d.ts.map +0 -1
  378. package/dist/execution/skill-loader.d.ts.map +0 -1
  379. package/dist/execution/strategy-compactor.d.ts.map +0 -1
  380. package/dist/execution/subagent-compaction.d.ts.map +0 -1
  381. package/dist/execution/tool-executor-logging.d.ts.map +0 -1
  382. package/dist/execution/tool-executor-results.d.ts.map +0 -1
  383. package/dist/execution/tool-executor-stream.d.ts.map +0 -1
  384. package/dist/execution/tool-executor-support.d.ts.map +0 -1
  385. package/dist/execution/tool-executor.d.ts.map +0 -1
  386. package/dist/extension/extension-points.d.ts.map +0 -1
  387. package/dist/extension/index.d.ts.map +0 -1
  388. package/dist/extension/index.js.map +0 -7
  389. package/dist/extension/registry.d.ts.map +0 -1
  390. package/dist/fleet-notifier.d.ts.map +0 -1
  391. package/dist/goal/checkpoint.d.ts.map +0 -1
  392. package/dist/goal/goal-assessor.d.ts.map +0 -1
  393. package/dist/goal/goal-planner.d.ts.map +0 -1
  394. package/dist/goal/goal-runner.d.ts.map +0 -1
  395. package/dist/goal/index.d.ts.map +0 -1
  396. package/dist/goal/index.js.map +0 -7
  397. package/dist/goal/phase-board-mutations.d.ts.map +0 -1
  398. package/dist/goal/phase-graph-builder.d.ts.map +0 -1
  399. package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
  400. package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
  401. package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
  402. package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
  403. package/dist/goal/phase-orchestrator.d.ts.map +0 -1
  404. package/dist/goal/phase-store.d.ts.map +0 -1
  405. package/dist/goal/types.d.ts.map +0 -1
  406. package/dist/hooks/http-executor.d.ts.map +0 -1
  407. package/dist/hooks/index.d.ts.map +0 -1
  408. package/dist/hooks/index.js.map +0 -7
  409. package/dist/hooks/registry.d.ts.map +0 -1
  410. package/dist/hooks/runner.d.ts.map +0 -1
  411. package/dist/hooks/shell-executor.d.ts.map +0 -1
  412. package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
  413. package/dist/hq/alerts.d.ts.map +0 -1
  414. package/dist/hq/auth-audit.d.ts.map +0 -1
  415. package/dist/hq/auth-store.d.ts.map +0 -1
  416. package/dist/hq/bootstrap-store.d.ts.map +0 -1
  417. package/dist/hq/brain-bridge.d.ts.map +0 -1
  418. package/dist/hq/bridge-context.d.ts.map +0 -1
  419. package/dist/hq/commands.d.ts.map +0 -1
  420. package/dist/hq/cost-bridge.d.ts.map +0 -1
  421. package/dist/hq/exposure.d.ts.map +0 -1
  422. package/dist/hq/factory.d.ts.map +0 -1
  423. package/dist/hq/fleet-bridge.d.ts.map +0 -1
  424. package/dist/hq/index.d.ts.map +0 -1
  425. package/dist/hq/index.js.map +0 -7
  426. package/dist/hq/kanban-store.d.ts.map +0 -1
  427. package/dist/hq/mailbox-mapper.d.ts.map +0 -1
  428. package/dist/hq/persistence/event-log.d.ts.map +0 -1
  429. package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
  430. package/dist/hq/persistence/simple-log.d.ts.map +0 -1
  431. package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
  432. package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
  433. package/dist/hq/persistence.d.ts.map +0 -1
  434. package/dist/hq/protocol/brain.d.ts.map +0 -1
  435. package/dist/hq/protocol/browser.d.ts.map +0 -1
  436. package/dist/hq/protocol/client.d.ts.map +0 -1
  437. package/dist/hq/protocol/core.d.ts.map +0 -1
  438. package/dist/hq/protocol/fleet.d.ts.map +0 -1
  439. package/dist/hq/protocol/kanban.d.ts.map +0 -1
  440. package/dist/hq/protocol/mailbox.d.ts.map +0 -1
  441. package/dist/hq/protocol/mcp.d.ts.map +0 -1
  442. package/dist/hq/protocol/peer.d.ts.map +0 -1
  443. package/dist/hq/protocol/project.d.ts.map +0 -1
  444. package/dist/hq/protocol/resume.d.ts.map +0 -1
  445. package/dist/hq/protocol/session.d.ts.map +0 -1
  446. package/dist/hq/protocol/tool.d.ts.map +0 -1
  447. package/dist/hq/protocol.d.ts.map +0 -1
  448. package/dist/hq/publisher.d.ts.map +0 -1
  449. package/dist/hq/redaction.d.ts.map +0 -1
  450. package/dist/hq/session-bridge.d.ts.map +0 -1
  451. package/dist/hq/tool-bridge.d.ts.map +0 -1
  452. package/dist/hq/transcript-mapper.d.ts.map +0 -1
  453. package/dist/hq/worktree-bridge.d.ts.map +0 -1
  454. package/dist/hq/write-queues.d.ts.map +0 -1
  455. package/dist/index.d.ts.map +0 -1
  456. package/dist/index.js.map +0 -7
  457. package/dist/infrastructure/context-manager.d.ts.map +0 -1
  458. package/dist/infrastructure/index.d.ts.map +0 -1
  459. package/dist/infrastructure/index.js.map +0 -7
  460. package/dist/infrastructure/logger.d.ts.map +0 -1
  461. package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
  462. package/dist/infrastructure/path-resolver.d.ts.map +0 -1
  463. package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
  464. package/dist/infrastructure/token-counter.d.ts.map +0 -1
  465. package/dist/kernel/container.d.ts.map +0 -1
  466. package/dist/kernel/events/agent-events.d.ts.map +0 -1
  467. package/dist/kernel/events/brain-events.d.ts.map +0 -1
  468. package/dist/kernel/events/file-events.d.ts.map +0 -1
  469. package/dist/kernel/events/fleet-events.d.ts.map +0 -1
  470. package/dist/kernel/events/memory-events.d.ts.map +0 -1
  471. package/dist/kernel/events/network-events.d.ts.map +0 -1
  472. package/dist/kernel/events/process-events.d.ts.map +0 -1
  473. package/dist/kernel/events/provider-events.d.ts.map +0 -1
  474. package/dist/kernel/events/sdd-events.d.ts.map +0 -1
  475. package/dist/kernel/events/session-events.d.ts.map +0 -1
  476. package/dist/kernel/events/tool-events.d.ts.map +0 -1
  477. package/dist/kernel/events/worktree-events.d.ts.map +0 -1
  478. package/dist/kernel/events.d.ts.map +0 -1
  479. package/dist/kernel/index.d.ts.map +0 -1
  480. package/dist/kernel/index.js.map +0 -7
  481. package/dist/kernel/pipeline.d.ts.map +0 -1
  482. package/dist/kernel/run-controller.d.ts.map +0 -1
  483. package/dist/kernel/tokens.d.ts.map +0 -1
  484. package/dist/mailbox-attach.d.ts.map +0 -1
  485. package/dist/middleware/collab-pause.d.ts.map +0 -1
  486. package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
  487. package/dist/models/codex-catalog.d.ts.map +0 -1
  488. package/dist/models/index.d.ts.map +0 -1
  489. package/dist/models/index.js.map +0 -7
  490. package/dist/models/llm-selector.d.ts.map +0 -1
  491. package/dist/models/mode-store.d.ts.map +0 -1
  492. package/dist/models/model-intelligence.d.ts.map +0 -1
  493. package/dist/models/model-router.d.ts.map +0 -1
  494. package/dist/models/models-registry.d.ts.map +0 -1
  495. package/dist/models/provider-model-resolve.d.ts.map +0 -1
  496. package/dist/notifications/index.d.ts.map +0 -1
  497. package/dist/notifications/index.js.map +0 -7
  498. package/dist/notifications/notifier-impl.d.ts.map +0 -1
  499. package/dist/notifications/notifier.d.ts.map +0 -1
  500. package/dist/notifications/types.d.ts.map +0 -1
  501. package/dist/observability/event-bridge.d.ts.map +0 -1
  502. package/dist/observability/health.d.ts.map +0 -1
  503. package/dist/observability/index.d.ts.map +0 -1
  504. package/dist/observability/index.js.map +0 -7
  505. package/dist/observability/metrics.d.ts.map +0 -1
  506. package/dist/observability/network-telemetry.d.ts.map +0 -1
  507. package/dist/observability/otel-tracer.d.ts.map +0 -1
  508. package/dist/observability/otlp-metrics.d.ts.map +0 -1
  509. package/dist/observability/otlp-traces.d.ts.map +0 -1
  510. package/dist/observability/process-telemetry.d.ts.map +0 -1
  511. package/dist/observability/prometheus.d.ts.map +0 -1
  512. package/dist/observability/redact-command.d.ts.map +0 -1
  513. package/dist/observability/tracer.d.ts.map +0 -1
  514. package/dist/plugin/api.d.ts.map +0 -1
  515. package/dist/plugin/config.d.ts.map +0 -1
  516. package/dist/plugin/index.d.ts.map +0 -1
  517. package/dist/plugin/index.js.map +0 -7
  518. package/dist/plugin/loader.d.ts.map +0 -1
  519. package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
  520. package/dist/plugins/chimera-plugin.d.ts.map +0 -1
  521. package/dist/plugins/prompts-plugin.d.ts.map +0 -1
  522. package/dist/plugins/review-claim-registry.d.ts.map +0 -1
  523. package/dist/plugins/review-context-builder.d.ts.map +0 -1
  524. package/dist/plugins/review-finding-commands.d.ts.map +0 -1
  525. package/dist/plugins/review-finding-integration.d.ts.map +0 -1
  526. package/dist/plugins/review-finding-parser.d.ts.map +0 -1
  527. package/dist/plugins/review-finding-store.d.ts.map +0 -1
  528. package/dist/plugins/review-finding-types.d.ts.map +0 -1
  529. package/dist/plugins/review-report-integration.d.ts.map +0 -1
  530. package/dist/plugins/review-report-store.d.ts.map +0 -1
  531. package/dist/plugins/review-report-types.d.ts.map +0 -1
  532. package/dist/plugins/review-types.d.ts.map +0 -1
  533. package/dist/plugins/skills-plugin.d.ts.map +0 -1
  534. package/dist/plugins/sync-plugin.d.ts.map +0 -1
  535. package/dist/prompts/index.d.ts.map +0 -1
  536. package/dist/prompts/prompt-installer.d.ts.map +0 -1
  537. package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
  538. package/dist/registry/index.d.ts.map +0 -1
  539. package/dist/registry/index.js.map +0 -7
  540. package/dist/registry/provider-registry.d.ts.map +0 -1
  541. package/dist/registry/slash-command-registry.d.ts.map +0 -1
  542. package/dist/registry/tool-registry.d.ts.map +0 -1
  543. package/dist/replay/hash.d.ts.map +0 -1
  544. package/dist/replay/index.d.ts.map +0 -1
  545. package/dist/replay/index.js.map +0 -7
  546. package/dist/replay/replay-provider-runner.d.ts.map +0 -1
  547. package/dist/security/capabilities.d.ts.map +0 -1
  548. package/dist/security/config-secrets.d.ts.map +0 -1
  549. package/dist/security/directory-permission-policy.d.ts.map +0 -1
  550. package/dist/security/directory-policy-schema.d.ts.map +0 -1
  551. package/dist/security/index.d.ts.map +0 -1
  552. package/dist/security/index.js.map +0 -7
  553. package/dist/security/kanban-boundary.d.ts.map +0 -1
  554. package/dist/security/permission-policy-schema.d.ts.map +0 -1
  555. package/dist/security/permission-policy.d.ts.map +0 -1
  556. package/dist/security/readonly-permission-policy.d.ts.map +0 -1
  557. package/dist/security/secret-scrubber.d.ts.map +0 -1
  558. package/dist/security/secret-vault.d.ts.map +0 -1
  559. package/dist/security/trust-boundary.d.ts.map +0 -1
  560. package/dist/security/yolo-risk.d.ts.map +0 -1
  561. package/dist/session-registry-atomic-file.d.ts.map +0 -1
  562. package/dist/session-registry-types.d.ts.map +0 -1
  563. package/dist/session-registry.d.ts.map +0 -1
  564. package/dist/skills/foreign-sources.d.ts.map +0 -1
  565. package/dist/skills/frontmatter.d.ts.map +0 -1
  566. package/dist/skills/github-fetcher.d.ts.map +0 -1
  567. package/dist/skills/index.d.ts.map +0 -1
  568. package/dist/skills/index.js.map +0 -7
  569. package/dist/skills/limits.d.ts.map +0 -1
  570. package/dist/skills/manifest-store.d.ts.map +0 -1
  571. package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
  572. package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
  573. package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
  574. package/dist/skills/skill-generator.d.ts.map +0 -1
  575. package/dist/skills/skill-installer.d.ts.map +0 -1
  576. package/dist/storage/annotations-store.d.ts.map +0 -1
  577. package/dist/storage/attachment-store.d.ts.map +0 -1
  578. package/dist/storage/cloud-sync.d.ts.map +0 -1
  579. package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
  580. package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
  581. package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
  582. package/dist/storage/config-loader/defaults.d.ts.map +0 -1
  583. package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
  584. package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
  585. package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
  586. package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
  587. package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
  588. package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
  589. package/dist/storage/config-loader/types.d.ts.map +0 -1
  590. package/dist/storage/config-loader/validation.d.ts.map +0 -1
  591. package/dist/storage/config-loader.d.ts.map +0 -1
  592. package/dist/storage/config-migration.d.ts.map +0 -1
  593. package/dist/storage/config-store.d.ts.map +0 -1
  594. package/dist/storage/director-state.d.ts.map +0 -1
  595. package/dist/storage/file-session-writer.d.ts.map +0 -1
  596. package/dist/storage/goal-coordination.d.ts.map +0 -1
  597. package/dist/storage/goal-kanban.d.ts.map +0 -1
  598. package/dist/storage/goal-store.d.ts.map +0 -1
  599. package/dist/storage/index.d.ts.map +0 -1
  600. package/dist/storage/index.js.map +0 -7
  601. package/dist/storage/input-history-store.d.ts.map +0 -1
  602. package/dist/storage/memory-backend.d.ts.map +0 -1
  603. package/dist/storage/memory-consolidator.d.ts.map +0 -1
  604. package/dist/storage/memory-graph-backend.d.ts.map +0 -1
  605. package/dist/storage/plan-store.d.ts.map +0 -1
  606. package/dist/storage/plan-templates.d.ts.map +0 -1
  607. package/dist/storage/prompt-store.d.ts.map +0 -1
  608. package/dist/storage/prompt-usage-store.d.ts.map +0 -1
  609. package/dist/storage/provider-config-watcher.d.ts.map +0 -1
  610. package/dist/storage/queue-store.d.ts.map +0 -1
  611. package/dist/storage/recovery-lock.d.ts.map +0 -1
  612. package/dist/storage/replay-log-store.d.ts.map +0 -1
  613. package/dist/storage/session-analyzer.d.ts.map +0 -1
  614. package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
  615. package/dist/storage/session-event-bridge.d.ts.map +0 -1
  616. package/dist/storage/session-helpers.d.ts.map +0 -1
  617. package/dist/storage/session-id-resolver.d.ts.map +0 -1
  618. package/dist/storage/session-id.d.ts.map +0 -1
  619. package/dist/storage/session-read-scrubber.d.ts.map +0 -1
  620. package/dist/storage/session-reader.d.ts.map +0 -1
  621. package/dist/storage/session-recovery.d.ts.map +0 -1
  622. package/dist/storage/session-resume-validation.d.ts.map +0 -1
  623. package/dist/storage/session-rewind-apply.d.ts.map +0 -1
  624. package/dist/storage/session-rewinder.d.ts.map +0 -1
  625. package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
  626. package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
  627. package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
  628. package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
  629. package/dist/storage/session-store/events.d.ts.map +0 -1
  630. package/dist/storage/session-store/fork-session.d.ts.map +0 -1
  631. package/dist/storage/session-store/index-reader.d.ts.map +0 -1
  632. package/dist/storage/session-store/load-cache.d.ts.map +0 -1
  633. package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
  634. package/dist/storage/session-store/paths.d.ts.map +0 -1
  635. package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
  636. package/dist/storage/session-store/replay.d.ts.map +0 -1
  637. package/dist/storage/session-store/search-events.d.ts.map +0 -1
  638. package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
  639. package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
  640. package/dist/storage/session-store/summary-header.d.ts.map +0 -1
  641. package/dist/storage/session-store/types.d.ts.map +0 -1
  642. package/dist/storage/session-store.d.ts.map +0 -1
  643. package/dist/storage/session-summary.d.ts.map +0 -1
  644. package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
  645. package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
  646. package/dist/storage/session-writer-truncate.d.ts.map +0 -1
  647. package/dist/storage/storage-concurrency.d.ts.map +0 -1
  648. package/dist/storage/task-store.d.ts.map +0 -1
  649. package/dist/storage/todos-checkpoint.d.ts.map +0 -1
  650. package/dist/storage/tool-audit-log.d.ts.map +0 -1
  651. package/dist/tasking/index.d.ts.map +0 -1
  652. package/dist/tasking/index.js.map +0 -7
  653. package/dist/tasking/task-store.d.ts.map +0 -1
  654. package/dist/tasking/task-tracker.d.ts.map +0 -1
  655. package/dist/tools/council-tool.d.ts.map +0 -1
  656. package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
  657. package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
  658. package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
  659. package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
  660. package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
  661. package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
  662. package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
  663. package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
  664. package/dist/tools/index.d.ts.map +0 -1
  665. package/dist/tools/index.js.map +0 -7
  666. package/dist/tools/mcp-control.d.ts.map +0 -1
  667. package/dist/tools/mcp-use.d.ts.map +0 -1
  668. package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
  669. package/dist/tools/plugin-manager.d.ts.map +0 -1
  670. package/dist/types/agent-bridge.d.ts.map +0 -1
  671. package/dist/types/attachment.d.ts.map +0 -1
  672. package/dist/types/autonomy.d.ts.map +0 -1
  673. package/dist/types/blocks.d.ts.map +0 -1
  674. package/dist/types/compactor.d.ts.map +0 -1
  675. package/dist/types/config/autonomy.d.ts.map +0 -1
  676. package/dist/types/config/context.d.ts.map +0 -1
  677. package/dist/types/config/fleet-chat.d.ts.map +0 -1
  678. package/dist/types/config/mcp-features.d.ts.map +0 -1
  679. package/dist/types/config/providers.d.ts.map +0 -1
  680. package/dist/types/config/root.d.ts.map +0 -1
  681. package/dist/types/config/runtime.d.ts.map +0 -1
  682. package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
  683. package/dist/types/config/tools.d.ts.map +0 -1
  684. package/dist/types/config.d.ts.map +0 -1
  685. package/dist/types/context-evidence.d.ts.map +0 -1
  686. package/dist/types/context-window.d.ts.map +0 -1
  687. package/dist/types/council.d.ts.map +0 -1
  688. package/dist/types/default-config.d.ts.map +0 -1
  689. package/dist/types/design-kit.d.ts.map +0 -1
  690. package/dist/types/error-handler.d.ts.map +0 -1
  691. package/dist/types/errors.d.ts.map +0 -1
  692. package/dist/types/file-event-record.d.ts.map +0 -1
  693. package/dist/types/hooks.d.ts.map +0 -1
  694. package/dist/types/index.d.ts.map +0 -1
  695. package/dist/types/index.js.map +0 -7
  696. package/dist/types/input-reader.d.ts.map +0 -1
  697. package/dist/types/logger.d.ts.map +0 -1
  698. package/dist/types/memory.d.ts.map +0 -1
  699. package/dist/types/messages.d.ts.map +0 -1
  700. package/dist/types/mode-prompts.d.ts.map +0 -1
  701. package/dist/types/mode.d.ts.map +0 -1
  702. package/dist/types/models-registry.d.ts.map +0 -1
  703. package/dist/types/multi-agent.d.ts.map +0 -1
  704. package/dist/types/observability.d.ts.map +0 -1
  705. package/dist/types/one-shot-llm.d.ts.map +0 -1
  706. package/dist/types/path-resolver.d.ts.map +0 -1
  707. package/dist/types/permission.d.ts.map +0 -1
  708. package/dist/types/plugin.d.ts.map +0 -1
  709. package/dist/types/prompt-registry.d.ts.map +0 -1
  710. package/dist/types/prompt.d.ts.map +0 -1
  711. package/dist/types/provider-runner.d.ts.map +0 -1
  712. package/dist/types/provider.d.ts.map +0 -1
  713. package/dist/types/quota-regex.d.ts.map +0 -1
  714. package/dist/types/renderer.d.ts.map +0 -1
  715. package/dist/types/retry-policy.d.ts.map +0 -1
  716. package/dist/types/secret-scrubber.d.ts.map +0 -1
  717. package/dist/types/secret-vault.d.ts.map +0 -1
  718. package/dist/types/selector.d.ts.map +0 -1
  719. package/dist/types/session-markers.d.ts.map +0 -1
  720. package/dist/types/session-markers.js.map +0 -7
  721. package/dist/types/session-reader.d.ts.map +0 -1
  722. package/dist/types/session-rewinder.d.ts.map +0 -1
  723. package/dist/types/session.d.ts.map +0 -1
  724. package/dist/types/side-effect.d.ts.map +0 -1
  725. package/dist/types/skill.d.ts.map +0 -1
  726. package/dist/types/slash-command.d.ts.map +0 -1
  727. package/dist/types/spec.d.ts.map +0 -1
  728. package/dist/types/system-prompt-contributor.d.ts.map +0 -1
  729. package/dist/types/system-prompt.d.ts.map +0 -1
  730. package/dist/types/task-graph.d.ts.map +0 -1
  731. package/dist/types/token-counter.d.ts.map +0 -1
  732. package/dist/types/tool-executor.d.ts.map +0 -1
  733. package/dist/types/tool-markers.d.ts.map +0 -1
  734. package/dist/types/tool.d.ts.map +0 -1
  735. package/dist/types/utility-types.d.ts.map +0 -1
  736. package/dist/utils/assert-never.d.ts.map +0 -1
  737. package/dist/utils/atomic-write.d.ts.map +0 -1
  738. package/dist/utils/cache-key.d.ts.map +0 -1
  739. package/dist/utils/child-env.d.ts.map +0 -1
  740. package/dist/utils/color.d.ts.map +0 -1
  741. package/dist/utils/compaction-preview.d.ts.map +0 -1
  742. package/dist/utils/config-backup.d.ts.map +0 -1
  743. package/dist/utils/config-json.d.ts.map +0 -1
  744. package/dist/utils/connectivity.d.ts.map +0 -1
  745. package/dist/utils/context-breakdown.d.ts.map +0 -1
  746. package/dist/utils/context-evidence.d.ts.map +0 -1
  747. package/dist/utils/continuous-memory-profiler.d.ts.map +0 -1
  748. package/dist/utils/crash-shield.d.ts.map +0 -1
  749. package/dist/utils/deep-merge.d.ts.map +0 -1
  750. package/dist/utils/diff.d.ts.map +0 -1
  751. package/dist/utils/error.d.ts.map +0 -1
  752. package/dist/utils/error.js.map +0 -7
  753. package/dist/utils/expect-defined.d.ts.map +0 -1
  754. package/dist/utils/expect-defined.js.map +0 -7
  755. package/dist/utils/glob-expand.d.ts.map +0 -1
  756. package/dist/utils/glob-match.d.ts.map +0 -1
  757. package/dist/utils/heap-watchdog-types.d.ts.map +0 -1
  758. package/dist/utils/heap-watchdog.d.ts.map +0 -1
  759. package/dist/utils/heap-watchdog.js.map +0 -7
  760. package/dist/utils/incoming-images.d.ts.map +0 -1
  761. package/dist/utils/index.d.ts.map +0 -1
  762. package/dist/utils/index.js.map +0 -7
  763. package/dist/utils/instruction-file.d.ts.map +0 -1
  764. package/dist/utils/ip-guard.d.ts.map +0 -1
  765. package/dist/utils/json-repair.d.ts.map +0 -1
  766. package/dist/utils/json-schema-validate.d.ts.map +0 -1
  767. package/dist/utils/lru-cache.d.ts.map +0 -1
  768. package/dist/utils/memory-flight-recorder.d.ts.map +0 -1
  769. package/dist/utils/merge-custom-models.d.ts.map +0 -1
  770. package/dist/utils/merge-models-payload.d.ts.map +0 -1
  771. package/dist/utils/message-invariants.d.ts.map +0 -1
  772. package/dist/utils/newline-normalize.d.ts.map +0 -1
  773. package/dist/utils/perf-profile.d.ts.map +0 -1
  774. package/dist/utils/pid.d.ts.map +0 -1
  775. package/dist/utils/project-identity.d.ts.map +0 -1
  776. package/dist/utils/project-watch.d.ts.map +0 -1
  777. package/dist/utils/regex-guard.d.ts.map +0 -1
  778. package/dist/utils/safe-json.d.ts.map +0 -1
  779. package/dist/utils/sage-output-block.d.ts.map +0 -1
  780. package/dist/utils/session-scoped-path.d.ts.map +0 -1
  781. package/dist/utils/sleep.d.ts.map +0 -1
  782. package/dist/utils/slug.d.ts.map +0 -1
  783. package/dist/utils/socket-path.d.ts.map +0 -1
  784. package/dist/utils/sqlite-warning.d.ts.map +0 -1
  785. package/dist/utils/string.d.ts.map +0 -1
  786. package/dist/utils/task-format.d.ts.map +0 -1
  787. package/dist/utils/term.d.ts.map +0 -1
  788. package/dist/utils/todos-format.d.ts.map +0 -1
  789. package/dist/utils/token-estimate.d.ts.map +0 -1
  790. package/dist/utils/tool-description-mode.d.ts.map +0 -1
  791. package/dist/utils/tool-name.d.ts.map +0 -1
  792. package/dist/utils/tool-output-serializer.d.ts.map +0 -1
  793. package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
  794. package/dist/utils/tool-subject.d.ts.map +0 -1
  795. package/dist/utils/tool-wire-compact.d.ts.map +0 -1
  796. package/dist/utils/tree-kill.d.ts.map +0 -1
  797. package/dist/utils/tree-kill.js.map +0 -7
  798. package/dist/utils/ulid.d.ts.map +0 -1
  799. package/dist/utils/walk-ignore.d.ts.map +0 -1
  800. package/dist/utils/wstack-paths.d.ts.map +0 -1
  801. package/dist/worktree/index.d.ts.map +0 -1
  802. package/dist/worktree/index.js.map +0 -7
  803. package/dist/worktree/worktree-git.d.ts.map +0 -1
  804. package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
  805. package/dist/worktree/worktree-manager.d.ts.map +0 -1
  806. 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);
@@ -6581,57 +6915,49 @@ function parseReviewSeverity(text) {
6581
6915
  const result = { critical: 0, high: 0, medium: 0 };
6582
6916
  if (!text) return result;
6583
6917
  for (const level of ["critical", "high", "medium"]) {
6584
- const countRe = new RegExp(`###\\s*${level}\\s*\\((\\d+)\\)`, "i");
6585
- const countMatch = text.match(countRe);
6918
+ const countMatch = text.match(new RegExp(`###\\s*${level}\\s*\\((\\d+)\\)`, "i"));
6586
6919
  if (countMatch?.[1]) {
6587
6920
  result[level] = Number.parseInt(countMatch[1], 10);
6588
6921
  continue;
6589
6922
  }
6590
- const sectionRe = new RegExp(`###\\s*${level}[^\\n]*\\n([\\s\\S]*?)(?=###|$)`, "i");
6591
- const sectionMatch = text.match(sectionRe);
6592
- if (sectionMatch?.[1]) {
6593
- const items = sectionMatch[1].match(/^\s*\d+\.\s/gm);
6594
- result[level] = items ? items.length : 0;
6595
- }
6923
+ const section = text.match(
6924
+ new RegExp(`###\\s*${level}[^\\n]*\\n([\\s\\S]*?)(?=###|$)`, "i")
6925
+ )?.[1];
6926
+ result[level] = section?.match(/^\s*\d+\.\s/gm)?.length ?? 0;
6596
6927
  }
6597
6928
  return result;
6598
6929
  }
6599
- var SECURITY_KEYWORDS = [
6600
- "injection",
6601
- "xss",
6602
- "csrf",
6603
- "ssrf",
6604
- "sql",
6605
- "secret",
6606
- "credential",
6607
- "password",
6608
- "api key",
6609
- "token",
6610
- "auth",
6611
- "shell injection",
6612
- "command injection",
6613
- "innerhtml",
6614
- "deserialization",
6615
- "path traversal",
6616
- "hardcoded",
6617
- "privilege",
6618
- "owasp"
6619
- ];
6620
6930
  function decideCascadeAgents(text, severities) {
6621
6931
  const agents = /* @__PURE__ */ new Set();
6622
- if (severities.critical > 0 || severities.high > 0) {
6623
- agents.add("bug-hunter");
6624
- }
6625
- const lower = text.toLowerCase();
6626
- const criticalHighRe = /###\s*(?:critical|high)[^\n]*\n([\s\S]*?)(?=###|$)/gi;
6627
- let section = criticalHighRe.exec(lower);
6628
- while (section !== null) {
6932
+ if (severities.critical > 0 || severities.high > 0) agents.add("bug-hunter");
6933
+ const securityKeywords = [
6934
+ "injection",
6935
+ "xss",
6936
+ "csrf",
6937
+ "ssrf",
6938
+ "sql",
6939
+ "secret",
6940
+ "credential",
6941
+ "password",
6942
+ "api key",
6943
+ "token",
6944
+ "auth",
6945
+ "shell injection",
6946
+ "command injection",
6947
+ "innerhtml",
6948
+ "deserialization",
6949
+ "path traversal",
6950
+ "hardcoded",
6951
+ "privilege",
6952
+ "owasp"
6953
+ ];
6954
+ const criticalHighSections = text.toLowerCase().matchAll(/###\s*(?:critical|high)[^\n]*\n([\s\S]*?)(?=###|$)/gi);
6955
+ for (const section of criticalHighSections) {
6629
6956
  const body = section[1] ?? "";
6630
- if (SECURITY_KEYWORDS.some((kw) => body.includes(kw))) {
6957
+ if (securityKeywords.some((keyword) => body.includes(keyword))) {
6631
6958
  agents.add("security-scanner");
6632
6959
  break;
6633
6960
  }
6634
- section = criticalHighRe.exec(lower);
6635
6961
  }
6636
6962
  return [...agents];
6637
6963
  }
@@ -6698,8 +7024,8 @@ async function snapshotChangedFiles(cwd) {
6698
7024
  if (file.path.startsWith(".wrongstack/")) continue;
6699
7025
  if (budget <= 0) break;
6700
7026
  try {
6701
- const stat6 = await fsp.stat(path14.join(cwd, file.path));
6702
- if (!stat6.isFile() || stat6.size > MAX_SNAPSHOT_FILE_BYTES) continue;
7027
+ const stat7 = await fsp.stat(path14.join(cwd, file.path));
7028
+ if (!stat7.isFile() || stat7.size > MAX_SNAPSHOT_FILE_BYTES) continue;
6703
7029
  const content = await fsp.readFile(path14.join(cwd, file.path), "utf8");
6704
7030
  budget -= content.length;
6705
7031
  snapshots.push({
@@ -6724,9 +7050,8 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
6724
7050
  "Detects git-tracked file edits and dispatches review subagents",
6725
7051
  "with configurable provider/model/fallback.",
6726
7052
  "",
6727
- "When a review report contains findings at or above the cascadeOn",
6728
- "threshold, follow-up agents (security-scanner, bug-hunter) are",
6729
- "automatically spawned to investigate.",
7053
+ "Reports are persisted and shown as passive notifications.",
7054
+ "They never wake the leader or spawn mutating follow-up agents.",
6730
7055
  "",
6731
7056
  "Commands:",
6732
7057
  " /auto-review Show current status and config",
@@ -6741,11 +7066,8 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
6741
7066
  " debounceMs debounce window (default 15000)",
6742
7067
  " maxFilesPerBatch max files per review (default 15)",
6743
7068
  " maxConcurrentReviews max parallel reviews (default 2)",
6744
- ' cascadeOn "off" | "critical" | "high" (default off)',
6745
- " Spawns security-scanner/bug-hunter when",
6746
- ' findings reach this severity. "high" fires',
6747
- ' on any High+ finding; "critical" only on Critical.',
6748
- " maxCascadeDepth max fix+re-review cycles (default 2, 0=off)"
7069
+ " cascadeOn off | critical | high (default off)",
7070
+ " maxCascadeDepth max fix+re-review cycles (default 2)"
6749
7071
  ].join("\n"),
6750
7072
  async run(args) {
6751
7073
  const cfg = getConfig();
@@ -6761,7 +7083,6 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
6761
7083
  };
6762
7084
  }
6763
7085
  const inFlight = getInFlightCount();
6764
- const cascadeDesc = cfg.cascadeOn === "off" ? "disabled" : `on ${cfg.cascadeOn}+ \u2192 spawns security-scanner/bug-hunter`;
6765
7086
  return {
6766
7087
  message: [
6767
7088
  `\u{1F4CB} Auto Review \u2014 ${cfg.enabled ? "\u2705 enabled" : "\u23F8\uFE0F disabled"}`,
@@ -6772,7 +7093,7 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
6772
7093
  ` Debounce: ${cfg.debounceMs} ms`,
6773
7094
  ` Max files: ${cfg.maxFilesPerBatch}`,
6774
7095
  ` Max parallel: ${cfg.maxConcurrentReviews}`,
6775
- ` Cascade: ${cascadeDesc}`,
7096
+ ` Cascade: ${cfg.cascadeOn === "off" ? "off" : `on ${cfg.cascadeOn}+ \u2192 spawns security-scanner/bug-hunter`}`,
6776
7097
  ` Max depth: ${cfg.maxCascadeDepth} re-review cycle(s)`,
6777
7098
  ` In-flight: ${inFlight} review(s)`,
6778
7099
  "",
@@ -7157,7 +7478,6 @@ function createAutoReviewPlugin() {
7157
7478
 
7158
7479
  // src/plugins/chimera-plugin.ts
7159
7480
  init_error();
7160
- import { randomUUID as randomUUID6 } from "node:crypto";
7161
7481
  import { spawn as spawn4 } from "node:child_process";
7162
7482
  import * as fsp4 from "node:fs/promises";
7163
7483
  import * as os5 from "node:os";
@@ -7233,10 +7553,20 @@ function parseFindingSegment(segment, severity, context) {
7233
7553
  if (tagMatch) {
7234
7554
  remaining = content.slice(tagMatch[0].length).trim();
7235
7555
  }
7556
+ const citationMatch = remaining.match(
7557
+ /^(`+)([a-zA-Z_./\\:][^`]*[a-zA-Z0-9_./\\:])\1(?=\s*[—–-]|\s*$)/
7558
+ );
7559
+ if (citationMatch) {
7560
+ const inner = citationMatch[2];
7561
+ const afterCitation = remaining.slice(citationMatch[0].length);
7562
+ remaining = `${inner}${afterCitation}`;
7563
+ }
7236
7564
  let file;
7237
7565
  let line;
7238
7566
  let desc = remaining;
7239
- const refMatch = remaining.match(/^(.+?)(?::(\d+))?\s*[—–-]\s*(.+)$/);
7567
+ const refMatch = remaining.match(
7568
+ /^([a-zA-Z_./\\][a-zA-Z0-9_./\\-]*\.\w+)(?::(\d+))?\s+(?:[—–]|-)\s+(.+)$/
7569
+ );
7240
7570
  if (refMatch) {
7241
7571
  file = refMatch[1].trim();
7242
7572
  if (refMatch[2] !== void 0) {
@@ -7334,12 +7664,26 @@ async function persistReviewReport(payload, reportId, projectDir) {
7334
7664
  ...cascadeDepth !== void 0 ? { cascadeDepth } : {}
7335
7665
  };
7336
7666
  await store.persist(input);
7667
+ if (reviewStatus === "success" && parsed.findings.length === 0 && parsed.unparseableCount === 0 && isExplicitAllClearReview(payload.reviewText)) {
7668
+ await store.transition(
7669
+ reportId,
7670
+ "completed",
7671
+ { id: "chimera", kind: "system" },
7672
+ {
7673
+ reason: "Successful Chimera review produced no actionable findings"
7674
+ }
7675
+ );
7676
+ }
7337
7677
  return {
7338
7678
  reportId,
7339
7679
  created: !existed,
7340
7680
  totalFindings: parsed.findings.length
7341
7681
  };
7342
7682
  }
7683
+ function isExplicitAllClearReview(text) {
7684
+ const normalized = text.trim().toLowerCase();
7685
+ return normalized.startsWith("## \u{1F982} chimera review \u2014 all clear") || normalized.includes("chimera review: all clear");
7686
+ }
7343
7687
  async function syncReportCompletion(reportId, projectDir, actor) {
7344
7688
  const reportStore = new JsonlReportStore(projectDir);
7345
7689
  const findingStore = new JsonlFindingStore(projectDir);
@@ -7812,49 +8156,6 @@ async function showStatus(ctx) {
7812
8156
  ].join("\n");
7813
8157
  }
7814
8158
 
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
8159
  // src/plugins/chimera-plugin.ts
7859
8160
  var DEFAULT_MAX_FILES = 15;
7860
8161
  var DEFAULT_CASCADE_ON = "off";
@@ -8010,18 +8311,6 @@ function buildReviewCommand(_getConfig) {
8010
8311
  }
8011
8312
  };
8012
8313
  }
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
8314
  function createChimeraPlugin() {
8026
8315
  return {
8027
8316
  name: "wstack-chimera",
@@ -8050,9 +8339,6 @@ function createChimeraPlugin() {
8050
8339
  });
8051
8340
  api.onPattern("chimera.review_complete", (_event, payload) => {
8052
8341
  recordCompletedReview(api.events, payload);
8053
- tryPersistFindings(payload).catch((err) => {
8054
- api.log.warn(`[review-finding] failed to persist findings: ${toErrorMessage(err)}`);
8055
- });
8056
8342
  });
8057
8343
  if (!resolved.enabled) {
8058
8344
  api.log.info("[chimera] disabled by config");
@@ -8115,7 +8401,9 @@ function createChimeraPlugin() {
8115
8401
  api.log.info("[chimera] skipped \u2014 changed files already have reviews in progress");
8116
8402
  return;
8117
8403
  }
8118
- api.log.info(`[chimera] emitted review_needed event (${emittedBundle.files.length} files)`);
8404
+ api.log.info(
8405
+ `[chimera] emitted review_needed event (${emittedBundle.files.length} files)`
8406
+ );
8119
8407
  } catch (err) {
8120
8408
  api.log.warn(`[chimera] session.ended handler failed: ${toErrorMessage(err)}`);
8121
8409
  }
@@ -8634,8 +8922,8 @@ var PromptUsageStore = class {
8634
8922
  }
8635
8923
  async fileSignature() {
8636
8924
  try {
8637
- const stat6 = await fs10.stat(this.file);
8638
- return { size: stat6.size, mtimeMs: stat6.mtimeMs, ctimeMs: stat6.ctimeMs };
8925
+ const stat7 = await fs10.stat(this.file);
8926
+ return { size: stat7.size, mtimeMs: stat7.mtimeMs, ctimeMs: stat7.ctimeMs };
8639
8927
  } catch {
8640
8928
  return null;
8641
8929
  }
@@ -9045,12 +9333,12 @@ function parseFlags(input) {
9045
9333
  while (s.startsWith("--") && (m = flagRe.exec(s))) {
9046
9334
  const name = expectDefined(m[1]);
9047
9335
  const rawVal = m[2] ?? m[3] ?? "true";
9048
- flags[name] = unquote(rawVal);
9336
+ flags[name] = unquote2(rawVal);
9049
9337
  s = s.slice(m[0].length);
9050
9338
  }
9051
9339
  return { flags, positional: s.trim() };
9052
9340
  }
9053
- function unquote(v) {
9341
+ function unquote2(v) {
9054
9342
  if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
9055
9343
  return v.slice(1, -1);
9056
9344
  }
@@ -9089,7 +9377,7 @@ function parseKeyValues(kvs) {
9089
9377
  const out = {};
9090
9378
  for (const kv of kvs) {
9091
9379
  const eq = kv.indexOf("=");
9092
- if (eq > 0) out[kv.slice(0, eq)] = unquote(kv.slice(eq + 1));
9380
+ if (eq > 0) out[kv.slice(0, eq)] = unquote2(kv.slice(eq + 1));
9093
9381
  }
9094
9382
  return out;
9095
9383
  }
@@ -9109,9 +9397,123 @@ function dim(s) {
9109
9397
  return `\x1B[2m${s}\x1B[0m`;
9110
9398
  }
9111
9399
 
9400
+ // src/plugins/review-finding-integration.ts
9401
+ init_review_finding_store();
9402
+ async function integrateFindings(payload, projectDir, reportId) {
9403
+ if (!payload.reviewText || payload.reviewText.trim().length === 0) {
9404
+ return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
9405
+ }
9406
+ const store = new JsonlFindingStore(projectDir);
9407
+ const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
9408
+ const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
9409
+ const sessionId = payload.sessionId ?? payload.cwd;
9410
+ const model = payload.bundle.config.model;
9411
+ const parsed = parseChimeraReviewReport(payload.reviewText, {
9412
+ sessionId,
9413
+ agentId,
9414
+ reviewerModel: model,
9415
+ reviewType: source,
9416
+ reportId
9417
+ });
9418
+ if (parsed.findings.length === 0) {
9419
+ return {
9420
+ created: 0,
9421
+ relinked: 0,
9422
+ reopened: 0,
9423
+ totalFindings: 0,
9424
+ unparseableCount: parsed.unparseableCount
9425
+ };
9426
+ }
9427
+ const result = await store.upsert(parsed.findings, {
9428
+ sessionId,
9429
+ reportId,
9430
+ agentId,
9431
+ model
9432
+ });
9433
+ return {
9434
+ created: result.created,
9435
+ relinked: result.relinked,
9436
+ reopened: result.reopened,
9437
+ reportId,
9438
+ totalFindings: parsed.findings.length,
9439
+ unparseableCount: parsed.unparseableCount
9440
+ };
9441
+ }
9442
+
9443
+ // src/plugins/review-store-maintenance.ts
9444
+ init_atomic_write();
9445
+ init_review_finding_store();
9446
+ init_review_report_store();
9447
+ import * as fsp5 from "node:fs/promises";
9448
+ import * as path21 from "node:path";
9449
+ var REVIEW_STORE_COMPACTION_THRESHOLD_BYTES = 8 * 1024 * 1024;
9450
+ var REVIEW_STORE_COMPACTION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
9451
+ var REVIEW_STORE_MAINTENANCE_FILE = ".review-store-maintenance.json";
9452
+ async function maybeCompactReviewStores(projectDir, opts = {}) {
9453
+ const thresholdBytes = opts.thresholdBytes ?? REVIEW_STORE_COMPACTION_THRESHOLD_BYTES;
9454
+ const intervalMs = opts.intervalMs ?? REVIEW_STORE_COMPACTION_INTERVAL_MS;
9455
+ const now = opts.now ?? Date.now();
9456
+ const maintenancePath = path21.join(projectDir, REVIEW_STORE_MAINTENANCE_FILE);
9457
+ return withFileLock(maintenancePath, async () => {
9458
+ const totalBytes = await fileSize(resolveReportStorePath(projectDir)) + await fileSize(resolveFindingStorePath(projectDir));
9459
+ if (totalBytes < thresholdBytes) {
9460
+ return emptyResult("below_threshold", totalBytes);
9461
+ }
9462
+ const state = await readMaintenanceState(maintenancePath);
9463
+ if (state && now - new Date(state.compactedAt).getTime() < intervalMs) {
9464
+ return emptyResult("interval", totalBytes);
9465
+ }
9466
+ const reportResult = await new JsonlReportStore(projectDir).compact();
9467
+ const findingResult = await new JsonlFindingStore(projectDir).compact();
9468
+ const nextState = {
9469
+ compactedAt: new Date(now).toISOString(),
9470
+ totalBytesBefore: totalBytes
9471
+ };
9472
+ await atomicWrite(maintenancePath, `${JSON.stringify(nextState)}
9473
+ `, { mode: 384 });
9474
+ return {
9475
+ compacted: true,
9476
+ totalBytes,
9477
+ reason: "compacted",
9478
+ removedReports: reportResult.removed,
9479
+ removedFindings: findingResult.removed,
9480
+ eventsFolded: reportResult.eventsFolded + findingResult.eventsFolded
9481
+ };
9482
+ });
9483
+ }
9484
+ function emptyResult(reason, totalBytes) {
9485
+ return {
9486
+ compacted: false,
9487
+ totalBytes,
9488
+ reason,
9489
+ removedReports: 0,
9490
+ removedFindings: 0,
9491
+ eventsFolded: 0
9492
+ };
9493
+ }
9494
+ async function fileSize(filePath) {
9495
+ try {
9496
+ return (await fsp5.stat(filePath)).size;
9497
+ } catch (error) {
9498
+ if (error.code === "ENOENT") return 0;
9499
+ throw error;
9500
+ }
9501
+ }
9502
+ async function readMaintenanceState(filePath) {
9503
+ try {
9504
+ const parsed = JSON.parse(await fsp5.readFile(filePath, "utf8"));
9505
+ return typeof parsed.compactedAt === "string" && Number.isFinite(parsed.totalBytesBefore) ? parsed : null;
9506
+ } catch (error) {
9507
+ if (error.code === "ENOENT" || error instanceof SyntaxError) {
9508
+ return null;
9509
+ }
9510
+ throw error;
9511
+ }
9512
+ }
9513
+
9112
9514
  // src/plugins/skills-plugin.ts
9113
9515
  import * as os7 from "node:os";
9114
- import * as path25 from "node:path";
9516
+ import * as path26 from "node:path";
9115
9517
 
9116
9518
  // src/skills/foreign-sources.ts
9117
9519
  var FOREIGN_SKILL_TOOLS = [
@@ -9294,104 +9696,7 @@ function numField(rec, key) {
9294
9696
  init_errors();
9295
9697
  import { spawn as spawn5 } from "node:child_process";
9296
9698
  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
9699
+ import * as path22 from "node:path";
9395
9700
  async function validateSkillNameAvailable(name, loader) {
9396
9701
  const formatViolations = validateSkillName(name);
9397
9702
  const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
@@ -9510,8 +9815,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
9510
9815
  subsystem: "general"
9511
9816
  });
9512
9817
  }
9513
- const skillDir = path21.join(skillsDir, name);
9514
- const skillFile = path21.join(skillDir, "SKILL.md");
9818
+ const skillDir = path22.join(skillsDir, name);
9819
+ const skillFile = path22.join(skillDir, "SKILL.md");
9515
9820
  if (!opts.overwrite) {
9516
9821
  try {
9517
9822
  await fs12.access(skillFile);
@@ -9570,13 +9875,14 @@ function defaultEditor() {
9570
9875
  init_errors();
9571
9876
  init_error();
9572
9877
  import * as fs15 from "node:fs/promises";
9573
- import * as path24 from "node:path";
9878
+ import * as path25 from "node:path";
9574
9879
 
9575
9880
  // src/skills/github-fetcher.ts
9576
9881
  init_errors();
9882
+ import { createWriteStream } from "node:fs";
9577
9883
  import * as fs13 from "node:fs/promises";
9578
9884
  import * as os6 from "node:os";
9579
- import * as path22 from "node:path";
9885
+ import * as path23 from "node:path";
9580
9886
  import { Readable } from "node:stream";
9581
9887
  import { pipeline } from "node:stream/promises";
9582
9888
  import { createGunzip } from "node:zlib";
@@ -9603,6 +9909,46 @@ function parseSkillRef(input) {
9603
9909
  }
9604
9910
  return { owner: expectDefined(parts[0]), repo: expectDefined(parts[1]), ref };
9605
9911
  }
9912
+ async function writeBoundedGzipStream(source, outputPath, maxBytes, maxCompressedBytes = SKILL_LIMITS.MAX_TARBALL_SIZE) {
9913
+ let compressedBytes = 0;
9914
+ let writtenBytes = 0;
9915
+ await pipeline(
9916
+ source,
9917
+ async function* (chunks) {
9918
+ for await (const chunk of chunks) {
9919
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9920
+ compressedBytes += buffer.byteLength;
9921
+ if (compressedBytes > maxCompressedBytes) {
9922
+ throw new WrongStackError({
9923
+ message: `Compressed tarball too large. Max: ${maxCompressedBytes / 1024 / 1024}MB`,
9924
+ code: ERROR_CODES.UNKNOWN,
9925
+ subsystem: "general",
9926
+ context: { compressedBytes, maxBytes: maxCompressedBytes }
9927
+ });
9928
+ }
9929
+ yield buffer;
9930
+ }
9931
+ },
9932
+ createGunzip(),
9933
+ async function* (chunks) {
9934
+ for await (const chunk of chunks) {
9935
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9936
+ writtenBytes += buffer.byteLength;
9937
+ if (writtenBytes > maxBytes) {
9938
+ throw new WrongStackError({
9939
+ message: `Uncompressed tarball too large. Max: ${maxBytes / 1024 / 1024}MB`,
9940
+ code: ERROR_CODES.UNKNOWN,
9941
+ subsystem: "general",
9942
+ context: { uncompressedBytes: writtenBytes, maxBytes }
9943
+ });
9944
+ }
9945
+ yield buffer;
9946
+ }
9947
+ },
9948
+ createWriteStream(outputPath, { flags: "wx" })
9949
+ );
9950
+ return writtenBytes;
9951
+ }
9606
9952
  function resolveGitHubToken(env = process.env) {
9607
9953
  const raw = env["WRONGSTACK_GITHUB_TOKEN"] ?? env["GITHUB_TOKEN"] ?? env["GH_TOKEN"];
9608
9954
  if (!raw) return void 0;
@@ -9678,7 +10024,7 @@ async function downloadGitHubTarball(parsed) {
9678
10024
  }
9679
10025
  });
9680
10026
  }
9681
- const tempDir = await fs13.mkdtemp(path22.join(os6.tmpdir(), "wskill-"));
10027
+ const tempDir = await fs13.mkdtemp(path23.join(os6.tmpdir(), "wskill-"));
9682
10028
  try {
9683
10029
  if (!response.body) {
9684
10030
  throw new WrongStackError({
@@ -9689,15 +10035,14 @@ async function downloadGitHubTarball(parsed) {
9689
10035
  });
9690
10036
  }
9691
10037
  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);
10038
+ const tarPath = path23.join(tempDir, ".wrongstack-download.tar");
10039
+ await writeBoundedGzipStream(nodeStream, tarPath, SKILL_LIMITS.MAX_UNCOMPRESSED_TARBALL_SIZE);
10040
+ const tarBuf = await fs13.readFile(tarPath);
10041
+ try {
10042
+ await extractTar(tarBuf, tempDir);
10043
+ } finally {
10044
+ await fs13.rm(tarPath, { force: true });
10045
+ }
9701
10046
  return { tempDir };
9702
10047
  } catch (err) {
9703
10048
  await fs13.rm(tempDir, { recursive: true, force: true }).catch(() => {
@@ -9705,6 +10050,44 @@ async function downloadGitHubTarball(parsed) {
9705
10050
  throw err;
9706
10051
  }
9707
10052
  }
10053
+ function readTarSize(buf, start) {
10054
+ const first = buf[start] ?? 0;
10055
+ if ((first & 128) !== 0) {
10056
+ if (first === 255) {
10057
+ throw new Error("tar: negative base-256 size field");
10058
+ }
10059
+ let value = first & 127;
10060
+ for (let i = start + 1; i < start + 12; i++) {
10061
+ value = value * 256 + (buf[i] ?? 0);
10062
+ if (!Number.isSafeInteger(value)) {
10063
+ throw new Error("tar: base-256 size exceeds the safe integer range");
10064
+ }
10065
+ }
10066
+ return value;
10067
+ }
10068
+ const text = readTarString(buf, start, 12).trim();
10069
+ if (text === "") return 0;
10070
+ if (!/^[0-7]+$/.test(text)) {
10071
+ throw new Error(`tar: unparseable size field ${JSON.stringify(text)}`);
10072
+ }
10073
+ const parsed = Number.parseInt(text, 8);
10074
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
10075
+ throw new Error("tar: size field out of range");
10076
+ }
10077
+ return parsed;
10078
+ }
10079
+ function readTarString(buf, start, maxLen) {
10080
+ let end = start;
10081
+ while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
10082
+ end++;
10083
+ }
10084
+ return buf.subarray(start, end).toString("utf8");
10085
+ }
10086
+ function stripTopDir(p) {
10087
+ const idx = p.indexOf("/");
10088
+ if (idx === -1) return "";
10089
+ return p.slice(idx + 1);
10090
+ }
9708
10091
  async function extractTar(buf, destDir) {
9709
10092
  let offset = 0;
9710
10093
  while (offset + 512 <= buf.length) {
@@ -9712,15 +10095,15 @@ async function extractTar(buf, destDir) {
9712
10095
  if (header.every((b) => b === 0)) break;
9713
10096
  const name = readTarString(buf, offset, 100);
9714
10097
  const prefix = readTarString(buf, offset + 345, 155);
9715
- const size = Number.parseInt(readTarString(buf, offset + 124, 12).trim(), 8) || 0;
10098
+ const size = readTarSize(buf, offset + 124);
9716
10099
  const typeflag = buf[offset + 156] ?? 0;
9717
10100
  const fullPath = prefix ? `${prefix}/${name}` : name;
9718
10101
  const relPath = stripTopDir(fullPath);
9719
10102
  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)) {
10103
+ const destPath = path23.join(destDir, relPath);
10104
+ const resolvedDest = path23.resolve(destPath);
10105
+ const resolvedRoot = path23.resolve(destDir);
10106
+ if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path23.sep)) {
9724
10107
  offset += 512 + Math.ceil(size / 512) * 512;
9725
10108
  continue;
9726
10109
  }
@@ -9730,7 +10113,7 @@ async function extractTar(buf, destDir) {
9730
10113
  }
9731
10114
  }
9732
10115
  if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
9733
- const dir = path22.dirname(destPath);
10116
+ const dir = path23.dirname(destPath);
9734
10117
  await fs13.mkdir(dir, { recursive: true });
9735
10118
  const dataStart = offset + 512;
9736
10119
  const dataEnd = dataStart + size;
@@ -9741,23 +10124,11 @@ async function extractTar(buf, destDir) {
9741
10124
  offset += 512 + Math.ceil(size / 512) * 512;
9742
10125
  }
9743
10126
  }
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
10127
 
9757
10128
  // src/skills/manifest-store.ts
9758
10129
  init_atomic_write();
9759
10130
  import * as fs14 from "node:fs/promises";
9760
- import * as path23 from "node:path";
10131
+ import * as path24 from "node:path";
9761
10132
  var SkillManifestStore = class {
9762
10133
  manifestPath;
9763
10134
  cache;
@@ -9780,7 +10151,7 @@ var SkillManifestStore = class {
9780
10151
  return this.cache;
9781
10152
  }
9782
10153
  async write(data) {
9783
- const dir = path23.dirname(this.manifestPath);
10154
+ const dir = path24.dirname(this.manifestPath);
9784
10155
  await fs14.mkdir(dir, { recursive: true });
9785
10156
  await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
9786
10157
  this.cache = data;
@@ -9818,6 +10189,10 @@ var SkillManifestStore = class {
9818
10189
  };
9819
10190
 
9820
10191
  // src/skills/skill-installer.ts
10192
+ function isInside(resolved, destDir) {
10193
+ const root = path25.resolve(destDir);
10194
+ return resolved === root || resolved.startsWith(root + path25.sep);
10195
+ }
9821
10196
  var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
9822
10197
  var SkillInstaller = class {
9823
10198
  opts;
@@ -9871,14 +10246,14 @@ var SkillInstaller = class {
9871
10246
  this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
9872
10247
  await this.removeSkillFiles(skill.name, scope);
9873
10248
  }
9874
- const destDir = path24.join(targetDir, skill.name);
10249
+ const destDir = path25.join(targetDir, skill.name);
9875
10250
  await fs15.mkdir(destDir, { recursive: true });
9876
10251
  const copiedFiles = [];
9877
10252
  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))) {
10253
+ const srcPath = path25.join(skill.baseDir, file);
10254
+ const destPath = path25.join(destDir, file);
10255
+ const resolved2 = path25.resolve(destPath);
10256
+ if (!isInside(resolved2, destDir)) {
9882
10257
  throw new FsError({
9883
10258
  message: `Path traversal detected in skill file: ${file}`,
9884
10259
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -9886,16 +10261,16 @@ var SkillInstaller = class {
9886
10261
  context: { reason: "path_traversal", skillName: skill.name }
9887
10262
  });
9888
10263
  }
9889
- const stat6 = await fs15.stat(srcPath);
9890
- if (stat6.size > MAX_SKILL_FILE_SIZE) {
10264
+ const stat7 = await fs15.stat(srcPath);
10265
+ if (stat7.size > MAX_SKILL_FILE_SIZE) {
9891
10266
  throw new FsError({
9892
- message: `Skill file "${file}" is too large (${(stat6.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
10267
+ message: `Skill file "${file}" is too large (${(stat7.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
9893
10268
  code: ERROR_CODES.FS_WRITE_FAILED,
9894
10269
  path: srcPath,
9895
- context: { skillName: skill.name, fileSize: stat6.size, maxSize: MAX_SKILL_FILE_SIZE }
10270
+ context: { skillName: skill.name, fileSize: stat7.size, maxSize: MAX_SKILL_FILE_SIZE }
9896
10271
  });
9897
10272
  }
9898
- await fs15.mkdir(path24.dirname(destPath), { recursive: true });
10273
+ await fs15.mkdir(path25.dirname(destPath), { recursive: true });
9899
10274
  await fs15.copyFile(srcPath, destPath);
9900
10275
  copiedFiles.push(file);
9901
10276
  }
@@ -9953,7 +10328,7 @@ var SkillInstaller = class {
9953
10328
  const results = [];
9954
10329
  for (const e of entries) {
9955
10330
  if (!await entryIsDirectory(srcDir, e)) continue;
9956
- const skillMdPath = path24.join(srcDir, e.name, "SKILL.md");
10331
+ const skillMdPath = path25.join(srcDir, e.name, "SKILL.md");
9957
10332
  let content;
9958
10333
  try {
9959
10334
  content = await fs15.readFile(skillMdPath, "utf8");
@@ -9966,16 +10341,16 @@ var SkillInstaller = class {
9966
10341
  if (existing.find((x) => x.scope === scope)) {
9967
10342
  await this.removeSkillFiles(fm.name, scope);
9968
10343
  }
9969
- const destDir = path24.join(targetDir, fm.name);
10344
+ const destDir = path25.join(targetDir, fm.name);
9970
10345
  await fs15.mkdir(destDir, { recursive: true });
9971
- const srcSkillDir = path24.join(srcDir, e.name);
10346
+ const srcSkillDir = path25.join(srcDir, e.name);
9972
10347
  const files = await collectFiles(srcSkillDir, srcSkillDir);
9973
10348
  const copiedFiles = [];
9974
10349
  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))) {
10350
+ const srcPath = path25.join(srcSkillDir, file);
10351
+ const destPath = path25.join(destDir, file);
10352
+ const resolved = path25.resolve(destPath);
10353
+ if (!isInside(resolved, destDir)) {
9979
10354
  throw new FsError({
9980
10355
  message: `Path traversal detected in skill file: ${file}`,
9981
10356
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -9983,7 +10358,7 @@ var SkillInstaller = class {
9983
10358
  context: { reason: "path_traversal", skillName: fm.name }
9984
10359
  });
9985
10360
  }
9986
- await fs15.mkdir(path24.dirname(destPath), { recursive: true });
10361
+ await fs15.mkdir(path25.dirname(destPath), { recursive: true });
9987
10362
  if (opts?.link) {
9988
10363
  try {
9989
10364
  await fs15.symlink(srcPath, destPath);
@@ -10146,7 +10521,7 @@ var SkillInstaller = class {
10146
10521
  */
10147
10522
  async detectSkills(baseDir) {
10148
10523
  const results = [];
10149
- const rootSkillMd = path24.join(baseDir, "SKILL.md");
10524
+ const rootSkillMd = path25.join(baseDir, "SKILL.md");
10150
10525
  try {
10151
10526
  await fs15.access(rootSkillMd);
10152
10527
  const content = await fs15.readFile(rootSkillMd, "utf8");
@@ -10161,17 +10536,17 @@ var SkillInstaller = class {
10161
10536
  }
10162
10537
  } catch {
10163
10538
  }
10164
- const skillsDir = path24.join(baseDir, "skills");
10539
+ const skillsDir = path25.join(baseDir, "skills");
10165
10540
  try {
10166
10541
  const entries = await fs15.readdir(skillsDir, { withFileTypes: true });
10167
10542
  for (const entry of entries) {
10168
10543
  if (!entry.isDirectory()) continue;
10169
- const skillFile = path24.join(skillsDir, entry.name, "SKILL.md");
10544
+ const skillFile = path25.join(skillsDir, entry.name, "SKILL.md");
10170
10545
  try {
10171
10546
  const content = await fs15.readFile(skillFile, "utf8");
10172
10547
  const fm = parseSkillFrontmatter(content);
10173
10548
  if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
10174
- const skillDir = path24.join(skillsDir, entry.name);
10549
+ const skillDir = path25.join(skillsDir, entry.name);
10175
10550
  const files = await collectFiles(skillDir, skillDir);
10176
10551
  results.push({
10177
10552
  name: fm.name,
@@ -10189,9 +10564,31 @@ var SkillInstaller = class {
10189
10564
  /**
10190
10565
  * Remove all files for an installed skill.
10191
10566
  */
10567
+ /**
10568
+ * Delete an installed skill's directory.
10569
+ *
10570
+ * The containment check is not ceremonial: this is a `recursive: true,
10571
+ * force: true` delete whose target is built from a skill NAME taken from
10572
+ * manifest frontmatter. `path.join` normalises `..`, so a crafted name
10573
+ * escapes `targetDir` and takes the recursive delete with it. This file
10574
+ * already had `isInside` and applied it on the copy path but not here.
10575
+ *
10576
+ * The strict-subdirectory requirement matters separately: `isInside` allows
10577
+ * equality by design, and an empty or `.` name resolves `skillDir` to
10578
+ * `targetDir` itself — deleting every installed skill (WS-097).
10579
+ */
10192
10580
  async removeSkillFiles(name, scope) {
10193
10581
  const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
10194
- const skillDir = path24.join(targetDir, name);
10582
+ const root = path25.resolve(targetDir);
10583
+ const skillDir = path25.resolve(path25.join(targetDir, name));
10584
+ if (skillDir === root || !isInside(skillDir, root)) {
10585
+ throw new FsError({
10586
+ message: `Refusing to delete skill files outside the skills directory: ${name}`,
10587
+ code: ERROR_CODES.FS_DELETE_FAILED,
10588
+ path: skillDir,
10589
+ context: { reason: "path_traversal", skillName: name, scope }
10590
+ });
10591
+ }
10195
10592
  await fs15.rm(skillDir, { recursive: true, force: true });
10196
10593
  }
10197
10594
  /**
@@ -10227,7 +10624,7 @@ async function entryIsDirectory(dir, entry) {
10227
10624
  if (entry.isDirectory()) return true;
10228
10625
  if (entry.isSymbolicLink()) {
10229
10626
  try {
10230
- return (await fs15.stat(path24.join(dir, entry.name))).isDirectory();
10627
+ return (await fs15.stat(path25.join(dir, entry.name))).isDirectory();
10231
10628
  } catch {
10232
10629
  return false;
10233
10630
  }
@@ -10238,8 +10635,8 @@ async function collectFiles(dir, baseDir) {
10238
10635
  const results = [];
10239
10636
  const entries = await fs15.readdir(dir, { withFileTypes: true });
10240
10637
  for (const entry of entries) {
10241
- const fullPath = path24.join(dir, entry.name);
10242
- const relPath = path24.relative(baseDir, fullPath);
10638
+ const fullPath = path25.join(dir, entry.name);
10639
+ const relPath = path25.relative(baseDir, fullPath);
10243
10640
  if (entry.isDirectory()) {
10244
10641
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
10245
10642
  results.push(...await collectFiles(fullPath, baseDir));
@@ -10318,7 +10715,7 @@ function createSkillsPlugin(opts) {
10318
10715
  function makeInstaller(skillLoader, projectRoot, registryAdapters) {
10319
10716
  const paths = resolveWstackPaths({ projectRoot });
10320
10717
  return new SkillInstaller({
10321
- manifestPath: path25.join(paths.configDir, "installed-skills.json"),
10718
+ manifestPath: path26.join(paths.configDir, "installed-skills.json"),
10322
10719
  projectSkillsDir: paths.inProjectSkills,
10323
10720
  globalSkillsDir: paths.globalSkills,
10324
10721
  projectHash: paths.projectHash,
@@ -10346,7 +10743,8 @@ ${lines.join("\n\n")}
10346
10743
  }
10347
10744
  const skill = await skillLoader.find(args.trim());
10348
10745
  if (!skill) return { message: `Skill "${args.trim()}" not found.` };
10349
- return { message: await skillLoader.readBody(skill.name) };
10746
+ const body = capSkillBody(stripFrontmatter(await skillLoader.readBody(skill.name)));
10747
+ return { message: body };
10350
10748
  }
10351
10749
  };
10352
10750
  }
@@ -10385,9 +10783,32 @@ function buildSkillGeneratorCommand(skillLoader) {
10385
10783
  return ` ${src} ${e.name}
10386
10784
  ${e.trigger}`;
10387
10785
  });
10388
- return { message: `Available Skills:
10786
+ let message = `Available Skills:
10389
10787
  ${lines.join("\n\n")}
10390
- ` };
10788
+ `;
10789
+ const diag = skillLoader.diagnostics?.();
10790
+ if (diag && (diag.shadowed.length > 0 || diag.skipped.length > 0)) {
10791
+ const notes = [];
10792
+ if (diag.shadowed.length > 0) {
10793
+ notes.push(color.dim("Shadowed (hidden by a higher-priority layer):"));
10794
+ for (const s of diag.shadowed) {
10795
+ notes.push(
10796
+ color.dim(` \u26A0 ${s.name} (${s.source}) \u2190 overridden by ${s.shadowedBy}`)
10797
+ );
10798
+ }
10799
+ }
10800
+ if (diag.skipped.length > 0) {
10801
+ notes.push(color.dim("Skipped (malformed SKILL.md):"));
10802
+ for (const k of diag.skipped) {
10803
+ const name = k.name ? ` "${k.name}"` : "";
10804
+ notes.push(color.dim(` \u2717 ${k.entry}${name} \u2014 ${k.reason}`));
10805
+ }
10806
+ }
10807
+ message += `
10808
+ ${notes.join("\n")}
10809
+ `;
10810
+ }
10811
+ return { message };
10391
10812
  }
10392
10813
  if (sub === "validate") {
10393
10814
  const name = rest[0];
@@ -10444,7 +10865,10 @@ ${lines.join("\n\n")}
10444
10865
  if (!skill) return { message: `Skill "${skillName}" not found.` };
10445
10866
  try {
10446
10867
  await openInEditor(skill.path);
10447
- return { message: `Opening ${skill.path} in your editor\u2026` };
10868
+ skillLoader.invalidateCache();
10869
+ return {
10870
+ message: `Opening ${skill.path} in your editor\u2026 (skill cache cleared \u2014 changes load on next use)`
10871
+ };
10448
10872
  } catch (err) {
10449
10873
  return { message: `\u2717 ${toErrorMessage(err)}` };
10450
10874
  }
@@ -10670,7 +11094,7 @@ function resolveImportSourceDir(tool, opts) {
10670
11094
  const entry = IMPORT_SOURCE_TOOLS.find((t) => t.id === tool);
10671
11095
  if (!entry) return void 0;
10672
11096
  const base = opts.global ? opts.homeDir ?? os7.homedir() : opts.projectRoot;
10673
- return path25.join(base, "." + entry.id, entry.subdir);
11097
+ return path26.join(base, "." + entry.id, entry.subdir);
10674
11098
  }
10675
11099
  function buildSkillImportCommand(skillLoader) {
10676
11100
  return {
@@ -10711,7 +11135,7 @@ function buildSkillImportCommand(skillLoader) {
10711
11135
  };
10712
11136
  }
10713
11137
  } else if (positional) {
10714
- srcDir = path25.resolve(ctx.projectRoot, positional);
11138
+ srcDir = path26.resolve(ctx.projectRoot, positional);
10715
11139
  } else {
10716
11140
  return {
10717
11141
  message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
@@ -10838,14 +11262,14 @@ function truncate(s, max) {
10838
11262
  }
10839
11263
 
10840
11264
  // src/plugins/sync-plugin.ts
10841
- import * as path27 from "node:path";
11265
+ import * as path28 from "node:path";
10842
11266
  init_error();
10843
11267
 
10844
11268
  // src/storage/cloud-sync.ts
10845
11269
  init_atomic_write();
10846
11270
  init_errors();
10847
11271
  import * as fs16 from "node:fs/promises";
10848
- import * as path26 from "node:path";
11272
+ import * as path27 from "node:path";
10849
11273
  import { createHash as createHash9 } from "node:crypto";
10850
11274
  var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
10851
11275
  var CloudSync = class {
@@ -10853,8 +11277,8 @@ var CloudSync = class {
10853
11277
  this.paths = paths;
10854
11278
  this.getConfig = getConfig;
10855
11279
  this.setConfig = setConfig;
10856
- this.statePath = path26.join(paths.configDir, "sync-state.json");
10857
- this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path26.join(this.paths.configDir, "config.json"));
11280
+ this.statePath = path27.join(paths.configDir, "sync-state.json");
11281
+ this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path27.join(this.paths.configDir, "config.json"));
10858
11282
  }
10859
11283
  paths;
10860
11284
  getConfig;
@@ -11134,13 +11558,13 @@ var CloudSync = class {
11134
11558
  const localPath = this.categoryToPath(cat);
11135
11559
  if (!localPath) continue;
11136
11560
  try {
11137
- const stat6 = await fs16.lstat(localPath);
11138
- if (stat6.isSymbolicLink()) continue;
11139
- if (stat6.isDirectory()) {
11561
+ const stat7 = await fs16.lstat(localPath);
11562
+ if (stat7.isSymbolicLink()) continue;
11563
+ if (stat7.isDirectory()) {
11140
11564
  const files = await this.walkDir(localPath, localPath);
11141
11565
  for (const file of files) {
11142
11566
  const content = await fs16.readFile(file, "utf8");
11143
- const rel = path26.relative(localPath, file).replace(/\\/g, "/");
11567
+ const rel = path27.relative(localPath, file).replace(/\\/g, "/");
11144
11568
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
11145
11569
  hashes.push(`${cat}/${rel}\0${content}`);
11146
11570
  }
@@ -11161,13 +11585,13 @@ var CloudSync = class {
11161
11585
  const localPath = this.categoryToPath(cat);
11162
11586
  if (!localPath) continue;
11163
11587
  try {
11164
- const stat6 = await fs16.lstat(localPath);
11165
- if (stat6.isSymbolicLink()) continue;
11166
- if (stat6.isDirectory()) {
11588
+ const stat7 = await fs16.lstat(localPath);
11589
+ if (stat7.isSymbolicLink()) continue;
11590
+ if (stat7.isDirectory()) {
11167
11591
  const files = await this.walkDir(localPath, localPath);
11168
11592
  for (const file of files) {
11169
11593
  const content = await fs16.readFile(file, "utf8");
11170
- const rel = path26.relative(localPath, file).replace(/\\/g, "/");
11594
+ const rel = path27.relative(localPath, file).replace(/\\/g, "/");
11171
11595
  hashes.push(`${cat}/${rel}\0${content}`);
11172
11596
  }
11173
11597
  } else {
@@ -11201,7 +11625,7 @@ var CloudSync = class {
11201
11625
  const entries = await fs16.readdir(dir, { withFileTypes: true });
11202
11626
  entries.sort((a, b) => a.name.localeCompare(b.name));
11203
11627
  for (const entry of entries) {
11204
- const full = path26.join(dir, entry.name);
11628
+ const full = path27.join(dir, entry.name);
11205
11629
  if (entry.isSymbolicLink()) continue;
11206
11630
  if (entry.isDirectory()) {
11207
11631
  results.push(...await this.walkDir(full, base));
@@ -11214,25 +11638,25 @@ var CloudSync = class {
11214
11638
  };
11215
11639
  async function preparePulledDestination(cat, localPath, destPath, remotePath) {
11216
11640
  const directoryBacked = cat === "skills" || cat === "prompts";
11217
- const rootPath = directoryBacked ? localPath : path26.dirname(localPath);
11641
+ const rootPath = directoryBacked ? localPath : path27.dirname(localPath);
11218
11642
  const rootStat = await lstatIfExists(rootPath);
11219
11643
  if (rootStat?.isSymbolicLink()) {
11220
11644
  throw unsafePulledSymlinkError(remotePath, rootPath);
11221
11645
  }
11222
11646
  if (directoryBacked) {
11223
- const relativeParent = path26.relative(rootPath, path26.dirname(destPath));
11647
+ const relativeParent = path27.relative(rootPath, path27.dirname(destPath));
11224
11648
  let cursor = rootPath;
11225
11649
  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);
11650
+ for (const segment of relativeParent.split(path27.sep)) {
11651
+ cursor = path27.join(cursor, segment);
11652
+ const stat7 = await lstatIfExists(cursor);
11653
+ if (stat7?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
11230
11654
  }
11231
11655
  }
11232
11656
  }
11233
11657
  const destStat = await lstatIfExists(destPath);
11234
11658
  if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
11235
- await fs16.mkdir(path26.dirname(destPath), { recursive: true });
11659
+ await fs16.mkdir(path27.dirname(destPath), { recursive: true });
11236
11660
  }
11237
11661
  async function lstatIfExists(filePath) {
11238
11662
  try {
@@ -11262,9 +11686,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
11262
11686
  return localPath;
11263
11687
  }
11264
11688
  if (!rel) return localPath;
11265
- const normalizedRel = path26.normalize(rel);
11266
- const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path26.sep}`);
11267
- if (path26.isAbsolute(normalizedRel) || traversesUp) {
11689
+ const normalizedRel = path27.normalize(rel);
11690
+ const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path27.sep}`);
11691
+ if (path27.isAbsolute(normalizedRel) || traversesUp) {
11268
11692
  throw new FsError({
11269
11693
  message: `Refusing CloudSync path traversal: ${remotePath}`,
11270
11694
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -11272,10 +11696,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
11272
11696
  context: { reason: "path_traversal", normalizedRel }
11273
11697
  });
11274
11698
  }
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)) {
11699
+ const dest = path27.resolve(localPath, normalizedRel);
11700
+ const root = path27.resolve(localPath);
11701
+ const relative5 = path27.relative(root, dest);
11702
+ if (relative5.startsWith("..") || path27.isAbsolute(relative5)) {
11279
11703
  throw new FsError({
11280
11704
  message: `Refusing CloudSync path outside category root: ${remotePath}`,
11281
11705
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -11318,7 +11742,7 @@ function createSyncPlugin(opts) {
11318
11742
  api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
11319
11743
  return;
11320
11744
  }
11321
- const syncConfigPath = paths.syncConfig ?? path27.join(paths.configDir, "sync.json");
11745
+ const syncConfigPath = paths.syncConfig ?? path28.join(paths.configDir, "sync.json");
11322
11746
  cloud = new CloudSync(
11323
11747
  paths,
11324
11748
  () => {
@@ -11329,7 +11753,7 @@ function createSyncPlugin(opts) {
11329
11753
  await persistSyncConfig(syncConfigPath, cfg, vault);
11330
11754
  configStore?.update({ sync: cfg });
11331
11755
  },
11332
- () => path27.join(paths.configDir, "config.json")
11756
+ () => path28.join(paths.configDir, "config.json")
11333
11757
  );
11334
11758
  void cloud.loadState();
11335
11759
  api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
@@ -11532,8 +11956,14 @@ export {
11532
11956
  definePlugin,
11533
11957
  diffPluginConfig,
11534
11958
  emitReviewIfChanged,
11959
+ integrateFindings,
11535
11960
  loadPlugins,
11961
+ maybeCompactReviewStores,
11962
+ parseChimeraReviewReport,
11536
11963
  parseReviewSeverity,
11964
+ persistReviewReport,
11965
+ recordCompletedReview,
11966
+ recordStartedReview,
11537
11967
  redactPluginConfig,
11538
11968
  resolvePluginConfig,
11539
11969
  resolvePluginManifestConfig,