@aitne/daemon 0.1.4 → 0.1.7

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 (272) hide show
  1. package/dist/adapters/notification-manager.d.ts +12 -0
  2. package/dist/adapters/notification-manager.d.ts.map +1 -1
  3. package/dist/adapters/notification-manager.js +39 -1
  4. package/dist/adapters/notification-manager.js.map +1 -1
  5. package/dist/api/routes/agent.d.ts.map +1 -1
  6. package/dist/api/routes/agent.js +7 -0
  7. package/dist/api/routes/agent.js.map +1 -1
  8. package/dist/api/routes/commands.d.ts.map +1 -1
  9. package/dist/api/routes/commands.js +16 -13
  10. package/dist/api/routes/commands.js.map +1 -1
  11. package/dist/api/routes/context.d.ts.map +1 -1
  12. package/dist/api/routes/context.js +13 -2
  13. package/dist/api/routes/context.js.map +1 -1
  14. package/dist/api/routes/dashboard.d.ts.map +1 -1
  15. package/dist/api/routes/dashboard.js +28 -0
  16. package/dist/api/routes/dashboard.js.map +1 -1
  17. package/dist/api/routes/fs.d.ts +23 -0
  18. package/dist/api/routes/fs.d.ts.map +1 -0
  19. package/dist/api/routes/fs.js +156 -0
  20. package/dist/api/routes/fs.js.map +1 -0
  21. package/dist/api/routes/fs.logic.d.ts +62 -0
  22. package/dist/api/routes/fs.logic.d.ts.map +1 -0
  23. package/dist/api/routes/fs.logic.js +137 -0
  24. package/dist/api/routes/fs.logic.js.map +1 -0
  25. package/dist/api/routes/health.d.ts.map +1 -1
  26. package/dist/api/routes/health.js +4 -2
  27. package/dist/api/routes/health.js.map +1 -1
  28. package/dist/api/routes/integrations.d.ts.map +1 -1
  29. package/dist/api/routes/integrations.js +8 -6
  30. package/dist/api/routes/integrations.js.map +1 -1
  31. package/dist/api/routes/metrics.d.ts +1 -0
  32. package/dist/api/routes/metrics.d.ts.map +1 -1
  33. package/dist/api/routes/metrics.js +24 -0
  34. package/dist/api/routes/metrics.js.map +1 -1
  35. package/dist/api/routes/observations.d.ts.map +1 -1
  36. package/dist/api/routes/observations.js +538 -25
  37. package/dist/api/routes/observations.js.map +1 -1
  38. package/dist/api/routes/skills.d.ts +9 -1
  39. package/dist/api/routes/skills.d.ts.map +1 -1
  40. package/dist/api/routes/skills.js +38 -16
  41. package/dist/api/routes/skills.js.map +1 -1
  42. package/dist/api/routes/wiki.d.ts +4 -0
  43. package/dist/api/routes/wiki.d.ts.map +1 -0
  44. package/dist/api/routes/wiki.js +1075 -0
  45. package/dist/api/routes/wiki.js.map +1 -0
  46. package/dist/api/server.d.ts +13 -0
  47. package/dist/api/server.d.ts.map +1 -1
  48. package/dist/api/server.js +27 -1
  49. package/dist/api/server.js.map +1 -1
  50. package/dist/config.d.ts.map +1 -1
  51. package/dist/config.js +26 -0
  52. package/dist/config.js.map +1 -1
  53. package/dist/core/agent-core.d.ts +25 -0
  54. package/dist/core/agent-core.d.ts.map +1 -1
  55. package/dist/core/agent-core.js.map +1 -1
  56. package/dist/core/backends/backend-router.d.ts +5 -1
  57. package/dist/core/backends/backend-router.d.ts.map +1 -1
  58. package/dist/core/backends/backend-router.js +10 -1
  59. package/dist/core/backends/backend-router.js.map +1 -1
  60. package/dist/core/backends/claude-code-core.d.ts.map +1 -1
  61. package/dist/core/backends/claude-code-core.js +62 -4
  62. package/dist/core/backends/claude-code-core.js.map +1 -1
  63. package/dist/core/backends/claude-tool-collection.d.ts +1 -1
  64. package/dist/core/backends/claude-tool-collection.d.ts.map +1 -1
  65. package/dist/core/backends/claude-tool-collection.js +327 -65
  66. package/dist/core/backends/claude-tool-collection.js.map +1 -1
  67. package/dist/core/backends/codex-core.d.ts.map +1 -1
  68. package/dist/core/backends/codex-core.js +36 -0
  69. package/dist/core/backends/codex-core.js.map +1 -1
  70. package/dist/core/backends/gemini-cli-core.d.ts +24 -5
  71. package/dist/core/backends/gemini-cli-core.d.ts.map +1 -1
  72. package/dist/core/backends/gemini-cli-core.js +62 -30
  73. package/dist/core/backends/gemini-cli-core.js.map +1 -1
  74. package/dist/core/backends/plan-presets.d.ts +3 -1
  75. package/dist/core/backends/plan-presets.d.ts.map +1 -1
  76. package/dist/core/backends/plan-presets.js +42 -2
  77. package/dist/core/backends/plan-presets.js.map +1 -1
  78. package/dist/core/bang-commands/commands-help.d.ts +5 -0
  79. package/dist/core/bang-commands/commands-help.d.ts.map +1 -0
  80. package/dist/core/bang-commands/commands-help.js +69 -0
  81. package/dist/core/bang-commands/commands-help.js.map +1 -0
  82. package/dist/core/bang-commands/commands-wiki.d.ts +75 -0
  83. package/dist/core/bang-commands/commands-wiki.d.ts.map +1 -0
  84. package/dist/core/bang-commands/commands-wiki.js +574 -0
  85. package/dist/core/bang-commands/commands-wiki.js.map +1 -0
  86. package/dist/core/bang-commands/index.d.ts +4 -2
  87. package/dist/core/bang-commands/index.d.ts.map +1 -1
  88. package/dist/core/bang-commands/index.js +15 -1
  89. package/dist/core/bang-commands/index.js.map +1 -1
  90. package/dist/core/bang-commands/registry.d.ts +47 -4
  91. package/dist/core/bang-commands/registry.d.ts.map +1 -1
  92. package/dist/core/bang-commands/registry.js +85 -15
  93. package/dist/core/bang-commands/registry.js.map +1 -1
  94. package/dist/core/context-builder.d.ts +17 -0
  95. package/dist/core/context-builder.d.ts.map +1 -1
  96. package/dist/core/context-builder.js +64 -6
  97. package/dist/core/context-builder.js.map +1 -1
  98. package/dist/core/daemon-api-cli.d.ts.map +1 -1
  99. package/dist/core/daemon-api-cli.js +50 -2
  100. package/dist/core/daemon-api-cli.js.map +1 -1
  101. package/dist/core/dispatcher-message-handler.d.ts.map +1 -1
  102. package/dist/core/dispatcher-message-handler.js +10 -0
  103. package/dist/core/dispatcher-message-handler.js.map +1 -1
  104. package/dist/core/dispatcher-morning-routine.d.ts.map +1 -1
  105. package/dist/core/dispatcher-morning-routine.js +17 -2
  106. package/dist/core/dispatcher-morning-routine.js.map +1 -1
  107. package/dist/core/dispatcher-result-processor.d.ts +23 -0
  108. package/dist/core/dispatcher-result-processor.d.ts.map +1 -1
  109. package/dist/core/dispatcher-result-processor.js +124 -5
  110. package/dist/core/dispatcher-result-processor.js.map +1 -1
  111. package/dist/core/dispatcher-scheduled-tasks.d.ts.map +1 -1
  112. package/dist/core/dispatcher-scheduled-tasks.js +114 -80
  113. package/dist/core/dispatcher-scheduled-tasks.js.map +1 -1
  114. package/dist/core/dispatcher-types.d.ts +116 -1
  115. package/dist/core/dispatcher-types.d.ts.map +1 -1
  116. package/dist/core/dispatcher-types.js.map +1 -1
  117. package/dist/core/dispatcher.d.ts +36 -0
  118. package/dist/core/dispatcher.d.ts.map +1 -1
  119. package/dist/core/dispatcher.js +94 -1
  120. package/dist/core/dispatcher.js.map +1 -1
  121. package/dist/core/integration-lifecycle.d.ts.map +1 -1
  122. package/dist/core/integration-lifecycle.js +6 -8
  123. package/dist/core/integration-lifecycle.js.map +1 -1
  124. package/dist/core/metrics.d.ts +127 -0
  125. package/dist/core/metrics.d.ts.map +1 -1
  126. package/dist/core/metrics.js +256 -1
  127. package/dist/core/metrics.js.map +1 -1
  128. package/dist/core/prompts.d.ts +2 -1
  129. package/dist/core/prompts.d.ts.map +1 -1
  130. package/dist/core/prompts.js +40 -0
  131. package/dist/core/prompts.js.map +1 -1
  132. package/dist/core/roadmap-validate.js +13 -1
  133. package/dist/core/roadmap-validate.js.map +1 -1
  134. package/dist/core/routine-acquisition-plan.d.ts +51 -0
  135. package/dist/core/routine-acquisition-plan.d.ts.map +1 -1
  136. package/dist/core/routine-acquisition-plan.js +111 -12
  137. package/dist/core/routine-acquisition-plan.js.map +1 -1
  138. package/dist/core/routine-fetch-window-retry.d.ts +109 -0
  139. package/dist/core/routine-fetch-window-retry.d.ts.map +1 -0
  140. package/dist/core/routine-fetch-window-retry.js +210 -0
  141. package/dist/core/routine-fetch-window-retry.js.map +1 -0
  142. package/dist/core/routine-fetch-window-runner.d.ts +258 -32
  143. package/dist/core/routine-fetch-window-runner.d.ts.map +1 -1
  144. package/dist/core/routine-fetch-window-runner.js +1115 -185
  145. package/dist/core/routine-fetch-window-runner.js.map +1 -1
  146. package/dist/core/routine-windows.d.ts +19 -4
  147. package/dist/core/routine-windows.d.ts.map +1 -1
  148. package/dist/core/routine-windows.js +47 -0
  149. package/dist/core/routine-windows.js.map +1 -1
  150. package/dist/core/scheduler.d.ts +50 -2
  151. package/dist/core/scheduler.d.ts.map +1 -1
  152. package/dist/core/scheduler.js +88 -7
  153. package/dist/core/scheduler.js.map +1 -1
  154. package/dist/core/skill-curation/declarations.d.ts.map +1 -1
  155. package/dist/core/skill-curation/declarations.js +11 -12
  156. package/dist/core/skill-curation/declarations.js.map +1 -1
  157. package/dist/core/skill-source-paths.d.ts +14 -0
  158. package/dist/core/skill-source-paths.d.ts.map +1 -0
  159. package/dist/core/skill-source-paths.js +82 -0
  160. package/dist/core/skill-source-paths.js.map +1 -0
  161. package/dist/core/skills-compiler.d.ts +18 -0
  162. package/dist/core/skills-compiler.d.ts.map +1 -1
  163. package/dist/core/skills-compiler.js +65 -18
  164. package/dist/core/skills-compiler.js.map +1 -1
  165. package/dist/core/skills-manifest.d.ts.map +1 -1
  166. package/dist/core/skills-manifest.js +46 -0
  167. package/dist/core/skills-manifest.js.map +1 -1
  168. package/dist/core/system-reset.d.ts +25 -0
  169. package/dist/core/system-reset.d.ts.map +1 -1
  170. package/dist/core/system-reset.js +47 -0
  171. package/dist/core/system-reset.js.map +1 -1
  172. package/dist/core/wiki/approval-queue.d.ts +31 -0
  173. package/dist/core/wiki/approval-queue.d.ts.map +1 -0
  174. package/dist/core/wiki/approval-queue.js +44 -0
  175. package/dist/core/wiki/approval-queue.js.map +1 -0
  176. package/dist/core/wiki/bridge.d.ts +74 -0
  177. package/dist/core/wiki/bridge.d.ts.map +1 -0
  178. package/dist/core/wiki/bridge.js +405 -0
  179. package/dist/core/wiki/bridge.js.map +1 -0
  180. package/dist/core/wiki/compile-lock.d.ts +42 -0
  181. package/dist/core/wiki/compile-lock.d.ts.map +1 -0
  182. package/dist/core/wiki/compile-lock.js +55 -0
  183. package/dist/core/wiki/compile-lock.js.map +1 -0
  184. package/dist/core/wiki/compile-preview.d.ts +8 -0
  185. package/dist/core/wiki/compile-preview.d.ts.map +1 -0
  186. package/dist/core/wiki/compile-preview.js +200 -0
  187. package/dist/core/wiki/compile-preview.js.map +1 -0
  188. package/dist/core/wiki/cost-estimate.d.ts +30 -0
  189. package/dist/core/wiki/cost-estimate.d.ts.map +1 -0
  190. package/dist/core/wiki/cost-estimate.js +243 -0
  191. package/dist/core/wiki/cost-estimate.js.map +1 -0
  192. package/dist/core/wiki/dispatcher.d.ts +48 -0
  193. package/dist/core/wiki/dispatcher.d.ts.map +1 -0
  194. package/dist/core/wiki/dispatcher.js +92 -0
  195. package/dist/core/wiki/dispatcher.js.map +1 -0
  196. package/dist/core/wiki/git-precompile.d.ts +86 -0
  197. package/dist/core/wiki/git-precompile.d.ts.map +1 -0
  198. package/dist/core/wiki/git-precompile.js +96 -0
  199. package/dist/core/wiki/git-precompile.js.map +1 -0
  200. package/dist/core/wiki/import-migrate.d.ts +38 -0
  201. package/dist/core/wiki/import-migrate.d.ts.map +1 -0
  202. package/dist/core/wiki/import-migrate.js +310 -0
  203. package/dist/core/wiki/import-migrate.js.map +1 -0
  204. package/dist/core/wiki/import-probe.d.ts +76 -0
  205. package/dist/core/wiki/import-probe.d.ts.map +1 -0
  206. package/dist/core/wiki/import-probe.js +245 -0
  207. package/dist/core/wiki/import-probe.js.map +1 -0
  208. package/dist/core/wiki/index-cache.d.ts +39 -0
  209. package/dist/core/wiki/index-cache.d.ts.map +1 -0
  210. package/dist/core/wiki/index-cache.js +152 -0
  211. package/dist/core/wiki/index-cache.js.map +1 -0
  212. package/dist/core/wiki/multi-url-dispatch.d.ts +52 -0
  213. package/dist/core/wiki/multi-url-dispatch.d.ts.map +1 -0
  214. package/dist/core/wiki/multi-url-dispatch.js +72 -0
  215. package/dist/core/wiki/multi-url-dispatch.js.map +1 -0
  216. package/dist/core/wiki/wiki-fts.d.ts +75 -0
  217. package/dist/core/wiki/wiki-fts.d.ts.map +1 -0
  218. package/dist/core/wiki/wiki-fts.js +265 -0
  219. package/dist/core/wiki/wiki-fts.js.map +1 -0
  220. package/dist/core/wiki/workspaces.d.ts +101 -0
  221. package/dist/core/wiki/workspaces.d.ts.map +1 -0
  222. package/dist/core/wiki/workspaces.js +352 -0
  223. package/dist/core/wiki/workspaces.js.map +1 -0
  224. package/dist/core/wiki/write-strategy.d.ts +70 -0
  225. package/dist/core/wiki/write-strategy.d.ts.map +1 -0
  226. package/dist/core/wiki/write-strategy.js +112 -0
  227. package/dist/core/wiki/write-strategy.js.map +1 -0
  228. package/dist/core/workdir.d.ts +8 -1
  229. package/dist/core/workdir.d.ts.map +1 -1
  230. package/dist/core/workdir.js +4 -1
  231. package/dist/core/workdir.js.map +1 -1
  232. package/dist/db/schema.d.ts.map +1 -1
  233. package/dist/db/schema.js +122 -0
  234. package/dist/db/schema.js.map +1 -1
  235. package/dist/db/wiki-store.d.ts +3 -0
  236. package/dist/db/wiki-store.d.ts.map +1 -0
  237. package/dist/db/wiki-store.js +7 -0
  238. package/dist/db/wiki-store.js.map +1 -0
  239. package/dist/index.js +87 -4
  240. package/dist/index.js.map +1 -1
  241. package/dist/messaging/setup-welcome-dm.d.ts +30 -0
  242. package/dist/messaging/setup-welcome-dm.d.ts.map +1 -0
  243. package/dist/messaging/setup-welcome-dm.js +86 -0
  244. package/dist/messaging/setup-welcome-dm.js.map +1 -0
  245. package/dist/messaging/url-extract.d.ts +8 -0
  246. package/dist/messaging/url-extract.d.ts.map +1 -0
  247. package/dist/messaging/url-extract.js +41 -0
  248. package/dist/messaging/url-extract.js.map +1 -0
  249. package/dist/observers/delegated-sync-worker.d.ts +33 -25
  250. package/dist/observers/delegated-sync-worker.d.ts.map +1 -1
  251. package/dist/observers/delegated-sync-worker.js +38 -31
  252. package/dist/observers/delegated-sync-worker.js.map +1 -1
  253. package/dist/observers/imminent-event-scheduler.d.ts +20 -7
  254. package/dist/observers/imminent-event-scheduler.d.ts.map +1 -1
  255. package/dist/observers/imminent-event-scheduler.js +134 -29
  256. package/dist/observers/imminent-event-scheduler.js.map +1 -1
  257. package/dist/safety/always-disallowed.d.ts +65 -0
  258. package/dist/safety/always-disallowed.d.ts.map +1 -1
  259. package/dist/safety/always-disallowed.js +106 -10
  260. package/dist/safety/always-disallowed.js.map +1 -1
  261. package/dist/safety/audit.d.ts +46 -1
  262. package/dist/safety/audit.d.ts.map +1 -1
  263. package/dist/safety/audit.js +79 -16
  264. package/dist/safety/audit.js.map +1 -1
  265. package/dist/safety/risk-classifier.d.ts.map +1 -1
  266. package/dist/safety/risk-classifier.js +29 -0
  267. package/dist/safety/risk-classifier.js.map +1 -1
  268. package/dist/settings/runtime-settings.d.ts +12 -1
  269. package/dist/settings/runtime-settings.d.ts.map +1 -1
  270. package/dist/settings/runtime-settings.js +59 -1
  271. package/dist/settings/runtime-settings.js.map +1 -1
  272. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-queue.js","sourceRoot":"","sources":["../../../src/core/wiki/approval-queue.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,MAAM,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAoCnD,MAAM,UAAU,mBAAmB,CACjC,EAAqB,EACrB,KAA+B;IAE/B,MAAM,eAAe,GAAG,sBAAsB,KAAK,CAAC,SAAS,aAAa,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACnN,sEAAsE;IACtE,qEAAqE;IACrE,uEAAuE;IACvE,sEAAsE;IACtE,mEAAmE;IACnE,oEAAoE;IACpE,kEAAkE;IAClE,6DAA6D;IAC7D,+DAA+D;IAC/D,MAAM,WAAW,GAAG;QAClB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,GAAG,EAAE,KAAK,CAAC,UAAU;QACrB,mBAAmB,EAAE,KAAK,CAAC,WAAW,CAAC,aAAa;QACpD,cAAc,EAAE,KAAK,CAAC,WAAW,CAAC,QAAQ;QAC1C,aAAa,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO;QACxC,WAAW,EAAE;YACX,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,QAAQ;YACpC,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO;YAClC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,QAAQ;YACpC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM;SACjC;KACF,CAAC;IAEF,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;;yEAGmE,CACpE;SACA,GAAG,CACF,eAAe,EACf,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAC3B,KAAK,CAAC,WAAW,CAAC,aAAa,CAChC,CAAC;IACJ,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,CACT;QACE,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;QACxC,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY;QACzC,UAAU;KACX,EACD,8CAA8C,CAC/C,CAAC;IACF,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { WikiBridgeProposal, WikiBridgeResult } from "@aitne/shared";
