@wrongstack/core 0.296.4 → 0.298.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (820) hide show
  1. package/dist/chronicle/index.js +126 -22
  2. package/dist/chronicle/project-server-client.d.ts +12 -0
  3. package/dist/chronicle/project-server-protocol.d.ts +22 -0
  4. package/dist/chronicle/project-server.js +1076 -283
  5. package/dist/coordination/agents/index.js +136 -1
  6. package/dist/coordination/agents/role-skills.d.ts +3 -2
  7. package/dist/coordination/brain-cache.d.ts +14 -0
  8. package/dist/coordination/brain-trace.d.ts +2 -1
  9. package/dist/coordination/director/director-task-registry.d.ts +12 -0
  10. package/dist/coordination/fleet-supervisor.d.ts +21 -0
  11. package/dist/coordination/index.d.ts +23 -21
  12. package/dist/coordination/index.js +16514 -15945
  13. package/dist/coordination/mail-tools.d.ts +3 -3
  14. package/dist/coordination/mailbox-credential-store.d.ts +22 -2
  15. package/dist/coordination/mailbox-credential-throttle.d.ts +63 -0
  16. package/dist/coordination/mailbox-http-router.d.ts +6 -0
  17. package/dist/coordination/mailbox-project-server-client.d.ts +16 -0
  18. package/dist/coordination/mailbox-project-server-protocol.d.ts +43 -5
  19. package/dist/coordination/mailbox-project-server.js +1270 -289
  20. package/dist/coordination/provider-status-tracker.d.ts +2 -0
  21. package/dist/coordination/remote-mailbox-credential-store.d.ts +5 -5
  22. package/dist/coordination/remote-mailbox.d.ts +30 -4
  23. package/dist/coordination/sqlite-mailbox-credentials.d.ts +11 -0
  24. package/dist/core/context.d.ts +5 -5
  25. package/dist/core/fallback-profile-manager.d.ts +14 -0
  26. package/dist/core/index.js +624 -168
  27. package/dist/core/instruction-bundle.d.ts +12 -0
  28. package/dist/core/system-prompt-builder.d.ts +14 -0
  29. package/dist/core/system-prompt-skill-bodies.d.ts +1 -1
  30. package/dist/core/system-prompt-skill-text.d.ts +1 -2
  31. package/dist/defaults/index.js +2393 -1302
  32. package/dist/design/index.js +47 -8
  33. package/dist/execution/design-materialize.d.ts +22 -0
  34. package/dist/execution/index.js +582 -285
  35. package/dist/execution/skill-loader.d.ts +10 -1
  36. package/dist/execution/tool-error-taxonomy.d.ts +31 -0
  37. package/dist/execution/tool-executor.d.ts +1 -0
  38. package/dist/goal/index.js +71 -17
  39. package/dist/goal/phase-store.d.ts +7 -0
  40. package/dist/hooks/index.js +5 -0
  41. package/dist/hq/auth-audit.d.ts +6 -0
  42. package/dist/hq/auth-store.d.ts +59 -3
  43. package/dist/hq/index.js +680 -163
  44. package/dist/hq/kanban-store.d.ts +3 -0
  45. package/dist/hq/persistence/event-log.d.ts +25 -0
  46. package/dist/hq/persistence.d.ts +1 -1
  47. package/dist/hq/protocol/browser.d.ts +2 -1
  48. package/dist/hq/protocol/client.d.ts +18 -1
  49. package/dist/hq/protocol/core.d.ts +5 -16
  50. package/dist/hq/protocol/envelope.d.ts +29 -0
  51. package/dist/hq/protocol/governance.d.ts +34 -0
  52. package/dist/hq/protocol/peer.d.ts +55 -0
  53. package/dist/hq/protocol/project.d.ts +3 -0
  54. package/dist/hq/protocol/resume.d.ts +56 -0
  55. package/dist/hq/protocol.d.ts +11 -8
  56. package/dist/hq/protocol.js +675 -0
  57. package/dist/hq/publisher.d.ts +31 -2
  58. package/dist/hq/session-bridge.d.ts +8 -0
  59. package/dist/index.js +7197 -4006
  60. package/dist/infrastructure/index.js +198 -101
  61. package/dist/kernel/events/session-events.d.ts +3 -0
  62. package/dist/kernel/events/tool-events.d.ts +3 -1
  63. package/dist/models/index.js +1 -1
  64. package/dist/observability/index.d.ts +1 -1
  65. package/dist/observability/index.js +103 -5
  66. package/dist/observability/metrics.d.ts +37 -0
  67. package/dist/observability/prometheus.d.ts +11 -0
  68. package/dist/plugin/index.d.ts +5 -1
  69. package/dist/plugin/index.js +965 -511
  70. package/dist/plugins/auto-review-plugin.d.ts +6 -0
  71. package/dist/plugins/review-store-maintenance.d.ts +26 -0
  72. package/dist/plugins/review-types.d.ts +6 -0
  73. package/dist/security/capabilities.d.ts +45 -1
  74. package/dist/security/error-sanitize.d.ts +49 -0
  75. package/dist/security/file-permissions.d.ts +41 -0
  76. package/dist/security/index.d.ts +9 -6
  77. package/dist/security/index.js +3007 -2032
  78. package/dist/security/permission-policy.d.ts +55 -3
  79. package/dist/security/secret-vault.d.ts +17 -0
  80. package/dist/security/totp.d.ts +86 -0
  81. package/dist/skills/frontmatter.d.ts +12 -1
  82. package/dist/skills/github-fetcher.d.ts +48 -0
  83. package/dist/skills/index.js +137 -26
  84. package/dist/skills/limits.d.ts +19 -0
  85. package/dist/skills/skill-installer.d.ts +13 -0
  86. package/dist/storage/file-session-writer.d.ts +23 -0
  87. package/dist/storage/index.js +1140 -905
  88. package/dist/storage/provider-config-watcher.d.ts +1 -0
  89. package/dist/storage/session-helpers.d.ts +1 -0
  90. package/dist/storage/session-reader.d.ts +0 -7
  91. package/dist/storage/session-store/types.d.ts +12 -1
  92. package/dist/storage/session-store.d.ts +11 -2
  93. package/dist/storage/session-workspace-checkpoints.d.ts +5 -0
  94. package/dist/tools/fallback-manage-tools.d.ts +6 -0
  95. package/dist/tools/index.js +305 -133
  96. package/dist/tools/mcp-use.d.ts +1 -1
  97. package/dist/types/blocks.d.ts +7 -0
  98. package/dist/types/config/autonomy.d.ts +12 -3
  99. package/dist/types/config/mcp-features.d.ts +15 -1
  100. package/dist/types/config/root.d.ts +10 -4
  101. package/dist/types/context-window.d.ts +15 -0
  102. package/dist/types/index.d.ts +1 -1
  103. package/dist/types/observability.d.ts +13 -0
  104. package/dist/types/secret-vault.d.ts +8 -0
  105. package/dist/types/session.d.ts +42 -0
  106. package/dist/types/skill.d.ts +56 -0
  107. package/dist/types/tool-executor.d.ts +2 -0
  108. package/dist/utils/continuous-memory-profiler.d.ts +35 -0
  109. package/dist/utils/env-typed.d.ts +64 -0
  110. package/dist/utils/glob-match.d.ts +21 -1
  111. package/dist/utils/heap-watchdog-types.d.ts +62 -0
  112. package/dist/utils/heap-watchdog.d.ts +15 -34
  113. package/dist/utils/heap-watchdog.js +592 -18
  114. package/dist/utils/incoming-images.d.ts +19 -0
  115. package/dist/utils/index.d.ts +15 -11
  116. package/dist/utils/index.js +1425 -545
  117. package/dist/utils/memory-flight-recorder.d.ts +47 -0
  118. package/dist/utils/path-segment.d.ts +29 -0
  119. package/dist/utils/tool-name.d.ts +34 -0
  120. package/dist/utils/win32-cmd.d.ts +25 -0
  121. package/dist/worktree/index.js +5 -0
  122. package/package.json +11 -3
  123. package/skills/chimera/SKILL.md +16 -4
  124. package/skills/data-governance/SKILL.md +92 -0
  125. package/skills/wrongstack-kanban/SKILL.md +129 -0
  126. package/skills/wrongstack-kanban/agents/openai.yaml +4 -0
  127. package/skills/wrongstack-mailbox-mcp/SKILL.md +72 -0
  128. package/skills/wrongstack-mailbox-mcp/agents/openai.yaml +4 -0
  129. package/dist/agent-status-helpers.d.ts.map +0 -1
  130. package/dist/agent-status-tracker.d.ts.map +0 -1
  131. package/dist/boot.d.ts.map +0 -1
  132. package/dist/chronicle/context.d.ts.map +0 -1
  133. package/dist/chronicle/decision-adapter.d.ts.map +0 -1
  134. package/dist/chronicle/domain-adapter.d.ts.map +0 -1
  135. package/dist/chronicle/event-hash.d.ts.map +0 -1
  136. package/dist/chronicle/file-observer.d.ts.map +0 -1
  137. package/dist/chronicle/health-monitor.d.ts.map +0 -1
  138. package/dist/chronicle/identity.d.ts.map +0 -1
  139. package/dist/chronicle/index.d.ts.map +0 -1
  140. package/dist/chronicle/index.js.map +0 -7
  141. package/dist/chronicle/journal.d.ts.map +0 -1
  142. package/dist/chronicle/legacy-journal-import.d.ts.map +0 -1
  143. package/dist/chronicle/metrics-store.d.ts.map +0 -1
  144. package/dist/chronicle/partition-filename.d.ts.map +0 -1
  145. package/dist/chronicle/partition-range-cache.d.ts.map +0 -1
  146. package/dist/chronicle/process-adapter.d.ts.map +0 -1
  147. package/dist/chronicle/project-access.d.ts.map +0 -1
  148. package/dist/chronicle/project-server-client.d.ts.map +0 -1
  149. package/dist/chronicle/project-server-endpoint.d.ts.map +0 -1
  150. package/dist/chronicle/project-server-protocol.d.ts.map +0 -1
  151. package/dist/chronicle/project-server.d.ts.map +0 -1
  152. package/dist/chronicle/project-server.js.map +0 -7
  153. package/dist/chronicle/prompt-manifest.d.ts.map +0 -1
  154. package/dist/chronicle/provider-adapter.d.ts.map +0 -1
  155. package/dist/chronicle/query.d.ts.map +0 -1
  156. package/dist/chronicle/review-adapter.d.ts.map +0 -1
  157. package/dist/chronicle/rollup-adapter.d.ts.map +0 -1
  158. package/dist/chronicle/sink.d.ts.map +0 -1
  159. package/dist/chronicle/sqlite-journal.d.ts.map +0 -1
  160. package/dist/chronicle/sqlite-query.d.ts.map +0 -1
  161. package/dist/chronicle/stream-adapter.d.ts.map +0 -1
  162. package/dist/chronicle/tool-adapter.d.ts.map +0 -1
  163. package/dist/chronicle/types.d.ts.map +0 -1
  164. package/dist/coordination/adaptive-concurrency.d.ts.map +0 -1
  165. package/dist/coordination/agent-bridge.d.ts.map +0 -1
  166. package/dist/coordination/agent-monitor.d.ts.map +0 -1
  167. package/dist/coordination/agent-subagent-runner.d.ts.map +0 -1
  168. package/dist/coordination/agents/agent-prompts.d.ts.map +0 -1
  169. package/dist/coordination/agents/index.d.ts.map +0 -1
  170. package/dist/coordination/agents/index.js.map +0 -7
  171. package/dist/coordination/agents/phase1-discovery.d.ts.map +0 -1
  172. package/dist/coordination/agents/phase2-planning.d.ts.map +0 -1
  173. package/dist/coordination/agents/phase3-build.d.ts.map +0 -1
  174. package/dist/coordination/agents/phase3-techstack.d.ts.map +0 -1
  175. package/dist/coordination/agents/phase3-wave1-platform.d.ts.map +0 -1
  176. package/dist/coordination/agents/phase3-wave2-meta.d.ts.map +0 -1
  177. package/dist/coordination/agents/phase4-verify.d.ts.map +0 -1
  178. package/dist/coordination/agents/phase5-review.d.ts.map +0 -1
  179. package/dist/coordination/agents/phase6-domain.d.ts.map +0 -1
  180. package/dist/coordination/agents/phase7-knowledge.d.ts.map +0 -1
  181. package/dist/coordination/agents/phase8-delivery.d.ts.map +0 -1
  182. package/dist/coordination/agents/phase8-wave3-products.d.ts.map +0 -1
  183. package/dist/coordination/agents/phase9-meta.d.ts.map +0 -1
  184. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts.map +0 -1
  185. package/dist/coordination/agents/project-agent-config-validation.d.ts.map +0 -1
  186. package/dist/coordination/agents/project-agent-consolidation.d.ts.map +0 -1
  187. package/dist/coordination/agents/project-agent-files.d.ts.map +0 -1
  188. package/dist/coordination/agents/project-agent-identity-types.d.ts.map +0 -1
  189. package/dist/coordination/agents/project-agent-identity.d.ts.map +0 -1
  190. package/dist/coordination/agents/project-agent-knowledge-manifests.d.ts.map +0 -1
  191. package/dist/coordination/agents/project-agent-learning-entries.d.ts.map +0 -1
  192. package/dist/coordination/agents/project-agent-learning-normalize.d.ts.map +0 -1
  193. package/dist/coordination/agents/project-agent-learning-policy.d.ts.map +0 -1
  194. package/dist/coordination/agents/project-agent-learning-structured.d.ts.map +0 -1
  195. package/dist/coordination/agents/project-agent-paths.d.ts.map +0 -1
  196. package/dist/coordination/agents/project-agent-profile.d.ts.map +0 -1
  197. package/dist/coordination/agents/role-skills.d.ts.map +0 -1
  198. package/dist/coordination/agents/types.d.ts.map +0 -1
  199. package/dist/coordination/agents.d.ts.map +0 -1
  200. package/dist/coordination/auto-extend.d.ts.map +0 -1
  201. package/dist/coordination/autonomous-brain.d.ts.map +0 -1
  202. package/dist/coordination/autonomous-coordinator.d.ts.map +0 -1
  203. package/dist/coordination/brain-cache.d.ts.map +0 -1
  204. package/dist/coordination/brain-heuristics.d.ts.map +0 -1
  205. package/dist/coordination/brain-ledger.d.ts.map +0 -1
  206. package/dist/coordination/brain-monitor.d.ts.map +0 -1
  207. package/dist/coordination/brain-rules.d.ts.map +0 -1
  208. package/dist/coordination/brain-telemetry.d.ts.map +0 -1
  209. package/dist/coordination/brain-trace.d.ts.map +0 -1
  210. package/dist/coordination/brain.d.ts.map +0 -1
  211. package/dist/coordination/change-manager.d.ts.map +0 -1
  212. package/dist/coordination/checkpoint-wiring.d.ts.map +0 -1
  213. package/dist/coordination/collab-bus.d.ts.map +0 -1
  214. package/dist/coordination/collab-debug-types.d.ts.map +0 -1
  215. package/dist/coordination/collab-debug.d.ts.map +0 -1
  216. package/dist/coordination/collab-director-host.d.ts.map +0 -1
  217. package/dist/coordination/commit-safety.d.ts.map +0 -1
  218. package/dist/coordination/consensus-protocol.d.ts.map +0 -1
  219. package/dist/coordination/coordinator/error-classifier.d.ts.map +0 -1
  220. package/dist/coordination/delegate-tool.d.ts.map +0 -1
  221. package/dist/coordination/dep-watcher-bridge.d.ts.map +0 -1
  222. package/dist/coordination/dep-watcher.d.ts.map +0 -1
  223. package/dist/coordination/director/director-btw-notes.d.ts.map +0 -1
  224. package/dist/coordination/director/director-budget-policy.d.ts.map +0 -1
  225. package/dist/coordination/director/director-collab.d.ts.map +0 -1
  226. package/dist/coordination/director/director-errors.d.ts.map +0 -1
  227. package/dist/coordination/director/director-task-registry.d.ts.map +0 -1
  228. package/dist/coordination/director/director-toolset.d.ts.map +0 -1
  229. package/dist/coordination/director-basic-tools.d.ts.map +0 -1
  230. package/dist/coordination/director-collab-tools.d.ts.map +0 -1
  231. package/dist/coordination/director-host-contracts.d.ts.map +0 -1
  232. package/dist/coordination/director-input-helpers.d.ts.map +0 -1
  233. package/dist/coordination/director-kanban-queue-helpers.d.ts.map +0 -1
  234. package/dist/coordination/director-options.d.ts.map +0 -1
  235. package/dist/coordination/director-prompts.d.ts.map +0 -1
  236. package/dist/coordination/director-quality-gate-tool.d.ts.map +0 -1
  237. package/dist/coordination/director-session.d.ts.map +0 -1
  238. package/dist/coordination/director-spawn-model.d.ts.map +0 -1
  239. package/dist/coordination/director-tools.d.ts.map +0 -1
  240. package/dist/coordination/director.d.ts.map +0 -1
  241. package/dist/coordination/dispatcher.d.ts.map +0 -1
  242. package/dist/coordination/file-author-tracker.d.ts.map +0 -1
  243. package/dist/coordination/fleet-bus.d.ts.map +0 -1
  244. package/dist/coordination/fleet-event-validation.d.ts.map +0 -1
  245. package/dist/coordination/fleet-manager.d.ts.map +0 -1
  246. package/dist/coordination/fleet-spawn.d.ts.map +0 -1
  247. package/dist/coordination/fleet-status-tool.d.ts.map +0 -1
  248. package/dist/coordination/fleet-supervisor.d.ts.map +0 -1
  249. package/dist/coordination/fleet.d.ts.map +0 -1
  250. package/dist/coordination/global-mailbox-completion.d.ts.map +0 -1
  251. package/dist/coordination/global-mailbox-paths.d.ts.map +0 -1
  252. package/dist/coordination/icoordinator.d.ts.map +0 -1
  253. package/dist/coordination/ifleet-manager.d.ts.map +0 -1
  254. package/dist/coordination/in-memory-transport.d.ts.map +0 -1
  255. package/dist/coordination/index.d.ts.map +0 -1
  256. package/dist/coordination/index.js.map +0 -7
  257. package/dist/coordination/knowledge-graph.d.ts.map +0 -1
  258. package/dist/coordination/large-answer-store.d.ts.map +0 -1
  259. package/dist/coordination/mail-tools.d.ts.map +0 -1
  260. package/dist/coordination/mailbox-actions.d.ts.map +0 -1
  261. package/dist/coordination/mailbox-auth-types.d.ts.map +0 -1
  262. package/dist/coordination/mailbox-codecs.d.ts.map +0 -1
  263. package/dist/coordination/mailbox-constants.d.ts.map +0 -1
  264. package/dist/coordination/mailbox-credential-store.d.ts.map +0 -1
  265. package/dist/coordination/mailbox-events.d.ts.map +0 -1
  266. package/dist/coordination/mailbox-health.d.ts.map +0 -1
  267. package/dist/coordination/mailbox-hooks.d.ts.map +0 -1
  268. package/dist/coordination/mailbox-http-auth.d.ts.map +0 -1
  269. package/dist/coordination/mailbox-http-rate-limit.d.ts.map +0 -1
  270. package/dist/coordination/mailbox-http-router.d.ts.map +0 -1
  271. package/dist/coordination/mailbox-http-validation.d.ts.map +0 -1
  272. package/dist/coordination/mailbox-message-codec.d.ts.map +0 -1
  273. package/dist/coordination/mailbox-parse-state.d.ts.map +0 -1
  274. package/dist/coordination/mailbox-project-server-client.d.ts.map +0 -1
  275. package/dist/coordination/mailbox-project-server-endpoint.d.ts.map +0 -1
  276. package/dist/coordination/mailbox-project-server-protocol.d.ts.map +0 -1
  277. package/dist/coordination/mailbox-project-server.d.ts.map +0 -1
  278. package/dist/coordination/mailbox-project-server.js.map +0 -7
  279. package/dist/coordination/mailbox-receipt-folding.d.ts.map +0 -1
  280. package/dist/coordination/mailbox-registry-codec.d.ts.map +0 -1
  281. package/dist/coordination/mailbox-retention-state.d.ts.map +0 -1
  282. package/dist/coordination/mailbox-status-mappers.d.ts.map +0 -1
  283. package/dist/coordination/mailbox-tool.d.ts.map +0 -1
  284. package/dist/coordination/mailbox-type-properties.d.ts.map +0 -1
  285. package/dist/coordination/mailbox-types.d.ts.map +0 -1
  286. package/dist/coordination/model-matrix.d.ts.map +0 -1
  287. package/dist/coordination/multi-agent-coordinator.d.ts.map +0 -1
  288. package/dist/coordination/multi-agent-timeout.d.ts.map +0 -1
  289. package/dist/coordination/null-fleet-bus.d.ts.map +0 -1
  290. package/dist/coordination/package-author-tracker.d.ts.map +0 -1
  291. package/dist/coordination/package-outdated-watcher.d.ts.map +0 -1
  292. package/dist/coordination/provider-status-tracker.d.ts.map +0 -1
  293. package/dist/coordination/remote-mailbox-credential-store.d.ts.map +0 -1
  294. package/dist/coordination/remote-mailbox.d.ts.map +0 -1
  295. package/dist/coordination/single-instance-mailbox.d.ts.map +0 -1
  296. package/dist/coordination/spawn-budget.d.ts.map +0 -1
  297. package/dist/coordination/sqlite-mailbox-compaction.d.ts.map +0 -1
  298. package/dist/coordination/sqlite-mailbox-credentials.d.ts.map +0 -1
  299. package/dist/coordination/sqlite-mailbox-rows.d.ts.map +0 -1
  300. package/dist/coordination/sqlite-mailbox-schema.d.ts.map +0 -1
  301. package/dist/coordination/sqlite-mailbox.d.ts.map +0 -1
  302. package/dist/coordination/subagent-budget.d.ts.map +0 -1
  303. package/dist/coordination/subagent-nicknames.d.ts.map +0 -1
  304. package/dist/coordination/subagent-result-tool.d.ts.map +0 -1
  305. package/dist/coordination/task-auctioneer.d.ts.map +0 -1
  306. package/dist/coordination/task-dag.d.ts.map +0 -1
  307. package/dist/coordination/techstack-mailbox-consumer.d.ts.map +0 -1
  308. package/dist/coordination/transport.d.ts.map +0 -1
  309. package/dist/coordination/worktree-task-runner.d.ts.map +0 -1
  310. package/dist/core/agent-internals.d.ts.map +0 -1
  311. package/dist/core/agent-loop.d.ts.map +0 -1
  312. package/dist/core/agent-response.d.ts.map +0 -1
  313. package/dist/core/agent-tools.d.ts.map +0 -1
  314. package/dist/core/agent-types.d.ts.map +0 -1
  315. package/dist/core/agent.d.ts.map +0 -1
  316. package/dist/core/btw.d.ts.map +0 -1
  317. package/dist/core/context.d.ts.map +0 -1
  318. package/dist/core/continue-intent.d.ts.map +0 -1
  319. package/dist/core/continue-to-next-iteration.d.ts.map +0 -1
  320. package/dist/core/conversation-state.d.ts.map +0 -1
  321. package/dist/core/fallback-model.d.ts.map +0 -1
  322. package/dist/core/fallback-profile-manager.d.ts.map +0 -1
  323. package/dist/core/fleet-pulse.d.ts.map +0 -1
  324. package/dist/core/index.d.ts.map +0 -1
  325. package/dist/core/index.js.map +0 -7
  326. package/dist/core/input-builder.d.ts.map +0 -1
  327. package/dist/core/instruction-bundle.d.ts.map +0 -1
  328. package/dist/core/iteration-limit.d.ts.map +0 -1
  329. package/dist/core/mailbox-loop.d.ts.map +0 -1
  330. package/dist/core/model-availability-calendar.d.ts.map +0 -1
  331. package/dist/core/model-ref.d.ts.map +0 -1
  332. package/dist/core/model-ref.js.map +0 -7
  333. package/dist/core/modes/brief.d.ts.map +0 -1
  334. package/dist/core/modes/default.d.ts.map +0 -1
  335. package/dist/core/modes/teach.d.ts.map +0 -1
  336. package/dist/core/provider-runner.d.ts.map +0 -1
  337. package/dist/core/queued-messages.d.ts.map +0 -1
  338. package/dist/core/request-provider-binding.d.ts.map +0 -1
  339. package/dist/core/run-env.d.ts.map +0 -1
  340. package/dist/core/streaming-response-builder.d.ts.map +0 -1
  341. package/dist/core/system-prompt-blocks.d.ts.map +0 -1
  342. package/dist/core/system-prompt-builder.d.ts.map +0 -1
  343. package/dist/core/system-prompt-environment-probes.d.ts.map +0 -1
  344. package/dist/core/system-prompt-environment.d.ts.map +0 -1
  345. package/dist/core/system-prompt-memory-skills.d.ts.map +0 -1
  346. package/dist/core/system-prompt-plan.d.ts.map +0 -1
  347. package/dist/core/system-prompt-shell.d.ts.map +0 -1
  348. package/dist/core/system-prompt-skill-bodies.d.ts.map +0 -1
  349. package/dist/core/system-prompt-skill-text.d.ts.map +0 -1
  350. package/dist/defaults/index.d.ts.map +0 -1
  351. package/dist/defaults/index.js.map +0 -7
  352. package/dist/design/index.d.ts.map +0 -1
  353. package/dist/design/index.js.map +0 -7
  354. package/dist/execution/auto-compaction-middleware.d.ts.map +0 -1
  355. package/dist/execution/autonomous-runner.d.ts.map +0 -1
  356. package/dist/execution/autonomy-brain.d.ts.map +0 -1
  357. package/dist/execution/autonomy-prompt-contributor.d.ts.map +0 -1
  358. package/dist/execution/brain-chain.d.ts.map +0 -1
  359. package/dist/execution/brain-circuit.d.ts.map +0 -1
  360. package/dist/execution/brain-evaluation.d.ts.map +0 -1
  361. package/dist/execution/brain-runtime-constants.d.ts.map +0 -1
  362. package/dist/execution/brain-runtime.d.ts.map +0 -1
  363. package/dist/execution/compaction-core.d.ts.map +0 -1
  364. package/dist/execution/compaction-scoring.d.ts.map +0 -1
  365. package/dist/execution/compaction-summary-cache.d.ts.map +0 -1
  366. package/dist/execution/compactor.d.ts.map +0 -1
  367. package/dist/execution/council-brain.d.ts.map +0 -1
  368. package/dist/execution/council-orchestrator.d.ts.map +0 -1
  369. package/dist/execution/council-personas.d.ts.map +0 -1
  370. package/dist/execution/council-profiles.d.ts.map +0 -1
  371. package/dist/execution/council-prompts.d.ts.map +0 -1
  372. package/dist/execution/council-resolution.d.ts.map +0 -1
  373. package/dist/execution/design-color.d.ts.map +0 -1
  374. package/dist/execution/design-detect.d.ts.map +0 -1
  375. package/dist/execution/design-kit-loader.d.ts.map +0 -1
  376. package/dist/execution/design-materialize.d.ts.map +0 -1
  377. package/dist/execution/design-project-store.d.ts.map +0 -1
  378. package/dist/execution/design-tune.d.ts.map +0 -1
  379. package/dist/execution/design-verify.d.ts.map +0 -1
  380. package/dist/execution/enhance-recovery.d.ts.map +0 -1
  381. package/dist/execution/error-handler.d.ts.map +0 -1
  382. package/dist/execution/eternal-autonomy-types.d.ts.map +0 -1
  383. package/dist/execution/eternal-autonomy.d.ts.map +0 -1
  384. package/dist/execution/goal-preamble.d.ts.map +0 -1
  385. package/dist/execution/index.d.ts.map +0 -1
  386. package/dist/execution/index.js.map +0 -7
  387. package/dist/execution/intelligent-compactor.d.ts.map +0 -1
  388. package/dist/execution/model-runtime.d.ts.map +0 -1
  389. package/dist/execution/one-shot-llm.d.ts.map +0 -1
  390. package/dist/execution/parallel-eternal-engine.d.ts.map +0 -1
  391. package/dist/execution/prompt-enhancer.d.ts.map +0 -1
  392. package/dist/execution/prompt-enhancer.js.map +0 -7
  393. package/dist/execution/prompt-loader.d.ts.map +0 -1
  394. package/dist/execution/provider-runner-impl.d.ts.map +0 -1
  395. package/dist/execution/regex-patterns.d.ts.map +0 -1
  396. package/dist/execution/retry-policy.d.ts.map +0 -1
  397. package/dist/execution/selective-compactor.d.ts.map +0 -1
  398. package/dist/execution/skill-loader.d.ts.map +0 -1
  399. package/dist/execution/strategy-compactor.d.ts.map +0 -1
  400. package/dist/execution/subagent-compaction.d.ts.map +0 -1
  401. package/dist/execution/tool-executor-logging.d.ts.map +0 -1
  402. package/dist/execution/tool-executor-results.d.ts.map +0 -1
  403. package/dist/execution/tool-executor-stream.d.ts.map +0 -1
  404. package/dist/execution/tool-executor-support.d.ts.map +0 -1
  405. package/dist/execution/tool-executor.d.ts.map +0 -1
  406. package/dist/extension/extension-points.d.ts.map +0 -1
  407. package/dist/extension/index.d.ts.map +0 -1
  408. package/dist/extension/index.js.map +0 -7
  409. package/dist/extension/registry.d.ts.map +0 -1
  410. package/dist/fleet-notifier.d.ts.map +0 -1
  411. package/dist/goal/checkpoint.d.ts.map +0 -1
  412. package/dist/goal/goal-assessor.d.ts.map +0 -1
  413. package/dist/goal/goal-planner.d.ts.map +0 -1
  414. package/dist/goal/goal-runner.d.ts.map +0 -1
  415. package/dist/goal/index.d.ts.map +0 -1
  416. package/dist/goal/index.js.map +0 -7
  417. package/dist/goal/phase-board-mutations.d.ts.map +0 -1
  418. package/dist/goal/phase-graph-builder.d.ts.map +0 -1
  419. package/dist/goal/phase-orchestrator-integration.d.ts.map +0 -1
  420. package/dist/goal/phase-orchestrator-queries.d.ts.map +0 -1
  421. package/dist/goal/phase-orchestrator-runtime.d.ts.map +0 -1
  422. package/dist/goal/phase-orchestrator-types.d.ts.map +0 -1
  423. package/dist/goal/phase-orchestrator.d.ts.map +0 -1
  424. package/dist/goal/phase-store.d.ts.map +0 -1
  425. package/dist/goal/types.d.ts.map +0 -1
  426. package/dist/hooks/http-executor.d.ts.map +0 -1
  427. package/dist/hooks/index.d.ts.map +0 -1
  428. package/dist/hooks/index.js.map +0 -7
  429. package/dist/hooks/registry.d.ts.map +0 -1
  430. package/dist/hooks/runner.d.ts.map +0 -1
  431. package/dist/hooks/shell-executor.d.ts.map +0 -1
  432. package/dist/hooks/shell-hooks-equal.d.ts.map +0 -1
  433. package/dist/hq/alerts.d.ts.map +0 -1
  434. package/dist/hq/auth-audit.d.ts.map +0 -1
  435. package/dist/hq/auth-store.d.ts.map +0 -1
  436. package/dist/hq/bootstrap-store.d.ts.map +0 -1
  437. package/dist/hq/brain-bridge.d.ts.map +0 -1
  438. package/dist/hq/bridge-context.d.ts.map +0 -1
  439. package/dist/hq/commands.d.ts.map +0 -1
  440. package/dist/hq/cost-bridge.d.ts.map +0 -1
  441. package/dist/hq/exposure.d.ts.map +0 -1
  442. package/dist/hq/factory.d.ts.map +0 -1
  443. package/dist/hq/fleet-bridge.d.ts.map +0 -1
  444. package/dist/hq/index.d.ts.map +0 -1
  445. package/dist/hq/index.js.map +0 -7
  446. package/dist/hq/kanban-store.d.ts.map +0 -1
  447. package/dist/hq/mailbox-mapper.d.ts.map +0 -1
  448. package/dist/hq/persistence/event-log.d.ts.map +0 -1
  449. package/dist/hq/persistence/jsonl-io.d.ts.map +0 -1
  450. package/dist/hq/persistence/simple-log.d.ts.map +0 -1
  451. package/dist/hq/persistence/snapshot-store.d.ts.map +0 -1
  452. package/dist/hq/persistence/timeseries-store.d.ts.map +0 -1
  453. package/dist/hq/persistence.d.ts.map +0 -1
  454. package/dist/hq/protocol/brain.d.ts.map +0 -1
  455. package/dist/hq/protocol/browser.d.ts.map +0 -1
  456. package/dist/hq/protocol/client.d.ts.map +0 -1
  457. package/dist/hq/protocol/core.d.ts.map +0 -1
  458. package/dist/hq/protocol/fleet.d.ts.map +0 -1
  459. package/dist/hq/protocol/kanban.d.ts.map +0 -1
  460. package/dist/hq/protocol/mailbox.d.ts.map +0 -1
  461. package/dist/hq/protocol/mcp.d.ts.map +0 -1
  462. package/dist/hq/protocol/project.d.ts.map +0 -1
  463. package/dist/hq/protocol/session.d.ts.map +0 -1
  464. package/dist/hq/protocol/tool.d.ts.map +0 -1
  465. package/dist/hq/protocol.d.ts.map +0 -1
  466. package/dist/hq/publisher.d.ts.map +0 -1
  467. package/dist/hq/redaction.d.ts.map +0 -1
  468. package/dist/hq/session-bridge.d.ts.map +0 -1
  469. package/dist/hq/tool-bridge.d.ts.map +0 -1
  470. package/dist/hq/transcript-mapper.d.ts.map +0 -1
  471. package/dist/hq/worktree-bridge.d.ts.map +0 -1
  472. package/dist/hq/write-queues.d.ts.map +0 -1
  473. package/dist/index.d.ts.map +0 -1
  474. package/dist/index.js.map +0 -7
  475. package/dist/infrastructure/context-manager.d.ts.map +0 -1
  476. package/dist/infrastructure/index.d.ts.map +0 -1
  477. package/dist/infrastructure/index.js.map +0 -7
  478. package/dist/infrastructure/logger.d.ts.map +0 -1
  479. package/dist/infrastructure/mcp-servers.d.ts.map +0 -1
  480. package/dist/infrastructure/path-resolver.d.ts.map +0 -1
  481. package/dist/infrastructure/provider-cache-ledger.d.ts.map +0 -1
  482. package/dist/infrastructure/token-counter.d.ts.map +0 -1
  483. package/dist/kernel/container.d.ts.map +0 -1
  484. package/dist/kernel/events/agent-events.d.ts.map +0 -1
  485. package/dist/kernel/events/brain-events.d.ts.map +0 -1
  486. package/dist/kernel/events/file-events.d.ts.map +0 -1
  487. package/dist/kernel/events/fleet-events.d.ts.map +0 -1
  488. package/dist/kernel/events/memory-events.d.ts.map +0 -1
  489. package/dist/kernel/events/network-events.d.ts.map +0 -1
  490. package/dist/kernel/events/process-events.d.ts.map +0 -1
  491. package/dist/kernel/events/provider-events.d.ts.map +0 -1
  492. package/dist/kernel/events/sdd-events.d.ts.map +0 -1
  493. package/dist/kernel/events/session-events.d.ts.map +0 -1
  494. package/dist/kernel/events/tool-events.d.ts.map +0 -1
  495. package/dist/kernel/events/worktree-events.d.ts.map +0 -1
  496. package/dist/kernel/events.d.ts.map +0 -1
  497. package/dist/kernel/index.d.ts.map +0 -1
  498. package/dist/kernel/index.js.map +0 -7
  499. package/dist/kernel/pipeline.d.ts.map +0 -1
  500. package/dist/kernel/run-controller.d.ts.map +0 -1
  501. package/dist/kernel/tokens.d.ts.map +0 -1
  502. package/dist/mailbox-attach.d.ts.map +0 -1
  503. package/dist/middleware/collab-pause.d.ts.map +0 -1
  504. package/dist/models/alibaba-token-plan-catalog.d.ts.map +0 -1
  505. package/dist/models/codex-catalog.d.ts.map +0 -1
  506. package/dist/models/index.d.ts.map +0 -1
  507. package/dist/models/index.js.map +0 -7
  508. package/dist/models/llm-selector.d.ts.map +0 -1
  509. package/dist/models/mode-store.d.ts.map +0 -1
  510. package/dist/models/model-intelligence.d.ts.map +0 -1
  511. package/dist/models/model-router.d.ts.map +0 -1
  512. package/dist/models/models-registry.d.ts.map +0 -1
  513. package/dist/models/provider-model-resolve.d.ts.map +0 -1
  514. package/dist/notifications/index.d.ts.map +0 -1
  515. package/dist/notifications/index.js.map +0 -7
  516. package/dist/notifications/notifier-impl.d.ts.map +0 -1
  517. package/dist/notifications/notifier.d.ts.map +0 -1
  518. package/dist/notifications/types.d.ts.map +0 -1
  519. package/dist/observability/event-bridge.d.ts.map +0 -1
  520. package/dist/observability/health.d.ts.map +0 -1
  521. package/dist/observability/index.d.ts.map +0 -1
  522. package/dist/observability/index.js.map +0 -7
  523. package/dist/observability/metrics.d.ts.map +0 -1
  524. package/dist/observability/network-telemetry.d.ts.map +0 -1
  525. package/dist/observability/otel-tracer.d.ts.map +0 -1
  526. package/dist/observability/otlp-metrics.d.ts.map +0 -1
  527. package/dist/observability/otlp-traces.d.ts.map +0 -1
  528. package/dist/observability/process-telemetry.d.ts.map +0 -1
  529. package/dist/observability/prometheus.d.ts.map +0 -1
  530. package/dist/observability/redact-command.d.ts.map +0 -1
  531. package/dist/observability/tracer.d.ts.map +0 -1
  532. package/dist/plugin/api.d.ts.map +0 -1
  533. package/dist/plugin/config.d.ts.map +0 -1
  534. package/dist/plugin/index.d.ts.map +0 -1
  535. package/dist/plugin/index.js.map +0 -7
  536. package/dist/plugin/loader.d.ts.map +0 -1
  537. package/dist/plugins/auto-review-plugin.d.ts.map +0 -1
  538. package/dist/plugins/chimera-plugin.d.ts.map +0 -1
  539. package/dist/plugins/prompts-plugin.d.ts.map +0 -1
  540. package/dist/plugins/review-claim-registry.d.ts.map +0 -1
  541. package/dist/plugins/review-context-builder.d.ts.map +0 -1
  542. package/dist/plugins/review-finding-commands.d.ts.map +0 -1
  543. package/dist/plugins/review-finding-integration.d.ts.map +0 -1
  544. package/dist/plugins/review-finding-parser.d.ts.map +0 -1
  545. package/dist/plugins/review-finding-store.d.ts.map +0 -1
  546. package/dist/plugins/review-finding-types.d.ts.map +0 -1
  547. package/dist/plugins/review-report-integration.d.ts.map +0 -1
  548. package/dist/plugins/review-report-store.d.ts.map +0 -1
  549. package/dist/plugins/review-report-types.d.ts.map +0 -1
  550. package/dist/plugins/review-types.d.ts.map +0 -1
  551. package/dist/plugins/skills-plugin.d.ts.map +0 -1
  552. package/dist/plugins/sync-plugin.d.ts.map +0 -1
  553. package/dist/prompts/index.d.ts.map +0 -1
  554. package/dist/prompts/prompt-installer.d.ts.map +0 -1
  555. package/dist/prompts/prompt-manifest-store.d.ts.map +0 -1
  556. package/dist/registry/index.d.ts.map +0 -1
  557. package/dist/registry/index.js.map +0 -7
  558. package/dist/registry/provider-registry.d.ts.map +0 -1
  559. package/dist/registry/slash-command-registry.d.ts.map +0 -1
  560. package/dist/registry/tool-registry.d.ts.map +0 -1
  561. package/dist/replay/hash.d.ts.map +0 -1
  562. package/dist/replay/index.d.ts.map +0 -1
  563. package/dist/replay/index.js.map +0 -7
  564. package/dist/replay/replay-provider-runner.d.ts.map +0 -1
  565. package/dist/security/capabilities.d.ts.map +0 -1
  566. package/dist/security/config-secrets.d.ts.map +0 -1
  567. package/dist/security/directory-permission-policy.d.ts.map +0 -1
  568. package/dist/security/directory-policy-schema.d.ts.map +0 -1
  569. package/dist/security/index.d.ts.map +0 -1
  570. package/dist/security/index.js.map +0 -7
  571. package/dist/security/kanban-boundary.d.ts.map +0 -1
  572. package/dist/security/permission-policy-schema.d.ts.map +0 -1
  573. package/dist/security/permission-policy.d.ts.map +0 -1
  574. package/dist/security/readonly-permission-policy.d.ts.map +0 -1
  575. package/dist/security/secret-scrubber.d.ts.map +0 -1
  576. package/dist/security/secret-vault.d.ts.map +0 -1
  577. package/dist/security/trust-boundary.d.ts.map +0 -1
  578. package/dist/security/yolo-risk.d.ts.map +0 -1
  579. package/dist/session-registry-atomic-file.d.ts.map +0 -1
  580. package/dist/session-registry-types.d.ts.map +0 -1
  581. package/dist/session-registry.d.ts.map +0 -1
  582. package/dist/skills/foreign-sources.d.ts.map +0 -1
  583. package/dist/skills/frontmatter.d.ts.map +0 -1
  584. package/dist/skills/github-fetcher.d.ts.map +0 -1
  585. package/dist/skills/index.d.ts.map +0 -1
  586. package/dist/skills/index.js.map +0 -7
  587. package/dist/skills/limits.d.ts.map +0 -1
  588. package/dist/skills/manifest-store.d.ts.map +0 -1
  589. package/dist/skills/registry/github-direct-adapter.d.ts.map +0 -1
  590. package/dist/skills/registry/registry-adapter.d.ts.map +0 -1
  591. package/dist/skills/registry/skills-sh-adapter.d.ts.map +0 -1
  592. package/dist/skills/skill-generator.d.ts.map +0 -1
  593. package/dist/skills/skill-installer.d.ts.map +0 -1
  594. package/dist/storage/annotations-store.d.ts.map +0 -1
  595. package/dist/storage/attachment-store.d.ts.map +0 -1
  596. package/dist/storage/cloud-sync.d.ts.map +0 -1
  597. package/dist/storage/completed-work-checkpoint.d.ts.map +0 -1
  598. package/dist/storage/config-loader/bootstrap.d.ts.map +0 -1
  599. package/dist/storage/config-loader/default-repair.d.ts.map +0 -1
  600. package/dist/storage/config-loader/defaults.d.ts.map +0 -1
  601. package/dist/storage/config-loader/diagnostics.d.ts.map +0 -1
  602. package/dist/storage/config-loader/env-overrides.d.ts.map +0 -1
  603. package/dist/storage/config-loader/in-project-policy.d.ts.map +0 -1
  604. package/dist/storage/config-loader/inline-provider-models.d.ts.map +0 -1
  605. package/dist/storage/config-loader/legacy-sage-migration.d.ts.map +0 -1
  606. package/dist/storage/config-loader/path-identity.d.ts.map +0 -1
  607. package/dist/storage/config-loader/types.d.ts.map +0 -1
  608. package/dist/storage/config-loader/validation.d.ts.map +0 -1
  609. package/dist/storage/config-loader.d.ts.map +0 -1
  610. package/dist/storage/config-migration.d.ts.map +0 -1
  611. package/dist/storage/config-store.d.ts.map +0 -1
  612. package/dist/storage/director-state.d.ts.map +0 -1
  613. package/dist/storage/file-session-writer.d.ts.map +0 -1
  614. package/dist/storage/goal-coordination.d.ts.map +0 -1
  615. package/dist/storage/goal-kanban.d.ts.map +0 -1
  616. package/dist/storage/goal-store.d.ts.map +0 -1
  617. package/dist/storage/index.d.ts.map +0 -1
  618. package/dist/storage/index.js.map +0 -7
  619. package/dist/storage/input-history-store.d.ts.map +0 -1
  620. package/dist/storage/memory-backend.d.ts.map +0 -1
  621. package/dist/storage/memory-consolidator.d.ts.map +0 -1
  622. package/dist/storage/memory-graph-backend.d.ts.map +0 -1
  623. package/dist/storage/plan-store.d.ts.map +0 -1
  624. package/dist/storage/plan-templates.d.ts.map +0 -1
  625. package/dist/storage/prompt-store.d.ts.map +0 -1
  626. package/dist/storage/prompt-usage-store.d.ts.map +0 -1
  627. package/dist/storage/provider-config-watcher.d.ts.map +0 -1
  628. package/dist/storage/queue-store.d.ts.map +0 -1
  629. package/dist/storage/recovery-lock.d.ts.map +0 -1
  630. package/dist/storage/replay-log-store.d.ts.map +0 -1
  631. package/dist/storage/session-analyzer.d.ts.map +0 -1
  632. package/dist/storage/session-checkpoint-cas.d.ts.map +0 -1
  633. package/dist/storage/session-event-bridge.d.ts.map +0 -1
  634. package/dist/storage/session-helpers.d.ts.map +0 -1
  635. package/dist/storage/session-id-resolver.d.ts.map +0 -1
  636. package/dist/storage/session-id.d.ts.map +0 -1
  637. package/dist/storage/session-read-scrubber.d.ts.map +0 -1
  638. package/dist/storage/session-reader.d.ts.map +0 -1
  639. package/dist/storage/session-recovery.d.ts.map +0 -1
  640. package/dist/storage/session-resume-validation.d.ts.map +0 -1
  641. package/dist/storage/session-rewind-apply.d.ts.map +0 -1
  642. package/dist/storage/session-rewinder.d.ts.map +0 -1
  643. package/dist/storage/session-store/delete-session-artifacts.d.ts.map +0 -1
  644. package/dist/storage/session-store/delete-session-guards.d.ts.map +0 -1
  645. package/dist/storage/session-store/directory-scan.d.ts.map +0 -1
  646. package/dist/storage/session-store/directory-session-files.d.ts.map +0 -1
  647. package/dist/storage/session-store/events.d.ts.map +0 -1
  648. package/dist/storage/session-store/fork-session.d.ts.map +0 -1
  649. package/dist/storage/session-store/index-reader.d.ts.map +0 -1
  650. package/dist/storage/session-store/load-cache.d.ts.map +0 -1
  651. package/dist/storage/session-store/load-session-data.d.ts.map +0 -1
  652. package/dist/storage/session-store/paths.d.ts.map +0 -1
  653. package/dist/storage/session-store/prune-helpers.d.ts.map +0 -1
  654. package/dist/storage/session-store/replay.d.ts.map +0 -1
  655. package/dist/storage/session-store/search-events.d.ts.map +0 -1
  656. package/dist/storage/session-store/shard-manifest.d.ts.map +0 -1
  657. package/dist/storage/session-store/summary-builder.d.ts.map +0 -1
  658. package/dist/storage/session-store/summary-header.d.ts.map +0 -1
  659. package/dist/storage/session-store/types.d.ts.map +0 -1
  660. package/dist/storage/session-store.d.ts.map +0 -1
  661. package/dist/storage/session-summary.d.ts.map +0 -1
  662. package/dist/storage/session-tool-call-ends.d.ts.map +0 -1
  663. package/dist/storage/session-writer-scrubber.d.ts.map +0 -1
  664. package/dist/storage/session-writer-truncate.d.ts.map +0 -1
  665. package/dist/storage/storage-concurrency.d.ts.map +0 -1
  666. package/dist/storage/task-store.d.ts.map +0 -1
  667. package/dist/storage/todos-checkpoint.d.ts.map +0 -1
  668. package/dist/storage/tool-audit-log.d.ts.map +0 -1
  669. package/dist/tasking/index.d.ts.map +0 -1
  670. package/dist/tasking/index.js.map +0 -7
  671. package/dist/tasking/task-store.d.ts.map +0 -1
  672. package/dist/tasking/task-tracker.d.ts.map +0 -1
  673. package/dist/tools/council-tool.d.ts.map +0 -1
  674. package/dist/tools/fallback-chain-manage-tool.d.ts.map +0 -1
  675. package/dist/tools/fallback-favorite-manage-tool.d.ts.map +0 -1
  676. package/dist/tools/fallback-manage-helpers.d.ts.map +0 -1
  677. package/dist/tools/fallback-manage-tool-options.d.ts.map +0 -1
  678. package/dist/tools/fallback-manage-tools.d.ts.map +0 -1
  679. package/dist/tools/fallback-model-ref-parse.d.ts.map +0 -1
  680. package/dist/tools/fallback-provider-key-store.d.ts.map +0 -1
  681. package/dist/tools/fallback-system-config-view-tool.d.ts.map +0 -1
  682. package/dist/tools/index.d.ts.map +0 -1
  683. package/dist/tools/index.js.map +0 -7
  684. package/dist/tools/mcp-control.d.ts.map +0 -1
  685. package/dist/tools/mcp-use.d.ts.map +0 -1
  686. package/dist/tools/one-shot-llm-tool.d.ts.map +0 -1
  687. package/dist/tools/plugin-manager.d.ts.map +0 -1
  688. package/dist/types/agent-bridge.d.ts.map +0 -1
  689. package/dist/types/attachment.d.ts.map +0 -1
  690. package/dist/types/autonomy.d.ts.map +0 -1
  691. package/dist/types/blocks.d.ts.map +0 -1
  692. package/dist/types/compactor.d.ts.map +0 -1
  693. package/dist/types/config/autonomy.d.ts.map +0 -1
  694. package/dist/types/config/context.d.ts.map +0 -1
  695. package/dist/types/config/fleet-chat.d.ts.map +0 -1
  696. package/dist/types/config/mcp-features.d.ts.map +0 -1
  697. package/dist/types/config/providers.d.ts.map +0 -1
  698. package/dist/types/config/root.d.ts.map +0 -1
  699. package/dist/types/config/runtime.d.ts.map +0 -1
  700. package/dist/types/config/skills-fleet-brain.d.ts.map +0 -1
  701. package/dist/types/config/tools.d.ts.map +0 -1
  702. package/dist/types/config.d.ts.map +0 -1
  703. package/dist/types/context-evidence.d.ts.map +0 -1
  704. package/dist/types/context-window.d.ts.map +0 -1
  705. package/dist/types/council.d.ts.map +0 -1
  706. package/dist/types/default-config.d.ts.map +0 -1
  707. package/dist/types/design-kit.d.ts.map +0 -1
  708. package/dist/types/error-handler.d.ts.map +0 -1
  709. package/dist/types/errors.d.ts.map +0 -1
  710. package/dist/types/file-event-record.d.ts.map +0 -1
  711. package/dist/types/hooks.d.ts.map +0 -1
  712. package/dist/types/index.d.ts.map +0 -1
  713. package/dist/types/index.js.map +0 -7
  714. package/dist/types/input-reader.d.ts.map +0 -1
  715. package/dist/types/logger.d.ts.map +0 -1
  716. package/dist/types/memory.d.ts.map +0 -1
  717. package/dist/types/messages.d.ts.map +0 -1
  718. package/dist/types/mode-prompts.d.ts.map +0 -1
  719. package/dist/types/mode.d.ts.map +0 -1
  720. package/dist/types/models-registry.d.ts.map +0 -1
  721. package/dist/types/multi-agent.d.ts.map +0 -1
  722. package/dist/types/observability.d.ts.map +0 -1
  723. package/dist/types/one-shot-llm.d.ts.map +0 -1
  724. package/dist/types/path-resolver.d.ts.map +0 -1
  725. package/dist/types/permission.d.ts.map +0 -1
  726. package/dist/types/plugin.d.ts.map +0 -1
  727. package/dist/types/prompt-registry.d.ts.map +0 -1
  728. package/dist/types/prompt.d.ts.map +0 -1
  729. package/dist/types/provider-runner.d.ts.map +0 -1
  730. package/dist/types/provider.d.ts.map +0 -1
  731. package/dist/types/quota-regex.d.ts.map +0 -1
  732. package/dist/types/renderer.d.ts.map +0 -1
  733. package/dist/types/retry-policy.d.ts.map +0 -1
  734. package/dist/types/secret-scrubber.d.ts.map +0 -1
  735. package/dist/types/secret-vault.d.ts.map +0 -1
  736. package/dist/types/selector.d.ts.map +0 -1
  737. package/dist/types/session-markers.d.ts.map +0 -1
  738. package/dist/types/session-markers.js.map +0 -7
  739. package/dist/types/session-reader.d.ts.map +0 -1
  740. package/dist/types/session-rewinder.d.ts.map +0 -1
  741. package/dist/types/session.d.ts.map +0 -1
  742. package/dist/types/side-effect.d.ts.map +0 -1
  743. package/dist/types/skill.d.ts.map +0 -1
  744. package/dist/types/slash-command.d.ts.map +0 -1
  745. package/dist/types/spec.d.ts.map +0 -1
  746. package/dist/types/system-prompt-contributor.d.ts.map +0 -1
  747. package/dist/types/system-prompt.d.ts.map +0 -1
  748. package/dist/types/task-graph.d.ts.map +0 -1
  749. package/dist/types/token-counter.d.ts.map +0 -1
  750. package/dist/types/tool-executor.d.ts.map +0 -1
  751. package/dist/types/tool-markers.d.ts.map +0 -1
  752. package/dist/types/tool.d.ts.map +0 -1
  753. package/dist/types/utility-types.d.ts.map +0 -1
  754. package/dist/utils/assert-never.d.ts.map +0 -1
  755. package/dist/utils/atomic-write.d.ts.map +0 -1
  756. package/dist/utils/cache-key.d.ts.map +0 -1
  757. package/dist/utils/child-env.d.ts.map +0 -1
  758. package/dist/utils/color.d.ts.map +0 -1
  759. package/dist/utils/compaction-preview.d.ts.map +0 -1
  760. package/dist/utils/config-backup.d.ts.map +0 -1
  761. package/dist/utils/config-json.d.ts.map +0 -1
  762. package/dist/utils/connectivity.d.ts.map +0 -1
  763. package/dist/utils/context-breakdown.d.ts.map +0 -1
  764. package/dist/utils/context-evidence.d.ts.map +0 -1
  765. package/dist/utils/crash-shield.d.ts.map +0 -1
  766. package/dist/utils/deep-merge.d.ts.map +0 -1
  767. package/dist/utils/diff.d.ts.map +0 -1
  768. package/dist/utils/error.d.ts.map +0 -1
  769. package/dist/utils/error.js.map +0 -7
  770. package/dist/utils/expect-defined.d.ts.map +0 -1
  771. package/dist/utils/expect-defined.js.map +0 -7
  772. package/dist/utils/glob-expand.d.ts.map +0 -1
  773. package/dist/utils/glob-match.d.ts.map +0 -1
  774. package/dist/utils/heap-watchdog.d.ts.map +0 -1
  775. package/dist/utils/heap-watchdog.js.map +0 -7
  776. package/dist/utils/incoming-images.d.ts.map +0 -1
  777. package/dist/utils/index.d.ts.map +0 -1
  778. package/dist/utils/index.js.map +0 -7
  779. package/dist/utils/instruction-file.d.ts.map +0 -1
  780. package/dist/utils/ip-guard.d.ts.map +0 -1
  781. package/dist/utils/json-repair.d.ts.map +0 -1
  782. package/dist/utils/json-schema-validate.d.ts.map +0 -1
  783. package/dist/utils/lru-cache.d.ts.map +0 -1
  784. package/dist/utils/merge-custom-models.d.ts.map +0 -1
  785. package/dist/utils/merge-models-payload.d.ts.map +0 -1
  786. package/dist/utils/message-invariants.d.ts.map +0 -1
  787. package/dist/utils/newline-normalize.d.ts.map +0 -1
  788. package/dist/utils/perf-profile.d.ts.map +0 -1
  789. package/dist/utils/pid.d.ts.map +0 -1
  790. package/dist/utils/project-identity.d.ts.map +0 -1
  791. package/dist/utils/project-watch.d.ts.map +0 -1
  792. package/dist/utils/regex-guard.d.ts.map +0 -1
  793. package/dist/utils/safe-json.d.ts.map +0 -1
  794. package/dist/utils/sage-output-block.d.ts.map +0 -1
  795. package/dist/utils/session-scoped-path.d.ts.map +0 -1
  796. package/dist/utils/sleep.d.ts.map +0 -1
  797. package/dist/utils/slug.d.ts.map +0 -1
  798. package/dist/utils/socket-path.d.ts.map +0 -1
  799. package/dist/utils/sqlite-warning.d.ts.map +0 -1
  800. package/dist/utils/string.d.ts.map +0 -1
  801. package/dist/utils/task-format.d.ts.map +0 -1
  802. package/dist/utils/term.d.ts.map +0 -1
  803. package/dist/utils/todos-format.d.ts.map +0 -1
  804. package/dist/utils/token-estimate.d.ts.map +0 -1
  805. package/dist/utils/tool-description-mode.d.ts.map +0 -1
  806. package/dist/utils/tool-output-serializer.d.ts.map +0 -1
  807. package/dist/utils/tool-result-render-mode.d.ts.map +0 -1
  808. package/dist/utils/tool-subject.d.ts.map +0 -1
  809. package/dist/utils/tool-wire-compact.d.ts.map +0 -1
  810. package/dist/utils/tree-kill.d.ts.map +0 -1
  811. package/dist/utils/tree-kill.js.map +0 -7
  812. package/dist/utils/ulid.d.ts.map +0 -1
  813. package/dist/utils/walk-ignore.d.ts.map +0 -1
  814. package/dist/utils/wstack-paths.d.ts.map +0 -1
  815. package/dist/worktree/index.d.ts.map +0 -1
  816. package/dist/worktree/index.js.map +0 -7
  817. package/dist/worktree/worktree-git.d.ts.map +0 -1
  818. package/dist/worktree/worktree-managed-ops.d.ts.map +0 -1
  819. package/dist/worktree/worktree-manager.d.ts.map +0 -1
  820. package/dist/worktree/worktree-types.d.ts.map +0 -1
