@repo-os/repoos 0.5.45

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 (362) hide show
  1. package/LICENSE.md +110 -0
  2. package/README.md +272 -0
  3. package/dist/.build-info.json +4 -0
  4. package/dist/.build-stamp.json +3 -0
  5. package/dist/cli/colors.d.ts +13 -0
  6. package/dist/cli/colors.js +37 -0
  7. package/dist/cli/index.d.ts +2 -0
  8. package/dist/cli/index.js +221 -0
  9. package/dist/commands/check.d.ts +170 -0
  10. package/dist/commands/check.js +1227 -0
  11. package/dist/commands/docs.d.ts +2 -0
  12. package/dist/commands/docs.js +70 -0
  13. package/dist/commands/gc.d.ts +1 -0
  14. package/dist/commands/gc.js +57 -0
  15. package/dist/commands/init.d.ts +9 -0
  16. package/dist/commands/init.js +699 -0
  17. package/dist/commands/screenshots.d.ts +7 -0
  18. package/dist/commands/screenshots.js +77 -0
  19. package/dist/commands/serve.d.ts +55 -0
  20. package/dist/commands/serve.js +204 -0
  21. package/dist/commands/status.d.ts +140 -0
  22. package/dist/commands/status.js +569 -0
  23. package/dist/commands/stop.d.ts +1 -0
  24. package/dist/commands/stop.js +59 -0
  25. package/dist/commands/tasks.d.ts +47 -0
  26. package/dist/commands/tasks.js +334 -0
  27. package/dist/commands/tunnel.d.ts +1 -0
  28. package/dist/commands/tunnel.js +1271 -0
  29. package/dist/commands/ui-harness.d.ts +53 -0
  30. package/dist/commands/ui-harness.js +62 -0
  31. package/dist/commands/ui-smoke.d.ts +6 -0
  32. package/dist/commands/ui-smoke.js +220 -0
  33. package/dist/commands/upgrade.d.ts +15 -0
  34. package/dist/commands/upgrade.js +188 -0
  35. package/dist/core/auth-store.d.ts +81 -0
  36. package/dist/core/auth-store.js +530 -0
  37. package/dist/core/auth.d.ts +75 -0
  38. package/dist/core/auth.js +124 -0
  39. package/dist/core/bootstrap.d.ts +41 -0
  40. package/dist/core/bootstrap.js +236 -0
  41. package/dist/core/build.d.ts +92 -0
  42. package/dist/core/build.js +249 -0
  43. package/dist/core/canary.d.ts +10 -0
  44. package/dist/core/canary.js +14 -0
  45. package/dist/core/check-failure-summary.d.ts +10 -0
  46. package/dist/core/check-failure-summary.js +34 -0
  47. package/dist/core/config.d.ts +160 -0
  48. package/dist/core/config.js +1288 -0
  49. package/dist/core/context-pack.d.ts +74 -0
  50. package/dist/core/context-pack.js +778 -0
  51. package/dist/core/db.d.ts +236 -0
  52. package/dist/core/db.js +747 -0
  53. package/dist/core/detect.d.ts +69 -0
  54. package/dist/core/detect.js +251 -0
  55. package/dist/core/docs.d.ts +76 -0
  56. package/dist/core/docs.js +225 -0
  57. package/dist/core/frontmatter.d.ts +29 -0
  58. package/dist/core/frontmatter.js +215 -0
  59. package/dist/core/git.d.ts +505 -0
  60. package/dist/core/git.js +1453 -0
  61. package/dist/core/indexer.d.ts +33 -0
  62. package/dist/core/indexer.js +282 -0
  63. package/dist/core/input.d.ts +66 -0
  64. package/dist/core/input.js +222 -0
  65. package/dist/core/logger.d.ts +70 -0
  66. package/dist/core/logger.js +138 -0
  67. package/dist/core/models.d.ts +45 -0
  68. package/dist/core/models.js +291 -0
  69. package/dist/core/net-probe.d.ts +4 -0
  70. package/dist/core/net-probe.js +20 -0
  71. package/dist/core/providers/deepinfra.d.ts +23 -0
  72. package/dist/core/providers/deepinfra.js +44 -0
  73. package/dist/core/providers/index.d.ts +24 -0
  74. package/dist/core/providers/index.js +59 -0
  75. package/dist/core/providers/openrouter.d.ts +28 -0
  76. package/dist/core/providers/openrouter.js +82 -0
  77. package/dist/core/providers/spend.d.ts +86 -0
  78. package/dist/core/providers/spend.js +286 -0
  79. package/dist/core/providers/types.d.ts +56 -0
  80. package/dist/core/providers/types.js +39 -0
  81. package/dist/core/repoos.d.ts +59 -0
  82. package/dist/core/repoos.js +221 -0
  83. package/dist/core/runtime.d.ts +35 -0
  84. package/dist/core/runtime.js +167 -0
  85. package/dist/core/skills-registry.d.ts +39 -0
  86. package/dist/core/skills-registry.js +148 -0
  87. package/dist/core/skills-registry.test.d.ts +1 -0
  88. package/dist/core/skills-registry.test.js +52 -0
  89. package/dist/core/sysmem.d.ts +7 -0
  90. package/dist/core/sysmem.js +55 -0
  91. package/dist/core/tailscale.d.ts +2 -0
  92. package/dist/core/tailscale.js +19 -0
  93. package/dist/core/task.d.ts +53 -0
  94. package/dist/core/task.js +310 -0
  95. package/dist/core/toml-line.d.ts +20 -0
  96. package/dist/core/toml-line.js +52 -0
  97. package/dist/core/toml-validate.d.ts +44 -0
  98. package/dist/core/toml-validate.js +335 -0
  99. package/dist/core/tunnel-assistant.d.ts +30 -0
  100. package/dist/core/tunnel-assistant.js +65 -0
  101. package/dist/core/tunnel-registry.d.ts +96 -0
  102. package/dist/core/tunnel-registry.js +267 -0
  103. package/dist/core/tunnel-registry.test.d.ts +1 -0
  104. package/dist/core/tunnel-registry.test.js +309 -0
  105. package/dist/core/tunnel.d.ts +103 -0
  106. package/dist/core/tunnel.js +320 -0
  107. package/dist/core/types.d.ts +811 -0
  108. package/dist/core/types.js +27 -0
  109. package/dist/core/worktree-gc.d.ts +57 -0
  110. package/dist/core/worktree-gc.js +194 -0
  111. package/dist/server/__tests__/integration-job.test.d.ts +1 -0
  112. package/dist/server/__tests__/integration-job.test.js +129 -0
  113. package/dist/server/agents.d.ts +1020 -0
  114. package/dist/server/agents.js +4070 -0
  115. package/dist/server/attachments.d.ts +51 -0
  116. package/dist/server/attachments.js +130 -0
  117. package/dist/server/auto-engineering.d.ts +45 -0
  118. package/dist/server/auto-engineering.js +275 -0
  119. package/dist/server/branchless-release.d.ts +22 -0
  120. package/dist/server/branchless-release.js +67 -0
  121. package/dist/server/built-in-agents.d.ts +305 -0
  122. package/dist/server/built-in-agents.js +1838 -0
  123. package/dist/server/cto-monitor.d.ts +35 -0
  124. package/dist/server/cto-monitor.js +281 -0
  125. package/dist/server/cto.d.ts +125 -0
  126. package/dist/server/cto.js +590 -0
  127. package/dist/server/deployments.d.ts +119 -0
  128. package/dist/server/deployments.js +325 -0
  129. package/dist/server/diff-snapshot.d.ts +20 -0
  130. package/dist/server/diff-snapshot.js +73 -0
  131. package/dist/server/done.d.ts +160 -0
  132. package/dist/server/done.js +488 -0
  133. package/dist/server/freeform.d.ts +55 -0
  134. package/dist/server/freeform.js +179 -0
  135. package/dist/server/handoff.d.ts +99 -0
  136. package/dist/server/handoff.js +575 -0
  137. package/dist/server/hetzner.d.ts +45 -0
  138. package/dist/server/hetzner.js +117 -0
  139. package/dist/server/icons.d.ts +8 -0
  140. package/dist/server/icons.js +195 -0
  141. package/dist/server/integration-job.d.ts +75 -0
  142. package/dist/server/integration-job.js +144 -0
  143. package/dist/server/integration-orchestrator.d.ts +211 -0
  144. package/dist/server/integration-orchestrator.js +1299 -0
  145. package/dist/server/integration-status.d.ts +48 -0
  146. package/dist/server/integration-status.js +71 -0
  147. package/dist/server/live-index.d.ts +295 -0
  148. package/dist/server/live-index.js +452 -0
  149. package/dist/server/model-test.d.ts +20 -0
  150. package/dist/server/model-test.js +100 -0
  151. package/dist/server/ntfy.d.ts +57 -0
  152. package/dist/server/ntfy.js +112 -0
  153. package/dist/server/pm-attachments.d.ts +35 -0
  154. package/dist/server/pm-attachments.js +181 -0
  155. package/dist/server/pm-runs.d.ts +58 -0
  156. package/dist/server/pm-runs.js +80 -0
  157. package/dist/server/preview.d.ts +174 -0
  158. package/dist/server/preview.js +641 -0
  159. package/dist/server/release.d.ts +88 -0
  160. package/dist/server/release.js +449 -0
  161. package/dist/server/reload.d.ts +194 -0
  162. package/dist/server/reload.js +586 -0
  163. package/dist/server/remote-validation.d.ts +132 -0
  164. package/dist/server/remote-validation.js +478 -0
  165. package/dist/server/repo-lock.d.ts +36 -0
  166. package/dist/server/repo-lock.js +141 -0
  167. package/dist/server/review-guard.d.ts +14 -0
  168. package/dist/server/review-guard.js +159 -0
  169. package/dist/server/review.d.ts +243 -0
  170. package/dist/server/review.js +1211 -0
  171. package/dist/server/routes/agents.d.ts +6 -0
  172. package/dist/server/routes/agents.js +28 -0
  173. package/dist/server/routes/auth.d.ts +60 -0
  174. package/dist/server/routes/auth.js +755 -0
  175. package/dist/server/routes/config.d.ts +20 -0
  176. package/dist/server/routes/config.js +347 -0
  177. package/dist/server/routes/debugger.d.ts +33 -0
  178. package/dist/server/routes/debugger.js +360 -0
  179. package/dist/server/routes/deployments.d.ts +3 -0
  180. package/dist/server/routes/deployments.js +16 -0
  181. package/dist/server/routes/docs.d.ts +8 -0
  182. package/dist/server/routes/docs.js +135 -0
  183. package/dist/server/routes/helpers.d.ts +21 -0
  184. package/dist/server/routes/helpers.js +171 -0
  185. package/dist/server/routes/index.d.ts +19 -0
  186. package/dist/server/routes/index.js +18 -0
  187. package/dist/server/routes/info.d.ts +17 -0
  188. package/dist/server/routes/info.js +177 -0
  189. package/dist/server/routes/inputs.d.ts +7 -0
  190. package/dist/server/routes/inputs.js +125 -0
  191. package/dist/server/routes/model-providers.d.ts +27 -0
  192. package/dist/server/routes/model-providers.js +94 -0
  193. package/dist/server/routes/models.d.ts +3 -0
  194. package/dist/server/routes/models.js +36 -0
  195. package/dist/server/routes/notify.d.ts +2 -0
  196. package/dist/server/routes/notify.js +17 -0
  197. package/dist/server/routes/playground.d.ts +29 -0
  198. package/dist/server/routes/playground.js +81 -0
  199. package/dist/server/routes/release.d.ts +20 -0
  200. package/dist/server/routes/release.js +86 -0
  201. package/dist/server/routes/router.d.ts +12 -0
  202. package/dist/server/routes/router.js +32 -0
  203. package/dist/server/routes/skill-registry.d.ts +5 -0
  204. package/dist/server/routes/skill-registry.js +51 -0
  205. package/dist/server/routes/tasks.d.ts +58 -0
  206. package/dist/server/routes/tasks.js +1442 -0
  207. package/dist/server/routes/transcribe.d.ts +2 -0
  208. package/dist/server/routes/transcribe.js +124 -0
  209. package/dist/server/routes/types.d.ts +68 -0
  210. package/dist/server/routes/types.js +1 -0
  211. package/dist/server/routes/ui.d.ts +5 -0
  212. package/dist/server/routes/ui.js +81 -0
  213. package/dist/server/routes/utils.d.ts +3 -0
  214. package/dist/server/routes/utils.js +23 -0
  215. package/dist/server/serve-reaper.d.ts +135 -0
  216. package/dist/server/serve-reaper.js +491 -0
  217. package/dist/server/server.d.ts +49 -0
  218. package/dist/server/server.js +2171 -0
  219. package/dist/server/supervisor.d.ts +89 -0
  220. package/dist/server/supervisor.js +231 -0
  221. package/dist/server/system.d.ts +198 -0
  222. package/dist/server/system.js +480 -0
  223. package/dist/server/task-check.d.ts +45 -0
  224. package/dist/server/task-check.js +71 -0
  225. package/dist/server/task-transitions.d.ts +51 -0
  226. package/dist/server/task-transitions.js +78 -0
  227. package/dist/server/task-watchdog.d.ts +158 -0
  228. package/dist/server/task-watchdog.js +681 -0
  229. package/dist/server/test-run.d.ts +28 -0
  230. package/dist/server/test-run.js +81 -0
  231. package/dist/server/watcher.d.ts +21 -0
  232. package/dist/server/watcher.js +194 -0
  233. package/dist/server/write.d.ts +94 -0
  234. package/dist/server/write.js +345 -0
  235. package/dist/ui/assets/AgentsView-CF4wRvHh.css +1 -0
  236. package/dist/ui/assets/AgentsView-D-myL-kA.js +1 -0
  237. package/dist/ui/assets/ContextView-D3TC-RSp.css +1 -0
  238. package/dist/ui/assets/ContextView-DsOqAdyE.js +4 -0
  239. package/dist/ui/assets/DashboardView-BOhsIJqO.js +1 -0
  240. package/dist/ui/assets/DashboardView-Ck9o0RP2.css +1 -0
  241. package/dist/ui/assets/DeploymentsView--iIUVfEH.css +1 -0
  242. package/dist/ui/assets/DeploymentsView-DXu_FYR2.js +1 -0
  243. package/dist/ui/assets/InputsView-24HVbVPk.js +1 -0
  244. package/dist/ui/assets/InputsView-BLb7GHtx.css +1 -0
  245. package/dist/ui/assets/LoginView-6QlGg6cx.css +1 -0
  246. package/dist/ui/assets/LoginView-BqupI0Lt.js +1 -0
  247. package/dist/ui/assets/ReleasesView-BEG1A0YH.css +1 -0
  248. package/dist/ui/assets/ReleasesView-CAgMuxpe.js +3 -0
  249. package/dist/ui/assets/SettingsView-CA-NYSMK.css +1 -0
  250. package/dist/ui/assets/SettingsView-O3iZSnjg.js +3 -0
  251. package/dist/ui/assets/WorkView-D8Tl6qwy.js +1 -0
  252. package/dist/ui/assets/WorkView-DMYL2s3W.css +1 -0
  253. package/dist/ui/assets/abnfDiagram-VCTEODGH-J5lkSnEE.js +1 -0
  254. package/dist/ui/assets/arc-BHZnmhhM.js +1 -0
  255. package/dist/ui/assets/architecture-7GRP2DOG-pLdFt-xS.js +1 -0
  256. package/dist/ui/assets/architectureDiagram-5GKGNRK7-C3k89uKX.js +36 -0
  257. package/dist/ui/assets/array-BifhSqXX.js +1 -0
  258. package/dist/ui/assets/blockDiagram-I7D4REHJ-AWNoBzop.js +129 -0
  259. package/dist/ui/assets/button-lbikqSph.js +1 -0
  260. package/dist/ui/assets/c4Diagram-7LVT6UL2-DKG1D5gd.js +38 -0
  261. package/dist/ui/assets/channel-gA4qBv3A.js +1 -0
  262. package/dist/ui/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  263. package/dist/ui/assets/chunk-4HAMMTFA-D1YR8lF_.js +62 -0
  264. package/dist/ui/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  265. package/dist/ui/assets/chunk-75Z2AOVW-5GuBxfsL.js +2 -0
  266. package/dist/ui/assets/chunk-DU6HZSFF-DfdNNqwa.js +127 -0
  267. package/dist/ui/assets/chunk-F27PBJKO-BPZzinQ4.js +1 -0
  268. package/dist/ui/assets/chunk-FOHPRMQF-l2z4K2jD.js +161 -0
  269. package/dist/ui/assets/chunk-GMAD6QVW-DGWvSKj5.js +72 -0
  270. package/dist/ui/assets/chunk-GVQU2GXP-D6Aw75wJ.js +1 -0
  271. package/dist/ui/assets/chunk-IMKFNOWR-B8mMBKCW.js +231 -0
  272. package/dist/ui/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  273. package/dist/ui/assets/chunk-L3NEJ4N5-D5OJuXYE.js +1 -0
  274. package/dist/ui/assets/chunk-OSK3NFVY-B7r9w2UW.js +10 -0
  275. package/dist/ui/assets/chunk-P2QGCYS3-C74X4AQX.js +1 -0
  276. package/dist/ui/assets/chunk-POPQ4Y6H-C5_u1gUS.js +1 -0
  277. package/dist/ui/assets/chunk-PWAF6VOD-DfoTLtxn.js +1 -0
  278. package/dist/ui/assets/chunk-SHT3W25Y-D40m2eqz.js +168 -0
  279. package/dist/ui/assets/chunk-SVP7TREG-euxi0Kap.js +88 -0
  280. package/dist/ui/assets/chunk-TICWLB2K-fkdxngzN.js +206 -0
  281. package/dist/ui/assets/chunk-XXDRQBXY-DFBUG-OT.js +1 -0
  282. package/dist/ui/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  283. package/dist/ui/assets/classDiagram-ZZMXUADV-BzW8bq2P.js +1 -0
  284. package/dist/ui/assets/classDiagram-v2-VYDZK3BY-BzW8bq2P.js +1 -0
  285. package/dist/ui/assets/cose-bilkent-JH36ORCC-BTcgMon1.js +1 -0
  286. package/dist/ui/assets/cynefin-OW5HDTMX-B5m_COsS.js +1 -0
  287. package/dist/ui/assets/cynefinDiagram-5FMLGOSQ-C-AG6CGe.js +62 -0
  288. package/dist/ui/assets/cytoscape.esm-FBntH-9t.js +321 -0
  289. package/dist/ui/assets/dagre-GXQ25YYZ-DDfDnp8L.js +4 -0
  290. package/dist/ui/assets/dagre-PrKaheQc.js +1 -0
  291. package/dist/ui/assets/defaultLocale-BFoDCU3G.js +1 -0
  292. package/dist/ui/assets/diagram-S7CK7UJ4-DjQZAlEY.js +30 -0
  293. package/dist/ui/assets/diagram-UQ7AKVKN-DAZ9yp1B.js +41 -0
  294. package/dist/ui/assets/diagram-VSXAHHWV-BWepUKJD.js +3 -0
  295. package/dist/ui/assets/diagram-VX7I27RA-EcV1J81b.js +24 -0
  296. package/dist/ui/assets/diagram-Z3DM3KII-Dbz7XU_K.js +24 -0
  297. package/dist/ui/assets/dist-DTg6UBE_.js +1 -0
  298. package/dist/ui/assets/ebnfDiagram-PWID7BFC-BUyQw8Mm.js +1 -0
  299. package/dist/ui/assets/erDiagram-RLTQ6QDP-WVf8ukKt.js +99 -0
  300. package/dist/ui/assets/eventmodeling-NTZA5JFV-DHqyLOAn.js +1 -0
  301. package/dist/ui/assets/flowDiagram-HODETNUW-CYk_ze5K.js +1 -0
  302. package/dist/ui/assets/ganttDiagram-EL5Y4UJY-rB4MZuB-.js +292 -0
  303. package/dist/ui/assets/gitGraph-4MIJSDKK-BOTWM8dY.js +1 -0
  304. package/dist/ui/assets/gitGraphDiagram-WWUBYQGX-eYscuhtP.js +106 -0
  305. package/dist/ui/assets/graphlib-DS17s2tU.js +1 -0
  306. package/dist/ui/assets/index-BACBfnga.css +1 -0
  307. package/dist/ui/assets/index-BOQ-ust6.js +26 -0
  308. package/dist/ui/assets/info-A6RAGUB7-_67wOORe.js +1 -0
  309. package/dist/ui/assets/infoDiagram-27XIBGKW-XVXbddTA.js +2 -0
  310. package/dist/ui/assets/init-C-OQMol4.js +1 -0
  311. package/dist/ui/assets/ishikawaDiagram-5VMMS53U-ClLNiEru.js +70 -0
  312. package/dist/ui/assets/journeyDiagram-3NMN7TZE-NRawjR6i.js +139 -0
  313. package/dist/ui/assets/kanban-definition-UXKFOSKX-BgSzBfIx.js +89 -0
  314. package/dist/ui/assets/katex-DolUETbr.js +257 -0
  315. package/dist/ui/assets/line-KAyfuul4.js +1 -0
  316. package/dist/ui/assets/linear-cCCPOpu7.js +1 -0
  317. package/dist/ui/assets/mermaid-parser.core-CgXZk1iN.js +7 -0
  318. package/dist/ui/assets/mermaid.core-BUUkChHW.js +44 -0
  319. package/dist/ui/assets/mindmap-definition-YA3MSWOX-Cpn7vW4r.js +96 -0
  320. package/dist/ui/assets/ordinal-BDEzSJ7C.js +1 -0
  321. package/dist/ui/assets/packet-AYTQ26CC-0lZwM-d6.js +1 -0
  322. package/dist/ui/assets/path-COt_16Va.js +1 -0
  323. package/dist/ui/assets/pegDiagram-XKGWAZYB-impy0inn.js +1 -0
  324. package/dist/ui/assets/pie-WAS4IAKB-CqfdGHYg.js +1 -0
  325. package/dist/ui/assets/pieDiagram-E7YTZNPT-CxjL4I1h.js +39 -0
  326. package/dist/ui/assets/quadrantDiagram-AXDQQJYC-Cjd1QMIe.js +7 -0
  327. package/dist/ui/assets/radar-RG4KPBEZ-CRkQIwiv.js +1 -0
  328. package/dist/ui/assets/railroad-74A4TZTK-i67XSWTB.js +1 -0
  329. package/dist/ui/assets/railroad-abnf-HS5TGJTU-Cv9m5aS3.js +1 -0
  330. package/dist/ui/assets/railroad-ebnf-LZEXJU2U-C5ZIn-Jh.js +1 -0
  331. package/dist/ui/assets/railroad-peg-WCYAUIDC-CGra9Oq-.js +1 -0
  332. package/dist/ui/assets/railroadDiagram-O6MQD6OU-_pK0qyaY.js +1 -0
  333. package/dist/ui/assets/releases-B0WNV-SY.js +1 -0
  334. package/dist/ui/assets/repoos-cto-square.webp +0 -0
  335. package/dist/ui/assets/repoos-helpful-pm-square.webp +0 -0
  336. package/dist/ui/assets/repoos-orchestrator-square.webp +0 -0
  337. package/dist/ui/assets/repoos-performance-agent-square.webp +0 -0
  338. package/dist/ui/assets/repoos-ross-from-friends-square.webp +0 -0
  339. package/dist/ui/assets/repoos-tech-debt-agent-square.webp +0 -0
  340. package/dist/ui/assets/requirementDiagram-BXWQKSXE-CRrFX-yw.js +84 -0
  341. package/dist/ui/assets/rough.esm-By172zw-.js +1 -0
  342. package/dist/ui/assets/sankeyDiagram-P5KCCOFB-X_xFRj9E.js +40 -0
  343. package/dist/ui/assets/sequenceDiagram-WJ2MYXX4-Byb49lKf.js +162 -0
  344. package/dist/ui/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  345. package/dist/ui/assets/src-BH-TyZbA.js +1 -0
  346. package/dist/ui/assets/stateDiagram-D77RDMKH-CzaPrqYF.js +1 -0
  347. package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-BCXckz7K.js +1 -0
  348. package/dist/ui/assets/swimlanes-42K2YHIH-Cx_1lnqr.js +1 -0
  349. package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-54qsKi6A.js +8 -0
  350. package/dist/ui/assets/timeline-definition-24CTP7MA-B1IbZPQ-.js +120 -0
  351. package/dist/ui/assets/treeView-Q6P3EWNA-DFWhVE3d.js +1 -0
  352. package/dist/ui/assets/treemap-WGGIJYW6-BmbYPThn.js +1 -0
  353. package/dist/ui/assets/vendor-ui-DPm7zLxi.js +3 -0
  354. package/dist/ui/assets/vendor-vue-CobgyEJp.js +1 -0
  355. package/dist/ui/assets/vennDiagram-4TSXK5OY-Ae2AtRpt.js +34 -0
  356. package/dist/ui/assets/wardley-WFR3VGLG-BtD4X4tL.js +1 -0
  357. package/dist/ui/assets/wardleyDiagram-VM6X3IG4-B3YN2fTd.js +78 -0
  358. package/dist/ui/assets/xychartDiagram-S5SC5T6Z-CIzJfMKA.js +7 -0
  359. package/dist/ui/favicon.svg +11 -0
  360. package/dist/ui/index.html +49 -0
  361. package/dist/ui/sw.js +48 -0
  362. package/package.json +91 -0
