@overdeck/desktop 0.45.24 → 0.47.0
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/drizzle/overdeck/0000_overdeck_init.sql +36 -1
- package/package.json +1 -1
- package/server/{acceptance-criteria-DDCnXF58.js → acceptance-criteria-10Ur5Dne.js} +2 -2
- package/server/activity-logger-CMthG6Vd.js +3 -0
- package/server/{activity-logger-DDlOIAML.js → activity-logger-CyteR4JO.js} +24 -13
- package/server/{advancing-selfheal-BVwW4qRn.js → advancing-selfheal-BNwqxseD.js} +6 -6
- package/server/{agent-gc-CHcnvonI.js → agent-gc-C3h9Or3a.js} +5 -5
- package/server/agent-state-CYXJVG72.js +3 -0
- package/server/agent-state-service-C63p_ftq.js +2 -0
- package/server/{agent-state-service-BsgWxZuB.js → agent-state-service-Ds6OeFvo.js} +15 -9
- package/server/{agents-EbI0zCJl.js → agents-J5mEnekq.js} +23 -16
- package/server/agents-ePFVoZbu.js +3 -0
- package/server/archive-planning-B2XplFzT.js +2 -0
- package/server/{archive-planning-Du25Jtst.js → archive-planning-BwhxeP7C.js} +22 -26
- package/server/{artifact-index-jobs-CbEDfCDu.js → artifact-index-jobs-D1q_vR3V.js} +2 -2
- package/server/{assemble-J2ZZ2C15.js → assemble-Bgwqv-Ro.js} +2 -2
- package/server/auto-spawn-consent-CQ9Bi9q6.js +1141 -0
- package/server/{backlog-auto-trigger-2R2jog7n.js → backlog-auto-trigger-n1lzPgN4.js} +3 -3
- package/server/{behavior-B3exJ42O.js → behavior-td6-xhQk.js} +2 -2
- package/server/boot-reconciled-stop-events-C7gGe3oB.js +44 -0
- package/server/bridge-pool-patrol-CYH2OLb5.js +136 -0
- package/server/{briefing-freshness-D1wzUIWv.js → briefing-freshness-DRqZ8lAz.js} +2 -2
- package/server/{build-info-Ie_D0_BT.js → build-info-7yiEpl6u.js} +5 -3
- package/server/{build-info-CZk_TITh.js → build-info-CpG__c63.js} +1 -1
- package/server/{checkpoint-manager-DwbQoqrC.js → checkpoint-manager-CkKmB0wZ.js} +1 -1
- package/server/{checkpoint-manager-BI1Wxoku.js → checkpoint-manager-DBcyNR8w.js} +2 -2
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-CQB1h765.js → checkpoints-D95apurL.js} +2 -2
- package/server/{checkpoints-BJIs5QIA.js → checkpoints-Wm963lm8.js} +1 -1
- package/server/{claude-hooks-provision-8Ngo8TpT.js → claude-hooks-provision-4RPxNkE8.js} +1 -1
- package/server/{claude-hooks-provision-D8GXF3_s.js → claude-hooks-provision-Bjitl9aI.js} +13 -2
- package/server/{claude-permissions-DNWEVV6z.js → claude-permissions-CpbpvUQ2.js} +2 -2
- package/server/{claude-settings-overlay-DWy-Bb4Y.js → claude-settings-overlay-BzkHYDwR.js} +1 -1
- package/server/{claude-settings-overlay-CEdaqpWI.js → claude-settings-overlay-_H9Yrzab.js} +2 -2
- package/server/cli-CjOCSnfj.js +3 -0
- package/server/{cli-RoOx5DUf.js → cli-Cte9ZFGn.js} +9 -9
- package/server/{cliproxy-C8a1vtTU.js → cliproxy-C5fMJ7rY.js} +2 -2
- package/server/{cliproxy-fHfIeiGd.js → cliproxy-DaAbWMjC.js} +1 -1
- package/server/{close-issue-DoOifFIK.js → close-issue-BPh1ARCF.js} +5 -5
- package/server/{closed-issue-reaper-CktPXo8m.js → closed-issue-reaper-DHRfRMrp.js} +1 -1
- package/server/{closed-issue-reaper-Bk3SU4RC.js → closed-issue-reaper-DoOZqGFK.js} +88 -17
- package/server/{codex-BZXGhUVB.js → codex-BzGDW_d3.js} +36 -7
- package/server/{codex-GcHuUF-k.js → codex-o8FJwzmy.js} +1 -1
- package/server/{codex-parser-CFZ1_1Jl.js → codex-parser-Dt-ycU8L.js} +2 -2
- package/server/compaction-continuation-CvXpbZ4w.js +200 -0
- package/server/{config-CKxYiCmX.js → config-Bi3u1VK7.js} +4 -3
- package/server/{config-BZ0sHTju.js → config-BvLe652W.js} +2 -2
- package/server/{config-DzV30TOm.js → config-CL3Gyvja.js} +1 -1
- package/server/{config-yaml-DySPNmKN.js → config-yaml-CxdwhAIA.js} +276 -14
- package/server/conflict-gate-CX80JYYS.js +3 -0
- package/server/{conflict-gate-BaCVrH-N.js → conflict-gate-E4nt7ZeS.js} +60 -14
- package/server/{context-layers-igZ4FI4_.js → context-layers-C_IIysnm.js} +3 -3
- package/server/{context-layers-BrPmE__h.js → context-layers-DAG83UZt.js} +2 -2
- package/server/{control-settings-BQp7_4uD.js → control-settings-CiqGxXnc.js} +56 -19
- package/server/{conversation-compaction-eQB5CkOe.js → conversation-compaction-BE3CNtHF.js} +1 -1
- package/server/{conversation-compaction-CgrR8YYp.js → conversation-compaction-D6-yLtqt.js} +8 -8
- package/server/{conversation-service-DPJ71F33.js → conversation-service-DBxoYMDl.js} +10 -8
- package/server/conversation-service-D_TS2b1r.js +3 -0
- package/server/{conversations-CAsJF9kh.js → conversations-BKDVpB-3.js} +1 -1
- package/server/{conversations-6AfUfbwc.js → conversations-D0UEdLtk.js} +4 -4
- package/server/{cost-R-m6Yi-W.js → cost-DS1s0DbG.js} +3 -3
- package/server/{cost-B2ddP6wq.js → cost-DpgYmYqR.js} +12 -2
- package/server/{cost-sync-BsN6ER0n.js → cost-sync-tOCCGnEt.js} +3 -3
- package/server/{dag-B1ucnjDU.js → dag-BtkgLeqY.js} +2 -2
- package/server/{dangerous-git-ops-BXqeWVSf.js → dangerous-git-ops-CFLykHWt.js} +1 -1
- package/server/dashboard-db-worker.js +7 -7
- package/server/deacon-BIblC-WX.js +4 -0
- package/server/{deacon-nudge-log-6wVqAaqz.js → deacon-nudge-log-B08gF0mh.js} +3 -3
- package/server/{deacon-CU_cAYSR.js → deacon-pLRLbPvR.js} +3308 -2707
- package/server/deacon-pending-lifecycle-B-Io84AP.js +33 -0
- package/server/deacon-swarm-B1XkIvfr.js +2 -0
- package/server/{deacon-swarm-BXZZ1Z2-.js → deacon-swarm-v5PMun-m.js} +15 -14
- package/server/deacon.js +14 -19
- package/server/dead-end-trip-D8A3msX9.js +13 -0
- package/server/delivery-BX9HR4wQ.js +3 -0
- package/server/{deploy-patrol-AiFoP8dw.js → deploy-patrol-sYgOxLeb.js} +69 -18
- package/server/deploy-queue-VfohaPN_.js +169 -0
- package/server/deploy-queue-gHJBycaF.js +3 -0
- package/server/deploy-window-CFRZ0-kt.js +3 -0
- package/server/{deploy-window-C3F-tihF.js → deploy-window-D4DQb8VP.js} +40 -16
- package/server/{dev-supervisor-bcOWqdQE.js → dev-supervisor-DiOBDM1c.js} +2 -2
- package/server/{devcontainer-renderer-_d6XhyND.js → devcontainer-renderer-BUOIlfgD.js} +3 -3
- package/server/dist-B3YPQa5A.js +3 -0
- package/server/{dist-Cb_0uvpS.js → dist-C3A8B8wM.js} +1 -1
- package/server/{dist-src-BSoS7mkd.js → dist-src-C0adpegX.js} +1 -1
- package/server/{docker-DcMTFTUC.js → docker-BJzlkqYB.js} +2 -2
- package/server/docker-Y3PElJb0.js +3 -0
- package/server/dod-DlNtcH6n.js +91 -0
- package/server/durable-review-pipeline-Cibps-Rg.js +20 -0
- package/server/durable-review-pipeline-DP6bIcOY.js +3 -0
- package/server/{ensure-devcontainer-DNi-ono3.js → ensure-devcontainer-BAofzBPv.js} +4 -4
- package/server/{ensure-devcontainer-BZgOhRo7.js → ensure-devcontainer-DMAbWqtQ.js} +1 -1
- package/server/{esm-shims-OSHAYaS1.js → esm-shims-BeObUkaw.js} +1 -1
- package/server/{event-store-EV2cMiXj.js → event-store-5UKzh9Jf.js} +1 -1
- package/server/{event-store-CQL6NeqB.js → event-store-CrHcVC5_.js} +23 -4
- package/server/{events-DTfAe4My.js → events-BNrvchBg.js} +3 -3
- package/server/{events-BTdrdEq8.js → events-CF8QDbuV.js} +1 -1
- package/server/{factory-CFibJuaw.js → factory-Cmm9Hsho.js} +5 -5
- package/server/{feature-registry-population-DKZFMbFt.js → feature-registry-population-B6HpNWRy.js} +4 -4
- package/server/{feature-registry-storage-BdPuLcBX.js → feature-registry-storage-DJEFx1Pf.js} +2 -2
- package/server/{features-ez2271oH.js → features-D5km80UI.js} +2 -2
- package/server/{feedback-target-CoFDHiM8.js → feedback-target-BJ5ZADsu.js} +1 -1
- package/server/{feedback-target-7mqqwrX6.js → feedback-target-DSxEL6lP.js} +8 -8
- package/server/{feedback-writer-CY5L1lB7.js → feedback-writer-C27Hak8a.js} +5 -5
- package/server/{feedback-writer-D3a22RCd.js → feedback-writer-CoB9Z6aU.js} +1 -1
- package/server/{flywheel-DHrgCphM.js → flywheel-BHx8XuMr.js} +47 -20
- package/server/{flywheel-SVF02Jpq.js → flywheel-DZZdtiOL.js} +1 -1
- package/server/{flywheel-DzGtWnJ1.js → flywheel-f662Q-y2.js} +16 -15
- package/server/flywheel-merge-order-D_xLMbJU.js +462 -0
- package/server/flywheel-merge-order-Dil0LmdN.js +2 -0
- package/server/forge-B5o319qI.js +3 -0
- package/server/forge-BaKGCya6.js +383 -0
- package/server/{from-kNxT0bZC.js → from-B3tZbB55.js} +1 -1
- package/server/fs-lock-Bre3sGoz.js +130 -0
- package/server/{fts-db-CE46vDkZ.js → fts-db-IVc4_M3f.js} +2 -2
- package/server/{fts-operations-CqY6zl-i.js → fts-operations-B9jG8wa3.js} +2 -2
- package/server/{git-utils-CRw2zLPC.js → git-utils-CsvYfJU3.js} +30 -5
- package/server/git-utils-Xg4PFN45.js +3 -0
- package/server/{github-app-ClZ2lk8D.js → github-app-Bmg4R9mv.js} +1 -1
- package/server/{github-app-C3QrAUd0.js → github-app-CmNk0zLU.js} +3 -3
- package/server/{github-client-DfQYVUaw.js → github-client-B6KM9_wA.js} +1 -1
- package/server/{github-client-BnIsSrEN.js → github-client-qazkPrg0.js} +3 -3
- package/server/github-pr-lookup-DAcVeRLK.js +58 -0
- package/server/{harness-binary-DPUi-Pv8.js → harness-binary-BSpiXaLw.js} +2 -2
- package/server/{harness-resolve-3lNZkyT4.js → harness-resolve-BAJu5MX8.js} +4 -4
- package/server/{health-events-BDOHby5Q.js → health-events-2Z6Wa9SM.js} +1 -1
- package/server/{health-events-BBcTYQKU.js → health-events-BwX32k8d.js} +2 -2
- package/server/{hooks-DPVX1rwQ.js → hooks-D1g1jKLI.js} +1 -1
- package/server/{hooks-CKZgXlJb.js → hooks-DbtbimEf.js} +2 -2
- package/server/{hume-Cz8igP9E.js → hume-DXNiu6nQ.js} +2 -2
- package/server/hume-VUCNbTgn.js +3 -0
- package/server/{idle-stack-reaper-CuLF0j2H.js → idle-stack-reaper-CRA1e0jr.js} +1 -1
- package/server/{idle-stack-reaper-DDIRwxUY.js → idle-stack-reaper-Cy-dQzW4.js} +99 -6
- package/server/in-flight-guard-D-sSkADM.js +45 -0
- package/server/{infra-BEqFxlJc.js → infra-BDQDRopn.js} +81 -5
- package/server/{injection-C8aiVJrF.js → injection-6AGnXxlj.js} +7 -7
- package/server/{injection-CPUIqNhI.js → injection-Bl8d_jHZ.js} +1 -1
- package/server/inspect-agent-CUwVmr2h.js +2 -0
- package/server/{inspect-agent-BLuJ1AkT.js → inspect-agent-nXdIptyh.js} +26 -25
- package/server/{internal-token-s0-oKybJ.js → internal-token-DzK385vD.js} +2 -2
- package/server/{internal-token-BrcU6qfe.js → internal-token-Ias7N8Kg.js} +1 -1
- package/server/{io-C9kF1wtJ.js → io-B00PBNku.js} +44 -27
- package/server/{issue-closed-CDJk4pIp.js → issue-closed-BehTG1be.js} +8 -8
- package/server/{issue-lifecycle-ojZAzDBP.js → issue-lifecycle-Birk-ifu.js} +42 -30
- package/server/{issue-lifecycle-B8sZHVHh.js → issue-lifecycle-BqSuQvbn.js} +1 -1
- package/server/{issue-service-singleton-BvJ09SaR.js → issue-service-singleton-B2wXiIlw.js} +1 -1
- package/server/{issue-service-singleton-Yx5DdmVJ.js → issue-service-singleton-C6ZduvuY.js} +10 -10
- package/server/{issues-BMmP_77e.js → issues-DQ5-LatB.js} +2 -2
- package/server/{jsonl-parser-BXSlHwEh.js → jsonl-parser-BDpnGFCl.js} +5 -4
- package/server/{label-cleanup-B0UJwnv5.js → label-cleanup-Dwnky8FG.js} +3 -3
- package/server/{lifecycle-xmBfK2GJ.js → lifecycle-B3s4sM1G.js} +6 -7
- package/server/{lifecycle-yPd___5E.js → lifecycle-B4Xdb4cY.js} +2 -2
- package/server/{lifecycle-io-DPo7x11I.js → lifecycle-io-CzTHEooc.js} +1 -1
- package/server/{lifecycle-io-BREGpnLk.js → lifecycle-io-DCo6s6ks.js} +5 -5
- package/server/{linear-client-BsuUvkdA.js → linear-client-9uq7fhiV.js} +3 -3
- package/server/{linear-client-CTskEeT_.js → linear-client-CnbtHiic.js} +1 -1
- package/server/linear-mcp-auth-BxUOzswy.js +280 -0
- package/server/linear-mcp-auth-D46fBCLf.js +2 -0
- package/server/memory-fts-worker.js +1 -1
- package/server/{merge-CefQNAnq.js → merge-DiW9RdSB.js} +13 -11
- package/server/{merge-agent-4WOWlSYA.js → merge-agent-BLUgRsz3.js} +234 -84
- package/server/{merge-agent-CKkgIBPB.js → merge-agent-DQTXZk8z.js} +1 -1
- package/server/{merge-batch-ClFn2T-y.js → merge-batch-Cp_j9BGk.js} +1 -1
- package/server/merge-completeness-B46KqhtY.js +277 -0
- package/server/merge-completeness-BLbB5-6n.js +3 -0
- package/server/merge-ops-1abz6O_P.js +2 -0
- package/server/merge-rebase-CJJVAJuz.js +2 -0
- package/server/{merge-rebase-BfaTyXsw.js → merge-rebase-DIkBjgwq.js} +3 -3
- package/server/{merge-set-DJ8-UErs.js → merge-set-CBgHfwM0.js} +11 -5
- package/server/merge-set-DeUxFsC3.js +3 -0
- package/server/{merge-B1DiziGU.js → merge-sr8Nrnmi.js} +1 -1
- package/server/merge-sync-CpGmk6Ch.js +3 -0
- package/server/{merge-sync-VPV28g0g.js → merge-sync-kr4vqyjM.js} +409 -153
- package/server/{merge-train-CHopycP0.js → merge-train-Dmrcus12.js} +18 -8
- package/server/{merge-train-deps-D1cOZzy2.js → merge-train-deps-D_uGX91G.js} +21 -15
- package/server/merge-verification-NvaAd8CZ.js +220 -0
- package/server/merged-docker-cleanup-worker-DH_hrGPI.js +3 -0
- package/server/merged-docker-cleanup-worker-Y1R06TEl.js +107 -0
- package/server/{multipart-parser-duPAfSBw.js → multipart-parser-R-oC8dQg.js} +2 -2
- package/server/{no-resume-mode-Nw29vaFb.js → no-resume-mode-BgD0JUmM.js} +1 -1
- package/server/node_modules/.package-lock.json +30 -30
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +3 -3
- package/server/node_modules/@google-cloud/common/package.json +2 -2
- package/server/node_modules/@types/node/README.md +1 -1
- package/server/node_modules/@types/node/crypto.d.ts +1 -1
- package/server/node_modules/@types/node/package.json +2 -2
- package/server/node_modules/gaxios/build/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/server/node_modules/gaxios/build/esm/tsconfig.tsbuildinfo +1 -1
- package/server/node_modules/gaxios/package.json +1 -1
- package/server/node_modules/google-auth-library/build/src/auth/googleauth.js +24 -19
- package/server/node_modules/google-auth-library/package.json +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/auth.proto +2 -1
- package/server/node_modules/google-gax/build/protos/google/api/backend.proto +12 -1
- package/server/node_modules/google-gax/build/protos/google/api/billing.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/client.proto +165 -53
- package/server/node_modules/google-gax/build/protos/google/api/cloudquotas/v1/resources.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/cloudquotas/v1beta/quota_adjuster_settings.proto +7 -3
- package/server/node_modules/google-gax/build/protos/google/api/cloudquotas/v1beta/resources.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/config_change.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/context.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/control.proto +3 -3
- package/server/node_modules/google-gax/build/protos/google/api/distribution.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/documentation.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/endpoint.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/error_reason.proto +186 -1
- package/server/node_modules/google-gax/build/protos/google/api/expr/v1alpha1/checked.proto +31 -3
- package/server/node_modules/google-gax/build/protos/google/api/expr/v1alpha1/eval.proto +8 -9
- package/server/node_modules/google-gax/build/protos/google/api/expr/v1alpha1/explain.proto +1 -2
- package/server/node_modules/google-gax/build/protos/google/api/expr/v1alpha1/syntax.proto +20 -22
- package/server/node_modules/google-gax/build/protos/google/api/expr/v1alpha1/value.proto +2 -3
- package/server/node_modules/google-gax/build/protos/google/api/field_behavior.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/field_info.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/http.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/httpbody.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/label.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/launch_stage.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/log.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/logging.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/metric.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/monitored_resource.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/monitoring.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/policy.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/quota.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/resource.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/routing.proto +8 -4
- package/server/node_modules/google-gax/build/protos/google/api/service.proto +2 -3
- package/server/node_modules/google-gax/build/protos/google/api/source_info.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/system_parameter.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/api/usage.proto +7 -27
- package/server/node_modules/google-gax/build/protos/google/api/visibility.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/longrunning/operations.proto +20 -1
- package/server/node_modules/google-gax/build/protos/google/protobuf/any.proto +52 -108
- package/server/node_modules/google-gax/build/protos/google/protobuf/compiler/ruby/ruby_generated_code.proto +2 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/cpp_features.proto +21 -1
- package/server/node_modules/google-gax/build/protos/google/protobuf/cpp_file_options.proto +24 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/cpp_options.proto +15 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/descriptor.proto +118 -30
- package/server/node_modules/google-gax/build/protos/google/protobuf/field_mask.proto +16 -18
- package/server/node_modules/google-gax/build/protos/google/protobuf/internal_options.proto +8 -1
- package/server/node_modules/google-gax/build/protos/google/protobuf/json/json_enumval_custom_string.proto +26 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/json_enumvalue_options.proto +29 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/json_options.proto +14 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/struct.proto +38 -22
- package/server/node_modules/google-gax/build/protos/google/protobuf/test_protos/forced_micro_string.proto +3 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/test_protos/repeated_field_proxy_import_message.proto +14 -0
- package/server/node_modules/google-gax/build/protos/google/protobuf/timestamp.proto +9 -8
- package/server/node_modules/google-gax/build/protos/google/protobuf/util/json_format_proto3.proto +18 -0
- package/server/node_modules/google-gax/build/protos/google/rpc/code.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/rpc/context/attribute_context.proto +7 -2
- package/server/node_modules/google-gax/build/protos/google/rpc/context/audit_context.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/rpc/error_details.proto +5 -5
- package/server/node_modules/google-gax/build/protos/google/rpc/http.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/rpc/status.proto +1 -2
- package/server/node_modules/google-gax/build/protos/google/type/calendar_period.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/type/color.proto +9 -10
- package/server/node_modules/google-gax/build/protos/google/type/date.proto +11 -9
- package/server/node_modules/google-gax/build/protos/google/type/datetime.proto +17 -17
- package/server/node_modules/google-gax/build/protos/google/type/dayofweek.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/type/decimal.proto +11 -13
- package/server/node_modules/google-gax/build/protos/google/type/expr.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/type/fraction.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/type/interval.proto +1 -2
- package/server/node_modules/google-gax/build/protos/google/type/latlng.proto +4 -5
- package/server/node_modules/google-gax/build/protos/google/type/localized_text.proto +3 -3
- package/server/node_modules/google-gax/build/protos/google/type/money.proto +1 -2
- package/server/node_modules/google-gax/build/protos/google/type/month.proto +1 -1
- package/server/node_modules/google-gax/build/protos/google/type/phone_number.proto +20 -15
- package/server/node_modules/google-gax/build/protos/google/type/postal_address.proto +39 -39
- package/server/node_modules/google-gax/build/protos/google/type/quaternion.proto +4 -4
- package/server/node_modules/google-gax/build/protos/google/type/timeofday.proto +11 -8
- package/server/node_modules/google-gax/package.json +5 -5
- package/server/node_modules/retry-request/package.json +4 -4
- package/server/node_modules/teeny-request/package.json +5 -5
- package/server/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
- package/server/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
- package/server/node_modules/undici/lib/core/request.js +12 -1
- package/server/node_modules/undici/lib/dispatcher/client-h1.js +11 -2
- package/server/node_modules/undici/lib/global.js +36 -16
- package/server/node_modules/undici/lib/handler/cache-handler.js +236 -116
- package/server/node_modules/undici/lib/handler/cache-revalidation-handler.js +3 -3
- package/server/node_modules/undici/lib/handler/retry-handler.js +24 -0
- package/server/node_modules/undici/lib/interceptor/cache.js +152 -62
- package/server/node_modules/undici/lib/interceptor/decompress.js +5 -2
- package/server/node_modules/undici/lib/util/cache.js +328 -66
- package/server/node_modules/undici/lib/util/date.js +23 -6
- package/server/node_modules/undici/lib/web/cookies/util.js +78 -8
- package/server/node_modules/undici/package.json +1 -1
- package/server/{orphan-proposed-reconciler-BvKkWMJQ.js → orphan-proposed-reconciler-B6vJHxtX.js} +242 -34
- package/server/{orphan-proposed-reconciler-CTSGcK8p.js → orphan-proposed-reconciler-DcgTPPFY.js} +1 -1
- package/server/package-lock.json +31 -31
- package/server/package.json +1 -1
- package/server/{pan-dir-B0c3w0Ya.js → pan-dir-DMzF5wne.js} +25 -11
- package/server/{paths-D-xWGHdh.js → paths-sJBSb7Ul.js} +2 -2
- package/server/pending-lifecycle-claim-DilzGfgk.js +110 -0
- package/server/persistent-logger-H_VjuOu7.js +57 -0
- package/server/{pickup-DUCLWrJY.js → pickup-DWhqzliO.js} +4 -3
- package/server/pipeline-membership-C88VBnhJ.js +3 -0
- package/server/pipeline-membership-D9SBvItj.js +57 -0
- package/server/pipeline-membership-gather-4eR-7Tqy.js +3 -0
- package/server/pipeline-membership-gather-CeVGnNJ2.js +593 -0
- package/server/{pipeline-notifier-BXkJzDC4.js → pipeline-notifier-D0ALV6Nw.js} +2 -2
- package/server/{pipeline-notifier-BJr8gQX6.js → pipeline-notifier-DT6xLFao.js} +1 -1
- package/server/post-merge-lifecycle-worker-8HIeS_J6.js +50 -0
- package/server/{project-pipelines-C0MWUeCU.js → project-pipelines-9SKt2bEc.js} +2 -2
- package/server/{project-repos-B6GycDh9.js → project-repos-B5pIphKg.js} +7 -3
- package/server/project-repos-DPjOdfPa.js +3 -0
- package/server/projects-_n3Zui6K.js +3 -0
- package/server/{prompts-DxzFXuLl.js → prompts-CgzMBvQF.js} +2 -2
- package/server/{providers-u4Ga0jOr.js → providers-BI1mOBQ4.js} +1 -1
- package/server/{providers-qQAwGQDW.js → providers-BJQSnAAp.js} +7 -7
- package/server/public/assets/{chunk-BO2N2NFS-BamJdinX.js → chunk-BO2N2NFS-D_pGACYN.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-DfOB8-w4.js → diagram-OG6HWLK6-BO6fe3hH.js} +1 -1
- package/server/public/assets/{dist-ByIuzMQW.js → dist-5zingMiA.js} +3 -3
- package/server/public/assets/{dist-D7zYSEA6.js → dist-CVxhbI2E.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-EdmRyXL3.js → ganttDiagram-6RSMTGT7-Bgj4A7kp.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-MerOfTX8.js → highlighted-body-OFNGDK62-DNPK7_cm.js} +1 -1
- package/server/public/assets/index-DEpY-D1O.js +807 -0
- package/server/public/assets/index-Ddkcz3WT.css +1 -0
- package/server/public/assets/{linear-BBbArIcK.js → linear-BB0jQT16.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-BzPfaQJ1.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-BKIddiJN.js → pieDiagram-4H26LBE5-DeGIzzpZ.js} +1 -1
- package/server/public/assets/{prod-B8vYiu52.js → prod-XBLvikex.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-D6RtoULk.js → quadrantDiagram-W4KKPZXB-BV9SLeWz.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-CLrCedZX.js → sankeyDiagram-5OEKKPKP-Dwja0gj8.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-hznR8DYl.js → xychartDiagram-2RQKCTM6-DCB4qvfw.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/{pull-requests-_lHueOHW.js → pull-requests-7BgLDsIo.js} +19 -10
- package/server/{pull-requests-7N8WKseP.js → pull-requests-Dq0y6IxE.js} +1 -1
- package/server/{queries-CjNIf-Ub.js → queries-C-MUZaIy.js} +824 -192
- package/server/{rally-CyWT_lNO.js → rally-CPysR4T_.js} +3 -3
- package/server/rally-D_VW4bJv.js +3 -0
- package/server/{rally-api-C8e_1JRi.js → rally-api-8Ptlp2os.js} +2 -2
- package/server/{rally-api-ClOSd-Tt.js → rally-api-CgosKdKL.js} +1 -1
- package/server/{rally-client-sgtVqzNU.js → rally-client-CCX0hADj.js} +1 -1
- package/server/{rally-client-lc-nokqr.js → rally-client-iYMHWQD7.js} +5 -5
- package/server/{reap-terminal-sessions-7KeHv1R1.js → reap-terminal-sessions-4Xg9NGA8.js} +2 -2
- package/server/{reap-terminal-sessions-BtHPo6Xc.js → reap-terminal-sessions-Qf-9LVQc.js} +2 -2
- package/server/{rebuild-stack-lwtsW0GO.js → rebuild-stack-CMdgaylx.js} +16 -7
- package/server/{rebuild-stack-CFvcBHsS.js → rebuild-stack-DqcOVmJO.js} +2 -2
- package/server/{reconstruct-cache-C3Ui7ojV.js → reconstruct-cache-CMZJ_Vjq.js} +9 -7
- package/server/record-BTwWhtBb.js +3 -0
- package/server/{record-update-dE1Aw83j.js → record-update-DaOKS7Wb.js} +124 -157
- package/server/record-update-DhI7eySG.js +3 -0
- package/server/{recovery-trip-BvRWfUXM.js → recovery-trip-DDH-02ng.js} +2 -2
- package/server/{release-engine-Cx48W7z8.js → release-engine-B2X9AfFC.js} +5 -5
- package/server/{release-set-CQfuN9-v.js → release-set-G4XKyQ8K.js} +3 -3
- package/server/{remote-C_2hasl7.js → remote-BXarMvqf.js} +3 -3
- package/server/{remote-ChgimyYa.js → remote-CUhyqjXk.js} +3 -3
- package/server/{remote-agents-By1ige5O.js → remote-agents-Bba-MgSA.js} +311 -48
- package/server/{remote-agents-CA3Ihlxj.js → remote-agents-CLZB3Coc.js} +2 -2
- package/server/{remote-completion-fVe9e_3u.js → remote-completion-CwAp79EC.js} +13 -13
- package/server/resume-mOREjlYu.js +3 -0
- package/server/{review-agent-CIGOQYBD.js → review-agent--pOptAEV.js} +65 -50
- package/server/{review-agent-DNboMyW4.js → review-agent-BTCNkq2h.js} +1 -1
- package/server/{review-artifacts-nRDPuMxd.js → review-artifacts-BNmw8dWE.js} +7 -6
- package/server/{review-context-2uj-YQ8J.js → review-context-DFxYOOJW.js} +9 -9
- package/server/{in-flight-guard-CAAkqPLu.js → review-convoy-liveness-BgU_1jJf.js} +3 -44
- package/server/review-status-CGvlA4o_.js +7737 -0
- package/server/review-status-Dma9SFaN.js +3 -0
- package/server/review-status-emit-DURrmGYX.js +50 -0
- package/server/{review-status-enrichment-Dci-ZwEt.js → review-status-enrichment-8NiNXi5W.js} +4 -4
- package/server/review-status-source-BLx_1siH.js +3 -0
- package/server/{review-status-source-CxuEjLGg.js → review-status-source-DIk1JSow.js} +24 -3
- package/server/{review-status-sync-BTOpxtTC.js → review-status-sync-0GxOqeqF.js} +11 -6
- package/server/{review-status-sync-DSDK3OMy.js → review-status-sync-muT-EBp2.js} +1 -1
- package/server/{review-verdict-feedback-CTd4QMBu.js → review-verdict-feedback-HwF6ODFy.js} +1 -1
- package/server/{review-verdict-feedback-CCjVA7Uk.js → review-verdict-feedback-xJNdqBnX.js} +65 -11
- package/server/{rollup-FGsKki9R.js → rollup-BQaol5TX.js} +8 -8
- package/server/{rollup-BKQC7jp4.js → rollup-BR4t_wck.js} +1 -1
- package/server/{scanner-CnqEZeDy.js → scanner-C-D2cFdX.js} +8 -7
- package/server/{sequence-io-D909zgeH.js → sequence-io-Bmf1EZM5.js} +4 -4
- package/server/{sequencer-agent-CzkcK6P5.js → sequencer-agent-CigMyKh2.js} +7 -6
- package/server/server.js +2005 -614
- package/server/{service-CLeAoU6G.js → service-CD0DvFvD.js} +114 -68
- package/server/{session-fork-CHI1XvL9.js → session-fork-B6cQ5eya.js} +2 -2
- package/server/{session-history-BT3IvqhC.js → session-history-3ON_IJjm.js} +7 -55
- package/server/settings-CVmWiJ-r.js +2 -0
- package/server/{settings-C0zgxOGf.js → settings-PilbFZAM.js} +3 -2
- package/server/{settings-BTMvpNFU.js → settings-VN0qOh4U.js} +3 -3
- package/server/{shadow-engineering-BJfgm-hX.js → shadow-engineering-DXvx77oE.js} +3 -3
- package/server/{shadow-state-7a-524T8.js → shadow-state-BBk_zacw.js} +2 -2
- package/server/{shadow-state-DnDyjujH.js → shadow-state-CZBp7pwq.js} +1 -1
- package/server/{shadow-utils-Db3oroFG.js → shadow-utils-DdZ05AJS.js} +2 -2
- package/server/{ship-log-D9MlVzYU.js → ship-log-7kJfjUX2.js} +1 -1
- package/server/{smart-compaction-CV2ukKND.js → smart-compaction-8fA5k5XN.js} +1 -1
- package/server/{smart-compaction-KCYScAU1.js → smart-compaction-ByhL9cRS.js} +8 -7
- package/server/{spawn-planning-session-DKpdFyOC.js → spawn-planning-session-pcF-YeFE.js} +38 -50
- package/server/spawn-planning-session-vLUJoFjy.js +3 -0
- package/server/{specialist-completion-Ky9wCDpb.js → specialist-completion-B07XjWD2.js} +1 -1
- package/server/{specialist-context-Bn3dCGS2.js → specialist-context-DJ-zFyL3.js} +5 -5
- package/server/{specialist-handoff-logger-CMEwYxa2.js → specialist-handoff-logger-aKSxbIgD.js} +2 -2
- package/server/{specialist-logs-C5p8G7tx.js → specialist-logs-Dae-n52_.js} +3 -3
- package/server/{specialists-CC4r-c2s.js → specialists-6PWdtWcg.js} +1177 -311
- package/server/{specialists-DM6bWjsi.js → specialists-Bz-wFT7R.js} +1 -1
- package/server/{specialists-jiuuyVkp.js → specialists-DUiExaxb.js} +18 -18
- package/server/{specialists-CShuVGWT.js → specialists-KR3pKulN.js} +1 -1
- package/server/specs--enInima.js +3 -0
- package/server/src-B948bGVR.js +11452 -0
- package/server/{src-CXmtj0im.js → src-rac0Mepv.js} +6 -6
- package/server/{src-CdmnTM2m.js → src-vHy2-oCv.js} +3 -3
- package/server/{stack-health-Bn3o8FBX.js → stack-health-BikqHSjn.js} +1 -1
- package/server/{stack-health-DxSdG9cW.js → stack-health-DqLTiEu4.js} +7 -5
- package/server/{stale-task-claims-KJKxxiiQ.js → stale-task-claims-Cab_Fo_Z.js} +5 -4
- package/server/{staleness-DPm7ClwA.js → staleness-C-a5rBxF.js} +1 -1
- package/server/{staleness-CT34nwr9.js → staleness-CGTZyp6V.js} +1 -1
- package/server/{state-home-Cn_Qu8IX.js → state-home-722Dkx92.js} +2 -2
- package/server/{state-mapping-BL_-3Yt8.js → state-mapping-CybR81Uf.js} +1 -1
- package/server/{state-migrate-BGg2ZaOt.js → state-migrate-2u8wIpoL.js} +4 -4
- package/server/{stuck-remediation-DYuPRYYw.js → stuck-remediation-CC6q3eqQ.js} +84 -26
- package/server/{stuck-remediation-s9_2qfi6.js → stuck-remediation-r1TJu68G.js} +1 -1
- package/server/{substrate-bug-weights-service-B-FwCs5V.js → substrate-bug-weights-service-CzIyyWFT.js} +3 -3
- package/server/{summary-fork-DpcxN9tf.js → summary-fork-BqgmgPDt.js} +2 -2
- package/server/{summary-fork-D1RAk9rJ.js → summary-fork-Df2WFijM.js} +8 -8
- package/server/supervisor/{injection-budget-Csw5tqfJ.js → injection-budget-Cg_KIb3o.js} +1 -1
- package/server/supervisor/{paths-DehGY2Fj.js → paths-BBOnCYlO.js} +10 -2
- package/server/supervisor/pty-supervisor.js +50 -4
- package/server/supervisor/{pty-token-x-ea28Us.js → pty-token-BbjwEUUM.js} +3 -3
- package/server/supervisor-B4anCCSm.js +2 -0
- package/server/{supervisor-wM4ooB5O.js → supervisor-BxqSpjcN.js} +3 -3
- package/server/{swarm-readiness-DlP_UjHq.js → swarm-readiness-DfFxa9-n.js} +3 -3
- package/server/{system-prerequisites-DUDj1YHf.js → system-prerequisites-ICLSkhhZ.js} +2 -2
- package/server/{teardown-workspace-DeTTImn-.js → teardown-workspace-DRdi_CPa.js} +15 -16
- package/server/{test-agent-queue-MbxX5vqq.js → test-agent-queue-A_-p-i0I.js} +8 -7
- package/server/{test-verdict-gscuksPv.js → test-verdict-BHgTAwIG.js} +1 -1
- package/server/{test-verdict-bWYBtqBg.js → test-verdict-C4i9aqEP.js} +1 -1
- package/server/{tldr-daemon-BYFkts95.js → tldr-daemon-CvWXBhX1.js} +1 -1
- package/server/{tldr-daemon-C-69c3OI.js → tldr-daemon-wvsU6bKv.js} +2 -2
- package/server/{tmux-R7N7y-Mh.js → tmux-CfDHob9M.js} +174 -4
- package/server/{tmux-B6z7h_vZ.js → tmux-Ctk6RV5l.js} +1 -1
- package/server/{token-BK6t8BIT.js → token-DrxwytsZ.js} +2 -2
- package/server/{token-util-DxXu-vd1.js → token-util-B48BlCba.js} +1 -1
- package/server/token-util-D411CAq9.js +3 -0
- package/server/{tracker-config-G6latr8C.js → tracker-config-BcPMElRB.js} +2 -2
- package/server/{tracker-utils-DHv5pSDT.js → tracker-utils-CJ6BHjcD.js} +3 -3
- package/server/{traefik-connect-Df2uXPsQ.js → traefik-connect-DZ6nMYMj.js} +1 -1
- package/server/{tunnel-DGdUkGoZ.js → tunnel-Bp-dRHZz.js} +1 -1
- package/server/{tunnel-CDVKJpRv.js → tunnel-DUbUPElU.js} +3 -3
- package/server/{typed-errors-BHhE85Ul.js → typed-errors-CKeoDdU3.js} +1 -1
- package/server/{typed-errors-2BTMxkZq.js → typed-errors-DyjseiB6.js} +1 -1
- package/server/{types-hraoaQIp.js → types-Cm5ASJbq.js} +1 -1
- package/server/{types-5M0lupud.js → types-Di8wdakq.js} +1 -1
- package/server/uat-promote-verification-CoJuh7XO.js +92 -0
- package/server/uat-train-4Q0k06CQ.js +0 -0
- package/server/uat-train-Dewoatps.js +2 -0
- package/server/{validate-IfDGkaVR.js → validate-B0C8p66t.js} +8 -6
- package/server/{validation-Dw1pzDzr.js → validation-B_kIRfNe.js} +4 -4
- package/server/{validation-CC9OPqJZ.js → validation-hVOwQk8T.js} +1 -1
- package/server/{verification-artifact-B3itKTxu.js → verification-artifact-BxlxTiYK.js} +1 -1
- package/server/{verification-artifact-TVFSz_q1.js → verification-artifact-D70AtckY.js} +1 -1
- package/server/{verification-runner-BW4HOKAz.js → verification-runner-Bc3cJvpC.js} +1 -1
- package/server/{verification-runner-CkgX6EtI.js → verification-runner-KZTz6u72.js} +40 -18
- package/server/{vtt-parser-DYPbKcIJ.js → vtt-parser-CE_i3Bcw.js} +1 -1
- package/server/{work-agent-prompt-Du8Vh2aJ.js → work-agent-prompt-ByrPAzOy.js} +20 -9
- package/server/{workflows-mbQzh6mQ.js → workflows-D0vP1WrK.js} +252 -99
- package/server/workflows-DtDX08ed.js +2 -0
- package/server/{workspace--8tnhDI0.js → workspace-COWvdibH.js} +1 -1
- package/server/{workspace-BPUws1-_.js → workspace-DQkRPLlQ.js} +3 -3
- package/server/workspace-anchor-drift-DXYIAHzr.js +224 -0
- package/server/workspace-anchor-drift-pwz23TI1.js +3 -0
- package/server/{workspace-config-CIVWZOQr.js → workspace-config-BdZM4PvZ.js} +1 -1
- package/server/{workspace-manager-CBhNdzE4.js → workspace-manager-BPgTrG66.js} +157 -118
- package/server/workspace-manager-C1F3XsnS.js +3 -0
- package/server/{workspace-metadata-BzHnwwX4.js → workspace-metadata-CdjzAP8x.js} +1 -1
- package/server/{workspace-metadata-_WygnyoX.js → workspace-metadata-DkO_iTLo.js} +2 -2
- package/server/{workspaces-Do_9J0LQ.js → workspaces-CRBJikLp.js} +749 -299
- package/sync-sources/dev-skills/pan-dashboard-restart/SKILL.md +34 -10
- package/sync-sources/hooks/linear-mcp-auth-hook +97 -0
- package/sync-sources/rules/ask-user-question-self-contained.md +9 -0
- package/sync-sources/skills/pan-close/SKILL.md +5 -3
- package/sync-sources/skills/pan-merge/SKILL.md +7 -5
- package/sync-sources/skills/pan-peer-review/SKILL.md +195 -0
- package/sync-sources/skills/pan-release/SKILL.md +57 -0
- package/sync-sources/skills/pan-reload/SKILL.md +3 -3
- package/sync-sources/skills/pan-restart/SKILL.md +5 -4
- package/sync-sources/skills/pan-review/SKILL.md +7 -1
- package/sync-sources/skills/pan-sync-main/SKILL.md +9 -8
- package/sync-sources/skills/pipeline-status/SKILL.md +10 -1
- package/sync-sources/skills/workspace-add-repo/SKILL.md +16 -1
- package/server/activity-logger-OEUBdfZ8.js +0 -3
- package/server/agent-state-Bc3tzUC8.js +0 -3
- package/server/agent-state-service-D5UGKIJL.js +0 -2
- package/server/agents-wi9NWzs2.js +0 -3
- package/server/archive-planning-BZDgzoEj.js +0 -3
- package/server/cli-B86rejVV.js +0 -3
- package/server/conflict-gate-BhAY7TUd.js +0 -3
- package/server/conversation-service-BLd3MYsG.js +0 -3
- package/server/deacon-kiQrb4ZT.js +0 -4
- package/server/deacon-swarm-C-GwfjJy.js +0 -2
- package/server/deploy-window-DkZraDyj.js +0 -3
- package/server/dist-Bzy0y69j.js +0 -3
- package/server/dod-C6n9RV3G.js +0 -66
- package/server/flywheel-merge-order-UU0tiUld.js +0 -245
- package/server/flywheel-merge-order-UUcsCDb6.js +0 -2
- package/server/forge-CNFnyqps.js +0 -270
- package/server/forge-DXnS_YFH.js +0 -2
- package/server/git-utils-D0_yhCgF.js +0 -3
- package/server/github-pr-lookup-D16NGsSO.js +0 -44
- package/server/hume-ccTf4wTX.js +0 -3
- package/server/inspect-agent-Brtz0URj.js +0 -2
- package/server/label-reconciler-B4iOAjlC.js +0 -113
- package/server/launcher-generator-BBWG_SiS.js +0 -473
- package/server/merge-ops-CR44oU9-.js +0 -2
- package/server/merge-set-bUqbm3yc.js +0 -3
- package/server/merge-sync-BJYeOODr.js +0 -3
- package/server/merge-verification-BkaOqPsw.js +0 -124
- package/server/pipeline-membership-mY3GprlK.js +0 -420
- package/server/project-repos-DXKQsc_m.js +0 -3
- package/server/projects-vjjcmiN8.js +0 -3
- package/server/public/assets/index-CWeMerGO.js +0 -804
- package/server/public/assets/index-CenuJ3Cw.css +0 -1
- package/server/public/assets/mermaid-GHXKKRXX-CpPWAFwE.js +0 -1
- package/server/rally-zhhtXuDP.js +0 -3
- package/server/record-CN0pj4_5.js +0 -3
- package/server/record-update-bLJxAXH4.js +0 -3
- package/server/resume-BFv1PGpA.js +0 -3
- package/server/review-status-btEYlaxA.js +0 -3
- package/server/review-status-kZj_KyCk.js +0 -1470
- package/server/settings-66A6uvIA.js +0 -2
- package/server/spawn-planning-session-qUC2VWu3.js +0 -2
- package/server/specs-C8Wsn2XO.js +0 -3
- package/server/src-DtcUOZCq.js +0 -4826
- package/server/supervisor-FTJAIsAK.js +0 -2
- package/server/token-util-DuPuNriz.js +0 -3
- package/server/tracker-utils-B4ylXZQK.js +0 -3
- package/server/uat-train-B05BWkp-.js +0 -2
- package/server/uat-train-DDSrSoV1.js +0 -2152
- package/server/workflows-BQu4RFQ-.js +0 -2
- package/server/workspace-manager-CWT55qeI.js +0 -3
package/server/server.js
CHANGED
|
@@ -1,110 +1,115 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import { A as canUseHarnessSync,
|
|
3
|
-
import { a as shouldRefuseHostDashboardPort, i as readHostDashboardApiPort, n as getDashboardIdentity, r as isNonPrimaryCheckoutRoot } from "./deacon-nudge-log-
|
|
4
|
-
import { $ as
|
|
5
|
-
import { a as
|
|
6
|
-
import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-
|
|
2
|
+
import { A as canUseHarnessSync, An as extractTeamPrefix, Cn as resolveStateReadHomeSync, D as resolveTieredExecutionEnabled, Dr as GitHubApiError, E as resolveTieredExecutionBlock, Fr as init_errors, Gn as init_projects, Gr as OVERDECK_HOME, H as init_providers, I as UnknownModelError, In as getIssuePrefix, Ir as AGENTS_DIR, J as defaultBackgroundAiFeatures, Jn as listProjects, M as init_harness_policy, Mn as findProjectByPathSync, Mt as getIssueWorkspacePath, Nr as TrackerError, On as ProjectRenameError, Pn as findProjectByTeamSync, Pt as init_record, Q as computeModelOrigin, Qr as SYNC_SOURCES, R as getBuiltInDefaultHarness, Sn as init_state_read_home, T as init_tier_table, Tr as FsError, V as getProviderForModelSync, Vr as CLAUDE_DIR, Wr as LOGS_DIR, X as DEFAULT_ROLES, Y as init_registry, Yn as listProjectsSync, Z as DEFAULT_WORKHORSES, Zn as loadProjectsConfigSync, _ as getDefaultDocsConfig, ai as getDocsTelemetryPath, ar as resolveProjectFromIssueSync, at as getModelEffortLevelsSync, ci as getOverdeckHome, cn as flushAutoCommits, ct as modelSupportsImagesSync, d as loadConfigNoMigration, di as packageRoot, dr as setProjectSwarmPolicySync, er as registerProjectSync, f as loadConfigSync, g as mergeConfigs, gr as init_issue_id, gt as ROLE_EFFORTS, h as jsYaml, hr as extractPrefixSync, ht as PARENT_MODEL_REF, i as getConversationsConfig, ii as getDocsIndexPath, ir as resolveProjectFromIssue, jr as ProcessSpawnError, k as validateTieredExecutionConfig, li as init_paths, ln as init_auto_commit, lr as setProjectAutoMergeDefaultSync, lt as resolveModelIdSync, m as init_js_yaml, mt as COMPLIANCE_MODES, n as clearConfigCache, ni as getDocsBudgetStatePath, nt as MODEL_CAPABILITIES, o as getGlobalConfigPath, ot as hasModelCapabilitySync, p as updateConversationsConfig, pi as sessionFilePath, r as getConversationSearchConfigSync, ri as getDocsDisableStatePath, rr as resolveInfraRepo, rt as MODEL_DEPRECATIONS, s as init_load, si as getLegacyHome, sn as flushAllPendingAutoCommits, st as init_model_capabilities, t as init_config_yaml, ti as encodeClaudeProjectDir, tr as renameProject, tt as resolveModel, u as isTldrEnabledSync, ui as isDevMode, ur as setProjectMergeTrainSync, v as getDefaultTtsDaemonConfig, vr as parseIssueIdSync, w as TieredExecutionConfigError, xr as require_dist$1, y as mergeTtsDaemonConfigs, z as getKimiAnthropicBaseUrl, zn as getProjectSync, zt as readIssueRecordSync } from "./config-yaml-CxdwhAIA.js";
|
|
3
|
+
import { a as shouldRefuseHostDashboardPort, i as readHostDashboardApiPort, n as getDashboardIdentity, r as isNonPrimaryCheckoutRoot } from "./deacon-nudge-log-B08gF0mh.js";
|
|
4
|
+
import { $ as composerCommandConfirmationFromBody, A as resolveAllowedHarness, At as jsonResponse, B as cleanupUnreferencedConversationAttachments, C as handleConversationCreate, Ct as waitForSessionRespawn, D as handleConversationStop, Dt as validateOriginHeaders, E as handleConversationResume, Et as validateOrigin$1, F as tmuxSessionExists, G as isManagedConversationAttachmentPath, H as extractConversationAttachmentPaths, I as waitForPiTuiReady, J as composerCommandResultHttpStatus, K as removeConversationAttachment, L as waitForTmuxSession$1, M as spawnConversationSession, N as startConversationModelBackfill, O as handleConversationSwitchModel, Ot as httpHandler, P as stopConversationRuntime, Q as ComposerCommandConfirmationError, R as cleanupConversationAttachments, S as conversationSessionAliveFromState, St as isRespawnPending, T as handleConversationRestartAll, Tt as isTrustedOriginForHost, U as getConversationAttachmentsRoot, V as ensureConversationAttachmentDir, W as hasConversationAttachment, X as resolvePolicy, Y as handleComposerCommandMessage, Z as ComposerCommandParseError, _ as isPiControlChannelHarness, _t as dashboardSessionCookieHeader, a as agentsRouteLayer, at as resolveConversationGitInfo, b as validateConversationControlAckOrigin, bt as rejectUnauthorizedDashboardSessionMintRequest, c as codexConversationPendingInput, d as handleConversationCodexApproval, dt as resolveAgentHarness, et as evaluateSpawnGuardrails, f as handleConversationCompact, ft as resolveClaudeSessionId, g as handleConversationThinkingLevel, gt as dashboardCsrfToken, h as handleConversationPlanAction, ht as resolvePiSessionPath, it as resolveAgentGitInfo, j as shouldReportUnresolvedLiveSession, jt as jsonStringResponse, k as isInsideGitWorkTree, kt as getDefaultCwd, l as deliverConversationViaControlChannel, lt as readLauncherPinnedSessionId, m as handleConversationDeliveryMethod, mt as resolveJsonlPath, nt as isInternalAgentRequest, o as saveAgentStateAndEmitEvent, p as handleConversationControlAck, pt as resolveCodexRolloutPath, q as runInBatches, rt as resolveRequestedStartedBy, s as saveAgentStateAndEmitEventProgram, st as panCliInvocation, t as specialistsRouteLayer, tt as invalidateAgentsCache, u as handleConversationAbort, ut as resolveAcpTranscriptPath, v as pickDeliverAs, vt as hasDashboardInternalToken, w as handleConversationDelete, wt as getHeaderFromMap, x as conversationNeedsRunningRepair, xt as rejectUnsafeDashboardMutationRequest, y as resolveConversationDeliveryMethod, yt as rejectUnauthorizedDashboardRequest, z as cleanupOrphanedConversationAttachments } from "./specialists-6PWdtWcg.js";
|
|
5
|
+
import { a as emitDashboardLifecycleSync, i as emitActivityTtsSync, o as init_activity_logger, r as emitActivityEntrySync } from "./activity-logger-CyteR4JO.js";
|
|
6
|
+
import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-BDQDRopn.js";
|
|
7
7
|
import { n as openDatabase, t as init_driver } from "./driver-CKVGi51s.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { a as init_event_store, i as initEventStore, n as getEventStore } from "./event-store-
|
|
11
|
-
import { A as
|
|
12
|
-
import {
|
|
13
|
-
import { a as EventStoreService, c as ReadModelService,
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { i as
|
|
17
|
-
import { n as
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { a as
|
|
21
|
-
import {
|
|
22
|
-
import { u as
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { i as
|
|
28
|
-
import { i as
|
|
29
|
-
import { i as
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import { i as
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import { C as
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import { i as
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import { l as
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import { i as
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
58
|
-
import { i as
|
|
59
|
-
import { n as
|
|
60
|
-
import {
|
|
61
|
-
import {
|
|
62
|
-
import {
|
|
63
|
-
import { c as
|
|
64
|
-
import {
|
|
65
|
-
import { c as
|
|
66
|
-
import { n as
|
|
67
|
-
import {
|
|
68
|
-
import {
|
|
69
|
-
import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-
|
|
70
|
-
import { _ as
|
|
71
|
-
import { B as getBook, C as readCurrentLatestFlywheelStatus, E as subscribeLatestFlywheelStatus, F as setItemRequirements, H as liveOrderIssueLookup, I as setSettings, L as setStatus, M as moveItem, N as removeItem, O as writeLatestFlywheelStatus, P as renameBook, R as backlogCandidates, T as resolveLiveFlywheelRunId, V as listBooks, b as isFlywheelRunId, j as createBook, k as addItems, p as buildClassifyLookups, v as getFlywheelRunDetail, x as listFlywheelRuns, z as computeBookProgress } from "./flywheel-
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
import { a as
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
77
|
-
import {
|
|
78
|
-
import {
|
|
79
|
-
import {
|
|
80
|
-
import { b as
|
|
81
|
-
import {
|
|
82
|
-
import {
|
|
83
|
-
import {
|
|
84
|
-
import {
|
|
85
|
-
import {
|
|
86
|
-
import {
|
|
87
|
-
import {
|
|
88
|
-
import {
|
|
89
|
-
import {
|
|
90
|
-
import { t as
|
|
91
|
-
import {
|
|
92
|
-
import {
|
|
93
|
-
import {
|
|
94
|
-
import {
|
|
95
|
-
import {
|
|
96
|
-
import { t as
|
|
97
|
-
import {
|
|
98
|
-
import {
|
|
99
|
-
import { n as
|
|
100
|
-
import {
|
|
101
|
-
import {
|
|
102
|
-
import {
|
|
103
|
-
import {
|
|
104
|
-
import {
|
|
105
|
-
import { a as
|
|
106
|
-
import "./
|
|
107
|
-
import { i as
|
|
8
|
+
import { i as updateIssueRecord, n as clearRecordPipelineClosedOutSync, r as init_record_update } from "./record-update-DaOKS7Wb.js";
|
|
9
|
+
import { B as sendKeysAsync, C as getWindowDimensions, D as killSession, E as isPaneDead, H as sessionExists, J as init_pane_choice_menu, L as resizeWindow, M as listSessionNames, T as isHarnessProcessAlive, V as sendRawKeystroke, Y as paneChoiceMenuSignature, Z as parsePaneChoiceMenu, at as buildChildEnvWithoutTmuxSync, d as ensureManagedTmuxContextOnce, i as capturePane, it as buildChildEnvSync, l as deliveryVerifyLine, n as buildTmuxArgs, nt as setUiTheme, o as capturePaneText, ot as init_child_env, q as buildChoiceKeystrokes, s as createSession, tt as init_ui_theme, w as init_tmux, z as sendKeys } from "./tmux-CfDHob9M.js";
|
|
10
|
+
import { a as init_event_store, i as initEventStore, n as getEventStore } from "./event-store-CrHcVC5_.js";
|
|
11
|
+
import { A as AgentRuntimeSnapshot, C as FlywheelStatus, E as SystemHealthSnapshot, M as ReviewStatusSnapshot, O as MemoryObservation, S as FlywheelRunId, T as DomainEvent, b as PanRpcGroup, j as AgentSnapshot, l as ContextLayerSaveRequest, n as COMPOSER_COMMAND_MANIFEST, p as FlywheelStats, r as compareIssueIds, s as getHarnessBehavior, t as init_src, u as ContextPreviewRequest, w as EDITORS, x as WS_METHODS, y as PanRpcError } from "./src-B948bGVR.js";
|
|
12
|
+
import { A as synchronizeAnalyticsServices, C as setReviewStatusSync, F as telemetryEnvironmentForcesOff, M as init_install_id, N as init_config, O as getAnalyticsService, P as resolveTelemetryEnabled, S as setReviewStatus, _ as markWorkspaceStuck, a as clearStuckMergeStatuses, c as fixStuckCommentedReviews, d as getReviewStatusSync, h as loadReviewStatuses, i as clearReviewStatus, j as getOrCreateInstallId, k as init_service, l as fixStuckReadyForMerge, m as loadReadyForMergeFlags, p as init_review_status, u as getReviewStatus } from "./review-status-CGvlA4o_.js";
|
|
13
|
+
import { a as EventStoreService, c as ReadModelService, f as init_read_model, h as toRole, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toAgentStatus, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentResolution, s as init_domain_services, t as IssueLifecycle, u as activityEntriesFromStoredEvents } from "./issue-lifecycle-Birk-ifu.js";
|
|
14
|
+
import { n as logAgentLifecycleSync, t as init_persistent_logger } from "./persistent-logger-H_VjuOu7.js";
|
|
15
|
+
import { c as listAllAgentsSync, n as AgentsResolverLive, o as init_agents } from "./agents-J5mEnekq.js";
|
|
16
|
+
import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-sJBSb7Ul.js";
|
|
17
|
+
import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-DRqZ8lAz.js";
|
|
18
|
+
import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-DJEFx1Pf.js";
|
|
19
|
+
import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-DBcyNR8w.js";
|
|
20
|
+
import { $ as operatorInterventionEvent, $n as getAgentDir, Bt as init_transcript_landing, Cr as init_agent_record_sync, D as init_tier_supervisor, E as deliverCommitForReview, Fn as init_openai_auth, Gr as init_codex_auth, Ir as waitForReadySignal, Lr as getAgentRuntimeState, Mt as deliverAgentMessage, Nr as normalizeAgentId, Pn as getOpenAIAuthStatus, Q as init_operator_interventions, Qt as init_staffing, Rr as getAgentRuntimeStateSync, Tn as init_claude_auth, Vt as probeTranscriptSince, Wr as checkCodexAuthStatus, X as messageAgent, Y as init_messaging, _r as saveAgentStateSync, a as listRunningAgentsSync, b as init_agents$1, bt as init_concurrency, c as getRuntimeCensus, d as panePidsForSession, dn as getProviderAuthMode, en as resolveImplicitStaffing, f as refreshRuntimeCensus, i as listRunningAgents, j as supervisorAgentId, kn as getProviderEnvForModel, l as getRuntimeCensusSnapshot, mn as injectPiConversationMemory, n as init_queries, p as runtimeCensusHasHarnessProcess, r as listAgentStates, rr as getAgentStateSync, tr as getAgentState, u as init_runtime_census, vt as emergencyBrake, wn as getClaudeAuthStatus, wr as readAgentHarnessModelRecordSync, zt as captureTranscriptUserRecordSnapshot } from "./queries-C-MUZaIy.js";
|
|
21
|
+
import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-tOCCGnEt.js";
|
|
22
|
+
import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-CD0DvFvD.js";
|
|
23
|
+
import { s as init_agent_runtime_mirror } from "./session-history-3ON_IJjm.js";
|
|
24
|
+
import { t as init_behavior } from "./behavior-td6-xhQk.js";
|
|
25
|
+
import { n as AgentStateServiceLive } from "./agent-state-service-Ds6OeFvo.js";
|
|
26
|
+
import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-BcPMElRB.js";
|
|
27
|
+
import { d as init_typed_errors, i as PlanEmpty, l as WorkspaceCreateError, n as AgentStartError, s as TrackerApiError, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-DyjseiB6.js";
|
|
28
|
+
import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-9uq7fhiV.js";
|
|
29
|
+
import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-qazkPrg0.js";
|
|
30
|
+
import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-iYMHWQD7.js";
|
|
31
|
+
import { n as resolveGitHubIssueSync, r as resolveTrackerTypeSync, t as init_tracker_utils } from "./tracker-utils-CJ6BHjcD.js";
|
|
32
|
+
import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-C6ZduvuY.js";
|
|
33
|
+
import { i as ensureInternalTokenSync, o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-DzK385vD.js";
|
|
34
|
+
import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-D0ALV6Nw.js";
|
|
35
|
+
import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-0GxOqeqF.js";
|
|
36
|
+
import { n as init_review_status_source, t as classifyAdvancingSessionLifecycle } from "./review-status-source-DIk1JSow.js";
|
|
37
|
+
import { a as PAN_DIRNAME, d as WORKSPACE_RUNTIME_DIRNAME, f as asPanSpecDocument, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-Cm5ASJbq.js";
|
|
38
|
+
import { C as scheduleAutoMergeWithResult, _ as markMerged, c as init_merge_sync, f as listActiveAutoMerges, g as markFailed, h as markBlocked, i as getActionableAutoMerge, l as isFlywheelGloballyPaused, m as listProblemAutoMerges, n as countActionableAutoMerges, p as listDuePendingAutoMerges, t as cancelPending, v as markMergingBlocked, w as transitionToMerging, x as requeueToPending } from "./merge-sync-kr4vqyjM.js";
|
|
39
|
+
import { D as writeSpecForIssue, E as writeSpecDocument, S as init_specs, a as findWorkspaceDraftPlan, m as readWorkspacePlanSync, o as init_io, p as readWorkspacePlan, r as findPlan, s as isPlanningComplete, u as readPlan, v as init_types$1, x as findSpecByIssue, y as subItemsOf } from "./io-B00PBNku.js";
|
|
40
|
+
import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-C5fMJ7rY.js";
|
|
41
|
+
import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, F as markConversationEnded, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, _t as getDiscoveredStats, at as aggregateDiscoveredSessionCost, b as getConversationByClaudeSessionId, ct as countDiscoveredSessions, et as updateConversationTitle, ft as findDiscoveredSessions, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, mt as getDiscoveredSessionById, ot as aggregateDiscoveredSessionCostBy, q as setFavorite, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-D0UEdLtk.js";
|
|
42
|
+
import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-D5km80UI.js";
|
|
43
|
+
import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-VN0qOh4U.js";
|
|
44
|
+
import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-BJQSnAAp.js";
|
|
45
|
+
import { C as init_launcher_generator, D as requireModelOverrideSync, E as normalizeModelOverrideSync, S as generateLauncherScriptSync, T as init_model_validation, w as MODEL_ID_PATTERN } from "./auto-spawn-consent-CQ9Bi9q6.js";
|
|
46
|
+
import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-CpbpvUQ2.js";
|
|
47
|
+
import { C as ensureProjectLayer, E as init_layers, I as workspaceContextFile, N as resolveProjectContextFile, P as resolveWorkspaceContextFile, S as codexGlobalContextFile, T as globalContextFile$1, b as validateTemplate, c as init_render, d as userContentOutsideRegion, i as workspaceContextWithoutProjectLayer, r as init_assemble, s as hasManagedRegion, v as init_harness, y as renderForHarness } from "./assemble-Bgwqv-Ro.js";
|
|
48
|
+
import { l as init_codex, s as findRolloutPath } from "./codex-BzGDW_d3.js";
|
|
49
|
+
import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-BSpiXaLw.js";
|
|
50
|
+
import { f as init_config$1, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-BvLe652W.js";
|
|
51
|
+
import { D as setSetting, E as setMergeTrainEnabled, S as setFlywheelAutoPickupBacklog, T as setLastCleanShutdownAt, b as setDeaconGloballyPausedSync, c as init_control_settings, d as isDeaconGloballyPausedSync, f as isFlywheelAutoPickupBacklog, g as setBootReconciliationDecision, h as isMergeTrainEnabled, l as isCloisterSpawnsPausedSync, m as isFlywheelRequireUatBeforeMerge, n as FLYWHEEL_GLOBAL_PAUSE_KEY, p as isFlywheelGloballyPaused$1, r as getBootReconciliationState, s as getSetting, t as FLYWHEEL_ACTIVE_RUN_ID_KEY, v as setCloisterSpawnsPausedSync, w as setFlywheelRequireUatBeforeMerge } from "./control-settings-CiqGxXnc.js";
|
|
52
|
+
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-BAJu5MX8.js";
|
|
53
|
+
import { a as loadCloisterConfigSync, o as saveCloisterConfigSync, r as init_config$2, s as shouldAutoStart } from "./config-Bi3u1VK7.js";
|
|
54
|
+
import { c as isStateMigrated, i as ensureStateWorktree, o as init_state_home, r as clearStateMigrationCache, s as inspectStateMigration } from "./state-home-722Dkx92.js";
|
|
55
|
+
import { i as checkPrdGateSync, s as promoteWorkspacePrdDraft, t as init_pan_dir } from "./pan-dir-DMzF5wne.js";
|
|
56
|
+
import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-DCo6s6ks.js";
|
|
57
|
+
import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-DfFxa9-n.js";
|
|
58
|
+
import { a as buildMatchQuery, c as init_query_expansion, i as resolveKnowledgeBundleRoot, n as init_injection, o as init_search, r as injectPromptTimeMemory, s as clearQueryExpansionCache } from "./injection-6AGnXxlj.js";
|
|
59
|
+
import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-IVc4_M3f.js";
|
|
60
|
+
import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-B48BlCba.js";
|
|
61
|
+
import { A as createSettledTtlPromiseCache, D as init_advisory_checks, E as verifyAppCanMerge, M as withConcurrencyLimit, O as isAdvisoryCheckName, d as getPullRequestState, f as init_github_app, j as init_concurrency$1, k as createPromiseConcurrencyLimiter, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-CmNk0zLU.js";
|
|
62
|
+
import { C as getWorkspacePathForIssue, E as stopAgentOutputService, S as resolveIssueHeadlineCost, T as startAgentOutputService, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, w as retainAgentOutputInterest, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-CRBJikLp.js";
|
|
63
|
+
import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, b as parseAcpConversationMessages, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages, y as init_acp_conversation_parser } from "./conversation-service-DBxoYMDl.js";
|
|
64
|
+
import { c as countPendingAskUserQuestionsForAgent, g as detectAwaitingInputFromPaneSync, h as detectAwaitingInputForAgent, l as getAgentJsonlMtime, m as scanPendingInputsPromise, o as getRuntimeForAgent, s as computeAgentEnrichment } from "./stuck-remediation-CC6q3eqQ.js";
|
|
65
|
+
import { a as enrichSessions, c as searchSessions, i as CostThresholdError, l as embed, n as getSessionsFeedFacets, o as embedSessions, r as listSessionsFeed, s as parseRelativeTime, t as scan } from "./scanner-C-D2cFdX.js";
|
|
66
|
+
import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-BNrvchBg.js";
|
|
67
|
+
import { n as recordBackgroundAiCost, t as init_cost } from "./cost-DS1s0DbG.js";
|
|
68
|
+
import { a as getByIssueId, i as parseFlywheelStatsWindow, n as derivePipelineRunStatsInputs, o as markFixed, r as computeFlywheelStats, s as upsert, t as listSubstrateBugWeights } from "./substrate-bug-weights-service-CzIyyWFT.js";
|
|
69
|
+
import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-Bmf1EZM5.js";
|
|
70
|
+
import { _ as normalizeGate, d as computeEpicGroups, f as computeLanes, h as init_pickup, l as classifyIssue, m as computeWaves, p as computeStats, u as computeCohort, v as selectNeedsPlanning } from "./pickup-DWhqzliO.js";
|
|
71
|
+
import { B as getBook, C as readCurrentLatestFlywheelStatus, D as writeFlywheelLaunchMetadata, E as subscribeLatestFlywheelStatus, F as setItemRequirements, H as liveOrderIssueLookup, I as setSettings, L as setStatus, M as moveItem, N as removeItem, O as writeLatestFlywheelStatus, P as renameBook, R as backlogCandidates, S as nextFlywheelRunId, T as resolveLiveFlywheelRunId, V as listBooks, a as isFlywheelDevcontainerRuntime, b as isFlywheelRunId, f as spawnFlywheelAgent, g as abortFlywheelRun, j as createBook, k as addItems, p as buildClassifyLookups, s as loadResumeSessionId, t as FLYWHEEL_ORCHESTRATOR_AGENT_ID, u as saveResumeSessionId, v as getFlywheelRunDetail, w as readFlywheelLaunchMetadata, x as listFlywheelRuns, z as computeBookProgress } from "./flywheel-BHx8XuMr.js";
|
|
72
|
+
import { Bt as isSmeeConfiguredSync, D as loadConfig, Et as paneShowsClaudeBootBlockingScreen, F as setAgentStoppedNotifier, Ft as getAcceptedSystemHealthSnapshot, G as isAutoResumableRole, Ht as classifyAgentHealth, I as setMergeReadyNotifier, It as getDeployStaleness, J as startBootReconciliation, K as isBootReconciliationCandidate, Mt as formatUptime, Nt as getContainerHistory, O as loadState, P as setAgentStatusChangedNotifier, Pt as getCurrentDockerStats, Rt as getSystemHealthEvidenceSnapshot, Vt as startSmeeProcessSync, W as extendBootReconciliationGrace, b as getDeaconLogs, jt as getResourceStacks, n as assessDeaconPatrolFreshness, q as listBootReconciliationCandidates, t as applyBootReconciliationDecision } from "./deacon-pLRLbPvR.js";
|
|
73
|
+
import { c as installGitHooksInDir, f as detectPlatform, p as init_platform, s as init_git_hooks } from "./workspace-manager-BPgTrG66.js";
|
|
74
|
+
import { a as getShadowState, s as init_shadow_state } from "./shadow-state-BBk_zacw.js";
|
|
75
|
+
import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-BehTG1be.js";
|
|
76
|
+
import { i as parseArtifactRef, r as init_forge } from "./forge-BaKGCya6.js";
|
|
77
|
+
import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-C27Hak8a.js";
|
|
78
|
+
import { V as getReviewerSessionName, t as init_specialists } from "./specialists-DUiExaxb.js";
|
|
79
|
+
import { s as findPrdAnywhereSync } from "./archive-planning-BwhxeP7C.js";
|
|
80
|
+
import { A as removeIssueReleasedLabel, C as applyIssueReleasedLabel, D as removeIssueObjectionLabel, E as removeIssueBlocksMainLabel, O as removeIssueParkedLabel, S as applyIssueReadyLabel, T as init_label_ops, a as gatherProjectLensSignals, b as applyIssueObjectionLabel, g as parseIssueIdFromTextSync, h as init_resource_utils, j as removeIssueVetoedLabel, k as removeIssueReadyLabel, n as PipelineMembershipUnavailableError, s as init_pipeline_membership_gather, u as listOpenPullRequestsSnapshot, w as applyIssueVetoedLabel, x as applyIssueParkedLabel, y as applyIssueBlocksMainLabel } from "./pipeline-membership-gather-CeVGnNJ2.js";
|
|
81
|
+
import { n as init_pipeline_membership, r as resolvePipelineMembership } from "./pipeline-membership-D9SBvItj.js";
|
|
82
|
+
import { b as resolveSwarmPolicy } from "./deacon-swarm-v5PMun-m.js";
|
|
83
|
+
import { a as init_boot_gates, i as formatBootGateState, o as resolveBootGates } from "./no-resume-mode-BgD0JUmM.js";
|
|
84
|
+
import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-D-sSkADM.js";
|
|
85
|
+
import { a as spawnPlanningSession, r as resolveAutoSpawnOnFinalize } from "./spawn-planning-session-pcF-YeFE.js";
|
|
86
|
+
import { r as computeMergeQueueFromCandidates, s as listEligibleCandidatesByProject } from "./flywheel-merge-order-D_xLMbJU.js";
|
|
87
|
+
import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-DkO_iTLo.js";
|
|
88
|
+
import { d as killRemoteAgent, m as loadRemoteAgentState, o as getRemoteAgentOutput, r as checkRemoteSpendCap, s as init_remote_agents, v as sendToRemoteAgent, y as spawnRemoteAgent } from "./remote-agents-Bba-MgSA.js";
|
|
89
|
+
import { r as spawnInspectAgent } from "./inspect-agent-nXdIptyh.js";
|
|
90
|
+
import { i as lookupPullRequestNumberForBranch, n as init_github_pr_lookup, t as githubPrLookupSource } from "./github-pr-lookup-DAcVeRLK.js";
|
|
91
|
+
import { a as fetchIssuePullRequestDiff, c as getCachedIssuePrTabResponse, d as setCachedIssuePrTabResponse, i as fetchIssuePullRequestDetails, l as getIssuePrTabCacheGeneration, n as fetchIssueCheckRuns, o as init_pull_requests, r as fetchIssuePullRequest, s as bumpIssuePrTabCacheGeneration, u as init_pr_tab_cache } from "./pull-requests-7BgLDsIo.js";
|
|
92
|
+
import { n as DOD_ROWS } from "./dod-DlNtcH6n.js";
|
|
93
|
+
import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-BQaol5TX.js";
|
|
94
|
+
import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-wvsU6bKv.js";
|
|
95
|
+
import { T as listGitOperationsSync, w as init_git_activity } from "./merge-agent-BLUgRsz3.js";
|
|
96
|
+
import { t as readVerificationArtifact } from "./verification-artifact-D70AtckY.js";
|
|
97
|
+
import { i as readPendingDeploy, n as init_deploy_queue } from "./deploy-queue-VfohaPN_.js";
|
|
98
|
+
import { t as getAgentCommandSync } from "./settings-PilbFZAM.js";
|
|
99
|
+
import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent--pOptAEV.js";
|
|
100
|
+
import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-BXarMvqf.js";
|
|
101
|
+
import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-_H9Yrzab.js";
|
|
102
|
+
import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-Df2WFijM.js";
|
|
103
|
+
import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-D6-yLtqt.js";
|
|
104
|
+
import { t as init_context_layers } from "./context-layers-C_IIysnm.js";
|
|
105
|
+
import { a as appendLinearMcpAuthHealthyEvent, r as appendLinearMcpAuthCallbackRelayedEvent, u as resolveLinearMcpAuthIntervention } from "./linear-mcp-auth-BxUOzswy.js";
|
|
106
|
+
import { i as getMergeBlockersPayload, n as hasOrderIssuePrd, r as validateBookForStart, t as createOrderPrdLookup } from "./validate-B0C8p66t.js";
|
|
107
|
+
import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-CigMyKh2.js";
|
|
108
|
+
import { n as sameCanonicalReviewStatus, t as emitReviewStatusChanged } from "./review-status-emit-DURrmGYX.js";
|
|
109
|
+
import "./supervisor-BxqSpjcN.js";
|
|
110
|
+
import { l as startUatTrainReconciler, u as stopUatTrainReconciler } from "./uat-train-4Q0k06CQ.js";
|
|
111
|
+
import { n as settlePendingLifecycleClaim, t as claimPendingLifecycleFile } from "./pending-lifecycle-claim-DilzGfgk.js";
|
|
112
|
+
import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-D95apurL.js";
|
|
108
113
|
import { createRequire } from "node:module";
|
|
109
114
|
import * as sp from "node:path";
|
|
110
115
|
import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
@@ -112,8 +117,8 @@ import { Cause, Context, Data, Duration, Effect, Exit, Fiber, FileSystem, Layer,
|
|
|
112
117
|
import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
113
118
|
import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "path";
|
|
114
119
|
import { homedir } from "os";
|
|
115
|
-
import { homedir as homedir$1, type } from "node:os";
|
|
116
|
-
import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1,
|
|
120
|
+
import { freemem as freemem$1, homedir as homedir$1, totalmem as totalmem$1, type } from "node:os";
|
|
121
|
+
import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, rmSync as rmSync$1, stat, statSync as statSync$1, unwatchFile, watch, watchFile } from "node:fs";
|
|
117
122
|
import { FetchHttpClient, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
118
123
|
import { EventEmitter } from "node:events";
|
|
119
124
|
import { access, appendFile, chmod, cp, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat as stat$1, unlink, writeFile } from "node:fs/promises";
|
|
@@ -329,9 +334,9 @@ const ServerConfigLayer = Layer.effect(ServerConfig, Effect.sync(() => {
|
|
|
329
334
|
const identity = getDashboardIdentity();
|
|
330
335
|
const hostDashboardApiPort = readHostDashboardApiPort();
|
|
331
336
|
const overrideRequested = process.env["OVERDECK_WORKSPACE_DASHBOARD_ALLOW_PRIMARY"] === "1";
|
|
332
|
-
const agentId = process.env["
|
|
337
|
+
const agentId = process.env["OVERDECK_DASHBOARD_SPAWNED_BY"];
|
|
333
338
|
if (overrideRequested && agentId !== void 0 && !agentId.startsWith("conv-")) {
|
|
334
|
-
const msg = `Refusing host dashboard port override for pipeline-role identity
|
|
339
|
+
const msg = `Refusing host dashboard port override for pipeline-role identity OVERDECK_DASHBOARD_SPAWNED_BY=${agentId}. Work, planning, review, and flywheel agents must never bind the host dashboard port; use the workspace container endpoint instead. Only an operator-supervised conversation (conv-*) or a process with no agent identity may use this emergency override.`;
|
|
335
340
|
console.error(`[overdeck] ${msg}`);
|
|
336
341
|
throw new ServerConfigError("API_PORT", msg);
|
|
337
342
|
}
|
|
@@ -399,8 +404,10 @@ init_js_yaml();
|
|
|
399
404
|
init_load();
|
|
400
405
|
init_config_yaml();
|
|
401
406
|
init_ui_theme();
|
|
407
|
+
init_pane_choice_menu();
|
|
402
408
|
init_infra();
|
|
403
409
|
init_event_store();
|
|
410
|
+
init_persistent_logger();
|
|
404
411
|
init_agents();
|
|
405
412
|
init_read_model();
|
|
406
413
|
init_checkpoint_manager();
|
|
@@ -713,7 +720,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
713
720
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
714
721
|
const plan = readWorkspacePlanSync(workspacePath);
|
|
715
722
|
if (!plan || plan.plan.items.length === 0) throw new PlanEmpty({ id: issueId });
|
|
716
|
-
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-
|
|
723
|
+
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-ePFVoZbu.js");
|
|
717
724
|
const normalizedId = normalizeAgentId(issueId);
|
|
718
725
|
if ((await Effect.runPromise(getAgentState(normalizedId)))?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
|
|
719
726
|
return {
|
|
@@ -723,7 +730,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
723
730
|
model: opts.model,
|
|
724
731
|
role: "work",
|
|
725
732
|
prompt: opts.prompt,
|
|
726
|
-
allowHost: opts.allowHost
|
|
733
|
+
allowHost: opts.allowHost,
|
|
734
|
+
startedBy: "dashboard:agent-spawner"
|
|
727
735
|
})).id ?? normalizedId,
|
|
728
736
|
issueId,
|
|
729
737
|
sessionName: normalizedId,
|
|
@@ -744,7 +752,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
744
752
|
const { workspacePath, projectPath, issue } = opts;
|
|
745
753
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
746
754
|
const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
|
|
747
|
-
const { spawnPlanningSession } = await import("./spawn-planning-session-
|
|
755
|
+
const { spawnPlanningSession } = await import("./spawn-planning-session-vLUJoFjy.js");
|
|
748
756
|
const result = await spawnPlanningSession({
|
|
749
757
|
issue: {
|
|
750
758
|
id: issue.id,
|
|
@@ -759,7 +767,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
759
767
|
sessionName,
|
|
760
768
|
workspaceLocation: "local",
|
|
761
769
|
shadowMode: opts.shadowMode ?? false,
|
|
762
|
-
autoSpawnOnFinalize: false
|
|
770
|
+
autoSpawnOnFinalize: false,
|
|
771
|
+
startedBy: "dashboard:agent-spawner"
|
|
763
772
|
});
|
|
764
773
|
if (!result.success) throw new AgentStartError({
|
|
765
774
|
id: issueId,
|
|
@@ -777,14 +786,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
777
786
|
}),
|
|
778
787
|
kill: (agentId) => Effect.tryPromise({
|
|
779
788
|
try: async () => {
|
|
780
|
-
const { stopAgent } = await import("./agents-
|
|
789
|
+
const { stopAgent } = await import("./agents-ePFVoZbu.js");
|
|
781
790
|
await Effect.runPromise(stopAgent(agentId));
|
|
782
791
|
},
|
|
783
792
|
catch: () => void 0
|
|
784
793
|
}).pipe(Effect.ignore),
|
|
785
794
|
message: (agentId, msg) => Effect.tryPromise({
|
|
786
795
|
try: async () => {
|
|
787
|
-
const { messageAgent } = await import("./agents-
|
|
796
|
+
const { messageAgent } = await import("./agents-ePFVoZbu.js");
|
|
788
797
|
await messageAgent(agentId, msg);
|
|
789
798
|
},
|
|
790
799
|
catch: (err) => new AgentStartError({
|
|
@@ -795,8 +804,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
795
804
|
}),
|
|
796
805
|
deepWipe: (issueId, opts) => Effect.tryPromise({
|
|
797
806
|
try: async () => {
|
|
798
|
-
const { deepWipe } = await import("./workflows-
|
|
799
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
807
|
+
const { deepWipe } = await import("./workflows-DtDX08ed.js");
|
|
808
|
+
const { resolveProjectFromIssueSync } = await import("./projects-_n3Zui6K.js");
|
|
800
809
|
const project = resolveProjectFromIssueSync(issueId);
|
|
801
810
|
const projectPath = project?.projectPath ?? process.cwd();
|
|
802
811
|
await Effect.runPromise(deepWipe({
|
|
@@ -828,7 +837,7 @@ init_types$1();
|
|
|
828
837
|
* Route handlers and AgentSpawner use this instead of calling workspace-manager directly.
|
|
829
838
|
*/
|
|
830
839
|
init_typed_errors();
|
|
831
|
-
const execAsync$
|
|
840
|
+
const execAsync$11 = promisify(exec);
|
|
832
841
|
var WorkspaceService = class extends Context.Service()("overdeck/dashboard/WorkspaceService") {};
|
|
833
842
|
const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
834
843
|
function getWorkspacePath(issueId) {
|
|
@@ -855,8 +864,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
855
864
|
const { workspacePath, branch } = getWorkspacePath(issueId);
|
|
856
865
|
const issueLower = issueId.toLowerCase();
|
|
857
866
|
if (existsSync$1(workspacePath)) return workspacePath;
|
|
858
|
-
const { createWorkspace } = await import("./workspace-manager-
|
|
859
|
-
const { loadProjectsConfigSync } = await import("./projects-
|
|
867
|
+
const { createWorkspace } = await import("./workspace-manager-C1F3XsnS.js");
|
|
868
|
+
const { loadProjectsConfigSync } = await import("./projects-_n3Zui6K.js");
|
|
860
869
|
const { projects } = loadProjectsConfigSync();
|
|
861
870
|
const project = resolveProjectFromIssueSync(issueId);
|
|
862
871
|
if (!project) throw new WorkspaceCreateError({
|
|
@@ -891,7 +900,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
891
900
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
892
901
|
const issueLower = issueId.toLowerCase();
|
|
893
902
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
894
|
-
const { removeWorkspace } = await import("./workspace-manager-
|
|
903
|
+
const { removeWorkspace } = await import("./workspace-manager-C1F3XsnS.js");
|
|
895
904
|
const project = resolveProjectFromIssueSync(issueId);
|
|
896
905
|
if (!project) throw new WorkspaceCreateError({
|
|
897
906
|
id: issueId,
|
|
@@ -922,7 +931,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
922
931
|
try: async () => {
|
|
923
932
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
924
933
|
const issueLower = issueId.toLowerCase();
|
|
925
|
-
const { stopWorkspaceDocker } = await import("./workspace-manager-
|
|
934
|
+
const { stopWorkspaceDocker } = await import("./workspace-manager-C1F3XsnS.js");
|
|
926
935
|
await Effect.runPromise(stopWorkspaceDocker(workspacePath, issueLower));
|
|
927
936
|
},
|
|
928
937
|
catch: () => void 0
|
|
@@ -991,7 +1000,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
991
1000
|
join(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
|
|
992
1001
|
];
|
|
993
1002
|
if (!composePaths.find((p) => existsSync$1(p))) {
|
|
994
|
-
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-
|
|
1003
|
+
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-DMAbWqtQ.js");
|
|
995
1004
|
const ensure = ensureDevcontainerSync({
|
|
996
1005
|
workspacePath,
|
|
997
1006
|
issueId
|
|
@@ -1002,7 +1011,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
1002
1011
|
});
|
|
1003
1012
|
}
|
|
1004
1013
|
const finalComposePath = composePaths.find((p) => existsSync$1(p));
|
|
1005
|
-
if (finalComposePath) await execAsync$
|
|
1014
|
+
if (finalComposePath) await execAsync$11(`docker compose -f "${finalComposePath}" up -d --build`, {
|
|
1006
1015
|
cwd: dirname(finalComposePath),
|
|
1007
1016
|
timeout: 3e5
|
|
1008
1017
|
});
|
|
@@ -1148,7 +1157,7 @@ const OpenRouterServiceLive = Layer.effect(OpenRouterService, Effect.sync(() =>
|
|
|
1148
1157
|
//#endregion
|
|
1149
1158
|
//#region services/open.ts
|
|
1150
1159
|
init_src();
|
|
1151
|
-
const execAsync$
|
|
1160
|
+
const execAsync$10 = promisify(exec);
|
|
1152
1161
|
function getFileManagerCommand() {
|
|
1153
1162
|
switch (process.platform) {
|
|
1154
1163
|
case "linux": return "xdg-open";
|
|
@@ -1181,7 +1190,7 @@ function launchDetached(launch) {
|
|
|
1181
1190
|
}
|
|
1182
1191
|
async function isCommandAvailable(command) {
|
|
1183
1192
|
try {
|
|
1184
|
-
await execAsync$
|
|
1193
|
+
await execAsync$10(`${process.platform === "win32" ? "where" : "which"} ${command}`);
|
|
1185
1194
|
return true;
|
|
1186
1195
|
} catch {
|
|
1187
1196
|
return false;
|
|
@@ -4858,14 +4867,14 @@ init_codex_auth();
|
|
|
4858
4867
|
init_queries();
|
|
4859
4868
|
init_cliproxy();
|
|
4860
4869
|
init_tmux();
|
|
4861
|
-
init_config();
|
|
4870
|
+
init_config$1();
|
|
4862
4871
|
const reauthSessions = /* @__PURE__ */ new Map();
|
|
4863
4872
|
const SESSION_MAX_AGE_MS = 3600 * 1e3;
|
|
4864
|
-
const readJsonBody$
|
|
4873
|
+
const readJsonBody$20 = Effect.gen(function* () {
|
|
4865
4874
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
4866
4875
|
return text ? JSON.parse(text) : {};
|
|
4867
4876
|
});
|
|
4868
|
-
function rejectInvalidOrigin(request) {
|
|
4877
|
+
function rejectInvalidOrigin$1(request) {
|
|
4869
4878
|
const originCheck = validateOrigin$1(request);
|
|
4870
4879
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
4871
4880
|
return null;
|
|
@@ -4940,7 +4949,7 @@ async function getExistingLiveReauthSession() {
|
|
|
4940
4949
|
return null;
|
|
4941
4950
|
}
|
|
4942
4951
|
const postCodexReauthRoute = HttpRouter.add("POST", "/api/settings/codex-reauth", httpHandler(Effect.gen(function* () {
|
|
4943
|
-
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
4952
|
+
const originError = rejectInvalidOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
4944
4953
|
if (originError) return originError;
|
|
4945
4954
|
const existing = yield* Effect.promise(() => getExistingLiveReauthSession());
|
|
4946
4955
|
if (existing) {
|
|
@@ -4964,9 +4973,9 @@ const postCodexReauthRoute = HttpRouter.add("POST", "/api/settings/codex-reauth"
|
|
|
4964
4973
|
}, { headers: { "Set-Cookie": buildTerminalCookie(sessionName, terminalToken) } });
|
|
4965
4974
|
})));
|
|
4966
4975
|
const postCodexReauthStatusRoute = HttpRouter.add("POST", "/api/settings/codex-reauth/status", httpHandler(Effect.gen(function* () {
|
|
4967
|
-
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
4976
|
+
const originError = rejectInvalidOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
4968
4977
|
if (originError) return originError;
|
|
4969
|
-
const body = yield* readJsonBody$
|
|
4978
|
+
const body = yield* readJsonBody$20;
|
|
4970
4979
|
const sessionName = typeof body.session === "string" ? body.session : "";
|
|
4971
4980
|
const token = typeof body.token === "string" ? body.token : "";
|
|
4972
4981
|
const session = getLiveReauthSession(sessionName);
|
|
@@ -5491,6 +5500,7 @@ init_codex();
|
|
|
5491
5500
|
init_launcher_generator();
|
|
5492
5501
|
init_transcript_landing();
|
|
5493
5502
|
init_operator_interventions();
|
|
5503
|
+
init_messaging();
|
|
5494
5504
|
init_agents$1();
|
|
5495
5505
|
init_runtime_census();
|
|
5496
5506
|
const MINIMUM_NODE_MAJOR = 24;
|
|
@@ -17255,7 +17265,7 @@ var require_get_vercel_oidc_token = /* @__PURE__ */ __commonJSMin(((exports, mod
|
|
|
17255
17265
|
err = error;
|
|
17256
17266
|
}
|
|
17257
17267
|
try {
|
|
17258
|
-
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-
|
|
17268
|
+
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-D411CAq9.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-DrxwytsZ.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
|
|
17259
17269
|
if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
|
|
17260
17270
|
await refreshToken(options);
|
|
17261
17271
|
token = getVercelOidcTokenSync();
|
|
@@ -29572,7 +29582,7 @@ var GoogleCloudTranscription = class {
|
|
|
29572
29582
|
}
|
|
29573
29583
|
async start(apiKey, model) {
|
|
29574
29584
|
try {
|
|
29575
|
-
const { SpeechClient } = await import("./src-
|
|
29585
|
+
const { SpeechClient } = await import("./src-rac0Mepv.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
|
|
29576
29586
|
if (this.closed) return;
|
|
29577
29587
|
const stream = new SpeechClient({ apiKey }).streamingRecognize({
|
|
29578
29588
|
config: {
|
|
@@ -29836,7 +29846,7 @@ const DEFAULT_VOICE_SETTINGS = {
|
|
|
29836
29846
|
model: "gpt-4.1-mini"
|
|
29837
29847
|
}
|
|
29838
29848
|
};
|
|
29839
|
-
const readJsonBody$
|
|
29849
|
+
const readJsonBody$19 = Effect.gen(function* () {
|
|
29840
29850
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
29841
29851
|
const contentLength = Number(request.headers["content-length"] ?? 0);
|
|
29842
29852
|
if (Number.isFinite(contentLength) && contentLength > MAX_VOICE_SETTINGS_BODY_BYTES) return {
|
|
@@ -29959,7 +29969,7 @@ const getVoiceSettingsRoute = HttpRouter.add("GET", "/api/voice/settings", httpH
|
|
|
29959
29969
|
const putVoiceSettingsRoute = HttpRouter.add("PUT", "/api/voice/settings", httpHandler(Effect.gen(function* () {
|
|
29960
29970
|
const originError = requireTrustedOrigin$2(yield* HttpServerRequest.HttpServerRequest);
|
|
29961
29971
|
if (originError) return originError;
|
|
29962
|
-
const parsed = yield* readJsonBody$
|
|
29972
|
+
const parsed = yield* readJsonBody$19;
|
|
29963
29973
|
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 413 });
|
|
29964
29974
|
const body = parsed.body;
|
|
29965
29975
|
if (!isVoiceSettings(body)) return jsonResponse({ error: "Invalid voice settings payload" }, { status: 400 });
|
|
@@ -30252,12 +30262,219 @@ function streamAgentOutput(eventStore, agentId) {
|
|
|
30252
30262
|
})))));
|
|
30253
30263
|
}
|
|
30254
30264
|
//#endregion
|
|
30255
|
-
//#region services/
|
|
30265
|
+
//#region services/dashboard-db-task.ts
|
|
30256
30266
|
init_acp_conversation_parser();
|
|
30257
30267
|
init_codex_conversation_parser();
|
|
30258
30268
|
init_ohmypi_conversation_parser();
|
|
30259
30269
|
init_pi_conversation_parser();
|
|
30260
30270
|
init_conversation_service();
|
|
30271
|
+
init_control_settings();
|
|
30272
|
+
const MAX_PENDING_JOBS = 32;
|
|
30273
|
+
const SEMANTIC_SEARCH_TIMEOUT_MS = Number.parseInt(process.env["OVERDECK_SEMANTIC_SEARCH_TIMEOUT_MS"] ?? "15000", 10);
|
|
30274
|
+
const COALESCED_OPERATIONS = new Set([
|
|
30275
|
+
"scanConversations",
|
|
30276
|
+
"enrichSessions",
|
|
30277
|
+
"embedSessions",
|
|
30278
|
+
"searchSessionsSemantic",
|
|
30279
|
+
"listSubstrateBugWeights"
|
|
30280
|
+
]);
|
|
30281
|
+
const workers = {
|
|
30282
|
+
read: null,
|
|
30283
|
+
long: null,
|
|
30284
|
+
semantic: null
|
|
30285
|
+
};
|
|
30286
|
+
const pending = /* @__PURE__ */ new Map();
|
|
30287
|
+
const sharedJobs = /* @__PURE__ */ new Map();
|
|
30288
|
+
let latestSemanticJobId = null;
|
|
30289
|
+
function workerScriptUrl() {
|
|
30290
|
+
return import.meta.url.endsWith(".ts") ? new URL("./dashboard-db-worker.ts", import.meta.url) : new URL("./dashboard-db-worker.js", import.meta.url);
|
|
30291
|
+
}
|
|
30292
|
+
function failPendingForLane(lane, err) {
|
|
30293
|
+
for (const [id, job] of pending.entries()) {
|
|
30294
|
+
if (job.lane !== lane) continue;
|
|
30295
|
+
if (job.timeout) clearTimeout(job.timeout);
|
|
30296
|
+
job.reject(err);
|
|
30297
|
+
pending.delete(id);
|
|
30298
|
+
}
|
|
30299
|
+
for (const [key, job] of sharedJobs.entries()) if (job.lane === lane) sharedJobs.delete(key);
|
|
30300
|
+
if (lane === "semantic") latestSemanticJobId = null;
|
|
30301
|
+
}
|
|
30302
|
+
function stableStringify(value) {
|
|
30303
|
+
if (value == null || typeof value !== "object") return JSON.stringify(value);
|
|
30304
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
30305
|
+
return `{${Object.entries(value).filter(([, v]) => typeof v !== "function" && v !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
|
|
30306
|
+
}
|
|
30307
|
+
function coalescingKey(operation, payload) {
|
|
30308
|
+
if (!COALESCED_OPERATIONS.has(operation)) return null;
|
|
30309
|
+
return `${operation}:${stableStringify(payload)}`;
|
|
30310
|
+
}
|
|
30311
|
+
function workerLane(operation) {
|
|
30312
|
+
if (operation === "searchSessionsSemantic") return "semantic";
|
|
30313
|
+
return COALESCED_OPERATIONS.has(operation) ? "long" : "read";
|
|
30314
|
+
}
|
|
30315
|
+
function cancelOlderSemanticSearches() {
|
|
30316
|
+
if (!latestSemanticJobId && !workers.semantic) return;
|
|
30317
|
+
failPendingForLane("semantic", /* @__PURE__ */ new Error("Superseded by a newer semantic search"));
|
|
30318
|
+
workers.semantic?.terminate();
|
|
30319
|
+
workers.semantic = null;
|
|
30320
|
+
}
|
|
30321
|
+
function aggregateDiscoveredSessionCostByPayload(payload) {
|
|
30322
|
+
if (typeof payload === "string") return aggregateDiscoveredSessionCostBy(payload);
|
|
30323
|
+
const input = payload;
|
|
30324
|
+
return aggregateDiscoveredSessionCostBy(input?.groupBy ?? "workspace", input?.filter ?? {});
|
|
30325
|
+
}
|
|
30326
|
+
function getWorker(lane) {
|
|
30327
|
+
const existing = workers[lane];
|
|
30328
|
+
if (existing) return existing;
|
|
30329
|
+
const worker = new Worker(workerScriptUrl(), { execArgv: process.execArgv.filter((arg) => !arg.startsWith("--inspect")) });
|
|
30330
|
+
workers[lane] = worker;
|
|
30331
|
+
worker.on("message", (message) => {
|
|
30332
|
+
const job = pending.get(message.id);
|
|
30333
|
+
if (!job) return;
|
|
30334
|
+
if (message.progress !== void 0) {
|
|
30335
|
+
job.progressChain = job.progressChain.then(async () => {
|
|
30336
|
+
for (const listener of job.progressListeners) await listener(message.progress);
|
|
30337
|
+
});
|
|
30338
|
+
return;
|
|
30339
|
+
}
|
|
30340
|
+
pending.delete(message.id);
|
|
30341
|
+
if (job.timeout) clearTimeout(job.timeout);
|
|
30342
|
+
if (job.lane === "semantic" && latestSemanticJobId === message.id) latestSemanticJobId = null;
|
|
30343
|
+
if (message.ok) {
|
|
30344
|
+
job.progressChain.then(() => job.resolve(message.result), job.reject);
|
|
30345
|
+
return;
|
|
30346
|
+
}
|
|
30347
|
+
const err = message.error?.name === "CostThresholdError" ? new CostThresholdError(message.error.estimatedCost ?? 0, message.error.threshold ?? 0, message.error.sessionCount ?? 0) : new Error(message.error?.message ?? "Dashboard database worker failed");
|
|
30348
|
+
err.name = message.error?.name ?? "DashboardDatabaseWorkerError";
|
|
30349
|
+
err.stack = message.error?.stack;
|
|
30350
|
+
job.progressChain.then(() => job.reject(err), job.reject);
|
|
30351
|
+
});
|
|
30352
|
+
worker.on("error", (err) => {
|
|
30353
|
+
failPendingForLane(lane, err);
|
|
30354
|
+
if (workers[lane] === worker) workers[lane] = null;
|
|
30355
|
+
});
|
|
30356
|
+
worker.on("exit", (code) => {
|
|
30357
|
+
if (code !== 0) failPendingForLane(lane, /* @__PURE__ */ new Error(`Dashboard database ${lane} worker exited with code ${code}`));
|
|
30358
|
+
if (workers[lane] === worker) workers[lane] = null;
|
|
30359
|
+
});
|
|
30360
|
+
return worker;
|
|
30361
|
+
}
|
|
30362
|
+
async function runInline$1(operation, payload, onProgress) {
|
|
30363
|
+
switch (operation) {
|
|
30364
|
+
case "getDiscoveredStats": return getDiscoveredStats();
|
|
30365
|
+
case "listDiscoveredSessions": {
|
|
30366
|
+
const filter = payload;
|
|
30367
|
+
return {
|
|
30368
|
+
sessions: findDiscoveredSessions(filter),
|
|
30369
|
+
total: countDiscoveredSessions({
|
|
30370
|
+
...filter,
|
|
30371
|
+
limit: void 0,
|
|
30372
|
+
offset: void 0
|
|
30373
|
+
})
|
|
30374
|
+
};
|
|
30375
|
+
}
|
|
30376
|
+
case "listSessionsFeed": return listSessionsFeed(payload);
|
|
30377
|
+
case "getSessionsFeedFacets": return getSessionsFeedFacets(payload);
|
|
30378
|
+
case "getDiscoveredSessionById": return getDiscoveredSessionById(payload);
|
|
30379
|
+
case "aggregateDiscoveredSessionCost": return aggregateDiscoveredSessionCost(payload);
|
|
30380
|
+
case "aggregateDiscoveredSessionCostBy": return aggregateDiscoveredSessionCostByPayload(payload);
|
|
30381
|
+
case "searchSessions":
|
|
30382
|
+
case "searchSessionsSemantic": return searchSessions(payload);
|
|
30383
|
+
case "scanConversations": return scan({
|
|
30384
|
+
...payload,
|
|
30385
|
+
onProgress
|
|
30386
|
+
});
|
|
30387
|
+
case "enrichSessions": return enrichSessions({
|
|
30388
|
+
...payload,
|
|
30389
|
+
onProgress
|
|
30390
|
+
});
|
|
30391
|
+
case "embedSessions": return embedSessions({
|
|
30392
|
+
...payload,
|
|
30393
|
+
autoInstall: true,
|
|
30394
|
+
onProgress
|
|
30395
|
+
});
|
|
30396
|
+
case "getConversationByName": return getConversationByName(payload);
|
|
30397
|
+
case "getSetting": return getSetting(payload);
|
|
30398
|
+
case "setSetting": {
|
|
30399
|
+
const input = payload;
|
|
30400
|
+
setSetting(input.key, input.value);
|
|
30401
|
+
return null;
|
|
30402
|
+
}
|
|
30403
|
+
case "listSubstrateBugWeights": {
|
|
30404
|
+
const input = payload;
|
|
30405
|
+
return listSubstrateBugWeights(input.window, {
|
|
30406
|
+
limit: input.limit,
|
|
30407
|
+
offset: input.offset
|
|
30408
|
+
});
|
|
30409
|
+
}
|
|
30410
|
+
case "getArtifactBySlug": {
|
|
30411
|
+
const { getArtifactBySlugJob } = await import("./artifact-index-jobs-D1q_vR3V.js");
|
|
30412
|
+
return getArtifactBySlugJob(payload);
|
|
30413
|
+
}
|
|
30414
|
+
case "listArtifactsForWorkspaceOrIssue": {
|
|
30415
|
+
const { listArtifactsForWorkspaceOrIssueJob } = await import("./artifact-index-jobs-D1q_vR3V.js");
|
|
30416
|
+
return listArtifactsForWorkspaceOrIssueJob(payload);
|
|
30417
|
+
}
|
|
30418
|
+
case "unshareArtifactBySlug": {
|
|
30419
|
+
const { unshareArtifactBySlugJob } = await import("./artifact-index-jobs-D1q_vR3V.js");
|
|
30420
|
+
return unshareArtifactBySlugJob(payload);
|
|
30421
|
+
}
|
|
30422
|
+
}
|
|
30423
|
+
}
|
|
30424
|
+
function runDashboardDbJob(operation, payload, onProgress) {
|
|
30425
|
+
if (import.meta.url.endsWith(".ts") && process.env["VITEST"]) return runInline$1(operation, payload, onProgress);
|
|
30426
|
+
const key = coalescingKey(operation, payload);
|
|
30427
|
+
const existing = key ? sharedJobs.get(key) : void 0;
|
|
30428
|
+
if (existing) {
|
|
30429
|
+
if (onProgress) existing.progressListeners.add(onProgress);
|
|
30430
|
+
return existing.promise;
|
|
30431
|
+
}
|
|
30432
|
+
if (pending.size >= MAX_PENDING_JOBS) return Promise.reject(/* @__PURE__ */ new Error("Dashboard database worker queue is full"));
|
|
30433
|
+
const id = randomUUID$1();
|
|
30434
|
+
const lane = workerLane(operation);
|
|
30435
|
+
if (operation === "searchSessionsSemantic") {
|
|
30436
|
+
cancelOlderSemanticSearches();
|
|
30437
|
+
latestSemanticJobId = id;
|
|
30438
|
+
}
|
|
30439
|
+
const progressListeners = /* @__PURE__ */ new Set();
|
|
30440
|
+
if (onProgress) progressListeners.add(onProgress);
|
|
30441
|
+
const promise = new Promise((resolve, reject) => {
|
|
30442
|
+
const timeout = operation === "searchSessionsSemantic" ? setTimeout(() => {
|
|
30443
|
+
if (!pending.get(id)) return;
|
|
30444
|
+
pending.delete(id);
|
|
30445
|
+
for (const [sharedKey, sharedJob] of sharedJobs.entries()) if (sharedJob.promise === promise) sharedJobs.delete(sharedKey);
|
|
30446
|
+
if (latestSemanticJobId === id) latestSemanticJobId = null;
|
|
30447
|
+
reject(/* @__PURE__ */ new Error("Semantic search timed out"));
|
|
30448
|
+
workers.semantic?.terminate();
|
|
30449
|
+
workers.semantic = null;
|
|
30450
|
+
}, Number.isFinite(SEMANTIC_SEARCH_TIMEOUT_MS) ? SEMANTIC_SEARCH_TIMEOUT_MS : 15e3) : null;
|
|
30451
|
+
pending.set(id, {
|
|
30452
|
+
lane,
|
|
30453
|
+
operation,
|
|
30454
|
+
resolve,
|
|
30455
|
+
reject,
|
|
30456
|
+
progressListeners,
|
|
30457
|
+
progressChain: Promise.resolve(),
|
|
30458
|
+
timeout
|
|
30459
|
+
});
|
|
30460
|
+
getWorker(lane).postMessage({
|
|
30461
|
+
id,
|
|
30462
|
+
operation,
|
|
30463
|
+
payload
|
|
30464
|
+
});
|
|
30465
|
+
});
|
|
30466
|
+
if (key) {
|
|
30467
|
+
sharedJobs.set(key, {
|
|
30468
|
+
lane,
|
|
30469
|
+
promise,
|
|
30470
|
+
progressListeners
|
|
30471
|
+
});
|
|
30472
|
+
promise.then(() => sharedJobs.delete(key), () => sharedJobs.delete(key));
|
|
30473
|
+
}
|
|
30474
|
+
return promise;
|
|
30475
|
+
}
|
|
30476
|
+
//#endregion
|
|
30477
|
+
//#region services/read-workspace-file.ts
|
|
30261
30478
|
init_src();
|
|
30262
30479
|
init_projects();
|
|
30263
30480
|
const MAX_WORKSPACE_FILE_BYTES = 256 * 1024;
|
|
@@ -30590,6 +30807,98 @@ function normalizeSessionsFeedFilter(input) {
|
|
|
30590
30807
|
};
|
|
30591
30808
|
}
|
|
30592
30809
|
//#endregion
|
|
30810
|
+
//#region services/conversation/subagents.ts
|
|
30811
|
+
/**
|
|
30812
|
+
* Read-only discovery and streaming support for Claude Code conversation subagents.
|
|
30813
|
+
* See docs/CONVERSATION-SUBAGENTS.md for the file layout and transport contract.
|
|
30814
|
+
*/
|
|
30815
|
+
const metaCache = /* @__PURE__ */ new Map();
|
|
30816
|
+
const SAFE_AGENT_ID = /^[A-Za-z0-9_-]+$/;
|
|
30817
|
+
function subagentsDirFor(sessionFile) {
|
|
30818
|
+
return join(sessionFile.endsWith(".jsonl") ? sessionFile.slice(0, -6) : sessionFile, "subagents");
|
|
30819
|
+
}
|
|
30820
|
+
function parseMeta(agentId, value) {
|
|
30821
|
+
if (typeof value !== "object" || value === null || !("agentType" in value) || typeof value.agentType !== "string" || !("description" in value) || typeof value.description !== "string" || !("toolUseId" in value) || typeof value.toolUseId !== "string" || !("spawnDepth" in value) || typeof value.spawnDepth !== "number") throw new Error("invalid subagent metadata");
|
|
30822
|
+
return {
|
|
30823
|
+
agentId,
|
|
30824
|
+
agentType: value.agentType,
|
|
30825
|
+
description: value.description,
|
|
30826
|
+
toolUseId: value.toolUseId,
|
|
30827
|
+
spawnDepth: value.spawnDepth
|
|
30828
|
+
};
|
|
30829
|
+
}
|
|
30830
|
+
async function readMeta(metaPath, agentId) {
|
|
30831
|
+
const cached = metaCache.get(metaPath);
|
|
30832
|
+
if (cached !== void 0) return cached;
|
|
30833
|
+
try {
|
|
30834
|
+
const parsed = parseMeta(agentId, JSON.parse(await readFile(metaPath, "utf8")));
|
|
30835
|
+
metaCache.set(metaPath, parsed);
|
|
30836
|
+
return parsed;
|
|
30837
|
+
} catch (error) {
|
|
30838
|
+
console.warn(`[conversation-subagents] Failed to parse ${metaPath}:`, error);
|
|
30839
|
+
return null;
|
|
30840
|
+
}
|
|
30841
|
+
}
|
|
30842
|
+
async function listSubagentMetas(sessionFile) {
|
|
30843
|
+
const subagentsDir = subagentsDirFor(sessionFile);
|
|
30844
|
+
let entries;
|
|
30845
|
+
try {
|
|
30846
|
+
entries = await readdir(subagentsDir);
|
|
30847
|
+
} catch (error) {
|
|
30848
|
+
if (error.code === "ENOENT") return [];
|
|
30849
|
+
throw error;
|
|
30850
|
+
}
|
|
30851
|
+
const metas = [];
|
|
30852
|
+
for (const entry of entries.sort()) {
|
|
30853
|
+
const match = /^agent-(.+)\.meta\.json$/.exec(entry);
|
|
30854
|
+
if (!match?.[1]) continue;
|
|
30855
|
+
const meta = await readMeta(join(subagentsDir, entry), match[1]);
|
|
30856
|
+
if (meta) metas.push(meta);
|
|
30857
|
+
}
|
|
30858
|
+
return metas;
|
|
30859
|
+
}
|
|
30860
|
+
function subagentTranscriptPath(sessionFile, agentId) {
|
|
30861
|
+
if (!SAFE_AGENT_ID.test(agentId)) return null;
|
|
30862
|
+
const subagentsDir = resolve(subagentsDirFor(sessionFile));
|
|
30863
|
+
const transcriptPath = resolve(subagentsDir, `agent-${agentId}.jsonl`);
|
|
30864
|
+
if (dirname(transcriptPath) !== subagentsDir || !transcriptPath.startsWith(`${subagentsDir}${sep}`)) return null;
|
|
30865
|
+
return transcriptPath;
|
|
30866
|
+
}
|
|
30867
|
+
async function startSubagentListPolling(sessionFile, pendingToolUseIds, emit) {
|
|
30868
|
+
let stopped = false;
|
|
30869
|
+
let lastSerialized = null;
|
|
30870
|
+
let refreshChain = Promise.resolve();
|
|
30871
|
+
const refresh = () => {
|
|
30872
|
+
refreshChain = refreshChain.then(async () => {
|
|
30873
|
+
if (stopped) return;
|
|
30874
|
+
const pending = pendingToolUseIds();
|
|
30875
|
+
const subagents = (await listSubagentMetas(sessionFile)).map((meta) => ({
|
|
30876
|
+
...meta,
|
|
30877
|
+
status: pending.has(meta.toolUseId) ? "running" : "done"
|
|
30878
|
+
}));
|
|
30879
|
+
const serialized = JSON.stringify(subagents);
|
|
30880
|
+
if (serialized === lastSerialized) return;
|
|
30881
|
+
lastSerialized = serialized;
|
|
30882
|
+
emit({
|
|
30883
|
+
kind: "subagents",
|
|
30884
|
+
subagents
|
|
30885
|
+
});
|
|
30886
|
+
}).catch((error) => {
|
|
30887
|
+
console.warn(`[conversation-subagents] Failed to refresh ${sessionFile}:`, error);
|
|
30888
|
+
});
|
|
30889
|
+
return refreshChain;
|
|
30890
|
+
};
|
|
30891
|
+
await refresh();
|
|
30892
|
+
const interval = setInterval(() => void refresh(), 2e3);
|
|
30893
|
+
return {
|
|
30894
|
+
refresh,
|
|
30895
|
+
stop: () => {
|
|
30896
|
+
stopped = true;
|
|
30897
|
+
clearInterval(interval);
|
|
30898
|
+
}
|
|
30899
|
+
};
|
|
30900
|
+
}
|
|
30901
|
+
//#endregion
|
|
30593
30902
|
//#region ws-rpc.ts
|
|
30594
30903
|
/**
|
|
30595
30904
|
* WebSocket RPC handlers — implements PanRpcGroup using Effect (PAN-428 B5)
|
|
@@ -30599,6 +30908,7 @@ function normalizeSessionsFeedFilter(input) {
|
|
|
30599
30908
|
* are implemented via TerminalService (dual-runtime PTY, B20).
|
|
30600
30909
|
*/
|
|
30601
30910
|
init_src();
|
|
30911
|
+
init_conversations();
|
|
30602
30912
|
init_paths();
|
|
30603
30913
|
init_projects();
|
|
30604
30914
|
function storedToDomainEvent(stored) {
|
|
@@ -31101,7 +31411,8 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
|
|
|
31101
31411
|
if (getHarnessBehavior(conv.harness).transcriptKind !== "claude-jsonl") return conversationDiscoveringStream();
|
|
31102
31412
|
const launcherTmuxSession = conv.tmuxSession;
|
|
31103
31413
|
const resolvedSessionId = (launcherTmuxSession ? yield* Effect.promise(() => readLauncherPinnedSessionId(launcherTmuxSession)) : null) ?? conv.claudeSessionId;
|
|
31104
|
-
const
|
|
31414
|
+
const parentSessionFile = resolvedSessionId ? sessionFilePath(conv.cwd, resolvedSessionId) : null;
|
|
31415
|
+
const sessionFile = parentSessionFile && input.agentId ? subagentTranscriptPath(parentSessionFile, input.agentId) : parentSessionFile;
|
|
31105
31416
|
const model = conv.model ?? null;
|
|
31106
31417
|
if (!sessionFile) return conversationDiscoveringStream();
|
|
31107
31418
|
if (isPiSessionFile(sessionFile)) return conversationDiscoveringStream();
|
|
@@ -31140,11 +31451,15 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
|
|
|
31140
31451
|
compactBoundaries: initial.compactBoundaries && initial.compactBoundaries.length > 0 ? initial.compactBoundaries : void 0,
|
|
31141
31452
|
contextUsage: currentContextUsage
|
|
31142
31453
|
});
|
|
31143
|
-
|
|
31454
|
+
let pendingSubagentToolUseIds = new Set(initial.pendingToolUse.keys());
|
|
31455
|
+
const subagentPoller = input.agentId ? null : await startSubagentListPolling(sessionFile, () => pendingSubagentToolUseIds, offer);
|
|
31456
|
+
const handle = watchConversation(sessionFile, (result) => {
|
|
31144
31457
|
const gate = gateSnapshotEmission(result.byteOffset < currentByteOffset, result.messages.length, highWaterCount);
|
|
31145
31458
|
highWaterCount = gate.highWaterCount;
|
|
31146
31459
|
currentByteOffset = result.byteOffset;
|
|
31147
31460
|
currentContextUsage = contextUsageFromParseResult(result, model);
|
|
31461
|
+
pendingSubagentToolUseIds = new Set(result.pendingToolUse.keys());
|
|
31462
|
+
subagentPoller?.refresh();
|
|
31148
31463
|
if (gate.suppressedShrink) console.warn(`[conv-stream] suppressed shrinking reset for ${input.conversationName}: byteOffset ${currentByteOffset} (re-parsed ${result.messages.length} msgs) < high-water ${highWaterCount} — treating as transient rewrite, merging instead of replacing`);
|
|
31149
31464
|
offer({
|
|
31150
31465
|
kind: "messages",
|
|
@@ -31160,6 +31475,10 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
|
|
|
31160
31475
|
byteOffset: initial.byteOffset,
|
|
31161
31476
|
priorState
|
|
31162
31477
|
});
|
|
31478
|
+
return { stop() {
|
|
31479
|
+
handle.stop();
|
|
31480
|
+
subagentPoller?.stop();
|
|
31481
|
+
} };
|
|
31163
31482
|
}), (handle) => Effect.sync(() => {
|
|
31164
31483
|
handle.stop();
|
|
31165
31484
|
})));
|
|
@@ -31372,7 +31691,6 @@ init_state_home();
|
|
|
31372
31691
|
init_pan_dir();
|
|
31373
31692
|
init_in_flight_guard();
|
|
31374
31693
|
init_remote_agents();
|
|
31375
|
-
init_dag();
|
|
31376
31694
|
init_swarm_readiness();
|
|
31377
31695
|
var PlanQualityLintError = class extends Error {
|
|
31378
31696
|
constructor(issues) {
|
|
@@ -31487,9 +31805,6 @@ const PARALLEL_SAFE_REASON_FIELDS = [
|
|
|
31487
31805
|
"readinessReason",
|
|
31488
31806
|
"readiness_reason"
|
|
31489
31807
|
];
|
|
31490
|
-
const FILE_SIZE_BASELINE_PATH = "scripts/file-size-baseline.txt";
|
|
31491
|
-
const FILE_SIZE_RECONCILIATION_PATTERN = /\b(?:drop(?:ped|ping)?|lower(?:ed|ing)?|reconcil(?:e|ed|es|ing|iation)|remov(?:e|ed|es|ing)|updat(?:e|ed|es|ing))\b/i;
|
|
31492
|
-
const FILE_SIZE_LINT_COMMAND_PATTERN = /(?:\b(?:bun|npm|pnpm|yarn)\s+(?:run\s+)?lint(?::file-size)?(?=$|[\s;&|])|scripts\/lint-file-size\.sh)/i;
|
|
31493
31808
|
function issue(itemId, rule, message) {
|
|
31494
31809
|
return {
|
|
31495
31810
|
itemId,
|
|
@@ -31630,44 +31945,6 @@ function lintDocsCoverage(doc) {
|
|
|
31630
31945
|
if (doc.plan.items.filter((item) => item.status !== "cancelled").some(documentsSomething)) return [];
|
|
31631
31946
|
return [issue(null, "docs-item-missing", "Plan has no documentation work item: no active item sets metadata.kind \"docs\" or names a documentation file (.md/.mdx, or a docs/ path) in metadata.files_scope. Add the item naming the exact doc files it touches, or set plan.metadata.docsJustification to state why the change alters no documented surface.")];
|
|
31632
31947
|
}
|
|
31633
|
-
function itemSearchText(item) {
|
|
31634
|
-
return [
|
|
31635
|
-
item.title,
|
|
31636
|
-
item.narrative?.Action,
|
|
31637
|
-
...item.metadata?.expected_outputs ?? [],
|
|
31638
|
-
...acceptanceCriteria(item).map((ac) => ac.title)
|
|
31639
|
-
].filter((value) => typeof value === "string").join("\n");
|
|
31640
|
-
}
|
|
31641
|
-
function scopeIncludesPath(item, filePath) {
|
|
31642
|
-
return (item.metadata?.files_scope ?? []).some((scope) => compileGlob(scope).regex.test(filePath));
|
|
31643
|
-
}
|
|
31644
|
-
function requiresFileSizeLint(item) {
|
|
31645
|
-
if ((item.metadata?.verify_commands ?? []).some((command) => typeof command === "string" && FILE_SIZE_LINT_COMMAND_PATTERN.test(command))) return true;
|
|
31646
|
-
return acceptanceCriteria(item).some((ac) => FILE_SIZE_LINT_COMMAND_PATTERN.test(ac.title));
|
|
31647
|
-
}
|
|
31648
|
-
function lintDeferredFileSizeRatchet(doc) {
|
|
31649
|
-
const activeItems = doc.plan.items.filter((item) => item.status !== "cancelled");
|
|
31650
|
-
const readiness = analyzeSwarmReadiness(doc);
|
|
31651
|
-
const issues = [];
|
|
31652
|
-
const seen = /* @__PURE__ */ new Set();
|
|
31653
|
-
for (const reconciliation of activeItems) {
|
|
31654
|
-
if (!scopeIncludesPath(reconciliation, FILE_SIZE_BASELINE_PATH)) continue;
|
|
31655
|
-
const reconciliationText = itemSearchText(reconciliation);
|
|
31656
|
-
if (!reconciliationText.includes(FILE_SIZE_BASELINE_PATH) || !FILE_SIZE_RECONCILIATION_PATTERN.test(reconciliationText)) continue;
|
|
31657
|
-
const reconciledSourceScopes = (reconciliation.metadata?.files_scope ?? []).filter((scope) => scope.startsWith("src/") && reconciliationText.includes(scope));
|
|
31658
|
-
if (reconciledSourceScopes.length === 0) continue;
|
|
31659
|
-
for (const candidate of activeItems) {
|
|
31660
|
-
if (candidate.id === reconciliation.id || scopeIncludesPath(candidate, FILE_SIZE_BASELINE_PATH) || !requiresFileSizeLint(candidate)) continue;
|
|
31661
|
-
const deferredFile = (readiness.overlapMatrix[candidate.id]?.[reconciliation.id] ?? []).find((filePath) => reconciledSourceScopes.some((scope) => compileGlob(scope).regex.test(filePath)));
|
|
31662
|
-
if (!deferredFile) continue;
|
|
31663
|
-
const key = `${candidate.id}\0${deferredFile}`;
|
|
31664
|
-
if (seen.has(key)) continue;
|
|
31665
|
-
seen.add(key);
|
|
31666
|
-
issues.push(issue(candidate.id, "deferred-file-size-ratchet", `Item ${candidate.id} requires file-size-backed lint after changing baselined file ${deferredFile}, but defers ${FILE_SIZE_BASELINE_PATH} reconciliation to item ${reconciliation.id}. Include the baseline in ${candidate.id} metadata.files_scope and reconcile it in the same commit, or use an intermediate verification command that excludes the file-size ratchet. For an active plan, return the issue to planning, preserve stable item IDs, apply one of these repairs, and re-finalize before rerunning inspection.`));
|
|
31667
|
-
}
|
|
31668
|
-
}
|
|
31669
|
-
return issues;
|
|
31670
|
-
}
|
|
31671
31948
|
function orderedPairKey(left, right) {
|
|
31672
31949
|
return [left, right].sort().join("\0");
|
|
31673
31950
|
}
|
|
@@ -31723,13 +32000,34 @@ function hasBlocksCycle(doc) {
|
|
|
31723
32000
|
}
|
|
31724
32001
|
return visited < itemIds.size;
|
|
31725
32002
|
}
|
|
32003
|
+
function lintProjectedSurface(doc) {
|
|
32004
|
+
const issues = [];
|
|
32005
|
+
const files = /* @__PURE__ */ new Set();
|
|
32006
|
+
const subsystems = /* @__PURE__ */ new Set();
|
|
32007
|
+
for (const item of doc.plan.items) {
|
|
32008
|
+
if (item.status === "cancelled") continue;
|
|
32009
|
+
const filesScope = item.metadata?.files_scope;
|
|
32010
|
+
if (Array.isArray(filesScope)) for (const scope of filesScope) {
|
|
32011
|
+
const normalized = scope.replace(/\/\*+$/, "");
|
|
32012
|
+
files.add(normalized);
|
|
32013
|
+
const parts = normalized.split("/");
|
|
32014
|
+
if (parts.length >= 2) subsystems.add(`${parts[0]}/${parts[1]}`);
|
|
32015
|
+
else if (parts.length === 1) subsystems.add(parts[0]);
|
|
32016
|
+
}
|
|
32017
|
+
}
|
|
32018
|
+
const fileCount = files.size;
|
|
32019
|
+
const subsystemCount = subsystems.size;
|
|
32020
|
+
const hasJustification = typeof doc.plan.metadata?.sizeJustification === "string" && doc.plan.metadata.sizeJustification.trim().length > 0;
|
|
32021
|
+
if ((fileCount > 25 || subsystemCount > 6) && !hasJustification) issues.push(issue(null, "projected-surface", `Plan touches ${fileCount} files (limit: 25) and ${subsystemCount} subsystems (limit: 6). Split into independently-shippable sibling issues per the swarm contract, or set plan.metadata.sizeJustification for genuinely inseparable work.`));
|
|
32022
|
+
return issues;
|
|
32023
|
+
}
|
|
31726
32024
|
function lintPlanQuality(doc, options = {}) {
|
|
31727
32025
|
return [
|
|
32026
|
+
...lintProjectedSurface(doc),
|
|
31728
32027
|
...doc.plan.items.flatMap((item) => item.status === "cancelled" ? [] : lintItem(item)),
|
|
31729
32028
|
...lintDocumentReferences(doc),
|
|
31730
32029
|
...lintDocsCoverage(doc),
|
|
31731
32030
|
...lintTraceCoverage(doc, options.prdText),
|
|
31732
|
-
...lintDeferredFileSizeRatchet(doc),
|
|
31733
32031
|
...lintOverlapAudit(doc, options)
|
|
31734
32032
|
];
|
|
31735
32033
|
}
|
|
@@ -31746,7 +32044,7 @@ const execFileAsync$18 = promisify(execFile);
|
|
|
31746
32044
|
async function loadTrackerIssues() {
|
|
31747
32045
|
const map = /* @__PURE__ */ new Map();
|
|
31748
32046
|
try {
|
|
31749
|
-
const { getSharedIssueService } = await import("./issue-service-singleton-
|
|
32047
|
+
const { getSharedIssueService } = await import("./issue-service-singleton-B2wXiIlw.js");
|
|
31750
32048
|
const issues = (await getSharedIssueService()).getIssues();
|
|
31751
32049
|
for (const issue of issues) if (issue.identifier) map.set(issue.identifier.toUpperCase(), issue);
|
|
31752
32050
|
} catch {}
|
|
@@ -31769,7 +32067,7 @@ async function loadDockerContainers() {
|
|
|
31769
32067
|
}
|
|
31770
32068
|
async function loadActiveRemoteAgentStates() {
|
|
31771
32069
|
try {
|
|
31772
|
-
const { listActiveRemoteAgentStates } = await import("./remote-agents-
|
|
32070
|
+
const { listActiveRemoteAgentStates } = await import("./remote-agents-CLZB3Coc.js");
|
|
31773
32071
|
return listActiveRemoteAgentStates();
|
|
31774
32072
|
} catch {
|
|
31775
32073
|
return [];
|
|
@@ -31824,9 +32122,11 @@ function refreshMembershipSnapshot(project, snapshot, getMembership, now) {
|
|
|
31824
32122
|
snapshot.value = value;
|
|
31825
32123
|
snapshot.refreshedAt = now();
|
|
31826
32124
|
snapshot.lastError = void 0;
|
|
32125
|
+
snapshot.lastErrorReason = void 0;
|
|
31827
32126
|
snapshot.lastErrorAt = void 0;
|
|
31828
32127
|
}).catch((error) => {
|
|
31829
32128
|
snapshot.lastError = error instanceof Error ? error.message : String(error);
|
|
32129
|
+
snapshot.lastErrorReason = error instanceof PipelineMembershipUnavailableError ? error.reason : "gather_failed";
|
|
31830
32130
|
snapshot.lastErrorAt = now();
|
|
31831
32131
|
console.warn(`[pipeline-membership] refresh failed for ${project.name ?? project.path}; keeping last-good snapshot:`, snapshot.lastError);
|
|
31832
32132
|
}).finally(() => {
|
|
@@ -31844,7 +32144,8 @@ function readPipelineMembershipSnapshotsForProjects(projects) {
|
|
|
31844
32144
|
};
|
|
31845
32145
|
return {
|
|
31846
32146
|
project,
|
|
31847
|
-
error: /* @__PURE__ */ new Error(snapshot?.lastError ? `Pipeline membership refresh failed: ${snapshot.lastError}` : "Pipeline membership snapshot is loading")
|
|
32147
|
+
error: /* @__PURE__ */ new Error(snapshot?.lastError ? `Pipeline membership refresh failed: ${snapshot.lastError}` : "Pipeline membership snapshot is loading"),
|
|
32148
|
+
unavailableReason: snapshot?.lastErrorReason
|
|
31848
32149
|
};
|
|
31849
32150
|
});
|
|
31850
32151
|
}
|
|
@@ -32927,15 +33228,19 @@ async function completePlanningAutoSpawn(options) {
|
|
|
32927
33228
|
},
|
|
32928
33229
|
body: JSON.stringify({
|
|
32929
33230
|
issueId: options.issueId,
|
|
32930
|
-
role: "work"
|
|
33231
|
+
role: "work",
|
|
33232
|
+
startedBy: "planning-auto-handoff",
|
|
33233
|
+
autoSpawnConsentRequired: true
|
|
32931
33234
|
})
|
|
32932
33235
|
});
|
|
32933
33236
|
const body = await response.json().catch(() => ({}));
|
|
32934
33237
|
const agentId = typeof body["agentId"] === "string" ? body["agentId"] : `agent-${options.issueId.toLowerCase()}`;
|
|
32935
33238
|
if (response.ok && body["success"] !== false) {
|
|
32936
|
-
|
|
33239
|
+
const workAgentQueued = body["startingContainers"] === true;
|
|
33240
|
+
emitCompletePlanningPhase(options.issueId, "autoSpawn", "success", workAgentQueued ? "container startup queued before work-agent spawn" : "work agent spawn requested", { agentId });
|
|
32937
33241
|
return {
|
|
32938
33242
|
workAgentSpawned: true,
|
|
33243
|
+
...workAgentQueued ? { workAgentQueued: true } : {},
|
|
32939
33244
|
workAgentSession: agentId
|
|
32940
33245
|
};
|
|
32941
33246
|
}
|
|
@@ -32945,9 +33250,14 @@ async function completePlanningAutoSpawn(options) {
|
|
|
32945
33250
|
const recovery = await (options.fetchImpl ?? fetch)(new URL(`/api/workspaces/${encodeURIComponent(options.issueId)}/rebuild-and-start`, dashboardOrigin), {
|
|
32946
33251
|
method: "POST",
|
|
32947
33252
|
headers: {
|
|
33253
|
+
"content-type": "application/json",
|
|
32948
33254
|
origin: dashboardOrigin,
|
|
32949
33255
|
...internalTokenHeaders
|
|
32950
|
-
}
|
|
33256
|
+
},
|
|
33257
|
+
body: JSON.stringify({
|
|
33258
|
+
startedBy: "planning-auto-handoff",
|
|
33259
|
+
autoSpawnConsentRequired: true
|
|
33260
|
+
})
|
|
32951
33261
|
});
|
|
32952
33262
|
const recoveryBody = await recovery.json().catch(() => ({}));
|
|
32953
33263
|
if (recovery.ok && recoveryBody["success"] !== false) {
|
|
@@ -33008,7 +33318,7 @@ async function completePlanningForIssue(options) {
|
|
|
33008
33318
|
const { request, id, body, eventStore, linear, lifecycle } = options;
|
|
33009
33319
|
const skipKill = body?.skipKill === true;
|
|
33010
33320
|
const bodyAutoSpawn = body?.autoSpawn;
|
|
33011
|
-
const autoSpawn = resolveAutoSpawnOnFinalize(bodyAutoSpawn, id);
|
|
33321
|
+
const autoSpawn = await resolveAutoSpawnOnFinalize(bodyAutoSpawn, id);
|
|
33012
33322
|
const noPrd = body?.noPrd === true;
|
|
33013
33323
|
if (bodyAutoSpawn === true) {
|
|
33014
33324
|
const originCheck = validateOrigin$1(request);
|
|
@@ -33096,8 +33406,10 @@ async function completePlanningForIssue(options) {
|
|
|
33096
33406
|
workspacePath,
|
|
33097
33407
|
issueId: id
|
|
33098
33408
|
}));
|
|
33099
|
-
if (draftPromotion.promoted)
|
|
33100
|
-
|
|
33409
|
+
if (draftPromotion.promoted) {
|
|
33410
|
+
const removalNote = draftPromotion.sourceRemoved ? "" : " (workspace copy left in place)";
|
|
33411
|
+
emitCompletePlanningPhase(id, "prdPromote", "success", `promoted ${draftPromotion.source} -> ${draftPromotion.path}${removalNote}`);
|
|
33412
|
+
} else emitCompletePlanningPhase(id, "prdPromote", "skipped", draftPromotion.reason);
|
|
33101
33413
|
} catch (error) {
|
|
33102
33414
|
const reason = error instanceof Error ? error.message : String(error);
|
|
33103
33415
|
emitCompletePlanningPhase(id, "prdPromote", "failure", reason);
|
|
@@ -33374,6 +33686,10 @@ async function reopenWorkspaceStatePromise(issueId, workspacePath, options = {})
|
|
|
33374
33686
|
});
|
|
33375
33687
|
result.specialistStatesReset = true;
|
|
33376
33688
|
const resolved = resolveProjectFromIssueSync(issueId);
|
|
33689
|
+
if (resolved) {
|
|
33690
|
+
const project = getProjectSync(resolved.projectKey);
|
|
33691
|
+
if (project) clearRecordPipelineClosedOutSync(project, issueId.toUpperCase());
|
|
33692
|
+
}
|
|
33377
33693
|
if (resolved) try {
|
|
33378
33694
|
const noteParts = [`Reopened on ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`];
|
|
33379
33695
|
if (options.reason) noteParts.push(`reason: ${options.reason}`);
|
|
@@ -33408,7 +33724,7 @@ init_projects();
|
|
|
33408
33724
|
init_tracker_utils();
|
|
33409
33725
|
init_agents$1();
|
|
33410
33726
|
init_issue_id();
|
|
33411
|
-
const execAsync$
|
|
33727
|
+
const execAsync$9 = promisify(exec);
|
|
33412
33728
|
const execFileAsync$15 = promisify(execFile);
|
|
33413
33729
|
function isGitHubIssue$4(issueId) {
|
|
33414
33730
|
const resolved = resolveGitHubIssueSync(issueId);
|
|
@@ -33480,7 +33796,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
|
|
|
33480
33796
|
timeout: 15e3
|
|
33481
33797
|
});
|
|
33482
33798
|
try {
|
|
33483
|
-
const { setReviewStatusSync } = await import("./review-status-
|
|
33799
|
+
const { setReviewStatusSync } = await import("./review-status-Dma9SFaN.js");
|
|
33484
33800
|
setReviewStatusSync(issueId.toUpperCase(), { prUrl: void 0 });
|
|
33485
33801
|
} catch {}
|
|
33486
33802
|
return [`Closed PR #${prNumber} on ${githubCheck.owner}/${githubCheck.repo}`];
|
|
@@ -33534,7 +33850,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33534
33850
|
const { ctx, projectConfig } = buildLifecycleContext(id, getIssueDataService$8().getIssueSource(id) ?? void 0);
|
|
33535
33851
|
const deleteWorkspace = opts.deleteWorkspace ?? true;
|
|
33536
33852
|
cleanupLog.push(...await closeIssuePullRequest(id, mode === "cancel" ? "Canceled via Overdeck" : "Reset to Todo via Overdeck"));
|
|
33537
|
-
const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-
|
|
33853
|
+
const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-B3s4sM1G.js");
|
|
33538
33854
|
const workflow = mode === "cancel" ? cancelIssueWorkflow : resetToTodo;
|
|
33539
33855
|
const result = await Effect.runPromise(workflow(ctx, {
|
|
33540
33856
|
deleteWorkspace,
|
|
@@ -33549,7 +33865,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33549
33865
|
}));
|
|
33550
33866
|
cleanupLog.push(...result.steps.flatMap((step) => step.details || [step.error].filter(Boolean)));
|
|
33551
33867
|
if (mode === "cancel") try {
|
|
33552
|
-
const { transitionXBriefOnMain } = await import("./lifecycle-io-
|
|
33868
|
+
const { transitionXBriefOnMain } = await import("./lifecycle-io-CzTHEooc.js");
|
|
33553
33869
|
const tx = await Effect.runPromise(transitionXBriefOnMain(ctx.projectPath, id, "cancelled", "cancelled", `scope: cancel ${id.toUpperCase()} xBRIEF`));
|
|
33554
33870
|
if (tx.moved) cleanupLog.push(`xBRIEF moved ${tx.fromDir} → cancelled`);
|
|
33555
33871
|
if (tx.committed) cleanupLog.push(`Committed xBRIEF cancellation on main`);
|
|
@@ -33557,8 +33873,8 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33557
33873
|
cleanupLog.push(`xBRIEF cancel transition failed (non-fatal): ${err?.message ?? err}`);
|
|
33558
33874
|
}
|
|
33559
33875
|
try {
|
|
33560
|
-
const { killAllReviewerSessions } = await import("./review-agent-
|
|
33561
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
33876
|
+
const { killAllReviewerSessions } = await import("./review-agent-BTCNkq2h.js");
|
|
33877
|
+
const { resolveProjectFromIssueSync } = await import("./projects-_n3Zui6K.js");
|
|
33562
33878
|
const projectKey = resolveProjectFromIssueSync(id)?.projectKey;
|
|
33563
33879
|
if (projectKey) {
|
|
33564
33880
|
const { killed } = await Effect.runPromise(killAllReviewerSessions(projectKey, id.toUpperCase()));
|
|
@@ -33572,7 +33888,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33572
33888
|
cleanupLog.push("Cleared review status");
|
|
33573
33889
|
} catch {}
|
|
33574
33890
|
try {
|
|
33575
|
-
const { resetPostMergeState } = await import("./merge-agent-
|
|
33891
|
+
const { resetPostMergeState } = await import("./merge-agent-DQTXZk8z.js");
|
|
33576
33892
|
resetPostMergeState(id);
|
|
33577
33893
|
resetPostMergeState(id.toUpperCase());
|
|
33578
33894
|
cleanupLog.push("Cleared merge state");
|
|
@@ -33592,7 +33908,7 @@ function closeIssueTransition(options) {
|
|
|
33592
33908
|
const { issueId, body, eventStore } = options;
|
|
33593
33909
|
const { reason } = body;
|
|
33594
33910
|
const projectPath = getProjectPath$3(void 0, extractPrefixSync(issueId) ?? issueId.split("-")[0]);
|
|
33595
|
-
const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-
|
|
33911
|
+
const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-B3s4sM1G.js"));
|
|
33596
33912
|
const githubCheck = isGitHubIssue$4(issueId);
|
|
33597
33913
|
const issueDataService = getIssueDataService$8();
|
|
33598
33914
|
const issueSource = issueDataService.getIssueSource(issueId);
|
|
@@ -33615,7 +33931,7 @@ function closeIssueTransition(options) {
|
|
|
33615
33931
|
};
|
|
33616
33932
|
}
|
|
33617
33933
|
const result = yield* closeWorkflow(ctx, { reason });
|
|
33618
|
-
if (githubCheck.isGitHub) execAsync$
|
|
33934
|
+
if (githubCheck.isGitHub) execAsync$9("pan sync", {
|
|
33619
33935
|
encoding: "utf-8",
|
|
33620
33936
|
timeout: 3e4
|
|
33621
33937
|
}).catch(() => {});
|
|
@@ -33826,13 +34142,13 @@ function reopenIssueTransition(options) {
|
|
|
33826
34142
|
}
|
|
33827
34143
|
yield* Effect.promise(async () => {
|
|
33828
34144
|
try {
|
|
33829
|
-
const { stdout } = await execAsync$
|
|
34145
|
+
const { stdout } = await execAsync$9(`gh pr list --head ${`feature/${id.toLowerCase()}`} --state closed --json number,mergedAt --limit 1`, {
|
|
33830
34146
|
encoding: "utf-8",
|
|
33831
34147
|
timeout: 15e3
|
|
33832
34148
|
});
|
|
33833
34149
|
const prs = JSON.parse(stdout.trim() || "[]");
|
|
33834
34150
|
if (prs.length > 0 && !prs[0].mergedAt) {
|
|
33835
|
-
await execAsync$
|
|
34151
|
+
await execAsync$9(`gh pr reopen ${prs[0].number}`, {
|
|
33836
34152
|
encoding: "utf-8",
|
|
33837
34153
|
timeout: 15e3
|
|
33838
34154
|
});
|
|
@@ -33859,7 +34175,7 @@ function reopenIssueTransition(options) {
|
|
|
33859
34175
|
else clearReviewStatus(id.toUpperCase());
|
|
33860
34176
|
} catch {}
|
|
33861
34177
|
try {
|
|
33862
|
-
const { resetPostMergeState } = await import("./merge-agent-
|
|
34178
|
+
const { resetPostMergeState } = await import("./merge-agent-DQTXZk8z.js");
|
|
33863
34179
|
resetPostMergeState(id);
|
|
33864
34180
|
resetPostMergeState(id.toUpperCase());
|
|
33865
34181
|
} catch {}
|
|
@@ -33923,7 +34239,7 @@ function moveIssueStatus(options) {
|
|
|
33923
34239
|
"done"
|
|
33924
34240
|
];
|
|
33925
34241
|
if (!targetStatus || !validStatuses.includes(targetStatus)) return jsonResponse({ error: `Invalid targetStatus. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 });
|
|
33926
|
-
const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-
|
|
34242
|
+
const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-CZBp7pwq.js"));
|
|
33927
34243
|
const issueState = {
|
|
33928
34244
|
backlog: "open",
|
|
33929
34245
|
todo: "open",
|
|
@@ -33986,7 +34302,7 @@ function moveIssueStatus(options) {
|
|
|
33986
34302
|
init_issue_service_singleton();
|
|
33987
34303
|
init_issue_id();
|
|
33988
34304
|
init_agents$1();
|
|
33989
|
-
const execAsync$
|
|
34305
|
+
const execAsync$8 = promisify(exec);
|
|
33990
34306
|
function getIssueDataService$7() {
|
|
33991
34307
|
return getSharedIssueService();
|
|
33992
34308
|
}
|
|
@@ -34011,28 +34327,28 @@ async function cleanupWorkspaceForIssue(rawId, eventStore) {
|
|
|
34011
34327
|
if (projectRoot) {
|
|
34012
34328
|
const workspacePath = join(projectRoot, "workspaces", `feature-${issueLower}`);
|
|
34013
34329
|
try {
|
|
34014
|
-
if ((await execAsync$
|
|
34330
|
+
if ((await execAsync$8("git worktree list --porcelain", {
|
|
34015
34331
|
cwd: projectRoot,
|
|
34016
34332
|
encoding: "utf-8"
|
|
34017
34333
|
})).stdout.includes(workspacePath)) {
|
|
34018
|
-
await execAsync$
|
|
34334
|
+
await execAsync$8(`git worktree remove "${workspacePath}" --force`, {
|
|
34019
34335
|
cwd: projectRoot,
|
|
34020
34336
|
encoding: "utf-8"
|
|
34021
34337
|
});
|
|
34022
34338
|
cleanupLog.push(`Removed git worktree: ${workspacePath}`);
|
|
34023
34339
|
} else if (existsSync$1(workspacePath)) {
|
|
34024
|
-
await execAsync$
|
|
34340
|
+
await execAsync$8(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
|
|
34025
34341
|
cleanupLog.push(`Removed directory: ${workspacePath}`);
|
|
34026
34342
|
}
|
|
34027
34343
|
} catch {
|
|
34028
34344
|
if (existsSync$1(workspacePath)) {
|
|
34029
|
-
await execAsync$
|
|
34345
|
+
await execAsync$8(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
|
|
34030
34346
|
cleanupLog.push(`Removed directory: ${workspacePath}`);
|
|
34031
34347
|
}
|
|
34032
34348
|
}
|
|
34033
34349
|
const branchName = `feature/${issueLower}`;
|
|
34034
34350
|
try {
|
|
34035
|
-
await execAsync$
|
|
34351
|
+
await execAsync$8(`git branch -D "${branchName}" 2>/dev/null || true`, {
|
|
34036
34352
|
cwd: projectRoot,
|
|
34037
34353
|
encoding: "utf-8"
|
|
34038
34354
|
});
|
|
@@ -34041,7 +34357,7 @@ async function cleanupWorkspaceForIssue(rawId, eventStore) {
|
|
|
34041
34357
|
}
|
|
34042
34358
|
const agentDir = join(homedir$1(), ".overdeck", "agents", `agent-${issueLower}`);
|
|
34043
34359
|
if (existsSync$1(agentDir)) {
|
|
34044
|
-
await execAsync$
|
|
34360
|
+
await execAsync$8(`rm -rf "${agentDir}"`, { encoding: "utf-8" });
|
|
34045
34361
|
cleanupLog.push(`Removed agent state: ${agentDir}`);
|
|
34046
34362
|
}
|
|
34047
34363
|
await Effect.runPromise(eventStore.append({
|
|
@@ -34150,7 +34466,7 @@ async function copySettingsToWorkspace(id) {
|
|
|
34150
34466
|
success: false,
|
|
34151
34467
|
error: "Workspace not found"
|
|
34152
34468
|
}, { status: 404 });
|
|
34153
|
-
const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-
|
|
34469
|
+
const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-C1F3XsnS.js");
|
|
34154
34470
|
const result = copyOverdeckSettingsToWorkspaceSync(workspacePath);
|
|
34155
34471
|
return jsonResponse({
|
|
34156
34472
|
success: result.errors.length === 0 || result.copied.length > 0,
|
|
@@ -34200,10 +34516,11 @@ init_lifecycle_io();
|
|
|
34200
34516
|
init_io();
|
|
34201
34517
|
init_issue_id();
|
|
34202
34518
|
init_projects();
|
|
34519
|
+
init_record_update();
|
|
34203
34520
|
init_tracker_utils();
|
|
34204
34521
|
init_tmux();
|
|
34205
34522
|
init_typed_errors();
|
|
34206
|
-
const execAsync$
|
|
34523
|
+
const execAsync$7 = promisify(exec);
|
|
34207
34524
|
const execFileAsync$14 = promisify(execFile);
|
|
34208
34525
|
function getIssueDataService$6() {
|
|
34209
34526
|
return getSharedIssueService();
|
|
@@ -34258,7 +34575,7 @@ function getProjectPath$2(linearProjectId, issuePrefix) {
|
|
|
34258
34575
|
}
|
|
34259
34576
|
function startPlanningForIssue(options) {
|
|
34260
34577
|
return Effect.gen(function* () {
|
|
34261
|
-
const { id, body, eventStore, linear, github, rally, lifecycle } = options;
|
|
34578
|
+
const { id, body, eventStore, linear, github, rally, lifecycle, startedBy } = options;
|
|
34262
34579
|
const { skipWorkspace = false, startDocker = false, workspaceLocation = "local", shadowMode = false, model: modelOverride, effort, auto = false, autoStart = false, probe = false, harness = "claude-code" } = body;
|
|
34263
34580
|
const requestedHarness = harness === "ohmypi" || harness === "claude-code" || harness === "codex" || harness === "acp" ? harness : "claude-code";
|
|
34264
34581
|
const workModelRaw = body.workModel;
|
|
@@ -34364,7 +34681,8 @@ function startPlanningForIssue(options) {
|
|
|
34364
34681
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34365
34682
|
role: "plan",
|
|
34366
34683
|
model: "",
|
|
34367
|
-
auto: auto === true
|
|
34684
|
+
auto: auto === true,
|
|
34685
|
+
startedBy
|
|
34368
34686
|
});
|
|
34369
34687
|
return Promise.resolve();
|
|
34370
34688
|
});
|
|
@@ -34439,6 +34757,7 @@ function startPlanningForIssue(options) {
|
|
|
34439
34757
|
auto: auto === true,
|
|
34440
34758
|
probe: probe === true,
|
|
34441
34759
|
autoSpawnOnFinalize: autoStart === true,
|
|
34760
|
+
startedBy,
|
|
34442
34761
|
onProgress: (event) => {
|
|
34443
34762
|
console.log(`[start-planning] Progress: step=${event.step} label="${event.label}" status=${event.status} detail="${event.detail}"`);
|
|
34444
34763
|
sendEvent({
|
|
@@ -34631,10 +34950,10 @@ function restartFromPlan(options) {
|
|
|
34631
34950
|
});
|
|
34632
34951
|
const resetResult = yield* Effect.promise(async () => {
|
|
34633
34952
|
try {
|
|
34634
|
-
const { runGitResetHard } = await import("./dangerous-git-ops-
|
|
34953
|
+
const { runGitResetHard } = await import("./dangerous-git-ops-CFLykHWt.js");
|
|
34635
34954
|
async function findPlanningCommit(grep, label) {
|
|
34636
34955
|
try {
|
|
34637
|
-
const { stdout } = await execAsync$
|
|
34956
|
+
const { stdout } = await execAsync$7(`git log --grep="${grep.replace(/"/g, "\\\"")}" --format=%H -1`, {
|
|
34638
34957
|
cwd: workspacePath,
|
|
34639
34958
|
encoding: "utf-8",
|
|
34640
34959
|
timeout: 1e4
|
|
@@ -34650,7 +34969,7 @@ function restartFromPlan(options) {
|
|
|
34650
34969
|
}
|
|
34651
34970
|
const found = await findPlanningCommit(`Complete planning for ${id}`, "complete-planning message") ?? await findPlanningCommit(`chore: planning artifacts for ${id}`, "agent-start message") ?? await (async () => {
|
|
34652
34971
|
try {
|
|
34653
|
-
const { stdout } = await execAsync$
|
|
34972
|
+
const { stdout } = await execAsync$7(`git log --diff-filter=A --format=%H -1 -- .pan/spec.vbrief.json`, {
|
|
34654
34973
|
cwd: workspacePath,
|
|
34655
34974
|
encoding: "utf-8",
|
|
34656
34975
|
timeout: 1e4
|
|
@@ -34783,7 +35102,7 @@ init_github_pr_lookup();
|
|
|
34783
35102
|
init_tracker_utils();
|
|
34784
35103
|
init_tracker_config();
|
|
34785
35104
|
init_pr_tab_cache();
|
|
34786
|
-
const execAsync$
|
|
35105
|
+
const execAsync$6 = promisify(exec);
|
|
34787
35106
|
function isGitHubIssue$2(issueId) {
|
|
34788
35107
|
const resolved = resolveGitHubIssueSync(issueId);
|
|
34789
35108
|
if (resolved.isGitHub) return {
|
|
@@ -34831,7 +35150,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34831
35150
|
if (githubCheck.isGitHub && githubCheck.owner && githubCheck.repo && githubCheck.number) {
|
|
34832
35151
|
const { owner, repo, number } = githubCheck;
|
|
34833
35152
|
try {
|
|
34834
|
-
const { stdout } = await execAsync$
|
|
35153
|
+
const { stdout } = await execAsync$6(`gh api "repos/${owner}/${repo}/issues/${number}/comments?per_page=100"`, {
|
|
34835
35154
|
encoding: "utf-8",
|
|
34836
35155
|
timeout: 15e3,
|
|
34837
35156
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -34894,7 +35213,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34894
35213
|
const collectedItems = [];
|
|
34895
35214
|
const prConversation = (async () => {
|
|
34896
35215
|
try {
|
|
34897
|
-
const { stdout } = await execAsync$
|
|
35216
|
+
const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/issues/${prNumber}/comments?per_page=100"`, {
|
|
34898
35217
|
encoding: "utf-8",
|
|
34899
35218
|
timeout: 15e3,
|
|
34900
35219
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -34915,7 +35234,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34915
35234
|
})();
|
|
34916
35235
|
const prReviews = (async () => {
|
|
34917
35236
|
try {
|
|
34918
|
-
const { stdout } = await execAsync$
|
|
35237
|
+
const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/reviews?per_page=100"`, {
|
|
34919
35238
|
encoding: "utf-8",
|
|
34920
35239
|
timeout: 15e3,
|
|
34921
35240
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -34940,7 +35259,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34940
35259
|
})();
|
|
34941
35260
|
const prInlineComments = (async () => {
|
|
34942
35261
|
try {
|
|
34943
|
-
const { stdout } = await execAsync$
|
|
35262
|
+
const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/comments?per_page=100"`, {
|
|
34944
35263
|
encoding: "utf-8",
|
|
34945
35264
|
timeout: 15e3,
|
|
34946
35265
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -35083,7 +35402,7 @@ function closeOutIssue(id, opts = {}) {
|
|
|
35083
35402
|
}
|
|
35084
35403
|
const closeOutResult = yield* Effect.promise(async () => {
|
|
35085
35404
|
try {
|
|
35086
|
-
const { closeOut } = await import("./lifecycle-
|
|
35405
|
+
const { closeOut } = await import("./lifecycle-B3s4sM1G.js");
|
|
35087
35406
|
return {
|
|
35088
35407
|
ok: true,
|
|
35089
35408
|
result: await Effect.runPromise(closeOut(ctx, {
|
|
@@ -35172,7 +35491,7 @@ function bulkCloseOut(body) {
|
|
|
35172
35491
|
const invalidIds = issueIds.filter((id) => !isValidIssueId(id));
|
|
35173
35492
|
if (invalidIds.length > 0) return jsonResponse({ error: `Invalid issue ID format: ${invalidIds.join(", ")}` }, { status: 400 });
|
|
35174
35493
|
const eventStore = yield* EventStoreService;
|
|
35175
|
-
const { closeOut } = yield* Effect.promise(() => import("./lifecycle-
|
|
35494
|
+
const { closeOut } = yield* Effect.promise(() => import("./lifecycle-B3s4sM1G.js"));
|
|
35176
35495
|
const issueDataService = getIssueDataService$5();
|
|
35177
35496
|
const tasks = [];
|
|
35178
35497
|
const agentChecks = yield* withConcurrencyLimit(issueIds.map((id) => Effect.promise(async () => {
|
|
@@ -35340,7 +35659,7 @@ const execFileAsync$13 = promisify(execFile);
|
|
|
35340
35659
|
function getIssueDataService$4() {
|
|
35341
35660
|
return getSharedIssueService();
|
|
35342
35661
|
}
|
|
35343
|
-
const readJsonBody$
|
|
35662
|
+
const readJsonBody$18 = Effect.gen(function* () {
|
|
35344
35663
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
35345
35664
|
try {
|
|
35346
35665
|
return text ? JSON.parse(text) : {};
|
|
@@ -35398,8 +35717,8 @@ const getIssueShipLogRoute = HttpRouter.add("GET", "/api/issues/:id/ship-log", h
|
|
|
35398
35717
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35399
35718
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35400
35719
|
return yield* Effect.promise(async () => {
|
|
35401
|
-
const { getShipLog } = await import("./ship-log-
|
|
35402
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
35720
|
+
const { getShipLog } = await import("./ship-log-7kJfjUX2.js");
|
|
35721
|
+
const { getReviewStatusSync } = await import("./review-status-Dma9SFaN.js");
|
|
35403
35722
|
const log = getShipLog(id);
|
|
35404
35723
|
const rs = getReviewStatusSync(id);
|
|
35405
35724
|
return jsonResponse({
|
|
@@ -35414,8 +35733,8 @@ const getIssueVerificationRoute = HttpRouter.add("GET", "/api/issues/:id/verific
|
|
|
35414
35733
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35415
35734
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35416
35735
|
return yield* Effect.promise(async () => {
|
|
35417
|
-
const { readVerificationArtifact } = await import("./verification-artifact-
|
|
35418
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
35736
|
+
const { readVerificationArtifact } = await import("./verification-artifact-BxlxTiYK.js");
|
|
35737
|
+
const { getReviewStatusSync } = await import("./review-status-Dma9SFaN.js");
|
|
35419
35738
|
const { join } = await import("node:path");
|
|
35420
35739
|
const resolved = resolveProjectFromIssueSync(id);
|
|
35421
35740
|
const workspacePath = resolved ? join(resolved.projectPath, "workspaces", `feature-${id.toLowerCase()}`) : null;
|
|
@@ -35433,21 +35752,35 @@ const postIssueCloseRoute = HttpRouter.add("POST", "/api/issues/:issueId/close",
|
|
|
35433
35752
|
if (!parseIssueIdSync(issueId)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35434
35753
|
return yield* closeIssueTransition({
|
|
35435
35754
|
issueId,
|
|
35436
|
-
body: yield* readJsonBody$
|
|
35755
|
+
body: yield* readJsonBody$18,
|
|
35437
35756
|
eventStore: yield* EventStoreService
|
|
35438
35757
|
});
|
|
35439
35758
|
})));
|
|
35440
35759
|
const postIssueStartPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/start-planning", httpHandler(Effect.gen(function* () {
|
|
35760
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
35441
35761
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35442
35762
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35763
|
+
const body = yield* readJsonBody$18;
|
|
35764
|
+
const eventStore = yield* EventStoreService;
|
|
35765
|
+
const linear = yield* LinearClient;
|
|
35766
|
+
const github = yield* GitHubClient;
|
|
35767
|
+
const rally = yield* RallyClient;
|
|
35768
|
+
const lifecycle = yield* IssueLifecycle;
|
|
35769
|
+
let startedBy;
|
|
35770
|
+
try {
|
|
35771
|
+
startedBy = resolveRequestedStartedBy(body.startedBy, yield* Effect.promise(() => isInternalAgentRequest(request)));
|
|
35772
|
+
} catch (error) {
|
|
35773
|
+
return jsonResponse({ error: error instanceof Error ? error.message : String(error) }, { status: 400 });
|
|
35774
|
+
}
|
|
35443
35775
|
return yield* startPlanningForIssue({
|
|
35444
35776
|
id,
|
|
35445
|
-
body
|
|
35446
|
-
eventStore
|
|
35447
|
-
linear
|
|
35448
|
-
github
|
|
35449
|
-
rally
|
|
35450
|
-
lifecycle
|
|
35777
|
+
body,
|
|
35778
|
+
eventStore,
|
|
35779
|
+
linear,
|
|
35780
|
+
github,
|
|
35781
|
+
rally,
|
|
35782
|
+
lifecycle,
|
|
35783
|
+
startedBy
|
|
35451
35784
|
});
|
|
35452
35785
|
})));
|
|
35453
35786
|
const postIssueAbortPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/abort-planning", httpHandler(Effect.gen(function* () {
|
|
@@ -35455,7 +35788,7 @@ const postIssueAbortPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/abor
|
|
|
35455
35788
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35456
35789
|
return yield* abortPlanningForIssue({
|
|
35457
35790
|
id,
|
|
35458
|
-
body: yield* readJsonBody$
|
|
35791
|
+
body: yield* readJsonBody$18,
|
|
35459
35792
|
lifecycle: yield* IssueLifecycle,
|
|
35460
35793
|
linear: yield* LinearClient,
|
|
35461
35794
|
eventStore: yield* EventStoreService
|
|
@@ -35465,7 +35798,7 @@ const postIssueCompletePlanningRoute = HttpRouter.add("POST", "/api/issues/:id/c
|
|
|
35465
35798
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
35466
35799
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35467
35800
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35468
|
-
const body = yield* readJsonBody$
|
|
35801
|
+
const body = yield* readJsonBody$18;
|
|
35469
35802
|
const eventStore = yield* EventStoreService;
|
|
35470
35803
|
const linear = yield* LinearClient;
|
|
35471
35804
|
const lifecycle = yield* IssueLifecycle;
|
|
@@ -35491,7 +35824,7 @@ const postIssueResetRoute = HttpRouter.add("POST", "/api/issues/:id/reset", http
|
|
|
35491
35824
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35492
35825
|
return yield* resetIssueTransition({
|
|
35493
35826
|
id,
|
|
35494
|
-
body: yield* readJsonBody$
|
|
35827
|
+
body: yield* readJsonBody$18,
|
|
35495
35828
|
eventStore: yield* EventStoreService
|
|
35496
35829
|
});
|
|
35497
35830
|
})));
|
|
@@ -35515,7 +35848,7 @@ const postIssueCancelRoute = HttpRouter.add("POST", "/api/issues/:id/cancel", ht
|
|
|
35515
35848
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35516
35849
|
return yield* cancelIssueTransition({
|
|
35517
35850
|
id,
|
|
35518
|
-
body: yield* readJsonBody$
|
|
35851
|
+
body: yield* readJsonBody$18,
|
|
35519
35852
|
eventStore: yield* EventStoreService
|
|
35520
35853
|
});
|
|
35521
35854
|
})));
|
|
@@ -35526,7 +35859,7 @@ const postIssueReopenRoute = HttpRouter.add("POST", "/api/issues/:id/reopen", ht
|
|
|
35526
35859
|
if (authError) return authError;
|
|
35527
35860
|
return yield* reopenIssueTransition({
|
|
35528
35861
|
id,
|
|
35529
|
-
body: yield* readJsonBody$
|
|
35862
|
+
body: yield* readJsonBody$18,
|
|
35530
35863
|
lifecycle: yield* IssueLifecycle,
|
|
35531
35864
|
linear: yield* LinearClient,
|
|
35532
35865
|
eventStore: yield* EventStoreService
|
|
@@ -35546,7 +35879,7 @@ const postIssueMoveStatusRoute = HttpRouter.add("POST", "/api/issues/:id/move-st
|
|
|
35546
35879
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35547
35880
|
return yield* moveIssueStatus({
|
|
35548
35881
|
id,
|
|
35549
|
-
body: yield* readJsonBody$
|
|
35882
|
+
body: yield* readJsonBody$18,
|
|
35550
35883
|
eventStore: yield* EventStoreService,
|
|
35551
35884
|
lifecycle: yield* IssueLifecycle
|
|
35552
35885
|
});
|
|
@@ -35558,7 +35891,7 @@ const postIssueCleanupWorkspaceRoute = HttpRouter.add("POST", "/api/issues/:id/c
|
|
|
35558
35891
|
})));
|
|
35559
35892
|
const postIssueDeepWipeRoute = HttpRouter.add("POST", "/api/issues/:id/deep-wipe", httpHandler(Effect.gen(function* () {
|
|
35560
35893
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35561
|
-
const body = yield* readJsonBody$
|
|
35894
|
+
const body = yield* readJsonBody$18;
|
|
35562
35895
|
const eventStore = yield* EventStoreService;
|
|
35563
35896
|
return yield* Effect.promise(() => deepWipeIssue(id, body, eventStore));
|
|
35564
35897
|
})));
|
|
@@ -35614,7 +35947,7 @@ const postIssueTaskInspectRoute = HttpRouter.add("POST", "/api/issues/:id/tasks/
|
|
|
35614
35947
|
return yield* inspectIssueTask({
|
|
35615
35948
|
id: (params["id"] ?? "").toUpperCase(),
|
|
35616
35949
|
itemId: params["itemId"] ?? "",
|
|
35617
|
-
body: yield* readJsonBody$
|
|
35950
|
+
body: yield* readJsonBody$18
|
|
35618
35951
|
});
|
|
35619
35952
|
})));
|
|
35620
35953
|
const getIssuePlanningStateRoute = HttpRouter.add("GET", "/api/issues/:id/planning-state", httpHandler(Effect.gen(function* () {
|
|
@@ -35756,7 +36089,13 @@ const getPipelineMembershipRoute = HttpRouter.add("GET", "/api/pipeline/membersh
|
|
|
35756
36089
|
if (!project) return jsonResponse({ error: `Project not found: ${projectKey}` }, { status: 404 });
|
|
35757
36090
|
const snapshot = readPipelineMembershipSnapshotsForProjects([project])[0];
|
|
35758
36091
|
if (snapshot?.memberships) return jsonResponse(snapshot.memberships);
|
|
35759
|
-
|
|
36092
|
+
if (snapshot?.error && snapshot.unavailableReason) return jsonResponse({
|
|
36093
|
+
status: "unavailable",
|
|
36094
|
+
reason: snapshot.unavailableReason ?? "gather_failed",
|
|
36095
|
+
message: snapshot.error instanceof Error ? snapshot.error.message : String(snapshot.error),
|
|
36096
|
+
projectKey
|
|
36097
|
+
});
|
|
36098
|
+
return jsonResponse({ error: "Pipeline membership snapshot is loading" }, { status: 503 });
|
|
35760
36099
|
})));
|
|
35761
36100
|
const postPipelineMembershipRefreshRoute = HttpRouter.add("POST", "/api/pipeline/membership/refresh", httpHandler(Effect.gen(function* () {
|
|
35762
36101
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
@@ -35769,7 +36108,12 @@ const postPipelineMembershipRefreshRoute = HttpRouter.add("POST", "/api/pipeline
|
|
|
35769
36108
|
yield* Effect.promise(() => refreshMembershipSnapshotsForProjects([project]));
|
|
35770
36109
|
const snapshot = readPipelineMembershipSnapshotsForProjects([project])[0];
|
|
35771
36110
|
if (snapshot?.memberships) return jsonResponse(snapshot.memberships);
|
|
35772
|
-
return jsonResponse({
|
|
36111
|
+
return jsonResponse({
|
|
36112
|
+
status: "unavailable",
|
|
36113
|
+
reason: snapshot?.unavailableReason ?? "gather_failed",
|
|
36114
|
+
message: snapshot?.error instanceof Error ? snapshot.error.message : "Pipeline membership refresh failed",
|
|
36115
|
+
projectKey
|
|
36116
|
+
});
|
|
35773
36117
|
})));
|
|
35774
36118
|
const pipelineMembershipRouteLayer = Layer.mergeAll(getPipelineMembershipRoute, postPipelineMembershipRefreshRoute);
|
|
35775
36119
|
//#endregion
|
|
@@ -36050,8 +36394,7 @@ const getCostsBackgroundRoute = HttpRouter.add("GET", "/api/costs/background", h
|
|
|
36050
36394
|
const costsRouteLayer = Layer.mergeAll(getCostsSummaryRoute, getCostsByIssueRoute, getCostsBackgroundRoute, postCostsRebuildRoute, postCostsDeduplicateRoute, getCostsStreamRoute, getCostsTrendsRoute, getCostsByModelRoute, getCostsIssueRoute, getCostsByAgentRoute, postCostsSyncWalRoute, postCostsReconcileRoute, getCostsExperimentsRoute);
|
|
36051
36395
|
//#endregion
|
|
36052
36396
|
//#region services/deacon-supervisor.ts
|
|
36053
|
-
|
|
36054
|
-
init_config$1();
|
|
36397
|
+
init_config$2();
|
|
36055
36398
|
init_concurrency();
|
|
36056
36399
|
init_activity_logger();
|
|
36057
36400
|
const DEFAULT_RESTART_WINDOW_MS = 6e4;
|
|
@@ -36222,6 +36565,7 @@ const isChildRunning = defaultSupervisor.isChildRunning;
|
|
|
36222
36565
|
//#endregion
|
|
36223
36566
|
//#region services/cloister-control-surface.ts
|
|
36224
36567
|
init_agents$1();
|
|
36568
|
+
init_control_settings();
|
|
36225
36569
|
init_paths();
|
|
36226
36570
|
function readDurableCloisterStatus(deps = {}) {
|
|
36227
36571
|
const cloisterState = (deps.readCloisterStateFile ?? readCloisterStateFile)();
|
|
@@ -36306,9 +36650,9 @@ function reloadDurableCloisterConfig(deps = {}) {
|
|
|
36306
36650
|
* PUT /api/cloister/config
|
|
36307
36651
|
* GET /api/cloister/agents/health
|
|
36308
36652
|
*/
|
|
36309
|
-
init_config$
|
|
36653
|
+
init_config$2();
|
|
36310
36654
|
init_agents$1();
|
|
36311
|
-
const readJsonBody$
|
|
36655
|
+
const readJsonBody$17 = Effect.gen(function* () {
|
|
36312
36656
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
36313
36657
|
try {
|
|
36314
36658
|
return text ? JSON.parse(text) : {};
|
|
@@ -36411,7 +36755,7 @@ const getCloisterConfigRoute = HttpRouter.add("GET", "/api/cloister/config", htt
|
|
|
36411
36755
|
catch: (err) => new Error(err instanceof Error ? err.message : String(err))
|
|
36412
36756
|
})));
|
|
36413
36757
|
const putCloisterConfigRoute = HttpRouter.add("PUT", "/api/cloister/config", httpHandler(Effect.gen(function* () {
|
|
36414
|
-
const updates = yield* readJsonBody$
|
|
36758
|
+
const updates = yield* readJsonBody$17;
|
|
36415
36759
|
yield* Effect.try({
|
|
36416
36760
|
try: () => {
|
|
36417
36761
|
saveCloisterConfigSync(updates);
|
|
@@ -37784,7 +38128,7 @@ const getStackTeardownEstimateRoute = HttpRouter.add("GET", "/api/resources/stac
|
|
|
37784
38128
|
})));
|
|
37785
38129
|
const postStackTeardownRoute = HttpRouter.add("POST", "/api/resources/stacks/:issueId/teardown", httpHandler(Effect.gen(function* () {
|
|
37786
38130
|
const params = yield* HttpRouter.params;
|
|
37787
|
-
const body = yield* readJsonBody$
|
|
38131
|
+
const body = yield* readJsonBody$16;
|
|
37788
38132
|
return yield* postStackTeardownEffect(params["issueId"] ?? "", body);
|
|
37789
38133
|
})));
|
|
37790
38134
|
function getStackTeardownEstimateEffect(issue) {
|
|
@@ -37958,7 +38302,7 @@ function lines(value) {
|
|
|
37958
38302
|
function isDockerIdentifier(value) {
|
|
37959
38303
|
return /^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/.test(value);
|
|
37960
38304
|
}
|
|
37961
|
-
const readJsonBody$
|
|
38305
|
+
const readJsonBody$16 = Effect.gen(function* () {
|
|
37962
38306
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
37963
38307
|
try {
|
|
37964
38308
|
return text ? JSON.parse(text) : {};
|
|
@@ -38067,7 +38411,6 @@ async function deriveSessionPresence(agentId, rtState, tmuxSessionNames) {
|
|
|
38067
38411
|
}
|
|
38068
38412
|
//#endregion
|
|
38069
38413
|
//#region ../../lib/settings-api-tiered-execution.ts
|
|
38070
|
-
init_prd_locations();
|
|
38071
38414
|
function tieredExecutionConfigForSave(config, providerAuth) {
|
|
38072
38415
|
if (config === void 0) return void 0;
|
|
38073
38416
|
const validated = validateTieredExecutionConfig(config, { providerAuth });
|
|
@@ -38093,6 +38436,17 @@ function validateTieredExecutionSettings(config, providerAuth) {
|
|
|
38093
38436
|
}
|
|
38094
38437
|
}
|
|
38095
38438
|
//#endregion
|
|
38439
|
+
//#region ../../lib/settings-api-telemetry.ts
|
|
38440
|
+
function validateApiTelemetryConfig(value) {
|
|
38441
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return ["telemetry must be an object"];
|
|
38442
|
+
const telemetry = value;
|
|
38443
|
+
const errors = [];
|
|
38444
|
+
if (typeof telemetry.enabled !== "boolean") errors.push("telemetry.enabled must be a boolean");
|
|
38445
|
+
if (telemetry.effectiveEnabled !== void 0 && typeof telemetry.effectiveEnabled !== "boolean") errors.push("telemetry.effectiveEnabled must be a boolean");
|
|
38446
|
+
if (telemetry.installId !== void 0 && typeof telemetry.installId !== "string") errors.push("telemetry.installId must be a string");
|
|
38447
|
+
return errors;
|
|
38448
|
+
}
|
|
38449
|
+
//#endregion
|
|
38096
38450
|
//#region ../../lib/settings-api.ts
|
|
38097
38451
|
/**
|
|
38098
38452
|
* Settings API Adapter
|
|
@@ -38101,6 +38455,9 @@ function validateTieredExecutionSettings(config, providerAuth) {
|
|
|
38101
38455
|
* Converts between YAML config format and frontend API format.
|
|
38102
38456
|
*/
|
|
38103
38457
|
init_config_yaml();
|
|
38458
|
+
init_config();
|
|
38459
|
+
init_install_id();
|
|
38460
|
+
init_service();
|
|
38104
38461
|
const API_TTS_KEYS = [
|
|
38105
38462
|
"enabled",
|
|
38106
38463
|
"voice",
|
|
@@ -38480,6 +38837,11 @@ function loadSettingsApi() {
|
|
|
38480
38837
|
rtk: { enabled: config.rtk?.enabled ?? false },
|
|
38481
38838
|
tldr: { enabled: config.tldr?.enabled ?? true }
|
|
38482
38839
|
},
|
|
38840
|
+
telemetry: {
|
|
38841
|
+
enabled: config.telemetry?.enabled ?? true,
|
|
38842
|
+
effectiveEnabled: resolveTelemetryEnabled(),
|
|
38843
|
+
installId: getOrCreateInstallId()
|
|
38844
|
+
},
|
|
38483
38845
|
tts: toApiTtsConfig(config.tts),
|
|
38484
38846
|
tts_summarizer: {
|
|
38485
38847
|
model: config.ttsSummarizer?.model,
|
|
@@ -38561,6 +38923,7 @@ async function writeYamlConfigPreservingComments(yamlConfig) {
|
|
|
38561
38923
|
["memory", config.memory],
|
|
38562
38924
|
["background_ai", config.background_ai],
|
|
38563
38925
|
["tracker_keys", config.tracker_keys],
|
|
38926
|
+
["telemetry", config.telemetry],
|
|
38564
38927
|
["experimental", config.experimental],
|
|
38565
38928
|
["claude", config.claude],
|
|
38566
38929
|
["codex", config.codex],
|
|
@@ -38660,6 +39023,7 @@ async function saveSettingsApiPromise(settings) {
|
|
|
38660
39023
|
features: settings.background_ai.features
|
|
38661
39024
|
} : void 0,
|
|
38662
39025
|
tracker_keys: settings.tracker_keys,
|
|
39026
|
+
telemetry: settings.telemetry ? { enabled: settings.telemetry.enabled } : void 0,
|
|
38663
39027
|
experimental: settings.experimental ? {
|
|
38664
39028
|
experimentalFeatures: settings.experimental.experimentalFeatures,
|
|
38665
39029
|
claudeCodeChannels: settings.experimental.claudeCodeChannels,
|
|
@@ -38673,6 +39037,7 @@ async function saveSettingsApiPromise(settings) {
|
|
|
38673
39037
|
tiered_execution: tieredExecutionConfigForSave(settings.tiered_execution, currentConfig.providerAuth)
|
|
38674
39038
|
});
|
|
38675
39039
|
clearConfigCache();
|
|
39040
|
+
await synchronizeAnalyticsServices();
|
|
38676
39041
|
}
|
|
38677
39042
|
async function updateSettingsApiPromise(updates) {
|
|
38678
39043
|
const current = loadSettingsApi();
|
|
@@ -38750,6 +39115,11 @@ async function updateSettingsApiPromise(updates) {
|
|
|
38750
39115
|
...current.tracker_keys,
|
|
38751
39116
|
...updates.tracker_keys
|
|
38752
39117
|
},
|
|
39118
|
+
telemetry: {
|
|
39119
|
+
enabled: updates.telemetry?.enabled ?? current.telemetry?.enabled ?? true,
|
|
39120
|
+
effectiveEnabled: !telemetryEnvironmentForcesOff() && (updates.telemetry?.enabled ?? current.telemetry?.enabled ?? true),
|
|
39121
|
+
installId: current.telemetry?.installId
|
|
39122
|
+
},
|
|
38753
39123
|
experimental: {
|
|
38754
39124
|
...current.experimental,
|
|
38755
39125
|
...updates.experimental
|
|
@@ -38821,6 +39191,7 @@ function validateSettingsApi(settings) {
|
|
|
38821
39191
|
if (settings.memory.sidebar_refresh_interval_ms !== void 0 && (!Number.isInteger(settings.memory.sidebar_refresh_interval_ms) || settings.memory.sidebar_refresh_interval_ms < 1)) errors.push("memory.sidebar_refresh_interval_ms must be a positive integer");
|
|
38822
39192
|
if (settings.memory.worker_concurrency !== void 0 && (!Number.isInteger(settings.memory.worker_concurrency) || settings.memory.worker_concurrency < 1)) errors.push("memory.worker_concurrency must be a positive integer");
|
|
38823
39193
|
}
|
|
39194
|
+
if (settings.telemetry !== void 0) errors.push(...validateApiTelemetryConfig(settings.telemetry));
|
|
38824
39195
|
if (settings.experimental !== void 0) if (typeof settings.experimental !== "object" || settings.experimental === null) errors.push("experimental must be an object");
|
|
38825
39196
|
else {
|
|
38826
39197
|
const experimental = settings.experimental;
|
|
@@ -39288,7 +39659,7 @@ init_linear_client();
|
|
|
39288
39659
|
init_config_yaml();
|
|
39289
39660
|
init_issue_service_singleton();
|
|
39290
39661
|
init_io();
|
|
39291
|
-
const execAsync$
|
|
39662
|
+
const execAsync$5 = promisify(exec);
|
|
39292
39663
|
const execFileAsync$8 = promisify(execFile);
|
|
39293
39664
|
function getIssueDataService$3() {
|
|
39294
39665
|
return getSharedIssueService();
|
|
@@ -39342,7 +39713,7 @@ function getProjectPath$1(issuePrefix) {
|
|
|
39342
39713
|
}
|
|
39343
39714
|
return setProjectPathCache(issuePrefix, join(homedir$1(), "Projects"));
|
|
39344
39715
|
}
|
|
39345
|
-
const readJsonBody$
|
|
39716
|
+
const readJsonBody$15 = Effect.gen(function* () {
|
|
39346
39717
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
39347
39718
|
try {
|
|
39348
39719
|
return text ? JSON.parse(text) : {};
|
|
@@ -39613,16 +39984,18 @@ async function fetchActivityDataWithContext(issueId, context = {}) {
|
|
|
39613
39984
|
const isShipStage = ss.type === "merge";
|
|
39614
39985
|
const nodeType = isShipStage ? "ship" : "test";
|
|
39615
39986
|
const specialistSessionId = isShipStage ? `agent-${issueLower}-ship` : `agent-${issueLower}-test`;
|
|
39987
|
+
const specialistIsLive = tmuxSessionNames.has(specialistSessionId);
|
|
39988
|
+
const specialistState = getAgentStateSync(specialistSessionId);
|
|
39989
|
+
if (isShipStage && !specialistIsLive && !specialistState) continue;
|
|
39616
39990
|
if (includeTranscripts && ss.status === "running") try {
|
|
39617
39991
|
const output = (await Effect.runPromise(capturePane(specialistSessionId, 100))).trim();
|
|
39618
39992
|
if (output && (output.includes(issueId.toUpperCase()) || output.includes(issueId) || output.includes(issueLower))) transcriptParts.push(`\n--- Live Output ---\n${output}`);
|
|
39619
39993
|
else if (output) transcriptParts.push(`\n--- Waiting ---\nSpecialist is processing another issue. Will update when it reaches ${issueId}.`);
|
|
39620
39994
|
} catch {}
|
|
39621
|
-
const specialistIsLive = tmuxSessionNames.has(specialistSessionId);
|
|
39622
39995
|
const specialistIsZombie = specialistIsLive && (ss.status === "completed" || ss.status === "failed");
|
|
39623
39996
|
const specialistPresence = specialistIsLive && !specialistIsZombie ? ss.status === "running" ? "active" : "idle" : specialistIsZombie ? "idle" : "ended";
|
|
39624
39997
|
const specialistJsonlPath = await resolveJsonlPath(specialistSessionId, workspacePath);
|
|
39625
|
-
|
|
39998
|
+
if (isShipStage && !specialistIsLive && !specialistJsonlPath) continue;
|
|
39626
39999
|
sections.push({
|
|
39627
40000
|
type: nodeType,
|
|
39628
40001
|
sessionId: specialistSessionId,
|
|
@@ -39841,7 +40214,7 @@ async function fetchPlanningData(issueId, options = {}) {
|
|
|
39841
40214
|
const cached = stashCountCache.get(cacheKey);
|
|
39842
40215
|
if (cached && cached.timestamp > Date.now() - STASH_COUNT_CACHE_TTL_MS) result.stashCount = cached.count;
|
|
39843
40216
|
else {
|
|
39844
|
-
const { stdout: stashList } = await execAsync$
|
|
40217
|
+
const { stdout: stashList } = await execAsync$5("git stash list", {
|
|
39845
40218
|
cwd: workspacePath,
|
|
39846
40219
|
encoding: "utf-8"
|
|
39847
40220
|
});
|
|
@@ -39929,7 +40302,7 @@ async function generateStatusReview(issueId) {
|
|
|
39929
40302
|
};
|
|
39930
40303
|
const execSafe = async (cmd, opts) => {
|
|
39931
40304
|
try {
|
|
39932
|
-
const { stdout } = await execAsync$
|
|
40305
|
+
const { stdout } = await execAsync$5(cmd, {
|
|
39933
40306
|
encoding: "utf-8",
|
|
39934
40307
|
timeout: 1e4,
|
|
39935
40308
|
...opts
|
|
@@ -40031,7 +40404,7 @@ Be specific: reference actual file names, function names, requirement text, disc
|
|
|
40031
40404
|
const { command: cliCmd, args: cliArgs } = getAgentCommandSync(statusModelId);
|
|
40032
40405
|
const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
|
|
40033
40406
|
const promptFile = join(planningDir, ".status-review-prompt.tmp");
|
|
40034
|
-
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-
|
|
40407
|
+
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-BI1mOBQ4.js");
|
|
40035
40408
|
let providerEnvStr = "";
|
|
40036
40409
|
let providerEnv = {};
|
|
40037
40410
|
const statusProvider = getProviderForModelSync(statusModelId);
|
|
@@ -40048,7 +40421,7 @@ Be specific: reference actual file names, function names, requirement text, disc
|
|
|
40048
40421
|
try {
|
|
40049
40422
|
const env = buildChildEnvSync(process.env, providerEnv);
|
|
40050
40423
|
const promptContent = await readFile(promptFile, "utf-8");
|
|
40051
|
-
const { stdout: aiReview } = await execAsync$
|
|
40424
|
+
const { stdout: aiReview } = await execAsync$5(`${cliCmd} -p${modelFlag} --no-session-persistence`, {
|
|
40052
40425
|
encoding: "utf-8",
|
|
40053
40426
|
timeout: 12e4,
|
|
40054
40427
|
maxBuffer: 1024 * 1024,
|
|
@@ -40106,7 +40479,7 @@ ${issueContext ? `## Issue Tracker Data\n${issueContext}\n` : ""}---
|
|
|
40106
40479
|
}
|
|
40107
40480
|
const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/planning/:issueId/upload", httpHandler(Effect.gen(function* () {
|
|
40108
40481
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40109
|
-
const { type, filename, content } = yield* readJsonBody$
|
|
40482
|
+
const { type, filename, content } = yield* readJsonBody$15;
|
|
40110
40483
|
const issueLower = issueId.toLowerCase();
|
|
40111
40484
|
const issuePrefix = extractPrefixSync(issueId) ?? issueId.split("-")[0];
|
|
40112
40485
|
if (!type || !filename || !content) return jsonResponse({ error: "type, filename, and content are required" }, { status: 400 });
|
|
@@ -40114,7 +40487,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
|
|
|
40114
40487
|
let safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
40115
40488
|
let processedContent = content;
|
|
40116
40489
|
if (safeName.endsWith(".vtt")) {
|
|
40117
|
-
const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-
|
|
40490
|
+
const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-CE_i3Bcw.js"));
|
|
40118
40491
|
processedContent = vttToMarkdown(content);
|
|
40119
40492
|
safeName = safeName.replace(/\.vtt$/, ".md");
|
|
40120
40493
|
}
|
|
@@ -40135,7 +40508,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
|
|
|
40135
40508
|
const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/command-deck/planning/:issueId/sync-discussions", httpHandler(Effect.gen(function* () {
|
|
40136
40509
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40137
40510
|
if (!parseIssueIdSync(issueId)) return jsonResponse({ error: "Invalid issue id: " + issueId }, { status: 400 });
|
|
40138
|
-
const body = yield* readJsonBody$
|
|
40511
|
+
const body = yield* readJsonBody$15;
|
|
40139
40512
|
const linear = yield* LinearClient;
|
|
40140
40513
|
const { tracker } = body;
|
|
40141
40514
|
const issueLower = issueId.toLowerCase();
|
|
@@ -40281,7 +40654,7 @@ const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/comm
|
|
|
40281
40654
|
})));
|
|
40282
40655
|
const postMissionControlPlanningInitRoute = HttpRouter.add("POST", "/api/command-deck/planning/:issueId/init", httpHandler(Effect.gen(function* () {
|
|
40283
40656
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40284
|
-
const body = yield* readJsonBody$
|
|
40657
|
+
const body = yield* readJsonBody$15;
|
|
40285
40658
|
const eventStore = yield* EventStoreService;
|
|
40286
40659
|
const { shadow } = body;
|
|
40287
40660
|
const issueLower = issueId.toLowerCase();
|
|
@@ -40340,7 +40713,7 @@ const commandDeckRouteLayer = Layer.mergeAll(getMissionControlActivityRoute, get
|
|
|
40340
40713
|
* GET /api/remote/workspaces/:issueId/agent/output
|
|
40341
40714
|
* POST /api/remote/workspaces/:issueId/agent/tell
|
|
40342
40715
|
*/
|
|
40343
|
-
init_config();
|
|
40716
|
+
init_config$1();
|
|
40344
40717
|
init_domain_services();
|
|
40345
40718
|
async function loadRemoteWorkspaceMetadata(issueId) {
|
|
40346
40719
|
const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
@@ -40366,7 +40739,7 @@ async function listRemoteWorkspaceMetadata() {
|
|
|
40366
40739
|
}
|
|
40367
40740
|
return workspaces;
|
|
40368
40741
|
}
|
|
40369
|
-
const readJsonBody$
|
|
40742
|
+
const readJsonBody$14 = Effect.gen(function* () {
|
|
40370
40743
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
40371
40744
|
try {
|
|
40372
40745
|
return text ? JSON.parse(text) : {};
|
|
@@ -40481,7 +40854,7 @@ const stopRemoteWorkspaceRoute = HttpRouter.add("POST", "/api/remote/workspaces/
|
|
|
40481
40854
|
})));
|
|
40482
40855
|
const startRemoteAgentRoute = HttpRouter.add("POST", "/api/remote/workspaces/:issueId/agent/start", httpHandler(Effect.gen(function* () {
|
|
40483
40856
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40484
|
-
const body = yield* readJsonBody$
|
|
40857
|
+
const body = yield* readJsonBody$14;
|
|
40485
40858
|
const eventStore = yield* EventStoreService;
|
|
40486
40859
|
const { prompt, model } = body;
|
|
40487
40860
|
const metadata = yield* Effect.promise(() => loadRemoteWorkspaceMetadata(issueId));
|
|
@@ -40497,6 +40870,7 @@ const startRemoteAgentRoute = HttpRouter.add("POST", "/api/remote/workspaces/:is
|
|
|
40497
40870
|
workspace: metadata,
|
|
40498
40871
|
prompt,
|
|
40499
40872
|
model,
|
|
40873
|
+
startedBy: "operator:dashboard",
|
|
40500
40874
|
tier: fly.getResiliencyTier()
|
|
40501
40875
|
});
|
|
40502
40876
|
},
|
|
@@ -40545,7 +40919,7 @@ const getRemoteAgentOutputRoute = HttpRouter.add("GET", "/api/remote/workspaces/
|
|
|
40545
40919
|
})));
|
|
40546
40920
|
const tellRemoteAgentRoute = HttpRouter.add("POST", "/api/remote/workspaces/:issueId/agent/tell", httpHandler(Effect.gen(function* () {
|
|
40547
40921
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40548
|
-
const { message } = yield* readJsonBody$
|
|
40922
|
+
const { message } = yield* readJsonBody$14;
|
|
40549
40923
|
if (!message) return jsonResponse({ error: "Message is required" }, { status: 400 });
|
|
40550
40924
|
const metadata = yield* Effect.promise(() => loadRemoteWorkspaceMetadata(issueId));
|
|
40551
40925
|
if (!metadata) return jsonResponse({ error: "Remote workspace not found" }, { status: 404 });
|
|
@@ -40562,6 +40936,24 @@ const remoteRouteLayer = Layer.mergeAll(getRemoteStatusRoute, listRemoteWorkspac
|
|
|
40562
40936
|
init_providers();
|
|
40563
40937
|
init_harness_policy();
|
|
40564
40938
|
/**
|
|
40939
|
+
* Model ids legal in the `?models=` query of GET /api/settings/harness-policy.
|
|
40940
|
+
*
|
|
40941
|
+
* Square brackets are significant: the long-context variants are named
|
|
40942
|
+
* `k3[1m]` and `claude-opus-5[1m]`. The pickers batch every known model id
|
|
40943
|
+
* into one request, so rejecting a single bracketed id 400s the whole batch
|
|
40944
|
+
* and leaves every model without a policy decision.
|
|
40945
|
+
*/
|
|
40946
|
+
const SAFE_MODEL_PATTERN$2 = /^[a-zA-Z0-9_.:\/[\]-]+$/;
|
|
40947
|
+
const MAX_HARNESS_POLICY_MODELS = 250;
|
|
40948
|
+
const MAX_HARNESS_POLICY_MODEL_LENGTH = 200;
|
|
40949
|
+
/** Parse and validate the `models` query value; `null` means reject with 400. */
|
|
40950
|
+
function parseHarnessPolicyModels(rawModels) {
|
|
40951
|
+
const models = (rawModels ?? "").split(",").map((model) => model.trim()).filter(Boolean);
|
|
40952
|
+
if (models.length === 0 || models.length > MAX_HARNESS_POLICY_MODELS) return null;
|
|
40953
|
+
if (models.some((model) => model.length > MAX_HARNESS_POLICY_MODEL_LENGTH || !SAFE_MODEL_PATTERN$2.test(model))) return null;
|
|
40954
|
+
return models;
|
|
40955
|
+
}
|
|
40956
|
+
/**
|
|
40565
40957
|
* Resolve a per-model harness-policy decision map for `models`.
|
|
40566
40958
|
*
|
|
40567
40959
|
* Caches the auth-mode resolver per provider so multiple models under one
|
|
@@ -44686,7 +45078,7 @@ function consumeReindexConfirmationNonce(nonce, estimatedUsd) {
|
|
|
44686
45078
|
reindexConfirmationNonces.delete(nonce);
|
|
44687
45079
|
return !!entry && entry.expiresAt > Date.now() && Math.abs(entry.estimatedUsd - estimatedUsd) < 1e-6;
|
|
44688
45080
|
}
|
|
44689
|
-
const readJsonBody$
|
|
45081
|
+
const readJsonBody$13 = Effect.gen(function* () {
|
|
44690
45082
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
44691
45083
|
try {
|
|
44692
45084
|
return text ? JSON.parse(text) : {};
|
|
@@ -44759,7 +45151,7 @@ const getOpenAIAuthRoute = HttpRouter.add("GET", "/api/settings/openai-auth", ht
|
|
|
44759
45151
|
return jsonResponse(yield* getOpenAIAuthStatus());
|
|
44760
45152
|
})));
|
|
44761
45153
|
const postTestApiKeyRoute = HttpRouter.add("POST", "/api/settings/test-api-key", httpHandler(Effect.gen(function* () {
|
|
44762
|
-
const { provider, apiKey, model } = yield* readJsonBody$
|
|
45154
|
+
const { provider, apiKey, model } = yield* readJsonBody$13;
|
|
44763
45155
|
if (!provider || !apiKey) return jsonResponse({ error: "Provider and apiKey are required" }, { status: 400 });
|
|
44764
45156
|
return yield* Effect.promise(async () => {
|
|
44765
45157
|
let success = false;
|
|
@@ -45069,7 +45461,7 @@ const postTestApiKeyRoute = HttpRouter.add("POST", "/api/settings/test-api-key",
|
|
|
45069
45461
|
});
|
|
45070
45462
|
})));
|
|
45071
45463
|
const postValidateApiKeyRoute = HttpRouter.add("POST", "/api/settings/validate-api-key", httpHandler(Effect.gen(function* () {
|
|
45072
|
-
const { provider, apiKey } = yield* readJsonBody$
|
|
45464
|
+
const { provider, apiKey } = yield* readJsonBody$13;
|
|
45073
45465
|
if (!provider || !apiKey) return jsonResponse({ error: "Provider and apiKey are required" }, { status: 400 });
|
|
45074
45466
|
if (![
|
|
45075
45467
|
"openai",
|
|
@@ -45304,7 +45696,7 @@ const getConversationSearchReindexEstimateRoute = HttpRouter.add("GET", "/api/se
|
|
|
45304
45696
|
const postConversationSearchReindexRoute = HttpRouter.add("POST", "/api/settings/conversation-search/reindex", httpHandler(Effect.gen(function* () {
|
|
45305
45697
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
45306
45698
|
if (authError) return authError;
|
|
45307
|
-
const body = yield* readJsonBody$
|
|
45699
|
+
const body = yield* readJsonBody$13;
|
|
45308
45700
|
return yield* Effect.promise(async () => {
|
|
45309
45701
|
if (activeConversationSearchReindex) return jsonResponse({ error: "Conversation search reindex already in progress" }, { status: 409 });
|
|
45310
45702
|
const job = (async () => {
|
|
@@ -45354,7 +45746,7 @@ const getConversationSearchReindexProgressRoute = HttpRouter.add("GET", "/api/se
|
|
|
45354
45746
|
return jsonResponse(conversationReindexProgress);
|
|
45355
45747
|
})));
|
|
45356
45748
|
const putSettingsRoute = HttpRouter.add("PUT", "/api/settings", httpHandler(Effect.gen(function* () {
|
|
45357
|
-
const body = yield* readJsonBody$
|
|
45749
|
+
const body = yield* readJsonBody$13;
|
|
45358
45750
|
return yield* Effect.promise(async () => {
|
|
45359
45751
|
try {
|
|
45360
45752
|
const newSettings = body;
|
|
@@ -45375,7 +45767,7 @@ const putSettingsRoute = HttpRouter.add("PUT", "/api/settings", httpHandler(Effe
|
|
|
45375
45767
|
});
|
|
45376
45768
|
})));
|
|
45377
45769
|
const putUiThemeRoute = HttpRouter.add("PUT", "/api/settings/ui-theme", httpHandler(Effect.gen(function* () {
|
|
45378
|
-
const body = yield* readJsonBody$
|
|
45770
|
+
const body = yield* readJsonBody$13;
|
|
45379
45771
|
return yield* Effect.promise(async () => {
|
|
45380
45772
|
const theme = body?.theme;
|
|
45381
45773
|
if (theme !== "light" && theme !== "dark") return jsonResponse({ error: "theme must be 'light' or 'dark'" }, { status: 400 });
|
|
@@ -45390,7 +45782,7 @@ const getOpenRouterModelsRoute = HttpRouter.add("GET", "/api/settings/openrouter
|
|
|
45390
45782
|
});
|
|
45391
45783
|
})));
|
|
45392
45784
|
const putOpenRouterFavoritesRoute = HttpRouter.add("PUT", "/api/settings/openrouter/favorites", httpHandler(Effect.gen(function* () {
|
|
45393
|
-
const { favorites } = yield* readJsonBody$
|
|
45785
|
+
const { favorites } = yield* readJsonBody$13;
|
|
45394
45786
|
if (!Array.isArray(favorites)) return jsonResponse({ error: "favorites must be an array of model IDs" }, { status: 400 });
|
|
45395
45787
|
const modelIds = favorites.filter((f) => typeof f === "string");
|
|
45396
45788
|
return yield* Effect.promise(async () => {
|
|
@@ -45406,7 +45798,7 @@ const putOpenRouterFavoritesRoute = HttpRouter.add("PUT", "/api/settings/openrou
|
|
|
45406
45798
|
});
|
|
45407
45799
|
})));
|
|
45408
45800
|
const putOpenRouterApiKeyRoute = HttpRouter.add("PUT", "/api/settings/openrouter/api-key", httpHandler(Effect.gen(function* () {
|
|
45409
|
-
const { apiKey } = yield* readJsonBody$
|
|
45801
|
+
const { apiKey } = yield* readJsonBody$13;
|
|
45410
45802
|
if (apiKey !== void 0 && typeof apiKey !== "string") return jsonResponse({ error: "apiKey must be a string when provided" }, { status: 400 });
|
|
45411
45803
|
return yield* Effect.promise(async () => {
|
|
45412
45804
|
try {
|
|
@@ -45421,18 +45813,16 @@ const putOpenRouterApiKeyRoute = HttpRouter.add("PUT", "/api/settings/openrouter
|
|
|
45421
45813
|
});
|
|
45422
45814
|
})));
|
|
45423
45815
|
const postOpenRouterTestKeyRoute = HttpRouter.add("POST", "/api/settings/openrouter/test-key", httpHandler(Effect.gen(function* () {
|
|
45424
|
-
const { apiKey } = yield* readJsonBody$
|
|
45816
|
+
const { apiKey } = yield* readJsonBody$13;
|
|
45425
45817
|
if (!apiKey) return jsonResponse({ error: "apiKey is required" }, { status: 400 });
|
|
45426
45818
|
return jsonResponse(yield* (yield* OpenRouterService).validateApiKey(apiKey));
|
|
45427
45819
|
})));
|
|
45428
|
-
const SAFE_MODEL_PATTERN$1 = /^[a-zA-Z0-9_
|
|
45429
|
-
const MAX_HARNESS_POLICY_MODELS = 250;
|
|
45430
|
-
const MAX_HARNESS_POLICY_MODEL_LENGTH = 200;
|
|
45820
|
+
const SAFE_MODEL_PATTERN$1 = /^[a-zA-Z0-9_.:\/[\]-]+$/;
|
|
45431
45821
|
const getHarnessPolicyRoute = HttpRouter.add("GET", "/api/settings/harness-policy", httpHandler(Effect.gen(function* () {
|
|
45432
45822
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
45433
45823
|
return yield* Effect.promise(async () => {
|
|
45434
|
-
const models = (new URL(request.url, "http://localhost").searchParams.get("models")
|
|
45435
|
-
if (models
|
|
45824
|
+
const models = parseHarnessPolicyModels(new URL(request.url, "http://localhost").searchParams.get("models"));
|
|
45825
|
+
if (!models) return jsonResponse({ error: "Valid models parameter is required" }, { status: 400 });
|
|
45436
45826
|
return jsonResponse({ decisions: await buildHarnessPolicyDecisions(models, getProviderAuthMode) });
|
|
45437
45827
|
});
|
|
45438
45828
|
})));
|
|
@@ -45474,7 +45864,7 @@ const getLegacyImportPreviewRoute = HttpRouter.add("GET", "/api/settings/legacy-
|
|
|
45474
45864
|
const postLegacyImportRoute = HttpRouter.add("POST", "/api/settings/legacy-import/conversations", httpHandler(Effect.gen(function* () {
|
|
45475
45865
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
45476
45866
|
if (authError) return authError;
|
|
45477
|
-
const body = yield* readJsonBody$
|
|
45867
|
+
const body = yield* readJsonBody$13;
|
|
45478
45868
|
return yield* Effect.try({
|
|
45479
45869
|
try: () => {
|
|
45480
45870
|
const { path, names } = body;
|
|
@@ -45486,7 +45876,7 @@ const postLegacyImportRoute = HttpRouter.add("POST", "/api/settings/legacy-impor
|
|
|
45486
45876
|
const settingsRouteLayer = Layer.mergeAll(getSettingsRoute, getAvailableModelsRoute, getOptimalDefaultsRoute, getMiniMaxDefaultsRoute, getClaudeAuthRoute, getOpenAIAuthRoute, postTestApiKeyRoute, postValidateApiKeyRoute, getConversationSearchStatusRoute, getConversationSearchReindexEstimateRoute, postConversationSearchReindexRoute, getConversationSearchReindexProgressRoute, putSettingsRoute, putUiThemeRoute, getOpenRouterModelsRoute, putOpenRouterFavoritesRoute, putOpenRouterApiKeyRoute, postOpenRouterTestKeyRoute, getHarnessPolicyRoute, getProviderEnvConflictsRoute, getLegacyImportPreviewRoute, postLegacyImportRoute);
|
|
45487
45877
|
//#endregion
|
|
45488
45878
|
//#region routes/autopreso.ts
|
|
45489
|
-
const readJsonBody$
|
|
45879
|
+
const readJsonBody$12 = Effect.gen(function* () {
|
|
45490
45880
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
45491
45881
|
const contentLength = Number(request.headers["content-length"] ?? 0);
|
|
45492
45882
|
if (Number.isFinite(contentLength) && contentLength > 256e3) return {
|
|
@@ -45517,7 +45907,7 @@ function requireTrustedOrigin$1(request) {
|
|
|
45517
45907
|
const startRoute = HttpRouter.add("POST", "/api/autopreso/start", httpHandler(Effect.gen(function* () {
|
|
45518
45908
|
const originError = requireTrustedOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
45519
45909
|
if (originError) return originError;
|
|
45520
|
-
const parsed = yield* readJsonBody$
|
|
45910
|
+
const parsed = yield* readJsonBody$12;
|
|
45521
45911
|
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 413 });
|
|
45522
45912
|
const elements = readElementLikes(parsed.body);
|
|
45523
45913
|
const validation = validateAutoPresoCanvasElements(elements);
|
|
@@ -45550,6 +45940,7 @@ const autopresoRouteLayer = Layer.mergeAll(startRoute, backToStagingRoute, reset
|
|
|
45550
45940
|
* GET /api/activity/:id
|
|
45551
45941
|
*/
|
|
45552
45942
|
init_domain_services();
|
|
45943
|
+
init_read_model();
|
|
45553
45944
|
init_agents$1();
|
|
45554
45945
|
init_review_status();
|
|
45555
45946
|
init_cost_sync();
|
|
@@ -45630,16 +46021,7 @@ const getMetricsStuckRoute = HttpRouter.add("GET", "/api/metrics/stuck", httpHan
|
|
|
45630
46021
|
});
|
|
45631
46022
|
})));
|
|
45632
46023
|
const getActivityRoute = HttpRouter.add("GET", "/api/activity", httpHandler(Effect.gen(function* () {
|
|
45633
|
-
return jsonResponse((yield* (yield* EventStoreService).queryByType("activity.entry", 100))
|
|
45634
|
-
id: e.payload["id"],
|
|
45635
|
-
timestamp: e.timestamp,
|
|
45636
|
-
source: e.payload["source"],
|
|
45637
|
-
level: e.payload["level"],
|
|
45638
|
-
message: e.payload["message"],
|
|
45639
|
-
details: e.payload["details"],
|
|
45640
|
-
issueId: e.payload["issueId"],
|
|
45641
|
-
link: e.payload["link"]
|
|
45642
|
-
})));
|
|
46024
|
+
return jsonResponse(activityEntriesFromStoredEvents(yield* (yield* EventStoreService).queryByType("activity.entry", 300), 100));
|
|
45643
46025
|
})));
|
|
45644
46026
|
const getActivityDetailedRoute = HttpRouter.add("GET", "/api/activity/detailed", httpHandler(Effect.gen(function* () {
|
|
45645
46027
|
return jsonResponse((yield* (yield* EventStoreService).queryByType("activity.detailed", 200)).map((e) => ({
|
|
@@ -45666,16 +46048,19 @@ const getActivityByIdRoute = HttpRouter.add("GET", "/api/activity/:id", httpHand
|
|
|
45666
46048
|
const params = yield* HttpRouter.params;
|
|
45667
46049
|
const eventStore = yield* EventStoreService;
|
|
45668
46050
|
const id = params["id"] ?? "";
|
|
45669
|
-
const activity = (yield* eventStore.queryByType("activity.entry", 1e3)).find((
|
|
46051
|
+
const activity = activityEntriesFromStoredEvents(yield* eventStore.queryByType("activity.entry", 1e3), 1e3).find((entry) => entry["id"] === id);
|
|
45670
46052
|
if (!activity) return jsonResponse({ error: "Activity not found" }, { status: 404 });
|
|
45671
46053
|
return jsonResponse({
|
|
45672
|
-
id: activity
|
|
45673
|
-
timestamp: activity
|
|
45674
|
-
source: activity
|
|
45675
|
-
level: activity
|
|
45676
|
-
|
|
45677
|
-
|
|
45678
|
-
|
|
46054
|
+
id: activity["id"],
|
|
46055
|
+
timestamp: activity["timestamp"],
|
|
46056
|
+
source: activity["source"],
|
|
46057
|
+
level: activity["level"],
|
|
46058
|
+
status: activity["status"],
|
|
46059
|
+
command: activity["command"],
|
|
46060
|
+
message: activity["message"],
|
|
46061
|
+
details: activity["details"],
|
|
46062
|
+
output: activity["output"],
|
|
46063
|
+
issueId: activity["issueId"]
|
|
45679
46064
|
});
|
|
45680
46065
|
})));
|
|
45681
46066
|
/** Parse and validate query params for GET /api/git-activity. Exported for unit testing. */
|
|
@@ -45723,7 +46108,7 @@ const metricsRouteLayer = Layer.mergeAll(getMetricsSummaryRoute, getMetricsCosts
|
|
|
45723
46108
|
//#region routes/boot-reconciliation.ts
|
|
45724
46109
|
init_tmux();
|
|
45725
46110
|
init_control_settings();
|
|
45726
|
-
const readJsonBody$
|
|
46111
|
+
const readJsonBody$11 = Effect.gen(function* () {
|
|
45727
46112
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
45728
46113
|
try {
|
|
45729
46114
|
return text ? JSON.parse(text) : {};
|
|
@@ -45734,7 +46119,7 @@ const readJsonBody$10 = Effect.gen(function* () {
|
|
|
45734
46119
|
function bootReconciliationWhyStopped(agent) {
|
|
45735
46120
|
if (agent.paused === true) return agent.pausedReason ? `paused: ${agent.pausedReason}` : "paused";
|
|
45736
46121
|
if (agent.troubled === true) return "troubled";
|
|
45737
|
-
if (agent.stoppedByUser === true
|
|
46122
|
+
if (agent.stoppedByUser === true) return "stopped by operator";
|
|
45738
46123
|
if (agent.status === "stopped" && agent.sessionId && !sessionExists(agent.sessionId)) return "orphaned: tmux session missing";
|
|
45739
46124
|
if (agent.status === "stopped") return "stopped cleanly";
|
|
45740
46125
|
if (agent.hostOverride) return "running remote";
|
|
@@ -45752,7 +46137,7 @@ function bootReconciliationReadOnly(agent) {
|
|
|
45752
46137
|
const getBootReconciliationRoute = HttpRouter.add("GET", "/api/boot-reconciliation", Effect.sync(() => {
|
|
45753
46138
|
const state = getBootReconciliationState();
|
|
45754
46139
|
const candidateIds = new Set(listBootReconciliationCandidates().map((agent) => agent.id));
|
|
45755
|
-
const
|
|
46140
|
+
const toRow = (agent) => ({
|
|
45756
46141
|
id: agent.id,
|
|
45757
46142
|
issueId: agent.issueId,
|
|
45758
46143
|
role: agent.role,
|
|
@@ -45762,13 +46147,32 @@ const getBootReconciliationRoute = HttpRouter.add("GET", "/api/boot-reconciliati
|
|
|
45762
46147
|
lastActivity: agent.lastActivity ?? agent.updatedAt ?? null,
|
|
45763
46148
|
cost: agent.costSoFar ?? null,
|
|
45764
46149
|
remote: Boolean(agent.hostOverride),
|
|
46150
|
+
stoppedByUser: agent.stoppedByUser === true,
|
|
45765
46151
|
readOnly: bootReconciliationReadOnly(agent)
|
|
45766
|
-
})
|
|
46152
|
+
});
|
|
46153
|
+
const autoResumableAgents = listAllAgentsSync().filter((agent) => isAutoResumableRole(agent.role));
|
|
46154
|
+
const set = autoResumableAgents.filter((agent) => candidateIds.has(agent.id)).map(toRow);
|
|
46155
|
+
const context = autoResumableAgents.filter((agent) => !candidateIds.has(agent.id) && (agent.paused === true || agent.troubled === true || Boolean(agent.hostOverride))).map(toRow);
|
|
46156
|
+
let heldCount = 0;
|
|
46157
|
+
if (state.decision === "hold_all") heldCount = set.length;
|
|
46158
|
+
else if (state.decision === "per_agent") heldCount = set.filter((agent) => state.perAgent[agent.issueId] !== "resume").length;
|
|
45767
46159
|
return jsonResponse({
|
|
45768
46160
|
...state,
|
|
45769
|
-
|
|
46161
|
+
maxGraceExtensions: 3,
|
|
46162
|
+
heldCount,
|
|
46163
|
+
set,
|
|
46164
|
+
context
|
|
45770
46165
|
});
|
|
45771
46166
|
}));
|
|
46167
|
+
/**
|
|
46168
|
+
* Push the grace deadline out while the operator is answering a different
|
|
46169
|
+
* blocking dialog. Bounded server-side by MAX_BOOT_RECONCILIATION_GRACE_EXTENSIONS;
|
|
46170
|
+
* the client may call this freely and the cap decides.
|
|
46171
|
+
*/
|
|
46172
|
+
const postBootReconciliationExtendRoute = HttpRouter.add("POST", "/api/boot-reconciliation/extend", httpHandler(Effect.sync(() => jsonResponse({
|
|
46173
|
+
ok: true,
|
|
46174
|
+
...extendBootReconciliationGrace()
|
|
46175
|
+
}))));
|
|
45772
46176
|
function isBootReconciliationDecision(value) {
|
|
45773
46177
|
return value === "resume_all" || value === "hold_all" || value === "per_agent";
|
|
45774
46178
|
}
|
|
@@ -45779,14 +46183,14 @@ function parsePerAgentMap(value) {
|
|
|
45779
46183
|
return parsed;
|
|
45780
46184
|
}
|
|
45781
46185
|
const postBootReconciliationDecisionRoute = HttpRouter.add("POST", "/api/boot-reconciliation/decision", httpHandler(Effect.gen(function* () {
|
|
45782
|
-
const body = yield* readJsonBody$
|
|
46186
|
+
const body = yield* readJsonBody$11;
|
|
45783
46187
|
if (!isBootReconciliationDecision(body.decision)) return jsonResponse({
|
|
45784
46188
|
ok: false,
|
|
45785
46189
|
error: "Body must include decision resume_all, hold_all, or per_agent"
|
|
45786
46190
|
}, { status: 400 });
|
|
45787
46191
|
const perAgent = body.decision === "per_agent" ? parsePerAgentMap(body.perAgent) : {};
|
|
45788
46192
|
setBootReconciliationDecision(body.decision, perAgent);
|
|
45789
|
-
const result = yield* Effect.promise(() => applyBootReconciliationDecision());
|
|
46193
|
+
const result = yield* Effect.promise(() => applyBootReconciliationDecision({ origin: "operator" }));
|
|
45790
46194
|
const resumed = result.resumed;
|
|
45791
46195
|
return jsonResponse({
|
|
45792
46196
|
ok: true,
|
|
@@ -45799,7 +46203,7 @@ const postBootReconciliationDecisionRoute = HttpRouter.add("POST", "/api/boot-re
|
|
|
45799
46203
|
count: resumed.length
|
|
45800
46204
|
});
|
|
45801
46205
|
})));
|
|
45802
|
-
const bootReconciliationRouteLayer = Layer.mergeAll(getBootReconciliationRoute, postBootReconciliationDecisionRoute);
|
|
46206
|
+
const bootReconciliationRouteLayer = Layer.mergeAll(getBootReconciliationRoute, postBootReconciliationDecisionRoute, postBootReconciliationExtendRoute);
|
|
45803
46207
|
//#endregion
|
|
45804
46208
|
//#region routes/misc/shared.ts
|
|
45805
46209
|
init_projects();
|
|
@@ -45876,7 +46280,7 @@ function getGitHubLocalPaths() {
|
|
|
45876
46280
|
}
|
|
45877
46281
|
return out;
|
|
45878
46282
|
}
|
|
45879
|
-
const readJsonBody$
|
|
46283
|
+
const readJsonBody$10 = Effect.gen(function* () {
|
|
45880
46284
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
45881
46285
|
try {
|
|
45882
46286
|
return text ? JSON.parse(text) : {};
|
|
@@ -45888,7 +46292,7 @@ const readJsonBody$9 = Effect.gen(function* () {
|
|
|
45888
46292
|
//#region routes/misc/project-mappings.ts
|
|
45889
46293
|
const getProjectMappingsRoute = HttpRouter.add("GET", "/api/project-mappings", httpHandler(Effect.promise(() => getProjectMappings().then((m) => jsonResponse(m)))));
|
|
45890
46294
|
const putProjectMappingsRoute = HttpRouter.add("PUT", "/api/project-mappings", Effect.gen(function* () {
|
|
45891
|
-
const mappings = yield* readJsonBody$
|
|
46295
|
+
const mappings = yield* readJsonBody$10;
|
|
45892
46296
|
if (!Array.isArray(mappings)) return jsonResponse({ error: "Expected array of mappings" }, { status: 400 });
|
|
45893
46297
|
yield* Effect.promise(() => saveProjectMappings(mappings));
|
|
45894
46298
|
return jsonResponse({
|
|
@@ -45897,7 +46301,7 @@ const putProjectMappingsRoute = HttpRouter.add("PUT", "/api/project-mappings", E
|
|
|
45897
46301
|
});
|
|
45898
46302
|
}));
|
|
45899
46303
|
const postProjectMappingsRoute = HttpRouter.add("POST", "/api/project-mappings", Effect.gen(function* () {
|
|
45900
|
-
const { linearProjectId, linearProjectName, linearPrefix, localPath } = yield* readJsonBody$
|
|
46304
|
+
const { linearProjectId, linearProjectName, linearPrefix, localPath } = yield* readJsonBody$10;
|
|
45901
46305
|
if (!linearProjectId || !localPath) return jsonResponse({ error: "linearProjectId and localPath required" }, { status: 400 });
|
|
45902
46306
|
return yield* Effect.promise(async () => {
|
|
45903
46307
|
try {
|
|
@@ -45924,7 +46328,7 @@ const postProjectMappingsRoute = HttpRouter.add("POST", "/api/project-mappings",
|
|
|
45924
46328
|
const projectMappingsRouteLayer = Layer.mergeAll(getProjectMappingsRoute, putProjectMappingsRoute, postProjectMappingsRoute);
|
|
45925
46329
|
//#endregion
|
|
45926
46330
|
//#region routes/misc/trackers.ts
|
|
45927
|
-
init_config();
|
|
46331
|
+
init_config$1();
|
|
45928
46332
|
init_config_yaml();
|
|
45929
46333
|
init_projects();
|
|
45930
46334
|
init_tracker_config();
|
|
@@ -46004,14 +46408,14 @@ const getTrackerStatusRoute = HttpRouter.add("GET", "/api/tracker-status", Effec
|
|
|
46004
46408
|
}
|
|
46005
46409
|
}));
|
|
46006
46410
|
const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Effect.gen(function* () {
|
|
46007
|
-
const { apiKey, server, workspace, project } = yield* readJsonBody$
|
|
46411
|
+
const { apiKey, server, workspace, project } = yield* readJsonBody$10;
|
|
46008
46412
|
if (!apiKey) return jsonResponse({
|
|
46009
46413
|
valid: false,
|
|
46010
46414
|
error: "API key is required"
|
|
46011
46415
|
}, { status: 400 });
|
|
46012
46416
|
return yield* Effect.promise(async () => {
|
|
46013
46417
|
try {
|
|
46014
|
-
const { RallyRestApi } = await import("./rally-api-
|
|
46418
|
+
const { RallyRestApi } = await import("./rally-api-CgosKdKL.js");
|
|
46015
46419
|
const api = new RallyRestApi({
|
|
46016
46420
|
apiKey,
|
|
46017
46421
|
server: server || "https://rally1.rallydev.com"
|
|
@@ -46353,7 +46757,7 @@ const getDeaconPauseRoute = HttpRouter.add("GET", "/api/deacon/pause", Effect.tr
|
|
|
46353
46757
|
* Persists to `app_settings` so the flag survives dashboard restarts.
|
|
46354
46758
|
*/
|
|
46355
46759
|
const postDeaconPauseRoute = HttpRouter.add("POST", "/api/deacon/pause", httpHandler(Effect.gen(function* () {
|
|
46356
|
-
const body = yield* readJsonBody$
|
|
46760
|
+
const body = yield* readJsonBody$10;
|
|
46357
46761
|
if (typeof body.paused !== "boolean") return jsonResponse({ error: "Body must include { paused: boolean }" }, { status: 400 });
|
|
46358
46762
|
setDeaconGloballyPausedSync(body.paused);
|
|
46359
46763
|
console.log(`[deacon] Global pause flag set to ${body.paused}`);
|
|
@@ -46365,6 +46769,7 @@ const deaconRouteLayer = Layer.mergeAll(getNoResumeModeRoute, postResumeAllRoute
|
|
|
46365
46769
|
init_config_yaml();
|
|
46366
46770
|
init_issue_id();
|
|
46367
46771
|
init_types();
|
|
46772
|
+
init_paths();
|
|
46368
46773
|
init_projects();
|
|
46369
46774
|
init_remote_agents();
|
|
46370
46775
|
init_tmux();
|
|
@@ -46396,7 +46801,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
|
|
|
46396
46801
|
const remoteState = loadRemoteAgentState(sessionName);
|
|
46397
46802
|
const isRemote = !!remoteState;
|
|
46398
46803
|
const vmName = remoteState?.vmName ?? "";
|
|
46399
|
-
const { getAgentStateSync } = await import("./agents-
|
|
46804
|
+
const { getAgentStateSync } = await import("./agents-ePFVoZbu.js");
|
|
46400
46805
|
const agentStarting = getAgentStateSync(sessionName)?.status === "starting";
|
|
46401
46806
|
let tmuxSessionAlive = false;
|
|
46402
46807
|
if (!isRemote) try {
|
|
@@ -46448,7 +46853,7 @@ const postPlanningMessageRoute = HttpRouter.add("POST", "/api/planning/:issueId/
|
|
|
46448
46853
|
const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
|
|
46449
46854
|
const sessionName = `planning-${issueId.toLowerCase()}`;
|
|
46450
46855
|
const issueLower = issueId.toLowerCase();
|
|
46451
|
-
const { message } = yield* readJsonBody$
|
|
46856
|
+
const { message } = yield* readJsonBody$10;
|
|
46452
46857
|
const eventStore = yield* EventStoreService;
|
|
46453
46858
|
if (!message) return jsonResponse({ error: "Message required" }, { status: 400 });
|
|
46454
46859
|
return yield* Effect.promise(async () => {
|
|
@@ -46540,7 +46945,7 @@ Continue the PLANNING session. Do NOT implement anything.
|
|
|
46540
46945
|
const agentCwd = workspacePath;
|
|
46541
46946
|
const harnessLaunch = await prepareHarnessLaunch("claude-code");
|
|
46542
46947
|
if (existsSync$1(outputFile)) await rename(outputFile, join(planningDir, `output-${Date.now()}.jsonl`));
|
|
46543
|
-
const { getAgentCommandSync } = await import("./settings-
|
|
46948
|
+
const { getAgentCommandSync } = await import("./settings-CVmWiJ-r.js");
|
|
46544
46949
|
let msgPlanningModel = "claude-sonnet-5";
|
|
46545
46950
|
try {
|
|
46546
46951
|
msgPlanningModel = resolveModel("plan", void 0, loadConfigSync().config);
|
|
@@ -46548,6 +46953,7 @@ Continue the PLANNING session. Do NOT implement anything.
|
|
|
46548
46953
|
const msgAgentCmd = getAgentCommandSync(msgPlanningModel);
|
|
46549
46954
|
const msgPermissionFlags = getClaudePermissionFlagsStringSync();
|
|
46550
46955
|
const msgCmdWithArgs = msgAgentCmd.args.length > 0 ? `${msgAgentCmd.command} ${msgAgentCmd.args.join(" ")} ${msgPermissionFlags}` : `${msgAgentCmd.command} ${msgPermissionFlags}`;
|
|
46956
|
+
const agentStateDir = join(getOverdeckHome(), "agents", sessionName);
|
|
46551
46957
|
const launcherScript = join(agentStateDir, "continuation-launcher.sh");
|
|
46552
46958
|
await mkdir(agentStateDir, { recursive: true });
|
|
46553
46959
|
await writeFile(launcherScript, generateLauncherScriptSync({
|
|
@@ -46662,7 +47068,7 @@ async function getIndexStats(rootPath, isMain) {
|
|
|
46662
47068
|
}
|
|
46663
47069
|
const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Effect.promise(async () => {
|
|
46664
47070
|
try {
|
|
46665
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
47071
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CvWXBhX1.js");
|
|
46666
47072
|
const projectRoot = process.cwd();
|
|
46667
47073
|
const venvPath = join(projectRoot, ".venv");
|
|
46668
47074
|
const results = [];
|
|
@@ -46707,7 +47113,7 @@ const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Ef
|
|
|
46707
47113
|
}));
|
|
46708
47114
|
const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Effect.promise(async () => {
|
|
46709
47115
|
try {
|
|
46710
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
47116
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CvWXBhX1.js");
|
|
46711
47117
|
const projectRoot = process.cwd();
|
|
46712
47118
|
const venvPath = join(projectRoot, ".venv");
|
|
46713
47119
|
if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
|
|
@@ -46724,7 +47130,7 @@ const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Ef
|
|
|
46724
47130
|
}));
|
|
46725
47131
|
const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effect.promise(async () => {
|
|
46726
47132
|
try {
|
|
46727
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
47133
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CvWXBhX1.js");
|
|
46728
47134
|
const projectRoot = process.cwd();
|
|
46729
47135
|
const venvPath = join(projectRoot, ".venv");
|
|
46730
47136
|
if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
|
|
@@ -46741,7 +47147,7 @@ const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effe
|
|
|
46741
47147
|
}));
|
|
46742
47148
|
const postTldrReloadRoute = HttpRouter.add("POST", "/api/services/tldr/reload", Effect.promise(async () => {
|
|
46743
47149
|
try {
|
|
46744
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
47150
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CvWXBhX1.js");
|
|
46745
47151
|
const enabled = isTldrEnabledSync();
|
|
46746
47152
|
const projectRoot = process.cwd();
|
|
46747
47153
|
const targets = [];
|
|
@@ -46904,7 +47310,7 @@ init_tracker_config();
|
|
|
46904
47310
|
init_issue_id();
|
|
46905
47311
|
init_projects();
|
|
46906
47312
|
init_tmux();
|
|
46907
|
-
const execAsync$
|
|
47313
|
+
const execAsync$4 = promisify(exec);
|
|
46908
47314
|
const execFileAsync$6 = promisify(execFile);
|
|
46909
47315
|
function getIssueDataService$1() {
|
|
46910
47316
|
const { getSharedIssueService } = (init_issue_service_singleton(), __toCommonJS(issue_service_singleton_exports));
|
|
@@ -46929,7 +47335,7 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
|
|
|
46929
47335
|
const version = await getOverdeckVersion();
|
|
46930
47336
|
let supervisorUrl = null;
|
|
46931
47337
|
try {
|
|
46932
|
-
const { getSupervisorUrlSync } = await import("./supervisor-
|
|
47338
|
+
const { getSupervisorUrlSync } = await import("./supervisor-B4anCCSm.js");
|
|
46933
47339
|
supervisorUrl = getSupervisorUrlSync();
|
|
46934
47340
|
} catch {}
|
|
46935
47341
|
return jsonResponse({
|
|
@@ -46939,11 +47345,11 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
|
|
|
46939
47345
|
});
|
|
46940
47346
|
}));
|
|
46941
47347
|
const getPrerequisitesRoute = HttpRouter.add("GET", "/api/prerequisites", Effect.promise(async () => {
|
|
46942
|
-
const { checkSystemPrerequisites } = await import("./system-prerequisites-
|
|
47348
|
+
const { checkSystemPrerequisites } = await import("./system-prerequisites-ICLSkhhZ.js");
|
|
46943
47349
|
return jsonResponse(await checkSystemPrerequisites());
|
|
46944
47350
|
}));
|
|
46945
47351
|
const getSetupDiagnosticsRoute = HttpRouter.add("GET", "/api/diagnostics/setup", Effect.promise(async () => {
|
|
46946
|
-
const { collectSetupDiagnostics } = await import("./system-prerequisites-
|
|
47352
|
+
const { collectSetupDiagnostics } = await import("./system-prerequisites-ICLSkhhZ.js");
|
|
46947
47353
|
return jsonResponse(await collectSetupDiagnostics(await getOverdeckVersion()));
|
|
46948
47354
|
}));
|
|
46949
47355
|
const getSyncStatusRoute = HttpRouter.add("GET", "/api/sync-status", Effect.sync(() => {
|
|
@@ -46975,6 +47381,7 @@ const getRegisteredProjectsRoute = HttpRouter.add("GET", "/api/registered-projec
|
|
|
46975
47381
|
name: p.config.name,
|
|
46976
47382
|
path: p.config.path,
|
|
46977
47383
|
linearTeam: getIssuePrefix(p.config) || null,
|
|
47384
|
+
membershipQueryable: Boolean(getIssuePrefix(p.config)),
|
|
46978
47385
|
githubRepo: p.config.github_repo || null,
|
|
46979
47386
|
linearProject: p.config.linear_project || null
|
|
46980
47387
|
})));
|
|
@@ -46987,7 +47394,7 @@ const getConfirmationsRoute = HttpRouter.add("GET", "/api/confirmations", Effect
|
|
|
46987
47394
|
const postConfirmationRespondRoute = HttpRouter.add("POST", "/api/confirmations/:id/respond", Effect.gen(function* () {
|
|
46988
47395
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
46989
47396
|
const id = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
|
|
46990
|
-
const { confirmed } = yield* readJsonBody$
|
|
47397
|
+
const { confirmed } = yield* readJsonBody$10;
|
|
46991
47398
|
const confirmationRequest = pendingConfirmations.get(id);
|
|
46992
47399
|
if (!confirmationRequest) return jsonResponse({ error: "Confirmation request not found" }, { status: 404 });
|
|
46993
47400
|
return yield* Effect.promise(async () => {
|
|
@@ -47123,7 +47530,7 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
|
|
|
47123
47530
|
const projectPath = await getProjectPath(issuePrefix);
|
|
47124
47531
|
const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
|
|
47125
47532
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
47126
|
-
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-
|
|
47533
|
+
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-DXvx77oE.js");
|
|
47127
47534
|
const config = {
|
|
47128
47535
|
issueId,
|
|
47129
47536
|
workspacePath,
|
|
@@ -47145,7 +47552,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
|
|
|
47145
47552
|
const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
|
|
47146
47553
|
const issueLower = issueId.toLowerCase();
|
|
47147
47554
|
const issuePrefix = extractPrefixSync(issueId) ?? issueId.split("-")[0];
|
|
47148
|
-
const { mode } = yield* readJsonBody$
|
|
47555
|
+
const { mode } = yield* readJsonBody$10;
|
|
47149
47556
|
return yield* Effect.promise(async () => {
|
|
47150
47557
|
try {
|
|
47151
47558
|
const projectPath = await getProjectPath(issuePrefix);
|
|
@@ -47153,7 +47560,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
|
|
|
47153
47560
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
47154
47561
|
const ghConfig = getGitHubConfig();
|
|
47155
47562
|
if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
|
|
47156
|
-
const { runObserverCycle } = await import("./shadow-engineering-
|
|
47563
|
+
const { runObserverCycle } = await import("./shadow-engineering-DXvx77oE.js");
|
|
47157
47564
|
const firstRepo = ghConfig.repos[0];
|
|
47158
47565
|
const config = {
|
|
47159
47566
|
issueId,
|
|
@@ -47185,7 +47592,7 @@ const postDevRebuildRoute = HttpRouter.add("POST", "/api/dev/rebuild", Effect.ge
|
|
|
47185
47592
|
if (!overdeckDevMode || !overdeckProjectRoot) return jsonResponse({ error: "Rebuild only available in dev mode" }, { status: 403 });
|
|
47186
47593
|
return yield* Effect.promise(async () => {
|
|
47187
47594
|
try {
|
|
47188
|
-
const { stdout, stderr } = await execAsync$
|
|
47595
|
+
const { stdout, stderr } = await execAsync$4("npm run build", {
|
|
47189
47596
|
cwd: overdeckProjectRoot,
|
|
47190
47597
|
timeout: 12e4
|
|
47191
47598
|
});
|
|
@@ -48538,6 +48945,7 @@ async function getConversationDiffTurn(name, turnId, fileFilter, deps) {
|
|
|
48538
48945
|
}
|
|
48539
48946
|
//#endregion
|
|
48540
48947
|
//#region ../../lib/conversations/discovered-session-file.ts
|
|
48948
|
+
init_discovered_sessions();
|
|
48541
48949
|
async function resolveDiscoveredSessionFile(locator) {
|
|
48542
48950
|
if (!locator) return null;
|
|
48543
48951
|
const discovered = getDiscoveredSessionBySessionId(locator);
|
|
@@ -48668,8 +49076,12 @@ function titleTranscriptWindow(transcript) {
|
|
|
48668
49076
|
* production code into the live checkout (main saw `fs-lock.ts` appear from a
|
|
48669
49077
|
* dead session). Three independent gates:
|
|
48670
49078
|
*
|
|
48671
|
-
* - `--
|
|
48672
|
-
* cwd and `~/.claude` — a repo's permissive
|
|
49079
|
+
* - `--safe-mode` + `--setting-sources ''` skip hooks, settings allowlists,
|
|
49080
|
+
* MCP, and CLAUDE.md from the cwd and `~/.claude` — a repo's permissive
|
|
49081
|
+
* settings can never re-arm it. (Formerly `--bare`, but as of Claude Code
|
|
49082
|
+
* 2.1.209 `--bare` also skips credential reads, so every spawn failed with
|
|
49083
|
+
* "Not logged in" under subscription OAuth; `--safe-mode` explicitly keeps
|
|
49084
|
+
* auth working.)
|
|
48673
49085
|
* - `--tools ''` + `--disallowedTools mcp__*` strip every built-in and MCP
|
|
48674
49086
|
* tool so the model never sees a tool definition;
|
|
48675
49087
|
* - `--permission-mode dontAsk` auto-denies (never prompts, never hangs) if
|
|
@@ -48681,7 +49093,9 @@ function titleTranscriptWindow(transcript) {
|
|
|
48681
49093
|
function buildStructuredClaudeArgs(schema, model) {
|
|
48682
49094
|
return [
|
|
48683
49095
|
"-p",
|
|
48684
|
-
"--
|
|
49096
|
+
"--safe-mode",
|
|
49097
|
+
"--setting-sources",
|
|
49098
|
+
"",
|
|
48685
49099
|
"--tools",
|
|
48686
49100
|
"",
|
|
48687
49101
|
"--disallowedTools",
|
|
@@ -48896,6 +49310,153 @@ function isNonEmptyJsonlLine(buffer) {
|
|
|
48896
49310
|
return buffer.subarray(0, end).some((byte) => byte !== 32 && byte !== 9);
|
|
48897
49311
|
}
|
|
48898
49312
|
//#endregion
|
|
49313
|
+
//#region ../../lib/overdeck/conversation-pane-choice.ts
|
|
49314
|
+
init_transcript_adapter();
|
|
49315
|
+
init_summary_fork();
|
|
49316
|
+
init_conversation_compaction();
|
|
49317
|
+
/**
|
|
49318
|
+
* PAN-3113 — surface blocking numbered-choice menus in claude-code
|
|
49319
|
+
* conversation panes (the session-resume gate is the driving case) as
|
|
49320
|
+
* actionable pending input, and answer them from the dashboard.
|
|
49321
|
+
*
|
|
49322
|
+
* Detection is request-driven, not a patrol: the pending-input feed already
|
|
49323
|
+
* polls every few seconds, so detection rides that cycle — when the menu
|
|
49324
|
+
* disappears (answered from the dashboard OR directly in the terminal) the
|
|
49325
|
+
* next poll simply stops reporting it. No server-side state machine, no
|
|
49326
|
+
* stale records.
|
|
49327
|
+
*
|
|
49328
|
+
* Answering re-captures uncached, verifies the menu the operator saw is still
|
|
49329
|
+
* the menu on screen (signature match), drives the selection with literal
|
|
49330
|
+
* keystrokes (Up/Down + Enter via sendRawKeystroke), then re-captures to
|
|
49331
|
+
* confirm the menu dismissed — the same contract as the Codex TUI approval
|
|
49332
|
+
* flow (`handleConversationCodexApproval`).
|
|
49333
|
+
*/
|
|
49334
|
+
init_conversations();
|
|
49335
|
+
init_behavior();
|
|
49336
|
+
init_tmux();
|
|
49337
|
+
const PANE_CAPTURE_LINES = 90;
|
|
49338
|
+
const KEYSTROKE_GAP_MS = 60;
|
|
49339
|
+
const DELIVERY_CONFIRM_WAIT_MS = 700;
|
|
49340
|
+
function isClaudeCodeConversation(conv) {
|
|
49341
|
+
return getHarnessBehavior(conv.harness).transcriptKind === "claude-jsonl";
|
|
49342
|
+
}
|
|
49343
|
+
/**
|
|
49344
|
+
* Parse the conversation's current pane for a blocking numbered-choice menu.
|
|
49345
|
+
* Returns null when the conversation is not claude-code, the capture fails,
|
|
49346
|
+
* or no menu is on screen. Detection-only callers (the pending-input feed)
|
|
49347
|
+
* use the shared cached capture; the answer path captures uncached.
|
|
49348
|
+
*/
|
|
49349
|
+
async function claudeConversationPaneChoice(conv, options = {}) {
|
|
49350
|
+
if (!isClaudeCodeConversation(conv)) return null;
|
|
49351
|
+
const capture = options.capture ?? ((sessionName, lines) => capturePaneText(sessionName, lines));
|
|
49352
|
+
let pane;
|
|
49353
|
+
try {
|
|
49354
|
+
pane = await capture(conv.tmuxSession, PANE_CAPTURE_LINES);
|
|
49355
|
+
} catch {
|
|
49356
|
+
return null;
|
|
49357
|
+
}
|
|
49358
|
+
const menu = parsePaneChoiceMenu(pane);
|
|
49359
|
+
if (!menu) return null;
|
|
49360
|
+
return {
|
|
49361
|
+
signature: paneChoiceMenuSignature(menu),
|
|
49362
|
+
title: menu.title,
|
|
49363
|
+
contextLines: menu.contextLines,
|
|
49364
|
+
options: menu.options.map((o) => ({
|
|
49365
|
+
number: o.number,
|
|
49366
|
+
label: o.label,
|
|
49367
|
+
recommended: o.recommended
|
|
49368
|
+
})),
|
|
49369
|
+
selectedIndex: menu.selectedIndex,
|
|
49370
|
+
footerHint: menu.footerHint,
|
|
49371
|
+
confidence: menu.confidence
|
|
49372
|
+
};
|
|
49373
|
+
}
|
|
49374
|
+
/**
|
|
49375
|
+
* POST /api/conversations/:id/pane-choice — answer the live pane menu.
|
|
49376
|
+
*
|
|
49377
|
+
* Body: `{ selectedIndex: number (0-based), signature: string }`. The
|
|
49378
|
+
* signature must match the menu currently on screen, or the operator answered
|
|
49379
|
+
* a stale card and we refuse (409) rather than send keystrokes into a
|
|
49380
|
+
* different prompt. Returns a plain `{ body, status }` for the route to
|
|
49381
|
+
* serialize — the same shape as the conversation-read handlers, so the
|
|
49382
|
+
* contract is unit-testable without an HTTP layer.
|
|
49383
|
+
*/
|
|
49384
|
+
async function handleConversationPaneChoiceAnswer(rawId, body, deps = {}) {
|
|
49385
|
+
try {
|
|
49386
|
+
const selectedIndex = Number(body["selectedIndex"]);
|
|
49387
|
+
const signature = typeof body["signature"] === "string" ? body["signature"] : "";
|
|
49388
|
+
if (!Number.isInteger(selectedIndex) || selectedIndex < 0 || selectedIndex > 8) return {
|
|
49389
|
+
body: { error: "selectedIndex must be an integer 0-8" },
|
|
49390
|
+
status: 400
|
|
49391
|
+
};
|
|
49392
|
+
if (!signature) return {
|
|
49393
|
+
body: { error: "signature is required" },
|
|
49394
|
+
status: 400
|
|
49395
|
+
};
|
|
49396
|
+
const numericId = Number(rawId);
|
|
49397
|
+
const conv = !Number.isNaN(numericId) && /^\d+$/.test(rawId) ? getConversationById(numericId) : getConversationByName(rawId);
|
|
49398
|
+
if (!conv) return {
|
|
49399
|
+
body: { error: "Conversation not found" },
|
|
49400
|
+
status: 404
|
|
49401
|
+
};
|
|
49402
|
+
if (!isClaudeCodeConversation(conv)) return {
|
|
49403
|
+
body: { error: "Not a Claude Code conversation" },
|
|
49404
|
+
status: 400
|
|
49405
|
+
};
|
|
49406
|
+
if (!await (deps.sessionExists ?? tmuxSessionExists)(conv.tmuxSession)) return {
|
|
49407
|
+
body: { error: "Conversation session is not running" },
|
|
49408
|
+
status: 409
|
|
49409
|
+
};
|
|
49410
|
+
const capture = deps.capture ?? ((sessionName, lines) => capturePaneText(sessionName, lines));
|
|
49411
|
+
const sendKey = deps.sendKey ?? ((sessionName, key) => Effect.runPromise(sendRawKeystroke(sessionName, key, "pane-choice")));
|
|
49412
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
49413
|
+
const menu = parsePaneChoiceMenu(await capture(conv.tmuxSession, PANE_CAPTURE_LINES));
|
|
49414
|
+
if (!menu) return {
|
|
49415
|
+
body: {
|
|
49416
|
+
error: "The choice menu is no longer on screen",
|
|
49417
|
+
code: "menu-gone"
|
|
49418
|
+
},
|
|
49419
|
+
status: 409
|
|
49420
|
+
};
|
|
49421
|
+
if (paneChoiceMenuSignature(menu) !== signature) return {
|
|
49422
|
+
body: {
|
|
49423
|
+
error: "The choice menu changed since the card was rendered — refresh and re-answer",
|
|
49424
|
+
code: "menu-changed"
|
|
49425
|
+
},
|
|
49426
|
+
status: 409
|
|
49427
|
+
};
|
|
49428
|
+
if (selectedIndex >= menu.options.length) return {
|
|
49429
|
+
body: { error: `selectedIndex out of range (0-${menu.options.length - 1})` },
|
|
49430
|
+
status: 400
|
|
49431
|
+
};
|
|
49432
|
+
const keys = buildChoiceKeystrokes(menu, selectedIndex);
|
|
49433
|
+
for (const key of keys) {
|
|
49434
|
+
await sendKey(conv.tmuxSession, key);
|
|
49435
|
+
await sleep(KEYSTROKE_GAP_MS);
|
|
49436
|
+
}
|
|
49437
|
+
await sleep(DELIVERY_CONFIRM_WAIT_MS);
|
|
49438
|
+
const after = parsePaneChoiceMenu(await capture(conv.tmuxSession, PANE_CAPTURE_LINES));
|
|
49439
|
+
if (after && paneChoiceMenuSignature(after) === signature) return {
|
|
49440
|
+
body: {
|
|
49441
|
+
error: "Keystrokes were sent but the menu is still on screen — answer it from the terminal",
|
|
49442
|
+
code: "delivery-unconfirmed"
|
|
49443
|
+
},
|
|
49444
|
+
status: 409
|
|
49445
|
+
};
|
|
49446
|
+
return { body: {
|
|
49447
|
+
ok: true,
|
|
49448
|
+
answeredLabel: menu.options[selectedIndex].label
|
|
49449
|
+
} };
|
|
49450
|
+
} catch (error) {
|
|
49451
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
49452
|
+
console.error("[conversations] pane-choice answer failed:", msg);
|
|
49453
|
+
return {
|
|
49454
|
+
body: { error: "Internal server error" },
|
|
49455
|
+
status: 500
|
|
49456
|
+
};
|
|
49457
|
+
}
|
|
49458
|
+
}
|
|
49459
|
+
//#endregion
|
|
48899
49460
|
//#region ../../lib/overdeck/conversation-reads.ts
|
|
48900
49461
|
init_concurrency$1();
|
|
48901
49462
|
init_behavior();
|
|
@@ -48907,7 +49468,6 @@ init_conversation_service();
|
|
|
48907
49468
|
init_pi_conversation_parser();
|
|
48908
49469
|
init_ohmypi_conversation_parser();
|
|
48909
49470
|
init_codex_conversation_parser();
|
|
48910
|
-
init_conversation_compaction();
|
|
48911
49471
|
function result(body, status) {
|
|
48912
49472
|
return status === void 0 ? { body } : {
|
|
48913
49473
|
body,
|
|
@@ -49130,13 +49690,16 @@ async function getConversationsPendingInputFeed(deps) {
|
|
|
49130
49690
|
const codex = await codexConversationPendingInput(conv, true, lastActivityAt ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
49131
49691
|
if (codex.approval) pending = codex.approval;
|
|
49132
49692
|
}
|
|
49133
|
-
|
|
49693
|
+
let paneChoice = null;
|
|
49694
|
+
if (!pending && !pendingPlan) paneChoice = await claudeConversationPaneChoice(conv);
|
|
49695
|
+
if (!pending && !pendingPlan && !paneChoice) return null;
|
|
49134
49696
|
return {
|
|
49135
49697
|
name: conv.name,
|
|
49136
49698
|
title: conv.title ?? null,
|
|
49137
49699
|
issueId: conv.issueId ?? null,
|
|
49138
49700
|
...pending ? { pendingAskUserQuestion: pending } : {},
|
|
49139
|
-
...pendingPlan ? { pendingProposedPlan: pendingPlan } : {}
|
|
49701
|
+
...pendingPlan ? { pendingProposedPlan: pendingPlan } : {},
|
|
49702
|
+
...paneChoice ? { pendingPaneChoice: paneChoice } : {}
|
|
49140
49703
|
};
|
|
49141
49704
|
})), 8))).filter((row) => row !== null));
|
|
49142
49705
|
} catch (error) {
|
|
@@ -49182,6 +49745,14 @@ async function getConversationRead(rawId, deps) {
|
|
|
49182
49745
|
if (codex.approval) pendingAskUserQuestion = codex.approval;
|
|
49183
49746
|
}
|
|
49184
49747
|
}
|
|
49748
|
+
let pendingPaneChoice = null;
|
|
49749
|
+
if (sessionAlive && pendingInputCount === 0) {
|
|
49750
|
+
pendingPaneChoice = await claudeConversationPaneChoice(conv);
|
|
49751
|
+
if (pendingPaneChoice) {
|
|
49752
|
+
pendingInputKinds = [...pendingInputKinds, "paneChoice"];
|
|
49753
|
+
pendingInputCount = pendingInputKinds.length;
|
|
49754
|
+
}
|
|
49755
|
+
}
|
|
49185
49756
|
return result({
|
|
49186
49757
|
...conv,
|
|
49187
49758
|
sessionAlive,
|
|
@@ -49191,6 +49762,7 @@ async function getConversationRead(rawId, deps) {
|
|
|
49191
49762
|
pendingInputCount,
|
|
49192
49763
|
pendingInputKinds,
|
|
49193
49764
|
pendingAskUserQuestion,
|
|
49765
|
+
...pendingPaneChoice ? { pendingPaneChoice } : {},
|
|
49194
49766
|
transcriptMissing: conversationTranscriptMissing(conv, sessionAlive, convSf),
|
|
49195
49767
|
needsTerminal: await conversationNeedsTerminal(conv, sessionAlive, convSf)
|
|
49196
49768
|
});
|
|
@@ -49272,7 +49844,7 @@ async function resolveSpecialistSessionFile(name) {
|
|
|
49272
49844
|
} catch {}
|
|
49273
49845
|
return null;
|
|
49274
49846
|
}
|
|
49275
|
-
async function getConversationMessagesRead(name, deps) {
|
|
49847
|
+
async function getConversationMessagesRead(name, deps, agentId) {
|
|
49276
49848
|
try {
|
|
49277
49849
|
const conv = getConversationByName(name);
|
|
49278
49850
|
let sessionFile = conv ? await deps.resolveSessionFile(conv) : void 0;
|
|
@@ -49293,15 +49865,24 @@ async function getConversationMessagesRead(name, deps) {
|
|
|
49293
49865
|
streaming: false
|
|
49294
49866
|
});
|
|
49295
49867
|
}
|
|
49868
|
+
const parentSessionFile = sessionFile;
|
|
49869
|
+
if (agentId !== void 0) {
|
|
49870
|
+
sessionFile = subagentTranscriptPath(parentSessionFile, agentId);
|
|
49871
|
+
if (!sessionFile) return result({ error: "Invalid subagent id" }, 400);
|
|
49872
|
+
}
|
|
49296
49873
|
try {
|
|
49297
49874
|
const parsed = await getCachedMessages(sessionFile, false);
|
|
49298
|
-
if (conv && (parsed.totalCost > 0 || parsed.totalTokens > 0)) updateConversationCost(name, parsed.totalCost, parsed.totalTokens);
|
|
49875
|
+
if (agentId === void 0 && conv && (parsed.totalCost > 0 || parsed.totalTokens > 0)) updateConversationCost(name, parsed.totalCost, parsed.totalTokens);
|
|
49299
49876
|
let contextUsage = null;
|
|
49300
49877
|
if (conv) try {
|
|
49301
49878
|
contextUsage = await computeContextUsage(sessionFile, conv.model);
|
|
49302
49879
|
} catch {
|
|
49303
49880
|
contextUsage = null;
|
|
49304
49881
|
}
|
|
49882
|
+
const subagents = agentId === void 0 ? (await listSubagentMetas(parentSessionFile)).map((meta) => ({
|
|
49883
|
+
...meta,
|
|
49884
|
+
status: "done"
|
|
49885
|
+
})) : void 0;
|
|
49305
49886
|
return result({
|
|
49306
49887
|
messages: parsed.messages,
|
|
49307
49888
|
workLog: parsed.workLog,
|
|
@@ -49311,7 +49892,8 @@ async function getConversationMessagesRead(name, deps) {
|
|
|
49311
49892
|
proposedPlan: parsed.proposedPlan,
|
|
49312
49893
|
compactBoundaries: (parsed.compactBoundaries?.length ?? 0) > 0 ? parsed.compactBoundaries : void 0,
|
|
49313
49894
|
compacting: isCompacting(sessionFile) || void 0,
|
|
49314
|
-
contextUsage
|
|
49895
|
+
contextUsage,
|
|
49896
|
+
subagents
|
|
49315
49897
|
});
|
|
49316
49898
|
} catch (parseErr) {
|
|
49317
49899
|
if (parseErr?.code === "ENOENT") return result({
|
|
@@ -49483,8 +50065,6 @@ async function getConversationAbout(name, forceRefresh, deps) {
|
|
|
49483
50065
|
}
|
|
49484
50066
|
//#endregion
|
|
49485
50067
|
//#region ../../lib/overdeck/conversation-list.ts
|
|
49486
|
-
init_transcript_adapter();
|
|
49487
|
-
init_summary_fork();
|
|
49488
50068
|
init_agents$1();
|
|
49489
50069
|
init_concurrency$1();
|
|
49490
50070
|
init_behavior();
|
|
@@ -49912,7 +50492,35 @@ async function handleConversationMessage(name, body, deps = {
|
|
|
49912
50492
|
const message = typeof body["message"] === "string" ? body["message"].trim() : "";
|
|
49913
50493
|
if (!message) return jsonResponse({ error: "Message is required" }, { status: 400 });
|
|
49914
50494
|
if (message.length > MAX_MESSAGE_LENGTH) return jsonResponse({ error: `Message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters` }, { status: 400 });
|
|
49915
|
-
|
|
50495
|
+
try {
|
|
50496
|
+
const result = await handleComposerCommandMessage({
|
|
50497
|
+
message,
|
|
50498
|
+
confirmation: composerCommandConfirmationFromBody(body),
|
|
50499
|
+
target: {
|
|
50500
|
+
kind: "conversation",
|
|
50501
|
+
id: conv.name,
|
|
50502
|
+
harness: conv.harness ?? "claude-code",
|
|
50503
|
+
cwd: conv.cwd,
|
|
50504
|
+
issueId: conv.issueId ?? void 0
|
|
50505
|
+
}
|
|
50506
|
+
});
|
|
50507
|
+
if (result !== null) return jsonResponse(result, { status: composerCommandResultHttpStatus(result) });
|
|
50508
|
+
} catch (error) {
|
|
50509
|
+
if (error instanceof ComposerCommandConfirmationError) return jsonResponse({
|
|
50510
|
+
error: error.message,
|
|
50511
|
+
code: error.code
|
|
50512
|
+
}, { status: 422 });
|
|
50513
|
+
if (!(error instanceof ComposerCommandParseError)) throw error;
|
|
50514
|
+
const status = error.code === "unknown-command" ? 404 : error.code === "unknown-flag" ? 422 : 400;
|
|
50515
|
+
return jsonResponse({
|
|
50516
|
+
error: error.message,
|
|
50517
|
+
code: error.code,
|
|
50518
|
+
token: error.token,
|
|
50519
|
+
expected: error.expected
|
|
50520
|
+
}, { status });
|
|
50521
|
+
}
|
|
50522
|
+
const interceptManualCompact = deps.shouldInterceptManualCompact ?? shouldInterceptManualCompact;
|
|
50523
|
+
if (getHarnessBehavior(conv.harness).transcriptKind === "claude-jsonl" && interceptManualCompact(message)) {
|
|
49916
50524
|
const compactSessionFile = await deps.resolveSessionFile(conv);
|
|
49917
50525
|
if (!compactSessionFile || !existsSync$1(compactSessionFile)) return jsonResponse({ error: `No session file found for conversation ${conv.name}` }, { status: 400 });
|
|
49918
50526
|
const compactResult = await compactConversationNative(compactSessionFile, conv.name);
|
|
@@ -49951,7 +50559,7 @@ async function handleConversationMessage(name, body, deps = {
|
|
|
49951
50559
|
const effectiveAttachmentPaths = partition.effectiveAttachmentPaths;
|
|
49952
50560
|
const droppedImageCount = partition.droppedImageCount;
|
|
49953
50561
|
if (droppedImageCount > 0 && !outboundMessage && effectiveAttachmentPaths.length === 0) return jsonResponse({ error: `${conv.model ?? "This model"} can't read images. Switch to a vision-capable model (e.g. mimo-v2.5) to send images.` }, { status: 422 });
|
|
49954
|
-
let deliveredMessage = transformMessageForHarness(outboundMessage, harness, effectiveAttachmentPaths);
|
|
50562
|
+
let deliveredMessage = (deps.transformMessageForHarness ?? transformMessageForHarness)(outboundMessage, harness, effectiveAttachmentPaths);
|
|
49955
50563
|
if (behavior.injectsPromptTimeMemory) deliveredMessage = await injectPiConversationMemory({
|
|
49956
50564
|
cwd: conv.cwd,
|
|
49957
50565
|
issueId: conv.issueId,
|
|
@@ -50352,7 +50960,7 @@ async function refreshMergeStateFromGitHub(issueId, repo, prNumber) {
|
|
|
50352
50960
|
let mergeState;
|
|
50353
50961
|
let isDraft;
|
|
50354
50962
|
let checksFailed;
|
|
50355
|
-
const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-
|
|
50963
|
+
const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-Bmg4R9mv.js");
|
|
50356
50964
|
if (isGitHubAppConfigured()) {
|
|
50357
50965
|
const prState = await Effect.runPromise(getPullRequestState(owner, repoName, prNumber));
|
|
50358
50966
|
mergeable = prState.mergeable === null ? "UNKNOWN" : prState.mergeable ? "MERGEABLE" : "CONFLICTING";
|
|
@@ -50503,8 +51111,8 @@ async function handlePullRequestPromise(payload) {
|
|
|
50503
51111
|
bumpIssuePrTabCacheGeneration(issueId);
|
|
50504
51112
|
const repo = payload.repository.full_name;
|
|
50505
51113
|
if (payload.action === "closed" && pr.merged === true) try {
|
|
50506
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
50507
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
51114
|
+
const { postMergeLifecycle } = await import("./merge-agent-DQTXZk8z.js");
|
|
51115
|
+
const { resolveProjectFromIssueSync } = await import("./projects-_n3Zui6K.js");
|
|
50508
51116
|
const project = resolveProjectFromIssueSync(issueId);
|
|
50509
51117
|
if (project) {
|
|
50510
51118
|
const branchName = pr.head.ref;
|
|
@@ -51351,7 +51959,7 @@ startConversationModelBackfill(resolveSessionFile);
|
|
|
51351
51959
|
function conversationReadJson(response) {
|
|
51352
51960
|
return jsonResponse(response.body, response.status === void 0 ? void 0 : { status: response.status });
|
|
51353
51961
|
}
|
|
51354
|
-
const readJsonBody$
|
|
51962
|
+
const readJsonBody$9 = Effect.gen(function* () {
|
|
51355
51963
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
51356
51964
|
try {
|
|
51357
51965
|
return text ? JSON.parse(text) : {};
|
|
@@ -51411,7 +52019,7 @@ const postConversationRoute = HttpRouter.add("POST", "/api/conversations", Effec
|
|
|
51411
52019
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
51412
52020
|
const originCheck = validateOrigin$1(request);
|
|
51413
52021
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51414
|
-
const body = yield* readJsonBody$
|
|
52022
|
+
const body = yield* readJsonBody$9;
|
|
51415
52023
|
const reqOrigin = getHeader(request, "origin") ?? "none";
|
|
51416
52024
|
const reqReferer = getHeader(request, "referer") ?? "none";
|
|
51417
52025
|
const reqUserAgent = getHeader(request, "user-agent") ?? "none";
|
|
@@ -51430,14 +52038,14 @@ const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:
|
|
|
51430
52038
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51431
52039
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51432
52040
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51433
|
-
const body = yield* readJsonBody$
|
|
52041
|
+
const body = yield* readJsonBody$9;
|
|
51434
52042
|
return yield* Effect.promise(async () => handleConversationResume(name, body, { resolveSessionFile }));
|
|
51435
52043
|
}));
|
|
51436
52044
|
const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversations/:name/switch-model", Effect.gen(function* () {
|
|
51437
52045
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51438
52046
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51439
52047
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51440
|
-
const body = yield* readJsonBody$
|
|
52048
|
+
const body = yield* readJsonBody$9;
|
|
51441
52049
|
return yield* Effect.promise(async () => {
|
|
51442
52050
|
try {
|
|
51443
52051
|
return await handleConversationSwitchModel(name, body);
|
|
@@ -51452,7 +52060,7 @@ const postConversationThinkingLevelRoute = HttpRouter.add("POST", "/api/conversa
|
|
|
51452
52060
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51453
52061
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51454
52062
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51455
|
-
const body = yield* readJsonBody$
|
|
52063
|
+
const body = yield* readJsonBody$9;
|
|
51456
52064
|
return yield* Effect.promise(async () => {
|
|
51457
52065
|
try {
|
|
51458
52066
|
return await handleConversationThinkingLevel(name, body);
|
|
@@ -51492,11 +52100,12 @@ const postConversationAbortRoute = HttpRouter.add("POST", "/api/conversations/:n
|
|
|
51492
52100
|
});
|
|
51493
52101
|
}));
|
|
51494
52102
|
const getConversationMessagesRoute = HttpRouter.add("GET", "/api/conversations/:name/messages", Effect.gen(function* () {
|
|
51495
|
-
const
|
|
52103
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
52104
|
+
const originCheck = validateOrigin$1(request);
|
|
51496
52105
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51497
52106
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51498
52107
|
return yield* Effect.promise(async () => {
|
|
51499
|
-
return conversationReadJson(await getConversationMessagesRead(name, conversationReadDependencies));
|
|
52108
|
+
return conversationReadJson(await getConversationMessagesRead(name, conversationReadDependencies, new URL(request.url, "http://localhost").searchParams.get("agentId") ?? void 0));
|
|
51500
52109
|
});
|
|
51501
52110
|
}));
|
|
51502
52111
|
const getConversationMessageLocatorRoute = HttpRouter.add("GET", "/api/conversations/:name/message-locator", Effect.gen(function* () {
|
|
@@ -51548,7 +52157,7 @@ const postConversationDeleteImageRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
51548
52157
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51549
52158
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51550
52159
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51551
|
-
const body = yield* readJsonBody$
|
|
52160
|
+
const body = yield* readJsonBody$9;
|
|
51552
52161
|
return yield* Effect.promise(async () => {
|
|
51553
52162
|
try {
|
|
51554
52163
|
return await handleConversationImageDelete(name, body);
|
|
@@ -51563,7 +52172,7 @@ const postConversationMessageRoute = HttpRouter.add("POST", "/api/conversations/
|
|
|
51563
52172
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51564
52173
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51565
52174
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51566
|
-
const body = yield* readJsonBody$
|
|
52175
|
+
const body = yield* readJsonBody$9;
|
|
51567
52176
|
return yield* Effect.promise(async () => {
|
|
51568
52177
|
try {
|
|
51569
52178
|
return await handleConversationMessage(name, body, conversationMessageDependencies);
|
|
@@ -51583,14 +52192,24 @@ const postConversationCodexApprovalRoute = HttpRouter.add("POST", "/api/conversa
|
|
|
51583
52192
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51584
52193
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51585
52194
|
const rawId = (yield* HttpRouter.params)["id"] ?? "";
|
|
51586
|
-
const body = yield* readJsonBody$
|
|
52195
|
+
const body = yield* readJsonBody$9;
|
|
51587
52196
|
return yield* Effect.promise(() => handleConversationCodexApproval(rawId, body));
|
|
51588
52197
|
}));
|
|
52198
|
+
const postConversationPaneChoiceRoute = HttpRouter.add("POST", "/api/conversations/:id/pane-choice", Effect.gen(function* () {
|
|
52199
|
+
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
52200
|
+
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
52201
|
+
const rawId = (yield* HttpRouter.params)["id"] ?? "";
|
|
52202
|
+
const body = yield* readJsonBody$9;
|
|
52203
|
+
return yield* Effect.promise(async () => {
|
|
52204
|
+
const result = await handleConversationPaneChoiceAnswer(rawId, body);
|
|
52205
|
+
return jsonResponse(result.body, { status: result.status });
|
|
52206
|
+
});
|
|
52207
|
+
}));
|
|
51589
52208
|
const postConversationDeliveryMethodRoute = HttpRouter.add("POST", "/api/conversations/:name/delivery-method", Effect.gen(function* () {
|
|
51590
52209
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51591
52210
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51592
52211
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51593
|
-
const body = yield* readJsonBody$
|
|
52212
|
+
const body = yield* readJsonBody$9;
|
|
51594
52213
|
return yield* Effect.promise(async () => {
|
|
51595
52214
|
try {
|
|
51596
52215
|
return await handleConversationDeliveryMethod(name, body);
|
|
@@ -51605,7 +52224,7 @@ const postConversationControlAckRoute = HttpRouter.add("POST", "/api/conversatio
|
|
|
51605
52224
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
51606
52225
|
const originCheck = validateConversationControlAckOrigin(request.headers, request.method);
|
|
51607
52226
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51608
|
-
const body = yield* readJsonBody$
|
|
52227
|
+
const body = yield* readJsonBody$9;
|
|
51609
52228
|
return yield* Effect.promise(async () => {
|
|
51610
52229
|
try {
|
|
51611
52230
|
const result = handleConversationControlAck(body);
|
|
@@ -51621,7 +52240,7 @@ const patchConversationRoute = HttpRouter.add("PATCH", "/api/conversations/:name
|
|
|
51621
52240
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51622
52241
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51623
52242
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51624
|
-
const body = yield* readJsonBody$
|
|
52243
|
+
const body = yield* readJsonBody$9;
|
|
51625
52244
|
return yield* Effect.promise(async () => {
|
|
51626
52245
|
try {
|
|
51627
52246
|
const result = patchConversationTitle(name, body);
|
|
@@ -51708,14 +52327,14 @@ const postConversationSummaryForkRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
51708
52327
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51709
52328
|
const params = yield* HttpRouter.params;
|
|
51710
52329
|
const name = decodeURIComponent(params["name"] ?? "");
|
|
51711
|
-
const body = yield* readJsonBody$
|
|
52330
|
+
const body = yield* readJsonBody$9;
|
|
51712
52331
|
return yield* Effect.promise(() => handleConversationSummaryFork(name, body));
|
|
51713
52332
|
}));
|
|
51714
52333
|
const postConversationPlanActionRoute = HttpRouter.add("POST", "/api/conversations/:name/plan-action", Effect.gen(function* () {
|
|
51715
52334
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51716
52335
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51717
52336
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51718
|
-
const body = yield* readJsonBody$
|
|
52337
|
+
const body = yield* readJsonBody$9;
|
|
51719
52338
|
return yield* Effect.promise(() => handleConversationPlanAction(name, body));
|
|
51720
52339
|
}));
|
|
51721
52340
|
const conversationDiffDependencies = {
|
|
@@ -51770,7 +52389,7 @@ const getConversationAboutRoute = HttpRouter.add("GET", "/api/conversations/:nam
|
|
|
51770
52389
|
return conversationReadJson(await getConversationAbout(name, new URL(request.url, "http://localhost").searchParams.get("refresh") === "1", conversationReadDependencies));
|
|
51771
52390
|
});
|
|
51772
52391
|
}));
|
|
51773
|
-
const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, getConversationsPendingInputRoute, getArchivedConversationsRoute, getConversationRoute, getConversationHandoffDocRoute, postConversationRoute, patchConversationRoute, deleteConversationRoute, postConversationStopRoute, postConversationResumeRoute, postConversationSwitchModelRoute, postConversationThinkingLevelRoute, postConversationCompactRoute, postConversationAbortRoute, postConversationRestartAllRoute, postConversationArchiveRoute, postConversationUnarchiveRoute, getConversationMessagesRoute, getConversationMessageLocatorRoute, postConversationUploadImageRoute, postConversationDeleteImageRoute, postConversationMessageRoute, postConversationCodexApprovalRoute, postConversationDeliveryMethodRoute, postConversationControlAckRoute, postConversationFavoriteRoute, deleteConversationFavoriteRoute, postConversationSummaryForkRoute, postConversationPlanActionRoute, getConversationDiffsRoute, getConversationDiffFullRoute, getConversationDiffTurnRoute, postConversationRetitleRoute, getConversationAboutRoute);
|
|
52392
|
+
const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, getConversationsPendingInputRoute, getArchivedConversationsRoute, getConversationRoute, getConversationHandoffDocRoute, postConversationRoute, patchConversationRoute, deleteConversationRoute, postConversationStopRoute, postConversationResumeRoute, postConversationSwitchModelRoute, postConversationThinkingLevelRoute, postConversationCompactRoute, postConversationAbortRoute, postConversationRestartAllRoute, postConversationArchiveRoute, postConversationUnarchiveRoute, getConversationMessagesRoute, getConversationMessageLocatorRoute, postConversationUploadImageRoute, postConversationDeleteImageRoute, postConversationMessageRoute, postConversationCodexApprovalRoute, postConversationPaneChoiceRoute, postConversationDeliveryMethodRoute, postConversationControlAckRoute, postConversationFavoriteRoute, deleteConversationFavoriteRoute, postConversationSummaryForkRoute, postConversationPlanActionRoute, getConversationDiffsRoute, getConversationDiffFullRoute, getConversationDiffTurnRoute, postConversationRetitleRoute, getConversationAboutRoute);
|
|
51774
52393
|
//#endregion
|
|
51775
52394
|
//#region routes/show.ts
|
|
51776
52395
|
/**
|
|
@@ -51817,7 +52436,7 @@ const showRouteLayer = Layer.mergeAll(getShowRoute, getShowShadowRoute, getShowH
|
|
|
51817
52436
|
//#endregion
|
|
51818
52437
|
//#region routes/project-rename.ts
|
|
51819
52438
|
init_projects();
|
|
51820
|
-
const readJsonBody$
|
|
52439
|
+
const readJsonBody$8 = Effect.gen(function* () {
|
|
51821
52440
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
51822
52441
|
try {
|
|
51823
52442
|
return text ? JSON.parse(text) : {};
|
|
@@ -51829,7 +52448,7 @@ const postProjectRenameRoute = HttpRouter.add("POST", "/api/projects/:projectKey
|
|
|
51829
52448
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51830
52449
|
if (authError) return authError;
|
|
51831
52450
|
const projectIdentifier = (yield* HttpRouter.params)["projectKey"] ?? "";
|
|
51832
|
-
const body = yield* readJsonBody$
|
|
52451
|
+
const body = yield* readJsonBody$8;
|
|
51833
52452
|
if (typeof body.name !== "string") return jsonResponse({ error: "Project name must be a string" }, { status: 400 });
|
|
51834
52453
|
const result = yield* Effect.result(renameProject(projectIdentifier, body.name));
|
|
51835
52454
|
if (Result$1.isFailure(result)) {
|
|
@@ -51848,9 +52467,8 @@ const postProjectRenameRoute = HttpRouter.add("POST", "/api/projects/:projectKey
|
|
|
51848
52467
|
* No chalk, no console, no execSync. Import and use from API routes or CLI.
|
|
51849
52468
|
*/
|
|
51850
52469
|
init_projects();
|
|
51851
|
-
init_paths();
|
|
51852
52470
|
init_context_layers();
|
|
51853
|
-
|
|
52471
|
+
init_git_hooks();
|
|
51854
52472
|
var DuplicateProjectError = class extends Error {
|
|
51855
52473
|
constructor(key, existingPath) {
|
|
51856
52474
|
super(`Project already registered with key: ${key} (path: ${existingPath})`);
|
|
@@ -51859,31 +52477,6 @@ var DuplicateProjectError = class extends Error {
|
|
|
51859
52477
|
this.name = "DuplicateProjectError";
|
|
51860
52478
|
}
|
|
51861
52479
|
};
|
|
51862
|
-
function installGitHooksInDir(gitDir) {
|
|
51863
|
-
const hooksTarget = join(gitDir, "hooks");
|
|
51864
|
-
let installed = 0;
|
|
51865
|
-
if (!existsSync$1(hooksTarget)) mkdirSync$1(hooksTarget, { recursive: true });
|
|
51866
|
-
if (!existsSync$1(BUNDLED_HOOKS_DIR)) return 0;
|
|
51867
|
-
try {
|
|
51868
|
-
const hooks = readdirSync$1(BUNDLED_HOOKS_DIR).filter((f) => {
|
|
51869
|
-
const p = join(BUNDLED_HOOKS_DIR, f);
|
|
51870
|
-
return existsSync$1(p) && statSync$1(p).isFile();
|
|
51871
|
-
});
|
|
51872
|
-
for (const hook of hooks) {
|
|
51873
|
-
const source = join(BUNDLED_HOOKS_DIR, hook);
|
|
51874
|
-
const target = join(hooksTarget, hook);
|
|
51875
|
-
if (existsSync$1(target)) {
|
|
51876
|
-
try {
|
|
51877
|
-
if (readlinkSync(target) === source) continue;
|
|
51878
|
-
} catch {}
|
|
51879
|
-
renameSync$1(target, `${target}.backup`);
|
|
51880
|
-
}
|
|
51881
|
-
symlinkSync$1(source, target);
|
|
51882
|
-
installed++;
|
|
51883
|
-
}
|
|
51884
|
-
} catch {}
|
|
51885
|
-
return installed;
|
|
51886
|
-
}
|
|
51887
52480
|
/**
|
|
51888
52481
|
* Register a project from a filesystem path.
|
|
51889
52482
|
*
|
|
@@ -51904,7 +52497,7 @@ async function registerProjectFromPath(opts) {
|
|
|
51904
52497
|
registerProjectSync(key, projectConfig);
|
|
51905
52498
|
const seededContextLayer = ensureProjectLayer(fullPath);
|
|
51906
52499
|
try {
|
|
51907
|
-
const { preTrustDirectorySync } = await import("./workspace-manager-
|
|
52500
|
+
const { preTrustDirectorySync } = await import("./workspace-manager-C1F3XsnS.js");
|
|
51908
52501
|
preTrustDirectorySync(fullPath);
|
|
51909
52502
|
} catch {}
|
|
51910
52503
|
let hooksInstalled = 0;
|
|
@@ -51943,9 +52536,9 @@ init_pan_dir();
|
|
|
51943
52536
|
init_io();
|
|
51944
52537
|
init_specs();
|
|
51945
52538
|
init_paths();
|
|
51946
|
-
const execAsync$
|
|
52539
|
+
const execAsync$3 = promisify(exec);
|
|
51947
52540
|
async function getIssueDataService() {
|
|
51948
|
-
const { getSharedIssueService } = await import("./issue-service-singleton-
|
|
52541
|
+
const { getSharedIssueService } = await import("./issue-service-singleton-B2wXiIlw.js");
|
|
51949
52542
|
return getSharedIssueService();
|
|
51950
52543
|
}
|
|
51951
52544
|
/** Returns true if the path exists (any type). */
|
|
@@ -52237,8 +52830,9 @@ async function collectSessionTreeNodes(issueId, workspacePath, projectPath, cont
|
|
|
52237
52830
|
if (latestMerge) {
|
|
52238
52831
|
const shipSessionName = `agent-${issueLower}-ship`;
|
|
52239
52832
|
const shipIsLive = context.tmuxSessionNames.has(shipSessionName);
|
|
52240
|
-
const
|
|
52241
|
-
|
|
52833
|
+
const shipState = getAgentStateSync(shipSessionName);
|
|
52834
|
+
const shipJsonlPath = shipIsLive || shipState ? await resolveJsonlPath(shipSessionName, workspacePath) : null;
|
|
52835
|
+
if (shipIsLive || shipJsonlPath) sections.push({
|
|
52242
52836
|
type: "ship",
|
|
52243
52837
|
sessionId: shipSessionName,
|
|
52244
52838
|
model: "specialist",
|
|
@@ -52321,11 +52915,22 @@ async function fetchProjectSessionTree(projectKey, sharedContext) {
|
|
|
52321
52915
|
const features = [];
|
|
52322
52916
|
const issueTitles = sharedContext?.issueTitles ?? await buildIssueTitleMap();
|
|
52323
52917
|
if (await pathExists$1(workspacesDir)) {
|
|
52324
|
-
const
|
|
52325
|
-
|
|
52326
|
-
|
|
52327
|
-
|
|
52328
|
-
|
|
52918
|
+
const entries = await readdir(workspacesDir, { withFileTypes: true }).catch(() => []);
|
|
52919
|
+
const candidateIssueLowers = /* @__PURE__ */ new Set();
|
|
52920
|
+
for (const entry of entries) {
|
|
52921
|
+
if (!entry.isDirectory()) continue;
|
|
52922
|
+
const match = /^feature-([a-z]+-\d+)(?:-strike|-slot-\d+)?$/.exec(entry.name);
|
|
52923
|
+
if (match) candidateIssueLowers.add(match[1]);
|
|
52924
|
+
}
|
|
52925
|
+
for (const issueLower of liveTmuxIssueIds) {
|
|
52926
|
+
if (candidateIssueLowers.has(issueLower)) continue;
|
|
52927
|
+
if (resolveProjectFromIssueSync(issueLower.toUpperCase())?.projectKey === project.key) candidateIssueLowers.add(issueLower);
|
|
52928
|
+
}
|
|
52929
|
+
const featureCandidates = [...candidateIssueLowers].map((issueLower) => ({
|
|
52930
|
+
name: `feature-${issueLower}`,
|
|
52931
|
+
issueLower,
|
|
52932
|
+
issueId: issueLower.toUpperCase()
|
|
52933
|
+
}));
|
|
52329
52934
|
const results = await Effect.runPromise(withConcurrencyLimit(featureCandidates.map((c) => Effect.promise(async () => {
|
|
52330
52935
|
const agentDir = join(getOverdeckHome(), "agents", `agent-${c.issueLower}`);
|
|
52331
52936
|
const planningAgentDir = join(getOverdeckHome(), "agents", `planning-${c.issueLower}`);
|
|
@@ -52403,7 +53008,7 @@ const getProjectReleaseStatusRoute = HttpRouter.add("GET", "/api/projects/:proje
|
|
|
52403
53008
|
const projectKey = (yield* HttpRouter.params)["projectKey"] ?? "";
|
|
52404
53009
|
return jsonResponse(yield* Effect.tryPromise({
|
|
52405
53010
|
try: async () => {
|
|
52406
|
-
const { fetchProjectReleaseStatus } = await import("./project-pipelines-
|
|
53011
|
+
const { fetchProjectReleaseStatus } = await import("./project-pipelines-9SKt2bEc.js");
|
|
52407
53012
|
return fetchProjectReleaseStatus(projectKey);
|
|
52408
53013
|
},
|
|
52409
53014
|
catch: (err) => new Error(err instanceof Error ? err.message : String(err))
|
|
@@ -52613,7 +53218,7 @@ const postProjectsRoute = HttpRouter.add("POST", "/api/projects", httpHandler(Ef
|
|
|
52613
53218
|
if ((await readdir(target).catch(() => [])).length > 0) return jsonResponse({ error: `target directory already exists and is non-empty: ${target}` }, { status: 409 });
|
|
52614
53219
|
}
|
|
52615
53220
|
await mkdir(target, { recursive: true });
|
|
52616
|
-
await execAsync$
|
|
53221
|
+
await execAsync$3("git init", { cwd: target });
|
|
52617
53222
|
try {
|
|
52618
53223
|
const result = await registerProjectFromPath({
|
|
52619
53224
|
path: target,
|
|
@@ -52638,6 +53243,271 @@ const postProjectsRoute = HttpRouter.add("POST", "/api/projects", httpHandler(Ef
|
|
|
52638
53243
|
})));
|
|
52639
53244
|
const projectsRouteLayer = Layer.mergeAll(getProjectSessionTreeRoute, getAllSessionTreesRoute, getProjectReleaseStatusRoute, getProjectAutoMergeDefaultRoute, postProjectAutoMergeDefaultRoute, postProjectRenameRoute, getProjectSwarmPolicyRoute, postProjectSwarmPolicyRoute, getIssueSwarmPolicyRoute, postIssueSwarmPolicyRoute, getIssueStaffingRoute, postIssueStaffingRoute, postProjectsRoute);
|
|
52640
53245
|
//#endregion
|
|
53246
|
+
//#region routes/projects-merge-train.ts
|
|
53247
|
+
/** PAN-1696: Per-project merge-train override endpoints (GET/POST) */
|
|
53248
|
+
init_projects();
|
|
53249
|
+
const getProjectMergeTrainRoute = HttpRouter.add("GET", "/api/projects/:projectKey/merge-train", httpHandler(Effect.gen(function* () {
|
|
53250
|
+
const config = getProjectSync((yield* HttpRouter.params)["projectKey"] ?? "");
|
|
53251
|
+
if (!config) return jsonResponse({ error: "Project not found" }, { status: 404 });
|
|
53252
|
+
const { isMergeTrainEnabledForProject } = yield* Effect.promise(() => import("./merge-sync-CpGmk6Ch.js"));
|
|
53253
|
+
return jsonResponse({
|
|
53254
|
+
value: config.merge_train ?? null,
|
|
53255
|
+
effective: isMergeTrainEnabledForProject(config)
|
|
53256
|
+
});
|
|
53257
|
+
})));
|
|
53258
|
+
const postProjectMergeTrainRoute = HttpRouter.add("POST", "/api/projects/:projectKey/merge-train", httpHandler(Effect.gen(function* () {
|
|
53259
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53260
|
+
if (authError) return authError;
|
|
53261
|
+
const key = (yield* HttpRouter.params)["projectKey"] ?? "";
|
|
53262
|
+
if (!getProjectSync(key)) return jsonResponse({ error: "Project not found" }, { status: 404 });
|
|
53263
|
+
const v = (yield* readProjectJsonBody).value;
|
|
53264
|
+
if (v !== "enabled" && v !== "disabled" && v !== null) return jsonResponse({ error: "value must be 'enabled', 'disabled', or null" }, { status: 400 });
|
|
53265
|
+
const { isMergeTrainEnabledForProject } = yield* Effect.promise(() => import("./merge-sync-CpGmk6Ch.js"));
|
|
53266
|
+
setProjectMergeTrainSync(key, v);
|
|
53267
|
+
const updated = getProjectSync(key);
|
|
53268
|
+
return jsonResponse({
|
|
53269
|
+
value: v,
|
|
53270
|
+
effective: updated ? isMergeTrainEnabledForProject(updated) : false
|
|
53271
|
+
});
|
|
53272
|
+
})));
|
|
53273
|
+
const projectsMergeTrainRouteLayer = Layer.mergeAll(getProjectMergeTrainRoute, postProjectMergeTrainRoute);
|
|
53274
|
+
//#endregion
|
|
53275
|
+
//#region routes/merge-train.ts
|
|
53276
|
+
/**
|
|
53277
|
+
* PAN-1696 merge-train-routes: the aggregate `/api/merge-train/*` namespace.
|
|
53278
|
+
*
|
|
53279
|
+
* The merge-train (conflict-aware merge order + UAT batch trains) is a
|
|
53280
|
+
* per-project pipeline concern, but its only HTTP surface used to live under
|
|
53281
|
+
* `/api/flywheel/*` and answered for the Overdeck repo alone. These routes
|
|
53282
|
+
* answer for EVERY tracked project and require no active flywheel run: the
|
|
53283
|
+
* ready set comes from the review-status records via
|
|
53284
|
+
* `listEligibleCandidatesByProject`, not from a run's `activePipeline`.
|
|
53285
|
+
*
|
|
53286
|
+
* The legacy `/api/flywheel/*` merge-train routes stay in place until the
|
|
53287
|
+
* frontend migrates — removing them is the remove-legacy-routes item.
|
|
53288
|
+
*/
|
|
53289
|
+
init_projects();
|
|
53290
|
+
const readUnknownJsonBody$1 = Effect.gen(function* () {
|
|
53291
|
+
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53292
|
+
try {
|
|
53293
|
+
return {
|
|
53294
|
+
ok: true,
|
|
53295
|
+
body: text ? JSON.parse(text) : {}
|
|
53296
|
+
};
|
|
53297
|
+
} catch {
|
|
53298
|
+
return {
|
|
53299
|
+
ok: false,
|
|
53300
|
+
error: "Request body must be valid JSON"
|
|
53301
|
+
};
|
|
53302
|
+
}
|
|
53303
|
+
});
|
|
53304
|
+
/** A plain JSON object — not null, not an array, not a primitive. */
|
|
53305
|
+
function isJsonObject(value) {
|
|
53306
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53307
|
+
}
|
|
53308
|
+
/**
|
|
53309
|
+
* A disabled project reports an empty queue rather than being omitted, so the
|
|
53310
|
+
* multi-project view can render it as an explicitly-off row instead of making
|
|
53311
|
+
* "off" and "no ready work" look identical.
|
|
53312
|
+
*/
|
|
53313
|
+
async function queueEntryForProject(key, config, enabled) {
|
|
53314
|
+
const base = {
|
|
53315
|
+
projectKey: key,
|
|
53316
|
+
projectName: config.name,
|
|
53317
|
+
enabled
|
|
53318
|
+
};
|
|
53319
|
+
if (!enabled) return {
|
|
53320
|
+
...base,
|
|
53321
|
+
queue: []
|
|
53322
|
+
};
|
|
53323
|
+
const projectPath = resolve(config.path);
|
|
53324
|
+
const candidates = listEligibleCandidatesByProject(projectPath);
|
|
53325
|
+
if (candidates.length === 0) return {
|
|
53326
|
+
...base,
|
|
53327
|
+
queue: []
|
|
53328
|
+
};
|
|
53329
|
+
const queue = await Effect.runPromise(computeMergeQueueFromCandidates(candidates, projectPath).pipe(Effect.provide(layer)));
|
|
53330
|
+
return {
|
|
53331
|
+
...base,
|
|
53332
|
+
queue
|
|
53333
|
+
};
|
|
53334
|
+
}
|
|
53335
|
+
/**
|
|
53336
|
+
* PAN-1696 AC1: one entry per tracked project, with that project's effective
|
|
53337
|
+
* flag and queue, with no flywheel run active. One project's git failure must
|
|
53338
|
+
* not blank the whole response, so a failed project reports an empty queue.
|
|
53339
|
+
*/
|
|
53340
|
+
async function getMergeTrainQueuesPayload() {
|
|
53341
|
+
const { isMergeTrainEnabledForProject } = await import("./merge-sync-CpGmk6Ch.js");
|
|
53342
|
+
const projects = listProjectsSync();
|
|
53343
|
+
return (await Promise.allSettled(projects.map(({ key, config }) => queueEntryForProject(key, config, isMergeTrainEnabledForProject(config))))).flatMap((outcome, i) => {
|
|
53344
|
+
if (outcome.status === "fulfilled") return [outcome.value];
|
|
53345
|
+
const entry = projects[i];
|
|
53346
|
+
if (!entry) return [];
|
|
53347
|
+
const reason = outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason);
|
|
53348
|
+
console.warn(`[merge-train] queue for project ${entry.key} failed: ${reason}`);
|
|
53349
|
+
return [{
|
|
53350
|
+
projectKey: entry.key,
|
|
53351
|
+
projectName: entry.config.name,
|
|
53352
|
+
enabled: true,
|
|
53353
|
+
queue: []
|
|
53354
|
+
}];
|
|
53355
|
+
});
|
|
53356
|
+
}
|
|
53357
|
+
/** PAN-1696 AC2: per-project generation chains across every tracked project. */
|
|
53358
|
+
async function getMergeTrainGenerationsPayload() {
|
|
53359
|
+
const { isMergeTrainEnabledForProject } = await import("./merge-sync-CpGmk6Ch.js");
|
|
53360
|
+
const { getUatGenerationsPayload } = await import("./uat-train-Dewoatps.js");
|
|
53361
|
+
return (await Promise.allSettled(listProjectsSync().map(async ({ key, config }) => ({
|
|
53362
|
+
projectKey: key,
|
|
53363
|
+
projectName: config.name,
|
|
53364
|
+
enabled: isMergeTrainEnabledForProject(config),
|
|
53365
|
+
generations: await getUatGenerationsPayload(resolve(config.path))
|
|
53366
|
+
})))).flatMap((outcome) => outcome.status === "fulfilled" ? [outcome.value] : []);
|
|
53367
|
+
}
|
|
53368
|
+
async function defaultOrderedIssueIdsForProject(projectPath) {
|
|
53369
|
+
const candidates = listEligibleCandidatesByProject(projectPath);
|
|
53370
|
+
if (candidates.length === 0) return [];
|
|
53371
|
+
return (await Effect.runPromise(computeMergeQueueFromCandidates(candidates, projectPath).pipe(Effect.provide(layer)))).map((item) => item.issueId);
|
|
53372
|
+
}
|
|
53373
|
+
async function defaultMergeOne(issueId) {
|
|
53374
|
+
const { triggerMerge } = await import("./merge-ops-1abz6O_P.js");
|
|
53375
|
+
const r = await triggerMerge(issueId);
|
|
53376
|
+
return r.success ? { ok: true } : {
|
|
53377
|
+
ok: false,
|
|
53378
|
+
reason: r.error ?? r.message ?? "merge failed"
|
|
53379
|
+
};
|
|
53380
|
+
}
|
|
53381
|
+
async function postMergeTrainMergeNextPayload(payload, deps = {}) {
|
|
53382
|
+
if (!isJsonObject(payload)) return {
|
|
53383
|
+
status: 400,
|
|
53384
|
+
body: { error: "body must be a JSON object: { n, project }" }
|
|
53385
|
+
};
|
|
53386
|
+
const body = payload;
|
|
53387
|
+
const n = typeof body.n === "number" && Number.isFinite(body.n) ? Math.floor(body.n) : 0;
|
|
53388
|
+
if (n <= 0) return {
|
|
53389
|
+
status: 400,
|
|
53390
|
+
body: { error: "n must be a positive integer" }
|
|
53391
|
+
};
|
|
53392
|
+
if (typeof body.project !== "string" || body.project.trim() === "") return {
|
|
53393
|
+
status: 400,
|
|
53394
|
+
body: { error: "project must be a non-empty string" }
|
|
53395
|
+
};
|
|
53396
|
+
const projectKey = body.project.trim();
|
|
53397
|
+
const config = getProjectSync(projectKey);
|
|
53398
|
+
if (!config) return {
|
|
53399
|
+
status: 404,
|
|
53400
|
+
body: { error: `Unknown project key: ${projectKey}` }
|
|
53401
|
+
};
|
|
53402
|
+
const { isMergeTrainEnabledForProject } = await import("./merge-sync-CpGmk6Ch.js");
|
|
53403
|
+
if (!isMergeTrainEnabledForProject(config)) return {
|
|
53404
|
+
status: 409,
|
|
53405
|
+
body: { error: `merge-train is disabled for project ${projectKey}` }
|
|
53406
|
+
};
|
|
53407
|
+
const issueIds = (await (deps.getOrderedIssueIds ?? defaultOrderedIssueIdsForProject)(resolve(config.path))).slice(0, n);
|
|
53408
|
+
const { shipMergeBatch } = await import("./merge-batch-Cp_j9BGk.js");
|
|
53409
|
+
return {
|
|
53410
|
+
status: 200,
|
|
53411
|
+
body: {
|
|
53412
|
+
projectKey,
|
|
53413
|
+
outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne })
|
|
53414
|
+
}
|
|
53415
|
+
};
|
|
53416
|
+
}
|
|
53417
|
+
/**
|
|
53418
|
+
* PAN-1696: forced reconcile. With `{ project }` it rebuilds that one project's
|
|
53419
|
+
* generation; with no body it reconciles every merge-train-enabled project.
|
|
53420
|
+
*/
|
|
53421
|
+
async function postMergeTrainAssemblePayload(payload) {
|
|
53422
|
+
if (!isJsonObject(payload)) return {
|
|
53423
|
+
status: 400,
|
|
53424
|
+
body: { error: "body must be a JSON object: {} for all projects, or { project }" }
|
|
53425
|
+
};
|
|
53426
|
+
if ("project" in payload) {
|
|
53427
|
+
const raw = payload["project"];
|
|
53428
|
+
if (typeof raw !== "string" || raw.trim() === "") return {
|
|
53429
|
+
status: 400,
|
|
53430
|
+
body: { error: "project must be a non-empty string; omit the field entirely to reconcile every project" }
|
|
53431
|
+
};
|
|
53432
|
+
const projectKey = raw.trim();
|
|
53433
|
+
const config = getProjectSync(projectKey);
|
|
53434
|
+
if (!config) return {
|
|
53435
|
+
status: 404,
|
|
53436
|
+
body: { error: `Unknown project key: ${projectKey}` }
|
|
53437
|
+
};
|
|
53438
|
+
const { runUatTrainReconcile } = await import("./uat-train-Dewoatps.js");
|
|
53439
|
+
return {
|
|
53440
|
+
status: 200,
|
|
53441
|
+
body: { projects: [{
|
|
53442
|
+
projectKey,
|
|
53443
|
+
result: await runUatTrainReconcile({
|
|
53444
|
+
force: true,
|
|
53445
|
+
projectRoot: resolve(config.path)
|
|
53446
|
+
})
|
|
53447
|
+
}] }
|
|
53448
|
+
};
|
|
53449
|
+
}
|
|
53450
|
+
const { runUatTrainReconcileAllProjects } = await import("./uat-train-Dewoatps.js");
|
|
53451
|
+
return {
|
|
53452
|
+
status: 200,
|
|
53453
|
+
body: { projects: await runUatTrainReconcileAllProjects({ force: true }) }
|
|
53454
|
+
};
|
|
53455
|
+
}
|
|
53456
|
+
/**
|
|
53457
|
+
* PAN-1737 generation names contain a slash (`uat/pan-otter-0610`); URL params
|
|
53458
|
+
* carry the name WITHOUT the `uat/` prefix and handlers reconstitute it. Same
|
|
53459
|
+
* reconstruction as the legacy flywheel routes so links stay interchangeable.
|
|
53460
|
+
*/
|
|
53461
|
+
function uatGenerationNameFromParam(param) {
|
|
53462
|
+
const decoded = decodeURIComponent(param);
|
|
53463
|
+
return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
|
|
53464
|
+
}
|
|
53465
|
+
const getMergeTrainQueuesRoute = HttpRouter.add("GET", "/api/merge-train/queues", httpHandler(Effect.gen(function* () {
|
|
53466
|
+
return jsonResponse(yield* Effect.promise(() => getMergeTrainQueuesPayload()));
|
|
53467
|
+
})));
|
|
53468
|
+
const getMergeTrainGenerationsRoute = HttpRouter.add("GET", "/api/merge-train/generations", httpHandler(Effect.gen(function* () {
|
|
53469
|
+
return jsonResponse(yield* Effect.promise(() => getMergeTrainGenerationsPayload()));
|
|
53470
|
+
})));
|
|
53471
|
+
const postMergeTrainGenerationStackRoute = HttpRouter.add("POST", "/api/merge-train/generations/:name/stack", httpHandler(Effect.gen(function* () {
|
|
53472
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53473
|
+
if (authError) return authError;
|
|
53474
|
+
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
53475
|
+
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-Dewoatps.js"));
|
|
53476
|
+
const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
|
|
53477
|
+
if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
|
|
53478
|
+
return jsonResponse({
|
|
53479
|
+
frontendUrl: result.frontendUrl,
|
|
53480
|
+
evicted: result.evicted
|
|
53481
|
+
});
|
|
53482
|
+
})));
|
|
53483
|
+
const postMergeTrainGenerationPromoteRoute = HttpRouter.add("POST", "/api/merge-train/generations/:name/promote", httpHandler(Effect.gen(function* () {
|
|
53484
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53485
|
+
if (authError) return authError;
|
|
53486
|
+
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
53487
|
+
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-Dewoatps.js"));
|
|
53488
|
+
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-KR3pKulN.js"));
|
|
53489
|
+
const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
|
|
53490
|
+
if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
|
|
53491
|
+
return jsonResponse(result);
|
|
53492
|
+
})));
|
|
53493
|
+
const postMergeTrainAssembleRoute = HttpRouter.add("POST", "/api/merge-train/assemble", httpHandler(Effect.gen(function* () {
|
|
53494
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53495
|
+
if (authError) return authError;
|
|
53496
|
+
const parsed = yield* readUnknownJsonBody$1;
|
|
53497
|
+
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 400 });
|
|
53498
|
+
const result = yield* Effect.promise(() => postMergeTrainAssemblePayload(parsed.body));
|
|
53499
|
+
return jsonResponse(result.body, { status: result.status });
|
|
53500
|
+
})));
|
|
53501
|
+
const postMergeTrainMergeNextRoute = HttpRouter.add("POST", "/api/merge-train/merge-next", httpHandler(Effect.gen(function* () {
|
|
53502
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53503
|
+
if (authError) return authError;
|
|
53504
|
+
const parsed = yield* readUnknownJsonBody$1;
|
|
53505
|
+
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 400 });
|
|
53506
|
+
const result = yield* Effect.promise(() => postMergeTrainMergeNextPayload(parsed.body));
|
|
53507
|
+
return jsonResponse(result.body, { status: result.status });
|
|
53508
|
+
})));
|
|
53509
|
+
const mergeTrainRouteLayer = Layer.mergeAll(getMergeTrainQueuesRoute, getMergeTrainGenerationsRoute, postMergeTrainGenerationStackRoute, postMergeTrainGenerationPromoteRoute, postMergeTrainAssembleRoute, postMergeTrainMergeNextRoute);
|
|
53510
|
+
//#endregion
|
|
52641
53511
|
//#region routes/context.ts
|
|
52642
53512
|
init_src();
|
|
52643
53513
|
init_layers();
|
|
@@ -53037,7 +53907,7 @@ function issueIdFromWorkspacePath(workspacePath) {
|
|
|
53037
53907
|
const match = /(?:^|[^a-z0-9])([a-z]+-\d+)(?:[^a-z0-9]|$)/i.exec(workspacePath);
|
|
53038
53908
|
return match ? match[1].toUpperCase() : null;
|
|
53039
53909
|
}
|
|
53040
|
-
function readJsonBody$
|
|
53910
|
+
function readJsonBody$7() {
|
|
53041
53911
|
return Effect.gen(function* () {
|
|
53042
53912
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53043
53913
|
return text ? JSON.parse(text) : {};
|
|
@@ -53051,7 +53921,7 @@ const getContextLayersRoute = HttpRouter.add("GET", "/api/context/layers", httpH
|
|
|
53051
53921
|
return jsonResponse(yield* Effect.promise(() => loadContextLayers(projects)));
|
|
53052
53922
|
})));
|
|
53053
53923
|
const postContextPreviewRoute = HttpRouter.add("POST", "/api/context/preview", httpHandler(Effect.gen(function* () {
|
|
53054
|
-
const body = yield* readJsonBody$
|
|
53924
|
+
const body = yield* readJsonBody$7();
|
|
53055
53925
|
const parsed = yield* Effect.try({
|
|
53056
53926
|
try: () => decodePreviewRequest(body),
|
|
53057
53927
|
catch: (error) => new Error(error instanceof Error ? error.message : String(error))
|
|
@@ -53060,7 +53930,7 @@ const postContextPreviewRoute = HttpRouter.add("POST", "/api/context/preview", h
|
|
|
53060
53930
|
return jsonResponse(yield* Effect.promise(() => previewContextLayers(projects, parsed)));
|
|
53061
53931
|
})));
|
|
53062
53932
|
const putContextLayerRoute = HttpRouter.add("PUT", "/api/context/layers", httpHandler(Effect.gen(function* () {
|
|
53063
|
-
const body = yield* readJsonBody$
|
|
53933
|
+
const body = yield* readJsonBody$7();
|
|
53064
53934
|
const parsed = yield* Effect.try({
|
|
53065
53935
|
try: () => decodeSaveRequest(body),
|
|
53066
53936
|
catch: (error) => new Error(error instanceof Error ? error.message : String(error))
|
|
@@ -53084,6 +53954,56 @@ const postContextSyncRoute = HttpRouter.add("POST", "/api/context/sync", httpHan
|
|
|
53084
53954
|
})));
|
|
53085
53955
|
const contextRouteLayer = Layer.mergeAll(getContextLayersRoute, postContextPreviewRoute, putContextLayerRoute, postContextSyncRoute);
|
|
53086
53956
|
//#endregion
|
|
53957
|
+
//#region routes/commands.ts
|
|
53958
|
+
init_src();
|
|
53959
|
+
const COMMANDS_API_HARNESSES = [
|
|
53960
|
+
"claude-code",
|
|
53961
|
+
"codex",
|
|
53962
|
+
"ohmypi",
|
|
53963
|
+
"acp"
|
|
53964
|
+
];
|
|
53965
|
+
const OVERDECK_COMMANDS = COMPOSER_COMMAND_MANIFEST.map((entry) => {
|
|
53966
|
+
const policy = resolvePolicy(entry.path);
|
|
53967
|
+
return {
|
|
53968
|
+
...entry,
|
|
53969
|
+
mode: policy.mode,
|
|
53970
|
+
safety: policy.safety
|
|
53971
|
+
};
|
|
53972
|
+
});
|
|
53973
|
+
const COMMAND_PAYLOADS = Object.fromEntries(COMMANDS_API_HARNESSES.map((harness) => [harness, {
|
|
53974
|
+
harness,
|
|
53975
|
+
overdeck: OVERDECK_COMMANDS,
|
|
53976
|
+
native: getHarnessBehavior(harness).nativeCommands ?? []
|
|
53977
|
+
}]));
|
|
53978
|
+
function getCommandsPayload(harness) {
|
|
53979
|
+
return COMMAND_PAYLOADS[harness];
|
|
53980
|
+
}
|
|
53981
|
+
function isCommandsApiHarness(value) {
|
|
53982
|
+
return COMMANDS_API_HARNESSES.includes(value);
|
|
53983
|
+
}
|
|
53984
|
+
function resolveCommandsRequest(harness) {
|
|
53985
|
+
const requestedHarness = harness ?? "claude-code";
|
|
53986
|
+
if (!isCommandsApiHarness(requestedHarness)) return {
|
|
53987
|
+
ok: false,
|
|
53988
|
+
error: `Unknown harness "${requestedHarness}". Expected one of: ${COMMANDS_API_HARNESSES.join(", ")}.`,
|
|
53989
|
+
accepted: COMMANDS_API_HARNESSES
|
|
53990
|
+
};
|
|
53991
|
+
return {
|
|
53992
|
+
ok: true,
|
|
53993
|
+
payload: getCommandsPayload(requestedHarness)
|
|
53994
|
+
};
|
|
53995
|
+
}
|
|
53996
|
+
const getCommandsRoute = HttpRouter.add("GET", "/api/commands", httpHandler(Effect.gen(function* () {
|
|
53997
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
53998
|
+
const result = resolveCommandsRequest(new URL(request.url, "http://localhost").searchParams.get("harness"));
|
|
53999
|
+
if (!result.ok) return jsonResponse({
|
|
54000
|
+
error: result.error,
|
|
54001
|
+
accepted: result.accepted
|
|
54002
|
+
}, { status: 400 });
|
|
54003
|
+
return jsonResponse(result.payload);
|
|
54004
|
+
})));
|
|
54005
|
+
const commandsRouteLayer = Layer.mergeAll(getCommandsRoute);
|
|
54006
|
+
//#endregion
|
|
53087
54007
|
//#region routes/admin.ts
|
|
53088
54008
|
init_tldr_daemon();
|
|
53089
54009
|
init_projects();
|
|
@@ -53193,7 +54113,7 @@ const adminRouteLayer = Layer.mergeAll(getAdminTldrRoute, postAdminBackfillTitle
|
|
|
53193
54113
|
* requiring a heavy `pan install` step before first use.
|
|
53194
54114
|
*/
|
|
53195
54115
|
init_platform();
|
|
53196
|
-
const execAsync$
|
|
54116
|
+
const execAsync$2 = promisify(exec);
|
|
53197
54117
|
const execFileAsync$2 = promisify(execFile);
|
|
53198
54118
|
const PREREQ_REGISTRY = {
|
|
53199
54119
|
addGitHubProject: ["gh"],
|
|
@@ -53252,7 +54172,7 @@ function getLinuxManualInstallHint(tool, packageManager) {
|
|
|
53252
54172
|
async function installLinuxPackage(tool) {
|
|
53253
54173
|
const packageManager = await detectLinuxPackageManager();
|
|
53254
54174
|
if (!packageManager) throw new Error(`No supported Linux package manager found. Install ${getLinuxManualInstallHint(tool, null)}`);
|
|
53255
|
-
await execAsync$
|
|
54175
|
+
await execAsync$2(getLinuxInstallCommand(tool, packageManager), { timeout: 12e4 });
|
|
53256
54176
|
}
|
|
53257
54177
|
async function isToolInstalled(tool) {
|
|
53258
54178
|
if (tool === "docker") return checkCommand("docker", ["info"]);
|
|
@@ -53295,7 +54215,7 @@ async function installTool(tool) {
|
|
|
53295
54215
|
}
|
|
53296
54216
|
}
|
|
53297
54217
|
async function installTmux() {
|
|
53298
|
-
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$
|
|
54218
|
+
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$2("brew install tmux", { timeout: 12e4 });
|
|
53299
54219
|
else await installLinuxPackage("tmux");
|
|
53300
54220
|
return {
|
|
53301
54221
|
tool: "tmux",
|
|
@@ -53309,14 +54229,14 @@ async function installTtyd() {
|
|
|
53309
54229
|
mkdirSync$1(binDir, { recursive: true });
|
|
53310
54230
|
const ttydPath = join(binDir, "ttyd");
|
|
53311
54231
|
if (plat === "darwin") try {
|
|
53312
|
-
await execAsync$
|
|
54232
|
+
await execAsync$2("brew install ttyd", { timeout: 12e4 });
|
|
53313
54233
|
return {
|
|
53314
54234
|
tool: "ttyd",
|
|
53315
54235
|
success: true,
|
|
53316
54236
|
message: "ttyd installed via Homebrew"
|
|
53317
54237
|
};
|
|
53318
54238
|
} catch {}
|
|
53319
|
-
await execAsync$
|
|
54239
|
+
await execAsync$2(`curl -sL "https://github.com/tsl0922/ttyd/releases/latest/download/ttyd.x86_64" -o "${ttydPath}" && chmod +x "${ttydPath}"`, { timeout: 6e4 });
|
|
53320
54240
|
return {
|
|
53321
54241
|
tool: "ttyd",
|
|
53322
54242
|
success: true,
|
|
@@ -53325,8 +54245,8 @@ async function installTtyd() {
|
|
|
53325
54245
|
}
|
|
53326
54246
|
async function installMkcert() {
|
|
53327
54247
|
if (await Effect.runPromise(detectPlatform()) === "darwin") {
|
|
53328
|
-
await execAsync$
|
|
53329
|
-
await execAsync$
|
|
54248
|
+
await execAsync$2("brew install mkcert", { timeout: 12e4 });
|
|
54249
|
+
await execAsync$2("mkcert -install", { timeout: 3e4 });
|
|
53330
54250
|
return {
|
|
53331
54251
|
tool: "mkcert",
|
|
53332
54252
|
success: true,
|
|
@@ -53336,8 +54256,8 @@ async function installMkcert() {
|
|
|
53336
54256
|
const binDir = join(homedir$1(), ".local", "bin");
|
|
53337
54257
|
mkdirSync$1(binDir, { recursive: true });
|
|
53338
54258
|
const mkcertPath = join(binDir, "mkcert");
|
|
53339
|
-
await execAsync$
|
|
53340
|
-
await execAsync$
|
|
54259
|
+
await execAsync$2(`curl -sL "https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-${process.arch === "x64" ? "amd64" : process.arch}" -o "${mkcertPath}" && chmod +x "${mkcertPath}"`, { timeout: 6e4 });
|
|
54260
|
+
await execAsync$2("mkcert -install", { timeout: 3e4 });
|
|
53341
54261
|
return {
|
|
53342
54262
|
tool: "mkcert",
|
|
53343
54263
|
success: true,
|
|
@@ -53345,7 +54265,7 @@ async function installMkcert() {
|
|
|
53345
54265
|
};
|
|
53346
54266
|
}
|
|
53347
54267
|
async function installJq() {
|
|
53348
|
-
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$
|
|
54268
|
+
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$2("brew install jq", { timeout: 12e4 });
|
|
53349
54269
|
else await installLinuxPackage("jq");
|
|
53350
54270
|
return {
|
|
53351
54271
|
tool: "jq",
|
|
@@ -53360,7 +54280,7 @@ async function installOx() {
|
|
|
53360
54280
|
const binDir = join(homedir$1(), ".local", "bin");
|
|
53361
54281
|
const oxPath = join(binDir, "ox");
|
|
53362
54282
|
mkdirSync$1(binDir, { recursive: true });
|
|
53363
|
-
await execAsync$
|
|
54283
|
+
await execAsync$2(`curl -sL "https://github.com/eltmon/ox/releases/download/latest/ox-${platform}-${arch}" -o "${oxPath}" && chmod +x "${oxPath}"`, { timeout: 6e4 });
|
|
53364
54284
|
return {
|
|
53365
54285
|
tool: "ox",
|
|
53366
54286
|
success: true,
|
|
@@ -53377,7 +54297,7 @@ async function installOx() {
|
|
|
53377
54297
|
* GET /api/prereqs/:feature — check which tools are missing for a feature
|
|
53378
54298
|
* POST /api/prereqs/install — install a specific tool by name
|
|
53379
54299
|
*/
|
|
53380
|
-
const readJsonBody$
|
|
54300
|
+
const readJsonBody$6 = Effect.gen(function* () {
|
|
53381
54301
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53382
54302
|
try {
|
|
53383
54303
|
return text ? JSON.parse(text) : {};
|
|
@@ -53414,7 +54334,7 @@ const checkFeatureRoute = HttpRouter.add("GET", "/api/prereqs/:feature", httpHan
|
|
|
53414
54334
|
});
|
|
53415
54335
|
})));
|
|
53416
54336
|
const installToolRoute = HttpRouter.add("POST", "/api/prereqs/install", httpHandler(Effect.gen(function* () {
|
|
53417
|
-
const tool = (yield* readJsonBody$
|
|
54337
|
+
const tool = (yield* readJsonBody$6).tool;
|
|
53418
54338
|
if (!tool) return jsonResponse({ error: "Missing 'tool' in request body" }, { status: 400 });
|
|
53419
54339
|
if (!INSTALLABLE_TOOLS.some((t) => t === tool)) return jsonResponse({ error: `Tool '${tool}' is not auto-installable` }, { status: 400 });
|
|
53420
54340
|
const result = yield* Effect.promise(() => installTool(tool));
|
|
@@ -54075,7 +54995,7 @@ function getCheckpointWorker() {
|
|
|
54075
54995
|
return worker;
|
|
54076
54996
|
}
|
|
54077
54997
|
async function runInline(operation, payload) {
|
|
54078
|
-
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-
|
|
54998
|
+
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-Wm963lm8.js");
|
|
54079
54999
|
switch (operation) {
|
|
54080
55000
|
case "claimTranscriptRange": return claimTranscriptRange(payload);
|
|
54081
55001
|
case "commitTranscriptRange": return commitTranscriptRange(payload);
|
|
@@ -55229,7 +56149,7 @@ function buildPendingTurn(input, fromOffset, toOffset, compressed) {
|
|
|
55229
56149
|
};
|
|
55230
56150
|
}
|
|
55231
56151
|
async function emitMemoryObservationCreated(observation, timestamp) {
|
|
55232
|
-
const { initEventStore } = await import("./event-store-
|
|
56152
|
+
const { initEventStore } = await import("./event-store-5UKzh9Jf.js");
|
|
55233
56153
|
await (await initEventStore()).appendAsync({
|
|
55234
56154
|
type: "memory.observation_created",
|
|
55235
56155
|
timestamp,
|
|
@@ -56360,7 +57280,16 @@ async function handleMemorySessionStartBody(body, options = {}) {
|
|
|
56360
57280
|
statusCode: 422,
|
|
56361
57281
|
error: "memory identity could not be resolved"
|
|
56362
57282
|
};
|
|
56363
|
-
|
|
57283
|
+
let fileStat;
|
|
57284
|
+
try {
|
|
57285
|
+
fileStat = await (options.statTranscript ?? getTranscriptStat$1)(trustedTranscriptPath);
|
|
57286
|
+
} catch (error) {
|
|
57287
|
+
if (error.code === "ENOENT") return {
|
|
57288
|
+
status: "transcript-missing",
|
|
57289
|
+
sessionId
|
|
57290
|
+
};
|
|
57291
|
+
throw error;
|
|
57292
|
+
}
|
|
56364
57293
|
(options.registerTranscript ?? registerTranscriptForPolling)({
|
|
56365
57294
|
agentId: stringField(body.agentId) ?? stringField(body.agent_id) ?? identity.runId,
|
|
56366
57295
|
sessionId,
|
|
@@ -56491,7 +57420,7 @@ const postMemorySessionStartRoute = HttpRouter.add("POST", "/api/memory/session/
|
|
|
56491
57420
|
}
|
|
56492
57421
|
const readModel = yield* ReadModelService;
|
|
56493
57422
|
const result = yield* Effect.promise(() => handleMemorySessionStartBody(body, { resolveAgentIdBySessionId: async (sessionId) => Effect.runPromise(readModel.getAgentIdBySessionId(sessionId)) }));
|
|
56494
|
-
if (result.status === "subagent" || result.status === "disabled") return HttpServerResponse.text("", { status: 204 });
|
|
57423
|
+
if (result.status === "subagent" || result.status === "disabled" || result.status === "transcript-missing") return HttpServerResponse.text("", { status: 204 });
|
|
56495
57424
|
if (result.status === "error") return jsonResponse({
|
|
56496
57425
|
ok: false,
|
|
56497
57426
|
error: result.error
|
|
@@ -56895,6 +57824,93 @@ const postTestCheckpointRoute = HttpRouter.add("POST", "/api/agents/:agentId/dif
|
|
|
56895
57824
|
}));
|
|
56896
57825
|
const diffsRouteLayer = Layer.mergeAll(getDiffsRoute, getTurnDiffRoute, getFullDiffRoute, getVsMainDiffRoute, postTestCheckpointRoute);
|
|
56897
57826
|
//#endregion
|
|
57827
|
+
//#region routes/linear-mcp-auth.ts
|
|
57828
|
+
init_issue_service_singleton();
|
|
57829
|
+
const LINEAR_MCP_AUTH_CALLBACK_COPY_PREFIX = "The operator completed the Linear OAuth authorization in their browser. Finish the flow now: call mcp__linear__complete_authentication with callback_url set to exactly this URL:";
|
|
57830
|
+
const readJsonBody$5 = Effect.gen(function* () {
|
|
57831
|
+
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
57832
|
+
return text ? JSON.parse(text) : {};
|
|
57833
|
+
});
|
|
57834
|
+
function rejectInvalidOrigin(request) {
|
|
57835
|
+
const originCheck = validateOrigin$1(request);
|
|
57836
|
+
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
57837
|
+
return null;
|
|
57838
|
+
}
|
|
57839
|
+
function isValidLinearMcpCallbackUrl(value) {
|
|
57840
|
+
try {
|
|
57841
|
+
const url = new URL(value);
|
|
57842
|
+
const localHost = url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
|
57843
|
+
return url.protocol === "http:" && localHost && !!url.searchParams.get("code") && !!url.searchParams.get("state");
|
|
57844
|
+
} catch {
|
|
57845
|
+
return false;
|
|
57846
|
+
}
|
|
57847
|
+
}
|
|
57848
|
+
function callbackCopy(callbackUrl) {
|
|
57849
|
+
return `${LINEAR_MCP_AUTH_CALLBACK_COPY_PREFIX} ${callbackUrl} — then re-check Linear access and resume your canonical task.`;
|
|
57850
|
+
}
|
|
57851
|
+
/**
|
|
57852
|
+
* Attach each blocked agent's canonical tracker URL (Linear web URL, GitHub
|
|
57853
|
+
* html_url) from the issues read door so the banner can link every blocked
|
|
57854
|
+
* agent's issue — including Linear-tracked ones the frontend cannot derive a
|
|
57855
|
+
* URL for. Best-effort: an unresolvable issue falls back to null and the
|
|
57856
|
+
* banner renders its own fallback.
|
|
57857
|
+
*/
|
|
57858
|
+
function withIssueUrls(intervention) {
|
|
57859
|
+
let urlByIdentifier;
|
|
57860
|
+
try {
|
|
57861
|
+
urlByIdentifier = /* @__PURE__ */ new Map();
|
|
57862
|
+
const issues = getSharedIssueService().getIssues({ includeCompleted: true });
|
|
57863
|
+
for (const issue of issues) if (typeof issue.identifier === "string" && typeof issue.url === "string" && issue.url !== "") urlByIdentifier.set(issue.identifier.toLowerCase(), issue.url);
|
|
57864
|
+
} catch {
|
|
57865
|
+
return intervention;
|
|
57866
|
+
}
|
|
57867
|
+
return {
|
|
57868
|
+
...intervention,
|
|
57869
|
+
blockedAgents: intervention.blockedAgents.map((agent) => ({
|
|
57870
|
+
...agent,
|
|
57871
|
+
issueUrl: agent.issueId ? urlByIdentifier.get(agent.issueId.toLowerCase()) ?? null : null
|
|
57872
|
+
}))
|
|
57873
|
+
};
|
|
57874
|
+
}
|
|
57875
|
+
const getLinearMcpAuthRoute = HttpRouter.add("GET", "/api/linear-mcp-auth", httpHandler(Effect.gen(function* () {
|
|
57876
|
+
return jsonResponse(withIssueUrls(yield* Effect.promise(() => resolveLinearMcpAuthIntervention())));
|
|
57877
|
+
})));
|
|
57878
|
+
const postLinearMcpAuthCallbackRoute = HttpRouter.add("POST", "/api/linear-mcp-auth/callback", httpHandler(Effect.gen(function* () {
|
|
57879
|
+
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
57880
|
+
if (originError) return originError;
|
|
57881
|
+
const body = yield* readJsonBody$5;
|
|
57882
|
+
const callbackUrl = typeof body["callbackUrl"] === "string" ? body["callbackUrl"] : "";
|
|
57883
|
+
if (!isValidLinearMcpCallbackUrl(callbackUrl)) return jsonResponse({
|
|
57884
|
+
success: false,
|
|
57885
|
+
error: "callbackUrl must be a localhost OAuth callback URL with code and state parameters"
|
|
57886
|
+
}, { status: 400 });
|
|
57887
|
+
const intervention = yield* Effect.promise(() => resolveLinearMcpAuthIntervention());
|
|
57888
|
+
if (intervention.authUrlAgentId === null) return jsonResponse({
|
|
57889
|
+
success: false,
|
|
57890
|
+
error: "No blocked agent owns the active Linear authorization URL"
|
|
57891
|
+
}, { status: 409 });
|
|
57892
|
+
yield* Effect.promise(() => messageAgent(intervention.authUrlAgentId, callbackCopy(callbackUrl), "linear-mcp-auth-callback"));
|
|
57893
|
+
yield* Effect.promise(() => appendLinearMcpAuthCallbackRelayedEvent({
|
|
57894
|
+
agentId: intervention.authUrlAgentId,
|
|
57895
|
+
issueId: intervention.blockedAgents.find((agent) => agent.agentId === intervention.authUrlAgentId)?.issueId ?? null
|
|
57896
|
+
}));
|
|
57897
|
+
return jsonResponse({
|
|
57898
|
+
success: true,
|
|
57899
|
+
relayedTo: intervention.authUrlAgentId
|
|
57900
|
+
});
|
|
57901
|
+
})));
|
|
57902
|
+
const postLinearMcpAuthCompleteRoute = HttpRouter.add("POST", "/api/linear-mcp-auth/complete", httpHandler(Effect.gen(function* () {
|
|
57903
|
+
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
57904
|
+
if (originError) return originError;
|
|
57905
|
+
yield* Effect.promise(() => appendLinearMcpAuthHealthyEvent({
|
|
57906
|
+
agentId: "operator",
|
|
57907
|
+
issueId: null,
|
|
57908
|
+
source: "operator"
|
|
57909
|
+
}));
|
|
57910
|
+
return jsonResponse({ success: true });
|
|
57911
|
+
})));
|
|
57912
|
+
const linearMcpAuthRouteLayer = Layer.mergeAll(getLinearMcpAuthRoute, postLinearMcpAuthCallbackRoute, postLinearMcpAuthCompleteRoute);
|
|
57913
|
+
//#endregion
|
|
56898
57914
|
//#region routes/terminals.ts
|
|
56899
57915
|
/**
|
|
56900
57916
|
* Terminal routes (PAN-1545 / PAN-1561) — ad-hoc tmux sessions for the
|
|
@@ -57644,6 +58660,287 @@ const getSubstrateBugWeightsRoute = HttpRouter.add("GET", "/api/flywheel/substra
|
|
|
57644
58660
|
})));
|
|
57645
58661
|
})));
|
|
57646
58662
|
//#endregion
|
|
58663
|
+
//#region services/flywheel-actions.ts
|
|
58664
|
+
init_config_yaml();
|
|
58665
|
+
init_harness_resolve();
|
|
58666
|
+
init_control_settings();
|
|
58667
|
+
init_tmux();
|
|
58668
|
+
const DEFAULT_BRIEF_PATH$1 = "docs/flywheel-brief.md";
|
|
58669
|
+
const execAsync$1 = promisify(exec);
|
|
58670
|
+
function mb(bytes) {
|
|
58671
|
+
return Math.round(bytes / 1024 / 1024);
|
|
58672
|
+
}
|
|
58673
|
+
function isInsideRoot$1(projectRoot, candidate) {
|
|
58674
|
+
const relativePath = relative(projectRoot, candidate);
|
|
58675
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
58676
|
+
}
|
|
58677
|
+
function resolveFlywheelStartBriefPath(cwd, requestedPath) {
|
|
58678
|
+
const rawPath = requestedPath?.trim() || DEFAULT_BRIEF_PATH$1;
|
|
58679
|
+
if (rawPath.includes("\0")) throw new Error("Brief path is invalid");
|
|
58680
|
+
const root = resolve(cwd);
|
|
58681
|
+
const absolutePath = isAbsolute(rawPath) ? resolve(rawPath) : resolve(root, rawPath);
|
|
58682
|
+
if (!isInsideRoot$1(root, absolutePath)) throw new Error("Brief path must stay inside the project root");
|
|
58683
|
+
const normalizedRoot = root.endsWith(sep) ? root : `${root}${sep}`;
|
|
58684
|
+
const displayPath = absolutePath === root ? "." : relative(root, absolutePath);
|
|
58685
|
+
return {
|
|
58686
|
+
absolutePath,
|
|
58687
|
+
displayPath: absolutePath.startsWith(normalizedRoot) ? displayPath : absolutePath
|
|
58688
|
+
};
|
|
58689
|
+
}
|
|
58690
|
+
async function assertExistingPathInsideRoot$1(projectRoot, candidate) {
|
|
58691
|
+
const [realRoot, realCandidate] = await Promise.all([realpath(projectRoot), realpath(candidate)]);
|
|
58692
|
+
if (!isInsideRoot$1(realRoot, realCandidate)) throw new Error("Brief path must stay inside the project root");
|
|
58693
|
+
}
|
|
58694
|
+
async function requireFlywheelBrief(cwd, requestedPath) {
|
|
58695
|
+
const resolved = resolveFlywheelStartBriefPath(cwd, requestedPath);
|
|
58696
|
+
try {
|
|
58697
|
+
await assertExistingPathInsideRoot$1(cwd, resolved.absolutePath);
|
|
58698
|
+
await readFile(resolved.absolutePath, "utf8");
|
|
58699
|
+
return resolved;
|
|
58700
|
+
} catch (error) {
|
|
58701
|
+
if ((typeof error === "object" && error !== null && "code" in error ? error.code : void 0) === "ENOENT") throw new Error(`Flywheel brief not found: ${resolved.displayPath}`);
|
|
58702
|
+
throw error;
|
|
58703
|
+
}
|
|
58704
|
+
}
|
|
58705
|
+
async function dashboardSetting(key) {
|
|
58706
|
+
return runDashboardDbJob("getSetting", key);
|
|
58707
|
+
}
|
|
58708
|
+
async function setDashboardSetting(key, value) {
|
|
58709
|
+
await runDashboardDbJob("setSetting", {
|
|
58710
|
+
key,
|
|
58711
|
+
value
|
|
58712
|
+
});
|
|
58713
|
+
}
|
|
58714
|
+
async function getActiveRunId() {
|
|
58715
|
+
const value = await dashboardSetting(FLYWHEEL_ACTIVE_RUN_ID_KEY);
|
|
58716
|
+
return value && value.trim() ? value : null;
|
|
58717
|
+
}
|
|
58718
|
+
async function setActiveRunId(runId) {
|
|
58719
|
+
await setDashboardSetting(FLYWHEEL_ACTIVE_RUN_ID_KEY, runId ?? "");
|
|
58720
|
+
}
|
|
58721
|
+
async function isPaused() {
|
|
58722
|
+
return await dashboardSetting(FLYWHEEL_GLOBAL_PAUSE_KEY) === "true";
|
|
58723
|
+
}
|
|
58724
|
+
async function setPaused(paused) {
|
|
58725
|
+
await setDashboardSetting(FLYWHEEL_GLOBAL_PAUSE_KEY, paused ? "true" : "false");
|
|
58726
|
+
}
|
|
58727
|
+
async function readGateSnapshot() {
|
|
58728
|
+
const [paused, activeRunId] = await Promise.all([isPaused(), getActiveRunId()]);
|
|
58729
|
+
return {
|
|
58730
|
+
paused,
|
|
58731
|
+
activeRunId
|
|
58732
|
+
};
|
|
58733
|
+
}
|
|
58734
|
+
async function resolveFlywheelRoleConfig() {
|
|
58735
|
+
const { config } = await Effect.runPromise(loadConfigNoMigration());
|
|
58736
|
+
const flywheel = config.roles?.flywheel;
|
|
58737
|
+
const model = resolveModel("flywheel", void 0, config);
|
|
58738
|
+
return {
|
|
58739
|
+
harness: await resolveHarness({ model }),
|
|
58740
|
+
model,
|
|
58741
|
+
effort: flywheel?.effort ?? "high",
|
|
58742
|
+
minAgents: flywheel?.minAgents ?? 20,
|
|
58743
|
+
maxAgents: flywheel?.maxAgents ?? 30,
|
|
58744
|
+
scope: flywheel?.scope ?? "pan-only"
|
|
58745
|
+
};
|
|
58746
|
+
}
|
|
58747
|
+
async function gitOutput(command, cwd) {
|
|
58748
|
+
const { stdout } = await execAsync$1(command, {
|
|
58749
|
+
cwd,
|
|
58750
|
+
encoding: "utf8"
|
|
58751
|
+
});
|
|
58752
|
+
return stdout.trim();
|
|
58753
|
+
}
|
|
58754
|
+
async function createInitialFlywheelStatus(runId, startedAt, cwd, agentModel, agentHarness, roleConfig) {
|
|
58755
|
+
const ramTotalMb = mb(totalmem$1());
|
|
58756
|
+
return {
|
|
58757
|
+
runId,
|
|
58758
|
+
startedAt,
|
|
58759
|
+
elapsedMs: 0,
|
|
58760
|
+
orchestrator: {
|
|
58761
|
+
harness: agentHarness ?? roleConfig.harness,
|
|
58762
|
+
model: agentModel ?? roleConfig.model,
|
|
58763
|
+
effort: roleConfig.effort,
|
|
58764
|
+
ctxPercent: 0
|
|
58765
|
+
},
|
|
58766
|
+
headline: {
|
|
58767
|
+
bugsFixed: 0,
|
|
58768
|
+
swarmItemsMerged: 0,
|
|
58769
|
+
swarmItemsTotal: 0,
|
|
58770
|
+
prsMerged: 0,
|
|
58771
|
+
awaitingUat: 0
|
|
58772
|
+
},
|
|
58773
|
+
scope: roleConfig.scope,
|
|
58774
|
+
activePipeline: [],
|
|
58775
|
+
substrateBugs: [],
|
|
58776
|
+
agents: [{
|
|
58777
|
+
id: FLYWHEEL_ORCHESTRATOR_AGENT_ID,
|
|
58778
|
+
label: "flywheel-orchestrator",
|
|
58779
|
+
status: "running",
|
|
58780
|
+
role: "flywheel",
|
|
58781
|
+
model: agentModel
|
|
58782
|
+
}],
|
|
58783
|
+
parked: [],
|
|
58784
|
+
suggestions: [],
|
|
58785
|
+
system: {
|
|
58786
|
+
mainHead: await gitOutput("git rev-parse --short HEAD", cwd).catch(() => "unknown"),
|
|
58787
|
+
ramUsedMb: Math.max(0, ramTotalMb - mb(freemem$1())),
|
|
58788
|
+
ramTotalMb,
|
|
58789
|
+
swapUsedMb: 0,
|
|
58790
|
+
swapTotalMb: 0,
|
|
58791
|
+
agentsActive: 1,
|
|
58792
|
+
agentsCap: roleConfig.maxAgents
|
|
58793
|
+
},
|
|
58794
|
+
openQuestions: [],
|
|
58795
|
+
ticks: 0,
|
|
58796
|
+
lastTickAt: startedAt
|
|
58797
|
+
};
|
|
58798
|
+
}
|
|
58799
|
+
async function startFlywheelRunForDashboard(options = {}) {
|
|
58800
|
+
const cwd = options.cwd ?? process.cwd();
|
|
58801
|
+
if (isFlywheelDevcontainerRuntime()) throw new Error("Refusing to spawn flywheel-orchestrator inside a workspace devcontainer");
|
|
58802
|
+
const activeRunId = await resolveLiveFlywheelRunId();
|
|
58803
|
+
if (activeRunId) if (!await Effect.runPromise(sessionExists("flywheel-orchestrator")) || await Effect.runPromise(isPaneDead("flywheel-orchestrator"))) {
|
|
58804
|
+
console.log(`[flywheel] ${activeRunId} gate stuck — orchestrator pane is dead; auto-aborting`);
|
|
58805
|
+
await Effect.runPromise(killSession(FLYWHEEL_ORCHESTRATOR_AGENT_ID)).catch(() => {});
|
|
58806
|
+
await abortFlywheelRun(activeRunId);
|
|
58807
|
+
} else throw new Error(`Flywheel run ${activeRunId} is already active; pause, resume, or report it before starting another run`);
|
|
58808
|
+
const brief = await requireFlywheelBrief(cwd, options.brief ?? DEFAULT_BRIEF_PATH$1);
|
|
58809
|
+
const runId = await nextFlywheelRunId();
|
|
58810
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
58811
|
+
const roleConfig = await resolveFlywheelRoleConfig();
|
|
58812
|
+
await writeFlywheelLaunchMetadata({
|
|
58813
|
+
version: 1,
|
|
58814
|
+
runId,
|
|
58815
|
+
workspace: cwd,
|
|
58816
|
+
briefPath: brief.absolutePath,
|
|
58817
|
+
briefDisplayPath: brief.displayPath,
|
|
58818
|
+
scope: roleConfig.scope
|
|
58819
|
+
});
|
|
58820
|
+
const agent = await spawnFlywheelAgent(runId, {
|
|
58821
|
+
briefPath: brief.absolutePath,
|
|
58822
|
+
workspace: cwd,
|
|
58823
|
+
model: roleConfig.model,
|
|
58824
|
+
harness: roleConfig.harness,
|
|
58825
|
+
effort: roleConfig.effort,
|
|
58826
|
+
minAgents: roleConfig.minAgents,
|
|
58827
|
+
maxAgents: roleConfig.maxAgents,
|
|
58828
|
+
scope: roleConfig.scope
|
|
58829
|
+
});
|
|
58830
|
+
await setActiveRunId(runId);
|
|
58831
|
+
await setPaused(false);
|
|
58832
|
+
await writeLatestFlywheelStatus(await createInitialFlywheelStatus(runId, startedAt, cwd, agent.model, agent.harness, roleConfig));
|
|
58833
|
+
return {
|
|
58834
|
+
runId,
|
|
58835
|
+
briefDisplayPath: resolveFlywheelStartBriefPath(cwd, options.brief ?? DEFAULT_BRIEF_PATH$1).displayPath,
|
|
58836
|
+
agentModel: agent.model
|
|
58837
|
+
};
|
|
58838
|
+
}
|
|
58839
|
+
async function pauseFlywheelRunForDashboard() {
|
|
58840
|
+
const before = await readGateSnapshot();
|
|
58841
|
+
if (before.paused) return {
|
|
58842
|
+
before,
|
|
58843
|
+
after: before,
|
|
58844
|
+
changed: false
|
|
58845
|
+
};
|
|
58846
|
+
if (before.activeRunId) try {
|
|
58847
|
+
const { readFile } = await import("node:fs/promises");
|
|
58848
|
+
const { join } = await import("node:path");
|
|
58849
|
+
const { getAgentDir } = await import("./agents-ePFVoZbu.js");
|
|
58850
|
+
const sessionId = (await readFile(join(getAgentDir(FLYWHEEL_ORCHESTRATOR_AGENT_ID), "session.id"), "utf-8")).trim();
|
|
58851
|
+
if (sessionId) await saveResumeSessionId(before.activeRunId, sessionId);
|
|
58852
|
+
} catch {}
|
|
58853
|
+
await setPaused(true);
|
|
58854
|
+
await import("./agents-ePFVoZbu.js").then(({ stopAgent }) => Effect.runPromise(stopAgent(FLYWHEEL_ORCHESTRATOR_AGENT_ID)));
|
|
58855
|
+
return {
|
|
58856
|
+
before,
|
|
58857
|
+
after: await readGateSnapshot(),
|
|
58858
|
+
changed: true
|
|
58859
|
+
};
|
|
58860
|
+
}
|
|
58861
|
+
async function abortFlywheelRunForDashboard() {
|
|
58862
|
+
const candidate = await getActiveRunId();
|
|
58863
|
+
if (!candidate) return { aborted: await resolveLiveFlywheelRunId() ?? null };
|
|
58864
|
+
const { stopAgent } = await import("./agents-ePFVoZbu.js");
|
|
58865
|
+
await Effect.runPromise(stopAgent(FLYWHEEL_ORCHESTRATOR_AGENT_ID));
|
|
58866
|
+
await abortFlywheelRun(candidate);
|
|
58867
|
+
return { aborted: candidate };
|
|
58868
|
+
}
|
|
58869
|
+
async function resumeFlywheelRunForDashboard() {
|
|
58870
|
+
const before = await readGateSnapshot();
|
|
58871
|
+
if (!before.paused && await Effect.runPromise(sessionExists("flywheel-orchestrator"))) return {
|
|
58872
|
+
before,
|
|
58873
|
+
after: before,
|
|
58874
|
+
changed: false
|
|
58875
|
+
};
|
|
58876
|
+
if (!before.activeRunId) throw new Error("No active flywheel run to resume");
|
|
58877
|
+
const launch = await readFlywheelLaunchMetadata(before.activeRunId);
|
|
58878
|
+
if (!launch) throw new Error(`Flywheel run ${before.activeRunId} is missing launch metadata; cannot resume safely`);
|
|
58879
|
+
const brief = await requireFlywheelBrief(launch.workspace, launch.briefPath);
|
|
58880
|
+
const roleConfig = await resolveFlywheelRoleConfig();
|
|
58881
|
+
if (launch.scope !== roleConfig.scope) await writeFlywheelLaunchMetadata({
|
|
58882
|
+
...launch,
|
|
58883
|
+
version: 1,
|
|
58884
|
+
scope: roleConfig.scope
|
|
58885
|
+
});
|
|
58886
|
+
const resumeSessionId = await loadResumeSessionId(before.activeRunId) ?? void 0;
|
|
58887
|
+
await spawnFlywheelAgent(before.activeRunId, {
|
|
58888
|
+
workspace: launch.workspace,
|
|
58889
|
+
briefPath: brief.absolutePath,
|
|
58890
|
+
model: roleConfig.model,
|
|
58891
|
+
harness: roleConfig.harness,
|
|
58892
|
+
effort: roleConfig.effort,
|
|
58893
|
+
minAgents: roleConfig.minAgents,
|
|
58894
|
+
maxAgents: roleConfig.maxAgents,
|
|
58895
|
+
scope: roleConfig.scope,
|
|
58896
|
+
resumeSessionId
|
|
58897
|
+
});
|
|
58898
|
+
await setPaused(false);
|
|
58899
|
+
return {
|
|
58900
|
+
before,
|
|
58901
|
+
after: await readGateSnapshot(),
|
|
58902
|
+
changed: true
|
|
58903
|
+
};
|
|
58904
|
+
}
|
|
58905
|
+
function getPlatformOpenCommand() {
|
|
58906
|
+
switch (process.platform) {
|
|
58907
|
+
case "linux": return "xdg-open";
|
|
58908
|
+
case "darwin": return "open";
|
|
58909
|
+
case "win32": return "explorer";
|
|
58910
|
+
default: throw new Error(`Opening files is not supported on ${process.platform}`);
|
|
58911
|
+
}
|
|
58912
|
+
}
|
|
58913
|
+
function openPathDetached(path) {
|
|
58914
|
+
spawn(getPlatformOpenCommand(), [path], {
|
|
58915
|
+
detached: true,
|
|
58916
|
+
stdio: "ignore"
|
|
58917
|
+
}).unref();
|
|
58918
|
+
}
|
|
58919
|
+
async function resolveReportOpenRunId(runId) {
|
|
58920
|
+
if (runId) return runId;
|
|
58921
|
+
const runs = await listFlywheelRuns();
|
|
58922
|
+
const run = runs.find((candidate) => candidate.status === "complete") ?? runs[0];
|
|
58923
|
+
if (!run) throw new Error("no flywheel run report to open");
|
|
58924
|
+
return run.id;
|
|
58925
|
+
}
|
|
58926
|
+
async function openFlywheelRunReportForDashboard(options = {}) {
|
|
58927
|
+
const runId = await resolveReportOpenRunId(options.runId);
|
|
58928
|
+
const detail = await getFlywheelRunDetail(runId);
|
|
58929
|
+
if (!detail) throw new Error(`Flywheel run not found: ${runId}`);
|
|
58930
|
+
if (!detail.paths.report) throw new Error(`No report exists for ${runId}`);
|
|
58931
|
+
await (options.opener ?? openPathDetached)(detail.paths.report);
|
|
58932
|
+
return {
|
|
58933
|
+
runId,
|
|
58934
|
+
path: detail.paths.report
|
|
58935
|
+
};
|
|
58936
|
+
}
|
|
58937
|
+
async function readCurrentFlywheelStatusForDashboard() {
|
|
58938
|
+
const activeRunId = await resolveLiveFlywheelRunId();
|
|
58939
|
+
if (!activeRunId) return null;
|
|
58940
|
+
const activeRun = await getFlywheelRunDetail(activeRunId);
|
|
58941
|
+
return activeRun?.status === "running" ? activeRun.latest : null;
|
|
58942
|
+
}
|
|
58943
|
+
//#endregion
|
|
57647
58944
|
//#region services/flywheel-state.ts
|
|
57648
58945
|
const FLYWHEEL_STATE_RELATIVE_PATH = "docs/FLYWHEEL-STATE.md";
|
|
57649
58946
|
function resolveStatePath(projectRoot) {
|
|
@@ -57679,6 +58976,7 @@ async function readFlywheelState(options = {}) {
|
|
|
57679
58976
|
const AUTO_MERGE_COOLDOWN_MS = 3e5;
|
|
57680
58977
|
//#endregion
|
|
57681
58978
|
//#region ../../lib/cloister/auto-merge-eligibility.ts
|
|
58979
|
+
init_forge();
|
|
57682
58980
|
init_review_status();
|
|
57683
58981
|
init_tracker_utils();
|
|
57684
58982
|
const execFileAsync$1 = promisify(execFile);
|
|
@@ -57938,6 +59236,7 @@ init_src();
|
|
|
57938
59236
|
init_activity_logger();
|
|
57939
59237
|
init_tmux();
|
|
57940
59238
|
init_control_settings();
|
|
59239
|
+
init_forge();
|
|
57941
59240
|
init_review_status();
|
|
57942
59241
|
init_projects();
|
|
57943
59242
|
const DEFAULT_BRIEF_PATH = "docs/flywheel-brief.md";
|
|
@@ -58225,7 +59524,8 @@ function deleteAutoMergePayload(issueIdParam, deps = {}) {
|
|
|
58225
59524
|
...entry,
|
|
58226
59525
|
status: "cancelled",
|
|
58227
59526
|
cancelledAt,
|
|
58228
|
-
cancelledBy: "operator"
|
|
59527
|
+
cancelledBy: "operator",
|
|
59528
|
+
remainingActionable: (deps.countRemaining ?? countActionableAutoMerges)(issueId)
|
|
58229
59529
|
}
|
|
58230
59530
|
};
|
|
58231
59531
|
}
|
|
@@ -58242,7 +59542,7 @@ async function getFlywheelConversationPayload() {
|
|
|
58242
59542
|
};
|
|
58243
59543
|
}
|
|
58244
59544
|
async function postFlywheelReportPayload() {
|
|
58245
|
-
const { flywheelReportCommand } = await import("./flywheel-
|
|
59545
|
+
const { flywheelReportCommand } = await import("./flywheel-f662Q-y2.js");
|
|
58246
59546
|
await flywheelReportCommand({ cwd: process.cwd() });
|
|
58247
59547
|
return {
|
|
58248
59548
|
status: 200,
|
|
@@ -58397,39 +59697,6 @@ const getAutoMergeProblemsRoute = HttpRouter.add("GET", "/api/flywheel/auto-merg
|
|
|
58397
59697
|
const getMergeBlockersRoute = HttpRouter.add("GET", "/api/flywheel/merge-blockers", httpHandler(Effect.gen(function* () {
|
|
58398
59698
|
return jsonResponse(getMergeBlockersPayload());
|
|
58399
59699
|
})));
|
|
58400
|
-
async function defaultGetOrderedIssueIds() {
|
|
58401
|
-
const status = await readCurrentFlywheelStatusForDashboard();
|
|
58402
|
-
if (!status) return [];
|
|
58403
|
-
const { computeMergeQueue } = await import("./flywheel-merge-order-UUcsCDb6.js");
|
|
58404
|
-
return (await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd()).pipe(Effect.provide(layer)))).map((i) => i.issueId);
|
|
58405
|
-
}
|
|
58406
|
-
async function defaultMergeOne(issueId) {
|
|
58407
|
-
const { triggerMerge } = await import("./merge-ops-CR44oU9-.js");
|
|
58408
|
-
const r = await triggerMerge(issueId);
|
|
58409
|
-
return r.success ? { ok: true } : {
|
|
58410
|
-
ok: false,
|
|
58411
|
-
reason: r.error ?? r.message ?? "merge failed"
|
|
58412
|
-
};
|
|
58413
|
-
}
|
|
58414
|
-
/**
|
|
58415
|
-
* PAN-1691 "merge next N" / "ship the UAT candidate": merge the first N issues
|
|
58416
|
-
* of the conflict-aware merge order, one at a time, stopping at the first
|
|
58417
|
-
* failure (the rest would need re-rebasing). Pure-ish + DI for testing.
|
|
58418
|
-
*/
|
|
58419
|
-
async function postFlywheelMergeNextPayload(payload, deps = {}) {
|
|
58420
|
-
const body = payload ?? {};
|
|
58421
|
-
const n = typeof body.n === "number" && Number.isFinite(body.n) ? Math.floor(body.n) : 0;
|
|
58422
|
-
if (n <= 0) return {
|
|
58423
|
-
status: 400,
|
|
58424
|
-
body: { error: "n must be a positive integer" }
|
|
58425
|
-
};
|
|
58426
|
-
const issueIds = (await (deps.getOrderedIssueIds ?? defaultGetOrderedIssueIds)()).slice(0, n);
|
|
58427
|
-
const { shipMergeBatch } = await import("./merge-batch-ClFn2T-y.js");
|
|
58428
|
-
return {
|
|
58429
|
-
status: 200,
|
|
58430
|
-
body: { outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne }) }
|
|
58431
|
-
};
|
|
58432
|
-
}
|
|
58433
59700
|
const postAutoMergeScheduleRoute = HttpRouter.add("POST", "/api/flywheel/auto-merge/schedule", httpHandler(Effect.gen(function* () {
|
|
58434
59701
|
const originError = requireTrustedOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
58435
59702
|
if (originError) return originError;
|
|
@@ -58438,14 +59705,6 @@ const postAutoMergeScheduleRoute = HttpRouter.add("POST", "/api/flywheel/auto-me
|
|
|
58438
59705
|
const result = yield* Effect.promise(() => postAutoMergeSchedulePayload(parsed.body));
|
|
58439
59706
|
return jsonResponse(result.body, { status: result.status });
|
|
58440
59707
|
})));
|
|
58441
|
-
const postFlywheelMergeNextRoute = HttpRouter.add("POST", "/api/flywheel/merge-next", httpHandler(Effect.gen(function* () {
|
|
58442
|
-
const originError = requireTrustedOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
58443
|
-
if (originError) return originError;
|
|
58444
|
-
const parsed = yield* readUnknownJsonBody;
|
|
58445
|
-
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 400 });
|
|
58446
|
-
const result = yield* Effect.promise(() => postFlywheelMergeNextPayload(parsed.body));
|
|
58447
|
-
return jsonResponse(result.body, { status: result.status });
|
|
58448
|
-
})));
|
|
58449
59708
|
const deleteAutoMergeRoute = HttpRouter.add("DELETE", "/api/flywheel/auto-merge/:id", httpHandler(Effect.gen(function* () {
|
|
58450
59709
|
const originError = requireTrustedOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
58451
59710
|
if (originError) return originError;
|
|
@@ -58577,68 +59836,14 @@ const postFlywheelBriefRoute = HttpRouter.add("POST", "/api/flywheel/brief", htt
|
|
|
58577
59836
|
});
|
|
58578
59837
|
});
|
|
58579
59838
|
})));
|
|
58580
|
-
const getFlywheelMergeQueueRoute = HttpRouter.add("GET", "/api/flywheel/merge-queue", httpHandler(Effect.gen(function* () {
|
|
58581
|
-
return yield* Effect.promise(async () => {
|
|
58582
|
-
const status = await readCurrentFlywheelStatusForDashboard();
|
|
58583
|
-
if (!status) return jsonResponse([]);
|
|
58584
|
-
const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-UUcsCDb6.js");
|
|
58585
|
-
return jsonResponse(await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd(), { getPrUrl: resolveMergeQueuePrUrl }).pipe(Effect.provide(layer))));
|
|
58586
|
-
});
|
|
58587
|
-
})));
|
|
58588
|
-
/**
|
|
58589
|
-
* PAN-1737 UAT batch trains. Generation names contain a slash
|
|
58590
|
-
* (`uat/pan-otter-0610`); URL params carry the name WITHOUT the `uat/`
|
|
58591
|
-
* prefix and handlers reconstitute it.
|
|
58592
|
-
*/
|
|
58593
|
-
function uatGenerationNameFromParam(param) {
|
|
58594
|
-
const decoded = decodeURIComponent(param);
|
|
58595
|
-
return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
|
|
58596
|
-
}
|
|
58597
|
-
const getUatGenerationsRoute = HttpRouter.add("GET", "/api/flywheel/uat-generations", httpHandler(Effect.gen(function* () {
|
|
58598
|
-
const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58599
|
-
return jsonResponse(yield* Effect.promise(() => getUatGenerationsPayload()));
|
|
58600
|
-
})));
|
|
58601
59839
|
const getUatCandidateRoute = HttpRouter.add("GET", "/api/flywheel/uat-candidate", httpHandler(Effect.gen(function* () {
|
|
58602
|
-
const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-
|
|
59840
|
+
const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-Dewoatps.js"));
|
|
58603
59841
|
return jsonResponse(yield* Effect.promise(() => getUatCandidatePayload()));
|
|
58604
59842
|
})));
|
|
58605
|
-
const postUatGenerationStackRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/stack", httpHandler(Effect.gen(function* () {
|
|
58606
|
-
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
58607
|
-
if (authError) return authError;
|
|
58608
|
-
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
58609
|
-
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58610
|
-
const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
|
|
58611
|
-
if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
|
|
58612
|
-
return jsonResponse({
|
|
58613
|
-
frontendUrl: result.frontendUrl,
|
|
58614
|
-
evicted: result.evicted
|
|
58615
|
-
});
|
|
58616
|
-
})));
|
|
58617
|
-
const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/promote", httpHandler(Effect.gen(function* () {
|
|
58618
|
-
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
58619
|
-
if (authError) return authError;
|
|
58620
|
-
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
58621
|
-
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58622
|
-
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-CShuVGWT.js"));
|
|
58623
|
-
const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
|
|
58624
|
-
if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
|
|
58625
|
-
return jsonResponse(result);
|
|
58626
|
-
})));
|
|
58627
|
-
/**
|
|
58628
|
-
* PAN-1737: repurposed from the PAN-1691 one-shot candidate assembly. Now a
|
|
58629
|
-
* FORCED reconcile — rebuild the current generation even when the chain
|
|
58630
|
-
* already answers the ready set (operator suspects staleness).
|
|
58631
|
-
*/
|
|
58632
|
-
const postFlywheelAssembleUatRoute = HttpRouter.add("POST", "/api/flywheel/assemble-uat", httpHandler(Effect.gen(function* () {
|
|
58633
|
-
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
58634
|
-
if (authError) return authError;
|
|
58635
|
-
const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58636
|
-
return jsonResponse(yield* Effect.promise(() => runUatTrainReconcile({ force: true })));
|
|
58637
|
-
})));
|
|
58638
59843
|
const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
|
|
58639
59844
|
return yield* Effect.promise(async () => jsonResponse(await readFlywheelState()));
|
|
58640
59845
|
})));
|
|
58641
|
-
const flywheelRouteLayer = Layer.mergeAll(getFlywheelRunsRoute, getFlywheelRunRoute, getFlywheelConversationRoute, getFlywheelCurrentRoute, getFlywheelStatsRoute, getSubstrateBugWeightsRoute, getFlywheelConfigRoute, postFlywheelConfigRoute, getPendingAutoMergeRoute, getAutoMergeProblemsRoute, getMergeBlockersRoute, getMergeBackendRoute, postAutoMergeScheduleRoute,
|
|
59846
|
+
const flywheelRouteLayer = Layer.mergeAll(getFlywheelRunsRoute, getFlywheelRunRoute, getFlywheelConversationRoute, getFlywheelCurrentRoute, getFlywheelStatsRoute, getSubstrateBugWeightsRoute, getFlywheelConfigRoute, postFlywheelConfigRoute, getPendingAutoMergeRoute, getAutoMergeProblemsRoute, getMergeBlockersRoute, getMergeBackendRoute, postAutoMergeScheduleRoute, deleteAutoMergeRoute, getUatCandidateRoute, getFlywheelStateRoute, postFlywheelStatusRoute, postFlywheelStartRoute, postFlywheelPauseRoute, postFlywheelResumeRoute, postFlywheelAbortRoute, postFlywheelReportRoute, postFlywheelReportOpenRoute, getFlywheelBriefRoute, postFlywheelBriefRoute);
|
|
58642
59847
|
//#endregion
|
|
58643
59848
|
//#region routes/orders.ts
|
|
58644
59849
|
init_projects();
|
|
@@ -58827,7 +60032,7 @@ function previewBrief(book) {
|
|
|
58827
60032
|
return `${lines.join("\n")}\n`;
|
|
58828
60033
|
}
|
|
58829
60034
|
async function defaultStartOrderBook(book) {
|
|
58830
|
-
const { startFlywheelRun } = await import("./flywheel-
|
|
60035
|
+
const { startFlywheelRun } = await import("./flywheel-f662Q-y2.js");
|
|
58831
60036
|
return startFlywheelRun({
|
|
58832
60037
|
cwd: process.cwd(),
|
|
58833
60038
|
orders: book.id
|
|
@@ -59505,6 +60710,7 @@ function agentStateToDbAgent(state) {
|
|
|
59505
60710
|
lastFailureReason: state.lastFailureReason ?? null,
|
|
59506
60711
|
lastFailureNextRetryAt: state.lastFailureNextRetryAt ?? null,
|
|
59507
60712
|
flywheelRunId: state.flywheelRunId ?? null,
|
|
60713
|
+
startedBy: state.startedBy ?? null,
|
|
59508
60714
|
roleRunHead: state.roleRunHead ?? null,
|
|
59509
60715
|
reviewSubRole: state.reviewSubRole ?? null,
|
|
59510
60716
|
reviewRunId: state.reviewRunId ?? null,
|
|
@@ -59581,6 +60787,7 @@ const COLUMN_MAP = {
|
|
|
59581
60787
|
lastFailureReason: "last_failure_reason",
|
|
59582
60788
|
lastFailureNextRetryAt: "last_failure_next_retry_at",
|
|
59583
60789
|
flywheelRunId: "flywheel_run_id",
|
|
60790
|
+
startedBy: "started_by",
|
|
59584
60791
|
roleRunHead: "role_run_head",
|
|
59585
60792
|
reviewSubRole: "review_sub_role",
|
|
59586
60793
|
reviewRunId: "review_run_id",
|
|
@@ -59653,7 +60860,7 @@ function backfillAgentsFromStateJsonSync(db, options) {
|
|
|
59653
60860
|
const readHarnessModel = options?.readHarnessModel ?? readAgentHarnessModelRecordSync;
|
|
59654
60861
|
let processed = 0;
|
|
59655
60862
|
let skipped = 0;
|
|
59656
|
-
|
|
60863
|
+
const markedStoppedIds = [];
|
|
59657
60864
|
let entries = [];
|
|
59658
60865
|
try {
|
|
59659
60866
|
entries = readdirSync$1(agentsDir);
|
|
@@ -59661,7 +60868,8 @@ function backfillAgentsFromStateJsonSync(db, options) {
|
|
|
59661
60868
|
return {
|
|
59662
60869
|
processed,
|
|
59663
60870
|
skipped,
|
|
59664
|
-
markedStopped
|
|
60871
|
+
markedStopped: 0,
|
|
60872
|
+
markedStoppedIds
|
|
59665
60873
|
};
|
|
59666
60874
|
}
|
|
59667
60875
|
const columns = Object.values(COLUMN_MAP);
|
|
@@ -59690,7 +60898,10 @@ function backfillAgentsFromStateJsonSync(db, options) {
|
|
|
59690
60898
|
continue;
|
|
59691
60899
|
}
|
|
59692
60900
|
const reconciled = reconcileAgentStatus(state, liveSessions);
|
|
59693
|
-
|
|
60901
|
+
const reconciledStop = reconciled.status === "stopped" && state.status !== "stopped" ? {
|
|
60902
|
+
id: state.id,
|
|
60903
|
+
previousStatus: state.status
|
|
60904
|
+
} : void 0;
|
|
59694
60905
|
let effective = reconciled;
|
|
59695
60906
|
if (reconciled.issueId) {
|
|
59696
60907
|
const rec = readHarnessModel(reconciled.issueId);
|
|
@@ -59702,14 +60913,17 @@ function backfillAgentsFromStateJsonSync(db, options) {
|
|
|
59702
60913
|
}
|
|
59703
60914
|
const row = agentStateToDbAgent(effective);
|
|
59704
60915
|
upsert.run(buildNamedParams(row));
|
|
60916
|
+
if (reconciledStop) markedStoppedIds.push(reconciledStop);
|
|
59705
60917
|
processed++;
|
|
59706
60918
|
if (options?.verbose) console.log(`[backfill] ${row.id} -> ${row.status}`);
|
|
59707
60919
|
}
|
|
59708
60920
|
})();
|
|
60921
|
+
for (const { id, previousStatus } of markedStoppedIds) logAgentLifecycleSync(id, `status changed: ${previousStatus} → stopped (boot backfill reconcile: no live tmux session)`);
|
|
59709
60922
|
return {
|
|
59710
60923
|
processed,
|
|
59711
60924
|
skipped,
|
|
59712
|
-
markedStopped
|
|
60925
|
+
markedStopped: markedStoppedIds.length,
|
|
60926
|
+
markedStoppedIds
|
|
59713
60927
|
};
|
|
59714
60928
|
}
|
|
59715
60929
|
function reconcileAgentStatus(state, liveSessions) {
|
|
@@ -59949,6 +61163,8 @@ function initSchema(db) {
|
|
|
59949
61163
|
review_spawned_at TEXT,
|
|
59950
61164
|
-- PAN-1765: timestamp when conflict resolution was dispatched
|
|
59951
61165
|
conflict_resolution_dispatched_at TEXT,
|
|
61166
|
+
-- PAN-3154: main-head SHA/paths that first made this branch conflict (JSON)
|
|
61167
|
+
conflicts_since TEXT,
|
|
59952
61168
|
-- PAN-699: number of test-agent dispatch retries (circuit breaker)
|
|
59953
61169
|
test_retry_count INTEGER DEFAULT 0,
|
|
59954
61170
|
-- PAN-794: parallel-review re-dispatch retry counter (scoped to current recovery cycle)
|
|
@@ -59966,7 +61182,9 @@ function initSchema(db) {
|
|
|
59966
61182
|
-- PAN-938: current merge pipeline step
|
|
59967
61183
|
merge_step TEXT,
|
|
59968
61184
|
-- PAN-1691: per-issue merge-train routing key (NULL=project default, 1=auto-merge, 0=hold-for-UAT)
|
|
59969
|
-
auto_merge INTEGER
|
|
61185
|
+
auto_merge INTEGER,
|
|
61186
|
+
-- PAN-3151: JSON array of review cycle history entries for convergence detection
|
|
61187
|
+
review_cycle_history TEXT
|
|
59970
61188
|
);
|
|
59971
61189
|
|
|
59972
61190
|
CREATE INDEX IF NOT EXISTS idx_review_status_updated
|
|
@@ -60152,7 +61370,7 @@ function initSchema(db) {
|
|
|
60152
61370
|
last_failure_at TEXT,
|
|
60153
61371
|
last_failure_reason TEXT,
|
|
60154
61372
|
last_failure_next_retry_at TEXT,
|
|
60155
|
-
flywheel_run_id TEXT,
|
|
61373
|
+
flywheel_run_id TEXT, started_by TEXT,
|
|
60156
61374
|
role_run_head TEXT,
|
|
60157
61375
|
review_sub_role TEXT,
|
|
60158
61376
|
review_run_id TEXT,
|
|
@@ -60471,7 +61689,7 @@ function initSchema(db) {
|
|
|
60471
61689
|
CREATE INDEX IF NOT EXISTS idx_backlog_sequence_project_rank
|
|
60472
61690
|
ON backlog_sequence(project_key, rank);
|
|
60473
61691
|
`);
|
|
60474
|
-
db.pragma(`user_version =
|
|
61692
|
+
db.pragma(`user_version = 63`);
|
|
60475
61693
|
}
|
|
60476
61694
|
/**
|
|
60477
61695
|
* Run schema migrations if the database version is older than SCHEMA_VERSION.
|
|
@@ -60479,12 +61697,18 @@ function initSchema(db) {
|
|
|
60479
61697
|
*/
|
|
60480
61698
|
function runMigrations(db, dbPath) {
|
|
60481
61699
|
const currentVersion = db.pragma("user_version", { simple: true });
|
|
60482
|
-
if (currentVersion === 61) tryIdempotentDdl(db, 61, "ALTER TABLE flywheel_substrate_bugs ADD COLUMN affected_criteria TEXT");
|
|
60483
|
-
if (currentVersion >= 61) return;
|
|
60484
61700
|
if (currentVersion === 0) {
|
|
60485
61701
|
initSchema(db);
|
|
60486
61702
|
return;
|
|
60487
61703
|
}
|
|
61704
|
+
if (currentVersion === 63) {
|
|
61705
|
+
tryIdempotentDdl(db, 61, "ALTER TABLE flywheel_substrate_bugs ADD COLUMN affected_criteria TEXT");
|
|
61706
|
+
tryIdempotentDdl(db, 61, "ALTER TABLE agents ADD COLUMN started_by TEXT");
|
|
61707
|
+
tryIdempotentDdl(db, 62, "ALTER TABLE review_status ADD COLUMN review_cycle_history TEXT");
|
|
61708
|
+
tryIdempotentDdl(db, 62, "ALTER TABLE review_status ADD COLUMN conflicts_since TEXT");
|
|
61709
|
+
return;
|
|
61710
|
+
}
|
|
61711
|
+
if (currentVersion > 63) return;
|
|
60488
61712
|
if (currentVersion < 2) db.exec(`
|
|
60489
61713
|
DELETE FROM status_history
|
|
60490
61714
|
WHERE id NOT IN (
|
|
@@ -61138,8 +62362,17 @@ function runMigrations(db, dbPath) {
|
|
|
61138
62362
|
tryIdempotentDdl(db, 60, `ALTER TABLE review_status ADD COLUMN release_status TEXT`);
|
|
61139
62363
|
tryIdempotentDdl(db, 60, `ALTER TABLE review_status ADD COLUMN release_notes TEXT`);
|
|
61140
62364
|
}
|
|
61141
|
-
|
|
61142
|
-
db
|
|
62365
|
+
tryIdempotentDdl(db, 61, "ALTER TABLE flywheel_substrate_bugs ADD COLUMN affected_criteria TEXT");
|
|
62366
|
+
tryIdempotentDdl(db, 61, "ALTER TABLE agents ADD COLUMN started_by TEXT");
|
|
62367
|
+
if (currentVersion < 62) {
|
|
62368
|
+
tryIdempotentDdl(db, 62, "ALTER TABLE review_status ADD COLUMN review_cycle_history TEXT");
|
|
62369
|
+
tryIdempotentDdl(db, 62, "ALTER TABLE review_status ADD COLUMN conflicts_since TEXT");
|
|
62370
|
+
}
|
|
62371
|
+
if (currentVersion < 63) {
|
|
62372
|
+
tryIdempotentDdl(db, 63, "ALTER TABLE review_status ADD COLUMN review_cycle_history TEXT");
|
|
62373
|
+
tryIdempotentDdl(db, 63, "ALTER TABLE review_status ADD COLUMN conflicts_since TEXT");
|
|
62374
|
+
}
|
|
62375
|
+
db.pragma(`user_version = 63`);
|
|
61143
62376
|
}
|
|
61144
62377
|
//#endregion
|
|
61145
62378
|
//#region ../../lib/database/index.ts
|
|
@@ -61985,7 +63218,8 @@ const staticRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* () {
|
|
|
61985
63218
|
const projectRoot = selfPath.includes("/dist/") ? pathService.resolve(selfPath, "..", "..") : pathService.resolve(selfPath, "..", "..", "..");
|
|
61986
63219
|
const staticDir = process.env["OVERDECK_FRONTEND_DIR"] ?? pathService.resolve(projectRoot, "dist", "dashboard", "public");
|
|
61987
63220
|
const staticRoot = pathService.resolve(staticDir);
|
|
61988
|
-
const
|
|
63221
|
+
const urlPath = url.value.pathname === "/" ? "/index.html" : url.value.pathname;
|
|
63222
|
+
const rawRelative = urlPath.replace(/^[/\\]+/, "");
|
|
61989
63223
|
const normalized = pathService.normalize(rawRelative).replace(/^[/\\]+/, "");
|
|
61990
63224
|
if (normalized.length === 0 || normalized.startsWith("..") || normalized.includes("\0")) return HttpServerResponse.text("Invalid path", { status: 400 });
|
|
61991
63225
|
const sep = pathService.sep;
|
|
@@ -61998,6 +63232,7 @@ const staticRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* () {
|
|
|
61998
63232
|
}
|
|
61999
63233
|
const fileInfo = yield* fileSystem.stat(filePath).pipe(Effect.catch(() => Effect.succeed(null)));
|
|
62000
63234
|
if (!fileInfo || fileInfo.type !== "File") {
|
|
63235
|
+
if (pathService.extname(urlPath)) return HttpServerResponse.text("Not Found", { status: 404 });
|
|
62001
63236
|
const indexPath = pathService.resolve(staticRoot, "index.html");
|
|
62002
63237
|
const indexInfo = yield* fileSystem.stat(indexPath).pipe(Effect.catch(() => Effect.succeed(null)));
|
|
62003
63238
|
if (!indexInfo || indexInfo.type !== "File") return HttpServerResponse.text("Not Found", { status: 404 });
|
|
@@ -62007,7 +63242,7 @@ const staticRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* () {
|
|
|
62007
63242
|
if (filePath.endsWith("index.html")) return HttpServerResponse.setHeader(res, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
62008
63243
|
return res;
|
|
62009
63244
|
}));
|
|
62010
|
-
const makeRoutesLayer = Layer.mergeAll(healthRouteLayer, dashboardSessionPreflightRouteLayer, dashboardSessionRouteLayer, websocketRpcRouteLayer, issuesRouteLayer, pipelineMembershipRouteLayer, agentsRouteLayer, workspacesRouteLayer, specialistsRouteLayer, costsRouteLayer, cloisterRouteLayer, resourcesRouteLayer, commandDeckRouteLayer, remoteRouteLayer, settingsRouteLayer, voiceRouteLayer, autopresoRouteLayer, metricsRouteLayer, miscRouteLayer, paletteRouteLayer, conversationsRouteLayer, eventsRouteLayer, showRouteLayer, projectsRouteLayer, contextRouteLayer, adminRouteLayer, prereqsRouteLayer, cliproxyRouteLayer, ttsRouteLayer, webhooksRouteLayer, hooksRouteLayer, diffsRouteLayer, codexAuthRouteLayer, terminalsRouteLayer, discoveredSessionsRouteLayer, flywheelRouteLayer, ordersRouteLayer, artifactsRouteLayer, featureRegistryRouteLayer, fsRouteLayer, tieredCalloutsRouteLayer, backlogRouteLayer, internalEventsRouteLayer, knowledgeViewerRouteLayer, staticRouteLayer);
|
|
63245
|
+
const makeRoutesLayer = Layer.mergeAll(healthRouteLayer, dashboardSessionPreflightRouteLayer, dashboardSessionRouteLayer, websocketRpcRouteLayer, issuesRouteLayer, pipelineMembershipRouteLayer, agentsRouteLayer, workspacesRouteLayer, specialistsRouteLayer, costsRouteLayer, cloisterRouteLayer, resourcesRouteLayer, commandDeckRouteLayer, remoteRouteLayer, settingsRouteLayer, voiceRouteLayer, autopresoRouteLayer, metricsRouteLayer, miscRouteLayer, paletteRouteLayer, conversationsRouteLayer, eventsRouteLayer, showRouteLayer, projectsRouteLayer, projectsMergeTrainRouteLayer, mergeTrainRouteLayer, contextRouteLayer, commandsRouteLayer, adminRouteLayer, prereqsRouteLayer, cliproxyRouteLayer, ttsRouteLayer, webhooksRouteLayer, hooksRouteLayer, diffsRouteLayer, codexAuthRouteLayer, linearMcpAuthRouteLayer, terminalsRouteLayer, discoveredSessionsRouteLayer, flywheelRouteLayer, ordersRouteLayer, artifactsRouteLayer, featureRegistryRouteLayer, fsRouteLayer, tieredCalloutsRouteLayer, backlogRouteLayer, internalEventsRouteLayer, knowledgeViewerRouteLayer, staticRouteLayer);
|
|
62011
63246
|
const OverdeckAgentsResolverLive = AgentsResolverLive.pipe(Layer.provide(Layer.mergeAll(DbLive, TmuxLive)));
|
|
62012
63247
|
const OverdeckCostResolverLive = CostResolverLive.pipe(Layer.provide(DbLive));
|
|
62013
63248
|
const ReadModelWithOverdeckLive = ReadModelServiceLive.pipe(Layer.provide(OverdeckAgentsResolverLive));
|
|
@@ -62060,6 +63295,7 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
62060
63295
|
init_agents$1();
|
|
62061
63296
|
init_review_status();
|
|
62062
63297
|
init_concurrency$1();
|
|
63298
|
+
init_runtime_census();
|
|
62063
63299
|
init_event_store();
|
|
62064
63300
|
init_activity_logger();
|
|
62065
63301
|
init_read_model();
|
|
@@ -62078,7 +63314,43 @@ function buildAwaitingInputActivityMessage(agentId, issueId, kinds) {
|
|
|
62078
63314
|
const kindList = kinds.length > 0 ? kinds.join(", ") : "input";
|
|
62079
63315
|
return issueId ? `${agentId} on ${issueId} is waiting for ${kindList}` : `${agentId} is waiting for ${kindList}`;
|
|
62080
63316
|
}
|
|
63317
|
+
function shouldSkipEnrichmentCycle(census) {
|
|
63318
|
+
return !census.tmuxAvailable;
|
|
63319
|
+
}
|
|
63320
|
+
function hasReapablePendingInput(enrichment) {
|
|
63321
|
+
return enrichment.pendingInputCount > 0 || enrichment.pendingAskUserQuestion != null || enrichment.pendingProposedPlan != null;
|
|
63322
|
+
}
|
|
63323
|
+
function buildPendingReapEvent(agentId, previous) {
|
|
63324
|
+
return {
|
|
63325
|
+
type: "agent.enrichment_changed",
|
|
63326
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
63327
|
+
payload: {
|
|
63328
|
+
agentId,
|
|
63329
|
+
role: previous.role,
|
|
63330
|
+
hasPendingQuestion: false,
|
|
63331
|
+
pendingQuestionCount: 0,
|
|
63332
|
+
pendingQuestionPrompt: void 0,
|
|
63333
|
+
pendingQuestionReason: void 0,
|
|
63334
|
+
pendingInputCount: 0,
|
|
63335
|
+
pendingInputKinds: [],
|
|
63336
|
+
pendingAskUserQuestion: void 0,
|
|
63337
|
+
pendingProposedPlan: void 0,
|
|
63338
|
+
resolution: previous.resolution,
|
|
63339
|
+
resolutionCount: previous.resolutionCount
|
|
63340
|
+
}
|
|
63341
|
+
};
|
|
63342
|
+
}
|
|
63343
|
+
function buildExpiredQuestionActivityMessage(agentId, issueId) {
|
|
63344
|
+
return `${issueId ? `${agentId} on ${issueId}` : agentId} stopped with its question unanswered — the question has expired and is no longer actionable`;
|
|
63345
|
+
}
|
|
62081
63346
|
async function pollOnce(state) {
|
|
63347
|
+
let census;
|
|
63348
|
+
try {
|
|
63349
|
+
census = await getRuntimeCensus();
|
|
63350
|
+
} catch {
|
|
63351
|
+
return;
|
|
63352
|
+
}
|
|
63353
|
+
if (shouldSkipEnrichmentCycle(census)) return;
|
|
62082
63354
|
let runningAgents;
|
|
62083
63355
|
try {
|
|
62084
63356
|
runningAgents = await Effect.runPromise(listRunningAgents());
|
|
@@ -62200,7 +63472,20 @@ async function pollOnce(state) {
|
|
|
62200
63472
|
} catch {}
|
|
62201
63473
|
})), 4));
|
|
62202
63474
|
const activeIds = new Set(activeAgents.map((a) => a.id));
|
|
62203
|
-
for (const id of state.lastEnrichment
|
|
63475
|
+
for (const [id, previousEnrichment] of state.lastEnrichment) if (!activeIds.has(id)) {
|
|
63476
|
+
if (hasReapablePendingInput(previousEnrichment)) {
|
|
63477
|
+
try {
|
|
63478
|
+
await eventStore.appendAsync(buildPendingReapEvent(id, previousEnrichment));
|
|
63479
|
+
} catch {}
|
|
63480
|
+
const agentRecord = runningAgents.find((agent) => agent.id === id);
|
|
63481
|
+
const issueId = agentRecord?.issueId;
|
|
63482
|
+
emitActivityEntrySync({
|
|
63483
|
+
source: toRole(agentRecord?.role) ?? "work",
|
|
63484
|
+
level: "info",
|
|
63485
|
+
message: buildExpiredQuestionActivityMessage(id, issueId),
|
|
63486
|
+
issueId
|
|
63487
|
+
});
|
|
63488
|
+
}
|
|
62204
63489
|
state.lastEnrichment.delete(id);
|
|
62205
63490
|
state.lastScan.delete(id);
|
|
62206
63491
|
}
|
|
@@ -62208,7 +63493,7 @@ async function pollOnce(state) {
|
|
|
62208
63493
|
/** Poll interval: 10 seconds (was 3s). The enrichment data changes slowly —
|
|
62209
63494
|
* pending questions, resolution state, phase — none of these need sub-second
|
|
62210
63495
|
* latency. 10s eliminates ~70% of poller I/O without any user-visible lag. */
|
|
62211
|
-
const POLL_INTERVAL_MS$
|
|
63496
|
+
const POLL_INTERVAL_MS$4 = 1e4;
|
|
62212
63497
|
const serviceState$2 = {
|
|
62213
63498
|
timer: null,
|
|
62214
63499
|
lastEnrichment: /* @__PURE__ */ new Map(),
|
|
@@ -62220,7 +63505,7 @@ function startAgentEnrichmentService() {
|
|
|
62220
63505
|
if (serviceState$2.timer !== null) return;
|
|
62221
63506
|
serviceState$2.timer = setInterval(() => {
|
|
62222
63507
|
pollOnce(serviceState$2).catch(() => {});
|
|
62223
|
-
}, POLL_INTERVAL_MS$
|
|
63508
|
+
}, POLL_INTERVAL_MS$4);
|
|
62224
63509
|
}
|
|
62225
63510
|
function stopAgentEnrichmentService() {
|
|
62226
63511
|
if (serviceState$2.timer !== null) {
|
|
@@ -62248,7 +63533,7 @@ function stopAgentEnrichmentService() {
|
|
|
62248
63533
|
* Bounded + cheap: each issue has a throttle. Ready/no-blocker rows use the PAN-1620
|
|
62249
63534
|
* 3-minute cadence; already-blocked mergeability rows use a 10-minute cadence.
|
|
62250
63535
|
*/
|
|
62251
|
-
const POLL_INTERVAL_MS$
|
|
63536
|
+
const POLL_INTERVAL_MS$3 = 6e4;
|
|
62252
63537
|
/** Re-check each ready-to-merge PR at most this often, to bound `gh` calls. */
|
|
62253
63538
|
const RECHECK_INTERVAL_MS = 18e4;
|
|
62254
63539
|
/** Re-check already-flagged mergeability blockers less often; they are not mergeable yet. */
|
|
@@ -62280,7 +63565,7 @@ function parsePrUrl$1(url) {
|
|
|
62280
63565
|
function hasMergeabilityBlocker(blockers) {
|
|
62281
63566
|
return blockers?.some((blocker) => MERGEABILITY_BLOCKERS.has(blocker.type)) ?? false;
|
|
62282
63567
|
}
|
|
62283
|
-
async function reconcileOnce(state) {
|
|
63568
|
+
async function reconcileOnce$1(state) {
|
|
62284
63569
|
const candidates = await Effect.runPromise(getMergeBlockerReconcileCandidates());
|
|
62285
63570
|
const now = Date.now();
|
|
62286
63571
|
for (const candidate of candidates) {
|
|
@@ -62316,8 +63601,8 @@ async function reconcileOnce(state) {
|
|
|
62316
63601
|
function startMergeBlockerReconcileService() {
|
|
62317
63602
|
if (serviceState$1.timer !== null) return;
|
|
62318
63603
|
serviceState$1.timer = setInterval(() => {
|
|
62319
|
-
reconcileOnce(serviceState$1).catch(() => {});
|
|
62320
|
-
}, POLL_INTERVAL_MS$
|
|
63604
|
+
reconcileOnce$1(serviceState$1).catch(() => {});
|
|
63605
|
+
}, POLL_INTERVAL_MS$3);
|
|
62321
63606
|
serviceState$1.timer.unref?.();
|
|
62322
63607
|
}
|
|
62323
63608
|
function enqueueRefresh(state, task) {
|
|
@@ -62341,6 +63626,51 @@ function drainRefreshQueue(state) {
|
|
|
62341
63626
|
}
|
|
62342
63627
|
}
|
|
62343
63628
|
//#endregion
|
|
63629
|
+
//#region services/review-status-reconcile-service.ts
|
|
63630
|
+
init_review_status();
|
|
63631
|
+
init_event_store();
|
|
63632
|
+
const POLL_INTERVAL_MS$2 = 6e4;
|
|
63633
|
+
let reconcileTimer = null;
|
|
63634
|
+
function reviewStatusPayload(event) {
|
|
63635
|
+
if (!event.payload || typeof event.payload !== "object") return null;
|
|
63636
|
+
const payload = event.payload;
|
|
63637
|
+
if (typeof payload.issueId !== "string" || !payload.status || typeof payload.status !== "object") return null;
|
|
63638
|
+
return payload;
|
|
63639
|
+
}
|
|
63640
|
+
async function reconcileOnce() {
|
|
63641
|
+
const cached = loadReviewStatuses();
|
|
63642
|
+
const canonicalByIssue = /* @__PURE__ */ new Map();
|
|
63643
|
+
for (const issueId of Object.keys(cached)) {
|
|
63644
|
+
const canonical = getReviewStatusSync(issueId);
|
|
63645
|
+
if (!canonical) continue;
|
|
63646
|
+
canonicalByIssue.set(issueId.toUpperCase(), canonical);
|
|
63647
|
+
}
|
|
63648
|
+
const store = getEventStore();
|
|
63649
|
+
const latestByIssue = /* @__PURE__ */ new Map();
|
|
63650
|
+
for (const event of store.queryLatestPerIssue("review.status_changed")) {
|
|
63651
|
+
const payload = reviewStatusPayload(event);
|
|
63652
|
+
if (payload) latestByIssue.set(payload.issueId.toUpperCase(), event);
|
|
63653
|
+
}
|
|
63654
|
+
for (const [issueId, canonical] of canonicalByIssue) {
|
|
63655
|
+
const latest = latestByIssue.get(issueId);
|
|
63656
|
+
const latestPayload = latest ? reviewStatusPayload(latest) : null;
|
|
63657
|
+
const lastUpdatedAt = latestPayload?.status.updatedAt ?? "";
|
|
63658
|
+
if (lastUpdatedAt > canonical.updatedAt) continue;
|
|
63659
|
+
if (lastUpdatedAt === canonical.updatedAt && latestPayload && sameCanonicalReviewStatus(latestPayload.status, canonical)) continue;
|
|
63660
|
+
console.log(`[review-status-reconcile] re-emitting status for ${issueId} (canonical differs from last event — healing lost status_changed)`);
|
|
63661
|
+
emitReviewStatusChanged((event) => store.append(event), issueId, canonical);
|
|
63662
|
+
}
|
|
63663
|
+
}
|
|
63664
|
+
function startReviewStatusReconcileService() {
|
|
63665
|
+
if (getDashboardIdentity().mode !== "primary") return false;
|
|
63666
|
+
if (reconcileTimer !== null) return true;
|
|
63667
|
+
reconcileTimer = setInterval(() => {
|
|
63668
|
+
reconcileOnce().catch(() => {});
|
|
63669
|
+
}, POLL_INTERVAL_MS$2);
|
|
63670
|
+
reconcileTimer.unref?.();
|
|
63671
|
+
return true;
|
|
63672
|
+
}
|
|
63673
|
+
//#endregion
|
|
62344
63674
|
//#region services/project-resource-refresh-queue.ts
|
|
62345
63675
|
init_projects();
|
|
62346
63676
|
const PROJECT_RESOURCE_CONVERGENCE_INTERVAL_MS = 5 * 6e4;
|
|
@@ -64028,14 +65358,42 @@ const RESTART_MARKER = join$1(homedir(), ".overdeck", "dashboard-restarting.json
|
|
|
64028
65358
|
* loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
|
|
64029
65359
|
*/
|
|
64030
65360
|
async function defaultLifecycleRunner(pending) {
|
|
64031
|
-
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-
|
|
65361
|
+
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-DQTXZk8z.js");
|
|
64032
65362
|
await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
|
|
64033
65363
|
if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
|
|
64034
65364
|
}
|
|
65365
|
+
async function runClaimedPendingLifecycle(claim, pending, runner, lifecycleDelayMs, startTime) {
|
|
65366
|
+
let succeeded = false;
|
|
65367
|
+
try {
|
|
65368
|
+
if (lifecycleDelayMs > 0) await new Promise((resolve) => setTimeout(resolve, lifecycleDelayMs));
|
|
65369
|
+
await runner(pending);
|
|
65370
|
+
succeeded = true;
|
|
65371
|
+
emitDashboardLifecycleSync("completed", {
|
|
65372
|
+
reason: pending.reason ?? "post-merge",
|
|
65373
|
+
issueId: pending.issueId,
|
|
65374
|
+
durationMs: Date.now() - startTime
|
|
65375
|
+
});
|
|
65376
|
+
} catch (error) {
|
|
65377
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65378
|
+
console.error(`[overdeck] Post-merge lifecycle failed for ${pending.issueId}: ${message}`);
|
|
65379
|
+
emitDashboardLifecycleSync("failed", {
|
|
65380
|
+
reason: pending.reason ?? "post-merge",
|
|
65381
|
+
issueId: pending.issueId,
|
|
65382
|
+
error: message
|
|
65383
|
+
});
|
|
65384
|
+
} finally {
|
|
65385
|
+
try {
|
|
65386
|
+
await settlePendingLifecycleClaim(claim, pending.issueId, succeeded);
|
|
65387
|
+
} catch (error) {
|
|
65388
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65389
|
+
console.warn(`[overdeck] Failed to settle pending lifecycle claim for ${pending.issueId}: ${message}`);
|
|
65390
|
+
}
|
|
65391
|
+
}
|
|
65392
|
+
}
|
|
64035
65393
|
/**
|
|
64036
65394
|
* Check for and process a pending post-merge lifecycle file.
|
|
64037
|
-
*
|
|
64038
|
-
*
|
|
65395
|
+
* Atomically claims the file before execution so dashboard and Deacon cannot
|
|
65396
|
+
* run the same handoff. The durable mergeStep marker owns retries after failure.
|
|
64039
65397
|
*
|
|
64040
65398
|
* Also checks for a RESTART_MARKER file (written by deploy script before killing
|
|
64041
65399
|
* the old server) and emits dashboard.lifecycle_started if found.
|
|
@@ -64061,35 +65419,25 @@ async function processPendingLifecycle(options) {
|
|
|
64061
65419
|
} catch (err) {
|
|
64062
65420
|
console.warn(`[overdeck] Failed to process restart marker: ${err.message}`);
|
|
64063
65421
|
}
|
|
64064
|
-
if (!existsSync(pendingFile)) return;
|
|
64065
65422
|
const startTime = Date.now();
|
|
64066
65423
|
try {
|
|
64067
|
-
const
|
|
64068
|
-
|
|
64069
|
-
|
|
65424
|
+
const claim = await claimPendingLifecycleFile(pendingFile);
|
|
65425
|
+
if (!claim) return;
|
|
65426
|
+
let pending;
|
|
65427
|
+
try {
|
|
65428
|
+
pending = JSON.parse(claim.raw);
|
|
65429
|
+
} catch (error) {
|
|
65430
|
+
await claim.discard();
|
|
65431
|
+
throw error;
|
|
65432
|
+
}
|
|
64070
65433
|
const age = (options?.now ?? Date.now()) - (pending.timestamp ?? 0);
|
|
64071
65434
|
if (age > staleThresholdMs) {
|
|
65435
|
+
await claim.discard();
|
|
64072
65436
|
console.warn(`[overdeck] Ignoring stale pending-post-merge.json (age: ${Math.round(age / 6e4)}min) for ${pending.issueId}`);
|
|
64073
65437
|
return;
|
|
64074
65438
|
}
|
|
64075
|
-
console.log(`[overdeck] Found pending post-merge lifecycle for ${pending.issueId} —
|
|
64076
|
-
|
|
64077
|
-
try {
|
|
64078
|
-
await runner(pending);
|
|
64079
|
-
emitDashboardLifecycleSync("completed", {
|
|
64080
|
-
reason: pending.reason ?? "post-merge",
|
|
64081
|
-
issueId: pending.issueId,
|
|
64082
|
-
durationMs: Date.now() - startTime
|
|
64083
|
-
});
|
|
64084
|
-
} catch (err) {
|
|
64085
|
-
console.error(`[overdeck] Post-merge lifecycle failed for ${pending.issueId}: ${err.message}`);
|
|
64086
|
-
emitDashboardLifecycleSync("failed", {
|
|
64087
|
-
reason: pending.reason ?? "post-merge",
|
|
64088
|
-
issueId: pending.issueId,
|
|
64089
|
-
error: err.message
|
|
64090
|
-
});
|
|
64091
|
-
}
|
|
64092
|
-
}, lifecycleDelayMs);
|
|
65439
|
+
console.log(`[overdeck] Found pending post-merge lifecycle for ${pending.issueId} — running in ${lifecycleDelayMs}ms`);
|
|
65440
|
+
runClaimedPendingLifecycle(claim, pending, runner, lifecycleDelayMs, startTime);
|
|
64093
65441
|
} catch (err) {
|
|
64094
65442
|
console.warn(`[overdeck] Failed to process pending-post-merge.json: ${err.message}`);
|
|
64095
65443
|
}
|
|
@@ -64337,6 +65685,8 @@ const cleanupClosedIssueAgentDirectories = (options) => Effect.tryPromise({
|
|
|
64337
65685
|
//#region services/auto-merge-executor.ts
|
|
64338
65686
|
init_activity_logger();
|
|
64339
65687
|
init_merge_sync();
|
|
65688
|
+
init_deploy_queue();
|
|
65689
|
+
init_review_status();
|
|
64340
65690
|
const AUTO_MERGE_EXECUTOR_INTERVAL_MS = 3e4;
|
|
64341
65691
|
const REQUEUE_BACKOFF_MS = 6e4;
|
|
64342
65692
|
let timer$1 = null;
|
|
@@ -64349,7 +65699,7 @@ function failureReason(result) {
|
|
|
64349
65699
|
return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
|
|
64350
65700
|
}
|
|
64351
65701
|
async function defaultMergeIssue(issueId) {
|
|
64352
|
-
const { triggerMerge } = await import("./merge-ops-
|
|
65702
|
+
const { triggerMerge } = await import("./merge-ops-1abz6O_P.js");
|
|
64353
65703
|
return triggerMerge(issueId);
|
|
64354
65704
|
}
|
|
64355
65705
|
function defaultAnnounceFailure(issueId, reason) {
|
|
@@ -64371,6 +65721,10 @@ async function tickAutoMergeExecutor(deps = {}) {
|
|
|
64371
65721
|
log("[auto-merge] flywheel paused, skipping tick");
|
|
64372
65722
|
return;
|
|
64373
65723
|
}
|
|
65724
|
+
if (await (deps.hasPendingDeploy ?? (async () => await readPendingDeploy() !== null))()) {
|
|
65725
|
+
log(`[auto-merge] dashboard deploy queued, deferring ${entries.length} merge(s) before preparation`);
|
|
65726
|
+
return;
|
|
65727
|
+
}
|
|
64374
65728
|
for (const entry of entries) {
|
|
64375
65729
|
if (isPaused()) {
|
|
64376
65730
|
log("[auto-merge] flywheel paused, skipping tick");
|
|
@@ -64397,6 +65751,25 @@ async function tickAutoMergeExecutor(deps = {}) {
|
|
|
64397
65751
|
continue;
|
|
64398
65752
|
}
|
|
64399
65753
|
const reason = failureReason(result);
|
|
65754
|
+
if (result.deferred) {
|
|
65755
|
+
const retryAt = new Date(nowDate.getTime() + REQUEUE_BACKOFF_MS).toISOString();
|
|
65756
|
+
log((deps.requeueToPending ?? requeueToPending)(entry.id, retryAt) ? `[auto-merge] merge deferred for ${entry.issueId}; requeued without consuming retry budget for ${retryAt}` : `[auto-merge] failed to requeue deferred merge for ${entry.issueId} (#${entry.id})`);
|
|
65757
|
+
continue;
|
|
65758
|
+
}
|
|
65759
|
+
if (result.retryable) {
|
|
65760
|
+
const retryCount = (deps.getMergeRetryCount ?? ((issueId) => getReviewStatusSync(issueId)?.mergeRetryCount ?? 0))(entry.issueId);
|
|
65761
|
+
if (retryCount >= 3) {
|
|
65762
|
+
const blockedReason = `Auto-merge for ${entry.issueId} blocked: ${reason} (retried ${retryCount} times — fix the underlying cause and re-schedule)`;
|
|
65763
|
+
if ((deps.markMergingBlocked ?? markMergingBlocked)(entry.id, blockedReason)) (deps.announceFailure ?? defaultAnnounceFailure)(entry.issueId, blockedReason);
|
|
65764
|
+
else log(`[auto-merge] lost circuit-breaker block race for ${entry.issueId} (#${entry.id}), skipping announcement`);
|
|
65765
|
+
} else {
|
|
65766
|
+
const nextRetryCount = retryCount + 1;
|
|
65767
|
+
(deps.setMergeRetryCount ?? ((issueId, count) => setReviewStatusSync(issueId, { mergeRetryCount: count })))(entry.issueId, nextRetryCount);
|
|
65768
|
+
const retryAt = new Date(nowDate.getTime() + REQUEUE_BACKOFF_MS).toISOString();
|
|
65769
|
+
log((deps.requeueToPending ?? requeueToPending)(entry.id, retryAt) ? `[auto-merge] retryable merge failure for ${entry.issueId}; requeued attempt ${nextRetryCount}/3 for ${retryAt}` : `[auto-merge] failed to requeue retryable merge for ${entry.issueId} (#${entry.id})`);
|
|
65770
|
+
}
|
|
65771
|
+
continue;
|
|
65772
|
+
}
|
|
64400
65773
|
(deps.markFailed ?? markFailed)(entry.id, reason);
|
|
64401
65774
|
(deps.announceFailure ?? defaultAnnounceFailure)(entry.issueId, reason);
|
|
64402
65775
|
} catch (error) {
|
|
@@ -64561,17 +65934,46 @@ function createOverdeckDatabase(options = {}) {
|
|
|
64561
65934
|
try {
|
|
64562
65935
|
applyMigration(db, migrationPath);
|
|
64563
65936
|
const tables = userTableNames(db);
|
|
64564
|
-
if (tables.length !==
|
|
65937
|
+
if (tables.length !== 34) throw new Error(`Expected 34 overdeck tables, found ${tables.length}: ${tables.join(", ")}`);
|
|
64565
65938
|
assertEmptyTables(db, tables);
|
|
64566
65939
|
} finally {
|
|
64567
65940
|
db.close();
|
|
64568
65941
|
}
|
|
64569
65942
|
return {
|
|
64570
65943
|
dbPath,
|
|
64571
|
-
tableCount:
|
|
65944
|
+
tableCount: 34
|
|
64572
65945
|
};
|
|
64573
65946
|
}
|
|
64574
65947
|
//#endregion
|
|
65948
|
+
//#region telemetry.ts
|
|
65949
|
+
init_agents$1();
|
|
65950
|
+
init_projects();
|
|
65951
|
+
init_service();
|
|
65952
|
+
const defaultDeps = {
|
|
65953
|
+
analytics: getAnalyticsService("server"),
|
|
65954
|
+
listProjects: listProjectsSync,
|
|
65955
|
+
listAgents: () => Effect.runPromise(listRunningAgents())
|
|
65956
|
+
};
|
|
65957
|
+
function bucketServerCount(value) {
|
|
65958
|
+
if (value <= 0) return "0";
|
|
65959
|
+
if (value <= 2) return "1-2";
|
|
65960
|
+
if (value <= 5) return "3-5";
|
|
65961
|
+
if (value <= 10) return "6-10";
|
|
65962
|
+
return "11+";
|
|
65963
|
+
}
|
|
65964
|
+
async function captureServerBootTelemetry(deps = defaultDeps) {
|
|
65965
|
+
try {
|
|
65966
|
+
const [projects, agents] = await Promise.all([Promise.resolve(deps.listProjects()), deps.listAgents()]);
|
|
65967
|
+
deps.analytics.capture("server_boot", {
|
|
65968
|
+
project_count: bucketServerCount(projects.length),
|
|
65969
|
+
active_agent_count: bucketServerCount(agents.filter((agent) => agent.tmuxActive).length)
|
|
65970
|
+
});
|
|
65971
|
+
} catch {}
|
|
65972
|
+
}
|
|
65973
|
+
function startServerBootTelemetry(deps = defaultDeps) {
|
|
65974
|
+
captureServerBootTelemetry(deps);
|
|
65975
|
+
}
|
|
65976
|
+
//#endregion
|
|
64575
65977
|
//#region ../../lib/state-auto-migrate.ts
|
|
64576
65978
|
init_projects();
|
|
64577
65979
|
init_state_home();
|
|
@@ -64596,7 +65998,7 @@ const defaultDependencies = {
|
|
|
64596
65998
|
inspect: inspectStateMigration,
|
|
64597
65999
|
ensureWorktree: ensureStateWorktree,
|
|
64598
66000
|
migrate: async (projectKey, project, signal) => {
|
|
64599
|
-
const { migrateProjectState } = await import("./state-migrate-
|
|
66001
|
+
const { migrateProjectState } = await import("./state-migrate-2u8wIpoL.js");
|
|
64600
66002
|
await migrateProjectState(projectKey, { signal }, project);
|
|
64601
66003
|
},
|
|
64602
66004
|
clearCache: clearStateMigrationCache,
|
|
@@ -64728,11 +66130,12 @@ init_internal_token();
|
|
|
64728
66130
|
init_review_status();
|
|
64729
66131
|
init_event_store();
|
|
64730
66132
|
init_activity_logger();
|
|
64731
|
-
init_config$
|
|
66133
|
+
init_config$2();
|
|
64732
66134
|
init_agents$1();
|
|
64733
66135
|
init_paths();
|
|
64734
66136
|
init_tmux();
|
|
64735
66137
|
init_fts_db();
|
|
66138
|
+
init_control_settings();
|
|
64736
66139
|
init_paths$1();
|
|
64737
66140
|
init_auto_commit();
|
|
64738
66141
|
init_projects();
|
|
@@ -64763,6 +66166,7 @@ if (typeof Bun !== "undefined") {
|
|
|
64763
66166
|
runMain(main);
|
|
64764
66167
|
}
|
|
64765
66168
|
await whenDashboardListening();
|
|
66169
|
+
startServerBootTelemetry();
|
|
64766
66170
|
startEventLoopMonitor();
|
|
64767
66171
|
console.log("[overdeck] Event loop delay monitor started");
|
|
64768
66172
|
warnIfAutonomousMergeBackendUnavailable();
|
|
@@ -64798,13 +66202,15 @@ startAgentOutputService();
|
|
|
64798
66202
|
console.log("[overdeck] AgentOutputService started");
|
|
64799
66203
|
startMergeBlockerReconcileService();
|
|
64800
66204
|
console.log("[overdeck] MergeBlockerReconcileService started");
|
|
66205
|
+
if (startReviewStatusReconcileService()) console.log("[overdeck] ReviewStatusReconcileService started");
|
|
66206
|
+
else console.log("[overdeck] ReviewStatusReconcileService skipped — non-primary dashboard process");
|
|
64801
66207
|
if (shouldStartStaleCheckRetriggerService()) {
|
|
64802
66208
|
startStaleCheckRetriggerService();
|
|
64803
66209
|
console.log("[overdeck] StaleCheckRetriggerService started");
|
|
64804
66210
|
}
|
|
64805
66211
|
if (process.env.OVERDECK_MODE === "desktop") (async () => {
|
|
64806
66212
|
try {
|
|
64807
|
-
const { provisionClaudeHooks } = await import("./claude-hooks-provision-
|
|
66213
|
+
const { provisionClaudeHooks } = await import("./claude-hooks-provision-4RPxNkE8.js");
|
|
64808
66214
|
const result = await provisionClaudeHooks();
|
|
64809
66215
|
if (!result.ok) console.warn(`[overdeck] Claude hook provisioning skipped: ${result.reason}`);
|
|
64810
66216
|
else if (result.changed) console.log(`[overdeck] Claude hooks provisioned: ${result.binariesSynced} scripts, registered ${result.registered.length} hook(s)${result.pruned.length ? `, pruned ${result.pruned.length} stale` : ""}`);
|
|
@@ -64816,21 +66222,11 @@ if (process.env.OVERDECK_MODE === "desktop") (async () => {
|
|
|
64816
66222
|
setPipelineHandlerSync((event) => {
|
|
64817
66223
|
switch (event.type) {
|
|
64818
66224
|
case "status_changed":
|
|
64819
|
-
|
|
64820
|
-
|
|
64821
|
-
|
|
64822
|
-
|
|
64823
|
-
|
|
64824
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64825
|
-
payload: {
|
|
64826
|
-
issueId: event.issueId,
|
|
64827
|
-
status: enriched
|
|
64828
|
-
}
|
|
64829
|
-
});
|
|
64830
|
-
} catch (err) {
|
|
64831
|
-
console.error("[pipeline] Failed to append status_changed event:", err);
|
|
64832
|
-
}
|
|
64833
|
-
})();
|
|
66225
|
+
try {
|
|
66226
|
+
emitReviewStatusChanged((domainEvent) => getEventStore().append(domainEvent), event.issueId, event.status);
|
|
66227
|
+
} catch (err) {
|
|
66228
|
+
console.error("[pipeline] Failed to append status_changed event:", err);
|
|
66229
|
+
}
|
|
64834
66230
|
return;
|
|
64835
66231
|
case "review.approved":
|
|
64836
66232
|
case "test.passed":
|
|
@@ -65012,21 +66408,11 @@ console.log("[overdeck] Agent stopped/status notifiers → domain events wired")
|
|
|
65012
66408
|
setMergeReadyNotifier((issueId) => {
|
|
65013
66409
|
const status = getReviewStatusSync(issueId);
|
|
65014
66410
|
if (!status) return;
|
|
65015
|
-
|
|
65016
|
-
|
|
65017
|
-
|
|
65018
|
-
|
|
65019
|
-
|
|
65020
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65021
|
-
payload: {
|
|
65022
|
-
issueId,
|
|
65023
|
-
status: enriched
|
|
65024
|
-
}
|
|
65025
|
-
});
|
|
65026
|
-
} catch (err) {
|
|
65027
|
-
console.error("[pipeline] Failed to append merge-ready event:", err);
|
|
65028
|
-
}
|
|
65029
|
-
})();
|
|
66411
|
+
try {
|
|
66412
|
+
emitReviewStatusChanged((domainEvent) => getEventStore().append(domainEvent), issueId, status);
|
|
66413
|
+
} catch (err) {
|
|
66414
|
+
console.error("[pipeline] Failed to append merge-ready event:", err);
|
|
66415
|
+
}
|
|
65030
66416
|
});
|
|
65031
66417
|
console.log("[overdeck] Merge-ready notifier → domain events wired");
|
|
65032
66418
|
startConversationLifecycleService();
|
|
@@ -65119,6 +66505,11 @@ let shuttingDown = false;
|
|
|
65119
66505
|
const handleShutdownSignal = async (signal) => {
|
|
65120
66506
|
if (shuttingDown) return;
|
|
65121
66507
|
shuttingDown = true;
|
|
66508
|
+
try {
|
|
66509
|
+
setLastCleanShutdownAt((/* @__PURE__ */ new Date()).toISOString());
|
|
66510
|
+
} catch (err) {
|
|
66511
|
+
console.warn("[overdeck] failed to record clean shutdown marker:", err);
|
|
66512
|
+
}
|
|
65122
66513
|
console.log(`[overdeck] received ${signal} (pid=${process.pid} ppid=${process.ppid}) — shutting down`);
|
|
65123
66514
|
try {
|
|
65124
66515
|
const notifiedClients = broadcastServerRestarting();
|
|
@@ -65148,7 +66539,7 @@ const handleShutdownSignal = async (signal) => {
|
|
|
65148
66539
|
await stopAllKnowledgeViewers().catch((err) => console.warn("[knowledge-viewer] shutdown failed:", err?.message ?? err));
|
|
65149
66540
|
await stopDeaconChild().catch((err) => console.warn("[deacon-supervisor] child shutdown failed:", err?.message ?? err));
|
|
65150
66541
|
try {
|
|
65151
|
-
const { killAllGateProcessGroups } = await import("./validation-
|
|
66542
|
+
const { killAllGateProcessGroups } = await import("./validation-hVOwQk8T.js");
|
|
65152
66543
|
const reaped = killAllGateProcessGroups();
|
|
65153
66544
|
if (reaped > 0) console.log(`[overdeck] reaped ${reaped} in-flight gate process group(s)`);
|
|
65154
66545
|
} catch (err) {
|
|
@@ -65203,7 +66594,7 @@ reconcileStaleGitHubBlockers().then((n) => {
|
|
|
65203
66594
|
}
|
|
65204
66595
|
}).catch((err) => console.warn(`[overdeck] Startup blocker reconciliation failed: ${err.message}`));
|
|
65205
66596
|
try {
|
|
65206
|
-
const { resetProcessingToQueued } = await import("./merge-sync-
|
|
66597
|
+
const { resetProcessingToQueued } = await import("./merge-sync-CpGmk6Ch.js");
|
|
65207
66598
|
const resetCount = resetProcessingToQueued();
|
|
65208
66599
|
if (resetCount > 0) {
|
|
65209
66600
|
console.log(`[overdeck] Reset ${resetCount} stuck merge queue entries to queued`);
|
|
@@ -65225,7 +66616,7 @@ else {
|
|
|
65225
66616
|
console.log("[overdeck] Auto-merge executor started");
|
|
65226
66617
|
}
|
|
65227
66618
|
try {
|
|
65228
|
-
const { reconcileInterruptedVerifications } = await import("./verification-runner-
|
|
66619
|
+
const { reconcileInterruptedVerifications } = await import("./verification-runner-Bc3cJvpC.js");
|
|
65229
66620
|
const interrupted = reconcileInterruptedVerifications();
|
|
65230
66621
|
if (interrupted > 0) console.log(`[overdeck] recovered ${interrupted} orphaned verification worker(s)`);
|
|
65231
66622
|
} catch (err) {
|