@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.
- package/LICENSE.md +110 -0
- package/README.md +272 -0
- package/dist/.build-info.json +4 -0
- package/dist/.build-stamp.json +3 -0
- package/dist/cli/colors.d.ts +13 -0
- package/dist/cli/colors.js +37 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +221 -0
- package/dist/commands/check.d.ts +170 -0
- package/dist/commands/check.js +1227 -0
- package/dist/commands/docs.d.ts +2 -0
- package/dist/commands/docs.js +70 -0
- package/dist/commands/gc.d.ts +1 -0
- package/dist/commands/gc.js +57 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.js +699 -0
- package/dist/commands/screenshots.d.ts +7 -0
- package/dist/commands/screenshots.js +77 -0
- package/dist/commands/serve.d.ts +55 -0
- package/dist/commands/serve.js +204 -0
- package/dist/commands/status.d.ts +140 -0
- package/dist/commands/status.js +569 -0
- package/dist/commands/stop.d.ts +1 -0
- package/dist/commands/stop.js +59 -0
- package/dist/commands/tasks.d.ts +47 -0
- package/dist/commands/tasks.js +334 -0
- package/dist/commands/tunnel.d.ts +1 -0
- package/dist/commands/tunnel.js +1271 -0
- package/dist/commands/ui-harness.d.ts +53 -0
- package/dist/commands/ui-harness.js +62 -0
- package/dist/commands/ui-smoke.d.ts +6 -0
- package/dist/commands/ui-smoke.js +220 -0
- package/dist/commands/upgrade.d.ts +15 -0
- package/dist/commands/upgrade.js +188 -0
- package/dist/core/auth-store.d.ts +81 -0
- package/dist/core/auth-store.js +530 -0
- package/dist/core/auth.d.ts +75 -0
- package/dist/core/auth.js +124 -0
- package/dist/core/bootstrap.d.ts +41 -0
- package/dist/core/bootstrap.js +236 -0
- package/dist/core/build.d.ts +92 -0
- package/dist/core/build.js +249 -0
- package/dist/core/canary.d.ts +10 -0
- package/dist/core/canary.js +14 -0
- package/dist/core/check-failure-summary.d.ts +10 -0
- package/dist/core/check-failure-summary.js +34 -0
- package/dist/core/config.d.ts +160 -0
- package/dist/core/config.js +1288 -0
- package/dist/core/context-pack.d.ts +74 -0
- package/dist/core/context-pack.js +778 -0
- package/dist/core/db.d.ts +236 -0
- package/dist/core/db.js +747 -0
- package/dist/core/detect.d.ts +69 -0
- package/dist/core/detect.js +251 -0
- package/dist/core/docs.d.ts +76 -0
- package/dist/core/docs.js +225 -0
- package/dist/core/frontmatter.d.ts +29 -0
- package/dist/core/frontmatter.js +215 -0
- package/dist/core/git.d.ts +505 -0
- package/dist/core/git.js +1453 -0
- package/dist/core/indexer.d.ts +33 -0
- package/dist/core/indexer.js +282 -0
- package/dist/core/input.d.ts +66 -0
- package/dist/core/input.js +222 -0
- package/dist/core/logger.d.ts +70 -0
- package/dist/core/logger.js +138 -0
- package/dist/core/models.d.ts +45 -0
- package/dist/core/models.js +291 -0
- package/dist/core/net-probe.d.ts +4 -0
- package/dist/core/net-probe.js +20 -0
- package/dist/core/providers/deepinfra.d.ts +23 -0
- package/dist/core/providers/deepinfra.js +44 -0
- package/dist/core/providers/index.d.ts +24 -0
- package/dist/core/providers/index.js +59 -0
- package/dist/core/providers/openrouter.d.ts +28 -0
- package/dist/core/providers/openrouter.js +82 -0
- package/dist/core/providers/spend.d.ts +86 -0
- package/dist/core/providers/spend.js +286 -0
- package/dist/core/providers/types.d.ts +56 -0
- package/dist/core/providers/types.js +39 -0
- package/dist/core/repoos.d.ts +59 -0
- package/dist/core/repoos.js +221 -0
- package/dist/core/runtime.d.ts +35 -0
- package/dist/core/runtime.js +167 -0
- package/dist/core/skills-registry.d.ts +39 -0
- package/dist/core/skills-registry.js +148 -0
- package/dist/core/skills-registry.test.d.ts +1 -0
- package/dist/core/skills-registry.test.js +52 -0
- package/dist/core/sysmem.d.ts +7 -0
- package/dist/core/sysmem.js +55 -0
- package/dist/core/tailscale.d.ts +2 -0
- package/dist/core/tailscale.js +19 -0
- package/dist/core/task.d.ts +53 -0
- package/dist/core/task.js +310 -0
- package/dist/core/toml-line.d.ts +20 -0
- package/dist/core/toml-line.js +52 -0
- package/dist/core/toml-validate.d.ts +44 -0
- package/dist/core/toml-validate.js +335 -0
- package/dist/core/tunnel-assistant.d.ts +30 -0
- package/dist/core/tunnel-assistant.js +65 -0
- package/dist/core/tunnel-registry.d.ts +96 -0
- package/dist/core/tunnel-registry.js +267 -0
- package/dist/core/tunnel-registry.test.d.ts +1 -0
- package/dist/core/tunnel-registry.test.js +309 -0
- package/dist/core/tunnel.d.ts +103 -0
- package/dist/core/tunnel.js +320 -0
- package/dist/core/types.d.ts +811 -0
- package/dist/core/types.js +27 -0
- package/dist/core/worktree-gc.d.ts +57 -0
- package/dist/core/worktree-gc.js +194 -0
- package/dist/server/__tests__/integration-job.test.d.ts +1 -0
- package/dist/server/__tests__/integration-job.test.js +129 -0
- package/dist/server/agents.d.ts +1020 -0
- package/dist/server/agents.js +4070 -0
- package/dist/server/attachments.d.ts +51 -0
- package/dist/server/attachments.js +130 -0
- package/dist/server/auto-engineering.d.ts +45 -0
- package/dist/server/auto-engineering.js +275 -0
- package/dist/server/branchless-release.d.ts +22 -0
- package/dist/server/branchless-release.js +67 -0
- package/dist/server/built-in-agents.d.ts +305 -0
- package/dist/server/built-in-agents.js +1838 -0
- package/dist/server/cto-monitor.d.ts +35 -0
- package/dist/server/cto-monitor.js +281 -0
- package/dist/server/cto.d.ts +125 -0
- package/dist/server/cto.js +590 -0
- package/dist/server/deployments.d.ts +119 -0
- package/dist/server/deployments.js +325 -0
- package/dist/server/diff-snapshot.d.ts +20 -0
- package/dist/server/diff-snapshot.js +73 -0
- package/dist/server/done.d.ts +160 -0
- package/dist/server/done.js +488 -0
- package/dist/server/freeform.d.ts +55 -0
- package/dist/server/freeform.js +179 -0
- package/dist/server/handoff.d.ts +99 -0
- package/dist/server/handoff.js +575 -0
- package/dist/server/hetzner.d.ts +45 -0
- package/dist/server/hetzner.js +117 -0
- package/dist/server/icons.d.ts +8 -0
- package/dist/server/icons.js +195 -0
- package/dist/server/integration-job.d.ts +75 -0
- package/dist/server/integration-job.js +144 -0
- package/dist/server/integration-orchestrator.d.ts +211 -0
- package/dist/server/integration-orchestrator.js +1299 -0
- package/dist/server/integration-status.d.ts +48 -0
- package/dist/server/integration-status.js +71 -0
- package/dist/server/live-index.d.ts +295 -0
- package/dist/server/live-index.js +452 -0
- package/dist/server/model-test.d.ts +20 -0
- package/dist/server/model-test.js +100 -0
- package/dist/server/ntfy.d.ts +57 -0
- package/dist/server/ntfy.js +112 -0
- package/dist/server/pm-attachments.d.ts +35 -0
- package/dist/server/pm-attachments.js +181 -0
- package/dist/server/pm-runs.d.ts +58 -0
- package/dist/server/pm-runs.js +80 -0
- package/dist/server/preview.d.ts +174 -0
- package/dist/server/preview.js +641 -0
- package/dist/server/release.d.ts +88 -0
- package/dist/server/release.js +449 -0
- package/dist/server/reload.d.ts +194 -0
- package/dist/server/reload.js +586 -0
- package/dist/server/remote-validation.d.ts +132 -0
- package/dist/server/remote-validation.js +478 -0
- package/dist/server/repo-lock.d.ts +36 -0
- package/dist/server/repo-lock.js +141 -0
- package/dist/server/review-guard.d.ts +14 -0
- package/dist/server/review-guard.js +159 -0
- package/dist/server/review.d.ts +243 -0
- package/dist/server/review.js +1211 -0
- package/dist/server/routes/agents.d.ts +6 -0
- package/dist/server/routes/agents.js +28 -0
- package/dist/server/routes/auth.d.ts +60 -0
- package/dist/server/routes/auth.js +755 -0
- package/dist/server/routes/config.d.ts +20 -0
- package/dist/server/routes/config.js +347 -0
- package/dist/server/routes/debugger.d.ts +33 -0
- package/dist/server/routes/debugger.js +360 -0
- package/dist/server/routes/deployments.d.ts +3 -0
- package/dist/server/routes/deployments.js +16 -0
- package/dist/server/routes/docs.d.ts +8 -0
- package/dist/server/routes/docs.js +135 -0
- package/dist/server/routes/helpers.d.ts +21 -0
- package/dist/server/routes/helpers.js +171 -0
- package/dist/server/routes/index.d.ts +19 -0
- package/dist/server/routes/index.js +18 -0
- package/dist/server/routes/info.d.ts +17 -0
- package/dist/server/routes/info.js +177 -0
- package/dist/server/routes/inputs.d.ts +7 -0
- package/dist/server/routes/inputs.js +125 -0
- package/dist/server/routes/model-providers.d.ts +27 -0
- package/dist/server/routes/model-providers.js +94 -0
- package/dist/server/routes/models.d.ts +3 -0
- package/dist/server/routes/models.js +36 -0
- package/dist/server/routes/notify.d.ts +2 -0
- package/dist/server/routes/notify.js +17 -0
- package/dist/server/routes/playground.d.ts +29 -0
- package/dist/server/routes/playground.js +81 -0
- package/dist/server/routes/release.d.ts +20 -0
- package/dist/server/routes/release.js +86 -0
- package/dist/server/routes/router.d.ts +12 -0
- package/dist/server/routes/router.js +32 -0
- package/dist/server/routes/skill-registry.d.ts +5 -0
- package/dist/server/routes/skill-registry.js +51 -0
- package/dist/server/routes/tasks.d.ts +58 -0
- package/dist/server/routes/tasks.js +1442 -0
- package/dist/server/routes/transcribe.d.ts +2 -0
- package/dist/server/routes/transcribe.js +124 -0
- package/dist/server/routes/types.d.ts +68 -0
- package/dist/server/routes/types.js +1 -0
- package/dist/server/routes/ui.d.ts +5 -0
- package/dist/server/routes/ui.js +81 -0
- package/dist/server/routes/utils.d.ts +3 -0
- package/dist/server/routes/utils.js +23 -0
- package/dist/server/serve-reaper.d.ts +135 -0
- package/dist/server/serve-reaper.js +491 -0
- package/dist/server/server.d.ts +49 -0
- package/dist/server/server.js +2171 -0
- package/dist/server/supervisor.d.ts +89 -0
- package/dist/server/supervisor.js +231 -0
- package/dist/server/system.d.ts +198 -0
- package/dist/server/system.js +480 -0
- package/dist/server/task-check.d.ts +45 -0
- package/dist/server/task-check.js +71 -0
- package/dist/server/task-transitions.d.ts +51 -0
- package/dist/server/task-transitions.js +78 -0
- package/dist/server/task-watchdog.d.ts +158 -0
- package/dist/server/task-watchdog.js +681 -0
- package/dist/server/test-run.d.ts +28 -0
- package/dist/server/test-run.js +81 -0
- package/dist/server/watcher.d.ts +21 -0
- package/dist/server/watcher.js +194 -0
- package/dist/server/write.d.ts +94 -0
- package/dist/server/write.js +345 -0
- package/dist/ui/assets/AgentsView-CF4wRvHh.css +1 -0
- package/dist/ui/assets/AgentsView-D-myL-kA.js +1 -0
- package/dist/ui/assets/ContextView-D3TC-RSp.css +1 -0
- package/dist/ui/assets/ContextView-DsOqAdyE.js +4 -0
- package/dist/ui/assets/DashboardView-BOhsIJqO.js +1 -0
- package/dist/ui/assets/DashboardView-Ck9o0RP2.css +1 -0
- package/dist/ui/assets/DeploymentsView--iIUVfEH.css +1 -0
- package/dist/ui/assets/DeploymentsView-DXu_FYR2.js +1 -0
- package/dist/ui/assets/InputsView-24HVbVPk.js +1 -0
- package/dist/ui/assets/InputsView-BLb7GHtx.css +1 -0
- package/dist/ui/assets/LoginView-6QlGg6cx.css +1 -0
- package/dist/ui/assets/LoginView-BqupI0Lt.js +1 -0
- package/dist/ui/assets/ReleasesView-BEG1A0YH.css +1 -0
- package/dist/ui/assets/ReleasesView-CAgMuxpe.js +3 -0
- package/dist/ui/assets/SettingsView-CA-NYSMK.css +1 -0
- package/dist/ui/assets/SettingsView-O3iZSnjg.js +3 -0
- package/dist/ui/assets/WorkView-D8Tl6qwy.js +1 -0
- package/dist/ui/assets/WorkView-DMYL2s3W.css +1 -0
- package/dist/ui/assets/abnfDiagram-VCTEODGH-J5lkSnEE.js +1 -0
- package/dist/ui/assets/arc-BHZnmhhM.js +1 -0
- package/dist/ui/assets/architecture-7GRP2DOG-pLdFt-xS.js +1 -0
- package/dist/ui/assets/architectureDiagram-5GKGNRK7-C3k89uKX.js +36 -0
- package/dist/ui/assets/array-BifhSqXX.js +1 -0
- package/dist/ui/assets/blockDiagram-I7D4REHJ-AWNoBzop.js +129 -0
- package/dist/ui/assets/button-lbikqSph.js +1 -0
- package/dist/ui/assets/c4Diagram-7LVT6UL2-DKG1D5gd.js +38 -0
- package/dist/ui/assets/channel-gA4qBv3A.js +1 -0
- package/dist/ui/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist/ui/assets/chunk-4HAMMTFA-D1YR8lF_.js +62 -0
- package/dist/ui/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/dist/ui/assets/chunk-75Z2AOVW-5GuBxfsL.js +2 -0
- package/dist/ui/assets/chunk-DU6HZSFF-DfdNNqwa.js +127 -0
- package/dist/ui/assets/chunk-F27PBJKO-BPZzinQ4.js +1 -0
- package/dist/ui/assets/chunk-FOHPRMQF-l2z4K2jD.js +161 -0
- package/dist/ui/assets/chunk-GMAD6QVW-DGWvSKj5.js +72 -0
- package/dist/ui/assets/chunk-GVQU2GXP-D6Aw75wJ.js +1 -0
- package/dist/ui/assets/chunk-IMKFNOWR-B8mMBKCW.js +231 -0
- package/dist/ui/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist/ui/assets/chunk-L3NEJ4N5-D5OJuXYE.js +1 -0
- package/dist/ui/assets/chunk-OSK3NFVY-B7r9w2UW.js +10 -0
- package/dist/ui/assets/chunk-P2QGCYS3-C74X4AQX.js +1 -0
- package/dist/ui/assets/chunk-POPQ4Y6H-C5_u1gUS.js +1 -0
- package/dist/ui/assets/chunk-PWAF6VOD-DfoTLtxn.js +1 -0
- package/dist/ui/assets/chunk-SHT3W25Y-D40m2eqz.js +168 -0
- package/dist/ui/assets/chunk-SVP7TREG-euxi0Kap.js +88 -0
- package/dist/ui/assets/chunk-TICWLB2K-fkdxngzN.js +206 -0
- package/dist/ui/assets/chunk-XXDRQBXY-DFBUG-OT.js +1 -0
- package/dist/ui/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist/ui/assets/classDiagram-ZZMXUADV-BzW8bq2P.js +1 -0
- package/dist/ui/assets/classDiagram-v2-VYDZK3BY-BzW8bq2P.js +1 -0
- package/dist/ui/assets/cose-bilkent-JH36ORCC-BTcgMon1.js +1 -0
- package/dist/ui/assets/cynefin-OW5HDTMX-B5m_COsS.js +1 -0
- package/dist/ui/assets/cynefinDiagram-5FMLGOSQ-C-AG6CGe.js +62 -0
- package/dist/ui/assets/cytoscape.esm-FBntH-9t.js +321 -0
- package/dist/ui/assets/dagre-GXQ25YYZ-DDfDnp8L.js +4 -0
- package/dist/ui/assets/dagre-PrKaheQc.js +1 -0
- package/dist/ui/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/dist/ui/assets/diagram-S7CK7UJ4-DjQZAlEY.js +30 -0
- package/dist/ui/assets/diagram-UQ7AKVKN-DAZ9yp1B.js +41 -0
- package/dist/ui/assets/diagram-VSXAHHWV-BWepUKJD.js +3 -0
- package/dist/ui/assets/diagram-VX7I27RA-EcV1J81b.js +24 -0
- package/dist/ui/assets/diagram-Z3DM3KII-Dbz7XU_K.js +24 -0
- package/dist/ui/assets/dist-DTg6UBE_.js +1 -0
- package/dist/ui/assets/ebnfDiagram-PWID7BFC-BUyQw8Mm.js +1 -0
- package/dist/ui/assets/erDiagram-RLTQ6QDP-WVf8ukKt.js +99 -0
- package/dist/ui/assets/eventmodeling-NTZA5JFV-DHqyLOAn.js +1 -0
- package/dist/ui/assets/flowDiagram-HODETNUW-CYk_ze5K.js +1 -0
- package/dist/ui/assets/ganttDiagram-EL5Y4UJY-rB4MZuB-.js +292 -0
- package/dist/ui/assets/gitGraph-4MIJSDKK-BOTWM8dY.js +1 -0
- package/dist/ui/assets/gitGraphDiagram-WWUBYQGX-eYscuhtP.js +106 -0
- package/dist/ui/assets/graphlib-DS17s2tU.js +1 -0
- package/dist/ui/assets/index-BACBfnga.css +1 -0
- package/dist/ui/assets/index-BOQ-ust6.js +26 -0
- package/dist/ui/assets/info-A6RAGUB7-_67wOORe.js +1 -0
- package/dist/ui/assets/infoDiagram-27XIBGKW-XVXbddTA.js +2 -0
- package/dist/ui/assets/init-C-OQMol4.js +1 -0
- package/dist/ui/assets/ishikawaDiagram-5VMMS53U-ClLNiEru.js +70 -0
- package/dist/ui/assets/journeyDiagram-3NMN7TZE-NRawjR6i.js +139 -0
- package/dist/ui/assets/kanban-definition-UXKFOSKX-BgSzBfIx.js +89 -0
- package/dist/ui/assets/katex-DolUETbr.js +257 -0
- package/dist/ui/assets/line-KAyfuul4.js +1 -0
- package/dist/ui/assets/linear-cCCPOpu7.js +1 -0
- package/dist/ui/assets/mermaid-parser.core-CgXZk1iN.js +7 -0
- package/dist/ui/assets/mermaid.core-BUUkChHW.js +44 -0
- package/dist/ui/assets/mindmap-definition-YA3MSWOX-Cpn7vW4r.js +96 -0
- package/dist/ui/assets/ordinal-BDEzSJ7C.js +1 -0
- package/dist/ui/assets/packet-AYTQ26CC-0lZwM-d6.js +1 -0
- package/dist/ui/assets/path-COt_16Va.js +1 -0
- package/dist/ui/assets/pegDiagram-XKGWAZYB-impy0inn.js +1 -0
- package/dist/ui/assets/pie-WAS4IAKB-CqfdGHYg.js +1 -0
- package/dist/ui/assets/pieDiagram-E7YTZNPT-CxjL4I1h.js +39 -0
- package/dist/ui/assets/quadrantDiagram-AXDQQJYC-Cjd1QMIe.js +7 -0
- package/dist/ui/assets/radar-RG4KPBEZ-CRkQIwiv.js +1 -0
- package/dist/ui/assets/railroad-74A4TZTK-i67XSWTB.js +1 -0
- package/dist/ui/assets/railroad-abnf-HS5TGJTU-Cv9m5aS3.js +1 -0
- package/dist/ui/assets/railroad-ebnf-LZEXJU2U-C5ZIn-Jh.js +1 -0
- package/dist/ui/assets/railroad-peg-WCYAUIDC-CGra9Oq-.js +1 -0
- package/dist/ui/assets/railroadDiagram-O6MQD6OU-_pK0qyaY.js +1 -0
- package/dist/ui/assets/releases-B0WNV-SY.js +1 -0
- package/dist/ui/assets/repoos-cto-square.webp +0 -0
- package/dist/ui/assets/repoos-helpful-pm-square.webp +0 -0
- package/dist/ui/assets/repoos-orchestrator-square.webp +0 -0
- package/dist/ui/assets/repoos-performance-agent-square.webp +0 -0
- package/dist/ui/assets/repoos-ross-from-friends-square.webp +0 -0
- package/dist/ui/assets/repoos-tech-debt-agent-square.webp +0 -0
- package/dist/ui/assets/requirementDiagram-BXWQKSXE-CRrFX-yw.js +84 -0
- package/dist/ui/assets/rough.esm-By172zw-.js +1 -0
- package/dist/ui/assets/sankeyDiagram-P5KCCOFB-X_xFRj9E.js +40 -0
- package/dist/ui/assets/sequenceDiagram-WJ2MYXX4-Byb49lKf.js +162 -0
- package/dist/ui/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
- package/dist/ui/assets/src-BH-TyZbA.js +1 -0
- package/dist/ui/assets/stateDiagram-D77RDMKH-CzaPrqYF.js +1 -0
- package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-BCXckz7K.js +1 -0
- package/dist/ui/assets/swimlanes-42K2YHIH-Cx_1lnqr.js +1 -0
- package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-54qsKi6A.js +8 -0
- package/dist/ui/assets/timeline-definition-24CTP7MA-B1IbZPQ-.js +120 -0
- package/dist/ui/assets/treeView-Q6P3EWNA-DFWhVE3d.js +1 -0
- package/dist/ui/assets/treemap-WGGIJYW6-BmbYPThn.js +1 -0
- package/dist/ui/assets/vendor-ui-DPm7zLxi.js +3 -0
- package/dist/ui/assets/vendor-vue-CobgyEJp.js +1 -0
- package/dist/ui/assets/vennDiagram-4TSXK5OY-Ae2AtRpt.js +34 -0
- package/dist/ui/assets/wardley-WFR3VGLG-BtD4X4tL.js +1 -0
- package/dist/ui/assets/wardleyDiagram-VM6X3IG4-B3YN2fTd.js +78 -0
- package/dist/ui/assets/xychartDiagram-S5SC5T6Z-CIzJfMKA.js +7 -0
- package/dist/ui/favicon.svg +11 -0
- package/dist/ui/index.html +49 -0
- package/dist/ui/sw.js +48 -0
- package/package.json +91 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { basename, extname, resolve, join, dirname } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { existsSync, readFileSync, statSync, readdirSync } from "node:fs";
|
|
4
|
+
import { STATUSES } from "../../core/types.js";
|
|
5
|
+
import { readBuildMeta } from "../../core/build.js";
|
|
6
|
+
export const UI_MIME = {
|
|
7
|
+
".html": "text/html; charset=utf-8",
|
|
8
|
+
".js": "application/javascript; charset=utf-8",
|
|
9
|
+
".css": "text/css; charset=utf-8",
|
|
10
|
+
".svg": "image/svg+xml; charset=utf-8",
|
|
11
|
+
".png": "image/png",
|
|
12
|
+
".webp": "image/webp",
|
|
13
|
+
".ico": "image/x-icon",
|
|
14
|
+
".json": "application/json",
|
|
15
|
+
".webmanifest": "application/manifest+json",
|
|
16
|
+
".woff": "font/woff",
|
|
17
|
+
".woff2": "font/woff2",
|
|
18
|
+
".ttf": "font/ttf",
|
|
19
|
+
".map": "application/json",
|
|
20
|
+
};
|
|
21
|
+
export function serveStaticUi(res, uiDir, urlPath) {
|
|
22
|
+
const rel = decodeURIComponent(urlPath).replace(/^\/+/, "");
|
|
23
|
+
if (rel.includes(".."))
|
|
24
|
+
return false;
|
|
25
|
+
const abs = resolve(uiDir, rel || "index.html");
|
|
26
|
+
if (!abs.startsWith(resolve(uiDir)))
|
|
27
|
+
return false;
|
|
28
|
+
if (!existsSync(abs) || !statSync(abs).isFile())
|
|
29
|
+
return false;
|
|
30
|
+
const ext = extname(abs).toLowerCase();
|
|
31
|
+
const noCache = rel === "sw.js" || rel === "manifest.webmanifest";
|
|
32
|
+
res.writeHead(200, {
|
|
33
|
+
"Content-Type": UI_MIME[ext] ?? "application/octet-stream",
|
|
34
|
+
"Cache-Control": noCache ? "no-cache" : ext === ".html" ? "no-cache" : "max-age=86400",
|
|
35
|
+
"Access-Control-Allow-Origin": "*",
|
|
36
|
+
});
|
|
37
|
+
res.end(readFileSync(abs));
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
export function safeRepoFile(root, urlPath) {
|
|
41
|
+
const rel = decodeURIComponent(urlPath.replace(/^\/+/, ""));
|
|
42
|
+
if (rel.includes(".."))
|
|
43
|
+
return null;
|
|
44
|
+
const abs = resolve(root, rel);
|
|
45
|
+
if (!abs.startsWith(resolve(root)))
|
|
46
|
+
return null;
|
|
47
|
+
if (!existsSync(abs) || !statSync(abs).isFile())
|
|
48
|
+
return null;
|
|
49
|
+
if (extname(abs) !== ".md")
|
|
50
|
+
return null;
|
|
51
|
+
return abs;
|
|
52
|
+
}
|
|
53
|
+
export function findUiDir(root) {
|
|
54
|
+
const candidates = [join(root, "dist", "ui")];
|
|
55
|
+
const here = dirname(dirname(fileURLToPath(import.meta.url))); // src/server
|
|
56
|
+
candidates.push(join(here, "ui"), join(here, "..", "..", "dist", "ui"));
|
|
57
|
+
for (const p of candidates)
|
|
58
|
+
if (existsSync(p))
|
|
59
|
+
return p;
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
export function findPackageRoot() {
|
|
63
|
+
const here = dirname(dirname(dirname(fileURLToPath(import.meta.url)))); // project root
|
|
64
|
+
if (existsSync(join(here, "package.json")))
|
|
65
|
+
return here;
|
|
66
|
+
const parent = dirname(here);
|
|
67
|
+
if (existsSync(join(parent, "package.json")))
|
|
68
|
+
return parent;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
export function loadBuildInfo() {
|
|
72
|
+
// Reads `.build-info.json` / `.build-stamp.json` relative to the running
|
|
73
|
+
// module — the only files that ship in a standalone (curl / `repoos upgrade`)
|
|
74
|
+
// install. The old package.json-only path left those installs at "unknown".
|
|
75
|
+
return readBuildMeta();
|
|
76
|
+
}
|
|
77
|
+
export function skillField(text, field) {
|
|
78
|
+
const fm = text.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
79
|
+
if (!fm)
|
|
80
|
+
return null;
|
|
81
|
+
const m = fm[1].match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
|
|
82
|
+
if (!m)
|
|
83
|
+
return null;
|
|
84
|
+
return m[1].trim().replace(/^["']|["']$/g, "");
|
|
85
|
+
}
|
|
86
|
+
export function listDocs(config) {
|
|
87
|
+
const out = [];
|
|
88
|
+
const seen = new Set();
|
|
89
|
+
const add = (abs, rel) => {
|
|
90
|
+
if (seen.has(rel) || !existsSync(abs))
|
|
91
|
+
return;
|
|
92
|
+
seen.add(rel);
|
|
93
|
+
let title = rel;
|
|
94
|
+
try {
|
|
95
|
+
const m = readFileSync(abs, "utf8").match(/^\s*#\s+(.+)$/m);
|
|
96
|
+
if (m)
|
|
97
|
+
title = m[1].trim();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
/* ignore */
|
|
101
|
+
}
|
|
102
|
+
out.push({ path: rel, title });
|
|
103
|
+
};
|
|
104
|
+
for (const name of ["AGENTS.md", "CLAUDE.md", "README.md"]) {
|
|
105
|
+
add(join(config.root, name), name);
|
|
106
|
+
}
|
|
107
|
+
const docsPath = join(config.root, config.docsDir);
|
|
108
|
+
const walk = (dir) => {
|
|
109
|
+
if (!existsSync(dir))
|
|
110
|
+
return;
|
|
111
|
+
for (const e of readdirSync(dir)) {
|
|
112
|
+
if (e.startsWith("."))
|
|
113
|
+
continue;
|
|
114
|
+
const full = join(dir, e);
|
|
115
|
+
const st = statSync(full);
|
|
116
|
+
if (st.isDirectory())
|
|
117
|
+
walk(full);
|
|
118
|
+
else if (extname(e) === ".md") {
|
|
119
|
+
const rel = full
|
|
120
|
+
.slice(config.root.length + 1)
|
|
121
|
+
.split("\\")
|
|
122
|
+
.join("/");
|
|
123
|
+
add(full, rel);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
walk(docsPath);
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
export function listSkills(config) {
|
|
131
|
+
const out = [];
|
|
132
|
+
const skillsPath = join(config.root, config.skillsDir);
|
|
133
|
+
if (!existsSync(skillsPath))
|
|
134
|
+
return out;
|
|
135
|
+
for (const e of readdirSync(skillsPath)) {
|
|
136
|
+
if (e.startsWith("."))
|
|
137
|
+
continue;
|
|
138
|
+
const dir = join(skillsPath, e);
|
|
139
|
+
if (!statSync(dir).isDirectory())
|
|
140
|
+
continue;
|
|
141
|
+
const file = join(dir, "SKILL.md");
|
|
142
|
+
if (!existsSync(file))
|
|
143
|
+
continue;
|
|
144
|
+
let text = "";
|
|
145
|
+
try {
|
|
146
|
+
text = readFileSync(file, "utf8");
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
out.push({
|
|
152
|
+
path: `${config.skillsDir.split("\\").join("/")}/${e}/SKILL.md`,
|
|
153
|
+
name: skillField(text, "name") ?? e,
|
|
154
|
+
description: skillField(text, "description") ?? "",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
export function repoGuideContext(config, tasks) {
|
|
160
|
+
const counts = new Map();
|
|
161
|
+
for (const task of tasks)
|
|
162
|
+
counts.set(task.status, (counts.get(task.status) ?? 0) + 1);
|
|
163
|
+
const statusSummary = STATUSES.map((status) => `${status}: ${counts.get(status) ?? 0}`).join(", ");
|
|
164
|
+
const taskSummary = tasks
|
|
165
|
+
.map((task) => `- #${task.id} [${task.status}] ${task.title} (type: ${task.type}, priority: ${task.priority}, area: ${task.area || "unspecified"}, file: ${task.path})`)
|
|
166
|
+
.join("\n");
|
|
167
|
+
const docs = listDocs(config)
|
|
168
|
+
.map((doc) => `- ${doc.title} (${doc.path})`)
|
|
169
|
+
.join("\n");
|
|
170
|
+
return `Repository: ${basename(config.root)}\nRoot: ${config.root}\nTask counts: ${statusSummary}\n\nTasks:\n${taskSummary || "- none"}\n\nContext documents:\n${docs || "- none"}`;
|
|
171
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from "./agents.js";
|
|
2
|
+
export * from "./config.js";
|
|
3
|
+
export * from "./docs.js";
|
|
4
|
+
export * from "./inputs.js";
|
|
5
|
+
export * from "./models.js";
|
|
6
|
+
export * from "./model-providers.js";
|
|
7
|
+
export * from "./playground.js";
|
|
8
|
+
export * from "./tasks.js";
|
|
9
|
+
export * from "./ui.js";
|
|
10
|
+
export * from "./utils.js";
|
|
11
|
+
export * from "./info.js";
|
|
12
|
+
export * from "./debugger.js";
|
|
13
|
+
export * from "./notify.js";
|
|
14
|
+
export * from "./transcribe.js";
|
|
15
|
+
export * from "./auth.js";
|
|
16
|
+
export * from "./skill-registry.js";
|
|
17
|
+
export { type RouteContext, type RouteHandler, type Route, type SyncResult } from "./types.js";
|
|
18
|
+
export { Router } from "./router.js";
|
|
19
|
+
export * from "./helpers.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export * from "./agents.js";
|
|
2
|
+
export * from "./config.js";
|
|
3
|
+
export * from "./docs.js";
|
|
4
|
+
export * from "./inputs.js";
|
|
5
|
+
export * from "./models.js";
|
|
6
|
+
export * from "./model-providers.js";
|
|
7
|
+
export * from "./playground.js";
|
|
8
|
+
export * from "./tasks.js";
|
|
9
|
+
export * from "./ui.js";
|
|
10
|
+
export * from "./utils.js";
|
|
11
|
+
export * from "./info.js";
|
|
12
|
+
export * from "./debugger.js";
|
|
13
|
+
export * from "./notify.js";
|
|
14
|
+
export * from "./transcribe.js";
|
|
15
|
+
export * from "./auth.js";
|
|
16
|
+
export * from "./skill-registry.js";
|
|
17
|
+
export { Router } from "./router.js";
|
|
18
|
+
export * from "./helpers.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RouteHandler } from "./types.js";
|
|
2
|
+
export declare function initInfoHandlers(hash: string, tunnelFn: (root: string, port?: number) => Promise<any>): void;
|
|
3
|
+
export declare const health: RouteHandler;
|
|
4
|
+
export declare const restart: RouteHandler;
|
|
5
|
+
export declare const getCounts: RouteHandler;
|
|
6
|
+
export declare const getIndex: RouteHandler;
|
|
7
|
+
/** Lightweight board endpoint — returns only the fields TaskCard.vue needs. */
|
|
8
|
+
export declare const getBoard: RouteHandler;
|
|
9
|
+
export declare const getDocs: RouteHandler;
|
|
10
|
+
export declare const getSkills: RouteHandler;
|
|
11
|
+
export declare const getSystem: RouteHandler;
|
|
12
|
+
export declare const getTunnelStatus: RouteHandler;
|
|
13
|
+
export declare const getChat: RouteHandler;
|
|
14
|
+
export declare const sendChatMessage: RouteHandler;
|
|
15
|
+
/** Interrupt a running RepoOS guide (Ross) response. Idempotent. */
|
|
16
|
+
export declare const interruptChatMessage: RouteHandler;
|
|
17
|
+
export declare const getSystemLogs: RouteHandler;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { json, readBody } from "./utils.js";
|
|
3
|
+
import { loadBuildInfo, listDocs, listSkills, repoGuideContext } from "./helpers.js";
|
|
4
|
+
import { sampleSystem } from "../system.js";
|
|
5
|
+
import { resolveRepoGuide, REPO_GUIDE_SESSION_ID } from "../agents.js";
|
|
6
|
+
import { withPmWorking } from "../pm-runs.js";
|
|
7
|
+
import { previewTargetOptions } from "../preview.js";
|
|
8
|
+
import { CANARY_COUNTER } from "../../core/canary.js";
|
|
9
|
+
// These will be passed via context in server.ts during integration
|
|
10
|
+
let loadedHash;
|
|
11
|
+
let tunnelReadinessFn;
|
|
12
|
+
export function initInfoHandlers(hash, tunnelFn) {
|
|
13
|
+
loadedHash = hash;
|
|
14
|
+
tunnelReadinessFn = tunnelFn;
|
|
15
|
+
}
|
|
16
|
+
export const health = (ctx, req, res) => {
|
|
17
|
+
const { index } = ctx;
|
|
18
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
19
|
+
const snap = index.snapshot();
|
|
20
|
+
const build = loadBuildInfo();
|
|
21
|
+
const secret = process.env.REPOOS_RELOAD_SECRET;
|
|
22
|
+
const handshake = typeof secret === "string" && secret !== "" && url.searchParams.get("reload") === secret;
|
|
23
|
+
// A build parked by a close-out (0143). Exposing it on /api/health gives a
|
|
24
|
+
// (re)connecting UI a reliable reconcile path that does not depend on the
|
|
25
|
+
// one-shot build.available SSE event arriving while it was connected.
|
|
26
|
+
const parked = ctx.reload?.buildAvailable ?? null;
|
|
27
|
+
return json(res, 200, {
|
|
28
|
+
ok: true,
|
|
29
|
+
root: ctx.config.root,
|
|
30
|
+
taskCount: snap.taskCount,
|
|
31
|
+
workDir: ctx.config.workDir,
|
|
32
|
+
version: build.version,
|
|
33
|
+
buildAt: build.buildAt,
|
|
34
|
+
buildHash: loadedHash,
|
|
35
|
+
buildAvailableHash: parked?.hash ?? null,
|
|
36
|
+
buildAvailableAt: parked?.buildAt ?? null,
|
|
37
|
+
// ISO start time of this serve process, derived from process.uptime(). Lets
|
|
38
|
+
// `repoos status` render uptime from /api/health when the serve lockfile is
|
|
39
|
+
// thin (missing startedAt) — the lockfile stays the primary source.
|
|
40
|
+
serverStartedAt: new Date(Date.now() - process.uptime() * 1000).toISOString(),
|
|
41
|
+
isPreviewBuild: process.env.REPOOS_PREVIEW_CHILD === "1",
|
|
42
|
+
canaryCounter: CANARY_COUNTER,
|
|
43
|
+
...(handshake ? { reloadHandshake: true } : {}),
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
export const restart = (ctx, _req, res) => {
|
|
47
|
+
const reload = ctx.reload;
|
|
48
|
+
const state = reload?.requestReload("manual restart", { manual: true }) ??
|
|
49
|
+
{
|
|
50
|
+
state: "not-stale",
|
|
51
|
+
reason: "auto-reload unavailable",
|
|
52
|
+
};
|
|
53
|
+
return json(res, 200, state);
|
|
54
|
+
};
|
|
55
|
+
export const getCounts = (ctx, _req, res) => {
|
|
56
|
+
const { index } = ctx;
|
|
57
|
+
return json(res, 200, index.counts());
|
|
58
|
+
};
|
|
59
|
+
export const getIndex = async (ctx, _req, res) => {
|
|
60
|
+
const { index, reviews, indexReady } = ctx;
|
|
61
|
+
await indexReady;
|
|
62
|
+
const snapshot = index.snapshot();
|
|
63
|
+
const withReviewStatus = (t) => ({
|
|
64
|
+
...withPmWorking(t),
|
|
65
|
+
automaticReview: {
|
|
66
|
+
running: reviews.isRunning(t.id),
|
|
67
|
+
enabled: reviews.enabled(),
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
return json(res, 200, {
|
|
71
|
+
...snapshot,
|
|
72
|
+
tasks: snapshot.tasks.map(withReviewStatus),
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
/** Lightweight board endpoint — returns only the fields TaskCard.vue needs. */
|
|
76
|
+
export const getBoard = async (ctx, _req, res) => {
|
|
77
|
+
const { config, index, reviews, indexReady } = ctx;
|
|
78
|
+
// A reload handoff spawns the replacement with the listener already accepting
|
|
79
|
+
// connections while the full index build runs in the background (0285). Await
|
|
80
|
+
// boot readiness so a sharp reconnect can never be answered from a stale or
|
|
81
|
+
// partially-built index — the snap must reflect disk before it is served.
|
|
82
|
+
await indexReady;
|
|
83
|
+
const snapshot = index.boardSnapshot();
|
|
84
|
+
const withReviewStatus = (t) => ({
|
|
85
|
+
...withPmWorking(t),
|
|
86
|
+
automaticReview: {
|
|
87
|
+
running: reviews.isRunning(t.id),
|
|
88
|
+
enabled: reviews.enabled(),
|
|
89
|
+
},
|
|
90
|
+
// #0379: preview target identity/multiplicity, same as GET /api/tasks/:id.
|
|
91
|
+
previewTargets: previewTargetOptions(config, t),
|
|
92
|
+
});
|
|
93
|
+
return json(res, 200, {
|
|
94
|
+
...snapshot,
|
|
95
|
+
tasks: snapshot.tasks.map(withReviewStatus),
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
export const getDocs = (ctx, _req, res) => {
|
|
99
|
+
const { config } = ctx;
|
|
100
|
+
return json(res, 200, listDocs(config));
|
|
101
|
+
};
|
|
102
|
+
export const getSkills = (ctx, _req, res) => {
|
|
103
|
+
const { config } = ctx;
|
|
104
|
+
return json(res, 200, listSkills(config));
|
|
105
|
+
};
|
|
106
|
+
export const getSystem = (ctx, _req, res) => {
|
|
107
|
+
const { config, runner } = ctx;
|
|
108
|
+
const stats = sampleSystem({
|
|
109
|
+
serverPid: process.pid,
|
|
110
|
+
cacheDir: join(config.root, config.cacheDir),
|
|
111
|
+
runningAgents: runner.running(),
|
|
112
|
+
root: config.root,
|
|
113
|
+
});
|
|
114
|
+
return json(res, 200, stats);
|
|
115
|
+
};
|
|
116
|
+
export const getTunnelStatus = async (ctx, req, res) => {
|
|
117
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
118
|
+
const rawPort = url.searchParams.get("port");
|
|
119
|
+
const port = rawPort ? Number(rawPort) : undefined;
|
|
120
|
+
if (rawPort) {
|
|
121
|
+
if (port === undefined || !Number.isInteger(port) || port < 1 || port > 65535) {
|
|
122
|
+
return json(res, 400, { error: "port must be an integer from 1 to 65535" });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return json(res, 200, await tunnelReadinessFn(ctx.config.root, port));
|
|
126
|
+
};
|
|
127
|
+
export const getChat = (ctx, _req, res) => {
|
|
128
|
+
const { config, runner } = ctx;
|
|
129
|
+
const agent = resolveRepoGuide(config);
|
|
130
|
+
const session = runner.output(REPO_GUIDE_SESSION_ID);
|
|
131
|
+
return json(res, 200, {
|
|
132
|
+
ok: true,
|
|
133
|
+
agent,
|
|
134
|
+
enabled: Boolean(agent?.enabled),
|
|
135
|
+
lines: session?.lines ?? [],
|
|
136
|
+
running: runner.isRunning(REPO_GUIDE_SESSION_ID),
|
|
137
|
+
stats: runner.stats(REPO_GUIDE_SESSION_ID),
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
export const sendChatMessage = async (ctx, req, res) => {
|
|
141
|
+
const { config, index, runner } = ctx;
|
|
142
|
+
const agent = resolveRepoGuide(config);
|
|
143
|
+
if (!agent) {
|
|
144
|
+
return json(res, 400, {
|
|
145
|
+
error: "Ross is disabled — enable it on the Agents page to chat",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const body = (await readBody(req));
|
|
149
|
+
const text = typeof body?.text === "string" ? body.text.trim() : "";
|
|
150
|
+
if (!text)
|
|
151
|
+
return json(res, 400, { error: "message text is required" });
|
|
152
|
+
const context = repoGuideContext(config, index.getTasks());
|
|
153
|
+
const existing = runner.output(REPO_GUIDE_SESSION_ID);
|
|
154
|
+
const result = existing
|
|
155
|
+
? runner.send(REPO_GUIDE_SESSION_ID, text, agent, {
|
|
156
|
+
resumePreamble: `Updated repository context:\n${context}`,
|
|
157
|
+
})
|
|
158
|
+
: runner.startChat(REPO_GUIDE_SESSION_ID, text, agent, context);
|
|
159
|
+
if (!result.ok && result.busy) {
|
|
160
|
+
return json(res, 409, { error: result.reason ?? "Ross is busy" });
|
|
161
|
+
}
|
|
162
|
+
if (!result.ok) {
|
|
163
|
+
return json(res, 400, { error: result.reason ?? "could not send message" });
|
|
164
|
+
}
|
|
165
|
+
return json(res, 200, { ok: true });
|
|
166
|
+
};
|
|
167
|
+
/** Interrupt a running RepoOS guide (Ross) response. Idempotent. */
|
|
168
|
+
export const interruptChatMessage = (ctx, _req, res) => {
|
|
169
|
+
const result = ctx.runner.interrupt(REPO_GUIDE_SESSION_ID);
|
|
170
|
+
return json(res, 200, { ok: true, ...result });
|
|
171
|
+
};
|
|
172
|
+
export const getSystemLogs = (ctx, _req, res) => {
|
|
173
|
+
const { logger } = ctx;
|
|
174
|
+
const limit = 1000;
|
|
175
|
+
const logs = logger.getSystemLogs(limit);
|
|
176
|
+
return json(res, 200, { ok: true, logs });
|
|
177
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RouteHandler } from "./types.js";
|
|
2
|
+
export declare const getInputs: RouteHandler;
|
|
3
|
+
export declare const postInput: RouteHandler;
|
|
4
|
+
export declare const patchInput: RouteHandler;
|
|
5
|
+
export declare const postResolveInput: RouteHandler;
|
|
6
|
+
export declare const uploadInputAttachment: RouteHandler;
|
|
7
|
+
export declare const getInputAttachment: RouteHandler;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { json, readBody } from "./utils.js";
|
|
3
|
+
import { createInput, enrichInput, listInputs, readInputAttachment, resolveInput, saveInputAttachment, updateInput, } from "../../core/input.js";
|
|
4
|
+
import { commitTaskFile } from "../../core/git.js";
|
|
5
|
+
import { resolvePmAgent, runPrompt, recordOneShotSession } from "../agents.js";
|
|
6
|
+
import { getCurrentUser } from "./auth.js";
|
|
7
|
+
/**
|
|
8
|
+
* Commit an input's markdown file to `main`, the same fail-soft way task
|
|
9
|
+
* files are committed (`commitTaskFile` just commits one path). Only the
|
|
10
|
+
* `.md` — attachments under `inputs/.attachments/` are gitignored and served
|
|
11
|
+
* from disk, never committed.
|
|
12
|
+
*/
|
|
13
|
+
function commitInput(root, input, verb) {
|
|
14
|
+
commitTaskFile(root, join(root, input.path), `inputs(${input.id}): ${verb}`);
|
|
15
|
+
}
|
|
16
|
+
function inputPrompt(body) {
|
|
17
|
+
return [
|
|
18
|
+
"You are the RepoOS PM agent. Classify this raw human input for triage.",
|
|
19
|
+
"Return ONLY a JSON object with exactly these string fields:",
|
|
20
|
+
'{"title":"short useful title","type":"idea|question|bug|improvement|feedback|other","area":"short product area or empty string"}',
|
|
21
|
+
"Keep the title under 80 characters. Do not invent details.",
|
|
22
|
+
"",
|
|
23
|
+
body,
|
|
24
|
+
].join("\n");
|
|
25
|
+
}
|
|
26
|
+
function parseEnrichment(raw) {
|
|
27
|
+
const match = raw.match(/\{[\s\S]*\}/);
|
|
28
|
+
if (!match)
|
|
29
|
+
return {};
|
|
30
|
+
try {
|
|
31
|
+
const value = JSON.parse(match[0]);
|
|
32
|
+
return {
|
|
33
|
+
title: typeof value.title === "string" ? value.title : undefined,
|
|
34
|
+
type: typeof value.type === "string" ? value.type : undefined,
|
|
35
|
+
area: typeof value.area === "string" ? value.area : undefined,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export const getInputs = (ctx, _req, res) => json(res, 200, listInputs(ctx.config));
|
|
43
|
+
export const postInput = async (ctx, req, res) => {
|
|
44
|
+
const b = (await readBody(req)), text = typeof b.text === "string" ? b.text.trim() : "";
|
|
45
|
+
if (!text)
|
|
46
|
+
return json(res, 400, { error: "text is required" });
|
|
47
|
+
const input = createInput(ctx.config, text, typeof b.type === "string" ? b.type : "other", getCurrentUser(req, ctx.config)?.email ?? (typeof b.createdBy === "string" ? b.createdBy : ""));
|
|
48
|
+
const pm = resolvePmAgent(ctx.config);
|
|
49
|
+
if (pm) {
|
|
50
|
+
try {
|
|
51
|
+
const result = await runPrompt(pm, inputPrompt(text), { cwd: ctx.config.root });
|
|
52
|
+
recordOneShotSession(ctx.config.root, pm, result, { sessionType: "pm", taskId: null });
|
|
53
|
+
if (result.ok && result.output) {
|
|
54
|
+
const enriched = enrichInput(ctx.config, input.id, parseEnrichment(result.output));
|
|
55
|
+
commitInput(ctx.config.root, enriched, "capture");
|
|
56
|
+
return json(res, 201, enriched);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
/* raw input remains safe if enrichment fails */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
commitInput(ctx.config.root, input, "capture");
|
|
64
|
+
return json(res, 201, input);
|
|
65
|
+
};
|
|
66
|
+
export const patchInput = async (ctx, req, res, p) => {
|
|
67
|
+
const b = (await readBody(req));
|
|
68
|
+
if (!["new", "reviewing", "processed"].includes(String(b.status)))
|
|
69
|
+
return json(res, 400, { error: "invalid status" });
|
|
70
|
+
try {
|
|
71
|
+
const updated = updateInput(ctx.config, p.param1, b.status);
|
|
72
|
+
commitInput(ctx.config.root, updated, updated.status);
|
|
73
|
+
return json(res, 200, updated);
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
return json(res, 404, { error: e.message });
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
export const postResolveInput = async (ctx, req, res, p) => {
|
|
80
|
+
const b = (await readBody(req));
|
|
81
|
+
const resolution = b.resolution;
|
|
82
|
+
if (resolution !== "task" && resolution !== "none")
|
|
83
|
+
return json(res, 400, { error: "resolution must be 'task' or 'none'" });
|
|
84
|
+
const taskId = typeof b.taskId === "string" ? b.taskId.trim() : "";
|
|
85
|
+
if (resolution === "task" && !taskId)
|
|
86
|
+
return json(res, 400, { error: "taskId is required when resolving to a task" });
|
|
87
|
+
try {
|
|
88
|
+
const updated = resolveInput(ctx.config, p.param1, resolution, resolution === "task" ? taskId : "");
|
|
89
|
+
commitInput(ctx.config.root, updated, resolution === "task" ? `resolved to task #${taskId}` : "resolved: no action");
|
|
90
|
+
return json(res, 200, updated);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
return json(res, 404, { error: e.message });
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
export const uploadInputAttachment = async (ctx, req, res, p) => {
|
|
97
|
+
const b = (await readBody(req));
|
|
98
|
+
if (typeof b.name !== "string" || typeof b.data !== "string")
|
|
99
|
+
return json(res, 400, { error: "name and data are required" });
|
|
100
|
+
try {
|
|
101
|
+
return json(res, 201, {
|
|
102
|
+
ok: true,
|
|
103
|
+
attachment: saveInputAttachment(ctx.config, p.param1, b.name, b.data),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
return json(res, 404, { error: e.message });
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
export const getInputAttachment = (ctx, _req, res, p) => {
|
|
111
|
+
try {
|
|
112
|
+
const file = readInputAttachment(ctx.config, p.param1, decodeURIComponent(p.param2));
|
|
113
|
+
res.writeHead(200, {
|
|
114
|
+
"Content-Type": file.mime,
|
|
115
|
+
"Content-Length": file.data.length,
|
|
116
|
+
"Content-Disposition": `inline; filename="${decodeURIComponent(p.param2)}"`,
|
|
117
|
+
"Access-Control-Allow-Origin": "*",
|
|
118
|
+
});
|
|
119
|
+
res.end(file.data);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
123
|
+
res.end("Not found");
|
|
124
|
+
}
|
|
125
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model providers tab routes (0327): the Agents-page "Model providers" tab's
|
|
3
|
+
* backend. Three endpoints —
|
|
4
|
+
*
|
|
5
|
+
* GET /api/model-providers static registry + per-row hasKey
|
|
6
|
+
* GET /api/model-providers/:id/usage live spend/usage for a "live" row
|
|
7
|
+
* POST /api/model-providers/:id/key save (or clear) a provider API key
|
|
8
|
+
*
|
|
9
|
+
* Keys are stored ONLY in the gitignored `.env` via `setDotEnvSecret`, under
|
|
10
|
+
* the fixed env-var names in the registry — the same env-var-secret pattern
|
|
11
|
+
* as the auth/whisper secrets. They are never written to repoos.toml, never
|
|
12
|
+
* logged, and never echoed back in any response (rows only ever see a
|
|
13
|
+
* boolean `hasKey`).
|
|
14
|
+
*/
|
|
15
|
+
import type { RouteHandler } from "./types.js";
|
|
16
|
+
import type { RepoOSConfig } from "../../core/types.js";
|
|
17
|
+
import type { ModelProviderRow } from "../../core/providers/spend.js";
|
|
18
|
+
/**
|
|
19
|
+
* The stored key for a live row, read through process.env FIRST so a save
|
|
20
|
+
* (which updates process.env in place, see `setDotEnvSecret`) is visible
|
|
21
|
+
* immediately, then the boot-time config snapshot. Empty string when unset.
|
|
22
|
+
* Exported for tests.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readProviderKey(config: RepoOSConfig, row: ModelProviderRow): string;
|
|
25
|
+
export declare const getModelProviders: RouteHandler;
|
|
26
|
+
export declare const getModelProviderUsage: RouteHandler;
|
|
27
|
+
export declare const setModelProviderKey: RouteHandler;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { json, readBody } from "./utils.js";
|
|
2
|
+
import { setDotEnvSecret } from "../../core/config.js";
|
|
3
|
+
import { MODEL_PROVIDERS, modelProviderById, fetchOpenRouterSpend, fetchOpenCodeGoUsage, } from "../../core/providers/spend.js";
|
|
4
|
+
/** Cap on pasted key length — real provider keys are far shorter. */
|
|
5
|
+
const MAX_KEY_LEN = 500;
|
|
6
|
+
/**
|
|
7
|
+
* The stored key for a live row, read through process.env FIRST so a save
|
|
8
|
+
* (which updates process.env in place, see `setDotEnvSecret`) is visible
|
|
9
|
+
* immediately, then the boot-time config snapshot. Empty string when unset.
|
|
10
|
+
* Exported for tests.
|
|
11
|
+
*/
|
|
12
|
+
export function readProviderKey(config, row) {
|
|
13
|
+
const fromEnv = row.envVar ? process.env[row.envVar] : undefined;
|
|
14
|
+
if (fromEnv)
|
|
15
|
+
return fromEnv;
|
|
16
|
+
if (row.configKey)
|
|
17
|
+
return config.modelProviders?.[row.configKey] ?? "";
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
export const getModelProviders = async (ctx, _req, res) => {
|
|
21
|
+
const providers = MODEL_PROVIDERS.map((p) => ({
|
|
22
|
+
id: p.id,
|
|
23
|
+
label: p.label,
|
|
24
|
+
kind: p.kind,
|
|
25
|
+
dashboardUrl: p.dashboardUrl,
|
|
26
|
+
note: p.note,
|
|
27
|
+
hasKey: readProviderKey(ctx.config, p).length > 0,
|
|
28
|
+
}));
|
|
29
|
+
return json(res, 200, { providers, at: new Date().toISOString() });
|
|
30
|
+
};
|
|
31
|
+
export const getModelProviderUsage = async (ctx, _req, res, params) => {
|
|
32
|
+
const row = modelProviderById(params.param1 ?? "");
|
|
33
|
+
if (!row)
|
|
34
|
+
return json(res, 404, { error: "Unknown model provider." });
|
|
35
|
+
if (row.kind !== "live") {
|
|
36
|
+
return json(res, 400, {
|
|
37
|
+
error: `${row.label} has no live usage API — it renders as a dashboard link-out.`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const apiKey = readProviderKey(ctx.config, row);
|
|
41
|
+
if (!apiKey) {
|
|
42
|
+
return json(res, 400, {
|
|
43
|
+
error: `No ${row.label} API key saved yet — paste one on its row first.`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
if (row.id === "openrouter") {
|
|
48
|
+
const spend = await fetchOpenRouterSpend(apiKey);
|
|
49
|
+
if (!spend.credits && !spend.key) {
|
|
50
|
+
return json(res, 502, {
|
|
51
|
+
error: spend.creditsError ?? spend.keyError ?? "OpenRouter request failed.",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return json(res, 200, { kind: row.id, ...spend, at: new Date().toISOString() });
|
|
55
|
+
}
|
|
56
|
+
if (row.id === "opencode-go") {
|
|
57
|
+
const usage = await fetchOpenCodeGoUsage(apiKey);
|
|
58
|
+
return json(res, 200, { kind: row.id, ...usage, at: new Date().toISOString() });
|
|
59
|
+
}
|
|
60
|
+
return json(res, 400, { error: "Unknown model provider." });
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
64
|
+
return json(res, 502, { error: reason });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
export const setModelProviderKey = async (ctx, req, res, params) => {
|
|
68
|
+
const row = modelProviderById(params.param1 ?? "");
|
|
69
|
+
if (!row)
|
|
70
|
+
return json(res, 404, { error: "Unknown model provider." });
|
|
71
|
+
if (row.kind !== "live" || !row.envVar) {
|
|
72
|
+
return json(res, 400, {
|
|
73
|
+
error: `${row.label} needs no API key — it renders as a dashboard link-out.`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const body = (await readBody(req));
|
|
77
|
+
if (typeof body.key !== "string") {
|
|
78
|
+
return json(res, 400, { error: "key must be a string." });
|
|
79
|
+
}
|
|
80
|
+
const key = body.key.trim();
|
|
81
|
+
if (key.length > MAX_KEY_LEN) {
|
|
82
|
+
return json(res, 400, { error: "That API key is too long to be valid." });
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
setDotEnvSecret(ctx.config.root, row.envVar, key);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
89
|
+
return json(res, 400, { error: `Could not save the key: ${reason}` });
|
|
90
|
+
}
|
|
91
|
+
// Deliberately no logging anywhere in this handler, and no echo of the
|
|
92
|
+
// value — the response carries only the resulting hasKey boolean.
|
|
93
|
+
return json(res, 200, { ok: true, hasKey: key.length > 0 });
|
|
94
|
+
};
|