@@ -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
  }
@@ -6502,6 +6831,14 @@ var DEFAULT_DEBOUNCE_MS = 15e3;
6502
6831
  var DEFAULT_MAX_FILES_PER_BATCH = 15;
6503
6832
  var DEFAULT_MAX_CONCURRENT_REVIEWS = 2;
6504
6833
  var DEFAULT_MAX_CASCADE_DEPTH = 2;
6834
+ var MAX_KNOWN_FINGERPRINTS = 5e3;
6835
+ function trimKnownFingerprints(map, max) {
6836
+ while (map.size > max) {
6837
+ const oldest = map.keys().next().value;
6838
+ if (oldest === void 0) break;
6839
+ map.delete(oldest);
6840
+ }
6841
+ }
6505
6842
  function buildReviewerModelPool(provider, model, fallbackModels = []) {
6506
6843
  const primaryProvider = provider.trim();
6507
6844
  const primaryModel = model.trim();
@@ -6546,7 +6883,12 @@ function selectRoundRobinReviewerAssignment(pool, cursor, fallbackProvider = "",
6546
6883
  }
6547
6884
  function resolveAutoReviewConfig(cfg, sessionConfig) {
6548
6885
  const mgr = new FallbackProfileManager(sessionConfig);
6549
- 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
+ });
6550
6892
  const rawProvider = cfg.provider?.trim();
