@geminixiang/mikan 1.0.0-beta.39 → 1.0.0-beta.40

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 (397) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +50 -23
  3. package/dist/adapter.d.ts +1 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/adapters/discord/bot.d.ts +2 -1
  7. package/dist/adapters/discord/bot.d.ts.map +1 -1
  8. package/dist/adapters/discord/bot.js +3 -3
  9. package/dist/adapters/discord/bot.js.map +1 -1
  10. package/dist/adapters/discord/context.d.ts +2 -1
  11. package/dist/adapters/discord/context.d.ts.map +1 -1
  12. package/dist/adapters/discord/context.js +1 -1
  13. package/dist/adapters/discord/context.js.map +1 -1
  14. package/dist/adapters/github/bot.d.ts +2 -1
  15. package/dist/adapters/github/bot.d.ts.map +1 -1
  16. package/dist/adapters/github/bot.js +11 -7
  17. package/dist/adapters/github/bot.js.map +1 -1
  18. package/dist/adapters/github/client.js +2 -2
  19. package/dist/adapters/github/client.js.map +1 -1
  20. package/dist/adapters/github/context.d.ts +4 -2
  21. package/dist/adapters/github/context.d.ts.map +1 -1
  22. package/dist/adapters/github/context.js +2 -2
  23. package/dist/adapters/github/context.js.map +1 -1
  24. package/dist/adapters/github/gcp-auth.js +2 -2
  25. package/dist/adapters/github/gcp-auth.js.map +1 -1
  26. package/dist/adapters/github/github-ops.d.ts +3 -2
  27. package/dist/adapters/github/github-ops.d.ts.map +1 -1
  28. package/dist/adapters/github/github-ops.js +1 -1
  29. package/dist/adapters/github/github-ops.js.map +1 -1
  30. package/dist/adapters/github/ids.d.ts.map +1 -1
  31. package/dist/adapters/github/ids.js +7 -3
  32. package/dist/adapters/github/ids.js.map +1 -1
  33. package/dist/adapters/github/repo.js +3 -3
  34. package/dist/adapters/github/repo.js.map +1 -1
  35. package/dist/adapters/github/types.d.ts +2 -1
  36. package/dist/adapters/github/types.d.ts.map +1 -1
  37. package/dist/adapters/github/types.js.map +1 -1
  38. package/dist/adapters/progressive-renderer.js +1 -1
  39. package/dist/adapters/progressive-renderer.js.map +1 -1
  40. package/dist/adapters/shared.js +4 -4
  41. package/dist/adapters/shared.js.map +1 -1
  42. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  43. package/dist/adapters/slack/blocks.js +3 -1
  44. package/dist/adapters/slack/blocks.js.map +1 -1
  45. package/dist/adapters/slack/bot.d.ts +12 -2
  46. package/dist/adapters/slack/bot.d.ts.map +1 -1
  47. package/dist/adapters/slack/bot.js +70 -9
  48. package/dist/adapters/slack/bot.js.map +1 -1
  49. package/dist/adapters/slack/context.d.ts +2 -1
  50. package/dist/adapters/slack/context.d.ts.map +1 -1
  51. package/dist/adapters/slack/context.js +1 -0
  52. package/dist/adapters/slack/context.js.map +1 -1
  53. package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
  54. package/dist/adapters/slack/response-lifecycle.js +4 -4
  55. package/dist/adapters/slack/response-lifecycle.js.map +1 -1
  56. package/dist/adapters/slack/session.d.ts.map +1 -1
  57. package/dist/adapters/slack/session.js +2 -3
  58. package/dist/adapters/slack/session.js.map +1 -1
  59. package/dist/adapters/slack/tools/attach.js +1 -1
  60. package/dist/adapters/slack/tools/attach.js.map +1 -1
  61. package/dist/adapters/telegram/bot.d.ts +2 -1
  62. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  63. package/dist/adapters/telegram/bot.js +6 -6
  64. package/dist/adapters/telegram/bot.js.map +1 -1
  65. package/dist/adapters/telegram/context.d.ts +2 -1
  66. package/dist/adapters/telegram/context.d.ts.map +1 -1
  67. package/dist/adapters/telegram/context.js.map +1 -1
  68. package/dist/adapters/telegram/html.d.ts.map +1 -1
  69. package/dist/adapters/telegram/html.js +10 -7
  70. package/dist/adapters/telegram/html.js.map +1 -1
  71. package/dist/adapters/types.d.ts +4 -2
  72. package/dist/adapters/types.d.ts.map +1 -1
  73. package/dist/adapters/types.js.map +1 -1
  74. package/dist/agent-events.d.ts +3 -2
  75. package/dist/agent-events.d.ts.map +1 -1
  76. package/dist/agent-events.js +19 -1
  77. package/dist/agent-events.js.map +1 -1
  78. package/dist/agent.d.ts.map +1 -1
  79. package/dist/agent.js +34 -9
  80. package/dist/agent.js.map +1 -1
  81. package/dist/cli/arg-grammar.d.ts.map +1 -1
  82. package/dist/cli/arg-grammar.js +5 -3
  83. package/dist/cli/arg-grammar.js.map +1 -1
  84. package/dist/cli/boot.d.ts.map +1 -1
  85. package/dist/cli/boot.js +5 -3
  86. package/dist/cli/boot.js.map +1 -1
  87. package/dist/cli/download.d.ts.map +1 -1
  88. package/dist/cli/download.js +2 -0
  89. package/dist/cli/download.js.map +1 -1
  90. package/dist/cli/ext-dev.d.ts.map +1 -1
  91. package/dist/cli/ext-dev.js +4 -1
  92. package/dist/cli/ext-dev.js.map +1 -1
  93. package/dist/cli/ext.d.ts.map +1 -1
  94. package/dist/cli/ext.js +123 -23
  95. package/dist/cli/ext.js.map +1 -1
  96. package/dist/cli/office.d.ts.map +1 -1
  97. package/dist/cli/office.js +2 -0
  98. package/dist/cli/office.js.map +1 -1
  99. package/dist/cli/types.d.ts +0 -6
  100. package/dist/cli/types.d.ts.map +1 -1
  101. package/dist/cli/types.js.map +1 -1
  102. package/dist/commands/admin.js +1 -1
  103. package/dist/commands/admin.js.map +1 -1
  104. package/dist/commands/auto-reply.js +2 -2
  105. package/dist/commands/auto-reply.js.map +1 -1
  106. package/dist/commands/extensions.js +1 -1
  107. package/dist/commands/extensions.js.map +1 -1
  108. package/dist/commands/login.js +1 -1
  109. package/dist/commands/login.js.map +1 -1
  110. package/dist/commands/manifest.d.ts +7 -0
  111. package/dist/commands/manifest.d.ts.map +1 -1
  112. package/dist/commands/manifest.js +28 -0
  113. package/dist/commands/manifest.js.map +1 -1
  114. package/dist/commands/model.d.ts.map +1 -1
  115. package/dist/commands/model.js +4 -1
  116. package/dist/commands/model.js.map +1 -1
  117. package/dist/commands/new.js +1 -1
  118. package/dist/commands/new.js.map +1 -1
  119. package/dist/commands/sandbox.js +3 -3
  120. package/dist/commands/sandbox.js.map +1 -1
  121. package/dist/commands/session-view.d.ts.map +1 -1
  122. package/dist/commands/session-view.js +5 -2
  123. package/dist/commands/session-view.js.map +1 -1
  124. package/dist/commands/types.d.ts +1 -1
  125. package/dist/commands/types.d.ts.map +1 -1
  126. package/dist/commands/types.js.map +1 -1
  127. package/dist/config.js +4 -4
  128. package/dist/config.js.map +1 -1
  129. package/dist/env-manifest.d.ts +2 -0
  130. package/dist/env-manifest.d.ts.map +1 -1
  131. package/dist/env-manifest.js +11 -1
  132. package/dist/env-manifest.js.map +1 -1
  133. package/dist/events.d.ts.map +1 -1
  134. package/dist/events.js +7 -6
  135. package/dist/events.js.map +1 -1
  136. package/dist/execution-resolver.d.ts.map +1 -1
  137. package/dist/execution-resolver.js +3 -2
  138. package/dist/execution-resolver.js.map +1 -1
  139. package/dist/extension-schedules.d.ts +31 -0
  140. package/dist/extension-schedules.d.ts.map +1 -0
  141. package/dist/extension-schedules.js +229 -0
  142. package/dist/extension-schedules.js.map +1 -0
  143. package/dist/harness/auth.js +5 -5
  144. package/dist/harness/auth.js.map +1 -1
  145. package/dist/harness/event-format.d.ts +2 -0
  146. package/dist/harness/event-format.d.ts.map +1 -1
  147. package/dist/harness/event-format.js +2 -1
  148. package/dist/harness/event-format.js.map +1 -1
  149. package/dist/harness/extensions/loader.d.ts +2 -2
  150. package/dist/harness/extensions/loader.d.ts.map +1 -1
  151. package/dist/harness/extensions/loader.js +135 -33
  152. package/dist/harness/extensions/loader.js.map +1 -1
  153. package/dist/harness/extensions/registry.d.ts +33 -1
  154. package/dist/harness/extensions/registry.d.ts.map +1 -1
  155. package/dist/harness/extensions/registry.js +79 -2
  156. package/dist/harness/extensions/registry.js.map +1 -1
  157. package/dist/harness/extensions/types.d.ts +165 -21
  158. package/dist/harness/extensions/types.d.ts.map +1 -1
  159. package/dist/harness/extensions/types.js.map +1 -1
  160. package/dist/harness/index.d.ts +2 -2
  161. package/dist/harness/index.d.ts.map +1 -1
  162. package/dist/harness/index.js +1 -1
  163. package/dist/harness/index.js.map +1 -1
  164. package/dist/harness/models.d.ts.map +1 -1
  165. package/dist/harness/models.js +36 -24
  166. package/dist/harness/models.js.map +1 -1
  167. package/dist/harness/runner.js +2 -2
  168. package/dist/harness/runner.js.map +1 -1
  169. package/dist/harness/session-store.d.ts.map +1 -1
  170. package/dist/harness/session-store.js +9 -7
  171. package/dist/harness/session-store.js.map +1 -1
  172. package/dist/harness/skills.js +3 -3
  173. package/dist/harness/skills.js.map +1 -1
  174. package/dist/harness/subagent-profiles.js +2 -2
  175. package/dist/harness/subagent-profiles.js.map +1 -1
  176. package/dist/harness/subagent-runner.js +3 -3
  177. package/dist/harness/subagent-runner.js.map +1 -1
  178. package/dist/index.d.ts +8 -8
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +5 -5
  181. package/dist/index.js.map +1 -1
  182. package/dist/main.js +58 -9
  183. package/dist/main.js.map +1 -1
  184. package/dist/observability/instrument.js +1 -1
  185. package/dist/observability/instrument.js.map +1 -1
  186. package/dist/observability/sentry.js +1 -1
  187. package/dist/observability/sentry.js.map +1 -1
  188. package/dist/office/index.d.ts +1 -1
  189. package/dist/office/index.d.ts.map +1 -1
  190. package/dist/office/index.js +1 -1
  191. package/dist/office/index.js.map +1 -1
  192. package/dist/office/layout.d.ts +7 -0
  193. package/dist/office/layout.d.ts.map +1 -1
  194. package/dist/office/layout.js +10 -1
  195. package/dist/office/layout.js.map +1 -1
  196. package/dist/office/registry.d.ts.map +1 -1
  197. package/dist/office/registry.js +7 -5
  198. package/dist/office/registry.js.map +1 -1
  199. package/dist/packages/materialize.js +10 -3
  200. package/dist/packages/materialize.js.map +1 -1
  201. package/dist/packages/source.d.ts +6 -0
  202. package/dist/packages/source.d.ts.map +1 -1
  203. package/dist/packages/source.js +14 -2
  204. package/dist/packages/source.js.map +1 -1
  205. package/dist/packages/types.d.ts +5 -3
  206. package/dist/packages/types.d.ts.map +1 -1
  207. package/dist/packages/types.js.map +1 -1
  208. package/dist/provisioner.js +5 -5
  209. package/dist/provisioner.js.map +1 -1
  210. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  211. package/dist/runtime/conversation-runtime.js +44 -2
  212. package/dist/runtime/conversation-runtime.js.map +1 -1
  213. package/dist/runtime/types.d.ts +10 -2
  214. package/dist/runtime/types.d.ts.map +1 -1
  215. package/dist/runtime/types.js.map +1 -1
  216. package/dist/sandbox/cloudflare.js +1 -1
  217. package/dist/sandbox/cloudflare.js.map +1 -1
  218. package/dist/sandbox/container.js +1 -2
  219. package/dist/sandbox/container.js.map +1 -1
  220. package/dist/sandbox/firecracker.js +1 -1
  221. package/dist/sandbox/firecracker.js.map +1 -1
  222. package/dist/sandbox/gondolin.d.ts.map +1 -1
  223. package/dist/sandbox/gondolin.js +1 -2
  224. package/dist/sandbox/gondolin.js.map +1 -1
  225. package/dist/sandbox/host.d.ts.map +1 -1
  226. package/dist/sandbox/host.js +4 -5
  227. package/dist/sandbox/host.js.map +1 -1
  228. package/dist/sandbox/index.js +1 -1
  229. package/dist/sandbox/index.js.map +1 -1
  230. package/dist/sandbox/utils.d.ts +2 -0
  231. package/dist/sandbox/utils.d.ts.map +1 -1
  232. package/dist/sandbox/utils.js +30 -1
  233. package/dist/sandbox/utils.js.map +1 -1
  234. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  235. package/dist/sessions/chat-history-sync.js +9 -8
  236. package/dist/sessions/chat-history-sync.js.map +1 -1
  237. package/dist/sessions/conversation-log.d.ts.map +1 -1
  238. package/dist/sessions/conversation-log.js +5 -2
  239. package/dist/sessions/conversation-log.js.map +1 -1
  240. package/dist/sessions/history-line.d.ts +9 -0
  241. package/dist/sessions/history-line.d.ts.map +1 -1
  242. package/dist/sessions/history-line.js +22 -1
  243. package/dist/sessions/history-line.js.map +1 -1
  244. package/dist/sessions/session-key.d.ts +5 -12
  245. package/dist/sessions/session-key.d.ts.map +1 -1
  246. package/dist/sessions/session-key.js +23 -0
  247. package/dist/sessions/session-key.js.map +1 -1
  248. package/dist/sessions/store.d.ts +2 -6
  249. package/dist/sessions/store.d.ts.map +1 -1
  250. package/dist/sessions/store.js +16 -16
  251. package/dist/sessions/store.js.map +1 -1
  252. package/dist/sessions/types.d.ts +2 -1
  253. package/dist/sessions/types.d.ts.map +1 -1
  254. package/dist/sessions/types.js.map +1 -1
  255. package/dist/tools/bash.js +1 -1
  256. package/dist/tools/bash.js.map +1 -1
  257. package/dist/tools/edit.d.ts.map +1 -1
  258. package/dist/tools/edit.js +4 -1
  259. package/dist/tools/edit.js.map +1 -1
  260. package/dist/tools/event.js +1 -1
  261. package/dist/tools/event.js.map +1 -1
  262. package/dist/tools/generate-image.js +3 -3
  263. package/dist/tools/generate-image.js.map +1 -1
  264. package/dist/tools/read.js +4 -4
  265. package/dist/tools/read.js.map +1 -1
  266. package/dist/tools/subagent.d.ts.map +1 -1
  267. package/dist/tools/subagent.js +9 -2
  268. package/dist/tools/subagent.js.map +1 -1
  269. package/dist/tools/types.d.ts +0 -26
  270. package/dist/tools/types.d.ts.map +1 -1
  271. package/dist/tools/types.js.map +1 -1
  272. package/dist/trigger.d.ts +2 -1
  273. package/dist/trigger.d.ts.map +1 -1
  274. package/dist/trigger.js.map +1 -1
  275. package/dist/types.d.ts +108 -16
  276. package/dist/types.d.ts.map +1 -1
  277. package/dist/types.js +2 -2
  278. package/dist/types.js.map +1 -1
  279. package/dist/utils/file-guards.d.ts +9 -0
  280. package/dist/utils/file-guards.d.ts.map +1 -1
  281. package/dist/utils/file-guards.js +44 -1
  282. package/dist/utils/file-guards.js.map +1 -1
  283. package/dist/vault/disabled.d.ts.map +1 -1
  284. package/dist/vault/disabled.js +3 -0
  285. package/dist/vault/disabled.js.map +1 -1
  286. package/dist/vault/index.d.ts +29 -0
  287. package/dist/vault/index.d.ts.map +1 -1
  288. package/dist/vault/index.js +68 -4
  289. package/dist/vault/index.js.map +1 -1
  290. package/dist/vault/types.d.ts +2 -0
  291. package/dist/vault/types.d.ts.map +1 -1
  292. package/dist/vault/types.js.map +1 -1
  293. package/dist/web/admin/portal.d.ts +1 -1
  294. package/dist/web/admin/portal.d.ts.map +1 -1
  295. package/dist/web/admin/portal.js +194 -22
  296. package/dist/web/admin/portal.js.map +1 -1
  297. package/dist/web/admin/provider-models.js +1 -1
  298. package/dist/web/admin/provider-models.js.map +1 -1
  299. package/dist/web/login/oauth.js +1 -1
  300. package/dist/web/login/oauth.js.map +1 -1
  301. package/dist/web/login/portal.d.ts +1 -1
  302. package/dist/web/login/portal.d.ts.map +1 -1
  303. package/dist/web/login/portal.js +13 -36
  304. package/dist/web/login/portal.js.map +1 -1
  305. package/dist/web/portal-shell.d.ts +17 -0
  306. package/dist/web/portal-shell.d.ts.map +1 -1
  307. package/dist/web/portal-shell.js +66 -1
  308. package/dist/web/portal-shell.js.map +1 -1
  309. package/dist/web/server.d.ts +3 -2
  310. package/dist/web/server.d.ts.map +1 -1
  311. package/dist/web/server.js +3 -3
  312. package/dist/web/server.js.map +1 -1
  313. package/dist/web/session-view/portal.d.ts +1 -1
  314. package/dist/web/session-view/portal.d.ts.map +1 -1
  315. package/dist/web/session-view/portal.js +10 -12
  316. package/dist/web/session-view/portal.js.map +1 -1
  317. package/dist/web/session-view/service.d.ts.map +1 -1
  318. package/dist/web/session-view/service.js +11 -6
  319. package/dist/web/session-view/service.js.map +1 -1
  320. package/dist/web/session-view/types.d.ts +0 -4
  321. package/dist/web/session-view/types.d.ts.map +1 -1
  322. package/dist/web/session-view/types.js.map +1 -1
  323. package/dist/web/token-store.js +1 -1
  324. package/dist/web/token-store.js.map +1 -1
  325. package/package.json +8 -17
  326. package/dist/cli/ext-git.d.ts +0 -17
  327. package/dist/cli/ext-git.d.ts.map +0 -1
  328. package/dist/cli/ext-git.js +0 -107
  329. package/dist/cli/ext-git.js.map +0 -1
  330. package/dist/commands/parse.d.ts +0 -7
  331. package/dist/commands/parse.d.ts.map +0 -1
  332. package/dist/commands/parse.js +0 -14
  333. package/dist/commands/parse.js.map +0 -1
  334. package/dist/commands/text.d.ts +0 -2
  335. package/dist/commands/text.d.ts.map +0 -1
  336. package/dist/commands/text.js +0 -16
  337. package/dist/commands/text.js.map +0 -1
  338. package/dist/harness/extensions/blockkit.d.ts +0 -19
  339. package/dist/harness/extensions/blockkit.d.ts.map +0 -1
  340. package/dist/harness/extensions/blockkit.js +0 -42
  341. package/dist/harness/extensions/blockkit.js.map +0 -1
  342. package/dist/sandbox/path-context.d.ts +0 -3
  343. package/dist/sandbox/path-context.d.ts.map +0 -1
  344. package/dist/sandbox/path-context.js +0 -30
  345. package/dist/sandbox/path-context.js.map +0 -1
  346. package/dist/sessions/metadata.d.ts +0 -3
  347. package/dist/sessions/metadata.d.ts.map +0 -1
  348. package/dist/sessions/metadata.js +0 -11
  349. package/dist/sessions/metadata.js.map +0 -1
  350. package/dist/sessions/policy.d.ts +0 -6
  351. package/dist/sessions/policy.d.ts.map +0 -1
  352. package/dist/sessions/policy.js +0 -25
  353. package/dist/sessions/policy.js.map +0 -1
  354. package/dist/tools/truncate.d.ts +0 -33
  355. package/dist/tools/truncate.d.ts.map +0 -1
  356. package/dist/tools/truncate.js +0 -184
  357. package/dist/tools/truncate.js.map +0 -1
  358. package/dist/utils/date.d.ts +0 -10
  359. package/dist/utils/date.d.ts.map +0 -1
  360. package/dist/utils/date.js +0 -23
  361. package/dist/utils/date.js.map +0 -1
  362. package/dist/utils/env.d.ts +0 -3
  363. package/dist/utils/env.d.ts.map +0 -1
  364. package/dist/utils/env.js +0 -12
  365. package/dist/utils/env.js.map +0 -1
  366. package/dist/utils/fs-atomic.d.ts +0 -10
  367. package/dist/utils/fs-atomic.d.ts.map +0 -1
  368. package/dist/utils/fs-atomic.js +0 -45
  369. package/dist/utils/fs-atomic.js.map +0 -1
  370. package/dist/utils/html.d.ts +0 -2
  371. package/dist/utils/html.d.ts.map +0 -1
  372. package/dist/utils/html.js +0 -4
  373. package/dist/utils/html.js.map +0 -1
  374. package/dist/utils/http-body.d.ts +0 -10
  375. package/dist/utils/http-body.d.ts.map +0 -1
  376. package/dist/utils/http-body.js +0 -34
  377. package/dist/utils/http-body.js.map +0 -1
  378. package/dist/vault/injection.d.ts +0 -12
  379. package/dist/vault/injection.d.ts.map +0 -1
  380. package/dist/vault/injection.js +0 -30
  381. package/dist/vault/injection.js.map +0 -1
  382. package/dist/vault/policy.d.ts +0 -20
  383. package/dist/vault/policy.d.ts.map +0 -1
  384. package/dist/vault/policy.js +0 -20
  385. package/dist/vault/policy.js.map +0 -1
  386. package/dist/web/agent-events/portal.d.ts +0 -3
  387. package/dist/web/agent-events/portal.d.ts.map +0 -1
  388. package/dist/web/agent-events/portal.js +0 -19
  389. package/dist/web/agent-events/portal.js.map +0 -1
  390. package/dist/web/request.d.ts +0 -3
  391. package/dist/web/request.d.ts.map +0 -1
  392. package/dist/web/request.js +0 -13
  393. package/dist/web/request.js.map +0 -1
  394. package/dist/web/session-view/command.d.ts +0 -4
  395. package/dist/web/session-view/command.d.ts.map +0 -1
  396. package/dist/web/session-view/command.js +0 -10
  397. package/dist/web/session-view/command.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/office/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { lstatSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport type {\n OfficeAddress,\n OfficeMigrationPreparation,\n OfficeMigrationRecord,\n OfficeMigrationStatus,\n OfficeRecord,\n OfficeRegistryState,\n PlatformName,\n} from \"../types.js\";\nimport {\n officeDir,\n officeKey,\n assertConversationId,\n assertPlatformName,\n validateOfficeAddress,\n} from \"./address.js\";\nimport { parseGithubConversationId } from \"../adapters/github/ids.js\";\nimport { isRecord, readTextFileIfExists } from \"../utils/file-guards.js\";\nimport { atomicWritePrivateFile } from \"../utils/fs-atomic.js\";\n\nconst REGISTRY_VERSION = 1;\nconst REGISTRY_FILENAME = \"office-registry.json\";\nconst MIGRATION_STATUSES = new Set<OfficeMigrationStatus>([\n \"needs-owner\",\n \"prepared\",\n \"moving\",\n \"committed\",\n \"failed\",\n]);\nconst REGISTRY_LOCK_FILENAME = \".office-registry.lock\";\nconst REGISTRY_LOCK_RETRY_MS = 25;\nconst REGISTRY_LOCK_TIMEOUT_MS = 5_000;\nconst REGISTRY_LOCK_STALE_MS = 60_000;\n\n/**\n * Host-only office directory and migration journal.\n *\n * Office records are the durable raw-id ↔ (platform, office) mapping: the\n * ADR 0005 layout migration renamed workspace dirs to office keys, so dir\n * names carry no raw platform ids and enumeration/legacy-scope lookups\n * resolve through these records. Migration records track claiming legacy\n * raw-id directories. Office materialization lives in `layout.ts`; this\n * module owns only the durable record and its crash-safe transitions.\n */\ninterface OfficeRegistryOptions {\n writeState?: (path: string, content: string) => void;\n lockTimeoutMs?: number;\n}\n\nexport class OfficeRegistry {\n private readonly stateDir: string;\n private readonly registryPath: string;\n private readonly lockPath: string;\n private readonly writeState: (path: string, content: string) => void;\n private readonly lockTimeoutMs: number;\n private state: OfficeRegistryState;\n\n constructor(stateDir: string, options: OfficeRegistryOptions = {}) {\n this.stateDir = resolve(stateDir);\n mkdirSync(this.stateDir, { recursive: true, mode: 0o700 });\n assertRegularDirectory(this.stateDir, \"State directory\");\n this.registryPath = resolve(this.stateDir, REGISTRY_FILENAME);\n this.lockPath = join(this.stateDir, REGISTRY_LOCK_FILENAME);\n this.writeState = options.writeState ?? atomicWritePrivateFile;\n this.lockTimeoutMs = options.lockTimeoutMs ?? REGISTRY_LOCK_TIMEOUT_MS;\n this.state = this.readState();\n }\n\n /** Reload the atomic registry file after another host process changed it. */\n reload(): OfficeRegistryState {\n this.state = this.readState();\n return this.state;\n }\n\n getState(): OfficeRegistryState {\n return this.state;\n }\n\n getMigration(rawConversationId: string): OfficeMigrationRecord | undefined {\n assertConversationId(rawConversationId);\n return this.state.migrations.find((record) => record.rawConversationId === rawConversationId);\n }\n\n enablePlatform(platform: PlatformName): OfficeRegistryState {\n const validPlatform = assertPlatformName(platform);\n return this.withExclusiveLease(() => {\n if (this.state.enabledPlatforms.includes(validPlatform)) return this.state;\n\n const enabledPlatforms = [...this.state.enabledPlatforms, validPlatform].toSorted();\n this.replaceState(enabledPlatforms, this.state.offices, this.state.migrations);\n return this.state;\n });\n }\n\n /**\n * Record that an office exists. Idempotent: re-recording a known office is\n * a lock-free cache hit for callers that materialize directories per\n * message, so this sits safely on hot write paths.\n */\n recordOffice(address: OfficeAddress): OfficeRecord {\n const normalized = validateOfficeAddress(address);\n const existing = this.findOffice(normalized);\n if (existing) return existing;\n return this.withExclusiveLease(() => {\n const found = this.findOffice(normalized);\n if (found) return found;\n const record: OfficeRecord = Object.freeze({\n platform: normalized.platform,\n conversationId: normalized.conversationId,\n recordedAt: new Date().toISOString(),\n });\n this.replaceState(\n this.state.enabledPlatforms,\n [...this.state.offices, record],\n this.state.migrations,\n );\n return record;\n });\n }\n\n getOffices(): readonly OfficeRecord[] {\n return this.state.offices;\n }\n\n private findOffice(address: OfficeAddress): OfficeRecord | undefined {\n return this.state.offices.find(\n (record) =>\n record.platform === address.platform && record.conversationId === address.conversationId,\n );\n }\n\n /**\n * Validate and record a legacy directory. With exactly one enabled platform,\n * ownership is safe to infer. With zero or multiple platforms, the record\n * remains explicit `needs-owner` unless the caller supplies an owner.\n */\n prepareLegacyMigration(options: OfficeMigrationPreparation): OfficeMigrationRecord {\n const rawConversationId = assertConversationId(options.rawConversationId);\n const sourceDir = resolve(options.sourceDir);\n const workspaceRoot = resolve(options.workspaceRoot);\n return this.withExclusiveLease(() => {\n const existing = this.getMigration(rawConversationId);\n assertCanonicalSource(sourceDir, workspaceRoot, rawConversationId);\n if (existing) {\n assertSameMigrationInputs(existing, sourceDir, workspaceRoot);\n if (existing.status !== \"needs-owner\") return existing;\n }\n\n assertRegularDirectory(sourceDir, \"Legacy office source\");\n const ownerPlatform = this.resolveOwner(options.ownerPlatform, rawConversationId);\n if (!ownerPlatform) {\n const record = makeRecord({\n rawConversationId,\n sourceDir,\n workspaceRoot,\n status: \"needs-owner\",\n });\n this.replaceMigration(existing, record);\n return record;\n }\n\n const targetDir = officeDir(workspaceRoot, {\n platform: ownerPlatform,\n conversationId: rawConversationId,\n });\n if (pathExists(targetDir)) {\n const failed = makeRecord({\n rawConversationId,\n sourceDir,\n workspaceRoot,\n ownerPlatform,\n targetDir,\n status: \"failed\",\n error: \"Target office directory already exists\",\n });\n this.replaceMigration(existing, failed);\n throw new Error(`${failed.error}: ${targetDir}`);\n }\n\n const prepared = makeRecord({\n rawConversationId,\n sourceDir,\n workspaceRoot,\n ownerPlatform,\n targetDir,\n status: \"prepared\",\n });\n this.replaceMigration(existing, prepared);\n return prepared;\n });\n }\n\n markMoving(rawConversationId: string): OfficeMigrationRecord {\n return this.withExclusiveLease(() => {\n const record = this.requireMigration(rawConversationId);\n if (\n record.status === \"moving\" ||\n record.status === \"committed\" ||\n record.status === \"failed\"\n ) {\n return record;\n }\n if (record.status === \"needs-owner\") {\n throw new Error(`Legacy office ${JSON.stringify(rawConversationId)} still needs an owner`);\n }\n assertRegularDirectory(record.sourceDir, \"Legacy office source\");\n const targetDir = migrationTarget(record);\n if (!targetDir) throw new Error(\"Prepared office migration has no target directory\");\n if (pathExists(targetDir)) {\n const failed = this.failRecord(record, \"Target office directory appeared before moving\");\n throw new Error(`${failed.error}: ${targetDir}`);\n }\n\n const moving = transitionRecord(record, \"moving\");\n this.replaceMigration(record, moving);\n return moving;\n });\n }\n\n markCommitted(rawConversationId: string): OfficeMigrationRecord {\n return this.withExclusiveLease(() => {\n const record = this.requireMigration(rawConversationId);\n if (record.status === \"committed\" || record.status === \"failed\") return record;\n if (record.status !== \"moving\") {\n throw new Error(`Cannot commit office migration from ${record.status}`);\n }\n const targetDir = migrationTarget(record);\n if (!targetDir) throw new Error(\"Moving office migration has no target directory\");\n assertRegularDirectory(targetDir, \"Migrated office target\");\n assertPathAbsent(record.sourceDir, \"Legacy office source\");\n\n const committed = transitionRecord(record, \"committed\");\n this.replaceMigration(record, committed);\n return committed;\n });\n }\n\n markFailed(rawConversationId: string, error: string): OfficeMigrationRecord {\n return this.withExclusiveLease(() => {\n const record = this.requireMigration(rawConversationId);\n if (record.status === \"committed\") {\n throw new Error(\"A committed office migration cannot be marked failed\");\n }\n if (record.status === \"failed\") return record;\n return this.failRecord(record, error);\n });\n }\n\n private resolveOwner(\n ownerPlatform: PlatformName | undefined,\n rawConversationId: string,\n ): PlatformName | undefined {\n if (ownerPlatform !== undefined) {\n const validPlatform = assertPlatformName(ownerPlatform);\n if (!this.state.enabledPlatforms.includes(validPlatform)) {\n throw new Error(`Owner platform ${validPlatform} is not enabled`);\n }\n return validPlatform;\n }\n const candidates = platformsMatchingConversationIdFormat(\n rawConversationId,\n this.state.enabledPlatforms,\n );\n return candidates.length === 1 ? candidates[0] : undefined;\n }\n\n private requireMigration(rawConversationId: string): OfficeMigrationRecord {\n assertConversationId(rawConversationId);\n const record = this.getMigration(rawConversationId);\n if (!record) throw new Error(`No office migration registered for ${rawConversationId}`);\n return record;\n }\n\n private failRecord(record: OfficeMigrationRecord, error: string): OfficeMigrationRecord {\n const message = error.trim();\n if (!message) throw new Error(\"Office migration failure reason must not be empty\");\n const failed = transitionRecord(record, \"failed\", message);\n this.replaceMigration(record, failed);\n return failed;\n }\n\n private replaceMigration(\n previous: OfficeMigrationRecord | undefined,\n next: OfficeMigrationRecord,\n ): void {\n const migrations = [...this.state.migrations];\n const index = previous\n ? migrations.findIndex((record) => record.rawConversationId === previous.rawConversationId)\n : -1;\n if (index === -1) migrations.push(next);\n else migrations[index] = next;\n this.replaceState(this.state.enabledPlatforms, this.state.offices, migrations);\n }\n\n private replaceState(\n enabledPlatforms: readonly PlatformName[],\n offices: readonly OfficeRecord[],\n migrations: readonly OfficeMigrationRecord[],\n ): void {\n const candidate = freezeState({ enabledPlatforms, offices, migrations });\n this.writeState(this.registryPath, `${JSON.stringify(candidate, null, 2)}\\n`);\n this.state = candidate;\n }\n\n /**\n * Acquire the domain lease, reload while holding it, then perform one\n * read-modify-write. A future move transaction can retain the same lease\n * across its filesystem operation instead of splitting the transition.\n */\n private withExclusiveLease<T>(operation: () => T): T {\n const release = acquireRegistryLease(this.lockPath, this.lockTimeoutMs);\n try {\n this.state = this.readState();\n return operation();\n } finally {\n release();\n }\n }\n\n private readState(): OfficeRegistryState {\n assertRegistryFileSafe(this.registryPath);\n const raw = readTextFileIfExists(this.registryPath);\n if (raw === undefined) {\n return freezeState({ enabledPlatforms: [], offices: [], migrations: [] });\n }\n\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (error) {\n throw new Error(`Invalid office registry JSON at ${this.registryPath}`, { cause: error });\n }\n return parseState(value, this.registryPath);\n }\n}\n\ninterface RecordFields {\n rawConversationId: string;\n sourceDir: string;\n workspaceRoot: string;\n ownerPlatform?: PlatformName;\n targetDir?: string;\n status: OfficeMigrationStatus;\n error?: string;\n updatedAt?: string;\n}\n\nfunction makeRecord(fields: RecordFields): OfficeMigrationRecord {\n const record: OfficeMigrationRecord = {\n rawConversationId: fields.rawConversationId,\n sourceDir: fields.sourceDir,\n workspaceRoot: fields.workspaceRoot,\n ...(fields.ownerPlatform ? { ownerPlatform: fields.ownerPlatform } : {}),\n ...(fields.targetDir ? { targetDir: fields.targetDir } : {}),\n status: fields.status,\n ...(fields.error ? { error: fields.error } : {}),\n updatedAt: fields.updatedAt ?? new Date().toISOString(),\n };\n return Object.freeze(record);\n}\n\nfunction transitionRecord(\n record: OfficeMigrationRecord,\n status: OfficeMigrationStatus,\n error?: string,\n): OfficeMigrationRecord {\n const targetDir = migrationTarget(record);\n return makeRecord({\n rawConversationId: record.rawConversationId,\n sourceDir: record.sourceDir,\n workspaceRoot: record.workspaceRoot,\n ...(record.ownerPlatform ? { ownerPlatform: record.ownerPlatform } : {}),\n ...(targetDir ? { targetDir } : {}),\n status,\n ...(error ? { error } : {}),\n });\n}\n\nfunction migrationTarget(record: OfficeMigrationRecord): string | undefined {\n return record.ownerPlatform\n ? officeDir(record.workspaceRoot, {\n platform: record.ownerPlatform,\n conversationId: record.rawConversationId,\n })\n : undefined;\n}\n\nfunction freezeState(input: {\n enabledPlatforms: readonly PlatformName[];\n offices: readonly OfficeRecord[];\n migrations: readonly OfficeMigrationRecord[];\n}): OfficeRegistryState {\n return Object.freeze({\n version: REGISTRY_VERSION as 1,\n enabledPlatforms: Object.freeze([...input.enabledPlatforms]),\n offices: Object.freeze(input.offices.map((record) => Object.freeze({ ...record }))),\n migrations: Object.freeze(input.migrations.map((record) => Object.freeze({ ...record }))),\n });\n}\n\nfunction parseState(value: unknown, path: string): OfficeRegistryState {\n if (!isRecord(value) || value.version !== REGISTRY_VERSION) {\n throw new Error(`Invalid office registry version at ${path}`);\n }\n if (!Array.isArray(value.enabledPlatforms) || !Array.isArray(value.migrations)) {\n throw new Error(`Invalid office registry shape at ${path}`);\n }\n\n const enabledPlatforms = value.enabledPlatforms.map((platform) => {\n if (typeof platform !== \"string\") throw new Error(`Invalid enabled platform in ${path}`);\n return assertPlatformName(platform);\n });\n if (new Set(enabledPlatforms).size !== enabledPlatforms.length) {\n throw new Error(`Duplicate enabled platform in ${path}`);\n }\n\n // Files written before office records existed simply have no offices yet.\n const offices = (Array.isArray(value.offices) ? value.offices : []).map((entry) =>\n parseOfficeRecord(entry, path),\n );\n if (new Set(offices.map((record) => officeKey(record))).size !== offices.length) {\n throw new Error(`Duplicate office record in ${path}`);\n }\n\n const migrations = value.migrations.map((entry) => parseRecord(entry, path, enabledPlatforms));\n if (new Set(migrations.map((record) => record.rawConversationId)).size !== migrations.length) {\n throw new Error(`Duplicate office migration in ${path}`);\n }\n return freezeState({ enabledPlatforms, offices, migrations });\n}\n\nfunction parseOfficeRecord(value: unknown, path: string): OfficeRecord {\n if (!isRecord(value)) throw new Error(`Invalid office record in ${path}`);\n if (\n typeof value.platform !== \"string\" ||\n typeof value.conversationId !== \"string\" ||\n typeof value.recordedAt !== \"string\"\n ) {\n throw new Error(`Invalid office record fields in ${path}`);\n }\n return Object.freeze({\n platform: assertPlatformName(value.platform),\n conversationId: assertConversationId(value.conversationId),\n recordedAt: value.recordedAt,\n });\n}\n\nfunction parseRecord(\n value: unknown,\n path: string,\n enabledPlatforms: readonly PlatformName[],\n): OfficeMigrationRecord {\n if (!isRecord(value)) throw new Error(`Invalid office migration record in ${path}`);\n if (\n typeof value.rawConversationId !== \"string\" ||\n typeof value.sourceDir !== \"string\" ||\n typeof value.workspaceRoot !== \"string\" ||\n typeof value.status !== \"string\" ||\n typeof value.updatedAt !== \"string\"\n ) {\n throw new Error(`Invalid office migration fields in ${path}`);\n }\n assertConversationId(value.rawConversationId);\n if (!isAbsolute(value.sourceDir) || !isAbsolute(value.workspaceRoot)) {\n throw new Error(`Office migration paths must be absolute in ${path}`);\n }\n assertCanonicalSource(value.sourceDir, value.workspaceRoot, value.rawConversationId);\n if (!MIGRATION_STATUSES.has(value.status as OfficeMigrationStatus)) {\n throw new Error(`Invalid office migration status in ${path}`);\n }\n\n const ownerPlatform = optionalPlatform(value.ownerPlatform);\n const targetDir = optionalString(value.targetDir);\n const error = optionalString(value.error);\n if (ownerPlatform !== undefined && !enabledPlatforms.includes(ownerPlatform)) {\n throw new Error(`Office migration owner is not enabled in ${path}`);\n }\n if (value.status === \"needs-owner\" && (ownerPlatform !== undefined || targetDir !== undefined)) {\n throw new Error(`Needs-owner migration cannot have an owner or target in ${path}`);\n }\n if (\n value.status !== \"needs-owner\" &&\n value.status !== \"failed\" &&\n (ownerPlatform === undefined || targetDir === undefined)\n ) {\n throw new Error(`Prepared office migration is missing ownership in ${path}`);\n }\n if (ownerPlatform === undefined && targetDir !== undefined) {\n throw new Error(`Office migration target has no owner in ${path}`);\n }\n const expectedTargetDir = ownerPlatform\n ? officeDir(value.workspaceRoot, {\n platform: ownerPlatform,\n conversationId: value.rawConversationId,\n })\n : undefined;\n if (targetDir !== expectedTargetDir) {\n throw new Error(`Office migration target does not match its office address in ${path}`);\n }\n if (value.status === \"failed\" && !error) {\n throw new Error(`Failed office migration is missing an error in ${path}`);\n }\n\n return makeRecord({\n rawConversationId: value.rawConversationId,\n sourceDir: value.sourceDir,\n workspaceRoot: value.workspaceRoot,\n ...(ownerPlatform ? { ownerPlatform } : {}),\n ...(expectedTargetDir ? { targetDir: expectedTargetDir } : {}),\n status: value.status as OfficeMigrationStatus,\n ...(error ? { error } : {}),\n updatedAt: value.updatedAt,\n });\n}\n\nfunction optionalPlatform(value: unknown): PlatformName | undefined {\n return value === undefined\n ? undefined\n : typeof value === \"string\"\n ? assertPlatformName(value)\n : failOptional(\"platform\");\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return value === undefined\n ? undefined\n : typeof value === \"string\"\n ? value\n : failOptional(\"string\");\n}\n\nfunction failOptional(label: string): never {\n throw new Error(`Invalid optional ${label} in office registry`);\n}\n\nfunction assertSameMigrationInputs(\n existing: OfficeMigrationRecord,\n sourceDir: string,\n workspaceRoot: string,\n): void {\n if (existing.sourceDir !== sourceDir || existing.workspaceRoot !== workspaceRoot) {\n throw new Error(`Legacy office migration inputs changed for ${existing.rawConversationId}`);\n }\n}\n\nfunction assertCanonicalSource(\n sourceDir: string,\n workspaceRoot: string,\n rawConversationId: string,\n): void {\n const expectedSourceDir = resolve(workspaceRoot, rawConversationId);\n if (sourceDir !== expectedSourceDir) {\n throw new Error(`Legacy office source must be ${expectedSourceDir}`);\n }\n assertRegularDirectory(workspaceRoot, \"Workspace root\");\n assertPathIfPresent(sourceDir, \"Legacy office source\");\n}\n\nfunction assertRegularDirectory(path: string, label: string): void {\n let stat;\n try {\n stat = lstatSync(path);\n } catch (error) {\n throw new Error(`${label} does not exist: ${path}`, { cause: error });\n }\n if (stat.isSymbolicLink() || !stat.isDirectory()) {\n throw new Error(`${label} must be a regular directory: ${path}`);\n }\n}\n\nfunction assertRegistryFileSafe(path: string): void {\n try {\n const stat = lstatSync(path);\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new Error(`Office registry must be a regular file: ${path}`);\n }\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return;\n throw error;\n }\n}\n\nfunction assertPathIfPresent(path: string, label: string): void {\n try {\n const stat = lstatSync(path);\n if (stat.isSymbolicLink() || !stat.isDirectory()) {\n throw new Error(`${label} must be a regular directory: ${path}`);\n }\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return;\n throw error;\n }\n}\n\nfunction assertPathAbsent(path: string, label: string): void {\n try {\n lstatSync(path);\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return;\n throw error;\n }\n throw new Error(`${label} must be absent: ${path}`);\n}\n\nfunction pathExists(path: string): boolean {\n try {\n lstatSync(path);\n return true;\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return false;\n throw error;\n }\n}\n\nfunction acquireRegistryLease(lockPath: string, timeoutMs: number): () => void {\n const deadline = Date.now() + timeoutMs;\n const token = `${process.pid}:${randomBytes(8).toString(\"hex\")}`;\n\n for (;;) {\n try {\n mkdirSync(lockPath, { mode: 0o700 });\n try {\n writeFileSync(join(lockPath, \"owner\"), `${token}\\n`, { mode: 0o600 });\n } catch (error) {\n rmSync(lockPath, { recursive: true, force: true });\n throw error;\n }\n return () => releaseRegistryLease(lockPath, token);\n } catch (error) {\n if (!isErrno(error, \"EEXIST\")) throw error;\n if (registryLockIsStale(lockPath)) {\n rmSync(lockPath, { recursive: true, force: true });\n continue;\n }\n if (Date.now() >= deadline) {\n throw new Error(`Timed out acquiring office registry lock: ${lockPath}`, { cause: error });\n }\n sleepSync(REGISTRY_LOCK_RETRY_MS);\n }\n }\n}\n\nfunction releaseRegistryLease(lockPath: string, token: string): void {\n try {\n if (readFileSync(join(lockPath, \"owner\"), \"utf8\").trim() === token) {\n rmSync(lockPath, { recursive: true, force: true });\n }\n } catch (error) {\n if (!isErrno(error, \"ENOENT\")) throw error;\n }\n}\n\nfunction registryLockIsStale(lockPath: string): boolean {\n let ownerKnown = false;\n let ownerAlive = false;\n try {\n const owner = readFileSync(join(lockPath, \"owner\"), \"utf8\").trim();\n const pid = Number(owner.split(\":\", 1)[0]);\n if (Number.isInteger(pid) && pid > 0) {\n ownerKnown = true;\n try {\n process.kill(pid, 0);\n ownerAlive = true;\n } catch (error) {\n if (isErrno(error, \"EPERM\")) ownerAlive = true;\n }\n }\n } catch {\n // The owner file may not have been written before its process died.\n }\n try {\n const oldEnough = Date.now() - statSync(lockPath).mtimeMs >= REGISTRY_LOCK_STALE_MS;\n return ownerKnown ? !ownerAlive : oldEnough;\n } catch {\n return false;\n }\n}\n\nfunction sleepSync(milliseconds: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);\n}\n\n// ── raw-id lookups (cold paths: CLI, Admin enumeration) ──────────────────────\n\n/**\n * Resolve the office behind a raw conversation id for surfaces that name\n * offices by raw id (CLI operators). The registry is the only authority:\n * office records first, then a committed migration's owner, then the sole\n * enabled platform. Two platforms sharing the raw id make the scope\n * genuinely ambiguous, and an unknown id has no office to resolve — both\n * fail loudly rather than guessing a directory.\n *\n * Constructs a registry per call, which re-reads the journal from disk; this\n * is a one-shot CLI/Admin surface, never a per-message path (those go\n * through the Workspace value's cached registry in `layout.ts`).\n */\nexport function resolveOwnedOfficeAddress(\n rawConversationId: string,\n stateDir: string,\n): OfficeAddress {\n assertConversationId(rawConversationId);\n const registry = new OfficeRegistry(stateDir);\n\n const matches = registry\n .getState()\n .offices.filter((record) => record.conversationId === rawConversationId);\n if (matches.length === 1) {\n return { platform: matches[0].platform, conversationId: rawConversationId };\n }\n if (matches.length > 1) {\n throw new Error(\n `Conversation id ${JSON.stringify(rawConversationId)} names offices on several platforms; ` +\n \"use a platform-scoped surface instead\",\n );\n }\n\n const migration = registry.getMigration(rawConversationId);\n if (migration?.ownerPlatform) {\n return { platform: migration.ownerPlatform, conversationId: rawConversationId };\n }\n const { enabledPlatforms } = registry.getState();\n if (enabledPlatforms.length === 1) {\n return { platform: enabledPlatforms[0], conversationId: rawConversationId };\n }\n throw new Error(\n `No office is registered for conversation id ${JSON.stringify(rawConversationId)}`,\n );\n}\n\n/** Current office inventory, read fresh from disk for cross-process freshness. */\nexport function listRegisteredOffices(stateDir: string): readonly OfficeRecord[] {\n return new OfficeRegistry(stateDir).getOffices();\n}\n\n/**\n * Enabled platforms whose id format could have produced this raw\n * conversation id. Auto-claiming uses this as verification, not guessing:\n * every format below is one mikan itself writes (GitHub ids are mikan-derived\n * slugs; Slack/Telegram/Discord ids are the platforms' own grammars), and a\n * directory is only claimed when exactly one enabled platform's format\n * matches. Bare digits stay ambiguous while both Telegram and Discord are\n * enabled (negative ids are Telegram-only); anything matching no enabled\n * format fails closed to needs-owner.\n */\nfunction platformsMatchingConversationIdFormat(\n rawConversationId: string,\n enabledPlatforms: readonly PlatformName[],\n): PlatformName[] {\n return enabledPlatforms.filter((platform) => {\n switch (platform) {\n case \"github\":\n return isGithubConversationId(rawConversationId);\n case \"telegram\":\n return /^-?\\d+$/.test(rawConversationId);\n case \"discord\":\n return /^\\d+$/.test(rawConversationId);\n case \"slack\":\n return /^[A-Z][A-Z0-9]*$/.test(rawConversationId);\n }\n });\n}\n\nfunction isGithubConversationId(rawConversationId: string): boolean {\n try {\n parseGithubConversationId(rawConversationId);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isErrno(error: unknown, code: string): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/office/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { lstatSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport type {\n OfficeAddress,\n OfficeMigrationPreparation,\n OfficeMigrationRecord,\n OfficeMigrationStatus,\n OfficeRecord,\n OfficeRegistryState,\n PlatformName,\n} from \"../types.js\";\nimport {\n officeDir,\n officeKey,\n assertConversationId,\n assertPlatformName,\n validateOfficeAddress,\n} from \"./address.js\";\nimport { parseGithubConversationId } from \"../adapters/github/ids.js\";\nimport { isRecord, readTextFileIfExists } from \"../utils/file-guards.js\";\nimport { atomicWritePrivateFile } from \"../utils/file-guards.js\";\n\nconst REGISTRY_VERSION = 1;\nconst REGISTRY_FILENAME = \"office-registry.json\";\nconst MIGRATION_STATUSES = new Set<OfficeMigrationStatus>([\n \"needs-owner\",\n \"prepared\",\n \"moving\",\n \"committed\",\n \"failed\",\n]);\nconst REGISTRY_LOCK_FILENAME = \".office-registry.lock\";\nconst REGISTRY_LOCK_RETRY_MS = 25;\nconst REGISTRY_LOCK_TIMEOUT_MS = 5_000;\nconst REGISTRY_LOCK_STALE_MS = 60_000;\n\n/**\n * Host-only office directory and migration journal.\n *\n * Office records are the durable raw-id ↔ (platform, office) mapping: the\n * ADR 0005 layout migration renamed workspace dirs to office keys, so dir\n * names carry no raw platform ids and enumeration/legacy-scope lookups\n * resolve through these records. Migration records track claiming legacy\n * raw-id directories. Office materialization lives in `layout.ts`; this\n * module owns only the durable record and its crash-safe transitions.\n */\ninterface OfficeRegistryOptions {\n writeState?: (path: string, content: string) => void;\n lockTimeoutMs?: number;\n}\n\nexport class OfficeRegistry {\n private readonly stateDir: string;\n private readonly registryPath: string;\n private readonly lockPath: string;\n private readonly writeState: (path: string, content: string) => void;\n private readonly lockTimeoutMs: number;\n private state: OfficeRegistryState;\n\n constructor(stateDir: string, options: OfficeRegistryOptions = {}) {\n this.stateDir = resolve(stateDir);\n mkdirSync(this.stateDir, { recursive: true, mode: 0o700 });\n assertRegularDirectory(this.stateDir, \"State directory\");\n this.registryPath = resolve(this.stateDir, REGISTRY_FILENAME);\n this.lockPath = join(this.stateDir, REGISTRY_LOCK_FILENAME);\n this.writeState = options.writeState ?? atomicWritePrivateFile;\n this.lockTimeoutMs = options.lockTimeoutMs ?? REGISTRY_LOCK_TIMEOUT_MS;\n this.state = this.readState();\n }\n\n /** Reload the atomic registry file after another host process changed it. */\n reload(): OfficeRegistryState {\n this.state = this.readState();\n return this.state;\n }\n\n getState(): OfficeRegistryState {\n return this.state;\n }\n\n getMigration(rawConversationId: string): OfficeMigrationRecord | undefined {\n assertConversationId(rawConversationId);\n return this.state.migrations.find((record) => record.rawConversationId === rawConversationId);\n }\n\n enablePlatform(platform: PlatformName): OfficeRegistryState {\n const validPlatform = assertPlatformName(platform);\n return this.withExclusiveLease(() => {\n if (this.state.enabledPlatforms.includes(validPlatform)) return this.state;\n\n const enabledPlatforms = [...this.state.enabledPlatforms, validPlatform].toSorted();\n this.replaceState(enabledPlatforms, this.state.offices, this.state.migrations);\n return this.state;\n });\n }\n\n /**\n * Record that an office exists. Idempotent: re-recording a known office is\n * a lock-free cache hit for callers that materialize directories per\n * message, so this sits safely on hot write paths.\n */\n recordOffice(address: OfficeAddress): OfficeRecord {\n const normalized = validateOfficeAddress(address);\n const existing = this.findOffice(normalized);\n if (existing) return existing;\n return this.withExclusiveLease(() => {\n const found = this.findOffice(normalized);\n if (found) return found;\n const record: OfficeRecord = Object.freeze({\n platform: normalized.platform,\n conversationId: normalized.conversationId,\n recordedAt: new Date().toISOString(),\n });\n this.replaceState(\n this.state.enabledPlatforms,\n [...this.state.offices, record],\n this.state.migrations,\n );\n return record;\n });\n }\n\n getOffices(): readonly OfficeRecord[] {\n return this.state.offices;\n }\n\n private findOffice(address: OfficeAddress): OfficeRecord | undefined {\n return this.state.offices.find(\n (record) =>\n record.platform === address.platform && record.conversationId === address.conversationId,\n );\n }\n\n /**\n * Validate and record a legacy directory. With exactly one enabled platform,\n * ownership is safe to infer. With zero or multiple platforms, the record\n * remains explicit `needs-owner` unless the caller supplies an owner.\n */\n prepareLegacyMigration(options: OfficeMigrationPreparation): OfficeMigrationRecord {\n const rawConversationId = assertConversationId(options.rawConversationId);\n const sourceDir = resolve(options.sourceDir);\n const workspaceRoot = resolve(options.workspaceRoot);\n return this.withExclusiveLease(() => {\n const existing = this.getMigration(rawConversationId);\n assertCanonicalSource(sourceDir, workspaceRoot, rawConversationId);\n if (existing) {\n assertSameMigrationInputs(existing, sourceDir, workspaceRoot);\n if (existing.status !== \"needs-owner\") return existing;\n }\n\n assertRegularDirectory(sourceDir, \"Legacy office source\");\n const ownerPlatform = this.resolveOwner(options.ownerPlatform, rawConversationId);\n if (!ownerPlatform) {\n const record = makeRecord({\n rawConversationId,\n sourceDir,\n workspaceRoot,\n status: \"needs-owner\",\n });\n this.replaceMigration(existing, record);\n return record;\n }\n\n const targetDir = officeDir(workspaceRoot, {\n platform: ownerPlatform,\n conversationId: rawConversationId,\n });\n if (pathExists(targetDir)) {\n const failed = makeRecord({\n rawConversationId,\n sourceDir,\n workspaceRoot,\n ownerPlatform,\n targetDir,\n status: \"failed\",\n error: \"Target office directory already exists\",\n });\n this.replaceMigration(existing, failed);\n throw new Error(`${failed.error}: ${targetDir}`);\n }\n\n const prepared = makeRecord({\n rawConversationId,\n sourceDir,\n workspaceRoot,\n ownerPlatform,\n targetDir,\n status: \"prepared\",\n });\n this.replaceMigration(existing, prepared);\n return prepared;\n });\n }\n\n markMoving(rawConversationId: string): OfficeMigrationRecord {\n return this.withExclusiveLease(() => {\n const record = this.requireMigration(rawConversationId);\n if (\n record.status === \"moving\" ||\n record.status === \"committed\" ||\n record.status === \"failed\"\n ) {\n return record;\n }\n if (record.status === \"needs-owner\") {\n throw new Error(`Legacy office ${JSON.stringify(rawConversationId)} still needs an owner`);\n }\n assertRegularDirectory(record.sourceDir, \"Legacy office source\");\n const targetDir = migrationTarget(record);\n if (!targetDir) throw new Error(\"Prepared office migration has no target directory\");\n if (pathExists(targetDir)) {\n const failed = this.failRecord(record, \"Target office directory appeared before moving\");\n throw new Error(`${failed.error}: ${targetDir}`);\n }\n\n const moving = transitionRecord(record, \"moving\");\n this.replaceMigration(record, moving);\n return moving;\n });\n }\n\n markCommitted(rawConversationId: string): OfficeMigrationRecord {\n return this.withExclusiveLease(() => {\n const record = this.requireMigration(rawConversationId);\n if (record.status === \"committed\" || record.status === \"failed\") return record;\n if (record.status !== \"moving\") {\n throw new Error(`Cannot commit office migration from ${record.status}`);\n }\n const targetDir = migrationTarget(record);\n if (!targetDir) throw new Error(\"Moving office migration has no target directory\");\n assertRegularDirectory(targetDir, \"Migrated office target\");\n assertPathAbsent(record.sourceDir, \"Legacy office source\");\n\n const committed = transitionRecord(record, \"committed\");\n this.replaceMigration(record, committed);\n return committed;\n });\n }\n\n markFailed(rawConversationId: string, error: string): OfficeMigrationRecord {\n return this.withExclusiveLease(() => {\n const record = this.requireMigration(rawConversationId);\n if (record.status === \"committed\") {\n throw new Error(\"A committed office migration cannot be marked failed\");\n }\n if (record.status === \"failed\") return record;\n return this.failRecord(record, error);\n });\n }\n\n private resolveOwner(\n ownerPlatform: PlatformName | undefined,\n rawConversationId: string,\n ): PlatformName | undefined {\n if (ownerPlatform !== undefined) {\n const validPlatform = assertPlatformName(ownerPlatform);\n if (!this.state.enabledPlatforms.includes(validPlatform)) {\n throw new Error(`Owner platform ${validPlatform} is not enabled`);\n }\n return validPlatform;\n }\n const candidates = platformsMatchingConversationIdFormat(\n rawConversationId,\n this.state.enabledPlatforms,\n );\n return candidates.length === 1 ? candidates[0] : undefined;\n }\n\n private requireMigration(rawConversationId: string): OfficeMigrationRecord {\n assertConversationId(rawConversationId);\n const record = this.getMigration(rawConversationId);\n if (!record) throw new Error(`No office migration registered for ${rawConversationId}`);\n return record;\n }\n\n private failRecord(record: OfficeMigrationRecord, error: string): OfficeMigrationRecord {\n const message = error.trim();\n if (!message) throw new Error(\"Office migration failure reason must not be empty\");\n const failed = transitionRecord(record, \"failed\", message);\n this.replaceMigration(record, failed);\n return failed;\n }\n\n private replaceMigration(\n previous: OfficeMigrationRecord | undefined,\n next: OfficeMigrationRecord,\n ): void {\n const migrations = [...this.state.migrations];\n const index = previous\n ? migrations.findIndex((record) => record.rawConversationId === previous.rawConversationId)\n : -1;\n if (index === -1) migrations.push(next);\n else migrations[index] = next;\n this.replaceState(this.state.enabledPlatforms, this.state.offices, migrations);\n }\n\n private replaceState(\n enabledPlatforms: readonly PlatformName[],\n offices: readonly OfficeRecord[],\n migrations: readonly OfficeMigrationRecord[],\n ): void {\n const candidate = freezeState({ enabledPlatforms, offices, migrations });\n this.writeState(this.registryPath, `${JSON.stringify(candidate, null, 2)}\\n`);\n this.state = candidate;\n }\n\n /**\n * Acquire the domain lease, reload while holding it, then perform one\n * read-modify-write. A future move transaction can retain the same lease\n * across its filesystem operation instead of splitting the transition.\n */\n private withExclusiveLease<T>(operation: () => T): T {\n const release = acquireRegistryLease(this.lockPath, this.lockTimeoutMs);\n try {\n this.state = this.readState();\n return operation();\n } finally {\n release();\n }\n }\n\n private readState(): OfficeRegistryState {\n assertRegistryFileSafe(this.registryPath);\n const raw = readTextFileIfExists(this.registryPath);\n if (raw === undefined) {\n return freezeState({ enabledPlatforms: [], offices: [], migrations: [] });\n }\n\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (error) {\n throw new Error(`Invalid office registry JSON at ${this.registryPath}`, { cause: error });\n }\n return parseState(value, this.registryPath);\n }\n}\n\ninterface RecordFields {\n rawConversationId: string;\n sourceDir: string;\n workspaceRoot: string;\n ownerPlatform?: PlatformName;\n targetDir?: string;\n status: OfficeMigrationStatus;\n error?: string;\n updatedAt?: string;\n}\n\nfunction makeRecord(fields: RecordFields): OfficeMigrationRecord {\n const record: OfficeMigrationRecord = {\n rawConversationId: fields.rawConversationId,\n sourceDir: fields.sourceDir,\n workspaceRoot: fields.workspaceRoot,\n ...(fields.ownerPlatform ? { ownerPlatform: fields.ownerPlatform } : {}),\n ...(fields.targetDir ? { targetDir: fields.targetDir } : {}),\n status: fields.status,\n ...(fields.error ? { error: fields.error } : {}),\n updatedAt: fields.updatedAt ?? new Date().toISOString(),\n };\n return Object.freeze(record);\n}\n\nfunction transitionRecord(\n record: OfficeMigrationRecord,\n status: OfficeMigrationStatus,\n error?: string,\n): OfficeMigrationRecord {\n const targetDir = migrationTarget(record);\n return makeRecord({\n rawConversationId: record.rawConversationId,\n sourceDir: record.sourceDir,\n workspaceRoot: record.workspaceRoot,\n ...(record.ownerPlatform ? { ownerPlatform: record.ownerPlatform } : {}),\n ...(targetDir ? { targetDir } : {}),\n status,\n ...(error ? { error } : {}),\n });\n}\n\nfunction migrationTarget(record: OfficeMigrationRecord): string | undefined {\n return record.ownerPlatform\n ? officeDir(record.workspaceRoot, {\n platform: record.ownerPlatform,\n conversationId: record.rawConversationId,\n })\n : undefined;\n}\n\nfunction freezeState(input: {\n enabledPlatforms: readonly PlatformName[];\n offices: readonly OfficeRecord[];\n migrations: readonly OfficeMigrationRecord[];\n}): OfficeRegistryState {\n return Object.freeze({\n version: REGISTRY_VERSION as 1,\n enabledPlatforms: Object.freeze([...input.enabledPlatforms]),\n offices: Object.freeze(input.offices.map((record) => Object.freeze({ ...record }))),\n migrations: Object.freeze(input.migrations.map((record) => Object.freeze({ ...record }))),\n });\n}\n\nfunction parseState(value: unknown, path: string): OfficeRegistryState {\n if (!isRecord(value) || value.version !== REGISTRY_VERSION) {\n throw new Error(`Invalid office registry version at ${path}`);\n }\n if (!Array.isArray(value.enabledPlatforms) || !Array.isArray(value.migrations)) {\n throw new Error(`Invalid office registry shape at ${path}`);\n }\n\n const enabledPlatforms = value.enabledPlatforms.map((platform) => {\n if (typeof platform !== \"string\") throw new Error(`Invalid enabled platform in ${path}`);\n return assertPlatformName(platform);\n });\n if (new Set(enabledPlatforms).size !== enabledPlatforms.length) {\n throw new Error(`Duplicate enabled platform in ${path}`);\n }\n\n // Files written before office records existed simply have no offices yet.\n const offices = (Array.isArray(value.offices) ? value.offices : []).map((entry) =>\n parseOfficeRecord(entry, path),\n );\n if (new Set(offices.map((record) => officeKey(record))).size !== offices.length) {\n throw new Error(`Duplicate office record in ${path}`);\n }\n\n const migrations = value.migrations.map((entry) => parseRecord(entry, path, enabledPlatforms));\n if (new Set(migrations.map((record) => record.rawConversationId)).size !== migrations.length) {\n throw new Error(`Duplicate office migration in ${path}`);\n }\n return freezeState({ enabledPlatforms, offices, migrations });\n}\n\nfunction parseOfficeRecord(value: unknown, path: string): OfficeRecord {\n if (!isRecord(value)) throw new Error(`Invalid office record in ${path}`);\n if (\n typeof value.platform !== \"string\" ||\n typeof value.conversationId !== \"string\" ||\n typeof value.recordedAt !== \"string\"\n ) {\n throw new Error(`Invalid office record fields in ${path}`);\n }\n return Object.freeze({\n platform: assertPlatformName(value.platform),\n conversationId: assertConversationId(value.conversationId),\n recordedAt: value.recordedAt,\n });\n}\n\nfunction parseRecord(\n value: unknown,\n path: string,\n enabledPlatforms: readonly PlatformName[],\n): OfficeMigrationRecord {\n if (!isRecord(value)) throw new Error(`Invalid office migration record in ${path}`);\n if (\n typeof value.rawConversationId !== \"string\" ||\n typeof value.sourceDir !== \"string\" ||\n typeof value.workspaceRoot !== \"string\" ||\n typeof value.status !== \"string\" ||\n typeof value.updatedAt !== \"string\"\n ) {\n throw new Error(`Invalid office migration fields in ${path}`);\n }\n assertConversationId(value.rawConversationId);\n if (!isAbsolute(value.sourceDir) || !isAbsolute(value.workspaceRoot)) {\n throw new Error(`Office migration paths must be absolute in ${path}`);\n }\n assertCanonicalSource(value.sourceDir, value.workspaceRoot, value.rawConversationId);\n if (!MIGRATION_STATUSES.has(value.status as OfficeMigrationStatus)) {\n throw new Error(`Invalid office migration status in ${path}`);\n }\n\n const ownerPlatform = optionalPlatform(value.ownerPlatform);\n const targetDir = optionalString(value.targetDir);\n const error = optionalString(value.error);\n if (ownerPlatform !== undefined && !enabledPlatforms.includes(ownerPlatform)) {\n throw new Error(`Office migration owner is not enabled in ${path}`);\n }\n if (value.status === \"needs-owner\" && (ownerPlatform !== undefined || targetDir !== undefined)) {\n throw new Error(`Needs-owner migration cannot have an owner or target in ${path}`);\n }\n if (\n value.status !== \"needs-owner\" &&\n value.status !== \"failed\" &&\n (ownerPlatform === undefined || targetDir === undefined)\n ) {\n throw new Error(`Prepared office migration is missing ownership in ${path}`);\n }\n if (ownerPlatform === undefined && targetDir !== undefined) {\n throw new Error(`Office migration target has no owner in ${path}`);\n }\n const expectedTargetDir = ownerPlatform\n ? officeDir(value.workspaceRoot, {\n platform: ownerPlatform,\n conversationId: value.rawConversationId,\n })\n : undefined;\n if (targetDir !== expectedTargetDir) {\n throw new Error(`Office migration target does not match its office address in ${path}`);\n }\n if (value.status === \"failed\" && !error) {\n throw new Error(`Failed office migration is missing an error in ${path}`);\n }\n\n return makeRecord({\n rawConversationId: value.rawConversationId,\n sourceDir: value.sourceDir,\n workspaceRoot: value.workspaceRoot,\n ...(ownerPlatform ? { ownerPlatform } : {}),\n ...(expectedTargetDir ? { targetDir: expectedTargetDir } : {}),\n status: value.status as OfficeMigrationStatus,\n ...(error ? { error } : {}),\n updatedAt: value.updatedAt,\n });\n}\n\nfunction optionalPlatform(value: unknown): PlatformName | undefined {\n return value === undefined\n ? undefined\n : typeof value === \"string\"\n ? assertPlatformName(value)\n : failOptional(\"platform\");\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return value === undefined\n ? undefined\n : typeof value === \"string\"\n ? value\n : failOptional(\"string\");\n}\n\nfunction failOptional(label: string): never {\n throw new Error(`Invalid optional ${label} in office registry`);\n}\n\nfunction assertSameMigrationInputs(\n existing: OfficeMigrationRecord,\n sourceDir: string,\n workspaceRoot: string,\n): void {\n if (existing.sourceDir !== sourceDir || existing.workspaceRoot !== workspaceRoot) {\n throw new Error(`Legacy office migration inputs changed for ${existing.rawConversationId}`);\n }\n}\n\nfunction assertCanonicalSource(\n sourceDir: string,\n workspaceRoot: string,\n rawConversationId: string,\n): void {\n const expectedSourceDir = resolve(workspaceRoot, rawConversationId);\n if (sourceDir !== expectedSourceDir) {\n throw new Error(`Legacy office source must be ${expectedSourceDir}`);\n }\n assertRegularDirectory(workspaceRoot, \"Workspace root\");\n assertPathIfPresent(sourceDir, \"Legacy office source\");\n}\n\nfunction assertRegularDirectory(path: string, label: string): void {\n let stat;\n try {\n stat = lstatSync(path);\n } catch (error) {\n throw new Error(`${label} does not exist: ${path}`, { cause: error });\n }\n if (stat.isSymbolicLink() || !stat.isDirectory()) {\n throw new Error(`${label} must be a regular directory: ${path}`);\n }\n}\n\nfunction assertRegistryFileSafe(path: string): void {\n try {\n const stat = lstatSync(path);\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new Error(`Office registry must be a regular file: ${path}`);\n }\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return;\n throw error;\n }\n}\n\nfunction assertPathIfPresent(path: string, label: string): void {\n try {\n const stat = lstatSync(path);\n if (stat.isSymbolicLink() || !stat.isDirectory()) {\n throw new Error(`${label} must be a regular directory: ${path}`);\n }\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return;\n throw error;\n }\n}\n\nfunction assertPathAbsent(path: string, label: string): void {\n try {\n lstatSync(path);\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return;\n throw error;\n }\n throw new Error(`${label} must be absent: ${path}`);\n}\n\nfunction pathExists(path: string): boolean {\n try {\n lstatSync(path);\n return true;\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) return false;\n throw error;\n }\n}\n\nfunction acquireRegistryLease(lockPath: string, timeoutMs: number): () => void {\n const deadline = Date.now() + timeoutMs;\n const token = `${process.pid}:${randomBytes(8).toString(\"hex\")}`;\n\n for (;;) {\n try {\n mkdirSync(lockPath, { mode: 0o700 });\n try {\n writeFileSync(join(lockPath, \"owner\"), `${token}\\n`, { mode: 0o600 });\n } catch (error) {\n rmSync(lockPath, { recursive: true, force: true });\n throw error;\n }\n return () => releaseRegistryLease(lockPath, token);\n } catch (error) {\n if (!isErrno(error, \"EEXIST\")) throw error;\n if (registryLockIsStale(lockPath)) {\n rmSync(lockPath, { recursive: true, force: true });\n continue;\n }\n if (Date.now() >= deadline) {\n throw new Error(`Timed out acquiring office registry lock: ${lockPath}`, { cause: error });\n }\n sleepSync(REGISTRY_LOCK_RETRY_MS);\n }\n }\n}\n\nfunction releaseRegistryLease(lockPath: string, token: string): void {\n try {\n if (readFileSync(join(lockPath, \"owner\"), \"utf8\").trim() === token) {\n rmSync(lockPath, { recursive: true, force: true });\n }\n } catch (error) {\n if (!isErrno(error, \"ENOENT\")) throw error;\n }\n}\n\nfunction registryLockIsStale(lockPath: string): boolean {\n let ownerKnown = false;\n let ownerAlive = false;\n try {\n const owner = readFileSync(join(lockPath, \"owner\"), \"utf8\").trim();\n const pid = Number(owner.split(\":\", 1)[0]);\n if (Number.isInteger(pid) && pid > 0) {\n ownerKnown = true;\n try {\n process.kill(pid, 0);\n ownerAlive = true;\n } catch (error) {\n if (isErrno(error, \"EPERM\")) ownerAlive = true;\n }\n }\n } catch {\n // The owner file may not have been written before its process died.\n }\n try {\n const oldEnough = Date.now() - statSync(lockPath).mtimeMs >= REGISTRY_LOCK_STALE_MS;\n return ownerKnown ? !ownerAlive : oldEnough;\n } catch {\n return false;\n }\n}\n\nfunction sleepSync(milliseconds: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);\n}\n\n// ── raw-id lookups (cold paths: CLI, Admin enumeration) ──────────────────────\n\n/**\n * Resolve the office behind a raw conversation id for surfaces that name\n * offices by raw id (CLI operators). The registry is the only authority:\n * office records first, then a committed migration's owner, then the sole\n * enabled platform. Two platforms sharing the raw id make the scope\n * genuinely ambiguous, and an unknown id has no office to resolve — both\n * fail loudly rather than guessing a directory.\n *\n * Constructs a registry per call, which re-reads the journal from disk; this\n * is a one-shot CLI/Admin surface, never a per-message path (those go\n * through the Workspace value's cached registry in `layout.ts`).\n */\nexport function resolveOwnedOfficeAddress(\n rawConversationId: string,\n stateDir: string,\n): OfficeAddress {\n assertConversationId(rawConversationId);\n const registry = new OfficeRegistry(stateDir);\n\n const matches = registry\n .getState()\n .offices.filter((record) => record.conversationId === rawConversationId);\n const single = matches.length === 1 ? matches[0] : undefined;\n if (single !== undefined) {\n return { platform: single.platform, conversationId: rawConversationId };\n }\n if (matches.length > 1) {\n throw new Error(\n `Conversation id ${JSON.stringify(rawConversationId)} names offices on several platforms; ` +\n \"use a platform-scoped surface instead\",\n );\n }\n\n const migration = registry.getMigration(rawConversationId);\n if (migration?.ownerPlatform) {\n return { platform: migration.ownerPlatform, conversationId: rawConversationId };\n }\n const { enabledPlatforms } = registry.getState();\n const onlyPlatform = enabledPlatforms.length === 1 ? enabledPlatforms[0] : undefined;\n if (onlyPlatform !== undefined) {\n return { platform: onlyPlatform, conversationId: rawConversationId };\n }\n throw new Error(\n `No office is registered for conversation id ${JSON.stringify(rawConversationId)}`,\n );\n}\n\n/** Current office inventory, read fresh from disk for cross-process freshness. */\nexport function listRegisteredOffices(stateDir: string): readonly OfficeRecord[] {\n return new OfficeRegistry(stateDir).getOffices();\n}\n\n/**\n * Enabled platforms whose id format could have produced this raw\n * conversation id. Auto-claiming uses this as verification, not guessing:\n * every format below is one mikan itself writes (GitHub ids are mikan-derived\n * slugs; Slack/Telegram/Discord ids are the platforms' own grammars), and a\n * directory is only claimed when exactly one enabled platform's format\n * matches. Bare digits stay ambiguous while both Telegram and Discord are\n * enabled (negative ids are Telegram-only); anything matching no enabled\n * format fails closed to needs-owner.\n */\nfunction platformsMatchingConversationIdFormat(\n rawConversationId: string,\n enabledPlatforms: readonly PlatformName[],\n): PlatformName[] {\n return enabledPlatforms.filter((platform) => {\n switch (platform) {\n case \"github\":\n return isGithubConversationId(rawConversationId);\n case \"telegram\":\n return /^-?\\d+$/.test(rawConversationId);\n case \"discord\":\n return /^\\d+$/.test(rawConversationId);\n case \"slack\":\n return /^[A-Z][A-Z0-9]*$/.test(rawConversationId);\n }\n });\n}\n\nfunction isGithubConversationId(rawConversationId: string): boolean {\n try {\n parseGithubConversationId(rawConversationId);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isErrno(error: unknown, code: string): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
@@ -13,8 +13,8 @@
13
13
  */
14
14
  import { execFileSync } from "node:child_process";
15
15
  import { createHash } from "node:crypto";
16
- import { cpSync, existsSync, rmSync, statSync, writeFileSync } from "node:fs";
17
- import { dirname, join } from "node:path";
16
+ import { cpSync, existsSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
17
+ import { dirname, isAbsolute, join, relative, sep } from "node:path";
18
18
  import { ensureDirExists, readTextFileIfExists } from "../utils/file-guards.js";
19
19
  import * as log from "../log.js";
20
20
  import { gitRepoPath, parseSource, sourceIdentity } from "./source.js";
@@ -60,7 +60,7 @@ export function packageScopeDir(scope, address, stateDir) {
60
60
  */
61
61
  export function gitCloneDir(url, scopeDir, ref) {
62
62
  const repoPath = gitRepoPath(url).split("/");
63
- const repoName = repoPath[repoPath.length - 1];
63
+ const repoName = repoPath[repoPath.length - 1] ?? "repo";
64
64
  const parent = repoPath.slice(0, -1);
65
65
  const checkoutName = ref === undefined || ref === "HEAD"
66
66
  ? repoName
@@ -223,6 +223,13 @@ function resolveSubpath(cloneDir, parsed) {
223
223
  if (!existsSync(dir)) {
224
224
  throw new Error(`Subpath not found in repository: ${parsed.subpath}`);
225
225
  }
226
+ // A symlink inside the repository must not select files outside the clone:
227
+ // the returned directory is imported (extensions) or mounted, so follow
228
+ // links before deciding the subpath stayed inside.
229
+ const relation = relative(realpathSync(cloneDir), realpathSync(dir));
230
+ if (isAbsolute(relation) || relation === ".." || relation.startsWith(`..${sep}`)) {
231
+ throw new Error(`Subpath escapes repository: ${parsed.subpath}`);
232
+ }
226
233
  return dir;
227
234
  }
228
235
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"materialize.js","sourceRoot":"","sources":["../../src/packages/materialize.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turning a parsed source into a directory on the host.\n *\n * Materialization is an explicit, reported step — it happens when a human adds\n * or updates a package, not lazily while a conversation is waiting for a\n * reply. Failures (bad URL, missing ref, no such subpath) therefore surface in\n * front of the person who typed the source instead of as a silently absent\n * feature in a chat.\n *\n * Everything lands under the host-only state dir, never the workspace: this\n * code is imported into the mikan process, so a mounted location would let\n * sandboxed code write what the host executes.\n */\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { cpSync, existsSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { ensureDirExists, readTextFileIfExists } from \"../utils/file-guards.js\";\nimport * as log from \"../log.js\";\nimport { gitRepoPath, parseSource, sourceIdentity } from \"./source.js\";\nimport { officeStateDir } from \"../office/index.js\";\nimport type { OfficeAddress } from \"../types.js\";\nimport type {\n MaterializeMode,\n MaterializeOptions,\n MaterializedPackage,\n PackageScope,\n PackageSourceString,\n ParsedSource,\n} from \"./types.js\";\n\nexport type { MaterializeOptions } from \"./types.js\";\n\n/** Git operations get a bounded wall clock so a hung remote cannot wedge a save. */\nconst GIT_TIMEOUT_MS = 120_000;\nconst NPM_TIMEOUT_MS = 300_000;\nconst MATERIALIZED_REF_FILE = \"mikan-ref\";\n\n/**\n * How far materialization may go to produce the package's files.\n *\n * - `offline`: use what is already on disk; never touch the network. This is\n * what a conversation load uses, so no chat reply can ever wait on a remote.\n * - `fetch`: clone a package that is not on disk yet, reuse an existing clone\n * when it already has the requested ref, or switch it to a new ref. What the\n * portal uses when a source is added.\n * - `refresh`: additionally re-fetch an existing clone, resetting and cleaning\n * it first. What the portal's Update action uses.\n *\n * One mode rather than two booleans: \"re-fetch an existing clone but refuse to\n * create a missing one\" is not a state any caller wants, and expressing it\n * should not be possible.\n */\n/**\n * Root of a scope's host-only assets: `<stateDir>/global` or\n * `<stateDir>/conversations/<id>`. The two are isomorphic by design — both\n * hold `extensions/`, `extension-data/`, and now `git/`. See\n * `src/harness/extensions/LAYOUT.md`.\n */\nexport function packageScopeDir(\n scope: PackageScope,\n address: OfficeAddress | undefined,\n stateDir: string,\n): string {\n if (scope === \"global\") return join(stateDir, \"global\");\n if (!address) throw new Error(\"A conversation-scoped package needs an office address\");\n return officeStateDir(stateDir, address);\n}\n\n/**\n * Where a git checkout lives.\n *\n * The unpinned checkout keeps the original path for compatibility. Explicit\n * refs get a sibling keyed by the ref, so two refs can never reset each\n * other's working tree; subpaths of one ref therefore still share a checkout.\n */\nexport function gitCloneDir(url: string, scopeDir: string, ref?: string): string {\n const repoPath = gitRepoPath(url).split(\"/\");\n const repoName = repoPath[repoPath.length - 1];\n const parent = repoPath.slice(0, -1);\n const checkoutName =\n ref === undefined || ref === \"HEAD\"\n ? repoName\n : `${repoName}.mikan-${createHash(\"sha256\").update(ref).digest(\"hex\")}`;\n return join(scopeDir, \"git\", ...parent, checkoutName);\n}\n\n/**\n * Materialize one source and return where its files ended up. Throws with a\n * message meant to be shown to a human — callers render it next to the input\n * that produced it.\n */\nexport function materializeSource(\n source: PackageSourceString,\n options: MaterializeOptions,\n): MaterializedPackage {\n const parsed = parseSource(source);\n const scopeDir = packageScopeDir(options.scope, options.address, options.stateDir);\n const dir =\n parsed.type === \"local\"\n ? materializeLocal(parsed)\n : materializeGit(parsed, scopeDir, options.mode ?? \"fetch\");\n\n return {\n source,\n parsed,\n identity: sourceIdentity(parsed),\n dir,\n scope: options.scope,\n };\n}\n\nfunction materializeLocal(parsed: Extract<ParsedSource, { type: \"local\" }>): string {\n if (!existsSync(parsed.path)) {\n throw new Error(`Path does not exist on the mikan host: ${parsed.path}`);\n }\n if (!statSync(parsed.path).isDirectory()) {\n throw new Error(`Package path must be a directory: ${parsed.path}`);\n }\n return parsed.path;\n}\n\nfunction materializeGit(\n parsed: Extract<ParsedSource, { type: \"git\" }>,\n scopeDir: string,\n mode: MaterializeMode,\n): string {\n const requestedRef = parsed.ref ?? \"HEAD\";\n const cloneDir = gitCloneDir(parsed.url, scopeDir, requestedRef);\n migrateLegacyCheckout(parsed.url, scopeDir, cloneDir, requestedRef);\n const alreadyCloned = existsSync(join(cloneDir, \".git\"));\n const markerPath = join(cloneDir, \".git\", MATERIALIZED_REF_FILE);\n const recordedRef = alreadyCloned ? readTextFileIfExists(markerPath)?.trim() : undefined;\n const canReuse =\n alreadyCloned &&\n mode !== \"refresh\" &&\n (recordedRef === requestedRef ||\n (mode === \"offline\" &&\n recordedRef === undefined &&\n markerlessCheckoutMatchesRef(cloneDir, requestedRef)));\n\n if (canReuse) {\n return resolveSubpath(cloneDir, parsed);\n }\n if (mode === \"offline\") {\n throw new Error(`Not fetched on this host yet: ${describeRef(parsed)}`);\n }\n\n // An incomplete checkout must not retain a marker from an earlier attempt:\n // otherwise a retry could mistake a failed dependency install for success.\n if (alreadyCloned) rmSync(markerPath, { force: true });\n\n if (!alreadyCloned) {\n // A leftover directory without .git means a previous attempt died partway.\n if (existsSync(cloneDir)) rmSync(cloneDir, { recursive: true, force: true });\n ensureDirExists(cloneDir);\n git(cloneDir, [\"init\", \"-q\"]);\n git(cloneDir, [\"remote\", \"add\", \"origin\", parsed.url]);\n } else {\n // Reconcile: drop anything a previous checkout left behind so the new ref\n // lands on a clean tree.\n git(cloneDir, [\"remote\", \"set-url\", \"origin\", parsed.url]);\n git(cloneDir, [\"reset\", \"--hard\", \"-q\"]);\n git(cloneDir, [\"clean\", \"-qfd\"]);\n }\n\n // One fetch shape for every kind of ref — tag, branch, or commit sha — and\n // `HEAD` for \"whatever the remote's default branch is now\".\n try {\n git(cloneDir, [\"fetch\", \"--depth\", \"1\", \"origin\", requestedRef]);\n } catch (err) {\n if (!alreadyCloned) rmSync(cloneDir, { recursive: true, force: true });\n throw new Error(`Could not fetch ${describeRef(parsed)}: ${gitErrorText(err)}`, { cause: err });\n }\n git(cloneDir, [\"checkout\", \"-q\", \"--detach\", \"FETCH_HEAD\"]);\n\n const dir = resolveSubpath(cloneDir, parsed);\n installDependencies(dir);\n // This is the completion marker, not merely a fetched-ref marker. Write it\n // last so a failed npm install is retried by the next materialization.\n writeFileSync(markerPath, `${requestedRef}\\n`);\n return dir;\n}\n\n/**\n * Before keyed checkout paths existed, every ref used the legacy repo path.\n * Copy a matching complete checkout on first use of its keyed path so offline\n * loads keep working. Markerless legacy checkouts are accepted only when git\n * can prove the requested ref is the checked-out commit; a different or\n * unprovable pinned ref is rebuilt by fetch/refresh instead.\n */\nfunction migrateLegacyCheckout(\n url: string,\n scopeDir: string,\n cloneDir: string,\n requestedRef: string,\n): void {\n const legacyDir = gitCloneDir(url, scopeDir);\n if (cloneDir === legacyDir || existsSync(cloneDir)) return;\n const legacyMarker = join(legacyDir, \".git\", MATERIALIZED_REF_FILE);\n if (!existsSync(join(legacyDir, \".git\"))) return;\n const recordedRef = readTextFileIfExists(legacyMarker)?.trim();\n if (recordedRef !== requestedRef) {\n if (recordedRef !== undefined || !markerlessCheckoutMatchesRef(legacyDir, requestedRef)) {\n return;\n }\n }\n\n ensureDirExists(dirname(cloneDir));\n cpSync(legacyDir, cloneDir, { recursive: true });\n}\n\n/**\n * Legacy checkouts have no completion marker. Accept them offline only when\n * the checkout is clean and the local git metadata identifies the requested\n * commit/ref; never infer a pinned ref from HEAD alone.\n */\nfunction markerlessCheckoutMatchesRef(cloneDir: string, requestedRef: string): boolean {\n let head: string;\n try {\n head = git(cloneDir, [\"rev-parse\", \"--verify\", \"HEAD\"]).trim();\n if (!head || git(cloneDir, [\"status\", \"--porcelain\", \"--untracked-files=no\"]).trim()) {\n return false;\n }\n } catch {\n return false;\n }\n\n if (requestedRef === \"HEAD\") return true;\n\n try {\n if (git(cloneDir, [\"rev-parse\", \"--verify\", `${requestedRef}^{commit}`]).trim() === head) {\n return true;\n }\n } catch {\n // A shallow legacy fetch may retain only FETCH_HEAD, not a local ref.\n }\n\n try {\n if (git(cloneDir, [\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]).trim() === requestedRef) {\n return true;\n }\n } catch {\n // Detached checkouts do not have a symbolic branch.\n }\n\n const fetchHead = readTextFileIfExists(join(cloneDir, \".git\", \"FETCH_HEAD\"));\n if (!fetchHead) return false;\n return fetchHead.split(\"\\n\").some((line) => {\n const match = /^(\\w+)\\s+.*(?:branch|tag) '([^']+)'/.exec(line);\n return match?.[1] === head && match[2] === requestedRef;\n });\n}\n\nfunction resolveSubpath(cloneDir: string, parsed: Extract<ParsedSource, { type: \"git\" }>): string {\n if (!parsed.subpath) return cloneDir;\n const dir = join(cloneDir, parsed.subpath);\n if (!existsSync(dir)) {\n throw new Error(`Subpath not found in repository: ${parsed.subpath}`);\n }\n return dir;\n}\n\n/**\n * Install runtime dependencies when the package declares any. This runs npm\n * on the host against code that was just fetched from a remote, which is the\n * same trust level as importing the package itself — but it is worth being\n * explicit that it happens, because it also runs the dependencies' install\n * scripts.\n */\nfunction installDependencies(dir: string): void {\n if (!hasDependencies(dir)) return;\n log.logInfo(`Installing package dependencies in ${dir}`);\n try {\n execFileSync(\"npm\", [\"install\", \"--omit=dev\", \"--no-audit\", \"--no-fund\"], {\n cwd: dir,\n timeout: NPM_TIMEOUT_MS,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch (err) {\n throw new Error(`npm install failed for the package: ${gitErrorText(err)}`, { cause: err });\n }\n}\n\nfunction hasDependencies(dir: string): boolean {\n const raw = readTextFileIfExists(join(dir, \"package.json\"));\n if (raw === undefined) return false;\n try {\n const pkg = JSON.parse(raw) as { dependencies?: Record<string, string> };\n return Boolean(pkg.dependencies && Object.keys(pkg.dependencies).length > 0);\n } catch {\n return false;\n }\n}\n\nfunction git(cwd: string, args: string[]): string {\n return execFileSync(\"git\", args, {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n // Never block a portal save on an interactive credential prompt.\n GIT_TERMINAL_PROMPT: \"0\",\n GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? \"ssh -o BatchMode=yes -o ConnectTimeout=10\",\n },\n });\n}\n\nfunction describeRef(parsed: Extract<ParsedSource, { type: \"git\" }>): string {\n return parsed.ref ? `${parsed.url} at ${parsed.ref}` : parsed.url;\n}\n\n/** Prefer git's stderr over the generic \"Command failed\" wrapper. */\nfunction gitErrorText(err: unknown): string {\n if (err && typeof err === \"object\" && \"stderr\" in err) {\n const stderr = (err as { stderr?: unknown }).stderr;\n const text = typeof stderr === \"string\" ? stderr.trim() : \"\";\n if (text) return text.split(\"\\n\").slice(-3).join(\" \");\n }\n return err instanceof Error ? err.message : String(err);\n}\n"]}
1
+ {"version":3,"file":"materialize.js","sourceRoot":"","sources":["../../src/packages/materialize.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turning a parsed source into a directory on the host.\n *\n * Materialization is an explicit, reported step — it happens when a human adds\n * or updates a package, not lazily while a conversation is waiting for a\n * reply. Failures (bad URL, missing ref, no such subpath) therefore surface in\n * front of the person who typed the source instead of as a silently absent\n * feature in a chat.\n *\n * Everything lands under the host-only state dir, never the workspace: this\n * code is imported into the mikan process, so a mounted location would let\n * sandboxed code write what the host executes.\n */\nimport { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { cpSync, existsSync, realpathSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, sep } from \"node:path\";\nimport { ensureDirExists, readTextFileIfExists } from \"../utils/file-guards.js\";\nimport * as log from \"../log.js\";\nimport { gitRepoPath, parseSource, sourceIdentity } from \"./source.js\";\nimport { officeStateDir } from \"../office/index.js\";\nimport type { OfficeAddress } from \"../types.js\";\nimport type {\n MaterializeMode,\n MaterializeOptions,\n MaterializedPackage,\n PackageScope,\n PackageSourceString,\n ParsedSource,\n} from \"./types.js\";\n\nexport type { MaterializeOptions } from \"./types.js\";\n\n/** Git operations get a bounded wall clock so a hung remote cannot wedge a save. */\nconst GIT_TIMEOUT_MS = 120_000;\nconst NPM_TIMEOUT_MS = 300_000;\nconst MATERIALIZED_REF_FILE = \"mikan-ref\";\n\n/**\n * How far materialization may go to produce the package's files.\n *\n * - `offline`: use what is already on disk; never touch the network. This is\n * what a conversation load uses, so no chat reply can ever wait on a remote.\n * - `fetch`: clone a package that is not on disk yet, reuse an existing clone\n * when it already has the requested ref, or switch it to a new ref. What the\n * portal uses when a source is added.\n * - `refresh`: additionally re-fetch an existing clone, resetting and cleaning\n * it first. What the portal's Update action uses.\n *\n * One mode rather than two booleans: \"re-fetch an existing clone but refuse to\n * create a missing one\" is not a state any caller wants, and expressing it\n * should not be possible.\n */\n/**\n * Root of a scope's host-only assets: `<stateDir>/global` or\n * `<stateDir>/conversations/<id>`. The two are isomorphic by design — both\n * hold `extensions/`, `extension-data/`, and now `git/`. See\n * `src/harness/extensions/LAYOUT.md`.\n */\nexport function packageScopeDir(\n scope: PackageScope,\n address: OfficeAddress | undefined,\n stateDir: string,\n): string {\n if (scope === \"global\") return join(stateDir, \"global\");\n if (!address) throw new Error(\"A conversation-scoped package needs an office address\");\n return officeStateDir(stateDir, address);\n}\n\n/**\n * Where a git checkout lives.\n *\n * The unpinned checkout keeps the original path for compatibility. Explicit\n * refs get a sibling keyed by the ref, so two refs can never reset each\n * other's working tree; subpaths of one ref therefore still share a checkout.\n */\nexport function gitCloneDir(url: string, scopeDir: string, ref?: string): string {\n const repoPath = gitRepoPath(url).split(\"/\");\n const repoName = repoPath[repoPath.length - 1] ?? \"repo\";\n const parent = repoPath.slice(0, -1);\n const checkoutName =\n ref === undefined || ref === \"HEAD\"\n ? repoName\n : `${repoName}.mikan-${createHash(\"sha256\").update(ref).digest(\"hex\")}`;\n return join(scopeDir, \"git\", ...parent, checkoutName);\n}\n\n/**\n * Materialize one source and return where its files ended up. Throws with a\n * message meant to be shown to a human — callers render it next to the input\n * that produced it.\n */\nexport function materializeSource(\n source: PackageSourceString,\n options: MaterializeOptions,\n): MaterializedPackage {\n const parsed = parseSource(source);\n const scopeDir = packageScopeDir(options.scope, options.address, options.stateDir);\n const dir =\n parsed.type === \"local\"\n ? materializeLocal(parsed)\n : materializeGit(parsed, scopeDir, options.mode ?? \"fetch\");\n\n return {\n source,\n parsed,\n identity: sourceIdentity(parsed),\n dir,\n scope: options.scope,\n };\n}\n\nfunction materializeLocal(parsed: Extract<ParsedSource, { type: \"local\" }>): string {\n if (!existsSync(parsed.path)) {\n throw new Error(`Path does not exist on the mikan host: ${parsed.path}`);\n }\n if (!statSync(parsed.path).isDirectory()) {\n throw new Error(`Package path must be a directory: ${parsed.path}`);\n }\n return parsed.path;\n}\n\nfunction materializeGit(\n parsed: Extract<ParsedSource, { type: \"git\" }>,\n scopeDir: string,\n mode: MaterializeMode,\n): string {\n const requestedRef = parsed.ref ?? \"HEAD\";\n const cloneDir = gitCloneDir(parsed.url, scopeDir, requestedRef);\n migrateLegacyCheckout(parsed.url, scopeDir, cloneDir, requestedRef);\n const alreadyCloned = existsSync(join(cloneDir, \".git\"));\n const markerPath = join(cloneDir, \".git\", MATERIALIZED_REF_FILE);\n const recordedRef = alreadyCloned ? readTextFileIfExists(markerPath)?.trim() : undefined;\n const canReuse =\n alreadyCloned &&\n mode !== \"refresh\" &&\n (recordedRef === requestedRef ||\n (mode === \"offline\" &&\n recordedRef === undefined &&\n markerlessCheckoutMatchesRef(cloneDir, requestedRef)));\n\n if (canReuse) {\n return resolveSubpath(cloneDir, parsed);\n }\n if (mode === \"offline\") {\n throw new Error(`Not fetched on this host yet: ${describeRef(parsed)}`);\n }\n\n // An incomplete checkout must not retain a marker from an earlier attempt:\n // otherwise a retry could mistake a failed dependency install for success.\n if (alreadyCloned) rmSync(markerPath, { force: true });\n\n if (!alreadyCloned) {\n // A leftover directory without .git means a previous attempt died partway.\n if (existsSync(cloneDir)) rmSync(cloneDir, { recursive: true, force: true });\n ensureDirExists(cloneDir);\n git(cloneDir, [\"init\", \"-q\"]);\n git(cloneDir, [\"remote\", \"add\", \"origin\", parsed.url]);\n } else {\n // Reconcile: drop anything a previous checkout left behind so the new ref\n // lands on a clean tree.\n git(cloneDir, [\"remote\", \"set-url\", \"origin\", parsed.url]);\n git(cloneDir, [\"reset\", \"--hard\", \"-q\"]);\n git(cloneDir, [\"clean\", \"-qfd\"]);\n }\n\n // One fetch shape for every kind of ref — tag, branch, or commit sha — and\n // `HEAD` for \"whatever the remote's default branch is now\".\n try {\n git(cloneDir, [\"fetch\", \"--depth\", \"1\", \"origin\", requestedRef]);\n } catch (err) {\n if (!alreadyCloned) rmSync(cloneDir, { recursive: true, force: true });\n throw new Error(`Could not fetch ${describeRef(parsed)}: ${gitErrorText(err)}`, { cause: err });\n }\n git(cloneDir, [\"checkout\", \"-q\", \"--detach\", \"FETCH_HEAD\"]);\n\n const dir = resolveSubpath(cloneDir, parsed);\n installDependencies(dir);\n // This is the completion marker, not merely a fetched-ref marker. Write it\n // last so a failed npm install is retried by the next materialization.\n writeFileSync(markerPath, `${requestedRef}\\n`);\n return dir;\n}\n\n/**\n * Before keyed checkout paths existed, every ref used the legacy repo path.\n * Copy a matching complete checkout on first use of its keyed path so offline\n * loads keep working. Markerless legacy checkouts are accepted only when git\n * can prove the requested ref is the checked-out commit; a different or\n * unprovable pinned ref is rebuilt by fetch/refresh instead.\n */\nfunction migrateLegacyCheckout(\n url: string,\n scopeDir: string,\n cloneDir: string,\n requestedRef: string,\n): void {\n const legacyDir = gitCloneDir(url, scopeDir);\n if (cloneDir === legacyDir || existsSync(cloneDir)) return;\n const legacyMarker = join(legacyDir, \".git\", MATERIALIZED_REF_FILE);\n if (!existsSync(join(legacyDir, \".git\"))) return;\n const recordedRef = readTextFileIfExists(legacyMarker)?.trim();\n if (recordedRef !== requestedRef) {\n if (recordedRef !== undefined || !markerlessCheckoutMatchesRef(legacyDir, requestedRef)) {\n return;\n }\n }\n\n ensureDirExists(dirname(cloneDir));\n cpSync(legacyDir, cloneDir, { recursive: true });\n}\n\n/**\n * Legacy checkouts have no completion marker. Accept them offline only when\n * the checkout is clean and the local git metadata identifies the requested\n * commit/ref; never infer a pinned ref from HEAD alone.\n */\nfunction markerlessCheckoutMatchesRef(cloneDir: string, requestedRef: string): boolean {\n let head: string;\n try {\n head = git(cloneDir, [\"rev-parse\", \"--verify\", \"HEAD\"]).trim();\n if (!head || git(cloneDir, [\"status\", \"--porcelain\", \"--untracked-files=no\"]).trim()) {\n return false;\n }\n } catch {\n return false;\n }\n\n if (requestedRef === \"HEAD\") return true;\n\n try {\n if (git(cloneDir, [\"rev-parse\", \"--verify\", `${requestedRef}^{commit}`]).trim() === head) {\n return true;\n }\n } catch {\n // A shallow legacy fetch may retain only FETCH_HEAD, not a local ref.\n }\n\n try {\n if (git(cloneDir, [\"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"]).trim() === requestedRef) {\n return true;\n }\n } catch {\n // Detached checkouts do not have a symbolic branch.\n }\n\n const fetchHead = readTextFileIfExists(join(cloneDir, \".git\", \"FETCH_HEAD\"));\n if (!fetchHead) return false;\n return fetchHead.split(\"\\n\").some((line) => {\n const match = /^(\\w+)\\s+.*(?:branch|tag) '([^']+)'/.exec(line);\n return match?.[1] === head && match[2] === requestedRef;\n });\n}\n\nfunction resolveSubpath(cloneDir: string, parsed: Extract<ParsedSource, { type: \"git\" }>): string {\n if (!parsed.subpath) return cloneDir;\n const dir = join(cloneDir, parsed.subpath);\n if (!existsSync(dir)) {\n throw new Error(`Subpath not found in repository: ${parsed.subpath}`);\n }\n // A symlink inside the repository must not select files outside the clone:\n // the returned directory is imported (extensions) or mounted, so follow\n // links before deciding the subpath stayed inside.\n const relation = relative(realpathSync(cloneDir), realpathSync(dir));\n if (isAbsolute(relation) || relation === \"..\" || relation.startsWith(`..${sep}`)) {\n throw new Error(`Subpath escapes repository: ${parsed.subpath}`);\n }\n return dir;\n}\n\n/**\n * Install runtime dependencies when the package declares any. This runs npm\n * on the host against code that was just fetched from a remote, which is the\n * same trust level as importing the package itself — but it is worth being\n * explicit that it happens, because it also runs the dependencies' install\n * scripts.\n */\nfunction installDependencies(dir: string): void {\n if (!hasDependencies(dir)) return;\n log.logInfo(`Installing package dependencies in ${dir}`);\n try {\n execFileSync(\"npm\", [\"install\", \"--omit=dev\", \"--no-audit\", \"--no-fund\"], {\n cwd: dir,\n timeout: NPM_TIMEOUT_MS,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch (err) {\n throw new Error(`npm install failed for the package: ${gitErrorText(err)}`, { cause: err });\n }\n}\n\nfunction hasDependencies(dir: string): boolean {\n const raw = readTextFileIfExists(join(dir, \"package.json\"));\n if (raw === undefined) return false;\n try {\n const pkg = JSON.parse(raw) as { dependencies?: Record<string, string> };\n return Boolean(pkg.dependencies && Object.keys(pkg.dependencies).length > 0);\n } catch {\n return false;\n }\n}\n\nfunction git(cwd: string, args: string[]): string {\n return execFileSync(\"git\", args, {\n cwd,\n timeout: GIT_TIMEOUT_MS,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n // Never block a portal save on an interactive credential prompt.\n GIT_TERMINAL_PROMPT: \"0\",\n GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? \"ssh -o BatchMode=yes -o ConnectTimeout=10\",\n },\n });\n}\n\nfunction describeRef(parsed: Extract<ParsedSource, { type: \"git\" }>): string {\n return parsed.ref ? `${parsed.url} at ${parsed.ref}` : parsed.url;\n}\n\n/** Prefer git's stderr over the generic \"Command failed\" wrapper. */\nfunction gitErrorText(err: unknown): string {\n if (err && typeof err === \"object\" && \"stderr\" in err) {\n const stderr = (err as { stderr?: unknown }).stderr;\n const text = typeof stderr === \"string\" ? stderr.trim() : \"\";\n if (text) return text.split(\"\\n\").slice(-3).join(\" \");\n }\n return err instanceof Error ? err.message : String(err);\n}\n"]}
@@ -1,4 +1,10 @@
1
1
  import type { PackageIdentity, ParsedSource } from "./types.js";
2
+ /**
3
+ * Whether a source string spells a git source (vs a local path) — the one
4
+ * home of the prefix rule. Classification only; `parseSource` still owns
5
+ * validation and error messages.
6
+ */
7
+ export declare function isGitSourceString(source: string): boolean;
2
8
  /**
3
9
  * Parse a source string. Throws with a user-facing message rather than
4
10
  * returning undefined: every caller (portal, settings load, CLI) needs to tell
@@ -1 +1 @@
1
- {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/packages/source.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAKhE;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAsCxD;AA2CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAIpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAc/C;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAKzD"}
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/packages/source.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAKhE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAQzD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAsCxD;AA2CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAIpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAc/C;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAKzD"}
@@ -29,6 +29,18 @@
29
29
  import { isAbsolute, resolve } from "node:path";
30
30
  const PROTOCOL_PREFIXES = ["https://", "http://", "ssh://", "git://", "file://"];
31
31
  const SCP_LIKE = /^[^@/\s]+@[^:/\s]+:/;
32
+ /**
33
+ * Whether a source string spells a git source (vs a local path) — the one
34
+ * home of the prefix rule. Classification only; `parseSource` still owns
35
+ * validation and error messages.
36
+ */
37
+ export function isGitSourceString(source) {
38
+ const locator = source.trim();
39
+ return (locator.startsWith("github:") ||
40
+ locator.startsWith("git:") ||
41
+ isProtocolUrl(locator) ||
42
+ SCP_LIKE.test(locator));
43
+ }
32
44
  /**
33
45
  * Parse a source string. Throws with a user-facing message rather than
34
46
  * returning undefined: every caller (portal, settings load, CLI) needs to tell
@@ -145,8 +157,8 @@ export function gitRepoPath(url) {
145
157
  const scpMatch = /^([^@/\s]+@)?([^:/\s]+)[:/](.+)$/.exec(remainder);
146
158
  if (!scpMatch)
147
159
  return sanitizeRepoPath(stripGitSuffix(remainder));
148
- const host = scpMatch[2].toLowerCase();
149
- const path = stripGitSuffix(scpMatch[3].replace(/^\/+/, ""));
160
+ const host = (scpMatch[2] ?? "").toLowerCase();
161
+ const path = stripGitSuffix((scpMatch[3] ?? "").replace(/^\/+/, ""));
150
162
  return sanitizeRepoPath(`${host}/${path}`);
151
163
  }
152
164
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/packages/source.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The package source grammar: one place that turns a human-written source\n * string into a {@link ParsedSource}, and one place that decides when two\n * sources are the same package ({@link sourceIdentity}).\n *\n * Only git and local-path sources are implemented. The tagged union and the\n * identity function are the seams a future `npm:` source slots into: adding it\n * means a new arm here and a new materializer, with nothing downstream —\n * resolution, scope precedence, the portal — needing to know.\n *\n * Grammar:\n *\n * <locator>[@<ref>][#<subpath>]\n *\n * locator: https://… http://… ssh://… git://… file://…\n * git@host:owner/repo\n * git:<any of the above, or host/owner/repo shorthand>\n * github:owner/repo\n * /abs/path ./rel/path (local, used by reference)\n *\n * `@<ref>` is recognized only when what follows the last `@` contains no `/`\n * and no `:` — otherwise the `@` belongs to the URL's authority\n * (`git@github.com:…`). A consequence: refs containing a slash\n * (`release/1.0`) cannot be written in the string form; pin to a tag or a\n * commit sha instead. The admin portal takes the URL and the ref as separate\n * inputs and assembles a canonical string, so this only constrains\n * hand-edited settings.\n */\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { PackageIdentity, ParsedSource } from \"./types.js\";\n\nconst PROTOCOL_PREFIXES = [\"https://\", \"http://\", \"ssh://\", \"git://\", \"file://\"];\nconst SCP_LIKE = /^[^@/\\s]+@[^:/\\s]+:/;\n\n/**\n * Parse a source string. Throws with a user-facing message rather than\n * returning undefined: every caller (portal, settings load, CLI) needs to tell\n * the human what was wrong with what they typed.\n */\nexport function parseSource(source: string): ParsedSource {\n const trimmed = source.trim();\n if (!trimmed) throw new Error(\"Package source is empty\");\n\n const { rest: withoutSubpath, subpath } = splitSubpath(trimmed);\n const { rest: locator, ref } = splitRef(withoutSubpath);\n\n if (locator.startsWith(\"github:\")) {\n const repo = stripGitSuffix(locator.slice(\"github:\".length).replace(/^\\/+/, \"\"));\n if (!repo.includes(\"/\")) {\n throw new Error(`github: source must be owner/repo, got ${JSON.stringify(locator)}`);\n }\n return git(`https://github.com/${repo}.git`, ref, subpath);\n }\n\n if (locator.startsWith(\"git:\")) {\n const inner = locator.slice(\"git:\".length);\n if (isProtocolUrl(inner) || SCP_LIKE.test(inner)) return git(inner, ref, subpath);\n // Shorthand: host/owner/repo — only meaningful with the git: prefix,\n // since bare host/owner/repo is ambiguous with a relative path.\n if (!inner.includes(\"/\")) {\n throw new Error(`git: source must include a path, got ${JSON.stringify(locator)}`);\n }\n return git(`https://${stripGitSuffix(inner)}.git`, ref, subpath);\n }\n\n if (isProtocolUrl(locator) || SCP_LIKE.test(locator)) return git(locator, ref, subpath);\n\n if (isAbsolute(locator) || locator.startsWith(\"./\") || locator.startsWith(\"../\")) {\n if (ref) throw new Error(\"A local path source cannot carry an @ref\");\n if (subpath) throw new Error(\"A local path source cannot carry a #subpath\");\n return { type: \"local\", path: resolve(locator) };\n }\n\n throw new Error(\n `Unrecognized package source ${JSON.stringify(source)}. ` +\n \"Use a git URL, github:owner/repo, git:host/owner/repo, or an absolute/relative path.\",\n );\n}\n\nfunction git(url: string, ref: string | undefined, subpath: string | undefined): ParsedSource {\n return { type: \"git\", url, ...(ref ? { ref } : {}), ...(subpath ? { subpath } : {}) };\n}\n\nfunction isProtocolUrl(value: string): boolean {\n return PROTOCOL_PREFIXES.some((prefix) => value.startsWith(prefix));\n}\n\nfunction stripGitSuffix(value: string): string {\n return value.replace(/\\.git$/, \"\").replace(/\\/+$/, \"\");\n}\n\nfunction splitSubpath(source: string): { rest: string; subpath?: string } {\n const hash = source.indexOf(\"#\");\n if (hash === -1) return { rest: source };\n const subpath = source.slice(hash + 1).trim();\n if (!subpath) return { rest: source.slice(0, hash) };\n assertSafeRelativePath(subpath, \"#subpath\");\n return { rest: source.slice(0, hash), subpath };\n}\n\n/**\n * Split a trailing `@ref`. The `@` in `git@github.com:owner/repo` is part of\n * the authority, not a ref, so a candidate only counts when its suffix looks\n * like a bare ref (no `/`, no `:`).\n */\nfunction splitRef(source: string): { rest: string; ref?: string } {\n const at = source.lastIndexOf(\"@\");\n if (at <= 0) return { rest: source };\n const candidate = source.slice(at + 1);\n if (!candidate || candidate.includes(\"/\") || candidate.includes(\":\")) return { rest: source };\n return { rest: source.slice(0, at), ref: candidate };\n}\n\n/** Reject traversal and absolute escapes in the parts that become paths. */\nfunction assertSafeRelativePath(value: string, label: string): void {\n if (isAbsolute(value) || value.split(/[\\\\/]/).some((segment) => segment === \"..\")) {\n throw new Error(`${label} must be a relative path without '..': ${JSON.stringify(value)}`);\n }\n}\n\n/**\n * Identity of the package a source refers to — the key for deduplication and\n * for letting a conversation's copy shadow the global one.\n *\n * Deliberate choices:\n * - The ref is excluded: the same repo pinned to two refs in two scopes is one\n * package installed twice, and the narrower scope wins.\n * - The subpath is included: two extensions living at different paths in one\n * monorepo are two packages.\n * - Transport is excluded: `git@github.com:o/r`, `https://github.com/o/r.git`\n * and `ssh://git@github.com/o/r` all identify the same package, so mixing\n * SSH and HTTPS spellings across scopes still dedups.\n */\nexport function sourceIdentity(parsed: ParsedSource): PackageIdentity {\n if (parsed.type === \"local\") return `local:${parsed.path}`;\n const repo = gitRepoPath(parsed.url);\n return parsed.subpath ? `git:${repo}#${parsed.subpath}` : `git:${repo}`;\n}\n\n/**\n * Transport-independent `<host>/<path>` of a git URL, lowercased host, no\n * `.git` suffix, no credentials. It is the base of the on-disk clone layout,\n * so it must stay free of anything that is not a safe path segment.\n */\nexport function gitRepoPath(url: string): string {\n let remainder = url;\n for (const prefix of PROTOCOL_PREFIXES) {\n if (remainder.startsWith(prefix)) {\n remainder = remainder.slice(prefix.length);\n break;\n }\n }\n // Drop any credentials in the authority (`user:pass@host`, `git@host`).\n const scpMatch = /^([^@/\\s]+@)?([^:/\\s]+)[:/](.+)$/.exec(remainder);\n if (!scpMatch) return sanitizeRepoPath(stripGitSuffix(remainder));\n const host = scpMatch[2].toLowerCase();\n const path = stripGitSuffix(scpMatch[3].replace(/^\\/+/, \"\"));\n return sanitizeRepoPath(`${host}/${path}`);\n}\n\n/**\n * `file://` URLs used in tests and local mirrors have no host, so the repo path\n * is an absolute filesystem path. Keep every segment filesystem-safe and drop\n * traversal, since this string becomes a directory under the state dir.\n */\nfunction sanitizeRepoPath(value: string): string {\n const segments = value\n .split(/[\\\\/]/)\n .map((segment) => segment.replace(/[^A-Za-z0-9._-]+/g, \"-\").replace(/^\\.+$/, \"\"))\n .filter((segment) => segment.length > 0);\n if (segments.length === 0) throw new Error(`Cannot derive a package path from ${value}`);\n return segments.join(\"/\");\n}\n\n/**\n * Canonical string form, used when writing settings so the stored value is\n * stable regardless of how the human spelled it.\n */\nexport function formatSource(parsed: ParsedSource): string {\n if (parsed.type === \"local\") return parsed.path;\n const ref = parsed.ref ? `@${parsed.ref}` : \"\";\n const subpath = parsed.subpath ? `#${parsed.subpath}` : \"\";\n return `${parsed.url}${ref}${subpath}`;\n}\n"]}
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/packages/source.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The package source grammar: one place that turns a human-written source\n * string into a {@link ParsedSource}, and one place that decides when two\n * sources are the same package ({@link sourceIdentity}).\n *\n * Only git and local-path sources are implemented. The tagged union and the\n * identity function are the seams a future `npm:` source slots into: adding it\n * means a new arm here and a new materializer, with nothing downstream —\n * resolution, scope precedence, the portal — needing to know.\n *\n * Grammar:\n *\n * <locator>[@<ref>][#<subpath>]\n *\n * locator: https://… http://… ssh://… git://… file://…\n * git@host:owner/repo\n * git:<any of the above, or host/owner/repo shorthand>\n * github:owner/repo\n * /abs/path ./rel/path (local, used by reference)\n *\n * `@<ref>` is recognized only when what follows the last `@` contains no `/`\n * and no `:` — otherwise the `@` belongs to the URL's authority\n * (`git@github.com:…`). A consequence: refs containing a slash\n * (`release/1.0`) cannot be written in the string form; pin to a tag or a\n * commit sha instead. The admin portal takes the URL and the ref as separate\n * inputs and assembles a canonical string, so this only constrains\n * hand-edited settings.\n */\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { PackageIdentity, ParsedSource } from \"./types.js\";\n\nconst PROTOCOL_PREFIXES = [\"https://\", \"http://\", \"ssh://\", \"git://\", \"file://\"];\nconst SCP_LIKE = /^[^@/\\s]+@[^:/\\s]+:/;\n\n/**\n * Whether a source string spells a git source (vs a local path) — the one\n * home of the prefix rule. Classification only; `parseSource` still owns\n * validation and error messages.\n */\nexport function isGitSourceString(source: string): boolean {\n const locator = source.trim();\n return (\n locator.startsWith(\"github:\") ||\n locator.startsWith(\"git:\") ||\n isProtocolUrl(locator) ||\n SCP_LIKE.test(locator)\n );\n}\n\n/**\n * Parse a source string. Throws with a user-facing message rather than\n * returning undefined: every caller (portal, settings load, CLI) needs to tell\n * the human what was wrong with what they typed.\n */\nexport function parseSource(source: string): ParsedSource {\n const trimmed = source.trim();\n if (!trimmed) throw new Error(\"Package source is empty\");\n\n const { rest: withoutSubpath, subpath } = splitSubpath(trimmed);\n const { rest: locator, ref } = splitRef(withoutSubpath);\n\n if (locator.startsWith(\"github:\")) {\n const repo = stripGitSuffix(locator.slice(\"github:\".length).replace(/^\\/+/, \"\"));\n if (!repo.includes(\"/\")) {\n throw new Error(`github: source must be owner/repo, got ${JSON.stringify(locator)}`);\n }\n return git(`https://github.com/${repo}.git`, ref, subpath);\n }\n\n if (locator.startsWith(\"git:\")) {\n const inner = locator.slice(\"git:\".length);\n if (isProtocolUrl(inner) || SCP_LIKE.test(inner)) return git(inner, ref, subpath);\n // Shorthand: host/owner/repo — only meaningful with the git: prefix,\n // since bare host/owner/repo is ambiguous with a relative path.\n if (!inner.includes(\"/\")) {\n throw new Error(`git: source must include a path, got ${JSON.stringify(locator)}`);\n }\n return git(`https://${stripGitSuffix(inner)}.git`, ref, subpath);\n }\n\n if (isProtocolUrl(locator) || SCP_LIKE.test(locator)) return git(locator, ref, subpath);\n\n if (isAbsolute(locator) || locator.startsWith(\"./\") || locator.startsWith(\"../\")) {\n if (ref) throw new Error(\"A local path source cannot carry an @ref\");\n if (subpath) throw new Error(\"A local path source cannot carry a #subpath\");\n return { type: \"local\", path: resolve(locator) };\n }\n\n throw new Error(\n `Unrecognized package source ${JSON.stringify(source)}. ` +\n \"Use a git URL, github:owner/repo, git:host/owner/repo, or an absolute/relative path.\",\n );\n}\n\nfunction git(url: string, ref: string | undefined, subpath: string | undefined): ParsedSource {\n return { type: \"git\", url, ...(ref ? { ref } : {}), ...(subpath ? { subpath } : {}) };\n}\n\nfunction isProtocolUrl(value: string): boolean {\n return PROTOCOL_PREFIXES.some((prefix) => value.startsWith(prefix));\n}\n\nfunction stripGitSuffix(value: string): string {\n return value.replace(/\\.git$/, \"\").replace(/\\/+$/, \"\");\n}\n\nfunction splitSubpath(source: string): { rest: string; subpath?: string } {\n const hash = source.indexOf(\"#\");\n if (hash === -1) return { rest: source };\n const subpath = source.slice(hash + 1).trim();\n if (!subpath) return { rest: source.slice(0, hash) };\n assertSafeRelativePath(subpath, \"#subpath\");\n return { rest: source.slice(0, hash), subpath };\n}\n\n/**\n * Split a trailing `@ref`. The `@` in `git@github.com:owner/repo` is part of\n * the authority, not a ref, so a candidate only counts when its suffix looks\n * like a bare ref (no `/`, no `:`).\n */\nfunction splitRef(source: string): { rest: string; ref?: string } {\n const at = source.lastIndexOf(\"@\");\n if (at <= 0) return { rest: source };\n const candidate = source.slice(at + 1);\n if (!candidate || candidate.includes(\"/\") || candidate.includes(\":\")) return { rest: source };\n return { rest: source.slice(0, at), ref: candidate };\n}\n\n/** Reject traversal and absolute escapes in the parts that become paths. */\nfunction assertSafeRelativePath(value: string, label: string): void {\n if (isAbsolute(value) || value.split(/[\\\\/]/).some((segment) => segment === \"..\")) {\n throw new Error(`${label} must be a relative path without '..': ${JSON.stringify(value)}`);\n }\n}\n\n/**\n * Identity of the package a source refers to — the key for deduplication and\n * for letting a conversation's copy shadow the global one.\n *\n * Deliberate choices:\n * - The ref is excluded: the same repo pinned to two refs in two scopes is one\n * package installed twice, and the narrower scope wins.\n * - The subpath is included: two extensions living at different paths in one\n * monorepo are two packages.\n * - Transport is excluded: `git@github.com:o/r`, `https://github.com/o/r.git`\n * and `ssh://git@github.com/o/r` all identify the same package, so mixing\n * SSH and HTTPS spellings across scopes still dedups.\n */\nexport function sourceIdentity(parsed: ParsedSource): PackageIdentity {\n if (parsed.type === \"local\") return `local:${parsed.path}`;\n const repo = gitRepoPath(parsed.url);\n return parsed.subpath ? `git:${repo}#${parsed.subpath}` : `git:${repo}`;\n}\n\n/**\n * Transport-independent `<host>/<path>` of a git URL, lowercased host, no\n * `.git` suffix, no credentials. It is the base of the on-disk clone layout,\n * so it must stay free of anything that is not a safe path segment.\n */\nexport function gitRepoPath(url: string): string {\n let remainder = url;\n for (const prefix of PROTOCOL_PREFIXES) {\n if (remainder.startsWith(prefix)) {\n remainder = remainder.slice(prefix.length);\n break;\n }\n }\n // Drop any credentials in the authority (`user:pass@host`, `git@host`).\n const scpMatch = /^([^@/\\s]+@)?([^:/\\s]+)[:/](.+)$/.exec(remainder);\n if (!scpMatch) return sanitizeRepoPath(stripGitSuffix(remainder));\n const host = (scpMatch[2] ?? \"\").toLowerCase();\n const path = stripGitSuffix((scpMatch[3] ?? \"\").replace(/^\\/+/, \"\"));\n return sanitizeRepoPath(`${host}/${path}`);\n}\n\n/**\n * `file://` URLs used in tests and local mirrors have no host, so the repo path\n * is an absolute filesystem path. Keep every segment filesystem-safe and drop\n * traversal, since this string becomes a directory under the state dir.\n */\nfunction sanitizeRepoPath(value: string): string {\n const segments = value\n .split(/[\\\\/]/)\n .map((segment) => segment.replace(/[^A-Za-z0-9._-]+/g, \"-\").replace(/^\\.+$/, \"\"))\n .filter((segment) => segment.length > 0);\n if (segments.length === 0) throw new Error(`Cannot derive a package path from ${value}`);\n return segments.join(\"/\");\n}\n\n/**\n * Canonical string form, used when writing settings so the stored value is\n * stable regardless of how the human spelled it.\n */\nexport function formatSource(parsed: ParsedSource): string {\n if (parsed.type === \"local\") return parsed.path;\n const ref = parsed.ref ? `@${parsed.ref}` : \"\";\n const subpath = parsed.subpath ? `#${parsed.subpath}` : \"\";\n return `${parsed.url}${ref}${subpath}`;\n}\n"]}
@@ -3,6 +3,8 @@
3
3
  * in global or conversation settings, and the string typed into the admin
4
4
  * portal. Parsing it is {@link parseSource}'s job.
5
5
  */
6
+ import type { Office } from "../office/types.js";
7
+ import type { GlobalRunnerCacheControl, OfficeAddress, RunnerCacheControl } from "../types.js";
6
8
  export type PackageSourceString = string;
7
9
  /** Scope a package belongs to. `global` spans every conversation. */
8
10
  export type PackageScope = "global" | "conversation";
@@ -67,13 +69,13 @@ export interface PackageSkillDir {
67
69
  }
68
70
  export interface ResolvePackagesOptions {
69
71
  /** Office whose packages resolve; identity and state-dir keys derive from it. */
70
- office: import("../office/types.js").Office;
72
+ office: Office;
71
73
  fetchMissing?: boolean;
72
74
  }
73
75
  export type MaterializeMode = "offline" | "fetch" | "refresh";
74
76
  export interface MaterializeOptions {
75
77
  scope: PackageScope;
76
- address?: import("../types.js").OfficeAddress;
78
+ address?: OfficeAddress;
77
79
  stateDir: string;
78
80
  mode?: MaterializeMode;
79
81
  }
@@ -92,7 +94,7 @@ export interface PackageInventory {
92
94
  conversation: PackageStatus[];
93
95
  }
94
96
  export interface PackageAdminContext extends ResolvePackagesOptions {
95
- runtime?: import("../types.js").RunnerCacheControl & import("../types.js").GlobalRunnerCacheControl;
97
+ runtime?: RunnerCacheControl & GlobalRunnerCacheControl;
96
98
  }
97
99
  export interface PackageWriteResult {
98
100
  source: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/packages/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC,qEAAqE;AACrE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,cAAc,CAAC;AAErD;;;;GAIG;AACH,UAAU,SAAS;IACjB,IAAI,EAAE,KAAK,CAAC;IACZ,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,UAAU,WAAW;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,MAAM,EAAE,OAAO,oBAAoB,EAAE,MAAM,CAAC;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,aAAa,EAAE,aAAa,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,EAAE,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAoB,SAAQ,sBAAsB;IACjE,OAAO,CAAC,EAAE,OAAO,aAAa,EAAE,kBAAkB,GAChD,OAAO,aAAa,EAAE,wBAAwB,CAAC;CAClD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/packages/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE/F,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC,qEAAqE;AACrE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,cAAc,CAAC;AAErD;;;;GAIG;AACH,UAAU,SAAS;IACjB,IAAI,EAAE,KAAK,CAAC;IACZ,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,UAAU,WAAW;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,EAAE,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAoB,SAAQ,sBAAsB;IACjE,OAAO,CAAC,EAAE,kBAAkB,GAAG,wBAAwB,CAAC;CACzD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/packages/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A package source as written by a human: the string stored in `packages[]`\n * in global or conversation settings, and the string typed into the admin\n * portal. Parsing it is {@link parseSource}'s job.\n */\nexport type PackageSourceString = string;\n\n/** Scope a package belongs to. `global` spans every conversation. */\nexport type PackageScope = \"global\" | \"conversation\";\n\n/**\n * A git source. `ref` is a tag, branch, or commit — absent means \"whatever the\n * remote's default branch points at now\", which only moves on an explicit\n * update. `subpath` addresses a package inside a larger repository.\n */\ninterface GitSource {\n type: \"git\";\n /** Clone URL handed to `git`, after shorthand expansion. */\n url: string;\n ref?: string;\n subpath?: string;\n}\n\n/**\n * A directory on the mikan host, used by reference — never copied. Editing the\n * directory is picked up by the next harness instance, which is what makes\n * host-side development of an extension bearable.\n */\ninterface LocalSource {\n type: \"local\";\n path: string;\n}\n\nexport type ParsedSource = GitSource | LocalSource;\n\n/**\n * Stable identity of a package, independent of version and of the scope it is\n * installed in. Two sources with the same identity are the same package, so\n * the conversation scope's copy can shadow the global one.\n *\n * Deliberately excludes the ref: `…/repo@v1` in global and `…/repo@v2` in a\n * conversation are one package pinned two ways, and the conversation wins.\n */\nexport type PackageIdentity = string;\n\n/** Where a materialized package's files live, plus how it got there. */\nexport interface MaterializedPackage {\n source: PackageSourceString;\n parsed: ParsedSource;\n identity: PackageIdentity;\n /**\n * Directory holding the package's files. For git this is inside the state\n * dir (a clone, plus `subpath`); for local it is the referenced path itself.\n */\n dir: string;\n scope: PackageScope;\n}\n\n/** A source that failed to materialize, reported back to whoever asked. */\nexport interface PackageError {\n source: PackageSourceString;\n message: string;\n}\n\nexport interface ResolvedPackages {\n packages: MaterializedPackage[];\n extensionDirs: string[];\n extensionRoots: string[];\n skillDirs: PackageSkillDir[];\n errors: PackageError[];\n}\n\nexport interface PackageSkillDir {\n slug: string;\n dir: string;\n}\n\nexport interface ResolvePackagesOptions {\n /** Office whose packages resolve; identity and state-dir keys derive from it. */\n office: import(\"../office/types.js\").Office;\n fetchMissing?: boolean;\n}\n\nexport type MaterializeMode = \"offline\" | \"fetch\" | \"refresh\";\n\nexport interface MaterializeOptions {\n scope: PackageScope;\n address?: import(\"../types.js\").OfficeAddress;\n stateDir: string;\n mode?: MaterializeMode;\n}\n\nexport interface PackageStatus {\n source: string;\n scope: PackageScope;\n ready: boolean;\n error?: string;\n dir?: string;\n shadowed?: boolean;\n extensions: string[];\n skills: string[];\n}\n\nexport interface PackageInventory {\n global: PackageStatus[];\n conversation: PackageStatus[];\n}\n\nexport interface PackageAdminContext extends ResolvePackagesOptions {\n runtime?: import(\"../types.js\").RunnerCacheControl &\n import(\"../types.js\").GlobalRunnerCacheControl;\n}\n\nexport interface PackageWriteResult {\n source: string;\n dir: string;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/packages/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A package source as written by a human: the string stored in `packages[]`\n * in global or conversation settings, and the string typed into the admin\n * portal. Parsing it is {@link parseSource}'s job.\n */\nimport type { Office } from \"../office/types.js\";\nimport type { GlobalRunnerCacheControl, OfficeAddress, RunnerCacheControl } from \"../types.js\";\n\nexport type PackageSourceString = string;\n\n/** Scope a package belongs to. `global` spans every conversation. */\nexport type PackageScope = \"global\" | \"conversation\";\n\n/**\n * A git source. `ref` is a tag, branch, or commit — absent means \"whatever the\n * remote's default branch points at now\", which only moves on an explicit\n * update. `subpath` addresses a package inside a larger repository.\n */\ninterface GitSource {\n type: \"git\";\n /** Clone URL handed to `git`, after shorthand expansion. */\n url: string;\n ref?: string;\n subpath?: string;\n}\n\n/**\n * A directory on the mikan host, used by reference — never copied. Editing the\n * directory is picked up by the next harness instance, which is what makes\n * host-side development of an extension bearable.\n */\ninterface LocalSource {\n type: \"local\";\n path: string;\n}\n\nexport type ParsedSource = GitSource | LocalSource;\n\n/**\n * Stable identity of a package, independent of version and of the scope it is\n * installed in. Two sources with the same identity are the same package, so\n * the conversation scope's copy can shadow the global one.\n *\n * Deliberately excludes the ref: `…/repo@v1` in global and `…/repo@v2` in a\n * conversation are one package pinned two ways, and the conversation wins.\n */\nexport type PackageIdentity = string;\n\n/** Where a materialized package's files live, plus how it got there. */\nexport interface MaterializedPackage {\n source: PackageSourceString;\n parsed: ParsedSource;\n identity: PackageIdentity;\n /**\n * Directory holding the package's files. For git this is inside the state\n * dir (a clone, plus `subpath`); for local it is the referenced path itself.\n */\n dir: string;\n scope: PackageScope;\n}\n\n/** A source that failed to materialize, reported back to whoever asked. */\nexport interface PackageError {\n source: PackageSourceString;\n message: string;\n}\n\nexport interface ResolvedPackages {\n packages: MaterializedPackage[];\n extensionDirs: string[];\n extensionRoots: string[];\n skillDirs: PackageSkillDir[];\n errors: PackageError[];\n}\n\nexport interface PackageSkillDir {\n slug: string;\n dir: string;\n}\n\nexport interface ResolvePackagesOptions {\n /** Office whose packages resolve; identity and state-dir keys derive from it. */\n office: Office;\n fetchMissing?: boolean;\n}\n\nexport type MaterializeMode = \"offline\" | \"fetch\" | \"refresh\";\n\nexport interface MaterializeOptions {\n scope: PackageScope;\n address?: OfficeAddress;\n stateDir: string;\n mode?: MaterializeMode;\n}\n\nexport interface PackageStatus {\n source: string;\n scope: PackageScope;\n ready: boolean;\n error?: string;\n dir?: string;\n shadowed?: boolean;\n extensions: string[];\n skills: string[];\n}\n\nexport interface PackageInventory {\n global: PackageStatus[];\n conversation: PackageStatus[];\n}\n\nexport interface PackageAdminContext extends ResolvePackagesOptions {\n runtime?: RunnerCacheControl & GlobalRunnerCacheControl;\n}\n\nexport interface PackageWriteResult {\n source: string;\n dir: string;\n}\n"]}
@@ -1,10 +1,10 @@
1
- import { execFile } from "child_process";
1
+ import { execFile } from "node:child_process";
2
2
  import { sanitizeIdentitySegment } from "./sandbox/identity.js";
3
- import { createHash } from "crypto";
4
- import { readFileSync, statSync } from "fs";
5
- import { promisify } from "util";
3
+ import { createHash } from "node:crypto";
4
+ import { readFileSync, statSync } from "node:fs";
5
+ import { promisify } from "node:util";
6
6
  import * as log from "./log.js";
7
- import { readEnv } from "./utils/env.js";
7
+ import { readEnv } from "./env-manifest.js";
8
8
  import { reportUserFacingError } from "./observability/sentry.js";
9
9
  const execFileAsync = promisify(execFile);
10
10
  function isDockerNotFoundError(err) {