@repo-os/repoos 0.5.75 → 0.5.76
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/README.md +12 -15
- package/dist/.build-info.json +2 -2
- package/dist/.build-stamp.json +1 -1
- package/dist/cli/api-route-parity.js +2 -0
- package/dist/cli/help.js +6 -0
- package/dist/cli/index.js +7 -1
- package/dist/commands/control-api.d.ts +6 -0
- package/dist/commands/control-api.js +53 -3
- package/dist/commands/init.js +13 -13
- package/dist/commands/schedule.js +15 -1
- package/dist/commands/serve-banner.test.js +24 -1
- package/dist/commands/serve.d.ts +5 -0
- package/dist/commands/serve.js +20 -0
- package/dist/commands/status.js +2 -2
- package/dist/commands/tasks.js +1 -1
- package/dist/commands/uninstall.d.ts +3 -0
- package/dist/commands/uninstall.js +84 -21
- package/dist/core/active-task-card.d.ts +11 -0
- package/dist/core/active-task-card.js +16 -1
- package/dist/core/check-plan.js +1 -1
- package/dist/core/check-skip.js +1 -1
- package/dist/core/config.js +29 -0
- package/dist/core/cross-process-slots.js +61 -22
- package/dist/core/cto-idle-nudge.d.ts +13 -0
- package/dist/core/cto-idle-nudge.js +13 -5
- package/dist/core/engineer-crash-recovery.d.ts +32 -0
- package/dist/core/engineer-crash-recovery.js +76 -8
- package/dist/core/git.d.ts +2 -0
- package/dist/core/git.js +18 -1
- package/dist/core/indexer.js +15 -4
- package/dist/core/install-layout.d.ts +11 -0
- package/dist/core/install-layout.js +50 -0
- package/dist/core/pipeline-view.d.ts +102 -0
- package/dist/core/pipeline-view.js +164 -0
- package/dist/core/pipeline-view.test.d.ts +1 -0
- package/dist/core/pipeline-view.test.js +147 -0
- package/dist/core/schedule.d.ts +9 -0
- package/dist/core/schedule.js +20 -1
- package/dist/core/shot-fixtures.d.ts +1 -1
- package/dist/core/shot-fixtures.js +15 -0
- package/dist/core/task.d.ts +6 -2
- package/dist/core/task.js +23 -4
- package/dist/core/types.d.ts +8 -0
- package/dist/server/agents.d.ts +61 -1
- package/dist/server/agents.js +189 -12
- package/dist/server/cto-actions.d.ts +5 -0
- package/dist/server/cto-actions.js +5 -0
- package/dist/server/cto-monitor.d.ts +13 -0
- package/dist/server/cto-monitor.js +97 -34
- package/dist/server/cto.js +4 -2
- package/dist/server/decision-digest.d.ts +6 -0
- package/dist/server/decision-digest.js +3 -1
- package/dist/server/driver-brief.d.ts +12 -0
- package/dist/server/driver-brief.js +7 -1
- package/dist/server/engineer-crash-recovery.js +13 -7
- package/dist/server/handoff-status.d.ts +59 -0
- package/dist/server/handoff-status.js +226 -0
- package/dist/server/handoff.js +37 -6
- package/dist/server/release-history.d.ts +46 -0
- package/dist/server/release-history.js +123 -0
- package/dist/server/release.js +158 -13
- package/dist/server/routes/decisions.js +1 -0
- package/dist/server/routes/driver.js +1 -0
- package/dist/server/routes/tasks.d.ts +6 -0
- package/dist/server/routes/tasks.js +18 -11
- package/dist/server/routes/ui.js +1 -1
- package/dist/server/server.js +16 -2
- package/dist/server/task-watchdog.js +1 -0
- package/dist/ui/assets/{ActivityIndicator-DsxETMHH.js → ActivityIndicator-meIh-6Qi.js} +1 -1
- package/dist/ui/assets/{AgentModelControl-BLHKdXCK.js → AgentModelControl-CUkgcahC.js} +1 -1
- package/dist/ui/assets/{AgentModelModal-DEAULUdA.js → AgentModelModal-et6vEhsU.js} +1 -1
- package/dist/ui/assets/AgentsView-DBPauK5u.css +1 -0
- package/dist/ui/assets/AgentsView-DF4JpOuL.js +2 -0
- package/dist/ui/assets/{ChatAgentModelChip-C1B23ArJ.js → ChatAgentModelChip-BzJzDKcR.js} +1 -1
- package/dist/ui/assets/{ChecksView-DaRwduJB.js → ChecksView-C7N3Ypeq.js} +0 -0
- package/dist/ui/assets/{ConfirmDialog-Dwn2G-I8.js → ConfirmDialog-C-nDmuId.js} +1 -1
- package/dist/ui/assets/ContextView-BZdavSqS.js +4 -0
- package/dist/ui/assets/DashboardView-OFLi1McO.js +1 -0
- package/dist/ui/assets/{DeleteConfirmDialog-CHkMTvmt.js → DeleteConfirmDialog-CZ-PtFd3.js} +1 -1
- package/dist/ui/assets/{DeploymentsView-DiB0gR1F.js → DeploymentsView-BvFWskO3.js} +1 -1
- package/dist/ui/assets/{DevView-B-32GGYO.js → DevView-DKXpK5Qm.js} +2 -2
- package/dist/ui/assets/{DiffView-DOftUGZx.js → DiffView-Br-vTJ0v.js} +2 -2
- package/dist/ui/assets/{FailedTestsList-C_9Floyr.js → FailedTestsList-DoNaF-o9.js} +1 -1
- package/dist/ui/assets/InputsView-KeayUEJY.js +1 -0
- package/dist/ui/assets/{LoginView-CcDGWaF3.js → LoginView-CvXpXpGP.js} +1 -1
- package/dist/ui/assets/{PageSkeleton-DRgDMfth.js → PageSkeleton-DJRKj5JK.js} +1 -1
- package/dist/ui/assets/{ReleasesView-Sxyylk3a.js → ReleasesView-9CdkP52G.js} +2 -2
- package/dist/ui/assets/SecretsView-BwDra-GT.js +1 -0
- package/dist/ui/assets/{SettingsView-T6midXQa.js → SettingsView-DNCRJx13.js} +3 -3
- package/dist/ui/assets/StoriesView-DEihGJ88.css +1 -0
- package/dist/ui/assets/StoriesView-to9fS2F0.js +1 -0
- package/dist/ui/assets/{VoiceDictate-D97LIVNB.js → VoiceDictate-CaVNQ8T-.js} +2 -2
- package/dist/ui/assets/WorkView-C7qnLKcz.css +1 -0
- package/dist/ui/assets/WorkView-D9GE8twS.js +2 -0
- package/dist/ui/assets/{abnfDiagram-VCTEODGH-B0BRuj2x.js → abnfDiagram-VCTEODGH-BI749mHF.js} +1 -1
- package/dist/ui/assets/{architectureDiagram-5GKGNRK7-ZfY0-Gdw.js → architectureDiagram-5GKGNRK7-CtGA7LVO.js} +1 -1
- package/dist/ui/assets/{blockDiagram-I7D4REHJ-C-J_DWun.js → blockDiagram-I7D4REHJ-puRAhxem.js} +1 -1
- package/dist/ui/assets/{button-BskHmmtR.js → button-II9J4IUe.js} +1 -1
- package/dist/ui/assets/{c4Diagram-7LVT6UL2-bQf4xDX5.js → c4Diagram-7LVT6UL2-C4CGYisP.js} +1 -1
- package/dist/ui/assets/channel-D_S1ZUW_.js +1 -0
- package/dist/ui/assets/check-setup-DSNmeJ0T.js +2 -0
- package/dist/ui/assets/{checkbox-BdCUqK2K.js → checkbox-4IcB0C9m.js} +1 -1
- package/dist/ui/assets/{chunk-2E4U76K2-DLFOie7L.js → chunk-2E4U76K2-DjnKVsYi.js} +1 -1
- package/dist/ui/assets/{chunk-4HAMMTFA-BPDy0z56.js → chunk-4HAMMTFA-CDnKKfj8.js} +1 -1
- package/dist/ui/assets/{chunk-75Z2AOVW-CGe3rSHt.js → chunk-75Z2AOVW-CKQ7DeM6.js} +1 -1
- package/dist/ui/assets/{chunk-CLGD4ZFX-Cc3Z-MGq.js → chunk-CLGD4ZFX-C4wu0WZN.js} +1 -1
- package/dist/ui/assets/{chunk-DU6HZSFF-DoNdcPzn.js → chunk-DU6HZSFF-DrJ5bmzy.js} +1 -1
- package/dist/ui/assets/{chunk-F27PBJKO-0W-eFq3z.js → chunk-F27PBJKO-CzXjmHDd.js} +1 -1
- package/dist/ui/assets/{chunk-GMAD6QVW-DIa91igC.js → chunk-GMAD6QVW-CcWcSwCd.js} +1 -1
- package/dist/ui/assets/{chunk-GVQU2GXP-B9kO2TNG.js → chunk-GVQU2GXP-BaenLrCK.js} +1 -1
- package/dist/ui/assets/{chunk-IMKFNOWR-BVh_kn6v.js → chunk-IMKFNOWR-JyaOH2dq.js} +1 -1
- package/dist/ui/assets/{chunk-L3NEJ4N5-BIAmP_VV.js → chunk-L3NEJ4N5-D-Soe8Pq.js} +1 -1
- package/dist/ui/assets/{chunk-OSK3NFVY-JwMwYbXa.js → chunk-OSK3NFVY-DyEqccWY.js} +1 -1
- package/dist/ui/assets/{chunk-P2QGCYS3-jcoeuQEp.js → chunk-P2QGCYS3-PZxLXffD.js} +1 -1
- package/dist/ui/assets/{chunk-POPQ4Y6H-DIWunY1p.js → chunk-POPQ4Y6H-CLOE0hWn.js} +1 -1
- package/dist/ui/assets/{chunk-PWAF6VOD-DK7-N58B.js → chunk-PWAF6VOD-092-eJK8.js} +1 -1
- package/dist/ui/assets/{chunk-SHT3W25Y-CcbXenLZ.js → chunk-SHT3W25Y-CSc5sy8R.js} +1 -1
- package/dist/ui/assets/{chunk-SVP7TREG-CU8QcmKz.js → chunk-SVP7TREG-BLTmX5VJ.js} +1 -1
- package/dist/ui/assets/{chunk-TICWLB2K-C2dfqOZm.js → chunk-TICWLB2K-SzItQUhb.js} +1 -1
- package/dist/ui/assets/{chunk-TLUHSLCS-D-41MDHJ.js → chunk-TLUHSLCS-DMnSH-ft.js} +2 -2
- package/dist/ui/assets/classDiagram-ZZMXUADV-B7QHFk-U.js +1 -0
- package/dist/ui/assets/classDiagram-v2-VYDZK3BY-B7QHFk-U.js +1 -0
- package/dist/ui/assets/{close-DyBUPuic.js → close-DcpwMOTE.js} +1 -1
- package/dist/ui/assets/{cynefinDiagram-5FMLGOSQ-OgOMfJ2M.js → cynefinDiagram-5FMLGOSQ-1ilx8mKu.js} +1 -1
- package/dist/ui/assets/{dagre-GXQ25YYZ-DbmwwCwb.js → dagre-GXQ25YYZ-C3A59Q6w.js} +1 -1
- package/dist/ui/assets/{diagram-S7CK7UJ4-fSJUV0Sv.js → diagram-S7CK7UJ4-B-6B9kWN.js} +1 -1
- package/dist/ui/assets/{diagram-UQ7AKVKN-CPLv2elu.js → diagram-UQ7AKVKN-BqxmQJR8.js} +1 -1
- package/dist/ui/assets/{diagram-VSXAHHWV-CsOV5L3Y.js → diagram-VSXAHHWV-Ck9wWlUm.js} +1 -1
- package/dist/ui/assets/{diagram-VX7I27RA-C6eTl1uM.js → diagram-VX7I27RA-BQe2g3vh.js} +1 -1
- package/dist/ui/assets/{diagram-Z3DM3KII-B4UZmomc.js → diagram-Z3DM3KII-DD8365dG.js} +1 -1
- package/dist/ui/assets/{docs-ZCGAA3kV.js → docs-itn09t2R.js} +1 -1
- package/dist/ui/assets/{ebnfDiagram-PWID7BFC-CSTTfh_S.js → ebnfDiagram-PWID7BFC-Bz8cpJNy.js} +1 -1
- package/dist/ui/assets/{erDiagram-RLTQ6QDP-BYT61Y7Q.js → erDiagram-RLTQ6QDP-Bc6u3S9N.js} +1 -1
- package/dist/ui/assets/flowDiagram-HODETNUW-Ba7ylFp4.js +1 -0
- package/dist/ui/assets/{ganttDiagram-EL5Y4UJY-DKTisdub.js → ganttDiagram-EL5Y4UJY-DVDVRjA0.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-WWUBYQGX-ZkPvOAfk.js → gitGraphDiagram-WWUBYQGX-CFUXHZWf.js} +1 -1
- package/dist/ui/assets/index-DITWgaOj.css +1 -0
- package/dist/ui/assets/index-DqJOYNud.js +68 -0
- package/dist/ui/assets/{infoDiagram-27XIBGKW-Ck98QGBN.js → infoDiagram-27XIBGKW-C-7l9NCQ.js} +1 -1
- package/dist/ui/assets/{input-BxW7xGjP.js → input-DYSaV-Uv.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-5VMMS53U-CqwQ5qZ8.js → ishikawaDiagram-5VMMS53U-Bjq-LdEc.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-3NMN7TZE-C1UQN2RN.js → journeyDiagram-3NMN7TZE-o4M0lP2i.js} +1 -1
- package/dist/ui/assets/{kanban-definition-UXKFOSKX-9zw0uM6N.js → kanban-definition-UXKFOSKX-BYqVEzsr.js} +1 -1
- package/dist/ui/assets/{line-CeMjuG_7.js → line-4TL08MsA.js} +1 -1
- package/dist/ui/assets/{mermaid-parser.core-Bosog0P9.js → mermaid-parser.core-DrM_vPwv.js} +1 -1
- package/dist/ui/assets/{mermaid.core-CJqh-dHb.js → mermaid.core-Dzz_-qU1.js} +3 -3
- package/dist/ui/assets/{mindmap-definition-YA3MSWOX-Da8qCo0o.js → mindmap-definition-YA3MSWOX-CaKNZzR5.js} +1 -1
- package/dist/ui/assets/{pegDiagram-XKGWAZYB-DELDftZr.js → pegDiagram-XKGWAZYB-DbKJ-jrI.js} +1 -1
- package/dist/ui/assets/{pieDiagram-E7YTZNPT-Da3NN6-R.js → pieDiagram-E7YTZNPT-CPiwJysC.js} +1 -1
- package/dist/ui/assets/{quadrantDiagram-AXDQQJYC-B51kliky.js → quadrantDiagram-AXDQQJYC-q32X56Gx.js} +1 -1
- package/dist/ui/assets/{railroadDiagram-O6MQD6OU-BgsVU5EU.js → railroadDiagram-O6MQD6OU-DNMhXeke.js} +1 -1
- package/dist/ui/assets/repo-BuEVC7d2.js +59 -0
- package/dist/ui/assets/{requirementDiagram-BXWQKSXE-D1AT3iV0.js → requirementDiagram-BXWQKSXE-BW09ERRd.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-P5KCCOFB-BDK2LYvj.js → sankeyDiagram-P5KCCOFB-BM5y8xIj.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-WJ2MYXX4-CNiCcLn-.js → sequenceDiagram-WJ2MYXX4-QCl8JI9d.js} +1 -1
- package/dist/ui/assets/{stateDiagram-D77RDMKH-Cf-064cv.js → stateDiagram-D77RDMKH-CURAhx8F.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-CnyC3tkF.js +1 -0
- package/dist/ui/assets/{swimlanes-42K2YHIH-D-tbu4wq.js → swimlanes-42K2YHIH-CxCV3G9b.js} +1 -1
- package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-R6ULRXhK.js +8 -0
- package/dist/ui/assets/{switch-QAs7KZBM.js → switch-fubkLBfv.js} +1 -1
- package/dist/ui/assets/{timeline-definition-24CTP7MA-DRufowda.js → timeline-definition-24CTP7MA-_hEyz10W.js} +1 -1
- package/dist/ui/assets/{title-Ct1YpRGS.js → title-DrjQrrPh.js} +1 -1
- package/dist/ui/assets/{value-CnDjI3IE.js → value-UmIPBXR_.js} +1 -1
- package/dist/ui/assets/vendor-ui-BIC6pWFX.js +3 -0
- package/dist/ui/assets/{vennDiagram-4TSXK5OY-D1vf8POQ.js → vennDiagram-4TSXK5OY-CdB16vQ8.js} +1 -1
- package/dist/ui/assets/{viewport-BF2CEetx.js → viewport-vp1hmik7.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-VM6X3IG4-B4fB0w_8.js → wardleyDiagram-VM6X3IG4-Bl7UPuNA.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-S5SC5T6Z-CpSh2ftP.js → xychartDiagram-S5SC5T6Z-BN1ho0Vx.js} +1 -1
- package/dist/ui/index.html +19 -19
- package/dist/ui/sw.js +2 -2
- package/package.json +3 -3
- package/dist/ui/assets/AgentsView-BWKykKEA.js +0 -2
- package/dist/ui/assets/AgentsView-DEIyf0uD.css +0 -1
- package/dist/ui/assets/ContextView-DQ6RW6w0.js +0 -4
- package/dist/ui/assets/DashboardView-B-7-dQLU.js +0 -1
- package/dist/ui/assets/InputsView-D4WtnYSg.js +0 -1
- package/dist/ui/assets/SecretsView-C99csAEO.js +0 -1
- package/dist/ui/assets/StoriesView-CRo6XH_e.css +0 -1
- package/dist/ui/assets/StoriesView-CpLqmKTx.js +0 -1
- package/dist/ui/assets/WorkView-C9Fd-nys.js +0 -2
- package/dist/ui/assets/WorkView-couHda3J.css +0 -1
- package/dist/ui/assets/channel-6uQ09cde.js +0 -1
- package/dist/ui/assets/check-progress-p3dLHxxW.js +0 -2
- package/dist/ui/assets/classDiagram-ZZMXUADV-CG7r0YBU.js +0 -1
- package/dist/ui/assets/classDiagram-v2-VYDZK3BY-CG7r0YBU.js +0 -1
- package/dist/ui/assets/flowDiagram-HODETNUW-DzLUu-VJ.js +0 -1
- package/dist/ui/assets/index-BUmR8syJ.css +0 -1
- package/dist/ui/assets/index-hshjr8FP.js +0 -68
- package/dist/ui/assets/repo-PZFVwA66.js +0 -54
- package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-CrFLdWWs.js +0 -1
- package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-D6iLKbDv.js +0 -8
- package/dist/ui/assets/vendor-ui-BJqOnU3b.js +0 -3
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# RepoOS
|
|
2
2
|
|
|
3
|
-
**The repo is the operating system.**
|
|
3
|
+
**The repo is the operating system. Your AI dev team, living in your repo, for CTOs and builders.**
|
|
4
4
|
|
|
5
5
|
RepoOS is a lightweight, repo-native way to track work that lives as markdown
|
|
6
|
-
files inside your
|
|
6
|
+
files inside your repo. Tasks, specs, bugs, and feature requests are plain
|
|
7
7
|
`.md` files with YAML frontmatter — versioned in git, readable by humans, and
|
|
8
8
|
designed to be consumed directly by AI coding agents.
|
|
9
9
|
|
|
@@ -50,7 +50,8 @@ curl -fsSL https://repoos.org/install | bash
|
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
It runs on Bun when available (recommended), otherwise requires Node.js >=
|
|
53
|
-
20.6.0. It installs to `~/.repoos` and links `repoos` into
|
|
53
|
+
20.6.0. It installs to `~/.local/share/repoos` and links `repoos` into
|
|
54
|
+
`~/.local/bin`. Machine state stays in `~/.repoos`.
|
|
54
55
|
|
|
55
56
|
### Homebrew
|
|
56
57
|
|
|
@@ -76,22 +77,18 @@ bun add -g @repo-os/repoos
|
|
|
76
77
|
pnpm add -g @repo-os/repoos
|
|
77
78
|
```
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
mise is not a recommended install method. See `docs/install-layout.md`.
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
This uses mise's built-in npm backend and records RepoOS in your global mise
|
|
86
|
-
configuration. Make sure [mise shell activation](https://mise.jdx.dev/getting-started.html)
|
|
87
|
-
is enabled so its `repoos` shim is on your PATH.
|
|
82
|
+
Bun installs `bun` into `~/.bun/bin`; add that directory to `PATH` before
|
|
83
|
+
`bun add -g`. pnpm on a clean account needs `SHELL` set and `pnpm setup`
|
|
84
|
+
before a global install.
|
|
88
85
|
|
|
89
86
|
Use the same tool to update a package-manager install: `npm update -g
|
|
90
87
|
@repo-os/repoos`, `bun update -g @repo-os/repoos`, `pnpm update -g
|
|
91
|
-
@repo-os/repoos`, `
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
@repo-os/repoos`, or `brew update && brew upgrade repo-os/tap/repoos`. A
|
|
89
|
+
standalone install updates with `repoos upgrade` and removes with
|
|
90
|
+
`repoos uninstall`. When run from a recognised package-manager install,
|
|
91
|
+
`repoos upgrade` prints the matching package-manager command instead.
|
|
95
92
|
|
|
96
93
|
Then in any repo:
|
|
97
94
|
|
package/dist/.build-info.json
CHANGED
package/dist/.build-stamp.json
CHANGED
|
@@ -18,6 +18,8 @@ const CONTROL_API_MATCHERS = [
|
|
|
18
18
|
re("POST", /^\/api\/tasks\/([^/]+)\/needs-input\/dismiss$/.source),
|
|
19
19
|
re("POST", /^\/api\/tasks\/([^/]+)\/review\/again$/.source),
|
|
20
20
|
re("GET", /^\/api\/tasks\/([^/]+)\/landable$/.source),
|
|
21
|
+
// Non-blocking handoff outcome for `repoos handoff-status` (#1028).
|
|
22
|
+
re("GET", /^\/api\/tasks\/([^/]+)\/handoff-status$/.source),
|
|
21
23
|
re("POST", /^\/api\/tasks\/([^/]+)\/preview$/.source),
|
|
22
24
|
re("POST", /^\/api\/tasks\/([^/]+)\/preview\/stop$/.source),
|
|
23
25
|
// `repoos shot` single-entry capture through the browser-capture policy (#0874).
|
package/dist/cli/help.js
CHANGED
|
@@ -160,6 +160,12 @@ const GROUPS = [
|
|
|
160
160
|
desc: "Read-only checks before merging (verdict, lock, worktree, merge, scope, main) — exits non-zero when the task is not ready to merge (GET /api/tasks/:id/landable)",
|
|
161
161
|
flags: "--json · --port",
|
|
162
162
|
},
|
|
163
|
+
{
|
|
164
|
+
name: "handoff-status",
|
|
165
|
+
usage: "handoff-status <id> [--json] [--port N]",
|
|
166
|
+
desc: "Non-blocking state of the latest handoff attempt: not requested, running, passed, failed or deferred (GET /api/tasks/:id/handoff-status)",
|
|
167
|
+
flags: "--json · --port",
|
|
168
|
+
},
|
|
163
169
|
{
|
|
164
170
|
name: "override",
|
|
165
171
|
usage: "override <id> [--cli <name>] [--model <model>] [--json] [--port N]",
|
package/dist/cli/index.js
CHANGED
|
@@ -27,7 +27,7 @@ import { cmdCertify } from "../commands/certify.js";
|
|
|
27
27
|
import { cmdSupport } from "../commands/support.js";
|
|
28
28
|
import { cmdService } from "../commands/service.js";
|
|
29
29
|
import { cmdServers } from "../commands/servers.js";
|
|
30
|
-
import { cmdAgentsRunning, cmdConfig, cmdDone, cmdLandable, cmdMessage, cmdSendBack, cmdOverride, cmdPause, cmdPreview, cmdDev, cmdReview, cmdVerify, cmdRunners, cmdStart, cmdSync, cmdStats, cmdDecisions, cmdApi, cmdIntegration, cmdAttention, cmdHold, cmdUnhold, } from "../commands/control-api.js";
|
|
30
|
+
import { cmdAgentsRunning, cmdConfig, cmdDone, cmdLandable, cmdHandoffStatus, cmdMessage, cmdSendBack, cmdOverride, cmdPause, cmdPreview, cmdDev, cmdReview, cmdVerify, cmdRunners, cmdStart, cmdSync, cmdStats, cmdDecisions, cmdApi, cmdIntegration, cmdAttention, cmdHold, cmdUnhold, } from "../commands/control-api.js";
|
|
31
31
|
import { cmdWatch } from "../commands/watch.js";
|
|
32
32
|
import { cmdDriver } from "../commands/driver.js";
|
|
33
33
|
import { cmdBundle } from "../commands/bundle.js";
|
|
@@ -327,6 +327,12 @@ function main() {
|
|
|
327
327
|
process.exitCode = code;
|
|
328
328
|
});
|
|
329
329
|
break;
|
|
330
|
+
case "handoff-status":
|
|
331
|
+
void cmdHandoffStatus(rest).then((code) => {
|
|
332
|
+
if (code !== 0)
|
|
333
|
+
process.exitCode = code;
|
|
334
|
+
});
|
|
335
|
+
break;
|
|
330
336
|
case "override":
|
|
331
337
|
void cmdOverride(rest).then((code) => {
|
|
332
338
|
if (code !== 0)
|
|
@@ -83,6 +83,12 @@ interface StatsGitJobView {
|
|
|
83
83
|
ageMs?: number;
|
|
84
84
|
}
|
|
85
85
|
export declare function printSystemSummary(system: StatsSystemView): void;
|
|
86
|
+
/**
|
|
87
|
+
* `repoos handoff-status <id>` (#1028): print the latest handoff attempt's
|
|
88
|
+
* state immediately. Never waits for, starts, or alters a handoff — safe to
|
|
89
|
+
* call from an engineer that is unsure whether its request reached the server.
|
|
90
|
+
*/
|
|
91
|
+
export declare function cmdHandoffStatus(args: string[]): Promise<number>;
|
|
86
92
|
/**
|
|
87
93
|
* `repoos landable <id>` (#0867): print the read-only landing pre-checks and
|
|
88
94
|
* exit 0 only when every check passes. Never edits, commits or moves status.
|
|
@@ -179,9 +179,9 @@ export async function cmdHold(args) {
|
|
|
179
179
|
return 1;
|
|
180
180
|
}
|
|
181
181
|
const api = new RepoOsApi({ port: opts.port });
|
|
182
|
-
// #0960
|
|
183
|
-
//
|
|
184
|
-
//
|
|
182
|
+
// #0960: the CLI still requires `--reason`. The HTTP hold route accepts a
|
|
183
|
+
// missing reason (#1033). `--until` must be a real date or it would never
|
|
184
|
+
// auto-release and become a permanent hold.
|
|
185
185
|
if (!opts.reason || !opts.reason.trim()) {
|
|
186
186
|
printErr("hold requires a --reason (free text documenting why the task is parked)");
|
|
187
187
|
return 1;
|
|
@@ -1506,6 +1506,56 @@ function landableIcon(status) {
|
|
|
1506
1506
|
return c.yellow("!");
|
|
1507
1507
|
return c.red("✗");
|
|
1508
1508
|
}
|
|
1509
|
+
/**
|
|
1510
|
+
* `repoos handoff-status <id>` (#1028): print the latest handoff attempt's
|
|
1511
|
+
* state immediately. Never waits for, starts, or alters a handoff — safe to
|
|
1512
|
+
* call from an engineer that is unsure whether its request reached the server.
|
|
1513
|
+
*/
|
|
1514
|
+
export async function cmdHandoffStatus(args) {
|
|
1515
|
+
const { rest, opts, error } = parseCommonFlags(args);
|
|
1516
|
+
if (error) {
|
|
1517
|
+
printErr(error);
|
|
1518
|
+
return 1;
|
|
1519
|
+
}
|
|
1520
|
+
const id = rest[0];
|
|
1521
|
+
if (!id) {
|
|
1522
|
+
printErr("Usage: repoos handoff-status <id> [--json] [--port N]");
|
|
1523
|
+
return 1;
|
|
1524
|
+
}
|
|
1525
|
+
const api = new RepoOsApi({ port: opts.port });
|
|
1526
|
+
try {
|
|
1527
|
+
await ensureServer(api);
|
|
1528
|
+
const status = (await api.requestOk("GET", `/api/tasks/${id}/handoff-status`));
|
|
1529
|
+
if (opts.json) {
|
|
1530
|
+
printJson(status);
|
|
1531
|
+
return 0;
|
|
1532
|
+
}
|
|
1533
|
+
const label = status.state === "passed"
|
|
1534
|
+
? c.green("passed")
|
|
1535
|
+
: status.state === "failed"
|
|
1536
|
+
? c.red("failed")
|
|
1537
|
+
: status.state === "running"
|
|
1538
|
+
? c.yellow("running")
|
|
1539
|
+
: status.state === "deferred"
|
|
1540
|
+
? c.yellow("deferred")
|
|
1541
|
+
: c.dim("not requested");
|
|
1542
|
+
console.log(` ${c.bold(`#${id}`)} handoff: ${label}`);
|
|
1543
|
+
if (status.step)
|
|
1544
|
+
console.log(` step: ${status.step}`);
|
|
1545
|
+
if (status.reason)
|
|
1546
|
+
console.log(` reason: ${status.reason}`);
|
|
1547
|
+
if (status.updatedAt)
|
|
1548
|
+
console.log(` at: ${status.updatedAt}`);
|
|
1549
|
+
if (status.state === "not_requested") {
|
|
1550
|
+
console.log(c.dim(` no handoff has been requested for this task (request it with \`repoos mv ${id} review\`)`));
|
|
1551
|
+
}
|
|
1552
|
+
return 0;
|
|
1553
|
+
}
|
|
1554
|
+
catch (e) {
|
|
1555
|
+
printErr(e.message);
|
|
1556
|
+
return 1;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1509
1559
|
/**
|
|
1510
1560
|
* `repoos landable <id>` (#0867): print the read-only landing pre-checks and
|
|
1511
1561
|
* exit 0 only when every check passes. Never edits, commits or moves status.
|
package/dist/commands/init.js
CHANGED
|
@@ -22,7 +22,7 @@ import { deriveServePort, findRepoRoot, loadConfig } from "../core/config.js";
|
|
|
22
22
|
import { CHECK_PLAN_PROPOSAL_FILE, proposeCheckPlan } from "../core/check-plan-proposal.js";
|
|
23
23
|
import { formatPlanToml } from "../core/check-plan.js";
|
|
24
24
|
import { importDocsInto, scaffoldDocsInto } from "./docs-io.js";
|
|
25
|
-
import { gitAvailable, gitCommitAll,
|
|
25
|
+
import { gitAvailable, gitCommitAll, gitIdentityConfigured, gitInit, isGitRepo, } from "../core/git.js";
|
|
26
26
|
import { c } from "../cli/colors.js";
|
|
27
27
|
import { cmdServe } from "./serve.js";
|
|
28
28
|
import { detectAgents } from "../core/detect.js";
|
|
@@ -178,11 +178,11 @@ repo itself is the source of truth. This file tells AI agents how to operate.
|
|
|
178
178
|
|
|
179
179
|
New to this repo? The board is \`${workDir}/\` — one markdown file per task.
|
|
180
180
|
Create work with \`repoos new "<title>"\`, move it with \`repoos mv <id> <status>\`,
|
|
181
|
-
and **never** edit \`${workDir}
|
|
181
|
+
and **never** edit task files under \`${workDir}/\` by hand (use the CLI or the HTTP API).
|
|
182
182
|
Project context lives under \`${docsDir}/\`; start there. Run \`repoos serve\` in a
|
|
183
183
|
terminal you keep open, or install \`repoos service\` for an unattended server —
|
|
184
184
|
a detached \`repoos serve\` started from an agent shell is reaped as a stray orphan
|
|
185
|
-
(see
|
|
185
|
+
(see https://docs.repoos.org/running-with-agents). RepoOS runs each managed agent turn in its
|
|
186
186
|
own process group and tears that group down when the turn ends; never use \`pkill\`
|
|
187
187
|
or \`killall\` to clean up helpers. When a task is done, run \`repoos check\` and
|
|
188
188
|
hand off with \`repoos mv <id> review\`; see the operating loop below.
|
|
@@ -192,8 +192,8 @@ hand off with \`repoos mv <id> review\`; see the operating loop below.
|
|
|
192
192
|
For a RepoOS-managed task runner:
|
|
193
193
|
|
|
194
194
|
1. Read this file, your assigned task under \`${workDir}/\`, and relevant
|
|
195
|
-
project docs under \`${docsDir}
|
|
196
|
-
|
|
195
|
+
project docs under \`${docsDir}/\`. Maintain ${docsDir}/README.md as the
|
|
196
|
+
reading-order index as the doc set grows. Before reading a
|
|
197
197
|
large file, run \`repoos outline <path>\` to get its symbols with line
|
|
198
198
|
numbers, then read only the range you need instead of the whole file.
|
|
199
199
|
2. Work in the task branch and dedicated worktree RepoOS assigned. The server
|
|
@@ -225,7 +225,7 @@ unless the human explicitly requests that separate workflow.
|
|
|
225
225
|
|
|
226
226
|
The reviewer agent, when enabled, writes an advisory report in the task drawer.
|
|
227
227
|
It does not edit code or replace human approval. After the human approves,
|
|
228
|
-
use **Move to done** in RepoOS or
|
|
228
|
+
use **Move to done** in RepoOS or POST /api/tasks/:id/done. The server
|
|
229
229
|
merges the task into a separate candidate worktree, validates the combined
|
|
230
230
|
result, rechecks the primary branch under a publication lock, publishes,
|
|
231
231
|
cleans up, and records completion. \`repoos mv <id> done\` only changes metadata;
|
|
@@ -233,7 +233,7 @@ it does not run close-out or merge code.
|
|
|
233
233
|
|
|
234
234
|
A direct commit on the primary branch is an exception requiring explicit
|
|
235
235
|
human authorization. If that already-landed work has a branchless task record,
|
|
236
|
-
the
|
|
236
|
+
the /done endpoint can check the primary checkout and record release without
|
|
237
237
|
a candidate merge. Do not erase a task's branch metadata to force this path.
|
|
238
238
|
|
|
239
239
|
## Rules
|
|
@@ -248,7 +248,7 @@ a candidate merge. Do not erase a task's branch metadata to force this path.
|
|
|
248
248
|
invent ownership rules for RepoOS directories; the config is the only source
|
|
249
249
|
of truth for layout.
|
|
250
250
|
- **Never** move task files between folders. Status lives in frontmatter.
|
|
251
|
-
- **Never write directly to \`${workDir}
|
|
251
|
+
- **Never write directly to task files under \`${workDir}/\`.** All task creation and
|
|
252
252
|
manipulation goes through \`repoos\` commands or HTTP API endpoints
|
|
253
253
|
(\`POST /api/tasks\`, \`PATCH /api/tasks/:id\`, etc.). If the RepoOS server
|
|
254
254
|
is unreachable, stop and report the issue — do not hand-write task files.
|
|
@@ -306,7 +306,7 @@ active/review.
|
|
|
306
306
|
## Declaring evidence shots (## Shots)
|
|
307
307
|
|
|
308
308
|
A task body may carry a \`## Shots\` section with a fenced JSON list of capture
|
|
309
|
-
entries (see
|
|
309
|
+
entries (see https://docs.repoos.org/cli#the-tasks-shots-list). Each entry has \`target\`, \`route\`, an
|
|
310
310
|
optional \`selector\` (element crop — the exception), an optional \`highlight\`
|
|
311
311
|
CSS selector (outlines changed elements), a \`label\`, and optional ordered
|
|
312
312
|
\`steps\` (click/fill/wait, plain CSS selectors). Use \`repoos update <id>
|
|
@@ -315,9 +315,9 @@ fenced section) without touching the rest of the body — a full \`--body\` repl
|
|
|
315
315
|
Problem / Desired UX / Acceptance criteria / Notes for AI is refused unless
|
|
316
316
|
\`--force\` is passed.
|
|
317
317
|
|
|
318
|
-
For tabbed views (e.g. Agents), prefer
|
|
319
|
-
(
|
|
320
|
-
is reached the same way (
|
|
318
|
+
For tabbed views (e.g. Agents), prefer ?tab=<id> routes
|
|
319
|
+
(/agents?tab=detected) over click steps to reach the right tab; a task drawer
|
|
320
|
+
is reached the same way (/work?task=<id>&tab=changes), and always
|
|
321
321
|
set \`highlight\` to the changed elements. Reach a populated state with a
|
|
322
322
|
\`route\` or a named \`state\` fixture, never with \`steps\` that click a
|
|
323
323
|
placeholder selector (\`data-task-id "9999"\` and the like) — such a step times
|
|
@@ -1724,7 +1724,7 @@ async function guidedNewRepo(opts) {
|
|
|
1724
1724
|
if (!gitOk) {
|
|
1725
1725
|
console.log(c.yellow("\n Warning: git doesn't appear to be installed — scaffolding without git."));
|
|
1726
1726
|
}
|
|
1727
|
-
else if (!
|
|
1727
|
+
else if (!gitIdentityConfigured(target)) {
|
|
1728
1728
|
console.log(c.yellow("\n Warning: no git identity is configured."));
|
|
1729
1729
|
console.log(c.dim(" git may auto-detect it, or the initial commit may fail. Set it with:"));
|
|
1730
1730
|
console.log(c.dim(' git config --global user.name "You" && git config --global user.email you@example.com'));
|
|
@@ -10,7 +10,7 @@ import { commitTaskFile } from "../core/git.js";
|
|
|
10
10
|
import { c } from "../cli/colors.js";
|
|
11
11
|
import { createRepoOS } from "../core/repoos.js";
|
|
12
12
|
import { computeNextRun, formatNextRunPreview, } from "../core/schedule-time.js";
|
|
13
|
-
import { createSchedule, getSchedule, listSchedules, updateSchedule, validateScheduleInput, } from "../core/schedule.js";
|
|
13
|
+
import { createSchedule, getSchedule, listSchedules, scheduleTemplateWarning, updateSchedule, validateScheduleInput, } from "../core/schedule.js";
|
|
14
14
|
import { executeScheduleRun, findDueSchedule, releaseScheduleOccurrenceLock, tryAcquireScheduleOccurrenceLock, } from "../server/schedule-runner.js";
|
|
15
15
|
import { scheduleHostileReason, scheduleRunRefusalMessage } from "../server/schedule-automation.js";
|
|
16
16
|
import { deleteScheduleDataFile } from "../server/write.js";
|
|
@@ -132,6 +132,16 @@ function flagsToCreateInput(flags, fallback) {
|
|
|
132
132
|
body: flags.body ?? fallback?.body,
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
+
function printScheduleTemplateWarning(input) {
|
|
136
|
+
const detail = scheduleTemplateWarning({
|
|
137
|
+
body: input.body ?? "",
|
|
138
|
+
taskArea: input.taskArea,
|
|
139
|
+
taskAssignedTo: input.taskAssignedTo,
|
|
140
|
+
});
|
|
141
|
+
if (detail) {
|
|
142
|
+
console.log(c.yellow(" warning: ") + c.dim("schedule template is underspecified — ") + detail);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
135
145
|
export function cmdScheduleList(args) {
|
|
136
146
|
const { flags, error } = parseScheduleFlags(args);
|
|
137
147
|
if (error) {
|
|
@@ -207,6 +217,7 @@ export function cmdScheduleNew(args) {
|
|
|
207
217
|
const created = createSchedule(config, input);
|
|
208
218
|
const committed = commitSchedule(config.root, created.path, created.id, "create");
|
|
209
219
|
console.log(c.green(` created schedule #${created.id} ${created.title}`));
|
|
220
|
+
printScheduleTemplateWarning(input);
|
|
210
221
|
if (!committed)
|
|
211
222
|
console.log(c.yellow(" warning: ") + c.dim("file left uncommitted"));
|
|
212
223
|
}
|
|
@@ -270,6 +281,9 @@ export function cmdScheduleUpdate(args) {
|
|
|
270
281
|
const updated = updateSchedule(config, existing.id, patch);
|
|
271
282
|
const committed = commitSchedule(config.root, updated.path, updated.id, "update");
|
|
272
283
|
console.log(c.green(` updated schedule #${updated.id}`));
|
|
284
|
+
const merged = flagsToCreateInput(flags, existing);
|
|
285
|
+
if (merged)
|
|
286
|
+
printScheduleTemplateWarning(merged);
|
|
273
287
|
if (!committed)
|
|
274
288
|
console.log(c.yellow(" warning: ") + c.dim("file left uncommitted"));
|
|
275
289
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { renderServeBanner } from "./serve.js";
|
|
2
|
+
import { formatServeBindBannerValue, renderServeBanner } from "./serve.js";
|
|
3
3
|
describe("renderServeBanner", () => {
|
|
4
4
|
const rows = [
|
|
5
5
|
{ label: "Local", value: "http://127.0.0.1:7515" },
|
|
@@ -10,6 +10,29 @@ describe("renderServeBanner", () => {
|
|
|
10
10
|
expect(out).toContain("RepoOS v1.2.3");
|
|
11
11
|
expect(out).toContain("Local http://127.0.0.1:7515");
|
|
12
12
|
});
|
|
13
|
+
it("names the bind address on localhost and tailnet rows", () => {
|
|
14
|
+
const localOnly = renderServeBanner("1.0.0", [
|
|
15
|
+
{ label: "Bind", value: formatServeBindBannerValue("127.0.0.1", false) },
|
|
16
|
+
{ label: "Local", value: "http://127.0.0.1:7515" },
|
|
17
|
+
]);
|
|
18
|
+
expect(localOnly).toMatch(/Bind\s+127\.0\.0\.1/);
|
|
19
|
+
const tailscale = renderServeBanner("1.0.0", [
|
|
20
|
+
{
|
|
21
|
+
label: "Bind",
|
|
22
|
+
value: formatServeBindBannerValue("0.0.0.0", true),
|
|
23
|
+
},
|
|
24
|
+
{ label: "Local", value: "http://127.0.0.1:7515" },
|
|
25
|
+
{ label: "Tailnet", value: "http://100.64.0.1:7515" },
|
|
26
|
+
]);
|
|
27
|
+
expect(tailscale).toMatch(/Bind\s+0\.0\.0\.0/);
|
|
28
|
+
expect(tailscale).toContain("--host 127.0.0.1");
|
|
29
|
+
});
|
|
30
|
+
it("formatServeBindBannerValue uses tailscaleDetected, not host alone", () => {
|
|
31
|
+
expect(formatServeBindBannerValue("0.0.0.0", false)).toContain("explicit --host");
|
|
32
|
+
expect(formatServeBindBannerValue("0.0.0.0", false)).not.toContain("Tailscale detected");
|
|
33
|
+
expect(formatServeBindBannerValue("0.0.0.0", true)).toContain("Tailscale detected");
|
|
34
|
+
expect(formatServeBindBannerValue("192.168.1.5", false)).toContain("192.168.1.5");
|
|
35
|
+
});
|
|
13
36
|
it("splits an HTTPS warning into problem, fix and link", () => {
|
|
14
37
|
const out = renderServeBanner("1.2.3", rows, "HTTPS certificates aren't enabled for your tailnet — turn on MagicDNS and HTTPS Certificates at https://login.tailscale.com/admin/dns");
|
|
15
38
|
expect(out).toContain("Tailscale HTTPS unavailable");
|
package/dist/commands/serve.d.ts
CHANGED
|
@@ -40,6 +40,11 @@ export declare function resolveServeHost(explicitHost?: string): {
|
|
|
40
40
|
tailscaleDetected: boolean;
|
|
41
41
|
tailscaleIP?: string;
|
|
42
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Bind row text for the serve startup banner. Uses {@link tailscaleDetected},
|
|
45
|
+
* not `host === "0.0.0.0"`, so an explicit `--host 0.0.0.0` is not mislabeled.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatServeBindBannerValue(host: string, tailscaleDetected: boolean): string;
|
|
43
48
|
/**
|
|
44
49
|
* Whether this `repoos serve` should apply the repo's preview-only
|
|
45
50
|
* `[preview.*]` config overlay (#0464).
|
package/dist/commands/serve.js
CHANGED
|
@@ -81,6 +81,22 @@ export function resolveServeHost(explicitHost) {
|
|
|
81
81
|
return { host: "0.0.0.0", tailscaleDetected: true, tailscaleIP };
|
|
82
82
|
return { host: "127.0.0.1", tailscaleDetected: false };
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Bind row text for the serve startup banner. Uses {@link tailscaleDetected},
|
|
86
|
+
* not `host === "0.0.0.0"`, so an explicit `--host 0.0.0.0` is not mislabeled.
|
|
87
|
+
*/
|
|
88
|
+
export function formatServeBindBannerValue(host, tailscaleDetected) {
|
|
89
|
+
if (tailscaleDetected) {
|
|
90
|
+
return (c.cyan("0.0.0.0") +
|
|
91
|
+
c.dim(" (all interfaces — Tailscale detected; pass ") +
|
|
92
|
+
c.cyan("--host 127.0.0.1") +
|
|
93
|
+
c.dim(" for localhost only)"));
|
|
94
|
+
}
|
|
95
|
+
if (host === "127.0.0.1") {
|
|
96
|
+
return c.cyan("127.0.0.1") + c.dim(" (localhost only)");
|
|
97
|
+
}
|
|
98
|
+
return c.cyan(host) + c.dim(" (explicit --host)");
|
|
99
|
+
}
|
|
84
100
|
/**
|
|
85
101
|
* Whether this `repoos serve` should apply the repo's preview-only
|
|
86
102
|
* `[preview.*]` config overlay (#0464).
|
|
@@ -225,6 +241,10 @@ export async function cmdServe(args, opts = {}) {
|
|
|
225
241
|
? `Bun ${process.versions.bun ?? ""}`.trim()
|
|
226
242
|
: `Node ${process.versions.node}`;
|
|
227
243
|
const rows = [
|
|
244
|
+
{
|
|
245
|
+
label: "Bind",
|
|
246
|
+
value: formatServeBindBannerValue(host, tailscaleDetected),
|
|
247
|
+
},
|
|
228
248
|
{ label: "Local", value: c.cyan(c.bold(handle.url)) },
|
|
229
249
|
{ label: "Events", value: c.cyan(handle.url + "/api/events") + c.dim(" (SSE)") },
|
|
230
250
|
{ label: "Watching", value: `${snap.taskCount} tasks` },
|
package/dist/commands/status.js
CHANGED
|
@@ -22,7 +22,7 @@ import { checkBuildForRoot, readBuildMeta, readBuildStamp } from "../core/build.
|
|
|
22
22
|
import { isManagedService } from "../core/service-manager.js";
|
|
23
23
|
import { readTunnelConfig } from "../core/tunnel.js";
|
|
24
24
|
import { readRegistry, reconcileIdentity, syncFromRepo, unionApps, } from "../core/tunnel-registry.js";
|
|
25
|
-
import { currentBranch, runGit } from "../core/git.js";
|
|
25
|
+
import { currentBranch, isGitRepo, runGit } from "../core/git.js";
|
|
26
26
|
import { countWorktrees, formatGcEntryDetails, sweepStaleWorktrees } from "../core/worktree-gc.js";
|
|
27
27
|
import { isOrphanServeCommand, isPortListening } from "../server/serve-reaper.js";
|
|
28
28
|
import { STATUSES } from "../core/types.js";
|
|
@@ -683,7 +683,7 @@ export function renderStatus(s, now = new Date()) {
|
|
|
683
683
|
}
|
|
684
684
|
// git
|
|
685
685
|
if (!s.git.branch) {
|
|
686
|
-
row("git", c.dim("not a git repository"));
|
|
686
|
+
row("git", c.dim(isGitRepo(s.root) ? "unknown branch" : "not a git repository"));
|
|
687
687
|
}
|
|
688
688
|
else {
|
|
689
689
|
const bits = [c.cyan(s.git.branch)];
|
package/dist/commands/tasks.js
CHANGED
|
@@ -105,7 +105,7 @@ async function listTasksViaApi(statusArg) {
|
|
|
105
105
|
return { rootName: root.split("/").pop() ?? "repo", tasks };
|
|
106
106
|
}
|
|
107
107
|
catch (error) {
|
|
108
|
-
console.warn(`[repoos]
|
|
108
|
+
console.warn(`[repoos] Server unavailable — using local index. Start with \`repoos serve\`.`);
|
|
109
109
|
return null;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export interface StandaloneUninstallPlan {
|
|
2
2
|
installDir: string;
|
|
3
|
+
/** True when the tarball was unpacked into the state directory (pre-split installs). */
|
|
4
|
+
legacyCombined: boolean;
|
|
3
5
|
launcherPath: string | null;
|
|
6
|
+
stateDir: string;
|
|
4
7
|
}
|
|
5
8
|
/**
|
|
6
9
|
* Return the files owned by a default curl install, or null for every other
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `repoos uninstall` — remove a standalone install created by install.sh.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Removes the install directory (`~/.local/share/repoos`, or a legacy
|
|
5
|
+
* `~/.repoos` payload) and the machine state entries RepoOS created there.
|
|
6
|
+
* Per-repo files (`repoos.toml`, a repo's `.repoos/` cache) are not touched.
|
|
7
|
+
* A package-manager install is not deleted; the command names the package
|
|
8
|
+
* manager command and any machine state that remains.
|
|
7
9
|
*/
|
|
8
|
-
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
10
|
+
import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
9
11
|
import { homedir } from "node:os";
|
|
10
12
|
import { dirname, join } from "node:path";
|
|
11
13
|
import { createInterface } from "node:readline/promises";
|
|
12
14
|
import { fileURLToPath } from "node:url";
|
|
13
15
|
import { c } from "../cli/colors.js";
|
|
14
|
-
import {
|
|
16
|
+
import { STANDALONE_INSTALL_PAYLOAD, classifyMachineState, isStandaloneInstallDir, machineStateDir, } from "../core/install-layout.js";
|
|
17
|
+
import { launcherScript, packageManagerUpgrade } from "./upgrade.js";
|
|
15
18
|
/**
|
|
16
19
|
* Return the files owned by a default curl install, or null for every other
|
|
17
20
|
* kind of execution (source checkout, npm/Bun, custom installation, etc.).
|
|
@@ -21,8 +24,8 @@ import { launcherScript } from "./upgrade.js";
|
|
|
21
24
|
*/
|
|
22
25
|
export function standaloneUninstallPlan(entryPath, home = homedir(), binDir = join(home, ".local", "bin")) {
|
|
23
26
|
const installDir = dirname(dirname(entryPath));
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
if (!isStandaloneInstallDir(installDir, home) ||
|
|
28
|
+
!existsSync(join(installDir, "cli", "index.js"))) {
|
|
26
29
|
return null;
|
|
27
30
|
}
|
|
28
31
|
const launcherPath = join(binDir, "repoos");
|
|
@@ -35,12 +38,18 @@ export function standaloneUninstallPlan(entryPath, home = homedir(), binDir = jo
|
|
|
35
38
|
catch {
|
|
36
39
|
// A launcher we cannot read is not safe to remove.
|
|
37
40
|
}
|
|
38
|
-
|
|
41
|
+
const stateDir = machineStateDir(home);
|
|
42
|
+
return {
|
|
43
|
+
installDir,
|
|
44
|
+
legacyCombined: installDir === stateDir,
|
|
45
|
+
launcherPath: ownsLauncher ? launcherPath : null,
|
|
46
|
+
stateDir,
|
|
47
|
+
};
|
|
39
48
|
}
|
|
40
49
|
async function confirm() {
|
|
41
50
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
42
51
|
try {
|
|
43
|
-
const answer = (await rl.question(" Remove the standalone RepoOS install? [y/N] "))
|
|
52
|
+
const answer = (await rl.question(" Remove the standalone RepoOS install and its machine state? [y/N] "))
|
|
44
53
|
.trim()
|
|
45
54
|
.toLowerCase();
|
|
46
55
|
return answer === "y" || answer === "yes";
|
|
@@ -49,27 +58,68 @@ async function confirm() {
|
|
|
49
58
|
rl.close();
|
|
50
59
|
}
|
|
51
60
|
}
|
|
52
|
-
function printPackageManagerRemoval() {
|
|
61
|
+
function printPackageManagerRemoval(home) {
|
|
53
62
|
console.log(c.yellow(" repoos was installed via a package manager."));
|
|
54
|
-
console.log(c.dim(" Remove
|
|
63
|
+
console.log(c.dim(" Remove the package with the same package manager:"));
|
|
55
64
|
console.log(c.dim(" npm uninstall -g @repo-os/repoos"));
|
|
56
65
|
console.log(c.dim(" bun remove -g @repo-os/repoos"));
|
|
57
66
|
console.log(c.dim(" pnpm remove -g @repo-os/repoos"));
|
|
58
|
-
console.log(c.dim("
|
|
67
|
+
console.log(c.dim(" brew uninstall repoos"));
|
|
68
|
+
console.log(c.dim(" mise is not a supported install method. If you used it anyway, remove the shim with:"));
|
|
69
|
+
console.log(c.dim(" mise unuse --global npm:@repo-os/repoos && mise prune"));
|
|
70
|
+
const stateDir = machineStateDir(home);
|
|
71
|
+
const { remove, keep } = classifyMachineState(stateDir);
|
|
72
|
+
if (remove.length === 0 && keep.length === 0 && !existsSync(join(stateDir, "cli", "index.js"))) {
|
|
73
|
+
console.log(c.dim(" No machine state was found in ~/.repoos."));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
console.log(c.dim(" This command did not delete machine state. Still on disk:"));
|
|
77
|
+
for (const name of remove)
|
|
78
|
+
console.log(c.dim(` ${join(stateDir, name)}`));
|
|
79
|
+
for (const name of keep)
|
|
80
|
+
console.log(c.dim(` ${join(stateDir, name)}`));
|
|
81
|
+
if (existsSync(join(stateDir, "cli", "index.js"))) {
|
|
82
|
+
console.log(c.dim(` ${join(stateDir, "cli")} (legacy install payload)`));
|
|
83
|
+
}
|
|
59
84
|
}
|
|
60
85
|
function printSourceRemoval() {
|
|
61
86
|
console.log(c.yellow(" repoos appears to be running from a source checkout, not a standalone install."));
|
|
62
87
|
console.log(c.dim(" There is nothing for RepoOS to uninstall. Remove the checkout only if you no longer need it."));
|
|
63
88
|
}
|
|
89
|
+
function removeStandalone(plan) {
|
|
90
|
+
if (plan.launcherPath)
|
|
91
|
+
rmSync(plan.launcherPath, { force: true });
|
|
92
|
+
if (plan.legacyCombined) {
|
|
93
|
+
for (const name of STANDALONE_INSTALL_PAYLOAD) {
|
|
94
|
+
rmSync(join(plan.installDir, name), { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
rmSync(plan.installDir, { recursive: true, force: true });
|
|
99
|
+
for (const name of STANDALONE_INSTALL_PAYLOAD) {
|
|
100
|
+
rmSync(join(plan.stateDir, name), { recursive: true, force: true });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const { remove, keep } = classifyMachineState(plan.stateDir);
|
|
104
|
+
const removedState = [];
|
|
105
|
+
for (const name of remove) {
|
|
106
|
+
rmSync(join(plan.stateDir, name), { recursive: true, force: true });
|
|
107
|
+
removedState.push(name);
|
|
108
|
+
}
|
|
109
|
+
if (existsSync(plan.stateDir) && readdirSync(plan.stateDir).length === 0) {
|
|
110
|
+
rmSync(plan.stateDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
return { removedState, keptState: keep };
|
|
113
|
+
}
|
|
64
114
|
export async function cmdUninstall(args) {
|
|
65
115
|
if (args.includes("--help") || args.includes("-h")) {
|
|
66
|
-
console.log("\n Usage: repoos uninstall [--yes]\n\n Remove the
|
|
116
|
+
console.log("\n Usage: repoos uninstall [--yes]\n\n Remove the standalone install created by install.sh (~/.local/share/repoos,\n or a legacy ~/.repoos payload) and machine state under ~/.repoos\n (servers, services.json, local-check-slots, agent-run-tmp).\n Other files in ~/.repoos are listed and left in place.\n Per-repo files are not removed. A package-manager install is not deleted;\n the command prints that package manager's uninstall and any state left behind.\n");
|
|
67
117
|
return;
|
|
68
118
|
}
|
|
69
119
|
const entryPath = fileURLToPath(import.meta.url);
|
|
70
120
|
const root = dirname(dirname(entryPath));
|
|
71
|
-
if (root
|
|
72
|
-
printPackageManagerRemoval();
|
|
121
|
+
if (packageManagerUpgrade(root)) {
|
|
122
|
+
printPackageManagerRemoval(homedir());
|
|
73
123
|
return;
|
|
74
124
|
}
|
|
75
125
|
const plan = standaloneUninstallPlan(entryPath);
|
|
@@ -86,26 +136,39 @@ export async function cmdUninstall(args) {
|
|
|
86
136
|
return;
|
|
87
137
|
}
|
|
88
138
|
if (!(await confirm())) {
|
|
89
|
-
console.log(c.dim(" Kept the standalone RepoOS install."));
|
|
139
|
+
console.log(c.dim(" Kept the standalone RepoOS install and machine state."));
|
|
90
140
|
return;
|
|
91
141
|
}
|
|
92
142
|
}
|
|
143
|
+
let removed;
|
|
93
144
|
try {
|
|
94
|
-
|
|
95
|
-
rmSync(plan.launcherPath, { force: true });
|
|
96
|
-
rmSync(plan.installDir, { recursive: true, force: true });
|
|
145
|
+
removed = removeStandalone(plan);
|
|
97
146
|
}
|
|
98
147
|
catch (e) {
|
|
99
148
|
console.error(c.red(" Failed to remove the standalone install: " + e.message));
|
|
100
149
|
process.exitCode = 1;
|
|
101
150
|
return;
|
|
102
151
|
}
|
|
103
|
-
console.log(c.green(
|
|
152
|
+
console.log(c.green(` Removed the standalone RepoOS install at ${plan.installDir}.`));
|
|
104
153
|
if (plan.launcherPath) {
|
|
105
154
|
console.log(c.dim(` Removed launcher: ${plan.launcherPath}`));
|
|
106
155
|
}
|
|
107
156
|
else {
|
|
108
157
|
console.log(c.dim(" Kept ~/.local/bin/repoos because it is not the launcher this install created."));
|
|
109
158
|
}
|
|
110
|
-
|
|
159
|
+
if (removed.removedState.length > 0) {
|
|
160
|
+
console.log(c.dim(" Removed machine state:"));
|
|
161
|
+
for (const name of removed.removedState) {
|
|
162
|
+
console.log(c.dim(` ${join(plan.stateDir, name)}`));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log(c.dim(" No RepoOS machine state entries were present under ~/.repoos."));
|
|
167
|
+
}
|
|
168
|
+
if (removed.keptState.length > 0) {
|
|
169
|
+
console.log(c.dim(" Left these entries in ~/.repoos (not created by RepoOS):"));
|
|
170
|
+
for (const name of removed.keptState)
|
|
171
|
+
console.log(c.dim(` ${join(plan.stateDir, name)}`));
|
|
172
|
+
}
|
|
173
|
+
console.log(c.dim(" Per-repo files were not removed (repoos.toml and each repo's .repoos/ directory)."));
|
|
111
174
|
}
|