@overdeck/core 0.49.0 → 0.49.1

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.
Files changed (60) hide show
  1. package/dist/{build-info-Ck2TzOSQ.js → build-info-Bts-0E0B.js} +3 -3
  2. package/dist/{build-info-Ck2TzOSQ.js.map → build-info-Bts-0E0B.js.map} +1 -1
  3. package/dist/build-info-CD0O1MvT.js +2 -0
  4. package/dist/cli/index.js +4 -4
  5. package/dist/dashboard/{build-info-DXfOjbg3.js → build-info-DTX8JwVP.js} +3 -3
  6. package/dist/dashboard/{build-info-DXfOjbg3.js.map → build-info-DTX8JwVP.js.map} +1 -1
  7. package/dist/dashboard/build-info-PQlh_Rhb.js +2 -0
  8. package/dist/dashboard/{deacon-CeqVPw0o.js → deacon-BEH-IY0v.js} +2 -2
  9. package/dist/dashboard/{deacon-CQxv6Qwv.js → deacon-TPYssFYt.js} +8 -8
  10. package/dist/dashboard/{deacon-CQxv6Qwv.js.map → deacon-TPYssFYt.js.map} +1 -1
  11. package/dist/dashboard/{deacon-merge-ugZ7jekt.js → deacon-merge-BOGFEV8_.js} +5 -5
  12. package/dist/dashboard/{deacon-merge-ugZ7jekt.js.map → deacon-merge-BOGFEV8_.js.map} +1 -1
  13. package/dist/dashboard/{deacon-pending-lifecycle-Cxu6Rezs.js → deacon-pending-lifecycle-DVHjOLje.js} +2 -2
  14. package/dist/dashboard/{deacon-pending-lifecycle-Cxu6Rezs.js.map → deacon-pending-lifecycle-DVHjOLje.js.map} +1 -1
  15. package/dist/dashboard/deacon.js +2 -2
  16. package/dist/dashboard/{deploy-patrol-DxnpZcnl.js → deploy-patrol-BXjlvoV3.js} +2 -2
  17. package/dist/dashboard/{deploy-patrol-DxnpZcnl.js.map → deploy-patrol-BXjlvoV3.js.map} +1 -1
  18. package/dist/dashboard/{identity-BnxKo9-z.js → identity-Bwh6VGeL.js} +2 -2
  19. package/dist/dashboard/{identity-BnxKo9-z.js.map → identity-Bwh6VGeL.js.map} +1 -1
  20. package/dist/dashboard/{lifecycle-ozA4GZNs.js → lifecycle-B0rL38D3.js} +2 -2
  21. package/dist/dashboard/{lifecycle-ozA4GZNs.js.map → lifecycle-B0rL38D3.js.map} +1 -1
  22. package/dist/dashboard/{memory-governor-W8994ASc.js → memory-governor-A4O6vI9d.js} +3 -3
  23. package/dist/dashboard/{memory-governor-W8994ASc.js.map → memory-governor-A4O6vI9d.js.map} +1 -1
  24. package/dist/dashboard/{memory-pressure-patrol-D_T_QLFC.js → memory-pressure-patrol-BWlWywmA.js} +2 -2
  25. package/dist/dashboard/{memory-pressure-patrol-D_T_QLFC.js.map → memory-pressure-patrol-BWlWywmA.js.map} +1 -1
  26. package/dist/dashboard/{merge-agent-B8YsWRDu.js → merge-agent-BRSz26Oh.js} +1 -1
  27. package/dist/dashboard/{merge-agent-DxecsTre.js → merge-agent-GWhmnxFk.js} +2 -2
  28. package/dist/dashboard/{merge-agent-DxecsTre.js.map → merge-agent-GWhmnxFk.js.map} +1 -1
  29. package/dist/dashboard/merge-ops-DtHx17Vd.js +2 -0
  30. package/dist/dashboard/{post-merge-lifecycle-worker-DC-i1kqz.js → post-merge-lifecycle-worker-KK1RTKRE.js} +2 -2
  31. package/dist/dashboard/{post-merge-lifecycle-worker-DC-i1kqz.js.map → post-merge-lifecycle-worker-KK1RTKRE.js.map} +1 -1
  32. package/dist/dashboard/{resolver-BdHzKhNL.js → resolver-C8rooxoz.js} +2 -2
  33. package/dist/dashboard/{resolver-BdHzKhNL.js.map → resolver-C8rooxoz.js.map} +1 -1
  34. package/dist/dashboard/server.js +28 -28
  35. package/dist/dashboard/{service-0hbSVeHz.js → service-BLb_CyPL.js} +6 -6
  36. package/dist/dashboard/{service-0hbSVeHz.js.map → service-BLb_CyPL.js.map} +1 -1
  37. package/dist/dashboard/{specialists-C2ZVszIW.js → specialists-DocAK-7A.js} +5 -5
  38. package/dist/dashboard/{specialists-C2ZVszIW.js.map → specialists-DocAK-7A.js.map} +1 -1
  39. package/dist/dashboard/{specialists-DhLEuxVX.js → specialists-xXcJHAyg.js} +1 -1
  40. package/dist/dashboard/{stall-sweeper-o4-q0vqY.js → stall-sweeper-DOyIfeLR.js} +2 -2
  41. package/dist/dashboard/{stall-sweeper-o4-q0vqY.js.map → stall-sweeper-DOyIfeLR.js.map} +1 -1
  42. package/dist/dashboard/{uat-train-fK0FbCx7.js → uat-train-COSy-vEX.js} +1 -1
  43. package/dist/dashboard/{uat-train-CSOval9z.js → uat-train-DVUNW03P.js} +0 -0
  44. package/dist/dashboard/{uat-train-CSOval9z.js.map → uat-train-DVUNW03P.js.map} +1 -1
  45. package/dist/dashboard/{workflows-BnNc1QlT.js → workflows-BYwR2aIN.js} +2 -2
  46. package/dist/dashboard/{workflows-BnNc1QlT.js.map → workflows-BYwR2aIN.js.map} +1 -1
  47. package/dist/dashboard/workflows-Cf4LAnhg.js +2 -0
  48. package/dist/dashboard/{workspaces-CqeaoIK6.js → workspaces-BlpbOPZ7.js} +11 -11
  49. package/dist/dashboard/{workspaces-CqeaoIK6.js.map → workspaces-BlpbOPZ7.js.map} +1 -1
  50. package/dist/{lifecycle-Bhu9mEsV.js → lifecycle-BhAciIXh.js} +1 -1
  51. package/dist/{lifecycle-CMRdm3mR.js → lifecycle-D8m3w850.js} +2 -2
  52. package/dist/{lifecycle-CMRdm3mR.js.map → lifecycle-D8m3w850.js.map} +1 -1
  53. package/dist/{merge-agent-DQ7DOXE2.js → merge-agent-CUnIrr8R.js} +2 -2
  54. package/dist/{merge-agent-DQ7DOXE2.js.map → merge-agent-CUnIrr8R.js.map} +1 -1
  55. package/dist/{merge-agent-D33x_y_T.js → merge-agent-DwfVId_E.js} +1 -1
  56. package/package.json +1 -1
  57. package/dist/build-info-B9bbKbXz.js +0 -2
  58. package/dist/dashboard/build-info-CrBYH-L2.js +0 -2
  59. package/dist/dashboard/merge-ops-C9wpFz1G.js +0 -2
  60. package/dist/dashboard/workflows-C6MkcBR_.js +0 -2
@@ -0,0 +1,2 @@
1
+ import { c as triggerMerge } from "./workspaces-BlpbOPZ7.js";
2
+ export { triggerMerge };
@@ -15,7 +15,7 @@ async function drainQueue() {
15
15
  continue;
16
16
  }
