@overdeck/desktop 0.45.24 → 0.46.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 +32 -0
- package/package.json +1 -1
- package/server/{acceptance-criteria-DDCnXF58.js → acceptance-criteria-CCwFGICj.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-De1L-Sb4.js} +6 -6
- package/server/{agent-gc-CHcnvonI.js → agent-gc-CBULruzm.js} +5 -5
- package/server/agent-state-VQk8fY9F.js +3 -0
- package/server/{agent-state-service-BsgWxZuB.js → agent-state-service-BlnSkRFA.js} +5 -5
- package/server/{agent-state-service-D5UGKIJL.js → agent-state-service-hZpxIw1E.js} +1 -1
- package/server/agents-BKKkxKgK.js +3 -0
- package/server/{agents-EbI0zCJl.js → agents-C5rWYhb6.js} +4 -4
- package/server/archive-planning-0FJ6Xd3b.js +2 -0
- package/server/{archive-planning-Du25Jtst.js → archive-planning-C0lAbNB_.js} +16 -24
- package/server/{artifact-index-jobs-CbEDfCDu.js → artifact-index-jobs-ug6ZxIP5.js} +2 -2
- package/server/{assemble-J2ZZ2C15.js → assemble-DnffNpOo.js} +2 -2
- package/server/{backlog-auto-trigger-2R2jog7n.js → backlog-auto-trigger-Dh-i9PQf.js} +3 -3
- package/server/{behavior-B3exJ42O.js → behavior-CfIg6pKp.js} +2 -2
- package/server/bridge-pool-patrol-CUFmjVDN.js +136 -0
- package/server/{briefing-freshness-D1wzUIWv.js → briefing-freshness-DHmCSLar.js} +2 -2
- package/server/{build-info-CZk_TITh.js → build-info-BP160gU7.js} +1 -1
- package/server/{build-info-Ie_D0_BT.js → build-info-CuFfxZxp.js} +5 -3
- package/server/{checkpoint-manager-BI1Wxoku.js → checkpoint-manager-DEWD82qK.js} +2 -2
- package/server/{checkpoint-manager-DwbQoqrC.js → checkpoint-manager-Dxh0FYsv.js} +1 -1
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-CQB1h765.js → checkpoints-CZvbtLnr.js} +2 -2
- package/server/{checkpoints-BJIs5QIA.js → checkpoints-DMTgXuLG.js} +1 -1
- package/server/{claude-hooks-provision-8Ngo8TpT.js → claude-hooks-provision-CN-xo-do.js} +1 -1
- package/server/{claude-hooks-provision-D8GXF3_s.js → claude-hooks-provision-fvy4RD2b.js} +13 -2
- package/server/{claude-permissions-DNWEVV6z.js → claude-permissions-CN0cSCPp.js} +2 -2
- package/server/{claude-settings-overlay-CEdaqpWI.js → claude-settings-overlay-CJn35FHQ.js} +2 -2
- package/server/{claude-settings-overlay-DWy-Bb4Y.js → claude-settings-overlay-Dabi9slj.js} +1 -1
- package/server/cli-DmXETsw-.js +3 -0
- package/server/{cli-RoOx5DUf.js → cli-oCWYA1pE.js} +9 -9
- package/server/{cliproxy-C8a1vtTU.js → cliproxy-C8mB3KuB.js} +2 -2
- package/server/{cliproxy-fHfIeiGd.js → cliproxy-PGwTX_o8.js} +1 -1
- package/server/{close-issue-DoOifFIK.js → close-issue-D5MF5GqF.js} +5 -5
- package/server/{closed-issue-reaper-CktPXo8m.js → closed-issue-reaper-CJ24u0Zt.js} +1 -1
- package/server/{closed-issue-reaper-Bk3SU4RC.js → closed-issue-reaper-Cltx86x5.js} +37 -16
- package/server/{codex-GcHuUF-k.js → codex-BdEsUFWh.js} +1 -1
- package/server/{codex-BZXGhUVB.js → codex-Drlf5Xhf.js} +36 -7
- package/server/{codex-parser-CFZ1_1Jl.js → codex-parser-DpB89Vqa.js} +2 -2
- package/server/compaction-continuation-K2AxQX4H.js +200 -0
- package/server/{config-CKxYiCmX.js → config-B2IMcBxx.js} +4 -3
- package/server/{config-DzV30TOm.js → config-DV-grfQc.js} +1 -1
- package/server/{config-BZ0sHTju.js → config-Dr3pW6w6.js} +2 -2
- package/server/{config-yaml-DySPNmKN.js → config-yaml-CmOPzmBb.js} +268 -14
- package/server/{conflict-gate-BaCVrH-N.js → conflict-gate-B9cN3SBi.js} +4 -4
- package/server/{conflict-gate-BhAY7TUd.js → conflict-gate-Dh754uyA.js} +1 -1
- package/server/{context-layers-BrPmE__h.js → context-layers-D6LZo3l1.js} +2 -2
- package/server/{context-layers-igZ4FI4_.js → context-layers-dR5YxHYB.js} +3 -3
- package/server/{control-settings-BQp7_4uD.js → control-settings-C7DUehE1.js} +49 -19
- package/server/{conversation-compaction-CgrR8YYp.js → conversation-compaction-BoqdDXWF.js} +8 -8
- package/server/{conversation-compaction-eQB5CkOe.js → conversation-compaction-Dj4FAKoZ.js} +1 -1
- package/server/{conversation-service-DPJ71F33.js → conversation-service-5aCnq1zR.js} +8 -7
- package/server/conversation-service-BCxl4f8Z.js +3 -0
- package/server/{conversations-6AfUfbwc.js → conversations-BUpYsOZg.js} +4 -4
- package/server/{conversations-CAsJF9kh.js → conversations-C34dyIb9.js} +1 -1
- package/server/{cost-B2ddP6wq.js → cost-Bgcub5kW.js} +12 -2
- package/server/{cost-R-m6Yi-W.js → cost-CvxRrucd.js} +3 -3
- package/server/{cost-sync-BsN6ER0n.js → cost-sync-Dv3LUaNW.js} +3 -3
- package/server/{dag-B1ucnjDU.js → dag-ombYYt4s.js} +2 -2
- package/server/{dangerous-git-ops-BXqeWVSf.js → dangerous-git-ops-BcJPC5Rr.js} +1 -1
- package/server/dashboard-db-worker.js +7 -7
- package/server/deacon-DrXqT9LQ.js +4 -0
- package/server/{deacon-CU_cAYSR.js → deacon-hi9KLPLT.js} +2933 -2704
- package/server/{deacon-nudge-log-6wVqAaqz.js → deacon-nudge-log-BNBebzeL.js} +3 -3
- package/server/deacon-pending-lifecycle-Cpk0k7Hi.js +33 -0
- package/server/{deacon-swarm-BXZZ1Z2-.js → deacon-swarm-DBxUaO-A.js} +13 -13
- package/server/deacon-swarm-I2JfX5Tg.js +2 -0
- package/server/deacon.js +14 -19
- package/server/dead-end-trip-CQcP70ND.js +13 -0
- package/server/delivery-Da0zEMY4.js +3 -0
- package/server/{deploy-patrol-AiFoP8dw.js → deploy-patrol-Df-Tmaq0.js} +69 -18
- package/server/deploy-queue-9SrhZR63.js +3 -0
- package/server/deploy-queue-UjKGYsDe.js +169 -0
- package/server/deploy-window-jOiPRHL0.js +3 -0
- package/server/{deploy-window-C3F-tihF.js → deploy-window-rpqpWqHA.js} +40 -16
- package/server/{dev-supervisor-bcOWqdQE.js → dev-supervisor-CC46Ig8q.js} +2 -2
- package/server/{devcontainer-renderer-_d6XhyND.js → devcontainer-renderer-68CSCRnu.js} +3 -3
- package/server/{dist-Cb_0uvpS.js → dist-CJy72uEg.js} +1 -1
- package/server/dist-DSlxIU1H.js +3 -0
- package/server/{dist-src-BSoS7mkd.js → dist-src-Bik83hFi.js} +1 -1
- package/server/docker-BMVTSFL5.js +3 -0
- package/server/{docker-DcMTFTUC.js → docker-Dam7mbIB.js} +2 -2
- package/server/{dod-C6n9RV3G.js → dod-Dar-yheg.js} +8 -4
- package/server/durable-review-pipeline-CGZ5QBxh.js +17 -0
- package/server/durable-review-pipeline-jpgCJZFp.js +3 -0
- package/server/{ensure-devcontainer-DNi-ono3.js → ensure-devcontainer-B057YA81.js} +4 -4
- package/server/{ensure-devcontainer-BZgOhRo7.js → ensure-devcontainer-C98V8yW-.js} +1 -1
- package/server/{esm-shims-OSHAYaS1.js → esm-shims-Br9BPdkR.js} +1 -1
- package/server/{event-store-EV2cMiXj.js → event-store-ELqkVOn0.js} +1 -1
- package/server/{event-store-CQL6NeqB.js → event-store-zY5MJHgF.js} +23 -4
- package/server/{events-BTdrdEq8.js → events-D6pyqhzM.js} +1 -1
- package/server/{events-DTfAe4My.js → events-D9PR1IC0.js} +3 -3
- package/server/{factory-CFibJuaw.js → factory-CRoOpGsF.js} +5 -5
- package/server/{feature-registry-population-DKZFMbFt.js → feature-registry-population--YUXU999.js} +4 -4
- package/server/{feature-registry-storage-BdPuLcBX.js → feature-registry-storage-BORBTo0y.js} +2 -2
- package/server/{features-ez2271oH.js → features--nFkJY8v.js} +2 -2
- package/server/{feedback-target-CoFDHiM8.js → feedback-target-C0ZzyHvU.js} +1 -1
- package/server/{feedback-target-7mqqwrX6.js → feedback-target-Dt9BsapX.js} +8 -8
- package/server/{feedback-writer-CY5L1lB7.js → feedback-writer-BG0RUZiu.js} +5 -5
- package/server/{feedback-writer-D3a22RCd.js → feedback-writer-D1fm-5Z8.js} +1 -1
- package/server/{flywheel-SVF02Jpq.js → flywheel-BekukH4i.js} +1 -1
- package/server/{flywheel-DHrgCphM.js → flywheel-BiT3odRb.js} +23 -15
- package/server/{flywheel-DzGtWnJ1.js → flywheel-CLVB55Be.js} +16 -15
- package/server/flywheel-merge-order-BJv1DZz1.js +462 -0
- package/server/flywheel-merge-order-BKw9o6ku.js +2 -0
- package/server/forge-CZbSg6Ds.js +383 -0
- package/server/forge-DK3blQb_.js +3 -0
- package/server/{from-kNxT0bZC.js → from-D_4_dk7i.js} +1 -1
- package/server/{fts-db-CE46vDkZ.js → fts-db-BeOomFa-.js} +2 -2
- package/server/{fts-operations-CqY6zl-i.js → fts-operations-BdewJ_g9.js} +2 -2
- package/server/git-utils-CI6cwyyC.js +3 -0
- package/server/{git-utils-CRw2zLPC.js → git-utils-ameCgDdy.js} +30 -5
- package/server/{github-app-C3QrAUd0.js → github-app-CQ1Lo6LA.js} +3 -3
- package/server/{github-app-ClZ2lk8D.js → github-app-DtAsvwzK.js} +1 -1
- package/server/{github-client-BnIsSrEN.js → github-client-BfyDxuRN.js} +2 -2
- package/server/{github-client-DfQYVUaw.js → github-client-Cj0yl_07.js} +1 -1
- package/server/github-pr-lookup-BDq6Wznz.js +58 -0
- package/server/{harness-binary-DPUi-Pv8.js → harness-binary-DqkftwTb.js} +2 -2
- package/server/{harness-resolve-3lNZkyT4.js → harness-resolve-CqMqM1Mb.js} +4 -4
- package/server/{health-events-BBcTYQKU.js → health-events-CazRxJUS.js} +2 -2
- package/server/{health-events-BDOHby5Q.js → health-events-_xfTaOUs.js} +1 -1
- package/server/{hooks-CKZgXlJb.js → hooks-BO3QT1sn.js} +2 -2
- package/server/{hooks-DPVX1rwQ.js → hooks-BnJsxlSq.js} +1 -1
- package/server/{hume-Cz8igP9E.js → hume-CDYJxqx-.js} +2 -2
- package/server/hume-Dq--7rOQ.js +3 -0
- package/server/{idle-stack-reaper-CuLF0j2H.js → idle-stack-reaper-BYqERdkE.js} +1 -1
- package/server/{idle-stack-reaper-DDIRwxUY.js → idle-stack-reaper-CnGx_PO_.js} +99 -6
- package/server/in-flight-guard-Bq3epG58.js +45 -0
- package/server/{infra-BEqFxlJc.js → infra-BjuxvjdS.js} +70 -5
- package/server/{injection-CPUIqNhI.js → injection-DZxlV2al.js} +1 -1
- package/server/{injection-C8aiVJrF.js → injection-UCf8EsjX.js} +7 -7
- package/server/{inspect-agent-BLuJ1AkT.js → inspect-agent-6kylZnrm.js} +26 -25
- package/server/inspect-agent-BVwDrVrz.js +2 -0
- package/server/{internal-token-s0-oKybJ.js → internal-token-DvMTQSOS.js} +2 -2
- package/server/{internal-token-BrcU6qfe.js → internal-token-M9omeXM1.js} +1 -1
- package/server/{io-C9kF1wtJ.js → io-VHvc0Ssp.js} +43 -26
- package/server/{issue-closed-CDJk4pIp.js → issue-closed-B6KJkmHZ.js} +7 -7
- package/server/{issue-lifecycle-B8sZHVHh.js → issue-lifecycle-9gk3fnXN.js} +1 -1
- package/server/{issue-lifecycle-ojZAzDBP.js → issue-lifecycle-C4Zj0WmE.js} +34 -28
- package/server/{issue-service-singleton-Yx5DdmVJ.js → issue-service-singleton-DmCh7EHj.js} +10 -10
- package/server/{issue-service-singleton-BvJ09SaR.js → issue-service-singleton-PMx8F1jr.js} +1 -1
- package/server/{issues-BMmP_77e.js → issues-CgnQ1OGQ.js} +2 -2
- package/server/{jsonl-parser-BXSlHwEh.js → jsonl-parser-DJOH_O-w.js} +5 -4
- package/server/{label-cleanup-B0UJwnv5.js → label-cleanup-Dv7AV_R1.js} +3 -3
- package/server/{label-reconciler-B4iOAjlC.js → label-reconciler--F85rufp.js} +4 -4
- package/server/{lifecycle-yPd___5E.js → lifecycle-CTdOWYMi.js} +2 -2
- package/server/{lifecycle-xmBfK2GJ.js → lifecycle-DDN8ApVY.js} +6 -7
- package/server/{lifecycle-io-BREGpnLk.js → lifecycle-io-D-lGdzK3.js} +5 -5
- package/server/{lifecycle-io-DPo7x11I.js → lifecycle-io-D_zTLvP1.js} +1 -1
- package/server/{linear-client-BsuUvkdA.js → linear-client-BQU36QqE.js} +2 -2
- package/server/{linear-client-CTskEeT_.js → linear-client-CY4O_Tu3.js} +1 -1
- package/server/linear-mcp-auth-BnU4TYfY.js +280 -0
- package/server/linear-mcp-auth-NYBq_oHZ.js +2 -0
- package/server/memory-fts-worker.js +1 -1
- package/server/{merge-CefQNAnq.js → merge-Bpx4jjht.js} +13 -11
- package/server/{merge-agent-4WOWlSYA.js → merge-agent-DdMVSV2Y.js} +233 -83
- package/server/{merge-agent-CKkgIBPB.js → merge-agent-DrXa1CpW.js} +1 -1
- package/server/{merge-batch-ClFn2T-y.js → merge-batch-C5q1c1GX.js} +1 -1
- package/server/merge-completeness-BMm8tMyZ.js +277 -0
- package/server/merge-completeness-D0ljXbk3.js +3 -0
- package/server/{merge-B1DiziGU.js → merge-idOG--29.js} +1 -1
- package/server/merge-ops-DdpTiEMt.js +2 -0
- package/server/merge-rebase-DGQpYJU3.js +2 -0
- package/server/{merge-rebase-BfaTyXsw.js → merge-rebase-xLnMlw5h.js} +3 -3
- package/server/{merge-set-DJ8-UErs.js → merge-set-DH7ot3yz.js} +11 -5
- package/server/merge-set-DzsOTBg5.js +3 -0
- package/server/{merge-sync-VPV28g0g.js → merge-sync-CQ-LgZ1_.js} +406 -153
- package/server/merge-sync-Ca7F5JnQ.js +3 -0
- package/server/{merge-train-CHopycP0.js → merge-train-DTEMyIu4.js} +18 -8
- package/server/{merge-train-deps-D1cOZzy2.js → merge-train-deps-CNPJzepw.js} +4 -4
- package/server/merge-verification-x3JO8Dtz.js +220 -0
- package/server/merged-docker-cleanup-worker-CTpC27Bs.js +107 -0
- package/server/merged-docker-cleanup-worker-Cdi9apm-.js +3 -0
- package/server/{multipart-parser-duPAfSBw.js → multipart-parser-IMSBfePV.js} +2 -2
- package/server/{no-resume-mode-Nw29vaFb.js → no-resume-mode-C5ULAXwO.js} +1 -1
- package/server/node_modules/.package-lock.json +27 -27
- 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/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-CTSGcK8p.js → orphan-proposed-reconciler-CWmOdM9-.js} +1 -1
- package/server/{orphan-proposed-reconciler-BvKkWMJQ.js → orphan-proposed-reconciler-Dg6U4ADZ.js} +24 -15
- package/server/package-lock.json +28 -28
- package/server/package.json +1 -1
- package/server/{pan-dir-B0c3w0Ya.js → pan-dir-ubraCiUg.js} +24 -10
- package/server/{paths-D-xWGHdh.js → paths-cXmOwSbh.js} +2 -2
- package/server/pending-lifecycle-claim-DEteYdS9.js +110 -0
- package/server/{pickup-DUCLWrJY.js → pickup-D8xtG1J2.js} +1 -1
- package/server/pipeline-membership-BGSvkT2M.js +3 -0
- package/server/pipeline-membership-CrAPLYtf.js +57 -0
- package/server/{pipeline-membership-mY3GprlK.js → pipeline-membership-gather-CET40frr.js} +177 -109
- package/server/pipeline-membership-gather-DTfcgxLl.js +3 -0
- package/server/{pipeline-notifier-BXkJzDC4.js → pipeline-notifier-BuQ0e4hF.js} +2 -2
- package/server/{pipeline-notifier-BJr8gQX6.js → pipeline-notifier-ImNXknf0.js} +1 -1
- package/server/post-merge-lifecycle-worker-DbO10pum.js +50 -0
- package/server/{project-pipelines-C0MWUeCU.js → project-pipelines-Bim6bThI.js} +2 -2
- package/server/{project-repos-B6GycDh9.js → project-repos-C0nuoBGv.js} +7 -3
- package/server/project-repos-CRE6Ykow.js +3 -0
- package/server/projects-B03Wr-xc.js +3 -0
- package/server/{prompts-DxzFXuLl.js → prompts-BEx08AIu.js} +2 -2
- package/server/{providers-u4Ga0jOr.js → providers-D7IluJe0.js} +1 -1
- package/server/{providers-qQAwGQDW.js → providers-evXhiQeg.js} +7 -7
- package/server/public/assets/{chunk-BO2N2NFS-BamJdinX.js → chunk-BO2N2NFS-D1s4-Sqp.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-DfOB8-w4.js → diagram-OG6HWLK6-1gdMoSF7.js} +1 -1
- package/server/public/assets/{dist-D7zYSEA6.js → dist-CxAOHbil.js} +1 -1
- package/server/public/assets/{dist-ByIuzMQW.js → dist-DqDRYW6P.js} +3 -3
- package/server/public/assets/{ganttDiagram-6RSMTGT7-EdmRyXL3.js → ganttDiagram-6RSMTGT7-BYex-Ec7.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-MerOfTX8.js → highlighted-body-OFNGDK62-DlVkiG0S.js} +1 -1
- package/server/public/assets/index-Cc7cnFC4.css +1 -0
- package/server/public/assets/index-K0hAYCgV.js +807 -0
- package/server/public/assets/{linear-BBbArIcK.js → linear-B4cuEFmO.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-DyDHFXHV.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-BKIddiJN.js → pieDiagram-4H26LBE5-CBHNBIJQ.js} +1 -1
- package/server/public/assets/{prod-B8vYiu52.js → prod-CN2nHBvX.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-D6RtoULk.js → quadrantDiagram-W4KKPZXB-Bom87VOQ.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-CLrCedZX.js → sankeyDiagram-5OEKKPKP-UrBeyLxk.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-hznR8DYl.js → xychartDiagram-2RQKCTM6-DhkbrIxR.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/{pull-requests-7N8WKseP.js → pull-requests-Cv7LxzUN.js} +1 -1
- package/server/{pull-requests-_lHueOHW.js → pull-requests-DHWiKxo7.js} +19 -10
- package/server/{queries-CjNIf-Ub.js → queries-DHJm7bTd.js} +631 -110
- package/server/{rally-CyWT_lNO.js → rally-B71M9f4o.js} +3 -3
- package/server/rally-YDjU513q.js +3 -0
- package/server/{rally-api-ClOSd-Tt.js → rally-api-D5uXN08-.js} +1 -1
- package/server/{rally-api-C8e_1JRi.js → rally-api-Dkqmok65.js} +2 -2
- package/server/{rally-client-lc-nokqr.js → rally-client-Bfqm6XI4.js} +4 -4
- package/server/{rally-client-sgtVqzNU.js → rally-client-CxsA6ExK.js} +1 -1
- package/server/{reap-terminal-sessions-7KeHv1R1.js → reap-terminal-sessions-BQ23nriz.js} +2 -2
- package/server/{reap-terminal-sessions-BtHPo6Xc.js → reap-terminal-sessions-CvmwaqKv.js} +2 -2
- package/server/{rebuild-stack-lwtsW0GO.js → rebuild-stack-0EEYReVZ.js} +16 -7
- package/server/{rebuild-stack-CFvcBHsS.js → rebuild-stack-qeRqHZxH.js} +2 -2
- package/server/{reconstruct-cache-C3Ui7ojV.js → reconstruct-cache-BbYFsqLa.js} +7 -6
- package/server/record-CtroO946.js +3 -0
- package/server/record-update-DH6dLJID.js +3 -0
- package/server/{record-update-dE1Aw83j.js → record-update-Z0QCxmMp.js} +124 -34
- package/server/{recovery-trip-BvRWfUXM.js → recovery-trip-eJe26h-f.js} +2 -2
- package/server/{release-engine-Cx48W7z8.js → release-engine-lPUp-MTd.js} +5 -5
- package/server/{release-set-CQfuN9-v.js → release-set-BwGeyZKX.js} +3 -3
- package/server/{remote-C_2hasl7.js → remote-BCd02Es1.js} +3 -3
- package/server/{remote-ChgimyYa.js → remote-CVGUhXMV.js} +3 -3
- package/server/{remote-agents-CA3Ihlxj.js → remote-agents-C1bssi41.js} +2 -2
- package/server/{remote-agents-By1ige5O.js → remote-agents-C_VxssLU.js} +300 -46
- package/server/{remote-completion-fVe9e_3u.js → remote-completion-DAB0P706.js} +12 -12
- package/server/resume-u9byntrq.js +3 -0
- package/server/{review-agent-DNboMyW4.js → review-agent-CD4RCI0Y.js} +1 -1
- package/server/{review-agent-CIGOQYBD.js → review-agent-CHhI66UP.js} +60 -47
- package/server/{review-artifacts-nRDPuMxd.js → review-artifacts-DSMRIfuJ.js} +7 -6
- package/server/{review-context-2uj-YQ8J.js → review-context-oFuBbiEE.js} +8 -8
- package/server/{in-flight-guard-CAAkqPLu.js → review-convoy-liveness-CpzrcJ5F.js} +3 -44
- package/server/review-status-BZH8h-6W.js +3 -0
- package/server/review-status-emit-CUExtHd5.js +50 -0
- package/server/{review-status-enrichment-Dci-ZwEt.js → review-status-enrichment-QV_hQkgS.js} +4 -4
- package/server/{review-status-source-CxuEjLGg.js → review-status-source-CpvJnvnQ.js} +24 -3
- package/server/review-status-source-ylw5QZUR.js +3 -0
- package/server/{review-status-sync-BTOpxtTC.js → review-status-sync-483sujRo.js} +2 -2
- package/server/{review-status-sync-DSDK3OMy.js → review-status-sync-NaWvI9Xf.js} +1 -1
- package/server/review-status-yljtTd-q.js +7521 -0
- package/server/{review-verdict-feedback-CTd4QMBu.js → review-verdict-feedback-BPDn4li_.js} +1 -1
- package/server/{review-verdict-feedback-CCjVA7Uk.js → review-verdict-feedback-CELeUinh.js} +48 -8
- package/server/{rollup-FGsKki9R.js → rollup-DTNvelz9.js} +8 -8
- package/server/{rollup-BKQC7jp4.js → rollup-DYZfq1c4.js} +1 -1
- package/server/{scanner-CnqEZeDy.js → scanner-CV35oSn4.js} +8 -7
- package/server/{sequence-io-D909zgeH.js → sequence-io-DF_8iuhV.js} +4 -4
- package/server/{sequencer-agent-CzkcK6P5.js → sequencer-agent-B2WeCtGi.js} +5 -5
- package/server/server.js +1952 -578
- package/server/{service-CLeAoU6G.js → service-Br9rpBNA.js} +81 -64
- package/server/{session-fork-CHI1XvL9.js → session-fork-D0LY152N.js} +2 -2
- package/server/{session-history-BT3IvqhC.js → session-history-BUyK29eq.js} +4 -4
- package/server/{settings-BTMvpNFU.js → settings-Bse1Pdcj.js} +3 -3
- package/server/settings-CdvIF84R.js +2 -0
- package/server/{settings-C0zgxOGf.js → settings-CvVGqNEs.js} +3 -2
- package/server/{shadow-engineering-BJfgm-hX.js → shadow-engineering-BWLa8ODz.js} +2 -2
- package/server/{shadow-state-7a-524T8.js → shadow-state-B4fpKxOO.js} +2 -2
- package/server/{shadow-state-DnDyjujH.js → shadow-state-FV6PHfEW.js} +1 -1
- package/server/{shadow-utils-Db3oroFG.js → shadow-utils-D7asqxOZ.js} +2 -2
- package/server/{ship-log-D9MlVzYU.js → ship-log-xplJ8t75.js} +1 -1
- package/server/{smart-compaction-CV2ukKND.js → smart-compaction-CPp2Ykf6.js} +1 -1
- package/server/{smart-compaction-KCYScAU1.js → smart-compaction-D3U_79f-.js} +8 -7
- package/server/{spawn-planning-session-qUC2VWu3.js → spawn-planning-session-1nFi3gfk.js} +1 -1
- package/server/{spawn-planning-session-DKpdFyOC.js → spawn-planning-session-DGfZ5B8D.js} +17 -17
- package/server/{specialist-completion-Ky9wCDpb.js → specialist-completion-Br48eiDP.js} +1 -1
- package/server/{specialist-context-Bn3dCGS2.js → specialist-context-cVbGnTa3.js} +5 -5
- package/server/{specialist-handoff-logger-CMEwYxa2.js → specialist-handoff-logger-DK-GTz4s.js} +2 -2
- package/server/{specialist-logs-C5p8G7tx.js → specialist-logs-Cl5-hqT8.js} +3 -3
- package/server/{specialists-CC4r-c2s.js → specialists-CNfYO3G2.js} +975 -227
- package/server/{specialists-jiuuyVkp.js → specialists-Cicieuzu.js} +18 -18
- package/server/{specialists-CShuVGWT.js → specialists-JHsdU3pA.js} +1 -1
- package/server/{specialists-DM6bWjsi.js → specialists-Tdezg_6N.js} +1 -1
- package/server/specs-Bt7WJDoC.js +3 -0
- package/server/src-CRmCHlma.js +11408 -0
- package/server/{src-CXmtj0im.js → src-Ck028hjO.js} +6 -6
- package/server/{src-CdmnTM2m.js → src-UWcGe0Ix.js} +3 -3
- package/server/{stack-health-Bn3o8FBX.js → stack-health-CJLMrLBl.js} +1 -1
- package/server/{stack-health-DxSdG9cW.js → stack-health-DqSqx0zv.js} +7 -5
- package/server/{stale-task-claims-KJKxxiiQ.js → stale-task-claims-CYFOUNlT.js} +4 -4
- package/server/{staleness-CT34nwr9.js → staleness-BQ-0gMYK.js} +1 -1
- package/server/{staleness-DPm7ClwA.js → staleness-D47CUJok.js} +1 -1
- package/server/{state-home-Cn_Qu8IX.js → state-home-BYV7qZTW.js} +2 -2
- package/server/{state-mapping-BL_-3Yt8.js → state-mapping-BVldLhBf.js} +1 -1
- package/server/{state-migrate-BGg2ZaOt.js → state-migrate-CvvBtS0Y.js} +4 -4
- package/server/{stuck-remediation-s9_2qfi6.js → stuck-remediation-Wt0UVvu1.js} +1 -1
- package/server/{stuck-remediation-DYuPRYYw.js → stuck-remediation-mkLC6G_t.js} +79 -22
- package/server/{substrate-bug-weights-service-B-FwCs5V.js → substrate-bug-weights-service-XfLAKnmK.js} +3 -3
- package/server/{summary-fork-DpcxN9tf.js → summary-fork-CD7GOts0.js} +2 -2
- package/server/{summary-fork-D1RAk9rJ.js → summary-fork-xiXBnWG9.js} +8 -8
- package/server/supervisor/{injection-budget-Csw5tqfJ.js → injection-budget-B5SbvDx2.js} +1 -1
- package/server/supervisor/{paths-DehGY2Fj.js → paths-K3noE4N_.js} +1 -1
- package/server/supervisor/pty-supervisor.js +49 -3
- package/server/supervisor/{pty-token-x-ea28Us.js → pty-token-B7lp0ElT.js} +2 -2
- package/server/{supervisor-wM4ooB5O.js → supervisor-DL788vos.js} +3 -3
- package/server/supervisor-UWiQNK-y.js +2 -0
- package/server/{swarm-readiness-DlP_UjHq.js → swarm-readiness-BV14DF5N.js} +3 -3
- package/server/{system-prerequisites-DUDj1YHf.js → system-prerequisites-pdWG6ZQs.js} +2 -2
- package/server/{teardown-workspace-DeTTImn-.js → teardown-workspace-l2F4_zim.js} +15 -16
- package/server/{test-agent-queue-MbxX5vqq.js → test-agent-queue-qakFIIGz.js} +6 -6
- package/server/{test-verdict-bWYBtqBg.js → test-verdict-BJYDggMm.js} +1 -1
- package/server/{test-verdict-gscuksPv.js → test-verdict-Gw-btEfb.js} +1 -1
- package/server/{tldr-daemon-BYFkts95.js → tldr-daemon-BKOYB616.js} +1 -1
- package/server/{tldr-daemon-C-69c3OI.js → tldr-daemon-CBaWkV9k.js} +2 -2
- package/server/{tmux-R7N7y-Mh.js → tmux-B1Wbxz5o.js} +3 -3
- package/server/{tmux-B6z7h_vZ.js → tmux-DQ6jB76i.js} +1 -1
- package/server/{launcher-generator-BBWG_SiS.js → tmux-dedup-DbN6MGzM.js} +428 -9
- package/server/{token-BK6t8BIT.js → token-Cxbk023d.js} +2 -2
- package/server/{token-util-DxXu-vd1.js → token-util-CLq2MmQt.js} +1 -1
- package/server/token-util-zlz9U0ki.js +3 -0
- package/server/{tracker-config-G6latr8C.js → tracker-config-DZ8Zn2nQ.js} +2 -2
- package/server/{tracker-utils-DHv5pSDT.js → tracker-utils-L0FKtjq2.js} +3 -3
- package/server/{traefik-connect-Df2uXPsQ.js → traefik-connect-bNX6jKkb.js} +1 -1
- package/server/{tunnel-CDVKJpRv.js → tunnel-BAm1XgjG.js} +3 -3
- package/server/{tunnel-DGdUkGoZ.js → tunnel-CjSnHdTc.js} +1 -1
- package/server/{types-5M0lupud.js → types-q67TYYg5.js} +1 -1
- package/server/uat-promote-verification-CKB9ZrKC.js +92 -0
- package/server/uat-train-Cu-4nvbf.js +2 -0
- package/server/uat-train-D5UjcyAa.js +0 -0
- package/server/{validate-IfDGkaVR.js → validate-Cxsx5Uz1.js} +8 -6
- package/server/{validation-CC9OPqJZ.js → validation-DEaTZafj.js} +1 -1
- package/server/{validation-Dw1pzDzr.js → validation-VZgJxmqc.js} +4 -4
- package/server/{verification-artifact-B3itKTxu.js → verification-artifact-C85cRTc_.js} +1 -1
- package/server/{verification-artifact-TVFSz_q1.js → verification-artifact-g3yuxQDL.js} +1 -1
- package/server/{verification-runner-BW4HOKAz.js → verification-runner-DlZI8yhw.js} +1 -1
- package/server/{verification-runner-CkgX6EtI.js → verification-runner-KDZIsBj4.js} +40 -18
- package/server/{vtt-parser-DYPbKcIJ.js → vtt-parser-Jr94BF3Y.js} +1 -1
- package/server/{work-agent-prompt-Du8Vh2aJ.js → work-agent-prompt-C-vuP3_J.js} +20 -9
- package/server/workflows-CHrx_hcW.js +2 -0
- package/server/{workflows-mbQzh6mQ.js → workflows-D0oip4eV.js} +161 -78
- package/server/{workspace--8tnhDI0.js → workspace-BqFg__wH.js} +1 -1
- package/server/{workspace-BPUws1-_.js → workspace-C0fH3aek.js} +3 -3
- package/server/workspace-anchor-drift-B4gMRHl4.js +3 -0
- package/server/workspace-anchor-drift-CZKofakh.js +224 -0
- package/server/{workspace-config-CIVWZOQr.js → workspace-config-B123aZl-.js} +1 -1
- package/server/workspace-manager-CDTKjjdU.js +3 -0
- package/server/{workspace-manager-CBhNdzE4.js → workspace-manager-CwO-Hek7.js} +156 -117
- package/server/{workspace-metadata-_WygnyoX.js → workspace-metadata-CQv00QwK.js} +2 -2
- package/server/{workspace-metadata-BzHnwwX4.js → workspace-metadata-D4M8BM4W.js} +1 -1
- package/server/{workspaces-Do_9J0LQ.js → workspaces-j1e_6aAT.js} +719 -292
- 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-peer-review/SKILL.md +195 -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/agents-wi9NWzs2.js +0 -3
- package/server/archive-planning-BZDgzoEj.js +0 -3
- package/server/cli-B86rejVV.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/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/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/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/specs-C8Wsn2XO.js +0 -3
- package/server/src-DtcUOZCq.js +0 -4826
- package/server/supervisor-FTJAIsAK.js +0 -2
- package/server/token-util-DuPuNriz.js +0 -3
- package/server/tracker-utils-B4ylXZQK.js +0 -3
- package/server/uat-train-B05BWkp-.js +0 -2
- package/server/uat-train-DDSrSoV1.js +0 -2152
- package/server/workflows-BQu4RFQ-.js +0 -2
- package/server/workspace-manager-CWT55qeI.js +0 -3
package/server/server.js
CHANGED
|
@@ -1,110 +1,115 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import { A as canUseHarnessSync,
|
|
3
|
-
import { a as shouldRefuseHostDashboardPort, i as readHostDashboardApiPort, n as getDashboardIdentity, r as isNonPrimaryCheckoutRoot } from "./deacon-nudge-log-
|
|
4
|
-
import { $ as
|
|
5
|
-
import { a as
|
|
6
|
-
import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-
|
|
2
|
+
import { A as canUseHarnessSync, An as extractTeamPrefix, Cn as resolveStateReadHomeSync, D as resolveTieredExecutionEnabled, Dr as GitHubApiError, E as resolveTieredExecutionBlock, Fr as init_errors, Gn as init_projects, Gr as OVERDECK_HOME, H as init_providers, I as UnknownModelError, In as getIssuePrefix, Ir as AGENTS_DIR, J as defaultBackgroundAiFeatures, Jn as listProjects, M as init_harness_policy, Mn as findProjectByPathSync, Mt as getIssueWorkspacePath, Nr as TrackerError, On as ProjectRenameError, Pn as findProjectByTeamSync, Pt as init_record, Q as computeModelOrigin, Qr as SYNC_SOURCES, R as getBuiltInDefaultHarness, Sn as init_state_read_home, T as init_tier_table, Tr as FsError, V as getProviderForModelSync, Vr as CLAUDE_DIR, Wr as LOGS_DIR, X as DEFAULT_ROLES, Y as init_registry, Yn as listProjectsSync, Z as DEFAULT_WORKHORSES, Zn as loadProjectsConfigSync, _ as getDefaultDocsConfig, ar as resolveProjectFromIssueSync, at as getModelEffortLevelsSync, ci as init_paths, cn as flushAutoCommits, ct as modelSupportsImagesSync, d as loadConfigNoMigration, dr as setProjectSwarmPolicySync, ei as encodeClaudeProjectDir, er as registerProjectSync, f as loadConfigSync, fi as sessionFilePath, g as mergeConfigs, gr as init_issue_id, gt as ROLE_EFFORTS, h as jsYaml, hr as extractPrefixSync, ht as PARENT_MODEL_REF, i as getConversationsConfig, ii as getDocsTelemetryPath, ir as resolveProjectFromIssue, jr as ProcessSpawnError, k as validateTieredExecutionConfig, li as isDevMode, ln as init_auto_commit, lr as setProjectAutoMergeDefaultSync, lt as resolveModelIdSync, m as init_js_yaml, mt as COMPLIANCE_MODES, n as clearConfigCache, ni as getDocsDisableStatePath, nt as MODEL_CAPABILITIES, o as getGlobalConfigPath, oi as getLegacyHome, ot as hasModelCapabilitySync, p as updateConversationsConfig, r as getConversationSearchConfigSync, ri as getDocsIndexPath, rr as resolveInfraRepo, rt as MODEL_DEPRECATIONS, s as init_load, si as getOverdeckHome, sn as flushAllPendingAutoCommits, st as init_model_capabilities, t as init_config_yaml, ti as getDocsBudgetStatePath, tr as renameProject, tt as resolveModel, u as isTldrEnabledSync, ui as packageRoot, ur as setProjectMergeTrainSync, v as getDefaultTtsDaemonConfig, vr as parseIssueIdSync, w as TieredExecutionConfigError, xr as require_dist$1, y as mergeTtsDaemonConfigs, z as getKimiAnthropicBaseUrl, zn as getProjectSync, zt as readIssueRecordSync } from "./config-yaml-CmOPzmBb.js";
|
|
3
|
+
import { a as shouldRefuseHostDashboardPort, i as readHostDashboardApiPort, n as getDashboardIdentity, r as isNonPrimaryCheckoutRoot } from "./deacon-nudge-log-BNBebzeL.js";
|
|
4
|
+
import { $ as composerCommandConfirmationFromBody, A as resolveAllowedHarness, B as cleanupUnreferencedConversationAttachments, C as handleConversationCreate, Ct as isTrustedOriginForHost, D as handleConversationStop, Dt as getDefaultCwd, E as handleConversationResume, Et as httpHandler, F as tmuxSessionExists, G as isManagedConversationAttachmentPath, H as extractConversationAttachmentPaths, I as waitForPiTuiReady, J as composerCommandResultHttpStatus, K as removeConversationAttachment, L as waitForTmuxSession$1, M as spawnConversationSession, N as startConversationModelBackfill, O as handleConversationSwitchModel, Ot as jsonResponse, P as stopConversationRuntime, Q as ComposerCommandConfirmationError, R as cleanupConversationAttachments, S as conversationSessionAliveFromState, St as getHeaderFromMap, T as handleConversationRestartAll, Tt as validateOriginHeaders, U as getConversationAttachmentsRoot, V as ensureConversationAttachmentDir, W as hasConversationAttachment, X as resolvePolicy, Y as handleComposerCommandMessage, Z as ComposerCommandParseError, _ as isPiControlChannelHarness, _t as rejectUnauthorizedDashboardRequest, a as agentsRouteLayer, at as panCliInvocation, b as validateConversationControlAckOrigin, bt as isRespawnPending, c as codexConversationPendingInput, ct as resolveAcpTranscriptPath, d as handleConversationCodexApproval, dt as resolveCodexRolloutPath, et as evaluateSpawnGuardrails, f as handleConversationCompact, ft as resolveJsonlPath, g as handleConversationThinkingLevel, gt as hasDashboardInternalToken, h as handleConversationPlanAction, ht as dashboardSessionCookieHeader, j as shouldReportUnresolvedLiveSession, k as isInsideGitWorkTree, kt as jsonStringResponse, l as deliverConversationViaControlChannel, lt as resolveAgentHarness, m as handleConversationDeliveryMethod, mt as dashboardCsrfToken, nt as resolveAgentGitInfo, o as saveAgentStateAndEmitEvent, p as handleConversationControlAck, pt as resolvePiSessionPath, q as runInBatches, rt as resolveConversationGitInfo, s as saveAgentStateAndEmitEventProgram, st as readLauncherPinnedSessionId, t as specialistsRouteLayer, tt as invalidateAgentsCache, u as handleConversationAbort, ut as resolveClaudeSessionId, v as pickDeliverAs, vt as rejectUnauthorizedDashboardSessionMintRequest, w as handleConversationDelete, wt as validateOrigin$1, x as conversationNeedsRunningRepair, xt as waitForSessionRespawn, y as resolveConversationDeliveryMethod, yt as rejectUnsafeDashboardMutationRequest, z as cleanupOrphanedConversationAttachments } from "./specialists-CNfYO3G2.js";
|
|
5
|
+
import { a as emitDashboardLifecycleSync, i as emitActivityTtsSync, o as init_activity_logger, r as emitActivityEntrySync } from "./activity-logger-CyteR4JO.js";
|
|
6
|
+
import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-BjuxvjdS.js";
|
|
7
7
|
import { n as openDatabase, t as init_driver } from "./driver-CKVGi51s.js";
|
|
8
|
-
import {
|
|
9
|
-
import { $ as
|
|
10
|
-
import { a as init_event_store, i as initEventStore, n as getEventStore } from "./event-store-
|
|
11
|
-
import { A as
|
|
12
|
-
import {
|
|
13
|
-
import { a as EventStoreService, c as ReadModelService,
|
|
14
|
-
import { c as listAllAgentsSync, n as AgentsResolverLive, o as init_agents } from "./agents-
|
|
15
|
-
import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-
|
|
16
|
-
import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-
|
|
17
|
-
import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-
|
|
18
|
-
import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-
|
|
19
|
-
import {
|
|
20
|
-
import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-
|
|
21
|
-
import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-
|
|
22
|
-
import { u as init_agent_runtime_mirror } from "./session-history-
|
|
23
|
-
import { t as init_behavior } from "./behavior-
|
|
24
|
-
import { n as AgentStateServiceLive } from "./agent-state-service-
|
|
25
|
-
import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-
|
|
8
|
+
import { i as updateIssueRecord, n as clearRecordPipelineClosedOutSync, r as init_record_update } from "./record-update-Z0QCxmMp.js";
|
|
9
|
+
import { $ as buildChildEnvSync, B as sendKeysAsync, C as getWindowDimensions, D as killSession, E as isPaneDead, H as sessionExists, L as resizeWindow, M as listSessionNames, T as isHarnessProcessAlive, V as sendRawKeystroke, X as init_ui_theme, Z as setUiTheme, d as ensureManagedTmuxContextOnce, et as buildChildEnvWithoutTmuxSync, i as capturePane, l as deliveryVerifyLine, n as buildTmuxArgs, o as capturePaneText, s as createSession, tt as init_child_env, w as init_tmux, z as sendKeys } from "./tmux-B1Wbxz5o.js";
|
|
10
|
+
import { a as init_event_store, i as initEventStore, n as getEventStore } from "./event-store-zY5MJHgF.js";
|
|
11
|
+
import { A as AgentRuntimeSnapshot, C as FlywheelStatus, E as SystemHealthSnapshot, M as ReviewStatusSnapshot, O as MemoryObservation, S as FlywheelRunId, T as DomainEvent, b as PanRpcGroup, j as AgentSnapshot, l as ContextLayerSaveRequest, n as COMPOSER_COMMAND_MANIFEST, p as FlywheelStats, r as compareIssueIds, s as getHarnessBehavior, t as init_src, u as ContextPreviewRequest, w as EDITORS, x as WS_METHODS, y as PanRpcError } from "./src-CRmCHlma.js";
|
|
12
|
+
import { A as getOrCreateInstallId, D as getAnalyticsService, M as init_config, N as resolveTelemetryEnabled, O as init_service, P as telemetryEnvironmentForcesOff, S as setReviewStatusSync, a as clearStuckMergeStatuses, c as fixStuckReadyForMerge, f as init_review_status, g as markWorkspaceStuck, i as clearReviewStatus, j as init_install_id, k as synchronizeAnalyticsServices, l as getReviewStatus, m as loadReviewStatuses, p as loadReadyForMergeFlags, s as fixStuckCommentedReviews, u as getReviewStatusSync, x as setReviewStatus } from "./review-status-yljtTd-q.js";
|
|
13
|
+
import { a as EventStoreService, c as ReadModelService, f as init_read_model, h as toRole, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toAgentStatus, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentResolution, s as init_domain_services, t as IssueLifecycle, u as activityEntriesFromStoredEvents } from "./issue-lifecycle-C4Zj0WmE.js";
|
|
14
|
+
import { c as listAllAgentsSync, n as AgentsResolverLive, o as init_agents } from "./agents-C5rWYhb6.js";
|
|
15
|
+
import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-cXmOwSbh.js";
|
|
16
|
+
import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-DHmCSLar.js";
|
|
17
|
+
import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-BORBTo0y.js";
|
|
18
|
+
import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-DEWD82qK.js";
|
|
19
|
+
import { $ as operatorInterventionEvent, $n as getAgentDir, Bt as init_transcript_landing, Cr as init_agent_record_sync, D as init_tier_supervisor, E as deliverCommitForReview, Fn as init_openai_auth, Fr as getAgentRuntimeState, Hr as checkCodexAuthStatus, Ir as getAgentRuntimeStateSync, Mt as deliverAgentMessage, Pn as getOpenAIAuthStatus, Pr as waitForReadySignal, Q as init_operator_interventions, Qt as init_staffing, Tn as init_claude_auth, Ur as init_codex_auth, Vt as probeTranscriptSince, X as messageAgent, Y as init_messaging, _r as saveAgentStateSync, a as listRunningAgentsSync, b as init_agents$1, bt as init_concurrency, c as getRuntimeCensus, d as panePidsForSession, dn as getProviderAuthMode, en as resolveImplicitStaffing, f as refreshRuntimeCensus, i as listRunningAgents, j as supervisorAgentId, jr as normalizeAgentId, kn as getProviderEnvForModel, l as getRuntimeCensusSnapshot, mn as injectPiConversationMemory, n as init_queries, p as runtimeCensusHasHarnessProcess, r as listAgentStates, rr as getAgentStateSync, tr as getAgentState, u as init_runtime_census, vt as emergencyBrake, wn as getClaudeAuthStatus, wr as readAgentHarnessModelRecordSync, zt as captureTranscriptUserRecordSnapshot } from "./queries-DHJm7bTd.js";
|
|
20
|
+
import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-Dv3LUaNW.js";
|
|
21
|
+
import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-Br9rpBNA.js";
|
|
22
|
+
import { u as init_agent_runtime_mirror } from "./session-history-BUyK29eq.js";
|
|
23
|
+
import { t as init_behavior } from "./behavior-CfIg6pKp.js";
|
|
24
|
+
import { n as AgentStateServiceLive } from "./agent-state-service-BlnSkRFA.js";
|
|
25
|
+
import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-DZ8Zn2nQ.js";
|
|
26
26
|
import { d as init_typed_errors, i as PlanEmpty, l as WorkspaceCreateError, n as AgentStartError, s as TrackerApiError, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-2BTMxkZq.js";
|
|
27
|
-
import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-
|
|
28
|
-
import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-
|
|
29
|
-
import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-
|
|
30
|
-
import {
|
|
31
|
-
import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-
|
|
32
|
-
import { i as ensureInternalTokenSync, o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-
|
|
33
|
-
import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-
|
|
34
|
-
import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-
|
|
35
|
-
import { n as init_review_status_source, t as classifyAdvancingSessionLifecycle } from "./review-status-source-
|
|
27
|
+
import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-BQU36QqE.js";
|
|
28
|
+
import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-BfyDxuRN.js";
|
|
29
|
+
import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-Bfqm6XI4.js";
|
|
30
|
+
import { n as resolveGitHubIssueSync, r as resolveTrackerTypeSync, t as init_tracker_utils } from "./tracker-utils-L0FKtjq2.js";
|
|
31
|
+
import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-DmCh7EHj.js";
|
|
32
|
+
import { i as ensureInternalTokenSync, o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-DvMTQSOS.js";
|
|
33
|
+
import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-BuQ0e4hF.js";
|
|
34
|
+
import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-483sujRo.js";
|
|
35
|
+
import { n as init_review_status_source, t as classifyAdvancingSessionLifecycle } from "./review-status-source-CpvJnvnQ.js";
|
|
36
36
|
import { a as PAN_DIRNAME, d as WORKSPACE_RUNTIME_DIRNAME, f as asPanSpecDocument, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-hraoaQIp.js";
|
|
37
|
-
import { C as transitionToMerging, _ as
|
|
38
|
-
import {
|
|
39
|
-
import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-
|
|
40
|
-
import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, F as markConversationEnded, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, b as getConversationByClaudeSessionId, et as updateConversationTitle, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, q as setFavorite, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-
|
|
41
|
-
import { n as isBackgroundFeatureEnabled, t as init_features } from "./features
|
|
42
|
-
import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-
|
|
43
|
-
import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-
|
|
44
|
-
import {
|
|
45
|
-
import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-
|
|
46
|
-
import { C as ensureProjectLayer, E as init_layers, I as workspaceContextFile, N as resolveProjectContextFile, P as resolveWorkspaceContextFile, S as codexGlobalContextFile, T as globalContextFile$1, b as validateTemplate, c as init_render, d as userContentOutsideRegion, i as workspaceContextWithoutProjectLayer, r as init_assemble, s as hasManagedRegion, v as init_harness, y as renderForHarness } from "./assemble-
|
|
47
|
-
import { l as init_codex, s as findRolloutPath } from "./codex-
|
|
48
|
-
import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-
|
|
49
|
-
import { f as init_config, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-
|
|
50
|
-
import { C as
|
|
51
|
-
import {
|
|
52
|
-
import { a as loadCloisterConfigSync, o as saveCloisterConfigSync, r as init_config$
|
|
53
|
-
import { c as isStateMigrated, i as ensureStateWorktree, o as init_state_home, r as clearStateMigrationCache, s as inspectStateMigration } from "./state-home-
|
|
54
|
-
import { i as checkPrdGateSync, s as promoteWorkspacePrdDraft, t as init_pan_dir } from "./pan-dir-
|
|
55
|
-
import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-
|
|
56
|
-
import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-
|
|
57
|
-
import { a as buildMatchQuery, c as init_query_expansion, i as resolveKnowledgeBundleRoot, n as init_injection, o as init_search, r as injectPromptTimeMemory, s as clearQueryExpansionCache } from "./injection-
|
|
58
|
-
import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-
|
|
59
|
-
import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-
|
|
60
|
-
import { A as createSettledTtlPromiseCache, D as init_advisory_checks, E as verifyAppCanMerge, M as withConcurrencyLimit, O as isAdvisoryCheckName, d as getPullRequestState, f as init_github_app, j as init_concurrency$1, k as createPromiseConcurrencyLimiter, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-
|
|
61
|
-
import { C as getWorkspacePathForIssue, E as stopAgentOutputService, S as resolveIssueHeadlineCost, T as startAgentOutputService, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, w as retainAgentOutputInterest, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-
|
|
62
|
-
import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, b as parseAcpConversationMessages, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages, y as init_acp_conversation_parser } from "./conversation-service-
|
|
63
|
-
import { c as countPendingAskUserQuestionsForAgent,
|
|
64
|
-
import { i as CostThresholdError, l as embed, s as parseRelativeTime } from "./scanner-
|
|
65
|
-
import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-
|
|
66
|
-
import { n as recordBackgroundAiCost, t as init_cost } from "./cost-
|
|
67
|
-
import { a as getByIssueId, i as parseFlywheelStatsWindow, n as derivePipelineRunStatsInputs, o as markFixed, r as computeFlywheelStats, s as upsert } from "./substrate-bug-weights-service-
|
|
68
|
-
import {
|
|
69
|
-
import {
|
|
70
|
-
import {
|
|
71
|
-
import {
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
import {
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
77
|
-
import {
|
|
78
|
-
import {
|
|
79
|
-
import {
|
|
80
|
-
import {
|
|
81
|
-
import {
|
|
82
|
-
import { a as applyIssueObjectionLabel, c as applyIssueReleasedLabel, d as removeIssueBlocksMainLabel, f as removeIssueObjectionLabel, g as removeIssueVetoedLabel, h as removeIssueReleasedLabel, i as applyIssueBlocksMainLabel, l as applyIssueVetoedLabel, m as removeIssueReadyLabel, o as applyIssueParkedLabel, p as removeIssueParkedLabel, s as applyIssueReadyLabel, u as init_label_ops } from "./label-reconciler
|
|
83
|
-
import {
|
|
84
|
-
import { a as
|
|
85
|
-
import {
|
|
86
|
-
import {
|
|
87
|
-
import {
|
|
88
|
-
import {
|
|
89
|
-
import {
|
|
90
|
-
import { t as
|
|
91
|
-
import {
|
|
92
|
-
import {
|
|
93
|
-
import {
|
|
94
|
-
import {
|
|
95
|
-
import {
|
|
96
|
-
import { t as
|
|
97
|
-
import {
|
|
98
|
-
import {
|
|
99
|
-
import { n as
|
|
100
|
-
import {
|
|
101
|
-
import {
|
|
102
|
-
import {
|
|
103
|
-
import {
|
|
104
|
-
import {
|
|
105
|
-
import { a as
|
|
106
|
-
import "./
|
|
107
|
-
import { i as
|
|
37
|
+
import { C as transitionToMerging, S as scheduleAutoMergeWithResult, _ as markMergingBlocked, b as requeueToPending, c as isFlywheelGloballyPaused, d as listActiveAutoMerges, f as listDuePendingAutoMerges, g as markMerged, h as markFailed, m as markBlocked, p as listProblemAutoMerges, r as getActionableAutoMerge, s as init_merge_sync, t as cancelPending } from "./merge-sync-CQ-LgZ1_.js";
|
|
38
|
+
import { D as writeSpecForIssue, E as writeSpecDocument, S as init_specs, a as findWorkspaceDraftPlan, m as readWorkspacePlanSync, o as init_io, p as readWorkspacePlan, r as findPlan, s as isPlanningComplete, u as readPlan, v as init_types$1, x as findSpecByIssue, y as subItemsOf } from "./io-VHvc0Ssp.js";
|
|
39
|
+
import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-C8mB3KuB.js";
|
|
40
|
+
import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, F as markConversationEnded, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, _t as getDiscoveredStats, at as aggregateDiscoveredSessionCost, b as getConversationByClaudeSessionId, ct as countDiscoveredSessions, et as updateConversationTitle, ft as findDiscoveredSessions, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, mt as getDiscoveredSessionById, ot as aggregateDiscoveredSessionCostBy, q as setFavorite, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-BUpYsOZg.js";
|
|
41
|
+
import { n as isBackgroundFeatureEnabled, t as init_features } from "./features--nFkJY8v.js";
|
|
42
|
+
import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-Bse1Pdcj.js";
|
|
43
|
+
import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-evXhiQeg.js";
|
|
44
|
+
import { d as generateLauncherScriptSync, f as init_launcher_generator, g as requireModelOverrideSync, h as normalizeModelOverrideSync, m as init_model_validation, p as MODEL_ID_PATTERN } from "./tmux-dedup-DbN6MGzM.js";
|
|
45
|
+
import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-CN0cSCPp.js";
|
|
46
|
+
import { C as ensureProjectLayer, E as init_layers, I as workspaceContextFile, N as resolveProjectContextFile, P as resolveWorkspaceContextFile, S as codexGlobalContextFile, T as globalContextFile$1, b as validateTemplate, c as init_render, d as userContentOutsideRegion, i as workspaceContextWithoutProjectLayer, r as init_assemble, s as hasManagedRegion, v as init_harness, y as renderForHarness } from "./assemble-DnffNpOo.js";
|
|
47
|
+
import { l as init_codex, s as findRolloutPath } from "./codex-Drlf5Xhf.js";
|
|
48
|
+
import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-DqkftwTb.js";
|
|
49
|
+
import { f as init_config$1, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-Dr3pW6w6.js";
|
|
50
|
+
import { C as setFlywheelRequireUatBeforeMerge, T as setSetting, _ as setCloisterSpawnsPausedSync, c as isCloisterSpawnsPausedSync, d as isFlywheelAutoPickupBacklog, f as isFlywheelGloballyPaused$1, h as setBootReconciliationDecision, m as isMergeTrainEnabled, n as FLYWHEEL_GLOBAL_PAUSE_KEY, o as getSetting, p as isFlywheelRequireUatBeforeMerge, r as getBootReconciliationState, s as init_control_settings, t as FLYWHEEL_ACTIVE_RUN_ID_KEY, u as isDeaconGloballyPausedSync, w as setMergeTrainEnabled, x as setFlywheelAutoPickupBacklog, y as setDeaconGloballyPausedSync } from "./control-settings-C7DUehE1.js";
|
|
51
|
+
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-CqMqM1Mb.js";
|
|
52
|
+
import { a as loadCloisterConfigSync, o as saveCloisterConfigSync, r as init_config$2, s as shouldAutoStart } from "./config-B2IMcBxx.js";
|
|
53
|
+
import { c as isStateMigrated, i as ensureStateWorktree, o as init_state_home, r as clearStateMigrationCache, s as inspectStateMigration } from "./state-home-BYV7qZTW.js";
|
|
54
|
+
import { i as checkPrdGateSync, s as promoteWorkspacePrdDraft, t as init_pan_dir } from "./pan-dir-ubraCiUg.js";
|
|
55
|
+
import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-D-lGdzK3.js";
|
|
56
|
+
import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-BV14DF5N.js";
|
|
57
|
+
import { a as buildMatchQuery, c as init_query_expansion, i as resolveKnowledgeBundleRoot, n as init_injection, o as init_search, r as injectPromptTimeMemory, s as clearQueryExpansionCache } from "./injection-UCf8EsjX.js";
|
|
58
|
+
import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-BeOomFa-.js";
|
|
59
|
+
import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-CLq2MmQt.js";
|
|
60
|
+
import { A as createSettledTtlPromiseCache, D as init_advisory_checks, E as verifyAppCanMerge, M as withConcurrencyLimit, O as isAdvisoryCheckName, d as getPullRequestState, f as init_github_app, j as init_concurrency$1, k as createPromiseConcurrencyLimiter, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-CQ1Lo6LA.js";
|
|
61
|
+
import { C as getWorkspacePathForIssue, E as stopAgentOutputService, S as resolveIssueHeadlineCost, T as startAgentOutputService, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, w as retainAgentOutputInterest, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-j1e_6aAT.js";
|
|
62
|
+
import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, b as parseAcpConversationMessages, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages, y as init_acp_conversation_parser } from "./conversation-service-5aCnq1zR.js";
|
|
63
|
+
import { c as countPendingAskUserQuestionsForAgent, g as detectAwaitingInputFromPaneSync, h as detectAwaitingInputForAgent, l as getAgentJsonlMtime, m as scanPendingInputsPromise, o as getRuntimeForAgent, s as computeAgentEnrichment } from "./stuck-remediation-mkLC6G_t.js";
|
|
64
|
+
import { a as enrichSessions, c as searchSessions, i as CostThresholdError, l as embed, n as getSessionsFeedFacets, o as embedSessions, r as listSessionsFeed, s as parseRelativeTime, t as scan } from "./scanner-CV35oSn4.js";
|
|
65
|
+
import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-D9PR1IC0.js";
|
|
66
|
+
import { n as recordBackgroundAiCost, t as init_cost } from "./cost-CvxRrucd.js";
|
|
67
|
+
import { a as getByIssueId, i as parseFlywheelStatsWindow, n as derivePipelineRunStatsInputs, o as markFixed, r as computeFlywheelStats, s as upsert, t as listSubstrateBugWeights } from "./substrate-bug-weights-service-XfLAKnmK.js";
|
|
68
|
+
import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-DF_8iuhV.js";
|
|
69
|
+
import { _ as selectNeedsPlanning, c as classifyIssue, d as computeLanes, f as computeStats, g as normalizeGate, l as computeCohort, m as init_pickup, p as computeWaves, u as computeEpicGroups } from "./pickup-D8xtG1J2.js";
|
|
70
|
+
import { B as getBook, C as readCurrentLatestFlywheelStatus, D as writeFlywheelLaunchMetadata, E as subscribeLatestFlywheelStatus, F as setItemRequirements, H as liveOrderIssueLookup, I as setSettings, L as setStatus, M as moveItem, N as removeItem, O as writeLatestFlywheelStatus, P as renameBook, R as backlogCandidates, S as nextFlywheelRunId, T as resolveLiveFlywheelRunId, V as listBooks, a as isFlywheelDevcontainerRuntime, b as isFlywheelRunId, f as spawnFlywheelAgent, g as abortFlywheelRun, j as createBook, k as addItems, p as buildClassifyLookups, s as loadResumeSessionId, t as FLYWHEEL_ORCHESTRATOR_AGENT_ID, u as saveResumeSessionId, v as getFlywheelRunDetail, w as readFlywheelLaunchMetadata, x as listFlywheelRuns, z as computeBookProgress } from "./flywheel-BiT3odRb.js";
|
|
71
|
+
import { At as formatUptime, Bt as classifyAgentHealth, D as loadConfig, F as setAgentStoppedNotifier, G as isBootReconciliationCandidate, I as setMergeReadyNotifier, It as getSystemHealthEvidenceSnapshot, K as listBootReconciliationCandidates, Mt as getCurrentDockerStats, Nt as getAcceptedSystemHealthSnapshot, O as loadState, P as setAgentStatusChangedNotifier, Pt as getDeployStaleness, Rt as isSmeeConfiguredSync, W as extendBootReconciliationGrace, b as getDeaconLogs, jt as getContainerHistory, kt as getResourceStacks, n as assessDeaconPatrolFreshness, q as startBootReconciliation, t as applyBootReconciliationDecision, wt as paneShowsClaudeBootBlockingScreen, zt as startSmeeProcessSync } from "./deacon-hi9KLPLT.js";
|
|
72
|
+
import { c as installGitHooksInDir, f as detectPlatform, p as init_platform, s as init_git_hooks } from "./workspace-manager-CwO-Hek7.js";
|
|
73
|
+
import { a as getShadowState, s as init_shadow_state } from "./shadow-state-B4fpKxOO.js";
|
|
74
|
+
import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-B6KJkmHZ.js";
|
|
75
|
+
import { i as parseArtifactRef, r as init_forge } from "./forge-CZbSg6Ds.js";
|
|
76
|
+
import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-BG0RUZiu.js";
|
|
77
|
+
import { V as getReviewerSessionName, t as init_specialists } from "./specialists-Cicieuzu.js";
|
|
78
|
+
import { s as findPrdAnywhereSync } from "./archive-planning-C0lAbNB_.js";
|
|
79
|
+
import { b as resolveSwarmPolicy } from "./deacon-swarm-DBxUaO-A.js";
|
|
80
|
+
import { a as init_boot_gates, i as formatBootGateState, o as resolveBootGates } from "./no-resume-mode-C5ULAXwO.js";
|
|
81
|
+
import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-Bq3epG58.js";
|
|
82
|
+
import { a as applyIssueObjectionLabel, c as applyIssueReleasedLabel, d as removeIssueBlocksMainLabel, f as removeIssueObjectionLabel, g as removeIssueVetoedLabel, h as removeIssueReleasedLabel, i as applyIssueBlocksMainLabel, l as applyIssueVetoedLabel, m as removeIssueReadyLabel, o as applyIssueParkedLabel, p as removeIssueParkedLabel, s as applyIssueReadyLabel, u as init_label_ops } from "./label-reconciler--F85rufp.js";
|
|
83
|
+
import { r as computeMergeQueueFromCandidates, s as listEligibleCandidatesByProject } from "./flywheel-merge-order-BJv1DZz1.js";
|
|
84
|
+
import { a as gatherProjectLensSignals, g as parseIssueIdFromTextSync, h as init_resource_utils, n as PipelineMembershipUnavailableError, s as init_pipeline_membership_gather, u as listOpenPullRequestsSnapshot } from "./pipeline-membership-gather-CET40frr.js";
|
|
85
|
+
import { n as init_pipeline_membership, r as resolvePipelineMembership } from "./pipeline-membership-CrAPLYtf.js";
|
|
86
|
+
import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-CQv00QwK.js";
|
|
87
|
+
import { i as resolveAutoSpawnOnFinalize, o as spawnPlanningSession } from "./spawn-planning-session-DGfZ5B8D.js";
|
|
88
|
+
import { d as killRemoteAgent, m as loadRemoteAgentState, o as getRemoteAgentOutput, r as checkRemoteSpendCap, s as init_remote_agents, v as sendToRemoteAgent, y as spawnRemoteAgent } from "./remote-agents-C_VxssLU.js";
|
|
89
|
+
import { r as spawnInspectAgent } from "./inspect-agent-6kylZnrm.js";
|
|
90
|
+
import { i as lookupPullRequestNumberForBranch, n as init_github_pr_lookup, t as githubPrLookupSource } from "./github-pr-lookup-BDq6Wznz.js";
|
|
91
|
+
import { a as fetchIssuePullRequestDiff, c as getCachedIssuePrTabResponse, d as setCachedIssuePrTabResponse, i as fetchIssuePullRequestDetails, l as getIssuePrTabCacheGeneration, n as fetchIssueCheckRuns, o as init_pull_requests, r as fetchIssuePullRequest, s as bumpIssuePrTabCacheGeneration, u as init_pr_tab_cache } from "./pull-requests-DHWiKxo7.js";
|
|
92
|
+
import { n as DOD_ROWS } from "./dod-Dar-yheg.js";
|
|
93
|
+
import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-DTNvelz9.js";
|
|
94
|
+
import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-CBaWkV9k.js";
|
|
95
|
+
import { T as listGitOperationsSync, w as init_git_activity } from "./merge-agent-DdMVSV2Y.js";
|
|
96
|
+
import { t as readVerificationArtifact } from "./verification-artifact-g3yuxQDL.js";
|
|
97
|
+
import { i as readPendingDeploy, n as init_deploy_queue } from "./deploy-queue-UjKGYsDe.js";
|
|
98
|
+
import { t as getAgentCommandSync } from "./settings-CvVGqNEs.js";
|
|
99
|
+
import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-CHhI66UP.js";
|
|
100
|
+
import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-BCd02Es1.js";
|
|
101
|
+
import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-CJn35FHQ.js";
|
|
102
|
+
import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-xiXBnWG9.js";
|
|
103
|
+
import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-BoqdDXWF.js";
|
|
104
|
+
import { t as init_context_layers } from "./context-layers-dR5YxHYB.js";
|
|
105
|
+
import { a as appendLinearMcpAuthHealthyEvent, r as appendLinearMcpAuthCallbackRelayedEvent, u as resolveLinearMcpAuthIntervention } from "./linear-mcp-auth-BnU4TYfY.js";
|
|
106
|
+
import { i as getMergeBlockersPayload, n as hasOrderIssuePrd, r as validateBookForStart, t as createOrderPrdLookup } from "./validate-Cxsx5Uz1.js";
|
|
107
|
+
import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-B2WeCtGi.js";
|
|
108
|
+
import { n as sameCanonicalReviewStatus, t as emitReviewStatusChanged } from "./review-status-emit-CUExtHd5.js";
|
|
109
|
+
import "./supervisor-DL788vos.js";
|
|
110
|
+
import { l as startUatTrainReconciler, u as stopUatTrainReconciler } from "./uat-train-D5UjcyAa.js";
|
|
111
|
+
import { n as settlePendingLifecycleClaim, t as claimPendingLifecycleFile } from "./pending-lifecycle-claim-DEteYdS9.js";
|
|
112
|
+
import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-CZvbtLnr.js";
|
|
108
113
|
import { createRequire } from "node:module";
|
|
109
114
|
import * as sp from "node:path";
|
|
110
115
|
import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
@@ -112,8 +117,8 @@ import { Cause, Context, Data, Duration, Effect, Exit, Fiber, FileSystem, Layer,
|
|
|
112
117
|
import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
113
118
|
import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "path";
|
|
114
119
|
import { homedir } from "os";
|
|
115
|
-
import { homedir as homedir$1, type } from "node:os";
|
|
116
|
-
import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1,
|
|
120
|
+
import { freemem as freemem$1, homedir as homedir$1, totalmem as totalmem$1, type } from "node:os";
|
|
121
|
+
import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, rmSync as rmSync$1, stat, statSync as statSync$1, unwatchFile, watch, watchFile } from "node:fs";
|
|
117
122
|
import { FetchHttpClient, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
118
123
|
import { EventEmitter } from "node:events";
|
|
119
124
|
import { access, appendFile, chmod, cp, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat as stat$1, unlink, writeFile } from "node:fs/promises";
|
|
@@ -329,9 +334,9 @@ const ServerConfigLayer = Layer.effect(ServerConfig, Effect.sync(() => {
|
|
|
329
334
|
const identity = getDashboardIdentity();
|
|
330
335
|
const hostDashboardApiPort = readHostDashboardApiPort();
|
|
331
336
|
const overrideRequested = process.env["OVERDECK_WORKSPACE_DASHBOARD_ALLOW_PRIMARY"] === "1";
|
|
332
|
-
const agentId = process.env["
|
|
337
|
+
const agentId = process.env["OVERDECK_DASHBOARD_SPAWNED_BY"];
|
|
333
338
|
if (overrideRequested && agentId !== void 0 && !agentId.startsWith("conv-")) {
|
|
334
|
-
const msg = `Refusing host dashboard port override for pipeline-role identity
|
|
339
|
+
const msg = `Refusing host dashboard port override for pipeline-role identity OVERDECK_DASHBOARD_SPAWNED_BY=${agentId}. Work, planning, review, and flywheel agents must never bind the host dashboard port; use the workspace container endpoint instead. Only an operator-supervised conversation (conv-*) or a process with no agent identity may use this emergency override.`;
|
|
335
340
|
console.error(`[overdeck] ${msg}`);
|
|
336
341
|
throw new ServerConfigError("API_PORT", msg);
|
|
337
342
|
}
|
|
@@ -713,7 +718,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
713
718
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
714
719
|
const plan = readWorkspacePlanSync(workspacePath);
|
|
715
720
|
if (!plan || plan.plan.items.length === 0) throw new PlanEmpty({ id: issueId });
|
|
716
|
-
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-
|
|
721
|
+
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-BKKkxKgK.js");
|
|
717
722
|
const normalizedId = normalizeAgentId(issueId);
|
|
718
723
|
if ((await Effect.runPromise(getAgentState(normalizedId)))?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
|
|
719
724
|
return {
|
|
@@ -744,7 +749,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
744
749
|
const { workspacePath, projectPath, issue } = opts;
|
|
745
750
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
746
751
|
const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
|
|
747
|
-
const { spawnPlanningSession } = await import("./spawn-planning-session-
|
|
752
|
+
const { spawnPlanningSession } = await import("./spawn-planning-session-1nFi3gfk.js");
|
|
748
753
|
const result = await spawnPlanningSession({
|
|
749
754
|
issue: {
|
|
750
755
|
id: issue.id,
|
|
@@ -777,14 +782,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
777
782
|
}),
|
|
778
783
|
kill: (agentId) => Effect.tryPromise({
|
|
779
784
|
try: async () => {
|
|
780
|
-
const { stopAgent } = await import("./agents-
|
|
785
|
+
const { stopAgent } = await import("./agents-BKKkxKgK.js");
|
|
781
786
|
await Effect.runPromise(stopAgent(agentId));
|
|
782
787
|
},
|
|
783
788
|
catch: () => void 0
|
|
784
789
|
}).pipe(Effect.ignore),
|
|
785
790
|
message: (agentId, msg) => Effect.tryPromise({
|
|
786
791
|
try: async () => {
|
|
787
|
-
const { messageAgent } = await import("./agents-
|
|
792
|
+
const { messageAgent } = await import("./agents-BKKkxKgK.js");
|
|
788
793
|
await messageAgent(agentId, msg);
|
|
789
794
|
},
|
|
790
795
|
catch: (err) => new AgentStartError({
|
|
@@ -795,8 +800,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
795
800
|
}),
|
|
796
801
|
deepWipe: (issueId, opts) => Effect.tryPromise({
|
|
797
802
|
try: async () => {
|
|
798
|
-
const { deepWipe } = await import("./workflows-
|
|
799
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
803
|
+
const { deepWipe } = await import("./workflows-CHrx_hcW.js");
|
|
804
|
+
const { resolveProjectFromIssueSync } = await import("./projects-B03Wr-xc.js");
|
|
800
805
|
const project = resolveProjectFromIssueSync(issueId);
|
|
801
806
|
const projectPath = project?.projectPath ?? process.cwd();
|
|
802
807
|
await Effect.runPromise(deepWipe({
|
|
@@ -828,7 +833,7 @@ init_types$1();
|
|
|
828
833
|
* Route handlers and AgentSpawner use this instead of calling workspace-manager directly.
|
|
829
834
|
*/
|
|
830
835
|
init_typed_errors();
|
|
831
|
-
const execAsync$
|
|
836
|
+
const execAsync$11 = promisify(exec);
|
|
832
837
|
var WorkspaceService = class extends Context.Service()("overdeck/dashboard/WorkspaceService") {};
|
|
833
838
|
const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
834
839
|
function getWorkspacePath(issueId) {
|
|
@@ -855,8 +860,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
855
860
|
const { workspacePath, branch } = getWorkspacePath(issueId);
|
|
856
861
|
const issueLower = issueId.toLowerCase();
|
|
857
862
|
if (existsSync$1(workspacePath)) return workspacePath;
|
|
858
|
-
const { createWorkspace } = await import("./workspace-manager-
|
|
859
|
-
const { loadProjectsConfigSync } = await import("./projects-
|
|
863
|
+
const { createWorkspace } = await import("./workspace-manager-CDTKjjdU.js");
|
|
864
|
+
const { loadProjectsConfigSync } = await import("./projects-B03Wr-xc.js");
|
|
860
865
|
const { projects } = loadProjectsConfigSync();
|
|
861
866
|
const project = resolveProjectFromIssueSync(issueId);
|
|
862
867
|
if (!project) throw new WorkspaceCreateError({
|
|
@@ -891,7 +896,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
891
896
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
892
897
|
const issueLower = issueId.toLowerCase();
|
|
893
898
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
894
|
-
const { removeWorkspace } = await import("./workspace-manager-
|
|
899
|
+
const { removeWorkspace } = await import("./workspace-manager-CDTKjjdU.js");
|
|
895
900
|
const project = resolveProjectFromIssueSync(issueId);
|
|
896
901
|
if (!project) throw new WorkspaceCreateError({
|
|
897
902
|
id: issueId,
|
|
@@ -922,7 +927,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
922
927
|
try: async () => {
|
|
923
928
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
924
929
|
const issueLower = issueId.toLowerCase();
|
|
925
|
-
const { stopWorkspaceDocker } = await import("./workspace-manager-
|
|
930
|
+
const { stopWorkspaceDocker } = await import("./workspace-manager-CDTKjjdU.js");
|
|
926
931
|
await Effect.runPromise(stopWorkspaceDocker(workspacePath, issueLower));
|
|
927
932
|
},
|
|
928
933
|
catch: () => void 0
|
|
@@ -991,7 +996,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
991
996
|
join(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
|
|
992
997
|
];
|
|
993
998
|
if (!composePaths.find((p) => existsSync$1(p))) {
|
|
994
|
-
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-
|
|
999
|
+
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-C98V8yW-.js");
|
|
995
1000
|
const ensure = ensureDevcontainerSync({
|
|
996
1001
|
workspacePath,
|
|
997
1002
|
issueId
|
|
@@ -1002,7 +1007,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
1002
1007
|
});
|
|
1003
1008
|
}
|
|
1004
1009
|
const finalComposePath = composePaths.find((p) => existsSync$1(p));
|
|
1005
|
-
if (finalComposePath) await execAsync$
|
|
1010
|
+
if (finalComposePath) await execAsync$11(`docker compose -f "${finalComposePath}" up -d --build`, {
|
|
1006
1011
|
cwd: dirname(finalComposePath),
|
|
1007
1012
|
timeout: 3e5
|
|
1008
1013
|
});
|
|
@@ -1148,7 +1153,7 @@ const OpenRouterServiceLive = Layer.effect(OpenRouterService, Effect.sync(() =>
|
|
|
1148
1153
|
//#endregion
|
|
1149
1154
|
//#region services/open.ts
|
|
1150
1155
|
init_src();
|
|
1151
|
-
const execAsync$
|
|
1156
|
+
const execAsync$10 = promisify(exec);
|
|
1152
1157
|
function getFileManagerCommand() {
|
|
1153
1158
|
switch (process.platform) {
|
|
1154
1159
|
case "linux": return "xdg-open";
|
|
@@ -1181,7 +1186,7 @@ function launchDetached(launch) {
|
|
|
1181
1186
|
}
|
|
1182
1187
|
async function isCommandAvailable(command) {
|
|
1183
1188
|
try {
|
|
1184
|
-
await execAsync$
|
|
1189
|
+
await execAsync$10(`${process.platform === "win32" ? "where" : "which"} ${command}`);
|
|
1185
1190
|
return true;
|
|
1186
1191
|
} catch {
|
|
1187
1192
|
return false;
|
|
@@ -4858,14 +4863,14 @@ init_codex_auth();
|
|
|
4858
4863
|
init_queries();
|
|
4859
4864
|
init_cliproxy();
|
|
4860
4865
|
init_tmux();
|
|
4861
|
-
init_config();
|
|
4866
|
+
init_config$1();
|
|
4862
4867
|
const reauthSessions = /* @__PURE__ */ new Map();
|
|
4863
4868
|
const SESSION_MAX_AGE_MS = 3600 * 1e3;
|
|
4864
|
-
const readJsonBody$
|
|
4869
|
+
const readJsonBody$20 = Effect.gen(function* () {
|
|
4865
4870
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
4866
4871
|
return text ? JSON.parse(text) : {};
|
|
4867
4872
|
});
|
|
4868
|
-
function rejectInvalidOrigin(request) {
|
|
4873
|
+
function rejectInvalidOrigin$1(request) {
|
|
4869
4874
|
const originCheck = validateOrigin$1(request);
|
|
4870
4875
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
4871
4876
|
return null;
|
|
@@ -4940,7 +4945,7 @@ async function getExistingLiveReauthSession() {
|
|
|
4940
4945
|
return null;
|
|
4941
4946
|
}
|
|
4942
4947
|
const postCodexReauthRoute = HttpRouter.add("POST", "/api/settings/codex-reauth", httpHandler(Effect.gen(function* () {
|
|
4943
|
-
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
4948
|
+
const originError = rejectInvalidOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
4944
4949
|
if (originError) return originError;
|
|
4945
4950
|
const existing = yield* Effect.promise(() => getExistingLiveReauthSession());
|
|
4946
4951
|
if (existing) {
|
|
@@ -4964,9 +4969,9 @@ const postCodexReauthRoute = HttpRouter.add("POST", "/api/settings/codex-reauth"
|
|
|
4964
4969
|
}, { headers: { "Set-Cookie": buildTerminalCookie(sessionName, terminalToken) } });
|
|
4965
4970
|
})));
|
|
4966
4971
|
const postCodexReauthStatusRoute = HttpRouter.add("POST", "/api/settings/codex-reauth/status", httpHandler(Effect.gen(function* () {
|
|
4967
|
-
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
4972
|
+
const originError = rejectInvalidOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
4968
4973
|
if (originError) return originError;
|
|
4969
|
-
const body = yield* readJsonBody$
|
|
4974
|
+
const body = yield* readJsonBody$20;
|
|
4970
4975
|
const sessionName = typeof body.session === "string" ? body.session : "";
|
|
4971
4976
|
const token = typeof body.token === "string" ? body.token : "";
|
|
4972
4977
|
const session = getLiveReauthSession(sessionName);
|
|
@@ -5491,6 +5496,7 @@ init_codex();
|
|
|
5491
5496
|
init_launcher_generator();
|
|
5492
5497
|
init_transcript_landing();
|
|
5493
5498
|
init_operator_interventions();
|
|
5499
|
+
init_messaging();
|
|
5494
5500
|
init_agents$1();
|
|
5495
5501
|
init_runtime_census();
|
|
5496
5502
|
const MINIMUM_NODE_MAJOR = 24;
|
|
@@ -17255,7 +17261,7 @@ var require_get_vercel_oidc_token = /* @__PURE__ */ __commonJSMin(((exports, mod
|
|
|
17255
17261
|
err = error;
|
|
17256
17262
|
}
|
|
17257
17263
|
try {
|
|
17258
|
-
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-
|
|
17264
|
+
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-zlz9U0ki.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-Cxbk023d.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
|
|
17259
17265
|
if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
|
|
17260
17266
|
await refreshToken(options);
|
|
17261
17267
|
token = getVercelOidcTokenSync();
|
|
@@ -29572,7 +29578,7 @@ var GoogleCloudTranscription = class {
|
|
|
29572
29578
|
}
|
|
29573
29579
|
async start(apiKey, model) {
|
|
29574
29580
|
try {
|
|
29575
|
-
const { SpeechClient } = await import("./src-
|
|
29581
|
+
const { SpeechClient } = await import("./src-Ck028hjO.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
|
|
29576
29582
|
if (this.closed) return;
|
|
29577
29583
|
const stream = new SpeechClient({ apiKey }).streamingRecognize({
|
|
29578
29584
|
config: {
|
|
@@ -29836,7 +29842,7 @@ const DEFAULT_VOICE_SETTINGS = {
|
|
|
29836
29842
|
model: "gpt-4.1-mini"
|
|
29837
29843
|
}
|
|
29838
29844
|
};
|
|
29839
|
-
const readJsonBody$
|
|
29845
|
+
const readJsonBody$19 = Effect.gen(function* () {
|
|
29840
29846
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
29841
29847
|
const contentLength = Number(request.headers["content-length"] ?? 0);
|
|
29842
29848
|
if (Number.isFinite(contentLength) && contentLength > MAX_VOICE_SETTINGS_BODY_BYTES) return {
|
|
@@ -29959,7 +29965,7 @@ const getVoiceSettingsRoute = HttpRouter.add("GET", "/api/voice/settings", httpH
|
|
|
29959
29965
|
const putVoiceSettingsRoute = HttpRouter.add("PUT", "/api/voice/settings", httpHandler(Effect.gen(function* () {
|
|
29960
29966
|
const originError = requireTrustedOrigin$2(yield* HttpServerRequest.HttpServerRequest);
|
|
29961
29967
|
if (originError) return originError;
|
|
29962
|
-
const parsed = yield* readJsonBody$
|
|
29968
|
+
const parsed = yield* readJsonBody$19;
|
|
29963
29969
|
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 413 });
|
|
29964
29970
|
const body = parsed.body;
|
|
29965
29971
|
if (!isVoiceSettings(body)) return jsonResponse({ error: "Invalid voice settings payload" }, { status: 400 });
|
|
@@ -30252,12 +30258,219 @@ function streamAgentOutput(eventStore, agentId) {
|
|
|
30252
30258
|
})))));
|
|
30253
30259
|
}
|
|
30254
30260
|
//#endregion
|
|
30255
|
-
//#region services/
|
|
30261
|
+
//#region services/dashboard-db-task.ts
|
|
30256
30262
|
init_acp_conversation_parser();
|
|
30257
30263
|
init_codex_conversation_parser();
|
|
30258
30264
|
init_ohmypi_conversation_parser();
|
|
30259
30265
|
init_pi_conversation_parser();
|
|
30260
30266
|
init_conversation_service();
|
|
30267
|
+
init_control_settings();
|
|
30268
|
+
const MAX_PENDING_JOBS = 32;
|
|
30269
|
+
const SEMANTIC_SEARCH_TIMEOUT_MS = Number.parseInt(process.env["OVERDECK_SEMANTIC_SEARCH_TIMEOUT_MS"] ?? "15000", 10);
|
|
30270
|
+
const COALESCED_OPERATIONS = new Set([
|
|
30271
|
+
"scanConversations",
|
|
30272
|
+
"enrichSessions",
|
|
30273
|
+
"embedSessions",
|
|
30274
|
+
"searchSessionsSemantic",
|
|
30275
|
+
"listSubstrateBugWeights"
|
|
30276
|
+
]);
|
|
30277
|
+
const workers = {
|
|
30278
|
+
read: null,
|
|
30279
|
+
long: null,
|
|
30280
|
+
semantic: null
|
|
30281
|
+
};
|
|
30282
|
+
const pending = /* @__PURE__ */ new Map();
|
|
30283
|
+
const sharedJobs = /* @__PURE__ */ new Map();
|
|
30284
|
+
let latestSemanticJobId = null;
|
|
30285
|
+
function workerScriptUrl() {
|
|
30286
|
+
return import.meta.url.endsWith(".ts") ? new URL("./dashboard-db-worker.ts", import.meta.url) : new URL("./dashboard-db-worker.js", import.meta.url);
|
|
30287
|
+
}
|
|
30288
|
+
function failPendingForLane(lane, err) {
|
|
30289
|
+
for (const [id, job] of pending.entries()) {
|
|
30290
|
+
if (job.lane !== lane) continue;
|
|
30291
|
+
if (job.timeout) clearTimeout(job.timeout);
|
|
30292
|
+
job.reject(err);
|
|
30293
|
+
pending.delete(id);
|
|
30294
|
+
}
|
|
30295
|
+
for (const [key, job] of sharedJobs.entries()) if (job.lane === lane) sharedJobs.delete(key);
|
|
30296
|
+
if (lane === "semantic") latestSemanticJobId = null;
|
|
30297
|
+
}
|
|
30298
|
+
function stableStringify(value) {
|
|
30299
|
+
if (value == null || typeof value !== "object") return JSON.stringify(value);
|
|
30300
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
30301
|
+
return `{${Object.entries(value).filter(([, v]) => typeof v !== "function" && v !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
|
|
30302
|
+
}
|
|
30303
|
+
function coalescingKey(operation, payload) {
|
|
30304
|
+
if (!COALESCED_OPERATIONS.has(operation)) return null;
|
|
30305
|
+
return `${operation}:${stableStringify(payload)}`;
|
|
30306
|
+
}
|
|
30307
|
+
function workerLane(operation) {
|
|
30308
|
+
if (operation === "searchSessionsSemantic") return "semantic";
|
|
30309
|
+
return COALESCED_OPERATIONS.has(operation) ? "long" : "read";
|
|
30310
|
+
}
|
|
30311
|
+
function cancelOlderSemanticSearches() {
|
|
30312
|
+
if (!latestSemanticJobId && !workers.semantic) return;
|
|
30313
|
+
failPendingForLane("semantic", /* @__PURE__ */ new Error("Superseded by a newer semantic search"));
|
|
30314
|
+
workers.semantic?.terminate();
|
|
30315
|
+
workers.semantic = null;
|
|
30316
|
+
}
|
|
30317
|
+
function aggregateDiscoveredSessionCostByPayload(payload) {
|
|
30318
|
+
if (typeof payload === "string") return aggregateDiscoveredSessionCostBy(payload);
|
|
30319
|
+
const input = payload;
|
|
30320
|
+
return aggregateDiscoveredSessionCostBy(input?.groupBy ?? "workspace", input?.filter ?? {});
|
|
30321
|
+
}
|
|
30322
|
+
function getWorker(lane) {
|
|
30323
|
+
const existing = workers[lane];
|
|
30324
|
+
if (existing) return existing;
|
|
30325
|
+
const worker = new Worker(workerScriptUrl(), { execArgv: process.execArgv.filter((arg) => !arg.startsWith("--inspect")) });
|
|
30326
|
+
workers[lane] = worker;
|
|
30327
|
+
worker.on("message", (message) => {
|
|
30328
|
+
const job = pending.get(message.id);
|
|
30329
|
+
if (!job) return;
|
|
30330
|
+
if (message.progress !== void 0) {
|
|
30331
|
+
job.progressChain = job.progressChain.then(async () => {
|
|
30332
|
+
for (const listener of job.progressListeners) await listener(message.progress);
|
|
30333
|
+
});
|
|
30334
|
+
return;
|
|
30335
|
+
}
|
|
30336
|
+
pending.delete(message.id);
|
|
30337
|
+
if (job.timeout) clearTimeout(job.timeout);
|
|
30338
|
+
if (job.lane === "semantic" && latestSemanticJobId === message.id) latestSemanticJobId = null;
|
|
30339
|
+
if (message.ok) {
|
|
30340
|
+
job.progressChain.then(() => job.resolve(message.result), job.reject);
|
|
30341
|
+
return;
|
|
30342
|
+
}
|
|
30343
|
+
const err = message.error?.name === "CostThresholdError" ? new CostThresholdError(message.error.estimatedCost ?? 0, message.error.threshold ?? 0, message.error.sessionCount ?? 0) : new Error(message.error?.message ?? "Dashboard database worker failed");
|
|
30344
|
+
err.name = message.error?.name ?? "DashboardDatabaseWorkerError";
|
|
30345
|
+
err.stack = message.error?.stack;
|
|
30346
|
+
job.progressChain.then(() => job.reject(err), job.reject);
|
|
30347
|
+
});
|
|
30348
|
+
worker.on("error", (err) => {
|
|
30349
|
+
failPendingForLane(lane, err);
|
|
30350
|
+
if (workers[lane] === worker) workers[lane] = null;
|
|
30351
|
+
});
|
|
30352
|
+
worker.on("exit", (code) => {
|
|
30353
|
+
if (code !== 0) failPendingForLane(lane, /* @__PURE__ */ new Error(`Dashboard database ${lane} worker exited with code ${code}`));
|
|
30354
|
+
if (workers[lane] === worker) workers[lane] = null;
|
|
30355
|
+
});
|
|
30356
|
+
return worker;
|
|
30357
|
+
}
|
|
30358
|
+
async function runInline$1(operation, payload, onProgress) {
|
|
30359
|
+
switch (operation) {
|
|
30360
|
+
case "getDiscoveredStats": return getDiscoveredStats();
|
|
30361
|
+
case "listDiscoveredSessions": {
|
|
30362
|
+
const filter = payload;
|
|
30363
|
+
return {
|
|
30364
|
+
sessions: findDiscoveredSessions(filter),
|
|
30365
|
+
total: countDiscoveredSessions({
|
|
30366
|
+
...filter,
|
|
30367
|
+
limit: void 0,
|
|
30368
|
+
offset: void 0
|
|
30369
|
+
})
|
|
30370
|
+
};
|
|
30371
|
+
}
|
|
30372
|
+
case "listSessionsFeed": return listSessionsFeed(payload);
|
|
30373
|
+
case "getSessionsFeedFacets": return getSessionsFeedFacets(payload);
|
|
30374
|
+
case "getDiscoveredSessionById": return getDiscoveredSessionById(payload);
|
|
30375
|
+
case "aggregateDiscoveredSessionCost": return aggregateDiscoveredSessionCost(payload);
|
|
30376
|
+
case "aggregateDiscoveredSessionCostBy": return aggregateDiscoveredSessionCostByPayload(payload);
|
|
30377
|
+
case "searchSessions":
|
|
30378
|
+
case "searchSessionsSemantic": return searchSessions(payload);
|
|
30379
|
+
case "scanConversations": return scan({
|
|
30380
|
+
...payload,
|
|
30381
|
+
onProgress
|
|
30382
|
+
});
|
|
30383
|
+
case "enrichSessions": return enrichSessions({
|
|
30384
|
+
...payload,
|
|
30385
|
+
onProgress
|
|
30386
|
+
});
|
|
30387
|
+
case "embedSessions": return embedSessions({
|
|
30388
|
+
...payload,
|
|
30389
|
+
autoInstall: true,
|
|
30390
|
+
onProgress
|
|
30391
|
+
});
|
|
30392
|
+
case "getConversationByName": return getConversationByName(payload);
|
|
30393
|
+
case "getSetting": return getSetting(payload);
|
|
30394
|
+
case "setSetting": {
|
|
30395
|
+
const input = payload;
|
|
30396
|
+
setSetting(input.key, input.value);
|
|
30397
|
+
return null;
|
|
30398
|
+
}
|
|
30399
|
+
case "listSubstrateBugWeights": {
|
|
30400
|
+
const input = payload;
|
|
30401
|
+
return listSubstrateBugWeights(input.window, {
|
|
30402
|
+
limit: input.limit,
|
|
30403
|
+
offset: input.offset
|
|
30404
|
+
});
|
|
30405
|
+
}
|
|
30406
|
+
case "getArtifactBySlug": {
|
|
30407
|
+
const { getArtifactBySlugJob } = await import("./artifact-index-jobs-ug6ZxIP5.js");
|
|
30408
|
+
return getArtifactBySlugJob(payload);
|
|
30409
|
+
}
|
|
30410
|
+
case "listArtifactsForWorkspaceOrIssue": {
|
|
30411
|
+
const { listArtifactsForWorkspaceOrIssueJob } = await import("./artifact-index-jobs-ug6ZxIP5.js");
|
|
30412
|
+
return listArtifactsForWorkspaceOrIssueJob(payload);
|
|
30413
|
+
}
|
|
30414
|
+
case "unshareArtifactBySlug": {
|
|
30415
|
+
const { unshareArtifactBySlugJob } = await import("./artifact-index-jobs-ug6ZxIP5.js");
|
|
30416
|
+
return unshareArtifactBySlugJob(payload);
|
|
30417
|
+
}
|
|
30418
|
+
}
|
|
30419
|
+
}
|
|
30420
|
+
function runDashboardDbJob(operation, payload, onProgress) {
|
|
30421
|
+
if (import.meta.url.endsWith(".ts") && process.env["VITEST"]) return runInline$1(operation, payload, onProgress);
|
|
30422
|
+
const key = coalescingKey(operation, payload);
|
|
30423
|
+
const existing = key ? sharedJobs.get(key) : void 0;
|
|
30424
|
+
if (existing) {
|
|
30425
|
+
if (onProgress) existing.progressListeners.add(onProgress);
|
|
30426
|
+
return existing.promise;
|
|
30427
|
+
}
|
|
30428
|
+
if (pending.size >= MAX_PENDING_JOBS) return Promise.reject(/* @__PURE__ */ new Error("Dashboard database worker queue is full"));
|
|
30429
|
+
const id = randomUUID$1();
|
|
30430
|
+
const lane = workerLane(operation);
|
|
30431
|
+
if (operation === "searchSessionsSemantic") {
|
|
30432
|
+
cancelOlderSemanticSearches();
|
|
30433
|
+
latestSemanticJobId = id;
|
|
30434
|
+
}
|
|
30435
|
+
const progressListeners = /* @__PURE__ */ new Set();
|
|
30436
|
+
if (onProgress) progressListeners.add(onProgress);
|
|
30437
|
+
const promise = new Promise((resolve, reject) => {
|
|
30438
|
+
const timeout = operation === "searchSessionsSemantic" ? setTimeout(() => {
|
|
30439
|
+
if (!pending.get(id)) return;
|
|
30440
|
+
pending.delete(id);
|
|
30441
|
+
for (const [sharedKey, sharedJob] of sharedJobs.entries()) if (sharedJob.promise === promise) sharedJobs.delete(sharedKey);
|
|
30442
|
+
if (latestSemanticJobId === id) latestSemanticJobId = null;
|
|
30443
|
+
reject(/* @__PURE__ */ new Error("Semantic search timed out"));
|
|
30444
|
+
workers.semantic?.terminate();
|
|
30445
|
+
workers.semantic = null;
|
|
30446
|
+
}, Number.isFinite(SEMANTIC_SEARCH_TIMEOUT_MS) ? SEMANTIC_SEARCH_TIMEOUT_MS : 15e3) : null;
|
|
30447
|
+
pending.set(id, {
|
|
30448
|
+
lane,
|
|
30449
|
+
operation,
|
|
30450
|
+
resolve,
|
|
30451
|
+
reject,
|
|
30452
|
+
progressListeners,
|
|
30453
|
+
progressChain: Promise.resolve(),
|
|
30454
|
+
timeout
|
|
30455
|
+
});
|
|
30456
|
+
getWorker(lane).postMessage({
|
|
30457
|
+
id,
|
|
30458
|
+
operation,
|
|
30459
|
+
payload
|
|
30460
|
+
});
|
|
30461
|
+
});
|
|
30462
|
+
if (key) {
|
|
30463
|
+
sharedJobs.set(key, {
|
|
30464
|
+
lane,
|
|
30465
|
+
promise,
|
|
30466
|
+
progressListeners
|
|
30467
|
+
});
|
|
30468
|
+
promise.then(() => sharedJobs.delete(key), () => sharedJobs.delete(key));
|
|
30469
|
+
}
|
|
30470
|
+
return promise;
|
|
30471
|
+
}
|
|
30472
|
+
//#endregion
|
|
30473
|
+
//#region services/read-workspace-file.ts
|
|
30261
30474
|
init_src();
|
|
30262
30475
|
init_projects();
|
|
30263
30476
|
const MAX_WORKSPACE_FILE_BYTES = 256 * 1024;
|
|
@@ -30599,6 +30812,7 @@ function normalizeSessionsFeedFilter(input) {
|
|
|
30599
30812
|
* are implemented via TerminalService (dual-runtime PTY, B20).
|
|
30600
30813
|
*/
|
|
30601
30814
|
init_src();
|
|
30815
|
+
init_conversations();
|
|
30602
30816
|
init_paths();
|
|
30603
30817
|
init_projects();
|
|
30604
30818
|
function storedToDomainEvent(stored) {
|
|
@@ -31372,7 +31586,6 @@ init_state_home();
|
|
|
31372
31586
|
init_pan_dir();
|
|
31373
31587
|
init_in_flight_guard();
|
|
31374
31588
|
init_remote_agents();
|
|
31375
|
-
init_dag();
|
|
31376
31589
|
init_swarm_readiness();
|
|
31377
31590
|
var PlanQualityLintError = class extends Error {
|
|
31378
31591
|
constructor(issues) {
|
|
@@ -31487,9 +31700,6 @@ const PARALLEL_SAFE_REASON_FIELDS = [
|
|
|
31487
31700
|
"readinessReason",
|
|
31488
31701
|
"readiness_reason"
|
|
31489
31702
|
];
|
|
31490
|
-
const FILE_SIZE_BASELINE_PATH = "scripts/file-size-baseline.txt";
|
|
31491
|
-
const FILE_SIZE_RECONCILIATION_PATTERN = /\b(?:drop(?:ped|ping)?|lower(?:ed|ing)?|reconcil(?:e|ed|es|ing|iation)|remov(?:e|ed|es|ing)|updat(?:e|ed|es|ing))\b/i;
|
|
31492
|
-
const FILE_SIZE_LINT_COMMAND_PATTERN = /(?:\b(?:bun|npm|pnpm|yarn)\s+(?:run\s+)?lint(?::file-size)?(?=$|[\s;&|])|scripts\/lint-file-size\.sh)/i;
|
|
31493
31703
|
function issue(itemId, rule, message) {
|
|
31494
31704
|
return {
|
|
31495
31705
|
itemId,
|
|
@@ -31630,44 +31840,6 @@ function lintDocsCoverage(doc) {
|
|
|
31630
31840
|
if (doc.plan.items.filter((item) => item.status !== "cancelled").some(documentsSomething)) return [];
|
|
31631
31841
|
return [issue(null, "docs-item-missing", "Plan has no documentation work item: no active item sets metadata.kind \"docs\" or names a documentation file (.md/.mdx, or a docs/ path) in metadata.files_scope. Add the item naming the exact doc files it touches, or set plan.metadata.docsJustification to state why the change alters no documented surface.")];
|
|
31632
31842
|
}
|
|
31633
|
-
function itemSearchText(item) {
|
|
31634
|
-
return [
|
|
31635
|
-
item.title,
|
|
31636
|
-
item.narrative?.Action,
|
|
31637
|
-
...item.metadata?.expected_outputs ?? [],
|
|
31638
|
-
...acceptanceCriteria(item).map((ac) => ac.title)
|
|
31639
|
-
].filter((value) => typeof value === "string").join("\n");
|
|
31640
|
-
}
|
|
31641
|
-
function scopeIncludesPath(item, filePath) {
|
|
31642
|
-
return (item.metadata?.files_scope ?? []).some((scope) => compileGlob(scope).regex.test(filePath));
|
|
31643
|
-
}
|
|
31644
|
-
function requiresFileSizeLint(item) {
|
|
31645
|
-
if ((item.metadata?.verify_commands ?? []).some((command) => typeof command === "string" && FILE_SIZE_LINT_COMMAND_PATTERN.test(command))) return true;
|
|
31646
|
-
return acceptanceCriteria(item).some((ac) => FILE_SIZE_LINT_COMMAND_PATTERN.test(ac.title));
|
|
31647
|
-
}
|
|
31648
|
-
function lintDeferredFileSizeRatchet(doc) {
|
|
31649
|
-
const activeItems = doc.plan.items.filter((item) => item.status !== "cancelled");
|
|
31650
|
-
const readiness = analyzeSwarmReadiness(doc);
|
|
31651
|
-
const issues = [];
|
|
31652
|
-
const seen = /* @__PURE__ */ new Set();
|
|
31653
|
-
for (const reconciliation of activeItems) {
|
|
31654
|
-
if (!scopeIncludesPath(reconciliation, FILE_SIZE_BASELINE_PATH)) continue;
|
|
31655
|
-
const reconciliationText = itemSearchText(reconciliation);
|
|
31656
|
-
if (!reconciliationText.includes(FILE_SIZE_BASELINE_PATH) || !FILE_SIZE_RECONCILIATION_PATTERN.test(reconciliationText)) continue;
|
|
31657
|
-
const reconciledSourceScopes = (reconciliation.metadata?.files_scope ?? []).filter((scope) => scope.startsWith("src/") && reconciliationText.includes(scope));
|
|
31658
|
-
if (reconciledSourceScopes.length === 0) continue;
|
|
31659
|
-
for (const candidate of activeItems) {
|
|
31660
|
-
if (candidate.id === reconciliation.id || scopeIncludesPath(candidate, FILE_SIZE_BASELINE_PATH) || !requiresFileSizeLint(candidate)) continue;
|
|
31661
|
-
const deferredFile = (readiness.overlapMatrix[candidate.id]?.[reconciliation.id] ?? []).find((filePath) => reconciledSourceScopes.some((scope) => compileGlob(scope).regex.test(filePath)));
|
|
31662
|
-
if (!deferredFile) continue;
|
|
31663
|
-
const key = `${candidate.id}\0${deferredFile}`;
|
|
31664
|
-
if (seen.has(key)) continue;
|
|
31665
|
-
seen.add(key);
|
|
31666
|
-
issues.push(issue(candidate.id, "deferred-file-size-ratchet", `Item ${candidate.id} requires file-size-backed lint after changing baselined file ${deferredFile}, but defers ${FILE_SIZE_BASELINE_PATH} reconciliation to item ${reconciliation.id}. Include the baseline in ${candidate.id} metadata.files_scope and reconcile it in the same commit, or use an intermediate verification command that excludes the file-size ratchet. For an active plan, return the issue to planning, preserve stable item IDs, apply one of these repairs, and re-finalize before rerunning inspection.`));
|
|
31667
|
-
}
|
|
31668
|
-
}
|
|
31669
|
-
return issues;
|
|
31670
|
-
}
|
|
31671
31843
|
function orderedPairKey(left, right) {
|
|
31672
31844
|
return [left, right].sort().join("\0");
|
|
31673
31845
|
}
|
|
@@ -31729,7 +31901,6 @@ function lintPlanQuality(doc, options = {}) {
|
|
|
31729
31901
|
...lintDocumentReferences(doc),
|
|
31730
31902
|
...lintDocsCoverage(doc),
|
|
31731
31903
|
...lintTraceCoverage(doc, options.prdText),
|
|
31732
|
-
...lintDeferredFileSizeRatchet(doc),
|
|
31733
31904
|
...lintOverlapAudit(doc, options)
|
|
31734
31905
|
];
|
|
31735
31906
|
}
|
|
@@ -31746,7 +31917,7 @@ const execFileAsync$18 = promisify(execFile);
|
|
|
31746
31917
|
async function loadTrackerIssues() {
|
|
31747
31918
|
const map = /* @__PURE__ */ new Map();
|
|
31748
31919
|
try {
|
|
31749
|
-
const { getSharedIssueService } = await import("./issue-service-singleton-
|
|
31920
|
+
const { getSharedIssueService } = await import("./issue-service-singleton-PMx8F1jr.js");
|
|
31750
31921
|
const issues = (await getSharedIssueService()).getIssues();
|
|
31751
31922
|
for (const issue of issues) if (issue.identifier) map.set(issue.identifier.toUpperCase(), issue);
|
|
31752
31923
|
} catch {}
|
|
@@ -31769,7 +31940,7 @@ async function loadDockerContainers() {
|
|
|
31769
31940
|
}
|
|
31770
31941
|
async function loadActiveRemoteAgentStates() {
|
|
31771
31942
|
try {
|
|
31772
|
-
const { listActiveRemoteAgentStates } = await import("./remote-agents-
|
|
31943
|
+
const { listActiveRemoteAgentStates } = await import("./remote-agents-C1bssi41.js");
|
|
31773
31944
|
return listActiveRemoteAgentStates();
|
|
31774
31945
|
} catch {
|
|
31775
31946
|
return [];
|
|
@@ -31824,9 +31995,11 @@ function refreshMembershipSnapshot(project, snapshot, getMembership, now) {
|
|
|
31824
31995
|
snapshot.value = value;
|
|
31825
31996
|
snapshot.refreshedAt = now();
|
|
31826
31997
|
snapshot.lastError = void 0;
|
|
31998
|
+
snapshot.lastErrorReason = void 0;
|
|
31827
31999
|
snapshot.lastErrorAt = void 0;
|
|
31828
32000
|
}).catch((error) => {
|
|
31829
32001
|
snapshot.lastError = error instanceof Error ? error.message : String(error);
|
|
32002
|
+
snapshot.lastErrorReason = error instanceof PipelineMembershipUnavailableError ? error.reason : "gather_failed";
|
|
31830
32003
|
snapshot.lastErrorAt = now();
|
|
31831
32004
|
console.warn(`[pipeline-membership] refresh failed for ${project.name ?? project.path}; keeping last-good snapshot:`, snapshot.lastError);
|
|
31832
32005
|
}).finally(() => {
|
|
@@ -31844,7 +32017,8 @@ function readPipelineMembershipSnapshotsForProjects(projects) {
|
|
|
31844
32017
|
};
|
|
31845
32018
|
return {
|
|
31846
32019
|
project,
|
|
31847
|
-
error: /* @__PURE__ */ new Error(snapshot?.lastError ? `Pipeline membership refresh failed: ${snapshot.lastError}` : "Pipeline membership snapshot is loading")
|
|
32020
|
+
error: /* @__PURE__ */ new Error(snapshot?.lastError ? `Pipeline membership refresh failed: ${snapshot.lastError}` : "Pipeline membership snapshot is loading"),
|
|
32021
|
+
unavailableReason: snapshot?.lastErrorReason
|
|
31848
32022
|
};
|
|
31849
32023
|
});
|
|
31850
32024
|
}
|
|
@@ -33096,8 +33270,10 @@ async function completePlanningForIssue(options) {
|
|
|
33096
33270
|
workspacePath,
|
|
33097
33271
|
issueId: id
|
|
33098
33272
|
}));
|
|
33099
|
-
if (draftPromotion.promoted)
|
|
33100
|
-
|
|
33273
|
+
if (draftPromotion.promoted) {
|
|
33274
|
+
const removalNote = draftPromotion.sourceRemoved ? "" : " (workspace copy left in place)";
|
|
33275
|
+
emitCompletePlanningPhase(id, "prdPromote", "success", `promoted ${draftPromotion.source} -> ${draftPromotion.path}${removalNote}`);
|
|
33276
|
+
} else emitCompletePlanningPhase(id, "prdPromote", "skipped", draftPromotion.reason);
|
|
33101
33277
|
} catch (error) {
|
|
33102
33278
|
const reason = error instanceof Error ? error.message : String(error);
|
|
33103
33279
|
emitCompletePlanningPhase(id, "prdPromote", "failure", reason);
|
|
@@ -33374,6 +33550,10 @@ async function reopenWorkspaceStatePromise(issueId, workspacePath, options = {})
|
|
|
33374
33550
|
});
|
|
33375
33551
|
result.specialistStatesReset = true;
|
|
33376
33552
|
const resolved = resolveProjectFromIssueSync(issueId);
|
|
33553
|
+
if (resolved) {
|
|
33554
|
+
const project = getProjectSync(resolved.projectKey);
|
|
33555
|
+
if (project) clearRecordPipelineClosedOutSync(project, issueId.toUpperCase());
|
|
33556
|
+
}
|
|
33377
33557
|
if (resolved) try {
|
|
33378
33558
|
const noteParts = [`Reopened on ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`];
|
|
33379
33559
|
if (options.reason) noteParts.push(`reason: ${options.reason}`);
|
|
@@ -33408,7 +33588,7 @@ init_projects();
|
|
|
33408
33588
|
init_tracker_utils();
|
|
33409
33589
|
init_agents$1();
|
|
33410
33590
|
init_issue_id();
|
|
33411
|
-
const execAsync$
|
|
33591
|
+
const execAsync$9 = promisify(exec);
|
|
33412
33592
|
const execFileAsync$15 = promisify(execFile);
|
|
33413
33593
|
function isGitHubIssue$4(issueId) {
|
|
33414
33594
|
const resolved = resolveGitHubIssueSync(issueId);
|
|
@@ -33480,7 +33660,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
|
|
|
33480
33660
|
timeout: 15e3
|
|
33481
33661
|
});
|
|
33482
33662
|
try {
|
|
33483
|
-
const { setReviewStatusSync } = await import("./review-status-
|
|
33663
|
+
const { setReviewStatusSync } = await import("./review-status-BZH8h-6W.js");
|
|
33484
33664
|
setReviewStatusSync(issueId.toUpperCase(), { prUrl: void 0 });
|
|
33485
33665
|
} catch {}
|
|
33486
33666
|
return [`Closed PR #${prNumber} on ${githubCheck.owner}/${githubCheck.repo}`];
|
|
@@ -33534,7 +33714,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33534
33714
|
const { ctx, projectConfig } = buildLifecycleContext(id, getIssueDataService$8().getIssueSource(id) ?? void 0);
|
|
33535
33715
|
const deleteWorkspace = opts.deleteWorkspace ?? true;
|
|
33536
33716
|
cleanupLog.push(...await closeIssuePullRequest(id, mode === "cancel" ? "Canceled via Overdeck" : "Reset to Todo via Overdeck"));
|
|
33537
|
-
const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-
|
|
33717
|
+
const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-DDN8ApVY.js");
|
|
33538
33718
|
const workflow = mode === "cancel" ? cancelIssueWorkflow : resetToTodo;
|
|
33539
33719
|
const result = await Effect.runPromise(workflow(ctx, {
|
|
33540
33720
|
deleteWorkspace,
|
|
@@ -33549,7 +33729,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33549
33729
|
}));
|
|
33550
33730
|
cleanupLog.push(...result.steps.flatMap((step) => step.details || [step.error].filter(Boolean)));
|
|
33551
33731
|
if (mode === "cancel") try {
|
|
33552
|
-
const { transitionXBriefOnMain } = await import("./lifecycle-io-
|
|
33732
|
+
const { transitionXBriefOnMain } = await import("./lifecycle-io-D_zTLvP1.js");
|
|
33553
33733
|
const tx = await Effect.runPromise(transitionXBriefOnMain(ctx.projectPath, id, "cancelled", "cancelled", `scope: cancel ${id.toUpperCase()} xBRIEF`));
|
|
33554
33734
|
if (tx.moved) cleanupLog.push(`xBRIEF moved ${tx.fromDir} → cancelled`);
|
|
33555
33735
|
if (tx.committed) cleanupLog.push(`Committed xBRIEF cancellation on main`);
|
|
@@ -33557,8 +33737,8 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33557
33737
|
cleanupLog.push(`xBRIEF cancel transition failed (non-fatal): ${err?.message ?? err}`);
|
|
33558
33738
|
}
|
|
33559
33739
|
try {
|
|
33560
|
-
const { killAllReviewerSessions } = await import("./review-agent-
|
|
33561
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
33740
|
+
const { killAllReviewerSessions } = await import("./review-agent-CD4RCI0Y.js");
|
|
33741
|
+
const { resolveProjectFromIssueSync } = await import("./projects-B03Wr-xc.js");
|
|
33562
33742
|
const projectKey = resolveProjectFromIssueSync(id)?.projectKey;
|
|
33563
33743
|
if (projectKey) {
|
|
33564
33744
|
const { killed } = await Effect.runPromise(killAllReviewerSessions(projectKey, id.toUpperCase()));
|
|
@@ -33572,7 +33752,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
|
|
|
33572
33752
|
cleanupLog.push("Cleared review status");
|
|
33573
33753
|
} catch {}
|
|
33574
33754
|
try {
|
|
33575
|
-
const { resetPostMergeState } = await import("./merge-agent-
|
|
33755
|
+
const { resetPostMergeState } = await import("./merge-agent-DrXa1CpW.js");
|
|
33576
33756
|
resetPostMergeState(id);
|
|
33577
33757
|
resetPostMergeState(id.toUpperCase());
|
|
33578
33758
|
cleanupLog.push("Cleared merge state");
|
|
@@ -33592,7 +33772,7 @@ function closeIssueTransition(options) {
|
|
|
33592
33772
|
const { issueId, body, eventStore } = options;
|
|
33593
33773
|
const { reason } = body;
|
|
33594
33774
|
const projectPath = getProjectPath$3(void 0, extractPrefixSync(issueId) ?? issueId.split("-")[0]);
|
|
33595
|
-
const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-
|
|
33775
|
+
const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-DDN8ApVY.js"));
|
|
33596
33776
|
const githubCheck = isGitHubIssue$4(issueId);
|
|
33597
33777
|
const issueDataService = getIssueDataService$8();
|
|
33598
33778
|
const issueSource = issueDataService.getIssueSource(issueId);
|
|
@@ -33615,7 +33795,7 @@ function closeIssueTransition(options) {
|
|
|
33615
33795
|
};
|
|
33616
33796
|
}
|
|
33617
33797
|
const result = yield* closeWorkflow(ctx, { reason });
|
|
33618
|
-
if (githubCheck.isGitHub) execAsync$
|
|
33798
|
+
if (githubCheck.isGitHub) execAsync$9("pan sync", {
|
|
33619
33799
|
encoding: "utf-8",
|
|
33620
33800
|
timeout: 3e4
|
|
33621
33801
|
}).catch(() => {});
|
|
@@ -33826,13 +34006,13 @@ function reopenIssueTransition(options) {
|
|
|
33826
34006
|
}
|
|
33827
34007
|
yield* Effect.promise(async () => {
|
|
33828
34008
|
try {
|
|
33829
|
-
const { stdout } = await execAsync$
|
|
34009
|
+
const { stdout } = await execAsync$9(`gh pr list --head ${`feature/${id.toLowerCase()}`} --state closed --json number,mergedAt --limit 1`, {
|
|
33830
34010
|
encoding: "utf-8",
|
|
33831
34011
|
timeout: 15e3
|
|
33832
34012
|
});
|
|
33833
34013
|
const prs = JSON.parse(stdout.trim() || "[]");
|
|
33834
34014
|
if (prs.length > 0 && !prs[0].mergedAt) {
|
|
33835
|
-
await execAsync$
|
|
34015
|
+
await execAsync$9(`gh pr reopen ${prs[0].number}`, {
|
|
33836
34016
|
encoding: "utf-8",
|
|
33837
34017
|
timeout: 15e3
|
|
33838
34018
|
});
|
|
@@ -33859,7 +34039,7 @@ function reopenIssueTransition(options) {
|
|
|
33859
34039
|
else clearReviewStatus(id.toUpperCase());
|
|
33860
34040
|
} catch {}
|
|
33861
34041
|
try {
|
|
33862
|
-
const { resetPostMergeState } = await import("./merge-agent-
|
|
34042
|
+
const { resetPostMergeState } = await import("./merge-agent-DrXa1CpW.js");
|
|
33863
34043
|
resetPostMergeState(id);
|
|
33864
34044
|
resetPostMergeState(id.toUpperCase());
|
|
33865
34045
|
} catch {}
|
|
@@ -33923,7 +34103,7 @@ function moveIssueStatus(options) {
|
|
|
33923
34103
|
"done"
|
|
33924
34104
|
];
|
|
33925
34105
|
if (!targetStatus || !validStatuses.includes(targetStatus)) return jsonResponse({ error: `Invalid targetStatus. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 });
|
|
33926
|
-
const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-
|
|
34106
|
+
const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-FV6PHfEW.js"));
|
|
33927
34107
|
const issueState = {
|
|
33928
34108
|
backlog: "open",
|
|
33929
34109
|
todo: "open",
|
|
@@ -33986,7 +34166,7 @@ function moveIssueStatus(options) {
|
|
|
33986
34166
|
init_issue_service_singleton();
|
|
33987
34167
|
init_issue_id();
|
|
33988
34168
|
init_agents$1();
|
|
33989
|
-
const execAsync$
|
|
34169
|
+
const execAsync$8 = promisify(exec);
|
|
33990
34170
|
function getIssueDataService$7() {
|
|
33991
34171
|
return getSharedIssueService();
|
|
33992
34172
|
}
|
|
@@ -34011,28 +34191,28 @@ async function cleanupWorkspaceForIssue(rawId, eventStore) {
|
|
|
34011
34191
|
if (projectRoot) {
|
|
34012
34192
|
const workspacePath = join(projectRoot, "workspaces", `feature-${issueLower}`);
|
|
34013
34193
|
try {
|
|
34014
|
-
if ((await execAsync$
|
|
34194
|
+
if ((await execAsync$8("git worktree list --porcelain", {
|
|
34015
34195
|
cwd: projectRoot,
|
|
34016
34196
|
encoding: "utf-8"
|
|
34017
34197
|
})).stdout.includes(workspacePath)) {
|
|
34018
|
-
await execAsync$
|
|
34198
|
+
await execAsync$8(`git worktree remove "${workspacePath}" --force`, {
|
|
34019
34199
|
cwd: projectRoot,
|
|
34020
34200
|
encoding: "utf-8"
|
|
34021
34201
|
});
|
|
34022
34202
|
cleanupLog.push(`Removed git worktree: ${workspacePath}`);
|
|
34023
34203
|
} else if (existsSync$1(workspacePath)) {
|
|
34024
|
-
await execAsync$
|
|
34204
|
+
await execAsync$8(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
|
|
34025
34205
|
cleanupLog.push(`Removed directory: ${workspacePath}`);
|
|
34026
34206
|
}
|
|
34027
34207
|
} catch {
|
|
34028
34208
|
if (existsSync$1(workspacePath)) {
|
|
34029
|
-
await execAsync$
|
|
34209
|
+
await execAsync$8(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
|
|
34030
34210
|
cleanupLog.push(`Removed directory: ${workspacePath}`);
|
|
34031
34211
|
}
|
|
34032
34212
|
}
|
|
34033
34213
|
const branchName = `feature/${issueLower}`;
|
|
34034
34214
|
try {
|
|
34035
|
-
await execAsync$
|
|
34215
|
+
await execAsync$8(`git branch -D "${branchName}" 2>/dev/null || true`, {
|
|
34036
34216
|
cwd: projectRoot,
|
|
34037
34217
|
encoding: "utf-8"
|
|
34038
34218
|
});
|
|
@@ -34041,7 +34221,7 @@ async function cleanupWorkspaceForIssue(rawId, eventStore) {
|
|
|
34041
34221
|
}
|
|
34042
34222
|
const agentDir = join(homedir$1(), ".overdeck", "agents", `agent-${issueLower}`);
|
|
34043
34223
|
if (existsSync$1(agentDir)) {
|
|
34044
|
-
await execAsync$
|
|
34224
|
+
await execAsync$8(`rm -rf "${agentDir}"`, { encoding: "utf-8" });
|
|
34045
34225
|
cleanupLog.push(`Removed agent state: ${agentDir}`);
|
|
34046
34226
|
}
|
|
34047
34227
|
await Effect.runPromise(eventStore.append({
|
|
@@ -34150,7 +34330,7 @@ async function copySettingsToWorkspace(id) {
|
|
|
34150
34330
|
success: false,
|
|
34151
34331
|
error: "Workspace not found"
|
|
34152
34332
|
}, { status: 404 });
|
|
34153
|
-
const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-
|
|
34333
|
+
const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-CDTKjjdU.js");
|
|
34154
34334
|
const result = copyOverdeckSettingsToWorkspaceSync(workspacePath);
|
|
34155
34335
|
return jsonResponse({
|
|
34156
34336
|
success: result.errors.length === 0 || result.copied.length > 0,
|
|
@@ -34200,10 +34380,11 @@ init_lifecycle_io();
|
|
|
34200
34380
|
init_io();
|
|
34201
34381
|
init_issue_id();
|
|
34202
34382
|
init_projects();
|
|
34383
|
+
init_record_update();
|
|
34203
34384
|
init_tracker_utils();
|
|
34204
34385
|
init_tmux();
|
|
34205
34386
|
init_typed_errors();
|
|
34206
|
-
const execAsync$
|
|
34387
|
+
const execAsync$7 = promisify(exec);
|
|
34207
34388
|
const execFileAsync$14 = promisify(execFile);
|
|
34208
34389
|
function getIssueDataService$6() {
|
|
34209
34390
|
return getSharedIssueService();
|
|
@@ -34631,10 +34812,10 @@ function restartFromPlan(options) {
|
|
|
34631
34812
|
});
|
|
34632
34813
|
const resetResult = yield* Effect.promise(async () => {
|
|
34633
34814
|
try {
|
|
34634
|
-
const { runGitResetHard } = await import("./dangerous-git-ops-
|
|
34815
|
+
const { runGitResetHard } = await import("./dangerous-git-ops-BcJPC5Rr.js");
|
|
34635
34816
|
async function findPlanningCommit(grep, label) {
|
|
34636
34817
|
try {
|
|
34637
|
-
const { stdout } = await execAsync$
|
|
34818
|
+
const { stdout } = await execAsync$7(`git log --grep="${grep.replace(/"/g, "\\\"")}" --format=%H -1`, {
|
|
34638
34819
|
cwd: workspacePath,
|
|
34639
34820
|
encoding: "utf-8",
|
|
34640
34821
|
timeout: 1e4
|
|
@@ -34650,7 +34831,7 @@ function restartFromPlan(options) {
|
|
|
34650
34831
|
}
|
|
34651
34832
|
const found = await findPlanningCommit(`Complete planning for ${id}`, "complete-planning message") ?? await findPlanningCommit(`chore: planning artifacts for ${id}`, "agent-start message") ?? await (async () => {
|
|
34652
34833
|
try {
|
|
34653
|
-
const { stdout } = await execAsync$
|
|
34834
|
+
const { stdout } = await execAsync$7(`git log --diff-filter=A --format=%H -1 -- .pan/spec.vbrief.json`, {
|
|
34654
34835
|
cwd: workspacePath,
|
|
34655
34836
|
encoding: "utf-8",
|
|
34656
34837
|
timeout: 1e4
|
|
@@ -34783,7 +34964,7 @@ init_github_pr_lookup();
|
|
|
34783
34964
|
init_tracker_utils();
|
|
34784
34965
|
init_tracker_config();
|
|
34785
34966
|
init_pr_tab_cache();
|
|
34786
|
-
const execAsync$
|
|
34967
|
+
const execAsync$6 = promisify(exec);
|
|
34787
34968
|
function isGitHubIssue$2(issueId) {
|
|
34788
34969
|
const resolved = resolveGitHubIssueSync(issueId);
|
|
34789
34970
|
if (resolved.isGitHub) return {
|
|
@@ -34831,7 +35012,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34831
35012
|
if (githubCheck.isGitHub && githubCheck.owner && githubCheck.repo && githubCheck.number) {
|
|
34832
35013
|
const { owner, repo, number } = githubCheck;
|
|
34833
35014
|
try {
|
|
34834
|
-
const { stdout } = await execAsync$
|
|
35015
|
+
const { stdout } = await execAsync$6(`gh api "repos/${owner}/${repo}/issues/${number}/comments?per_page=100"`, {
|
|
34835
35016
|
encoding: "utf-8",
|
|
34836
35017
|
timeout: 15e3,
|
|
34837
35018
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -34894,7 +35075,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34894
35075
|
const collectedItems = [];
|
|
34895
35076
|
const prConversation = (async () => {
|
|
34896
35077
|
try {
|
|
34897
|
-
const { stdout } = await execAsync$
|
|
35078
|
+
const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/issues/${prNumber}/comments?per_page=100"`, {
|
|
34898
35079
|
encoding: "utf-8",
|
|
34899
35080
|
timeout: 15e3,
|
|
34900
35081
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -34915,7 +35096,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34915
35096
|
})();
|
|
34916
35097
|
const prReviews = (async () => {
|
|
34917
35098
|
try {
|
|
34918
|
-
const { stdout } = await execAsync$
|
|
35099
|
+
const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/reviews?per_page=100"`, {
|
|
34919
35100
|
encoding: "utf-8",
|
|
34920
35101
|
timeout: 15e3,
|
|
34921
35102
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -34940,7 +35121,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
|
|
|
34940
35121
|
})();
|
|
34941
35122
|
const prInlineComments = (async () => {
|
|
34942
35123
|
try {
|
|
34943
|
-
const { stdout } = await execAsync$
|
|
35124
|
+
const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/comments?per_page=100"`, {
|
|
34944
35125
|
encoding: "utf-8",
|
|
34945
35126
|
timeout: 15e3,
|
|
34946
35127
|
maxBuffer: 8 * 1024 * 1024
|
|
@@ -35083,7 +35264,7 @@ function closeOutIssue(id, opts = {}) {
|
|
|
35083
35264
|
}
|
|
35084
35265
|
const closeOutResult = yield* Effect.promise(async () => {
|
|
35085
35266
|
try {
|
|
35086
|
-
const { closeOut } = await import("./lifecycle-
|
|
35267
|
+
const { closeOut } = await import("./lifecycle-DDN8ApVY.js");
|
|
35087
35268
|
return {
|
|
35088
35269
|
ok: true,
|
|
35089
35270
|
result: await Effect.runPromise(closeOut(ctx, {
|
|
@@ -35172,7 +35353,7 @@ function bulkCloseOut(body) {
|
|
|
35172
35353
|
const invalidIds = issueIds.filter((id) => !isValidIssueId(id));
|
|
35173
35354
|
if (invalidIds.length > 0) return jsonResponse({ error: `Invalid issue ID format: ${invalidIds.join(", ")}` }, { status: 400 });
|
|
35174
35355
|
const eventStore = yield* EventStoreService;
|
|
35175
|
-
const { closeOut } = yield* Effect.promise(() => import("./lifecycle-
|
|
35356
|
+
const { closeOut } = yield* Effect.promise(() => import("./lifecycle-DDN8ApVY.js"));
|
|
35176
35357
|
const issueDataService = getIssueDataService$5();
|
|
35177
35358
|
const tasks = [];
|
|
35178
35359
|
const agentChecks = yield* withConcurrencyLimit(issueIds.map((id) => Effect.promise(async () => {
|
|
@@ -35340,7 +35521,7 @@ const execFileAsync$13 = promisify(execFile);
|
|
|
35340
35521
|
function getIssueDataService$4() {
|
|
35341
35522
|
return getSharedIssueService();
|
|
35342
35523
|
}
|
|
35343
|
-
const readJsonBody$
|
|
35524
|
+
const readJsonBody$18 = Effect.gen(function* () {
|
|
35344
35525
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
35345
35526
|
try {
|
|
35346
35527
|
return text ? JSON.parse(text) : {};
|
|
@@ -35398,8 +35579,8 @@ const getIssueShipLogRoute = HttpRouter.add("GET", "/api/issues/:id/ship-log", h
|
|
|
35398
35579
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35399
35580
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35400
35581
|
return yield* Effect.promise(async () => {
|
|
35401
|
-
const { getShipLog } = await import("./ship-log-
|
|
35402
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
35582
|
+
const { getShipLog } = await import("./ship-log-xplJ8t75.js");
|
|
35583
|
+
const { getReviewStatusSync } = await import("./review-status-BZH8h-6W.js");
|
|
35403
35584
|
const log = getShipLog(id);
|
|
35404
35585
|
const rs = getReviewStatusSync(id);
|
|
35405
35586
|
return jsonResponse({
|
|
@@ -35414,8 +35595,8 @@ const getIssueVerificationRoute = HttpRouter.add("GET", "/api/issues/:id/verific
|
|
|
35414
35595
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35415
35596
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35416
35597
|
return yield* Effect.promise(async () => {
|
|
35417
|
-
const { readVerificationArtifact } = await import("./verification-artifact-
|
|
35418
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
35598
|
+
const { readVerificationArtifact } = await import("./verification-artifact-C85cRTc_.js");
|
|
35599
|
+
const { getReviewStatusSync } = await import("./review-status-BZH8h-6W.js");
|
|
35419
35600
|
const { join } = await import("node:path");
|
|
35420
35601
|
const resolved = resolveProjectFromIssueSync(id);
|
|
35421
35602
|
const workspacePath = resolved ? join(resolved.projectPath, "workspaces", `feature-${id.toLowerCase()}`) : null;
|
|
@@ -35433,7 +35614,7 @@ const postIssueCloseRoute = HttpRouter.add("POST", "/api/issues/:issueId/close",
|
|
|
35433
35614
|
if (!parseIssueIdSync(issueId)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35434
35615
|
return yield* closeIssueTransition({
|
|
35435
35616
|
issueId,
|
|
35436
|
-
body: yield* readJsonBody$
|
|
35617
|
+
body: yield* readJsonBody$18,
|
|
35437
35618
|
eventStore: yield* EventStoreService
|
|
35438
35619
|
});
|
|
35439
35620
|
})));
|
|
@@ -35442,7 +35623,7 @@ const postIssueStartPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/star
|
|
|
35442
35623
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35443
35624
|
return yield* startPlanningForIssue({
|
|
35444
35625
|
id,
|
|
35445
|
-
body: yield* readJsonBody$
|
|
35626
|
+
body: yield* readJsonBody$18,
|
|
35446
35627
|
eventStore: yield* EventStoreService,
|
|
35447
35628
|
linear: yield* LinearClient,
|
|
35448
35629
|
github: yield* GitHubClient,
|
|
@@ -35455,7 +35636,7 @@ const postIssueAbortPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/abor
|
|
|
35455
35636
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35456
35637
|
return yield* abortPlanningForIssue({
|
|
35457
35638
|
id,
|
|
35458
|
-
body: yield* readJsonBody$
|
|
35639
|
+
body: yield* readJsonBody$18,
|
|
35459
35640
|
lifecycle: yield* IssueLifecycle,
|
|
35460
35641
|
linear: yield* LinearClient,
|
|
35461
35642
|
eventStore: yield* EventStoreService
|
|
@@ -35465,7 +35646,7 @@ const postIssueCompletePlanningRoute = HttpRouter.add("POST", "/api/issues/:id/c
|
|
|
35465
35646
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
35466
35647
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35467
35648
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35468
|
-
const body = yield* readJsonBody$
|
|
35649
|
+
const body = yield* readJsonBody$18;
|
|
35469
35650
|
const eventStore = yield* EventStoreService;
|
|
35470
35651
|
const linear = yield* LinearClient;
|
|
35471
35652
|
const lifecycle = yield* IssueLifecycle;
|
|
@@ -35491,7 +35672,7 @@ const postIssueResetRoute = HttpRouter.add("POST", "/api/issues/:id/reset", http
|
|
|
35491
35672
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35492
35673
|
return yield* resetIssueTransition({
|
|
35493
35674
|
id,
|
|
35494
|
-
body: yield* readJsonBody$
|
|
35675
|
+
body: yield* readJsonBody$18,
|
|
35495
35676
|
eventStore: yield* EventStoreService
|
|
35496
35677
|
});
|
|
35497
35678
|
})));
|
|
@@ -35515,7 +35696,7 @@ const postIssueCancelRoute = HttpRouter.add("POST", "/api/issues/:id/cancel", ht
|
|
|
35515
35696
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35516
35697
|
return yield* cancelIssueTransition({
|
|
35517
35698
|
id,
|
|
35518
|
-
body: yield* readJsonBody$
|
|
35699
|
+
body: yield* readJsonBody$18,
|
|
35519
35700
|
eventStore: yield* EventStoreService
|
|
35520
35701
|
});
|
|
35521
35702
|
})));
|
|
@@ -35526,7 +35707,7 @@ const postIssueReopenRoute = HttpRouter.add("POST", "/api/issues/:id/reopen", ht
|
|
|
35526
35707
|
if (authError) return authError;
|
|
35527
35708
|
return yield* reopenIssueTransition({
|
|
35528
35709
|
id,
|
|
35529
|
-
body: yield* readJsonBody$
|
|
35710
|
+
body: yield* readJsonBody$18,
|
|
35530
35711
|
lifecycle: yield* IssueLifecycle,
|
|
35531
35712
|
linear: yield* LinearClient,
|
|
35532
35713
|
eventStore: yield* EventStoreService
|
|
@@ -35546,7 +35727,7 @@ const postIssueMoveStatusRoute = HttpRouter.add("POST", "/api/issues/:id/move-st
|
|
|
35546
35727
|
if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
|
|
35547
35728
|
return yield* moveIssueStatus({
|
|
35548
35729
|
id,
|
|
35549
|
-
body: yield* readJsonBody$
|
|
35730
|
+
body: yield* readJsonBody$18,
|
|
35550
35731
|
eventStore: yield* EventStoreService,
|
|
35551
35732
|
lifecycle: yield* IssueLifecycle
|
|
35552
35733
|
});
|
|
@@ -35558,7 +35739,7 @@ const postIssueCleanupWorkspaceRoute = HttpRouter.add("POST", "/api/issues/:id/c
|
|
|
35558
35739
|
})));
|
|
35559
35740
|
const postIssueDeepWipeRoute = HttpRouter.add("POST", "/api/issues/:id/deep-wipe", httpHandler(Effect.gen(function* () {
|
|
35560
35741
|
const id = (yield* HttpRouter.params)["id"] ?? "";
|
|
35561
|
-
const body = yield* readJsonBody$
|
|
35742
|
+
const body = yield* readJsonBody$18;
|
|
35562
35743
|
const eventStore = yield* EventStoreService;
|
|
35563
35744
|
return yield* Effect.promise(() => deepWipeIssue(id, body, eventStore));
|
|
35564
35745
|
})));
|
|
@@ -35614,7 +35795,7 @@ const postIssueTaskInspectRoute = HttpRouter.add("POST", "/api/issues/:id/tasks/
|
|
|
35614
35795
|
return yield* inspectIssueTask({
|
|
35615
35796
|
id: (params["id"] ?? "").toUpperCase(),
|
|
35616
35797
|
itemId: params["itemId"] ?? "",
|
|
35617
|
-
body: yield* readJsonBody$
|
|
35798
|
+
body: yield* readJsonBody$18
|
|
35618
35799
|
});
|
|
35619
35800
|
})));
|
|
35620
35801
|
const getIssuePlanningStateRoute = HttpRouter.add("GET", "/api/issues/:id/planning-state", httpHandler(Effect.gen(function* () {
|
|
@@ -35756,7 +35937,13 @@ const getPipelineMembershipRoute = HttpRouter.add("GET", "/api/pipeline/membersh
|
|
|
35756
35937
|
if (!project) return jsonResponse({ error: `Project not found: ${projectKey}` }, { status: 404 });
|
|
35757
35938
|
const snapshot = readPipelineMembershipSnapshotsForProjects([project])[0];
|
|
35758
35939
|
if (snapshot?.memberships) return jsonResponse(snapshot.memberships);
|
|
35759
|
-
|
|
35940
|
+
if (snapshot?.error && snapshot.unavailableReason) return jsonResponse({
|
|
35941
|
+
status: "unavailable",
|
|
35942
|
+
reason: snapshot.unavailableReason ?? "gather_failed",
|
|
35943
|
+
message: snapshot.error instanceof Error ? snapshot.error.message : String(snapshot.error),
|
|
35944
|
+
projectKey
|
|
35945
|
+
});
|
|
35946
|
+
return jsonResponse({ error: "Pipeline membership snapshot is loading" }, { status: 503 });
|
|
35760
35947
|
})));
|
|
35761
35948
|
const postPipelineMembershipRefreshRoute = HttpRouter.add("POST", "/api/pipeline/membership/refresh", httpHandler(Effect.gen(function* () {
|
|
35762
35949
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
@@ -35769,7 +35956,12 @@ const postPipelineMembershipRefreshRoute = HttpRouter.add("POST", "/api/pipeline
|
|
|
35769
35956
|
yield* Effect.promise(() => refreshMembershipSnapshotsForProjects([project]));
|
|
35770
35957
|
const snapshot = readPipelineMembershipSnapshotsForProjects([project])[0];
|
|
35771
35958
|
if (snapshot?.memberships) return jsonResponse(snapshot.memberships);
|
|
35772
|
-
return jsonResponse({
|
|
35959
|
+
return jsonResponse({
|
|
35960
|
+
status: "unavailable",
|
|
35961
|
+
reason: snapshot?.unavailableReason ?? "gather_failed",
|
|
35962
|
+
message: snapshot?.error instanceof Error ? snapshot.error.message : "Pipeline membership refresh failed",
|
|
35963
|
+
projectKey
|
|
35964
|
+
});
|
|
35773
35965
|
})));
|
|
35774
35966
|
const pipelineMembershipRouteLayer = Layer.mergeAll(getPipelineMembershipRoute, postPipelineMembershipRefreshRoute);
|
|
35775
35967
|
//#endregion
|
|
@@ -36050,8 +36242,7 @@ const getCostsBackgroundRoute = HttpRouter.add("GET", "/api/costs/background", h
|
|
|
36050
36242
|
const costsRouteLayer = Layer.mergeAll(getCostsSummaryRoute, getCostsByIssueRoute, getCostsBackgroundRoute, postCostsRebuildRoute, postCostsDeduplicateRoute, getCostsStreamRoute, getCostsTrendsRoute, getCostsByModelRoute, getCostsIssueRoute, getCostsByAgentRoute, postCostsSyncWalRoute, postCostsReconcileRoute, getCostsExperimentsRoute);
|
|
36051
36243
|
//#endregion
|
|
36052
36244
|
//#region services/deacon-supervisor.ts
|
|
36053
|
-
|
|
36054
|
-
init_config$1();
|
|
36245
|
+
init_config$2();
|
|
36055
36246
|
init_concurrency();
|
|
36056
36247
|
init_activity_logger();
|
|
36057
36248
|
const DEFAULT_RESTART_WINDOW_MS = 6e4;
|
|
@@ -36222,6 +36413,7 @@ const isChildRunning = defaultSupervisor.isChildRunning;
|
|
|
36222
36413
|
//#endregion
|
|
36223
36414
|
//#region services/cloister-control-surface.ts
|
|
36224
36415
|
init_agents$1();
|
|
36416
|
+
init_control_settings();
|
|
36225
36417
|
init_paths();
|
|
36226
36418
|
function readDurableCloisterStatus(deps = {}) {
|
|
36227
36419
|
const cloisterState = (deps.readCloisterStateFile ?? readCloisterStateFile)();
|
|
@@ -36306,9 +36498,9 @@ function reloadDurableCloisterConfig(deps = {}) {
|
|
|
36306
36498
|
* PUT /api/cloister/config
|
|
36307
36499
|
* GET /api/cloister/agents/health
|
|
36308
36500
|
*/
|
|
36309
|
-
init_config$
|
|
36501
|
+
init_config$2();
|
|
36310
36502
|
init_agents$1();
|
|
36311
|
-
const readJsonBody$
|
|
36503
|
+
const readJsonBody$17 = Effect.gen(function* () {
|
|
36312
36504
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
36313
36505
|
try {
|
|
36314
36506
|
return text ? JSON.parse(text) : {};
|
|
@@ -36411,7 +36603,7 @@ const getCloisterConfigRoute = HttpRouter.add("GET", "/api/cloister/config", htt
|
|
|
36411
36603
|
catch: (err) => new Error(err instanceof Error ? err.message : String(err))
|
|
36412
36604
|
})));
|
|
36413
36605
|
const putCloisterConfigRoute = HttpRouter.add("PUT", "/api/cloister/config", httpHandler(Effect.gen(function* () {
|
|
36414
|
-
const updates = yield* readJsonBody$
|
|
36606
|
+
const updates = yield* readJsonBody$17;
|
|
36415
36607
|
yield* Effect.try({
|
|
36416
36608
|
try: () => {
|
|
36417
36609
|
saveCloisterConfigSync(updates);
|
|
@@ -37784,7 +37976,7 @@ const getStackTeardownEstimateRoute = HttpRouter.add("GET", "/api/resources/stac
|
|
|
37784
37976
|
})));
|
|
37785
37977
|
const postStackTeardownRoute = HttpRouter.add("POST", "/api/resources/stacks/:issueId/teardown", httpHandler(Effect.gen(function* () {
|
|
37786
37978
|
const params = yield* HttpRouter.params;
|
|
37787
|
-
const body = yield* readJsonBody$
|
|
37979
|
+
const body = yield* readJsonBody$16;
|
|
37788
37980
|
return yield* postStackTeardownEffect(params["issueId"] ?? "", body);
|
|
37789
37981
|
})));
|
|
37790
37982
|
function getStackTeardownEstimateEffect(issue) {
|
|
@@ -37958,7 +38150,7 @@ function lines(value) {
|
|
|
37958
38150
|
function isDockerIdentifier(value) {
|
|
37959
38151
|
return /^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/.test(value);
|
|
37960
38152
|
}
|
|
37961
|
-
const readJsonBody$
|
|
38153
|
+
const readJsonBody$16 = Effect.gen(function* () {
|
|
37962
38154
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
37963
38155
|
try {
|
|
37964
38156
|
return text ? JSON.parse(text) : {};
|
|
@@ -38067,7 +38259,6 @@ async function deriveSessionPresence(agentId, rtState, tmuxSessionNames) {
|
|
|
38067
38259
|
}
|
|
38068
38260
|
//#endregion
|
|
38069
38261
|
//#region ../../lib/settings-api-tiered-execution.ts
|
|
38070
|
-
init_prd_locations();
|
|
38071
38262
|
function tieredExecutionConfigForSave(config, providerAuth) {
|
|
38072
38263
|
if (config === void 0) return void 0;
|
|
38073
38264
|
const validated = validateTieredExecutionConfig(config, { providerAuth });
|
|
@@ -38093,6 +38284,17 @@ function validateTieredExecutionSettings(config, providerAuth) {
|
|
|
38093
38284
|
}
|
|
38094
38285
|
}
|
|
38095
38286
|
//#endregion
|
|
38287
|
+
//#region ../../lib/settings-api-telemetry.ts
|
|
38288
|
+
function validateApiTelemetryConfig(value) {
|
|
38289
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return ["telemetry must be an object"];
|
|
38290
|
+
const telemetry = value;
|
|
38291
|
+
const errors = [];
|
|
38292
|
+
if (typeof telemetry.enabled !== "boolean") errors.push("telemetry.enabled must be a boolean");
|
|
38293
|
+
if (telemetry.effectiveEnabled !== void 0 && typeof telemetry.effectiveEnabled !== "boolean") errors.push("telemetry.effectiveEnabled must be a boolean");
|
|
38294
|
+
if (telemetry.installId !== void 0 && typeof telemetry.installId !== "string") errors.push("telemetry.installId must be a string");
|
|
38295
|
+
return errors;
|
|
38296
|
+
}
|
|
38297
|
+
//#endregion
|
|
38096
38298
|
//#region ../../lib/settings-api.ts
|
|
38097
38299
|
/**
|
|
38098
38300
|
* Settings API Adapter
|
|
@@ -38101,6 +38303,9 @@ function validateTieredExecutionSettings(config, providerAuth) {
|
|
|
38101
38303
|
* Converts between YAML config format and frontend API format.
|
|
38102
38304
|
*/
|
|
38103
38305
|
init_config_yaml();
|
|
38306
|
+
init_config();
|
|
38307
|
+
init_install_id();
|
|
38308
|
+
init_service();
|
|
38104
38309
|
const API_TTS_KEYS = [
|
|
38105
38310
|
"enabled",
|
|
38106
38311
|
"voice",
|
|
@@ -38480,6 +38685,11 @@ function loadSettingsApi() {
|
|
|
38480
38685
|
rtk: { enabled: config.rtk?.enabled ?? false },
|
|
38481
38686
|
tldr: { enabled: config.tldr?.enabled ?? true }
|
|
38482
38687
|
},
|
|
38688
|
+
telemetry: {
|
|
38689
|
+
enabled: config.telemetry?.enabled ?? true,
|
|
38690
|
+
effectiveEnabled: resolveTelemetryEnabled(),
|
|
38691
|
+
installId: getOrCreateInstallId()
|
|
38692
|
+
},
|
|
38483
38693
|
tts: toApiTtsConfig(config.tts),
|
|
38484
38694
|
tts_summarizer: {
|
|
38485
38695
|
model: config.ttsSummarizer?.model,
|
|
@@ -38561,6 +38771,7 @@ async function writeYamlConfigPreservingComments(yamlConfig) {
|
|
|
38561
38771
|
["memory", config.memory],
|
|
38562
38772
|
["background_ai", config.background_ai],
|
|
38563
38773
|
["tracker_keys", config.tracker_keys],
|
|
38774
|
+
["telemetry", config.telemetry],
|
|
38564
38775
|
["experimental", config.experimental],
|
|
38565
38776
|
["claude", config.claude],
|
|
38566
38777
|
["codex", config.codex],
|
|
@@ -38660,6 +38871,7 @@ async function saveSettingsApiPromise(settings) {
|
|
|
38660
38871
|
features: settings.background_ai.features
|
|
38661
38872
|
} : void 0,
|
|
38662
38873
|
tracker_keys: settings.tracker_keys,
|
|
38874
|
+
telemetry: settings.telemetry ? { enabled: settings.telemetry.enabled } : void 0,
|
|
38663
38875
|
experimental: settings.experimental ? {
|
|
38664
38876
|
experimentalFeatures: settings.experimental.experimentalFeatures,
|
|
38665
38877
|
claudeCodeChannels: settings.experimental.claudeCodeChannels,
|
|
@@ -38673,6 +38885,7 @@ async function saveSettingsApiPromise(settings) {
|
|
|
38673
38885
|
tiered_execution: tieredExecutionConfigForSave(settings.tiered_execution, currentConfig.providerAuth)
|
|
38674
38886
|
});
|
|
38675
38887
|
clearConfigCache();
|
|
38888
|
+
await synchronizeAnalyticsServices();
|
|
38676
38889
|
}
|
|
38677
38890
|
async function updateSettingsApiPromise(updates) {
|
|
38678
38891
|
const current = loadSettingsApi();
|
|
@@ -38750,6 +38963,11 @@ async function updateSettingsApiPromise(updates) {
|
|
|
38750
38963
|
...current.tracker_keys,
|
|
38751
38964
|
...updates.tracker_keys
|
|
38752
38965
|
},
|
|
38966
|
+
telemetry: {
|
|
38967
|
+
enabled: updates.telemetry?.enabled ?? current.telemetry?.enabled ?? true,
|
|
38968
|
+
effectiveEnabled: !telemetryEnvironmentForcesOff() && (updates.telemetry?.enabled ?? current.telemetry?.enabled ?? true),
|
|
38969
|
+
installId: current.telemetry?.installId
|
|
38970
|
+
},
|
|
38753
38971
|
experimental: {
|
|
38754
38972
|
...current.experimental,
|
|
38755
38973
|
...updates.experimental
|
|
@@ -38821,6 +39039,7 @@ function validateSettingsApi(settings) {
|
|
|
38821
39039
|
if (settings.memory.sidebar_refresh_interval_ms !== void 0 && (!Number.isInteger(settings.memory.sidebar_refresh_interval_ms) || settings.memory.sidebar_refresh_interval_ms < 1)) errors.push("memory.sidebar_refresh_interval_ms must be a positive integer");
|
|
38822
39040
|
if (settings.memory.worker_concurrency !== void 0 && (!Number.isInteger(settings.memory.worker_concurrency) || settings.memory.worker_concurrency < 1)) errors.push("memory.worker_concurrency must be a positive integer");
|
|
38823
39041
|
}
|
|
39042
|
+
if (settings.telemetry !== void 0) errors.push(...validateApiTelemetryConfig(settings.telemetry));
|
|
38824
39043
|
if (settings.experimental !== void 0) if (typeof settings.experimental !== "object" || settings.experimental === null) errors.push("experimental must be an object");
|
|
38825
39044
|
else {
|
|
38826
39045
|
const experimental = settings.experimental;
|
|
@@ -39288,7 +39507,7 @@ init_linear_client();
|
|
|
39288
39507
|
init_config_yaml();
|
|
39289
39508
|
init_issue_service_singleton();
|
|
39290
39509
|
init_io();
|
|
39291
|
-
const execAsync$
|
|
39510
|
+
const execAsync$5 = promisify(exec);
|
|
39292
39511
|
const execFileAsync$8 = promisify(execFile);
|
|
39293
39512
|
function getIssueDataService$3() {
|
|
39294
39513
|
return getSharedIssueService();
|
|
@@ -39342,7 +39561,7 @@ function getProjectPath$1(issuePrefix) {
|
|
|
39342
39561
|
}
|
|
39343
39562
|
return setProjectPathCache(issuePrefix, join(homedir$1(), "Projects"));
|
|
39344
39563
|
}
|
|
39345
|
-
const readJsonBody$
|
|
39564
|
+
const readJsonBody$15 = Effect.gen(function* () {
|
|
39346
39565
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
39347
39566
|
try {
|
|
39348
39567
|
return text ? JSON.parse(text) : {};
|
|
@@ -39613,16 +39832,18 @@ async function fetchActivityDataWithContext(issueId, context = {}) {
|
|
|
39613
39832
|
const isShipStage = ss.type === "merge";
|
|
39614
39833
|
const nodeType = isShipStage ? "ship" : "test";
|
|
39615
39834
|
const specialistSessionId = isShipStage ? `agent-${issueLower}-ship` : `agent-${issueLower}-test`;
|
|
39835
|
+
const specialistIsLive = tmuxSessionNames.has(specialistSessionId);
|
|
39836
|
+
const specialistState = getAgentStateSync(specialistSessionId);
|
|
39837
|
+
if (isShipStage && !specialistIsLive && !specialistState) continue;
|
|
39616
39838
|
if (includeTranscripts && ss.status === "running") try {
|
|
39617
39839
|
const output = (await Effect.runPromise(capturePane(specialistSessionId, 100))).trim();
|
|
39618
39840
|
if (output && (output.includes(issueId.toUpperCase()) || output.includes(issueId) || output.includes(issueLower))) transcriptParts.push(`\n--- Live Output ---\n${output}`);
|
|
39619
39841
|
else if (output) transcriptParts.push(`\n--- Waiting ---\nSpecialist is processing another issue. Will update when it reaches ${issueId}.`);
|
|
39620
39842
|
} catch {}
|
|
39621
|
-
const specialistIsLive = tmuxSessionNames.has(specialistSessionId);
|
|
39622
39843
|
const specialistIsZombie = specialistIsLive && (ss.status === "completed" || ss.status === "failed");
|
|
39623
39844
|
const specialistPresence = specialistIsLive && !specialistIsZombie ? ss.status === "running" ? "active" : "idle" : specialistIsZombie ? "idle" : "ended";
|
|
39624
39845
|
const specialistJsonlPath = await resolveJsonlPath(specialistSessionId, workspacePath);
|
|
39625
|
-
|
|
39846
|
+
if (isShipStage && !specialistIsLive && !specialistJsonlPath) continue;
|
|
39626
39847
|
sections.push({
|
|
39627
39848
|
type: nodeType,
|
|
39628
39849
|
sessionId: specialistSessionId,
|
|
@@ -39841,7 +40062,7 @@ async function fetchPlanningData(issueId, options = {}) {
|
|
|
39841
40062
|
const cached = stashCountCache.get(cacheKey);
|
|
39842
40063
|
if (cached && cached.timestamp > Date.now() - STASH_COUNT_CACHE_TTL_MS) result.stashCount = cached.count;
|
|
39843
40064
|
else {
|
|
39844
|
-
const { stdout: stashList } = await execAsync$
|
|
40065
|
+
const { stdout: stashList } = await execAsync$5("git stash list", {
|
|
39845
40066
|
cwd: workspacePath,
|
|
39846
40067
|
encoding: "utf-8"
|
|
39847
40068
|
});
|
|
@@ -39929,7 +40150,7 @@ async function generateStatusReview(issueId) {
|
|
|
39929
40150
|
};
|
|
39930
40151
|
const execSafe = async (cmd, opts) => {
|
|
39931
40152
|
try {
|
|
39932
|
-
const { stdout } = await execAsync$
|
|
40153
|
+
const { stdout } = await execAsync$5(cmd, {
|
|
39933
40154
|
encoding: "utf-8",
|
|
39934
40155
|
timeout: 1e4,
|
|
39935
40156
|
...opts
|
|
@@ -40031,7 +40252,7 @@ Be specific: reference actual file names, function names, requirement text, disc
|
|
|
40031
40252
|
const { command: cliCmd, args: cliArgs } = getAgentCommandSync(statusModelId);
|
|
40032
40253
|
const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
|
|
40033
40254
|
const promptFile = join(planningDir, ".status-review-prompt.tmp");
|
|
40034
|
-
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-
|
|
40255
|
+
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-D7IluJe0.js");
|
|
40035
40256
|
let providerEnvStr = "";
|
|
40036
40257
|
let providerEnv = {};
|
|
40037
40258
|
const statusProvider = getProviderForModelSync(statusModelId);
|
|
@@ -40048,7 +40269,7 @@ Be specific: reference actual file names, function names, requirement text, disc
|
|
|
40048
40269
|
try {
|
|
40049
40270
|
const env = buildChildEnvSync(process.env, providerEnv);
|
|
40050
40271
|
const promptContent = await readFile(promptFile, "utf-8");
|
|
40051
|
-
const { stdout: aiReview } = await execAsync$
|
|
40272
|
+
const { stdout: aiReview } = await execAsync$5(`${cliCmd} -p${modelFlag} --no-session-persistence`, {
|
|
40052
40273
|
encoding: "utf-8",
|
|
40053
40274
|
timeout: 12e4,
|
|
40054
40275
|
maxBuffer: 1024 * 1024,
|
|
@@ -40106,7 +40327,7 @@ ${issueContext ? `## Issue Tracker Data\n${issueContext}\n` : ""}---
|
|
|
40106
40327
|
}
|
|
40107
40328
|
const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/planning/:issueId/upload", httpHandler(Effect.gen(function* () {
|
|
40108
40329
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40109
|
-
const { type, filename, content } = yield* readJsonBody$
|
|
40330
|
+
const { type, filename, content } = yield* readJsonBody$15;
|
|
40110
40331
|
const issueLower = issueId.toLowerCase();
|
|
40111
40332
|
const issuePrefix = extractPrefixSync(issueId) ?? issueId.split("-")[0];
|
|
40112
40333
|
if (!type || !filename || !content) return jsonResponse({ error: "type, filename, and content are required" }, { status: 400 });
|
|
@@ -40114,7 +40335,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
|
|
|
40114
40335
|
let safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
40115
40336
|
let processedContent = content;
|
|
40116
40337
|
if (safeName.endsWith(".vtt")) {
|
|
40117
|
-
const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-
|
|
40338
|
+
const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-Jr94BF3Y.js"));
|
|
40118
40339
|
processedContent = vttToMarkdown(content);
|
|
40119
40340
|
safeName = safeName.replace(/\.vtt$/, ".md");
|
|
40120
40341
|
}
|
|
@@ -40135,7 +40356,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
|
|
|
40135
40356
|
const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/command-deck/planning/:issueId/sync-discussions", httpHandler(Effect.gen(function* () {
|
|
40136
40357
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40137
40358
|
if (!parseIssueIdSync(issueId)) return jsonResponse({ error: "Invalid issue id: " + issueId }, { status: 400 });
|
|
40138
|
-
const body = yield* readJsonBody$
|
|
40359
|
+
const body = yield* readJsonBody$15;
|
|
40139
40360
|
const linear = yield* LinearClient;
|
|
40140
40361
|
const { tracker } = body;
|
|
40141
40362
|
const issueLower = issueId.toLowerCase();
|
|
@@ -40281,7 +40502,7 @@ const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/comm
|
|
|
40281
40502
|
})));
|
|
40282
40503
|
const postMissionControlPlanningInitRoute = HttpRouter.add("POST", "/api/command-deck/planning/:issueId/init", httpHandler(Effect.gen(function* () {
|
|
40283
40504
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40284
|
-
const body = yield* readJsonBody$
|
|
40505
|
+
const body = yield* readJsonBody$15;
|
|
40285
40506
|
const eventStore = yield* EventStoreService;
|
|
40286
40507
|
const { shadow } = body;
|
|
40287
40508
|
const issueLower = issueId.toLowerCase();
|
|
@@ -40340,7 +40561,7 @@ const commandDeckRouteLayer = Layer.mergeAll(getMissionControlActivityRoute, get
|
|
|
40340
40561
|
* GET /api/remote/workspaces/:issueId/agent/output
|
|
40341
40562
|
* POST /api/remote/workspaces/:issueId/agent/tell
|
|
40342
40563
|
*/
|
|
40343
|
-
init_config();
|
|
40564
|
+
init_config$1();
|
|
40344
40565
|
init_domain_services();
|
|
40345
40566
|
async function loadRemoteWorkspaceMetadata(issueId) {
|
|
40346
40567
|
const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
@@ -40366,7 +40587,7 @@ async function listRemoteWorkspaceMetadata() {
|
|
|
40366
40587
|
}
|
|
40367
40588
|
return workspaces;
|
|
40368
40589
|
}
|
|
40369
|
-
const readJsonBody$
|
|
40590
|
+
const readJsonBody$14 = Effect.gen(function* () {
|
|
40370
40591
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
40371
40592
|
try {
|
|
40372
40593
|
return text ? JSON.parse(text) : {};
|
|
@@ -40481,7 +40702,7 @@ const stopRemoteWorkspaceRoute = HttpRouter.add("POST", "/api/remote/workspaces/
|
|
|
40481
40702
|
})));
|
|
40482
40703
|
const startRemoteAgentRoute = HttpRouter.add("POST", "/api/remote/workspaces/:issueId/agent/start", httpHandler(Effect.gen(function* () {
|
|
40483
40704
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40484
|
-
const body = yield* readJsonBody$
|
|
40705
|
+
const body = yield* readJsonBody$14;
|
|
40485
40706
|
const eventStore = yield* EventStoreService;
|
|
40486
40707
|
const { prompt, model } = body;
|
|
40487
40708
|
const metadata = yield* Effect.promise(() => loadRemoteWorkspaceMetadata(issueId));
|
|
@@ -40545,7 +40766,7 @@ const getRemoteAgentOutputRoute = HttpRouter.add("GET", "/api/remote/workspaces/
|
|
|
40545
40766
|
})));
|
|
40546
40767
|
const tellRemoteAgentRoute = HttpRouter.add("POST", "/api/remote/workspaces/:issueId/agent/tell", httpHandler(Effect.gen(function* () {
|
|
40547
40768
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
40548
|
-
const { message } = yield* readJsonBody$
|
|
40769
|
+
const { message } = yield* readJsonBody$14;
|
|
40549
40770
|
if (!message) return jsonResponse({ error: "Message is required" }, { status: 400 });
|
|
40550
40771
|
const metadata = yield* Effect.promise(() => loadRemoteWorkspaceMetadata(issueId));
|
|
40551
40772
|
if (!metadata) return jsonResponse({ error: "Remote workspace not found" }, { status: 404 });
|
|
@@ -40562,6 +40783,24 @@ const remoteRouteLayer = Layer.mergeAll(getRemoteStatusRoute, listRemoteWorkspac
|
|
|
40562
40783
|
init_providers();
|
|
40563
40784
|
init_harness_policy();
|
|
40564
40785
|
/**
|
|
40786
|
+
* Model ids legal in the `?models=` query of GET /api/settings/harness-policy.
|
|
40787
|
+
*
|
|
40788
|
+
* Square brackets are significant: the long-context variants are named
|
|
40789
|
+
* `k3[1m]` and `claude-opus-5[1m]`. The pickers batch every known model id
|
|
40790
|
+
* into one request, so rejecting a single bracketed id 400s the whole batch
|
|
40791
|
+
* and leaves every model without a policy decision.
|
|
40792
|
+
*/
|
|
40793
|
+
const SAFE_MODEL_PATTERN$2 = /^[a-zA-Z0-9_.:\/[\]-]+$/;
|
|
40794
|
+
const MAX_HARNESS_POLICY_MODELS = 250;
|
|
40795
|
+
const MAX_HARNESS_POLICY_MODEL_LENGTH = 200;
|
|
40796
|
+
/** Parse and validate the `models` query value; `null` means reject with 400. */
|
|
40797
|
+
function parseHarnessPolicyModels(rawModels) {
|
|
40798
|
+
const models = (rawModels ?? "").split(",").map((model) => model.trim()).filter(Boolean);
|
|
40799
|
+
if (models.length === 0 || models.length > MAX_HARNESS_POLICY_MODELS) return null;
|
|
40800
|
+
if (models.some((model) => model.length > MAX_HARNESS_POLICY_MODEL_LENGTH || !SAFE_MODEL_PATTERN$2.test(model))) return null;
|
|
40801
|
+
return models;
|
|
40802
|
+
}
|
|
40803
|
+
/**
|
|
40565
40804
|
* Resolve a per-model harness-policy decision map for `models`.
|
|
40566
40805
|
*
|
|
40567
40806
|
* Caches the auth-mode resolver per provider so multiple models under one
|
|
@@ -44686,7 +44925,7 @@ function consumeReindexConfirmationNonce(nonce, estimatedUsd) {
|
|
|
44686
44925
|
reindexConfirmationNonces.delete(nonce);
|
|
44687
44926
|
return !!entry && entry.expiresAt > Date.now() && Math.abs(entry.estimatedUsd - estimatedUsd) < 1e-6;
|
|
44688
44927
|
}
|
|
44689
|
-
const readJsonBody$
|
|
44928
|
+
const readJsonBody$13 = Effect.gen(function* () {
|
|
44690
44929
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
44691
44930
|
try {
|
|
44692
44931
|
return text ? JSON.parse(text) : {};
|
|
@@ -44759,7 +44998,7 @@ const getOpenAIAuthRoute = HttpRouter.add("GET", "/api/settings/openai-auth", ht
|
|
|
44759
44998
|
return jsonResponse(yield* getOpenAIAuthStatus());
|
|
44760
44999
|
})));
|
|
44761
45000
|
const postTestApiKeyRoute = HttpRouter.add("POST", "/api/settings/test-api-key", httpHandler(Effect.gen(function* () {
|
|
44762
|
-
const { provider, apiKey, model } = yield* readJsonBody$
|
|
45001
|
+
const { provider, apiKey, model } = yield* readJsonBody$13;
|
|
44763
45002
|
if (!provider || !apiKey) return jsonResponse({ error: "Provider and apiKey are required" }, { status: 400 });
|
|
44764
45003
|
return yield* Effect.promise(async () => {
|
|
44765
45004
|
let success = false;
|
|
@@ -45069,7 +45308,7 @@ const postTestApiKeyRoute = HttpRouter.add("POST", "/api/settings/test-api-key",
|
|
|
45069
45308
|
});
|
|
45070
45309
|
})));
|
|
45071
45310
|
const postValidateApiKeyRoute = HttpRouter.add("POST", "/api/settings/validate-api-key", httpHandler(Effect.gen(function* () {
|
|
45072
|
-
const { provider, apiKey } = yield* readJsonBody$
|
|
45311
|
+
const { provider, apiKey } = yield* readJsonBody$13;
|
|
45073
45312
|
if (!provider || !apiKey) return jsonResponse({ error: "Provider and apiKey are required" }, { status: 400 });
|
|
45074
45313
|
if (![
|
|
45075
45314
|
"openai",
|
|
@@ -45304,7 +45543,7 @@ const getConversationSearchReindexEstimateRoute = HttpRouter.add("GET", "/api/se
|
|
|
45304
45543
|
const postConversationSearchReindexRoute = HttpRouter.add("POST", "/api/settings/conversation-search/reindex", httpHandler(Effect.gen(function* () {
|
|
45305
45544
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
45306
45545
|
if (authError) return authError;
|
|
45307
|
-
const body = yield* readJsonBody$
|
|
45546
|
+
const body = yield* readJsonBody$13;
|
|
45308
45547
|
return yield* Effect.promise(async () => {
|
|
45309
45548
|
if (activeConversationSearchReindex) return jsonResponse({ error: "Conversation search reindex already in progress" }, { status: 409 });
|
|
45310
45549
|
const job = (async () => {
|
|
@@ -45354,7 +45593,7 @@ const getConversationSearchReindexProgressRoute = HttpRouter.add("GET", "/api/se
|
|
|
45354
45593
|
return jsonResponse(conversationReindexProgress);
|
|
45355
45594
|
})));
|
|
45356
45595
|
const putSettingsRoute = HttpRouter.add("PUT", "/api/settings", httpHandler(Effect.gen(function* () {
|
|
45357
|
-
const body = yield* readJsonBody$
|
|
45596
|
+
const body = yield* readJsonBody$13;
|
|
45358
45597
|
return yield* Effect.promise(async () => {
|
|
45359
45598
|
try {
|
|
45360
45599
|
const newSettings = body;
|
|
@@ -45375,7 +45614,7 @@ const putSettingsRoute = HttpRouter.add("PUT", "/api/settings", httpHandler(Effe
|
|
|
45375
45614
|
});
|
|
45376
45615
|
})));
|
|
45377
45616
|
const putUiThemeRoute = HttpRouter.add("PUT", "/api/settings/ui-theme", httpHandler(Effect.gen(function* () {
|
|
45378
|
-
const body = yield* readJsonBody$
|
|
45617
|
+
const body = yield* readJsonBody$13;
|
|
45379
45618
|
return yield* Effect.promise(async () => {
|
|
45380
45619
|
const theme = body?.theme;
|
|
45381
45620
|
if (theme !== "light" && theme !== "dark") return jsonResponse({ error: "theme must be 'light' or 'dark'" }, { status: 400 });
|
|
@@ -45390,7 +45629,7 @@ const getOpenRouterModelsRoute = HttpRouter.add("GET", "/api/settings/openrouter
|
|
|
45390
45629
|
});
|
|
45391
45630
|
})));
|
|
45392
45631
|
const putOpenRouterFavoritesRoute = HttpRouter.add("PUT", "/api/settings/openrouter/favorites", httpHandler(Effect.gen(function* () {
|
|
45393
|
-
const { favorites } = yield* readJsonBody$
|
|
45632
|
+
const { favorites } = yield* readJsonBody$13;
|
|
45394
45633
|
if (!Array.isArray(favorites)) return jsonResponse({ error: "favorites must be an array of model IDs" }, { status: 400 });
|
|
45395
45634
|
const modelIds = favorites.filter((f) => typeof f === "string");
|
|
45396
45635
|
return yield* Effect.promise(async () => {
|
|
@@ -45406,7 +45645,7 @@ const putOpenRouterFavoritesRoute = HttpRouter.add("PUT", "/api/settings/openrou
|
|
|
45406
45645
|
});
|
|
45407
45646
|
})));
|
|
45408
45647
|
const putOpenRouterApiKeyRoute = HttpRouter.add("PUT", "/api/settings/openrouter/api-key", httpHandler(Effect.gen(function* () {
|
|
45409
|
-
const { apiKey } = yield* readJsonBody$
|
|
45648
|
+
const { apiKey } = yield* readJsonBody$13;
|
|
45410
45649
|
if (apiKey !== void 0 && typeof apiKey !== "string") return jsonResponse({ error: "apiKey must be a string when provided" }, { status: 400 });
|
|
45411
45650
|
return yield* Effect.promise(async () => {
|
|
45412
45651
|
try {
|
|
@@ -45421,18 +45660,16 @@ const putOpenRouterApiKeyRoute = HttpRouter.add("PUT", "/api/settings/openrouter
|
|
|
45421
45660
|
});
|
|
45422
45661
|
})));
|
|
45423
45662
|
const postOpenRouterTestKeyRoute = HttpRouter.add("POST", "/api/settings/openrouter/test-key", httpHandler(Effect.gen(function* () {
|
|
45424
|
-
const { apiKey } = yield* readJsonBody$
|
|
45663
|
+
const { apiKey } = yield* readJsonBody$13;
|
|
45425
45664
|
if (!apiKey) return jsonResponse({ error: "apiKey is required" }, { status: 400 });
|
|
45426
45665
|
return jsonResponse(yield* (yield* OpenRouterService).validateApiKey(apiKey));
|
|
45427
45666
|
})));
|
|
45428
|
-
const SAFE_MODEL_PATTERN$1 = /^[a-zA-Z0-9_
|
|
45429
|
-
const MAX_HARNESS_POLICY_MODELS = 250;
|
|
45430
|
-
const MAX_HARNESS_POLICY_MODEL_LENGTH = 200;
|
|
45667
|
+
const SAFE_MODEL_PATTERN$1 = /^[a-zA-Z0-9_.:\/[\]-]+$/;
|
|
45431
45668
|
const getHarnessPolicyRoute = HttpRouter.add("GET", "/api/settings/harness-policy", httpHandler(Effect.gen(function* () {
|
|
45432
45669
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
45433
45670
|
return yield* Effect.promise(async () => {
|
|
45434
|
-
const models = (new URL(request.url, "http://localhost").searchParams.get("models")
|
|
45435
|
-
if (models
|
|
45671
|
+
const models = parseHarnessPolicyModels(new URL(request.url, "http://localhost").searchParams.get("models"));
|
|
45672
|
+
if (!models) return jsonResponse({ error: "Valid models parameter is required" }, { status: 400 });
|
|
45436
45673
|
return jsonResponse({ decisions: await buildHarnessPolicyDecisions(models, getProviderAuthMode) });
|
|
45437
45674
|
});
|
|
45438
45675
|
})));
|
|
@@ -45474,7 +45711,7 @@ const getLegacyImportPreviewRoute = HttpRouter.add("GET", "/api/settings/legacy-
|
|
|
45474
45711
|
const postLegacyImportRoute = HttpRouter.add("POST", "/api/settings/legacy-import/conversations", httpHandler(Effect.gen(function* () {
|
|
45475
45712
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
45476
45713
|
if (authError) return authError;
|
|
45477
|
-
const body = yield* readJsonBody$
|
|
45714
|
+
const body = yield* readJsonBody$13;
|
|
45478
45715
|
return yield* Effect.try({
|
|
45479
45716
|
try: () => {
|
|
45480
45717
|
const { path, names } = body;
|
|
@@ -45486,7 +45723,7 @@ const postLegacyImportRoute = HttpRouter.add("POST", "/api/settings/legacy-impor
|
|
|
45486
45723
|
const settingsRouteLayer = Layer.mergeAll(getSettingsRoute, getAvailableModelsRoute, getOptimalDefaultsRoute, getMiniMaxDefaultsRoute, getClaudeAuthRoute, getOpenAIAuthRoute, postTestApiKeyRoute, postValidateApiKeyRoute, getConversationSearchStatusRoute, getConversationSearchReindexEstimateRoute, postConversationSearchReindexRoute, getConversationSearchReindexProgressRoute, putSettingsRoute, putUiThemeRoute, getOpenRouterModelsRoute, putOpenRouterFavoritesRoute, putOpenRouterApiKeyRoute, postOpenRouterTestKeyRoute, getHarnessPolicyRoute, getProviderEnvConflictsRoute, getLegacyImportPreviewRoute, postLegacyImportRoute);
|
|
45487
45724
|
//#endregion
|
|
45488
45725
|
//#region routes/autopreso.ts
|
|
45489
|
-
const readJsonBody$
|
|
45726
|
+
const readJsonBody$12 = Effect.gen(function* () {
|
|
45490
45727
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
45491
45728
|
const contentLength = Number(request.headers["content-length"] ?? 0);
|
|
45492
45729
|
if (Number.isFinite(contentLength) && contentLength > 256e3) return {
|
|
@@ -45517,7 +45754,7 @@ function requireTrustedOrigin$1(request) {
|
|
|
45517
45754
|
const startRoute = HttpRouter.add("POST", "/api/autopreso/start", httpHandler(Effect.gen(function* () {
|
|
45518
45755
|
const originError = requireTrustedOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
45519
45756
|
if (originError) return originError;
|
|
45520
|
-
const parsed = yield* readJsonBody$
|
|
45757
|
+
const parsed = yield* readJsonBody$12;
|
|
45521
45758
|
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 413 });
|
|
45522
45759
|
const elements = readElementLikes(parsed.body);
|
|
45523
45760
|
const validation = validateAutoPresoCanvasElements(elements);
|
|
@@ -45550,6 +45787,7 @@ const autopresoRouteLayer = Layer.mergeAll(startRoute, backToStagingRoute, reset
|
|
|
45550
45787
|
* GET /api/activity/:id
|
|
45551
45788
|
*/
|
|
45552
45789
|
init_domain_services();
|
|
45790
|
+
init_read_model();
|
|
45553
45791
|
init_agents$1();
|
|
45554
45792
|
init_review_status();
|
|
45555
45793
|
init_cost_sync();
|
|
@@ -45630,16 +45868,7 @@ const getMetricsStuckRoute = HttpRouter.add("GET", "/api/metrics/stuck", httpHan
|
|
|
45630
45868
|
});
|
|
45631
45869
|
})));
|
|
45632
45870
|
const getActivityRoute = HttpRouter.add("GET", "/api/activity", httpHandler(Effect.gen(function* () {
|
|
45633
|
-
return jsonResponse((yield* (yield* EventStoreService).queryByType("activity.entry", 100))
|
|
45634
|
-
id: e.payload["id"],
|
|
45635
|
-
timestamp: e.timestamp,
|
|
45636
|
-
source: e.payload["source"],
|
|
45637
|
-
level: e.payload["level"],
|
|
45638
|
-
message: e.payload["message"],
|
|
45639
|
-
details: e.payload["details"],
|
|
45640
|
-
issueId: e.payload["issueId"],
|
|
45641
|
-
link: e.payload["link"]
|
|
45642
|
-
})));
|
|
45871
|
+
return jsonResponse(activityEntriesFromStoredEvents(yield* (yield* EventStoreService).queryByType("activity.entry", 300), 100));
|
|
45643
45872
|
})));
|
|
45644
45873
|
const getActivityDetailedRoute = HttpRouter.add("GET", "/api/activity/detailed", httpHandler(Effect.gen(function* () {
|
|
45645
45874
|
return jsonResponse((yield* (yield* EventStoreService).queryByType("activity.detailed", 200)).map((e) => ({
|
|
@@ -45666,16 +45895,19 @@ const getActivityByIdRoute = HttpRouter.add("GET", "/api/activity/:id", httpHand
|
|
|
45666
45895
|
const params = yield* HttpRouter.params;
|
|
45667
45896
|
const eventStore = yield* EventStoreService;
|
|
45668
45897
|
const id = params["id"] ?? "";
|
|
45669
|
-
const activity = (yield* eventStore.queryByType("activity.entry", 1e3)).find((
|
|
45898
|
+
const activity = activityEntriesFromStoredEvents(yield* eventStore.queryByType("activity.entry", 1e3), 1e3).find((entry) => entry["id"] === id);
|
|
45670
45899
|
if (!activity) return jsonResponse({ error: "Activity not found" }, { status: 404 });
|
|
45671
45900
|
return jsonResponse({
|
|
45672
|
-
id: activity
|
|
45673
|
-
timestamp: activity
|
|
45674
|
-
source: activity
|
|
45675
|
-
level: activity
|
|
45676
|
-
|
|
45677
|
-
|
|
45678
|
-
|
|
45901
|
+
id: activity["id"],
|
|
45902
|
+
timestamp: activity["timestamp"],
|
|
45903
|
+
source: activity["source"],
|
|
45904
|
+
level: activity["level"],
|
|
45905
|
+
status: activity["status"],
|
|
45906
|
+
command: activity["command"],
|
|
45907
|
+
message: activity["message"],
|
|
45908
|
+
details: activity["details"],
|
|
45909
|
+
output: activity["output"],
|
|
45910
|
+
issueId: activity["issueId"]
|
|
45679
45911
|
});
|
|
45680
45912
|
})));
|
|
45681
45913
|
/** Parse and validate query params for GET /api/git-activity. Exported for unit testing. */
|
|
@@ -45723,7 +45955,7 @@ const metricsRouteLayer = Layer.mergeAll(getMetricsSummaryRoute, getMetricsCosts
|
|
|
45723
45955
|
//#region routes/boot-reconciliation.ts
|
|
45724
45956
|
init_tmux();
|
|
45725
45957
|
init_control_settings();
|
|
45726
|
-
const readJsonBody$
|
|
45958
|
+
const readJsonBody$11 = Effect.gen(function* () {
|
|
45727
45959
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
45728
45960
|
try {
|
|
45729
45961
|
return text ? JSON.parse(text) : {};
|
|
@@ -45752,7 +45984,7 @@ function bootReconciliationReadOnly(agent) {
|
|
|
45752
45984
|
const getBootReconciliationRoute = HttpRouter.add("GET", "/api/boot-reconciliation", Effect.sync(() => {
|
|
45753
45985
|
const state = getBootReconciliationState();
|
|
45754
45986
|
const candidateIds = new Set(listBootReconciliationCandidates().map((agent) => agent.id));
|
|
45755
|
-
const
|
|
45987
|
+
const toRow = (agent) => ({
|
|
45756
45988
|
id: agent.id,
|
|
45757
45989
|
issueId: agent.issueId,
|
|
45758
45990
|
role: agent.role,
|
|
@@ -45763,12 +45995,26 @@ const getBootReconciliationRoute = HttpRouter.add("GET", "/api/boot-reconciliati
|
|
|
45763
45995
|
cost: agent.costSoFar ?? null,
|
|
45764
45996
|
remote: Boolean(agent.hostOverride),
|
|
45765
45997
|
readOnly: bootReconciliationReadOnly(agent)
|
|
45766
|
-
})
|
|
45998
|
+
});
|
|
45999
|
+
const workAgents = listAllAgentsSync().filter((agent) => agent.role === "work");
|
|
46000
|
+
const set = workAgents.filter((agent) => candidateIds.has(agent.id)).map(toRow);
|
|
46001
|
+
const context = workAgents.filter((agent) => !candidateIds.has(agent.id) && (agent.paused === true || agent.troubled === true || Boolean(agent.hostOverride))).map(toRow);
|
|
45767
46002
|
return jsonResponse({
|
|
45768
46003
|
...state,
|
|
45769
|
-
|
|
46004
|
+
maxGraceExtensions: 3,
|
|
46005
|
+
set,
|
|
46006
|
+
context
|
|
45770
46007
|
});
|
|
45771
46008
|
}));
|
|
46009
|
+
/**
|
|
46010
|
+
* Push the grace deadline out while the operator is answering a different
|
|
46011
|
+
* blocking dialog. Bounded server-side by MAX_BOOT_RECONCILIATION_GRACE_EXTENSIONS;
|
|
46012
|
+
* the client may call this freely and the cap decides.
|
|
46013
|
+
*/
|
|
46014
|
+
const postBootReconciliationExtendRoute = HttpRouter.add("POST", "/api/boot-reconciliation/extend", httpHandler(Effect.sync(() => jsonResponse({
|
|
46015
|
+
ok: true,
|
|
46016
|
+
...extendBootReconciliationGrace()
|
|
46017
|
+
}))));
|
|
45772
46018
|
function isBootReconciliationDecision(value) {
|
|
45773
46019
|
return value === "resume_all" || value === "hold_all" || value === "per_agent";
|
|
45774
46020
|
}
|
|
@@ -45779,7 +46025,7 @@ function parsePerAgentMap(value) {
|
|
|
45779
46025
|
return parsed;
|
|
45780
46026
|
}
|
|
45781
46027
|
const postBootReconciliationDecisionRoute = HttpRouter.add("POST", "/api/boot-reconciliation/decision", httpHandler(Effect.gen(function* () {
|
|
45782
|
-
const body = yield* readJsonBody$
|
|
46028
|
+
const body = yield* readJsonBody$11;
|
|
45783
46029
|
if (!isBootReconciliationDecision(body.decision)) return jsonResponse({
|
|
45784
46030
|
ok: false,
|
|
45785
46031
|
error: "Body must include decision resume_all, hold_all, or per_agent"
|
|
@@ -45799,7 +46045,7 @@ const postBootReconciliationDecisionRoute = HttpRouter.add("POST", "/api/boot-re
|
|
|
45799
46045
|
count: resumed.length
|
|
45800
46046
|
});
|
|
45801
46047
|
})));
|
|
45802
|
-
const bootReconciliationRouteLayer = Layer.mergeAll(getBootReconciliationRoute, postBootReconciliationDecisionRoute);
|
|
46048
|
+
const bootReconciliationRouteLayer = Layer.mergeAll(getBootReconciliationRoute, postBootReconciliationDecisionRoute, postBootReconciliationExtendRoute);
|
|
45803
46049
|
//#endregion
|
|
45804
46050
|
//#region routes/misc/shared.ts
|
|
45805
46051
|
init_projects();
|
|
@@ -45876,7 +46122,7 @@ function getGitHubLocalPaths() {
|
|
|
45876
46122
|
}
|
|
45877
46123
|
return out;
|
|
45878
46124
|
}
|
|
45879
|
-
const readJsonBody$
|
|
46125
|
+
const readJsonBody$10 = Effect.gen(function* () {
|
|
45880
46126
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
45881
46127
|
try {
|
|
45882
46128
|
return text ? JSON.parse(text) : {};
|
|
@@ -45888,7 +46134,7 @@ const readJsonBody$9 = Effect.gen(function* () {
|
|
|
45888
46134
|
//#region routes/misc/project-mappings.ts
|
|
45889
46135
|
const getProjectMappingsRoute = HttpRouter.add("GET", "/api/project-mappings", httpHandler(Effect.promise(() => getProjectMappings().then((m) => jsonResponse(m)))));
|
|
45890
46136
|
const putProjectMappingsRoute = HttpRouter.add("PUT", "/api/project-mappings", Effect.gen(function* () {
|
|
45891
|
-
const mappings = yield* readJsonBody$
|
|
46137
|
+
const mappings = yield* readJsonBody$10;
|
|
45892
46138
|
if (!Array.isArray(mappings)) return jsonResponse({ error: "Expected array of mappings" }, { status: 400 });
|
|
45893
46139
|
yield* Effect.promise(() => saveProjectMappings(mappings));
|
|
45894
46140
|
return jsonResponse({
|
|
@@ -45897,7 +46143,7 @@ const putProjectMappingsRoute = HttpRouter.add("PUT", "/api/project-mappings", E
|
|
|
45897
46143
|
});
|
|
45898
46144
|
}));
|
|
45899
46145
|
const postProjectMappingsRoute = HttpRouter.add("POST", "/api/project-mappings", Effect.gen(function* () {
|
|
45900
|
-
const { linearProjectId, linearProjectName, linearPrefix, localPath } = yield* readJsonBody$
|
|
46146
|
+
const { linearProjectId, linearProjectName, linearPrefix, localPath } = yield* readJsonBody$10;
|
|
45901
46147
|
if (!linearProjectId || !localPath) return jsonResponse({ error: "linearProjectId and localPath required" }, { status: 400 });
|
|
45902
46148
|
return yield* Effect.promise(async () => {
|
|
45903
46149
|
try {
|
|
@@ -45924,7 +46170,7 @@ const postProjectMappingsRoute = HttpRouter.add("POST", "/api/project-mappings",
|
|
|
45924
46170
|
const projectMappingsRouteLayer = Layer.mergeAll(getProjectMappingsRoute, putProjectMappingsRoute, postProjectMappingsRoute);
|
|
45925
46171
|
//#endregion
|
|
45926
46172
|
//#region routes/misc/trackers.ts
|
|
45927
|
-
init_config();
|
|
46173
|
+
init_config$1();
|
|
45928
46174
|
init_config_yaml();
|
|
45929
46175
|
init_projects();
|
|
45930
46176
|
init_tracker_config();
|
|
@@ -46004,14 +46250,14 @@ const getTrackerStatusRoute = HttpRouter.add("GET", "/api/tracker-status", Effec
|
|
|
46004
46250
|
}
|
|
46005
46251
|
}));
|
|
46006
46252
|
const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Effect.gen(function* () {
|
|
46007
|
-
const { apiKey, server, workspace, project } = yield* readJsonBody$
|
|
46253
|
+
const { apiKey, server, workspace, project } = yield* readJsonBody$10;
|
|
46008
46254
|
if (!apiKey) return jsonResponse({
|
|
46009
46255
|
valid: false,
|
|
46010
46256
|
error: "API key is required"
|
|
46011
46257
|
}, { status: 400 });
|
|
46012
46258
|
return yield* Effect.promise(async () => {
|
|
46013
46259
|
try {
|
|
46014
|
-
const { RallyRestApi } = await import("./rally-api-
|
|
46260
|
+
const { RallyRestApi } = await import("./rally-api-D5uXN08-.js");
|
|
46015
46261
|
const api = new RallyRestApi({
|
|
46016
46262
|
apiKey,
|
|
46017
46263
|
server: server || "https://rally1.rallydev.com"
|
|
@@ -46353,7 +46599,7 @@ const getDeaconPauseRoute = HttpRouter.add("GET", "/api/deacon/pause", Effect.tr
|
|
|
46353
46599
|
* Persists to `app_settings` so the flag survives dashboard restarts.
|
|
46354
46600
|
*/
|
|
46355
46601
|
const postDeaconPauseRoute = HttpRouter.add("POST", "/api/deacon/pause", httpHandler(Effect.gen(function* () {
|
|
46356
|
-
const body = yield* readJsonBody$
|
|
46602
|
+
const body = yield* readJsonBody$10;
|
|
46357
46603
|
if (typeof body.paused !== "boolean") return jsonResponse({ error: "Body must include { paused: boolean }" }, { status: 400 });
|
|
46358
46604
|
setDeaconGloballyPausedSync(body.paused);
|
|
46359
46605
|
console.log(`[deacon] Global pause flag set to ${body.paused}`);
|
|
@@ -46365,6 +46611,7 @@ const deaconRouteLayer = Layer.mergeAll(getNoResumeModeRoute, postResumeAllRoute
|
|
|
46365
46611
|
init_config_yaml();
|
|
46366
46612
|
init_issue_id();
|
|
46367
46613
|
init_types();
|
|
46614
|
+
init_paths();
|
|
46368
46615
|
init_projects();
|
|
46369
46616
|
init_remote_agents();
|
|
46370
46617
|
init_tmux();
|
|
@@ -46396,7 +46643,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
|
|
|
46396
46643
|
const remoteState = loadRemoteAgentState(sessionName);
|
|
46397
46644
|
const isRemote = !!remoteState;
|
|
46398
46645
|
const vmName = remoteState?.vmName ?? "";
|
|
46399
|
-
const { getAgentStateSync } = await import("./agents-
|
|
46646
|
+
const { getAgentStateSync } = await import("./agents-BKKkxKgK.js");
|
|
46400
46647
|
const agentStarting = getAgentStateSync(sessionName)?.status === "starting";
|
|
46401
46648
|
let tmuxSessionAlive = false;
|
|
46402
46649
|
if (!isRemote) try {
|
|
@@ -46448,7 +46695,7 @@ const postPlanningMessageRoute = HttpRouter.add("POST", "/api/planning/:issueId/
|
|
|
46448
46695
|
const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
|
|
46449
46696
|
const sessionName = `planning-${issueId.toLowerCase()}`;
|
|
46450
46697
|
const issueLower = issueId.toLowerCase();
|
|
46451
|
-
const { message } = yield* readJsonBody$
|
|
46698
|
+
const { message } = yield* readJsonBody$10;
|
|
46452
46699
|
const eventStore = yield* EventStoreService;
|
|
46453
46700
|
if (!message) return jsonResponse({ error: "Message required" }, { status: 400 });
|
|
46454
46701
|
return yield* Effect.promise(async () => {
|
|
@@ -46540,7 +46787,7 @@ Continue the PLANNING session. Do NOT implement anything.
|
|
|
46540
46787
|
const agentCwd = workspacePath;
|
|
46541
46788
|
const harnessLaunch = await prepareHarnessLaunch("claude-code");
|
|
46542
46789
|
if (existsSync$1(outputFile)) await rename(outputFile, join(planningDir, `output-${Date.now()}.jsonl`));
|
|
46543
|
-
const { getAgentCommandSync } = await import("./settings-
|
|
46790
|
+
const { getAgentCommandSync } = await import("./settings-CdvIF84R.js");
|
|
46544
46791
|
let msgPlanningModel = "claude-sonnet-5";
|
|
46545
46792
|
try {
|
|
46546
46793
|
msgPlanningModel = resolveModel("plan", void 0, loadConfigSync().config);
|
|
@@ -46548,6 +46795,7 @@ Continue the PLANNING session. Do NOT implement anything.
|
|
|
46548
46795
|
const msgAgentCmd = getAgentCommandSync(msgPlanningModel);
|
|
46549
46796
|
const msgPermissionFlags = getClaudePermissionFlagsStringSync();
|
|
46550
46797
|
const msgCmdWithArgs = msgAgentCmd.args.length > 0 ? `${msgAgentCmd.command} ${msgAgentCmd.args.join(" ")} ${msgPermissionFlags}` : `${msgAgentCmd.command} ${msgPermissionFlags}`;
|
|
46798
|
+
const agentStateDir = join(getOverdeckHome(), "agents", sessionName);
|
|
46551
46799
|
const launcherScript = join(agentStateDir, "continuation-launcher.sh");
|
|
46552
46800
|
await mkdir(agentStateDir, { recursive: true });
|
|
46553
46801
|
await writeFile(launcherScript, generateLauncherScriptSync({
|
|
@@ -46662,7 +46910,7 @@ async function getIndexStats(rootPath, isMain) {
|
|
|
46662
46910
|
}
|
|
46663
46911
|
const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Effect.promise(async () => {
|
|
46664
46912
|
try {
|
|
46665
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
46913
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BKOYB616.js");
|
|
46666
46914
|
const projectRoot = process.cwd();
|
|
46667
46915
|
const venvPath = join(projectRoot, ".venv");
|
|
46668
46916
|
const results = [];
|
|
@@ -46707,7 +46955,7 @@ const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Ef
|
|
|
46707
46955
|
}));
|
|
46708
46956
|
const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Effect.promise(async () => {
|
|
46709
46957
|
try {
|
|
46710
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
46958
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BKOYB616.js");
|
|
46711
46959
|
const projectRoot = process.cwd();
|
|
46712
46960
|
const venvPath = join(projectRoot, ".venv");
|
|
46713
46961
|
if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
|
|
@@ -46724,7 +46972,7 @@ const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Ef
|
|
|
46724
46972
|
}));
|
|
46725
46973
|
const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effect.promise(async () => {
|
|
46726
46974
|
try {
|
|
46727
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
46975
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BKOYB616.js");
|
|
46728
46976
|
const projectRoot = process.cwd();
|
|
46729
46977
|
const venvPath = join(projectRoot, ".venv");
|
|
46730
46978
|
if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
|
|
@@ -46741,7 +46989,7 @@ const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effe
|
|
|
46741
46989
|
}));
|
|
46742
46990
|
const postTldrReloadRoute = HttpRouter.add("POST", "/api/services/tldr/reload", Effect.promise(async () => {
|
|
46743
46991
|
try {
|
|
46744
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
46992
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BKOYB616.js");
|
|
46745
46993
|
const enabled = isTldrEnabledSync();
|
|
46746
46994
|
const projectRoot = process.cwd();
|
|
46747
46995
|
const targets = [];
|
|
@@ -46904,7 +47152,7 @@ init_tracker_config();
|
|
|
46904
47152
|
init_issue_id();
|
|
46905
47153
|
init_projects();
|
|
46906
47154
|
init_tmux();
|
|
46907
|
-
const execAsync$
|
|
47155
|
+
const execAsync$4 = promisify(exec);
|
|
46908
47156
|
const execFileAsync$6 = promisify(execFile);
|
|
46909
47157
|
function getIssueDataService$1() {
|
|
46910
47158
|
const { getSharedIssueService } = (init_issue_service_singleton(), __toCommonJS(issue_service_singleton_exports));
|
|
@@ -46929,7 +47177,7 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
|
|
|
46929
47177
|
const version = await getOverdeckVersion();
|
|
46930
47178
|
let supervisorUrl = null;
|
|
46931
47179
|
try {
|
|
46932
|
-
const { getSupervisorUrlSync } = await import("./supervisor-
|
|
47180
|
+
const { getSupervisorUrlSync } = await import("./supervisor-UWiQNK-y.js");
|
|
46933
47181
|
supervisorUrl = getSupervisorUrlSync();
|
|
46934
47182
|
} catch {}
|
|
46935
47183
|
return jsonResponse({
|
|
@@ -46939,11 +47187,11 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
|
|
|
46939
47187
|
});
|
|
46940
47188
|
}));
|
|
46941
47189
|
const getPrerequisitesRoute = HttpRouter.add("GET", "/api/prerequisites", Effect.promise(async () => {
|
|
46942
|
-
const { checkSystemPrerequisites } = await import("./system-prerequisites-
|
|
47190
|
+
const { checkSystemPrerequisites } = await import("./system-prerequisites-pdWG6ZQs.js");
|
|
46943
47191
|
return jsonResponse(await checkSystemPrerequisites());
|
|
46944
47192
|
}));
|
|
46945
47193
|
const getSetupDiagnosticsRoute = HttpRouter.add("GET", "/api/diagnostics/setup", Effect.promise(async () => {
|
|
46946
|
-
const { collectSetupDiagnostics } = await import("./system-prerequisites-
|
|
47194
|
+
const { collectSetupDiagnostics } = await import("./system-prerequisites-pdWG6ZQs.js");
|
|
46947
47195
|
return jsonResponse(await collectSetupDiagnostics(await getOverdeckVersion()));
|
|
46948
47196
|
}));
|
|
46949
47197
|
const getSyncStatusRoute = HttpRouter.add("GET", "/api/sync-status", Effect.sync(() => {
|
|
@@ -46975,6 +47223,7 @@ const getRegisteredProjectsRoute = HttpRouter.add("GET", "/api/registered-projec
|
|
|
46975
47223
|
name: p.config.name,
|
|
46976
47224
|
path: p.config.path,
|
|
46977
47225
|
linearTeam: getIssuePrefix(p.config) || null,
|
|
47226
|
+
membershipQueryable: Boolean(getIssuePrefix(p.config)),
|
|
46978
47227
|
githubRepo: p.config.github_repo || null,
|
|
46979
47228
|
linearProject: p.config.linear_project || null
|
|
46980
47229
|
})));
|
|
@@ -46987,7 +47236,7 @@ const getConfirmationsRoute = HttpRouter.add("GET", "/api/confirmations", Effect
|
|
|
46987
47236
|
const postConfirmationRespondRoute = HttpRouter.add("POST", "/api/confirmations/:id/respond", Effect.gen(function* () {
|
|
46988
47237
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
46989
47238
|
const id = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
|
|
46990
|
-
const { confirmed } = yield* readJsonBody$
|
|
47239
|
+
const { confirmed } = yield* readJsonBody$10;
|
|
46991
47240
|
const confirmationRequest = pendingConfirmations.get(id);
|
|
46992
47241
|
if (!confirmationRequest) return jsonResponse({ error: "Confirmation request not found" }, { status: 404 });
|
|
46993
47242
|
return yield* Effect.promise(async () => {
|
|
@@ -47123,7 +47372,7 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
|
|
|
47123
47372
|
const projectPath = await getProjectPath(issuePrefix);
|
|
47124
47373
|
const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
|
|
47125
47374
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
47126
|
-
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-
|
|
47375
|
+
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-BWLa8ODz.js");
|
|
47127
47376
|
const config = {
|
|
47128
47377
|
issueId,
|
|
47129
47378
|
workspacePath,
|
|
@@ -47145,7 +47394,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
|
|
|
47145
47394
|
const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
|
|
47146
47395
|
const issueLower = issueId.toLowerCase();
|
|
47147
47396
|
const issuePrefix = extractPrefixSync(issueId) ?? issueId.split("-")[0];
|
|
47148
|
-
const { mode } = yield* readJsonBody$
|
|
47397
|
+
const { mode } = yield* readJsonBody$10;
|
|
47149
47398
|
return yield* Effect.promise(async () => {
|
|
47150
47399
|
try {
|
|
47151
47400
|
const projectPath = await getProjectPath(issuePrefix);
|
|
@@ -47153,7 +47402,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
|
|
|
47153
47402
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
47154
47403
|
const ghConfig = getGitHubConfig();
|
|
47155
47404
|
if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
|
|
47156
|
-
const { runObserverCycle } = await import("./shadow-engineering-
|
|
47405
|
+
const { runObserverCycle } = await import("./shadow-engineering-BWLa8ODz.js");
|
|
47157
47406
|
const firstRepo = ghConfig.repos[0];
|
|
47158
47407
|
const config = {
|
|
47159
47408
|
issueId,
|
|
@@ -47185,7 +47434,7 @@ const postDevRebuildRoute = HttpRouter.add("POST", "/api/dev/rebuild", Effect.ge
|
|
|
47185
47434
|
if (!overdeckDevMode || !overdeckProjectRoot) return jsonResponse({ error: "Rebuild only available in dev mode" }, { status: 403 });
|
|
47186
47435
|
return yield* Effect.promise(async () => {
|
|
47187
47436
|
try {
|
|
47188
|
-
const { stdout, stderr } = await execAsync$
|
|
47437
|
+
const { stdout, stderr } = await execAsync$4("npm run build", {
|
|
47189
47438
|
cwd: overdeckProjectRoot,
|
|
47190
47439
|
timeout: 12e4
|
|
47191
47440
|
});
|
|
@@ -48538,6 +48787,7 @@ async function getConversationDiffTurn(name, turnId, fileFilter, deps) {
|
|
|
48538
48787
|
}
|
|
48539
48788
|
//#endregion
|
|
48540
48789
|
//#region ../../lib/conversations/discovered-session-file.ts
|
|
48790
|
+
init_discovered_sessions();
|
|
48541
48791
|
async function resolveDiscoveredSessionFile(locator) {
|
|
48542
48792
|
if (!locator) return null;
|
|
48543
48793
|
const discovered = getDiscoveredSessionBySessionId(locator);
|
|
@@ -48668,8 +48918,12 @@ function titleTranscriptWindow(transcript) {
|
|
|
48668
48918
|
* production code into the live checkout (main saw `fs-lock.ts` appear from a
|
|
48669
48919
|
* dead session). Three independent gates:
|
|
48670
48920
|
*
|
|
48671
|
-
* - `--
|
|
48672
|
-
* cwd and `~/.claude` — a repo's permissive
|
|
48921
|
+
* - `--safe-mode` + `--setting-sources ''` skip hooks, settings allowlists,
|
|
48922
|
+
* MCP, and CLAUDE.md from the cwd and `~/.claude` — a repo's permissive
|
|
48923
|
+
* settings can never re-arm it. (Formerly `--bare`, but as of Claude Code
|
|
48924
|
+
* 2.1.209 `--bare` also skips credential reads, so every spawn failed with
|
|
48925
|
+
* "Not logged in" under subscription OAuth; `--safe-mode` explicitly keeps
|
|
48926
|
+
* auth working.)
|
|
48673
48927
|
* - `--tools ''` + `--disallowedTools mcp__*` strip every built-in and MCP
|
|
48674
48928
|
* tool so the model never sees a tool definition;
|
|
48675
48929
|
* - `--permission-mode dontAsk` auto-denies (never prompts, never hangs) if
|
|
@@ -48681,7 +48935,9 @@ function titleTranscriptWindow(transcript) {
|
|
|
48681
48935
|
function buildStructuredClaudeArgs(schema, model) {
|
|
48682
48936
|
return [
|
|
48683
48937
|
"-p",
|
|
48684
|
-
"--
|
|
48938
|
+
"--safe-mode",
|
|
48939
|
+
"--setting-sources",
|
|
48940
|
+
"",
|
|
48685
48941
|
"--tools",
|
|
48686
48942
|
"",
|
|
48687
48943
|
"--disallowedTools",
|
|
@@ -48896,6 +49152,340 @@ function isNonEmptyJsonlLine(buffer) {
|
|
|
48896
49152
|
return buffer.subarray(0, end).some((byte) => byte !== 32 && byte !== 9);
|
|
48897
49153
|
}
|
|
48898
49154
|
//#endregion
|
|
49155
|
+
//#region ../../lib/pane-choice-menu.ts
|
|
49156
|
+
init_transcript_adapter();
|
|
49157
|
+
init_summary_fork();
|
|
49158
|
+
init_conversation_compaction();
|
|
49159
|
+
/**
|
|
49160
|
+
* PAN-3113 — parse blocking numbered-choice menus from a captured tmux pane.
|
|
49161
|
+
*
|
|
49162
|
+
* Claude Code (and sibling harnesses) render modal choices as a cursor-driven
|
|
49163
|
+
* numbered menu — the session-resume gate is the driving case:
|
|
49164
|
+
*
|
|
49165
|
+
* This session is 4h 5m old and 146.9k tokens.
|
|
49166
|
+
*
|
|
49167
|
+
* Resuming the full session will consume a substantial portion of your
|
|
49168
|
+
* usage limits. We recommend resuming from a summary.
|
|
49169
|
+
*
|
|
49170
|
+
* ❯ 1. Resume from summary (recommended)
|
|
49171
|
+
* 2. Resume full session as-is
|
|
49172
|
+
* 3. Don't ask me again
|
|
49173
|
+
*
|
|
49174
|
+
* Enter to confirm · Esc to cancel
|
|
49175
|
+
*
|
|
49176
|
+
* These menus never appear as transcript tool calls, so neither the AUQ
|
|
49177
|
+
* pipeline nor the JSONL pending-input scan can see them. This module turns
|
|
49178
|
+
* the pane text into a structured menu the dashboard can render as an
|
|
49179
|
+
* actionable card (PAN-3113 mockup A) and answer with literal keystrokes
|
|
49180
|
+
* (Down × N + Enter).
|
|
49181
|
+
*
|
|
49182
|
+
* The parser is deliberately conservative — a false positive parks a phantom
|
|
49183
|
+
* decision card in a live conversation, which is worse than a miss:
|
|
49184
|
+
*
|
|
49185
|
+
* - Options must be numbered sequentially from 1 (kills prose lists such as
|
|
49186
|
+
* "3. FCM push is dead…" and "1. First step / 2. Second step" plans).
|
|
49187
|
+
* - High confidence requires BOTH a ❯ cursor row and a harness footer hint
|
|
49188
|
+
* ("Enter to confirm · Esc to cancel"). Exactly one of the two is low
|
|
49189
|
+
* confidence (render the verbatim mirror, not the card). Neither → null.
|
|
49190
|
+
* - The menu must be the current bottom-of-pane surface: after the menu and
|
|
49191
|
+
* its footer, only blank lines, box separators, or further footer hints
|
|
49192
|
+
* may follow. Real output below the menu means it was answered/scrolled.
|
|
49193
|
+
* - Claude permission menus ("1. Yes / 2. Yes, and allow / 3. No") are
|
|
49194
|
+
* excluded — the existing tool_permission detection path owns them.
|
|
49195
|
+
* - Multi-select menus ("space to select") are excluded — answering needs
|
|
49196
|
+
* toggle semantics the card does not model.
|
|
49197
|
+
*/
|
|
49198
|
+
const ANSI_PATTERN = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
49199
|
+
/** "❯ 1. Resume from summary (recommended)" / " 2. Resume full session as-is" */
|
|
49200
|
+
const OPTION_LINE = /^\s*(❯|›)?\s*(\d{1,2})[.)]\s+(\S.*)$/;
|
|
49201
|
+
/** Box-drawing separator lines (Claude draws ─── rules around its input box). */
|
|
49202
|
+
const SEPARATOR_LINE = /^\s*[─━═]{6,}\s*$/;
|
|
49203
|
+
/** Bare input prompt with nothing typed — the menu is gone when this follows. */
|
|
49204
|
+
const BARE_PROMPT_LINE = /^\s*(❯|›)\s*$/;
|
|
49205
|
+
const MAX_TRAILING_LINES = 6;
|
|
49206
|
+
const MAX_CONTEXT_LINES = 8;
|
|
49207
|
+
const MAX_OPTIONS = 9;
|
|
49208
|
+
const MAX_LABEL_CHARS = 100;
|
|
49209
|
+
const RECOMMENDED_SUFFIX = /\s*\((recommended)\)\s*$/i;
|
|
49210
|
+
function cleanLine(line) {
|
|
49211
|
+
return line.replace(ANSI_PATTERN, "").replace(/[\x00-\x1f\x7f]/g, "").replace(/\s+$/g, "");
|
|
49212
|
+
}
|
|
49213
|
+
/**
|
|
49214
|
+
* PAN-3068 shape — key/action pairs separated by "·". Every segment must open
|
|
49215
|
+
* with a key name, so real post-answer output never qualifies.
|
|
49216
|
+
*/
|
|
49217
|
+
function looksLikeHarnessFooterHint(line) {
|
|
49218
|
+
const segments = line.split("·").map((s) => s.trim()).filter(Boolean);
|
|
49219
|
+
if (segments.length === 0) return false;
|
|
49220
|
+
return segments.every((segment) => /^(?:esc(?:ape)?|tab|enter|return|space|backspace|shift\+\S+|ctrl\+\S+|alt\+\S+|\?)\b/i.test(segment) || /^press\s+\S+/i.test(segment));
|
|
49221
|
+
}
|
|
49222
|
+
/** "1. Yes / 2. Yes, and allow… / 3. No" — owned by the permission-menu path. */
|
|
49223
|
+
function looksLikePermissionOptions(options) {
|
|
49224
|
+
if (options.length !== 3) return false;
|
|
49225
|
+
return /^yes$/i.test(options[0].label) && /^yes,?\s*(?:and\s*)?(?:allow|don't ask|always)/i.test(options[1].label) && /^no\b/i.test(options[2].label);
|
|
49226
|
+
}
|
|
49227
|
+
function parseOptionLine(line) {
|
|
49228
|
+
const match = OPTION_LINE.exec(line);
|
|
49229
|
+
if (!match) return null;
|
|
49230
|
+
const number = Number(match[2]);
|
|
49231
|
+
if (!Number.isInteger(number) || number < 1 || number > MAX_OPTIONS) return null;
|
|
49232
|
+
const rawLabel = match[3].trim();
|
|
49233
|
+
if (rawLabel.length === 0 || rawLabel.length > MAX_LABEL_CHARS) return null;
|
|
49234
|
+
return {
|
|
49235
|
+
cursor: Boolean(match[1]),
|
|
49236
|
+
number,
|
|
49237
|
+
rawLabel
|
|
49238
|
+
};
|
|
49239
|
+
}
|
|
49240
|
+
/**
|
|
49241
|
+
* Parse the last numbered-choice menu in the pane, or null when the pane is
|
|
49242
|
+
* not currently blocked on one. See the module header for the conservative
|
|
49243
|
+
* acceptance rules.
|
|
49244
|
+
*/
|
|
49245
|
+
function parsePaneChoiceMenu(paneText) {
|
|
49246
|
+
if (!paneText) return null;
|
|
49247
|
+
const lines = paneText.split("\n").map(cleanLine);
|
|
49248
|
+
let end = lines.length - 1;
|
|
49249
|
+
while (end >= 0 && lines[end].trim() === "") end -= 1;
|
|
49250
|
+
if (end < 0) return null;
|
|
49251
|
+
let lastOption = -1;
|
|
49252
|
+
for (let i = end; i >= 0; i -= 1) {
|
|
49253
|
+
if (parseOptionLine(lines[i])) {
|
|
49254
|
+
lastOption = i;
|
|
49255
|
+
break;
|
|
49256
|
+
}
|
|
49257
|
+
if (end - i > MAX_TRAILING_LINES + MAX_OPTIONS) break;
|
|
49258
|
+
}
|
|
49259
|
+
if (lastOption < 0) return null;
|
|
49260
|
+
const optionLines = [];
|
|
49261
|
+
let firstOption = lastOption;
|
|
49262
|
+
for (let i = lastOption; i >= 0; i -= 1) {
|
|
49263
|
+
const parsed = parseOptionLine(lines[i]);
|
|
49264
|
+
if (!parsed) break;
|
|
49265
|
+
optionLines.unshift(parsed);
|
|
49266
|
+
firstOption = i;
|
|
49267
|
+
}
|
|
49268
|
+
if (optionLines.length < 2 || optionLines.length > MAX_OPTIONS) return null;
|
|
49269
|
+
for (let i = 0; i < optionLines.length; i += 1) if (optionLines[i].number !== i + 1) return null;
|
|
49270
|
+
const cursorRows = optionLines.map((opt, index) => opt.cursor ? index : -1).filter((index) => index >= 0);
|
|
49271
|
+
if (cursorRows.length > 1) return null;
|
|
49272
|
+
const trailing = lines.slice(lastOption + 1).filter((line) => line.trim() !== "");
|
|
49273
|
+
if (trailing.length > MAX_TRAILING_LINES) return null;
|
|
49274
|
+
let footerHint = null;
|
|
49275
|
+
for (const line of trailing) {
|
|
49276
|
+
if (BARE_PROMPT_LINE.test(line)) return null;
|
|
49277
|
+
if (SEPARATOR_LINE.test(line)) continue;
|
|
49278
|
+
if (looksLikeHarnessFooterHint(line.trim())) {
|
|
49279
|
+
if (footerHint === null) footerHint = line.trim();
|
|
49280
|
+
continue;
|
|
49281
|
+
}
|
|
49282
|
+
return null;
|
|
49283
|
+
}
|
|
49284
|
+
const options = optionLines.map((opt) => {
|
|
49285
|
+
const recommended = RECOMMENDED_SUFFIX.test(opt.rawLabel);
|
|
49286
|
+
return {
|
|
49287
|
+
number: opt.number,
|
|
49288
|
+
label: recommended ? opt.rawLabel.replace(RECOMMENDED_SUFFIX, "") : opt.rawLabel,
|
|
49289
|
+
recommended
|
|
49290
|
+
};
|
|
49291
|
+
});
|
|
49292
|
+
if (looksLikePermissionOptions(options)) return null;
|
|
49293
|
+
if (footerHint && /space\s+to\s+(?:select|toggle)/i.test(footerHint)) return null;
|
|
49294
|
+
const contextLines = [];
|
|
49295
|
+
let paragraphs = 0;
|
|
49296
|
+
let i = firstOption - 1;
|
|
49297
|
+
while (i >= 0 && lines[i].trim() === "") i -= 1;
|
|
49298
|
+
for (; i >= 0 && contextLines.length < MAX_CONTEXT_LINES; i -= 1) {
|
|
49299
|
+
const line = lines[i];
|
|
49300
|
+
if (SEPARATOR_LINE.test(line) || BARE_PROMPT_LINE.test(line)) break;
|
|
49301
|
+
if (parseOptionLine(line)) break;
|
|
49302
|
+
if (line.trim() === "") {
|
|
49303
|
+
if (paragraphs >= 2) break;
|
|
49304
|
+
let j = i - 1;
|
|
49305
|
+
while (j >= 0 && lines[j].trim() === "") j -= 1;
|
|
49306
|
+
if (j < 0 || SEPARATOR_LINE.test(lines[j]) || BARE_PROMPT_LINE.test(lines[j]) || parseOptionLine(lines[j])) break;
|
|
49307
|
+
i = j + 1;
|
|
49308
|
+
continue;
|
|
49309
|
+
}
|
|
49310
|
+
if (lines[i + 1] === void 0 || lines[i + 1].trim() === "") paragraphs += 1;
|
|
49311
|
+
contextLines.unshift(line.trim());
|
|
49312
|
+
}
|
|
49313
|
+
const hasCursor = cursorRows.length === 1;
|
|
49314
|
+
if (!hasCursor && footerHint === null) return null;
|
|
49315
|
+
const confidence = hasCursor && footerHint !== null ? "high" : "low";
|
|
49316
|
+
return {
|
|
49317
|
+
title: contextLines[0] ?? options[0].label,
|
|
49318
|
+
contextLines,
|
|
49319
|
+
options,
|
|
49320
|
+
selectedIndex: hasCursor ? cursorRows[0] : 0,
|
|
49321
|
+
footerHint,
|
|
49322
|
+
confidence
|
|
49323
|
+
};
|
|
49324
|
+
}
|
|
49325
|
+
/** Stable identity for patrol dedupe — same menu re-parsed must not re-surface. */
|
|
49326
|
+
function paneChoiceMenuSignature(menu) {
|
|
49327
|
+
return `${menu.title}::${menu.options.map((o) => `${o.number}:${o.label}`).join("|")}`;
|
|
49328
|
+
}
|
|
49329
|
+
/**
|
|
49330
|
+
* Literal tmux keystrokes answering the menu with `selectedIndex`: arrow the
|
|
49331
|
+
* cursor from its current row to the target, then confirm. Claude Code menus
|
|
49332
|
+
* move the ❯ cursor with ↑/↓ and confirm with Enter; number keys are not
|
|
49333
|
+
* guaranteed across harness versions, so arrows are the universal path.
|
|
49334
|
+
*/
|
|
49335
|
+
function buildChoiceKeystrokes(menu, selectedIndex) {
|
|
49336
|
+
const clamped = Math.max(0, Math.min(selectedIndex, menu.options.length - 1));
|
|
49337
|
+
const from = menu.selectedIndex;
|
|
49338
|
+
const keys = [];
|
|
49339
|
+
for (let i = from; i < clamped; i += 1) keys.push("Down");
|
|
49340
|
+
for (let i = from; i > clamped; i -= 1) keys.push("Up");
|
|
49341
|
+
keys.push("Enter");
|
|
49342
|
+
return keys;
|
|
49343
|
+
}
|
|
49344
|
+
//#endregion
|
|
49345
|
+
//#region ../../lib/overdeck/conversation-pane-choice.ts
|
|
49346
|
+
/**
|
|
49347
|
+
* PAN-3113 — surface blocking numbered-choice menus in claude-code
|
|
49348
|
+
* conversation panes (the session-resume gate is the driving case) as
|
|
49349
|
+
* actionable pending input, and answer them from the dashboard.
|
|
49350
|
+
*
|
|
49351
|
+
* Detection is request-driven, not a patrol: the pending-input feed already
|
|
49352
|
+
* polls every few seconds, so detection rides that cycle — when the menu
|
|
49353
|
+
* disappears (answered from the dashboard OR directly in the terminal) the
|
|
49354
|
+
* next poll simply stops reporting it. No server-side state machine, no
|
|
49355
|
+
* stale records.
|
|
49356
|
+
*
|
|
49357
|
+
* Answering re-captures uncached, verifies the menu the operator saw is still
|
|
49358
|
+
* the menu on screen (signature match), drives the selection with literal
|
|
49359
|
+
* keystrokes (Up/Down + Enter via sendRawKeystroke), then re-captures to
|
|
49360
|
+
* confirm the menu dismissed — the same contract as the Codex TUI approval
|
|
49361
|
+
* flow (`handleConversationCodexApproval`).
|
|
49362
|
+
*/
|
|
49363
|
+
init_conversations();
|
|
49364
|
+
init_behavior();
|
|
49365
|
+
init_tmux();
|
|
49366
|
+
const PANE_CAPTURE_LINES = 90;
|
|
49367
|
+
const KEYSTROKE_GAP_MS = 60;
|
|
49368
|
+
const DELIVERY_CONFIRM_WAIT_MS = 700;
|
|
49369
|
+
function isClaudeCodeConversation(conv) {
|
|
49370
|
+
return getHarnessBehavior(conv.harness).transcriptKind === "claude-jsonl";
|
|
49371
|
+
}
|
|
49372
|
+
/**
|
|
49373
|
+
* Parse the conversation's current pane for a blocking numbered-choice menu.
|
|
49374
|
+
* Returns null when the conversation is not claude-code, the capture fails,
|
|
49375
|
+
* or no menu is on screen. Detection-only callers (the pending-input feed)
|
|
49376
|
+
* use the shared cached capture; the answer path captures uncached.
|
|
49377
|
+
*/
|
|
49378
|
+
async function claudeConversationPaneChoice(conv, options = {}) {
|
|
49379
|
+
if (!isClaudeCodeConversation(conv)) return null;
|
|
49380
|
+
const capture = options.capture ?? ((sessionName, lines) => capturePaneText(sessionName, lines));
|
|
49381
|
+
let pane;
|
|
49382
|
+
try {
|
|
49383
|
+
pane = await capture(conv.tmuxSession, PANE_CAPTURE_LINES);
|
|
49384
|
+
} catch {
|
|
49385
|
+
return null;
|
|
49386
|
+
}
|
|
49387
|
+
const menu = parsePaneChoiceMenu(pane);
|
|
49388
|
+
if (!menu) return null;
|
|
49389
|
+
return {
|
|
49390
|
+
signature: paneChoiceMenuSignature(menu),
|
|
49391
|
+
title: menu.title,
|
|
49392
|
+
contextLines: menu.contextLines,
|
|
49393
|
+
options: menu.options.map((o) => ({
|
|
49394
|
+
number: o.number,
|
|
49395
|
+
label: o.label,
|
|
49396
|
+
recommended: o.recommended
|
|
49397
|
+
})),
|
|
49398
|
+
selectedIndex: menu.selectedIndex,
|
|
49399
|
+
footerHint: menu.footerHint,
|
|
49400
|
+
confidence: menu.confidence
|
|
49401
|
+
};
|
|
49402
|
+
}
|
|
49403
|
+
/**
|
|
49404
|
+
* POST /api/conversations/:id/pane-choice — answer the live pane menu.
|
|
49405
|
+
*
|
|
49406
|
+
* Body: `{ selectedIndex: number (0-based), signature: string }`. The
|
|
49407
|
+
* signature must match the menu currently on screen, or the operator answered
|
|
49408
|
+
* a stale card and we refuse (409) rather than send keystrokes into a
|
|
49409
|
+
* different prompt. Returns a plain `{ body, status }` for the route to
|
|
49410
|
+
* serialize — the same shape as the conversation-read handlers, so the
|
|
49411
|
+
* contract is unit-testable without an HTTP layer.
|
|
49412
|
+
*/
|
|
49413
|
+
async function handleConversationPaneChoiceAnswer(rawId, body, deps = {}) {
|
|
49414
|
+
try {
|
|
49415
|
+
const selectedIndex = Number(body["selectedIndex"]);
|
|
49416
|
+
const signature = typeof body["signature"] === "string" ? body["signature"] : "";
|
|
49417
|
+
if (!Number.isInteger(selectedIndex) || selectedIndex < 0 || selectedIndex > 8) return {
|
|
49418
|
+
body: { error: "selectedIndex must be an integer 0-8" },
|
|
49419
|
+
status: 400
|
|
49420
|
+
};
|
|
49421
|
+
if (!signature) return {
|
|
49422
|
+
body: { error: "signature is required" },
|
|
49423
|
+
status: 400
|
|
49424
|
+
};
|
|
49425
|
+
const numericId = Number(rawId);
|
|
49426
|
+
const conv = !Number.isNaN(numericId) && /^\d+$/.test(rawId) ? getConversationById(numericId) : getConversationByName(rawId);
|
|
49427
|
+
if (!conv) return {
|
|
49428
|
+
body: { error: "Conversation not found" },
|
|
49429
|
+
status: 404
|
|
49430
|
+
};
|
|
49431
|
+
if (!isClaudeCodeConversation(conv)) return {
|
|
49432
|
+
body: { error: "Not a Claude Code conversation" },
|
|
49433
|
+
status: 400
|
|
49434
|
+
};
|
|
49435
|
+
if (!await (deps.sessionExists ?? tmuxSessionExists)(conv.tmuxSession)) return {
|
|
49436
|
+
body: { error: "Conversation session is not running" },
|
|
49437
|
+
status: 409
|
|
49438
|
+
};
|
|
49439
|
+
const capture = deps.capture ?? ((sessionName, lines) => capturePaneText(sessionName, lines));
|
|
49440
|
+
const sendKey = deps.sendKey ?? ((sessionName, key) => Effect.runPromise(sendRawKeystroke(sessionName, key, "pane-choice")));
|
|
49441
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
49442
|
+
const menu = parsePaneChoiceMenu(await capture(conv.tmuxSession, PANE_CAPTURE_LINES));
|
|
49443
|
+
if (!menu) return {
|
|
49444
|
+
body: {
|
|
49445
|
+
error: "The choice menu is no longer on screen",
|
|
49446
|
+
code: "menu-gone"
|
|
49447
|
+
},
|
|
49448
|
+
status: 409
|
|
49449
|
+
};
|
|
49450
|
+
if (paneChoiceMenuSignature(menu) !== signature) return {
|
|
49451
|
+
body: {
|
|
49452
|
+
error: "The choice menu changed since the card was rendered — refresh and re-answer",
|
|
49453
|
+
code: "menu-changed"
|
|
49454
|
+
},
|
|
49455
|
+
status: 409
|
|
49456
|
+
};
|
|
49457
|
+
if (selectedIndex >= menu.options.length) return {
|
|
49458
|
+
body: { error: `selectedIndex out of range (0-${menu.options.length - 1})` },
|
|
49459
|
+
status: 400
|
|
49460
|
+
};
|
|
49461
|
+
const keys = buildChoiceKeystrokes(menu, selectedIndex);
|
|
49462
|
+
for (const key of keys) {
|
|
49463
|
+
await sendKey(conv.tmuxSession, key);
|
|
49464
|
+
await sleep(KEYSTROKE_GAP_MS);
|
|
49465
|
+
}
|
|
49466
|
+
await sleep(DELIVERY_CONFIRM_WAIT_MS);
|
|
49467
|
+
const after = parsePaneChoiceMenu(await capture(conv.tmuxSession, PANE_CAPTURE_LINES));
|
|
49468
|
+
if (after && paneChoiceMenuSignature(after) === signature) return {
|
|
49469
|
+
body: {
|
|
49470
|
+
error: "Keystrokes were sent but the menu is still on screen — answer it from the terminal",
|
|
49471
|
+
code: "delivery-unconfirmed"
|
|
49472
|
+
},
|
|
49473
|
+
status: 409
|
|
49474
|
+
};
|
|
49475
|
+
return { body: {
|
|
49476
|
+
ok: true,
|
|
49477
|
+
answeredLabel: menu.options[selectedIndex].label
|
|
49478
|
+
} };
|
|
49479
|
+
} catch (error) {
|
|
49480
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
49481
|
+
console.error("[conversations] pane-choice answer failed:", msg);
|
|
49482
|
+
return {
|
|
49483
|
+
body: { error: "Internal server error" },
|
|
49484
|
+
status: 500
|
|
49485
|
+
};
|
|
49486
|
+
}
|
|
49487
|
+
}
|
|
49488
|
+
//#endregion
|
|
48899
49489
|
//#region ../../lib/overdeck/conversation-reads.ts
|
|
48900
49490
|
init_concurrency$1();
|
|
48901
49491
|
init_behavior();
|
|
@@ -48907,7 +49497,6 @@ init_conversation_service();
|
|
|
48907
49497
|
init_pi_conversation_parser();
|
|
48908
49498
|
init_ohmypi_conversation_parser();
|
|
48909
49499
|
init_codex_conversation_parser();
|
|
48910
|
-
init_conversation_compaction();
|
|
48911
49500
|
function result(body, status) {
|
|
48912
49501
|
return status === void 0 ? { body } : {
|
|
48913
49502
|
body,
|
|
@@ -49130,13 +49719,16 @@ async function getConversationsPendingInputFeed(deps) {
|
|
|
49130
49719
|
const codex = await codexConversationPendingInput(conv, true, lastActivityAt ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
49131
49720
|
if (codex.approval) pending = codex.approval;
|
|
49132
49721
|
}
|
|
49133
|
-
|
|
49722
|
+
let paneChoice = null;
|
|
49723
|
+
if (!pending && !pendingPlan) paneChoice = await claudeConversationPaneChoice(conv);
|
|
49724
|
+
if (!pending && !pendingPlan && !paneChoice) return null;
|
|
49134
49725
|
return {
|
|
49135
49726
|
name: conv.name,
|
|
49136
49727
|
title: conv.title ?? null,
|
|
49137
49728
|
issueId: conv.issueId ?? null,
|
|
49138
49729
|
...pending ? { pendingAskUserQuestion: pending } : {},
|
|
49139
|
-
...pendingPlan ? { pendingProposedPlan: pendingPlan } : {}
|
|
49730
|
+
...pendingPlan ? { pendingProposedPlan: pendingPlan } : {},
|
|
49731
|
+
...paneChoice ? { pendingPaneChoice: paneChoice } : {}
|
|
49140
49732
|
};
|
|
49141
49733
|
})), 8))).filter((row) => row !== null));
|
|
49142
49734
|
} catch (error) {
|
|
@@ -49182,6 +49774,14 @@ async function getConversationRead(rawId, deps) {
|
|
|
49182
49774
|
if (codex.approval) pendingAskUserQuestion = codex.approval;
|
|
49183
49775
|
}
|
|
49184
49776
|
}
|
|
49777
|
+
let pendingPaneChoice = null;
|
|
49778
|
+
if (sessionAlive && pendingInputCount === 0) {
|
|
49779
|
+
pendingPaneChoice = await claudeConversationPaneChoice(conv);
|
|
49780
|
+
if (pendingPaneChoice) {
|
|
49781
|
+
pendingInputKinds = [...pendingInputKinds, "paneChoice"];
|
|
49782
|
+
pendingInputCount = pendingInputKinds.length;
|
|
49783
|
+
}
|
|
49784
|
+
}
|
|
49185
49785
|
return result({
|
|
49186
49786
|
...conv,
|
|
49187
49787
|
sessionAlive,
|
|
@@ -49191,6 +49791,7 @@ async function getConversationRead(rawId, deps) {
|
|
|
49191
49791
|
pendingInputCount,
|
|
49192
49792
|
pendingInputKinds,
|
|
49193
49793
|
pendingAskUserQuestion,
|
|
49794
|
+
...pendingPaneChoice ? { pendingPaneChoice } : {},
|
|
49194
49795
|
transcriptMissing: conversationTranscriptMissing(conv, sessionAlive, convSf),
|
|
49195
49796
|
needsTerminal: await conversationNeedsTerminal(conv, sessionAlive, convSf)
|
|
49196
49797
|
});
|
|
@@ -49483,8 +50084,6 @@ async function getConversationAbout(name, forceRefresh, deps) {
|
|
|
49483
50084
|
}
|
|
49484
50085
|
//#endregion
|
|
49485
50086
|
//#region ../../lib/overdeck/conversation-list.ts
|
|
49486
|
-
init_transcript_adapter();
|
|
49487
|
-
init_summary_fork();
|
|
49488
50087
|
init_agents$1();
|
|
49489
50088
|
init_concurrency$1();
|
|
49490
50089
|
init_behavior();
|
|
@@ -49912,7 +50511,35 @@ async function handleConversationMessage(name, body, deps = {
|
|
|
49912
50511
|
const message = typeof body["message"] === "string" ? body["message"].trim() : "";
|
|
49913
50512
|
if (!message) return jsonResponse({ error: "Message is required" }, { status: 400 });
|
|
49914
50513
|
if (message.length > MAX_MESSAGE_LENGTH) return jsonResponse({ error: `Message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters` }, { status: 400 });
|
|
49915
|
-
|
|
50514
|
+
try {
|
|
50515
|
+
const result = await handleComposerCommandMessage({
|
|
50516
|
+
message,
|
|
50517
|
+
confirmation: composerCommandConfirmationFromBody(body),
|
|
50518
|
+
target: {
|
|
50519
|
+
kind: "conversation",
|
|
50520
|
+
id: conv.name,
|
|
50521
|
+
harness: conv.harness ?? "claude-code",
|
|
50522
|
+
cwd: conv.cwd,
|
|
50523
|
+
issueId: conv.issueId ?? void 0
|
|
50524
|
+
}
|
|
50525
|
+
});
|
|
50526
|
+
if (result !== null) return jsonResponse(result, { status: composerCommandResultHttpStatus(result) });
|
|
50527
|
+
} catch (error) {
|
|
50528
|
+
if (error instanceof ComposerCommandConfirmationError) return jsonResponse({
|
|
50529
|
+
error: error.message,
|
|
50530
|
+
code: error.code
|
|
50531
|
+
}, { status: 422 });
|
|
50532
|
+
if (!(error instanceof ComposerCommandParseError)) throw error;
|
|
50533
|
+
const status = error.code === "unknown-command" ? 404 : error.code === "unknown-flag" ? 422 : 400;
|
|
50534
|
+
return jsonResponse({
|
|
50535
|
+
error: error.message,
|
|
50536
|
+
code: error.code,
|
|
50537
|
+
token: error.token,
|
|
50538
|
+
expected: error.expected
|
|
50539
|
+
}, { status });
|
|
50540
|
+
}
|
|
50541
|
+
const interceptManualCompact = deps.shouldInterceptManualCompact ?? shouldInterceptManualCompact;
|
|
50542
|
+
if (getHarnessBehavior(conv.harness).transcriptKind === "claude-jsonl" && interceptManualCompact(message)) {
|
|
49916
50543
|
const compactSessionFile = await deps.resolveSessionFile(conv);
|
|
49917
50544
|
if (!compactSessionFile || !existsSync$1(compactSessionFile)) return jsonResponse({ error: `No session file found for conversation ${conv.name}` }, { status: 400 });
|
|
49918
50545
|
const compactResult = await compactConversationNative(compactSessionFile, conv.name);
|
|
@@ -49951,7 +50578,7 @@ async function handleConversationMessage(name, body, deps = {
|
|
|
49951
50578
|
const effectiveAttachmentPaths = partition.effectiveAttachmentPaths;
|
|
49952
50579
|
const droppedImageCount = partition.droppedImageCount;
|
|
49953
50580
|
if (droppedImageCount > 0 && !outboundMessage && effectiveAttachmentPaths.length === 0) return jsonResponse({ error: `${conv.model ?? "This model"} can't read images. Switch to a vision-capable model (e.g. mimo-v2.5) to send images.` }, { status: 422 });
|
|
49954
|
-
let deliveredMessage = transformMessageForHarness(outboundMessage, harness, effectiveAttachmentPaths);
|
|
50581
|
+
let deliveredMessage = (deps.transformMessageForHarness ?? transformMessageForHarness)(outboundMessage, harness, effectiveAttachmentPaths);
|
|
49955
50582
|
if (behavior.injectsPromptTimeMemory) deliveredMessage = await injectPiConversationMemory({
|
|
49956
50583
|
cwd: conv.cwd,
|
|
49957
50584
|
issueId: conv.issueId,
|
|
@@ -50352,7 +50979,7 @@ async function refreshMergeStateFromGitHub(issueId, repo, prNumber) {
|
|
|
50352
50979
|
let mergeState;
|
|
50353
50980
|
let isDraft;
|
|
50354
50981
|
let checksFailed;
|
|
50355
|
-
const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-
|
|
50982
|
+
const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-DtAsvwzK.js");
|
|
50356
50983
|
if (isGitHubAppConfigured()) {
|
|
50357
50984
|
const prState = await Effect.runPromise(getPullRequestState(owner, repoName, prNumber));
|
|
50358
50985
|
mergeable = prState.mergeable === null ? "UNKNOWN" : prState.mergeable ? "MERGEABLE" : "CONFLICTING";
|
|
@@ -50503,8 +51130,8 @@ async function handlePullRequestPromise(payload) {
|
|
|
50503
51130
|
bumpIssuePrTabCacheGeneration(issueId);
|
|
50504
51131
|
const repo = payload.repository.full_name;
|
|
50505
51132
|
if (payload.action === "closed" && pr.merged === true) try {
|
|
50506
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
50507
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
51133
|
+
const { postMergeLifecycle } = await import("./merge-agent-DrXa1CpW.js");
|
|
51134
|
+
const { resolveProjectFromIssueSync } = await import("./projects-B03Wr-xc.js");
|
|
50508
51135
|
const project = resolveProjectFromIssueSync(issueId);
|
|
50509
51136
|
if (project) {
|
|
50510
51137
|
const branchName = pr.head.ref;
|
|
@@ -51351,7 +51978,7 @@ startConversationModelBackfill(resolveSessionFile);
|
|
|
51351
51978
|
function conversationReadJson(response) {
|
|
51352
51979
|
return jsonResponse(response.body, response.status === void 0 ? void 0 : { status: response.status });
|
|
51353
51980
|
}
|
|
51354
|
-
const readJsonBody$
|
|
51981
|
+
const readJsonBody$9 = Effect.gen(function* () {
|
|
51355
51982
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
51356
51983
|
try {
|
|
51357
51984
|
return text ? JSON.parse(text) : {};
|
|
@@ -51411,7 +52038,7 @@ const postConversationRoute = HttpRouter.add("POST", "/api/conversations", Effec
|
|
|
51411
52038
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
51412
52039
|
const originCheck = validateOrigin$1(request);
|
|
51413
52040
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51414
|
-
const body = yield* readJsonBody$
|
|
52041
|
+
const body = yield* readJsonBody$9;
|
|
51415
52042
|
const reqOrigin = getHeader(request, "origin") ?? "none";
|
|
51416
52043
|
const reqReferer = getHeader(request, "referer") ?? "none";
|
|
51417
52044
|
const reqUserAgent = getHeader(request, "user-agent") ?? "none";
|
|
@@ -51430,14 +52057,14 @@ const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:
|
|
|
51430
52057
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51431
52058
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51432
52059
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51433
|
-
const body = yield* readJsonBody$
|
|
52060
|
+
const body = yield* readJsonBody$9;
|
|
51434
52061
|
return yield* Effect.promise(async () => handleConversationResume(name, body, { resolveSessionFile }));
|
|
51435
52062
|
}));
|
|
51436
52063
|
const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversations/:name/switch-model", Effect.gen(function* () {
|
|
51437
52064
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51438
52065
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51439
52066
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51440
|
-
const body = yield* readJsonBody$
|
|
52067
|
+
const body = yield* readJsonBody$9;
|
|
51441
52068
|
return yield* Effect.promise(async () => {
|
|
51442
52069
|
try {
|
|
51443
52070
|
return await handleConversationSwitchModel(name, body);
|
|
@@ -51452,7 +52079,7 @@ const postConversationThinkingLevelRoute = HttpRouter.add("POST", "/api/conversa
|
|
|
51452
52079
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51453
52080
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51454
52081
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51455
|
-
const body = yield* readJsonBody$
|
|
52082
|
+
const body = yield* readJsonBody$9;
|
|
51456
52083
|
return yield* Effect.promise(async () => {
|
|
51457
52084
|
try {
|
|
51458
52085
|
return await handleConversationThinkingLevel(name, body);
|
|
@@ -51548,7 +52175,7 @@ const postConversationDeleteImageRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
51548
52175
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51549
52176
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51550
52177
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51551
|
-
const body = yield* readJsonBody$
|
|
52178
|
+
const body = yield* readJsonBody$9;
|
|
51552
52179
|
return yield* Effect.promise(async () => {
|
|
51553
52180
|
try {
|
|
51554
52181
|
return await handleConversationImageDelete(name, body);
|
|
@@ -51563,7 +52190,7 @@ const postConversationMessageRoute = HttpRouter.add("POST", "/api/conversations/
|
|
|
51563
52190
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51564
52191
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51565
52192
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51566
|
-
const body = yield* readJsonBody$
|
|
52193
|
+
const body = yield* readJsonBody$9;
|
|
51567
52194
|
return yield* Effect.promise(async () => {
|
|
51568
52195
|
try {
|
|
51569
52196
|
return await handleConversationMessage(name, body, conversationMessageDependencies);
|
|
@@ -51583,14 +52210,24 @@ const postConversationCodexApprovalRoute = HttpRouter.add("POST", "/api/conversa
|
|
|
51583
52210
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51584
52211
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51585
52212
|
const rawId = (yield* HttpRouter.params)["id"] ?? "";
|
|
51586
|
-
const body = yield* readJsonBody$
|
|
52213
|
+
const body = yield* readJsonBody$9;
|
|
51587
52214
|
return yield* Effect.promise(() => handleConversationCodexApproval(rawId, body));
|
|
51588
52215
|
}));
|
|
52216
|
+
const postConversationPaneChoiceRoute = HttpRouter.add("POST", "/api/conversations/:id/pane-choice", Effect.gen(function* () {
|
|
52217
|
+
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
52218
|
+
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
52219
|
+
const rawId = (yield* HttpRouter.params)["id"] ?? "";
|
|
52220
|
+
const body = yield* readJsonBody$9;
|
|
52221
|
+
return yield* Effect.promise(async () => {
|
|
52222
|
+
const result = await handleConversationPaneChoiceAnswer(rawId, body);
|
|
52223
|
+
return jsonResponse(result.body, { status: result.status });
|
|
52224
|
+
});
|
|
52225
|
+
}));
|
|
51589
52226
|
const postConversationDeliveryMethodRoute = HttpRouter.add("POST", "/api/conversations/:name/delivery-method", Effect.gen(function* () {
|
|
51590
52227
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51591
52228
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51592
52229
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51593
|
-
const body = yield* readJsonBody$
|
|
52230
|
+
const body = yield* readJsonBody$9;
|
|
51594
52231
|
return yield* Effect.promise(async () => {
|
|
51595
52232
|
try {
|
|
51596
52233
|
return await handleConversationDeliveryMethod(name, body);
|
|
@@ -51605,7 +52242,7 @@ const postConversationControlAckRoute = HttpRouter.add("POST", "/api/conversatio
|
|
|
51605
52242
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
51606
52243
|
const originCheck = validateConversationControlAckOrigin(request.headers, request.method);
|
|
51607
52244
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51608
|
-
const body = yield* readJsonBody$
|
|
52245
|
+
const body = yield* readJsonBody$9;
|
|
51609
52246
|
return yield* Effect.promise(async () => {
|
|
51610
52247
|
try {
|
|
51611
52248
|
const result = handleConversationControlAck(body);
|
|
@@ -51621,7 +52258,7 @@ const patchConversationRoute = HttpRouter.add("PATCH", "/api/conversations/:name
|
|
|
51621
52258
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51622
52259
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51623
52260
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51624
|
-
const body = yield* readJsonBody$
|
|
52261
|
+
const body = yield* readJsonBody$9;
|
|
51625
52262
|
return yield* Effect.promise(async () => {
|
|
51626
52263
|
try {
|
|
51627
52264
|
const result = patchConversationTitle(name, body);
|
|
@@ -51708,14 +52345,14 @@ const postConversationSummaryForkRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
51708
52345
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51709
52346
|
const params = yield* HttpRouter.params;
|
|
51710
52347
|
const name = decodeURIComponent(params["name"] ?? "");
|
|
51711
|
-
const body = yield* readJsonBody$
|
|
52348
|
+
const body = yield* readJsonBody$9;
|
|
51712
52349
|
return yield* Effect.promise(() => handleConversationSummaryFork(name, body));
|
|
51713
52350
|
}));
|
|
51714
52351
|
const postConversationPlanActionRoute = HttpRouter.add("POST", "/api/conversations/:name/plan-action", Effect.gen(function* () {
|
|
51715
52352
|
const originCheck = validateOrigin$1(yield* HttpServerRequest.HttpServerRequest);
|
|
51716
52353
|
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
51717
52354
|
const name = (yield* HttpRouter.params)["name"] ?? "";
|
|
51718
|
-
const body = yield* readJsonBody$
|
|
52355
|
+
const body = yield* readJsonBody$9;
|
|
51719
52356
|
return yield* Effect.promise(() => handleConversationPlanAction(name, body));
|
|
51720
52357
|
}));
|
|
51721
52358
|
const conversationDiffDependencies = {
|
|
@@ -51770,7 +52407,7 @@ const getConversationAboutRoute = HttpRouter.add("GET", "/api/conversations/:nam
|
|
|
51770
52407
|
return conversationReadJson(await getConversationAbout(name, new URL(request.url, "http://localhost").searchParams.get("refresh") === "1", conversationReadDependencies));
|
|
51771
52408
|
});
|
|
51772
52409
|
}));
|
|
51773
|
-
const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, getConversationsPendingInputRoute, getArchivedConversationsRoute, getConversationRoute, getConversationHandoffDocRoute, postConversationRoute, patchConversationRoute, deleteConversationRoute, postConversationStopRoute, postConversationResumeRoute, postConversationSwitchModelRoute, postConversationThinkingLevelRoute, postConversationCompactRoute, postConversationAbortRoute, postConversationRestartAllRoute, postConversationArchiveRoute, postConversationUnarchiveRoute, getConversationMessagesRoute, getConversationMessageLocatorRoute, postConversationUploadImageRoute, postConversationDeleteImageRoute, postConversationMessageRoute, postConversationCodexApprovalRoute, postConversationDeliveryMethodRoute, postConversationControlAckRoute, postConversationFavoriteRoute, deleteConversationFavoriteRoute, postConversationSummaryForkRoute, postConversationPlanActionRoute, getConversationDiffsRoute, getConversationDiffFullRoute, getConversationDiffTurnRoute, postConversationRetitleRoute, getConversationAboutRoute);
|
|
52410
|
+
const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, getConversationsPendingInputRoute, getArchivedConversationsRoute, getConversationRoute, getConversationHandoffDocRoute, postConversationRoute, patchConversationRoute, deleteConversationRoute, postConversationStopRoute, postConversationResumeRoute, postConversationSwitchModelRoute, postConversationThinkingLevelRoute, postConversationCompactRoute, postConversationAbortRoute, postConversationRestartAllRoute, postConversationArchiveRoute, postConversationUnarchiveRoute, getConversationMessagesRoute, getConversationMessageLocatorRoute, postConversationUploadImageRoute, postConversationDeleteImageRoute, postConversationMessageRoute, postConversationCodexApprovalRoute, postConversationPaneChoiceRoute, postConversationDeliveryMethodRoute, postConversationControlAckRoute, postConversationFavoriteRoute, deleteConversationFavoriteRoute, postConversationSummaryForkRoute, postConversationPlanActionRoute, getConversationDiffsRoute, getConversationDiffFullRoute, getConversationDiffTurnRoute, postConversationRetitleRoute, getConversationAboutRoute);
|
|
51774
52411
|
//#endregion
|
|
51775
52412
|
//#region routes/show.ts
|
|
51776
52413
|
/**
|
|
@@ -51817,7 +52454,7 @@ const showRouteLayer = Layer.mergeAll(getShowRoute, getShowShadowRoute, getShowH
|
|
|
51817
52454
|
//#endregion
|
|
51818
52455
|
//#region routes/project-rename.ts
|
|
51819
52456
|
init_projects();
|
|
51820
|
-
const readJsonBody$
|
|
52457
|
+
const readJsonBody$8 = Effect.gen(function* () {
|
|
51821
52458
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
51822
52459
|
try {
|
|
51823
52460
|
return text ? JSON.parse(text) : {};
|
|
@@ -51829,7 +52466,7 @@ const postProjectRenameRoute = HttpRouter.add("POST", "/api/projects/:projectKey
|
|
|
51829
52466
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51830
52467
|
if (authError) return authError;
|
|
51831
52468
|
const projectIdentifier = (yield* HttpRouter.params)["projectKey"] ?? "";
|
|
51832
|
-
const body = yield* readJsonBody$
|
|
52469
|
+
const body = yield* readJsonBody$8;
|
|
51833
52470
|
if (typeof body.name !== "string") return jsonResponse({ error: "Project name must be a string" }, { status: 400 });
|
|
51834
52471
|
const result = yield* Effect.result(renameProject(projectIdentifier, body.name));
|
|
51835
52472
|
if (Result$1.isFailure(result)) {
|
|
@@ -51848,9 +52485,8 @@ const postProjectRenameRoute = HttpRouter.add("POST", "/api/projects/:projectKey
|
|
|
51848
52485
|
* No chalk, no console, no execSync. Import and use from API routes or CLI.
|
|
51849
52486
|
*/
|
|
51850
52487
|
init_projects();
|
|
51851
|
-
init_paths();
|
|
51852
52488
|
init_context_layers();
|
|
51853
|
-
|
|
52489
|
+
init_git_hooks();
|
|
51854
52490
|
var DuplicateProjectError = class extends Error {
|
|
51855
52491
|
constructor(key, existingPath) {
|
|
51856
52492
|
super(`Project already registered with key: ${key} (path: ${existingPath})`);
|
|
@@ -51859,31 +52495,6 @@ var DuplicateProjectError = class extends Error {
|
|
|
51859
52495
|
this.name = "DuplicateProjectError";
|
|
51860
52496
|
}
|
|
51861
52497
|
};
|
|
51862
|
-
function installGitHooksInDir(gitDir) {
|
|
51863
|
-
const hooksTarget = join(gitDir, "hooks");
|
|
51864
|
-
let installed = 0;
|
|
51865
|
-
if (!existsSync$1(hooksTarget)) mkdirSync$1(hooksTarget, { recursive: true });
|
|
51866
|
-
if (!existsSync$1(BUNDLED_HOOKS_DIR)) return 0;
|
|
51867
|
-
try {
|
|
51868
|
-
const hooks = readdirSync$1(BUNDLED_HOOKS_DIR).filter((f) => {
|
|
51869
|
-
const p = join(BUNDLED_HOOKS_DIR, f);
|
|
51870
|
-
return existsSync$1(p) && statSync$1(p).isFile();
|
|
51871
|
-
});
|
|
51872
|
-
for (const hook of hooks) {
|
|
51873
|
-
const source = join(BUNDLED_HOOKS_DIR, hook);
|
|
51874
|
-
const target = join(hooksTarget, hook);
|
|
51875
|
-
if (existsSync$1(target)) {
|
|
51876
|
-
try {
|
|
51877
|
-
if (readlinkSync(target) === source) continue;
|
|
51878
|
-
} catch {}
|
|
51879
|
-
renameSync$1(target, `${target}.backup`);
|
|
51880
|
-
}
|
|
51881
|
-
symlinkSync$1(source, target);
|
|
51882
|
-
installed++;
|
|
51883
|
-
}
|
|
51884
|
-
} catch {}
|
|
51885
|
-
return installed;
|
|
51886
|
-
}
|
|
51887
52498
|
/**
|
|
51888
52499
|
* Register a project from a filesystem path.
|
|
51889
52500
|
*
|
|
@@ -51904,7 +52515,7 @@ async function registerProjectFromPath(opts) {
|
|
|
51904
52515
|
registerProjectSync(key, projectConfig);
|
|
51905
52516
|
const seededContextLayer = ensureProjectLayer(fullPath);
|
|
51906
52517
|
try {
|
|
51907
|
-
const { preTrustDirectorySync } = await import("./workspace-manager-
|
|
52518
|
+
const { preTrustDirectorySync } = await import("./workspace-manager-CDTKjjdU.js");
|
|
51908
52519
|
preTrustDirectorySync(fullPath);
|
|
51909
52520
|
} catch {}
|
|
51910
52521
|
let hooksInstalled = 0;
|
|
@@ -51943,9 +52554,9 @@ init_pan_dir();
|
|
|
51943
52554
|
init_io();
|
|
51944
52555
|
init_specs();
|
|
51945
52556
|
init_paths();
|
|
51946
|
-
const execAsync$
|
|
52557
|
+
const execAsync$3 = promisify(exec);
|
|
51947
52558
|
async function getIssueDataService() {
|
|
51948
|
-
const { getSharedIssueService } = await import("./issue-service-singleton-
|
|
52559
|
+
const { getSharedIssueService } = await import("./issue-service-singleton-PMx8F1jr.js");
|
|
51949
52560
|
return getSharedIssueService();
|
|
51950
52561
|
}
|
|
51951
52562
|
/** Returns true if the path exists (any type). */
|
|
@@ -52237,8 +52848,9 @@ async function collectSessionTreeNodes(issueId, workspacePath, projectPath, cont
|
|
|
52237
52848
|
if (latestMerge) {
|
|
52238
52849
|
const shipSessionName = `agent-${issueLower}-ship`;
|
|
52239
52850
|
const shipIsLive = context.tmuxSessionNames.has(shipSessionName);
|
|
52240
|
-
const
|
|
52241
|
-
|
|
52851
|
+
const shipState = getAgentStateSync(shipSessionName);
|
|
52852
|
+
const shipJsonlPath = shipIsLive || shipState ? await resolveJsonlPath(shipSessionName, workspacePath) : null;
|
|
52853
|
+
if (shipIsLive || shipJsonlPath) sections.push({
|
|
52242
52854
|
type: "ship",
|
|
52243
52855
|
sessionId: shipSessionName,
|
|
52244
52856
|
model: "specialist",
|
|
@@ -52321,11 +52933,22 @@ async function fetchProjectSessionTree(projectKey, sharedContext) {
|
|
|
52321
52933
|
const features = [];
|
|
52322
52934
|
const issueTitles = sharedContext?.issueTitles ?? await buildIssueTitleMap();
|
|
52323
52935
|
if (await pathExists$1(workspacesDir)) {
|
|
52324
|
-
const
|
|
52325
|
-
|
|
52326
|
-
|
|
52327
|
-
|
|
52328
|
-
|
|
52936
|
+
const entries = await readdir(workspacesDir, { withFileTypes: true }).catch(() => []);
|
|
52937
|
+
const candidateIssueLowers = /* @__PURE__ */ new Set();
|
|
52938
|
+
for (const entry of entries) {
|
|
52939
|
+
if (!entry.isDirectory()) continue;
|
|
52940
|
+
const match = /^feature-([a-z]+-\d+)(?:-strike|-slot-\d+)?$/.exec(entry.name);
|
|
52941
|
+
if (match) candidateIssueLowers.add(match[1]);
|
|
52942
|
+
}
|
|
52943
|
+
for (const issueLower of liveTmuxIssueIds) {
|
|
52944
|
+
if (candidateIssueLowers.has(issueLower)) continue;
|
|
52945
|
+
if (resolveProjectFromIssueSync(issueLower.toUpperCase())?.projectKey === project.key) candidateIssueLowers.add(issueLower);
|
|
52946
|
+
}
|
|
52947
|
+
const featureCandidates = [...candidateIssueLowers].map((issueLower) => ({
|
|
52948
|
+
name: `feature-${issueLower}`,
|
|
52949
|
+
issueLower,
|
|
52950
|
+
issueId: issueLower.toUpperCase()
|
|
52951
|
+
}));
|
|
52329
52952
|
const results = await Effect.runPromise(withConcurrencyLimit(featureCandidates.map((c) => Effect.promise(async () => {
|
|
52330
52953
|
const agentDir = join(getOverdeckHome(), "agents", `agent-${c.issueLower}`);
|
|
52331
52954
|
const planningAgentDir = join(getOverdeckHome(), "agents", `planning-${c.issueLower}`);
|
|
@@ -52403,7 +53026,7 @@ const getProjectReleaseStatusRoute = HttpRouter.add("GET", "/api/projects/:proje
|
|
|
52403
53026
|
const projectKey = (yield* HttpRouter.params)["projectKey"] ?? "";
|
|
52404
53027
|
return jsonResponse(yield* Effect.tryPromise({
|
|
52405
53028
|
try: async () => {
|
|
52406
|
-
const { fetchProjectReleaseStatus } = await import("./project-pipelines-
|
|
53029
|
+
const { fetchProjectReleaseStatus } = await import("./project-pipelines-Bim6bThI.js");
|
|
52407
53030
|
return fetchProjectReleaseStatus(projectKey);
|
|
52408
53031
|
},
|
|
52409
53032
|
catch: (err) => new Error(err instanceof Error ? err.message : String(err))
|
|
@@ -52613,7 +53236,7 @@ const postProjectsRoute = HttpRouter.add("POST", "/api/projects", httpHandler(Ef
|
|
|
52613
53236
|
if ((await readdir(target).catch(() => [])).length > 0) return jsonResponse({ error: `target directory already exists and is non-empty: ${target}` }, { status: 409 });
|
|
52614
53237
|
}
|
|
52615
53238
|
await mkdir(target, { recursive: true });
|
|
52616
|
-
await execAsync$
|
|
53239
|
+
await execAsync$3("git init", { cwd: target });
|
|
52617
53240
|
try {
|
|
52618
53241
|
const result = await registerProjectFromPath({
|
|
52619
53242
|
path: target,
|
|
@@ -52638,6 +53261,271 @@ const postProjectsRoute = HttpRouter.add("POST", "/api/projects", httpHandler(Ef
|
|
|
52638
53261
|
})));
|
|
52639
53262
|
const projectsRouteLayer = Layer.mergeAll(getProjectSessionTreeRoute, getAllSessionTreesRoute, getProjectReleaseStatusRoute, getProjectAutoMergeDefaultRoute, postProjectAutoMergeDefaultRoute, postProjectRenameRoute, getProjectSwarmPolicyRoute, postProjectSwarmPolicyRoute, getIssueSwarmPolicyRoute, postIssueSwarmPolicyRoute, getIssueStaffingRoute, postIssueStaffingRoute, postProjectsRoute);
|
|
52640
53263
|
//#endregion
|
|
53264
|
+
//#region routes/projects-merge-train.ts
|
|
53265
|
+
/** PAN-1696: Per-project merge-train override endpoints (GET/POST) */
|
|
53266
|
+
init_projects();
|
|
53267
|
+
const getProjectMergeTrainRoute = HttpRouter.add("GET", "/api/projects/:projectKey/merge-train", httpHandler(Effect.gen(function* () {
|
|
53268
|
+
const config = getProjectSync((yield* HttpRouter.params)["projectKey"] ?? "");
|
|
53269
|
+
if (!config) return jsonResponse({ error: "Project not found" }, { status: 404 });
|
|
53270
|
+
const { isMergeTrainEnabledForProject } = yield* Effect.promise(() => import("./merge-sync-Ca7F5JnQ.js"));
|
|
53271
|
+
return jsonResponse({
|
|
53272
|
+
value: config.merge_train ?? null,
|
|
53273
|
+
effective: isMergeTrainEnabledForProject(config)
|
|
53274
|
+
});
|
|
53275
|
+
})));
|
|
53276
|
+
const postProjectMergeTrainRoute = HttpRouter.add("POST", "/api/projects/:projectKey/merge-train", httpHandler(Effect.gen(function* () {
|
|
53277
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53278
|
+
if (authError) return authError;
|
|
53279
|
+
const key = (yield* HttpRouter.params)["projectKey"] ?? "";
|
|
53280
|
+
if (!getProjectSync(key)) return jsonResponse({ error: "Project not found" }, { status: 404 });
|
|
53281
|
+
const v = (yield* readProjectJsonBody).value;
|
|
53282
|
+
if (v !== "enabled" && v !== "disabled" && v !== null) return jsonResponse({ error: "value must be 'enabled', 'disabled', or null" }, { status: 400 });
|
|
53283
|
+
const { isMergeTrainEnabledForProject } = yield* Effect.promise(() => import("./merge-sync-Ca7F5JnQ.js"));
|
|
53284
|
+
setProjectMergeTrainSync(key, v);
|
|
53285
|
+
const updated = getProjectSync(key);
|
|
53286
|
+
return jsonResponse({
|
|
53287
|
+
value: v,
|
|
53288
|
+
effective: updated ? isMergeTrainEnabledForProject(updated) : false
|
|
53289
|
+
});
|
|
53290
|
+
})));
|
|
53291
|
+
const projectsMergeTrainRouteLayer = Layer.mergeAll(getProjectMergeTrainRoute, postProjectMergeTrainRoute);
|
|
53292
|
+
//#endregion
|
|
53293
|
+
//#region routes/merge-train.ts
|
|
53294
|
+
/**
|
|
53295
|
+
* PAN-1696 merge-train-routes: the aggregate `/api/merge-train/*` namespace.
|
|
53296
|
+
*
|
|
53297
|
+
* The merge-train (conflict-aware merge order + UAT batch trains) is a
|
|
53298
|
+
* per-project pipeline concern, but its only HTTP surface used to live under
|
|
53299
|
+
* `/api/flywheel/*` and answered for the Overdeck repo alone. These routes
|
|
53300
|
+
* answer for EVERY tracked project and require no active flywheel run: the
|
|
53301
|
+
* ready set comes from the review-status records via
|
|
53302
|
+
* `listEligibleCandidatesByProject`, not from a run's `activePipeline`.
|
|
53303
|
+
*
|
|
53304
|
+
* The legacy `/api/flywheel/*` merge-train routes stay in place until the
|
|
53305
|
+
* frontend migrates — removing them is the remove-legacy-routes item.
|
|
53306
|
+
*/
|
|
53307
|
+
init_projects();
|
|
53308
|
+
const readUnknownJsonBody$1 = Effect.gen(function* () {
|
|
53309
|
+
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53310
|
+
try {
|
|
53311
|
+
return {
|
|
53312
|
+
ok: true,
|
|
53313
|
+
body: text ? JSON.parse(text) : {}
|
|
53314
|
+
};
|
|
53315
|
+
} catch {
|
|
53316
|
+
return {
|
|
53317
|
+
ok: false,
|
|
53318
|
+
error: "Request body must be valid JSON"
|
|
53319
|
+
};
|
|
53320
|
+
}
|
|
53321
|
+
});
|
|
53322
|
+
/** A plain JSON object — not null, not an array, not a primitive. */
|
|
53323
|
+
function isJsonObject(value) {
|
|
53324
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
53325
|
+
}
|
|
53326
|
+
/**
|
|
53327
|
+
* A disabled project reports an empty queue rather than being omitted, so the
|
|
53328
|
+
* multi-project view can render it as an explicitly-off row instead of making
|
|
53329
|
+
* "off" and "no ready work" look identical.
|
|
53330
|
+
*/
|
|
53331
|
+
async function queueEntryForProject(key, config, enabled) {
|
|
53332
|
+
const base = {
|
|
53333
|
+
projectKey: key,
|
|
53334
|
+
projectName: config.name,
|
|
53335
|
+
enabled
|
|
53336
|
+
};
|
|
53337
|
+
if (!enabled) return {
|
|
53338
|
+
...base,
|
|
53339
|
+
queue: []
|
|
53340
|
+
};
|
|
53341
|
+
const projectPath = resolve(config.path);
|
|
53342
|
+
const candidates = listEligibleCandidatesByProject(projectPath);
|
|
53343
|
+
if (candidates.length === 0) return {
|
|
53344
|
+
...base,
|
|
53345
|
+
queue: []
|
|
53346
|
+
};
|
|
53347
|
+
const queue = await Effect.runPromise(computeMergeQueueFromCandidates(candidates, projectPath).pipe(Effect.provide(layer)));
|
|
53348
|
+
return {
|
|
53349
|
+
...base,
|
|
53350
|
+
queue
|
|
53351
|
+
};
|
|
53352
|
+
}
|
|
53353
|
+
/**
|
|
53354
|
+
* PAN-1696 AC1: one entry per tracked project, with that project's effective
|
|
53355
|
+
* flag and queue, with no flywheel run active. One project's git failure must
|
|
53356
|
+
* not blank the whole response, so a failed project reports an empty queue.
|
|
53357
|
+
*/
|
|
53358
|
+
async function getMergeTrainQueuesPayload() {
|
|
53359
|
+
const { isMergeTrainEnabledForProject } = await import("./merge-sync-Ca7F5JnQ.js");
|
|
53360
|
+
const projects = listProjectsSync();
|
|
53361
|
+
return (await Promise.allSettled(projects.map(({ key, config }) => queueEntryForProject(key, config, isMergeTrainEnabledForProject(config))))).flatMap((outcome, i) => {
|
|
53362
|
+
if (outcome.status === "fulfilled") return [outcome.value];
|
|
53363
|
+
const entry = projects[i];
|
|
53364
|
+
if (!entry) return [];
|
|
53365
|
+
const reason = outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason);
|
|
53366
|
+
console.warn(`[merge-train] queue for project ${entry.key} failed: ${reason}`);
|
|
53367
|
+
return [{
|
|
53368
|
+
projectKey: entry.key,
|
|
53369
|
+
projectName: entry.config.name,
|
|
53370
|
+
enabled: true,
|
|
53371
|
+
queue: []
|
|
53372
|
+
}];
|
|
53373
|
+
});
|
|
53374
|
+
}
|
|
53375
|
+
/** PAN-1696 AC2: per-project generation chains across every tracked project. */
|
|
53376
|
+
async function getMergeTrainGenerationsPayload() {
|
|
53377
|
+
const { isMergeTrainEnabledForProject } = await import("./merge-sync-Ca7F5JnQ.js");
|
|
53378
|
+
const { getUatGenerationsPayload } = await import("./uat-train-Cu-4nvbf.js");
|
|
53379
|
+
return (await Promise.allSettled(listProjectsSync().map(async ({ key, config }) => ({
|
|
53380
|
+
projectKey: key,
|
|
53381
|
+
projectName: config.name,
|
|
53382
|
+
enabled: isMergeTrainEnabledForProject(config),
|
|
53383
|
+
generations: await getUatGenerationsPayload(resolve(config.path))
|
|
53384
|
+
})))).flatMap((outcome) => outcome.status === "fulfilled" ? [outcome.value] : []);
|
|
53385
|
+
}
|
|
53386
|
+
async function defaultOrderedIssueIdsForProject(projectPath) {
|
|
53387
|
+
const candidates = listEligibleCandidatesByProject(projectPath);
|
|
53388
|
+
if (candidates.length === 0) return [];
|
|
53389
|
+
return (await Effect.runPromise(computeMergeQueueFromCandidates(candidates, projectPath).pipe(Effect.provide(layer)))).map((item) => item.issueId);
|
|
53390
|
+
}
|
|
53391
|
+
async function defaultMergeOne(issueId) {
|
|
53392
|
+
const { triggerMerge } = await import("./merge-ops-DdpTiEMt.js");
|
|
53393
|
+
const r = await triggerMerge(issueId);
|
|
53394
|
+
return r.success ? { ok: true } : {
|
|
53395
|
+
ok: false,
|
|
53396
|
+
reason: r.error ?? r.message ?? "merge failed"
|
|
53397
|
+
};
|
|
53398
|
+
}
|
|
53399
|
+
async function postMergeTrainMergeNextPayload(payload, deps = {}) {
|
|
53400
|
+
if (!isJsonObject(payload)) return {
|
|
53401
|
+
status: 400,
|
|
53402
|
+
body: { error: "body must be a JSON object: { n, project }" }
|
|
53403
|
+
};
|
|
53404
|
+
const body = payload;
|
|
53405
|
+
const n = typeof body.n === "number" && Number.isFinite(body.n) ? Math.floor(body.n) : 0;
|
|
53406
|
+
if (n <= 0) return {
|
|
53407
|
+
status: 400,
|
|
53408
|
+
body: { error: "n must be a positive integer" }
|
|
53409
|
+
};
|
|
53410
|
+
if (typeof body.project !== "string" || body.project.trim() === "") return {
|
|
53411
|
+
status: 400,
|
|
53412
|
+
body: { error: "project must be a non-empty string" }
|
|
53413
|
+
};
|
|
53414
|
+
const projectKey = body.project.trim();
|
|
53415
|
+
const config = getProjectSync(projectKey);
|
|
53416
|
+
if (!config) return {
|
|
53417
|
+
status: 404,
|
|
53418
|
+
body: { error: `Unknown project key: ${projectKey}` }
|
|
53419
|
+
};
|
|
53420
|
+
const { isMergeTrainEnabledForProject } = await import("./merge-sync-Ca7F5JnQ.js");
|
|
53421
|
+
if (!isMergeTrainEnabledForProject(config)) return {
|
|
53422
|
+
status: 409,
|
|
53423
|
+
body: { error: `merge-train is disabled for project ${projectKey}` }
|
|
53424
|
+
};
|
|
53425
|
+
const issueIds = (await (deps.getOrderedIssueIds ?? defaultOrderedIssueIdsForProject)(resolve(config.path))).slice(0, n);
|
|
53426
|
+
const { shipMergeBatch } = await import("./merge-batch-C5q1c1GX.js");
|
|
53427
|
+
return {
|
|
53428
|
+
status: 200,
|
|
53429
|
+
body: {
|
|
53430
|
+
projectKey,
|
|
53431
|
+
outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne })
|
|
53432
|
+
}
|
|
53433
|
+
};
|
|
53434
|
+
}
|
|
53435
|
+
/**
|
|
53436
|
+
* PAN-1696: forced reconcile. With `{ project }` it rebuilds that one project's
|
|
53437
|
+
* generation; with no body it reconciles every merge-train-enabled project.
|
|
53438
|
+
*/
|
|
53439
|
+
async function postMergeTrainAssemblePayload(payload) {
|
|
53440
|
+
if (!isJsonObject(payload)) return {
|
|
53441
|
+
status: 400,
|
|
53442
|
+
body: { error: "body must be a JSON object: {} for all projects, or { project }" }
|
|
53443
|
+
};
|
|
53444
|
+
if ("project" in payload) {
|
|
53445
|
+
const raw = payload["project"];
|
|
53446
|
+
if (typeof raw !== "string" || raw.trim() === "") return {
|
|
53447
|
+
status: 400,
|
|
53448
|
+
body: { error: "project must be a non-empty string; omit the field entirely to reconcile every project" }
|
|
53449
|
+
};
|
|
53450
|
+
const projectKey = raw.trim();
|
|
53451
|
+
const config = getProjectSync(projectKey);
|
|
53452
|
+
if (!config) return {
|
|
53453
|
+
status: 404,
|
|
53454
|
+
body: { error: `Unknown project key: ${projectKey}` }
|
|
53455
|
+
};
|
|
53456
|
+
const { runUatTrainReconcile } = await import("./uat-train-Cu-4nvbf.js");
|
|
53457
|
+
return {
|
|
53458
|
+
status: 200,
|
|
53459
|
+
body: { projects: [{
|
|
53460
|
+
projectKey,
|
|
53461
|
+
result: await runUatTrainReconcile({
|
|
53462
|
+
force: true,
|
|
53463
|
+
projectRoot: resolve(config.path)
|
|
53464
|
+
})
|
|
53465
|
+
}] }
|
|
53466
|
+
};
|
|
53467
|
+
}
|
|
53468
|
+
const { runUatTrainReconcileAllProjects } = await import("./uat-train-Cu-4nvbf.js");
|
|
53469
|
+
return {
|
|
53470
|
+
status: 200,
|
|
53471
|
+
body: { projects: await runUatTrainReconcileAllProjects({ force: true }) }
|
|
53472
|
+
};
|
|
53473
|
+
}
|
|
53474
|
+
/**
|
|
53475
|
+
* PAN-1737 generation names contain a slash (`uat/pan-otter-0610`); URL params
|
|
53476
|
+
* carry the name WITHOUT the `uat/` prefix and handlers reconstitute it. Same
|
|
53477
|
+
* reconstruction as the legacy flywheel routes so links stay interchangeable.
|
|
53478
|
+
*/
|
|
53479
|
+
function uatGenerationNameFromParam(param) {
|
|
53480
|
+
const decoded = decodeURIComponent(param);
|
|
53481
|
+
return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
|
|
53482
|
+
}
|
|
53483
|
+
const getMergeTrainQueuesRoute = HttpRouter.add("GET", "/api/merge-train/queues", httpHandler(Effect.gen(function* () {
|
|
53484
|
+
return jsonResponse(yield* Effect.promise(() => getMergeTrainQueuesPayload()));
|
|
53485
|
+
})));
|
|
53486
|
+
const getMergeTrainGenerationsRoute = HttpRouter.add("GET", "/api/merge-train/generations", httpHandler(Effect.gen(function* () {
|
|
53487
|
+
return jsonResponse(yield* Effect.promise(() => getMergeTrainGenerationsPayload()));
|
|
53488
|
+
})));
|
|
53489
|
+
const postMergeTrainGenerationStackRoute = HttpRouter.add("POST", "/api/merge-train/generations/:name/stack", httpHandler(Effect.gen(function* () {
|
|
53490
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53491
|
+
if (authError) return authError;
|
|
53492
|
+
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
53493
|
+
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-Cu-4nvbf.js"));
|
|
53494
|
+
const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
|
|
53495
|
+
if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
|
|
53496
|
+
return jsonResponse({
|
|
53497
|
+
frontendUrl: result.frontendUrl,
|
|
53498
|
+
evicted: result.evicted
|
|
53499
|
+
});
|
|
53500
|
+
})));
|
|
53501
|
+
const postMergeTrainGenerationPromoteRoute = HttpRouter.add("POST", "/api/merge-train/generations/:name/promote", httpHandler(Effect.gen(function* () {
|
|
53502
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53503
|
+
if (authError) return authError;
|
|
53504
|
+
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
53505
|
+
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-Cu-4nvbf.js"));
|
|
53506
|
+
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-JHsdU3pA.js"));
|
|
53507
|
+
const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
|
|
53508
|
+
if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
|
|
53509
|
+
return jsonResponse(result);
|
|
53510
|
+
})));
|
|
53511
|
+
const postMergeTrainAssembleRoute = HttpRouter.add("POST", "/api/merge-train/assemble", httpHandler(Effect.gen(function* () {
|
|
53512
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53513
|
+
if (authError) return authError;
|
|
53514
|
+
const parsed = yield* readUnknownJsonBody$1;
|
|
53515
|
+
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 400 });
|
|
53516
|
+
const result = yield* Effect.promise(() => postMergeTrainAssemblePayload(parsed.body));
|
|
53517
|
+
return jsonResponse(result.body, { status: result.status });
|
|
53518
|
+
})));
|
|
53519
|
+
const postMergeTrainMergeNextRoute = HttpRouter.add("POST", "/api/merge-train/merge-next", httpHandler(Effect.gen(function* () {
|
|
53520
|
+
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
53521
|
+
if (authError) return authError;
|
|
53522
|
+
const parsed = yield* readUnknownJsonBody$1;
|
|
53523
|
+
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 400 });
|
|
53524
|
+
const result = yield* Effect.promise(() => postMergeTrainMergeNextPayload(parsed.body));
|
|
53525
|
+
return jsonResponse(result.body, { status: result.status });
|
|
53526
|
+
})));
|
|
53527
|
+
const mergeTrainRouteLayer = Layer.mergeAll(getMergeTrainQueuesRoute, getMergeTrainGenerationsRoute, postMergeTrainGenerationStackRoute, postMergeTrainGenerationPromoteRoute, postMergeTrainAssembleRoute, postMergeTrainMergeNextRoute);
|
|
53528
|
+
//#endregion
|
|
52641
53529
|
//#region routes/context.ts
|
|
52642
53530
|
init_src();
|
|
52643
53531
|
init_layers();
|
|
@@ -53037,7 +53925,7 @@ function issueIdFromWorkspacePath(workspacePath) {
|
|
|
53037
53925
|
const match = /(?:^|[^a-z0-9])([a-z]+-\d+)(?:[^a-z0-9]|$)/i.exec(workspacePath);
|
|
53038
53926
|
return match ? match[1].toUpperCase() : null;
|
|
53039
53927
|
}
|
|
53040
|
-
function readJsonBody$
|
|
53928
|
+
function readJsonBody$7() {
|
|
53041
53929
|
return Effect.gen(function* () {
|
|
53042
53930
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53043
53931
|
return text ? JSON.parse(text) : {};
|
|
@@ -53051,7 +53939,7 @@ const getContextLayersRoute = HttpRouter.add("GET", "/api/context/layers", httpH
|
|
|
53051
53939
|
return jsonResponse(yield* Effect.promise(() => loadContextLayers(projects)));
|
|
53052
53940
|
})));
|
|
53053
53941
|
const postContextPreviewRoute = HttpRouter.add("POST", "/api/context/preview", httpHandler(Effect.gen(function* () {
|
|
53054
|
-
const body = yield* readJsonBody$
|
|
53942
|
+
const body = yield* readJsonBody$7();
|
|
53055
53943
|
const parsed = yield* Effect.try({
|
|
53056
53944
|
try: () => decodePreviewRequest(body),
|
|
53057
53945
|
catch: (error) => new Error(error instanceof Error ? error.message : String(error))
|
|
@@ -53060,7 +53948,7 @@ const postContextPreviewRoute = HttpRouter.add("POST", "/api/context/preview", h
|
|
|
53060
53948
|
return jsonResponse(yield* Effect.promise(() => previewContextLayers(projects, parsed)));
|
|
53061
53949
|
})));
|
|
53062
53950
|
const putContextLayerRoute = HttpRouter.add("PUT", "/api/context/layers", httpHandler(Effect.gen(function* () {
|
|
53063
|
-
const body = yield* readJsonBody$
|
|
53951
|
+
const body = yield* readJsonBody$7();
|
|
53064
53952
|
const parsed = yield* Effect.try({
|
|
53065
53953
|
try: () => decodeSaveRequest(body),
|
|
53066
53954
|
catch: (error) => new Error(error instanceof Error ? error.message : String(error))
|
|
@@ -53084,6 +53972,56 @@ const postContextSyncRoute = HttpRouter.add("POST", "/api/context/sync", httpHan
|
|
|
53084
53972
|
})));
|
|
53085
53973
|
const contextRouteLayer = Layer.mergeAll(getContextLayersRoute, postContextPreviewRoute, putContextLayerRoute, postContextSyncRoute);
|
|
53086
53974
|
//#endregion
|
|
53975
|
+
//#region routes/commands.ts
|
|
53976
|
+
init_src();
|
|
53977
|
+
const COMMANDS_API_HARNESSES = [
|
|
53978
|
+
"claude-code",
|
|
53979
|
+
"codex",
|
|
53980
|
+
"ohmypi",
|
|
53981
|
+
"acp"
|
|
53982
|
+
];
|
|
53983
|
+
const OVERDECK_COMMANDS = COMPOSER_COMMAND_MANIFEST.map((entry) => {
|
|
53984
|
+
const policy = resolvePolicy(entry.path);
|
|
53985
|
+
return {
|
|
53986
|
+
...entry,
|
|
53987
|
+
mode: policy.mode,
|
|
53988
|
+
safety: policy.safety
|
|
53989
|
+
};
|
|
53990
|
+
});
|
|
53991
|
+
const COMMAND_PAYLOADS = Object.fromEntries(COMMANDS_API_HARNESSES.map((harness) => [harness, {
|
|
53992
|
+
harness,
|
|
53993
|
+
overdeck: OVERDECK_COMMANDS,
|
|
53994
|
+
native: getHarnessBehavior(harness).nativeCommands ?? []
|
|
53995
|
+
}]));
|
|
53996
|
+
function getCommandsPayload(harness) {
|
|
53997
|
+
return COMMAND_PAYLOADS[harness];
|
|
53998
|
+
}
|
|
53999
|
+
function isCommandsApiHarness(value) {
|
|
54000
|
+
return COMMANDS_API_HARNESSES.includes(value);
|
|
54001
|
+
}
|
|
54002
|
+
function resolveCommandsRequest(harness) {
|
|
54003
|
+
const requestedHarness = harness ?? "claude-code";
|
|
54004
|
+
if (!isCommandsApiHarness(requestedHarness)) return {
|
|
54005
|
+
ok: false,
|
|
54006
|
+
error: `Unknown harness "${requestedHarness}". Expected one of: ${COMMANDS_API_HARNESSES.join(", ")}.`,
|
|
54007
|
+
accepted: COMMANDS_API_HARNESSES
|
|
54008
|
+
};
|
|
54009
|
+
return {
|
|
54010
|
+
ok: true,
|
|
54011
|
+
payload: getCommandsPayload(requestedHarness)
|
|
54012
|
+
};
|
|
54013
|
+
}
|
|
54014
|
+
const getCommandsRoute = HttpRouter.add("GET", "/api/commands", httpHandler(Effect.gen(function* () {
|
|
54015
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
54016
|
+
const result = resolveCommandsRequest(new URL(request.url, "http://localhost").searchParams.get("harness"));
|
|
54017
|
+
if (!result.ok) return jsonResponse({
|
|
54018
|
+
error: result.error,
|
|
54019
|
+
accepted: result.accepted
|
|
54020
|
+
}, { status: 400 });
|
|
54021
|
+
return jsonResponse(result.payload);
|
|
54022
|
+
})));
|
|
54023
|
+
const commandsRouteLayer = Layer.mergeAll(getCommandsRoute);
|
|
54024
|
+
//#endregion
|
|
53087
54025
|
//#region routes/admin.ts
|
|
53088
54026
|
init_tldr_daemon();
|
|
53089
54027
|
init_projects();
|
|
@@ -53193,7 +54131,7 @@ const adminRouteLayer = Layer.mergeAll(getAdminTldrRoute, postAdminBackfillTitle
|
|
|
53193
54131
|
* requiring a heavy `pan install` step before first use.
|
|
53194
54132
|
*/
|
|
53195
54133
|
init_platform();
|
|
53196
|
-
const execAsync$
|
|
54134
|
+
const execAsync$2 = promisify(exec);
|
|
53197
54135
|
const execFileAsync$2 = promisify(execFile);
|
|
53198
54136
|
const PREREQ_REGISTRY = {
|
|
53199
54137
|
addGitHubProject: ["gh"],
|
|
@@ -53252,7 +54190,7 @@ function getLinuxManualInstallHint(tool, packageManager) {
|
|
|
53252
54190
|
async function installLinuxPackage(tool) {
|
|
53253
54191
|
const packageManager = await detectLinuxPackageManager();
|
|
53254
54192
|
if (!packageManager) throw new Error(`No supported Linux package manager found. Install ${getLinuxManualInstallHint(tool, null)}`);
|
|
53255
|
-
await execAsync$
|
|
54193
|
+
await execAsync$2(getLinuxInstallCommand(tool, packageManager), { timeout: 12e4 });
|
|
53256
54194
|
}
|
|
53257
54195
|
async function isToolInstalled(tool) {
|
|
53258
54196
|
if (tool === "docker") return checkCommand("docker", ["info"]);
|
|
@@ -53295,7 +54233,7 @@ async function installTool(tool) {
|
|
|
53295
54233
|
}
|
|
53296
54234
|
}
|
|
53297
54235
|
async function installTmux() {
|
|
53298
|
-
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$
|
|
54236
|
+
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$2("brew install tmux", { timeout: 12e4 });
|
|
53299
54237
|
else await installLinuxPackage("tmux");
|
|
53300
54238
|
return {
|
|
53301
54239
|
tool: "tmux",
|
|
@@ -53309,14 +54247,14 @@ async function installTtyd() {
|
|
|
53309
54247
|
mkdirSync$1(binDir, { recursive: true });
|
|
53310
54248
|
const ttydPath = join(binDir, "ttyd");
|
|
53311
54249
|
if (plat === "darwin") try {
|
|
53312
|
-
await execAsync$
|
|
54250
|
+
await execAsync$2("brew install ttyd", { timeout: 12e4 });
|
|
53313
54251
|
return {
|
|
53314
54252
|
tool: "ttyd",
|
|
53315
54253
|
success: true,
|
|
53316
54254
|
message: "ttyd installed via Homebrew"
|
|
53317
54255
|
};
|
|
53318
54256
|
} catch {}
|
|
53319
|
-
await execAsync$
|
|
54257
|
+
await execAsync$2(`curl -sL "https://github.com/tsl0922/ttyd/releases/latest/download/ttyd.x86_64" -o "${ttydPath}" && chmod +x "${ttydPath}"`, { timeout: 6e4 });
|
|
53320
54258
|
return {
|
|
53321
54259
|
tool: "ttyd",
|
|
53322
54260
|
success: true,
|
|
@@ -53325,8 +54263,8 @@ async function installTtyd() {
|
|
|
53325
54263
|
}
|
|
53326
54264
|
async function installMkcert() {
|
|
53327
54265
|
if (await Effect.runPromise(detectPlatform()) === "darwin") {
|
|
53328
|
-
await execAsync$
|
|
53329
|
-
await execAsync$
|
|
54266
|
+
await execAsync$2("brew install mkcert", { timeout: 12e4 });
|
|
54267
|
+
await execAsync$2("mkcert -install", { timeout: 3e4 });
|
|
53330
54268
|
return {
|
|
53331
54269
|
tool: "mkcert",
|
|
53332
54270
|
success: true,
|
|
@@ -53336,8 +54274,8 @@ async function installMkcert() {
|
|
|
53336
54274
|
const binDir = join(homedir$1(), ".local", "bin");
|
|
53337
54275
|
mkdirSync$1(binDir, { recursive: true });
|
|
53338
54276
|
const mkcertPath = join(binDir, "mkcert");
|
|
53339
|
-
await execAsync$
|
|
53340
|
-
await execAsync$
|
|
54277
|
+
await execAsync$2(`curl -sL "https://github.com/FiloSottile/mkcert/releases/latest/download/mkcert-v1.4.4-linux-${process.arch === "x64" ? "amd64" : process.arch}" -o "${mkcertPath}" && chmod +x "${mkcertPath}"`, { timeout: 6e4 });
|
|
54278
|
+
await execAsync$2("mkcert -install", { timeout: 3e4 });
|
|
53341
54279
|
return {
|
|
53342
54280
|
tool: "mkcert",
|
|
53343
54281
|
success: true,
|
|
@@ -53345,7 +54283,7 @@ async function installMkcert() {
|
|
|
53345
54283
|
};
|
|
53346
54284
|
}
|
|
53347
54285
|
async function installJq() {
|
|
53348
|
-
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$
|
|
54286
|
+
if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$2("brew install jq", { timeout: 12e4 });
|
|
53349
54287
|
else await installLinuxPackage("jq");
|
|
53350
54288
|
return {
|
|
53351
54289
|
tool: "jq",
|
|
@@ -53360,7 +54298,7 @@ async function installOx() {
|
|
|
53360
54298
|
const binDir = join(homedir$1(), ".local", "bin");
|
|
53361
54299
|
const oxPath = join(binDir, "ox");
|
|
53362
54300
|
mkdirSync$1(binDir, { recursive: true });
|
|
53363
|
-
await execAsync$
|
|
54301
|
+
await execAsync$2(`curl -sL "https://github.com/eltmon/ox/releases/download/latest/ox-${platform}-${arch}" -o "${oxPath}" && chmod +x "${oxPath}"`, { timeout: 6e4 });
|
|
53364
54302
|
return {
|
|
53365
54303
|
tool: "ox",
|
|
53366
54304
|
success: true,
|
|
@@ -53377,7 +54315,7 @@ async function installOx() {
|
|
|
53377
54315
|
* GET /api/prereqs/:feature — check which tools are missing for a feature
|
|
53378
54316
|
* POST /api/prereqs/install — install a specific tool by name
|
|
53379
54317
|
*/
|
|
53380
|
-
const readJsonBody$
|
|
54318
|
+
const readJsonBody$6 = Effect.gen(function* () {
|
|
53381
54319
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53382
54320
|
try {
|
|
53383
54321
|
return text ? JSON.parse(text) : {};
|
|
@@ -53414,7 +54352,7 @@ const checkFeatureRoute = HttpRouter.add("GET", "/api/prereqs/:feature", httpHan
|
|
|
53414
54352
|
});
|
|
53415
54353
|
})));
|
|
53416
54354
|
const installToolRoute = HttpRouter.add("POST", "/api/prereqs/install", httpHandler(Effect.gen(function* () {
|
|
53417
|
-
const tool = (yield* readJsonBody$
|
|
54355
|
+
const tool = (yield* readJsonBody$6).tool;
|
|
53418
54356
|
if (!tool) return jsonResponse({ error: "Missing 'tool' in request body" }, { status: 400 });
|
|
53419
54357
|
if (!INSTALLABLE_TOOLS.some((t) => t === tool)) return jsonResponse({ error: `Tool '${tool}' is not auto-installable` }, { status: 400 });
|
|
53420
54358
|
const result = yield* Effect.promise(() => installTool(tool));
|
|
@@ -54075,7 +55013,7 @@ function getCheckpointWorker() {
|
|
|
54075
55013
|
return worker;
|
|
54076
55014
|
}
|
|
54077
55015
|
async function runInline(operation, payload) {
|
|
54078
|
-
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-
|
|
55016
|
+
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-DMTgXuLG.js");
|
|
54079
55017
|
switch (operation) {
|
|
54080
55018
|
case "claimTranscriptRange": return claimTranscriptRange(payload);
|
|
54081
55019
|
case "commitTranscriptRange": return commitTranscriptRange(payload);
|
|
@@ -55229,7 +56167,7 @@ function buildPendingTurn(input, fromOffset, toOffset, compressed) {
|
|
|
55229
56167
|
};
|
|
55230
56168
|
}
|
|
55231
56169
|
async function emitMemoryObservationCreated(observation, timestamp) {
|
|
55232
|
-
const { initEventStore } = await import("./event-store-
|
|
56170
|
+
const { initEventStore } = await import("./event-store-ELqkVOn0.js");
|
|
55233
56171
|
await (await initEventStore()).appendAsync({
|
|
55234
56172
|
type: "memory.observation_created",
|
|
55235
56173
|
timestamp,
|
|
@@ -56360,7 +57298,16 @@ async function handleMemorySessionStartBody(body, options = {}) {
|
|
|
56360
57298
|
statusCode: 422,
|
|
56361
57299
|
error: "memory identity could not be resolved"
|
|
56362
57300
|
};
|
|
56363
|
-
|
|
57301
|
+
let fileStat;
|
|
57302
|
+
try {
|
|
57303
|
+
fileStat = await (options.statTranscript ?? getTranscriptStat$1)(trustedTranscriptPath);
|
|
57304
|
+
} catch (error) {
|
|
57305
|
+
if (error.code === "ENOENT") return {
|
|
57306
|
+
status: "transcript-missing",
|
|
57307
|
+
sessionId
|
|
57308
|
+
};
|
|
57309
|
+
throw error;
|
|
57310
|
+
}
|
|
56364
57311
|
(options.registerTranscript ?? registerTranscriptForPolling)({
|
|
56365
57312
|
agentId: stringField(body.agentId) ?? stringField(body.agent_id) ?? identity.runId,
|
|
56366
57313
|
sessionId,
|
|
@@ -56491,7 +57438,7 @@ const postMemorySessionStartRoute = HttpRouter.add("POST", "/api/memory/session/
|
|
|
56491
57438
|
}
|
|
56492
57439
|
const readModel = yield* ReadModelService;
|
|
56493
57440
|
const result = yield* Effect.promise(() => handleMemorySessionStartBody(body, { resolveAgentIdBySessionId: async (sessionId) => Effect.runPromise(readModel.getAgentIdBySessionId(sessionId)) }));
|
|
56494
|
-
if (result.status === "subagent" || result.status === "disabled") return HttpServerResponse.text("", { status: 204 });
|
|
57441
|
+
if (result.status === "subagent" || result.status === "disabled" || result.status === "transcript-missing") return HttpServerResponse.text("", { status: 204 });
|
|
56495
57442
|
if (result.status === "error") return jsonResponse({
|
|
56496
57443
|
ok: false,
|
|
56497
57444
|
error: result.error
|
|
@@ -56895,6 +57842,93 @@ const postTestCheckpointRoute = HttpRouter.add("POST", "/api/agents/:agentId/dif
|
|
|
56895
57842
|
}));
|
|
56896
57843
|
const diffsRouteLayer = Layer.mergeAll(getDiffsRoute, getTurnDiffRoute, getFullDiffRoute, getVsMainDiffRoute, postTestCheckpointRoute);
|
|
56897
57844
|
//#endregion
|
|
57845
|
+
//#region routes/linear-mcp-auth.ts
|
|
57846
|
+
init_issue_service_singleton();
|
|
57847
|
+
const LINEAR_MCP_AUTH_CALLBACK_COPY_PREFIX = "The operator completed the Linear OAuth authorization in their browser. Finish the flow now: call mcp__linear__complete_authentication with callback_url set to exactly this URL:";
|
|
57848
|
+
const readJsonBody$5 = Effect.gen(function* () {
|
|
57849
|
+
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
57850
|
+
return text ? JSON.parse(text) : {};
|
|
57851
|
+
});
|
|
57852
|
+
function rejectInvalidOrigin(request) {
|
|
57853
|
+
const originCheck = validateOrigin$1(request);
|
|
57854
|
+
if (!originCheck.ok) return jsonResponse({ error: originCheck.error }, { status: 403 });
|
|
57855
|
+
return null;
|
|
57856
|
+
}
|
|
57857
|
+
function isValidLinearMcpCallbackUrl(value) {
|
|
57858
|
+
try {
|
|
57859
|
+
const url = new URL(value);
|
|
57860
|
+
const localHost = url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
|
57861
|
+
return url.protocol === "http:" && localHost && !!url.searchParams.get("code") && !!url.searchParams.get("state");
|
|
57862
|
+
} catch {
|
|
57863
|
+
return false;
|
|
57864
|
+
}
|
|
57865
|
+
}
|
|
57866
|
+
function callbackCopy(callbackUrl) {
|
|
57867
|
+
return `${LINEAR_MCP_AUTH_CALLBACK_COPY_PREFIX} ${callbackUrl} — then re-check Linear access and resume your canonical task.`;
|
|
57868
|
+
}
|
|
57869
|
+
/**
|
|
57870
|
+
* Attach each blocked agent's canonical tracker URL (Linear web URL, GitHub
|
|
57871
|
+
* html_url) from the issues read door so the banner can link every blocked
|
|
57872
|
+
* agent's issue — including Linear-tracked ones the frontend cannot derive a
|
|
57873
|
+
* URL for. Best-effort: an unresolvable issue falls back to null and the
|
|
57874
|
+
* banner renders its own fallback.
|
|
57875
|
+
*/
|
|
57876
|
+
function withIssueUrls(intervention) {
|
|
57877
|
+
let urlByIdentifier;
|
|
57878
|
+
try {
|
|
57879
|
+
urlByIdentifier = /* @__PURE__ */ new Map();
|
|
57880
|
+
const issues = getSharedIssueService().getIssues({ includeCompleted: true });
|
|
57881
|
+
for (const issue of issues) if (typeof issue.identifier === "string" && typeof issue.url === "string" && issue.url !== "") urlByIdentifier.set(issue.identifier.toLowerCase(), issue.url);
|
|
57882
|
+
} catch {
|
|
57883
|
+
return intervention;
|
|
57884
|
+
}
|
|
57885
|
+
return {
|
|
57886
|
+
...intervention,
|
|
57887
|
+
blockedAgents: intervention.blockedAgents.map((agent) => ({
|
|
57888
|
+
...agent,
|
|
57889
|
+
issueUrl: agent.issueId ? urlByIdentifier.get(agent.issueId.toLowerCase()) ?? null : null
|
|
57890
|
+
}))
|
|
57891
|
+
};
|
|
57892
|
+
}
|
|
57893
|
+
const getLinearMcpAuthRoute = HttpRouter.add("GET", "/api/linear-mcp-auth", httpHandler(Effect.gen(function* () {
|
|
57894
|
+
return jsonResponse(withIssueUrls(yield* Effect.promise(() => resolveLinearMcpAuthIntervention())));
|
|
57895
|
+
})));
|
|
57896
|
+
const postLinearMcpAuthCallbackRoute = HttpRouter.add("POST", "/api/linear-mcp-auth/callback", httpHandler(Effect.gen(function* () {
|
|
57897
|
+
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
57898
|
+
if (originError) return originError;
|
|
57899
|
+
const body = yield* readJsonBody$5;
|
|
57900
|
+
const callbackUrl = typeof body["callbackUrl"] === "string" ? body["callbackUrl"] : "";
|
|
57901
|
+
if (!isValidLinearMcpCallbackUrl(callbackUrl)) return jsonResponse({
|
|
57902
|
+
success: false,
|
|
57903
|
+
error: "callbackUrl must be a localhost OAuth callback URL with code and state parameters"
|
|
57904
|
+
}, { status: 400 });
|
|
57905
|
+
const intervention = yield* Effect.promise(() => resolveLinearMcpAuthIntervention());
|
|
57906
|
+
if (intervention.authUrlAgentId === null) return jsonResponse({
|
|
57907
|
+
success: false,
|
|
57908
|
+
error: "No blocked agent owns the active Linear authorization URL"
|
|
57909
|
+
}, { status: 409 });
|
|
57910
|
+
yield* Effect.promise(() => messageAgent(intervention.authUrlAgentId, callbackCopy(callbackUrl), "linear-mcp-auth-callback"));
|
|
57911
|
+
yield* Effect.promise(() => appendLinearMcpAuthCallbackRelayedEvent({
|
|
57912
|
+
agentId: intervention.authUrlAgentId,
|
|
57913
|
+
issueId: intervention.blockedAgents.find((agent) => agent.agentId === intervention.authUrlAgentId)?.issueId ?? null
|
|
57914
|
+
}));
|
|
57915
|
+
return jsonResponse({
|
|
57916
|
+
success: true,
|
|
57917
|
+
relayedTo: intervention.authUrlAgentId
|
|
57918
|
+
});
|
|
57919
|
+
})));
|
|
57920
|
+
const postLinearMcpAuthCompleteRoute = HttpRouter.add("POST", "/api/linear-mcp-auth/complete", httpHandler(Effect.gen(function* () {
|
|
57921
|
+
const originError = rejectInvalidOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
57922
|
+
if (originError) return originError;
|
|
57923
|
+
yield* Effect.promise(() => appendLinearMcpAuthHealthyEvent({
|
|
57924
|
+
agentId: "operator",
|
|
57925
|
+
issueId: null,
|
|
57926
|
+
source: "operator"
|
|
57927
|
+
}));
|
|
57928
|
+
return jsonResponse({ success: true });
|
|
57929
|
+
})));
|
|
57930
|
+
const linearMcpAuthRouteLayer = Layer.mergeAll(getLinearMcpAuthRoute, postLinearMcpAuthCallbackRoute, postLinearMcpAuthCompleteRoute);
|
|
57931
|
+
//#endregion
|
|
56898
57932
|
//#region routes/terminals.ts
|
|
56899
57933
|
/**
|
|
56900
57934
|
* Terminal routes (PAN-1545 / PAN-1561) — ad-hoc tmux sessions for the
|
|
@@ -57644,6 +58678,287 @@ const getSubstrateBugWeightsRoute = HttpRouter.add("GET", "/api/flywheel/substra
|
|
|
57644
58678
|
})));
|
|
57645
58679
|
})));
|
|
57646
58680
|
//#endregion
|
|
58681
|
+
//#region services/flywheel-actions.ts
|
|
58682
|
+
init_config_yaml();
|
|
58683
|
+
init_harness_resolve();
|
|
58684
|
+
init_control_settings();
|
|
58685
|
+
init_tmux();
|
|
58686
|
+
const DEFAULT_BRIEF_PATH$1 = "docs/flywheel-brief.md";
|
|
58687
|
+
const execAsync$1 = promisify(exec);
|
|
58688
|
+
function mb(bytes) {
|
|
58689
|
+
return Math.round(bytes / 1024 / 1024);
|
|
58690
|
+
}
|
|
58691
|
+
function isInsideRoot$1(projectRoot, candidate) {
|
|
58692
|
+
const relativePath = relative(projectRoot, candidate);
|
|
58693
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
58694
|
+
}
|
|
58695
|
+
function resolveFlywheelStartBriefPath(cwd, requestedPath) {
|
|
58696
|
+
const rawPath = requestedPath?.trim() || DEFAULT_BRIEF_PATH$1;
|
|
58697
|
+
if (rawPath.includes("\0")) throw new Error("Brief path is invalid");
|
|
58698
|
+
const root = resolve(cwd);
|
|
58699
|
+
const absolutePath = isAbsolute(rawPath) ? resolve(rawPath) : resolve(root, rawPath);
|
|
58700
|
+
if (!isInsideRoot$1(root, absolutePath)) throw new Error("Brief path must stay inside the project root");
|
|
58701
|
+
const normalizedRoot = root.endsWith(sep) ? root : `${root}${sep}`;
|
|
58702
|
+
const displayPath = absolutePath === root ? "." : relative(root, absolutePath);
|
|
58703
|
+
return {
|
|
58704
|
+
absolutePath,
|
|
58705
|
+
displayPath: absolutePath.startsWith(normalizedRoot) ? displayPath : absolutePath
|
|
58706
|
+
};
|
|
58707
|
+
}
|
|
58708
|
+
async function assertExistingPathInsideRoot$1(projectRoot, candidate) {
|
|
58709
|
+
const [realRoot, realCandidate] = await Promise.all([realpath(projectRoot), realpath(candidate)]);
|
|
58710
|
+
if (!isInsideRoot$1(realRoot, realCandidate)) throw new Error("Brief path must stay inside the project root");
|
|
58711
|
+
}
|
|
58712
|
+
async function requireFlywheelBrief(cwd, requestedPath) {
|
|
58713
|
+
const resolved = resolveFlywheelStartBriefPath(cwd, requestedPath);
|
|
58714
|
+
try {
|
|
58715
|
+
await assertExistingPathInsideRoot$1(cwd, resolved.absolutePath);
|
|
58716
|
+
await readFile(resolved.absolutePath, "utf8");
|
|
58717
|
+
return resolved;
|
|
58718
|
+
} catch (error) {
|
|
58719
|
+
if ((typeof error === "object" && error !== null && "code" in error ? error.code : void 0) === "ENOENT") throw new Error(`Flywheel brief not found: ${resolved.displayPath}`);
|
|
58720
|
+
throw error;
|
|
58721
|
+
}
|
|
58722
|
+
}
|
|
58723
|
+
async function dashboardSetting(key) {
|
|
58724
|
+
return runDashboardDbJob("getSetting", key);
|
|
58725
|
+
}
|
|
58726
|
+
async function setDashboardSetting(key, value) {
|
|
58727
|
+
await runDashboardDbJob("setSetting", {
|
|
58728
|
+
key,
|
|
58729
|
+
value
|
|
58730
|
+
});
|
|
58731
|
+
}
|
|
58732
|
+
async function getActiveRunId() {
|
|
58733
|
+
const value = await dashboardSetting(FLYWHEEL_ACTIVE_RUN_ID_KEY);
|
|
58734
|
+
return value && value.trim() ? value : null;
|
|
58735
|
+
}
|
|
58736
|
+
async function setActiveRunId(runId) {
|
|
58737
|
+
await setDashboardSetting(FLYWHEEL_ACTIVE_RUN_ID_KEY, runId ?? "");
|
|
58738
|
+
}
|
|
58739
|
+
async function isPaused() {
|
|
58740
|
+
return await dashboardSetting(FLYWHEEL_GLOBAL_PAUSE_KEY) === "true";
|
|
58741
|
+
}
|
|
58742
|
+
async function setPaused(paused) {
|
|
58743
|
+
await setDashboardSetting(FLYWHEEL_GLOBAL_PAUSE_KEY, paused ? "true" : "false");
|
|
58744
|
+
}
|
|
58745
|
+
async function readGateSnapshot() {
|
|
58746
|
+
const [paused, activeRunId] = await Promise.all([isPaused(), getActiveRunId()]);
|
|
58747
|
+
return {
|
|
58748
|
+
paused,
|
|
58749
|
+
activeRunId
|
|
58750
|
+
};
|
|
58751
|
+
}
|
|
58752
|
+
async function resolveFlywheelRoleConfig() {
|
|
58753
|
+
const { config } = await Effect.runPromise(loadConfigNoMigration());
|
|
58754
|
+
const flywheel = config.roles?.flywheel;
|
|
58755
|
+
const model = resolveModel("flywheel", void 0, config);
|
|
58756
|
+
return {
|
|
58757
|
+
harness: await resolveHarness({ model }),
|
|
58758
|
+
model,
|
|
58759
|
+
effort: flywheel?.effort ?? "high",
|
|
58760
|
+
minAgents: flywheel?.minAgents ?? 20,
|
|
58761
|
+
maxAgents: flywheel?.maxAgents ?? 30,
|
|
58762
|
+
scope: flywheel?.scope ?? "pan-only"
|
|
58763
|
+
};
|
|
58764
|
+
}
|
|
58765
|
+
async function gitOutput(command, cwd) {
|
|
58766
|
+
const { stdout } = await execAsync$1(command, {
|
|
58767
|
+
cwd,
|
|
58768
|
+
encoding: "utf8"
|
|
58769
|
+
});
|
|
58770
|
+
return stdout.trim();
|
|
58771
|
+
}
|
|
58772
|
+
async function createInitialFlywheelStatus(runId, startedAt, cwd, agentModel, agentHarness, roleConfig) {
|
|
58773
|
+
const ramTotalMb = mb(totalmem$1());
|
|
58774
|
+
return {
|
|
58775
|
+
runId,
|
|
58776
|
+
startedAt,
|
|
58777
|
+
elapsedMs: 0,
|
|
58778
|
+
orchestrator: {
|
|
58779
|
+
harness: agentHarness ?? roleConfig.harness,
|
|
58780
|
+
model: agentModel ?? roleConfig.model,
|
|
58781
|
+
effort: roleConfig.effort,
|
|
58782
|
+
ctxPercent: 0
|
|
58783
|
+
},
|
|
58784
|
+
headline: {
|
|
58785
|
+
bugsFixed: 0,
|
|
58786
|
+
swarmItemsMerged: 0,
|
|
58787
|
+
swarmItemsTotal: 0,
|
|
58788
|
+
prsMerged: 0,
|
|
58789
|
+
awaitingUat: 0
|
|
58790
|
+
},
|
|
58791
|
+
scope: roleConfig.scope,
|
|
58792
|
+
activePipeline: [],
|
|
58793
|
+
substrateBugs: [],
|
|
58794
|
+
agents: [{
|
|
58795
|
+
id: FLYWHEEL_ORCHESTRATOR_AGENT_ID,
|
|
58796
|
+
label: "flywheel-orchestrator",
|
|
58797
|
+
status: "running",
|
|
58798
|
+
role: "flywheel",
|
|
58799
|
+
model: agentModel
|
|
58800
|
+
}],
|
|
58801
|
+
parked: [],
|
|
58802
|
+
suggestions: [],
|
|
58803
|
+
system: {
|
|
58804
|
+
mainHead: await gitOutput("git rev-parse --short HEAD", cwd).catch(() => "unknown"),
|
|
58805
|
+
ramUsedMb: Math.max(0, ramTotalMb - mb(freemem$1())),
|
|
58806
|
+
ramTotalMb,
|
|
58807
|
+
swapUsedMb: 0,
|
|
58808
|
+
swapTotalMb: 0,
|
|
58809
|
+
agentsActive: 1,
|
|
58810
|
+
agentsCap: roleConfig.maxAgents
|
|
58811
|
+
},
|
|
58812
|
+
openQuestions: [],
|
|
58813
|
+
ticks: 0,
|
|
58814
|
+
lastTickAt: startedAt
|
|
58815
|
+
};
|
|
58816
|
+
}
|
|
58817
|
+
async function startFlywheelRunForDashboard(options = {}) {
|
|
58818
|
+
const cwd = options.cwd ?? process.cwd();
|
|
58819
|
+
if (isFlywheelDevcontainerRuntime()) throw new Error("Refusing to spawn flywheel-orchestrator inside a workspace devcontainer");
|
|
58820
|
+
const activeRunId = await resolveLiveFlywheelRunId();
|
|
58821
|
+
if (activeRunId) if (!await Effect.runPromise(sessionExists("flywheel-orchestrator")) || await Effect.runPromise(isPaneDead("flywheel-orchestrator"))) {
|
|
58822
|
+
console.log(`[flywheel] ${activeRunId} gate stuck — orchestrator pane is dead; auto-aborting`);
|
|
58823
|
+
await Effect.runPromise(killSession(FLYWHEEL_ORCHESTRATOR_AGENT_ID)).catch(() => {});
|
|
58824
|
+
await abortFlywheelRun(activeRunId);
|
|
58825
|
+
} else throw new Error(`Flywheel run ${activeRunId} is already active; pause, resume, or report it before starting another run`);
|
|
58826
|
+
const brief = await requireFlywheelBrief(cwd, options.brief ?? DEFAULT_BRIEF_PATH$1);
|
|
58827
|
+
const runId = await nextFlywheelRunId();
|
|
58828
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
58829
|
+
const roleConfig = await resolveFlywheelRoleConfig();
|
|
58830
|
+
await writeFlywheelLaunchMetadata({
|
|
58831
|
+
version: 1,
|
|
58832
|
+
runId,
|
|
58833
|
+
workspace: cwd,
|
|
58834
|
+
briefPath: brief.absolutePath,
|
|
58835
|
+
briefDisplayPath: brief.displayPath,
|
|
58836
|
+
scope: roleConfig.scope
|
|
58837
|
+
});
|
|
58838
|
+
const agent = await spawnFlywheelAgent(runId, {
|
|
58839
|
+
briefPath: brief.absolutePath,
|
|
58840
|
+
workspace: cwd,
|
|
58841
|
+
model: roleConfig.model,
|
|
58842
|
+
harness: roleConfig.harness,
|
|
58843
|
+
effort: roleConfig.effort,
|
|
58844
|
+
minAgents: roleConfig.minAgents,
|
|
58845
|
+
maxAgents: roleConfig.maxAgents,
|
|
58846
|
+
scope: roleConfig.scope
|
|
58847
|
+
});
|
|
58848
|
+
await setActiveRunId(runId);
|
|
58849
|
+
await setPaused(false);
|
|
58850
|
+
await writeLatestFlywheelStatus(await createInitialFlywheelStatus(runId, startedAt, cwd, agent.model, agent.harness, roleConfig));
|
|
58851
|
+
return {
|
|
58852
|
+
runId,
|
|
58853
|
+
briefDisplayPath: resolveFlywheelStartBriefPath(cwd, options.brief ?? DEFAULT_BRIEF_PATH$1).displayPath,
|
|
58854
|
+
agentModel: agent.model
|
|
58855
|
+
};
|
|
58856
|
+
}
|
|
58857
|
+
async function pauseFlywheelRunForDashboard() {
|
|
58858
|
+
const before = await readGateSnapshot();
|
|
58859
|
+
if (before.paused) return {
|
|
58860
|
+
before,
|
|
58861
|
+
after: before,
|
|
58862
|
+
changed: false
|
|
58863
|
+
};
|
|
58864
|
+
if (before.activeRunId) try {
|
|
58865
|
+
const { readFile } = await import("node:fs/promises");
|
|
58866
|
+
const { join } = await import("node:path");
|
|
58867
|
+
const { getAgentDir } = await import("./agents-BKKkxKgK.js");
|
|
58868
|
+
const sessionId = (await readFile(join(getAgentDir(FLYWHEEL_ORCHESTRATOR_AGENT_ID), "session.id"), "utf-8")).trim();
|
|
58869
|
+
if (sessionId) await saveResumeSessionId(before.activeRunId, sessionId);
|
|
58870
|
+
} catch {}
|
|
58871
|
+
await setPaused(true);
|
|
58872
|
+
await import("./agents-BKKkxKgK.js").then(({ stopAgent }) => Effect.runPromise(stopAgent(FLYWHEEL_ORCHESTRATOR_AGENT_ID)));
|
|
58873
|
+
return {
|
|
58874
|
+
before,
|
|
58875
|
+
after: await readGateSnapshot(),
|
|
58876
|
+
changed: true
|
|
58877
|
+
};
|
|
58878
|
+
}
|
|
58879
|
+
async function abortFlywheelRunForDashboard() {
|
|
58880
|
+
const candidate = await getActiveRunId();
|
|
58881
|
+
if (!candidate) return { aborted: await resolveLiveFlywheelRunId() ?? null };
|
|
58882
|
+
const { stopAgent } = await import("./agents-BKKkxKgK.js");
|
|
58883
|
+
await Effect.runPromise(stopAgent(FLYWHEEL_ORCHESTRATOR_AGENT_ID));
|
|
58884
|
+
await abortFlywheelRun(candidate);
|
|
58885
|
+
return { aborted: candidate };
|
|
58886
|
+
}
|
|
58887
|
+
async function resumeFlywheelRunForDashboard() {
|
|
58888
|
+
const before = await readGateSnapshot();
|
|
58889
|
+
if (!before.paused && await Effect.runPromise(sessionExists("flywheel-orchestrator"))) return {
|
|
58890
|
+
before,
|
|
58891
|
+
after: before,
|
|
58892
|
+
changed: false
|
|
58893
|
+
};
|
|
58894
|
+
if (!before.activeRunId) throw new Error("No active flywheel run to resume");
|
|
58895
|
+
const launch = await readFlywheelLaunchMetadata(before.activeRunId);
|
|
58896
|
+
if (!launch) throw new Error(`Flywheel run ${before.activeRunId} is missing launch metadata; cannot resume safely`);
|
|
58897
|
+
const brief = await requireFlywheelBrief(launch.workspace, launch.briefPath);
|
|
58898
|
+
const roleConfig = await resolveFlywheelRoleConfig();
|
|
58899
|
+
if (launch.scope !== roleConfig.scope) await writeFlywheelLaunchMetadata({
|
|
58900
|
+
...launch,
|
|
58901
|
+
version: 1,
|
|
58902
|
+
scope: roleConfig.scope
|
|
58903
|
+
});
|
|
58904
|
+
const resumeSessionId = await loadResumeSessionId(before.activeRunId) ?? void 0;
|
|
58905
|
+
await spawnFlywheelAgent(before.activeRunId, {
|
|
58906
|
+
workspace: launch.workspace,
|
|
58907
|
+
briefPath: brief.absolutePath,
|
|
58908
|
+
model: roleConfig.model,
|
|
58909
|
+
harness: roleConfig.harness,
|
|
58910
|
+
effort: roleConfig.effort,
|
|
58911
|
+
minAgents: roleConfig.minAgents,
|
|
58912
|
+
maxAgents: roleConfig.maxAgents,
|
|
58913
|
+
scope: roleConfig.scope,
|
|
58914
|
+
resumeSessionId
|
|
58915
|
+
});
|
|
58916
|
+
await setPaused(false);
|
|
58917
|
+
return {
|
|
58918
|
+
before,
|
|
58919
|
+
after: await readGateSnapshot(),
|
|
58920
|
+
changed: true
|
|
58921
|
+
};
|
|
58922
|
+
}
|
|
58923
|
+
function getPlatformOpenCommand() {
|
|
58924
|
+
switch (process.platform) {
|
|
58925
|
+
case "linux": return "xdg-open";
|
|
58926
|
+
case "darwin": return "open";
|
|
58927
|
+
case "win32": return "explorer";
|
|
58928
|
+
default: throw new Error(`Opening files is not supported on ${process.platform}`);
|
|
58929
|
+
}
|
|
58930
|
+
}
|
|
58931
|
+
function openPathDetached(path) {
|
|
58932
|
+
spawn(getPlatformOpenCommand(), [path], {
|
|
58933
|
+
detached: true,
|
|
58934
|
+
stdio: "ignore"
|
|
58935
|
+
}).unref();
|
|
58936
|
+
}
|
|
58937
|
+
async function resolveReportOpenRunId(runId) {
|
|
58938
|
+
if (runId) return runId;
|
|
58939
|
+
const runs = await listFlywheelRuns();
|
|
58940
|
+
const run = runs.find((candidate) => candidate.status === "complete") ?? runs[0];
|
|
58941
|
+
if (!run) throw new Error("no flywheel run report to open");
|
|
58942
|
+
return run.id;
|
|
58943
|
+
}
|
|
58944
|
+
async function openFlywheelRunReportForDashboard(options = {}) {
|
|
58945
|
+
const runId = await resolveReportOpenRunId(options.runId);
|
|
58946
|
+
const detail = await getFlywheelRunDetail(runId);
|
|
58947
|
+
if (!detail) throw new Error(`Flywheel run not found: ${runId}`);
|
|
58948
|
+
if (!detail.paths.report) throw new Error(`No report exists for ${runId}`);
|
|
58949
|
+
await (options.opener ?? openPathDetached)(detail.paths.report);
|
|
58950
|
+
return {
|
|
58951
|
+
runId,
|
|
58952
|
+
path: detail.paths.report
|
|
58953
|
+
};
|
|
58954
|
+
}
|
|
58955
|
+
async function readCurrentFlywheelStatusForDashboard() {
|
|
58956
|
+
const activeRunId = await resolveLiveFlywheelRunId();
|
|
58957
|
+
if (!activeRunId) return null;
|
|
58958
|
+
const activeRun = await getFlywheelRunDetail(activeRunId);
|
|
58959
|
+
return activeRun?.status === "running" ? activeRun.latest : null;
|
|
58960
|
+
}
|
|
58961
|
+
//#endregion
|
|
57647
58962
|
//#region services/flywheel-state.ts
|
|
57648
58963
|
const FLYWHEEL_STATE_RELATIVE_PATH = "docs/FLYWHEEL-STATE.md";
|
|
57649
58964
|
function resolveStatePath(projectRoot) {
|
|
@@ -57679,6 +58994,7 @@ async function readFlywheelState(options = {}) {
|
|
|
57679
58994
|
const AUTO_MERGE_COOLDOWN_MS = 3e5;
|
|
57680
58995
|
//#endregion
|
|
57681
58996
|
//#region ../../lib/cloister/auto-merge-eligibility.ts
|
|
58997
|
+
init_forge();
|
|
57682
58998
|
init_review_status();
|
|
57683
58999
|
init_tracker_utils();
|
|
57684
59000
|
const execFileAsync$1 = promisify(execFile);
|
|
@@ -57938,6 +59254,7 @@ init_src();
|
|
|
57938
59254
|
init_activity_logger();
|
|
57939
59255
|
init_tmux();
|
|
57940
59256
|
init_control_settings();
|
|
59257
|
+
init_forge();
|
|
57941
59258
|
init_review_status();
|
|
57942
59259
|
init_projects();
|
|
57943
59260
|
const DEFAULT_BRIEF_PATH = "docs/flywheel-brief.md";
|
|
@@ -58242,7 +59559,7 @@ async function getFlywheelConversationPayload() {
|
|
|
58242
59559
|
};
|
|
58243
59560
|
}
|
|
58244
59561
|
async function postFlywheelReportPayload() {
|
|
58245
|
-
const { flywheelReportCommand } = await import("./flywheel-
|
|
59562
|
+
const { flywheelReportCommand } = await import("./flywheel-CLVB55Be.js");
|
|
58246
59563
|
await flywheelReportCommand({ cwd: process.cwd() });
|
|
58247
59564
|
return {
|
|
58248
59565
|
status: 200,
|
|
@@ -58397,39 +59714,6 @@ const getAutoMergeProblemsRoute = HttpRouter.add("GET", "/api/flywheel/auto-merg
|
|
|
58397
59714
|
const getMergeBlockersRoute = HttpRouter.add("GET", "/api/flywheel/merge-blockers", httpHandler(Effect.gen(function* () {
|
|
58398
59715
|
return jsonResponse(getMergeBlockersPayload());
|
|
58399
59716
|
})));
|
|
58400
|
-
async function defaultGetOrderedIssueIds() {
|
|
58401
|
-
const status = await readCurrentFlywheelStatusForDashboard();
|
|
58402
|
-
if (!status) return [];
|
|
58403
|
-
const { computeMergeQueue } = await import("./flywheel-merge-order-UUcsCDb6.js");
|
|
58404
|
-
return (await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd()).pipe(Effect.provide(layer)))).map((i) => i.issueId);
|
|
58405
|
-
}
|
|
58406
|
-
async function defaultMergeOne(issueId) {
|
|
58407
|
-
const { triggerMerge } = await import("./merge-ops-CR44oU9-.js");
|
|
58408
|
-
const r = await triggerMerge(issueId);
|
|
58409
|
-
return r.success ? { ok: true } : {
|
|
58410
|
-
ok: false,
|
|
58411
|
-
reason: r.error ?? r.message ?? "merge failed"
|
|
58412
|
-
};
|
|
58413
|
-
}
|
|
58414
|
-
/**
|
|
58415
|
-
* PAN-1691 "merge next N" / "ship the UAT candidate": merge the first N issues
|
|
58416
|
-
* of the conflict-aware merge order, one at a time, stopping at the first
|
|
58417
|
-
* failure (the rest would need re-rebasing). Pure-ish + DI for testing.
|
|
58418
|
-
*/
|
|
58419
|
-
async function postFlywheelMergeNextPayload(payload, deps = {}) {
|
|
58420
|
-
const body = payload ?? {};
|
|
58421
|
-
const n = typeof body.n === "number" && Number.isFinite(body.n) ? Math.floor(body.n) : 0;
|
|
58422
|
-
if (n <= 0) return {
|
|
58423
|
-
status: 400,
|
|
58424
|
-
body: { error: "n must be a positive integer" }
|
|
58425
|
-
};
|
|
58426
|
-
const issueIds = (await (deps.getOrderedIssueIds ?? defaultGetOrderedIssueIds)()).slice(0, n);
|
|
58427
|
-
const { shipMergeBatch } = await import("./merge-batch-ClFn2T-y.js");
|
|
58428
|
-
return {
|
|
58429
|
-
status: 200,
|
|
58430
|
-
body: { outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne }) }
|
|
58431
|
-
};
|
|
58432
|
-
}
|
|
58433
59717
|
const postAutoMergeScheduleRoute = HttpRouter.add("POST", "/api/flywheel/auto-merge/schedule", httpHandler(Effect.gen(function* () {
|
|
58434
59718
|
const originError = requireTrustedOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
58435
59719
|
if (originError) return originError;
|
|
@@ -58438,14 +59722,6 @@ const postAutoMergeScheduleRoute = HttpRouter.add("POST", "/api/flywheel/auto-me
|
|
|
58438
59722
|
const result = yield* Effect.promise(() => postAutoMergeSchedulePayload(parsed.body));
|
|
58439
59723
|
return jsonResponse(result.body, { status: result.status });
|
|
58440
59724
|
})));
|
|
58441
|
-
const postFlywheelMergeNextRoute = HttpRouter.add("POST", "/api/flywheel/merge-next", httpHandler(Effect.gen(function* () {
|
|
58442
|
-
const originError = requireTrustedOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
58443
|
-
if (originError) return originError;
|
|
58444
|
-
const parsed = yield* readUnknownJsonBody;
|
|
58445
|
-
if (!parsed.ok) return jsonResponse({ error: parsed.error }, { status: 400 });
|
|
58446
|
-
const result = yield* Effect.promise(() => postFlywheelMergeNextPayload(parsed.body));
|
|
58447
|
-
return jsonResponse(result.body, { status: result.status });
|
|
58448
|
-
})));
|
|
58449
59725
|
const deleteAutoMergeRoute = HttpRouter.add("DELETE", "/api/flywheel/auto-merge/:id", httpHandler(Effect.gen(function* () {
|
|
58450
59726
|
const originError = requireTrustedOrigin(yield* HttpServerRequest.HttpServerRequest);
|
|
58451
59727
|
if (originError) return originError;
|
|
@@ -58577,68 +59853,14 @@ const postFlywheelBriefRoute = HttpRouter.add("POST", "/api/flywheel/brief", htt
|
|
|
58577
59853
|
});
|
|
58578
59854
|
});
|
|
58579
59855
|
})));
|
|
58580
|
-
const getFlywheelMergeQueueRoute = HttpRouter.add("GET", "/api/flywheel/merge-queue", httpHandler(Effect.gen(function* () {
|
|
58581
|
-
return yield* Effect.promise(async () => {
|
|
58582
|
-
const status = await readCurrentFlywheelStatusForDashboard();
|
|
58583
|
-
if (!status) return jsonResponse([]);
|
|
58584
|
-
const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-UUcsCDb6.js");
|
|
58585
|
-
return jsonResponse(await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd(), { getPrUrl: resolveMergeQueuePrUrl }).pipe(Effect.provide(layer))));
|
|
58586
|
-
});
|
|
58587
|
-
})));
|
|
58588
|
-
/**
|
|
58589
|
-
* PAN-1737 UAT batch trains. Generation names contain a slash
|
|
58590
|
-
* (`uat/pan-otter-0610`); URL params carry the name WITHOUT the `uat/`
|
|
58591
|
-
* prefix and handlers reconstitute it.
|
|
58592
|
-
*/
|
|
58593
|
-
function uatGenerationNameFromParam(param) {
|
|
58594
|
-
const decoded = decodeURIComponent(param);
|
|
58595
|
-
return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
|
|
58596
|
-
}
|
|
58597
|
-
const getUatGenerationsRoute = HttpRouter.add("GET", "/api/flywheel/uat-generations", httpHandler(Effect.gen(function* () {
|
|
58598
|
-
const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58599
|
-
return jsonResponse(yield* Effect.promise(() => getUatGenerationsPayload()));
|
|
58600
|
-
})));
|
|
58601
59856
|
const getUatCandidateRoute = HttpRouter.add("GET", "/api/flywheel/uat-candidate", httpHandler(Effect.gen(function* () {
|
|
58602
|
-
const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-
|
|
59857
|
+
const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-Cu-4nvbf.js"));
|
|
58603
59858
|
return jsonResponse(yield* Effect.promise(() => getUatCandidatePayload()));
|
|
58604
59859
|
})));
|
|
58605
|
-
const postUatGenerationStackRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/stack", httpHandler(Effect.gen(function* () {
|
|
58606
|
-
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
58607
|
-
if (authError) return authError;
|
|
58608
|
-
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
58609
|
-
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58610
|
-
const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
|
|
58611
|
-
if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
|
|
58612
|
-
return jsonResponse({
|
|
58613
|
-
frontendUrl: result.frontendUrl,
|
|
58614
|
-
evicted: result.evicted
|
|
58615
|
-
});
|
|
58616
|
-
})));
|
|
58617
|
-
const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/promote", httpHandler(Effect.gen(function* () {
|
|
58618
|
-
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
58619
|
-
if (authError) return authError;
|
|
58620
|
-
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
58621
|
-
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58622
|
-
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-CShuVGWT.js"));
|
|
58623
|
-
const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
|
|
58624
|
-
if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
|
|
58625
|
-
return jsonResponse(result);
|
|
58626
|
-
})));
|
|
58627
|
-
/**
|
|
58628
|
-
* PAN-1737: repurposed from the PAN-1691 one-shot candidate assembly. Now a
|
|
58629
|
-
* FORCED reconcile — rebuild the current generation even when the chain
|
|
58630
|
-
* already answers the ready set (operator suspects staleness).
|
|
58631
|
-
*/
|
|
58632
|
-
const postFlywheelAssembleUatRoute = HttpRouter.add("POST", "/api/flywheel/assemble-uat", httpHandler(Effect.gen(function* () {
|
|
58633
|
-
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
58634
|
-
if (authError) return authError;
|
|
58635
|
-
const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-B05BWkp-.js"));
|
|
58636
|
-
return jsonResponse(yield* Effect.promise(() => runUatTrainReconcile({ force: true })));
|
|
58637
|
-
})));
|
|
58638
59860
|
const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
|
|
58639
59861
|
return yield* Effect.promise(async () => jsonResponse(await readFlywheelState()));
|
|
58640
59862
|
})));
|
|
58641
|
-
const flywheelRouteLayer = Layer.mergeAll(getFlywheelRunsRoute, getFlywheelRunRoute, getFlywheelConversationRoute, getFlywheelCurrentRoute, getFlywheelStatsRoute, getSubstrateBugWeightsRoute, getFlywheelConfigRoute, postFlywheelConfigRoute, getPendingAutoMergeRoute, getAutoMergeProblemsRoute, getMergeBlockersRoute, getMergeBackendRoute, postAutoMergeScheduleRoute,
|
|
59863
|
+
const flywheelRouteLayer = Layer.mergeAll(getFlywheelRunsRoute, getFlywheelRunRoute, getFlywheelConversationRoute, getFlywheelCurrentRoute, getFlywheelStatsRoute, getSubstrateBugWeightsRoute, getFlywheelConfigRoute, postFlywheelConfigRoute, getPendingAutoMergeRoute, getAutoMergeProblemsRoute, getMergeBlockersRoute, getMergeBackendRoute, postAutoMergeScheduleRoute, deleteAutoMergeRoute, getUatCandidateRoute, getFlywheelStateRoute, postFlywheelStatusRoute, postFlywheelStartRoute, postFlywheelPauseRoute, postFlywheelResumeRoute, postFlywheelAbortRoute, postFlywheelReportRoute, postFlywheelReportOpenRoute, getFlywheelBriefRoute, postFlywheelBriefRoute);
|
|
58642
59864
|
//#endregion
|
|
58643
59865
|
//#region routes/orders.ts
|
|
58644
59866
|
init_projects();
|
|
@@ -58827,7 +60049,7 @@ function previewBrief(book) {
|
|
|
58827
60049
|
return `${lines.join("\n")}\n`;
|
|
58828
60050
|
}
|
|
58829
60051
|
async function defaultStartOrderBook(book) {
|
|
58830
|
-
const { startFlywheelRun } = await import("./flywheel-
|
|
60052
|
+
const { startFlywheelRun } = await import("./flywheel-CLVB55Be.js");
|
|
58831
60053
|
return startFlywheelRun({
|
|
58832
60054
|
cwd: process.cwd(),
|
|
58833
60055
|
orders: book.id
|
|
@@ -61985,7 +63207,8 @@ const staticRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* () {
|
|
|
61985
63207
|
const projectRoot = selfPath.includes("/dist/") ? pathService.resolve(selfPath, "..", "..") : pathService.resolve(selfPath, "..", "..", "..");
|
|
61986
63208
|
const staticDir = process.env["OVERDECK_FRONTEND_DIR"] ?? pathService.resolve(projectRoot, "dist", "dashboard", "public");
|
|
61987
63209
|
const staticRoot = pathService.resolve(staticDir);
|
|
61988
|
-
const
|
|
63210
|
+
const urlPath = url.value.pathname === "/" ? "/index.html" : url.value.pathname;
|
|
63211
|
+
const rawRelative = urlPath.replace(/^[/\\]+/, "");
|
|
61989
63212
|
const normalized = pathService.normalize(rawRelative).replace(/^[/\\]+/, "");
|
|
61990
63213
|
if (normalized.length === 0 || normalized.startsWith("..") || normalized.includes("\0")) return HttpServerResponse.text("Invalid path", { status: 400 });
|
|
61991
63214
|
const sep = pathService.sep;
|
|
@@ -61998,6 +63221,7 @@ const staticRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* () {
|
|
|
61998
63221
|
}
|
|
61999
63222
|
const fileInfo = yield* fileSystem.stat(filePath).pipe(Effect.catch(() => Effect.succeed(null)));
|
|
62000
63223
|
if (!fileInfo || fileInfo.type !== "File") {
|
|
63224
|
+
if (pathService.extname(urlPath)) return HttpServerResponse.text("Not Found", { status: 404 });
|
|
62001
63225
|
const indexPath = pathService.resolve(staticRoot, "index.html");
|
|
62002
63226
|
const indexInfo = yield* fileSystem.stat(indexPath).pipe(Effect.catch(() => Effect.succeed(null)));
|
|
62003
63227
|
if (!indexInfo || indexInfo.type !== "File") return HttpServerResponse.text("Not Found", { status: 404 });
|
|
@@ -62007,7 +63231,7 @@ const staticRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* () {
|
|
|
62007
63231
|
if (filePath.endsWith("index.html")) return HttpServerResponse.setHeader(res, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
62008
63232
|
return res;
|
|
62009
63233
|
}));
|
|
62010
|
-
const makeRoutesLayer = Layer.mergeAll(healthRouteLayer, dashboardSessionPreflightRouteLayer, dashboardSessionRouteLayer, websocketRpcRouteLayer, issuesRouteLayer, pipelineMembershipRouteLayer, agentsRouteLayer, workspacesRouteLayer, specialistsRouteLayer, costsRouteLayer, cloisterRouteLayer, resourcesRouteLayer, commandDeckRouteLayer, remoteRouteLayer, settingsRouteLayer, voiceRouteLayer, autopresoRouteLayer, metricsRouteLayer, miscRouteLayer, paletteRouteLayer, conversationsRouteLayer, eventsRouteLayer, showRouteLayer, projectsRouteLayer, contextRouteLayer, adminRouteLayer, prereqsRouteLayer, cliproxyRouteLayer, ttsRouteLayer, webhooksRouteLayer, hooksRouteLayer, diffsRouteLayer, codexAuthRouteLayer, terminalsRouteLayer, discoveredSessionsRouteLayer, flywheelRouteLayer, ordersRouteLayer, artifactsRouteLayer, featureRegistryRouteLayer, fsRouteLayer, tieredCalloutsRouteLayer, backlogRouteLayer, internalEventsRouteLayer, knowledgeViewerRouteLayer, staticRouteLayer);
|
|
63234
|
+
const makeRoutesLayer = Layer.mergeAll(healthRouteLayer, dashboardSessionPreflightRouteLayer, dashboardSessionRouteLayer, websocketRpcRouteLayer, issuesRouteLayer, pipelineMembershipRouteLayer, agentsRouteLayer, workspacesRouteLayer, specialistsRouteLayer, costsRouteLayer, cloisterRouteLayer, resourcesRouteLayer, commandDeckRouteLayer, remoteRouteLayer, settingsRouteLayer, voiceRouteLayer, autopresoRouteLayer, metricsRouteLayer, miscRouteLayer, paletteRouteLayer, conversationsRouteLayer, eventsRouteLayer, showRouteLayer, projectsRouteLayer, projectsMergeTrainRouteLayer, mergeTrainRouteLayer, contextRouteLayer, commandsRouteLayer, adminRouteLayer, prereqsRouteLayer, cliproxyRouteLayer, ttsRouteLayer, webhooksRouteLayer, hooksRouteLayer, diffsRouteLayer, codexAuthRouteLayer, linearMcpAuthRouteLayer, terminalsRouteLayer, discoveredSessionsRouteLayer, flywheelRouteLayer, ordersRouteLayer, artifactsRouteLayer, featureRegistryRouteLayer, fsRouteLayer, tieredCalloutsRouteLayer, backlogRouteLayer, internalEventsRouteLayer, knowledgeViewerRouteLayer, staticRouteLayer);
|
|
62011
63235
|
const OverdeckAgentsResolverLive = AgentsResolverLive.pipe(Layer.provide(Layer.mergeAll(DbLive, TmuxLive)));
|
|
62012
63236
|
const OverdeckCostResolverLive = CostResolverLive.pipe(Layer.provide(DbLive));
|
|
62013
63237
|
const ReadModelWithOverdeckLive = ReadModelServiceLive.pipe(Layer.provide(OverdeckAgentsResolverLive));
|
|
@@ -62060,6 +63284,7 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
62060
63284
|
init_agents$1();
|
|
62061
63285
|
init_review_status();
|
|
62062
63286
|
init_concurrency$1();
|
|
63287
|
+
init_runtime_census();
|
|
62063
63288
|
init_event_store();
|
|
62064
63289
|
init_activity_logger();
|
|
62065
63290
|
init_read_model();
|
|
@@ -62078,7 +63303,43 @@ function buildAwaitingInputActivityMessage(agentId, issueId, kinds) {
|
|
|
62078
63303
|
const kindList = kinds.length > 0 ? kinds.join(", ") : "input";
|
|
62079
63304
|
return issueId ? `${agentId} on ${issueId} is waiting for ${kindList}` : `${agentId} is waiting for ${kindList}`;
|
|
62080
63305
|
}
|
|
63306
|
+
function shouldSkipEnrichmentCycle(census) {
|
|
63307
|
+
return !census.tmuxAvailable;
|
|
63308
|
+
}
|
|
63309
|
+
function hasReapablePendingInput(enrichment) {
|
|
63310
|
+
return enrichment.pendingInputCount > 0 || enrichment.pendingAskUserQuestion != null || enrichment.pendingProposedPlan != null;
|
|
63311
|
+
}
|
|
63312
|
+
function buildPendingReapEvent(agentId, previous) {
|
|
63313
|
+
return {
|
|
63314
|
+
type: "agent.enrichment_changed",
|
|
63315
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
63316
|
+
payload: {
|
|
63317
|
+
agentId,
|
|
63318
|
+
role: previous.role,
|
|
63319
|
+
hasPendingQuestion: false,
|
|
63320
|
+
pendingQuestionCount: 0,
|
|
63321
|
+
pendingQuestionPrompt: void 0,
|
|
63322
|
+
pendingQuestionReason: void 0,
|
|
63323
|
+
pendingInputCount: 0,
|
|
63324
|
+
pendingInputKinds: [],
|
|
63325
|
+
pendingAskUserQuestion: void 0,
|
|
63326
|
+
pendingProposedPlan: void 0,
|
|
63327
|
+
resolution: previous.resolution,
|
|
63328
|
+
resolutionCount: previous.resolutionCount
|
|
63329
|
+
}
|
|
63330
|
+
};
|
|
63331
|
+
}
|
|
63332
|
+
function buildExpiredQuestionActivityMessage(agentId, issueId) {
|
|
63333
|
+
return `${issueId ? `${agentId} on ${issueId}` : agentId} stopped with its question unanswered — the question has expired and is no longer actionable`;
|
|
63334
|
+
}
|
|
62081
63335
|
async function pollOnce(state) {
|
|
63336
|
+
let census;
|
|
63337
|
+
try {
|
|
63338
|
+
census = await getRuntimeCensus();
|
|
63339
|
+
} catch {
|
|
63340
|
+
return;
|
|
63341
|
+
}
|
|
63342
|
+
if (shouldSkipEnrichmentCycle(census)) return;
|
|
62082
63343
|
let runningAgents;
|
|
62083
63344
|
try {
|
|
62084
63345
|
runningAgents = await Effect.runPromise(listRunningAgents());
|
|
@@ -62200,7 +63461,20 @@ async function pollOnce(state) {
|
|
|
62200
63461
|
} catch {}
|
|
62201
63462
|
})), 4));
|
|
62202
63463
|
const activeIds = new Set(activeAgents.map((a) => a.id));
|
|
62203
|
-
for (const id of state.lastEnrichment
|
|
63464
|
+
for (const [id, previousEnrichment] of state.lastEnrichment) if (!activeIds.has(id)) {
|
|
63465
|
+
if (hasReapablePendingInput(previousEnrichment)) {
|
|
63466
|
+
try {
|
|
63467
|
+
await eventStore.appendAsync(buildPendingReapEvent(id, previousEnrichment));
|
|
63468
|
+
} catch {}
|
|
63469
|
+
const agentRecord = runningAgents.find((agent) => agent.id === id);
|
|
63470
|
+
const issueId = agentRecord?.issueId;
|
|
63471
|
+
emitActivityEntrySync({
|
|
63472
|
+
source: toRole(agentRecord?.role) ?? "work",
|
|
63473
|
+
level: "info",
|
|
63474
|
+
message: buildExpiredQuestionActivityMessage(id, issueId),
|
|
63475
|
+
issueId
|
|
63476
|
+
});
|
|
63477
|
+
}
|
|
62204
63478
|
state.lastEnrichment.delete(id);
|
|
62205
63479
|
state.lastScan.delete(id);
|
|
62206
63480
|
}
|
|
@@ -62208,7 +63482,7 @@ async function pollOnce(state) {
|
|
|
62208
63482
|
/** Poll interval: 10 seconds (was 3s). The enrichment data changes slowly —
|
|
62209
63483
|
* pending questions, resolution state, phase — none of these need sub-second
|
|
62210
63484
|
* latency. 10s eliminates ~70% of poller I/O without any user-visible lag. */
|
|
62211
|
-
const POLL_INTERVAL_MS$
|
|
63485
|
+
const POLL_INTERVAL_MS$4 = 1e4;
|
|
62212
63486
|
const serviceState$2 = {
|
|
62213
63487
|
timer: null,
|
|
62214
63488
|
lastEnrichment: /* @__PURE__ */ new Map(),
|
|
@@ -62220,7 +63494,7 @@ function startAgentEnrichmentService() {
|
|
|
62220
63494
|
if (serviceState$2.timer !== null) return;
|
|
62221
63495
|
serviceState$2.timer = setInterval(() => {
|
|
62222
63496
|
pollOnce(serviceState$2).catch(() => {});
|
|
62223
|
-
}, POLL_INTERVAL_MS$
|
|
63497
|
+
}, POLL_INTERVAL_MS$4);
|
|
62224
63498
|
}
|
|
62225
63499
|
function stopAgentEnrichmentService() {
|
|
62226
63500
|
if (serviceState$2.timer !== null) {
|
|
@@ -62248,7 +63522,7 @@ function stopAgentEnrichmentService() {
|
|
|
62248
63522
|
* Bounded + cheap: each issue has a throttle. Ready/no-blocker rows use the PAN-1620
|
|
62249
63523
|
* 3-minute cadence; already-blocked mergeability rows use a 10-minute cadence.
|
|
62250
63524
|
*/
|
|
62251
|
-
const POLL_INTERVAL_MS$
|
|
63525
|
+
const POLL_INTERVAL_MS$3 = 6e4;
|
|
62252
63526
|
/** Re-check each ready-to-merge PR at most this often, to bound `gh` calls. */
|
|
62253
63527
|
const RECHECK_INTERVAL_MS = 18e4;
|
|
62254
63528
|
/** Re-check already-flagged mergeability blockers less often; they are not mergeable yet. */
|
|
@@ -62280,7 +63554,7 @@ function parsePrUrl$1(url) {
|
|
|
62280
63554
|
function hasMergeabilityBlocker(blockers) {
|
|
62281
63555
|
return blockers?.some((blocker) => MERGEABILITY_BLOCKERS.has(blocker.type)) ?? false;
|
|
62282
63556
|
}
|
|
62283
|
-
async function reconcileOnce(state) {
|
|
63557
|
+
async function reconcileOnce$1(state) {
|
|
62284
63558
|
const candidates = await Effect.runPromise(getMergeBlockerReconcileCandidates());
|
|
62285
63559
|
const now = Date.now();
|
|
62286
63560
|
for (const candidate of candidates) {
|
|
@@ -62316,8 +63590,8 @@ async function reconcileOnce(state) {
|
|
|
62316
63590
|
function startMergeBlockerReconcileService() {
|
|
62317
63591
|
if (serviceState$1.timer !== null) return;
|
|
62318
63592
|
serviceState$1.timer = setInterval(() => {
|
|
62319
|
-
reconcileOnce(serviceState$1).catch(() => {});
|
|
62320
|
-
}, POLL_INTERVAL_MS$
|
|
63593
|
+
reconcileOnce$1(serviceState$1).catch(() => {});
|
|
63594
|
+
}, POLL_INTERVAL_MS$3);
|
|
62321
63595
|
serviceState$1.timer.unref?.();
|
|
62322
63596
|
}
|
|
62323
63597
|
function enqueueRefresh(state, task) {
|
|
@@ -62341,6 +63615,51 @@ function drainRefreshQueue(state) {
|
|
|
62341
63615
|
}
|
|
62342
63616
|
}
|
|
62343
63617
|
//#endregion
|
|
63618
|
+
//#region services/review-status-reconcile-service.ts
|
|
63619
|
+
init_review_status();
|
|
63620
|
+
init_event_store();
|
|
63621
|
+
const POLL_INTERVAL_MS$2 = 6e4;
|
|
63622
|
+
let reconcileTimer = null;
|
|
63623
|
+
function reviewStatusPayload(event) {
|
|
63624
|
+
if (!event.payload || typeof event.payload !== "object") return null;
|
|
63625
|
+
const payload = event.payload;
|
|
63626
|
+
if (typeof payload.issueId !== "string" || !payload.status || typeof payload.status !== "object") return null;
|
|
63627
|
+
return payload;
|
|
63628
|
+
}
|
|
63629
|
+
async function reconcileOnce() {
|
|
63630
|
+
const cached = loadReviewStatuses();
|
|
63631
|
+
const canonicalByIssue = /* @__PURE__ */ new Map();
|
|
63632
|
+
for (const issueId of Object.keys(cached)) {
|
|
63633
|
+
const canonical = getReviewStatusSync(issueId);
|
|
63634
|
+
if (!canonical) continue;
|
|
63635
|
+
canonicalByIssue.set(issueId.toUpperCase(), canonical);
|
|
63636
|
+
}
|
|
63637
|
+
const store = getEventStore();
|
|
63638
|
+
const latestByIssue = /* @__PURE__ */ new Map();
|
|
63639
|
+
for (const event of store.queryLatestPerIssue("review.status_changed")) {
|
|
63640
|
+
const payload = reviewStatusPayload(event);
|
|
63641
|
+
if (payload) latestByIssue.set(payload.issueId.toUpperCase(), event);
|
|
63642
|
+
}
|
|
63643
|
+
for (const [issueId, canonical] of canonicalByIssue) {
|
|
63644
|
+
const latest = latestByIssue.get(issueId);
|
|
63645
|
+
const latestPayload = latest ? reviewStatusPayload(latest) : null;
|
|
63646
|
+
const lastUpdatedAt = latestPayload?.status.updatedAt ?? "";
|
|
63647
|
+
if (lastUpdatedAt > canonical.updatedAt) continue;
|
|
63648
|
+
if (lastUpdatedAt === canonical.updatedAt && latestPayload && sameCanonicalReviewStatus(latestPayload.status, canonical)) continue;
|
|
63649
|
+
console.log(`[review-status-reconcile] re-emitting status for ${issueId} (canonical differs from last event — healing lost status_changed)`);
|
|
63650
|
+
emitReviewStatusChanged((event) => store.append(event), issueId, canonical);
|
|
63651
|
+
}
|
|
63652
|
+
}
|
|
63653
|
+
function startReviewStatusReconcileService() {
|
|
63654
|
+
if (getDashboardIdentity().mode !== "primary") return false;
|
|
63655
|
+
if (reconcileTimer !== null) return true;
|
|
63656
|
+
reconcileTimer = setInterval(() => {
|
|
63657
|
+
reconcileOnce().catch(() => {});
|
|
63658
|
+
}, POLL_INTERVAL_MS$2);
|
|
63659
|
+
reconcileTimer.unref?.();
|
|
63660
|
+
return true;
|
|
63661
|
+
}
|
|
63662
|
+
//#endregion
|
|
62344
63663
|
//#region services/project-resource-refresh-queue.ts
|
|
62345
63664
|
init_projects();
|
|
62346
63665
|
const PROJECT_RESOURCE_CONVERGENCE_INTERVAL_MS = 5 * 6e4;
|
|
@@ -64028,14 +65347,42 @@ const RESTART_MARKER = join$1(homedir(), ".overdeck", "dashboard-restarting.json
|
|
|
64028
65347
|
* loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
|
|
64029
65348
|
*/
|
|
64030
65349
|
async function defaultLifecycleRunner(pending) {
|
|
64031
|
-
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-
|
|
65350
|
+
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-DrXa1CpW.js");
|
|
64032
65351
|
await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
|
|
64033
65352
|
if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
|
|
64034
65353
|
}
|
|
65354
|
+
async function runClaimedPendingLifecycle(claim, pending, runner, lifecycleDelayMs, startTime) {
|
|
65355
|
+
let succeeded = false;
|
|
65356
|
+
try {
|
|
65357
|
+
if (lifecycleDelayMs > 0) await new Promise((resolve) => setTimeout(resolve, lifecycleDelayMs));
|
|
65358
|
+
await runner(pending);
|
|
65359
|
+
succeeded = true;
|
|
65360
|
+
emitDashboardLifecycleSync("completed", {
|
|
65361
|
+
reason: pending.reason ?? "post-merge",
|
|
65362
|
+
issueId: pending.issueId,
|
|
65363
|
+
durationMs: Date.now() - startTime
|
|
65364
|
+
});
|
|
65365
|
+
} catch (error) {
|
|
65366
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65367
|
+
console.error(`[overdeck] Post-merge lifecycle failed for ${pending.issueId}: ${message}`);
|
|
65368
|
+
emitDashboardLifecycleSync("failed", {
|
|
65369
|
+
reason: pending.reason ?? "post-merge",
|
|
65370
|
+
issueId: pending.issueId,
|
|
65371
|
+
error: message
|
|
65372
|
+
});
|
|
65373
|
+
} finally {
|
|
65374
|
+
try {
|
|
65375
|
+
await settlePendingLifecycleClaim(claim, pending.issueId, succeeded);
|
|
65376
|
+
} catch (error) {
|
|
65377
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65378
|
+
console.warn(`[overdeck] Failed to settle pending lifecycle claim for ${pending.issueId}: ${message}`);
|
|
65379
|
+
}
|
|
65380
|
+
}
|
|
65381
|
+
}
|
|
64035
65382
|
/**
|
|
64036
65383
|
* Check for and process a pending post-merge lifecycle file.
|
|
64037
|
-
*
|
|
64038
|
-
*
|
|
65384
|
+
* Atomically claims the file before execution so dashboard and Deacon cannot
|
|
65385
|
+
* run the same handoff. The durable mergeStep marker owns retries after failure.
|
|
64039
65386
|
*
|
|
64040
65387
|
* Also checks for a RESTART_MARKER file (written by deploy script before killing
|
|
64041
65388
|
* the old server) and emits dashboard.lifecycle_started if found.
|
|
@@ -64061,35 +65408,25 @@ async function processPendingLifecycle(options) {
|
|
|
64061
65408
|
} catch (err) {
|
|
64062
65409
|
console.warn(`[overdeck] Failed to process restart marker: ${err.message}`);
|
|
64063
65410
|
}
|
|
64064
|
-
if (!existsSync(pendingFile)) return;
|
|
64065
65411
|
const startTime = Date.now();
|
|
64066
65412
|
try {
|
|
64067
|
-
const
|
|
64068
|
-
|
|
64069
|
-
|
|
65413
|
+
const claim = await claimPendingLifecycleFile(pendingFile);
|
|
65414
|
+
if (!claim) return;
|
|
65415
|
+
let pending;
|
|
65416
|
+
try {
|
|
65417
|
+
pending = JSON.parse(claim.raw);
|
|
65418
|
+
} catch (error) {
|
|
65419
|
+
await claim.discard();
|
|
65420
|
+
throw error;
|
|
65421
|
+
}
|
|
64070
65422
|
const age = (options?.now ?? Date.now()) - (pending.timestamp ?? 0);
|
|
64071
65423
|
if (age > staleThresholdMs) {
|
|
65424
|
+
await claim.discard();
|
|
64072
65425
|
console.warn(`[overdeck] Ignoring stale pending-post-merge.json (age: ${Math.round(age / 6e4)}min) for ${pending.issueId}`);
|
|
64073
65426
|
return;
|
|
64074
65427
|
}
|
|
64075
|
-
console.log(`[overdeck] Found pending post-merge lifecycle for ${pending.issueId} —
|
|
64076
|
-
|
|
64077
|
-
try {
|
|
64078
|
-
await runner(pending);
|
|
64079
|
-
emitDashboardLifecycleSync("completed", {
|
|
64080
|
-
reason: pending.reason ?? "post-merge",
|
|
64081
|
-
issueId: pending.issueId,
|
|
64082
|
-
durationMs: Date.now() - startTime
|
|
64083
|
-
});
|
|
64084
|
-
} catch (err) {
|
|
64085
|
-
console.error(`[overdeck] Post-merge lifecycle failed for ${pending.issueId}: ${err.message}`);
|
|
64086
|
-
emitDashboardLifecycleSync("failed", {
|
|
64087
|
-
reason: pending.reason ?? "post-merge",
|
|
64088
|
-
issueId: pending.issueId,
|
|
64089
|
-
error: err.message
|
|
64090
|
-
});
|
|
64091
|
-
}
|
|
64092
|
-
}, lifecycleDelayMs);
|
|
65428
|
+
console.log(`[overdeck] Found pending post-merge lifecycle for ${pending.issueId} — running in ${lifecycleDelayMs}ms`);
|
|
65429
|
+
runClaimedPendingLifecycle(claim, pending, runner, lifecycleDelayMs, startTime);
|
|
64093
65430
|
} catch (err) {
|
|
64094
65431
|
console.warn(`[overdeck] Failed to process pending-post-merge.json: ${err.message}`);
|
|
64095
65432
|
}
|
|
@@ -64337,6 +65674,8 @@ const cleanupClosedIssueAgentDirectories = (options) => Effect.tryPromise({
|
|
|
64337
65674
|
//#region services/auto-merge-executor.ts
|
|
64338
65675
|
init_activity_logger();
|
|
64339
65676
|
init_merge_sync();
|
|
65677
|
+
init_deploy_queue();
|
|
65678
|
+
init_review_status();
|
|
64340
65679
|
const AUTO_MERGE_EXECUTOR_INTERVAL_MS = 3e4;
|
|
64341
65680
|
const REQUEUE_BACKOFF_MS = 6e4;
|
|
64342
65681
|
let timer$1 = null;
|
|
@@ -64349,7 +65688,7 @@ function failureReason(result) {
|
|
|
64349
65688
|
return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
|
|
64350
65689
|
}
|
|
64351
65690
|
async function defaultMergeIssue(issueId) {
|
|
64352
|
-
const { triggerMerge } = await import("./merge-ops-
|
|
65691
|
+
const { triggerMerge } = await import("./merge-ops-DdpTiEMt.js");
|
|
64353
65692
|
return triggerMerge(issueId);
|
|
64354
65693
|
}
|
|
64355
65694
|
function defaultAnnounceFailure(issueId, reason) {
|
|
@@ -64371,6 +65710,10 @@ async function tickAutoMergeExecutor(deps = {}) {
|
|
|
64371
65710
|
log("[auto-merge] flywheel paused, skipping tick");
|
|
64372
65711
|
return;
|
|
64373
65712
|
}
|
|
65713
|
+
if (await (deps.hasPendingDeploy ?? (async () => await readPendingDeploy() !== null))()) {
|
|
65714
|
+
log(`[auto-merge] dashboard deploy queued, deferring ${entries.length} merge(s) before preparation`);
|
|
65715
|
+
return;
|
|
65716
|
+
}
|
|
64374
65717
|
for (const entry of entries) {
|
|
64375
65718
|
if (isPaused()) {
|
|
64376
65719
|
log("[auto-merge] flywheel paused, skipping tick");
|
|
@@ -64397,6 +65740,25 @@ async function tickAutoMergeExecutor(deps = {}) {
|
|
|
64397
65740
|
continue;
|
|
64398
65741
|
}
|
|
64399
65742
|
const reason = failureReason(result);
|
|
65743
|
+
if (result.deferred) {
|
|
65744
|
+
const retryAt = new Date(nowDate.getTime() + REQUEUE_BACKOFF_MS).toISOString();
|
|
65745
|
+
log((deps.requeueToPending ?? requeueToPending)(entry.id, retryAt) ? `[auto-merge] merge deferred for ${entry.issueId}; requeued without consuming retry budget for ${retryAt}` : `[auto-merge] failed to requeue deferred merge for ${entry.issueId} (#${entry.id})`);
|
|
65746
|
+
continue;
|
|
65747
|
+
}
|
|
65748
|
+
if (result.retryable) {
|
|
65749
|
+
const retryCount = (deps.getMergeRetryCount ?? ((issueId) => getReviewStatusSync(issueId)?.mergeRetryCount ?? 0))(entry.issueId);
|
|
65750
|
+
if (retryCount >= 3) {
|
|
65751
|
+
const blockedReason = `Auto-merge for ${entry.issueId} blocked: ${reason} (retried ${retryCount} times — fix the underlying cause and re-schedule)`;
|
|
65752
|
+
if ((deps.markMergingBlocked ?? markMergingBlocked)(entry.id, blockedReason)) (deps.announceFailure ?? defaultAnnounceFailure)(entry.issueId, blockedReason);
|
|
65753
|
+
else log(`[auto-merge] lost circuit-breaker block race for ${entry.issueId} (#${entry.id}), skipping announcement`);
|
|
65754
|
+
} else {
|
|
65755
|
+
const nextRetryCount = retryCount + 1;
|
|
65756
|
+
(deps.setMergeRetryCount ?? ((issueId, count) => setReviewStatusSync(issueId, { mergeRetryCount: count })))(entry.issueId, nextRetryCount);
|
|
65757
|
+
const retryAt = new Date(nowDate.getTime() + REQUEUE_BACKOFF_MS).toISOString();
|
|
65758
|
+
log((deps.requeueToPending ?? requeueToPending)(entry.id, retryAt) ? `[auto-merge] retryable merge failure for ${entry.issueId}; requeued attempt ${nextRetryCount}/3 for ${retryAt}` : `[auto-merge] failed to requeue retryable merge for ${entry.issueId} (#${entry.id})`);
|
|
65759
|
+
}
|
|
65760
|
+
continue;
|
|
65761
|
+
}
|
|
64400
65762
|
(deps.markFailed ?? markFailed)(entry.id, reason);
|
|
64401
65763
|
(deps.announceFailure ?? defaultAnnounceFailure)(entry.issueId, reason);
|
|
64402
65764
|
} catch (error) {
|
|
@@ -64561,17 +65923,46 @@ function createOverdeckDatabase(options = {}) {
|
|
|
64561
65923
|
try {
|
|
64562
65924
|
applyMigration(db, migrationPath);
|
|
64563
65925
|
const tables = userTableNames(db);
|
|
64564
|
-
if (tables.length !==
|
|
65926
|
+
if (tables.length !== 34) throw new Error(`Expected 34 overdeck tables, found ${tables.length}: ${tables.join(", ")}`);
|
|
64565
65927
|
assertEmptyTables(db, tables);
|
|
64566
65928
|
} finally {
|
|
64567
65929
|
db.close();
|
|
64568
65930
|
}
|
|
64569
65931
|
return {
|
|
64570
65932
|
dbPath,
|
|
64571
|
-
tableCount:
|
|
65933
|
+
tableCount: 34
|
|
64572
65934
|
};
|
|
64573
65935
|
}
|
|
64574
65936
|
//#endregion
|
|
65937
|
+
//#region telemetry.ts
|
|
65938
|
+
init_agents$1();
|
|
65939
|
+
init_projects();
|
|
65940
|
+
init_service();
|
|
65941
|
+
const defaultDeps = {
|
|
65942
|
+
analytics: getAnalyticsService("server"),
|
|
65943
|
+
listProjects: listProjectsSync,
|
|
65944
|
+
listAgents: () => Effect.runPromise(listRunningAgents())
|
|
65945
|
+
};
|
|
65946
|
+
function bucketServerCount(value) {
|
|
65947
|
+
if (value <= 0) return "0";
|
|
65948
|
+
if (value <= 2) return "1-2";
|
|
65949
|
+
if (value <= 5) return "3-5";
|
|
65950
|
+
if (value <= 10) return "6-10";
|
|
65951
|
+
return "11+";
|
|
65952
|
+
}
|
|
65953
|
+
async function captureServerBootTelemetry(deps = defaultDeps) {
|
|
65954
|
+
try {
|
|
65955
|
+
const [projects, agents] = await Promise.all([Promise.resolve(deps.listProjects()), deps.listAgents()]);
|
|
65956
|
+
deps.analytics.capture("server_boot", {
|
|
65957
|
+
project_count: bucketServerCount(projects.length),
|
|
65958
|
+
active_agent_count: bucketServerCount(agents.filter((agent) => agent.tmuxActive).length)
|
|
65959
|
+
});
|
|
65960
|
+
} catch {}
|
|
65961
|
+
}
|
|
65962
|
+
function startServerBootTelemetry(deps = defaultDeps) {
|
|
65963
|
+
captureServerBootTelemetry(deps);
|
|
65964
|
+
}
|
|
65965
|
+
//#endregion
|
|
64575
65966
|
//#region ../../lib/state-auto-migrate.ts
|
|
64576
65967
|
init_projects();
|
|
64577
65968
|
init_state_home();
|
|
@@ -64596,7 +65987,7 @@ const defaultDependencies = {
|
|
|
64596
65987
|
inspect: inspectStateMigration,
|
|
64597
65988
|
ensureWorktree: ensureStateWorktree,
|
|
64598
65989
|
migrate: async (projectKey, project, signal) => {
|
|
64599
|
-
const { migrateProjectState } = await import("./state-migrate-
|
|
65990
|
+
const { migrateProjectState } = await import("./state-migrate-CvvBtS0Y.js");
|
|
64600
65991
|
await migrateProjectState(projectKey, { signal }, project);
|
|
64601
65992
|
},
|
|
64602
65993
|
clearCache: clearStateMigrationCache,
|
|
@@ -64728,7 +66119,7 @@ init_internal_token();
|
|
|
64728
66119
|
init_review_status();
|
|
64729
66120
|
init_event_store();
|
|
64730
66121
|
init_activity_logger();
|
|
64731
|
-
init_config$
|
|
66122
|
+
init_config$2();
|
|
64732
66123
|
init_agents$1();
|
|
64733
66124
|
init_paths();
|
|
64734
66125
|
init_tmux();
|
|
@@ -64763,6 +66154,7 @@ if (typeof Bun !== "undefined") {
|
|
|
64763
66154
|
runMain(main);
|
|
64764
66155
|
}
|
|
64765
66156
|
await whenDashboardListening();
|
|
66157
|
+
startServerBootTelemetry();
|
|
64766
66158
|
startEventLoopMonitor();
|
|
64767
66159
|
console.log("[overdeck] Event loop delay monitor started");
|
|
64768
66160
|
warnIfAutonomousMergeBackendUnavailable();
|
|
@@ -64798,13 +66190,15 @@ startAgentOutputService();
|
|
|
64798
66190
|
console.log("[overdeck] AgentOutputService started");
|
|
64799
66191
|
startMergeBlockerReconcileService();
|
|
64800
66192
|
console.log("[overdeck] MergeBlockerReconcileService started");
|
|
66193
|
+
if (startReviewStatusReconcileService()) console.log("[overdeck] ReviewStatusReconcileService started");
|
|
66194
|
+
else console.log("[overdeck] ReviewStatusReconcileService skipped — non-primary dashboard process");
|
|
64801
66195
|
if (shouldStartStaleCheckRetriggerService()) {
|
|
64802
66196
|
startStaleCheckRetriggerService();
|
|
64803
66197
|
console.log("[overdeck] StaleCheckRetriggerService started");
|
|
64804
66198
|
}
|
|
64805
66199
|
if (process.env.OVERDECK_MODE === "desktop") (async () => {
|
|
64806
66200
|
try {
|
|
64807
|
-
const { provisionClaudeHooks } = await import("./claude-hooks-provision-
|
|
66201
|
+
const { provisionClaudeHooks } = await import("./claude-hooks-provision-CN-xo-do.js");
|
|
64808
66202
|
const result = await provisionClaudeHooks();
|
|
64809
66203
|
if (!result.ok) console.warn(`[overdeck] Claude hook provisioning skipped: ${result.reason}`);
|
|
64810
66204
|
else if (result.changed) console.log(`[overdeck] Claude hooks provisioned: ${result.binariesSynced} scripts, registered ${result.registered.length} hook(s)${result.pruned.length ? `, pruned ${result.pruned.length} stale` : ""}`);
|
|
@@ -64816,21 +66210,11 @@ if (process.env.OVERDECK_MODE === "desktop") (async () => {
|
|
|
64816
66210
|
setPipelineHandlerSync((event) => {
|
|
64817
66211
|
switch (event.type) {
|
|
64818
66212
|
case "status_changed":
|
|
64819
|
-
|
|
64820
|
-
|
|
64821
|
-
|
|
64822
|
-
|
|
64823
|
-
|
|
64824
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64825
|
-
payload: {
|
|
64826
|
-
issueId: event.issueId,
|
|
64827
|
-
status: enriched
|
|
64828
|
-
}
|
|
64829
|
-
});
|
|
64830
|
-
} catch (err) {
|
|
64831
|
-
console.error("[pipeline] Failed to append status_changed event:", err);
|
|
64832
|
-
}
|
|
64833
|
-
})();
|
|
66213
|
+
try {
|
|
66214
|
+
emitReviewStatusChanged((domainEvent) => getEventStore().append(domainEvent), event.issueId, event.status);
|
|
66215
|
+
} catch (err) {
|
|
66216
|
+
console.error("[pipeline] Failed to append status_changed event:", err);
|
|
66217
|
+
}
|
|
64834
66218
|
return;
|
|
64835
66219
|
case "review.approved":
|
|
64836
66220
|
case "test.passed":
|
|
@@ -65012,21 +66396,11 @@ console.log("[overdeck] Agent stopped/status notifiers → domain events wired")
|
|
|
65012
66396
|
setMergeReadyNotifier((issueId) => {
|
|
65013
66397
|
const status = getReviewStatusSync(issueId);
|
|
65014
66398
|
if (!status) return;
|
|
65015
|
-
|
|
65016
|
-
|
|
65017
|
-
|
|
65018
|
-
|
|
65019
|
-
|
|
65020
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65021
|
-
payload: {
|
|
65022
|
-
issueId,
|
|
65023
|
-
status: enriched
|
|
65024
|
-
}
|
|
65025
|
-
});
|
|
65026
|
-
} catch (err) {
|
|
65027
|
-
console.error("[pipeline] Failed to append merge-ready event:", err);
|
|
65028
|
-
}
|
|
65029
|
-
})();
|
|
66399
|
+
try {
|
|
66400
|
+
emitReviewStatusChanged((domainEvent) => getEventStore().append(domainEvent), issueId, status);
|
|
66401
|
+
} catch (err) {
|
|
66402
|
+
console.error("[pipeline] Failed to append merge-ready event:", err);
|
|
66403
|
+
}
|
|
65030
66404
|
});
|
|
65031
66405
|
console.log("[overdeck] Merge-ready notifier → domain events wired");
|
|
65032
66406
|
startConversationLifecycleService();
|
|
@@ -65148,7 +66522,7 @@ const handleShutdownSignal = async (signal) => {
|
|
|
65148
66522
|
await stopAllKnowledgeViewers().catch((err) => console.warn("[knowledge-viewer] shutdown failed:", err?.message ?? err));
|
|
65149
66523
|
await stopDeaconChild().catch((err) => console.warn("[deacon-supervisor] child shutdown failed:", err?.message ?? err));
|
|
65150
66524
|
try {
|
|
65151
|
-
const { killAllGateProcessGroups } = await import("./validation-
|
|
66525
|
+
const { killAllGateProcessGroups } = await import("./validation-DEaTZafj.js");
|
|
65152
66526
|
const reaped = killAllGateProcessGroups();
|
|
65153
66527
|
if (reaped > 0) console.log(`[overdeck] reaped ${reaped} in-flight gate process group(s)`);
|
|
65154
66528
|
} catch (err) {
|
|
@@ -65203,7 +66577,7 @@ reconcileStaleGitHubBlockers().then((n) => {
|
|
|
65203
66577
|
}
|
|
65204
66578
|
}).catch((err) => console.warn(`[overdeck] Startup blocker reconciliation failed: ${err.message}`));
|
|
65205
66579
|
try {
|
|
65206
|
-
const { resetProcessingToQueued } = await import("./merge-sync-
|
|
66580
|
+
const { resetProcessingToQueued } = await import("./merge-sync-Ca7F5JnQ.js");
|
|
65207
66581
|
const resetCount = resetProcessingToQueued();
|
|
65208
66582
|
if (resetCount > 0) {
|
|
65209
66583
|
console.log(`[overdeck] Reset ${resetCount} stuck merge queue entries to queued`);
|
|
@@ -65225,7 +66599,7 @@ else {
|
|
|
65225
66599
|
console.log("[overdeck] Auto-merge executor started");
|
|
65226
66600
|
}
|
|
65227
66601
|
try {
|
|
65228
|
-
const { reconcileInterruptedVerifications } = await import("./verification-runner-
|
|
66602
|
+
const { reconcileInterruptedVerifications } = await import("./verification-runner-DlZI8yhw.js");
|
|
65229
66603
|
const interrupted = reconcileInterruptedVerifications();
|
|
65230
66604
|
if (interrupted > 0) console.log(`[overdeck] recovered ${interrupted} orphaned verification worker(s)`);
|
|
65231
66605
|
} catch (err) {
|