6551
6893
  const rawModel = cfg.model?.trim();
6552
6894
  const resolvedProvider = rawProvider || (chain.length > 0 ? chain[0].providerId : sessionConfig.provider);
@@ -6690,8 +7032,8 @@ async function snapshotChangedFiles(cwd) {
6690
7032
  if (file.path.startsWith(".wrongstack/")) continue;
6691
7033
  if (budget <= 0) break;
6692
7034
  try {
6693
- const stat6 = await fsp.stat(path14.join(cwd, file.path));
6694
- if (!stat6.isFile() || stat6.size > MAX_SNAPSHOT_FILE_BYTES) continue;
7035
+ const stat7 = await fsp.stat(path14.join(cwd, file.path));
7036
+ if (!stat7.isFile() || stat7.size > MAX_SNAPSHOT_FILE_BYTES) continue;
6695
7037
  const content = await fsp.readFile(path14.join(cwd, file.path), "utf8");
6696
7038
  budget -= content.length;
6697
7039
  snapshots.push({
@@ -6823,6 +7165,11 @@ function createAutoReviewPlugin() {
6823
7165
  let pendingReviewWork;
6824
7166
  let sessionEnded = false;
6825
7167
  let latestIterationPayload;
7168
+ const rememberKnownFingerprint = (filePath, fingerprint2) => {
7169
+ if (knownFingerprints.has(filePath)) knownFingerprints.delete(filePath);
7170
+ knownFingerprints.set(filePath, fingerprint2);
7171
+ trimKnownFingerprints(knownFingerprints, MAX_KNOWN_FINGERPRINTS);
7172
+ };
6826
7173
  let snapshotInFlight = false;
6827
7174
  const withSnapshotLock = async (fn) => {
6828
7175
  if (snapshotInFlight) {
@@ -6843,7 +7190,7 @@ function createAutoReviewPlugin() {
6843
7190
  const snapshots = await withSnapshotLock(() => snapshotChangedFiles(cwd));
6844
7191
  if (!snapshots) return;
6845
7192
  for (const file of snapshots) {
6846
- knownFingerprints.set(file.path, file.fingerprint);
7193
+ rememberKnownFingerprint(file.path, file.fingerprint);
6847
7194
  }
6848
7195
  api.log.info(`[auto-review] seeded ${knownFingerprints.size} known file snapshot(s)`);
6849
7196
  } catch {
@@ -7000,7 +7347,7 @@ function createAutoReviewPlugin() {
7000
7347
  inFlight.push(inflightEntry);
7001
7348
  for (const file of toReview) {
7002
7349
  if (!emittedPaths.has(file.path)) continue;
7003
- knownFingerprints.set(file.path, file.fingerprint);
7350
+ rememberKnownFingerprint(file.path, file.fingerprint);
7004
7351
  pendingFiles.delete(file.path);
7005
7352
  }
7006
7353
  api.log.info(
@@ -7144,7 +7491,6 @@ function createAutoReviewPlugin() {
7144
7491
 
7145
7492
  // src/plugins/chimera-plugin.ts
7146
7493
  init_error();
7147
- import { randomUUID as randomUUID6 } from "node:crypto";
7148
7494
  import { spawn as spawn4 } from "node:child_process";
7149
7495
  import * as fsp4 from "node:fs/promises";
7150
7496
  import * as os5 from "node:os";
@@ -7220,10 +7566,20 @@ function parseFindingSegment(segment, severity, context) {
7220
7566
  if (tagMatch) {
7221
7567
  remaining = content.slice(tagMatch[0].length).trim();
7222
7568
  }
7569
+ const citationMatch = remaining.match(
7570
+ /^(`+)([a-zA-Z_./\\:][^`]*[a-zA-Z0-9_./\\:])\1(?=\s*[—–-]|\s*$)/
7571
+ );
7572
+ if (citationMatch) {
7573
+ const inner = citationMatch[2];
7574
+ const afterCitation = remaining.slice(citationMatch[0].length);
7575
+ remaining = `${inner}${afterCitation}`;
7576
+ }
7223
7577
  let file;
7224
7578
  let line;
7225
7579
  let desc = remaining;
7226
- const refMatch = remaining.match(/^(.+?)(?::(\d+))?\s*[—–-]\s*(.+)$/);
7580
+ const refMatch = remaining.match(
7581
+ /^([a-zA-Z_./\\][a-zA-Z0-9_./\\-]*\.\w+)(?::(\d+))?\s+(?:[—–]|-)\s+(.+)$/
7582
+ );
7227
7583
  if (refMatch) {
7228
7584
  file = refMatch[1].trim();
7229
7585
  if (refMatch[2] !== void 0) {
@@ -7321,12 +7677,26 @@ async function persistReviewReport(payload, reportId, projectDir) {
7321
7677
  ...cascadeDepth !== void 0 ? { cascadeDepth } : {}
7322
7678
  };
7323
7679
  await store.persist(input);
7680
+ if (reviewStatus === "success" && parsed.findings.length === 0 && parsed.unparseableCount === 0 && isExplicitAllClearReview(payload.reviewText)) {
7681
+ await store.transition(
7682
+ reportId,
7683
+ "completed",
7684
+ { id: "chimera", kind: "system" },
7685
+ {
7686
+ reason: "Successful Chimera review produced no actionable findings"
7687
+ }
7688
+ );
7689
+ }
7324
7690
  return {
7325
7691
  reportId,
7326
7692
  created: !existed,
7327
7693
  totalFindings: parsed.findings.length
7328
7694
  };
7329
7695
  }
7696
+ function isExplicitAllClearReview(text) {
7697
+ const normalized = text.trim().toLowerCase();
7698
+ return normalized.startsWith("## \u{1F982} chimera review \u2014 all clear") || normalized.includes("chimera review: all clear");
7699
+ }
7330
7700
  async function syncReportCompletion(reportId, projectDir, actor) {
7331
7701
  const reportStore = new JsonlReportStore(projectDir);
7332
7702
  const findingStore = new JsonlFindingStore(projectDir);
@@ -7799,49 +8169,6 @@ async function showStatus(ctx) {
7799
8169
  ].join("\n");
7800
8170
  }
7801
8171
 
7802
- // src/plugins/review-finding-integration.ts
7803
- init_review_finding_store();
7804
- async function integrateFindings(payload, projectDir, reportId) {
7805
- if (!payload.reviewText || payload.reviewText.trim().length === 0) {
7806
- return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
7807
- }
7808
- const store = new JsonlFindingStore(projectDir);
7809
- const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
7810
- const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
7811
- const sessionId = payload.sessionId ?? payload.cwd;
7812
- const model = payload.bundle.config.model;
7813
- const parsed = parseChimeraReviewReport(payload.reviewText, {
7814
- sessionId,
7815
- agentId,
7816
- reviewerModel: model,
7817
- reviewType: source,
7818
- reportId
7819
- });
7820
- if (parsed.findings.length === 0) {
7821
- return {
7822
- created: 0,
7823
- relinked: 0,
7824
- reopened: 0,
7825
- totalFindings: 0,
7826
- unparseableCount: parsed.unparseableCount
7827
- };
7828
- }
7829
- const result = await store.upsert(parsed.findings, {
7830
- sessionId,
7831
- reportId,
7832
- agentId,
7833
- model
7834
- });
7835
- return {
7836
- created: result.created,
7837
- relinked: result.relinked,
7838
- reopened: result.reopened,
7839
- reportId,
7840
- totalFindings: parsed.findings.length,
7841
- unparseableCount: parsed.unparseableCount
7842
- };
7843
- }
7844
-
7845
8172
  // src/plugins/chimera-plugin.ts
7846
8173
  var DEFAULT_MAX_FILES = 15;
7847
8174
  var DEFAULT_CASCADE_ON = "off";
@@ -7997,18 +8324,6 @@ function buildReviewCommand(_getConfig) {
7997
8324
  }
7998
8325
  };
7999
8326
  }
8000
- async function tryPersistFindings(payload) {
8001
- if (!payload || typeof payload !== "object") return;
8002
- const p = payload;
8003
- const cwd = p.cwd ?? p.bundle?.cwd;
8004
- if (!cwd) return;
8005
- const slug = projectSlug(cwd);
8006
- const globalRoot = path17.join(os5.homedir(), ".wrongstack");
8007
- const projectDir = path17.join(globalRoot, "projects", slug);
8008
- const reportId = randomUUID6();
8009
- await persistReviewReport(payload, reportId, projectDir);
8010
- await integrateFindings(payload, projectDir, reportId);
8011
- }
8012
8327
  function createChimeraPlugin() {
8013
8328
  return {
8014
8329
  name: "wstack-chimera",
@@ -8037,9 +8352,6 @@ function createChimeraPlugin() {
8037
8352
  });
8038
8353
  api.onPattern("chimera.review_complete", (_event, payload) => {
8039
8354
  recordCompletedReview(api.events, payload);
8040
- tryPersistFindings(payload).catch((err) => {
8041
- api.log.warn(`[review-finding] failed to persist findings: ${toErrorMessage(err)}`);
8042
- });
8043
8355
  });
8044
8356
  if (!resolved.enabled) {
8045
8357
  api.log.info("[chimera] disabled by config");
@@ -8621,8 +8933,8 @@ var PromptUsageStore = class {
8621
8933
  }
8622
8934
  async fileSignature() {
8623
8935
  try {
8624
- const stat6 = await fs10.stat(this.file);
8625
- return { size: stat6.size, mtimeMs: stat6.mtimeMs, ctimeMs: stat6.ctimeMs };
8936
+ const stat7 = await fs10.stat(this.file);
8937
+ return { size: stat7.size, mtimeMs: stat7.mtimeMs, ctimeMs: stat7.ctimeMs };
8626
8938
  } catch {
8627
8939
  return null;
8628
8940
  }
@@ -9032,12 +9344,12 @@ function parseFlags(input) {
9032
9344
  while (s.startsWith("--") && (m = flagRe.exec(s))) {
9033
9345
  const name = expectDefined(m[1]);
9034
9346
  const rawVal = m[2] ?? m[3] ?? "true";
9035
- flags[name] = unquote(rawVal);
9347
+ flags[name] = unquote2(rawVal);
9036
9348
  s = s.slice(m[0].length);
9037
9349
  }
9038
9350
  return { flags, positional: s.trim() };
9039
9351
  }
9040
- function unquote(v) {
9352
+ function unquote2(v) {
9041
9353
  if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
9042
9354
  return v.slice(1, -1);
9043
9355
  }
@@ -9076,7 +9388,7 @@ function parseKeyValues(kvs) {
9076
9388
  const out = {};
9077
9389
  for (const kv of kvs) {
9078
9390
  const eq = kv.indexOf("=");
9079
- if (eq > 0) out[kv.slice(0, eq)] = unquote(kv.slice(eq + 1));
9391
+ if (eq > 0) out[kv.slice(0, eq)] = unquote2(kv.slice(eq + 1));
9080
9392
  }
9081
9393
  return out;
9082
9394
  }
@@ -9096,9 +9408,123 @@ function dim(s) {
9096
9408
  return `\x1B[2m${s}\x1B[0m`;
9097
9409
  }
9098
9410
 
9411
+ // src/plugins/review-finding-integration.ts
9412
+ init_review_finding_store();
9413
+ async function integrateFindings(payload, projectDir, reportId) {
9414
+ if (!payload.reviewText || payload.reviewText.trim().length === 0) {
9415
+ return { created: 0, relinked: 0, reopened: 0, totalFindings: 0, unparseableCount: 0 };
9416
+ }
9417
+ const store = new JsonlFindingStore(projectDir);
9418
+ const source = (payload.bundle.cascadeDepth ?? 0) > 0 ? "cascade" : payload.bundle.cascadeOn !== void 0 && payload.bundle.cascadeOn !== "off" ? "auto" : "chimera";
9419
+ const agentId = payload.bundle.fileProvenance?.find((entry) => entry.agentId)?.agentId ?? "chimera-review";
9420
+ const sessionId = payload.sessionId ?? payload.cwd;
9421
+ const model = payload.bundle.config.model;
9422
+ const parsed = parseChimeraReviewReport(payload.reviewText, {
9423
+ sessionId,
9424
+ agentId,
9425
+ reviewerModel: model,
9426
+ reviewType: source,
9427
+ reportId
9428
+ });
9429
+ if (parsed.findings.length === 0) {
9430
+ return {
9431
+ created: 0,
9432
+ relinked: 0,
9433
+ reopened: 0,
9434
+ totalFindings: 0,
9435
+ unparseableCount: parsed.unparseableCount
9436
+ };
9437
+ }
9438
+ const result = await store.upsert(parsed.findings, {
9439
+ sessionId,
9440
+ reportId,
9441
+ agentId,
9442
+ model
9443
+ });
9444
+ return {
9445
+ created: result.created,
9446
+ relinked: result.relinked,
9447
+ reopened: result.reopened,
9448
+ reportId,
9449
+ totalFindings: parsed.findings.length,
9450
+ unparseableCount: parsed.unparseableCount
9451
+ };
9452
+ }
9453
+
9454
+ // src/plugins/review-store-maintenance.ts
9455
+ init_atomic_write();
9456
+ init_review_finding_store();
9457
+ init_review_report_store();
9458
+ import * as fsp5 from "node:fs/promises";
9459
+ import * as path21 from "node:path";
9460
+ var REVIEW_STORE_COMPACTION_THRESHOLD_BYTES = 8 * 1024 * 1024;
9461
+ var REVIEW_STORE_COMPACTION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
9462
+ var REVIEW_STORE_MAINTENANCE_FILE = ".review-store-maintenance.json";
9463
+ async function maybeCompactReviewStores(projectDir, opts = {}) {
9464
+ const thresholdBytes = opts.thresholdBytes ?? REVIEW_STORE_COMPACTION_THRESHOLD_BYTES;
9465
+ const intervalMs = opts.intervalMs ?? REVIEW_STORE_COMPACTION_INTERVAL_MS;
9466
+ const now = opts.now ?? Date.now();
9467
+ const maintenancePath = path21.join(projectDir, REVIEW_STORE_MAINTENANCE_FILE);
9468
+ return withFileLock(maintenancePath, async () => {
9469
+ const totalBytes = await fileSize(resolveReportStorePath(projectDir)) + await fileSize(resolveFindingStorePath(projectDir));
9470
+ if (totalBytes < thresholdBytes) {
9471
+ return emptyResult("below_threshold", totalBytes);
9472
+ }
9473
+ const state = await readMaintenanceState(maintenancePath);
9474
+ if (state && now - new Date(state.compactedAt).getTime() < intervalMs) {
9475
+ return emptyResult("interval", totalBytes);
9476
+ }
9477
+ const reportResult = await new JsonlReportStore(projectDir).compact();
9478
+ const findingResult = await new JsonlFindingStore(projectDir).compact();
9479
+ const nextState = {
9480
+ compactedAt: new Date(now).toISOString(),
9481
+ totalBytesBefore: totalBytes
9482
+ };
9483
+ await atomicWrite(maintenancePath, `${JSON.stringify(nextState)}
9484
+ `, { mode: 384 });
9485
+ return {
9486
+ compacted: true,
9487
+ totalBytes,
9488
+ reason: "compacted",
9489
+ removedReports: reportResult.removed,
9490
+ removedFindings: findingResult.removed,
9491
+ eventsFolded: reportResult.eventsFolded + findingResult.eventsFolded
9492
+ };
9493
+ });
9494
+ }
9495
+ function emptyResult(reason, totalBytes) {
9496
+ return {
9497
+ compacted: false,
9498
+ totalBytes,
9499
+ reason,
9500
+ removedReports: 0,
9501
+ removedFindings: 0,
9502
+ eventsFolded: 0
9503
+ };
9504
+ }
9505
+ async function fileSize(filePath) {
9506
+ try {
9507
+ return (await fsp5.stat(filePath)).size;
9508
+ } catch (error) {
9509
+ if (error.code === "ENOENT") return 0;
9510
+ throw error;
9511
+ }
9512
+ }
9513
+ async function readMaintenanceState(filePath) {
9514
+ try {
9515
+ const parsed = JSON.parse(await fsp5.readFile(filePath, "utf8"));
9516
+ return typeof parsed.compactedAt === "string" && Number.isFinite(parsed.totalBytesBefore) ? parsed : null;
9517
+ } catch (error) {
9518
+ if (error.code === "ENOENT" || error instanceof SyntaxError) {
9519
+ return null;
9520
+ }
9521
+ throw error;
9522
+ }
9523
+ }
9524
+
9099
9525
  // src/plugins/skills-plugin.ts
9100
9526
  import * as os7 from "node:os";
9101
- import * as path25 from "node:path";
9527
+ import * as path26 from "node:path";
9102
9528
 
9103
9529
  // src/skills/foreign-sources.ts
9104
9530
  var FOREIGN_SKILL_TOOLS = [
@@ -9281,104 +9707,7 @@ function numField(rec, key) {
9281
9707
  init_errors();
9282
9708
  import { spawn as spawn5 } from "node:child_process";
9283
9709
  import * as fs12 from "node:fs/promises";
9284
- import * as path21 from "node:path";
9285
-
9286
- // src/skills/frontmatter.ts
9287
- var SCALAR_KEYS = /* @__PURE__ */ new Set(["name", "description", "version", "license", "compatibility"]);
9288
- function parseSkillFrontmatter(raw) {
9289
- const text = normalizeLineEndings(raw);
9290
- if (!text.startsWith("---")) return {};
9291
- const end = text.indexOf("\n---", 4);
9292
- if (end === -1) return {};
9293
- return parseFrontmatterBlock(text.slice(4, end));
9294
- }
9295
- function normalizeLineEndings(s) {
9296
- return s.replace(/\r\n?/g, "\n");
9297
- }
9298
- function parseFrontmatterBlock(block) {
9299
- const out = {};
9300
- const lines = block.split("\n");
9301
- let i = 0;
9302
- while (i < lines.length) {
9303
- const line = lines[i] ?? "";
9304
- const m = /^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/.exec(line);
9305
- if (!m) {
9306
- i++;
9307
- continue;
9308
- }
9309
- const key = m[1] ?? "";
9310
- const rest = (m[2] ?? "").trim();
9311
- if (key === "metadata") {
9312
- const map = {};
9313
- i++;
9314
- while (i < lines.length) {
9315
- const sub = lines[i] ?? "";
9316
- const sm = /^\s+([a-zA-Z0-9_.-]+):\s*(.*)$/.exec(sub);
9317
- if (!sm) break;
9318
- map[sm[1] ?? ""] = unquote2((sm[2] ?? "").trim());
9319
- i++;
9320
- }
9321
- if (Object.keys(map).length > 0) out.metadata = map;
9322
- continue;
9323
- }
9324
- if (rest === "|" || rest === ">") {
9325
- const collected = [];
9326
- i++;
9327
- while (i < lines.length) {
9328
- const sub = lines[i] ?? "";
9329
- if (sub === "" || sub.startsWith(" ") || sub.startsWith(" ")) {
9330
- collected.push(sub.replace(/^\s+/, ""));
9331
- i++;
9332
- } else break;
9333
- }
9334
- out[normalizeKey2(key)] = collected.join("\n").trim();
9335
- continue;
9336
- }
9337
- if (key === "allowed-tools" || key === "allowedTools") {
9338
- out.allowedTools = rest.split(/[\s,]+/).filter(Boolean);
9339
- i++;
9340
- continue;
9341
- }
9342
- if (SCALAR_KEYS.has(key)) {
9343
- out[key] = unquote2(rest);
9344
- i++;
9345
- continue;
9346
- }
9347
- i++;
9348
- }
9349
- return out;
9350
- }
9351
- function normalizeKey2(key) {
9352
- return key === "allowed-tools" ? "allowedTools" : key;
9353
- }
9354
- function unquote2(s) {
9355
- if (s.length >= 2 && (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'"))) {
9356
- return s.slice(1, -1);
9357
- }
9358
- return s;
9359
- }
9360
- function isValidSkillNameFormat(name) {
9361
- return name.length >= 1 && name.length <= 64 && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
9362
- }
9363
- function validateSkillName(name, parentDirName) {
9364
- const errors = [];
9365
- if (!name || name.trim().length === 0) {
9366
- errors.push("name is empty");
9367
- return errors;
9368
- }
9369
- if (name.length > 64) errors.push(`name is ${name.length} characters (max 64)`);
9370
- if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
9371
- errors.push(
9372
- "name must be lowercase letters, digits, and single hyphens only (no leading/trailing/consecutive hyphens)"
9373
- );
9374
- }
9375
- if (parentDirName !== void 0 && name !== parentDirName) {
9376
- errors.push(`name "${name}" must match its parent directory "${parentDirName}"`);
9377
- }
9378
- return errors;
9379
- }
9380
-
9381
- // src/skills/skill-generator.ts
9710
+ import * as path22 from "node:path";
9382
9711
  async function validateSkillNameAvailable(name, loader) {
9383
9712
  const formatViolations = validateSkillName(name);
9384
9713
  const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
@@ -9497,8 +9826,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
9497
9826
  subsystem: "general"
9498
9827
  });
9499
9828
  }
9500
- const skillDir = path21.join(skillsDir, name);
9501
- const skillFile = path21.join(skillDir, "SKILL.md");
9829
+ const skillDir = path22.join(skillsDir, name);
9830
+ const skillFile = path22.join(skillDir, "SKILL.md");
9502
9831
  if (!opts.overwrite) {
9503
9832
  try {
9504
9833
  await fs12.access(skillFile);
@@ -9557,13 +9886,14 @@ function defaultEditor() {
9557
9886
  init_errors();
9558
9887
  init_error();
9559
9888
  import * as fs15 from "node:fs/promises";
9560
- import * as path24 from "node:path";
9889
+ import * as path25 from "node:path";
9561
9890
 
9562
9891
  // src/skills/github-fetcher.ts
9563
9892
  init_errors();
9893
+ import { createWriteStream } from "node:fs";
9564
9894
  import * as fs13 from "node:fs/promises";
9565
9895
  import * as os6 from "node:os";
9566
- import * as path22 from "node:path";
9896
+ import * as path23 from "node:path";
9567
9897
  import { Readable } from "node:stream";
9568
9898
  import { pipeline } from "node:stream/promises";
9569
9899
  import { createGunzip } from "node:zlib";
@@ -9590,6 +9920,46 @@ function parseSkillRef(input) {
9590
9920
  }
9591
9921
  return { owner: expectDefined(parts[0]), repo: expectDefined(parts[1]), ref };
9592
9922
  }
9923
+ async function writeBoundedGzipStream(source, outputPath, maxBytes, maxCompressedBytes = SKILL_LIMITS.MAX_TARBALL_SIZE) {
9924
+ let compressedBytes = 0;
9925
+ let writtenBytes = 0;
9926
+ await pipeline(
9927
+ source,
9928
+ async function* (chunks) {
9929
+ for await (const chunk of chunks) {
9930
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9931
+ compressedBytes += buffer.byteLength;
9932
+ if (compressedBytes > maxCompressedBytes) {
9933
+ throw new WrongStackError({
9934
+ message: `Compressed tarball too large. Max: ${maxCompressedBytes / 1024 / 1024}MB`,
9935
+ code: ERROR_CODES.UNKNOWN,
9936
+ subsystem: "general",
9937
+ context: { compressedBytes, maxBytes: maxCompressedBytes }
9938
+ });
9939
+ }
9940
+ yield buffer;
9941
+ }
9942
+ },
9943
+ createGunzip(),
9944
+ async function* (chunks) {
9945
+ for await (const chunk of chunks) {
9946
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
9947
+ writtenBytes += buffer.byteLength;
9948
+ if (writtenBytes > maxBytes) {
9949
+ throw new WrongStackError({
9950
+ message: `Uncompressed tarball too large. Max: ${maxBytes / 1024 / 1024}MB`,
9951
+ code: ERROR_CODES.UNKNOWN,
9952
+ subsystem: "general",
9953
+ context: { uncompressedBytes: writtenBytes, maxBytes }
9954
+ });
9955
+ }
9956
+ yield buffer;
9957
+ }
9958
+ },
9959
+ createWriteStream(outputPath, { flags: "wx" })
9960
+ );
9961
+ return writtenBytes;
9962
+ }
9593
9963
  function resolveGitHubToken(env = process.env) {
9594
9964
  const raw = env["WRONGSTACK_GITHUB_TOKEN"] ?? env["GITHUB_TOKEN"] ?? env["GH_TOKEN"];
9595
9965
  if (!raw) return void 0;
@@ -9665,7 +10035,7 @@ async function downloadGitHubTarball(parsed) {
9665
10035
  }
9666
10036
  });
9667
10037
  }
9668
- const tempDir = await fs13.mkdtemp(path22.join(os6.tmpdir(), "wskill-"));
10038
+ const tempDir = await fs13.mkdtemp(path23.join(os6.tmpdir(), "wskill-"));
9669
10039
  try {
9670
10040
  if (!response.body) {
9671
10041
  throw new WrongStackError({
@@ -9676,15 +10046,14 @@ async function downloadGitHubTarball(parsed) {
9676
10046
  });
9677
10047
  }
9678
10048
  const nodeStream = Readable.fromWeb(response.body);
9679
- const gunzip = createGunzip();
9680
- const chunks = [];
9681
- await pipeline(nodeStream, gunzip, async (source) => {
9682
- for await (const chunk of source) {
9683
- chunks.push(Buffer.from(chunk));
9684
- }
9685
- });
9686
- const tarBuf = Buffer.concat(chunks);
9687
- await extractTar(tarBuf, tempDir);
10049
+ const tarPath = path23.join(tempDir, ".wrongstack-download.tar");
10050
+ await writeBoundedGzipStream(nodeStream, tarPath, SKILL_LIMITS.MAX_UNCOMPRESSED_TARBALL_SIZE);
10051
+ const tarBuf = await fs13.readFile(tarPath);
10052
+ try {
10053
+ await extractTar(tarBuf, tempDir);
10054
+ } finally {
10055
+ await fs13.rm(tarPath, { force: true });
10056
+ }
9688
10057
  return { tempDir };
9689
10058
  } catch (err) {
9690
10059
  await fs13.rm(tempDir, { recursive: true, force: true }).catch(() => {
@@ -9692,6 +10061,44 @@ async function downloadGitHubTarball(parsed) {
9692
10061
  throw err;
9693
10062
  }
9694
10063
  }
10064
+ function readTarSize(buf, start) {
10065
+ const first = buf[start] ?? 0;
10066
+ if ((first & 128) !== 0) {
10067
+ if (first === 255) {
10068
+ throw new Error("tar: negative base-256 size field");
10069
+ }
10070
+ let value = first & 127;
10071
+ for (let i = start + 1; i < start + 12; i++) {
10072
+ value = value * 256 + (buf[i] ?? 0);
10073
+ if (!Number.isSafeInteger(value)) {
10074
+ throw new Error("tar: base-256 size exceeds the safe integer range");
10075
+ }
10076
+ }
10077
+ return value;
10078
+ }
10079
+ const text = readTarString(buf, start, 12).trim();
10080
+ if (text === "") return 0;
10081
+ if (!/^[0-7]+$/.test(text)) {
10082
+ throw new Error(`tar: unparseable size field ${JSON.stringify(text)}`);
10083
+ }
10084
+ const parsed = Number.parseInt(text, 8);
10085
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
10086
+ throw new Error("tar: size field out of range");
10087
+ }
10088
+ return parsed;
10089
+ }
10090
+ function readTarString(buf, start, maxLen) {
10091
+ let end = start;
10092
+ while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
10093
+ end++;
10094
+ }
10095
+ return buf.subarray(start, end).toString("utf8");
10096
+ }
10097
+ function stripTopDir(p) {
10098
+ const idx = p.indexOf("/");
10099
+ if (idx === -1) return "";
10100
+ return p.slice(idx + 1);
10101
+ }
9695
10102
  async function extractTar(buf, destDir) {
9696
10103
  let offset = 0;
9697
10104
  while (offset + 512 <= buf.length) {
@@ -9699,15 +10106,15 @@ async function extractTar(buf, destDir) {
9699
10106
  if (header.every((b) => b === 0)) break;
9700
10107
  const name = readTarString(buf, offset, 100);
9701
10108
  const prefix = readTarString(buf, offset + 345, 155);
9702
- const size = Number.parseInt(readTarString(buf, offset + 124, 12).trim(), 8) || 0;
10109
+ const size = readTarSize(buf, offset + 124);
9703
10110
  const typeflag = buf[offset + 156] ?? 0;
9704
10111
  const fullPath = prefix ? `${prefix}/${name}` : name;
9705
10112
  const relPath = stripTopDir(fullPath);
9706
10113
  if (relPath && relPath !== "." && relPath !== "..") {
9707
- const destPath = path22.join(destDir, relPath);
9708
- const resolvedDest = path22.resolve(destPath);
9709
- const resolvedRoot = path22.resolve(destDir);
9710
- if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path22.sep)) {
10114
+ const destPath = path23.join(destDir, relPath);
10115
+ const resolvedDest = path23.resolve(destPath);
10116
+ const resolvedRoot = path23.resolve(destDir);
10117
+ if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path23.sep)) {
9711
10118
  offset += 512 + Math.ceil(size / 512) * 512;
9712
10119
  continue;
9713
10120
  }
@@ -9717,7 +10124,7 @@ async function extractTar(buf, destDir) {
9717
10124
  }
9718
10125
  }
9719
10126
  if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
9720
- const dir = path22.dirname(destPath);
10127
+ const dir = path23.dirname(destPath);
9721
10128
  await fs13.mkdir(dir, { recursive: true });
9722
10129
  const dataStart = offset + 512;
9723
10130
  const dataEnd = dataStart + size;
@@ -9728,23 +10135,11 @@ async function extractTar(buf, destDir) {
9728
10135
  offset += 512 + Math.ceil(size / 512) * 512;
9729
10136
  }
9730
10137
  }
9731
- function readTarString(buf, start, maxLen) {
9732
- let end = start;
9733
- while (end < start + maxLen && end < buf.length && buf[end] !== 0) {
9734
- end++;
9735
- }
9736
- return buf.subarray(start, end).toString("utf8");
9737
- }
9738
- function stripTopDir(p) {
9739
- const idx = p.indexOf("/");
9740
- if (idx === -1) return "";
9741
- return p.slice(idx + 1);
9742
- }
9743
10138
 
9744
10139
  // src/skills/manifest-store.ts
9745
10140
  init_atomic_write();
9746
10141
  import * as fs14 from "node:fs/promises";
9747
- import * as path23 from "node:path";
10142
+ import * as path24 from "node:path";
9748
10143
  var SkillManifestStore = class {
9749
10144
  manifestPath;
9750
10145
  cache;
@@ -9767,7 +10162,7 @@ var SkillManifestStore = class {
9767
10162
  return this.cache;
9768
10163
  }
9769
10164
  async write(data) {
9770
- const dir = path23.dirname(this.manifestPath);
10165
+ const dir = path24.dirname(this.manifestPath);
9771
10166
  await fs14.mkdir(dir, { recursive: true });
9772
10167
  await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
9773
10168
  this.cache = data;
@@ -9805,6 +10200,10 @@ var SkillManifestStore = class {
9805
10200
  };
9806
10201
 
9807
10202
  // src/skills/skill-installer.ts
10203
+ function isInside(resolved, destDir) {
10204
+ const root = path25.resolve(destDir);
10205
+ return resolved === root || resolved.startsWith(root + path25.sep);
10206
+ }
9808
10207
  var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
9809
10208
  var SkillInstaller = class {
9810
10209
  opts;
@@ -9858,14 +10257,14 @@ var SkillInstaller = class {
9858
10257
  this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
9859
10258
  await this.removeSkillFiles(skill.name, scope);
9860
10259
  }
9861
- const destDir = path24.join(targetDir, skill.name);
10260
+ const destDir = path25.join(targetDir, skill.name);
9862
10261
  await fs15.mkdir(destDir, { recursive: true });
9863
10262
  const copiedFiles = [];
9864
10263
  for (const file of skill.files) {
9865
- const srcPath = path24.join(skill.baseDir, file);
9866
- const destPath = path24.join(destDir, file);
9867
- const resolved2 = path24.resolve(destPath);
9868
- if (!resolved2.startsWith(path24.resolve(destDir))) {
10264
+ const srcPath = path25.join(skill.baseDir, file);
10265
+ const destPath = path25.join(destDir, file);
10266
+ const resolved2 = path25.resolve(destPath);
10267
+ if (!isInside(resolved2, destDir)) {
9869
10268
  throw new FsError({
9870
10269
  message: `Path traversal detected in skill file: ${file}`,
9871
10270
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -9873,16 +10272,16 @@ var SkillInstaller = class {
9873
10272
  context: { reason: "path_traversal", skillName: skill.name }
9874
10273
  });
9875
10274
  }
9876
- const stat6 = await fs15.stat(srcPath);
9877
- if (stat6.size > MAX_SKILL_FILE_SIZE) {
10275
+ const stat7 = await fs15.stat(srcPath);
10276
+ if (stat7.size > MAX_SKILL_FILE_SIZE) {
9878
10277
  throw new FsError({
9879
- message: `Skill file "${file}" is too large (${(stat6.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
10278
+ message: `Skill file "${file}" is too large (${(stat7.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
9880
10279
  code: ERROR_CODES.FS_WRITE_FAILED,
9881
10280
  path: srcPath,
9882
- context: { skillName: skill.name, fileSize: stat6.size, maxSize: MAX_SKILL_FILE_SIZE }
10281
+ context: { skillName: skill.name, fileSize: stat7.size, maxSize: MAX_SKILL_FILE_SIZE }
9883
10282
  });
9884
10283
  }
9885
- await fs15.mkdir(path24.dirname(destPath), { recursive: true });
10284
+ await fs15.mkdir(path25.dirname(destPath), { recursive: true });
9886
10285
  await fs15.copyFile(srcPath, destPath);
9887
10286
  copiedFiles.push(file);
9888
10287
  }
@@ -9940,7 +10339,7 @@ var SkillInstaller = class {
9940
10339
  const results = [];
9941
10340
  for (const e of entries) {
9942
10341
  if (!await entryIsDirectory(srcDir, e)) continue;
9943
- const skillMdPath = path24.join(srcDir, e.name, "SKILL.md");
10342
+ const skillMdPath = path25.join(srcDir, e.name, "SKILL.md");
9944
10343
  let content;
9945
10344
  try {
9946
10345
  content = await fs15.readFile(skillMdPath, "utf8");
@@ -9953,16 +10352,16 @@ var SkillInstaller = class {
9953
10352
  if (existing.find((x) => x.scope === scope)) {
9954
10353
  await this.removeSkillFiles(fm.name, scope);
9955
10354
  }
9956
- const destDir = path24.join(targetDir, fm.name);
10355
+ const destDir = path25.join(targetDir, fm.name);
9957
10356
  await fs15.mkdir(destDir, { recursive: true });
9958
- const srcSkillDir = path24.join(srcDir, e.name);
10357
+ const srcSkillDir = path25.join(srcDir, e.name);
9959
10358
  const files = await collectFiles(srcSkillDir, srcSkillDir);
9960
10359
  const copiedFiles = [];
9961
10360
  for (const file of files) {
9962
- const srcPath = path24.join(srcSkillDir, file);
9963
- const destPath = path24.join(destDir, file);
9964
- const resolved = path24.resolve(destPath);
9965
- if (!resolved.startsWith(path24.resolve(destDir))) {
10361
+ const srcPath = path25.join(srcSkillDir, file);
10362
+ const destPath = path25.join(destDir, file);
10363
+ const resolved = path25.resolve(destPath);
10364
+ if (!isInside(resolved, destDir)) {
9966
10365
  throw new FsError({
9967
10366
  message: `Path traversal detected in skill file: ${file}`,
9968
10367
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -9970,7 +10369,7 @@ var SkillInstaller = class {
9970
10369
  context: { reason: "path_traversal", skillName: fm.name }
9971
10370
  });
9972
10371
  }
9973
- await fs15.mkdir(path24.dirname(destPath), { recursive: true });
10372
+ await fs15.mkdir(path25.dirname(destPath), { recursive: true });
9974
10373
  if (opts?.link) {
9975
10374
  try {
9976
10375
  await fs15.symlink(srcPath, destPath);
@@ -10133,7 +10532,7 @@ var SkillInstaller = class {
10133
10532
  */
10134
10533
  async detectSkills(baseDir) {
10135
10534
  const results = [];
10136
- const rootSkillMd = path24.join(baseDir, "SKILL.md");
10535
+ const rootSkillMd = path25.join(baseDir, "SKILL.md");
10137
10536
  try {
10138
10537
  await fs15.access(rootSkillMd);
10139
10538
  const content = await fs15.readFile(rootSkillMd, "utf8");
@@ -10148,17 +10547,17 @@ var SkillInstaller = class {
10148
10547
  }
10149
10548
  } catch {
10150
10549
  }
10151
- const skillsDir = path24.join(baseDir, "skills");
10550
+ const skillsDir = path25.join(baseDir, "skills");
10152
10551
  try {
10153
10552
  const entries = await fs15.readdir(skillsDir, { withFileTypes: true });
10154
10553
  for (const entry of entries) {
10155
10554
  if (!entry.isDirectory()) continue;
10156
- const skillFile = path24.join(skillsDir, entry.name, "SKILL.md");
10555
+ const skillFile = path25.join(skillsDir, entry.name, "SKILL.md");
10157
10556
  try {
10158
10557
  const content = await fs15.readFile(skillFile, "utf8");
10159
10558
  const fm = parseSkillFrontmatter(content);
10160
10559
  if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
10161
- const skillDir = path24.join(skillsDir, entry.name);
10560
+ const skillDir = path25.join(skillsDir, entry.name);
10162
10561
  const files = await collectFiles(skillDir, skillDir);
10163
10562
  results.push({
10164
10563
  name: fm.name,
@@ -10176,9 +10575,31 @@ var SkillInstaller = class {
10176
10575
  /**
10177
10576
  * Remove all files for an installed skill.
10178
10577
  */
10578
+ /**
10579
+ * Delete an installed skill's directory.
10580
+ *
10581
+ * The containment check is not ceremonial: this is a `recursive: true,
10582
+ * force: true` delete whose target is built from a skill NAME taken from
10583
+ * manifest frontmatter. `path.join` normalises `..`, so a crafted name
10584
+ * escapes `targetDir` and takes the recursive delete with it. This file
10585
+ * already had `isInside` and applied it on the copy path but not here.
10586
+ *
10587
+ * The strict-subdirectory requirement matters separately: `isInside` allows
10588
+ * equality by design, and an empty or `.` name resolves `skillDir` to
10589
+ * `targetDir` itself — deleting every installed skill (WS-097).
10590
+ */
10179
10591
  async removeSkillFiles(name, scope) {
10180
10592
  const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
10181
- const skillDir = path24.join(targetDir, name);
10593
+ const root = path25.resolve(targetDir);
10594
+ const skillDir = path25.resolve(path25.join(targetDir, name));
10595
+ if (skillDir === root || !isInside(skillDir, root)) {
10596
+ throw new FsError({
10597
+ message: `Refusing to delete skill files outside the skills directory: ${name}`,
10598
+ code: ERROR_CODES.FS_DELETE_FAILED,
10599
+ path: skillDir,
10600
+ context: { reason: "path_traversal", skillName: name, scope }
10601
+ });
10602
+ }
10182
10603
  await fs15.rm(skillDir, { recursive: true, force: true });
10183
10604
  }
10184
10605
  /**
@@ -10214,7 +10635,7 @@ async function entryIsDirectory(dir, entry) {
10214
10635
  if (entry.isDirectory()) return true;
10215
10636
  if (entry.isSymbolicLink()) {
10216
10637
  try {
10217
- return (await fs15.stat(path24.join(dir, entry.name))).isDirectory();
10638
+ return (await fs15.stat(path25.join(dir, entry.name))).isDirectory();
10218
10639
  } catch {
10219
10640
  return false;
10220
10641
  }
@@ -10225,8 +10646,8 @@ async function collectFiles(dir, baseDir) {
10225
10646
  const results = [];
10226
10647
  const entries = await fs15.readdir(dir, { withFileTypes: true });
10227
10648
  for (const entry of entries) {
10228
- const fullPath = path24.join(dir, entry.name);
10229
- const relPath = path24.relative(baseDir, fullPath);
10649
+ const fullPath = path25.join(dir, entry.name);
10650
+ const relPath = path25.relative(baseDir, fullPath);
10230
10651
  if (entry.isDirectory()) {
10231
10652
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
10232
10653
  results.push(...await collectFiles(fullPath, baseDir));
@@ -10305,7 +10726,7 @@ function createSkillsPlugin(opts) {
10305
10726
  function makeInstaller(skillLoader, projectRoot, registryAdapters) {
10306
10727
  const paths = resolveWstackPaths({ projectRoot });
10307
10728
  return new SkillInstaller({
10308
- manifestPath: path25.join(paths.configDir, "installed-skills.json"),
10729
+ manifestPath: path26.join(paths.configDir, "installed-skills.json"),
10309
10730
  projectSkillsDir: paths.inProjectSkills,
10310
10731
  globalSkillsDir: paths.globalSkills,
10311
10732
  projectHash: paths.projectHash,
@@ -10333,7 +10754,8 @@ ${lines.join("\n\n")}
10333
10754
  }
10334
10755
  const skill = await skillLoader.find(args.trim());
10335
10756
  if (!skill) return { message: `Skill "${args.trim()}" not found.` };
10336
- return { message: await skillLoader.readBody(skill.name) };
10757
+ const body = capSkillBody(stripFrontmatter(await skillLoader.readBody(skill.name)));
10758
+ return { message: body };
10337
10759
  }
10338
10760
  };
10339
10761
  }
@@ -10372,9 +10794,32 @@ function buildSkillGeneratorCommand(skillLoader) {
10372
10794
  return ` ${src} ${e.name}
10373
10795
  ${e.trigger}`;
10374
10796
  });
10375
- return { message: `Available Skills:
10797
+ let message = `Available Skills:
10376
10798
  ${lines.join("\n\n")}
10377
- ` };
10799
+ `;
10800
+ const diag = skillLoader.diagnostics?.();
10801
+ if (diag && (diag.shadowed.length > 0 || diag.skipped.length > 0)) {
10802
+ const notes = [];
10803
+ if (diag.shadowed.length > 0) {
10804
+ notes.push(color.dim("Shadowed (hidden by a higher-priority layer):"));
10805
+ for (const s of diag.shadowed) {
10806
+ notes.push(
10807
+ color.dim(` \u26A0 ${s.name} (${s.source}) \u2190 overridden by ${s.shadowedBy}`)
10808
+ );
10809
+ }
10810
+ }
10811
+ if (diag.skipped.length > 0) {
10812
+ notes.push(color.dim("Skipped (malformed SKILL.md):"));
10813
+ for (const k of diag.skipped) {
10814
+ const name = k.name ? ` "${k.name}"` : "";
10815
+ notes.push(color.dim(` \u2717 ${k.entry}${name} \u2014 ${k.reason}`));
10816
+ }
10817
+ }
10818
+ message += `
10819
+ ${notes.join("\n")}
10820
+ `;
10821
+ }
10822
+ return { message };
10378
10823
  }
10379
10824
  if (sub === "validate") {
10380
10825
  const name = rest[0];
@@ -10431,7 +10876,10 @@ ${lines.join("\n\n")}
10431
10876
  if (!skill) return { message: `Skill "${skillName}" not found.` };
10432
10877
  try {
10433
10878
  await openInEditor(skill.path);
10434
- return { message: `Opening ${skill.path} in your editor\u2026` };
10879
+ skillLoader.invalidateCache();
10880
+ return {
10881
+ message: `Opening ${skill.path} in your editor\u2026 (skill cache cleared \u2014 changes load on next use)`
10882
+ };
10435
10883
  } catch (err) {
10436
10884
  return { message: `\u2717 ${toErrorMessage(err)}` };
10437
10885
  }
@@ -10657,7 +11105,7 @@ function resolveImportSourceDir(tool, opts) {
10657
11105
  const entry = IMPORT_SOURCE_TOOLS.find((t) => t.id === tool);
10658
11106
  if (!entry) return void 0;
10659
11107
  const base = opts.global ? opts.homeDir ?? os7.homedir() : opts.projectRoot;
10660
- return path25.join(base, "." + entry.id, entry.subdir);
11108
+ return path26.join(base, "." + entry.id, entry.subdir);
10661
11109
  }
10662
11110
  function buildSkillImportCommand(skillLoader) {
10663
11111
  return {
@@ -10698,7 +11146,7 @@ function buildSkillImportCommand(skillLoader) {
10698
11146
  };
10699
11147
  }
10700
11148
  } else if (positional) {
10701
- srcDir = path25.resolve(ctx.projectRoot, positional);
11149
+ srcDir = path26.resolve(ctx.projectRoot, positional);
10702
11150
  } else {
10703
11151
  return {
10704
11152
  message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
@@ -10825,14 +11273,14 @@ function truncate(s, max) {
10825
11273
  }
10826
11274
 
10827
11275
  // src/plugins/sync-plugin.ts
10828
- import * as path27 from "node:path";
11276
+ import * as path28 from "node:path";
10829
11277
  init_error();
10830
11278
 
10831
11279
  // src/storage/cloud-sync.ts
10832
11280
  init_atomic_write();
10833
11281
  init_errors();
10834
11282
  import * as fs16 from "node:fs/promises";
10835
- import * as path26 from "node:path";
11283
+ import * as path27 from "node:path";
10836
11284
  import { createHash as createHash9 } from "node:crypto";
10837
11285
  var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
10838
11286
  var CloudSync = class {
@@ -10840,8 +11288,8 @@ var CloudSync = class {
10840
11288
  this.paths = paths;
10841
11289
  this.getConfig = getConfig;
10842
11290
  this.setConfig = setConfig;
10843
- this.statePath = path26.join(paths.configDir, "sync-state.json");
10844
- this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path26.join(this.paths.configDir, "config.json"));
11291
+ this.statePath = path27.join(paths.configDir, "sync-state.json");
11292
+ this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path27.join(this.paths.configDir, "config.json"));
10845
11293
  }
10846
11294
  paths;
10847
11295
  getConfig;
@@ -11121,13 +11569,13 @@ var CloudSync = class {
11121
11569
  const localPath = this.categoryToPath(cat);
11122
11570
  if (!localPath) continue;
11123
11571
  try {
11124
- const stat6 = await fs16.lstat(localPath);
11125
- if (stat6.isSymbolicLink()) continue;
11126
- if (stat6.isDirectory()) {
11572
+ const stat7 = await fs16.lstat(localPath);
11573
+ if (stat7.isSymbolicLink()) continue;
11574
+ if (stat7.isDirectory()) {
11127
11575
  const files = await this.walkDir(localPath, localPath);
11128
11576
  for (const file of files) {
11129
11577
  const content = await fs16.readFile(file, "utf8");
11130
- const rel = path26.relative(localPath, file).replace(/\\/g, "/");
11578
+ const rel = path27.relative(localPath, file).replace(/\\/g, "/");
11131
11579
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
11132
11580
  hashes.push(`${cat}/${rel}\0${content}`);
11133
11581
  }
@@ -11148,13 +11596,13 @@ var CloudSync = class {
11148
11596
  const localPath = this.categoryToPath(cat);
11149
11597
  if (!localPath) continue;
11150
11598
  try {
11151
- const stat6 = await fs16.lstat(localPath);
11152
- if (stat6.isSymbolicLink()) continue;
11153
- if (stat6.isDirectory()) {
11599
+ const stat7 = await fs16.lstat(localPath);
11600
+ if (stat7.isSymbolicLink()) continue;
11601
+ if (stat7.isDirectory()) {
11154
11602
  const files = await this.walkDir(localPath, localPath);
11155
11603
  for (const file of files) {
11156
11604
  const content = await fs16.readFile(file, "utf8");
11157
- const rel = path26.relative(localPath, file).replace(/\\/g, "/");
11605
+ const rel = path27.relative(localPath, file).replace(/\\/g, "/");
11158
11606
  hashes.push(`${cat}/${rel}\0${content}`);
11159
11607
  }
11160
11608
  } else {
@@ -11188,7 +11636,7 @@ var CloudSync = class {
11188
11636
  const entries = await fs16.readdir(dir, { withFileTypes: true });
11189
11637
  entries.sort((a, b) => a.name.localeCompare(b.name));
11190
11638
  for (const entry of entries) {
11191
- const full = path26.join(dir, entry.name);
11639
+ const full = path27.join(dir, entry.name);
11192
11640
  if (entry.isSymbolicLink()) continue;
11193
11641
  if (entry.isDirectory()) {
11194
11642
  results.push(...await this.walkDir(full, base));
@@ -11201,25 +11649,25 @@ var CloudSync = class {
11201
11649
  };
11202
11650
  async function preparePulledDestination(cat, localPath, destPath, remotePath) {
11203
11651
  const directoryBacked = cat === "skills" || cat === "prompts";
11204
- const rootPath = directoryBacked ? localPath : path26.dirname(localPath);
11652
+ const rootPath = directoryBacked ? localPath : path27.dirname(localPath);
11205
11653
  const rootStat = await lstatIfExists(rootPath);
11206
11654
  if (rootStat?.isSymbolicLink()) {
11207
11655
  throw unsafePulledSymlinkError(remotePath, rootPath);
11208
11656
  }
11209
11657
  if (directoryBacked) {
11210
- const relativeParent = path26.relative(rootPath, path26.dirname(destPath));
11658
+ const relativeParent = path27.relative(rootPath, path27.dirname(destPath));
11211
11659
  let cursor = rootPath;
11212
11660
  if (relativeParent) {
11213
- for (const segment of relativeParent.split(path26.sep)) {
11214
- cursor = path26.join(cursor, segment);
11215
- const stat6 = await lstatIfExists(cursor);
11216
- if (stat6?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
11661
+ for (const segment of relativeParent.split(path27.sep)) {
11662
+ cursor = path27.join(cursor, segment);
11663
+ const stat7 = await lstatIfExists(cursor);
11664
+ if (stat7?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
11217
11665
  }
11218
11666
  }
11219
11667
  }
11220
11668
  const destStat = await lstatIfExists(destPath);
11221
11669
  if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
11222
- await fs16.mkdir(path26.dirname(destPath), { recursive: true });
11670
+ await fs16.mkdir(path27.dirname(destPath), { recursive: true });
11223
11671
  }
11224
11672
  async function lstatIfExists(filePath) {
11225
11673
  try {
@@ -11249,9 +11697,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
11249
11697
  return localPath;
11250
11698
  }
11251
11699
  if (!rel) return localPath;
11252
- const normalizedRel = path26.normalize(rel);
11253
- const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path26.sep}`);
11254
- if (path26.isAbsolute(normalizedRel) || traversesUp) {
11700
+ const normalizedRel = path27.normalize(rel);
11701
+ const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path27.sep}`);
11702
+ if (path27.isAbsolute(normalizedRel) || traversesUp) {
11255
11703
  throw new FsError({
11256
11704
  message: `Refusing CloudSync path traversal: ${remotePath}`,
11257
11705
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -11259,10 +11707,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
11259
11707
  context: { reason: "path_traversal", normalizedRel }
11260
11708
  });
11261
11709
  }
11262
- const dest = path26.resolve(localPath, normalizedRel);
11263
- const root = path26.resolve(localPath);
11264
- const relative5 = path26.relative(root, dest);
11265
- if (relative5.startsWith("..") || path26.isAbsolute(relative5)) {
11710
+ const dest = path27.resolve(localPath, normalizedRel);
11711
+ const root = path27.resolve(localPath);
11712
+ const relative5 = path27.relative(root, dest);
11713
+ if (relative5.startsWith("..") || path27.isAbsolute(relative5)) {
11266
11714
  throw new FsError({
11267
11715
  message: `Refusing CloudSync path outside category root: ${remotePath}`,
11268
11716
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -11305,7 +11753,7 @@ function createSyncPlugin(opts) {
11305
11753
  api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
11306
11754
  return;
11307
11755
  }
11308
- const syncConfigPath = paths.syncConfig ?? path27.join(paths.configDir, "sync.json");
11756
+ const syncConfigPath = paths.syncConfig ?? path28.join(paths.configDir, "sync.json");
11309
11757
  cloud = new CloudSync(
11310
11758
  paths,
11311
11759
  () => {
@@ -11316,7 +11764,7 @@ function createSyncPlugin(opts) {
11316
11764
  await persistSyncConfig(syncConfigPath, cfg, vault);
11317
11765
  configStore?.update({ sync: cfg });
11318
11766
  },
11319
- () => path27.join(paths.configDir, "config.json")
11767
+ () => path28.join(paths.configDir, "config.json")
11320
11768
  );
11321
11769
  void cloud.loadState();
11322
11770
  api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
@@ -11519,8 +11967,14 @@ export {
11519
11967
  definePlugin,
11520
11968
  diffPluginConfig,
11521
11969
  emitReviewIfChanged,
11970
+ integrateFindings,
11522
11971
  loadPlugins,
11972
+ maybeCompactReviewStores,
11973
+ parseChimeraReviewReport,
11523
11974
  parseReviewSeverity,
11975
+ persistReviewReport,
11976
+ recordCompletedReview,
11977
+ recordStartedReview,
11524
11978
  redactPluginConfig,
11525
11979
  resolvePluginConfig,
11526
11980
  resolvePluginManifestConfig,