3
+ import type { WikiWorkspaceRow } from "./workspaces.js";
4
+ export declare const BRIDGE_FILE_RE: RegExp;
5
+ /**
6
+ * Inputs the bridge writer takes. The proposal payload is the
7
+ * `WikiBridgeProposal` from `@aitne/shared`; the workspace + db come
8
+ * from the API route handler.
9
+ */
10
+ export interface ProcessBridgeProposalInput {
11
+ db: Database.Database;
12
+ workspace: WikiWorkspaceRow;
13
+ proposal: WikiBridgeProposal;
14
+ /** Override the timestamp used for filename + frontmatter. Tests only. */
15
+ nowIso?: string;
16
+ /** Override the actor recorded in `agent_actions`. Tests only. */
17
+ actor?: string;
18
+ /**
19
+ * Optional writer override for the bridge file. When omitted, the
20
+ * processor uses `writeFileAtomically` directly — fine for internal
21
+ * workspaces and tests. The API route injects a strategy-aware writer
22
+ * here so external-mode workspaces (iCloud-sandboxed) fall back to
23
+ * the Obsidian CLI on EPERM instead of throwing. Signature mirrors
24
+ * `WikiWriteStrategyResolver.writeFile` (workspace-relative path).
25
+ */
26
+ writeFile?: (relPath: string, content: string) => Promise<void>;
27
+ }
28
+ /**
29
+ * The chokepoint. Synchronous (no network or LLM dependency): hashing,
30
+ * dedup lookup, and file write are all local. The route handler awaits
31
+ * it but only the FS write is async-shaped.
32
+ */
33
+ export declare function processBridgeProposal(input: ProcessBridgeProposalInput): Promise<WikiBridgeResult>;
34
+ /**
35
+ * Public helper — exposed for tests and dashboard inspection. Same
36
+ * normalisation rule the writer uses so callers that need to
37
+ * pre-dedup against `wiki_bridge_dedup` can reproduce the hash.
38
+ */
39
+ export declare function computeBridgeContentHash(proposal: Pick<WikiBridgeProposal, "summary" | "excerpt">): string;
40
+ /**
41
+ * Filename derivation per §10.2. Timestamp segment encodes seconds-
42
+ * resolution and is timezone-stable (UTC). Slug is derived from the
43
+ * caller's hint or, failing that, from the summary's first words.
44
+ */
45
+ export declare function bridgeFilename(nowIso: string, slug: string): string;
46
+ /**
47
+ * Slug derivation. Caller hint wins when it matches the slug regex;
48
+ * otherwise we slugify the summary's first words. We clamp to 40
49
+ * chars so the filename stays well within ext4 / APFS 255-byte limits
50
+ * after the `bridge-<ts>-` prefix.
51
+ */
52
+ export declare function canonicalBridgeSlug(proposal: WikiBridgeProposal): string;
53
+ interface BridgeRenderContext {
54
+ detectedAtIso: string;
55
+ confidence: number;
56
+ workspaceName: string;
57
+ }
58
+ /**
59
+ * `type: bridge` frontmatter — the compiler keys segregation on this
60
+ * (§10.2). The body carries the summary first, then the verbatim
61
+ * excerpt under a heading the compiler can locate without parsing the
62
+ * agent's prose. When the caller supplies a `body` override we use it
63
+ * verbatim — the LLM may want to phrase it differently than the
64
+ * default scaffold.
65
+ */
66
+ export declare function renderBridgeMarkdown(proposal: WikiBridgeProposal, ctx: BridgeRenderContext): string;
67
+ /**
68
+ * Test helper — verify a vault tree has the bridge file. Pure read.
69
+ * Used by integration tests that hit the API and then assert the
70
+ * resulting file landed.
71
+ */
72
+ export declare function bridgeFileExists(workspaceRoot: string, relPath: string): boolean;
73
+ export {};
74
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../../src/core/wiki/bridge.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAEV,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,eAAO,MAAM,cAAc,QAA4C,CAAC;AAGxE;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,gBAAgB,CAAC,CA6N3B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,SAAS,CAAC,GACxD,MAAM,CAMR;AAsBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAIxE;AAcD,UAAU,mBAAmB;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,mBAAmB,GACvB,MAAM,CA6BR;AAiGD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAGT"}
@@ -0,0 +1,405 @@
1
+ /**
2
+ * WIKI_BUILDER_DESIGN.md Phase 5 — bridge mechanism.
3
+ *
4
+ * The DM agent (or any in-process caller) proposes a bridge candidate;
5
+ * this module decides whether to:
6
+ *
7
+ * 1. drop it as a loop-guard violation (the source is itself a
8
+ * bridge file — never re-bridge our own output),
9
+ * 2. drop it as below the per-workspace confidence threshold
10
+ * (`bridge_min_confidence`, §10.3 Q6),
11
+ * 3. dedup it against an earlier proposal with the same canonical
12
+ * content (§10.3 Q3 — SHA-256 over normalised body text),
13
+ * 4. log it as a `wiki.bridge.candidate` row in `agent_actions` while
14
+ * the workspace is in measurement-only mode (§P5.A),
15
+ * 5. write it to `<vault>/10_raw/bridge-<ts>-<slug>.md` with the
16
+ * `type: bridge` frontmatter the compiler keys on (§10.2).
17
+ *
18
+ * Pure-ish: the writer takes its filesystem clock as `nowIso`/`nowMs`
19
+ * for deterministic tests. Real callers use the no-arg defaults.
20
+ */
21
+ import { createHash } from "node:crypto";
22
+ import { existsSync, mkdirSync } from "node:fs";
23
+ import { dirname, resolve } from "node:path";
24
+ import { writeFileAtomically } from "../atomic-write.js";
25
+ import { upsertWikiFulltextRow } from "./wiki-fts.js";
26
+ export const BRIDGE_FILE_RE = /^10_raw\/bridge-[a-z0-9][a-z0-9-]*\.md$/;
27
+ const BRIDGE_SLUG_RE = /^[a-z0-9][a-z0-9-]*$/;
28
+ /**
29
+ * The chokepoint. Synchronous (no network or LLM dependency): hashing,
30
+ * dedup lookup, and file write are all local. The route handler awaits
31
+ * it but only the FS write is async-shaped.
32
+ */
33
+ export async function processBridgeProposal(input) {
34
+ const { db, workspace, proposal } = input;
35
+ const nowIso = input.nowIso ?? new Date().toISOString();
36
+ const confidence = effectiveConfidence(proposal);
37
+ const contentHash = computeBridgeContentHash(proposal);
38
+ const dedupKey = {
39
+ sourceKind: proposal.sourceKind,
40
+ sourceRef: proposal.sourceRef,
41
+ };
42
+ // (1) Loop guard. The DM agent must never bridge its own output — a
43
+ // `sourceRef` that already names a bridge file is a self-reference
44
+ // and would compound on every compile. The check is path-shaped
45
+ // because `sourceRef` semantics differ per caller (a session id, a
46
+ // file path, a message id), but only the file-path case can collide.
47
+ if (BRIDGE_FILE_RE.test(proposal.sourceRef)) {
48
+ recordBridgeAudit(db, workspace, {
49
+ actor: input.actor,
50
+ outcome: "loop_guard",
51
+ proposal,
52
+ confidence,
53
+ contentHash,
54
+ path: null,
55
+ detectedAtIso: nowIso,
56
+ });
57
+ return {
58
+ outcome: "loop_guard",
59
+ workspace: workspace.name,
60
+ path: null,
61
+ contentHash,
62
+ confidence,
63
+ measurementOnly: workspace.bridge_measurement_only === 1,
64
+ dedupKey,
65
+ reason: "source is itself a bridge file",
66
+ };
67
+ }
68
+ // (2) Feature gate. `bridge_enabled = 0` means the workspace owner
69
+ // never opted in; we don't even log a candidate row. `dm_agent_write_enabled`
70
+ // is the API-route precondition; this module trusts the route's
71
+ // 403 enforcement and only re-checks `bridge_enabled` because the
72
+ // in-process callers (e.g. a future routine) bypass the route auth.
73
+ if (workspace.bridge_enabled !== 1) {
74
+ return {
75
+ outcome: "feature_disabled",
76
+ workspace: workspace.name,
77
+ path: null,
78
+ contentHash,
79
+ confidence,
80
+ measurementOnly: workspace.bridge_measurement_only === 1,
81
+ dedupKey,
82
+ reason: "bridge_enabled is 0 on the workspace",
83
+ };
84
+ }
85
+ // (3) Confidence threshold. Explicit triggers always pass — the
86
+ // owner asked for it. Self-judged proposals must clear the
87
+ // per-workspace floor.
88
+ if (proposal.trigger === "self_judged" && confidence < workspace.bridge_min_confidence) {
89
+ recordBridgeAudit(db, workspace, {
90
+ actor: input.actor,
91
+ outcome: "below_threshold",
92
+ proposal,
93
+ confidence,
94
+ contentHash,
95
+ path: null,
96
+ detectedAtIso: nowIso,
97
+ });
98
+ return {
99
+ outcome: "below_threshold",
100
+ workspace: workspace.name,
101
+ path: null,
102
+ contentHash,
103
+ confidence,
104
+ measurementOnly: workspace.bridge_measurement_only === 1,
105
+ dedupKey,
106
+ reason: `confidence ${confidence} below threshold ${workspace.bridge_min_confidence}`,
107
+ };
108
+ }
109
+ // (4) Dedup. The unique index on `(workspace_id, content_hash)` is
110
+ // the durable enforcement; the SELECT lets us return the prior
111
+ // bridge's path so the caller (and the audit row) can surface "this
112
+ // is the same insight you bridged on 2026-05-01".
113
+ const prior = db
114
+ .prepare(`SELECT bridge_path FROM wiki_bridge_dedup
115
+ WHERE workspace_id = ? AND content_hash = ?
116
+ LIMIT 1`)
117
+ .get(workspace.id, contentHash);
118
+ if (prior) {
119
+ recordBridgeAudit(db, workspace, {
120
+ actor: input.actor,
121
+ outcome: "deduplicated",
122
+ proposal,
123
+ confidence,
124
+ contentHash,
125
+ path: null,
126
+ detectedAtIso: nowIso,
127
+ existingPath: prior.bridge_path,
128
+ });
129
+ return {
130
+ outcome: "deduplicated",
131
+ workspace: workspace.name,
132
+ path: null,
133
+ contentHash,
134
+ confidence,
135
+ measurementOnly: workspace.bridge_measurement_only === 1,
136
+ dedupKey,
137
+ existingPath: prior.bridge_path,
138
+ reason: "same content_hash already bridged in this workspace",
139
+ };
140
+ }
141
+ // (5) Measurement-only mode. Log the candidate, persist the dedup
142
+ // row (so a re-proposal of the same content still short-circuits),
143
+ // but do NOT touch the filesystem.
144
+ const measurementOnly = workspace.bridge_measurement_only === 1;
145
+ if (measurementOnly) {
146
+ db.prepare(`INSERT OR IGNORE INTO wiki_bridge_dedup
147
+ (workspace_id, content_hash, source_kind, source_ref,
148
+ bridge_path, confidence, accepted, detected_at)
149
+ VALUES (?, ?, ?, ?, NULL, ?, 0, ?)`).run(workspace.id, contentHash, proposal.sourceKind, proposal.sourceRef, confidence, nowIso);
150
+ recordBridgeAudit(db, workspace, {
151
+ actor: input.actor,
152
+ outcome: "candidate_logged",
153
+ proposal,
154
+ confidence,
155
+ contentHash,
156
+ path: null,
157
+ detectedAtIso: nowIso,
158
+ });
159
+ return {
160
+ outcome: "candidate_logged",
161
+ workspace: workspace.name,
162
+ path: null,
163
+ contentHash,
164
+ confidence,
165
+ measurementOnly: true,
166
+ dedupKey,
167
+ reason: "workspace is in bridge_measurement_only mode",
168
+ };
169
+ }
170
+ // (6) Real write. Compose the filename and body, snapshot the dedup
171
+ // row, then materialise. The file is `create-only` (the raw-layer
172
+ // append-only invariant) so we rely on the unique-index dedup to
173
+ // serialise identical content; truly-distinct content gets a
174
+ // unique timestamp+slug filename.
175
+ const slug = canonicalBridgeSlug(proposal);
176
+ const filename = bridgeFilename(nowIso, slug);
177
+ const relPath = `10_raw/${filename}`;
178
+ const absPath = resolve(workspace.root_path, relPath);
179
+ const body = renderBridgeMarkdown(proposal, {
180
+ detectedAtIso: nowIso,
181
+ confidence,
182
+ workspaceName: workspace.name,
183
+ });
184
+ mkdirSync(dirname(absPath), { recursive: true });
185
+ if (input.writeFile) {
186
+ await input.writeFile(relPath, body);
187
+ }
188
+ else {
189
+ writeFileAtomically(absPath, body);
190
+ }
191
+ db.prepare(`INSERT OR REPLACE INTO wiki_bridge_dedup
192
+ (workspace_id, content_hash, source_kind, source_ref,
193
+ bridge_path, confidence, accepted, detected_at)
194
+ VALUES (?, ?, ?, ?, ?, ?, 1, ?)`).run(workspace.id, contentHash, proposal.sourceKind, proposal.sourceRef, relPath, confidence, nowIso);
195
+ upsertWikiFulltextRow(db, {
196
+ workspaceId: workspace.id,
197
+ path: relPath,
198
+ layer: "raw",
199
+ content: body,
200
+ });
201
+ recordBridgeAudit(db, workspace, {
202
+ actor: input.actor,
203
+ outcome: "written",
204
+ proposal,
205
+ confidence,
206
+ contentHash,
207
+ path: relPath,
208
+ detectedAtIso: nowIso,
209
+ });
210
+ db.prepare(`UPDATE wiki_workspaces SET updated_at = CURRENT_TIMESTAMP WHERE id = ?`).run(workspace.id);
211
+ return {
212
+ outcome: "written",
213
+ workspace: workspace.name,
214
+ path: relPath,
215
+ contentHash,
216
+ confidence,
217
+ measurementOnly: false,
218
+ dedupKey,
219
+ };
220
+ }
221
+ /**
222
+ * Public helper — exposed for tests and dashboard inspection. Same
223
+ * normalisation rule the writer uses so callers that need to
224
+ * pre-dedup against `wiki_bridge_dedup` can reproduce the hash.
225
+ */
226
+ export function computeBridgeContentHash(proposal) {
227
+ return createHash("sha256")
228
+ .update(normaliseForHash(proposal.summary))
229
+ .update("\n--\n")
230
+ .update(normaliseForHash(proposal.excerpt))
231
+ .digest("hex");
232
+ }
233
+ /**
234
+ * Canonicalise free-form prose into a stable hash input: lowercase,
235
+ * collapse whitespace, strip trailing/leading whitespace, and drop
236
+ * common punctuation. Survives spelling-preserving paraphrases that
237
+ * keep the same words but re-flow them across lines.
238
+ */
239
+ function normaliseForHash(text) {
240
+ return text
241
+ .toLowerCase()
242
+ .replace(/[\p{Pd}\p{Pe}\p{Pf}\p{Pi}\p{Po}\p{Ps}]/gu, " ")
243
+ .replace(/\s+/gu, " ")
244
+ .trim();
245
+ }
246
+ function effectiveConfidence(proposal) {
247
+ if (proposal.trigger === "explicit")
248
+ return 1;
249
+ if (typeof proposal.confidence !== "number")
250
+ return 0;
251
+ return Math.max(0, Math.min(1, proposal.confidence));
252
+ }
253
+ /**
254
+ * Filename derivation per §10.2. Timestamp segment encodes seconds-
255
+ * resolution and is timezone-stable (UTC). Slug is derived from the
256
+ * caller's hint or, failing that, from the summary's first words.
257
+ */
258
+ export function bridgeFilename(nowIso, slug) {
259
+ const ts = nowIso.replace(/[-:T]/g, "").replace(/\..+/, "").slice(0, 14);
260
+ // ts is e.g. "20260512T101530" → strip the embedded T → "20260512101530"
261
+ // but we want a hyphenated form `YYYY-MM-DD-HHmmss`.
262
+ const formatted = `${ts.slice(0, 4)}-${ts.slice(4, 6)}-${ts.slice(6, 8)}-${ts.slice(8, 14)}`;
263
+ return `bridge-${formatted}-${slug}.md`;
264
+ }
265
+ /**
266
+ * Slug derivation. Caller hint wins when it matches the slug regex;
267
+ * otherwise we slugify the summary's first words. We clamp to 40
268
+ * chars so the filename stays well within ext4 / APFS 255-byte limits
269
+ * after the `bridge-<ts>-` prefix.
270
+ */
271
+ export function canonicalBridgeSlug(proposal) {
272
+ const hint = (proposal.slug ?? "").trim().toLowerCase();
273
+ if (hint && BRIDGE_SLUG_RE.test(hint))
274
+ return clampSlug(hint);
275
+ return clampSlug(slugifyFromSummary(proposal.summary));
276
+ }
277
+ function slugifyFromSummary(summary) {
278
+ const slug = summary
279
+ .toLowerCase()
280
+ .replace(/[^a-z0-9]+/g, "-")
281
+ .replace(/^-+|-+$/g, "");
282
+ return slug || "untitled";
283
+ }
284
+ function clampSlug(slug) {
285
+ return slug.slice(0, 40).replace(/-+$/, "") || "untitled";
286
+ }
287
+ /**
288
+ * `type: bridge` frontmatter — the compiler keys segregation on this
289
+ * (§10.2). The body carries the summary first, then the verbatim
290
+ * excerpt under a heading the compiler can locate without parsing the
291
+ * agent's prose. When the caller supplies a `body` override we use it
292
+ * verbatim — the LLM may want to phrase it differently than the
293
+ * default scaffold.
294
+ */
295
+ export function renderBridgeMarkdown(proposal, ctx) {
296
+ if (proposal.body) {
297
+ return proposal.body.endsWith("\n") ? proposal.body : `${proposal.body}\n`;
298
+ }
299
+ const lines = [];
300
+ lines.push("---");
301
+ lines.push(`type: bridge`);
302
+ lines.push(`workspace: ${ctx.workspaceName}`);
303
+ lines.push(`trigger: ${proposal.trigger}`);
304
+ lines.push(`detected_at: ${ctx.detectedAtIso}`);
305
+ lines.push(`confidence: ${ctx.confidence.toFixed(2)}`);
306
+ lines.push(`source_kind: ${proposal.sourceKind}`);
307
+ lines.push(`source_ref: ${proposal.sourceRef}`);
308
+ if (proposal.sessionId)
309
+ lines.push(`session_id: ${proposal.sessionId}`);
310
+ if (proposal.messageId)
311
+ lines.push(`message_id: ${proposal.messageId}`);
312
+ if (proposal.routineName)
313
+ lines.push(`routine: ${proposal.routineName}`);
314
+ lines.push("---");
315
+ lines.push("");
316
+ lines.push("# Bridge");
317
+ lines.push("");
318
+ lines.push("## Summary");
319
+ lines.push("");
320
+ lines.push(proposal.summary.trim());
321
+ lines.push("");
322
+ lines.push("## Source excerpt");
323
+ lines.push("");
324
+ lines.push(proposal.excerpt.trim());
325
+ lines.push("");
326
+ return `${lines.join("\n")}`;
327
+ }
328
+ /**
329
+ * §11.1 — re-use `agent_actions`. The action_type encodes the outcome
330
+ * so the dashboard timeline filter can split written vs. candidate vs.
331
+ * dedup rows without parsing `detail` JSON.
332
+ *
333
+ * - `wiki.bridge` — written
334
+ * - `wiki.bridge.candidate` — measurement-only candidate logged
335
+ * - `wiki.bridge.dedup` — dedup short-circuit
336
+ * - `wiki.bridge.skip` — below_threshold / loop_guard
337
+ *
338
+ * `source_kind = 'wiki'` keeps the existing
339
+ * `idx_agent_actions_source` lookup working for the wiki dashboard.
340
+ */
341
+ function recordBridgeAudit(db, workspace, input) {
342
+ const actionType = bridgeActionType(input.outcome);
343
+ const detail = {
344
+ processKey: "wiki.bridge",
345
+ workspace: workspace.name,
346
+ workspace_id: workspace.id,
347
+ outcome: input.outcome,
348
+ trigger: input.proposal.trigger,
349
+ confidence: input.confidence,
350
+ content_hash: input.contentHash,
351
+ source_kind_of: input.proposal.sourceKind,
352
+ source_ref_of: input.proposal.sourceRef,
353
+ session_id: input.proposal.sessionId ?? null,
354
+ message_id: input.proposal.messageId ?? null,
355
+ routine: input.proposal.routineName ?? null,
356
+ targets: input.path ? [input.path] : [],
357
+ existing_path: input.existingPath ?? null,
358
+ summary_chars: input.proposal.summary.length,
359
+ excerpt_chars: input.proposal.excerpt.length,
360
+ actor: input.actor ?? "dm-agent",
361
+ };
362
+ db.prepare(`INSERT INTO agent_actions
363
+ (event_id, action_type, trigger, result, detail,
364
+ started_at, completed_at, source_kind, source_ref)
365
+ VALUES (?, ?, 'autonomous', ?, json(?), ?, ?, 'wiki', ?)`).run(`wiki.bridge:${workspace.name}:${input.contentHash}`, actionType, bridgeAuditResult(input.outcome), JSON.stringify(detail), input.detectedAtIso, input.detectedAtIso, workspace.name);
366
+ }
367
+ function bridgeActionType(outcome) {
368
+ switch (outcome) {
369
+ case "written":
370
+ return "wiki.bridge";
371
+ case "candidate_logged":
372
+ return "wiki.bridge.candidate";
373
+ case "deduplicated":
374
+ return "wiki.bridge.dedup";
375
+ case "below_threshold":
376
+ case "loop_guard":
377
+ case "feature_disabled":
378
+ return "wiki.bridge.skip";
379
+ default: {
380
+ // Exhaustiveness guard — adding a new outcome upstream without
381
+ // mapping it here is a compile-time error.
382
+ const _exhaustive = outcome;
383
+ void _exhaustive;
384
+ return "wiki.bridge.skip";
385
+ }
386
+ }
387
+ }
388
+ function bridgeAuditResult(outcome) {
389
+ if (outcome === "written")
390
+ return "success";
391
+ if (outcome === "candidate_logged" || outcome === "deduplicated")
392
+ return "partial";
393
+ return "skipped";
394
+ }
395
+ /**
396
+ * Test helper — verify a vault tree has the bridge file. Pure read.
397
+ * Used by integration tests that hit the API and then assert the
398
+ * resulting file landed.
399
+ */
400
+ export function bridgeFileExists(workspaceRoot, relPath) {
401
+ if (!BRIDGE_FILE_RE.test(relPath))
402
+ return false;
403
+ return existsSync(resolve(workspaceRoot, relPath));
404
+ }
405
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../../src/core/wiki/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Workspace-scoped in-process lock for `wiki.compile` sessions.
3
+ *
4
+ * WIKI_BUILDER_DESIGN.md §3.5 / §14 Q4 — "Second `!compile` mid-`!compile`
5
+ * → returns 409 `compile_in_progress` with the running session's id.
6
+ * Compiles are not queued: a queued compile would land on a vault state
7
+ * already reflecting the queued user's intent (because the in-progress
8
+ * run picked up the same raw items), producing duplicate work."
9
+ *
10
+ * Design:
11
+ * - The bang handler calls `tryAcquireWikiCompileLock` at enqueue
12
+ * time. The lock is held until the dispatcher releases it via
13
+ * `releaseWikiCompileLock` in `executeDefault`'s `finally` block.
14
+ * - The lock is purely in-process; that matches the dispatcher's
15
+ * existing concurrency invariants (`hourlyCheckInProgress`,
16
+ * `morningRoutineActive` are also in-memory flags). A second
17
+ * daemon process would not see the lock — but the daemon is
18
+ * single-process by design.
19
+ * - TTL fallback: an unreleased lock older than 1h is treated as
20
+ * orphaned (daemon crashed before release, or a session legitimately
21
+ * ran longer than any wiki.compile budget envelope tolerates). The
22
+ * next acquire succeeds and overwrites the stale entry. Without
23
+ * this, a crash mid-compile would block all future `!compile` calls
24
+ * for that workspace until the next daemon restart.
25
+ */
26
+ export interface WikiCompileLockHolder {
27
+ workspace: string;
28
+ startedAt: Date;
29
+ correlationId?: string;
30
+ }
31
+ export type WikiCompileLockAcquireResult = {
32
+ ok: true;
33
+ } | {
34
+ ok: false;
35
+ holder: WikiCompileLockHolder;
36
+ };
37
+ export declare function tryAcquireWikiCompileLock(workspace: string, correlationId?: string, now?: Date): WikiCompileLockAcquireResult;
38
+ export declare function releaseWikiCompileLock(workspace: string): void;
39
+ export declare function getWikiCompileLockHolder(workspace: string): WikiCompileLockHolder | null;
40
+ /** Test helper — wipes the lock state. Never call outside test setup. */
41
+ export declare function __resetWikiCompileLockForTests(): void;
42
+ //# sourceMappingURL=compile-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-lock.d.ts","sourceRoot":"","sources":["../../../src/core/wiki/compile-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,MAAM,MAAM,4BAA4B,GACpC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEjD,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,EACtB,GAAG,GAAE,IAAiB,GACrB,4BAA4B,CAgB9B;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,GAChB,qBAAqB,GAAG,IAAI,CAE9B;AAED,yEAAyE;AACzE,wBAAgB,8BAA8B,IAAI,IAAI,CAErD"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Workspace-scoped in-process lock for `wiki.compile` sessions.
3
+ *
4
+ * WIKI_BUILDER_DESIGN.md §3.5 / §14 Q4 — "Second `!compile` mid-`!compile`
5
+ * → returns 409 `compile_in_progress` with the running session's id.
6
+ * Compiles are not queued: a queued compile would land on a vault state
7
+ * already reflecting the queued user's intent (because the in-progress
8
+ * run picked up the same raw items), producing duplicate work."
9
+ *
10
+ * Design:
11
+ * - The bang handler calls `tryAcquireWikiCompileLock` at enqueue
12
+ * time. The lock is held until the dispatcher releases it via
13
+ * `releaseWikiCompileLock` in `executeDefault`'s `finally` block.
14
+ * - The lock is purely in-process; that matches the dispatcher's
15
+ * existing concurrency invariants (`hourlyCheckInProgress`,
16
+ * `morningRoutineActive` are also in-memory flags). A second
17
+ * daemon process would not see the lock — but the daemon is
18
+ * single-process by design.
19
+ * - TTL fallback: an unreleased lock older than 1h is treated as
20
+ * orphaned (daemon crashed before release, or a session legitimately
21
+ * ran longer than any wiki.compile budget envelope tolerates). The
22
+ * next acquire succeeds and overwrites the stale entry. Without
23
+ * this, a crash mid-compile would block all future `!compile` calls
24
+ * for that workspace until the next daemon restart.
25
+ */
26
+ const LOCK_TTL_MS = 60 * 60 * 1000;
27
+ const inFlight = new Map();
28
+ export function tryAcquireWikiCompileLock(workspace, correlationId, now = new Date()) {
29
+ const existing = inFlight.get(workspace);
30
+ if (existing) {
31
+ const age = now.getTime() - existing.startedAt.getTime();
32
+ if (age < LOCK_TTL_MS) {
33
+ return { ok: false, holder: existing };
34
+ }
35
+ // Stale — overwrite below.
36
+ }
37
+ const holder = {
38
+ workspace,
39
+ startedAt: now,
40
+ ...(correlationId ? { correlationId } : {}),
41
+ };
42
+ inFlight.set(workspace, holder);
43
+ return { ok: true };
44
+ }
45
+ export function releaseWikiCompileLock(workspace) {
46
+ inFlight.delete(workspace);
47
+ }
48
+ export function getWikiCompileLockHolder(workspace) {
49
+ return inFlight.get(workspace) ?? null;
50
+ }
51
+ /** Test helper — wipes the lock state. Never call outside test setup. */
52
+ export function __resetWikiCompileLockForTests() {
53
+ inFlight.clear();
54
+ }
55
+ //# sourceMappingURL=compile-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-lock.js","sourceRoot":"","sources":["../../../src/core/wiki/compile-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAQnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAiC,CAAC;AAM1D,MAAM,UAAU,yBAAyB,CACvC,SAAiB,EACjB,aAAsB,EACtB,MAAY,IAAI,IAAI,EAAE;IAEtB,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACzD,IAAI,GAAG,GAAG,WAAW,EAAE,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACzC,CAAC;QACD,2BAA2B;IAC7B,CAAC;IACD,MAAM,MAAM,GAA0B;QACpC,SAAS;QACT,SAAS,EAAE,GAAG;QACd,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5C,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,SAAiB;IAEjB,OAAO,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AACzC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,8BAA8B;IAC5C,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { WikiCompilePreview, WikiCompileMode } from "@aitne/shared";
2
+ import type { WikiWorkspaceRow } from "./workspaces.js";
3
+ export interface CompilePreviewInput {
4
+ workspace: WikiWorkspaceRow;
5
+ mode: WikiCompileMode;
6
+ }
7
+ export declare function buildCompilePreview(input: CompilePreviewInput): WikiCompilePreview;
8
+ //# sourceMappingURL=compile-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-preview.d.ts","sourceRoot":"","sources":["../../../src/core/wiki/compile-preview.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAuCxD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,GAAG,kBAAkB,CAkElF"}