@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
|
@@ -1,46 +1,47 @@
|
|
|
1
1
|
import { a as __toCommonJS } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import { A as canUseHarnessSync,
|
|
3
|
-
import {
|
|
4
|
-
import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-
|
|
5
|
-
import {
|
|
6
|
-
import { a as init_event_store, n as getEventStore } from "./event-store-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { a as EventStoreService, c as ReadModelService, d as init_read_model, i as init_issue_lifecycle, s as init_domain_services, t as IssueLifecycle
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { t as init_behavior } from "./behavior-
|
|
17
|
-
import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-
|
|
18
|
-
import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-
|
|
19
|
-
import { o as getInternalTokenSync, s as init_internal_token } from "./internal-token-
|
|
20
|
-
import { a as PAN_DIRNAME, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import { _ as
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
2
|
+
import { A as canUseHarnessSync, Cn as resolveStateReadHomeSync, D as resolveTieredExecutionEnabled, Fr as init_errors, Gn as init_projects, H as init_providers, I as UnknownModelError, M as init_harness_policy, Mn as findProjectByPathSync, O as resolveTieredExecutionEnabledForIssue, Sn as init_state_read_home, T as init_tier_table, Tr as FsError, U as piProviderForModel, V as getProviderForModelSync, Yn as listProjectsSync, ar as resolveProjectFromIssueSync, c as isClaudeCodeChannelsEnabled, ci as getOverdeckHome, di as packageRoot, ei as claudeSessionTranscriptExists, f as loadConfigSync, fi as resolveOhmypiExtensionPath, gr as init_issue_id, h as jsYaml, hn as init_state_plane, hr as extractPrefixSync, li as init_paths, m as init_js_yaml, t as init_config_yaml, ti as encodeClaudeProjectDir, tt as resolveModel, vn as parsePorcelainStatusPaths, vr as parseIssueIdSync, wn as shouldCommitLegacyWorkspaceArtifacts, zn as getProjectSync } from "./config-yaml-CxdwhAIA.js";
|
|
3
|
+
import { n as emitActivityEntryDurable, o as init_activity_logger, r as emitActivityEntrySync } from "./activity-logger-CyteR4JO.js";
|
|
4
|
+
import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-BDQDRopn.js";
|
|
5
|
+
import { B as sendKeysAsync, D as killSession, H as sessionExists, J as init_pane_choice_menu, M as listSessionNames, N as listSessions, T as isHarnessProcessAlive, U as sessionExistsSync, V as sendRawKeystroke, W as setOption, X as paneHasBlockingChoiceMenu, at as buildChildEnvWithoutTmuxSync, g as findManagedServerPidSync, i as capturePane, m as exactPaneTarget, o as capturePaneText, ot as init_child_env, rt as BLANKED_PROVIDER_ENV, s as createSession, w as init_tmux } from "./tmux-CfDHob9M.js";
|
|
6
|
+
import { a as init_event_store, n as getEventStore } from "./event-store-CrHcVC5_.js";
|
|
7
|
+
import { N as normalizeChannelReplyPayload, T as DomainEvent, n as COMPOSER_COMMAND_MANIFEST, s as getHarnessBehavior, t as init_src } from "./src-B948bGVR.js";
|
|
8
|
+
import { C as setReviewStatusSync, Q as stateToOverdeckParamsForDb, Y as init_agent_state_sync, d as getReviewStatusSync, h as loadReviewStatuses, o as clearWorkspaceStuck, p as init_review_status, q as AGENT_COLUMNS_FOR_DB } from "./review-status-CGvlA4o_.js";
|
|
9
|
+
import { a as EventStoreService, c as ReadModelService, d as getClosedIssueIdsForReadSource, f as init_read_model, i as init_issue_lifecycle, s as init_domain_services, t as IssueLifecycle } from "./issue-lifecycle-Birk-ifu.js";
|
|
10
|
+
import { n as logAgentLifecycleSync, t as init_persistent_logger } from "./persistent-logger-H_VjuOu7.js";
|
|
11
|
+
import { d as isTerminalIssueStage, o as init_agents, u as getIssueStageSync } from "./agents-J5mEnekq.js";
|
|
12
|
+
import { n as ensureSessionContextBriefingFile, r as init_briefing_freshness } from "./briefing-freshness-DRqZ8lAz.js";
|
|
13
|
+
import { o as getPricingSync, s as init_cost, t as calculateCostSync } from "./cost-DpgYmYqR.js";
|
|
14
|
+
import { $ as operatorInterventionEvent, $n as getAgentDir, An as getProviderExportsForModel, Ar as resolvePtySupervisorScriptPath, Bn as dismissDevChannelsDialog, Br as saveAgentRuntimeState, Dr as init_pty_token, Er as init_resume_contract, F as init_tier_escalation, G as resumeAgent, Gr as init_codex_auth, Gt as assertWorkspaceStackHealthyForSpawn, H as restartAgent, Ht as BRIDGE_TOKEN_HEADER, Ir as waitForReadySignal, Jt as init_spawn_prep, Lr as getAgentRuntimeState, Mn as init_provider_health, Mt as deliverAgentMessage, Nn as validateProviderHealth, Nr as normalizeAgentId, Nt as deliverAgentPermissionDecision, On as determineModel, Or as writePtyToken, P as decideEscalation, Q as init_operator_interventions, Qt as init_staffing, Rr as getAgentRuntimeStateSync, Rt as setAgentDeliveryMethod, Sr as writeAgentStateJsonSync, Tr as buildResumeContract, Un as writeChannelsBridgeMcpConfig, Ut as init_bridge_token, V as recoverAgent, Wr as checkCodexAuthStatus, Wt as writeBridgeTokenSync, X as messageAgent, Xt as transitionIssueToInProgress, Yn as clearAgentTroubled, _r as saveAgentStateSync, b as init_agents$1, bn as init_ohmypi_fifo, cn as getAgentRuntimeBaseCommand, dn as getProviderAuthMode, gn as waitForAcpHostReady, gr as saveAgentState, i as listRunningAgents, it as getSessionId, jr as clearReadySignal, kr as init_pty_supervisor_locate, nn as resolveStaffing, nt as getLatestSessionId, ot as saveSessionId, pn as init_runtime_command, pt as stopAgent, qn as clearAgentPaused, r as listAgentStates, rr as getAgentStateSync, rt as getLatestSessionIdSync, sn as getAcpLauncherFields, tn as resolveIssueWorkModel, tr as getAgentState, tt as getActivity, ur as markAgentStoppedState, vn as init_pi_fifo, vr as setAgentPaused, xn as ohmypiFifoPaths, xr as wipeAgentStateDirs, yn as piFifoPaths } from "./queries-C-MUZaIy.js";
|
|
15
|
+
import { a as performHandoff, i as checkAllTriggers, s as getAgentHealth, t as getCloisterService } from "./service-CD0DvFvD.js";
|
|
16
|
+
import { t as init_behavior } from "./behavior-td6-xhQk.js";
|
|
17
|
+
import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-BcPMElRB.js";
|
|
18
|
+
import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-C6ZduvuY.js";
|
|
19
|
+
import { o as getInternalTokenSync, s as init_internal_token } from "./internal-token-DzK385vD.js";
|
|
20
|
+
import { a as PAN_DIRNAME, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-Cm5ASJbq.js";
|
|
21
|
+
import { l as resolveWorkspaceRepoRootsSync, o as resolvePrimaryWorkspaceRepoDirSync, r as init_project_repos } from "./project-repos-B5pIphKg.js";
|
|
22
|
+
import { a as generateXBriefFilename, o as init_lifecycle } from "./lifecycle-B4Xdb4cY.js";
|
|
23
|
+
import { f as readTierOverrides, g as serializeXBriefDocument, h as recordTierPromotion, m as readWorkspacePlanSync, o as init_io, r as findPlan, u as readPlan } from "./io-B00PBNku.js";
|
|
24
|
+
import { B as removeFavorite, E as hasOtherActiveConversationOnTmuxSession, F as markConversationEnded, G as setConversationHarness, K as setConversationModel, M as listConversations, P as markConversationActive, Q as updateConversationDeliveryMethod, S as getConversationByName, W as setConversationEffort, g as backfillConversationModel, h as archiveConversation, k as init_conversations, nt as updateLastAttached, rt as updateSpawnError, x as getConversationById, y as createConversation } from "./conversations-D0UEdLtk.js";
|
|
25
|
+
import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-B6HpNWRy.js";
|
|
26
|
+
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, x as normalizeFlywheelRunId, y as init_provenance } from "./auto-spawn-consent-CQ9Bi9q6.js";
|
|
27
|
+
import { a as init_claude_permissions, o as resolvePermissionModeSync, r as getClaudePermissionFlagsStringSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-CpbpvUQ2.js";
|
|
28
|
+
import { E as init_layers, I as workspaceContextFile, k as piGlobalContextFile } from "./assemble-Bgwqv-Ro.js";
|
|
29
|
+
import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-BSpiXaLw.js";
|
|
30
|
+
import { a as getWorkspaceStackHealth, s as init_stack_health } from "./stack-health-DqLTiEu4.js";
|
|
31
|
+
import { l as init_dag, o as getDispatchableItems } from "./dag-BtkgLeqY.js";
|
|
32
|
+
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-BAJu5MX8.js";
|
|
33
|
+
import { a as loadCloisterConfigSync, r as init_config } from "./config-Bi3u1VK7.js";
|
|
34
|
+
import { c as isStateMigrated, o as init_state_home } from "./state-home-722Dkx92.js";
|
|
35
|
+
import { a as init_lifecycle_io, c as updatePlanStatus, s as transitionXBriefOnMain } from "./lifecycle-io-DCo6s6ks.js";
|
|
36
|
+
import { _ as init_codex_conversation_parser, b as parseAcpConversationMessages, c as parseEntireConversation, d as init_pi_conversation_parser, g as parseOhmypiConversationMessages, m as init_ohmypi_conversation_parser, p as parsePiConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages, y as init_acp_conversation_parser } from "./conversation-service-DBxoYMDl.js";
|
|
37
|
+
import { _ as normalizeAwaitingInputPrompt, d as getAgentPendingQuestions$1, f as getAgentWorkspace$1, h as detectAwaitingInputForAgent, m as scanPendingInputsPromise, o as getRuntimeForAgent, p as isBlockedOnPendingInput, s as computeAgentEnrichment, u as getAgentJsonlPath$1, v as parseCodexApprovalPrompt } from "./stuck-remediation-CC6q3eqQ.js";
|
|
38
|
+
import { B as getBook, H as liveOrderIssueLookup, T as resolveLiveFlywheelRunId, w as readFlywheelLaunchMetadata, y as getFlywheelRunDir, z as computeBookProgress } from "./flywheel-BHx8XuMr.js";
|
|
39
|
+
import { At as classifyMemoryPressure, Lt as getResourceConfig, zt as getSystemHealthSnapshot } from "./deacon-pLRLbPvR.js";
|
|
40
|
+
import { o as stopWorkspaceDocker, r as init_workspace_manager } from "./workspace-manager-BPgTrG66.js";
|
|
41
|
+
import { a as init_jsonl_parser, o as normalizeModelName } from "./jsonl-parser-BDpnGFCl.js";
|
|
42
|
+
import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-D-sSkADM.js";
|
|
43
|
+
import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-DkO_iTLo.js";
|
|
44
|
+
import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
44
45
|
import { Cause, Data, Effect, Layer, Option, Schema, Stream } from "effect";
|
|
45
46
|
import { join as join$1 } from "path";
|
|
46
47
|
import { homedir, networkInterfaces } from "node:os";
|
|
@@ -52,9 +53,9 @@ import { mkdir as mkdir$1, writeFile as writeFile$1 } from "fs/promises";
|
|
|
52
53
|
import { exec, execFile, spawn } from "node:child_process";
|
|
53
54
|
import { promisify } from "node:util";
|
|
54
55
|
import { createHash as createHash$1, createHmac, randomBytes, randomUUID as randomUUID$1, timingSafeEqual } from "node:crypto";
|
|
56
|
+
import { createInterface } from "node:readline";
|
|
55
57
|
import { pathToFileURL } from "node:url";
|
|
56
58
|
import { request } from "node:http";
|
|
57
|
-
import { createInterface } from "node:readline";
|
|
58
59
|
import * as Result$1 from "effect/Result";
|
|
59
60
|
//#region http-helpers.ts
|
|
60
61
|
init_paths();
|
|
@@ -86,21 +87,24 @@ init_projects();
|
|
|
86
87
|
init_providers();
|
|
87
88
|
init_harness_policy();
|
|
88
89
|
init_tier_table();
|
|
90
|
+
init_js_yaml();
|
|
89
91
|
init_config_yaml();
|
|
90
92
|
init_child_env();
|
|
93
|
+
init_pane_choice_menu();
|
|
91
94
|
init_tmux();
|
|
92
95
|
init_infra();
|
|
93
96
|
init_event_store();
|
|
94
97
|
init_src();
|
|
95
98
|
init_agent_state_sync();
|
|
99
|
+
init_persistent_logger();
|
|
96
100
|
init_agents();
|
|
97
101
|
init_read_model();
|
|
98
102
|
init_briefing_freshness();
|
|
99
103
|
init_domain_services();
|
|
100
104
|
init_cost();
|
|
101
105
|
init_behavior();
|
|
102
|
-
init_persistent_logger();
|
|
103
106
|
init_tracker_config();
|
|
107
|
+
init_project_repos();
|
|
104
108
|
init_lifecycle();
|
|
105
109
|
init_review_status();
|
|
106
110
|
init_io();
|
|
@@ -193,6 +197,7 @@ function httpHandler(effect) {
|
|
|
193
197
|
init_conversations();
|
|
194
198
|
init_pty_supervisor_locate();
|
|
195
199
|
init_pty_token();
|
|
200
|
+
init_resume_contract();
|
|
196
201
|
init_feature_registry_population();
|
|
197
202
|
init_model_validation();
|
|
198
203
|
init_provider_health();
|
|
@@ -205,6 +210,7 @@ init_runtime_command();
|
|
|
205
210
|
init_stack_health();
|
|
206
211
|
init_launcher_generator();
|
|
207
212
|
init_dag();
|
|
213
|
+
init_provenance();
|
|
208
214
|
init_staffing();
|
|
209
215
|
init_spawn_prep();
|
|
210
216
|
init_harness_resolve();
|
|
@@ -218,6 +224,27 @@ function addTrustedOrigin(origins, raw) {
|
|
|
218
224
|
const normalized = normalizeOrigin(raw.trim());
|
|
219
225
|
if (normalized) origins.add(normalized);
|
|
220
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Last-resort origin config for launches that carry no origin env at all
|
|
229
|
+
* (manual `node dist/...`, ad-hoc re-exec). `pan up` builds its launch env from
|
|
230
|
+
* this same config.yaml, so reading it here keeps every launch path trusting the
|
|
231
|
+
* same Traefik domain instead of 403ing /ws/* into a "Reconnecting" loop.
|
|
232
|
+
*/
|
|
233
|
+
function readTraefikConfigFromYaml() {
|
|
234
|
+
try {
|
|
235
|
+
const configPath = join(process.env["OVERDECK_HOME"] || join(homedir(), ".overdeck"), "config.yaml");
|
|
236
|
+
if (!existsSync(configPath)) return null;
|
|
237
|
+
const traefik = jsYaml.load(readFileSync(configPath, "utf8"))?.traefik;
|
|
238
|
+
if (!traefik || typeof traefik !== "object") return null;
|
|
239
|
+
if (typeof traefik.domain !== "string" || traefik.domain.trim() === "") return null;
|
|
240
|
+
return {
|
|
241
|
+
enabled: traefik.enabled === true,
|
|
242
|
+
domain: traefik.domain.trim()
|
|
243
|
+
};
|
|
244
|
+
} catch {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
221
248
|
function getTrustedOrigins() {
|
|
222
249
|
if (cachedTrustedOrigins !== void 0) return cachedTrustedOrigins;
|
|
223
250
|
const port = parseInt(process.env["API_PORT"] ?? process.env["PORT"] ?? "3011", 10);
|
|
@@ -232,6 +259,10 @@ function getTrustedOrigins() {
|
|
|
232
259
|
for (const origin of trustedOrigins?.split(",") ?? []) addTrustedOrigin(origins, origin);
|
|
233
260
|
const traefikDomain = process.env["OVERDECK_TRAEFIK_DOMAIN"] ?? process.env["TRAEFIK_DOMAIN"];
|
|
234
261
|
if (process.env["OVERDECK_TRAEFIK_ENABLED"] === "1" && traefikDomain) addTrustedOrigin(origins, `https://${traefikDomain}`);
|
|
262
|
+
if (!(process.env["OVERDECK_TRAEFIK_ENABLED"] !== void 0 || traefikDomain !== void 0 || process.env["OVERDECK_TRUSTED_ORIGINS"] !== void 0)) {
|
|
263
|
+
const fromYaml = readTraefikConfigFromYaml();
|
|
264
|
+
if (fromYaml?.enabled) addTrustedOrigin(origins, `https://${fromYaml.domain}`);
|
|
265
|
+
}
|
|
235
266
|
if (process.env["NODE_ENV"] === "development") {
|
|
236
267
|
addTrustedOrigin(origins, "http://localhost:3000");
|
|
237
268
|
addTrustedOrigin(origins, "http://127.0.0.1:3000");
|
|
@@ -799,7 +830,7 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
|
|
|
799
830
|
const agentDir = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId);
|
|
800
831
|
const codexHome = join(agentDir, "codex-home");
|
|
801
832
|
if (!await pathExists$1(codexHome)) return null;
|
|
802
|
-
const { findRolloutPath, findLatestRollout } = await import("./codex-
|
|
833
|
+
const { findRolloutPath, findLatestRollout } = await import("./codex-o8FJwzmy.js");
|
|
803
834
|
const threadId = (await readOptional(join(agentDir, "codex-thread-id")))?.trim();
|
|
804
835
|
if (threadId) {
|
|
805
836
|
const rollout = findRolloutPath(codexHome, threadId);
|
|
@@ -898,6 +929,7 @@ function spawnPanCli(args, options = {}) {
|
|
|
898
929
|
//#endregion
|
|
899
930
|
//#region ../../lib/work-agent-lifecycle.ts
|
|
900
931
|
init_agents$1();
|
|
932
|
+
init_paths();
|
|
901
933
|
init_tmux();
|
|
902
934
|
async function pathExists(path) {
|
|
903
935
|
try {
|
|
@@ -912,9 +944,11 @@ function getWorkAgentLifecycleStateSync(agentOrIssueId) {
|
|
|
912
944
|
const agentState = getAgentStateSync(agentId);
|
|
913
945
|
const runtimeState = getAgentRuntimeStateSync(agentId);
|
|
914
946
|
const hasAgentState = !!agentState;
|
|
915
|
-
const
|
|
947
|
+
const sessionId = getLatestSessionIdSync(agentId) ?? null;
|
|
948
|
+
const hasSavedSession = !!sessionId;
|
|
916
949
|
const hasLiveTmuxSession = sessionExistsSync(agentId);
|
|
917
950
|
const hasWorkspace = !!agentState?.workspace && existsSync(agentState.workspace);
|
|
951
|
+
const hasResumableTranscript = !sessionId || !!agentState?.harness && agentState.harness !== "claude-code" || !agentState?.workspace || claudeSessionTranscriptExists(agentState.workspace, sessionId);
|
|
918
952
|
const agentStatus = agentState?.status || "unknown";
|
|
919
953
|
const runtime = runtimeState?.state || "uninitialized";
|
|
920
954
|
const isCompleted = runtimeState?.resolution === "completed";
|
|
@@ -925,7 +959,7 @@ function getWorkAgentLifecycleStateSync(agentOrIssueId) {
|
|
|
925
959
|
const isRunningButStuck = isRunning && (runtime === "idle" || runtime === "suspended");
|
|
926
960
|
const hasResumableBackingState = hasAgentState && hasWorkspace && !isPlaceholder;
|
|
927
961
|
const isOrphaned = !hasLiveTmuxSession && (hasSavedSession && !hasResumableBackingState || hasAgentState && (!hasWorkspace || isPlaceholder));
|
|
928
|
-
const requiresSessionResetBeforeFreshStart = hasSavedSession && !hasLiveTmuxSession && hasResumableBackingState && (isStopped || isCrashed);
|
|
962
|
+
const requiresSessionResetBeforeFreshStart = hasSavedSession && hasResumableTranscript && !hasLiveTmuxSession && hasResumableBackingState && (isStopped || isCrashed);
|
|
929
963
|
let recommendedAction = "start";
|
|
930
964
|
let reason;
|
|
931
965
|
if (isRunningButStuck) {
|
|
@@ -943,6 +977,9 @@ function getWorkAgentLifecycleStateSync(agentOrIssueId) {
|
|
|
943
977
|
} else if (requiresSessionResetBeforeFreshStart) {
|
|
944
978
|
recommendedAction = "resume";
|
|
945
979
|
reason = `Agent ${agentId} has a resumable Claude session. Use 'pan resume ${agentOrIssueId}' to continue it, or 'pan start ${agentOrIssueId} --fresh' to start a new session (e.g. to switch model).`;
|
|
980
|
+
} else if (hasSavedSession && !hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed)) {
|
|
981
|
+
recommendedAction = "start";
|
|
982
|
+
reason = `Agent ${agentId} has a saved Claude session id but its transcript is missing on disk (jsonl-missing). Start Agent will create a fresh session in the existing workspace.`;
|
|
946
983
|
} else if (hasAgentState && !hasSavedSession && isStopped) {
|
|
947
984
|
recommendedAction = "start";
|
|
948
985
|
reason = `Agent ${agentId} is stopped and has no saved Claude session. Start Agent will create a fresh session in the existing workspace.`;
|
|
@@ -955,6 +992,7 @@ function getWorkAgentLifecycleStateSync(agentOrIssueId) {
|
|
|
955
992
|
hasAgentState,
|
|
956
993
|
hasLiveTmuxSession,
|
|
957
994
|
hasSavedSession,
|
|
995
|
+
hasResumableTranscript,
|
|
958
996
|
hasWorkspace,
|
|
959
997
|
isPlaceholder,
|
|
960
998
|
isOrphaned,
|
|
@@ -966,9 +1004,9 @@ function getWorkAgentLifecycleStateSync(agentOrIssueId) {
|
|
|
966
1004
|
runtimeState: runtime,
|
|
967
1005
|
agentStatus,
|
|
968
1006
|
canStartFresh: (!hasLiveTmuxSession || hasLiveTmuxSession && isStopped) && (!requiresSessionResetBeforeFreshStart || isOrphaned),
|
|
969
|
-
canResumeSession: !isRunning && hasSavedSession && hasResumableBackingState && (isStopped || isCrashed),
|
|
1007
|
+
canResumeSession: !isRunning && hasSavedSession && hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed),
|
|
970
1008
|
canRestartWithContext: hasAgentState && hasWorkspace,
|
|
971
|
-
canResetSession: hasSavedSession && hasResumableBackingState,
|
|
1009
|
+
canResetSession: hasSavedSession && hasResumableTranscript && hasResumableBackingState,
|
|
972
1010
|
requiresSessionResetBeforeFreshStart,
|
|
973
1011
|
recommendedAction,
|
|
974
1012
|
reason
|
|
@@ -979,9 +1017,11 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
|
|
|
979
1017
|
const agentState = await Effect.runPromise(getAgentState(agentId));
|
|
980
1018
|
const runtimeState = await Effect.runPromise(getAgentRuntimeState(agentId));
|
|
981
1019
|
const hasAgentState = !!agentState;
|
|
982
|
-
const
|
|
1020
|
+
const sessionId = await Effect.runPromise(getLatestSessionId(agentId)) ?? null;
|
|
1021
|
+
const hasSavedSession = !!sessionId;
|
|
983
1022
|
const hasLiveTmuxSession = await Effect.runPromise(sessionExists(agentId));
|
|
984
1023
|
const hasWorkspace = !!agentState?.workspace && await pathExists(agentState.workspace);
|
|
1024
|
+
const hasResumableTranscript = !sessionId || !!agentState?.harness && agentState.harness !== "claude-code" || !agentState?.workspace || claudeSessionTranscriptExists(agentState.workspace, sessionId);
|
|
985
1025
|
const agentStatus = agentState?.status || "unknown";
|
|
986
1026
|
const runtime = runtimeState?.state || "uninitialized";
|
|
987
1027
|
const isCompleted = runtimeState?.resolution === "completed";
|
|
@@ -992,7 +1032,7 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
|
|
|
992
1032
|
const isRunningButStuck = isRunning && (runtime === "idle" || runtime === "suspended");
|
|
993
1033
|
const hasResumableBackingState = hasAgentState && hasWorkspace && !isPlaceholder;
|
|
994
1034
|
const isOrphaned = !hasLiveTmuxSession && (hasSavedSession && !hasResumableBackingState || hasAgentState && (!hasWorkspace || isPlaceholder));
|
|
995
|
-
const requiresSessionResetBeforeFreshStart = hasSavedSession && !hasLiveTmuxSession && hasResumableBackingState && (isStopped || isCrashed);
|
|
1035
|
+
const requiresSessionResetBeforeFreshStart = hasSavedSession && hasResumableTranscript && !hasLiveTmuxSession && hasResumableBackingState && (isStopped || isCrashed);
|
|
996
1036
|
let recommendedAction = "start";
|
|
997
1037
|
let reason;
|
|
998
1038
|
if (isRunningButStuck) {
|
|
@@ -1010,6 +1050,9 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
|
|
|
1010
1050
|
} else if (requiresSessionResetBeforeFreshStart) {
|
|
1011
1051
|
recommendedAction = "resume";
|
|
1012
1052
|
reason = `Agent ${agentId} has a resumable Claude session. Use 'pan resume ${agentOrIssueId}' to continue it, or 'pan start ${agentOrIssueId} --fresh' to start a new session (e.g. to switch model).`;
|
|
1053
|
+
} else if (hasSavedSession && !hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed)) {
|
|
1054
|
+
recommendedAction = "start";
|
|
1055
|
+
reason = `Agent ${agentId} has a saved Claude session id but its transcript is missing on disk (jsonl-missing). Start Agent will create a fresh session in the existing workspace.`;
|
|
1013
1056
|
} else if (hasAgentState && !hasSavedSession && isStopped) {
|
|
1014
1057
|
recommendedAction = "start";
|
|
1015
1058
|
reason = `Agent ${agentId} is stopped and has no saved Claude session. Start Agent will create a fresh session in the existing workspace.`;
|
|
@@ -1022,6 +1065,7 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
|
|
|
1022
1065
|
hasAgentState,
|
|
1023
1066
|
hasLiveTmuxSession,
|
|
1024
1067
|
hasSavedSession,
|
|
1068
|
+
hasResumableTranscript,
|
|
1025
1069
|
hasWorkspace,
|
|
1026
1070
|
isPlaceholder,
|
|
1027
1071
|
isOrphaned,
|
|
@@ -1033,9 +1077,9 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
|
|
|
1033
1077
|
runtimeState: runtime,
|
|
1034
1078
|
agentStatus,
|
|
1035
1079
|
canStartFresh: (!hasLiveTmuxSession || hasLiveTmuxSession && isStopped) && (!requiresSessionResetBeforeFreshStart || isOrphaned),
|
|
1036
|
-
canResumeSession: !isRunning && hasSavedSession && hasResumableBackingState && (isStopped || isCrashed),
|
|
1080
|
+
canResumeSession: !isRunning && hasSavedSession && hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed),
|
|
1037
1081
|
canRestartWithContext: hasAgentState && hasWorkspace,
|
|
1038
|
-
canResetSession: hasSavedSession && hasResumableBackingState,
|
|
1082
|
+
canResetSession: hasSavedSession && hasResumableTranscript && hasResumableBackingState,
|
|
1039
1083
|
requiresSessionResetBeforeFreshStart,
|
|
1040
1084
|
recommendedAction,
|
|
1041
1085
|
reason
|
|
@@ -1185,111 +1229,357 @@ async function resolveAgentGitInfo(workspacePath, expectedBranch) {
|
|
|
1185
1229
|
};
|
|
1186
1230
|
}
|
|
1187
1231
|
//#endregion
|
|
1188
|
-
//#region
|
|
1232
|
+
//#region ../../lib/composer-commands/executors.ts
|
|
1233
|
+
const CAPTURED_COMMAND_MAX_OUTPUT_BYTES = 64 * 1024;
|
|
1234
|
+
const TRUNCATION_MESSAGE = "\n\nOutput was truncated after 65,536 bytes.";
|
|
1235
|
+
function runCapturedCommand(argv, dependencies = {}) {
|
|
1236
|
+
const command = `/pan ${argv.join(" ")}`;
|
|
1237
|
+
const spawnCommand = dependencies.spawnPanCli ?? spawnPanCli;
|
|
1238
|
+
const timeoutMs = dependencies.timeoutMs ?? 3e4;
|
|
1239
|
+
const child = spawnCommand(argv, { stdio: [
|
|
1240
|
+
"ignore",
|
|
1241
|
+
"pipe",
|
|
1242
|
+
"pipe"
|
|
1243
|
+
] });
|
|
1244
|
+
return new Promise((resolve) => {
|
|
1245
|
+
const chunks = [];
|
|
1246
|
+
let bufferedBytes = 0;
|
|
1247
|
+
let settled = false;
|
|
1248
|
+
let timeout;
|
|
1249
|
+
let truncated = false;
|
|
1250
|
+
const appendOutput = (data) => {
|
|
1251
|
+
if (truncated) return;
|
|
1252
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1253
|
+
const remaining = CAPTURED_COMMAND_MAX_OUTPUT_BYTES - Buffer.byteLength(TRUNCATION_MESSAGE) - bufferedBytes;
|
|
1254
|
+
if (buffer.length <= remaining) {
|
|
1255
|
+
chunks.push(buffer);
|
|
1256
|
+
bufferedBytes += buffer.length;
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
if (remaining > 0) {
|
|
1260
|
+
chunks.push(buffer.subarray(0, remaining));
|
|
1261
|
+
bufferedBytes += remaining;
|
|
1262
|
+
}
|
|
1263
|
+
truncated = true;
|
|
1264
|
+
};
|
|
1265
|
+
const output = () => {
|
|
1266
|
+
const captured = Buffer.concat(chunks, bufferedBytes).toString("utf8");
|
|
1267
|
+
return truncated ? `${captured}${TRUNCATION_MESSAGE}` : captured;
|
|
1268
|
+
};
|
|
1269
|
+
const finish = (result) => {
|
|
1270
|
+
if (settled) return;
|
|
1271
|
+
settled = true;
|
|
1272
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
1273
|
+
resolve(result);
|
|
1274
|
+
};
|
|
1275
|
+
child.stdout?.on("data", appendOutput);
|
|
1276
|
+
child.stderr?.on("data", appendOutput);
|
|
1277
|
+
child.once("error", (error) => {
|
|
1278
|
+
finish({
|
|
1279
|
+
kind: "captured",
|
|
1280
|
+
status: "failed",
|
|
1281
|
+
command,
|
|
1282
|
+
output: `Command ${command} could not start: ${error.message}`,
|
|
1283
|
+
truncated: false
|
|
1284
|
+
});
|
|
1285
|
+
});
|
|
1286
|
+
child.once("close", (code) => {
|
|
1287
|
+
const captured = output();
|
|
1288
|
+
finish({
|
|
1289
|
+
kind: "captured",
|
|
1290
|
+
status: code === 0 ? "completed" : "failed",
|
|
1291
|
+
command,
|
|
1292
|
+
output: captured || `Command ${command} ${code === 0 ? "completed without output." : `failed with exit code ${code ?? "unknown"}.`}`,
|
|
1293
|
+
truncated
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
timeout = setTimeout(() => {
|
|
1297
|
+
stopChild(child);
|
|
1298
|
+
finish({
|
|
1299
|
+
kind: "captured",
|
|
1300
|
+
status: "failed",
|
|
1301
|
+
command,
|
|
1302
|
+
output: `Command ${command} timed out after ${Math.round(timeoutMs / 1e3)} seconds and was stopped.`,
|
|
1303
|
+
truncated: false
|
|
1304
|
+
});
|
|
1305
|
+
}, timeoutMs);
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
function stopChild(child) {
|
|
1309
|
+
child.kill("SIGTERM");
|
|
1310
|
+
}
|
|
1311
|
+
//#endregion
|
|
1312
|
+
//#region ../../lib/composer-commands/detached.ts
|
|
1189
1313
|
init_paths();
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1314
|
+
const DETACHED_TRUNCATION_MESSAGE = "\n\nOutput was truncated after 65,536 bytes.";
|
|
1315
|
+
function resolveAgentDirectory(overdeckHome, agentId) {
|
|
1316
|
+
if (agentId.length === 0 || agentId === "." || agentId === ".." || agentId.includes("/") || agentId.includes("\\") || isAbsolute(agentId)) throw new Error("Agent ID must be a single filesystem-safe path segment.");
|
|
1317
|
+
return join(resolve(overdeckHome, "agents"), agentId);
|
|
1318
|
+
}
|
|
1319
|
+
async function readBoundedSpawnOutput(spawnLogPath, startOffset) {
|
|
1320
|
+
const maximumPrefixBytes = CAPTURED_COMMAND_MAX_OUTPUT_BYTES - Buffer.byteLength(DETACHED_TRUNCATION_MESSAGE);
|
|
1321
|
+
const handle = await open(spawnLogPath, "r");
|
|
1322
|
+
try {
|
|
1323
|
+
const stats = await handle.stat();
|
|
1324
|
+
const outputBytes = Math.max(0, stats.size - startOffset);
|
|
1325
|
+
if (outputBytes === 0) return "";
|
|
1326
|
+
const bytesToRead = Math.min(outputBytes, maximumPrefixBytes);
|
|
1327
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
1328
|
+
const { bytesRead } = await handle.read(buffer, 0, bytesToRead, startOffset);
|
|
1329
|
+
const output = buffer.subarray(0, bytesRead).toString("utf8");
|
|
1330
|
+
return outputBytes > maximumPrefixBytes ? `${output}${DETACHED_TRUNCATION_MESSAGE}` : output;
|
|
1331
|
+
} finally {
|
|
1332
|
+
await handle.close().catch(() => void 0);
|
|
1333
|
+
}
|
|
1205
1334
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1335
|
+
async function appendAgentLifecycleLog(agentId, event, details = {}, overdeckHome = getOverdeckHome()) {
|
|
1336
|
+
const agentDir = resolveAgentDirectory(overdeckHome, agentId);
|
|
1337
|
+
await mkdir(agentDir, { recursive: true });
|
|
1338
|
+
const logLine = JSON.stringify({
|
|
1339
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1340
|
+
event,
|
|
1341
|
+
...details
|
|
1342
|
+
});
|
|
1343
|
+
await appendFile(join(agentDir, "lifecycle.log"), `${logLine}\n`);
|
|
1344
|
+
}
|
|
1345
|
+
async function launchPanCommandDetached(input, dependencies = {}) {
|
|
1215
1346
|
const { agentSessionName, issueId, role, workspacePath, args } = input;
|
|
1216
1347
|
const cwd = input.cwd ?? workspacePath;
|
|
1217
|
-
const
|
|
1218
|
-
const
|
|
1348
|
+
const overdeckHome = dependencies.overdeckHome ?? getOverdeckHome();
|
|
1349
|
+
const activityId = input.activityId ?? `activity-${(dependencies.now ?? Date.now)()}`;
|
|
1350
|
+
const agentDir = resolveAgentDirectory(overdeckHome, agentSessionName);
|
|
1219
1351
|
await mkdir(agentDir, { recursive: true });
|
|
1220
1352
|
const spawnLogPath = join(agentDir, "spawn.log");
|
|
1221
1353
|
const spawnLogHandle = await open(spawnLogPath, "a");
|
|
1222
|
-
const
|
|
1223
|
-
const child =
|
|
1354
|
+
const spawnLogStart = (await spawnLogHandle.stat()).size;
|
|
1355
|
+
const child = (dependencies.spawnPanCli ?? spawnPanCli)(args, {
|
|
1224
1356
|
cwd,
|
|
1225
1357
|
detached: true,
|
|
1226
1358
|
stdio: [
|
|
1227
1359
|
"ignore",
|
|
1228
1360
|
spawnLogHandle.fd,
|
|
1229
1361
|
spawnLogHandle.fd
|
|
1230
|
-
]
|
|
1362
|
+
],
|
|
1363
|
+
env: {
|
|
1364
|
+
...process.env,
|
|
1365
|
+
...input.env
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
let spawned = false;
|
|
1369
|
+
let settleSpawn;
|
|
1370
|
+
let rejectSpawn;
|
|
1371
|
+
const spawnPromise = new Promise((resolve, reject) => {
|
|
1372
|
+
settleSpawn = resolve;
|
|
1373
|
+
rejectSpawn = reject;
|
|
1231
1374
|
});
|
|
1375
|
+
const completion = commandCompletion(child, {
|
|
1376
|
+
agentSessionName,
|
|
1377
|
+
issueId,
|
|
1378
|
+
role,
|
|
1379
|
+
workspacePath,
|
|
1380
|
+
activityId,
|
|
1381
|
+
args,
|
|
1382
|
+
cwd,
|
|
1383
|
+
spawnLogPath,
|
|
1384
|
+
spawnLogStart,
|
|
1385
|
+
spawnLogHandle,
|
|
1386
|
+
overdeckHome,
|
|
1387
|
+
onSpawn: () => {
|
|
1388
|
+
spawned = true;
|
|
1389
|
+
settleSpawn?.();
|
|
1390
|
+
},
|
|
1391
|
+
onError: (error) => {
|
|
1392
|
+
if (!spawned) rejectSpawn?.(error);
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
completion.catch(() => void 0);
|
|
1396
|
+
await spawnPromise;
|
|
1397
|
+
child.unref();
|
|
1398
|
+
return {
|
|
1399
|
+
activityId,
|
|
1400
|
+
spawnLogPath,
|
|
1401
|
+
spawnLogStart,
|
|
1402
|
+
completion
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
function commandCompletion(child, context) {
|
|
1232
1406
|
child.once("spawn", () => {
|
|
1233
|
-
appendAgentLifecycleLog(agentSessionName, "agent.work_spawn_process_spawned", {
|
|
1234
|
-
issueId,
|
|
1235
|
-
role,
|
|
1236
|
-
workspacePath,
|
|
1237
|
-
activityId,
|
|
1407
|
+
appendAgentLifecycleLog(context.agentSessionName, "agent.work_spawn_process_spawned", {
|
|
1408
|
+
issueId: context.issueId,
|
|
1409
|
+
role: context.role,
|
|
1410
|
+
workspacePath: context.workspacePath,
|
|
1411
|
+
activityId: context.activityId,
|
|
1238
1412
|
pid: child.pid,
|
|
1239
|
-
args,
|
|
1240
|
-
cwd,
|
|
1241
|
-
spawnLogPath
|
|
1242
|
-
}).catch(() => void 0);
|
|
1413
|
+
args: context.args,
|
|
1414
|
+
cwd: context.cwd,
|
|
1415
|
+
spawnLogPath: context.spawnLogPath
|
|
1416
|
+
}, context.overdeckHome).catch(() => void 0).finally(context.onSpawn);
|
|
1243
1417
|
});
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1418
|
+
return new Promise((resolve, reject) => {
|
|
1419
|
+
let settled = false;
|
|
1420
|
+
const finish = async (error) => {
|
|
1421
|
+
if (settled) return;
|
|
1422
|
+
settled = true;
|
|
1423
|
+
await context.spawnLogHandle.close().catch(() => void 0);
|
|
1424
|
+
if (error) reject(error);
|
|
1425
|
+
else resolve();
|
|
1426
|
+
};
|
|
1427
|
+
child.once("error", (error) => {
|
|
1428
|
+
(async () => {
|
|
1429
|
+
await appendAgentLifecycleLog(context.agentSessionName, "agent.work_spawn_process_error", {
|
|
1430
|
+
issueId: context.issueId,
|
|
1431
|
+
role: context.role,
|
|
1432
|
+
workspacePath: context.workspacePath,
|
|
1433
|
+
activityId: context.activityId,
|
|
1252
1434
|
error: error.message,
|
|
1253
|
-
args,
|
|
1254
|
-
cwd,
|
|
1255
|
-
spawnLogPath
|
|
1256
|
-
}).catch(() => void 0);
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1435
|
+
args: context.args,
|
|
1436
|
+
cwd: context.cwd,
|
|
1437
|
+
spawnLogPath: context.spawnLogPath
|
|
1438
|
+
}, context.overdeckHome).catch(() => void 0);
|
|
1439
|
+
context.onError(error);
|
|
1440
|
+
await finish(error);
|
|
1441
|
+
})();
|
|
1442
|
+
});
|
|
1443
|
+
child.once("close", (code, signal) => {
|
|
1444
|
+
(async () => {
|
|
1445
|
+
await appendAgentLifecycleLog(context.agentSessionName, "agent.work_spawn_process_closed", {
|
|
1446
|
+
issueId: context.issueId,
|
|
1447
|
+
role: context.role,
|
|
1448
|
+
workspacePath: context.workspacePath,
|
|
1449
|
+
activityId: context.activityId,
|
|
1265
1450
|
code,
|
|
1266
1451
|
signal,
|
|
1267
|
-
args,
|
|
1268
|
-
cwd,
|
|
1269
|
-
spawnLogPath
|
|
1270
|
-
}).catch(() => void 0);
|
|
1271
|
-
|
|
1452
|
+
args: context.args,
|
|
1453
|
+
cwd: context.cwd,
|
|
1454
|
+
spawnLogPath: context.spawnLogPath
|
|
1455
|
+
}, context.overdeckHome).catch(() => void 0);
|
|
1456
|
+
if (code === 0) {
|
|
1457
|
+
await finish();
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
const output = await readBoundedSpawnOutput(context.spawnLogPath, context.spawnLogStart).catch(() => "");
|
|
1461
|
+
const error = new Error(output.trim() || `pan ${context.args.join(" ")} exited with code ${code ?? "null"}`);
|
|
1462
|
+
Object.assign(error, {
|
|
1463
|
+
activityId: context.activityId,
|
|
1464
|
+
spawnLogPath: context.spawnLogPath,
|
|
1272
1465
|
code,
|
|
1273
|
-
signal
|
|
1466
|
+
signal,
|
|
1467
|
+
output
|
|
1274
1468
|
});
|
|
1275
|
-
|
|
1469
|
+
await finish(error);
|
|
1470
|
+
})();
|
|
1276
1471
|
});
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
async function runDetachedCommand(argv, dependencies = {}) {
|
|
1475
|
+
const issueId = argv[1] ?? "";
|
|
1476
|
+
const parsedIssueId = parseIssueIdSync(issueId);
|
|
1477
|
+
if (!parsedIssueId) return {
|
|
1478
|
+
kind: "terminal-only",
|
|
1479
|
+
status: "rejected",
|
|
1480
|
+
message: `/pan ${argv[0] ?? "command"} requires a canonical issue ID such as PAN-1525.`
|
|
1481
|
+
};
|
|
1482
|
+
const role = argv[0] === "plan" ? "plan" : "work";
|
|
1483
|
+
const agentSessionName = `${role === "plan" ? "planning" : "agent"}-${parsedIssueId.normalized}`;
|
|
1484
|
+
const command = `/pan ${argv.join(" ")}`;
|
|
1485
|
+
const activityId = `activity-${(dependencies.now ?? Date.now)()}`;
|
|
1486
|
+
const emitActivity = dependencies.emitActivity ?? emitActivityEntryDurable;
|
|
1487
|
+
const source = role === "plan" ? "planning-agent" : "work-agent";
|
|
1488
|
+
const emitTransition = (status, level, message, output) => emitActivity({
|
|
1489
|
+
id: activityId,
|
|
1490
|
+
source,
|
|
1491
|
+
level,
|
|
1492
|
+
status,
|
|
1493
|
+
command,
|
|
1494
|
+
message,
|
|
1495
|
+
details: output,
|
|
1496
|
+
output,
|
|
1497
|
+
issueId
|
|
1498
|
+
});
|
|
1499
|
+
await emitTransition("accepted", "info", `Accepted ${command} for ${issueId} as activity ${activityId}.`);
|
|
1500
|
+
let launch;
|
|
1501
|
+
try {
|
|
1502
|
+
launch = await launchPanCommandDetached({
|
|
1503
|
+
agentSessionName,
|
|
1504
|
+
issueId,
|
|
1505
|
+
role,
|
|
1506
|
+
workspacePath: process.cwd(),
|
|
1507
|
+
args: argv,
|
|
1508
|
+
activityId
|
|
1509
|
+
}, dependencies);
|
|
1510
|
+
} catch (error) {
|
|
1511
|
+
const output = error instanceof Error ? error.message : String(error);
|
|
1512
|
+
await emitTransition("failed", "error", `Activity ${activityId} failed to start ${command} for ${issueId}.`, output).catch(() => void 0);
|
|
1513
|
+
throw error;
|
|
1292
1514
|
}
|
|
1515
|
+
await emitTransition("running", "info", `Activity ${activityId} is running ${command} for ${issueId}.`).catch(() => void 0);
|
|
1516
|
+
launch.completion.then(async () => {
|
|
1517
|
+
const output = await readBoundedSpawnOutput(launch.spawnLogPath, launch.spawnLogStart).catch(() => "");
|
|
1518
|
+
await emitTransition("completed", "success", `Activity ${activityId} completed ${command} for ${issueId}.`, output || `Command ${command} completed without output.`);
|
|
1519
|
+
}, async (error) => {
|
|
1520
|
+
const activityError = error;
|
|
1521
|
+
const output = activityError.output?.trim() || activityError.message;
|
|
1522
|
+
await emitTransition("failed", "error", `Activity ${activityId} failed ${command} for ${issueId}.`, output);
|
|
1523
|
+
}).catch(() => void 0);
|
|
1524
|
+
return {
|
|
1525
|
+
kind: "activity",
|
|
1526
|
+
status: "accepted",
|
|
1527
|
+
command,
|
|
1528
|
+
activityId: launch.activityId,
|
|
1529
|
+
message: `Started ${command} for ${issueId}. Watch activity ${launch.activityId} or the ${issueId} issue view for progress.`
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
//#endregion
|
|
1533
|
+
//#region routes/agents/shared.ts
|
|
1534
|
+
init_paths();
|
|
1535
|
+
init_agents$1();
|
|
1536
|
+
init_activity_logger();
|
|
1537
|
+
init_tmux();
|
|
1538
|
+
const execAsync$2 = promisify(exec);
|
|
1539
|
+
const execFileAsync$2 = promisify(execFile);
|
|
1540
|
+
function buildPanStartArgs(input) {
|
|
1541
|
+
return [
|
|
1542
|
+
"start",
|
|
1543
|
+
input.issueId,
|
|
1544
|
+
"--local",
|
|
1545
|
+
"--model",
|
|
1546
|
+
input.model,
|
|
1547
|
+
...input.harness ? ["--harness", input.harness] : [],
|
|
1548
|
+
...input.allowHost ? ["--host", "--yes"] : [],
|
|
1549
|
+
...input.offBook ? ["--off-book"] : []
|
|
1550
|
+
];
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* PAN-1985: detached-spawn helper for `pan <args>`, shared between the
|
|
1554
|
+
* standard work-spawn route and the restart-fresh route. The neutral launcher
|
|
1555
|
+
* owns process/log lifecycle; this route-compatible wrapper preserves the
|
|
1556
|
+
* original behavior by waiting for a successful child exit.
|
|
1557
|
+
*/
|
|
1558
|
+
const INTERNAL_STARTED_BY_TOKENS = new Set([
|
|
1559
|
+
"operator:cli:pan-start",
|
|
1560
|
+
"operator:cli:pan-plan",
|
|
1561
|
+
"planning-auto-handoff",
|
|
1562
|
+
"orphan-proposed-reconciler",
|
|
1563
|
+
"workspace-rebuild-recovery",
|
|
1564
|
+
"resume-agent"
|
|
1565
|
+
]);
|
|
1566
|
+
function resolveRequestedStartedBy(value, internalRequest = false) {
|
|
1567
|
+
if (!internalRequest) return "operator:dashboard";
|
|
1568
|
+
const token = typeof value === "string" ? value.trim() : "";
|
|
1569
|
+
const flywheelRunId = token.startsWith("flywheel:") ? normalizeFlywheelRunId(token.slice(9)) : void 0;
|
|
1570
|
+
if (flywheelRunId) return `flywheel:${flywheelRunId}`;
|
|
1571
|
+
if (!INTERNAL_STARTED_BY_TOKENS.has(token)) throw new Error("Invalid internal startedBy provenance token.");
|
|
1572
|
+
return token;
|
|
1573
|
+
}
|
|
1574
|
+
async function isInternalAgentRequest(request) {
|
|
1575
|
+
const expected = await readInternalTokenForRequest();
|
|
1576
|
+
if (!expected) return false;
|
|
1577
|
+
return constantTimeTokenEqual(getHeaderFromMap(request.headers, INTERNAL_TOKEN_HEADER), expected);
|
|
1578
|
+
}
|
|
1579
|
+
async function spawnPanCommandDetached(input, dependencies = {}) {
|
|
1580
|
+
const launch = await launchPanCommandDetached(input, dependencies);
|
|
1581
|
+
await launch.completion;
|
|
1582
|
+
return launch.activityId;
|
|
1293
1583
|
}
|
|
1294
1584
|
function emitStartAgentPhase(issueId, phase, status, reason, details = {}) {
|
|
1295
1585
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1344,16 +1634,6 @@ async function validateAgentRuntimeEventAuth(request) {
|
|
|
1344
1634
|
}, { status: 403 })
|
|
1345
1635
|
};
|
|
1346
1636
|
}
|
|
1347
|
-
async function appendAgentLifecycleLog(agentId, event, details = {}) {
|
|
1348
|
-
const agentDir = join(homedir(), ".overdeck", "agents", agentId);
|
|
1349
|
-
await mkdir(agentDir, { recursive: true });
|
|
1350
|
-
const logLine = JSON.stringify({
|
|
1351
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1352
|
-
event,
|
|
1353
|
-
...details
|
|
1354
|
-
});
|
|
1355
|
-
await appendFile(join(agentDir, "lifecycle.log"), logLine + "\n");
|
|
1356
|
-
}
|
|
1357
1637
|
function updateRegistryForAgentStart(issueId, workspacePath, agentId) {
|
|
1358
1638
|
recordFeatureRegistryLifecycle({
|
|
1359
1639
|
issueId,
|
|
@@ -1434,8 +1714,10 @@ function buildStoppedAgentLifecycle(agentOrIssueId, state, runtimeData) {
|
|
|
1434
1714
|
const agentId = normalizeAgentId(agentOrIssueId);
|
|
1435
1715
|
const hasAgentState = true;
|
|
1436
1716
|
const hasLiveTmuxSession = false;
|
|
1437
|
-
const
|
|
1717
|
+
const sessionId = getLatestSessionIdSync(agentId) ?? runtimeData.claudeSessionId ?? null;
|
|
1718
|
+
const hasSavedSession = !!sessionId;
|
|
1438
1719
|
const hasWorkspace = typeof state.workspace === "string" && state.workspace.length > 0;
|
|
1720
|
+
const hasResumableTranscript = !sessionId || !!state.harness && state.harness !== "claude-code" || !state.workspace || claudeSessionTranscriptExists(state.workspace, sessionId);
|
|
1439
1721
|
const agentStatus = state.status || "unknown";
|
|
1440
1722
|
const runtime = runtimeData.state || "uninitialized";
|
|
1441
1723
|
const isCompleted = runtimeData.resolution === "completed";
|
|
@@ -1446,7 +1728,7 @@ function buildStoppedAgentLifecycle(agentOrIssueId, state, runtimeData) {
|
|
|
1446
1728
|
const isRunningButStuck = false;
|
|
1447
1729
|
const hasResumableBackingState = hasWorkspace && !isPlaceholder;
|
|
1448
1730
|
const isOrphaned = hasSavedSession && !hasResumableBackingState || !hasWorkspace || isPlaceholder;
|
|
1449
|
-
const requiresSessionResetBeforeFreshStart = hasSavedSession && hasResumableBackingState && (isStopped || isCrashed);
|
|
1731
|
+
const requiresSessionResetBeforeFreshStart = hasSavedSession && hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed);
|
|
1450
1732
|
let recommendedAction = "start";
|
|
1451
1733
|
let reason;
|
|
1452
1734
|
if (isOrphaned) {
|
|
@@ -1455,6 +1737,9 @@ function buildStoppedAgentLifecycle(agentOrIssueId, state, runtimeData) {
|
|
|
1455
1737
|
} else if (requiresSessionResetBeforeFreshStart) {
|
|
1456
1738
|
recommendedAction = "resume";
|
|
1457
1739
|
reason = `Agent ${agentId} has a resumable Claude session. Use 'pan resume ${agentOrIssueId}' to continue it, or 'pan start ${agentOrIssueId} --fresh' to start a new session (e.g. to switch model).`;
|
|
1740
|
+
} else if (hasSavedSession && !hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed)) {
|
|
1741
|
+
recommendedAction = "start";
|
|
1742
|
+
reason = `Agent ${agentId} has a saved Claude session id but its transcript is missing on disk (jsonl-missing). Start Agent will create a fresh session in the existing workspace.`;
|
|
1458
1743
|
} else if (!hasSavedSession && isStopped) {
|
|
1459
1744
|
recommendedAction = "start";
|
|
1460
1745
|
reason = `Agent ${agentId} is stopped and has no saved Claude session. Start Agent will create a fresh session in the existing workspace.`;
|
|
@@ -1464,6 +1749,7 @@ function buildStoppedAgentLifecycle(agentOrIssueId, state, runtimeData) {
|
|
|
1464
1749
|
hasAgentState,
|
|
1465
1750
|
hasLiveTmuxSession,
|
|
1466
1751
|
hasSavedSession,
|
|
1752
|
+
hasResumableTranscript,
|
|
1467
1753
|
hasWorkspace,
|
|
1468
1754
|
isPlaceholder,
|
|
1469
1755
|
isOrphaned,
|
|
@@ -1475,9 +1761,9 @@ function buildStoppedAgentLifecycle(agentOrIssueId, state, runtimeData) {
|
|
|
1475
1761
|
runtimeState: runtime,
|
|
1476
1762
|
agentStatus,
|
|
1477
1763
|
canStartFresh: !requiresSessionResetBeforeFreshStart || isOrphaned,
|
|
1478
|
-
canResumeSession: hasSavedSession && hasResumableBackingState && (isStopped || isCrashed),
|
|
1764
|
+
canResumeSession: hasSavedSession && hasResumableTranscript && hasResumableBackingState && (isStopped || isCrashed),
|
|
1479
1765
|
canRestartWithContext: hasWorkspace,
|
|
1480
|
-
canResetSession: hasSavedSession && hasResumableBackingState,
|
|
1766
|
+
canResetSession: hasSavedSession && hasResumableTranscript && hasResumableBackingState,
|
|
1481
1767
|
requiresSessionResetBeforeFreshStart,
|
|
1482
1768
|
recommendedAction,
|
|
1483
1769
|
reason
|
|
@@ -1537,13 +1823,14 @@ async function getWorkspaceLocation(issueId) {
|
|
|
1537
1823
|
}
|
|
1538
1824
|
} catch {}
|
|
1539
1825
|
}
|
|
1540
|
-
async function getGitStatusAsync(workspacePath) {
|
|
1826
|
+
async function getGitStatusAsync(issueId, workspacePath) {
|
|
1541
1827
|
try {
|
|
1542
1828
|
if (!existsSync(workspacePath)) return null;
|
|
1829
|
+
const repoDir = resolvePrimaryWorkspaceRepoDirSync(issueId, workspacePath);
|
|
1543
1830
|
const [branchResult, uncommittedResult, commitResult] = await Promise.all([
|
|
1544
|
-
execAsync$2("git rev-parse --abbrev-ref HEAD 2>/dev/null || echo \"\"", { cwd:
|
|
1545
|
-
execAsync$2("git status --porcelain 2>/dev/null | wc -l", { cwd:
|
|
1546
|
-
execAsync$2("git log -1 --pretty=format:\"%s\" 2>/dev/null || echo \"\"", { cwd:
|
|
1831
|
+
execAsync$2("git rev-parse --abbrev-ref HEAD 2>/dev/null || echo \"\"", { cwd: repoDir }),
|
|
1832
|
+
execAsync$2("git status --porcelain 2>/dev/null | wc -l", { cwd: repoDir }),
|
|
1833
|
+
execAsync$2("git log -1 --pretty=format:\"%s\" 2>/dev/null || echo \"\"", { cwd: repoDir })
|
|
1547
1834
|
]);
|
|
1548
1835
|
const branch = branchResult.stdout.trim();
|
|
1549
1836
|
const uncommitted = uncommittedResult.stdout.trim();
|
|
@@ -1700,6 +1987,22 @@ const getAgentPendingQuestions = getAgentPendingQuestions$1;
|
|
|
1700
1987
|
//#region routes/agents/listing.ts
|
|
1701
1988
|
init_agents$1();
|
|
1702
1989
|
init_tmux();
|
|
1990
|
+
/**
|
|
1991
|
+
* PAN-3070 — the health status a live agent row reports.
|
|
1992
|
+
*
|
|
1993
|
+
* A live tmux session used to mean `healthy` unconditionally, so an agent frozen
|
|
1994
|
+
* for hours on an unanswered tool-permission prompt was reported
|
|
1995
|
+
* `status: healthy` / `resolution: working` while the Decisions surface
|
|
1996
|
+
* simultaneously showed it as needing the operator. Two surfaces answering "is
|
|
1997
|
+
* this agent stuck?" from different evidence, and this one stale.
|
|
1998
|
+
*
|
|
1999
|
+
* `warning` is the value `src/lib/health.ts` already reports for an agent
|
|
2000
|
+
* waiting on a human, and it stays inside the fleet-view status set, so a
|
|
2001
|
+
* blocked agent is flagged without disappearing from any existing list.
|
|
2002
|
+
*/
|
|
2003
|
+
function liveAgentHealthStatus(enrichment) {
|
|
2004
|
+
return isBlockedOnPendingInput(enrichment) ? "warning" : "healthy";
|
|
2005
|
+
}
|
|
1703
2006
|
const getAgentsRoute = HttpRouter.add("GET", "/api/agents", httpHandler(Effect.gen(function* () {
|
|
1704
2007
|
const now = Date.now();
|
|
1705
2008
|
if (agentsCache.data && now - agentsCache.timestamp < 5e3) return jsonResponse(agentsCache.data);
|
|
@@ -1833,7 +2136,7 @@ const getAgentsRoute = HttpRouter.add("GET", "/api/agents", httpHandler(Effect.g
|
|
|
1833
2136
|
const enrichment = await Effect.runPromise(computeAgentEnrichment(name, startedAt, hasActiveSpecialist));
|
|
1834
2137
|
const workspaceLocation = isRemote ? "remote" : await getWorkspaceLocation(issueId);
|
|
1835
2138
|
const workspace = isRemote && remoteState.vmName ? `/workspace (${String(remoteState.vmName)})` : state.workspace || null;
|
|
1836
|
-
const gitStatus = workspace && !isRemote ? await getGitStatusAsync(workspace) : null;
|
|
2139
|
+
const gitStatus = workspace && !isRemote ? await getGitStatusAsync(issueId, workspace) : null;
|
|
1837
2140
|
let contextPercent = null;
|
|
1838
2141
|
let initialContextPercent = null;
|
|
1839
2142
|
const agentCtxDir = join(homedir(), ".overdeck", "agents", name);
|
|
@@ -1843,12 +2146,13 @@ const getAgentsRoute = HttpRouter.add("GET", "/api/agents", httpHandler(Effect.g
|
|
|
1843
2146
|
const initCtxFile = join(agentCtxDir, "initial-context-pct");
|
|
1844
2147
|
initialContextPercent = parseInt((await readFile(initCtxFile, "utf-8").catch(() => "")).trim(), 10) || null;
|
|
1845
2148
|
} catch {}
|
|
2149
|
+
const blockedOnPendingInput = isBlockedOnPendingInput(enrichment);
|
|
1846
2150
|
return {
|
|
1847
2151
|
id: name,
|
|
1848
2152
|
issueId,
|
|
1849
2153
|
runtime: state.harness ?? "claude-code",
|
|
1850
2154
|
model: state.model || (isPlanning ? "opus" : "sonnet"),
|
|
1851
|
-
status:
|
|
2155
|
+
status: liveAgentHealthStatus(enrichment),
|
|
1852
2156
|
startedAt,
|
|
1853
2157
|
...buildAgentGateFailureSnapshot(state),
|
|
1854
2158
|
killCount: health.killCount || 0,
|
|
@@ -1865,7 +2169,7 @@ const getAgentsRoute = HttpRouter.add("GET", "/api/agents", httpHandler(Effect.g
|
|
|
1865
2169
|
pendingInputCount: enrichment.pendingInputCount,
|
|
1866
2170
|
pendingInputKinds: enrichment.pendingInputKinds,
|
|
1867
2171
|
pendingAskUserQuestion: enrichment.pendingAskUserQuestion,
|
|
1868
|
-
resolution: runtimeData?.resolution || enrichment.resolution || "working",
|
|
2172
|
+
resolution: blockedOnPendingInput ? "needs_input" : runtimeData?.resolution || enrichment.resolution || "working",
|
|
1869
2173
|
resolutionCount: runtimeData?.resolutionCount || enrichment.resolutionCount || 0,
|
|
1870
2174
|
contextPercent,
|
|
1871
2175
|
initialContextPercent,
|
|
@@ -1951,7 +2255,7 @@ const getAgentOutputRoute = HttpRouter.add("GET", "/api/agents/:id/output", http
|
|
|
1951
2255
|
} catch {}
|
|
1952
2256
|
let stdout;
|
|
1953
2257
|
if (isRemote && vmName) {
|
|
1954
|
-
const { getRemoteAgentOutput } = await import("./remote-agents-
|
|
2258
|
+
const { getRemoteAgentOutput } = await import("./remote-agents-CLZB3Coc.js");
|
|
1955
2259
|
stdout = await getRemoteAgentOutput(id, vmName, parseInt(String(lines), 10) || 100);
|
|
1956
2260
|
} else stdout = await Effect.runPromise(capturePane(id, parseInt(String(lines), 10) || 100));
|
|
1957
2261
|
if (!stdout || stdout.trim() === "" || stdout.trim() === "Session not found") {
|
|
@@ -2104,6 +2408,352 @@ const getAgentTimelineRoute = HttpRouter.add("GET", "/api/agents/:id/timeline",
|
|
|
2104
2408
|
return jsonResponse({ timeline: events.slice(0, limit) });
|
|
2105
2409
|
})));
|
|
2106
2410
|
//#endregion
|
|
2411
|
+
//#region ../../lib/composer-commands/confirmations.ts
|
|
2412
|
+
const COMPOSER_CONFIRMATION_TTL_MS = 300 * 1e3;
|
|
2413
|
+
function composerCommandConfirmationFromBody(body) {
|
|
2414
|
+
if (!("confirmationNonce" in body) && !("confirmationText" in body)) return void 0;
|
|
2415
|
+
return {
|
|
2416
|
+
nonce: body["confirmationNonce"],
|
|
2417
|
+
typedText: body["confirmationText"]
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
var ComposerCommandConfirmationError = class extends Error {
|
|
2421
|
+
code = "invalid-confirmation";
|
|
2422
|
+
constructor(message) {
|
|
2423
|
+
super(message);
|
|
2424
|
+
this.name = "ComposerCommandConfirmationError";
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
function createComposerConfirmationStore(dependencies = {}) {
|
|
2428
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2429
|
+
const now = dependencies.now ?? Date.now;
|
|
2430
|
+
const createNonce = dependencies.createNonce ?? (() => randomBytes(24).toString("base64url"));
|
|
2431
|
+
function pruneExpired() {
|
|
2432
|
+
const currentTime = now();
|
|
2433
|
+
for (const [nonce, entry] of entries) if (entry.expiresAt <= currentTime) entries.delete(nonce);
|
|
2434
|
+
}
|
|
2435
|
+
return {
|
|
2436
|
+
issue({ target, argv, policy, display }) {
|
|
2437
|
+
if (policy.safety === "destructive" && !policy.typedConfirmation) throw new Error(`Destructive composer policy for ${display} must define typedConfirmation.`);
|
|
2438
|
+
pruneExpired();
|
|
2439
|
+
const nonce = createNonce();
|
|
2440
|
+
entries.set(nonce, {
|
|
2441
|
+
targetKind: target.kind,
|
|
2442
|
+
targetId: target.id,
|
|
2443
|
+
argv: [...argv],
|
|
2444
|
+
safety: policy.safety,
|
|
2445
|
+
typedText: policy.typedConfirmation,
|
|
2446
|
+
expiresAt: now() + COMPOSER_CONFIRMATION_TTL_MS
|
|
2447
|
+
});
|
|
2448
|
+
return {
|
|
2449
|
+
kind: "confirmation",
|
|
2450
|
+
status: "confirmation_required",
|
|
2451
|
+
nonce,
|
|
2452
|
+
consequence: policy.confirmationText ?? `Running ${display} requires confirmation before Overdeck continues.`,
|
|
2453
|
+
...policy.typedConfirmation ? { typedText: policy.typedConfirmation } : {}
|
|
2454
|
+
};
|
|
2455
|
+
},
|
|
2456
|
+
consume({ target, argv, policy, confirmation }) {
|
|
2457
|
+
if (typeof confirmation.nonce !== "string") throw new ComposerCommandConfirmationError("A valid confirmation nonce is required before this command can run.");
|
|
2458
|
+
const entry = entries.get(confirmation.nonce);
|
|
2459
|
+
entries.delete(confirmation.nonce);
|
|
2460
|
+
if (!entry) throw new ComposerCommandConfirmationError("This command confirmation is missing, invalid, or has already been used. Request a new confirmation and try again.");
|
|
2461
|
+
if (entry.expiresAt <= now()) throw new ComposerCommandConfirmationError("This command confirmation has expired. Request a new confirmation and try again.");
|
|
2462
|
+
if (entry.targetKind !== target.kind || entry.targetId !== target.id || entry.safety !== policy.safety || !sameArgv(entry.argv, argv)) throw new ComposerCommandConfirmationError("This command confirmation does not match the current target or command. Request a new confirmation and try again.");
|
|
2463
|
+
if (policy.safety === "destructive" && (typeof confirmation.typedText !== "string" || confirmation.typedText !== entry.typedText)) throw new ComposerCommandConfirmationError(`Type "${entry.typedText ?? ""}" exactly to confirm this destructive command.`);
|
|
2464
|
+
}
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
function sameArgv(left, right) {
|
|
2468
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
2469
|
+
}
|
|
2470
|
+
const composerConfirmationStore = createComposerConfirmationStore();
|
|
2471
|
+
//#endregion
|
|
2472
|
+
//#region ../../lib/composer-commands/parser.ts
|
|
2473
|
+
var ComposerCommandParseError = class extends Error {
|
|
2474
|
+
constructor(code, message, token, expected) {
|
|
2475
|
+
super(message);
|
|
2476
|
+
this.code = code;
|
|
2477
|
+
this.token = token;
|
|
2478
|
+
this.expected = expected;
|
|
2479
|
+
this.name = "ComposerCommandParseError";
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
const FORBIDDEN_TOKEN = /\$\(|[;|&<>`]/;
|
|
2483
|
+
function expectedSyntax(entry) {
|
|
2484
|
+
const args = entry.args.map((argument) => {
|
|
2485
|
+
const name = argument.variadic ? `${argument.name}...` : argument.name;
|
|
2486
|
+
return argument.required ? `<${name}>` : `[${name}]`;
|
|
2487
|
+
});
|
|
2488
|
+
const options = entry.options.length > 0 ? ["[options]"] : [];
|
|
2489
|
+
return [
|
|
2490
|
+
entry.display,
|
|
2491
|
+
...args,
|
|
2492
|
+
...options
|
|
2493
|
+
].join(" ");
|
|
2494
|
+
}
|
|
2495
|
+
function tokenize(input) {
|
|
2496
|
+
const tokens = [];
|
|
2497
|
+
let current = "";
|
|
2498
|
+
let quote = null;
|
|
2499
|
+
let escaped = false;
|
|
2500
|
+
const pushCurrent = () => {
|
|
2501
|
+
if (current.length === 0) return;
|
|
2502
|
+
tokens.push(current);
|
|
2503
|
+
current = "";
|
|
2504
|
+
};
|
|
2505
|
+
for (const character of input) {
|
|
2506
|
+
if (escaped) {
|
|
2507
|
+
current += character;
|
|
2508
|
+
escaped = false;
|
|
2509
|
+
continue;
|
|
2510
|
+
}
|
|
2511
|
+
if (character === "\\") {
|
|
2512
|
+
escaped = true;
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2515
|
+
if (quote !== null) {
|
|
2516
|
+
if (character === quote) quote = null;
|
|
2517
|
+
else current += character;
|
|
2518
|
+
continue;
|
|
2519
|
+
}
|
|
2520
|
+
if (character === "\"" || character === "'") {
|
|
2521
|
+
quote = character;
|
|
2522
|
+
continue;
|
|
2523
|
+
}
|
|
2524
|
+
if (/\s/.test(character)) {
|
|
2525
|
+
pushCurrent();
|
|
2526
|
+
continue;
|
|
2527
|
+
}
|
|
2528
|
+
current += character;
|
|
2529
|
+
}
|
|
2530
|
+
if (escaped) current += "\\";
|
|
2531
|
+
if (quote !== null) throw new ComposerCommandParseError("missing-argument", `Unclosed ${quote} quote. Close the quoted value before submitting the command.`, quote, `a closing ${quote}`);
|
|
2532
|
+
pushCurrent();
|
|
2533
|
+
return tokens;
|
|
2534
|
+
}
|
|
2535
|
+
function aliasesForPath(entry) {
|
|
2536
|
+
let candidates = [[]];
|
|
2537
|
+
for (let index = 0; index < entry.path.length; index += 1) {
|
|
2538
|
+
const prefix = entry.path.slice(0, index + 1);
|
|
2539
|
+
const prefixEntry = COMPOSER_COMMAND_MANIFEST.find((candidate) => candidate.path.length === prefix.length && candidate.path.every((part, partIndex) => part === prefix[partIndex]));
|
|
2540
|
+
const names = [entry.path[index], ...prefixEntry?.aliases ?? []];
|
|
2541
|
+
candidates = candidates.flatMap((candidate) => names.map((name) => [...candidate, name]));
|
|
2542
|
+
}
|
|
2543
|
+
return candidates;
|
|
2544
|
+
}
|
|
2545
|
+
function resolveEntry(tokens) {
|
|
2546
|
+
const match = COMPOSER_COMMAND_MANIFEST.flatMap((entry) => aliasesForPath(entry).filter((path) => path.every((part, index) => tokens[index] === part)).map((path) => ({
|
|
2547
|
+
entry,
|
|
2548
|
+
pathLength: path.length
|
|
2549
|
+
}))).sort((left, right) => right.pathLength - left.pathLength)[0];
|
|
2550
|
+
if (match) return match;
|
|
2551
|
+
const token = tokens[0] ?? "";
|
|
2552
|
+
throw new ComposerCommandParseError("unknown-command", token ? `Unknown Overdeck command "${token}". Type /pan to list available commands.` : "Missing an Overdeck command after /pan. Type /pan to list available commands.", token, "/pan <command>");
|
|
2553
|
+
}
|
|
2554
|
+
function optionDefinitions(entry) {
|
|
2555
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2556
|
+
for (const option of entry.options) {
|
|
2557
|
+
const flags = option.flags.split(/[ ,|]+/).filter((part) => part.startsWith("-"));
|
|
2558
|
+
const canonicalFlag = flags.find((flag) => flag.startsWith("--")) ?? flags[0];
|
|
2559
|
+
for (const flag of flags) definitions.set(flag, {
|
|
2560
|
+
option,
|
|
2561
|
+
canonicalFlag
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
return definitions;
|
|
2565
|
+
}
|
|
2566
|
+
function splitFlag(token) {
|
|
2567
|
+
const separator = token.indexOf("=");
|
|
2568
|
+
if (separator === -1) return { flag: token };
|
|
2569
|
+
return {
|
|
2570
|
+
flag: token.slice(0, separator),
|
|
2571
|
+
inlineValue: token.slice(separator + 1)
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
function parseOverdeckComposerCommand(message) {
|
|
2575
|
+
if (!/^\/pan(?:\s|$)/.test(message)) return null;
|
|
2576
|
+
const forbidden = message.match(FORBIDDEN_TOKEN)?.[0];
|
|
2577
|
+
if (forbidden !== void 0) throw new ComposerCommandParseError("forbidden-token", `The token "${forbidden}" is not allowed in /pan commands. Run compound shell syntax in a terminal instead.`, forbidden, "plain arguments without shell operators");
|
|
2578
|
+
const tokens = tokenize(message.slice(4).trim());
|
|
2579
|
+
const { entry, pathLength } = resolveEntry(tokens);
|
|
2580
|
+
const remaining = tokens.slice(pathLength);
|
|
2581
|
+
const definitions = optionDefinitions(entry);
|
|
2582
|
+
const positionals = [];
|
|
2583
|
+
const flags = [];
|
|
2584
|
+
for (let index = 0; index < remaining.length; index += 1) {
|
|
2585
|
+
const token = remaining[index];
|
|
2586
|
+
if (!token.startsWith("-")) {
|
|
2587
|
+
positionals.push(token);
|
|
2588
|
+
continue;
|
|
2589
|
+
}
|
|
2590
|
+
const { flag, inlineValue } = splitFlag(token);
|
|
2591
|
+
const definition = definitions.get(flag);
|
|
2592
|
+
if (definition === void 0) throw new ComposerCommandParseError("unknown-flag", `Unknown flag "${flag}" for ${entry.display}. Expected syntax: ${expectedSyntax(entry)}.`, flag, expectedSyntax(entry));
|
|
2593
|
+
flags.push(definition.canonicalFlag);
|
|
2594
|
+
if (definition.option.valueHint === null) {
|
|
2595
|
+
if (inlineValue !== void 0) throw new ComposerCommandParseError("unknown-flag", `Flag "${flag}" does not accept a value. Expected syntax: ${expectedSyntax(entry)}.`, token, expectedSyntax(entry));
|
|
2596
|
+
continue;
|
|
2597
|
+
}
|
|
2598
|
+
if (inlineValue !== void 0) {
|
|
2599
|
+
if (inlineValue.length === 0 && definition.option.required) throw new ComposerCommandParseError("missing-argument", `Flag "${flag}" requires <${definition.option.valueHint}>. Expected syntax: ${expectedSyntax(entry)}.`, flag, expectedSyntax(entry));
|
|
2600
|
+
if (inlineValue.length > 0) flags.push(inlineValue);
|
|
2601
|
+
continue;
|
|
2602
|
+
}
|
|
2603
|
+
const next = remaining[index + 1];
|
|
2604
|
+
const nextIsFlag = next?.startsWith("-") === true;
|
|
2605
|
+
if (definition.option.required && (next === void 0 || nextIsFlag)) throw new ComposerCommandParseError("missing-argument", `Flag "${flag}" requires <${definition.option.valueHint}>. Expected syntax: ${expectedSyntax(entry)}.`, flag, expectedSyntax(entry));
|
|
2606
|
+
if (next !== void 0 && !nextIsFlag) {
|
|
2607
|
+
flags.push(next);
|
|
2608
|
+
index += 1;
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
if (!(entry.args.at(-1)?.variadic === true) && positionals.length > entry.args.length) {
|
|
2612
|
+
const token = positionals[entry.args.length];
|
|
2613
|
+
throw new ComposerCommandParseError("unknown-command", `Unexpected token "${token}" for ${entry.display}. Expected syntax: ${expectedSyntax(entry)}.`, token, expectedSyntax(entry));
|
|
2614
|
+
}
|
|
2615
|
+
const missing = entry.args.find((argument, index) => argument.required && positionals[index] === void 0);
|
|
2616
|
+
if (missing !== void 0) throw new ComposerCommandParseError("missing-argument", `Missing required argument <${missing.name}> for ${entry.display}. Expected syntax: ${expectedSyntax(entry)}.`, missing.name, expectedSyntax(entry));
|
|
2617
|
+
return {
|
|
2618
|
+
entry,
|
|
2619
|
+
argv: [
|
|
2620
|
+
...entry.path,
|
|
2621
|
+
...positionals,
|
|
2622
|
+
...flags
|
|
2623
|
+
]
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
//#endregion
|
|
2627
|
+
//#region ../../lib/composer-commands/policy.ts
|
|
2628
|
+
init_src();
|
|
2629
|
+
const COMPOSER_COMMAND_POLICIES = {
|
|
2630
|
+
start: {
|
|
2631
|
+
mode: "detached",
|
|
2632
|
+
safety: "safe"
|
|
2633
|
+
},
|
|
2634
|
+
plan: {
|
|
2635
|
+
mode: "detached",
|
|
2636
|
+
safety: "safe"
|
|
2637
|
+
},
|
|
2638
|
+
show: {
|
|
2639
|
+
mode: "captured",
|
|
2640
|
+
safety: "safe"
|
|
2641
|
+
},
|
|
2642
|
+
status: {
|
|
2643
|
+
mode: "captured",
|
|
2644
|
+
safety: "safe"
|
|
2645
|
+
},
|
|
2646
|
+
tell: {
|
|
2647
|
+
mode: "captured",
|
|
2648
|
+
safety: "safe"
|
|
2649
|
+
},
|
|
2650
|
+
handoff: {
|
|
2651
|
+
mode: "ui",
|
|
2652
|
+
safety: "dialog",
|
|
2653
|
+
uiAction: "handoff",
|
|
2654
|
+
confirmationText: "This opens the handoff dialog for the selected conversation. Review the destination and focus before continuing."
|
|
2655
|
+
},
|
|
2656
|
+
fork: {
|
|
2657
|
+
mode: "ui",
|
|
2658
|
+
safety: "dialog",
|
|
2659
|
+
uiAction: "fork",
|
|
2660
|
+
confirmationText: "This opens the fork dialog for the selected conversation. Review the fork mode and destination before continuing."
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
const DEFAULT_POLICY = {
|
|
2664
|
+
mode: "terminal-only",
|
|
2665
|
+
safety: "safe"
|
|
2666
|
+
};
|
|
2667
|
+
function assertPolicyOverlayIntegrity(policies = COMPOSER_COMMAND_POLICIES, manifest = COMPOSER_COMMAND_MANIFEST) {
|
|
2668
|
+
for (const path of Object.keys(policies)) {
|
|
2669
|
+
const matches = manifest.filter((entry) => entry.path.join(" ") === path);
|
|
2670
|
+
if (matches.length !== 1) throw new Error(`Composer command policy path "${path}" must match exactly one manifest entry; found ${matches.length}.`);
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
function resolvePolicy(path) {
|
|
2674
|
+
return COMPOSER_COMMAND_POLICIES[path.join(" ")] ?? DEFAULT_POLICY;
|
|
2675
|
+
}
|
|
2676
|
+
assertPolicyOverlayIntegrity();
|
|
2677
|
+
//#endregion
|
|
2678
|
+
//#region ../../lib/composer-commands/router.ts
|
|
2679
|
+
const UI_COMMAND_PATTERNS = [{
|
|
2680
|
+
action: "handoff",
|
|
2681
|
+
pattern: /^\/(?:handoff|pan-handoff|pan\s+handoff)(?:\s+([\s\S]+))?$/i
|
|
2682
|
+
}, {
|
|
2683
|
+
action: "fork",
|
|
2684
|
+
pattern: /^\/pan\s+fork(?:\s+([\s\S]+))?$/i
|
|
2685
|
+
}];
|
|
2686
|
+
function isComposerCommandMessage(message) {
|
|
2687
|
+
return UI_COMMAND_PATTERNS.some(({ pattern }) => pattern.test(message)) || /^\/pan(?:\s|$)/.test(message);
|
|
2688
|
+
}
|
|
2689
|
+
async function handleComposerCommandMessage({ message, target, confirmation }, dependencies = {}) {
|
|
2690
|
+
for (const { action, pattern } of UI_COMMAND_PATTERNS) {
|
|
2691
|
+
const match = message.match(pattern);
|
|
2692
|
+
if (match) {
|
|
2693
|
+
const parsed = parseOverdeckComposerCommand(`/pan ${action}`);
|
|
2694
|
+
const focus = match[1]?.trim();
|
|
2695
|
+
if (focus) parsed.argv.push(focus);
|
|
2696
|
+
return handleComposerCommand({
|
|
2697
|
+
parsed,
|
|
2698
|
+
target,
|
|
2699
|
+
confirmation
|
|
2700
|
+
}, dependencies);
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
const parsed = parseOverdeckComposerCommand(message);
|
|
2704
|
+
if (parsed === null) return null;
|
|
2705
|
+
return handleComposerCommand({
|
|
2706
|
+
parsed,
|
|
2707
|
+
target,
|
|
2708
|
+
confirmation
|
|
2709
|
+
}, dependencies);
|
|
2710
|
+
}
|
|
2711
|
+
async function handleComposerCommand({ parsed, target, confirmation }, dependencies = {}) {
|
|
2712
|
+
const policy = (dependencies.resolvePolicy ?? resolvePolicy)(parsed.entry.path);
|
|
2713
|
+
if (policy.safety !== "safe") {
|
|
2714
|
+
const confirmationStore = dependencies.confirmationStore ?? composerConfirmationStore;
|
|
2715
|
+
if (confirmation === void 0) return confirmationStore.issue({
|
|
2716
|
+
target,
|
|
2717
|
+
argv: parsed.argv,
|
|
2718
|
+
policy,
|
|
2719
|
+
display: parsed.entry.display
|
|
2720
|
+
});
|
|
2721
|
+
confirmationStore.consume({
|
|
2722
|
+
target,
|
|
2723
|
+
argv: parsed.argv,
|
|
2724
|
+
policy,
|
|
2725
|
+
confirmation
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
if (policy.mode === "captured") return runCapturedCommand(parsed.argv);
|
|
2729
|
+
if (policy.mode === "detached") return runDetachedCommand(parsed.argv);
|
|
2730
|
+
if (policy.mode === "ui" && policy.uiAction) return uiCommandResult(policy.uiAction, parsed.argv.slice(parsed.entry.path.length).join(" ") || void 0);
|
|
2731
|
+
if (policy.mode === "terminal-only") return {
|
|
2732
|
+
kind: "terminal-only",
|
|
2733
|
+
status: "rejected",
|
|
2734
|
+
message: `${parsed.entry.display} must run in a terminal. Composer execution has not been enabled for this command.`
|
|
2735
|
+
};
|
|
2736
|
+
return missingExecutorResult(parsed.entry.display, policy);
|
|
2737
|
+
}
|
|
2738
|
+
function uiCommandResult(action, focus) {
|
|
2739
|
+
return {
|
|
2740
|
+
kind: "ui",
|
|
2741
|
+
status: "requires_ui",
|
|
2742
|
+
action,
|
|
2743
|
+
args: focus ? { focus } : {}
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
function missingExecutorResult(display, policy) {
|
|
2747
|
+
return {
|
|
2748
|
+
kind: "terminal-only",
|
|
2749
|
+
status: "rejected",
|
|
2750
|
+
message: `${display} is recognized as a ${policy.mode} command, but its composer executor is not registered yet. Run it in a terminal for now.`
|
|
2751
|
+
};
|
|
2752
|
+
}
|
|
2753
|
+
function composerCommandResultHttpStatus(result) {
|
|
2754
|
+
return result.kind === "terminal-only" ? 422 : 200;
|
|
2755
|
+
}
|
|
2756
|
+
//#endregion
|
|
2107
2757
|
//#region routes/agents/messaging.ts
|
|
2108
2758
|
init_agents$1();
|
|
2109
2759
|
async function sendAgentMessage(id, message) {
|
|
@@ -2119,6 +2769,55 @@ async function sendAgentMessage(id, message) {
|
|
|
2119
2769
|
remote: true
|
|
2120
2770
|
} : { success: true };
|
|
2121
2771
|
}
|
|
2772
|
+
async function handleAgentMessage(id, message, confirmation) {
|
|
2773
|
+
try {
|
|
2774
|
+
if (isComposerCommandMessage(message)) {
|
|
2775
|
+
let agentState;
|
|
2776
|
+
try {
|
|
2777
|
+
agentState = await Effect.runPromise(getAgentState(id));
|
|
2778
|
+
} catch {
|
|
2779
|
+
return jsonResponse({
|
|
2780
|
+
error: `Failed to resolve agent target: ${id}`,
|
|
2781
|
+
code: "agent-resolution-failed"
|
|
2782
|
+
}, { status: 503 });
|
|
2783
|
+
}
|
|
2784
|
+
if (!agentState) return jsonResponse({
|
|
2785
|
+
error: `Agent not found: ${id}`,
|
|
2786
|
+
code: "agent-not-found"
|
|
2787
|
+
}, { status: 404 });
|
|
2788
|
+
if (!agentState.harness) return jsonResponse({
|
|
2789
|
+
error: `Agent harness could not be resolved: ${id}`,
|
|
2790
|
+
code: "agent-harness-unresolved"
|
|
2791
|
+
}, { status: 503 });
|
|
2792
|
+
const result = await handleComposerCommandMessage({
|
|
2793
|
+
message,
|
|
2794
|
+
confirmation,
|
|
2795
|
+
target: {
|
|
2796
|
+
kind: "agent",
|
|
2797
|
+
id,
|
|
2798
|
+
harness: agentState.harness,
|
|
2799
|
+
cwd: agentState.workspace,
|
|
2800
|
+
issueId: agentState.issueId
|
|
2801
|
+
}
|
|
2802
|
+
});
|
|
2803
|
+
if (result !== null) return jsonResponse(result, { status: composerCommandResultHttpStatus(result) });
|
|
2804
|
+
}
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
if (error instanceof ComposerCommandConfirmationError) return jsonResponse({
|
|
2807
|
+
error: error.message,
|
|
2808
|
+
code: error.code
|
|
2809
|
+
}, { status: 422 });
|
|
2810
|
+
if (!(error instanceof ComposerCommandParseError)) throw error;
|
|
2811
|
+
const status = error.code === "unknown-command" ? 404 : error.code === "unknown-flag" ? 422 : 400;
|
|
2812
|
+
return jsonResponse({
|
|
2813
|
+
error: error.message,
|
|
2814
|
+
code: error.code,
|
|
2815
|
+
token: error.token,
|
|
2816
|
+
expected: error.expected
|
|
2817
|
+
}, { status });
|
|
2818
|
+
}
|
|
2819
|
+
return jsonResponse(await sendAgentMessage(id, message));
|
|
2820
|
+
}
|
|
2122
2821
|
function validateAgentMessageOrigin(request) {
|
|
2123
2822
|
const originCheck = validateOrigin(request);
|
|
2124
2823
|
if (!originCheck.ok) return {
|
|
@@ -2135,9 +2834,10 @@ function postAgentMessageLikeRoute(path) {
|
|
|
2135
2834
|
const originCheck = validateAgentMessageOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
2136
2835
|
if (!originCheck.ok) return originCheck.response;
|
|
2137
2836
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
2138
|
-
const
|
|
2837
|
+
const body = yield* readJsonBody$1;
|
|
2838
|
+
const { message } = body;
|
|
2139
2839
|
if (!message) return jsonResponse({ error: "Message required" }, { status: 400 });
|
|
2140
|
-
return yield* Effect.promise(() =>
|
|
2840
|
+
return yield* Effect.promise(() => handleAgentMessage(id, message, composerCommandConfirmationFromBody(body)));
|
|
2141
2841
|
})));
|
|
2142
2842
|
}
|
|
2143
2843
|
const postAgentMessageRoute = postAgentMessageLikeRoute("/api/agents/:id/message");
|
|
@@ -2386,7 +3086,7 @@ async function cleanupConversationAttachments(name) {
|
|
|
2386
3086
|
* sessions that the lifecycle poller missed. */
|
|
2387
3087
|
async function cleanupOrphanedConversationAttachments() {
|
|
2388
3088
|
try {
|
|
2389
|
-
const { listConversations } = await import("./conversations-
|
|
3089
|
+
const { listConversations } = await import("./conversations-BKDVpB-3.js");
|
|
2390
3090
|
const convNames = new Set(listConversations().map((c) => c.name));
|
|
2391
3091
|
const root = getConversationAttachmentsRoot();
|
|
2392
3092
|
await runInBatches((await readdir(root, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !convNames.has(entry.name)).map((entry) => join(root, entry.name)), 10, (path) => rm(path, {
|
|
@@ -2811,6 +3511,21 @@ async function handleConversationSwitchModel(name, body) {
|
|
|
2811
3511
|
function getPtySupervisorSocketPath(agentId) {
|
|
2812
3512
|
return join(getOverdeckHome(), "sockets", `pty-${agentId}.sock`);
|
|
2813
3513
|
}
|
|
3514
|
+
/**
|
|
3515
|
+
* Pull the supervisor's own failure out of the tmux pane it died in.
|
|
3516
|
+
*
|
|
3517
|
+
* A supervisor that cannot load its native node-pty exits instantly with an
|
|
3518
|
+
* ERR_MODULE_NOT_FOUND on stderr; all the spawn path sees is the socket that
|
|
3519
|
+
* never appeared. Reporting only the timeout hides the actual cause and sent
|
|
3520
|
+
* an operator hunting the memory governor instead (PAN-3172).
|
|
3521
|
+
*/
|
|
3522
|
+
function extractSupervisorFailure(paneText) {
|
|
3523
|
+
const lines = paneText.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
3524
|
+
const errors = lines.filter((line) => /error|cannot find|ERR_[A-Z_]+|pty-supervisor:/i.test(line));
|
|
3525
|
+
const chosen = (errors.length > 0 ? errors : lines).slice(-3);
|
|
3526
|
+
if (chosen.length === 0) return null;
|
|
3527
|
+
return chosen.join(" | ").slice(0, 500);
|
|
3528
|
+
}
|
|
2814
3529
|
async function waitForPtySupervisorSocket(agentId, timeoutMs = PTY_SUPERVISOR_SOCKET_WAIT_MS) {
|
|
2815
3530
|
const socketPath = getPtySupervisorSocketPath(agentId);
|
|
2816
3531
|
const start = Date.now();
|
|
@@ -2820,7 +3535,8 @@ async function waitForPtySupervisorSocket(agentId, timeoutMs = PTY_SUPERVISOR_SO
|
|
|
2820
3535
|
} catch {}
|
|
2821
3536
|
await new Promise((r) => setTimeout(r, 250));
|
|
2822
3537
|
}
|
|
2823
|
-
|
|
3538
|
+
const failure = extractSupervisorFailure(await capturePaneText(agentId, 40));
|
|
3539
|
+
throw new Error(`Timed out waiting for PTY supervisor socket ${socketPath}` + (failure ? ` — supervisor output: ${failure}` : ""));
|
|
2824
3540
|
}
|
|
2825
3541
|
async function extractModelFromSessionFile(sessionFile) {
|
|
2826
3542
|
try {
|
|
@@ -2980,7 +3696,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2980
3696
|
const codexApprovalPolicy = codexPermMode === "full-access" ? "never" : "on-request";
|
|
2981
3697
|
const codexSandboxMode = codexPermMode === "full-access" ? "danger-full-access" : codexPermMode === "read-only" ? "read-only" : "workspace-write";
|
|
2982
3698
|
const codexApprovalsReviewer = codexPermMode === "auto-review" ? "auto_review" : void 0;
|
|
2983
|
-
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-
|
|
3699
|
+
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-o8FJwzmy.js");
|
|
2984
3700
|
initCodexHome(codexHome, {
|
|
2985
3701
|
trustedDir: cwd,
|
|
2986
3702
|
approvalPolicy: codexApprovalPolicy,
|
|
@@ -3049,7 +3765,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
3049
3765
|
} catch {}
|
|
3050
3766
|
console.log(`[claude-invoke] purpose=conversation-session | model=${model || "default"} | source=conversations.ts:spawnConversationSession | session=${tmuxSession} | resume=${resume} | command="${runtimeCommand}"`);
|
|
3051
3767
|
try {
|
|
3052
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
3768
|
+
const { preTrustDirectory } = await import("./workspace-manager-C1F3XsnS.js");
|
|
3053
3769
|
preTrustDirectory(cwd);
|
|
3054
3770
|
} catch {}
|
|
3055
3771
|
try {
|
|
@@ -3066,7 +3782,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
3066
3782
|
const codexHomeDir = codexFields.codexHome;
|
|
3067
3783
|
(async () => {
|
|
3068
3784
|
try {
|
|
3069
|
-
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-
|
|
3785
|
+
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-o8FJwzmy.js");
|
|
3070
3786
|
const rollout = await waitForCodexRollout(codexHomeDir, 12e4);
|
|
3071
3787
|
if (rollout) {
|
|
3072
3788
|
const threadId = extractThreadIdFromRollout(rollout);
|
|
@@ -3208,6 +3924,7 @@ async function handleConversationResume(name, body, deps) {
|
|
|
3208
3924
|
});
|
|
3209
3925
|
}
|
|
3210
3926
|
const oldSessionId = conv.claudeSessionId;
|
|
3927
|
+
const resumeCause = conv.status === "ended" ? "operator" : "system";
|
|
3211
3928
|
const harness = conv.harness ?? "claude-code";
|
|
3212
3929
|
const modelChanged = !!model && model !== conv.model;
|
|
3213
3930
|
if (!await validateCwdContainment(conv.cwd)) return jsonResponse({ error: "Invalid cwd" }, { status: 400 });
|
|
@@ -3226,6 +3943,13 @@ async function handleConversationResume(name, body, deps) {
|
|
|
3226
3943
|
await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), model, effort, conv.issueId ?? void 0, canResume, harness);
|
|
3227
3944
|
await waitForTmuxSession(conv.tmuxSession);
|
|
3228
3945
|
await waitForConversationRuntimeReady(conv.tmuxSession, harness, "respawn");
|
|
3946
|
+
const resumeGatePane = await capturePaneText(conv.tmuxSession, 90).catch(() => "");
|
|
3947
|
+
if (resumeGatePane && paneHasBlockingChoiceMenu(resumeGatePane)) console.log(`[conversations] resume contract skipped for ${name} — the harness is showing a blocking choice menu; the operator answers it`);
|
|
3948
|
+
else try {
|
|
3949
|
+
await deliverAgentMessage(conv.tmuxSession, `CONVERSATION RESUME: ${buildResumeContract(resumeCause)}`, "conversation-resume", resolveConversationDeliveryMethod(conv));
|
|
3950
|
+
} catch (err) {
|
|
3951
|
+
console.error(`[conversations] resume contract delivery failed for ${name}:`, err instanceof Error ? err.message : String(err));
|
|
3952
|
+
}
|
|
3229
3953
|
markConversationActive(name);
|
|
3230
3954
|
return jsonResponse({
|
|
3231
3955
|
...conv,
|
|
@@ -3957,7 +4681,7 @@ const postInternalAgentPermissionRequestRoute = HttpRouter.add("POST", "/api/int
|
|
|
3957
4681
|
error: "missing agent id"
|
|
3958
4682
|
}, { status: 400 });
|
|
3959
4683
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
3960
|
-
const { INTERNAL_TOKEN_HEADER, getInternalTokenSync } = yield* Effect.promise(() => import("./internal-token-
|
|
4684
|
+
const { INTERNAL_TOKEN_HEADER, getInternalTokenSync } = yield* Effect.promise(() => import("./internal-token-Ias7N8Kg.js"));
|
|
3961
4685
|
const expected = getInternalTokenSync();
|
|
3962
4686
|
if (!expected) return jsonResponse({
|
|
3963
4687
|
ok: false,
|
|
@@ -4093,6 +4817,7 @@ const postAgentPermissionResponseRoute = HttpRouter.add("POST", "/api/agents/:id
|
|
|
4093
4817
|
* pollers (PAN-1134). Extracted from routes/agents.ts so Pi event polling
|
|
4094
4818
|
* can reuse bodyToEvent without importing a heavy route module.
|
|
4095
4819
|
*/
|
|
4820
|
+
init_src();
|
|
4096
4821
|
/**
|
|
4097
4822
|
* Translate a decoded body into an unsigned DomainEvent (no sequence yet).
|
|
4098
4823
|
* Returns null if the body doesn't map to a runtime event.
|
|
@@ -4213,6 +4938,25 @@ const bodyToEvent = (agentId, body, timestamp) => {
|
|
|
4213
4938
|
contextSaturatedAt: source["contextSaturatedAt"]
|
|
4214
4939
|
}
|
|
4215
4940
|
};
|
|
4941
|
+
case "linear_mcp_auth_required": return {
|
|
4942
|
+
type: "linear_mcp_auth.required",
|
|
4943
|
+
timestamp,
|
|
4944
|
+
payload: {
|
|
4945
|
+
agentId,
|
|
4946
|
+
issueId: source["issueId"] ?? null,
|
|
4947
|
+
authUrl: source["authUrl"] ?? null,
|
|
4948
|
+
expiresAt: source["expiresAt"] ?? null
|
|
4949
|
+
}
|
|
4950
|
+
};
|
|
4951
|
+
case "linear_mcp_auth_healthy": return {
|
|
4952
|
+
type: "linear_mcp_auth.healthy",
|
|
4953
|
+
timestamp,
|
|
4954
|
+
payload: {
|
|
4955
|
+
agentId,
|
|
4956
|
+
issueId: source["issueId"] ?? null,
|
|
4957
|
+
source: "hook"
|
|
4958
|
+
}
|
|
4959
|
+
};
|
|
4216
4960
|
default: return null;
|
|
4217
4961
|
}
|
|
4218
4962
|
};
|
|
@@ -4224,7 +4968,7 @@ const getAgentHealthHistoryRoute = HttpRouter.add("GET", "/api/agents/:id/health
|
|
|
4224
4968
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
4225
4969
|
const urlOpt = HttpServerRequest.toURL(request);
|
|
4226
4970
|
const hours = Option.isSome(urlOpt) ? urlOpt.value.searchParams.get("hours") ?? "24" : "24";
|
|
4227
|
-
const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-
|
|
4971
|
+
const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-2Z6Wa9SM.js"));
|
|
4228
4972
|
const endTime = /* @__PURE__ */ new Date();
|
|
4229
4973
|
const startTime = /* @__PURE__ */ new Date(endTime.getTime() - parseInt(hours) * 60 * 60 * 1e3);
|
|
4230
4974
|
const events = getHealthHistory(id, startTime.toISOString(), endTime.toISOString());
|
|
@@ -4237,9 +4981,18 @@ const getAgentHealthHistoryRoute = HttpRouter.add("GET", "/api/agents/:id/health
|
|
|
4237
4981
|
})));
|
|
4238
4982
|
function emitAgentRuntimeEvent(id, body, timestamp) {
|
|
4239
4983
|
return Effect.gen(function* () {
|
|
4984
|
+
let eventBody = body;
|
|
4985
|
+
if (body["kind"] === "linear_mcp_auth_required" || body["kind"] === "linear_mcp_auth_healthy") {
|
|
4986
|
+
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-C63p_ftq.js"));
|
|
4987
|
+
const snapshot = yield* (yield* AgentStateService).get(id);
|
|
4988
|
+
eventBody = {
|
|
4989
|
+
...body,
|
|
4990
|
+
issueId: snapshot?.currentIssue ?? null
|
|
4991
|
+
};
|
|
4992
|
+
}
|
|
4240
4993
|
let raw;
|
|
4241
4994
|
try {
|
|
4242
|
-
raw = bodyToEvent(id,
|
|
4995
|
+
raw = bodyToEvent(id, eventBody, timestamp);
|
|
4243
4996
|
} catch (error) {
|
|
4244
4997
|
return {
|
|
4245
4998
|
ok: false,
|
|
@@ -4265,7 +5018,7 @@ function emitAgentRuntimeEvent(id, body, timestamp) {
|
|
|
4265
5018
|
detail: String(decoded.failure)
|
|
4266
5019
|
}, { status: 400 })
|
|
4267
5020
|
};
|
|
4268
|
-
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-
|
|
5021
|
+
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-C63p_ftq.js"));
|
|
4269
5022
|
yield* (yield* AgentStateService).emit(decoded.success);
|
|
4270
5023
|
return {
|
|
4271
5024
|
ok: true,
|
|
@@ -4347,7 +5100,7 @@ const getAgentRuntimeRoute = HttpRouter.add("GET", "/api/agents/:id/runtime", ht
|
|
|
4347
5100
|
success: false,
|
|
4348
5101
|
error: "missing agent id"
|
|
4349
5102
|
}, { status: 400 });
|
|
4350
|
-
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-
|
|
5103
|
+
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-C63p_ftq.js"));
|
|
4351
5104
|
const snapshot = yield* (yield* AgentStateService).get(id);
|
|
4352
5105
|
if (!snapshot) return jsonResponse({
|
|
4353
5106
|
success: false,
|
|
@@ -4532,8 +5285,8 @@ function createAgentStopHandler(lifecycleEvent) {
|
|
|
4532
5285
|
yield* stopAgent(id);
|
|
4533
5286
|
if (stateBeforeStop?.issueId) yield* Effect.promise(async () => {
|
|
4534
5287
|
try {
|
|
4535
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
4536
|
-
const { findWorkspacePath } = await import("./archive-planning-
|
|
5288
|
+
const { resolveProjectFromIssueSync } = await import("./projects-_n3Zui6K.js");
|
|
5289
|
+
const { findWorkspacePath } = await import("./archive-planning-B2XplFzT.js");
|
|
4537
5290
|
const issueLower = stateBeforeStop.issueId.toLowerCase();
|
|
4538
5291
|
const workspacePath = findWorkspacePath(resolveProjectFromIssueSync(stateBeforeStop.issueId)?.projectPath ?? process.cwd(), issueLower);
|
|
4539
5292
|
if (workspacePath) {
|
|
@@ -4673,7 +5426,7 @@ const postAgentUnpauseRoute = HttpRouter.add("POST", "/api/agents/:id/unpause",
|
|
|
4673
5426
|
if ((yield* getWorkAgentLifecycleState(id)).canResumeSession && updatedState.troubled !== true) {
|
|
4674
5427
|
resumeTriggered = true;
|
|
4675
5428
|
yield* Effect.promise(() => appendAgentLifecycleLog(id, "agent.unpause_immediate_resume_triggered"));
|
|
4676
|
-
import("./resume-
|
|
5429
|
+
import("./resume-mOREjlYu.js").then(({ resumeAgent }) => resumeAgent(id)).then((result) => {
|
|
4677
5430
|
if (!result.success) console.warn(`[agents] immediate resume after unpause failed for ${id}: ${result.error}`);
|
|
4678
5431
|
}).catch((err) => console.warn(`[agents] immediate resume after unpause errored for ${id}:`, err));
|
|
4679
5432
|
}
|
|
@@ -5960,18 +6713,72 @@ const writeAutoStartXBrief = (projectRoot, workspacePath, issue) => Effect.tryPr
|
|
|
5960
6713
|
//#region routes/agents/spawn-helpers.ts
|
|
5961
6714
|
init_child_env();
|
|
5962
6715
|
init_agents$1();
|
|
6716
|
+
function buildAgentStartPlaceholder(input) {
|
|
6717
|
+
return {
|
|
6718
|
+
state: {
|
|
6719
|
+
id: input.agentSessionName,
|
|
6720
|
+
issueId: input.issueId,
|
|
6721
|
+
workspace: input.workspacePath,
|
|
6722
|
+
role: input.role,
|
|
6723
|
+
...input.effectiveHarness ? { harness: input.effectiveHarness } : {},
|
|
6724
|
+
model: "pending-work-spawn",
|
|
6725
|
+
status: "starting",
|
|
6726
|
+
startedAt: input.startedAt,
|
|
6727
|
+
startedBy: input.startedBy,
|
|
6728
|
+
hostOverride: input.allowHost || void 0
|
|
6729
|
+
},
|
|
6730
|
+
event: {
|
|
6731
|
+
type: "agent.started",
|
|
6732
|
+
timestamp: input.startedAt,
|
|
6733
|
+
payload: {
|
|
6734
|
+
agentId: input.agentSessionName,
|
|
6735
|
+
issueId: input.issueId,
|
|
6736
|
+
agent: {
|
|
6737
|
+
id: input.agentSessionName,
|
|
6738
|
+
issueId: input.issueId,
|
|
6739
|
+
workspace: input.workspacePath,
|
|
6740
|
+
status: "starting",
|
|
6741
|
+
startedAt: input.startedAt,
|
|
6742
|
+
role: input.role,
|
|
6743
|
+
startedBy: input.startedBy,
|
|
6744
|
+
...input.effectiveHarness ? { runtime: input.effectiveHarness } : {}
|
|
6745
|
+
}
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
};
|
|
6749
|
+
}
|
|
6750
|
+
function buildContainerStartState(input) {
|
|
6751
|
+
return {
|
|
6752
|
+
id: input.agentSessionName,
|
|
6753
|
+
issueId: input.issueId,
|
|
6754
|
+
...input.effectiveHarness ? { harness: input.effectiveHarness } : {},
|
|
6755
|
+
model: "pending-container-start",
|
|
6756
|
+
status: input.status,
|
|
6757
|
+
startedAt: input.startedAt,
|
|
6758
|
+
workspace: input.workspacePath,
|
|
6759
|
+
role: input.role,
|
|
6760
|
+
startedBy: input.startedBy,
|
|
6761
|
+
hostOverride: input.allowHost || void 0
|
|
6762
|
+
};
|
|
6763
|
+
}
|
|
6764
|
+
async function requestWorkStartAfterContainers(input) {
|
|
6765
|
+
const activityId = await input.spawnPanCommand(input.args, input.workspacePath);
|
|
6766
|
+
await input.markWorkStartAccepted();
|
|
6767
|
+
await input.updateIssueStatus();
|
|
6768
|
+
return activityId;
|
|
6769
|
+
}
|
|
5963
6770
|
function handleRemoteAgentSpawn(input) {
|
|
5964
6771
|
return Effect.gen(function* () {
|
|
5965
|
-
const { issueId, workspacePath, workspaceMetadata, spawnModel, projectPath, spawnGuardrails, lifecycle } = input;
|
|
5966
|
-
const { spawnRemoteAgent, checkRemoteSpendCap } = yield* Effect.promise(() => import("./remote-agents-
|
|
5967
|
-
const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-
|
|
5968
|
-
const { loadConfigSync: loadPanConfig } = yield* Effect.promise(() => import("./config-
|
|
6772
|
+
const { issueId, workspacePath, workspaceMetadata, spawnModel, startedBy, autoSpawnConsentRequired, projectPath, spawnGuardrails, lifecycle } = input;
|
|
6773
|
+
const { spawnRemoteAgent, checkRemoteSpendCap } = yield* Effect.promise(() => import("./remote-agents-CLZB3Coc.js"));
|
|
6774
|
+
const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-CUhyqjXk.js"));
|
|
6775
|
+
const { loadConfigSync: loadPanConfig } = yield* Effect.promise(() => import("./config-CL3Gyvja.js"));
|
|
5969
6776
|
const panConfig = loadPanConfig();
|
|
5970
6777
|
const spendCap = checkRemoteSpendCap(panConfig);
|
|
5971
6778
|
if (!spendCap.allowed) return jsonResponse({ error: spendCap.message }, { status: 429 });
|
|
5972
6779
|
const fly = createFlyProviderFromConfig(panConfig.remote);
|
|
5973
6780
|
yield* Effect.promise(() => fly.syncAllCredentials(workspaceMetadata.vmName));
|
|
5974
|
-
const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-
|
|
6781
|
+
const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-ByrPAzOy.js"));
|
|
5975
6782
|
const trackerContext = yield* Effect.promise(() => getTrackerContext(issueId, workspacePath));
|
|
5976
6783
|
const agentPrompt = yield* Effect.promise(() => buildWorkAgentPrompt({
|
|
5977
6784
|
issueId,
|
|
@@ -5989,6 +6796,8 @@ function handleRemoteAgentSpawn(input) {
|
|
|
5989
6796
|
workspace: workspaceMetadata,
|
|
5990
6797
|
prompt: agentPrompt,
|
|
5991
6798
|
model: spawnModel,
|
|
6799
|
+
startedBy,
|
|
6800
|
+
autoSpawnConsentRequired,
|
|
5992
6801
|
tier: fly.getResiliencyTier()
|
|
5993
6802
|
}));
|
|
5994
6803
|
yield* saveAgentState({
|
|
@@ -5999,7 +6808,8 @@ function handleRemoteAgentSpawn(input) {
|
|
|
5999
6808
|
model: spawnModel,
|
|
6000
6809
|
status: "starting",
|
|
6001
6810
|
startedAt: state.startedAt,
|
|
6002
|
-
harness: "claude-code"
|
|
6811
|
+
harness: "claude-code",
|
|
6812
|
+
startedBy
|
|
6003
6813
|
});
|
|
6004
6814
|
updateRegistryForAgentStart(state.issueId, workspacePath, state.id);
|
|
6005
6815
|
yield* Effect.promise(() => Effect.runPromise(lifecycle.transitionTo(issueId, "in_progress").pipe(Effect.catch(() => Effect.void))));
|
|
@@ -6011,7 +6821,8 @@ function handleRemoteAgentSpawn(input) {
|
|
|
6011
6821
|
model: spawnModel,
|
|
6012
6822
|
status: state.status,
|
|
6013
6823
|
startedAt: state.startedAt,
|
|
6014
|
-
harness: "claude-code"
|
|
6824
|
+
harness: "claude-code",
|
|
6825
|
+
startedBy
|
|
6015
6826
|
}, {
|
|
6016
6827
|
type: "agent.started",
|
|
6017
6828
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -6025,7 +6836,8 @@ function handleRemoteAgentSpawn(input) {
|
|
|
6025
6836
|
model: spawnModel,
|
|
6026
6837
|
status: state.status,
|
|
6027
6838
|
startedAt: state.startedAt,
|
|
6028
|
-
lastActivity: state.lastActivity
|
|
6839
|
+
lastActivity: state.lastActivity,
|
|
6840
|
+
startedBy
|
|
6029
6841
|
}
|
|
6030
6842
|
}
|
|
6031
6843
|
});
|
|
@@ -6053,7 +6865,7 @@ function handleRemoteAgentSpawn(input) {
|
|
|
6053
6865
|
}
|
|
6054
6866
|
function handleContainerOrchestration(input) {
|
|
6055
6867
|
return Effect.gen(function* () {
|
|
6056
|
-
const { issueId, workspacePath, devScript, agentSessionName, role, effectiveHarness, allowHost, spawnModel, spawnGuardrails, projectPath, eventStore, spawnPanCommand, updateIssueStatus } = input;
|
|
6868
|
+
const { issueId, workspacePath, devScript, agentSessionName, role, effectiveHarness, startedBy, allowHost, spawnModel, spawnGuardrails, projectPath, eventStore, spawnPanCommand, markWorkStartAccepted, updateIssueStatus } = input;
|
|
6057
6869
|
if (existsSync(workspacePath) && existsSync(devScript)) {
|
|
6058
6870
|
let dockerRunning = false;
|
|
6059
6871
|
try {
|
|
@@ -6122,17 +6934,17 @@ function handleContainerOrchestration(input) {
|
|
|
6122
6934
|
const earlyAgentId = agentSessionName;
|
|
6123
6935
|
const earlyStateDir = join(homedir(), ".overdeck", "agents", earlyAgentId);
|
|
6124
6936
|
yield* Effect.promise(() => mkdir(earlyStateDir, { recursive: true }));
|
|
6125
|
-
saveAgentStateSync({
|
|
6126
|
-
|
|
6937
|
+
saveAgentStateSync(buildContainerStartState({
|
|
6938
|
+
agentSessionName: earlyAgentId,
|
|
6127
6939
|
issueId,
|
|
6128
|
-
|
|
6129
|
-
model: "pending-container-start",
|
|
6130
|
-
status: "starting",
|
|
6131
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6132
|
-
workspace: workspacePath,
|
|
6940
|
+
workspacePath,
|
|
6133
6941
|
role,
|
|
6134
|
-
|
|
6135
|
-
|
|
6942
|
+
effectiveHarness,
|
|
6943
|
+
startedBy,
|
|
6944
|
+
allowHost,
|
|
6945
|
+
status: "starting",
|
|
6946
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6947
|
+
}));
|
|
6136
6948
|
updateRegistryForAgentStart(issueId, workspacePath, earlyAgentId);
|
|
6137
6949
|
yield* Effect.promise(() => appendAgentLifecycleLog(earlyAgentId, "agent.start_waiting_for_containers", {
|
|
6138
6950
|
issueId,
|
|
@@ -6190,16 +7002,17 @@ function handleContainerOrchestration(input) {
|
|
|
6190
7002
|
waitedMs: Date.now() - startTime
|
|
6191
7003
|
});
|
|
6192
7004
|
if (!healthy) {
|
|
6193
|
-
saveAgentStateSync({
|
|
6194
|
-
|
|
7005
|
+
saveAgentStateSync(buildContainerStartState({
|
|
7006
|
+
agentSessionName: earlyAgentId,
|
|
6195
7007
|
issueId,
|
|
6196
|
-
|
|
6197
|
-
|
|
7008
|
+
workspacePath,
|
|
7009
|
+
role,
|
|
7010
|
+
effectiveHarness,
|
|
7011
|
+
startedBy,
|
|
7012
|
+
allowHost,
|
|
6198
7013
|
status: "error",
|
|
6199
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6200
|
-
|
|
6201
|
-
role
|
|
6202
|
-
});
|
|
7014
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7015
|
+
}));
|
|
6203
7016
|
return;
|
|
6204
7017
|
}
|
|
6205
7018
|
for (const nmDir of [join(workspacePath, "node_modules"), join(workspacePath, "src", "dashboard", "frontend", "node_modules")]) try {
|
|
@@ -6224,14 +7037,19 @@ function handleContainerOrchestration(input) {
|
|
|
6224
7037
|
emitStartAgentPhase(issueId, "spawn", "start", "starting local work agent after containers became healthy", { workspacePath });
|
|
6225
7038
|
emitStartAgentPhase(issueId, "spawn", "success", "local work agent spawn requested after container startup", {
|
|
6226
7039
|
workspacePath,
|
|
6227
|
-
activityId: await
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
7040
|
+
activityId: await requestWorkStartAfterContainers({
|
|
7041
|
+
args: buildPanStartArgs({
|
|
7042
|
+
issueId,
|
|
7043
|
+
model: spawnModel,
|
|
7044
|
+
harness: effectiveHarness,
|
|
7045
|
+
allowHost
|
|
7046
|
+
}),
|
|
7047
|
+
workspacePath,
|
|
7048
|
+
spawnPanCommand,
|
|
7049
|
+
markWorkStartAccepted,
|
|
7050
|
+
updateIssueStatus
|
|
7051
|
+
})
|
|
6233
7052
|
});
|
|
6234
|
-
await updateIssueStatus();
|
|
6235
7053
|
} catch (err) {
|
|
6236
7054
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
6237
7055
|
emitStartAgentPhase(issueId, "spawn", "failure", errorMessage, { workspacePath });
|
|
@@ -6240,15 +7058,17 @@ function handleContainerOrchestration(input) {
|
|
|
6240
7058
|
error: errorMessage
|
|
6241
7059
|
}).catch(() => void 0);
|
|
6242
7060
|
try {
|
|
6243
|
-
saveAgentStateSync({
|
|
6244
|
-
|
|
7061
|
+
saveAgentStateSync(buildContainerStartState({
|
|
7062
|
+
agentSessionName: earlyAgentId,
|
|
6245
7063
|
issueId,
|
|
6246
|
-
|
|
7064
|
+
workspacePath,
|
|
7065
|
+
role,
|
|
7066
|
+
effectiveHarness,
|
|
7067
|
+
startedBy,
|
|
7068
|
+
allowHost,
|
|
6247
7069
|
status: "error",
|
|
6248
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6249
|
-
|
|
6250
|
-
role
|
|
6251
|
-
});
|
|
7070
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7071
|
+
}));
|
|
6252
7072
|
} catch {}
|
|
6253
7073
|
console.error(`[start-agent] Background container startup failed for ${issueId}:`, err);
|
|
6254
7074
|
}
|
|
@@ -6287,10 +7107,12 @@ function handleContainerOrchestration(input) {
|
|
|
6287
7107
|
//#endregion
|
|
6288
7108
|
//#region routes/agents/spawn.ts
|
|
6289
7109
|
init_agents$1();
|
|
7110
|
+
init_staffing();
|
|
6290
7111
|
init_operator_interventions();
|
|
6291
7112
|
init_child_env();
|
|
6292
7113
|
init_harness_policy();
|
|
6293
7114
|
init_activity_logger();
|
|
7115
|
+
init_issue_id();
|
|
6294
7116
|
init_projects();
|
|
6295
7117
|
init_review_status();
|
|
6296
7118
|
init_state_read_home();
|
|
@@ -6328,20 +7150,17 @@ function emitDirtyWorkspaceRefusalActivity(issueId, porcelain) {
|
|
|
6328
7150
|
});
|
|
6329
7151
|
} catch {}
|
|
6330
7152
|
}
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
]);
|
|
7153
|
+
/**
|
|
7154
|
+
* Both workspace runtime directories are Overdeck-owned in full, so both get a
|
|
7155
|
+
* blanket prefix match. The legacy `.pan/` allowlist only matched the collapsed
|
|
7156
|
+
* `?? .pan/` porcelain form plus a closed set of files — but this gate always
|
|
7157
|
+
* runs with `--untracked-files=all`, which expands untracked directories into
|
|
7158
|
+
* individual paths. A pipeline-authored `.pan/drafts/<ISSUE>.md` therefore read
|
|
7159
|
+
* as operator dirt and 409'd the planning→work auto-handoff (PAN-3042).
|
|
7160
|
+
*/
|
|
6340
7161
|
function isOverdeckWorkspaceRuntimePath(path) {
|
|
6341
7162
|
if (path === ".overdeck" || path.startsWith(".overdeck/")) return true;
|
|
6342
|
-
|
|
6343
|
-
if (LEGACY_WORKSPACE_RUNTIME_FILES.has(path)) return true;
|
|
6344
|
-
return path.startsWith(".pan/feedback/") || path.startsWith(".pan/review/") || path.startsWith(".pan/test/") || path.startsWith(".pan/handoff-");
|
|
7163
|
+
return path === ".pan" || path === ".pan/" || path.startsWith(".pan/");
|
|
6345
7164
|
}
|
|
6346
7165
|
/** True when git porcelain contains only Overdeck-owned workspace runtime files. */
|
|
6347
7166
|
function isOnlyOverdeckRuntimeWorkspaceChanges(porcelain) {
|
|
@@ -6368,14 +7187,23 @@ async function spawnAfterClearingStartGates(input) {
|
|
|
6368
7187
|
}
|
|
6369
7188
|
}
|
|
6370
7189
|
const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect.gen(function* () {
|
|
6371
|
-
const
|
|
7190
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
7191
|
+
const authError = rejectUnsafeDashboardMutationRequest(request);
|
|
6372
7192
|
if (authError) return authError;
|
|
6373
7193
|
const body = yield* readJsonBody$1;
|
|
6374
7194
|
const eventStore = yield* EventStoreService;
|
|
6375
7195
|
const lifecycle = yield* IssueLifecycle;
|
|
6376
7196
|
yield* ReadModelService;
|
|
6377
7197
|
const { issueId, projectId } = body;
|
|
7198
|
+
const internalRequest = yield* Effect.promise(() => isInternalAgentRequest(request));
|
|
7199
|
+
let startedBy;
|
|
7200
|
+
try {
|
|
7201
|
+
startedBy = resolveRequestedStartedBy(body.startedBy, internalRequest);
|
|
7202
|
+
} catch (error) {
|
|
7203
|
+
return jsonResponse({ error: error instanceof Error ? error.message : String(error) }, { status: 400 });
|
|
7204
|
+
}
|
|
6378
7205
|
const autoStart = body.auto === true;
|
|
7206
|
+
const autoSpawnConsentRequired = internalRequest && body.autoSpawnConsentRequired === true;
|
|
6379
7207
|
const guardrailAcknowledged = body.guardrailAcknowledged === true;
|
|
6380
7208
|
const offBook = body.offBook === true;
|
|
6381
7209
|
const requestedHostOverride = body.host === true || body.allowHost === true;
|
|
@@ -6534,7 +7362,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6534
7362
|
let spawnModel;
|
|
6535
7363
|
try {
|
|
6536
7364
|
spawnModel = determineModel({
|
|
6537
|
-
model: body.model,
|
|
7365
|
+
model: body.model ?? resolveIssueWorkModel(issueId),
|
|
6538
7366
|
role,
|
|
6539
7367
|
spawnKey: `${role}:${issueId}`
|
|
6540
7368
|
});
|
|
@@ -6692,7 +7520,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6692
7520
|
console.warn(`[start-agent] Failed to set plan.status=running (non-fatal): ${planStatusErr?.message ?? planStatusErr}`);
|
|
6693
7521
|
}
|
|
6694
7522
|
try {
|
|
6695
|
-
const { appendSessionEntry, getProjectConfigFromWorkspacePath, resolveProjectForIssue } = await import("./record-
|
|
7523
|
+
const { appendSessionEntry, getProjectConfigFromWorkspacePath, resolveProjectForIssue } = await import("./record-BTwWhtBb.js");
|
|
6696
7524
|
await appendSessionEntry(resolveProjectForIssue(issueId) ?? getProjectConfigFromWorkspacePath(workspacePath), issueId, {
|
|
6697
7525
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6698
7526
|
reason: "start",
|
|
@@ -6717,6 +7545,8 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6717
7545
|
workspacePath,
|
|
6718
7546
|
workspaceMetadata,
|
|
6719
7547
|
spawnModel,
|
|
7548
|
+
startedBy,
|
|
7549
|
+
autoSpawnConsentRequired,
|
|
6720
7550
|
projectPath,
|
|
6721
7551
|
spawnGuardrails,
|
|
6722
7552
|
lifecycle
|
|
@@ -6810,7 +7640,11 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6810
7640
|
role,
|
|
6811
7641
|
workspacePath,
|
|
6812
7642
|
args,
|
|
6813
|
-
cwd
|
|
7643
|
+
cwd,
|
|
7644
|
+
env: {
|
|
7645
|
+
OVERDECK_AGENT_STARTED_BY: startedBy,
|
|
7646
|
+
OVERDECK_AUTO_SPAWN_CONSENT_REQUIRED: autoSpawnConsentRequired ? "1" : "0"
|
|
7647
|
+
}
|
|
6814
7648
|
})
|
|
6815
7649
|
}));
|
|
6816
7650
|
if (!admitted.check.decision.eligible || !admitted.result) throw new OrderDispatchReservationError(admitted.check);
|
|
@@ -6827,48 +7661,29 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6827
7661
|
agentSessionName,
|
|
6828
7662
|
role,
|
|
6829
7663
|
effectiveHarness,
|
|
7664
|
+
startedBy,
|
|
6830
7665
|
allowHost,
|
|
6831
7666
|
spawnModel,
|
|
6832
7667
|
spawnGuardrails,
|
|
6833
7668
|
projectPath,
|
|
6834
7669
|
eventStore,
|
|
6835
7670
|
spawnPanCommand,
|
|
7671
|
+
markWorkStartAccepted,
|
|
6836
7672
|
updateIssueStatus
|
|
6837
7673
|
});
|
|
6838
|
-
if (containerResponse)
|
|
6839
|
-
if (containerResponse.status >= 200 && containerResponse.status < 300) yield* Effect.promise(markWorkStartAccepted);
|
|
6840
|
-
return containerResponse;
|
|
6841
|
-
}
|
|
7674
|
+
if (containerResponse) return containerResponse;
|
|
6842
7675
|
const placeholderStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6843
|
-
const placeholderState = {
|
|
6844
|
-
|
|
7676
|
+
const { state: placeholderState, event: placeholderEvent } = buildAgentStartPlaceholder({
|
|
7677
|
+
agentSessionName,
|
|
6845
7678
|
issueId,
|
|
6846
|
-
|
|
7679
|
+
workspacePath,
|
|
6847
7680
|
role,
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
startedAt: placeholderStartedAt
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
const hasLiveTmuxSession = yield* sessionExists(agentSessionName).pipe(Effect.catch(() => Effect.succeed(true)));
|
|
6855
|
-
const placeholderClaim = yield* claimAgentStartPlaceholderProgram(placeholderState, {
|
|
6856
|
-
type: "agent.started",
|
|
6857
|
-
timestamp: placeholderStartedAt,
|
|
6858
|
-
payload: {
|
|
6859
|
-
agentId: agentSessionName,
|
|
6860
|
-
issueId,
|
|
6861
|
-
agent: {
|
|
6862
|
-
id: agentSessionName,
|
|
6863
|
-
issueId,
|
|
6864
|
-
workspace: workspacePath,
|
|
6865
|
-
status: "starting",
|
|
6866
|
-
startedAt: placeholderStartedAt,
|
|
6867
|
-
role,
|
|
6868
|
-
...effectiveHarness ? { runtime: effectiveHarness } : {}
|
|
6869
|
-
}
|
|
6870
|
-
}
|
|
6871
|
-
}, hasLiveTmuxSession);
|
|
7681
|
+
effectiveHarness,
|
|
7682
|
+
startedBy,
|
|
7683
|
+
allowHost,
|
|
7684
|
+
startedAt: placeholderStartedAt
|
|
7685
|
+
});
|
|
7686
|
+
const placeholderClaim = yield* claimAgentStartPlaceholderProgram(placeholderState, placeholderEvent, yield* sessionExists(agentSessionName).pipe(Effect.catch(() => Effect.succeed(true))));
|
|
6872
7687
|
if (!placeholderClaim.claimed) {
|
|
6873
7688
|
yield* Effect.promise(() => appendAgentLifecycleLog(agentSessionName, "agent.start_placeholder_blocked", {
|
|
6874
7689
|
issueId,
|
|
@@ -7142,16 +7957,26 @@ const readJsonBody = Effect.gen(function* () {
|
|
|
7142
7957
|
const postMergeGuard = createInFlightGuard();
|
|
7143
7958
|
const _serverManagedMerges = /* @__PURE__ */ new Set();
|
|
7144
7959
|
function firePostMergeLifecycle(issueId, options) {
|
|
7145
|
-
const
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7960
|
+
const parsedIssueId = parseIssueIdSync(issueId.trim());
|
|
7961
|
+
if (!parsedIssueId) {
|
|
7962
|
+
console.error(`[merge] Refusing post-merge lifecycle for invalid issue ID: ${issueId}`);
|
|
7963
|
+
return false;
|
|
7964
|
+
}
|
|
7965
|
+
const normalizedIssueId = parsedIssueId.normalized.toUpperCase();
|
|
7966
|
+
const started = postMergeGuard.run(normalizedIssueId, async () => {
|
|
7967
|
+
const projectPath = getProjectPathForIssue(parsedIssueId.prefix);
|
|
7968
|
+
const { postMergeLifecycle } = await import("./merge-agent-DQTXZk8z.js");
|
|
7969
|
+
const lifecycleOptions = {
|
|
7970
|
+
...options?.verifiedMergedRef ? { verifiedMergedRef: options.verifiedMergedRef } : {},
|
|
7971
|
+
...options?.verifiedMergedRepos?.length ? { verifiedMergedRepos: options.verifiedMergedRepos } : {}
|
|
7972
|
+
};
|
|
7973
|
+
await postMergeLifecycle(normalizedIssueId, projectPath, options?.sourceBranch, Object.keys(lifecycleOptions).length > 0 ? lifecycleOptions : void 0);
|
|
7974
|
+
console.log(`[merge] post-merge lifecycle completed for ${normalizedIssueId}`);
|
|
7975
|
+
const { runMergeTrainReconcile } = await import("./merge-train-Dmrcus12.js");
|
|
7976
|
+
const outcomes = await runMergeTrainReconcile(normalizedIssueId);
|
|
7977
|
+
if (outcomes.length > 0) console.log(`[merge-train] reconciled ${outcomes.length} sibling(s) after ${normalizedIssueId}: ` + outcomes.map((o) => `${o.issueId}=${o.result}`).join(", "));
|
|
7978
|
+
}, (err) => console.error(`[merge] post-merge lifecycle failed for ${normalizedIssueId}:`, err));
|
|
7979
|
+
if (!started) console.log(`[merge] firePostMergeLifecycle: skipping ${normalizedIssueId} — already in flight`);
|
|
7155
7980
|
return started;
|
|
7156
7981
|
}
|
|
7157
7982
|
function getProjectPathForIssue(issuePrefix) {
|
|
@@ -7168,15 +7993,15 @@ init_io();
|
|
|
7168
7993
|
init_domain_services();
|
|
7169
7994
|
init_tmux();
|
|
7170
7995
|
const getSpecialistsRoute = HttpRouter.add("GET", "/api/specialists", httpHandler(Effect.gen(function* () {
|
|
7171
|
-
const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-
|
|
7996
|
+
const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7172
7997
|
return jsonResponse({
|
|
7173
7998
|
specialists: yield* Effect.promise(() => getAllSpecialistStatus()),
|
|
7174
7999
|
projects: yield* Effect.promise(() => getAllProjectSpecialistStatuses())
|
|
7175
8000
|
});
|
|
7176
8001
|
})));
|
|
7177
8002
|
const postSpecialistsResetAllRoute = HttpRouter.add("POST", "/api/specialists/reset-all", httpHandler(Effect.gen(function* () {
|
|
7178
|
-
const { getAllSpecialists, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-
|
|
7179
|
-
const { clearHookSync } = yield* Effect.promise(() => import("./hooks-
|
|
8003
|
+
const { getAllSpecialists, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
8004
|
+
const { clearHookSync } = yield* Effect.promise(() => import("./hooks-D1g1jKLI.js"));
|
|
7180
8005
|
const specialists = getAllSpecialists();
|
|
7181
8006
|
const results = [];
|
|
7182
8007
|
for (const specialist of specialists) {
|
|
@@ -7211,7 +8036,7 @@ const postSpecialistsResetAllRoute = HttpRouter.add("POST", "/api/specialists/re
|
|
|
7211
8036
|
const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done", httpHandler(Effect.gen(function* () {
|
|
7212
8037
|
const body = yield* readJsonBody;
|
|
7213
8038
|
const eventStore = yield* EventStoreService;
|
|
7214
|
-
const { specialist, issueId, status, notes, itemId } = body;
|
|
8039
|
+
const { specialist, issueId, status, notes, itemId, runId } = body;
|
|
7215
8040
|
const validSpecialists = [
|
|
7216
8041
|
"review",
|
|
7217
8042
|
"test",
|
|
@@ -7232,7 +8057,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7232
8057
|
}
|
|
7233
8058
|
console.log(`[specialists/done] ${specialist} signaling ${status} for ${normalizedIssueId}`);
|
|
7234
8059
|
if (specialist === "merge") {
|
|
7235
|
-
const { reportSpecialistCompletion } = yield* Effect.promise(() => import("./specialist-completion-
|
|
8060
|
+
const { reportSpecialistCompletion } = yield* Effect.promise(() => import("./specialist-completion-B07XjWD2.js"));
|
|
7236
8061
|
if (yield* reportSpecialistCompletion(normalizedIssueId, {
|
|
7237
8062
|
status,
|
|
7238
8063
|
notes
|
|
@@ -7276,10 +8101,27 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7276
8101
|
break;
|
|
7277
8102
|
}
|
|
7278
8103
|
const updatedStatus = setReviewStatusSync(normalizedIssueId, update);
|
|
7279
|
-
if (specialist === "inspect" && status === "failed")
|
|
8104
|
+
if (specialist === "inspect" && status === "failed") {
|
|
8105
|
+
yield* Effect.promise(() => reportTieredInspectFailureEscalation(normalizedIssueId, notes));
|
|
8106
|
+
yield* Effect.promise(async () => {
|
|
8107
|
+
try {
|
|
8108
|
+
const failedItemId = itemId ?? getReviewStatusSync(normalizedIssueId)?.inspectBeadId ?? void 0;
|
|
8109
|
+
const project = resolveProjectFromIssueSync(normalizedIssueId);
|
|
8110
|
+
if (project && failedItemId) {
|
|
8111
|
+
const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
|
|
8112
|
+
if (existsSync(workspacePath)) {
|
|
8113
|
+
const { onInspectComplete } = await import("./inspect-agent-CUwVmr2h.js");
|
|
8114
|
+
await Effect.runPromise(onInspectComplete(project.projectKey, normalizedIssueId, failedItemId, "failed", workspacePath, notes));
|
|
8115
|
+
}
|
|
8116
|
+
}
|
|
8117
|
+
} catch (err) {
|
|
8118
|
+
console.error(`[specialists/done] Error delivering failed inspect verdict for ${normalizedIssueId}:`, err);
|
|
8119
|
+
}
|
|
8120
|
+
});
|
|
8121
|
+
}
|
|
7280
8122
|
yield* Effect.promise(async () => {
|
|
7281
8123
|
try {
|
|
7282
|
-
const { getTmuxSessionName, updateRunMetadata, makeSpecialistRegistryKey } = await import("./specialists-
|
|
8124
|
+
const { getTmuxSessionName, updateRunMetadata, makeSpecialistRegistryKey } = await import("./specialists-Bz-wFT7R.js");
|
|
7283
8125
|
const projectKey = resolveProjectFromIssueSync(normalizedIssueId)?.projectKey;
|
|
7284
8126
|
const tmuxSession = projectKey ? getTmuxSessionName(`${specialist}-agent`, projectKey, normalizedIssueId) : getTmuxSessionName(`${specialist}-agent`);
|
|
7285
8127
|
saveAgentRuntimeState(tmuxSession, {
|
|
@@ -7298,7 +8140,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7298
8140
|
});
|
|
7299
8141
|
console.log(`[specialists/done] Cleared registry lock for ${registryKey} (${projectKey})`);
|
|
7300
8142
|
}
|
|
7301
|
-
const { updateSpecialistHandoffStatus } = await import("./specialist-handoff-logger-
|
|
8143
|
+
const { updateSpecialistHandoffStatus } = await import("./specialist-handoff-logger-aKSxbIgD.js");
|
|
7302
8144
|
if (await Effect.runPromise(updateSpecialistHandoffStatus(normalizedIssueId, `${specialist}-agent`, status === "passed" ? "completed" : "failed", status === "passed" ? "success" : "failure"))) console.log(`[specialists/done] Updated handoff log: ${specialist}-agent ${normalizedIssueId} → ${status}`);
|
|
7303
8145
|
} catch (err) {
|
|
7304
8146
|
console.error(`[specialists/done] Error managing specialist state:`, err);
|
|
@@ -7310,10 +8152,12 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7310
8152
|
if (project) {
|
|
7311
8153
|
const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
|
|
7312
8154
|
if (existsSync(workspacePath)) {
|
|
7313
|
-
const {
|
|
7314
|
-
const
|
|
7315
|
-
|
|
7316
|
-
|
|
8155
|
+
const { formatAnchorShort, snapshotWorkspaceHeadsPromise } = await import("./git-utils-Xg4PFN45.js");
|
|
8156
|
+
const headAnchor = await snapshotWorkspaceHeadsPromise(normalizedIssueId, workspacePath);
|
|
8157
|
+
if (headAnchor) {
|
|
8158
|
+
setReviewStatusSync(normalizedIssueId, { reviewedAtCommit: headAnchor });
|
|
8159
|
+
console.log(`[specialists/done] Snapshotted reviewedAtCommit=${formatAnchorShort(headAnchor)} for ${normalizedIssueId}`);
|
|
8160
|
+
}
|
|
7317
8161
|
}
|
|
7318
8162
|
}
|
|
7319
8163
|
} catch (err) {
|
|
@@ -7322,11 +8166,11 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7322
8166
|
});
|
|
7323
8167
|
if (specialist === "inspect" && status === "passed") yield* Effect.promise(async () => {
|
|
7324
8168
|
try {
|
|
7325
|
-
const { onInspectComplete } = await import("./inspect-agent-
|
|
8169
|
+
const { onInspectComplete } = await import("./inspect-agent-CUwVmr2h.js");
|
|
7326
8170
|
const project = resolveProjectFromIssueSync(normalizedIssueId);
|
|
7327
8171
|
if (project) {
|
|
7328
8172
|
const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
|
|
7329
|
-
if (existsSync(workspacePath)) await Effect.runPromise(onInspectComplete(project.projectKey, normalizedIssueId, itemId, "passed", workspacePath));
|
|
8173
|
+
if (existsSync(workspacePath)) await Effect.runPromise(onInspectComplete(project.projectKey, normalizedIssueId, itemId, "passed", workspacePath, notes));
|
|
7330
8174
|
}
|
|
7331
8175
|
} catch (err) {
|
|
7332
8176
|
console.error(`[specialists/done] Error saving inspect checkpoint:`, err);
|
|
@@ -7338,7 +8182,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7338
8182
|
if (project) {
|
|
7339
8183
|
if (existsSync(join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`))) {
|
|
7340
8184
|
setReviewStatusSync(normalizedIssueId, { testStatus: "passed" });
|
|
7341
|
-
const { initEventStore } = await import("./event-store-
|
|
8185
|
+
const { initEventStore } = await import("./event-store-5UKzh9Jf.js");
|
|
7342
8186
|
await (await initEventStore()).appendAsync({
|
|
7343
8187
|
type: "test.passed",
|
|
7344
8188
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -7391,8 +8235,8 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7391
8235
|
if (notes?.toLowerCase().includes("conflict")) yield* Effect.promise(async () => {
|
|
7392
8236
|
try {
|
|
7393
8237
|
const workAgentId = `agent-${normalizedIssueId.toLowerCase()}`;
|
|
7394
|
-
const { sessionExists } = await import("./tmux-
|
|
7395
|
-
const { messageAgent, spawnAgent, getAgentStateSync } = await import("./agents-
|
|
8238
|
+
const { sessionExists } = await import("./tmux-Ctk6RV5l.js");
|
|
8239
|
+
const { messageAgent, spawnAgent, getAgentStateSync } = await import("./agents-ePFVoZbu.js");
|
|
7396
8240
|
if (await Effect.runPromise(sessionExists(workAgentId))) {
|
|
7397
8241
|
await messageAgent(workAgentId, `MERGE CONFLICT: The merge-agent could not rebase your branch onto main due to conflicts. Please fix this now:\n\n1. git fetch origin main\n2. git rebase origin/main\n3. Resolve any conflicts (git add <file> && git rebase --continue)\n4. git push --force-with-lease\n5. Resubmit: curl -s -X POST http://localhost:3011/api/review/${normalizedIssueId}/request -H "Content-Type: application/json" -d "{}"\n\nConflict details: ${notes}`);
|
|
7398
8242
|
console.log(`[specialists/done] Sent rebase instructions to ${workAgentId}`);
|
|
@@ -7406,19 +8250,38 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7406
8250
|
try {
|
|
7407
8251
|
const project = resolveProjectFromIssueSync(normalizedIssueId);
|
|
7408
8252
|
const workspacePath = project ? join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`) : void 0;
|
|
7409
|
-
const { deliverReviewVerdictFeedback } = await import("./review-verdict-feedback-
|
|
8253
|
+
const { deliverReviewVerdictFeedback } = await import("./review-verdict-feedback-HwF6ODFy.js");
|
|
7410
8254
|
const result = await Effect.runPromise(deliverReviewVerdictFeedback({
|
|
7411
8255
|
issueId: normalizedIssueId,
|
|
7412
8256
|
verdict: status === "failed" ? "failed" : "blocked",
|
|
7413
8257
|
notes,
|
|
7414
8258
|
workspacePath,
|
|
7415
|
-
prUrl: updatedStatus.prUrl
|
|
8259
|
+
prUrl: updatedStatus.prUrl,
|
|
8260
|
+
...runId ? { runId } : {}
|
|
7416
8261
|
}));
|
|
7417
8262
|
console.log(`[specialists/done] Delivered review verdict feedback for ${normalizedIssueId} (feedback=${result.feedbackPath ?? "none"}, synthesis=${result.synthesisPath ?? "none"}, prComment=${result.prCommentPosted})`);
|
|
7418
8263
|
} catch (err) {
|
|
7419
8264
|
console.warn(`[specialists/done] Failed to deliver review verdict feedback: ${err.message}`);
|
|
7420
8265
|
}
|
|
7421
8266
|
});
|
|
8267
|
+
if (specialist === "review" && status === "failed") yield* Effect.promise(async () => {
|
|
8268
|
+
try {
|
|
8269
|
+
const project = resolveProjectFromIssueSync(normalizedIssueId);
|
|
8270
|
+
if (project) {
|
|
8271
|
+
const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
|
|
8272
|
+
if (existsSync(workspacePath)) {
|
|
8273
|
+
const { formatAnchorShort, snapshotWorkspaceHeadsPromise } = await import("./git-utils-Xg4PFN45.js");
|
|
8274
|
+
const reviewedAtCommit = await snapshotWorkspaceHeadsPromise(normalizedIssueId, workspacePath);
|
|
8275
|
+
if (reviewedAtCommit) {
|
|
8276
|
+
setReviewStatusSync(normalizedIssueId, { reviewedAtCommit });
|
|
8277
|
+
console.log(`[specialists/done] Snapshotted blocked reviewedAtCommit=${formatAnchorShort(reviewedAtCommit)} for ${normalizedIssueId}`);
|
|
8278
|
+
}
|
|
8279
|
+
}
|
|
8280
|
+
}
|
|
8281
|
+
} catch (err) {
|
|
8282
|
+
console.error(`[specialists/done] Failed to snapshot blocked reviewedAtCommit for ${normalizedIssueId}:`, err);
|
|
8283
|
+
}
|
|
8284
|
+
});
|
|
7422
8285
|
const eventRole = specialistEventRole(specialist);
|
|
7423
8286
|
if (eventRole) if (status === "passed") yield* eventStore.append({
|
|
7424
8287
|
type: "specialist.completed",
|
|
@@ -7447,7 +8310,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7447
8310
|
});
|
|
7448
8311
|
})));
|
|
7449
8312
|
const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/specialists/logs/cleanup-all", httpHandler(Effect.gen(function* () {
|
|
7450
|
-
const { cleanupAllLogsSync } = yield* Effect.promise(() => import("./specialist-logs-
|
|
8313
|
+
const { cleanupAllLogsSync } = yield* Effect.promise(() => import("./specialist-logs-Dae-n52_.js"));
|
|
7451
8314
|
const results = cleanupAllLogsSync();
|
|
7452
8315
|
return jsonResponse({
|
|
7453
8316
|
success: true,
|
|
@@ -7457,7 +8320,7 @@ const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/speciali
|
|
|
7457
8320
|
});
|
|
7458
8321
|
})));
|
|
7459
8322
|
const getSpecialistsProjectsRoute = HttpRouter.add("GET", "/api/specialists/projects", httpHandler(Effect.gen(function* () {
|
|
7460
|
-
const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-
|
|
8323
|
+
const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7461
8324
|
return jsonResponse(yield* Effect.promise(() => getAllProjectSpecialistStatuses()));
|
|
7462
8325
|
})));
|
|
7463
8326
|
const postSpecialistWakeRoute = HttpRouter.add("POST", "/api/specialists/:name/wake", httpHandler(Effect.gen(function* () {
|
|
@@ -7501,7 +8364,7 @@ const postSpecialistReportStatusRoute = HttpRouter.add("POST", "/api/specialists
|
|
|
7501
8364
|
"blocked",
|
|
7502
8365
|
"failed"
|
|
7503
8366
|
].includes(status)) {
|
|
7504
|
-
const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-
|
|
8367
|
+
const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7505
8368
|
saveAgentRuntimeState(getTmuxSessionName(name), {
|
|
7506
8369
|
state: "idle",
|
|
7507
8370
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7600,6 +8463,7 @@ const specialistsLegacyRouteLayer = Layer.mergeAll(getSpecialistsRoute, getSpeci
|
|
|
7600
8463
|
//#endregion
|
|
7601
8464
|
//#region routes/specialists/project-routes.ts
|
|
7602
8465
|
init_config_yaml();
|
|
8466
|
+
init_project_repos();
|
|
7603
8467
|
init_projects();
|
|
7604
8468
|
init_review_status();
|
|
7605
8469
|
init_tmux();
|
|
@@ -7622,7 +8486,7 @@ const postProjectSpecialistKillRoute = HttpRouter.add("POST", "/api/specialists/
|
|
|
7622
8486
|
const issueId = params["issueId"];
|
|
7623
8487
|
const type = params["type"];
|
|
7624
8488
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7625
|
-
const { getTmuxSessionName, makeSpecialistRegistryKey, getRunMetadata } = yield* Effect.promise(() => import("./specialists-
|
|
8489
|
+
const { getTmuxSessionName, makeSpecialistRegistryKey, getRunMetadata } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7626
8490
|
const tmuxSession = getRunMetadata(project, makeSpecialistRegistryKey(type, issueId)).tmuxSession ?? getTmuxSessionName(type, project, issueId);
|
|
7627
8491
|
yield* Effect.promise(() => Effect.runPromise(killSession(tmuxSession)).catch(() => {}));
|
|
7628
8492
|
saveAgentRuntimeState(tmuxSession, {
|
|
@@ -7649,7 +8513,7 @@ const getProjectSpecialistRunsRoute = HttpRouter.add("GET", "/api/specialists/:p
|
|
|
7649
8513
|
if (limitParam) limit = parseInt(limitParam, 10);
|
|
7650
8514
|
if (offsetParam) offset = parseInt(offsetParam, 10);
|
|
7651
8515
|
}
|
|
7652
|
-
const { listRunLogsSync } = yield* Effect.promise(() => import("./specialist-logs-
|
|
8516
|
+
const { listRunLogsSync } = yield* Effect.promise(() => import("./specialist-logs-Dae-n52_.js"));
|
|
7653
8517
|
return jsonResponse(listRunLogsSync(project, type, {
|
|
7654
8518
|
limit,
|
|
7655
8519
|
offset
|
|
@@ -7660,7 +8524,7 @@ const getProjectSpecialistRunStreamRoute = HttpRouter.add("GET", "/api/specialis
|
|
|
7660
8524
|
const project = params["project"];
|
|
7661
8525
|
const type = params["type"];
|
|
7662
8526
|
const runId = params["runId"];
|
|
7663
|
-
const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-
|
|
8527
|
+
const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-Dae-n52_.js"));
|
|
7664
8528
|
const logPath = getRunLogPath(project, type, runId);
|
|
7665
8529
|
if (!existsSync(logPath)) return jsonResponse({ error: "Run log not found" }, { status: 404 });
|
|
7666
8530
|
const encoder = new TextEncoder();
|
|
@@ -7719,7 +8583,7 @@ const getProjectSpecialistRunRoute = HttpRouter.add("GET", "/api/specialists/:pr
|
|
|
7719
8583
|
const project = params["project"];
|
|
7720
8584
|
const type = params["type"];
|
|
7721
8585
|
const runId = params["runId"];
|
|
7722
|
-
const { getRunLogSync, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-
|
|
8586
|
+
const { getRunLogSync, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-Dae-n52_.js"));
|
|
7723
8587
|
const content = getRunLogSync(project, type, runId);
|
|
7724
8588
|
if (!content) return jsonResponse({ error: "Run log not found" }, { status: 404 });
|
|
7725
8589
|
return jsonResponse({
|
|
@@ -7733,7 +8597,7 @@ const postProjectSpecialistRunTerminateRoute = HttpRouter.add("POST", "/api/spec
|
|
|
7733
8597
|
const project = params["project"];
|
|
7734
8598
|
const type = params["type"];
|
|
7735
8599
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7736
|
-
const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-
|
|
8600
|
+
const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7737
8601
|
yield* Effect.promise(() => terminateSpecialist(project, type));
|
|
7738
8602
|
return jsonResponse({
|
|
7739
8603
|
success: true,
|
|
@@ -7745,7 +8609,7 @@ const postProjectSpecialistGracePauseRoute = HttpRouter.add("POST", "/api/specia
|
|
|
7745
8609
|
const project = params["project"];
|
|
7746
8610
|
const type = params["type"];
|
|
7747
8611
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7748
|
-
const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-
|
|
8612
|
+
const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7749
8613
|
if (pauseGracePeriod(project, type)) return jsonResponse({
|
|
7750
8614
|
success: true,
|
|
7751
8615
|
message: "Grace period paused"
|
|
@@ -7757,7 +8621,7 @@ const postProjectSpecialistGraceResumeRoute = HttpRouter.add("POST", "/api/speci
|
|
|
7757
8621
|
const project = params["project"];
|
|
7758
8622
|
const type = params["type"];
|
|
7759
8623
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7760
|
-
const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-
|
|
8624
|
+
const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7761
8625
|
if (resumeGracePeriod(project, type)) return jsonResponse({
|
|
7762
8626
|
success: true,
|
|
7763
8627
|
message: "Grace period resumed"
|
|
@@ -7769,7 +8633,7 @@ const postProjectSpecialistGraceExitRoute = HttpRouter.add("POST", "/api/special
|
|
|
7769
8633
|
const project = params["project"];
|
|
7770
8634
|
const type = params["type"];
|
|
7771
8635
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7772
|
-
const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-
|
|
8636
|
+
const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7773
8637
|
exitGracePeriod(project, type);
|
|
7774
8638
|
return jsonResponse({
|
|
7775
8639
|
success: true,
|
|
@@ -7781,7 +8645,7 @@ const getProjectSpecialistGraceRoute = HttpRouter.add("GET", "/api/specialists/:
|
|
|
7781
8645
|
const project = params["project"];
|
|
7782
8646
|
const type = params["type"];
|
|
7783
8647
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7784
|
-
const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-
|
|
8648
|
+
const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7785
8649
|
const state = getGracePeriodState(project, type);
|
|
7786
8650
|
if (state) return jsonResponse(state);
|
|
7787
8651
|
else return jsonResponse({ error: "No active grace period" }, { status: 404 });
|
|
@@ -7790,7 +8654,7 @@ const getProjectSpecialistContextRoute = HttpRouter.add("GET", "/api/specialists
|
|
|
7790
8654
|
const params = yield* HttpRouter.params;
|
|
7791
8655
|
const project = params["project"];
|
|
7792
8656
|
const type = params["type"];
|
|
7793
|
-
const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-
|
|
8657
|
+
const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-DJ-zFyL3.js"));
|
|
7794
8658
|
const digest = loadContextDigest(project, type);
|
|
7795
8659
|
if (digest) return jsonResponse({ digest });
|
|
7796
8660
|
else return jsonResponse({ error: "No context digest found" }, { status: 404 });
|
|
@@ -7799,7 +8663,7 @@ const postProjectSpecialistContextRegenerateRoute = HttpRouter.add("POST", "/api
|
|
|
7799
8663
|
const params = yield* HttpRouter.params;
|
|
7800
8664
|
const project = params["project"];
|
|
7801
8665
|
const type = params["type"];
|
|
7802
|
-
const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-
|
|
8666
|
+
const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-DJ-zFyL3.js"));
|
|
7803
8667
|
const digest = yield* Effect.promise(() => regenerateContextDigest(project, type));
|
|
7804
8668
|
if (digest) return jsonResponse({
|
|
7805
8669
|
digest,
|
|
@@ -7818,7 +8682,7 @@ const postProjectSpecialistCompleteRoute = HttpRouter.add("POST", "/api/speciali
|
|
|
7818
8682
|
"blocked"
|
|
7819
8683
|
].includes(status)) return jsonResponse({ error: "Valid status (passed/failed/blocked) is required" }, { status: 400 });
|
|
7820
8684
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7821
|
-
const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-
|
|
8685
|
+
const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-Bz-wFT7R.js"));
|
|
7822
8686
|
signalSpecialistCompletion(project, type, {
|
|
7823
8687
|
status,
|
|
7824
8688
|
notes
|
|
@@ -7852,8 +8716,8 @@ const postProjectSpecialistLogsCleanupRoute = HttpRouter.add("POST", "/api/speci
|
|
|
7852
8716
|
const params = yield* HttpRouter.params;
|
|
7853
8717
|
const project = params["project"];
|
|
7854
8718
|
const type = params["type"];
|
|
7855
|
-
const { cleanupOldLogsSync } = yield* Effect.promise(() => import("./specialist-logs-
|
|
7856
|
-
const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-
|
|
8719
|
+
const { cleanupOldLogsSync } = yield* Effect.promise(() => import("./specialist-logs-Dae-n52_.js"));
|
|
8720
|
+
const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-_n3Zui6K.js"));
|
|
7857
8721
|
const retention = getSpecialistRetention(project);
|
|
7858
8722
|
const deleted = cleanupOldLogsSync(project, type, {
|
|
7859
8723
|
maxDays: retention.max_days,
|
|
@@ -7874,21 +8738,23 @@ const postProjectReviewRestartRoute = HttpRouter.add("POST", "/api/specialists/:
|
|
|
7874
8738
|
const project = params["project"];
|
|
7875
8739
|
const issueId = params["issueId"];
|
|
7876
8740
|
const { model, harness } = yield* readJsonBody;
|
|
7877
|
-
const { killAllReviewerSessions } = yield* Effect.promise(() => import("./review-agent-
|
|
8741
|
+
const { killAllReviewerSessions } = yield* Effect.promise(() => import("./review-agent-BTCNkq2h.js"));
|
|
7878
8742
|
const killResult = yield* killAllReviewerSessions(project, issueId);
|
|
7879
8743
|
const projectConfig = resolveProjectFromIssueSync(issueId);
|
|
7880
8744
|
if (!projectConfig) return jsonResponse({ error: `Cannot resolve project for ${issueId}` }, { status: 404 });
|
|
7881
8745
|
const workspacePath = join(projectConfig.projectPath, "workspaces", `feature-${issueId.toLowerCase()}`);
|
|
7882
8746
|
if (!existsSync(workspacePath)) return jsonResponse({ error: `Workspace not found: ${workspacePath}` }, { status: 404 });
|
|
7883
|
-
|
|
8747
|
+
const primaryRepo = resolveWorkspaceRepoRootsSync(issueId, workspacePath)[0];
|
|
8748
|
+
let branch = primaryRepo.sourceBranch;
|
|
7884
8749
|
try {
|
|
7885
|
-
const { stdout } = yield* Effect.promise(() => execAsync(
|
|
8750
|
+
const { stdout } = yield* Effect.promise(() => execAsync("git branch --show-current", {
|
|
8751
|
+
cwd: resolvePrimaryWorkspaceRepoDirSync(issueId, workspacePath),
|
|
7886
8752
|
encoding: "utf-8",
|
|
7887
8753
|
timeout: 5e3
|
|
7888
8754
|
}));
|
|
7889
|
-
branch = stdout.trim() ||
|
|
8755
|
+
branch = stdout.trim() || primaryRepo.sourceBranch;
|
|
7890
8756
|
} catch {}
|
|
7891
|
-
const { spawnReviewRoleForIssue } = yield* Effect.promise(() => import("./review-agent-
|
|
8757
|
+
const { spawnReviewRoleForIssue } = yield* Effect.promise(() => import("./review-agent-BTCNkq2h.js"));
|
|
7892
8758
|
const prUrl = getReviewStatusSync(issueId)?.prUrl;
|
|
7893
8759
|
const result = yield* spawnReviewRoleForIssue({
|
|
7894
8760
|
issueId,
|
|
@@ -8037,6 +8903,6 @@ const specialistsProjectRouteLayer = Layer.mergeAll(getProjectSpecialistStatusRo
|
|
|
8037
8903
|
*/
|
|
8038
8904
|
const specialistsRouteLayer = Layer.mergeAll(specialistsLegacyRouteLayer, specialistsProjectRouteLayer);
|
|
8039
8905
|
//#endregion
|
|
8040
|
-
export {
|
|
8906
|
+
export { composerCommandConfirmationFromBody as $, resolveAllowedHarness as A, jsonResponse as At, cleanupUnreferencedConversationAttachments as B, handleConversationCreate as C, waitForSessionRespawn as Ct, handleConversationStop as D, validateOriginHeaders as Dt, handleConversationResume as E, validateOrigin as Et, tmuxSessionExists as F, isManagedConversationAttachmentPath as G, extractConversationAttachmentPaths as H, waitForPiTuiReady as I, composerCommandResultHttpStatus as J, removeConversationAttachment as K, waitForTmuxSession as L, spawnConversationSession as M, startConversationModelBackfill as N, handleConversationSwitchModel as O, httpHandler as Ot, stopConversationRuntime as P, ComposerCommandConfirmationError as Q, cleanupConversationAttachments as R, conversationSessionAliveFromState as S, isRespawnPending as St, handleConversationRestartAll as T, isTrustedOriginForHost as Tt, getConversationAttachmentsRoot as U, ensureConversationAttachmentDir as V, hasConversationAttachment as W, resolvePolicy as X, handleComposerCommandMessage as Y, ComposerCommandParseError as Z, isPiControlChannelHarness as _, dashboardSessionCookieHeader as _t, agentsRouteLayer as a, resolveConversationGitInfo as at, validateConversationControlAckOrigin as b, rejectUnauthorizedDashboardSessionMintRequest as bt, codexConversationPendingInput as c, spawnPanCli as ct, handleConversationCodexApproval as d, resolveAgentHarness as dt, evaluateSpawnGuardrails as et, handleConversationCompact as f, resolveClaudeSessionId as ft, handleConversationThinkingLevel as g, dashboardCsrfToken as gt, handleConversationPlanAction as h, resolvePiSessionPath as ht, validateSpecialistAutoCompleteMetadata as i, resolveAgentGitInfo as it, shouldReportUnresolvedLiveSession as j, jsonStringResponse as jt, isInsideGitWorkTree as k, getDefaultCwd as kt, deliverConversationViaControlChannel as l, readLauncherPinnedSessionId as lt, handleConversationDeliveryMethod as m, resolveJsonlPath as mt, _serverManagedMerges as n, isInternalAgentRequest as nt, saveAgentStateAndEmitEvent as o, getWorkAgentLifecycleStateSync as ot, handleConversationControlAck as p, resolveCodexRolloutPath as pt, runInBatches as q, firePostMergeLifecycle as r, resolveRequestedStartedBy as rt, saveAgentStateAndEmitEventProgram as s, panCliInvocation as st, specialistsRouteLayer as t, invalidateAgentsCache as tt, handleConversationAbort as u, resolveAcpTranscriptPath as ut, pickDeliverAs as v, hasDashboardInternalToken as vt, handleConversationDelete as w, getHeaderFromMap as wt, conversationNeedsRunningRepair as x, rejectUnsafeDashboardMutationRequest as xt, resolveConversationDeliveryMethod as y, rejectUnauthorizedDashboardRequest as yt, cleanupOrphanedConversationAttachments as z };
|
|
8041
8907
|
|
|
8042
|
-
//# sourceMappingURL=specialists-
|
|
8908
|
+
//# sourceMappingURL=specialists-6PWdtWcg.js.map
|