@@ -0,0 +1,33 @@
1
+ import { type RepoIndex, type RepoOSConfig } from "./types.js";
2
+ import { type WorktreeDirtyCache } from "./git.js";
3
+ export declare function buildIndex(config: RepoOSConfig): RepoIndex;
4
+ /**
5
+ * Async counterpart of `buildIndex`. Identical result, but the per-task git
6
+ * enrichment (last commit + worktree status) runs CONCURRENTLY instead of one
7
+ * task at a time on the main thread — `buildIndex`'s synchronous git spawns
8
+ * each block the event loop for a full OS round-trip, so N tasks cost N
9
+ * serial round-trips no matter how idle the machine is. With 260+ tasks that
10
+ * was several seconds of RepoOS's slow boot on top of the redundant spawns
11
+ * fixed above (#0271 follow-up). Used by the server's startup path, which can
12
+ * let `listen()` proceed while this populates the index in the background;
13
+ * `buildIndex` remains for callers (the CLI) that want a synchronous result.
14
+ *
15
+ * `opts.fastWorktreeStatus` skips the per-worktree `git status` entirely and
16
+ * reports each task's `dirty` from the persisted cache plus its ahead count.
17
+ * The server passes this at boot and follows up with
18
+ * `LiveIndex.reconcileWorktreeStatus()` a moment later, trading a few seconds
19
+ * of a possibly-stale "uncommitted changes" dot for a fast first paint.
20
+ */
21
+ export declare function buildIndexAsync(config: RepoOSConfig, opts?: {
22
+ fastWorktreeStatus?: boolean;
23
+ }): Promise<RepoIndex>;
24
+ export declare function indexCachePath(config: RepoOSConfig): string;
25
+ /**
26
+ * Load the persisted per-branch working-tree dirtiness so a rebuild can skip
27
+ * `git status` for worktrees whose HEAD has not moved. Always safe: a missing,
28
+ * malformed, or stale file just means more `git status` calls this run.
29
+ */
30
+ export declare function readWorktreeDirtyCache(config: RepoOSConfig): WorktreeDirtyCache;
31
+ export declare function writeWorktreeDirtyCache(config: RepoOSConfig, cache: WorktreeDirtyCache): void;
32
+ export declare function writeIndexCache(config: RepoOSConfig, index: RepoIndex): void;
33
+ export declare function readIndexCache(config: RepoOSConfig): RepoIndex | null;
@@ -0,0 +1,282 @@
1
+ /**
2
+ * The indexer. Walks the work directory, parses every task file, enriches with
3
+ * best-effort git facts, sorts deterministically, and produces a RepoIndex.
4
+ *
5
+ * The index is DERIVED: it can be thrown away and rebuilt from files at any
6
+ * time. It is written to <cacheDir>/index.json purely as a cache for fast reads
7
+ * (and, later, for the Stage 2 server to serve without re-walking on every
8
+ * request).
9
+ */
10
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
11
+ import { extname, join } from "node:path";
12
+ import { STATUSES, PRIORITIES, } from "./types.js";
13
+ import { parseTask } from "./task.js";
14
+ import { parseDocument } from "./frontmatter.js";
15
+ import { isGitRepo, localBranches, lastCommitsForDir, lastCommitsForDirAsync, worktreeStatus, worktreePaths, currentBranch, emptyGitInfo, resolveWorktreeStatuses, } from "./git.js";
16
+ const INDEX_VERSION = 1;
17
+ function walkFiles(dir, exts, acc = []) {
18
+ if (!existsSync(dir))
19
+ return acc;
20
+ for (const entry of readdirSync(dir)) {
21
+ if (entry.startsWith("."))
22
+ continue;
23
+ const full = join(dir, entry);
24
+ const st = statSync(full);
25
+ if (st.isDirectory()) {
26
+ walkFiles(full, exts, acc);
27
+ }
28
+ else if (exts.includes(extname(entry))) {
29
+ acc.push(full);
30
+ }
31
+ }
32
+ return acc;
33
+ }
34
+ function priorityRank(p) {
35
+ const i = PRIORITIES.indexOf(p);
36
+ return i === -1 ? PRIORITIES.length : i;
37
+ }
38
+ function statusRank(s) {
39
+ return STATUSES.indexOf(s);
40
+ }
41
+ export function buildIndex(config) {
42
+ const workPath = join(config.root, config.workDir);
43
+ const files = walkFiles(workPath, config.taskExtensions);
44
+ const useGit = isGitRepo(config.root);
45
+ const branches = useGit ? localBranches(config.root) : new Set();
46
+ const worktrees = useGit ? worktreePaths(config.root) : new Map();
47
+ // Fetched once and passed to every `worktreeStatus` call below — otherwise
48
+ // each of the N tasks with a branch re-runs `git worktree list` and
49
+ // `git rev-parse HEAD` itself, turning a 260-task index build into
50
+ // hundreds of redundant git spawns (#0271 follow-up: this was a large
51
+ // share of RepoOS's 20-30s boot time).
52
+ const baseBranch = useGit ? currentBranch(config.root) : null;
53
+ // One `git log` pass for every task file's last commit, instead of one
54
+ // history walk per file inside the loop below (#0271 follow-up).
55
+ const lastCommits = useGit
56
+ ? lastCommitsForDir(config.root, config.workDir)
57
+ : new Map();
58
+ let skippedTaskFiles = 0;
59
+ const tasks = files.flatMap((absPath) => {
60
+ const content = readFileSync(absPath, "utf8");
61
+ // Reject files with no explicit `id` in frontmatter — the API always sets
62
+ // it, so a missing id means a human or AI agent hand-wrote the file. These
63
+ // get an opaque derived id and would silently pollute the task list.
64
+ const { data } = parseDocument(content);
65
+ if (!("id" in data)) {
66
+ skippedTaskFiles++;
67
+ return [];
68
+ }
69
+ const base = parseTask({
70
+ content,
71
+ absPath,
72
+ root: config.root,
73
+ defaultStatus: config.defaultStatus,
74
+ defaultAssignee: config.defaultAssignee,
75
+ git: emptyGitInfo(),
76
+ });
77
+ if (useGit) {
78
+ const { subject, date } = lastCommits.get(base.path) ?? {
79
+ subject: null,
80
+ date: null,
81
+ };
82
+ const wt = base.branch
83
+ ? worktreeStatus(config.root, base.branch, { worktrees, baseBranch })
84
+ : { path: null, dirty: false };
85
+ base.git = {
86
+ branchExists: base.branch ? branches.has(base.branch) : false,
87
+ worktreeExists: base.branch ? worktrees.has(base.branch) : false,
88
+ lastCommit: subject,
89
+ lastCommitAt: date,
90
+ worktreePath: wt.path,
91
+ dirty: wt.dirty,
92
+ };
93
+ }
94
+ return [base];
95
+ });
96
+ if (skippedTaskFiles > 0) {
97
+ console.warn(`[repoos] skipped ${skippedTaskFiles} task file(s) with no \`id\` in frontmatter — ` +
98
+ `use the API (POST /api/tasks or PATCH /api/tasks/:id) instead of writing work/*.md directly`);
99
+ }
100
+ tasks.sort((a, b) => {
101
+ const s = statusRank(a.status) - statusRank(b.status);
102
+ if (s !== 0)
103
+ return s;
104
+ const p = priorityRank(a.priority) - priorityRank(b.priority);
105
+ if (p !== 0)
106
+ return p;
107
+ return a.id.localeCompare(b.id);
108
+ });
109
+ const counts = Object.fromEntries(STATUSES.map((s) => [s, 0]));
110
+ for (const t of tasks)
111
+ counts[t.status]++;
112
+ return {
113
+ version: INDEX_VERSION,
114
+ generatedAt: new Date().toISOString(),
115
+ root: config.root,
116
+ taskCount: tasks.length,
117
+ tasks,
118
+ counts,
119
+ };
120
+ }
121
+ /**
122
+ * Async counterpart of `buildIndex`. Identical result, but the per-task git
123
+ * enrichment (last commit + worktree status) runs CONCURRENTLY instead of one
124
+ * task at a time on the main thread — `buildIndex`'s synchronous git spawns
125
+ * each block the event loop for a full OS round-trip, so N tasks cost N
126
+ * serial round-trips no matter how idle the machine is. With 260+ tasks that
127
+ * was several seconds of RepoOS's slow boot on top of the redundant spawns
128
+ * fixed above (#0271 follow-up). Used by the server's startup path, which can
129
+ * let `listen()` proceed while this populates the index in the background;
130
+ * `buildIndex` remains for callers (the CLI) that want a synchronous result.
131
+ *
132
+ * `opts.fastWorktreeStatus` skips the per-worktree `git status` entirely and
133
+ * reports each task's `dirty` from the persisted cache plus its ahead count.
134
+ * The server passes this at boot and follows up with
135
+ * `LiveIndex.reconcileWorktreeStatus()` a moment later, trading a few seconds
136
+ * of a possibly-stale "uncommitted changes" dot for a fast first paint.
137
+ */
138
+ export async function buildIndexAsync(config, opts = {}) {
139
+ const workPath = join(config.root, config.workDir);
140
+ const files = walkFiles(workPath, config.taskExtensions);
141
+ const useGit = isGitRepo(config.root);
142
+ const branches = useGit ? localBranches(config.root) : new Set();
143
+ const worktrees = useGit ? worktreePaths(config.root) : new Map();
144
+ const baseBranch = useGit ? currentBranch(config.root) : null;
145
+ const lastCommits = useGit
146
+ ? await lastCommitsForDirAsync(config.root, config.workDir)
147
+ : new Map();
148
+ let skippedTaskFiles = 0;
149
+ const tasks = [];
150
+ for (const absPath of files) {
151
+ const content = readFileSync(absPath, "utf8");
152
+ const { data } = parseDocument(content);
153
+ if (!("id" in data)) {
154
+ skippedTaskFiles++;
155
+ continue;
156
+ }
157
+ tasks.push(parseTask({
158
+ content,
159
+ absPath,
160
+ root: config.root,
161
+ defaultStatus: config.defaultStatus,
162
+ defaultAssignee: config.defaultAssignee,
163
+ git: emptyGitInfo(),
164
+ }));
165
+ }
166
+ if (skippedTaskFiles > 0) {
167
+ console.warn(`[repoos] skipped ${skippedTaskFiles} task file(s) with no \`id\` in frontmatter — ` +
168
+ `use the API (POST /api/tasks or PATCH /api/tasks/:id) instead of writing work/*.md directly`);
169
+ }
170
+ if (useGit) {
171
+ // Batched worktree status: two git spawns for every branch's ahead count
172
+ // and worktree HEAD, then one `git status` only per worktree whose HEAD
173
+ // moved since the last run (persisted in worktree-status.json). On a
174
+ // server reload — HEADs unchanged — this does zero `git status` calls;
175
+ // the old path ran two spawns per task branch (~2.5s at 40 branches).
176
+ const dirtyCache = readWorktreeDirtyCache(config);
177
+ const branchesWithTasks = tasks.map((t) => t.branch).filter((b) => !!b);
178
+ const { statuses, cache, changed } = await resolveWorktreeStatuses(config.root, branchesWithTasks, { baseBranch, cache: dirtyCache, skipStatus: opts.fastWorktreeStatus });
179
+ if (changed)
180
+ writeWorktreeDirtyCache(config, cache);
181
+ for (const base of tasks) {
182
+ const { subject, date } = lastCommits.get(base.path) ?? {
183
+ subject: null,
184
+ date: null,
185
+ };
186
+ const wt = (base.branch && statuses.get(base.branch)) || { path: null, dirty: false };
187
+ base.git = {
188
+ branchExists: base.branch ? branches.has(base.branch) : false,
189
+ worktreeExists: base.branch ? worktrees.has(base.branch) : false,
190
+ lastCommit: subject,
191
+ lastCommitAt: date,
192
+ worktreePath: wt.path,
193
+ dirty: wt.dirty,
194
+ };
195
+ }
196
+ }
197
+ tasks.sort((a, b) => {
198
+ const s = statusRank(a.status) - statusRank(b.status);
199
+ if (s !== 0)
200
+ return s;
201
+ const p = priorityRank(a.priority) - priorityRank(b.priority);
202
+ if (p !== 0)
203
+ return p;
204
+ return a.id.localeCompare(b.id);
205
+ });
206
+ const counts = Object.fromEntries(STATUSES.map((s) => [s, 0]));
207
+ for (const t of tasks)
208
+ counts[t.status]++;
209
+ return {
210
+ version: INDEX_VERSION,
211
+ generatedAt: new Date().toISOString(),
212
+ root: config.root,
213
+ taskCount: tasks.length,
214
+ tasks,
215
+ counts,
216
+ };
217
+ }
218
+ export function indexCachePath(config) {
219
+ return join(config.root, config.cacheDir, "index.json");
220
+ }
221
+ function worktreeDirtyCachePath(config) {
222
+ return join(config.root, config.cacheDir, "worktree-status.json");
223
+ }
224
+ /**
225
+ * Load the persisted per-branch working-tree dirtiness so a rebuild can skip
226
+ * `git status` for worktrees whose HEAD has not moved. Always safe: a missing,
227
+ * malformed, or stale file just means more `git status` calls this run.
228
+ */
229
+ export function readWorktreeDirtyCache(config) {
230
+ const cache = new Map();
231
+ try {
232
+ const raw = JSON.parse(readFileSync(worktreeDirtyCachePath(config), "utf8"));
233
+ if (raw?.version === 1 && raw.branches) {
234
+ for (const [branch, v] of Object.entries(raw.branches)) {
235
+ if (v && typeof v.head === "string" && typeof v.uncommitted === "boolean") {
236
+ cache.set(branch, { head: v.head, uncommitted: v.uncommitted });
237
+ }
238
+ }
239
+ }
240
+ }
241
+ catch {
242
+ /* no cache / bad cache -> empty */
243
+ }
244
+ return cache;
245
+ }
246
+ export function writeWorktreeDirtyCache(config, cache) {
247
+ const dir = join(config.root, config.cacheDir);
248
+ try {
249
+ if (!existsSync(dir))
250
+ mkdirSync(dir, { recursive: true });
251
+ const branches = {};
252
+ for (const [branch, v] of cache)
253
+ branches[branch] = { ...v };
254
+ writeFileSync(worktreeDirtyCachePath(config), JSON.stringify({ version: 1, branches }));
255
+ }
256
+ catch {
257
+ /* best-effort: losing the cache only costs `git status` calls next run */
258
+ }
259
+ }
260
+ export function writeIndexCache(config, index) {
261
+ const dir = join(config.root, config.cacheDir);
262
+ if (!existsSync(dir))
263
+ mkdirSync(dir, { recursive: true });
264
+ // Strip absPath/body from the cache to keep it small and portable; callers
265
+ // that need them should read the file or rebuild in-memory.
266
+ const slim = {
267
+ ...index,
268
+ tasks: index.tasks.map((t) => ({ ...t, body: "", absPath: "" })),
269
+ };
270
+ writeFileSync(indexCachePath(config), JSON.stringify(slim, null, 2));
271
+ }
272
+ export function readIndexCache(config) {
273
+ const p = indexCachePath(config);
274
+ if (!existsSync(p))
275
+ return null;
276
+ try {
277
+ return JSON.parse(readFileSync(p, "utf8"));
278
+ }
279
+ catch {
280
+ return null;
281
+ }
282
+ }
@@ -0,0 +1,66 @@
1
+ import type { RepoOSConfig } from "./types.js";
2
+ export type InputStatus = "new" | "reviewing" | "processed";
3
+ /**
4
+ * How a `processed` input was resolved: `task` means it became a task (the id
5
+ * is in `resolvedTask`), `none` means the decision was to take no action. An
6
+ * empty string means no resolution was recorded (e.g. an input moved to
7
+ * `processed` by hand before this feature existed).
8
+ */
9
+ export type InputResolution = "task" | "none";
10
+ export interface InputAttachment {
11
+ name: string;
12
+ mime: string;
13
+ size: number;
14
+ path: string;
15
+ }
16
+ export interface Input {
17
+ id: string;
18
+ /**
19
+ * Stable, zero-padded 4-digit number (`"0001"`), the input's counterpart to
20
+ * a task's `id`. Assigned once — at creation, or retroactively by
21
+ * `ensureInputNumbers` — and never reused or renumbered. Empty string only
22
+ * for an input written before this field existed and not yet migrated.
23
+ */
24
+ number: string;
25
+ title: string;
26
+ status: InputStatus;
27
+ body: string;
28
+ type: string;
29
+ area: string;
30
+ createdBy: string;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ path: string;
34
+ attachments: InputAttachment[];
35
+ resolution: InputResolution | "";
36
+ resolvedTask: string;
37
+ }
38
+ /**
39
+ * Retroactively assign a stable number to every input that lacks one, in
40
+ * place. Idempotent: numbers already present are never touched, renumbered, or
41
+ * reused, so a restart (or a repeated call) is a no-op. Existing inputs are
42
+ * numbered oldest-first (by `created_at`, then path) so the assignment is
43
+ * deterministic. Returns the inputs that were changed, for callers that want
44
+ * to commit them; an empty array means everything already had a number.
45
+ * See AGENTS.md — this touches the repo's own `inputs/*.md` data.
46
+ */
47
+ export declare function ensureInputNumbers(c: RepoOSConfig): Input[];
48
+ export declare function listInputs(c: RepoOSConfig): Input[];
49
+ export declare function createInput(c: RepoOSConfig, body: string, type?: string, createdBy?: string): Input;
50
+ export declare function updateInput(c: RepoOSConfig, id: string, status: InputStatus): Input;
51
+ /**
52
+ * Record how an input was resolved and move it to `processed`. `task` stores
53
+ * the created task's id in `resolved_task`; `none` clears it. Both keys are
54
+ * persisted in the input file so the outcome survives a reload.
55
+ */
56
+ export declare function resolveInput(c: RepoOSConfig, id: string, resolution: InputResolution, taskId?: string): Input;
57
+ export declare function enrichInput(c: RepoOSConfig, id: string, fields: {
58
+ title?: string;
59
+ type?: string;
60
+ area?: string;
61
+ }): Input;
62
+ export declare function saveInputAttachment(c: RepoOSConfig, id: string, name: string, data: string): InputAttachment;
63
+ export declare function readInputAttachment(c: RepoOSConfig, id: string, name: string): {
64
+ data: Buffer;
65
+ mime: string;
66
+ };
@@ -0,0 +1,222 @@
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { parseDocument } from "./frontmatter.js";
4
+ const q = (v) => `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
5
+ /**
6
+ * Set a frontmatter key in a file's raw content, adding it to the block if it
7
+ * isn't there yet. Assumes the content's frontmatter is the first `---` block
8
+ * (true for every input file `createInput` writes).
9
+ */
10
+ function setField(content, key, value) {
11
+ const line = `${key}: ${q(value)}`;
12
+ const re = new RegExp(`^${key}:.*$`, "m");
13
+ return re.test(content) ? content.replace(re, line) : content.replace("---\n", `---\n${line}\n`);
14
+ }
15
+ const slug = (v) => v
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9]+/g, "-")
18
+ .replace(/^-|-$/g, "")
19
+ .slice(0, 55) || "input";
20
+ const inputRoot = (c) => c.inputsDir ?? "inputs";
21
+ const dir = (c) => join(c.root, inputRoot(c));
22
+ const attDir = (c, id) => join(dir(c), ".attachments", id);
23
+ /**
24
+ * Normalize a raw frontmatter `number` to the canonical zero-padded form.
25
+ * Returns `""` for anything that isn't a plain integer (missing, empty, or
26
+ * garbage), which callers treat as "needs a number".
27
+ */
28
+ function normalizeNumber(v) {
29
+ if (typeof v === "number" && Number.isFinite(v))
30
+ return String(Math.trunc(v)).padStart(4, "0");
31
+ if (typeof v === "string" && /^\d+$/.test(v.trim()))
32
+ return v.trim().padStart(4, "0");
33
+ return "";
34
+ }
35
+ /** Next free 4-digit input number: highest existing number + 1, else `"0001"`. */
36
+ function nextInputNumber(c) {
37
+ let max = 0;
38
+ for (const i of listInputs(c)) {
39
+ const n = parseInt(i.number, 10);
40
+ if (!Number.isNaN(n) && n > max)
41
+ max = n;
42
+ }
43
+ return String(max + 1).padStart(4, "0");
44
+ }
45
+ /**
46
+ * Retroactively assign a stable number to every input that lacks one, in
47
+ * place. Idempotent: numbers already present are never touched, renumbered, or
48
+ * reused, so a restart (or a repeated call) is a no-op. Existing inputs are
49
+ * numbered oldest-first (by `created_at`, then path) so the assignment is
50
+ * deterministic. Returns the inputs that were changed, for callers that want
51
+ * to commit them; an empty array means everything already had a number.
52
+ * See AGENTS.md — this touches the repo's own `inputs/*.md` data.
53
+ */
54
+ export function ensureInputNumbers(c) {
55
+ const items = listInputs(c);
56
+ const missing = items
57
+ .filter((i) => !i.number)
58
+ .sort((a, b) => (a.createdAt || "").localeCompare(b.createdAt || "") || a.path.localeCompare(b.path));
59
+ if (!missing.length)
60
+ return [];
61
+ const used = new Set(items.map((i) => i.number).filter(Boolean));
62
+ let max = 0;
63
+ for (const n of used)
64
+ max = Math.max(max, parseInt(n, 10));
65
+ const changed = [];
66
+ for (const item of missing) {
67
+ let number = String(max + 1).padStart(4, "0");
68
+ while (used.has(number))
69
+ number = String(++max).padStart(4, "0");
70
+ used.add(number);
71
+ max = parseInt(number, 10);
72
+ const file = join(c.root, item.path);
73
+ writeFileSync(file, setField(readFileSync(file, "utf8"), "number", number));
74
+ changed.push({ ...item, number });
75
+ }
76
+ return changed;
77
+ }
78
+ export function listInputs(c) {
79
+ if (!existsSync(dir(c)))
80
+ return [];
81
+ return readdirSync(dir(c))
82
+ .filter((n) => n.endsWith(".md"))
83
+ .flatMap((name) => {
84
+ const path = join(inputRoot(c), name), parsed = parseDocument(readFileSync(join(dir(c), name), "utf8")), d = parsed.data;
85
+ if (typeof d.id !== "string")
86
+ return [];
87
+ const ad = attDir(c, d.id), attachments = existsSync(ad)
88
+ ? readdirSync(ad).map((n) => ({
89
+ name: n,
90
+ mime: mimeForName(n),
91
+ size: statSync(join(ad, n)).size,
92
+ path: join(inputRoot(c), ".attachments", d.id, n),
93
+ }))
94
+ : [];
95
+ return [
96
+ {
97
+ id: d.id,
98
+ number: normalizeNumber(d.number),
99
+ title: String(d.title ?? "Untitled input"),
100
+ status: (d.status === "reviewing" || d.status === "processed"
101
+ ? d.status
102
+ : "new"),
103
+ type: String(d.type ?? "other"),
104
+ area: String(d.area ?? ""),
105
+ createdBy: String(d.created_by ?? ""),
106
+ createdAt: String(d.created_at ?? ""),
107
+ updatedAt: String(d.updated_at ?? ""),
108
+ path,
109
+ body: parsed.body.trim(),
110
+ attachments,
111
+ resolution: (d.resolution === "task" || d.resolution === "none" ? d.resolution : ""),
112
+ resolvedTask: typeof d.resolved_task === "string" ? d.resolved_task : "",
113
+ },
114
+ ];
115
+ })
116
+ .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
117
+ }
118
+ export function createInput(c, body, type = "other", createdBy = "") {
119
+ const now = new Date().toISOString(), id = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`, number = nextInputNumber(c), title = body.trim().split(/\n/)[0].replace(/^#\s*/, "").slice(0, 100) || "Untitled input", name = `${id}-${slug(title)}.md`;
120
+ mkdirSync(dir(c), { recursive: true });
121
+ writeFileSync(join(dir(c), name), [
122
+ "---",
123
+ `id: ${q(id)}`,
124
+ `number: ${q(number)}`,
125
+ `title: ${q(title)}`,
126
+ "status: new",
127
+ `type: ${q(type)}`,
128
+ `created_by: ${q(createdBy)}`,
129
+ `created_at: ${q(now)}`,
130
+ `updated_at: ${q(now)}`,
131
+ "---",
132
+ "",
133
+ body.trim(),
134
+ "",
135
+ ].join("\n"));
136
+ return listInputs(c).find((i) => i.id === id);
137
+ }
138
+ export function updateInput(c, id, status) {
139
+ const item = listInputs(c).find((i) => i.id === id);
140
+ if (!item)
141
+ throw new Error("input not found");
142
+ const file = join(c.root, item.path);
143
+ let content = readFileSync(file, "utf8")
144
+ .replace(/^status:.*$/m, `status: ${status}`)
145
+ .replace(/^updated_at:.*$/m, `updated_at: ${q(new Date().toISOString())}`);
146
+ // A manual move out of `processed` invalidates any recorded resolution —
147
+ // leaving it behind would re-display a stale outcome if the input is later
148
+ // marked processed again without a real resolve action.
149
+ if (status !== "processed") {
150
+ content = setField(content, "resolution", "");
151
+ content = setField(content, "resolved_task", "");
152
+ }
153
+ writeFileSync(file, content);
154
+ return listInputs(c).find((i) => i.id === id);
155
+ }
156
+ /**
157
+ * Record how an input was resolved and move it to `processed`. `task` stores
158
+ * the created task's id in `resolved_task`; `none` clears it. Both keys are
159
+ * persisted in the input file so the outcome survives a reload.
160
+ */
161
+ export function resolveInput(c, id, resolution, taskId = "") {
162
+ const item = listInputs(c).find((i) => i.id === id);
163
+ if (!item)
164
+ throw new Error("input not found");
165
+ const file = join(c.root, item.path);
166
+ let content = readFileSync(file, "utf8");
167
+ content = setField(content, "status", "processed");
168
+ content = setField(content, "resolution", resolution);
169
+ content = setField(content, "resolved_task", resolution === "task" ? taskId : "");
170
+ content = content.replace(/^updated_at:.*$/m, `updated_at: ${q(new Date().toISOString())}`);
171
+ writeFileSync(file, content);
172
+ return listInputs(c).find((i) => i.id === id);
173
+ }
174
+ export function enrichInput(c, id, fields) {
175
+ const item = listInputs(c).find((i) => i.id === id);
176
+ if (!item)
177
+ throw new Error("input not found");
178
+ const file = join(c.root, item.path);
179
+ let content = readFileSync(file, "utf8");
180
+ for (const [key, value] of Object.entries(fields))
181
+ if (typeof value === "string" && value.trim()) {
182
+ content = setField(content, key, value.trim());
183
+ }
184
+ content = content.replace(/^updated_at:.*$/m, `updated_at: ${q(new Date().toISOString())}`);
185
+ writeFileSync(file, content);
186
+ return listInputs(c).find((i) => i.id === id);
187
+ }
188
+ export function saveInputAttachment(c, id, name, data) {
189
+ if (!listInputs(c).some((i) => i.id === id))
190
+ throw new Error("input not found");
191
+ const safe = name.replace(/[^a-zA-Z0-9._-]/g, "-") || "attachment", target = join(attDir(c, id), safe);
192
+ mkdirSync(attDir(c, id), { recursive: true });
193
+ writeFileSync(target, Buffer.from(data, "base64"));
194
+ return {
195
+ name: safe,
196
+ mime: mimeForName(safe),
197
+ size: Buffer.byteLength(data, "base64"),
198
+ path: join(inputRoot(c), ".attachments", id, safe),
199
+ };
200
+ }
201
+ function mimeForName(name) {
202
+ const ext = name.toLowerCase().split(".").pop();
203
+ return ({
204
+ png: "image/png",
205
+ jpg: "image/jpeg",
206
+ jpeg: "image/jpeg",
207
+ gif: "image/gif",
208
+ webp: "image/webp",
209
+ svg: "image/svg+xml",
210
+ pdf: "application/pdf",
211
+ txt: "text/plain",
212
+ md: "text/markdown",
213
+ }[ext ?? ""] ?? "application/octet-stream");
214
+ }
215
+ export function readInputAttachment(c, id, name) {
216
+ if (!/^[a-zA-Z0-9._-]+$/.test(name) || !listInputs(c).some((i) => i.id === id))
217
+ throw new Error("attachment not found");
218
+ const base = resolve(attDir(c, id)), file = resolve(join(base, name));
219
+ if (!file.startsWith(`${base}/`) || !existsSync(file))
220
+ throw new Error("attachment not found");
221
+ return { data: readFileSync(file), mime: mimeForName(name) };
222
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Centralized logging for RepoOS system, tasks, and agents.
3
+ * Logs are stored as newline-delimited JSON (NDJSON) in .repoos/logs/
4
+ * Structure:
5
+ * .repoos/logs/system.log - System-wide errors and critical events
6
+ * .repoos/logs/tasks/<id>.log - Per-task lifecycle and state changes
7
+ * .repoos/logs/agents/<id>.log - Per-agent activity and errors
8
+ */
9
+ export type LogLevel = "debug" | "info" | "warn" | "error" | "fatal";
10
+ export interface LogEntry {
11
+ timestamp: string;
12
+ level: LogLevel;
13
+ component: "system" | "task" | "agent" | "integration";
14
+ message: string;
15
+ context?: Record<string, unknown>;
16
+ }
17
+ interface LoggerOptions {
18
+ root: string;
19
+ }
20
+ /**
21
+ * Central logger for RepoOS. Creates and manages log files in .repoos/logs/
22
+ */
23
+ export declare class Logger {
24
+ private root;
25
+ private logsDir;
26
+ constructor(opts: LoggerOptions);
27
+ /**
28
+ * Log a system-wide event or error. Includes fatal crashes and critical failures.
29
+ */
30
+ system(level: LogLevel, message: string, context?: Record<string, unknown>): void;
31
+ /**
32
+ * Log a task lifecycle event: state changes, errors, transitions through pipeline.
33
+ */
34
+ task(taskId: string, level: LogLevel, message: string, context?: Record<string, unknown>): void;
35
+ /**
36
+ * Log agent activity: startup, completion, errors, output streams.
37
+ */
38
+ agent(agentId: string, level: LogLevel, message: string, context?: Record<string, unknown>): void;
39
+ /**
40
+ * Log integration/merge job activity (phase transitions, errors).
41
+ */
42
+ integration(taskId: string, level: LogLevel, message: string, context?: Record<string, unknown>): void;
43
+ /**
44
+ * Read up to `limit` log entries for a specific task or agent, in
45
+ * chronological order (oldest first). Callers that want most-recent-first
46
+ * (`getTaskLogs`, `getAgentLogs`, `getSystemLogs`) reverse the result.
47
+ */
48
+ readLogs(logPath: string, limit?: number): LogEntry[];
49
+ /**
50
+ * Get task logs in reverse order (most recent first).
51
+ */
52
+ getTaskLogs(taskId: string, limit?: number): LogEntry[];
53
+ /**
54
+ * Get agent logs in reverse order (most recent first).
55
+ */
56
+ getAgentLogs(agentId: string, limit?: number): LogEntry[];
57
+ /**
58
+ * Get system logs in reverse order (most recent first).
59
+ */
60
+ getSystemLogs(limit?: number): LogEntry[];
61
+ /**
62
+ * Write a log entry as NDJSON to the appropriate log file.
63
+ */
64
+ private write;
65
+ }
66
+ /**
67
+ * Create a logger for a repository root.
68
+ */
69
+ export declare function createLogger(root: string): Logger;
70
+ export {};