17
17
  try {
18
- const { postMergeLifecycle } = await import("./merge-agent-B8YsWRDu.js");
18
+ const { postMergeLifecycle } = await import("./merge-agent-BRSz26Oh.js");
19
19
  await postMergeLifecycle(entry.issueId, entry.projectPath, entry.sourceBranch, { skipDeploy: true });
20
20
  console.log(`[deacon] Completed pending post-merge lifecycle for ${entry.issueId}`);
21
21
  } catch (error) {
@@ -47,4 +47,4 @@ function enqueuePostMergeLifecycle(issueId, projectPath, sourceBranch) {
47
47
  //#endregion
48
48
  export { enqueuePostMergeLifecycle };
49
49
 
50
- //# sourceMappingURL=post-merge-lifecycle-worker-DC-i1kqz.js.map
50
+ //# sourceMappingURL=post-merge-lifecycle-worker-KK1RTKRE.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"post-merge-lifecycle-worker-DC-i1kqz.js","names":[],"sources":["../../src/lib/cloister/post-merge-lifecycle-worker.ts"],"sourcesContent":["import { resolveCanonicalReviewStatus } from './review-status-source.js';\n\ninterface LifecycleEntry {\n issueId: string;\n projectPath: string;\n sourceBranch: string;\n running: boolean;\n}\n\nconst queue = new Map<string, LifecycleEntry>();\nlet workerPromise: Promise<void> | null = null;\n\nfunction nextEntry(): LifecycleEntry | null {\n return [...queue.values()].find((entry) => !entry.running) ?? null;\n}\n\nasync function drainQueue(): Promise<void> {\n for (let entry = nextEntry(); entry; entry = nextEntry()) {\n entry.running = true;\n const status = resolveCanonicalReviewStatus(entry.issueId);\n if (!status.available || status.status?.mergeStatus !== 'merged'\n || status.status.mergeStep !== 'post-merge-cleanup') {\n queue.delete(entry.issueId);\n continue;\n }\n try {\n const { postMergeLifecycle } = await import('./merge-agent.js');\n await postMergeLifecycle(entry.issueId, entry.projectPath, entry.sourceBranch, { skipDeploy: true });\n console.log(`[deacon] Completed pending post-merge lifecycle for ${entry.issueId}`);\n } catch (error) {\n console.warn(`[deacon] Pending post-merge lifecycle retry failed for ${entry.issueId}: ${error}`);\n } finally {\n queue.delete(entry.issueId);\n }\n }\n}\n\nfunction startWorker(): void {\n if (workerPromise || !nextEntry()) return;\n workerPromise = drainQueue().finally(() => {\n workerPromise = null;\n if (nextEntry()) startWorker();\n });\n}\n\nexport function enqueuePostMergeLifecycle(\n issueId: string,\n projectPath: string,\n sourceBranch: string,\n): string | null {\n const normalizedIssueId = issueId.trim().toUpperCase();\n if (!normalizedIssueId || queue.has(normalizedIssueId)) return null;\n queue.set(normalizedIssueId, {\n issueId: normalizedIssueId,\n projectPath,\n sourceBranch,\n running: false,\n });\n startWorker();\n return `Queued pending post-merge lifecycle for ${normalizedIssueId}`;\n}\n\nexport async function waitForPostMergeLifecycleIdleForTests(): Promise<void> {\n while (workerPromise) await workerPromise;\n}\n\nexport async function resetPostMergeLifecycleWorkerForTests(): Promise<void> {\n await waitForPostMergeLifecycleIdleForTests();\n queue.clear();\n}\n"],"mappings":";;2BAAyE;AASzE,MAAM,wBAAQ,IAAI,KAA6B;AAC/C,IAAI,gBAAsC;AAE1C,SAAS,YAAmC;AAC1C,QAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,QAAQ,IAAI;;AAGhE,eAAe,aAA4B;AACzC,MAAK,IAAI,QAAQ,WAAW,EAAE,OAAO,QAAQ,WAAW,EAAE;AACxD,QAAM,UAAU;EAChB,MAAM,SAAS,6BAA6B,MAAM,QAAQ;AAC1D,MAAI,CAAC,OAAO,aAAa,OAAO,QAAQ,gBAAgB,YACnD,OAAO,OAAO,cAAc,sBAAsB;AACrD,SAAM,OAAO,MAAM,QAAQ;AAC3B;;AAEF,MAAI;GACF,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAC5C,SAAM,mBAAmB,MAAM,SAAS,MAAM,aAAa,MAAM,cAAc,EAAE,YAAY,MAAM,CAAC;AACpG,WAAQ,IAAI,uDAAuD,MAAM,UAAU;WAC5E,OAAO;AACd,WAAQ,KAAK,0DAA0D,MAAM,QAAQ,IAAI,QAAQ;YACzF;AACR,SAAM,OAAO,MAAM,QAAQ;;;;AAKjC,SAAS,cAAoB;AAC3B,KAAI,iBAAiB,CAAC,WAAW,CAAE;AACnC,iBAAgB,YAAY,CAAC,cAAc;AACzC,kBAAgB;AAChB,MAAI,WAAW,CAAE,cAAa;GAC9B;;AAGJ,SAAgB,0BACd,SACA,aACA,cACe;CACf,MAAM,oBAAoB,QAAQ,MAAM,CAAC,aAAa;AACtD,KAAI,CAAC,qBAAqB,MAAM,IAAI,kBAAkB,CAAE,QAAO;AAC/D,OAAM,IAAI,mBAAmB;EAC3B,SAAS;EACT;EACA;EACA,SAAS;EACV,CAAC;AACF,cAAa;AACb,QAAO,2CAA2C"}
1
+ {"version":3,"file":"post-merge-lifecycle-worker-KK1RTKRE.js","names":[],"sources":["../../src/lib/cloister/post-merge-lifecycle-worker.ts"],"sourcesContent":["import { resolveCanonicalReviewStatus } from './review-status-source.js';\n\ninterface LifecycleEntry {\n issueId: string;\n projectPath: string;\n sourceBranch: string;\n running: boolean;\n}\n\nconst queue = new Map<string, LifecycleEntry>();\nlet workerPromise: Promise<void> | null = null;\n\nfunction nextEntry(): LifecycleEntry | null {\n return [...queue.values()].find((entry) => !entry.running) ?? null;\n}\n\nasync function drainQueue(): Promise<void> {\n for (let entry = nextEntry(); entry; entry = nextEntry()) {\n entry.running = true;\n const status = resolveCanonicalReviewStatus(entry.issueId);\n if (!status.available || status.status?.mergeStatus !== 'merged'\n || status.status.mergeStep !== 'post-merge-cleanup') {\n queue.delete(entry.issueId);\n continue;\n }\n try {\n const { postMergeLifecycle } = await import('./merge-agent.js');\n await postMergeLifecycle(entry.issueId, entry.projectPath, entry.sourceBranch, { skipDeploy: true });\n console.log(`[deacon] Completed pending post-merge lifecycle for ${entry.issueId}`);\n } catch (error) {\n console.warn(`[deacon] Pending post-merge lifecycle retry failed for ${entry.issueId}: ${error}`);\n } finally {\n queue.delete(entry.issueId);\n }\n }\n}\n\nfunction startWorker(): void {\n if (workerPromise || !nextEntry()) return;\n workerPromise = drainQueue().finally(() => {\n workerPromise = null;\n if (nextEntry()) startWorker();\n });\n}\n\nexport function enqueuePostMergeLifecycle(\n issueId: string,\n projectPath: string,\n sourceBranch: string,\n): string | null {\n const normalizedIssueId = issueId.trim().toUpperCase();\n if (!normalizedIssueId || queue.has(normalizedIssueId)) return null;\n queue.set(normalizedIssueId, {\n issueId: normalizedIssueId,\n projectPath,\n sourceBranch,\n running: false,\n });\n startWorker();\n return `Queued pending post-merge lifecycle for ${normalizedIssueId}`;\n}\n\nexport async function waitForPostMergeLifecycleIdleForTests(): Promise<void> {\n while (workerPromise) await workerPromise;\n}\n\nexport async function resetPostMergeLifecycleWorkerForTests(): Promise<void> {\n await waitForPostMergeLifecycleIdleForTests();\n queue.clear();\n}\n"],"mappings":";;2BAAyE;AASzE,MAAM,wBAAQ,IAAI,KAA6B;AAC/C,IAAI,gBAAsC;AAE1C,SAAS,YAAmC;AAC1C,QAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,QAAQ,IAAI;;AAGhE,eAAe,aAA4B;AACzC,MAAK,IAAI,QAAQ,WAAW,EAAE,OAAO,QAAQ,WAAW,EAAE;AACxD,QAAM,UAAU;EAChB,MAAM,SAAS,6BAA6B,MAAM,QAAQ;AAC1D,MAAI,CAAC,OAAO,aAAa,OAAO,QAAQ,gBAAgB,YACnD,OAAO,OAAO,cAAc,sBAAsB;AACrD,SAAM,OAAO,MAAM,QAAQ;AAC3B;;AAEF,MAAI;GACF,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAC5C,SAAM,mBAAmB,MAAM,SAAS,MAAM,aAAa,MAAM,cAAc,EAAE,YAAY,MAAM,CAAC;AACpG,WAAQ,IAAI,uDAAuD,MAAM,UAAU;WAC5E,OAAO;AACd,WAAQ,KAAK,0DAA0D,MAAM,QAAQ,IAAI,QAAQ;YACzF;AACR,SAAM,OAAO,MAAM,QAAQ;;;;AAKjC,SAAS,cAAoB;AAC3B,KAAI,iBAAiB,CAAC,WAAW,CAAE;AACnC,iBAAgB,YAAY,CAAC,cAAc;AACzC,kBAAgB;AAChB,MAAI,WAAW,CAAE,cAAa;GAC9B;;AAGJ,SAAgB,0BACd,SACA,aACA,cACe;CACf,MAAM,oBAAoB,QAAQ,MAAM,CAAC,aAAa;AACtD,KAAI,CAAC,qBAAqB,MAAM,IAAI,kBAAkB,CAAE,QAAO;AAC/D,OAAM,IAAI,mBAAmB;EAC3B,SAAS;EACT;EACA;EACA,SAAS;EACV,CAAC;AACF,cAAa;AACb,QAAO,2CAA2C"}
@@ -3,7 +3,7 @@ import { cn as listAgentStates, sn as init_queries, un as listRunningAgentsSync
3
3
  import { h as loadReviewStatuses, p as init_review_status } from "./review-status-DBnR5t4z.js";
4
4
  import { i as shouldSkipReviewStatus } from "./stuck-remediation-Di5JYkoo.js";
5
5
  import { n as init_issue_closed, r as isIssueClosed } from "./issue-closed-dvEWKO7Q.js";
6
- import "./deacon-merge-ugZ7jekt.js";
6
+ import "./deacon-merge-BOGFEV8_.js";
7
7
  import { existsSync } from "fs";
8
8
  import { join } from "path";
9
9
  //#region ../../lib/parked/resolver.ts
@@ -362,4 +362,4 @@ function summarizeParked(rows) {
362
362
  //#endregion
363
363
  export { resolveParkedPopulation as n, summarizeParked as r, PARKED_ORBIT_SEVERITY as t };
364
364
 
365
- //# sourceMappingURL=resolver-BdHzKhNL.js.map
365
+ //# sourceMappingURL=resolver-C8rooxoz.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolver-BdHzKhNL.js","names":[],"sources":["../../src/lib/parked/resolver.ts"],"sourcesContent":["/**\n * Single authoritative parked-population resolver (PAN-3485, epic phase 1).\n *\n * A \"parked orbit\" is any state an issue can sit in where no autonomous actor\n * will advance it within 24h without operator or flywheel intervention. Over\n * months of incident response, each failure mode grew its own safety valve —\n * stuck flags, needs-you trips, deacon-ignore, resume gates, UAT gates, merge\n * retry caps, and circuit breakers — and every one of them converts autonomous\n * motion into operator work. Nine of those valves exist today, in six subsystems,\n * and no surface could answer \"what is stalled, why, and what would release it.\"\n * This resolver is that answer: ONE read door that unions all nine orbits into\n * typed rows, so the CLI, the API, the dashboard, and the stall sweeper all agree\n * by construction.\n *\n * Modeled on `resolvePipelineMembership()` (src/lib/pipeline-membership.ts):\n * a pure classifier over gathered signals, with the gathering done here through\n * existing read doors only (review-status door, agents table, tmux liveness,\n * the per-issue record door for recovery trips). No surface may re-derive\n * parking independently.\n *\n * The nine orbits (see docs/PARKED-POPULATION.md):\n *\n * 1. stuck-flag review_status.stuck = 1 (any stuck_reason)\n * 2. needs-you an open recovery trip in the permanent record\n * 3. deacon-ignored review_status.deaconIgnored = true\n * 4. operator-gate paused (operator, not yield) / troubled / stoppedByUser\n * 5. uat-failed uatStatus failed with merge still pending\n * 6. merge-failed mergeStatus failed (retries saturated or abandoned)\n * 7. zombie-session live agent whose issue is merged/closed\n * 8. idle-running live agent, no pipeline owner, idle beyond threshold\n * 9. circuit-breaker autoRequeueCount >= 25 (dead-end recovery exhausted)\n */\n\nimport { loadReviewStatuses, type ReviewStatus } from '../review-status.js';\nimport { listAgentStates, listRunningAgentsSync } from '../agents/queries.js';\nimport type { AgentState } from '../agents.js';\nimport { FAILED_MERGE_MAX_RETRIES } from '../cloister/deacon-merge.js';\nimport { shouldSkipReviewStatus } from '../cloister/stuck-remediation.js';\nimport { isIssueClosed } from '../cloister/issue-closed.js';\nimport { readIssueRecord } from '../pan-dir/record.js';\nimport { getProjectSync, resolveProjectFromIssueSync } from '../projects.js';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\n\nexport const PARKED_ORBITS = [\n 'stuck-flag',\n 'needs-you',\n 'deacon-ignored',\n 'operator-gate',\n 'uat-failed',\n 'merge-failed',\n 'zombie-session',\n 'idle-running',\n 'circuit-breaker',\n] as const;\n\nexport type ParkedOrbit = (typeof PARKED_ORBITS)[number];\n\n/**\n * Severity order — recommendations surface these orbits in this order, with\n * operator-gated rows last so a full report ends by surfacing what only a human\n * can release. The God View tints an orb\n * by its most severe orbit.\n */\nexport const PARKED_ORBIT_SEVERITY: readonly ParkedOrbit[] = [\n 'zombie-session',\n 'merge-failed',\n 'uat-failed',\n 'stuck-flag',\n 'circuit-breaker',\n 'idle-running',\n 'needs-you',\n 'deacon-ignored',\n 'operator-gate',\n];\n\nexport interface ParkedRow {\n issueId: string;\n orbit: ParkedOrbit;\n /** ISO timestamp the issue entered this orbit (best available evidence). */\n parkedAt: string;\n /** Operator-facing sentence: why the issue is parked. */\n parkReason: string;\n /** Operator-facing sentence: what would release it. */\n unparkCondition: string;\n /** Orbit-specific evidence (stuck reason, gate kind, idle minutes, …). */\n details?: Record<string, unknown>;\n}\n\n/** A human sentence per stuck_reason — the stuck flag carries the machine code, the resolver owns the copy.\n * GUARD-EXIT INVARIANT (PAN-3488): every stuck_reason written anywhere in src/ MUST have an entry\n * here — scripts/guard-park-exits.sh fails the lint on an undocumented flavor. */\nconst STUCK_REASON_COPY: Record<string, { park: string; unpark: string }> = {\n feedback_delivery_needs_you: {\n park: 'review/test feedback could not be delivered — the work agent is not running and nothing resumed it',\n unpark: 'resume the work agent with its pending feedback through the established work-resume door',\n },\n review_infrastructure_failure: {\n park: 'the review pipeline failed repeatedly for infrastructure reasons, not verdict reasons',\n unpark: 're-dispatch a fresh review through the review door once the infra cause is resolved',\n },\n review_parent_stalled_needs_you: {\n park: 'the review parent exceeded its deadline with no terminal verdict in the row or verdict artifact',\n unpark: 'inspect the parent pane and review artifacts, then pan unstick <id> and pan review restart <id> if a fresh review is required',\n },\n verification_stuck: {\n park: 'verification exhausted its cycles without passing',\n unpark: 're-drive the verification feedback to a resumed work agent',\n },\n 'dead-end-rebuild': {\n park: 'dead-end recovery exhausted 25 requeues',\n unpark: 'operator decision — decompose or pan unstick after the root cause is fixed',\n },\n main_diverged: {\n park: 'the PR branch diverged from main and cannot merge cleanly',\n unpark: 'sync-main and resolve conflicts, then re-drive through the normal pipeline',\n },\n model_divergence: {\n park: 'the agent hit a model/API divergence error and was parked for investigation',\n unpark: 'investigate the model error (pane + transcript), then pan unstick and resume',\n },\n usage_limit: {\n park: 'the agent hit a provider usage limit and stopped mid-flight',\n unpark: 'wait for the provider window to reset, then pan unstick and resume',\n },\n context_overflow: {\n park: 'the agent overflowed its context window and cannot continue in this session',\n unpark: 'pan unstick after compaction/fork — resume with a fresh session',\n },\n review_convoy_unrecoverable: {\n park: 'the review convoy died and could not be recovered in place',\n unpark: 're-dispatch a fresh review convoy through the review door after the root cause is resolved',\n },\n test_signal_strand: {\n park: 'a test verdict was written but never delivered to the pipeline',\n unpark: 're-drive the stranded verdict to a resumed work agent',\n },\n 'review-not-converging': {\n park: 'review cycles stopped converging (stall or reversal across ≥3 cycles) — rework is suppressed',\n unpark: 'decompose into sibling issues, or pan unstick to clear the gate and attempt rework',\n },\n state_derived_verification_hold: {\n park: 'verification is held by a derived-state rule (the recorded state forbids advancing)',\n unpark: 'fix the underlying state mismatch, then pan unstick to release the hold',\n },\n};\n\n/** Idle threshold for the idle-running orbit: below this a live idle agent is warm, not parked. */\nexport const IDLE_RUNNING_THRESHOLD_MS = 6 * 60 * 60_000;\n\n/**\n * Roles the idle-running orbit must NEVER touch: orchestrators and\n * conversations. Their real activity lives in the conversation/runtime plane,\n * not the agents-table lastActivity this orbit reads — the sweeper's first\n * night proved the trap when its idle nudge→stop killed the FLYWHEEL (its\n * agents-table stamp was a day stale while it ticked normally), halting all\n * new dispatch for 90 minutes. A \"stopped orchestrator\" is not a freed slot;\n * it is the pipeline going silent.\n */\nexport const IDLE_EXEMPT_ROLES: ReadonlySet<string> = new Set(['flywheel', 'sequencer', 'conversation', 'knowledge']);\n\n/** Per-issue gathered signals — the classifier's entire input. Gathered through read doors, never stores. */\nexport interface ParkedSignals {\n issueId: string;\n reviewStatus: ReviewStatus | null;\n /** All agents (any status) carrying this issue id. */\n agents: AgentState[];\n /** Live (running + tmux-active) agents for this issue. */\n liveAgents: (AgentState & { tmuxActive: boolean })[];\n /** Open recovery trips from the permanent record (needs-you orbit). */\n openRecoveryTrips: { recoveryPath: string; needsYouEmittedAt?: string }[];\n /** Tracker-closed (only resolved for live-agent candidates; null = unknown/not checked). */\n issueClosed: boolean | null;\n now: number;\n}\n\nfunction isoOr(ts: string | number | null | undefined, fallback: number): string {\n if (typeof ts === 'number' && Number.isFinite(ts)) return new Date(ts).toISOString();\n if (typeof ts === 'string' && ts) {\n const parsed = Date.parse(ts);\n if (Number.isFinite(parsed)) return new Date(parsed).toISOString();\n }\n return new Date(fallback).toISOString();\n}\n\n/**\n * `pan done` marks the work agent stoppedByUser as an auto-resume suppressor\n * (done.ts:439/:869 — finished, don't idle-revive; the PAN-2668 completed-\n * handoff exception is the sanctioned rework path). That is a NORMAL lifecycle\n * completion, not an operator park — reporting it as an operator gate makes\n * the sweeper escalate false gates every TTL (observed on PAN-3512 at\n * 00:02:26Z, self-cleared 80s later by the rework resume). A completed\n * handoff marker means finished, not parked.\n */\nexport function hasCompletedHandoffMarker(agentId: string): boolean {\n const dir = join(getOverdeckHome(), 'agents', agentId);\n return existsSync(join(dir, 'completed')) || existsSync(join(dir, 'completed.processed'));\n}\n\n/**\n * Agent rows occasionally carry a bare numeric issue id (\"2156\") where every\n * other surface keys \"PAN-2156\" — without normalization the issue loses its\n * review-status row and trip enrichment. Uppercase always; for bare numerics\n * that fail project resolution, retry with the PAN- prefix.\n */\nexport function normalizeParkedIssueId(raw: string): string {\n const upper = raw.trim().toUpperCase();\n if (!/^\\d+$/.test(upper)) return upper;\n if (resolveProjectFromIssueSync(upper)) return upper;\n return `PAN-${upper}`;\n}\n\nfunction stuckCopy(reason: string | undefined): { park: string; unpark: string } {\n if (reason && STUCK_REASON_COPY[reason]) return STUCK_REASON_COPY[reason];\n return {\n park: `stuck flag set${reason ? ` (${reason})` : ''} — nothing autonomous will advance this issue`,\n unpark: 'pan unstick after the underlying cause is fixed',\n };\n}\n\n/**\n * Classify one issue's parked orbits from gathered signals. Pure — unit-tested\n * with fixtures. Emits at most one row per orbit; an issue may legitimately\n * occupy several orbits at once (e.g. a stuck flag AND a dead operator-stopped\n * agent). idle-running is only emitted when no other orbit already explains\n * the stall — it is the orbit of last resort (\"live but leaderless\").\n */\nexport function classifyParked(s: ParkedSignals): ParkedRow[] {\n const rows: ParkedRow[] = [];\n const r = s.reviewStatus;\n const issueId = s.issueId;\n const push = (orbit: ParkedOrbit, parkedAt: string, parkReason: string, unparkCondition: string, details?: Record<string, unknown>) => {\n rows.push({ issueId, orbit, parkedAt, parkReason, unparkCondition, ...(details ? { details } : {}) });\n };\n\n // Terminal issues are never parked — they are residue. A closed issue can\n // only produce zombie-session rows (a live agent to reap); every other orbit\n // is moot once the issue is done. issueClosed === null means \"unknown\" — the\n // gather resolves it for row-producing issues and re-classifies (pass 2).\n const closed = s.issueClosed === true;\n\n // 1. stuck-flag\n if (!closed && r?.stuck) {\n const copy = stuckCopy(r.stuckReason);\n push('stuck-flag', isoOr(r.stuckAt ?? r.updatedAt, s.now), copy.park, copy.unpark, { stuckReason: r.stuckReason ?? null });\n }\n\n // 2. needs-you (open recovery trips from the permanent record)\n if (!closed) for (const trip of s.openRecoveryTrips) {\n push(\n 'needs-you',\n isoOr(trip.needsYouEmittedAt, s.now),\n `a durable needs-you escalation fired (${trip.recoveryPath}) and went silent — the operator never answered`,\n 'answer the escalation (pan answer / dashboard needs-you), or let the sweeper re-surface it on its TTL',\n { recoveryPath: trip.recoveryPath },\n );\n }\n\n // 3. deacon-ignored\n if (!closed && r?.deaconIgnored) {\n push(\n 'deacon-ignored',\n isoOr(r.deaconIgnoredAt ?? r.updatedAt, s.now),\n `deacon is ignoring this issue${r.deaconIgnoredReason ? ` — ${r.deaconIgnoredReason}` : ''}`,\n 'clear the ignore flag once the reason it was set is resolved',\n { reason: r.deaconIgnoredReason ?? null },\n );\n }\n\n // 4. operator-gate — operator-set resume gates on this issue's agents,\n // grouped one row per gate kind (an issue with three stopped agents has\n // ONE operator-stop park, not three). A scheduler YIELD reuses the paused\n // flag but is self-clearing (the preemptive scheduler resumes yielded\n // agents oldest-first) — NOT a park.\n if (!closed) {\n const gateRows = new Map<'paused' | 'troubled' | 'stopped-by-user', { parkedAt: string; agentIds: string[]; reason: string; unpark: string }>();\n for (const agent of s.agents) {\n if (agent.paused === true && agent.yieldedByScheduler !== true) {\n const row = gateRows.get('paused') ?? { parkedAt: isoOr(agent.pausedAt, s.now), agentIds: [], reason: '', unpark: '' };\n row.agentIds.push(agent.id);\n const at = isoOr(agent.pausedAt, s.now);\n if (at < row.parkedAt) row.parkedAt = at;\n if (agent.pausedReason && !row.reason) row.reason = agent.pausedReason;\n gateRows.set('paused', row);\n } else if (agent.troubled === true) {\n const row = gateRows.get('troubled') ?? { parkedAt: isoOr(agent.troubledAt, s.now), agentIds: [], reason: '', unpark: '' };\n row.agentIds.push(agent.id);\n const at = isoOr(agent.troubledAt, s.now);\n if (at < row.parkedAt) row.parkedAt = at;\n gateRows.set('troubled', row);\n } else if (agent.stoppedByUser === true && agent.status !== 'running' && !hasCompletedHandoffMarker(agent.id)) {\n const row = gateRows.get('stopped-by-user') ?? { parkedAt: isoOr(agent.stoppedAt, s.now), agentIds: [], reason: '', unpark: '' };\n row.agentIds.push(agent.id);\n const at = isoOr(agent.stoppedAt, s.now);\n if (at < row.parkedAt) row.parkedAt = at;\n gateRows.set('stopped-by-user', row);\n }\n }\n for (const [gate, row] of gateRows) {\n const names = row.agentIds.join(', ');\n if (gate === 'paused') {\n push('operator-gate', row.parkedAt, `${names} manually paused${row.reason ? ` — ${row.reason}` : ''}`, 'pan unpause <id> (operator-only; the sweeper re-surfaces on TTL, never overrides)', { gate, agentIds: row.agentIds });\n } else if (gate === 'troubled') {\n push('operator-gate', row.parkedAt, `${names} marked troubled after repeated resume/crash failures`, 'pan untroubled <id> after the crash cause is investigated', { gate, agentIds: row.agentIds });\n } else {\n push('operator-gate', row.parkedAt, `${names} explicitly stopped by the operator with no completed handoff to re-drive`, 'pan start <id> (operator-only; explicit start clears the stop gate)', { gate, agentIds: row.agentIds });\n }\n }\n }\n\n // 5. uat-failed — the feedback relay already owns rework while work is live.\n const hasLiveWorkAgent = s.liveAgents.some((agent) => agent.role === 'work');\n if (!closed && r?.uatStatus === 'failed' && r.mergeStatus !== 'merged' && !r.readyForMerge && !hasLiveWorkAgent) {\n push(\n 'uat-failed',\n isoOr(r.updatedAt, s.now),\n 'UAT failed and no work agent is live to rework it — the merge gate will not take the issue and the UAT-failure relay found no delivery target',\n 'pan start <id> to put a work agent on the UAT feedback; the relay redelivers on the next failed verdict',\n { uatNotes: r.uatNotes ?? null },\n );\n }\n\n // 6. merge-failed — a failed merge that nothing is retrying\n if (!closed && r?.mergeStatus === 'failed') {\n const retries = r.mergeRetryCount ?? 0;\n push(\n 'merge-failed',\n isoOr(r.updatedAt, s.now),\n retries >= FAILED_MERGE_MAX_RETRIES\n ? `merge failed and its ${FAILED_MERGE_MAX_RETRIES} automatic retries are exhausted`\n : 'merge failed and no retry is in flight',\n 'one fresh merge attempt once main CI is green and the branch is conflict-free (sweeper tries once per scan window)',\n { mergeRetryCount: retries, mergeNotes: r.mergeNotes ?? null },\n );\n }\n\n // 7. zombie-session — live agent whose issue is already merged/closed\n for (const agent of s.liveAgents) {\n const merged = r?.mergeStatus === 'merged' || s.issueClosed === true;\n if (!merged) continue;\n push(\n 'zombie-session',\n isoOr(agent.lastActivity ?? agent.startedAt, s.now),\n `${agent.id} is still running but the issue is ${r?.mergeStatus === 'merged' ? 'merged' : 'closed'} — it holds a session and a concurrency slot for nothing`,\n 'reap the session through the established merged-zombie teardown door',\n { agentId: agent.id, mergeStatus: r?.mergeStatus ?? null },\n );\n }\n\n // 9. circuit-breaker — dead-end recovery exhausted\n const requeues = r?.autoRequeueCount ?? 0;\n if (!closed && requeues >= 25) {\n push(\n 'circuit-breaker',\n isoOr(r?.updatedAt, s.now),\n `dead-end recovery used all ${requeues}/25 requeues — the circuit breaker is permanently open`,\n 'operator decision — decompose the change or pan unstick after the root cause is fixed',\n { autoRequeueCount: requeues },\n );\n }\n\n // 8. idle-running — live agent, no pipeline owner, idle beyond threshold, and\n // no other orbit already explains the stall (orbit of last resort).\n if (!closed && rows.length === 0) {\n for (const agent of s.liveAgents) {\n // Orchestrators and conversations are exempt (IDLE_EXEMPT_ROLES): their\n // activity does not live in the stamp this orbit reads, and stopping one\n // silences the pipeline instead of freeing a slot.\n if (IDLE_EXEMPT_ROLES.has(String(agent.role ?? ''))) continue;\n const lastMs = Date.parse(agent.lastActivity ?? agent.startedAt ?? '');\n if (!Number.isFinite(lastMs)) continue;\n const idleMs = s.now - lastMs;\n if (idleMs < IDLE_RUNNING_THRESHOLD_MS) continue;\n // Warm-idle on a pipeline-owned issue is the intended state (PAN-2579):\n // review/test/merge owns the next move, the agent is SUPPOSED to wait.\n if (shouldSkipReviewStatus(r)) continue;\n push(\n 'idle-running',\n new Date(lastMs).toISOString(),\n `${agent.id} is alive but has done nothing for ${Math.floor(idleMs / 60_000)} minutes and no pipeline stage owns the next move`,\n 'poke for progress; if none, stop or resume with a nudge through the established agent-control door',\n { agentId: agent.id, idleMinutes: Math.floor(idleMs / 60_000) },\n );\n }\n }\n\n return rows;\n}\n\n/** Options for the gather pass — injectable for tests. */\nexport interface ResolveParkedOptions {\n now?: number;\n /** Per-issue open recovery trips (defaults to the record door). */\n readOpenTrips?: (issueId: string) => Promise<{ recoveryPath: string; needsYouEmittedAt?: string }[]>;\n /** Tracker-closed check (defaults to isIssueClosed). Only called for live-agent candidates. */\n isClosed?: (issueId: string) => Promise<boolean>;\n}\n\nasync function defaultReadOpenTrips(issueId: string): Promise<{ recoveryPath: string; needsYouEmittedAt?: string }[]> {\n try {\n const resolved = resolveProjectFromIssueSync(issueId);\n if (!resolved) return [];\n const project = getProjectSync(resolved.projectKey);\n if (!project) return [];\n const record = await readIssueRecord(project, issueId);\n return (record?.recoveryTrips ?? [])\n .filter((trip) => trip.open === true)\n .map((trip) => ({ recoveryPath: trip.recoveryPath, ...(trip.needsYouEmittedAt ? { needsYouEmittedAt: trip.needsYouEmittedAt } : {}) }));\n } catch {\n // A record that cannot be read must never fail the whole resolve — the\n // issue simply loses its needs-you enrichment for this pass.\n return [];\n }\n}\n\n/**\n * Gather signals through the read doors and classify every candidate issue.\n * Candidates = every issue with a review_status row OR a registered agent —\n * the bounded in-flight universe (~dozens), never the 800-row backlog (an\n * untouched backlog issue is not parked; it was never started).\n *\n * Returns rows sorted oldest-first (the sweep order).\n */\nexport async function resolveParkedPopulation(options: ResolveParkedOptions = {}): Promise<ParkedRow[]> {\n const now = options.now ?? Date.now();\n const readTrips = options.readOpenTrips ?? defaultReadOpenTrips;\n const isClosed = options.isClosed ?? isIssueClosed;\n\n const statuses = loadReviewStatuses();\n const allAgents = listAgentStates();\n const liveAgents = listRunningAgentsSync().filter((a) => a.tmuxActive && (a.status === 'running' || a.status === 'starting'));\n\n const agentsByIssue = new Map<string, AgentState[]>();\n for (const agent of allAgents) {\n const issueId = normalizeParkedIssueId(agent.issueId ?? '');\n if (!issueId) continue;\n const list = agentsByIssue.get(issueId) ?? [];\n list.push(agent);\n agentsByIssue.set(issueId, list);\n }\n const liveByIssue = new Map<string, (AgentState & { tmuxActive: boolean })[]>();\n for (const agent of liveAgents) {\n const issueId = normalizeParkedIssueId(agent.issueId ?? '');\n if (!issueId) continue;\n const list = liveByIssue.get(issueId) ?? [];\n list.push(agent);\n liveByIssue.set(issueId, list);\n }\n\n const candidateIds = new Set<string>([...Object.keys(statuses).map((id) => id.toUpperCase()), ...agentsByIssue.keys(), ...liveByIssue.keys()]);\n\n // Pass 1: classify with closedness unknown (null) except where cheap local\n // evidence already decides (live-agent zombie checks resolve it below).\n // Pass 2: for every issue that PRODUCED a row, resolve tracker-closed\n // (TTL-cached, shadow-state-first) and re-classify — a closed issue keeps\n // only its zombie-session rows; every other orbit is moot residue.\n const closedByIssue = new Map<string, boolean>();\n const classifyOne = async (issueId: string): Promise<ParkedRow[]> => {\n const statusKey = Object.keys(statuses).find((key) => key.toUpperCase() === issueId) ?? issueId;\n const reviewStatus = statuses[statusKey] ?? null;\n const live = liveByIssue.get(issueId) ?? [];\n let issueClosed = closedByIssue.get(issueId) ?? null;\n if (issueClosed === null && live.length > 0 && reviewStatus?.mergeStatus !== 'merged') {\n // Zombie detection needs tracker-closed only when the cheap local signals\n // can't decide (strikes bypass the review pipeline, so mergeStatus never\n // records their merge). Bound the check to live-agent candidates.\n try { issueClosed = await isClosed(issueId); closedByIssue.set(issueId, issueClosed); } catch { issueClosed = null; }\n }\n const trips = issueClosed === true ? [] : await readTrips(issueId);\n return classifyParked({\n issueId,\n reviewStatus,\n agents: agentsByIssue.get(issueId) ?? [],\n liveAgents: live,\n openRecoveryTrips: trips,\n issueClosed,\n now,\n });\n };\n\n const firstPass = new Map<string, ParkedRow[]>();\n for (const issueId of candidateIds) {\n const rows = await classifyOne(issueId);\n if (rows.length > 0) firstPass.set(issueId, rows);\n }\n const rows: ParkedRow[] = [];\n for (const [issueId, produced] of firstPass) {\n if (!closedByIssue.has(issueId)) {\n try { closedByIssue.set(issueId, await isClosed(issueId)); } catch { /* unknown — keep the open-issue reading */ }\n }\n if (closedByIssue.get(issueId) === true) {\n // Closed: residue — keep only zombie-session rows (reap candidates).\n rows.push(...produced.filter((row) => row.orbit === 'zombie-session'));\n } else {\n rows.push(...produced);\n }\n }\n\n return rows.sort((a, b) => a.parkedAt.localeCompare(b.parkedAt) || a.issueId.localeCompare(b.issueId));\n}\n\n/** Rollup for dashboards: count by orbit plus the primary (most severe) orbit per issue. */\nexport function summarizeParked(rows: readonly ParkedRow[]): { total: number; byOrbit: Record<string, number>; primaryByIssue: Record<string, ParkedOrbit> } {\n const byOrbit: Record<string, number> = {};\n const primaryByIssue: Record<string, ParkedOrbit> = {};\n const issues = new Set<string>();\n for (const row of rows) {\n byOrbit[row.orbit] = (byOrbit[row.orbit] ?? 0) + 1;\n issues.add(row.issueId);\n const current = primaryByIssue[row.issueId];\n if (!current || PARKED_ORBIT_SEVERITY.indexOf(row.orbit) < PARKED_ORBIT_SEVERITY.indexOf(current)) {\n primaryByIssue[row.issueId] = row.orbit;\n }\n }\n return { total: issues.size, byOrbit, primaryByIssue };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"resolver-C8rooxoz.js","names":[],"sources":["../../src/lib/parked/resolver.ts"],"sourcesContent":["/**\n * Single authoritative parked-population resolver (PAN-3485, epic phase 1).\n *\n * A \"parked orbit\" is any state an issue can sit in where no autonomous actor\n * will advance it within 24h without operator or flywheel intervention. Over\n * months of incident response, each failure mode grew its own safety valve —\n * stuck flags, needs-you trips, deacon-ignore, resume gates, UAT gates, merge\n * retry caps, and circuit breakers — and every one of them converts autonomous\n * motion into operator work. Nine of those valves exist today, in six subsystems,\n * and no surface could answer \"what is stalled, why, and what would release it.\"\n * This resolver is that answer: ONE read door that unions all nine orbits into\n * typed rows, so the CLI, the API, the dashboard, and the stall sweeper all agree\n * by construction.\n *\n * Modeled on `resolvePipelineMembership()` (src/lib/pipeline-membership.ts):\n * a pure classifier over gathered signals, with the gathering done here through\n * existing read doors only (review-status door, agents table, tmux liveness,\n * the per-issue record door for recovery trips). No surface may re-derive\n * parking independently.\n *\n * The nine orbits (see docs/PARKED-POPULATION.md):\n *\n * 1. stuck-flag review_status.stuck = 1 (any stuck_reason)\n * 2. needs-you an open recovery trip in the permanent record\n * 3. deacon-ignored review_status.deaconIgnored = true\n * 4. operator-gate paused (operator, not yield) / troubled / stoppedByUser\n * 5. uat-failed uatStatus failed with merge still pending\n * 6. merge-failed mergeStatus failed (retries saturated or abandoned)\n * 7. zombie-session live agent whose issue is merged/closed\n * 8. idle-running live agent, no pipeline owner, idle beyond threshold\n * 9. circuit-breaker autoRequeueCount >= 25 (dead-end recovery exhausted)\n */\n\nimport { loadReviewStatuses, type ReviewStatus } from '../review-status.js';\nimport { listAgentStates, listRunningAgentsSync } from '../agents/queries.js';\nimport type { AgentState } from '../agents.js';\nimport { FAILED_MERGE_MAX_RETRIES } from '../cloister/deacon-merge.js';\nimport { shouldSkipReviewStatus } from '../cloister/stuck-remediation.js';\nimport { isIssueClosed } from '../cloister/issue-closed.js';\nimport { readIssueRecord } from '../pan-dir/record.js';\nimport { getProjectSync, resolveProjectFromIssueSync } from '../projects.js';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\n\nexport const PARKED_ORBITS = [\n 'stuck-flag',\n 'needs-you',\n 'deacon-ignored',\n 'operator-gate',\n 'uat-failed',\n 'merge-failed',\n 'zombie-session',\n 'idle-running',\n 'circuit-breaker',\n] as const;\n\nexport type ParkedOrbit = (typeof PARKED_ORBITS)[number];\n\n/**\n * Severity order — recommendations surface these orbits in this order, with\n * operator-gated rows last so a full report ends by surfacing what only a human\n * can release. The God View tints an orb\n * by its most severe orbit.\n */\nexport const PARKED_ORBIT_SEVERITY: readonly ParkedOrbit[] = [\n 'zombie-session',\n 'merge-failed',\n 'uat-failed',\n 'stuck-flag',\n 'circuit-breaker',\n 'idle-running',\n 'needs-you',\n 'deacon-ignored',\n 'operator-gate',\n];\n\nexport interface ParkedRow {\n issueId: string;\n orbit: ParkedOrbit;\n /** ISO timestamp the issue entered this orbit (best available evidence). */\n parkedAt: string;\n /** Operator-facing sentence: why the issue is parked. */\n parkReason: string;\n /** Operator-facing sentence: what would release it. */\n unparkCondition: string;\n /** Orbit-specific evidence (stuck reason, gate kind, idle minutes, …). */\n details?: Record<string, unknown>;\n}\n\n/** A human sentence per stuck_reason — the stuck flag carries the machine code, the resolver owns the copy.\n * GUARD-EXIT INVARIANT (PAN-3488): every stuck_reason written anywhere in src/ MUST have an entry\n * here — scripts/guard-park-exits.sh fails the lint on an undocumented flavor. */\nconst STUCK_REASON_COPY: Record<string, { park: string; unpark: string }> = {\n feedback_delivery_needs_you: {\n park: 'review/test feedback could not be delivered — the work agent is not running and nothing resumed it',\n unpark: 'resume the work agent with its pending feedback through the established work-resume door',\n },\n review_infrastructure_failure: {\n park: 'the review pipeline failed repeatedly for infrastructure reasons, not verdict reasons',\n unpark: 're-dispatch a fresh review through the review door once the infra cause is resolved',\n },\n review_parent_stalled_needs_you: {\n park: 'the review parent exceeded its deadline with no terminal verdict in the row or verdict artifact',\n unpark: 'inspect the parent pane and review artifacts, then pan unstick <id> and pan review restart <id> if a fresh review is required',\n },\n verification_stuck: {\n park: 'verification exhausted its cycles without passing',\n unpark: 're-drive the verification feedback to a resumed work agent',\n },\n 'dead-end-rebuild': {\n park: 'dead-end recovery exhausted 25 requeues',\n unpark: 'operator decision — decompose or pan unstick after the root cause is fixed',\n },\n main_diverged: {\n park: 'the PR branch diverged from main and cannot merge cleanly',\n unpark: 'sync-main and resolve conflicts, then re-drive through the normal pipeline',\n },\n model_divergence: {\n park: 'the agent hit a model/API divergence error and was parked for investigation',\n unpark: 'investigate the model error (pane + transcript), then pan unstick and resume',\n },\n usage_limit: {\n park: 'the agent hit a provider usage limit and stopped mid-flight',\n unpark: 'wait for the provider window to reset, then pan unstick and resume',\n },\n context_overflow: {\n park: 'the agent overflowed its context window and cannot continue in this session',\n unpark: 'pan unstick after compaction/fork — resume with a fresh session',\n },\n review_convoy_unrecoverable: {\n park: 'the review convoy died and could not be recovered in place',\n unpark: 're-dispatch a fresh review convoy through the review door after the root cause is resolved',\n },\n test_signal_strand: {\n park: 'a test verdict was written but never delivered to the pipeline',\n unpark: 're-drive the stranded verdict to a resumed work agent',\n },\n 'review-not-converging': {\n park: 'review cycles stopped converging (stall or reversal across ≥3 cycles) — rework is suppressed',\n unpark: 'decompose into sibling issues, or pan unstick to clear the gate and attempt rework',\n },\n state_derived_verification_hold: {\n park: 'verification is held by a derived-state rule (the recorded state forbids advancing)',\n unpark: 'fix the underlying state mismatch, then pan unstick to release the hold',\n },\n};\n\n/** Idle threshold for the idle-running orbit: below this a live idle agent is warm, not parked. */\nexport const IDLE_RUNNING_THRESHOLD_MS = 6 * 60 * 60_000;\n\n/**\n * Roles the idle-running orbit must NEVER touch: orchestrators and\n * conversations. Their real activity lives in the conversation/runtime plane,\n * not the agents-table lastActivity this orbit reads — the sweeper's first\n * night proved the trap when its idle nudge→stop killed the FLYWHEEL (its\n * agents-table stamp was a day stale while it ticked normally), halting all\n * new dispatch for 90 minutes. A \"stopped orchestrator\" is not a freed slot;\n * it is the pipeline going silent.\n */\nexport const IDLE_EXEMPT_ROLES: ReadonlySet<string> = new Set(['flywheel', 'sequencer', 'conversation', 'knowledge']);\n\n/** Per-issue gathered signals — the classifier's entire input. Gathered through read doors, never stores. */\nexport interface ParkedSignals {\n issueId: string;\n reviewStatus: ReviewStatus | null;\n /** All agents (any status) carrying this issue id. */\n agents: AgentState[];\n /** Live (running + tmux-active) agents for this issue. */\n liveAgents: (AgentState & { tmuxActive: boolean })[];\n /** Open recovery trips from the permanent record (needs-you orbit). */\n openRecoveryTrips: { recoveryPath: string; needsYouEmittedAt?: string }[];\n /** Tracker-closed (only resolved for live-agent candidates; null = unknown/not checked). */\n issueClosed: boolean | null;\n now: number;\n}\n\nfunction isoOr(ts: string | number | null | undefined, fallback: number): string {\n if (typeof ts === 'number' && Number.isFinite(ts)) return new Date(ts).toISOString();\n if (typeof ts === 'string' && ts) {\n const parsed = Date.parse(ts);\n if (Number.isFinite(parsed)) return new Date(parsed).toISOString();\n }\n return new Date(fallback).toISOString();\n}\n\n/**\n * `pan done` marks the work agent stoppedByUser as an auto-resume suppressor\n * (done.ts:439/:869 — finished, don't idle-revive; the PAN-2668 completed-\n * handoff exception is the sanctioned rework path). That is a NORMAL lifecycle\n * completion, not an operator park — reporting it as an operator gate makes\n * the sweeper escalate false gates every TTL (observed on PAN-3512 at\n * 00:02:26Z, self-cleared 80s later by the rework resume). A completed\n * handoff marker means finished, not parked.\n */\nexport function hasCompletedHandoffMarker(agentId: string): boolean {\n const dir = join(getOverdeckHome(), 'agents', agentId);\n return existsSync(join(dir, 'completed')) || existsSync(join(dir, 'completed.processed'));\n}\n\n/**\n * Agent rows occasionally carry a bare numeric issue id (\"2156\") where every\n * other surface keys \"PAN-2156\" — without normalization the issue loses its\n * review-status row and trip enrichment. Uppercase always; for bare numerics\n * that fail project resolution, retry with the PAN- prefix.\n */\nexport function normalizeParkedIssueId(raw: string): string {\n const upper = raw.trim().toUpperCase();\n if (!/^\\d+$/.test(upper)) return upper;\n if (resolveProjectFromIssueSync(upper)) return upper;\n return `PAN-${upper}`;\n}\n\nfunction stuckCopy(reason: string | undefined): { park: string; unpark: string } {\n if (reason && STUCK_REASON_COPY[reason]) return STUCK_REASON_COPY[reason];\n return {\n park: `stuck flag set${reason ? ` (${reason})` : ''} — nothing autonomous will advance this issue`,\n unpark: 'pan unstick after the underlying cause is fixed',\n };\n}\n\n/**\n * Classify one issue's parked orbits from gathered signals. Pure — unit-tested\n * with fixtures. Emits at most one row per orbit; an issue may legitimately\n * occupy several orbits at once (e.g. a stuck flag AND a dead operator-stopped\n * agent). idle-running is only emitted when no other orbit already explains\n * the stall — it is the orbit of last resort (\"live but leaderless\").\n */\nexport function classifyParked(s: ParkedSignals): ParkedRow[] {\n const rows: ParkedRow[] = [];\n const r = s.reviewStatus;\n const issueId = s.issueId;\n const push = (orbit: ParkedOrbit, parkedAt: string, parkReason: string, unparkCondition: string, details?: Record<string, unknown>) => {\n rows.push({ issueId, orbit, parkedAt, parkReason, unparkCondition, ...(details ? { details } : {}) });\n };\n\n // Terminal issues are never parked — they are residue. A closed issue can\n // only produce zombie-session rows (a live agent to reap); every other orbit\n // is moot once the issue is done. issueClosed === null means \"unknown\" — the\n // gather resolves it for row-producing issues and re-classifies (pass 2).\n const closed = s.issueClosed === true;\n\n // 1. stuck-flag\n if (!closed && r?.stuck) {\n const copy = stuckCopy(r.stuckReason);\n push('stuck-flag', isoOr(r.stuckAt ?? r.updatedAt, s.now), copy.park, copy.unpark, { stuckReason: r.stuckReason ?? null });\n }\n\n // 2. needs-you (open recovery trips from the permanent record)\n if (!closed) for (const trip of s.openRecoveryTrips) {\n push(\n 'needs-you',\n isoOr(trip.needsYouEmittedAt, s.now),\n `a durable needs-you escalation fired (${trip.recoveryPath}) and went silent — the operator never answered`,\n 'answer the escalation (pan answer / dashboard needs-you), or let the sweeper re-surface it on its TTL',\n { recoveryPath: trip.recoveryPath },\n );\n }\n\n // 3. deacon-ignored\n if (!closed && r?.deaconIgnored) {\n push(\n 'deacon-ignored',\n isoOr(r.deaconIgnoredAt ?? r.updatedAt, s.now),\n `deacon is ignoring this issue${r.deaconIgnoredReason ? ` — ${r.deaconIgnoredReason}` : ''}`,\n 'clear the ignore flag once the reason it was set is resolved',\n { reason: r.deaconIgnoredReason ?? null },\n );\n }\n\n // 4. operator-gate — operator-set resume gates on this issue's agents,\n // grouped one row per gate kind (an issue with three stopped agents has\n // ONE operator-stop park, not three). A scheduler YIELD reuses the paused\n // flag but is self-clearing (the preemptive scheduler resumes yielded\n // agents oldest-first) — NOT a park.\n if (!closed) {\n const gateRows = new Map<'paused' | 'troubled' | 'stopped-by-user', { parkedAt: string; agentIds: string[]; reason: string; unpark: string }>();\n for (const agent of s.agents) {\n if (agent.paused === true && agent.yieldedByScheduler !== true) {\n const row = gateRows.get('paused') ?? { parkedAt: isoOr(agent.pausedAt, s.now), agentIds: [], reason: '', unpark: '' };\n row.agentIds.push(agent.id);\n const at = isoOr(agent.pausedAt, s.now);\n if (at < row.parkedAt) row.parkedAt = at;\n if (agent.pausedReason && !row.reason) row.reason = agent.pausedReason;\n gateRows.set('paused', row);\n } else if (agent.troubled === true) {\n const row = gateRows.get('troubled') ?? { parkedAt: isoOr(agent.troubledAt, s.now), agentIds: [], reason: '', unpark: '' };\n row.agentIds.push(agent.id);\n const at = isoOr(agent.troubledAt, s.now);\n if (at < row.parkedAt) row.parkedAt = at;\n gateRows.set('troubled', row);\n } else if (agent.stoppedByUser === true && agent.status !== 'running' && !hasCompletedHandoffMarker(agent.id)) {\n const row = gateRows.get('stopped-by-user') ?? { parkedAt: isoOr(agent.stoppedAt, s.now), agentIds: [], reason: '', unpark: '' };\n row.agentIds.push(agent.id);\n const at = isoOr(agent.stoppedAt, s.now);\n if (at < row.parkedAt) row.parkedAt = at;\n gateRows.set('stopped-by-user', row);\n }\n }\n for (const [gate, row] of gateRows) {\n const names = row.agentIds.join(', ');\n if (gate === 'paused') {\n push('operator-gate', row.parkedAt, `${names} manually paused${row.reason ? ` — ${row.reason}` : ''}`, 'pan unpause <id> (operator-only; the sweeper re-surfaces on TTL, never overrides)', { gate, agentIds: row.agentIds });\n } else if (gate === 'troubled') {\n push('operator-gate', row.parkedAt, `${names} marked troubled after repeated resume/crash failures`, 'pan untroubled <id> after the crash cause is investigated', { gate, agentIds: row.agentIds });\n } else {\n push('operator-gate', row.parkedAt, `${names} explicitly stopped by the operator with no completed handoff to re-drive`, 'pan start <id> (operator-only; explicit start clears the stop gate)', { gate, agentIds: row.agentIds });\n }\n }\n }\n\n // 5. uat-failed — the feedback relay already owns rework while work is live.\n const hasLiveWorkAgent = s.liveAgents.some((agent) => agent.role === 'work');\n if (!closed && r?.uatStatus === 'failed' && r.mergeStatus !== 'merged' && !r.readyForMerge && !hasLiveWorkAgent) {\n push(\n 'uat-failed',\n isoOr(r.updatedAt, s.now),\n 'UAT failed and no work agent is live to rework it — the merge gate will not take the issue and the UAT-failure relay found no delivery target',\n 'pan start <id> to put a work agent on the UAT feedback; the relay redelivers on the next failed verdict',\n { uatNotes: r.uatNotes ?? null },\n );\n }\n\n // 6. merge-failed — a failed merge that nothing is retrying\n if (!closed && r?.mergeStatus === 'failed') {\n const retries = r.mergeRetryCount ?? 0;\n push(\n 'merge-failed',\n isoOr(r.updatedAt, s.now),\n retries >= FAILED_MERGE_MAX_RETRIES\n ? `merge failed and its ${FAILED_MERGE_MAX_RETRIES} automatic retries are exhausted`\n : 'merge failed and no retry is in flight',\n 'one fresh merge attempt once main CI is green and the branch is conflict-free (sweeper tries once per scan window)',\n { mergeRetryCount: retries, mergeNotes: r.mergeNotes ?? null },\n );\n }\n\n // 7. zombie-session — live agent whose issue is already merged/closed\n for (const agent of s.liveAgents) {\n const merged = r?.mergeStatus === 'merged' || s.issueClosed === true;\n if (!merged) continue;\n push(\n 'zombie-session',\n isoOr(agent.lastActivity ?? agent.startedAt, s.now),\n `${agent.id} is still running but the issue is ${r?.mergeStatus === 'merged' ? 'merged' : 'closed'} — it holds a session and a concurrency slot for nothing`,\n 'reap the session through the established merged-zombie teardown door',\n { agentId: agent.id, mergeStatus: r?.mergeStatus ?? null },\n );\n }\n\n // 9. circuit-breaker — dead-end recovery exhausted\n const requeues = r?.autoRequeueCount ?? 0;\n if (!closed && requeues >= 25) {\n push(\n 'circuit-breaker',\n isoOr(r?.updatedAt, s.now),\n `dead-end recovery used all ${requeues}/25 requeues — the circuit breaker is permanently open`,\n 'operator decision — decompose the change or pan unstick after the root cause is fixed',\n { autoRequeueCount: requeues },\n );\n }\n\n // 8. idle-running — live agent, no pipeline owner, idle beyond threshold, and\n // no other orbit already explains the stall (orbit of last resort).\n if (!closed && rows.length === 0) {\n for (const agent of s.liveAgents) {\n // Orchestrators and conversations are exempt (IDLE_EXEMPT_ROLES): their\n // activity does not live in the stamp this orbit reads, and stopping one\n // silences the pipeline instead of freeing a slot.\n if (IDLE_EXEMPT_ROLES.has(String(agent.role ?? ''))) continue;\n const lastMs = Date.parse(agent.lastActivity ?? agent.startedAt ?? '');\n if (!Number.isFinite(lastMs)) continue;\n const idleMs = s.now - lastMs;\n if (idleMs < IDLE_RUNNING_THRESHOLD_MS) continue;\n // Warm-idle on a pipeline-owned issue is the intended state (PAN-2579):\n // review/test/merge owns the next move, the agent is SUPPOSED to wait.\n if (shouldSkipReviewStatus(r)) continue;\n push(\n 'idle-running',\n new Date(lastMs).toISOString(),\n `${agent.id} is alive but has done nothing for ${Math.floor(idleMs / 60_000)} minutes and no pipeline stage owns the next move`,\n 'poke for progress; if none, stop or resume with a nudge through the established agent-control door',\n { agentId: agent.id, idleMinutes: Math.floor(idleMs / 60_000) },\n );\n }\n }\n\n return rows;\n}\n\n/** Options for the gather pass — injectable for tests. */\nexport interface ResolveParkedOptions {\n now?: number;\n /** Per-issue open recovery trips (defaults to the record door). */\n readOpenTrips?: (issueId: string) => Promise<{ recoveryPath: string; needsYouEmittedAt?: string }[]>;\n /** Tracker-closed check (defaults to isIssueClosed). Only called for live-agent candidates. */\n isClosed?: (issueId: string) => Promise<boolean>;\n}\n\nasync function defaultReadOpenTrips(issueId: string): Promise<{ recoveryPath: string; needsYouEmittedAt?: string }[]> {\n try {\n const resolved = resolveProjectFromIssueSync(issueId);\n if (!resolved) return [];\n const project = getProjectSync(resolved.projectKey);\n if (!project) return [];\n const record = await readIssueRecord(project, issueId);\n return (record?.recoveryTrips ?? [])\n .filter((trip) => trip.open === true)\n .map((trip) => ({ recoveryPath: trip.recoveryPath, ...(trip.needsYouEmittedAt ? { needsYouEmittedAt: trip.needsYouEmittedAt } : {}) }));\n } catch {\n // A record that cannot be read must never fail the whole resolve — the\n // issue simply loses its needs-you enrichment for this pass.\n return [];\n }\n}\n\n/**\n * Gather signals through the read doors and classify every candidate issue.\n * Candidates = every issue with a review_status row OR a registered agent —\n * the bounded in-flight universe (~dozens), never the 800-row backlog (an\n * untouched backlog issue is not parked; it was never started).\n *\n * Returns rows sorted oldest-first (the sweep order).\n */\nexport async function resolveParkedPopulation(options: ResolveParkedOptions = {}): Promise<ParkedRow[]> {\n const now = options.now ?? Date.now();\n const readTrips = options.readOpenTrips ?? defaultReadOpenTrips;\n const isClosed = options.isClosed ?? isIssueClosed;\n\n const statuses = loadReviewStatuses();\n const allAgents = listAgentStates();\n const liveAgents = listRunningAgentsSync().filter((a) => a.tmuxActive && (a.status === 'running' || a.status === 'starting'));\n\n const agentsByIssue = new Map<string, AgentState[]>();\n for (const agent of allAgents) {\n const issueId = normalizeParkedIssueId(agent.issueId ?? '');\n if (!issueId) continue;\n const list = agentsByIssue.get(issueId) ?? [];\n list.push(agent);\n agentsByIssue.set(issueId, list);\n }\n const liveByIssue = new Map<string, (AgentState & { tmuxActive: boolean })[]>();\n for (const agent of liveAgents) {\n const issueId = normalizeParkedIssueId(agent.issueId ?? '');\n if (!issueId) continue;\n const list = liveByIssue.get(issueId) ?? [];\n list.push(agent);\n liveByIssue.set(issueId, list);\n }\n\n const candidateIds = new Set<string>([...Object.keys(statuses).map((id) => id.toUpperCase()), ...agentsByIssue.keys(), ...liveByIssue.keys()]);\n\n // Pass 1: classify with closedness unknown (null) except where cheap local\n // evidence already decides (live-agent zombie checks resolve it below).\n // Pass 2: for every issue that PRODUCED a row, resolve tracker-closed\n // (TTL-cached, shadow-state-first) and re-classify — a closed issue keeps\n // only its zombie-session rows; every other orbit is moot residue.\n const closedByIssue = new Map<string, boolean>();\n const classifyOne = async (issueId: string): Promise<ParkedRow[]> => {\n const statusKey = Object.keys(statuses).find((key) => key.toUpperCase() === issueId) ?? issueId;\n const reviewStatus = statuses[statusKey] ?? null;\n const live = liveByIssue.get(issueId) ?? [];\n let issueClosed = closedByIssue.get(issueId) ?? null;\n if (issueClosed === null && live.length > 0 && reviewStatus?.mergeStatus !== 'merged') {\n // Zombie detection needs tracker-closed only when the cheap local signals\n // can't decide (strikes bypass the review pipeline, so mergeStatus never\n // records their merge). Bound the check to live-agent candidates.\n try { issueClosed = await isClosed(issueId); closedByIssue.set(issueId, issueClosed); } catch { issueClosed = null; }\n }\n const trips = issueClosed === true ? [] : await readTrips(issueId);\n return classifyParked({\n issueId,\n reviewStatus,\n agents: agentsByIssue.get(issueId) ?? [],\n liveAgents: live,\n openRecoveryTrips: trips,\n issueClosed,\n now,\n });\n };\n\n const firstPass = new Map<string, ParkedRow[]>();\n for (const issueId of candidateIds) {\n const rows = await classifyOne(issueId);\n if (rows.length > 0) firstPass.set(issueId, rows);\n }\n const rows: ParkedRow[] = [];\n for (const [issueId, produced] of firstPass) {\n if (!closedByIssue.has(issueId)) {\n try { closedByIssue.set(issueId, await isClosed(issueId)); } catch { /* unknown — keep the open-issue reading */ }\n }\n if (closedByIssue.get(issueId) === true) {\n // Closed: residue — keep only zombie-session rows (reap candidates).\n rows.push(...produced.filter((row) => row.orbit === 'zombie-session'));\n } else {\n rows.push(...produced);\n }\n }\n\n return rows.sort((a, b) => a.parkedAt.localeCompare(b.parkedAt) || a.issueId.localeCompare(b.issueId));\n}\n\n/** Rollup for dashboards: count by orbit plus the primary (most severe) orbit per issue. */\nexport function summarizeParked(rows: readonly ParkedRow[]): { total: number; byOrbit: Record<string, number>; primaryByIssue: Record<string, ParkedOrbit> } {\n const byOrbit: Record<string, number> = {};\n const primaryByIssue: Record<string, ParkedOrbit> = {};\n const issues = new Set<string>();\n for (const row of rows) {\n byOrbit[row.orbit] = (byOrbit[row.orbit] ?? 0) + 1;\n issues.add(row.issueId);\n const current = primaryByIssue[row.issueId];\n if (!current || PARKED_ORBIT_SEVERITY.indexOf(row.orbit) < PARKED_ORBIT_SEVERITY.indexOf(current)) {\n primaryByIssue[row.issueId] = row.orbit;\n }\n }\n return { total: issues.size, byOrbit, primaryByIssue };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
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
2
  import { $n as canUseHarnessSync, $t as findProjectByPathSync, A as validateTieredExecutionConfig, Ai as getDocsIndexPath, An as resolveProjectKeyForCwdAsync, Ar as getModelEffortLevelsSync, Bi as sessionFilePath, Ci as SYNC_SOURCES, Cn as registerProjectSync, Cr as computeModelOrigin, Ct as flushAllPendingAutoCommits, D as resolveTieredExecutionBlock, Di as encodeClaudeProjectDir, Dn as resolveProjectFromIssue, Dr as MODEL_CAPABILITIES, E as init_tier_table, En as resolveInfraRepo, Er as resolveModel, Fi as init_paths, Gn as init_issue_id, Gr as ROLE_EFFORTS, Hn as validateVersionSyncConfig, Ht as init_state_read_home, Ii as isDeploymentGenerationRoot, In as setProjectMergeTrain, Jt as PROJECTS_CONFIG_FILE, Kt as init_project_key, Li as isDevMode, Mr as init_model_capabilities, Ni as getLegacyHome, Nr as modelSupportsImagesSync, O as resolveTieredExecutionEnabled, Oi as getDocsBudgetStatePath, On as resolveProjectFromIssueSync, Or as MODEL_DEPRECATIONS, Pi as getOverdeckHome, Pn as setProjectAutoMergeDefault, Pr as resolveModelIdSync, Qn as require_dist$1, Ri as packageRoot, Rn as setProjectSwarmPolicy, Sr as DEFAULT_WORKHORSES, T as TieredExecutionConfigError, Ti as activeDeploymentRepoRoot, Tt as init_auto_commit, Ur as COMPLIANCE_MODES, Ut as resolveStateReadHomeAsync, Wn as extractPrefixSync, Wr as PARENT_MODEL_REF, Wt as resolveStateReadHomeSync, Xn as init_projects_config_write, Y as init_record, Yr as FsError, Yt as ProjectRenameError, Zn as updateProjectsConfigText, Zr as GitHubApiError, Zt as extractTeamPrefix, _ as mergeConfigs, _n as listProjectsAsync, _r as getDashScopeUpstreamBaseUrl, ar as UnknownModelError, b as mergeTtsDaemonConfigs, bn as loadProjectsConfigSync, br as init_registry, c as init_load, cr as getKimiAnthropicBaseUrl, d as isTldrEnabledSync, dr as init_providers, f as loadConfigNoMigration, fi as CLAUDE_DIR, fn as init_projects, g as jsYaml, gi as OVERDECK_HOME, gn as listProjects, h as init_js_yaml, hi as LOGS_DIR, hn as invalidateProjectsConfigCache, i as getConversationsConfig, ii as TrackerError, ji as getDocsTelemetryPath, jn as resolveProjectPath, jr as hasModelCapabilitySync, ki as getDocsDisableStatePath, m as updateConversationsConfig, n as clearConfigCache, ni as ProcessSpawnError, o as getGlobalConfigPath, oi as init_errors, on as getProjectSync, p as loadConfigSync, q as getIssueWorkspacePath, qn as parseIssueIdSync, qt as projectKey, r as getConversationSearchConfigSync, rn as getIssuePrefix, s as getOpenInEditorCommand, sr as getBuiltInDefaultHarness, t as init_config_yaml, tn as findProjectByTeamSync, tr as init_harness_policy, tt as readIssueRecordSync, ur as getProviderForModelSync, v as getDefaultDocsConfig, vn as listProjectsSync, vr as init_openai_compatible_proxy, wn as renameProject, wt as flushAutoCommits, x as DEFAULT_CONFIG$1, xr as DEFAULT_ROLES, y as getDefaultTtsDaemonConfig, yr as defaultBackgroundAiFeatures } from "./config-yaml-BwOEANMr.js";
3
- import { i as shouldRefuseHostDashboardPort, n as isNonPrimaryCheckoutRoot, r as readHostDashboardApiPort, t as getDashboardIdentity } from "./identity-BnxKo9-z.js";
4
- import { $ as resolvePolicy, A as handleConversationSwitchModel, At as validateOrigin$1, B as waitForTmuxSession$1, C as conversationNeedsRunningRepair, Ct as rejectUnauthorizedDashboardRequest, D as handleConversationRestartAll, Dt as waitForSessionRespawn, E as handleConversationDelete, Et as isRespawnPending, F as spawnConversationSession, Ft as jsonStringResponse, G as extractConversationAttachmentPaths, H as cleanupOrphanedConversationAttachments, I as startConversationModelBackfill, J as isManagedConversationAttachmentPath, K as getConversationAttachmentsRoot, L as stopConversationRuntime, M as resolveAllowedHarness, Mt as httpHandler, N as resolveRegisteredProject, Nt as getDefaultCwd, O as handleConversationResume, Ot as getHeaderFromMap, P as shouldReportUnresolvedLiveSession, Pt as jsonResponse, Q as handleComposerCommandMessage, R as tmuxSessionExists, S as validateConversationControlAckOrigin, St as hasDashboardInternalToken, T as handleConversationCreate, Tt as rejectUnsafeDashboardMutationRequest, U as cleanupUnreferencedConversationAttachments, V as cleanupConversationAttachments, W as ensureConversationAttachmentDir, X as runInBatches, Y as removeConversationAttachment, Z as composerCommandResultHttpStatus, _ as handleConversationPlanAction, _t as resolveJsonlPath, a as agentsRouteLayer, at as isInternalAgentRequest, b as pickDeliverAs, bt as dashboardCsrfToken, c as answerSessionPaneChoice, ct as resolveConversationGitInfo, d as deliverConversationViaControlChannel, et as ComposerCommandParseError, f as handleConversationAbort, ft as readLauncherPinnedSessionId, g as handleConversationDeliveryMethod, gt as resolveCodexRolloutPath, h as handleConversationControlAck, ht as resolveClaudeSessionId, it as invalidateAgentsCache, j as isInsideGitWorkTree, jt as validateOriginHeaders, k as handleConversationStop, kt as isTrustedOriginForHost, l as captureSessionPaneChoice, m as handleConversationCompact, mt as resolveAgentHarness, nt as composerCommandConfirmationFromBody, o as saveAgentStateAndEmitEvent, ot as resolveRequestedStartedBy, p as handleConversationCodexApproval, pt as resolveAcpTranscriptPath, q as hasConversationAttachment, rt as evaluateSpawnGuardrails, s as saveAgentStateAndEmitEventProgram, st as resolveAgentGitInfo, t as specialistsRouteLayer, tt as ComposerCommandConfirmationError, u as codexConversationPendingInput, ut as panCliInvocation, v as handleConversationThinkingLevel, vt as resolveKimiWirePath, w as conversationSessionAliveFromState, wt as rejectUnauthorizedDashboardSessionMintRequest, x as resolveConversationDeliveryMethod, xt as dashboardSessionCookieHeader, y as isPiControlChannelHarness, yt as resolvePiSessionPath, z as waitForPiTuiReady } from "./specialists-C2ZVszIW.js";
3
+ import { i as shouldRefuseHostDashboardPort, n as isNonPrimaryCheckoutRoot, r as readHostDashboardApiPort, t as getDashboardIdentity } from "./identity-Bwh6VGeL.js";
4
+ import { $ as resolvePolicy, A as handleConversationSwitchModel, At as validateOrigin$1, B as waitForTmuxSession$1, C as conversationNeedsRunningRepair, Ct as rejectUnauthorizedDashboardRequest, D as handleConversationRestartAll, Dt as waitForSessionRespawn, E as handleConversationDelete, Et as isRespawnPending, F as spawnConversationSession, Ft as jsonStringResponse, G as extractConversationAttachmentPaths, H as cleanupOrphanedConversationAttachments, I as startConversationModelBackfill, J as isManagedConversationAttachmentPath, K as getConversationAttachmentsRoot, L as stopConversationRuntime, M as resolveAllowedHarness, Mt as httpHandler, N as resolveRegisteredProject, Nt as getDefaultCwd, O as handleConversationResume, Ot as getHeaderFromMap, P as shouldReportUnresolvedLiveSession, Pt as jsonResponse, Q as handleComposerCommandMessage, R as tmuxSessionExists, S as validateConversationControlAckOrigin, St as hasDashboardInternalToken, T as handleConversationCreate, Tt as rejectUnsafeDashboardMutationRequest, U as cleanupUnreferencedConversationAttachments, V as cleanupConversationAttachments, W as ensureConversationAttachmentDir, X as runInBatches, Y as removeConversationAttachment, Z as composerCommandResultHttpStatus, _ as handleConversationPlanAction, _t as resolveJsonlPath, a as agentsRouteLayer, at as isInternalAgentRequest, b as pickDeliverAs, bt as dashboardCsrfToken, c as answerSessionPaneChoice, ct as resolveConversationGitInfo, d as deliverConversationViaControlChannel, et as ComposerCommandParseError, f as handleConversationAbort, ft as readLauncherPinnedSessionId, g as handleConversationDeliveryMethod, gt as resolveCodexRolloutPath, h as handleConversationControlAck, ht as resolveClaudeSessionId, it as invalidateAgentsCache, j as isInsideGitWorkTree, jt as validateOriginHeaders, k as handleConversationStop, kt as isTrustedOriginForHost, l as captureSessionPaneChoice, m as handleConversationCompact, mt as resolveAgentHarness, nt as composerCommandConfirmationFromBody, o as saveAgentStateAndEmitEvent, ot as resolveRequestedStartedBy, p as handleConversationCodexApproval, pt as resolveAcpTranscriptPath, q as hasConversationAttachment, rt as evaluateSpawnGuardrails, s as saveAgentStateAndEmitEventProgram, st as resolveAgentGitInfo, t as specialistsRouteLayer, tt as ComposerCommandConfirmationError, u as codexConversationPendingInput, ut as panCliInvocation, v as handleConversationThinkingLevel, vt as resolveKimiWirePath, w as conversationSessionAliveFromState, wt as rejectUnauthorizedDashboardSessionMintRequest, x as resolveConversationDeliveryMethod, xt as dashboardSessionCookieHeader, y as isPiControlChannelHarness, yt as resolvePiSessionPath, z as waitForPiTuiReady } from "./specialists-DocAK-7A.js";
5
5
  import { h as loadConfigSync$1, p as init_config, s as getDashboardApiUrlSync } from "./config-tucKBCCc.js";
6
6
  import { a as emitActivityEntrySync, c as init_activity_logger, o as emitActivityTtsSync, s as emitDashboardLifecycleSync } from "./activity-logger-BAVLrkR7.js";
7
7
  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-KTp9KV9u.js";
@@ -20,7 +20,7 @@ import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit,
20
20
  import { Ai as init_agent_runtime_mirror, B as waitForReadySignal, Bt as init_operator_interventions, Cn as refreshRuntimeCensus, Cr as resolveImplicitStaffing, Di as init_agent_record_sync, Dt as detectAwaitingInputFromPaneSync, Et as detectAwaitingInputForAgent, Fr as getProviderAuthMode, G as init_agents$1, H as getAgentRuntimeStateSync, In as init_concurrency, L as normalizeAgentId, Lt as init_messaging, O as saveAgentStateSync, Oi as readAgentHarnessModelRecordSync, Ot as init_agent_input_detection, Pn as emergencyBrake, Q as init_tier_supervisor, Rt as messageAgent, Sn as panePidsForSession, Sr as init_staffing, St as init_agent_enrichment, Tt as scanPendingInputsPromise, V as getAgentRuntimeState, Vt as operatorInterventionEvent, Xn as deliverAgentMessage, Xr as init_claude_auth, Yr as getClaudeAuthStatus, Z as deliverCommitForReview, _t as countPendingAskUserQuestionsForAgent, ai as getOpenAIAuthStatus, ar as init_transcript_landing, bn as getRuntimeCensusSnapshot, cn as listAgentStates, dr as checkCodexAuthStatus, ei as getProviderEnvForModel, f as getAgentState, fr as init_codex_auth, gt as computeAgentEnrichment, ir as captureTranscriptUserRecordSnapshot, ln as listRunningAgents, m as getAgentStateSync, nt as supervisorAgentId, oi as init_openai_auth, or as probeTranscriptSince, sn as init_queries, u as getAgentDir, un as listRunningAgentsSync, vt as getAgentJsonlMtime, wn as runtimeCensusHasHarnessProcess, wt as isInteractiveRoleAgent, xn as init_runtime_census, yn as getRuntimeCensus, zr as injectPiConversationMemory } from "./agent-state-Bb3UUxQm.js";
21
21
  import { t as init_behavior } from "./behavior-Bitko0mD.js";
22
22
  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-B-ADeXKY.js";
23
- import { a as generateHealthSummary, c as CostDoorLive, d as CostWriter, l as CostResolver, n as readCloisterStateFile, o as getAgentHealth, s as getAgentsNeedingAttention, t as getCloisterService, u as CostResolverLive } from "./service-0hbSVeHz.js";
23
+ import { a as generateHealthSummary, c as CostDoorLive, d as CostWriter, l as CostResolver, n as readCloisterStateFile, o as getAgentHealth, s as getAgentsNeedingAttention, t as getCloisterService, u as CostResolverLive } from "./service-BLb_CyPL.js";
24
24
  import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-CGopJXdU.js";
25
25
  import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-B9-H2K_E.js";
26
26
  import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-DrfK0Ip8.js";
@@ -59,7 +59,7 @@ import { a as clearQueryExpansionCache, i as resolveKnowledgeBundleRoot, n as in
59
59
  import { a as init_fts_db, i as closeMemoryFtsDatabases, n as init_search, o as runMemoryFtsStatement, s as runMemoryFtsTransaction, t as buildMatchQuery } from "./search-DwHYaj66.js";
60
60
  import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-DyJJyX_B.js";
61
61
  import { A as createSettledTtlPromiseCache, D as init_advisory_checks, E as verifyAppCanMerge, M as withConcurrencyLimit, O as isAdvisoryCheckName, d as getPullRequestState, f as init_github_app, j as init_concurrency$1, k as createPromiseConcurrencyLimiter, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-4UX8VIr8.js";
62
- import { C as getWorkspacePathForIssue, E as stopAgentOutputService, S as resolveIssueHeadlineCost, T as startAgentOutputService, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, w as retainAgentOutputInterest, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-CqeaoIK6.js";
62
+ import { C as getWorkspacePathForIssue, E as stopAgentOutputService, S as resolveIssueHeadlineCost, T as startAgentOutputService, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, w as retainAgentOutputInterest, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-BlpbOPZ7.js";
63
63
  import { S as parseAcpConversationMessages, _ as isOhmypiSessionFile, a as contextUsageFromParseResult, b as parseCodexConversationMessages, c as parseEntireConversation, d as init_kimi_conversation_parser, f as parseKimiConversationMessages, g as init_ohmypi_conversation_parser, h as parsePiConversationMessages, i as computeContextUsage, l as parseFromLastCompactBoundary, m as isPiSessionFile, n as gateSnapshotEmission, o as summarizeConversationActivity, p as init_pi_conversation_parser, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseOhmypiConversationMessages, x as init_acp_conversation_parser, y as init_codex_conversation_parser } from "./conversation-service-BteE4ELK.js";
64
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-2aHeLC3W.js";
65
65
  import { c as tailEventsSync, n as deduplicateEventsSync, s as readEventsSync } from "./events-BIKGJZOT.js";
@@ -68,15 +68,15 @@ import { a as getByIssueId, i as parseFlywheelStatsWindow, n as derivePipelineRu
68
68
  import { n as writeSequenceMd, t as parseSequenceMd } from "./sequence-io-POKWdusG.js";
69
69
  import { _ as normalizeGate, d as computeEpicGroups, f as computeLanes, h as init_pickup, l as classifyIssue, m as computeWaves, p as computeStats, u as computeCohort, v as selectNeedsPlanning } from "./pickup-BjJsSX12.js";
70
70
  import { C as readCurrentLatestFlywheelStatus, D as writeFlywheelLaunchMetadata, E as subscribeLatestFlywheelStatus, F as setItemRequirements, G as liveOrderIssueLookup, H as getBook, 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, U as getBookAsync, W 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-C7yek87O.js";
71
- import { a as getResourceStacks, c as getCurrentDockerStats, f as getSystemHealthEvidenceSnapshot, g as classifyAgentHealth, h as startSmeeProcessSync, l as getAcceptedSystemHealthSnapshot, m as isSmeeConfiguredSync, o as formatUptime, s as getContainerHistory, u as getDeployStaleness } from "./memory-governor-W8994ASc.js";
71
+ import { a as getResourceStacks, c as getCurrentDockerStats, f as getSystemHealthEvidenceSnapshot, g as classifyAgentHealth, h as startSmeeProcessSync, l as getAcceptedSystemHealthSnapshot, m as isSmeeConfiguredSync, o as formatUptime, s as getContainerHistory, u as getDeployStaleness } from "./memory-governor-A4O6vI9d.js";
72
72
  import { D as detectPlatform, E as validateFeatureName, O as init_platform, S as init_worktree_ops, _ as updateWorkspaceLayout, b as readWorkspaceIdentity, c as installGitHooksInDir, d as init_writer, f as relocateWorkspace, g as unarchiveWorkspace, h as touchWorkspaceAccessed, l as archiveWorkspace, m as setWorkspaceRunCommand, p as setWorkspaceFavorite, s as init_git_hooks, u as createWorkspace, v as upsertProjectFromConfig, x as writeWorkspaceIdentity, y as init_identity_record } from "./workspace-manager-W1OnbvU5.js";
73
73
  import { n as init_workspace_config, t as getDefaultWorkspaceConfigSync } from "./workspace-config-D0CavVtz.js";
74
- import { B as cleanupClosedIssueAgentDirectories, F as setAgentStatusChangedNotifier, I as setAgentStoppedNotifier, J as isBootReconciliationCandidate, K as extendBootReconciliationGrace, L as setMergeReadyNotifier, O as loadConfig, X as startBootReconciliation, Y as listBootReconciliationCandidates, ht as paneShowsClaudeBootBlockingScreen, k as loadState, n as applyBootReconciliationDecision, q as isAutoResumableRole, r as assessDeaconPatrolFreshness, x as getDeaconLogs } from "./deacon-CQxv6Qwv.js";
74
+ import { B as cleanupClosedIssueAgentDirectories, F as setAgentStatusChangedNotifier, I as setAgentStoppedNotifier, J as isBootReconciliationCandidate, K as extendBootReconciliationGrace, L as setMergeReadyNotifier, O as loadConfig, X as startBootReconciliation, Y as listBootReconciliationCandidates, ht as paneShowsClaudeBootBlockingScreen, k as loadState, n as applyBootReconciliationDecision, q as isAutoResumableRole, r as assessDeaconPatrolFreshness, x as getDeaconLogs } from "./deacon-TPYssFYt.js";
75
75
  import { s as getRuntimeForAgent } from "./stuck-remediation-Di5JYkoo.js";
76
76
  import { a as getShadowState, s as init_shadow_state } from "./shadow-state-CEGrrECe.js";
77
77
  import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-dvEWKO7Q.js";
78
78
  import { r as parseArtifactRef } from "./forge-DYX9sKzG.js";
79
- import "./deacon-merge-ugZ7jekt.js";
79
+ import "./deacon-merge-BOGFEV8_.js";
80
80
  import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-D4ULO4qG.js";
81
81
  import { V as getReviewerSessionName, t as init_specialists } from "./specialists-8LcQi9Np.js";
82
82
  import { c as findPrdAnywhereSync, l as readPrdContent, s as findDraftPrd } from "./archive-planning-BwEhu9Oq.js";
@@ -93,11 +93,11 @@ import { r as spawnInspectAgent } from "./inspect-agent-VHSihlb7.js";
93
93
  import { r as lookupPullRequestNumberForBranch, t as githubPrLookupSource } from "./github-pr-lookup-C9Vokb0W.js";
94
94
  import { a as fetchIssuePullRequestDiff, c as getCachedIssuePrTabResponse, i as fetchIssuePullRequestDetails, l as getIssuePrTabCacheGeneration, n as fetchIssueCheckRuns, r as fetchIssuePullRequest, s as bumpIssuePrTabCacheGeneration, u as setCachedIssuePrTabResponse } from "./pull-requests-BcHIsFJv.js";
95
95
  import { n as DOD_ROWS } from "./dod-gK835UMf.js";
96
- import { n as resolveParkedPopulation, r as summarizeParked } from "./resolver-BdHzKhNL.js";
96
+ import { n as resolveParkedPopulation, r as summarizeParked } from "./resolver-C8rooxoz.js";
97
97
  import { a as readCurrentStatus, l as maybeTriggerStatusRollup, s as readRecentObservations, u as writePendingTurn } from "./rollup-QCwYcBdP.js";
98
98
  import { r as isExtendedReviewEnabled } from "./review-agent-7C2w5CzU.js";
99
99
  import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-CMVBT4kT.js";
100
- import { S as ensureSyncGitQuiescent, x as listGitOperationsSync } from "./merge-agent-DxecsTre.js";
100
+ import { S as ensureSyncGitQuiescent, x as listGitOperationsSync } from "./merge-agent-GWhmnxFk.js";
101
101
  import { t as readVerificationArtifact } from "./verification-artifact-0Zku8N-W.js";
102
102
  import { t as getAgentCommandSync } from "./settings-Clw8UVNs.js";
103
103
  import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-CBpLi4Yy.js";
@@ -111,7 +111,7 @@ import { i as getMergeBlockersPayload, n as hasOrderIssuePrd, r as validateBookF
111
111
  import { i as spawnSequencerAgent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-DS00KHVm.js";
112
112
  import { n as sameCanonicalReviewStatus, t as emitReviewStatusChanged } from "./review-status-emit-Cg4tOb8U.js";
113
113
  import "./supervisor-D4v0WfiQ.js";
114
- import { l as startUatTrainReconciler, u as stopUatTrainReconciler } from "./uat-train-CSOval9z.js";
114
+ import { l as startUatTrainReconciler, u as stopUatTrainReconciler } from "./uat-train-DVUNW03P.js";
115
115
  import { n as settlePendingLifecycleClaim, t as claimPendingLifecycleFile } from "./pending-lifecycle-claim-CYgMiDAP.js";
116
116
  import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-BGfl0cHM.js";
117
117
  import { r as readPendingDeploy } from "./deploy-queue-o7shYg1j.js";
@@ -805,7 +805,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
805
805
  }),
806
806
  deepWipe: (issueId, opts) => Effect.tryPromise({
807
807
  try: async () => {
808
- const { deepWipe } = await import("./workflows-C6MkcBR_.js");
808
+ const { deepWipe } = await import("./workflows-Cf4LAnhg.js");
809
809
  const { resolveProjectFromIssueSync } = await import("./projects-DvPEAP18.js");
810
810
  const project = resolveProjectFromIssueSync(issueId);
811
811
  const projectPath = project?.projectPath ?? process.cwd();
@@ -34159,7 +34159,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
34159
34159
  const { ctx, projectConfig } = buildLifecycleContext(id, getIssueDataService$8().getIssueSource(id) ?? void 0);
34160
34160
  const deleteWorkspace = opts.deleteWorkspace ?? true;
34161
34161
  cleanupLog.push(...await closeIssuePullRequest(id, mode === "cancel" ? "Canceled via Overdeck" : "Reset to Todo via Overdeck"));
34162
- const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-ozA4GZNs.js");
34162
+ const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-B0rL38D3.js");
34163
34163
  const workflow = mode === "cancel" ? cancelIssueWorkflow : resetToTodo;
34164
34164
  const result = await Effect.runPromise(workflow(ctx, {
34165
34165
  deleteWorkspace,
@@ -34197,7 +34197,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
34197
34197
  cleanupLog.push("Cleared review status");
34198
34198
  } catch {}
34199
34199
  try {
34200
- const { resetPostMergeState } = await import("./merge-agent-B8YsWRDu.js");
34200
+ const { resetPostMergeState } = await import("./merge-agent-BRSz26Oh.js");
34201
34201
  resetPostMergeState(id);
34202
34202
  resetPostMergeState(id.toUpperCase());
34203
34203
  cleanupLog.push("Cleared merge state");
@@ -34217,7 +34217,7 @@ function closeIssueTransition(options) {
34217
34217
  const { issueId, body, eventStore } = options;
34218
34218
  const { reason } = body;
34219
34219
  const projectPath = getProjectPath$3(void 0, extractPrefixSync(issueId) ?? issueId.split("-")[0]);
34220
- const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-ozA4GZNs.js"));
34220
+ const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-B0rL38D3.js"));
34221
34221
  const githubCheck = isGitHubIssue$4(issueId);
34222
34222
  const issueDataService = getIssueDataService$8();
34223
34223
  const issueSource = issueDataService.getIssueSource(issueId);
@@ -34484,7 +34484,7 @@ function reopenIssueTransition(options) {
34484
34484
  else clearReviewStatus(id.toUpperCase());
34485
34485
  } catch {}
34486
34486
  try {
34487
- const { resetPostMergeState } = await import("./merge-agent-B8YsWRDu.js");
34487
+ const { resetPostMergeState } = await import("./merge-agent-BRSz26Oh.js");
34488
34488
  resetPostMergeState(id);
34489
34489
  resetPostMergeState(id.toUpperCase());
34490
34490
  } catch {}
@@ -35743,7 +35743,7 @@ function closeOutIssue(id, opts = {}) {
35743
35743
  }
35744
35744
  const closeOutResult = yield* Effect.promise(async () => {
35745
35745
  try {
35746
- const { closeOut } = await import("./lifecycle-ozA4GZNs.js");
35746
+ const { closeOut } = await import("./lifecycle-B0rL38D3.js");
35747
35747
  return {
35748
35748
  ok: true,
35749
35749
  result: await Effect.runPromise(closeOut(ctx, {
@@ -35833,7 +35833,7 @@ function bulkCloseOut(body) {
35833
35833
  const invalidIds = issueIds.filter((id) => !isValidIssueId(id));
35834
35834
  if (invalidIds.length > 0) return jsonResponse({ error: `Invalid issue ID format: ${invalidIds.join(", ")}` }, { status: 400 });
35835
35835
  const eventStore = yield* EventStoreService;
35836
- const { closeOut } = yield* Effect.promise(() => import("./lifecycle-ozA4GZNs.js"));
35836
+ const { closeOut } = yield* Effect.promise(() => import("./lifecycle-B0rL38D3.js"));
35837
35837
  const issueDataService = getIssueDataService$5();
35838
35838
  const tasks = [];
35839
35839
  const agentChecks = yield* withConcurrencyLimit(issueIds.map((id) => Effect.promise(async () => {
@@ -51340,7 +51340,7 @@ async function handlePullRequestPromise(payload) {
51340
51340
  bumpIssuePrTabCacheGeneration(issueId);
51341
51341
  const repo = payload.repository.full_name;
51342
51342
  if (payload.action === "closed" && pr.merged === true) try {
51343
- const { postMergeLifecycle } = await import("./merge-agent-B8YsWRDu.js");
51343
+ const { postMergeLifecycle } = await import("./merge-agent-BRSz26Oh.js");
51344
51344
  const { resolveProjectFromIssueSync } = await import("./projects-DvPEAP18.js");
51345
51345
  const project = resolveProjectFromIssueSync(issueId);
51346
51346
  if (project) {
@@ -53846,7 +53846,7 @@ async function getMergeTrainQueuesPayload() {
53846
53846
  /** PAN-1696 AC2: per-project generation chains across every tracked project. */
53847
53847
  async function getMergeTrainGenerationsPayload() {
53848
53848
  const { isMergeTrainEnabledForProject } = await import("./merge-sync-CM2-myXu.js");
53849
- const { getUatGenerationsPayload } = await import("./uat-train-fK0FbCx7.js");
53849
+ const { getUatGenerationsPayload } = await import("./uat-train-COSy-vEX.js");
53850
53850
  return (await Promise.allSettled(listProjectsSync().map(async ({ key, config }) => ({
53851
53851
  projectKey: key,
53852
53852
  projectName: config.name,
@@ -53860,7 +53860,7 @@ async function defaultOrderedIssueIdsForProject(projectPath) {
53860
53860
  return (await Effect.runPromise(computeMergeQueueFromCandidates(candidates, projectPath).pipe(Effect.provide(layer)))).map((item) => item.issueId);
53861
53861
  }
53862
53862
  async function defaultMergeOne(issueId) {
53863
- const { triggerMerge } = await import("./merge-ops-C9wpFz1G.js");
53863
+ const { triggerMerge } = await import("./merge-ops-DtHx17Vd.js");
53864
53864
  const r = await triggerMerge(issueId);
53865
53865
  return r.success ? { ok: true } : {
53866
53866
  ok: false,
@@ -53924,7 +53924,7 @@ async function postMergeTrainAssemblePayload(payload) {
53924
53924
  status: 404,
53925
53925
  body: { error: `Unknown project key: ${projectKey}` }
53926
53926
  };
53927
- const { runUatTrainReconcile } = await import("./uat-train-fK0FbCx7.js");
53927
+ const { runUatTrainReconcile } = await import("./uat-train-COSy-vEX.js");
53928
53928
  return {
53929
53929
  status: 200,
53930
53930
  body: { projects: [{
@@ -53936,7 +53936,7 @@ async function postMergeTrainAssemblePayload(payload) {
53936
53936
  }] }
53937
53937
  };
53938
53938
  }
53939
- const { runUatTrainReconcileAllProjects } = await import("./uat-train-fK0FbCx7.js");
53939
+ const { runUatTrainReconcileAllProjects } = await import("./uat-train-COSy-vEX.js");
53940
53940
  return {
53941
53941
  status: 200,
53942
53942
  body: { projects: await runUatTrainReconcileAllProjects({ force: true }) }
@@ -53986,7 +53986,7 @@ const postMergeTrainGenerationStackRoute = HttpRouter.add("POST", "/api/merge-tr
53986
53986
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
53987
53987
  if (authError) return authError;
53988
53988
  const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
53989
- const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-fK0FbCx7.js"));
53989
+ const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-COSy-vEX.js"));
53990
53990
  const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
53991
53991
  if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
53992
53992
  return jsonResponse({
@@ -54003,8 +54003,8 @@ const postMergeTrainGenerationPromoteRoute = HttpRouter.add("POST", "/api/merge-
54003
54003
  const rawShipVersion = parsed.body["shipVersion"];
54004
54004
  if (rawShipVersion !== void 0 && (typeof rawShipVersion !== "string" || !/^\d+\.\d+\.\d+$/.test(rawShipVersion))) return jsonResponse({ error: "shipVersion must look like 48.8.0" }, { status: 400 });
54005
54005
  const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
54006
- const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-fK0FbCx7.js"));
54007
- const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-DhLEuxVX.js"));
54006
+ const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-COSy-vEX.js"));
54007
+ const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-xXcJHAyg.js"));
54008
54008
  const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle, rawShipVersion));
54009
54009
  if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
54010
54010
  return jsonResponse(result);
@@ -60597,7 +60597,7 @@ const postFlywheelBriefRoute = HttpRouter.add("POST", "/api/flywheel/brief", htt
60597
60597
  });
60598
60598
  })));
60599
60599
  const getUatCandidateRoute = HttpRouter.add("GET", "/api/flywheel/uat-candidate", httpHandler(Effect.gen(function* () {
60600
- const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-fK0FbCx7.js"));
60600
+ const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-COSy-vEX.js"));
60601
60601
  return jsonResponse(yield* Effect.promise(() => getUatCandidatePayload()));
60602
60602
  })));
60603
60603
  const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
@@ -66179,7 +66179,7 @@ const RESTART_MARKER = join$1(homedir(), ".overdeck", "dashboard-restarting.json
66179
66179
  * loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
66180
66180
  */
66181
66181
  async function defaultLifecycleRunner(pending) {
66182
- const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-B8YsWRDu.js");
66182
+ const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-BRSz26Oh.js");
66183
66183
  await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
66184
66184
  if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
66185
66185
  }
@@ -66376,7 +66376,7 @@ function failureReason(result) {
66376
66376
  return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
66377
66377
  }
66378
66378
  async function defaultMergeIssue(issueId) {
66379
- const { triggerMerge } = await import("./merge-ops-C9wpFz1G.js");
66379
+ const { triggerMerge } = await import("./merge-ops-DtHx17Vd.js");
66380
66380
  return triggerMerge(issueId);
66381
66381
  }
66382
66382
  function defaultAnnounceFailure(issueId, reason) {
@@ -20,7 +20,7 @@ import { i as issue_service_singleton_exports, n as init_issue_service_singleton
20
20
  import { h as loadReviewStatuses, p as init_review_status, w as setReviewStatusSync } from "./review-status-DBnR5t4z.js";
21
21
  import { h as init_pickup, r as LEGACY_PARKED_LABELS } from "./pickup-BjJsSX12.js";
22
22
  import "./flywheel-C7yek87O.js";
23
- import { C as getLastPatrolResult, D as isDeaconRunning, N as runPatrol, R as startDeacon, S as getDeaconStatus, r as assessDeaconPatrolFreshness, x as getDeaconLogs, z as stopDeacon } from "./deacon-CQxv6Qwv.js";
23
+ import { C as getLastPatrolResult, D as isDeaconRunning, N as runPatrol, R as startDeacon, S as getDeaconStatus, r as assessDeaconPatrolFreshness, x as getDeaconLogs, z as stopDeacon } from "./deacon-TPYssFYt.js";
24
24
  import { n as renderPrompt, t as init_prompts } from "./prompts-BiS5I2tZ.js";
25
25
  import { t as getCloisterEventStore } from "./event-store-provider-BKvk2rDj.js";
26
26
  import { s as getRuntimeForAgent } from "./stuck-remediation-Di5JYkoo.js";
@@ -1855,7 +1855,7 @@ async function handleCloisterDomainEventPromise(event) {
1855
1855
  if (event.type === "agent.stopped") {
1856
1856
  const agentId = event.payload?.agentId;
1857
1857
  if (agentId) {
1858
- const { handleAgentStoppedEvent, handleAgentStoppedForOrphanReviewerSessions } = await import("./deacon-CeqVPw0o.js");
1858
+ const { handleAgentStoppedEvent, handleAgentStoppedForOrphanReviewerSessions } = await import("./deacon-BEH-IY0v.js");
1859
1859
  const { handleAgentLifecycleEventForIdleStack } = await import("./idle-stack-reaper-CHtCNpvd.js");
1860
1860
  handleAgentLifecycleEventForIdleStack(agentId);
1861
1861
  const slotMatch = /^agent-(.+)-slot-\d+$/.exec(agentId);
@@ -1875,7 +1875,7 @@ async function handleCloisterDomainEventPromise(event) {
1875
1875
  if (event.type === "agent.heartbeat_dead") {
1876
1876
  const agentId = event.payload?.agentId;
1877
1877
  if (agentId) {
1878
- const { handleAgentHeartbeatDeadEvent } = await import("./deacon-CeqVPw0o.js");
1878
+ const { handleAgentHeartbeatDeadEvent } = await import("./deacon-BEH-IY0v.js");
1879
1879
  await handleAgentHeartbeatDeadEvent(agentId, "event");
1880
1880
  }
1881
1881
  return;
@@ -1884,7 +1884,7 @@ async function handleCloisterDomainEventPromise(event) {
1884
1884
  const payload = event.payload;
1885
1885
  const issueId = payload?.issueId;
1886
1886
  if (issueId) {
1887
- const { handleReviewCoordinatorDied } = await import("./deacon-CeqVPw0o.js");
1887
+ const { handleReviewCoordinatorDied } = await import("./deacon-BEH-IY0v.js");
1888
1888
  await handleReviewCoordinatorDied(issueId, payload?.sessionName ?? "", payload?.reason ?? "");
1889
1889
  }
1890
1890
  return;
@@ -1892,7 +1892,7 @@ async function handleCloisterDomainEventPromise(event) {
1892
1892
  if (event.type === "work.completed") {
1893
1893
  const issueId = event.payload?.issueId;
1894
1894
  if (issueId) {
1895
- const { handleWorkCompleted } = await import("./deacon-CeqVPw0o.js");
1895
+ const { handleWorkCompleted } = await import("./deacon-BEH-IY0v.js");
1896
1896
  await handleWorkCompleted(issueId);
1897
1897
  }
1898
1898
  }
@@ -4066,4 +4066,4 @@ function getCloisterService() {
4066
4066
  //#endregion
4067
4067
  export { generateHealthSummary as a, CostDoorLive as c, CostWriter as d, performHandoff as i, CostResolver as l, readCloisterStateFile as n, getAgentHealth as o, checkAllTriggers as r, getAgentsNeedingAttention as s, getCloisterService as t, CostResolverLive as u };
4068
4068
 
4069
- //# sourceMappingURL=service-0hbSVeHz.js.map
4069
+ //# sourceMappingURL=service-BLb_CyPL.js.map