panopticon-cli 0.6.4 → 0.6.6
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 +2 -2
- package/dist/{agents-DfYify9s.js → agents-CfFDs52G.js} +14 -14
- package/dist/{agents-DfYify9s.js.map → agents-CfFDs52G.js.map} +1 -1
- package/dist/{agents-BKsVoIc9.js → agents-D_2oRFVf.js} +1 -1
- package/dist/{archive-planning-BJrZ3tmN.js → archive-planning-D97ziGec.js} +3 -3
- package/dist/{archive-planning-BJrZ3tmN.js.map → archive-planning-D97ziGec.js.map} +1 -1
- package/dist/{archive-planning-C3m3hfa5.js → archive-planning-DK90wn9Q.js} +1 -1
- package/dist/{browser-Cvdznzc0.js → browser-CX7jXfXX.js} +1 -1
- package/dist/{browser-Cvdznzc0.js.map → browser-CX7jXfXX.js.map} +1 -1
- package/dist/{clean-planning-DvhZAUv4.js → clean-planning-D_lz4aQq.js} +2 -2
- package/dist/{clean-planning-DvhZAUv4.js.map → clean-planning-D_lz4aQq.js.map} +1 -1
- package/dist/clean-planning-x1S-JdmO.js +2 -0
- package/dist/cli/index.js +291 -760
- package/dist/cli/index.js.map +1 -1
- package/dist/{close-issue-Dr7yZmrr.js → close-issue-CaFE0stN.js} +11 -7
- package/dist/close-issue-CaFE0stN.js.map +1 -0
- package/dist/close-issue-CjcfZI9s.js +2 -0
- package/dist/compact-beads-B0_qE1w3.js +2 -0
- package/dist/{compact-beads-BCOtIIRl.js → compact-beads-CjFkteSU.js} +2 -2
- package/dist/{compact-beads-BCOtIIRl.js.map → compact-beads-CjFkteSU.js.map} +1 -1
- package/dist/{config-CRzMQRgA.js → config-BQNKsi9G.js} +2 -2
- package/dist/{config-CRzMQRgA.js.map → config-BQNKsi9G.js.map} +1 -1
- package/dist/{config-BYgUzQ21.js → config-agyKgF5C.js} +1 -1
- package/dist/{config-yaml-BgOACZAB.js → config-yaml-DGbLSMCa.js} +1 -1
- package/dist/{config-yaml-BgOACZAB.js.map → config-yaml-DGbLSMCa.js.map} +1 -1
- package/dist/{config-yaml-fdyvyL0S.js → config-yaml-Dqt4FWQH.js} +1 -1
- package/dist/dashboard/{acceptance-criteria-e5iiHlRx.js → acceptance-criteria-Dk9hhiYj.js} +1 -1
- package/dist/dashboard/{acceptance-criteria-e5iiHlRx.js.map → acceptance-criteria-Dk9hhiYj.js.map} +1 -1
- package/dist/dashboard/{agent-enrichment-C67LJBgD.js → agent-enrichment-DdO7ZqjI.js} +11 -7
- package/dist/dashboard/agent-enrichment-DdO7ZqjI.js.map +1 -0
- package/dist/dashboard/{agent-enrichment-Cq0P1cNZ.js → agent-enrichment-dLeGE1fX.js} +1 -1
- package/dist/dashboard/{agents-YyO6t5Xa.js → agents-DCpQQ_W5.js} +14 -14
- package/dist/dashboard/{agents-YyO6t5Xa.js.map → agents-DCpQQ_W5.js.map} +1 -1
- package/dist/dashboard/{agents-BVBVCyat.js → agents-Dgh2TjSp.js} +1 -1
- package/dist/dashboard/{archive-planning-h-hAjk0P.js → archive-planning-BmW9UDTr.js} +3 -3
- package/dist/dashboard/{archive-planning-h-hAjk0P.js.map → archive-planning-BmW9UDTr.js.map} +1 -1
- package/dist/dashboard/{archive-planning-CScs1MOC.js → archive-planning-C3Ebf9yC.js} +1 -1
- package/dist/dashboard/{beads-qNB0yAHV.js → beads-Bv-AdX7G.js} +3 -3
- package/dist/dashboard/{beads-qNB0yAHV.js.map → beads-Bv-AdX7G.js.map} +1 -1
- package/dist/dashboard/{beads-D_FRedEJ.js → beads-By6-X07V.js} +1 -1
- package/dist/dashboard/clean-planning-D60L8rPY.js +2 -0
- package/dist/dashboard/{clean-planning-qafw99vY.js → clean-planning-VEJu5suh.js} +2 -2
- package/dist/dashboard/{clean-planning-qafw99vY.js.map → clean-planning-VEJu5suh.js.map} +1 -1
- package/dist/dashboard/close-issue-C2KeSKKJ.js +2 -0
- package/dist/dashboard/{close-issue-DfIggeZD.js → close-issue-DtKdsSTm.js} +11 -7
- package/dist/dashboard/close-issue-DtKdsSTm.js.map +1 -0
- package/dist/dashboard/compact-beads-C7BN5N11.js +2 -0
- package/dist/dashboard/{compact-beads-Dt0qTqsC.js → compact-beads-D8Vt3qyv.js} +2 -2
- package/dist/dashboard/{compact-beads-Dt0qTqsC.js.map → compact-beads-D8Vt3qyv.js.map} +1 -1
- package/dist/dashboard/{config-CUREjHP7.js → config-CDkGjnwy.js} +2 -2
- package/dist/dashboard/{config-CUREjHP7.js.map → config-CDkGjnwy.js.map} +1 -1
- package/dist/dashboard/{config-BeI3uy-8.js → config-CTXkBATQ.js} +1 -1
- package/dist/dashboard/{database-CozA13Wy.js → database-DhqASALP.js} +1 -1
- package/dist/dashboard/{database-C0y0hXBx.js → database-cxmQryoh.js} +2 -2
- package/dist/dashboard/{database-C0y0hXBx.js.map → database-cxmQryoh.js.map} +1 -1
- package/dist/dashboard/{dist-src-oG2iHzgI.js → dist-src-DTm11oQr.js} +1 -1
- package/dist/dashboard/{dist-src-oG2iHzgI.js.map → dist-src-DTm11oQr.js.map} +1 -1
- package/dist/dashboard/{event-store-D7kLBd07.js → event-store-VWWUmOfn.js} +1 -1
- package/dist/dashboard/{event-store-O9q0Gweh.js → event-store-vSmAA3Zp.js} +9 -4
- package/dist/dashboard/event-store-vSmAA3Zp.js.map +1 -0
- package/dist/dashboard/{factory-BnLdiQW-.js → factory-C8nhLGHB.js} +3 -3
- package/dist/dashboard/{factory-BnLdiQW-.js.map → factory-C8nhLGHB.js.map} +1 -1
- package/dist/dashboard/{feedback-writer-DyovUANg.js → feedback-writer-CudSe1WK.js} +2 -2
- package/dist/dashboard/{feedback-writer-DyovUANg.js.map → feedback-writer-CudSe1WK.js.map} +1 -1
- package/dist/dashboard/{feedback-writer-gSUv_W0h.js → feedback-writer-Wgv1cd1r.js} +1 -1
- package/dist/dashboard/{git-utils-BJRioREj.js → git-utils-C1m4SwAe.js} +1 -1
- package/dist/dashboard/{git-utils-BJRioREj.js.map → git-utils-C1m4SwAe.js.map} +1 -1
- package/dist/dashboard/{git-utils-BtCRddq3.js → git-utils-DQI8EYoj.js} +1 -1
- package/dist/dashboard/{github-app-XO-LBUGk.js → github-app-DClWjjHr.js} +1 -1
- package/dist/dashboard/{github-app-XO-LBUGk.js.map → github-app-DClWjjHr.js.map} +1 -1
- package/dist/dashboard/{health-events-db-584nYgJB.js → health-events-db-BMXQfInV.js} +1 -1
- package/dist/dashboard/{health-events-db-B3ChzN65.js → health-events-db-Do4NrOhC.js} +2 -2
- package/dist/dashboard/{health-events-db-B3ChzN65.js.map → health-events-db-Do4NrOhC.js.map} +1 -1
- package/dist/dashboard/{hooks-CKhs3N68.js → hooks-CB4T47NC.js} +1 -1
- package/dist/dashboard/{hooks-CErbP8Oq.js → hooks-CjqXOlNb.js} +2 -2
- package/dist/dashboard/{hooks-CErbP8Oq.js.map → hooks-CjqXOlNb.js.map} +1 -1
- package/dist/dashboard/hume-CA2pftu_.js +3 -0
- package/dist/dashboard/{hume-CX_U3Qha.js → hume-JsAlMOJC.js} +2 -2
- package/dist/dashboard/{hume-CX_U3Qha.js.map → hume-JsAlMOJC.js.map} +1 -1
- package/dist/dashboard/{inspect-agent-B57kGDUV.js → inspect-agent-7eour7EA.js} +3 -3
- package/dist/dashboard/{inspect-agent-B57kGDUV.js.map → inspect-agent-7eour7EA.js.map} +1 -1
- package/dist/dashboard/{io-yGovuG4U.js → io-CWlFW78i.js} +1 -1
- package/dist/dashboard/{io-AJg-mzFi.js → io-DKS6359z.js} +1 -1
- package/dist/dashboard/{io-AJg-mzFi.js.map → io-DKS6359z.js.map} +1 -1
- package/dist/dashboard/issue-id-vwYJdsf8.js +62 -0
- package/dist/dashboard/issue-id-vwYJdsf8.js.map +1 -0
- package/dist/dashboard/{issue-service-singleton-DQK42EqH.js → issue-service-singleton-Co__-6kL.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-sb2HkB9f.js → issue-service-singleton-Wv4xBm3y.js} +7 -7
- package/dist/dashboard/{issue-service-singleton-sb2HkB9f.js.map → issue-service-singleton-Wv4xBm3y.js.map} +1 -1
- package/dist/dashboard/{label-cleanup-CZEsbtq9.js → label-cleanup-nVKTmIIW.js} +7 -4
- package/dist/dashboard/label-cleanup-nVKTmIIW.js.map +1 -0
- package/dist/dashboard/lifecycle-BcUmtkR4.js +7 -0
- package/dist/dashboard/{merge-agent-GLtMEsTu.js → merge-agent-CGN3TT0a.js} +1 -1
- package/dist/dashboard/{merge-agent-twroFuAh.js → merge-agent-yudQOPZc.js} +148 -46
- package/dist/dashboard/merge-agent-yudQOPZc.js.map +1 -0
- package/dist/dashboard/{paths-COdEvoXR.js → paths-BDyJ7BiV.js} +19 -2
- package/dist/dashboard/{paths-COdEvoXR.js.map → paths-BDyJ7BiV.js.map} +1 -1
- package/dist/dashboard/{pipeline-notifier-DM5AHG5Q.js → pipeline-notifier-CCSN-jar.js} +1 -1
- package/dist/dashboard/{pipeline-notifier-DM5AHG5Q.js.map → pipeline-notifier-CCSN-jar.js.map} +1 -1
- package/dist/dashboard/{plan-utils-BkCIhn3B.js → plan-utils-Bkcsqr_s.js} +3 -3
- package/dist/dashboard/{plan-utils-BkCIhn3B.js.map → plan-utils-Bkcsqr_s.js.map} +1 -1
- package/dist/dashboard/{prd-draft-D09Afalc.js → prd-draft-BD8oMkZ1.js} +2 -2
- package/dist/dashboard/{prd-draft-D09Afalc.js.map → prd-draft-BD8oMkZ1.js.map} +1 -1
- package/dist/dashboard/{projection-cache-DQ9zegkK.js → projection-cache-C0EL8s8h.js} +1 -1
- package/dist/dashboard/{projection-cache-DQ9zegkK.js.map → projection-cache-C0EL8s8h.js.map} +1 -1
- package/dist/dashboard/{projects-DyT3vSy-.js → projects-C5ozxjwP.js} +1 -1
- package/dist/dashboard/{projects-Cq3TWdPS.js → projects-CFVl4oHn.js} +25 -13
- package/dist/dashboard/projects-CFVl4oHn.js.map +1 -0
- package/dist/dashboard/{providers-Ck2sQd_F.js → providers-B5Y4H2Mg.js} +4 -4
- package/dist/dashboard/providers-B5Y4H2Mg.js.map +1 -0
- package/dist/dashboard/{providers-DVQnDekG.js → providers-csVZVPkE.js} +1 -1
- package/dist/dashboard/public/assets/{dist-CCJbQrSB.js → dist-BaQPC-c6.js} +1 -1
- package/dist/dashboard/public/assets/index-ByLmYGhW.js +212 -0
- package/dist/dashboard/public/assets/index-OEEbThNN.css +1 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/rally-6McpKKRa.js +3 -0
- package/dist/dashboard/{rally-Cwuae-4C.js → rally-YjFRxIiC.js} +2 -2
- package/dist/dashboard/{rally-Cwuae-4C.js.map → rally-YjFRxIiC.js.map} +1 -1
- package/dist/dashboard/{rally-api-DSUxm7EO.js → rally-api-C0WqCSkT.js} +1 -1
- package/dist/dashboard/{rally-api-DSUxm7EO.js.map → rally-api-C0WqCSkT.js.map} +1 -1
- package/dist/dashboard/{rally-api-CEH5KZi4.js → rally-api-DNttdCW4.js} +1 -1
- package/dist/dashboard/{remote-BHTTMpJJ.js → remote-Cigqjj3f.js} +2 -2
- package/dist/dashboard/{remote-BXo_iIku.js → remote-ObpNZ7hF.js} +2 -2
- package/dist/dashboard/{remote-BXo_iIku.js.map → remote-ObpNZ7hF.js.map} +1 -1
- package/dist/dashboard/{remote-agents-CTKVhFFY.js → remote-agents-Bf3GuM7t.js} +1 -1
- package/dist/dashboard/{remote-agents-C0_0LLNd.js → remote-agents-DFyjT1Le.js} +1 -1
- package/dist/dashboard/{remote-agents-C0_0LLNd.js.map → remote-agents-DFyjT1Le.js.map} +1 -1
- package/dist/dashboard/{review-status-CK3eBGyb.js → review-status-BtXqWBhS.js} +1 -1
- package/dist/dashboard/{review-status-CV55Tl-n.js → review-status-Bymwzh2i.js} +44 -4
- package/dist/dashboard/{review-status-CV55Tl-n.js.map → review-status-Bymwzh2i.js.map} +1 -1
- package/dist/dashboard/server.js +565 -265
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/{settings-CuHV-wcv.js → settings-BHlDG7TK.js} +2 -2
- package/dist/dashboard/settings-BHlDG7TK.js.map +1 -0
- package/dist/dashboard/settings-XWvDcj-D.js +2 -0
- package/dist/dashboard/{shadow-engineering-BUeZunaE.js → shadow-engineering-lIn1W_95.js} +1 -1
- package/dist/dashboard/{shadow-engineering-BUeZunaE.js.map → shadow-engineering-lIn1W_95.js.map} +1 -1
- package/dist/dashboard/{shadow-state-DHQ-kASN.js → shadow-state-BIexcxkv.js} +1 -1
- package/dist/dashboard/{shadow-state-DHQ-kASN.js.map → shadow-state-BIexcxkv.js.map} +1 -1
- package/dist/dashboard/{spawn-planning-session-8FFAqLdK.js → spawn-planning-session-33Jf-d5T.js} +6 -6
- package/dist/dashboard/{spawn-planning-session-8FFAqLdK.js.map → spawn-planning-session-33Jf-d5T.js.map} +1 -1
- package/dist/dashboard/{spawn-planning-session-U0Lqpjen.js → spawn-planning-session-D5hrVdWM.js} +1 -1
- package/dist/dashboard/{specialist-context-ColzlmGE.js → specialist-context-DGukHSn8.js} +6 -6
- package/dist/dashboard/{specialist-context-ColzlmGE.js.map → specialist-context-DGukHSn8.js.map} +1 -1
- package/dist/dashboard/{specialist-logs-BhmDpFIq.js → specialist-logs-CIw4qfTy.js} +1 -1
- package/dist/dashboard/{specialists-C6s3U6tX.js → specialists-B_zrayaP.js} +37 -36
- package/dist/dashboard/specialists-B_zrayaP.js.map +1 -0
- package/dist/dashboard/{specialists-Cny632-T.js → specialists-Cp-PgspS.js} +1 -1
- package/dist/dashboard/{test-agent-queue-tqI4VDsu.js → test-agent-queue-ypF_ecHo.js} +4 -4
- package/dist/dashboard/{test-agent-queue-tqI4VDsu.js.map → test-agent-queue-ypF_ecHo.js.map} +1 -1
- package/dist/dashboard/{tldr-daemon-BNFyS7W_.js → tldr-daemon-B_oLRD8z.js} +2 -2
- package/dist/dashboard/{tldr-daemon-BNFyS7W_.js.map → tldr-daemon-B_oLRD8z.js.map} +1 -1
- package/dist/dashboard/{tldr-daemon-A6JqC59u.js → tldr-daemon-Cfs0bXTi.js} +1 -1
- package/dist/dashboard/{tmux-DYGAVJfb.js → tmux-BzxdKItf.js} +1 -1
- package/dist/dashboard/{tmux-IlN1Slv-.js → tmux-LwG0tHhU.js} +2 -2
- package/dist/dashboard/{tmux-IlN1Slv-.js.map → tmux-LwG0tHhU.js.map} +1 -1
- package/dist/dashboard/{tracker-config-BzNLnmcE.js → tracker-config-BP59uH4V.js} +1 -1
- package/dist/dashboard/{tracker-config-CNM_5rEf.js → tracker-config-e7ph1QqT.js} +2 -2
- package/dist/dashboard/{tracker-config-CNM_5rEf.js.map → tracker-config-e7ph1QqT.js.map} +1 -1
- package/dist/dashboard/{tunnel-D2BkwU7k.js → tunnel-0RzzuXPf.js} +1 -1
- package/dist/dashboard/{tunnel-Dub2hiAA.js → tunnel-DldbBPWL.js} +2 -2
- package/dist/dashboard/{tunnel-Dub2hiAA.js.map → tunnel-DldbBPWL.js.map} +1 -1
- package/dist/dashboard/{types-CWA-o4UN.js → types-RKZjGE5N.js} +1 -1
- package/dist/dashboard/{types-CWA-o4UN.js.map → types-RKZjGE5N.js.map} +1 -1
- package/dist/dashboard/{vtt-parser-BAXygRf0.js → vtt-parser-99vFekRQ.js} +1 -1
- package/dist/dashboard/{vtt-parser-BAXygRf0.js.map → vtt-parser-99vFekRQ.js.map} +1 -1
- package/dist/dashboard/{work-agent-prompt-JYq_OugP.js → work-agent-prompt-fCg67nyo.js} +65 -10
- package/dist/dashboard/{work-agent-prompt-JYq_OugP.js.map → work-agent-prompt-fCg67nyo.js.map} +1 -1
- package/dist/dashboard/{work-type-router-Cxp8_ur2.js → work-type-router-CWVW2Wk_.js} +1 -1
- package/dist/dashboard/{work-type-router-Cxp8_ur2.js.map → work-type-router-CWVW2Wk_.js.map} +1 -1
- package/dist/dashboard/{work-type-router-Com2amST.js → work-type-router-Di5gCQwh.js} +1 -1
- package/dist/dashboard/{workflows-N1UTipYl.js → workflows-BSMipN07.js} +35 -17
- package/dist/dashboard/workflows-BSMipN07.js.map +1 -0
- package/dist/dashboard/workflows-DaYWQIS2.js +2 -0
- package/dist/dashboard/{workspace-config-cmp5_ipD.js → workspace-config-DVDR-Ukh.js} +1 -1
- package/dist/dashboard/workspace-config-DVDR-Ukh.js.map +1 -0
- package/dist/dashboard/{workspace-manager-CjpWPgzL.js → workspace-manager-BYfzs_t2.js} +1 -1
- package/dist/dashboard/{workspace-manager-D_y9ZmW_.js → workspace-manager-C7OfT62A.js} +44 -24
- package/dist/dashboard/workspace-manager-C7OfT62A.js.map +1 -0
- package/dist/{dns-BKzHm-2q.js → dns-D_aKQJjb.js} +1 -1
- package/dist/{dns-DZwOWvVO.js → dns-Yxq4NNS7.js} +1 -1
- package/dist/{dns-DZwOWvVO.js.map → dns-Yxq4NNS7.js.map} +1 -1
- package/dist/{factory-DFu3IT4r.js → factory-BRBGw6OB.js} +1 -1
- package/dist/{factory-DfzczxN1.js → factory-DzsOiZVc.js} +3 -3
- package/dist/{factory-DfzczxN1.js.map → factory-DzsOiZVc.js.map} +1 -1
- package/dist/{feedback-writer-CwdnOkPO.js → feedback-writer-ygXN5F9N.js} +2 -2
- package/dist/{feedback-writer-CwdnOkPO.js.map → feedback-writer-ygXN5F9N.js.map} +1 -1
- package/dist/{github-app-CHKwxOeQ.js → github-app-DykduJ0X.js} +1 -1
- package/dist/{github-app-CHKwxOeQ.js.map → github-app-DykduJ0X.js.map} +1 -1
- package/dist/hume-9nv1VmMV.js +3 -0
- package/dist/{hume-DnV-tDsh.js → hume-DoCbph2h.js} +2 -2
- package/dist/{hume-DnV-tDsh.js.map → hume-DoCbph2h.js.map} +1 -1
- package/dist/index.d.ts +17 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -7
- package/dist/issue-id-CAcekoIw.js +62 -0
- package/dist/issue-id-CAcekoIw.js.map +1 -0
- package/dist/{label-cleanup-31ElPqqv.js → label-cleanup-C8R9Rspn.js} +7 -4
- package/dist/label-cleanup-C8R9Rspn.js.map +1 -0
- package/dist/{manifest-DL0oDbpv.js → manifest-B4ghOD-V.js} +1 -1
- package/dist/{manifest-DL0oDbpv.js.map → manifest-B4ghOD-V.js.map} +1 -1
- package/dist/{merge-agent-VQH9z9t8.js → merge-agent-DlUiUanN.js} +86 -33
- package/dist/merge-agent-DlUiUanN.js.map +1 -0
- package/dist/{paths-lMaxrYtT.js → paths-CDJ_HsbN.js} +19 -2
- package/dist/{paths-lMaxrYtT.js.map → paths-CDJ_HsbN.js.map} +1 -1
- package/dist/{pipeline-notifier-OJ-d3Y60.js → pipeline-notifier-XgDdCdvT.js} +1 -1
- package/dist/{pipeline-notifier-OJ-d3Y60.js.map → pipeline-notifier-XgDdCdvT.js.map} +1 -1
- package/dist/{projects-CvLepaxC.js → projects-Bk-5QhFQ.js} +25 -13
- package/dist/projects-Bk-5QhFQ.js.map +1 -0
- package/dist/{projects-DMWmPeIU.js → projects-DhU7rAVN.js} +1 -1
- package/dist/{providers-DcCPZ5K4.js → providers-DSU1vfQF.js} +4 -4
- package/dist/providers-DSU1vfQF.js.map +1 -0
- package/dist/rally-DdPvGa-w.js +3 -0
- package/dist/{rally-uUUZXp1h.js → rally-Dy00NElU.js} +1 -1
- package/dist/{rally-uUUZXp1h.js.map → rally-Dy00NElU.js.map} +1 -1
- package/dist/{remote-CkLBqLJc.js → remote-CYiOJg0q.js} +2 -2
- package/dist/{remote-CkLBqLJc.js.map → remote-CYiOJg0q.js.map} +1 -1
- package/dist/{remote-agents-C5Bd2fgt.js → remote-agents-CZXrUF4f.js} +1 -1
- package/dist/{remote-agents-C5Bd2fgt.js.map → remote-agents-CZXrUF4f.js.map} +1 -1
- package/dist/{remote-agents-BTzD-wMQ.js → remote-agents-ycHHVsgf.js} +1 -1
- package/dist/{remote-workspace-Dxghqiti.js → remote-workspace-CA33UuVI.js} +4 -4
- package/dist/{remote-workspace-Dxghqiti.js.map → remote-workspace-CA33UuVI.js.map} +1 -1
- package/dist/{review-status-2TdtHNcs.js → review-status-D6H2WOw8.js} +1 -1
- package/dist/{review-status-Bm1bWNEa.js → review-status-DEDvCKMP.js} +44 -4
- package/dist/{review-status-Bm1bWNEa.js.map → review-status-DEDvCKMP.js.map} +1 -1
- package/dist/{tracker-C_62ukEq.js → settings-BcWPTrua.js} +7 -199
- package/dist/settings-BcWPTrua.js.map +1 -0
- package/dist/shadow-state-BZzxfEGw.js +2 -0
- package/dist/{shadow-state-CFFHf05M.js → shadow-state-CE3dQfll.js} +1 -1
- package/dist/{shadow-state-CFFHf05M.js.map → shadow-state-CE3dQfll.js.map} +1 -1
- package/dist/{specialist-context-BdNFsfMG.js → specialist-context-BAUWL1Fl.js} +6 -6
- package/dist/{specialist-context-BdNFsfMG.js.map → specialist-context-BAUWL1Fl.js.map} +1 -1
- package/dist/{specialist-logs-CLztE_bE.js → specialist-logs-DQKKQV9B.js} +1 -1
- package/dist/{specialists-aUoUVWsN.js → specialists-Bfb9ATzw.js} +1 -1
- package/dist/{specialists-DEKqgkxp.js → specialists-D7Kj5o6s.js} +35 -34
- package/dist/specialists-D7Kj5o6s.js.map +1 -0
- package/dist/sync-DMfgd389.js +693 -0
- package/dist/sync-DMfgd389.js.map +1 -0
- package/dist/sync-TL6y-8K6.js +2 -0
- package/dist/{tldr-daemon-BCEFPItr.js → tldr-daemon-CFx4LXAl.js} +2 -2
- package/dist/{tldr-daemon-BCEFPItr.js.map → tldr-daemon-CFx4LXAl.js.map} +1 -1
- package/dist/{tldr-daemon-xBAx4cBE.js → tldr-daemon-D_EooADG.js} +1 -1
- package/dist/{tmux-DN6H886Y.js → tmux-CBtui_Cl.js} +1 -1
- package/dist/{tmux-CKdNxxJx.js → tmux-D6Ah4I8z.js} +2 -2
- package/dist/{tmux-CKdNxxJx.js.map → tmux-D6Ah4I8z.js.map} +1 -1
- package/dist/tracker-BhYYvU3p.js +198 -0
- package/dist/tracker-BhYYvU3p.js.map +1 -0
- package/dist/{tracker-utils-CVU2W1sX.js → tracker-utils-ChQyut8w.js} +34 -12
- package/dist/tracker-utils-ChQyut8w.js.map +1 -0
- package/dist/{traefik-DHgBoWXX.js → traefik-C80EbDu_.js} +4 -4
- package/dist/{traefik-DHgBoWXX.js.map → traefik-C80EbDu_.js.map} +1 -1
- package/dist/{traefik-BR-edbZv.js → traefik-CgHl7Bge.js} +1 -1
- package/dist/{tunnel-BZO9Q5oe.js → tunnel-DXOJ1wMM.js} +1 -1
- package/dist/{tunnel-Bl1qNSyQ.js → tunnel-DzXEPwIc.js} +2 -2
- package/dist/{tunnel-Bl1qNSyQ.js.map → tunnel-DzXEPwIc.js.map} +1 -1
- package/dist/{types-DewGdaIP.js → types-BhJj1SP1.js} +1 -1
- package/dist/{types-DewGdaIP.js.map → types-BhJj1SP1.js.map} +1 -1
- package/dist/{work-type-router-CS2BB1vS.js → work-type-router-CHjciPyS.js} +3 -3
- package/dist/{work-type-router-CS2BB1vS.js.map → work-type-router-CHjciPyS.js.map} +1 -1
- package/dist/{workspace-config-CNXOpKuj.js → workspace-config-fUafvYMp.js} +1 -1
- package/dist/workspace-config-fUafvYMp.js.map +1 -0
- package/dist/workspace-manager-B9jS4Dsq.js +3 -0
- package/dist/{workspace-manager-CncdZkIy.js → workspace-manager-DuLhnzJV.js} +112 -27
- package/dist/workspace-manager-DuLhnzJV.js.map +1 -0
- package/package.json +2 -1
- package/scripts/post-merge-deploy.sh +25 -5
- package/scripts/record-cost-event.js +57 -7
- package/scripts/record-cost-event.js.map +1 -1
- package/skills/pan-help/SKILL.md +1 -1
- package/skills/pan-sync/SKILL.md +6 -6
- package/skills/workspace-add-repo/skill.md +46 -0
- package/templates/claude-md/sections/warnings.md +15 -2
- package/dist/clean-planning-sZXvy3Y5.js +0 -2
- package/dist/close-issue-Dml437qV.js +0 -2
- package/dist/close-issue-Dr7yZmrr.js.map +0 -1
- package/dist/compact-beads-iu218JcO.js +0 -2
- package/dist/dashboard/agent-enrichment-C67LJBgD.js.map +0 -1
- package/dist/dashboard/clean-planning-DCu3cOTu.js +0 -2
- package/dist/dashboard/close-issue-DfIggeZD.js.map +0 -1
- package/dist/dashboard/close-issue-DwdwYtar.js +0 -2
- package/dist/dashboard/compact-beads-DXY2fK2s.js +0 -2
- package/dist/dashboard/event-store-O9q0Gweh.js.map +0 -1
- package/dist/dashboard/hume-MZndNDVU.js +0 -3
- package/dist/dashboard/label-cleanup-CZEsbtq9.js.map +0 -1
- package/dist/dashboard/lifecycle-ZTYdrr2O.js +0 -7
- package/dist/dashboard/merge-agent-twroFuAh.js.map +0 -1
- package/dist/dashboard/projects-Cq3TWdPS.js.map +0 -1
- package/dist/dashboard/providers-Ck2sQd_F.js.map +0 -1
- package/dist/dashboard/public/assets/index-CpSmB2ts.css +0 -1
- package/dist/dashboard/public/assets/index-yarWhi0M.js +0 -214
- package/dist/dashboard/rally-CQ1OBJrJ.js +0 -3
- package/dist/dashboard/settings-CuHV-wcv.js.map +0 -1
- package/dist/dashboard/settings-DMeGBRsk.js +0 -2
- package/dist/dashboard/specialists-C6s3U6tX.js.map +0 -1
- package/dist/dashboard/workflows-B2ARUpOa.js +0 -2
- package/dist/dashboard/workflows-N1UTipYl.js.map +0 -1
- package/dist/dashboard/workspace-config-cmp5_ipD.js.map +0 -1
- package/dist/dashboard/workspace-manager-D_y9ZmW_.js.map +0 -1
- package/dist/hume-BjmwmJ9E.js +0 -3
- package/dist/label-cleanup-31ElPqqv.js.map +0 -1
- package/dist/merge-agent-VQH9z9t8.js.map +0 -1
- package/dist/projects-CvLepaxC.js.map +0 -1
- package/dist/providers-DcCPZ5K4.js.map +0 -1
- package/dist/rally-DR9x8--6.js +0 -3
- package/dist/shadow-state-p3jpGRPJ.js +0 -2
- package/dist/specialists-DEKqgkxp.js.map +0 -1
- package/dist/tracker-C_62ukEq.js.map +0 -1
- package/dist/tracker-utils-CVU2W1sX.js.map +0 -1
- package/dist/workspace-config-CNXOpKuj.js.map +0 -1
- package/dist/workspace-manager-CncdZkIy.js.map +0 -1
- package/dist/workspace-manager-Cx0r2Jnv.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-CErbP8Oq.js","names":[],"sources":["../../src/lib/hooks.ts"],"sourcesContent":["/**\n * FPP Hooks System - Fixed Point Principle\n *\n * \"Any runnable action is a fixed point and must resolve before the system can rest.\"\n *\n * Inspired by Doctor Who: a fixed point in time must occur — it cannot be avoided.\n *\n * Hooks are persistent work queues for agents. When an agent starts,\n * it checks its hook for pending work and executes immediately.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from 'fs';\nimport { join } from 'path';\nimport { AGENTS_DIR } from './paths.js';\n\nexport interface HookItem {\n id: string;\n type: 'task' | 'message' | 'notification';\n priority: 'urgent' | 'high' | 'normal' | 'low';\n source: string;\n payload: {\n issueId?: string;\n message?: string;\n action?: string;\n context?: Record<string, any>;\n };\n createdAt: string;\n expiresAt?: string;\n}\n\nexport interface Hook {\n agentId: string;\n items: HookItem[];\n lastChecked?: string;\n}\n\nfunction getHookDir(agentId: string): string {\n return join(AGENTS_DIR, agentId);\n}\n\nfunction getHookFile(agentId: string): string {\n return join(getHookDir(agentId), 'hook.json');\n}\n\nfunction getMailDir(agentId: string): string {\n return join(getHookDir(agentId), 'mail');\n}\n\n/**\n * Initialize hook structure for an agent\n */\nexport function initHook(agentId: string): void {\n const hookDir = getHookDir(agentId);\n const mailDir = getMailDir(agentId);\n\n mkdirSync(hookDir, { recursive: true });\n mkdirSync(mailDir, { recursive: true });\n\n const hookFile = getHookFile(agentId);\n if (!existsSync(hookFile)) {\n const hook: Hook = {\n agentId,\n items: [],\n };\n writeFileSync(hookFile, JSON.stringify(hook, null, 2));\n }\n}\n\n/**\n * Get the hook for an agent\n */\nexport function getHook(agentId: string): Hook | null {\n const hookFile = getHookFile(agentId);\n if (!existsSync(hookFile)) {\n return null;\n }\n\n try {\n const content = readFileSync(hookFile, 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\n/**\n * Add work to an agent's hook (FPP trigger)\n */\nexport function pushToHook(agentId: string, item: Omit<HookItem, 'id' | 'createdAt'>): HookItem {\n initHook(agentId);\n\n const hook = getHook(agentId) || { agentId, items: [] };\n\n const newItem: HookItem = {\n ...item,\n id: `hook-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n createdAt: new Date().toISOString(),\n };\n\n hook.items.push(newItem);\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n\n return newItem;\n}\n\n/**\n * Check if agent has pending work (FPP check)\n */\nexport function checkHook(agentId: string): { hasWork: boolean; urgentCount: number; items: HookItem[] } {\n const hook = getHook(agentId);\n\n if (!hook || hook.items.length === 0) {\n // Also check mail directory for incoming messages\n const mailDir = getMailDir(agentId);\n if (existsSync(mailDir)) {\n const mails = readdirSync(mailDir).filter((f) => f.endsWith('.json'));\n if (mails.length > 0) {\n // Convert mail to hook items\n const mailItems: HookItem[] = mails.map((file) => {\n try {\n const content = readFileSync(join(mailDir, file), 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n }).filter(Boolean) as HookItem[];\n\n return {\n hasWork: mailItems.length > 0,\n urgentCount: mailItems.filter((i) => i.priority === 'urgent').length,\n items: mailItems,\n };\n }\n }\n\n return { hasWork: false, urgentCount: 0, items: [] };\n }\n\n // Filter out expired items\n const now = new Date();\n const activeItems = hook.items.filter((item) => {\n if (item.expiresAt) {\n return new Date(item.expiresAt) > now;\n }\n return true;\n });\n\n // Sort by priority: urgent > high > normal > low\n const priorityOrder = { urgent: 0, high: 1, normal: 2, low: 3 };\n activeItems.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);\n\n return {\n hasWork: activeItems.length > 0,\n urgentCount: activeItems.filter((i) => i.priority === 'urgent').length,\n items: activeItems,\n };\n}\n\n/**\n * Pop the next work item from hook (after execution)\n */\nexport function popFromHook(agentId: string, itemId: string): boolean {\n const hook = getHook(agentId);\n if (!hook) return false;\n\n const index = hook.items.findIndex((i) => i.id === itemId);\n if (index === -1) return false;\n\n hook.items.splice(index, 1);\n hook.lastChecked = new Date().toISOString();\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n\n return true;\n}\n\n/**\n * Clear all items from hook\n */\nexport function clearHook(agentId: string): void {\n const hook = getHook(agentId);\n if (!hook) return;\n\n hook.items = [];\n hook.lastChecked = new Date().toISOString();\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n}\n\n/**\n * Reorder hook items by providing a new order of item IDs\n * Used for manual queue management from dashboard\n */\nexport function reorderHookItems(agentId: string, orderedItemIds: string[]): boolean {\n const hook = getHook(agentId);\n if (!hook) return false;\n\n // Validate that all provided IDs exist in the hook\n const existingIds = new Set(hook.items.map((item) => item.id));\n const providedIds = new Set(orderedItemIds);\n\n // Check if all provided IDs exist\n for (const id of orderedItemIds) {\n if (!existingIds.has(id)) {\n console.error(`[hooks] Cannot reorder: item ${id} not found in hook`);\n return false;\n }\n }\n\n // Check if all existing IDs are provided\n if (existingIds.size !== providedIds.size) {\n console.error(`[hooks] Cannot reorder: mismatch in item count (existing: ${existingIds.size}, provided: ${providedIds.size})`);\n return false;\n }\n\n // Build a map for quick lookup\n const itemMap = new Map(hook.items.map((item) => [item.id, item]));\n\n // Reorder items based on provided IDs\n hook.items = orderedItemIds.map((id) => itemMap.get(id)!);\n\n // Write back to file\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n\n return true;\n}\n\n/**\n * Send a message to an agent's mailbox\n */\nexport function sendMail(\n toAgentId: string,\n from: string,\n message: string,\n priority: HookItem['priority'] = 'normal'\n): void {\n initHook(toAgentId);\n const mailDir = getMailDir(toAgentId);\n\n const mailItem: HookItem = {\n id: `mail-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n type: 'message',\n priority,\n source: from,\n payload: { message },\n createdAt: new Date().toISOString(),\n };\n\n writeFileSync(\n join(mailDir, `${mailItem.id}.json`),\n JSON.stringify(mailItem, null, 2)\n );\n}\n\n/**\n * Get and clear mail for an agent\n */\nexport function collectMail(agentId: string): HookItem[] {\n const mailDir = getMailDir(agentId);\n if (!existsSync(mailDir)) return [];\n\n const mails: HookItem[] = [];\n const files = readdirSync(mailDir).filter((f) => f.endsWith('.json'));\n\n for (const file of files) {\n const filePath = join(mailDir, file);\n try {\n const content = readFileSync(filePath, 'utf-8');\n mails.push(JSON.parse(content));\n unlinkSync(filePath); // Remove after reading\n } catch {\n // Skip invalid mail\n }\n }\n\n return mails;\n}\n\n/**\n * Generate Fixed Point prompt for agent startup\n */\nexport function generateFixedPointPrompt(agentId: string): string | null {\n const { hasWork, urgentCount, items } = checkHook(agentId);\n\n if (!hasWork) return null;\n\n const lines: string[] = [\n '# FPP: Work Found on Your Hook',\n '',\n '> \"Any runnable action is a fixed point and must resolve before the system can rest.\"',\n '',\n ];\n\n if (urgentCount > 0) {\n lines.push(`⚠️ **${urgentCount} URGENT item(s) require immediate attention**`);\n lines.push('');\n }\n\n lines.push(`## Pending Work Items (${items.length})`);\n lines.push('');\n\n for (const item of items) {\n const priorityEmoji = {\n urgent: '🔴',\n high: '🟠',\n normal: '🟢',\n low: '⚪',\n }[item.priority];\n\n lines.push(`### ${priorityEmoji} ${item.type.toUpperCase()}: ${item.id}`);\n lines.push(`- Source: ${item.source}`);\n lines.push(`- Created: ${item.createdAt}`);\n\n if (item.payload.issueId) {\n lines.push(`- Issue: ${item.payload.issueId}`);\n }\n if (item.payload.message) {\n lines.push(`- Message: ${item.payload.message}`);\n }\n if (item.payload.action) {\n lines.push(`- Action: ${item.payload.action}`);\n }\n lines.push('');\n }\n\n lines.push('---');\n lines.push('');\n lines.push('Execute these items in priority order. Use `bd hook pop <id>` after completing each item.');\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hooks-CjqXOlNb.js","names":[],"sources":["../../src/lib/hooks.ts"],"sourcesContent":["/**\n * FPP Hooks System - Fixed Point Principle\n *\n * \"Any runnable action is a fixed point and must resolve before the system can rest.\"\n *\n * Inspired by Doctor Who: a fixed point in time must occur — it cannot be avoided.\n *\n * Hooks are persistent work queues for agents. When an agent starts,\n * it checks its hook for pending work and executes immediately.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from 'fs';\nimport { join } from 'path';\nimport { AGENTS_DIR } from './paths.js';\n\nexport interface HookItem {\n id: string;\n type: 'task' | 'message' | 'notification';\n priority: 'urgent' | 'high' | 'normal' | 'low';\n source: string;\n payload: {\n issueId?: string;\n message?: string;\n action?: string;\n context?: Record<string, any>;\n };\n createdAt: string;\n expiresAt?: string;\n}\n\nexport interface Hook {\n agentId: string;\n items: HookItem[];\n lastChecked?: string;\n}\n\nfunction getHookDir(agentId: string): string {\n return join(AGENTS_DIR, agentId);\n}\n\nfunction getHookFile(agentId: string): string {\n return join(getHookDir(agentId), 'hook.json');\n}\n\nfunction getMailDir(agentId: string): string {\n return join(getHookDir(agentId), 'mail');\n}\n\n/**\n * Initialize hook structure for an agent\n */\nexport function initHook(agentId: string): void {\n const hookDir = getHookDir(agentId);\n const mailDir = getMailDir(agentId);\n\n mkdirSync(hookDir, { recursive: true });\n mkdirSync(mailDir, { recursive: true });\n\n const hookFile = getHookFile(agentId);\n if (!existsSync(hookFile)) {\n const hook: Hook = {\n agentId,\n items: [],\n };\n writeFileSync(hookFile, JSON.stringify(hook, null, 2));\n }\n}\n\n/**\n * Get the hook for an agent\n */\nexport function getHook(agentId: string): Hook | null {\n const hookFile = getHookFile(agentId);\n if (!existsSync(hookFile)) {\n return null;\n }\n\n try {\n const content = readFileSync(hookFile, 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\n/**\n * Add work to an agent's hook (FPP trigger)\n */\nexport function pushToHook(agentId: string, item: Omit<HookItem, 'id' | 'createdAt'>): HookItem {\n initHook(agentId);\n\n const hook = getHook(agentId) || { agentId, items: [] };\n\n const newItem: HookItem = {\n ...item,\n id: `hook-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n createdAt: new Date().toISOString(),\n };\n\n hook.items.push(newItem);\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n\n return newItem;\n}\n\n/**\n * Check if agent has pending work (FPP check)\n */\nexport function checkHook(agentId: string): { hasWork: boolean; urgentCount: number; items: HookItem[] } {\n const hook = getHook(agentId);\n\n if (!hook || hook.items.length === 0) {\n // Also check mail directory for incoming messages\n const mailDir = getMailDir(agentId);\n if (existsSync(mailDir)) {\n const mails = readdirSync(mailDir).filter((f) => f.endsWith('.json'));\n if (mails.length > 0) {\n // Convert mail to hook items\n const mailItems: HookItem[] = mails.map((file) => {\n try {\n const content = readFileSync(join(mailDir, file), 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n }).filter(Boolean) as HookItem[];\n\n return {\n hasWork: mailItems.length > 0,\n urgentCount: mailItems.filter((i) => i.priority === 'urgent').length,\n items: mailItems,\n };\n }\n }\n\n return { hasWork: false, urgentCount: 0, items: [] };\n }\n\n // Filter out expired items\n const now = new Date();\n const activeItems = hook.items.filter((item) => {\n if (item.expiresAt) {\n return new Date(item.expiresAt) > now;\n }\n return true;\n });\n\n // Sort by priority: urgent > high > normal > low\n const priorityOrder = { urgent: 0, high: 1, normal: 2, low: 3 };\n activeItems.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);\n\n return {\n hasWork: activeItems.length > 0,\n urgentCount: activeItems.filter((i) => i.priority === 'urgent').length,\n items: activeItems,\n };\n}\n\n/**\n * Pop the next work item from hook (after execution)\n */\nexport function popFromHook(agentId: string, itemId: string): boolean {\n const hook = getHook(agentId);\n if (!hook) return false;\n\n const index = hook.items.findIndex((i) => i.id === itemId);\n if (index === -1) return false;\n\n hook.items.splice(index, 1);\n hook.lastChecked = new Date().toISOString();\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n\n return true;\n}\n\n/**\n * Clear all items from hook\n */\nexport function clearHook(agentId: string): void {\n const hook = getHook(agentId);\n if (!hook) return;\n\n hook.items = [];\n hook.lastChecked = new Date().toISOString();\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n}\n\n/**\n * Reorder hook items by providing a new order of item IDs\n * Used for manual queue management from dashboard\n */\nexport function reorderHookItems(agentId: string, orderedItemIds: string[]): boolean {\n const hook = getHook(agentId);\n if (!hook) return false;\n\n // Validate that all provided IDs exist in the hook\n const existingIds = new Set(hook.items.map((item) => item.id));\n const providedIds = new Set(orderedItemIds);\n\n // Check if all provided IDs exist\n for (const id of orderedItemIds) {\n if (!existingIds.has(id)) {\n console.error(`[hooks] Cannot reorder: item ${id} not found in hook`);\n return false;\n }\n }\n\n // Check if all existing IDs are provided\n if (existingIds.size !== providedIds.size) {\n console.error(`[hooks] Cannot reorder: mismatch in item count (existing: ${existingIds.size}, provided: ${providedIds.size})`);\n return false;\n }\n\n // Build a map for quick lookup\n const itemMap = new Map(hook.items.map((item) => [item.id, item]));\n\n // Reorder items based on provided IDs\n hook.items = orderedItemIds.map((id) => itemMap.get(id)!);\n\n // Write back to file\n writeFileSync(getHookFile(agentId), JSON.stringify(hook, null, 2));\n\n return true;\n}\n\n/**\n * Send a message to an agent's mailbox\n */\nexport function sendMail(\n toAgentId: string,\n from: string,\n message: string,\n priority: HookItem['priority'] = 'normal'\n): void {\n initHook(toAgentId);\n const mailDir = getMailDir(toAgentId);\n\n const mailItem: HookItem = {\n id: `mail-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n type: 'message',\n priority,\n source: from,\n payload: { message },\n createdAt: new Date().toISOString(),\n };\n\n writeFileSync(\n join(mailDir, `${mailItem.id}.json`),\n JSON.stringify(mailItem, null, 2)\n );\n}\n\n/**\n * Get and clear mail for an agent\n */\nexport function collectMail(agentId: string): HookItem[] {\n const mailDir = getMailDir(agentId);\n if (!existsSync(mailDir)) return [];\n\n const mails: HookItem[] = [];\n const files = readdirSync(mailDir).filter((f) => f.endsWith('.json'));\n\n for (const file of files) {\n const filePath = join(mailDir, file);\n try {\n const content = readFileSync(filePath, 'utf-8');\n mails.push(JSON.parse(content));\n unlinkSync(filePath); // Remove after reading\n } catch {\n // Skip invalid mail\n }\n }\n\n return mails;\n}\n\n/**\n * Generate Fixed Point prompt for agent startup\n */\nexport function generateFixedPointPrompt(agentId: string): string | null {\n const { hasWork, urgentCount, items } = checkHook(agentId);\n\n if (!hasWork) return null;\n\n const lines: string[] = [\n '# FPP: Work Found on Your Hook',\n '',\n '> \"Any runnable action is a fixed point and must resolve before the system can rest.\"',\n '',\n ];\n\n if (urgentCount > 0) {\n lines.push(`⚠️ **${urgentCount} URGENT item(s) require immediate attention**`);\n lines.push('');\n }\n\n lines.push(`## Pending Work Items (${items.length})`);\n lines.push('');\n\n for (const item of items) {\n const priorityEmoji = {\n urgent: '🔴',\n high: '🟠',\n normal: '🟢',\n low: '⚪',\n }[item.priority];\n\n lines.push(`### ${priorityEmoji} ${item.type.toUpperCase()}: ${item.id}`);\n lines.push(`- Source: ${item.source}`);\n lines.push(`- Created: ${item.createdAt}`);\n\n if (item.payload.issueId) {\n lines.push(`- Issue: ${item.payload.issueId}`);\n }\n if (item.payload.message) {\n lines.push(`- Message: ${item.payload.message}`);\n }\n if (item.payload.action) {\n lines.push(`- Action: ${item.payload.action}`);\n }\n lines.push('');\n }\n\n lines.push('---');\n lines.push('');\n lines.push('Execute these items in priority order. Use `bd hook pop <id>` after completing each item.');\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __esmMin } from "./chunk-DORXReHP.js";
|
|
2
|
-
import { n as init_workspace_config, r as replacePlaceholders } from "./workspace-config-
|
|
2
|
+
import { n as init_workspace_config, r as replacePlaceholders } from "./workspace-config-DVDR-Ukh.js";
|
|
3
3
|
//#region ../../lib/hume.ts
|
|
4
4
|
/**
|
|
5
5
|
* Make an authenticated Hume API request.
|
|
@@ -179,4 +179,4 @@ var init_hume = __esmMin((() => {
|
|
|
179
179
|
//#endregion
|
|
180
180
|
export { deleteHumeConfig as n, init_hume as r, createHumeConfig as t };
|
|
181
181
|
|
|
182
|
-
//# sourceMappingURL=hume-
|
|
182
|
+
//# sourceMappingURL=hume-JsAlMOJC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hume-CX_U3Qha.js","names":[],"sources":["../../src/lib/hume.ts"],"sourcesContent":["/**\n * Hume EVI Config Management\n *\n * Manages per-workspace Hume EVI configs for BYOLLM (Bring Your Own LLM).\n * Called during workspace create (createHumeConfig) and workspace remove/deep-wipe (deleteHumeConfig).\n *\n * Pattern mirrors tunnel.ts — stateless CRUD against external API.\n */\n\nimport { HumeConfig, TemplatePlaceholders, replacePlaceholders } from './workspace-config.js';\n\nexport interface HumeResult {\n success: boolean;\n steps: string[];\n /** Populated on successful create */\n configId?: string;\n configName?: string;\n}\n\nconst HUME_API = 'https://api.hume.ai/v0/evi';\nconst FETCH_TIMEOUT = 15_000;\n\n/**\n * Make an authenticated Hume API request.\n * Auth via X-Hume-Api-Key header.\n */\nasync function humeFetch(\n path: string,\n apiKey: string,\n method: 'GET' | 'POST' | 'DELETE' = 'GET',\n body?: unknown,\n): Promise<{ ok: boolean; status: number; data: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT);\n\n try {\n const resp = await fetch(`${HUME_API}${path}`, {\n method,\n headers: {\n 'X-Hume-Api-Key': apiKey,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n // DELETE returns 204 No Content\n if (resp.status === 204) {\n return { ok: true, status: 204, data: null };\n }\n\n const json = await resp.json();\n return { ok: resp.ok, status: resp.status, data: json };\n } catch (err: any) {\n return { ok: false, status: 0, data: { message: err.message } };\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Create a workspace-specific Hume EVI config by cloning the template config.\n *\n * Steps:\n * 1. Resolve config name from name_pattern with placeholders\n * 2. Check if config already exists (idempotent)\n * 3. GET template config to extract voice, prompt, tools, etc.\n * 4. POST new config with workspace-specific BYOLLM URL\n */\nexport async function createHumeConfig(\n config: HumeConfig,\n placeholders: TemplatePlaceholders,\n): Promise<HumeResult> {\n const steps: string[] = [];\n\n // Resolve API key\n const apiKey = process.env[config.api_key_env || 'HUME_API_KEY'];\n if (!apiKey) {\n return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || 'HUME_API_KEY'}`] };\n }\n\n // Resolve config name and BYOLLM URL\n const configName = replacePlaceholders(config.name_pattern, placeholders);\n const byollmUrl = replacePlaceholders(config.byollm_url_pattern, placeholders);\n steps.push(`[hume] Target config: ${configName}`);\n steps.push(`[hume] BYOLLM URL: ${byollmUrl}`);\n\n // Check if config already exists (idempotent)\n const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);\n if (listResult.ok) {\n const configs = listResult.data?.configs_page ?? [];\n const existing = Array.isArray(configs)\n ? configs.find((c: any) => c.name === configName)\n : null;\n if (existing) {\n steps.push(`[hume] Config \"${configName}\" already exists (ID: ${existing.id}), skipping creation`);\n return { success: true, steps, configId: existing.id, configName };\n }\n }\n\n // GET template config (API returns paginated format even for single-config lookup)\n const templateResult = await humeFetch(`/configs/${config.template_config_id}`, apiKey);\n if (!templateResult.ok) {\n steps.push(`[hume] Failed to get template config ${config.template_config_id}: ${JSON.stringify(templateResult.data)}`);\n return { success: false, steps };\n }\n\n // Extract config from paginated response\n const templatePage = templateResult.data?.configs_page;\n const template = Array.isArray(templatePage) ? templatePage[0] : templateResult.data;\n if (!template || !template.id) {\n steps.push(`[hume] Template config ${config.template_config_id} not found in response`);\n return { success: false, steps };\n }\n steps.push(`[hume] Read template config: ${template.name || config.template_config_id}`);\n\n // Build new config payload — clone template but override name and BYOLLM URL\n const newConfig: Record<string, any> = {\n name: configName,\n evi_version: template.evi_version || '3',\n language_model: {\n model_provider: 'CUSTOM_LANGUAGE_MODEL',\n model_resource: byollmUrl,\n },\n };\n\n // Preserve voice from template\n if (template.voice) {\n newConfig.voice = template.voice;\n }\n\n // Preserve prompt from template\n if (template.prompt) {\n newConfig.prompt = template.prompt;\n }\n\n // Preserve event messages from template\n if (template.event_messages) {\n newConfig.event_messages = template.event_messages;\n }\n\n // Preserve timeouts from template\n if (template.timeouts) {\n newConfig.timeouts = template.timeouts;\n }\n\n // Preserve tools from template\n if (template.tools) {\n newConfig.tools = template.tools;\n }\n\n // Preserve builtin_tools from template\n if (template.builtin_tools) {\n newConfig.builtin_tools = template.builtin_tools;\n }\n\n // Preserve ellm_model (quick responses) from template\n if (template.ellm_model) {\n newConfig.ellm_model = template.ellm_model;\n }\n\n // Create new config\n const createResult = await humeFetch('/configs', apiKey, 'POST', newConfig);\n if (!createResult.ok) {\n steps.push(`[hume] Failed to create config: ${JSON.stringify(createResult.data)}`);\n return { success: false, steps };\n }\n\n const newId = createResult.data?.id;\n steps.push(`[hume] Created config \"${configName}\" (ID: ${newId})`);\n\n return { success: true, steps, configId: newId, configName };\n}\n\n/**\n * Delete a workspace-specific Hume EVI config.\n *\n * Steps:\n * 1. List configs matching the workspace name\n * 2. DELETE each match\n */\nexport async function deleteHumeConfig(\n config: HumeConfig,\n placeholders: TemplatePlaceholders,\n): Promise<HumeResult> {\n const steps: string[] = [];\n\n // Resolve API key\n const apiKey = process.env[config.api_key_env || 'HUME_API_KEY'];\n if (!apiKey) {\n return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || 'HUME_API_KEY'}`] };\n }\n\n const configName = replacePlaceholders(config.name_pattern, placeholders);\n steps.push(`[hume] Looking for config: ${configName}`);\n\n // List configs matching the name\n const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);\n if (!listResult.ok) {\n steps.push(`[hume] Failed to list configs: ${JSON.stringify(listResult.data)}`);\n return { success: false, steps };\n }\n\n const configs = listResult.data?.configs_page ?? [];\n const matches = Array.isArray(configs)\n ? configs.filter((c: any) => c.name === configName)\n : [];\n\n if (matches.length === 0) {\n steps.push(`[hume] No config found with name \"${configName}\"`);\n return { success: true, steps };\n }\n\n let allOk = true;\n for (const match of matches) {\n const delResult = await humeFetch(`/configs/${match.id}`, apiKey, 'DELETE');\n if (delResult.ok) {\n steps.push(`[hume] Deleted config \"${configName}\" (ID: ${match.id})`);\n } else {\n steps.push(`[hume] Failed to delete config ${match.id}: ${JSON.stringify(delResult.data)}`);\n allOk = false;\n }\n }\n\n return { success: allOk, steps };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hume-JsAlMOJC.js","names":[],"sources":["../../src/lib/hume.ts"],"sourcesContent":["/**\n * Hume EVI Config Management\n *\n * Manages per-workspace Hume EVI configs for BYOLLM (Bring Your Own LLM).\n * Called during workspace create (createHumeConfig) and workspace remove/deep-wipe (deleteHumeConfig).\n *\n * Pattern mirrors tunnel.ts — stateless CRUD against external API.\n */\n\nimport { HumeConfig, TemplatePlaceholders, replacePlaceholders } from './workspace-config.js';\n\nexport interface HumeResult {\n success: boolean;\n steps: string[];\n /** Populated on successful create */\n configId?: string;\n configName?: string;\n}\n\nconst HUME_API = 'https://api.hume.ai/v0/evi';\nconst FETCH_TIMEOUT = 15_000;\n\n/**\n * Make an authenticated Hume API request.\n * Auth via X-Hume-Api-Key header.\n */\nasync function humeFetch(\n path: string,\n apiKey: string,\n method: 'GET' | 'POST' | 'DELETE' = 'GET',\n body?: unknown,\n): Promise<{ ok: boolean; status: number; data: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT);\n\n try {\n const resp = await fetch(`${HUME_API}${path}`, {\n method,\n headers: {\n 'X-Hume-Api-Key': apiKey,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n // DELETE returns 204 No Content\n if (resp.status === 204) {\n return { ok: true, status: 204, data: null };\n }\n\n const json = await resp.json();\n return { ok: resp.ok, status: resp.status, data: json };\n } catch (err: any) {\n return { ok: false, status: 0, data: { message: err.message } };\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Create a workspace-specific Hume EVI config by cloning the template config.\n *\n * Steps:\n * 1. Resolve config name from name_pattern with placeholders\n * 2. Check if config already exists (idempotent)\n * 3. GET template config to extract voice, prompt, tools, etc.\n * 4. POST new config with workspace-specific BYOLLM URL\n */\nexport async function createHumeConfig(\n config: HumeConfig,\n placeholders: TemplatePlaceholders,\n): Promise<HumeResult> {\n const steps: string[] = [];\n\n // Resolve API key\n const apiKey = process.env[config.api_key_env || 'HUME_API_KEY'];\n if (!apiKey) {\n return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || 'HUME_API_KEY'}`] };\n }\n\n // Resolve config name and BYOLLM URL\n const configName = replacePlaceholders(config.name_pattern, placeholders);\n const byollmUrl = replacePlaceholders(config.byollm_url_pattern, placeholders);\n steps.push(`[hume] Target config: ${configName}`);\n steps.push(`[hume] BYOLLM URL: ${byollmUrl}`);\n\n // Check if config already exists (idempotent)\n const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);\n if (listResult.ok) {\n const configs = listResult.data?.configs_page ?? [];\n const existing = Array.isArray(configs)\n ? configs.find((c: any) => c.name === configName)\n : null;\n if (existing) {\n steps.push(`[hume] Config \"${configName}\" already exists (ID: ${existing.id}), skipping creation`);\n return { success: true, steps, configId: existing.id, configName };\n }\n }\n\n // GET template config (API returns paginated format even for single-config lookup)\n const templateResult = await humeFetch(`/configs/${config.template_config_id}`, apiKey);\n if (!templateResult.ok) {\n steps.push(`[hume] Failed to get template config ${config.template_config_id}: ${JSON.stringify(templateResult.data)}`);\n return { success: false, steps };\n }\n\n // Extract config from paginated response\n const templatePage = templateResult.data?.configs_page;\n const template = Array.isArray(templatePage) ? templatePage[0] : templateResult.data;\n if (!template || !template.id) {\n steps.push(`[hume] Template config ${config.template_config_id} not found in response`);\n return { success: false, steps };\n }\n steps.push(`[hume] Read template config: ${template.name || config.template_config_id}`);\n\n // Build new config payload — clone template but override name and BYOLLM URL\n const newConfig: Record<string, any> = {\n name: configName,\n evi_version: template.evi_version || '3',\n language_model: {\n model_provider: 'CUSTOM_LANGUAGE_MODEL',\n model_resource: byollmUrl,\n },\n };\n\n // Preserve voice from template\n if (template.voice) {\n newConfig.voice = template.voice;\n }\n\n // Preserve prompt from template\n if (template.prompt) {\n newConfig.prompt = template.prompt;\n }\n\n // Preserve event messages from template\n if (template.event_messages) {\n newConfig.event_messages = template.event_messages;\n }\n\n // Preserve timeouts from template\n if (template.timeouts) {\n newConfig.timeouts = template.timeouts;\n }\n\n // Preserve tools from template\n if (template.tools) {\n newConfig.tools = template.tools;\n }\n\n // Preserve builtin_tools from template\n if (template.builtin_tools) {\n newConfig.builtin_tools = template.builtin_tools;\n }\n\n // Preserve ellm_model (quick responses) from template\n if (template.ellm_model) {\n newConfig.ellm_model = template.ellm_model;\n }\n\n // Create new config\n const createResult = await humeFetch('/configs', apiKey, 'POST', newConfig);\n if (!createResult.ok) {\n steps.push(`[hume] Failed to create config: ${JSON.stringify(createResult.data)}`);\n return { success: false, steps };\n }\n\n const newId = createResult.data?.id;\n steps.push(`[hume] Created config \"${configName}\" (ID: ${newId})`);\n\n return { success: true, steps, configId: newId, configName };\n}\n\n/**\n * Delete a workspace-specific Hume EVI config.\n *\n * Steps:\n * 1. List configs matching the workspace name\n * 2. DELETE each match\n */\nexport async function deleteHumeConfig(\n config: HumeConfig,\n placeholders: TemplatePlaceholders,\n): Promise<HumeResult> {\n const steps: string[] = [];\n\n // Resolve API key\n const apiKey = process.env[config.api_key_env || 'HUME_API_KEY'];\n if (!apiKey) {\n return { success: false, steps: [`[hume] API key not found in env var ${config.api_key_env || 'HUME_API_KEY'}`] };\n }\n\n const configName = replacePlaceholders(config.name_pattern, placeholders);\n steps.push(`[hume] Looking for config: ${configName}`);\n\n // List configs matching the name\n const listResult = await humeFetch(`/configs?name=${encodeURIComponent(configName)}`, apiKey);\n if (!listResult.ok) {\n steps.push(`[hume] Failed to list configs: ${JSON.stringify(listResult.data)}`);\n return { success: false, steps };\n }\n\n const configs = listResult.data?.configs_page ?? [];\n const matches = Array.isArray(configs)\n ? configs.filter((c: any) => c.name === configName)\n : [];\n\n if (matches.length === 0) {\n steps.push(`[hume] No config found with name \"${configName}\"`);\n return { success: true, steps };\n }\n\n let allOk = true;\n for (const match of matches) {\n const delResult = await humeFetch(`/configs/${match.id}`, apiKey, 'DELETE');\n if (delResult.ok) {\n steps.push(`[hume] Deleted config \"${configName}\" (ID: ${match.id})`);\n } else {\n steps.push(`[hume] Failed to delete config ${match.id}: ${JSON.stringify(delResult.data)}`);\n allOk = false;\n }\n }\n\n return { success: allOk, steps };\n}\n"],"mappings":";;;;;;;AA0BA,eAAe,UACb,MACA,QACA,SAAoC,OACpC,MACqD;CACrD,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,UAAU,iBAAiB,WAAW,OAAO,EAAE,cAAc;AAEnE,KAAI;EACF,MAAM,OAAO,MAAM,MAAM,GAAG,WAAW,QAAQ;GAC7C;GACA,SAAS;IACP,kBAAkB;IAClB,gBAAgB;IACjB;GACD,MAAM,OAAO,KAAK,UAAU,KAAK,GAAG,KAAA;GACpC,QAAQ,WAAW;GACpB,CAAC;AAGF,MAAI,KAAK,WAAW,IAClB,QAAO;GAAE,IAAI;GAAM,QAAQ;GAAK,MAAM;GAAM;EAG9C,MAAM,OAAO,MAAM,KAAK,MAAM;AAC9B,SAAO;GAAE,IAAI,KAAK;GAAI,QAAQ,KAAK;GAAQ,MAAM;GAAM;UAChD,KAAU;AACjB,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAG,MAAM,EAAE,SAAS,IAAI,SAAS;GAAE;WACvD;AACR,eAAa,QAAQ;;;;;;;;;;;;AAazB,eAAsB,iBACpB,QACA,cACqB;CACrB,MAAM,QAAkB,EAAE;CAG1B,MAAM,SAAS,QAAQ,IAAI,OAAO,eAAe;AACjD,KAAI,CAAC,OACH,QAAO;EAAE,SAAS;EAAO,OAAO,CAAC,uCAAuC,OAAO,eAAe,iBAAiB;EAAE;CAInH,MAAM,aAAa,oBAAoB,OAAO,cAAc,aAAa;CACzE,MAAM,YAAY,oBAAoB,OAAO,oBAAoB,aAAa;AAC9E,OAAM,KAAK,yBAAyB,aAAa;AACjD,OAAM,KAAK,sBAAsB,YAAY;CAG7C,MAAM,aAAa,MAAM,UAAU,iBAAiB,mBAAmB,WAAW,IAAI,OAAO;AAC7F,KAAI,WAAW,IAAI;EACjB,MAAM,UAAU,WAAW,MAAM,gBAAgB,EAAE;EACnD,MAAM,WAAW,MAAM,QAAQ,QAAQ,GACnC,QAAQ,MAAM,MAAW,EAAE,SAAS,WAAW,GAC/C;AACJ,MAAI,UAAU;AACZ,SAAM,KAAK,kBAAkB,WAAW,wBAAwB,SAAS,GAAG,sBAAsB;AAClG,UAAO;IAAE,SAAS;IAAM;IAAO,UAAU,SAAS;IAAI;IAAY;;;CAKtE,MAAM,iBAAiB,MAAM,UAAU,YAAY,OAAO,sBAAsB,OAAO;AACvF,KAAI,CAAC,eAAe,IAAI;AACtB,QAAM,KAAK,wCAAwC,OAAO,mBAAmB,IAAI,KAAK,UAAU,eAAe,KAAK,GAAG;AACvH,SAAO;GAAE,SAAS;GAAO;GAAO;;CAIlC,MAAM,eAAe,eAAe,MAAM;CAC1C,MAAM,WAAW,MAAM,QAAQ,aAAa,GAAG,aAAa,KAAK,eAAe;AAChF,KAAI,CAAC,YAAY,CAAC,SAAS,IAAI;AAC7B,QAAM,KAAK,0BAA0B,OAAO,mBAAmB,wBAAwB;AACvF,SAAO;GAAE,SAAS;GAAO;GAAO;;AAElC,OAAM,KAAK,gCAAgC,SAAS,QAAQ,OAAO,qBAAqB;CAGxF,MAAM,YAAiC;EACrC,MAAM;EACN,aAAa,SAAS,eAAe;EACrC,gBAAgB;GACd,gBAAgB;GAChB,gBAAgB;GACjB;EACF;AAGD,KAAI,SAAS,MACX,WAAU,QAAQ,SAAS;AAI7B,KAAI,SAAS,OACX,WAAU,SAAS,SAAS;AAI9B,KAAI,SAAS,eACX,WAAU,iBAAiB,SAAS;AAItC,KAAI,SAAS,SACX,WAAU,WAAW,SAAS;AAIhC,KAAI,SAAS,MACX,WAAU,QAAQ,SAAS;AAI7B,KAAI,SAAS,cACX,WAAU,gBAAgB,SAAS;AAIrC,KAAI,SAAS,WACX,WAAU,aAAa,SAAS;CAIlC,MAAM,eAAe,MAAM,UAAU,YAAY,QAAQ,QAAQ,UAAU;AAC3E,KAAI,CAAC,aAAa,IAAI;AACpB,QAAM,KAAK,mCAAmC,KAAK,UAAU,aAAa,KAAK,GAAG;AAClF,SAAO;GAAE,SAAS;GAAO;GAAO;;CAGlC,MAAM,QAAQ,aAAa,MAAM;AACjC,OAAM,KAAK,0BAA0B,WAAW,SAAS,MAAM,GAAG;AAElE,QAAO;EAAE,SAAS;EAAM;EAAO,UAAU;EAAO;EAAY;;;;;;;;;AAU9D,eAAsB,iBACpB,QACA,cACqB;CACrB,MAAM,QAAkB,EAAE;CAG1B,MAAM,SAAS,QAAQ,IAAI,OAAO,eAAe;AACjD,KAAI,CAAC,OACH,QAAO;EAAE,SAAS;EAAO,OAAO,CAAC,uCAAuC,OAAO,eAAe,iBAAiB;EAAE;CAGnH,MAAM,aAAa,oBAAoB,OAAO,cAAc,aAAa;AACzE,OAAM,KAAK,8BAA8B,aAAa;CAGtD,MAAM,aAAa,MAAM,UAAU,iBAAiB,mBAAmB,WAAW,IAAI,OAAO;AAC7F,KAAI,CAAC,WAAW,IAAI;AAClB,QAAM,KAAK,kCAAkC,KAAK,UAAU,WAAW,KAAK,GAAG;AAC/E,SAAO;GAAE,SAAS;GAAO;GAAO;;CAGlC,MAAM,UAAU,WAAW,MAAM,gBAAgB,EAAE;CACnD,MAAM,UAAU,MAAM,QAAQ,QAAQ,GAClC,QAAQ,QAAQ,MAAW,EAAE,SAAS,WAAW,GACjD,EAAE;AAEN,KAAI,QAAQ,WAAW,GAAG;AACxB,QAAM,KAAK,qCAAqC,WAAW,GAAG;AAC9D,SAAO;GAAE,SAAS;GAAM;GAAO;;CAGjC,IAAI,QAAQ;AACZ,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,YAAY,MAAM,UAAU,YAAY,MAAM,MAAM,QAAQ,SAAS;AAC3E,MAAI,UAAU,GACZ,OAAM,KAAK,0BAA0B,WAAW,SAAS,MAAM,GAAG,GAAG;OAChE;AACL,SAAM,KAAK,kCAAkC,MAAM,GAAG,IAAI,KAAK,UAAU,UAAU,KAAK,GAAG;AAC3F,WAAQ;;;AAIZ,QAAO;EAAE,SAAS;EAAO;EAAO;;;;wBAvN4D;AAUxF,YAAW;AACX,iBAAgB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as init_review_status } from "./review-status-
|
|
2
|
-
import { j as init_specialists } from "./specialists-
|
|
1
|
+
import { i as init_review_status } from "./review-status-Bymwzh2i.js";
|
|
2
|
+
import { j as init_specialists } from "./specialists-B_zrayaP.js";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import { homedir } from "os";
|
|
@@ -95,4 +95,4 @@ async function onInspectComplete(projectKey, issueId, beadId, status, workspaceP
|
|
|
95
95
|
//#endregion
|
|
96
96
|
export { onInspectComplete };
|
|
97
97
|
|
|
98
|
-
//# sourceMappingURL=inspect-agent-
|
|
98
|
+
//# sourceMappingURL=inspect-agent-7eour7EA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect-agent-B57kGDUV.js","names":["execAsync"],"sources":["../../src/lib/cloister/inspect-checkpoints.ts","../../src/lib/cloister/inspect-agent.ts"],"sourcesContent":["/**\n * PAN-382: Inspection checkpoint system.\n *\n * Tracks commit SHAs where inspections passed, scoping subsequent\n * inspection diffs to only the changes since the last checkpoint.\n *\n * First inspection: diff from branch base (main...HEAD)\n * Subsequent: diff from last checkpoint SHA to HEAD\n */\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\nconst PANOPTICON_HOME = join(homedir(), '.panopticon');\n\nexport interface InspectCheckpoint {\n beadId: string;\n commitSha: string;\n passedAt: string; // ISO 8601\n}\n\nexport interface InspectCheckpointFile {\n issueId: string;\n checkpoints: InspectCheckpoint[];\n}\n\n/**\n * Get the directory for a project's inspect checkpoints.\n */\nfunction getCheckpointDir(projectKey: string): string {\n return join(PANOPTICON_HOME, 'specialists', projectKey, 'inspect-agent', 'checkpoints');\n}\n\n/**\n * Get the checkpoint file path for an issue.\n */\nfunction getCheckpointPath(projectKey: string, issueId: string): string {\n return join(getCheckpointDir(projectKey), `${issueId.toUpperCase()}.json`);\n}\n\n/**\n * Load checkpoints for an issue. Returns null if no checkpoints exist.\n */\nexport function loadCheckpoints(projectKey: string, issueId: string): InspectCheckpointFile | null {\n const filePath = getCheckpointPath(projectKey, issueId);\n if (!existsSync(filePath)) return null;\n\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Get the last checkpoint for an issue, or null if none exist.\n */\nexport function getLastCheckpoint(projectKey: string, issueId: string): InspectCheckpoint | null {\n const data = loadCheckpoints(projectKey, issueId);\n if (!data || data.checkpoints.length === 0) return null;\n return data.checkpoints[data.checkpoints.length - 1];\n}\n\n/**\n * Save a new checkpoint after a successful inspection.\n */\nexport function saveCheckpoint(\n projectKey: string,\n issueId: string,\n beadId: string,\n commitSha: string\n): InspectCheckpoint {\n const dir = getCheckpointDir(projectKey);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const data = loadCheckpoints(projectKey, issueId) || {\n issueId: issueId.toUpperCase(),\n checkpoints: [],\n };\n\n const checkpoint: InspectCheckpoint = {\n beadId,\n commitSha,\n passedAt: new Date().toISOString(),\n };\n\n data.checkpoints.push(checkpoint);\n writeFileSync(getCheckpointPath(projectKey, issueId), JSON.stringify(data, null, 2));\n\n return checkpoint;\n}\n\n/**\n * Get the diff base for an inspection.\n *\n * - If a previous checkpoint exists, diff from that commit\n * - Otherwise, diff from the merge-base with main (full branch diff)\n *\n * Returns the commit SHA or ref to diff from.\n */\nexport async function getDiffBase(projectKey: string, issueId: string, workspacePath: string): Promise<string> {\n const lastCheckpoint = getLastCheckpoint(projectKey, issueId);\n\n if (lastCheckpoint) {\n return lastCheckpoint.commitSha;\n }\n\n // No checkpoint — use the merge-base with main\n try {\n const { stdout } = await execAsync('git merge-base main HEAD', {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim();\n } catch {\n // Fallback to 'main' if merge-base fails\n return 'main';\n }\n}\n\n/**\n * Get the diff stats (files changed, insertions, deletions) for the inspection scope.\n */\nexport async function getDiffStats(workspacePath: string, diffBase: string): Promise<string> {\n try {\n const { stdout } = await execAsync(`git diff --stat ${diffBase}...HEAD`, {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim() || 'No changes detected';\n } catch {\n return 'Unable to compute diff stats';\n }\n}\n\n/**\n * Get the current HEAD commit SHA.\n */\nexport async function getCurrentHead(workspacePath: string): Promise<string> {\n try {\n const { stdout } = await execAsync('git rev-parse HEAD', {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim();\n } catch {\n return 'unknown';\n }\n}\n","/**\n * PAN-382: Inspect Agent — Per-step verification specialist.\n *\n * Spawns after each bead completion to verify the implementation matches\n * its specification and architectural constraints before the agent\n * proceeds to the next bead.\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport {\n getDiffBase,\n getDiffStats,\n getCurrentHead,\n saveCheckpoint,\n} from './inspect-checkpoints.js';\nimport { spawnEphemeralSpecialist, type SpecialistType } from './specialists.js';\nimport { setReviewStatus } from '../review-status.js';\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Context for an inspection request\n */\nexport interface InspectContext {\n projectKey: string;\n projectPath: string;\n issueId: string;\n beadId: string;\n workspace: string;\n branch?: string;\n}\n\n/**\n * Result of inspection\n */\nexport interface InspectResult {\n success: boolean;\n inspectResult: 'PASS' | 'BLOCKED';\n beadId: string;\n notes?: string;\n}\n\n/**\n * Read a bead's description using the bd CLI.\n */\nasync function getBeadDescription(beadId: string, workspacePath: string): Promise<string> {\n try {\n const { stdout } = await execAsync(`bd show ${beadId} --json`, {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n const bead = JSON.parse(stdout);\n const parts: string[] = [];\n if (bead.title) parts.push(`**Title:** ${bead.title}`);\n if (bead.description) parts.push(`**Description:** ${bead.description}`);\n if (bead.acceptance) parts.push(`**Acceptance Criteria:** ${bead.acceptance}`);\n if (bead.notes) parts.push(`**Notes:** ${bead.notes}`);\n if (bead.labels?.length) parts.push(`**Labels:** ${bead.labels.join(', ')}`);\n return parts.join('\\n\\n') || `Bead ${beadId} (no description available)`;\n } catch {\n // Fallback: try without --json\n try {\n const { stdout } = await execAsync(`bd show ${beadId}`, {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim() || `Bead ${beadId} (no description available)`;\n } catch {\n return `Bead ${beadId} (unable to read bead description)`;\n }\n }\n}\n\n/**\n * Detect the compile/lint command for the workspace.\n */\nfunction detectCompileCommand(workspacePath: string): string {\n // Check for common project types\n const checks: Array<{ file: string; command: string }> = [\n { file: 'tsconfig.json', command: 'npx tsc --noEmit && npx eslint . --max-warnings=0 2>/dev/null || npx eslint .' },\n { file: 'package.json', command: 'npm run build 2>&1 | tail -20' },\n { file: 'pom.xml', command: './mvnw compile -q' },\n { file: 'Cargo.toml', command: 'cargo check' },\n { file: 'go.mod', command: 'go build ./...' },\n ];\n\n for (const check of checks) {\n // Check workspace root and common subdirectories\n for (const subdir of ['', 'fe', 'api', 'frontend', 'backend']) {\n const checkPath = subdir ? join(workspacePath, subdir, check.file) : join(workspacePath, check.file);\n if (existsSync(checkPath)) {\n const cwd = subdir ? `cd ${subdir} && ` : '';\n return `${cwd}${check.command}`;\n }\n }\n }\n\n return 'echo \"No compile command detected — skipping compile check\"';\n}\n\n/**\n * Build the prompt for the inspect specialist.\n */\nexport async function buildInspectPrompt(context: InspectContext): Promise<string> {\n const templatePath = join(__dirname, 'prompts', 'inspect-agent.md');\n\n if (!existsSync(templatePath)) {\n throw new Error(`Inspect agent prompt template not found at ${templatePath}`);\n }\n\n const template = readFileSync(templatePath, 'utf-8');\n\n // Get bead description\n const beadDescription = await getBeadDescription(context.beadId, context.workspace);\n\n // Get diff scope\n const diffBase = await getDiffBase(context.projectKey, context.issueId, context.workspace);\n const diffStats = await getDiffStats(context.workspace, diffBase);\n const compileCommand = detectCompileCommand(context.workspace);\n\n const apiUrl = process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || '3011'}`;\n\n // Replace template variables\n const prompt = template\n .replace(/\\{\\{apiUrl\\}\\}/g, apiUrl)\n .replace(/\\{\\{projectPath\\}\\}/g, context.projectPath)\n .replace(/\\{\\{issueId\\}\\}/g, context.issueId)\n .replace(/\\{\\{beadId\\}\\}/g, context.beadId)\n .replace(/\\{\\{workspacePath\\}\\}/g, context.workspace)\n .replace(/\\{\\{checkpoint\\}\\}/g, diffBase.substring(0, 8))\n .replace(/\\{\\{diffBase\\}\\}/g, diffBase)\n .replace(/\\{\\{diffStats\\}\\}/g, diffStats)\n .replace(/\\{\\{beadDescription\\}\\}/g, beadDescription)\n .replace(/\\{\\{compileCommand\\}\\}/g, compileCommand)\n .replace(/\\{\\{resultStatus\\}\\}/g, '${RESULT_STATUS}') // Placeholder for specialist to fill\n .replace(/\\{\\{resultNotes\\}\\}/g, '${RESULT_NOTES}'); // Placeholder for specialist to fill\n\n return `<!-- panopticon:orchestration-context-start -->\\n${prompt}\\n<!-- panopticon:orchestration-context-end -->`;\n}\n\n/**\n * Spawn the inspect specialist for a bead.\n */\nexport async function spawnInspectAgent(context: InspectContext): Promise<{\n success: boolean;\n runId?: string;\n tmuxSession?: string;\n message: string;\n error?: string;\n}> {\n // Build the prompt\n const prompt = await buildInspectPrompt(context);\n\n // Update status to inspecting\n setReviewStatus(context.issueId.toUpperCase(), {\n inspectStatus: 'inspecting',\n inspectNotes: `Inspecting bead ${context.beadId}`,\n });\n\n // Spawn the ephemeral specialist\n return spawnEphemeralSpecialist(context.projectKey, 'inspect-agent' as SpecialistType, {\n issueId: context.issueId,\n branch: context.branch,\n workspace: context.workspace,\n promptOverride: prompt,\n });\n}\n\n/**\n * Handle inspect completion — called when the inspect specialist signals done.\n * Saves checkpoint on PASS.\n */\nexport async function onInspectComplete(\n projectKey: string,\n issueId: string,\n beadId: string,\n status: 'passed' | 'failed',\n workspacePath: string\n): Promise<void> {\n if (status === 'passed') {\n const commitSha = await getCurrentHead(workspacePath);\n saveCheckpoint(projectKey, issueId, beadId, commitSha);\n console.log(`[inspect] Checkpoint saved for ${issueId} bead ${beadId} at ${commitSha.substring(0, 8)}`);\n\n } else {\n console.log(`[inspect] Bead ${beadId} blocked for ${issueId} — no checkpoint saved`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAeA,MAAMA,cAAY,UAAU,KAAK;AAEjC,MAAM,kBAAkB,KAAK,SAAS,EAAE,cAAc;;;;AAgBtD,SAAS,iBAAiB,YAA4B;AACpD,QAAO,KAAK,iBAAiB,eAAe,YAAY,iBAAiB,cAAc;;;;;AAMzF,SAAS,kBAAkB,YAAoB,SAAyB;AACtE,QAAO,KAAK,iBAAiB,WAAW,EAAE,GAAG,QAAQ,aAAa,CAAC,OAAO;;;;;AAM5E,SAAgB,gBAAgB,YAAoB,SAA+C;CACjG,MAAM,WAAW,kBAAkB,YAAY,QAAQ;AACvD,KAAI,CAAC,WAAW,SAAS,CAAE,QAAO;AAElC,KAAI;AACF,SAAO,KAAK,MAAM,aAAa,UAAU,QAAQ,CAAC;SAC5C;AACN,SAAO;;;;;;AAgBX,SAAgB,eACd,YACA,SACA,QACA,WACmB;CACnB,MAAM,MAAM,iBAAiB,WAAW;AACxC,KAAI,CAAC,WAAW,IAAI,CAClB,WAAU,KAAK,EAAE,WAAW,MAAM,CAAC;CAGrC,MAAM,OAAO,gBAAgB,YAAY,QAAQ,IAAI;EACnD,SAAS,QAAQ,aAAa;EAC9B,aAAa,EAAE;EAChB;CAED,MAAM,aAAgC;EACpC;EACA;EACA,2BAAU,IAAI,MAAM,EAAC,aAAa;EACnC;AAED,MAAK,YAAY,KAAK,WAAW;AACjC,eAAc,kBAAkB,YAAY,QAAQ,EAAE,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;AAEpF,QAAO;;;;;AAiDT,eAAsB,eAAe,eAAwC;AAC3E,KAAI;EACF,MAAM,EAAE,WAAW,MAAMA,YAAU,sBAAsB;GACvD,KAAK;GACL,UAAU;GACX,CAAC;AACF,SAAO,OAAO,MAAM;SACd;AACN,SAAO;;;;;kBCrIsE;oBAC3B;AAEpC,UAAU,KAAK;AAGf,QADC,cAAc,OAAO,KAAK,IAAI,CACZ;;;;;AA0JrC,eAAsB,kBACpB,YACA,SACA,QACA,QACA,eACe;AACf,KAAI,WAAW,UAAU;EACvB,MAAM,YAAY,MAAM,eAAe,cAAc;AACrD,iBAAe,YAAY,SAAS,QAAQ,UAAU;AACtD,UAAQ,IAAI,kCAAkC,QAAQ,QAAQ,OAAO,MAAM,UAAU,UAAU,GAAG,EAAE,GAAG;OAGvG,SAAQ,IAAI,kBAAkB,OAAO,eAAe,QAAQ,wBAAwB"}
|
|
1
|
+
{"version":3,"file":"inspect-agent-7eour7EA.js","names":["execAsync"],"sources":["../../src/lib/cloister/inspect-checkpoints.ts","../../src/lib/cloister/inspect-agent.ts"],"sourcesContent":["/**\n * PAN-382: Inspection checkpoint system.\n *\n * Tracks commit SHAs where inspections passed, scoping subsequent\n * inspection diffs to only the changes since the last checkpoint.\n *\n * First inspection: diff from branch base (main...HEAD)\n * Subsequent: diff from last checkpoint SHA to HEAD\n */\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\nconst PANOPTICON_HOME = join(homedir(), '.panopticon');\n\nexport interface InspectCheckpoint {\n beadId: string;\n commitSha: string;\n passedAt: string; // ISO 8601\n}\n\nexport interface InspectCheckpointFile {\n issueId: string;\n checkpoints: InspectCheckpoint[];\n}\n\n/**\n * Get the directory for a project's inspect checkpoints.\n */\nfunction getCheckpointDir(projectKey: string): string {\n return join(PANOPTICON_HOME, 'specialists', projectKey, 'inspect-agent', 'checkpoints');\n}\n\n/**\n * Get the checkpoint file path for an issue.\n */\nfunction getCheckpointPath(projectKey: string, issueId: string): string {\n return join(getCheckpointDir(projectKey), `${issueId.toUpperCase()}.json`);\n}\n\n/**\n * Load checkpoints for an issue. Returns null if no checkpoints exist.\n */\nexport function loadCheckpoints(projectKey: string, issueId: string): InspectCheckpointFile | null {\n const filePath = getCheckpointPath(projectKey, issueId);\n if (!existsSync(filePath)) return null;\n\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Get the last checkpoint for an issue, or null if none exist.\n */\nexport function getLastCheckpoint(projectKey: string, issueId: string): InspectCheckpoint | null {\n const data = loadCheckpoints(projectKey, issueId);\n if (!data || data.checkpoints.length === 0) return null;\n return data.checkpoints[data.checkpoints.length - 1];\n}\n\n/**\n * Save a new checkpoint after a successful inspection.\n */\nexport function saveCheckpoint(\n projectKey: string,\n issueId: string,\n beadId: string,\n commitSha: string\n): InspectCheckpoint {\n const dir = getCheckpointDir(projectKey);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const data = loadCheckpoints(projectKey, issueId) || {\n issueId: issueId.toUpperCase(),\n checkpoints: [],\n };\n\n const checkpoint: InspectCheckpoint = {\n beadId,\n commitSha,\n passedAt: new Date().toISOString(),\n };\n\n data.checkpoints.push(checkpoint);\n writeFileSync(getCheckpointPath(projectKey, issueId), JSON.stringify(data, null, 2));\n\n return checkpoint;\n}\n\n/**\n * Get the diff base for an inspection.\n *\n * - If a previous checkpoint exists, diff from that commit\n * - Otherwise, diff from the merge-base with main (full branch diff)\n *\n * Returns the commit SHA or ref to diff from.\n */\nexport async function getDiffBase(projectKey: string, issueId: string, workspacePath: string): Promise<string> {\n const lastCheckpoint = getLastCheckpoint(projectKey, issueId);\n\n if (lastCheckpoint) {\n return lastCheckpoint.commitSha;\n }\n\n // No checkpoint — use the merge-base with main\n try {\n const { stdout } = await execAsync('git merge-base main HEAD', {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim();\n } catch {\n // Fallback to 'main' if merge-base fails\n return 'main';\n }\n}\n\n/**\n * Get the diff stats (files changed, insertions, deletions) for the inspection scope.\n */\nexport async function getDiffStats(workspacePath: string, diffBase: string): Promise<string> {\n try {\n const { stdout } = await execAsync(`git diff --stat ${diffBase}...HEAD`, {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim() || 'No changes detected';\n } catch {\n return 'Unable to compute diff stats';\n }\n}\n\n/**\n * Get the current HEAD commit SHA.\n */\nexport async function getCurrentHead(workspacePath: string): Promise<string> {\n try {\n const { stdout } = await execAsync('git rev-parse HEAD', {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim();\n } catch {\n return 'unknown';\n }\n}\n","/**\n * PAN-382: Inspect Agent — Per-step verification specialist.\n *\n * Spawns after each bead completion to verify the implementation matches\n * its specification and architectural constraints before the agent\n * proceeds to the next bead.\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport {\n getDiffBase,\n getDiffStats,\n getCurrentHead,\n saveCheckpoint,\n} from './inspect-checkpoints.js';\nimport { spawnEphemeralSpecialist, type SpecialistType } from './specialists.js';\nimport { setReviewStatus } from '../review-status.js';\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Context for an inspection request\n */\nexport interface InspectContext {\n projectKey: string;\n projectPath: string;\n issueId: string;\n beadId: string;\n workspace: string;\n branch?: string;\n}\n\n/**\n * Result of inspection\n */\nexport interface InspectResult {\n success: boolean;\n inspectResult: 'PASS' | 'BLOCKED';\n beadId: string;\n notes?: string;\n}\n\n/**\n * Read a bead's description using the bd CLI.\n */\nasync function getBeadDescription(beadId: string, workspacePath: string): Promise<string> {\n try {\n const { stdout } = await execAsync(`bd show ${beadId} --json`, {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n const bead = JSON.parse(stdout);\n const parts: string[] = [];\n if (bead.title) parts.push(`**Title:** ${bead.title}`);\n if (bead.description) parts.push(`**Description:** ${bead.description}`);\n if (bead.acceptance) parts.push(`**Acceptance Criteria:** ${bead.acceptance}`);\n if (bead.notes) parts.push(`**Notes:** ${bead.notes}`);\n if (bead.labels?.length) parts.push(`**Labels:** ${bead.labels.join(', ')}`);\n return parts.join('\\n\\n') || `Bead ${beadId} (no description available)`;\n } catch {\n // Fallback: try without --json\n try {\n const { stdout } = await execAsync(`bd show ${beadId}`, {\n cwd: workspacePath,\n encoding: 'utf-8',\n });\n return stdout.trim() || `Bead ${beadId} (no description available)`;\n } catch {\n return `Bead ${beadId} (unable to read bead description)`;\n }\n }\n}\n\n/**\n * Detect the compile/lint command for the workspace.\n */\nfunction detectCompileCommand(workspacePath: string): string {\n // Check for common project types\n const checks: Array<{ file: string; command: string }> = [\n { file: 'tsconfig.json', command: 'npx tsc --noEmit && npx eslint . --max-warnings=0 2>/dev/null || npx eslint .' },\n { file: 'package.json', command: 'npm run build 2>&1 | tail -20' },\n { file: 'pom.xml', command: './mvnw compile -q' },\n { file: 'Cargo.toml', command: 'cargo check' },\n { file: 'go.mod', command: 'go build ./...' },\n ];\n\n for (const check of checks) {\n // Check workspace root and common subdirectories\n for (const subdir of ['', 'fe', 'api', 'frontend', 'backend']) {\n const checkPath = subdir ? join(workspacePath, subdir, check.file) : join(workspacePath, check.file);\n if (existsSync(checkPath)) {\n const cwd = subdir ? `cd ${subdir} && ` : '';\n return `${cwd}${check.command}`;\n }\n }\n }\n\n return 'echo \"No compile command detected — skipping compile check\"';\n}\n\n/**\n * Build the prompt for the inspect specialist.\n */\nexport async function buildInspectPrompt(context: InspectContext): Promise<string> {\n const templatePath = join(__dirname, 'prompts', 'inspect-agent.md');\n\n if (!existsSync(templatePath)) {\n throw new Error(`Inspect agent prompt template not found at ${templatePath}`);\n }\n\n const template = readFileSync(templatePath, 'utf-8');\n\n // Get bead description\n const beadDescription = await getBeadDescription(context.beadId, context.workspace);\n\n // Get diff scope\n const diffBase = await getDiffBase(context.projectKey, context.issueId, context.workspace);\n const diffStats = await getDiffStats(context.workspace, diffBase);\n const compileCommand = detectCompileCommand(context.workspace);\n\n const apiUrl = process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || '3011'}`;\n\n // Replace template variables\n const prompt = template\n .replace(/\\{\\{apiUrl\\}\\}/g, apiUrl)\n .replace(/\\{\\{projectPath\\}\\}/g, context.projectPath)\n .replace(/\\{\\{issueId\\}\\}/g, context.issueId)\n .replace(/\\{\\{beadId\\}\\}/g, context.beadId)\n .replace(/\\{\\{workspacePath\\}\\}/g, context.workspace)\n .replace(/\\{\\{checkpoint\\}\\}/g, diffBase.substring(0, 8))\n .replace(/\\{\\{diffBase\\}\\}/g, diffBase)\n .replace(/\\{\\{diffStats\\}\\}/g, diffStats)\n .replace(/\\{\\{beadDescription\\}\\}/g, beadDescription)\n .replace(/\\{\\{compileCommand\\}\\}/g, compileCommand)\n .replace(/\\{\\{resultStatus\\}\\}/g, '${RESULT_STATUS}') // Placeholder for specialist to fill\n .replace(/\\{\\{resultNotes\\}\\}/g, '${RESULT_NOTES}'); // Placeholder for specialist to fill\n\n return `<!-- panopticon:orchestration-context-start -->\\n${prompt}\\n<!-- panopticon:orchestration-context-end -->`;\n}\n\n/**\n * Spawn the inspect specialist for a bead.\n */\nexport async function spawnInspectAgent(context: InspectContext): Promise<{\n success: boolean;\n runId?: string;\n tmuxSession?: string;\n message: string;\n error?: string;\n}> {\n // Build the prompt\n const prompt = await buildInspectPrompt(context);\n\n // Update status to inspecting\n setReviewStatus(context.issueId.toUpperCase(), {\n inspectStatus: 'inspecting',\n inspectNotes: `Inspecting bead ${context.beadId}`,\n });\n\n // Spawn the ephemeral specialist\n return spawnEphemeralSpecialist(context.projectKey, 'inspect-agent' as SpecialistType, {\n issueId: context.issueId,\n branch: context.branch,\n workspace: context.workspace,\n promptOverride: prompt,\n });\n}\n\n/**\n * Handle inspect completion — called when the inspect specialist signals done.\n * Saves checkpoint on PASS.\n */\nexport async function onInspectComplete(\n projectKey: string,\n issueId: string,\n beadId: string,\n status: 'passed' | 'failed',\n workspacePath: string\n): Promise<void> {\n if (status === 'passed') {\n const commitSha = await getCurrentHead(workspacePath);\n saveCheckpoint(projectKey, issueId, beadId, commitSha);\n console.log(`[inspect] Checkpoint saved for ${issueId} bead ${beadId} at ${commitSha.substring(0, 8)}`);\n\n } else {\n console.log(`[inspect] Bead ${beadId} blocked for ${issueId} — no checkpoint saved`);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAeA,MAAMA,cAAY,UAAU,KAAK;AAEjC,MAAM,kBAAkB,KAAK,SAAS,EAAE,cAAc;;;;AAgBtD,SAAS,iBAAiB,YAA4B;AACpD,QAAO,KAAK,iBAAiB,eAAe,YAAY,iBAAiB,cAAc;;;;;AAMzF,SAAS,kBAAkB,YAAoB,SAAyB;AACtE,QAAO,KAAK,iBAAiB,WAAW,EAAE,GAAG,QAAQ,aAAa,CAAC,OAAO;;;;;AAM5E,SAAgB,gBAAgB,YAAoB,SAA+C;CACjG,MAAM,WAAW,kBAAkB,YAAY,QAAQ;AACvD,KAAI,CAAC,WAAW,SAAS,CAAE,QAAO;AAElC,KAAI;AACF,SAAO,KAAK,MAAM,aAAa,UAAU,QAAQ,CAAC;SAC5C;AACN,SAAO;;;;;;AAgBX,SAAgB,eACd,YACA,SACA,QACA,WACmB;CACnB,MAAM,MAAM,iBAAiB,WAAW;AACxC,KAAI,CAAC,WAAW,IAAI,CAClB,WAAU,KAAK,EAAE,WAAW,MAAM,CAAC;CAGrC,MAAM,OAAO,gBAAgB,YAAY,QAAQ,IAAI;EACnD,SAAS,QAAQ,aAAa;EAC9B,aAAa,EAAE;EAChB;CAED,MAAM,aAAgC;EACpC;EACA;EACA,2BAAU,IAAI,MAAM,EAAC,aAAa;EACnC;AAED,MAAK,YAAY,KAAK,WAAW;AACjC,eAAc,kBAAkB,YAAY,QAAQ,EAAE,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;AAEpF,QAAO;;;;;AAiDT,eAAsB,eAAe,eAAwC;AAC3E,KAAI;EACF,MAAM,EAAE,WAAW,MAAMA,YAAU,sBAAsB;GACvD,KAAK;GACL,UAAU;GACX,CAAC;AACF,SAAO,OAAO,MAAM;SACd;AACN,SAAO;;;;;kBCrIsE;oBAC3B;AAEpC,UAAU,KAAK;AAGf,QADC,cAAc,OAAO,KAAK,IAAI,CACZ;;;;;AA0JrC,eAAsB,kBACpB,YACA,SACA,QACA,QACA,eACe;AACf,KAAI,WAAW,UAAU;EACvB,MAAM,YAAY,MAAM,eAAe,cAAc;AACrD,iBAAe,YAAY,SAAS,QAAQ,UAAU;AACtD,UAAQ,IAAI,kCAAkC,QAAQ,QAAQ,OAAO,MAAM,UAAU,UAAU,GAAG,EAAE,GAAG;OAGvG,SAAQ,IAAI,kBAAkB,OAAO,eAAe,QAAQ,wBAAwB"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as updateItemStatus, i as readWorkspacePlan, n as init_io, o as updateSubItemStatus, r as readPlan, t as findPlan } from "./io-
|
|
1
|
+
import { a as updateItemStatus, i as readWorkspacePlan, n as init_io, o as updateSubItemStatus, r as readPlan, t as findPlan } from "./io-DKS6359z.js";
|
|
2
2
|
init_io();
|
|
3
3
|
export { findPlan, readPlan, readWorkspacePlan, updateItemStatus, updateSubItemStatus };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io-
|
|
1
|
+
{"version":3,"file":"io-DKS6359z.js","names":[],"sources":["../../src/lib/vbrief/io.ts"],"sourcesContent":["/**\n * vBRIEF File I/O Utilities\n *\n * Read and write plan.vbrief.json from workspace .planning/ directories.\n */\n\nimport { existsSync, readFileSync, renameSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport type { VBriefDocument, VBriefItemStatus } from './types.js';\n\nconst PLAN_FILENAME = 'plan.vbrief.json';\n\n/**\n * Returns the path to plan.vbrief.json for a workspace, or null if it doesn't exist.\n */\nexport function findPlan(workspacePath: string): string | null {\n const planPath = join(workspacePath, '.planning', PLAN_FILENAME);\n return existsSync(planPath) ? planPath : null;\n}\n\n/**\n * Reads and parses plan.vbrief.json from the given path.\n * Handles both standard format ({ vBRIEFInfo, plan: {...} }) and flat format\n * ({ issue, title, items, edges? }) produced by some planning prompts.\n * Throws if the file does not exist or is invalid JSON.\n */\nexport function readPlan(planPath: string): VBriefDocument {\n const raw = readFileSync(planPath, 'utf-8');\n const parsed = JSON.parse(raw);\n\n // vBRIEF v0.5 requires exactly two top-level keys: vBRIEFInfo and plan\n if (parsed.vBRIEFInfo && parsed.plan) {\n return parsed as VBriefDocument;\n }\n\n // Non-spec format — reject with helpful error\n throw new Error(\n `Invalid vBRIEF format in ${planPath}: missing 'vBRIEFInfo' and/or 'plan' top-level keys. ` +\n `vBRIEF v0.5 requires exactly { \"vBRIEFInfo\": { \"version\": \"0.5\" }, \"plan\": { ... } }. ` +\n `See docs/VBRIEF.md for the correct format.`\n );\n}\n\n/**\n * Reads plan.vbrief.json from a workspace directory.\n * Returns null if no plan exists.\n */\nexport function readWorkspacePlan(workspacePath: string): VBriefDocument | null {\n const planPath = findPlan(workspacePath);\n if (!planPath) return null;\n return readPlan(planPath);\n}\n\n/**\n * Updates the status of a specific item in plan.vbrief.json.\n * Uses a write-to-temp-then-rename pattern to minimize race conditions.\n * No-ops gracefully if the file or item doesn't exist.\n */\nexport function updateItemStatus(workspacePath: string, itemId: string, status: VBriefItemStatus): void {\n const planPath = findPlan(workspacePath);\n if (!planPath) return;\n\n const doc = readPlan(planPath);\n const item = doc.plan.items.find(i => i.id === itemId);\n if (!item) return;\n\n const now = new Date().toISOString();\n item.status = status;\n if (status === 'completed') {\n item.completed = now;\n }\n\n // Update timestamps and increment sequence counter\n doc.vBRIEFInfo.updated = now;\n doc.plan.updated = now;\n doc.plan.sequence = (doc.plan.sequence ?? 0) + 1;\n\n // Atomic rename: write to .tmp then rename to avoid partial reads\n const tempPath = planPath + '.tmp';\n writeFileSync(tempPath, JSON.stringify(doc, null, 2), 'utf-8');\n renameSync(tempPath, planPath);\n}\n\n/**\n * Updates the status of a specific subItem within an item in plan.vbrief.json.\n * Uses write-to-temp-then-rename pattern for atomicity.\n * No-ops gracefully if the file, item, or subItem doesn't exist.\n */\nexport function updateSubItemStatus(\n workspacePath: string,\n itemId: string,\n subItemId: string,\n status: VBriefItemStatus,\n): void {\n const planPath = findPlan(workspacePath);\n if (!planPath) return;\n\n const doc = readPlan(planPath);\n const item = doc.plan.items.find(i => i.id === itemId);\n if (!item?.subItems) return;\n\n const subItem = item.subItems.find(s => s.id === subItemId);\n if (!subItem) return;\n\n const now = new Date().toISOString();\n subItem.status = status;\n if (status === 'completed') {\n subItem.completed = now;\n }\n\n // Update timestamps and increment sequence counter\n doc.vBRIEFInfo.updated = now;\n doc.plan.updated = now;\n doc.plan.sequence = (doc.plan.sequence ?? 0) + 1;\n\n const tempPath = planPath + '.tmp';\n writeFileSync(tempPath, JSON.stringify(doc, null, 2), 'utf-8');\n renameSync(tempPath, planPath);\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,SAAS,eAAsC;CAC7D,MAAM,WAAW,KAAK,eAAe,aAAa,cAAc;AAChE,QAAO,WAAW,SAAS,GAAG,WAAW;;;;;;;;AAS3C,SAAgB,SAAS,UAAkC;CACzD,MAAM,MAAM,aAAa,UAAU,QAAQ;CAC3C,MAAM,SAAS,KAAK,MAAM,IAAI;AAG9B,KAAI,OAAO,cAAc,OAAO,KAC9B,QAAO;AAIT,OAAM,IAAI,MACR,4BAA4B,SAAS,uLAGtC;;;;;;AAOH,SAAgB,kBAAkB,eAA8C;CAC9E,MAAM,WAAW,SAAS,cAAc;AACxC,KAAI,CAAC,SAAU,QAAO;AACtB,QAAO,SAAS,SAAS;;;;;;;AAQ3B,SAAgB,iBAAiB,eAAuB,QAAgB,QAAgC;CACtG,MAAM,WAAW,SAAS,cAAc;AACxC,KAAI,CAAC,SAAU;CAEf,MAAM,MAAM,SAAS,SAAS;CAC9B,MAAM,OAAO,IAAI,KAAK,MAAM,MAAK,MAAK,EAAE,OAAO,OAAO;AACtD,KAAI,CAAC,KAAM;CAEX,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,MAAK,SAAS;AACd,KAAI,WAAW,YACb,MAAK,YAAY;AAInB,KAAI,WAAW,UAAU;AACzB,KAAI,KAAK,UAAU;AACnB,KAAI,KAAK,YAAY,IAAI,KAAK,YAAY,KAAK;CAG/C,MAAM,WAAW,WAAW;AAC5B,eAAc,UAAU,KAAK,UAAU,KAAK,MAAM,EAAE,EAAE,QAAQ;AAC9D,YAAW,UAAU,SAAS;;;;;;;AAQhC,SAAgB,oBACd,eACA,QACA,WACA,QACM;CACN,MAAM,WAAW,SAAS,cAAc;AACxC,KAAI,CAAC,SAAU;CAEf,MAAM,MAAM,SAAS,SAAS;CAC9B,MAAM,OAAO,IAAI,KAAK,MAAM,MAAK,MAAK,EAAE,OAAO,OAAO;AACtD,KAAI,CAAC,MAAM,SAAU;CAErB,MAAM,UAAU,KAAK,SAAS,MAAK,MAAK,EAAE,OAAO,UAAU;AAC3D,KAAI,CAAC,QAAS;CAEd,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,SAAQ,SAAS;AACjB,KAAI,WAAW,YACb,SAAQ,YAAY;AAItB,KAAI,WAAW,UAAU;AACzB,KAAI,KAAK,UAAU;AACnB,KAAI,KAAK,YAAY,IAAI,KAAK,YAAY,KAAK;CAE/C,MAAM,WAAW,WAAW;AAC5B,eAAc,UAAU,KAAK,UAAU,KAAK,MAAM,EAAE,EAAE,QAAQ;AAC9D,YAAW,UAAU,SAAS;;;;AA3G1B,iBAAgB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { n as __esmMin } from "./chunk-DORXReHP.js";
|
|
2
|
+
//#region ../../lib/issue-id.ts
|
|
3
|
+
/**
|
|
4
|
+
* Parse an issue ID into its components.
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - Standard: PREFIX-NUMBER (e.g., MIN-123, PAN-456)
|
|
8
|
+
* - Rally: TYPENUMBER (e.g., F29698, US12345, DE118304, TA4567)
|
|
9
|
+
* - Custom: Per-project regex patterns
|
|
10
|
+
*
|
|
11
|
+
* @param issueId - The raw issue ID string
|
|
12
|
+
* @param projectConfig - Optional project config for custom patterns
|
|
13
|
+
* @returns ParsedIssueId or null if no format matches
|
|
14
|
+
*/
|
|
15
|
+
function parseIssueId(issueId, projectConfig) {
|
|
16
|
+
const standardMatch = issueId.match(/^([A-Za-z]+)-(\d+)$/);
|
|
17
|
+
if (standardMatch) return {
|
|
18
|
+
raw: issueId,
|
|
19
|
+
prefix: standardMatch[1].toUpperCase(),
|
|
20
|
+
number: parseInt(standardMatch[2], 10),
|
|
21
|
+
normalized: issueId.toLowerCase(),
|
|
22
|
+
format: "standard"
|
|
23
|
+
};
|
|
24
|
+
const rallyMatch = issueId.match(/^(F|US|DE|TA|TC)(\d+)$/i);
|
|
25
|
+
if (rallyMatch) return {
|
|
26
|
+
raw: issueId,
|
|
27
|
+
prefix: rallyMatch[1].toUpperCase(),
|
|
28
|
+
number: parseInt(rallyMatch[2], 10),
|
|
29
|
+
normalized: issueId.toLowerCase(),
|
|
30
|
+
format: "rally"
|
|
31
|
+
};
|
|
32
|
+
if (projectConfig?.issue_pattern) {
|
|
33
|
+
const customMatch = issueId.match(new RegExp(projectConfig.issue_pattern, "i"));
|
|
34
|
+
if (customMatch && customMatch[1] && customMatch[2]) return {
|
|
35
|
+
raw: issueId,
|
|
36
|
+
prefix: customMatch[1].toUpperCase(),
|
|
37
|
+
number: parseInt(customMatch[2], 10),
|
|
38
|
+
normalized: issueId.toLowerCase(),
|
|
39
|
+
format: "custom"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Extract just the team/project prefix from an issue ID.
|
|
46
|
+
* Handles standard (MIN-123), Rally (F29698), and custom formats.
|
|
47
|
+
*/
|
|
48
|
+
function extractPrefix(issueId) {
|
|
49
|
+
return parseIssueId(issueId)?.prefix ?? null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extract the numeric portion of an issue ID.
|
|
53
|
+
* Handles standard (MIN-123), Rally (F29698), and custom formats.
|
|
54
|
+
*/
|
|
55
|
+
function extractNumber(issueId) {
|
|
56
|
+
return parseIssueId(issueId)?.number ?? null;
|
|
57
|
+
}
|
|
58
|
+
var init_issue_id = __esmMin((() => {}));
|
|
59
|
+
//#endregion
|
|
60
|
+
export { parseIssueId as i, extractPrefix as n, init_issue_id as r, extractNumber as t };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=issue-id-vwYJdsf8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-id-vwYJdsf8.js","names":[],"sources":["../../src/lib/issue-id.ts"],"sourcesContent":["/**\n * Unified Issue ID Parser\n *\n * Handles multiple issue ID formats:\n * - Standard: PREFIX-NUMBER (e.g., MIN-123, PAN-456)\n * - Rally: TYPENUMBER (e.g., F29698, US12345, DE118304, TA4567)\n * - Custom: Per-project regex patterns\n */\n\nimport type { ProjectConfig } from './projects.js';\n\n/**\n * Parsed representation of any issue ID format.\n */\nexport interface ParsedIssueId {\n /** Original ID as provided (e.g., \"MIN-123\", \"F29698\") */\n raw: string;\n /** Extracted prefix for project resolution (e.g., \"MIN\", \"F\", \"US\") */\n prefix: string;\n /** Numeric portion (e.g., 123, 29698) */\n number: number;\n /** Normalized lowercase form for filesystem use (e.g., \"min-123\", \"f29698\") */\n normalized: string;\n /** Format that was matched */\n format: 'standard' | 'rally' | 'custom';\n}\n\n/**\n * Parse an issue ID into its components.\n *\n * Supports:\n * - Standard: PREFIX-NUMBER (e.g., MIN-123, PAN-456)\n * - Rally: TYPENUMBER (e.g., F29698, US12345, DE118304, TA4567)\n * - Custom: Per-project regex patterns\n *\n * @param issueId - The raw issue ID string\n * @param projectConfig - Optional project config for custom patterns\n * @returns ParsedIssueId or null if no format matches\n */\nexport function parseIssueId(issueId: string, projectConfig?: ProjectConfig): ParsedIssueId | null {\n // Standard format first (most common): PREFIX-NUMBER\n const standardMatch = issueId.match(/^([A-Za-z]+)-(\\d+)$/);\n if (standardMatch) {\n return {\n raw: issueId,\n prefix: standardMatch[1].toUpperCase(),\n number: parseInt(standardMatch[2], 10),\n normalized: issueId.toLowerCase(),\n format: 'standard',\n };\n }\n\n // Rally format: TYPE_PREFIX followed by NUMBER (no separator)\n // Known Rally prefixes: F (Feature), US (User Story), DE (Defect),\n // TA (Task), TC (Test Case)\n const rallyMatch = issueId.match(/^(F|US|DE|TA|TC)(\\d+)$/i);\n if (rallyMatch) {\n return {\n raw: issueId,\n prefix: rallyMatch[1].toUpperCase(),\n number: parseInt(rallyMatch[2], 10),\n normalized: issueId.toLowerCase(),\n format: 'rally',\n };\n }\n\n // Custom project pattern if provided\n if (projectConfig?.issue_pattern) {\n const customMatch = issueId.match(new RegExp(projectConfig.issue_pattern, 'i'));\n if (customMatch && customMatch[1] && customMatch[2]) {\n return {\n raw: issueId,\n prefix: customMatch[1].toUpperCase(),\n number: parseInt(customMatch[2], 10),\n normalized: issueId.toLowerCase(),\n format: 'custom',\n };\n }\n }\n\n return null;\n}\n\n/**\n * Extract just the team/project prefix from an issue ID.\n * Handles standard (MIN-123), Rally (F29698), and custom formats.\n */\nexport function extractPrefix(issueId: string): string | null {\n const parsed = parseIssueId(issueId);\n return parsed?.prefix ?? null;\n}\n\n/**\n * Extract the numeric portion of an issue ID.\n * Handles standard (MIN-123), Rally (F29698), and custom formats.\n */\nexport function extractNumber(issueId: string): number | null {\n const parsed = parseIssueId(issueId);\n return parsed?.number ?? null;\n}\n\n/**\n * Get the normalized (lowercase, filesystem-safe) form of an issue ID.\n * Standard IDs keep the dash: \"min-123\". Rally IDs stay concatenated: \"f29698\".\n */\nexport function normalizeIssueId(issueId: string): string {\n const parsed = parseIssueId(issueId);\n return parsed?.normalized ?? issueId.toLowerCase();\n}\n\n/**\n * Extract prefix from a standard format issue ID (PREFIX-NUMBER).\n * Returns null for non-standard formats like Rally IDs.\n * Use extractPrefix() for unified handling of all formats.\n */\nexport function extractStandardPrefix(issueId: string): string | null {\n const match = issueId.match(/^([A-Za-z]+)-\\d+$/i);\n return match ? match[1].toUpperCase() : null;\n}\n\n/**\n * Extract number from a standard format issue ID (PREFIX-NUMBER).\n * Returns null for non-standard formats like Rally IDs.\n * Use extractNumber() for unified handling of all formats.\n */\nexport function extractStandardNumber(issueId: string): number | null {\n const match = issueId.match(/^([A-Za-z]+)-(\\d+)$/i);\n return match ? parseInt(match[2], 10) : null;\n}\n"],"mappings":";;;;;;;;;;;;;;AAuCA,SAAgB,aAAa,SAAiB,eAAqD;CAEjG,MAAM,gBAAgB,QAAQ,MAAM,sBAAsB;AAC1D,KAAI,cACF,QAAO;EACL,KAAK;EACL,QAAQ,cAAc,GAAG,aAAa;EACtC,QAAQ,SAAS,cAAc,IAAI,GAAG;EACtC,YAAY,QAAQ,aAAa;EACjC,QAAQ;EACT;CAMH,MAAM,aAAa,QAAQ,MAAM,0BAA0B;AAC3D,KAAI,WACF,QAAO;EACL,KAAK;EACL,QAAQ,WAAW,GAAG,aAAa;EACnC,QAAQ,SAAS,WAAW,IAAI,GAAG;EACnC,YAAY,QAAQ,aAAa;EACjC,QAAQ;EACT;AAIH,KAAI,eAAe,eAAe;EAChC,MAAM,cAAc,QAAQ,MAAM,IAAI,OAAO,cAAc,eAAe,IAAI,CAAC;AAC/E,MAAI,eAAe,YAAY,MAAM,YAAY,GAC/C,QAAO;GACL,KAAK;GACL,QAAQ,YAAY,GAAG,aAAa;GACpC,QAAQ,SAAS,YAAY,IAAI,GAAG;GACpC,YAAY,QAAQ,aAAa;GACjC,QAAQ;GACT;;AAIL,QAAO;;;;;;AAOT,SAAgB,cAAc,SAAgC;AAE5D,QADe,aAAa,QAAQ,EACrB,UAAU;;;;;;AAO3B,SAAgB,cAAc,SAAgC;AAE5D,QADe,aAAa,QAAQ,EACrB,UAAU"}
|
package/dist/dashboard/{issue-service-singleton-DQK42EqH.js → issue-service-singleton-Co__-6kL.js}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as startSharedIssueService, n as init_issue_service_singleton, t as getSharedIssueService } from "./issue-service-singleton-
|
|
1
|
+
import { i as startSharedIssueService, n as init_issue_service_singleton, t as getSharedIssueService } from "./issue-service-singleton-Wv4xBm3y.js";
|
|
2
2
|
init_issue_service_singleton();
|
|
3
3
|
export { getSharedIssueService, startSharedIssueService };
|
package/dist/dashboard/{issue-service-singleton-sb2HkB9f.js → issue-service-singleton-Wv4xBm3y.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as __esmMin, r as __exportAll } from "./chunk-DORXReHP.js";
|
|
2
|
-
import { a as validateRallyConfig, i as init_tracker_config, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-
|
|
3
|
-
import { n as init_dist_src, t as Octokit } from "./dist-src-
|
|
4
|
-
import { a as loadReviewStatuses, i as init_review_status } from "./review-status-
|
|
2
|
+
import { a as validateRallyConfig, i as init_tracker_config, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-e7ph1QqT.js";
|
|
3
|
+
import { n as init_dist_src, t as Octokit } from "./dist-src-DTm11oQr.js";
|
|
4
|
+
import { a as loadReviewStatuses, i as init_review_status } from "./review-status-Bymwzh2i.js";
|
|
5
5
|
import { existsSync, mkdirSync } from "fs";
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import { homedir } from "os";
|
|
@@ -618,7 +618,7 @@ var init_issue_data_service = __esmMin((() => {
|
|
|
618
618
|
async ensureShadowStateLoaded() {
|
|
619
619
|
if (this.shadowStateModule) return;
|
|
620
620
|
try {
|
|
621
|
-
this.shadowStateModule = await import("./shadow-state-
|
|
621
|
+
this.shadowStateModule = await import("./shadow-state-BIexcxkv.js");
|
|
622
622
|
} catch {}
|
|
623
623
|
}
|
|
624
624
|
loadCachedData() {
|
|
@@ -1029,8 +1029,8 @@ var init_issue_data_service = __esmMin((() => {
|
|
|
1029
1029
|
}
|
|
1030
1030
|
if (!this.cache.isStale("rally", "issues") && this.trackers.rally.lastFetchedIssues.length > 0) return;
|
|
1031
1031
|
try {
|
|
1032
|
-
const { RallyTracker } = await import("./rally-
|
|
1033
|
-
const { findProjectsByRallyProject } = await import("./projects-
|
|
1032
|
+
const { RallyTracker } = await import("./rally-6McpKKRa.js");
|
|
1033
|
+
const { findProjectsByRallyProject } = await import("./projects-C5ozxjwP.js");
|
|
1034
1034
|
const rallyProjects = findProjectsByRallyProject();
|
|
1035
1035
|
let allFormatted = [];
|
|
1036
1036
|
if (rallyProjects.length > 0) {
|
|
@@ -1123,4 +1123,4 @@ var init_issue_service_singleton = __esmMin((() => {
|
|
|
1123
1123
|
//#endregion
|
|
1124
1124
|
export { startSharedIssueService as i, init_issue_service_singleton as n, issue_service_singleton_exports as r, getSharedIssueService as t };
|
|
1125
1125
|
|
|
1126
|
-
//# sourceMappingURL=issue-service-singleton-
|
|
1126
|
+
//# sourceMappingURL=issue-service-singleton-Wv4xBm3y.js.map
|