@repo-os/repoos 0.5.54 → 0.5.56
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 -11
- package/dist/.build-info.json +2 -2
- package/dist/.build-stamp.json +1 -1
- package/dist/commands/check.js +18 -2
- package/dist/commands/init.js +19 -7
- package/dist/commands/tasks.d.ts +51 -31
- package/dist/commands/tasks.js +91 -31
- package/dist/core/config.js +2 -2
- package/dist/core/doctor.js +2 -2
- package/dist/core/input.d.ts +5 -1
- package/dist/core/input.js +34 -8
- package/dist/core/needs-input.d.ts +8 -0
- package/dist/core/needs-input.js +13 -0
- package/dist/core/repo-log.d.ts +78 -0
- package/dist/core/repo-log.js +322 -0
- package/dist/core/story-display.d.ts +17 -2
- package/dist/core/story-display.js +6 -0
- package/dist/core/types.d.ts +16 -3
- package/dist/core/types.js +4 -0
- package/dist/server/agents.d.ts +74 -2
- package/dist/server/agents.js +239 -55
- package/dist/server/cto-monitor.d.ts +3 -1
- package/dist/server/cto-monitor.js +16 -2
- package/dist/server/handoff-request.d.ts +29 -0
- package/dist/server/handoff-request.js +103 -0
- package/dist/server/handoff.d.ts +42 -8
- package/dist/server/handoff.js +272 -212
- package/dist/server/needs-input-dismiss.d.ts +6 -0
- package/dist/server/needs-input-dismiss.js +38 -0
- package/dist/server/review.js +5 -3
- package/dist/server/routes/index.d.ts +1 -0
- package/dist/server/routes/index.js +1 -0
- package/dist/server/routes/inputs.js +17 -4
- package/dist/server/routes/repo-log.d.ts +8 -0
- package/dist/server/routes/repo-log.js +67 -0
- package/dist/server/routes/tasks.d.ts +1 -0
- package/dist/server/routes/tasks.js +48 -10
- package/dist/server/routes/types.d.ts +18 -0
- package/dist/server/server.js +173 -55
- package/dist/server/task-watchdog.js +15 -11
- package/dist/ui/assets/AgentsView-CqkgzCze.js +1 -0
- package/dist/ui/assets/ChecksView-Doy8ZRcs.js +0 -0
- package/dist/ui/assets/ContextView-BKPMIh5Q.css +1 -0
- package/dist/ui/assets/ContextView-HTKy3bOH.js +4 -0
- package/dist/ui/assets/DashboardView-DP7D-o1S.js +1 -0
- package/dist/ui/assets/DeploymentsView-BRgF6h-S.js +1 -0
- package/dist/ui/assets/DiffView-B9-i6C6C.css +1 -0
- package/dist/ui/assets/DiffView-g587DbeS.js +4 -0
- package/dist/ui/assets/InputsView-BLhcZaQg.js +1 -0
- package/dist/ui/assets/InputsView-CAOnQPzO.css +1 -0
- package/dist/ui/assets/{LoginView-CV_1xAvv.js → LoginView-BKLriI-b.js} +1 -1
- package/dist/ui/assets/ReleasesView-BpUqzAYv.js +3 -0
- package/dist/ui/assets/SettingsView-DkZ64CDa.js +4 -0
- package/dist/ui/assets/StoriesView-BLX17KW4.css +1 -0
- package/dist/ui/assets/StoriesView-BqHkUyKa.js +1 -0
- package/dist/ui/assets/WorkView-Dpkonfs7.js +2 -0
- package/dist/ui/assets/{abnfDiagram-VCTEODGH-CTfjwe9G.js → abnfDiagram-VCTEODGH-C6WykvNa.js} +1 -1
- package/dist/ui/assets/architecture-7GRP2DOG-BobXoPbG.js +1 -0
- package/dist/ui/assets/{architectureDiagram-5GKGNRK7-CVfIBdXM.js → architectureDiagram-5GKGNRK7-roEGL8m0.js} +1 -1
- package/dist/ui/assets/{blockDiagram-I7D4REHJ-DHrovPE1.js → blockDiagram-I7D4REHJ-DJuucocN.js} +1 -1
- package/dist/ui/assets/button-DQcC_aLE.js +1 -0
- package/dist/ui/assets/{c4Diagram-7LVT6UL2-D1_IKyVU.js → c4Diagram-7LVT6UL2-6sUrKoSN.js} +1 -1
- package/dist/ui/assets/channel-Cy_U0xgO.js +1 -0
- package/dist/ui/assets/{chunk-4HAMMTFA-BQK2Qs9d.js → chunk-4HAMMTFA-J0_pcEVf.js} +1 -1
- package/dist/ui/assets/{chunk-75Z2AOVW-C560CV9I.js → chunk-75Z2AOVW-BxJ2TNvr.js} +1 -1
- package/dist/ui/assets/{chunk-DU6HZSFF-BX9aRA1h.js → chunk-DU6HZSFF-BX0XMIVw.js} +1 -1
- package/dist/ui/assets/{chunk-F27PBJKO-MId0AvWB.js → chunk-F27PBJKO-atSjCf8v.js} +1 -1
- package/dist/ui/assets/{chunk-GMAD6QVW-B8uV52pK.js → chunk-GMAD6QVW-Bos7znjM.js} +1 -1
- package/dist/ui/assets/{chunk-GVQU2GXP-BHRWhJBs.js → chunk-GVQU2GXP-Co0d8Tfs.js} +1 -1
- package/dist/ui/assets/{chunk-IMKFNOWR-C2p26tmJ.js → chunk-IMKFNOWR-DkOJUS_A.js} +1 -1
- package/dist/ui/assets/{chunk-L3NEJ4N5-CiNIjzhG.js → chunk-L3NEJ4N5-GBmbBw5A.js} +1 -1
- package/dist/ui/assets/{chunk-OSK3NFVY-DOZ8UOk-.js → chunk-OSK3NFVY-Pao3zNLe.js} +1 -1
- package/dist/ui/assets/{chunk-P2QGCYS3-CWkpd0sS.js → chunk-P2QGCYS3-NVMl_E1J.js} +1 -1
- package/dist/ui/assets/{chunk-POPQ4Y6H-C_jAEIPq.js → chunk-POPQ4Y6H-tzZL78RS.js} +1 -1
- package/dist/ui/assets/{chunk-PWAF6VOD-DlV-Z1d6.js → chunk-PWAF6VOD-DwrkqNeH.js} +1 -1
- package/dist/ui/assets/{chunk-SHT3W25Y-CDcQrQRH.js → chunk-SHT3W25Y-8I7NMlT4.js} +1 -1
- package/dist/ui/assets/{chunk-SVP7TREG-CXMcWUhi.js → chunk-SVP7TREG-BpweZcGw.js} +1 -1
- package/dist/ui/assets/{chunk-TICWLB2K-C9NkrBRa.js → chunk-TICWLB2K-B8ZvCXdY.js} +1 -1
- package/dist/ui/assets/classDiagram-ZZMXUADV-DentwTwE.js +1 -0
- package/dist/ui/assets/classDiagram-v2-VYDZK3BY-DentwTwE.js +1 -0
- package/dist/ui/assets/config-Cl3iDM_B.js +1 -0
- package/dist/ui/assets/{cynefin-OW5HDTMX-BOREGtlU.js → cynefin-OW5HDTMX-BHvKo-Aq.js} +1 -1
- package/dist/ui/assets/{cynefinDiagram-5FMLGOSQ-B4ry75uw.js → cynefinDiagram-5FMLGOSQ-3kuG-1VM.js} +1 -1
- package/dist/ui/assets/{dagre-GXQ25YYZ-DaFuaEbQ.js → dagre-GXQ25YYZ-2P8Yk_4G.js} +1 -1
- package/dist/ui/assets/{diagram-S7CK7UJ4-CWKov5PL.js → diagram-S7CK7UJ4-DRs3pJcK.js} +1 -1
- package/dist/ui/assets/{diagram-UQ7AKVKN-BIaDBoBe.js → diagram-UQ7AKVKN-B3pbA6Zl.js} +1 -1
- package/dist/ui/assets/{diagram-VSXAHHWV-BjTKaekf.js → diagram-VSXAHHWV-BmFgGjHb.js} +1 -1
- package/dist/ui/assets/{diagram-VX7I27RA-Yx3scpQA.js → diagram-VX7I27RA-D5jJPu_a.js} +1 -1
- package/dist/ui/assets/{diagram-Z3DM3KII-Zj02SBoH.js → diagram-Z3DM3KII-cCr1BFg7.js} +1 -1
- package/dist/ui/assets/{ebnfDiagram-PWID7BFC-0YAqIwpj.js → ebnfDiagram-PWID7BFC-Dg1VhPuY.js} +1 -1
- package/dist/ui/assets/{erDiagram-RLTQ6QDP-D1qzM_C2.js → erDiagram-RLTQ6QDP-CT4xW2dC.js} +1 -1
- package/dist/ui/assets/eventmodeling-NTZA5JFV-C-x4iElw.js +1 -0
- package/dist/ui/assets/flowDiagram-HODETNUW-BSzze3T9.js +1 -0
- package/dist/ui/assets/{ganttDiagram-EL5Y4UJY-BfFGqNAR.js → ganttDiagram-EL5Y4UJY-Hc1my0Jy.js} +1 -1
- package/dist/ui/assets/{gitGraph-4MIJSDKK-C8Hio8mK.js → gitGraph-4MIJSDKK-ClQZHGcg.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-WWUBYQGX-zDzdEhVR.js → gitGraphDiagram-WWUBYQGX-BwlfrDKb.js} +1 -1
- package/dist/ui/assets/index-CWATVnBi.css +1 -0
- package/dist/ui/assets/index-ChI6cY4t.js +35 -0
- package/dist/ui/assets/{info-A6RAGUB7-Co-frmaH.js → info-A6RAGUB7-GHiNutT4.js} +1 -1
- package/dist/ui/assets/{infoDiagram-27XIBGKW-C8vJrt_c.js → infoDiagram-27XIBGKW-B5tfXwvj.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-5VMMS53U-BGO19EHJ.js → ishikawaDiagram-5VMMS53U-B8G11EdJ.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-3NMN7TZE-DduoU3Je.js → journeyDiagram-3NMN7TZE-ubCuNa3S.js} +1 -1
- package/dist/ui/assets/{kanban-definition-UXKFOSKX-D7pp8Jfx.js → kanban-definition-UXKFOSKX-RHlFG4is.js} +1 -1
- package/dist/ui/assets/{line-un3qDwwl.js → line-DMrn1eUc.js} +1 -1
- package/dist/ui/assets/{mermaid-parser.core-BbfKCEpr.js → mermaid-parser.core-D_ycqYZL.js} +3 -3
- package/dist/ui/assets/{mermaid.core-BN7qhUmq.js → mermaid.core-CaXJ86pu.js} +4 -4
- package/dist/ui/assets/{mindmap-definition-YA3MSWOX-BYD5kmA5.js → mindmap-definition-YA3MSWOX-kx1nN_cJ.js} +1 -1
- package/dist/ui/assets/{packet-AYTQ26CC-C4FJPnFC.js → packet-AYTQ26CC-L5erT19p.js} +1 -1
- package/dist/ui/assets/{pegDiagram-XKGWAZYB-DsBi7Fms.js → pegDiagram-XKGWAZYB-C_KTXpQM.js} +1 -1
- package/dist/ui/assets/{pie-WAS4IAKB-C79YZGPK.js → pie-WAS4IAKB-q2S3rGf9.js} +1 -1
- package/dist/ui/assets/{pieDiagram-E7YTZNPT-BkOWAtjO.js → pieDiagram-E7YTZNPT-BLHxbu3z.js} +1 -1
- package/dist/ui/assets/{quadrantDiagram-AXDQQJYC-4cKZyntK.js → quadrantDiagram-AXDQQJYC-DNxwy4on.js} +1 -1
- package/dist/ui/assets/{radar-RG4KPBEZ-BRRdMOI4.js → radar-RG4KPBEZ-5paFbTrA.js} +1 -1
- package/dist/ui/assets/{railroad-74A4TZTK-Bbhl18lT.js → railroad-74A4TZTK-C4zNgPiH.js} +1 -1
- package/dist/ui/assets/railroad-abnf-HS5TGJTU-BXfjNyx0.js +1 -0
- package/dist/ui/assets/railroad-ebnf-LZEXJU2U-jn0Yk9uc.js +1 -0
- package/dist/ui/assets/railroad-peg-WCYAUIDC-Cv8anGyJ.js +1 -0
- package/dist/ui/assets/{railroadDiagram-O6MQD6OU-Bbg60dv2.js → railroadDiagram-O6MQD6OU-VmXZ6m0T.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-BXWQKSXE-DoLwPzhb.js → requirementDiagram-BXWQKSXE-BHuX0BwK.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-P5KCCOFB-BVBS_VZc.js → sankeyDiagram-P5KCCOFB-5kDwMhVC.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-WJ2MYXX4-BACpdW4n.js → sequenceDiagram-WJ2MYXX4-KSqKjCpq.js} +1 -1
- package/dist/ui/assets/{stateDiagram-D77RDMKH-DlGZE9N1.js → stateDiagram-D77RDMKH-A_P_Un-0.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-BuGnvM9I.js +1 -0
- package/dist/ui/assets/{swimlanes-42K2YHIH-DLQ7Vteo.js → swimlanes-42K2YHIH-BMAnXKSs.js} +1 -1
- package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-DK-DtsW-.js +8 -0
- package/dist/ui/assets/{timeline-definition-24CTP7MA-b99HY5j-.js → timeline-definition-24CTP7MA-BWweJQmR.js} +1 -1
- package/dist/ui/assets/title-ComEuLCp.js +1 -0
- package/dist/ui/assets/{treeView-Q6P3EWNA-BKXQAE6F.js → treeView-Q6P3EWNA-DusMk7Rp.js} +1 -1
- package/dist/ui/assets/{treemap-WGGIJYW6-CZj1ym9X.js → treemap-WGGIJYW6-BoIcxm2V.js} +1 -1
- package/dist/ui/assets/vendor-ui-DFGj-ZXN.js +3 -0
- package/dist/ui/assets/{vennDiagram-4TSXK5OY-Syj4tlui.js → vennDiagram-4TSXK5OY-DENh7Izt.js} +1 -1
- package/dist/ui/assets/{wardley-WFR3VGLG-W_snBoVU.js → wardley-WFR3VGLG-D-IbkF5y.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-VM6X3IG4-BnpA19Oz.js → wardleyDiagram-VM6X3IG4-Cwsu4-ww.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-S5SC5T6Z-g474RiA-.js → xychartDiagram-S5SC5T6Z-wZXsbj8s.js} +1 -1
- package/dist/ui/index.html +6 -3
- package/dist/ui/sw.js +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/AgentsView-UghV_I0u.js +0 -1
- package/dist/ui/assets/ChecksView-CE9_UWEH.js +0 -0
- package/dist/ui/assets/ContextView-C3cJribS.js +0 -4
- package/dist/ui/assets/ContextView-TVoMpCso.css +0 -1
- package/dist/ui/assets/DashboardView-DydNm09c.js +0 -1
- package/dist/ui/assets/DeploymentsView-DVMkUs04.js +0 -1
- package/dist/ui/assets/DiffView-BpW0Agf3.css +0 -1
- package/dist/ui/assets/DiffView-CCOUztfU.js +0 -4
- package/dist/ui/assets/InputsView-CgH2DwWm.css +0 -1
- package/dist/ui/assets/InputsView-uzRKFx_8.js +0 -1
- package/dist/ui/assets/ReleasesView-CMTPaJGR.js +0 -3
- package/dist/ui/assets/SettingsView-3Y2d6VYS.js +0 -4
- package/dist/ui/assets/StoriesView-DGnU5Cy9.js +0 -1
- package/dist/ui/assets/StoriesView-DTqtvuk_.css +0 -1
- package/dist/ui/assets/TaskCard-hX9bZtBs.js +0 -1
- package/dist/ui/assets/WorkView-DpL4RTSC.js +0 -2
- package/dist/ui/assets/architecture-7GRP2DOG-iLDzG2hD.js +0 -1
- package/dist/ui/assets/channel-C2SsuvKM.js +0 -1
- package/dist/ui/assets/classDiagram-ZZMXUADV-DOc-KWik.js +0 -1
- package/dist/ui/assets/classDiagram-v2-VYDZK3BY-DOc-KWik.js +0 -1
- package/dist/ui/assets/eventmodeling-NTZA5JFV-DoMudewO.js +0 -1
- package/dist/ui/assets/flowDiagram-HODETNUW-COa-0qtC.js +0 -1
- package/dist/ui/assets/index-CxZVHdeX.js +0 -35
- package/dist/ui/assets/index-DCiwKRGz.css +0 -1
- package/dist/ui/assets/railroad-abnf-HS5TGJTU-DP10zylu.js +0 -1
- package/dist/ui/assets/railroad-ebnf-LZEXJU2U-CD0qyNXa.js +0 -1
- package/dist/ui/assets/railroad-peg-WCYAUIDC-B4QvCxtr.js +0 -1
- package/dist/ui/assets/stateDiagram-v2-MP3YSRHH-BAXOtgDm.js +0 -1
- package/dist/ui/assets/swimlanesDiagram-VR7AAH4N-BBsmj1pm.js +0 -8
- package/dist/ui/assets/vendor-ui-Cke7Wpgg.js +0 -3
package/README.md
CHANGED
|
@@ -298,21 +298,22 @@ no API tokens leave your machine unless you configure them.
|
|
|
298
298
|
|
|
299
299
|
## RepoOS Hub for macOS
|
|
300
300
|
|
|
301
|
-
A native Mac app (macOS 13+; sessions persist across relaunches on
|
|
302
|
-
|
|
303
|
-
one window
|
|
304
|
-
and Dock badge, and jump between servers and tasks with Cmd-K. Each
|
|
305
|
-
loads in its own isolated WebKit session — sessions are never shared
|
|
306
|
-
servers, and server pages get no bridge into your files or Keychain.
|
|
307
|
-
loopback servers need zero setup; remote servers use short-lived,
|
|
308
|
-
capability tokens (created over HTTPS on the server, stored in the
|
|
309
|
-
for their attention and search endpoints.
|
|
301
|
+
A native Mac companion app (macOS 13+; sessions persist across relaunches on
|
|
302
|
+
macOS 14+) that connects to the RepoOS servers you run locally or remotely.
|
|
303
|
+
From one window, pin tasks across servers, see live attention counts in the
|
|
304
|
+
sidebar and Dock badge, and jump between servers and tasks with Cmd-K. Each
|
|
305
|
+
server loads in its own isolated WebKit session — sessions are never shared
|
|
306
|
+
between servers, and server pages get no bridge into your files or Keychain.
|
|
307
|
+
Local loopback servers need zero setup; remote servers use short-lived,
|
|
308
|
+
revocable capability tokens (created over HTTPS on the server, stored in the
|
|
309
|
+
Keychain) for their attention and search endpoints.
|
|
310
310
|
|
|
311
311
|
Download the latest [RepoOS Hub DMG](https://github.com/repo-os/repoos/releases/latest/download/RepoOSHub.dmg),
|
|
312
312
|
or browse [GitHub Releases](https://github.com/repo-os/repoos/releases). Setup,
|
|
313
313
|
pairing, and limitation details are in the [Hub guide](https://docs.repoos.org/macos-hub).
|
|
314
|
-
Current builds are ad-hoc signed
|
|
315
|
-
|
|
314
|
+
Current builds are ad-hoc signed and not notarized. After a first blocked launch,
|
|
315
|
+
use **System Settings → Privacy & Security → Open Anyway**; the guide has the
|
|
316
|
+
exact steps. Developer ID signing and notarization are planned.
|
|
316
317
|
|
|
317
318
|
## Roadmap
|
|
318
319
|
|
package/dist/.build-info.json
CHANGED
package/dist/.build-stamp.json
CHANGED
package/dist/commands/check.js
CHANGED
|
@@ -499,6 +499,22 @@ function resolveVar(value, map, depth = 0) {
|
|
|
499
499
|
const next = map[`--${m[1]}`];
|
|
500
500
|
return next !== undefined ? resolveVar(next, map, depth + 1) : value;
|
|
501
501
|
}
|
|
502
|
+
// KNOWN LIMITATION (fix tracked in #0504, found while registering the gruvbox
|
|
503
|
+
// theme in #0503): the rgb()/rgba() branches below tolerate no whitespace between
|
|
504
|
+
// components, but oxfmt writes `rgba(110, 157, 106, 0.22)` with spaces, so every
|
|
505
|
+
// spaced literal fails to parse and returns null. A pair whose fg or bg yields no
|
|
506
|
+
// candidates is SKIPPED rather than failed, so a `[check] contrastPairs` bg token
|
|
507
|
+
// written as a spaced `rgba()` is silently never checked — as are the spaced
|
|
508
|
+
// `rgba()` stops inside a gradient, which drop out of `colorCandidates`. Measured
|
|
509
|
+
// on this repo's own stylesheet: 425 spaced literals, leaving 4-6 of the 9
|
|
510
|
+
// configured pairs unchecked in every theme. A whitespace-tolerant regex (`\s*`
|
|
511
|
+
// after each separator) was measured to produce ZERO new offenders across all five
|
|
512
|
+
// themes, so the fix is a one-liner that only strengthens the gate. It is its own
|
|
513
|
+
// task rather than folded into a theme change because it alters the guard's
|
|
514
|
+
// behaviour repo-wide and for every project that configures
|
|
515
|
+
// `[check] contrastPairs`. Until it lands, do not rely on this guard to catch a
|
|
516
|
+
// contrast problem in a token written as `rgba(r, g, b, a)`; gruvbox deliberately
|
|
517
|
+
// uses 8-digit hex for its checked alpha tokens to stay verifiable.
|
|
502
518
|
function parseColor(v) {
|
|
503
519
|
const s = v.trim().toLowerCase();
|
|
504
520
|
if (!s || s === "none")
|
|
@@ -521,7 +537,7 @@ function parseColor(v) {
|
|
|
521
537
|
}
|
|
522
538
|
return null;
|
|
523
539
|
}
|
|
524
|
-
const m = s.match(/^rgba?\(([\d.]+)
|
|
540
|
+
const m = s.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)$/);
|
|
525
541
|
if (m) {
|
|
526
542
|
return {
|
|
527
543
|
r: parseInt(m[1], 10),
|
|
@@ -556,7 +572,7 @@ function colorCandidates(raw, map, bg) {
|
|
|
556
572
|
const resolved = resolveVar(raw, map);
|
|
557
573
|
const out = [];
|
|
558
574
|
if (resolved.includes("gradient(")) {
|
|
559
|
-
const re = /#[0-9a-fA-F]{3,8}|rgba?\([
|
|
575
|
+
const re = /#[0-9a-fA-F]{3,8}|rgba?\(\s*[\d.]+\s*,\s*[\d.]+\s*,\s*[\d.]+(?:\s*,\s*[\d.]+)?\s*\)|transparent/g;
|
|
560
576
|
let m;
|
|
561
577
|
while ((m = re.exec(resolved))) {
|
|
562
578
|
const c = parseColor(m[0]);
|
package/dist/commands/init.js
CHANGED
|
@@ -101,8 +101,9 @@ ${description
|
|
|
101
101
|
architecture note. Keep them specific to this project.
|
|
102
102
|
4. Break the result into a handful of concrete tasks with
|
|
103
103
|
\`repoos new "<title>"\`, and move the ones that are ready into \`ready\`.
|
|
104
|
-
5. Record the docs you wrote here, then
|
|
105
|
-
\`
|
|
104
|
+
5. Record the docs you wrote here, then hand this task off with
|
|
105
|
+
\`repoos mv <id> review\` and stop — RepoOS runs the checks and moves the
|
|
106
|
+
status (or \`done\` if there is genuinely nothing left to capture).
|
|
106
107
|
|
|
107
108
|
## Notes for AI
|
|
108
109
|
|
|
@@ -140,8 +141,9 @@ then turn what's missing into work.
|
|
|
140
141
|
conventions anyone working here must follow.
|
|
141
142
|
3. Draft a small starter backlog of real tasks with \`repoos new "<title>"\`,
|
|
142
143
|
each concrete enough to work on its own.
|
|
143
|
-
4. Record what you wrote here, then
|
|
144
|
-
|
|
144
|
+
4. Record what you wrote here, then hand this task off with
|
|
145
|
+
\`repoos mv <id> review\` and stop — RepoOS runs the checks and moves the
|
|
146
|
+
status (or \`done\` if there is nothing left to capture).
|
|
145
147
|
|
|
146
148
|
## Notes for AI
|
|
147
149
|
|
|
@@ -160,14 +162,24 @@ repo itself is the source of truth. This file tells AI agents how to operate.
|
|
|
160
162
|
2. Pick a task from \`${workDir}/\` whose \`status: ready\`.
|
|
161
163
|
3. Set its \`status: active\` (edit the frontmatter; do not move the file).
|
|
162
164
|
4. Create a worktree on the branch named in the task's \`branch:\` field, or set one.
|
|
163
|
-
5.
|
|
164
|
-
|
|
165
|
+
5. Run \`repoos check\` and confirm it passes, then implement → test → if the repo
|
|
166
|
+
has a git remote, open an MR/PR against main.
|
|
167
|
+
6. When ready for human sign-off, run \`repoos mv <id> review\` and stop. **That
|
|
168
|
+
records a handoff request; it does not set the status.** RepoOS re-runs the
|
|
169
|
+
check, commits the branch and moves the task to \`review\`. The task stays
|
|
170
|
+
\`active\` until then, and stays \`active\` with the failure shown if the check
|
|
171
|
+
fails. **Leave the worktree open; do NOT merge its branch.**
|
|
165
172
|
|
|
166
173
|
## Review and sign-off
|
|
167
174
|
|
|
168
175
|
A \`review\` task stays in its open worktree until a human (or another AI) signs
|
|
169
176
|
off; the implementer never merges to \`main\` at \`review\` time.
|
|
170
177
|
|
|
178
|
+
Every route into \`review\` — the Review button, a board drag, a
|
|
179
|
+
\`PATCH status: review\`, \`repoos mv\`, or an agent's handoff signal — runs the
|
|
180
|
+
same finalization: scoped \`repoos check\`, then the commit guard, then
|
|
181
|
+
\`review\`. Nothing reaches \`review\` on the commit guard alone.
|
|
182
|
+
|
|
171
183
|
- No git remote: on approval, the reviewer says **"move task <id> to done"**. The
|
|
172
184
|
implementer then sets \`status: done\` (commit \`docs(<id>): set status done\`),
|
|
173
185
|
fast-forward merges the branch to \`main\`, removes the worktree, and deletes
|
|
@@ -177,7 +189,7 @@ off; the implementer never merges to \`main\` at \`review\` time.
|
|
|
177
189
|
<id> to done"), then remote + local branches are deleted and \`status\` is set
|
|
178
190
|
to \`done\`.
|
|
179
191
|
- Requested changes are fixed on the same worktree, tests re-run, and the task
|
|
180
|
-
|
|
192
|
+
handed off again.
|
|
181
193
|
- If the \`reviewer\` agent is enabled on the Agents page, RepoOS reviews the
|
|
182
194
|
task automatically when it lands in \`review\` and shows a short report (bugs,
|
|
183
195
|
edge cases, suggestions) in the task drawer. It is advisory: the human still
|
package/dist/commands/tasks.d.ts
CHANGED
|
@@ -2,41 +2,61 @@
|
|
|
2
2
|
export declare function cmdList(statusArg?: string): void;
|
|
3
3
|
/** `repoos show <id>` — full task detail. */
|
|
4
4
|
export declare function cmdShow(id?: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* True when this process is a managed agent working on `id` — the runner
|
|
7
|
+
* injects `REPOOS_AGENT=1` into every managed agent process, and
|
|
8
|
+
* `REPOOS_TASK_ID` / `REPOOS_RUN_ID` into a task turn (agents.ts). Both must
|
|
9
|
+
* match: without the run id the recorded request could not be tied to a live
|
|
10
|
+
* turn, and without the task id this would hijack `repoos mv` calls an agent
|
|
11
|
+
* makes about some OTHER task. A human in their own shell has neither, so they
|
|
12
|
+
* keep the plain status edit (which the server still runs through the same
|
|
13
|
+
* finalization via the file-watch route).
|
|
14
|
+
*/
|
|
15
|
+
export declare function isRunnerSessionForTask(id: string): boolean;
|
|
5
16
|
/**
|
|
6
17
|
* `repoos mv <id> <status>` — change status (frontmatter edit).
|
|
7
18
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* the
|
|
23
|
-
*
|
|
19
|
+
* Two transitions are special-cased, because both are ones this command
|
|
20
|
+
* cannot perform on its own.
|
|
21
|
+
*
|
|
22
|
+
* **`review` from inside the runner session for that same task (#0507)** does
|
|
23
|
+
* NOT flip `status:`. It records a handoff request in the board's cache dir
|
|
24
|
+
* (`.repoos/handoff-requests/<id>.json`) and exits 0; the runner picks that up
|
|
25
|
+
* exactly like the `::repoos-handoff-ready::` signal and finalizes when the
|
|
26
|
+
* turn ends — scoped `repoos check`, then the commit/vacuity gate, then
|
|
27
|
+
* `review`. This is the single most-used route in practice: engineers reach for
|
|
28
|
+
* it because the CTO nudge says "hand off to review" and the operating loop
|
|
29
|
+
* says "set `status: review`". A bare frontmatter write is not a handoff — it
|
|
30
|
+
* skips the check, and because the task leaves `active` the server stops the
|
|
31
|
+
* very agent that asked, which `cleanup()` then books as a dev error (#0505,
|
|
32
|
+
* #0499: "needs input" next to "waiting for human" on a task that passed
|
|
33
|
+
* review). Detection is the runner's own marker — `REPOOS_AGENT=1` plus a
|
|
34
|
+
* `REPOOS_TASK_ID` equal to the id being moved — so a human running the same
|
|
35
|
+
* command in their own shell still gets a plain status edit, picked up by the
|
|
36
|
+
* server and run through the same finalization via the file-watch route.
|
|
37
|
+
*
|
|
38
|
+
* `done` gets a narrow guard for the mirror-image reason (confirmed live,
|
|
39
|
+
* 2026-09-17 — see #0399 and the #0185/#0389 incidents in this session):
|
|
40
|
+
* unlike every other status, `done` claims the task's code is actually on
|
|
41
|
+
* `main`. The server's own HTTP PATCH route already refuses a bare
|
|
42
|
+
* `status: "done"` for exactly this reason (routes/tasks.ts) and forces callers
|
|
43
|
+
* through `POST /api/tasks/:id/done`, the real close-out pipeline — but this CLI
|
|
44
|
+
* command never went through that route to begin with, so it silently flips the
|
|
45
|
+
* flag with zero merge awareness. If the task has a `branch` that still exists
|
|
46
|
+
* locally and is NOT an ancestor of main, that branch's code has not landed;
|
|
47
|
+
* refuse rather than mark it done from under the user. This intentionally fails
|
|
48
|
+
* OPEN (allows the move) whenever it can't tell for sure — no branch recorded,
|
|
49
|
+
* the branch was already deleted (the normal post-merge cleanup), or git can't
|
|
50
|
+
* answer the ancestry question — so it never blocks the many legitimate `mv`
|
|
51
|
+
* calls that have nothing to do with code at all.
|
|
24
52
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* silently flips the flag with zero merge awareness. If the task has a
|
|
33
|
-
* `branch` that still exists locally and is NOT an ancestor of main, that
|
|
34
|
-
* branch's code has not landed; refuse rather than mark it done from under
|
|
35
|
-
* the user. This intentionally fails OPEN (allows the move) whenever it
|
|
36
|
-
* can't tell for sure — no branch recorded, the branch was already deleted
|
|
37
|
-
* (the normal post-merge cleanup), or git can't answer the ancestry question
|
|
38
|
-
* — so it never blocks the many legitimate `mv` calls that have nothing to
|
|
39
|
-
* do with code at all.
|
|
53
|
+
* Every other status is a plain frontmatter edit. `updateStatus` (via
|
|
54
|
+
* `rewrite()` in core/repoos.ts) always commits the task file in the main
|
|
55
|
+
* checkout, so the write itself is never left as an untrusted dirty file. Note
|
|
56
|
+
* that a move into `review` from OUTSIDE a runner session still goes through
|
|
57
|
+
* the full server-side finalization — the server intercepts the file write and
|
|
58
|
+
* runs the same check the handoff signal does, keeping the task `active` until
|
|
59
|
+
* it passes.
|
|
40
60
|
*/
|
|
41
61
|
export declare function cmdMv(id?: string, status?: string, note?: string, opts?: {
|
|
42
62
|
force?: boolean;
|
package/dist/commands/tasks.js
CHANGED
|
@@ -13,6 +13,7 @@ import { boardRoot, loadConfig, resolveColumnLabels } from "../core/config.js";
|
|
|
13
13
|
import { STATUSES } from "../core/types.js";
|
|
14
14
|
import { c, statusColor, priorityColor } from "../cli/colors.js";
|
|
15
15
|
import { patchTaskFile } from "../server/write.js";
|
|
16
|
+
import { writeHandoffRequest } from "../server/handoff-request.js";
|
|
16
17
|
import { isAncestor } from "../core/git.js";
|
|
17
18
|
/**
|
|
18
19
|
* RepoOS facade rooted at the LIVE BOARD's checkout (the main checkout), even
|
|
@@ -136,41 +137,98 @@ function detectMainBranch(root) {
|
|
|
136
137
|
}
|
|
137
138
|
return null;
|
|
138
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* True when this process is a managed agent working on `id` — the runner
|
|
142
|
+
* injects `REPOOS_AGENT=1` into every managed agent process, and
|
|
143
|
+
* `REPOOS_TASK_ID` / `REPOOS_RUN_ID` into a task turn (agents.ts). Both must
|
|
144
|
+
* match: without the run id the recorded request could not be tied to a live
|
|
145
|
+
* turn, and without the task id this would hijack `repoos mv` calls an agent
|
|
146
|
+
* makes about some OTHER task. A human in their own shell has neither, so they
|
|
147
|
+
* keep the plain status edit (which the server still runs through the same
|
|
148
|
+
* finalization via the file-watch route).
|
|
149
|
+
*/
|
|
150
|
+
export function isRunnerSessionForTask(id) {
|
|
151
|
+
return (process.env.REPOOS_AGENT === "1" &&
|
|
152
|
+
Boolean(process.env.REPOOS_RUN_ID) &&
|
|
153
|
+
process.env.REPOOS_TASK_ID === id);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* #0507: record a handoff request instead of flipping `status: review`, when
|
|
157
|
+
* the task's own agent is the one asking. Returns true when the request was
|
|
158
|
+
* recorded and `cmdMv` must stop there. On failure it returns false so the
|
|
159
|
+
* caller falls through to the ordinary status edit — worse, but never a dead
|
|
160
|
+
* end for the agent mid-turn.
|
|
161
|
+
*/
|
|
162
|
+
function handoffRequestFromRunner(id) {
|
|
163
|
+
if (!isRunnerSessionForTask(id))
|
|
164
|
+
return false;
|
|
165
|
+
const { root } = boardRoot();
|
|
166
|
+
const request = {
|
|
167
|
+
taskId: id,
|
|
168
|
+
runId: process.env.REPOOS_RUN_ID,
|
|
169
|
+
at: new Date().toISOString(),
|
|
170
|
+
source: "repoos-mv",
|
|
171
|
+
};
|
|
172
|
+
if (!writeHandoffRequest(root, loadConfig(root).cacheDir, request)) {
|
|
173
|
+
console.error(c.red(` Could not record a handoff request for #${id} — `) +
|
|
174
|
+
c.dim("RepoOS could not write its handoff-request file."));
|
|
175
|
+
console.error(c.dim(" Falling back to a plain status edit, which SKIPS the checks and stops this " +
|
|
176
|
+
"agent mid-turn. Prefer ending your turn and letting the reviewer pick it up."));
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
console.log(" " +
|
|
180
|
+
c.green("handoff requested ") +
|
|
181
|
+
c.dim("#" + id) +
|
|
182
|
+
c.dim(" —") +
|
|
183
|
+
"\n" +
|
|
184
|
+
c.dim(" RepoOS will run `repoos check`, pass the commit gate, and move this to review."));
|
|
185
|
+
console.log(c.dim(" `status:` was left alone — end your turn now; finalization runs on exit."));
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
139
188
|
/**
|
|
140
189
|
* `repoos mv <id> <status>` — change status (frontmatter edit).
|
|
141
190
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* the
|
|
157
|
-
*
|
|
191
|
+
* Two transitions are special-cased, because both are ones this command
|
|
192
|
+
* cannot perform on its own.
|
|
193
|
+
*
|
|
194
|
+
* **`review` from inside the runner session for that same task (#0507)** does
|
|
195
|
+
* NOT flip `status:`. It records a handoff request in the board's cache dir
|
|
196
|
+
* (`.repoos/handoff-requests/<id>.json`) and exits 0; the runner picks that up
|
|
197
|
+
* exactly like the `::repoos-handoff-ready::` signal and finalizes when the
|
|
198
|
+
* turn ends — scoped `repoos check`, then the commit/vacuity gate, then
|
|
199
|
+
* `review`. This is the single most-used route in practice: engineers reach for
|
|
200
|
+
* it because the CTO nudge says "hand off to review" and the operating loop
|
|
201
|
+
* says "set `status: review`". A bare frontmatter write is not a handoff — it
|
|
202
|
+
* skips the check, and because the task leaves `active` the server stops the
|
|
203
|
+
* very agent that asked, which `cleanup()` then books as a dev error (#0505,
|
|
204
|
+
* #0499: "needs input" next to "waiting for human" on a task that passed
|
|
205
|
+
* review). Detection is the runner's own marker — `REPOOS_AGENT=1` plus a
|
|
206
|
+
* `REPOOS_TASK_ID` equal to the id being moved — so a human running the same
|
|
207
|
+
* command in their own shell still gets a plain status edit, picked up by the
|
|
208
|
+
* server and run through the same finalization via the file-watch route.
|
|
158
209
|
*
|
|
159
|
-
* `done` gets
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
210
|
+
* `done` gets a narrow guard for the mirror-image reason (confirmed live,
|
|
211
|
+
* 2026-09-17 — see #0399 and the #0185/#0389 incidents in this session):
|
|
212
|
+
* unlike every other status, `done` claims the task's code is actually on
|
|
213
|
+
* `main`. The server's own HTTP PATCH route already refuses a bare
|
|
214
|
+
* `status: "done"` for exactly this reason (routes/tasks.ts) and forces callers
|
|
215
|
+
* through `POST /api/tasks/:id/done`, the real close-out pipeline — but this CLI
|
|
216
|
+
* command never went through that route to begin with, so it silently flips the
|
|
217
|
+
* flag with zero merge awareness. If the task has a `branch` that still exists
|
|
218
|
+
* locally and is NOT an ancestor of main, that branch's code has not landed;
|
|
219
|
+
* refuse rather than mark it done from under the user. This intentionally fails
|
|
220
|
+
* OPEN (allows the move) whenever it can't tell for sure — no branch recorded,
|
|
221
|
+
* the branch was already deleted (the normal post-merge cleanup), or git can't
|
|
222
|
+
* answer the ancestry question — so it never blocks the many legitimate `mv`
|
|
223
|
+
* calls that have nothing to do with code at all.
|
|
224
|
+
*
|
|
225
|
+
* Every other status is a plain frontmatter edit. `updateStatus` (via
|
|
226
|
+
* `rewrite()` in core/repoos.ts) always commits the task file in the main
|
|
227
|
+
* checkout, so the write itself is never left as an untrusted dirty file. Note
|
|
228
|
+
* that a move into `review` from OUTSIDE a runner session still goes through
|
|
229
|
+
* the full server-side finalization — the server intercepts the file write and
|
|
230
|
+
* runs the same check the handoff signal does, keeping the task `active` until
|
|
231
|
+
* it passes.
|
|
174
232
|
*/
|
|
175
233
|
export function cmdMv(id, status, note, opts = {}) {
|
|
176
234
|
if (!id || !status) {
|
|
@@ -186,6 +244,8 @@ export function cmdMv(id, status, note, opts = {}) {
|
|
|
186
244
|
// .git) is a silent no-op from the board's perspective.
|
|
187
245
|
const repoos = boardRepoOS();
|
|
188
246
|
try {
|
|
247
|
+
if (status === "review" && handoffRequestFromRunner(id))
|
|
248
|
+
return;
|
|
189
249
|
if (status === "done" && !opts.force) {
|
|
190
250
|
const existing = repoos.getTask(id);
|
|
191
251
|
if (existing && existing.status !== "done" && existing.branch) {
|
package/dist/core/config.js
CHANGED
|
@@ -1482,12 +1482,12 @@ export function getConfigSchema() {
|
|
|
1482
1482
|
// [board.columns] — display-only label overrides (#0396).
|
|
1483
1483
|
...STATUSES.map((status) => ({
|
|
1484
1484
|
key: `board.columns.${status}`,
|
|
1485
|
-
label:
|
|
1485
|
+
label: `${status.charAt(0).toUpperCase() + status.slice(1)} column`,
|
|
1486
1486
|
type: "string",
|
|
1487
1487
|
tier: "live",
|
|
1488
1488
|
restartRequired: false,
|
|
1489
1489
|
default: DEFAULT_COLUMN_LABELS[status],
|
|
1490
|
-
description: `Display label
|
|
1490
|
+
description: `Display label only — the "${status}" status ID never changes (default: ${DEFAULT_COLUMN_LABELS[status]})`,
|
|
1491
1491
|
})),
|
|
1492
1492
|
];
|
|
1493
1493
|
}
|
package/dist/core/doctor.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { accessSync, constants, existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
20
20
|
import { extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
21
21
|
import { findRepoRoot, isLinkedWorktreeRoot, loadConfig, mainCheckoutRoot, parseFlatToml, projectDisplayName, resolveServePort, SUPPORTED_TOML_KEYS, worktreesDir, } from "./config.js";
|
|
22
|
-
import { STATUSES } from "./types.js";
|
|
22
|
+
import { STATUSES, UI_THEMES } from "./types.js";
|
|
23
23
|
import { checkBuildForRoot } from "./build.js";
|
|
24
24
|
import { detectRepoMarkers, hasBinary, installHint, missingBinaries, prereqDetail, } from "./check-runner.js";
|
|
25
25
|
import { resolveCheckPlan } from "./check-plan.js";
|
|
@@ -187,7 +187,7 @@ export function findConfigValueProblems(parsed) {
|
|
|
187
187
|
enumCheck("defaultAssignee", ["ai", "human", "unassigned"]);
|
|
188
188
|
enumCheck("defaultTaskMode", ["freeform", "manual"]);
|
|
189
189
|
enumCheck("theme", ["dark", "light", "system"]);
|
|
190
|
-
enumCheck("uiTheme",
|
|
190
|
+
enumCheck("uiTheme", UI_THEMES);
|
|
191
191
|
const boolCheck = (key) => {
|
|
192
192
|
const v = get(key);
|
|
193
193
|
if (v !== undefined && typeof v !== "boolean") {
|
package/dist/core/input.d.ts
CHANGED
|
@@ -47,7 +47,11 @@ export interface Input {
|
|
|
47
47
|
export declare function ensureInputNumbers(c: RepoOSConfig): Input[];
|
|
48
48
|
export declare function listInputs(c: RepoOSConfig): Input[];
|
|
49
49
|
export declare function createInput(c: RepoOSConfig, body: string, type?: string, createdBy?: string): Input;
|
|
50
|
-
export
|
|
50
|
+
export type InputPatch = {
|
|
51
|
+
status?: InputStatus;
|
|
52
|
+
text?: string;
|
|
53
|
+
};
|
|
54
|
+
export declare function updateInput(c: RepoOSConfig, id: string, patch: InputPatch): Input;
|
|
51
55
|
/**
|
|
52
56
|
* Record how an input was resolved and move it to `processed`. `task` stores
|
|
53
57
|
* the created task's id in `resolved_task`; `none` clears it. Both keys are
|
package/dist/core/input.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import { parseDocument } from "./frontmatter.js";
|
|
3
|
+
import { parseDocument, serializeDocument } from "./frontmatter.js";
|
|
4
4
|
const q = (v) => `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
5
5
|
/**
|
|
6
6
|
* Set a frontmatter key in a file's raw content, adding it to the block if it
|
|
@@ -12,6 +12,19 @@ function setField(content, key, value) {
|
|
|
12
12
|
const re = new RegExp(`^${key}:.*$`, "m");
|
|
13
13
|
return re.test(content) ? content.replace(re, line) : content.replace("---\n", `---\n${line}\n`);
|
|
14
14
|
}
|
|
15
|
+
const INPUT_KEY_ORDER = [
|
|
16
|
+
"id",
|
|
17
|
+
"number",
|
|
18
|
+
"title",
|
|
19
|
+
"status",
|
|
20
|
+
"type",
|
|
21
|
+
"area",
|
|
22
|
+
"created_by",
|
|
23
|
+
"created_at",
|
|
24
|
+
"updated_at",
|
|
25
|
+
"resolution",
|
|
26
|
+
"resolved_task",
|
|
27
|
+
];
|
|
15
28
|
const slug = (v) => v
|
|
16
29
|
.toLowerCase()
|
|
17
30
|
.replace(/[^a-z0-9]+/g, "-")
|
|
@@ -135,22 +148,35 @@ export function createInput(c, body, type = "other", createdBy = "") {
|
|
|
135
148
|
].join("\n"));
|
|
136
149
|
return listInputs(c).find((i) => i.id === id);
|
|
137
150
|
}
|
|
138
|
-
export function updateInput(c, id,
|
|
151
|
+
export function updateInput(c, id, patch) {
|
|
152
|
+
if (patch.status === undefined && patch.text === undefined)
|
|
153
|
+
throw new Error("nothing to update");
|
|
139
154
|
const item = listInputs(c).find((i) => i.id === id);
|
|
140
155
|
if (!item)
|
|
141
156
|
throw new Error("input not found");
|
|
142
157
|
const file = join(c.root, item.path);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
const parsed = parseDocument(readFileSync(file, "utf8"));
|
|
159
|
+
const status = patch.status ?? item.status;
|
|
160
|
+
let body = parsed.body.trim();
|
|
161
|
+
let title = String(parsed.data.title ?? item.title);
|
|
162
|
+
if (patch.text !== undefined) {
|
|
163
|
+
body = patch.text.trim();
|
|
164
|
+
title = body.split(/\n/)[0].replace(/^#\s*/, "").slice(0, 100) || "Untitled input";
|
|
165
|
+
}
|
|
166
|
+
const data = {
|
|
167
|
+
...parsed.data,
|
|
168
|
+
status,
|
|
169
|
+
title,
|
|
170
|
+
updated_at: new Date().toISOString(),
|
|
171
|
+
};
|
|
146
172
|
// A manual move out of `processed` invalidates any recorded resolution —
|
|
147
173
|
// leaving it behind would re-display a stale outcome if the input is later
|
|
148
174
|
// marked processed again without a real resolve action.
|
|
149
175
|
if (status !== "processed") {
|
|
150
|
-
|
|
151
|
-
|
|
176
|
+
data.resolution = "";
|
|
177
|
+
data.resolved_task = "";
|
|
152
178
|
}
|
|
153
|
-
writeFileSync(file,
|
|
179
|
+
writeFileSync(file, serializeDocument(data, `${body}\n`, INPUT_KEY_ORDER));
|
|
154
180
|
return listInputs(c).find((i) => i.id === id);
|
|
155
181
|
}
|
|
156
182
|
/**
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Task } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stale `dev-error` on a `review` task: the engineer reached review but a
|
|
4
|
+
* handoff-signal glitch left the flag set (see TaskDrawer banner note).
|
|
5
|
+
*/
|
|
6
|
+
export declare function needsInputSuppressedOnReview(task: Pick<Task, "status" | "needsInput" | "needsInputReason">): boolean;
|
|
7
|
+
/** A successful review run clears these reviewer-episode flags (#0511). */
|
|
8
|
+
export declare function needsInputClearsOnSuccessfulReview(task: Pick<Task, "status" | "needsInputReason">): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stale `dev-error` on a `review` task: the engineer reached review but a
|
|
3
|
+
* handoff-signal glitch left the flag set (see TaskDrawer banner note).
|
|
4
|
+
*/
|
|
5
|
+
export function needsInputSuppressedOnReview(task) {
|
|
6
|
+
return Boolean(task.needsInput && task.status === "review" && task.needsInputReason === "dev-error");
|
|
7
|
+
}
|
|
8
|
+
/** A successful review run clears these reviewer-episode flags (#0511). */
|
|
9
|
+
export function needsInputClearsOnSuccessfulReview(task) {
|
|
10
|
+
if (task.needsInputReason === "review-failed")
|
|
11
|
+
return true;
|
|
12
|
+
return task.needsInputReason === "watchdog-stuck" && task.status === "review";
|
|
13
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only git history for the Context page History tab.
|
|
3
|
+
*
|
|
4
|
+
* Every git invocation is argv (never a shell string). Inputs are validated
|
|
5
|
+
* before they reach `git`. Output is a machine format with unit-separator
|
|
6
|
+
* fields and a NUL record terminator — never parsed from human `git log`
|
|
7
|
+
* pretty-print.
|
|
8
|
+
*/
|
|
9
|
+
import { type DiffResult } from "./git.js";
|
|
10
|
+
export declare const DEFAULT_LOG_LIMIT = 50;
|
|
11
|
+
export declare const MAX_LOG_LIMIT = 100;
|
|
12
|
+
export interface RepoCommit {
|
|
13
|
+
sha: string;
|
|
14
|
+
shortSha: string;
|
|
15
|
+
subject: string;
|
|
16
|
+
body: string;
|
|
17
|
+
authorName: string;
|
|
18
|
+
authorEmail: string;
|
|
19
|
+
date: string;
|
|
20
|
+
refs: string[];
|
|
21
|
+
parents: string[];
|
|
22
|
+
taskId: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface RepoCommitFile {
|
|
25
|
+
path: string;
|
|
26
|
+
additions: number;
|
|
27
|
+
deletions: number;
|
|
28
|
+
status: "added" | "deleted" | "modified" | "binary";
|
|
29
|
+
}
|
|
30
|
+
export interface RepoCommitDetail extends RepoCommit {
|
|
31
|
+
files: RepoCommitFile[];
|
|
32
|
+
patch: string;
|
|
33
|
+
truncated: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface RepoLogPage {
|
|
36
|
+
ok: true;
|
|
37
|
+
commits: RepoCommit[];
|
|
38
|
+
nextCursor: string | null;
|
|
39
|
+
branch: string;
|
|
40
|
+
defaultBranch: string;
|
|
41
|
+
}
|
|
42
|
+
export interface RepoBranchList {
|
|
43
|
+
ok: true;
|
|
44
|
+
defaultBranch: string;
|
|
45
|
+
branches: string[];
|
|
46
|
+
}
|
|
47
|
+
export type RepoLogError = {
|
|
48
|
+
ok: false;
|
|
49
|
+
error: string;
|
|
50
|
+
code: "not-git" | "invalid" | "missing";
|
|
51
|
+
};
|
|
52
|
+
export declare function isValidSha(value: string): boolean;
|
|
53
|
+
export declare function isValidBranch(value: string): boolean;
|
|
54
|
+
/** Strip trailing slashes so `src/ui-app/` is the same filter as `src/ui-app`. */
|
|
55
|
+
export declare function normalizePathFilter(value: string): string;
|
|
56
|
+
export declare function isValidPathFilter(value: string): boolean;
|
|
57
|
+
/** `type(NNNN): subject` — the RepoOS commit-message convention. */
|
|
58
|
+
export declare function extractTaskId(subject: string): string | null;
|
|
59
|
+
export declare function parseDecorations(raw: string): string[];
|
|
60
|
+
/** Parse NUL-terminated `--format` records from `git log`. Exported for tests. */
|
|
61
|
+
export declare function parseGitLogOutput(stdout: string): RepoCommit[];
|
|
62
|
+
export declare function resolveDefaultBranch(root: string): Promise<string>;
|
|
63
|
+
export declare function listRepoBranches(root: string): Promise<RepoBranchList | RepoLogError>;
|
|
64
|
+
export declare function listRepoLog(root: string, opts?: {
|
|
65
|
+
branch?: string;
|
|
66
|
+
path?: string;
|
|
67
|
+
limit?: number;
|
|
68
|
+
before?: string;
|
|
69
|
+
}): Promise<RepoLogPage | RepoLogError>;
|
|
70
|
+
export declare function truncatePatch(stdout: string): DiffResult;
|
|
71
|
+
export declare function getRepoCommit(root: string, sha: string): Promise<RepoCommitDetail | RepoLogError>;
|
|
72
|
+
export declare function getCommitFileContents(root: string, sha: string, filePath: string): Promise<{
|
|
73
|
+
ok: true;
|
|
74
|
+
before: string;
|
|
75
|
+
after: string;
|
|
76
|
+
existsBefore: boolean;
|
|
77
|
+
existsAfter: boolean;
|
|
78
|
+
} | RepoLogError>;
|