@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.
- package/dist/{build-info-Ck2TzOSQ.js → build-info-Bts-0E0B.js} +3 -3
- package/dist/{build-info-Ck2TzOSQ.js.map → build-info-Bts-0E0B.js.map} +1 -1
- package/dist/build-info-CD0O1MvT.js +2 -0
- package/dist/cli/index.js +4 -4
- package/dist/dashboard/{build-info-DXfOjbg3.js → build-info-DTX8JwVP.js} +3 -3
- package/dist/dashboard/{build-info-DXfOjbg3.js.map → build-info-DTX8JwVP.js.map} +1 -1
- package/dist/dashboard/build-info-PQlh_Rhb.js +2 -0
- package/dist/dashboard/{deacon-CeqVPw0o.js → deacon-BEH-IY0v.js} +2 -2
- package/dist/dashboard/{deacon-CQxv6Qwv.js → deacon-TPYssFYt.js} +8 -8
- package/dist/dashboard/{deacon-CQxv6Qwv.js.map → deacon-TPYssFYt.js.map} +1 -1
- package/dist/dashboard/{deacon-merge-ugZ7jekt.js → deacon-merge-BOGFEV8_.js} +5 -5
- package/dist/dashboard/{deacon-merge-ugZ7jekt.js.map → deacon-merge-BOGFEV8_.js.map} +1 -1
- package/dist/dashboard/{deacon-pending-lifecycle-Cxu6Rezs.js → deacon-pending-lifecycle-DVHjOLje.js} +2 -2
- package/dist/dashboard/{deacon-pending-lifecycle-Cxu6Rezs.js.map → deacon-pending-lifecycle-DVHjOLje.js.map} +1 -1
- package/dist/dashboard/deacon.js +2 -2
- package/dist/dashboard/{deploy-patrol-DxnpZcnl.js → deploy-patrol-BXjlvoV3.js} +2 -2
- package/dist/dashboard/{deploy-patrol-DxnpZcnl.js.map → deploy-patrol-BXjlvoV3.js.map} +1 -1
- package/dist/dashboard/{identity-BnxKo9-z.js → identity-Bwh6VGeL.js} +2 -2
- package/dist/dashboard/{identity-BnxKo9-z.js.map → identity-Bwh6VGeL.js.map} +1 -1
- package/dist/dashboard/{lifecycle-ozA4GZNs.js → lifecycle-B0rL38D3.js} +2 -2
- package/dist/dashboard/{lifecycle-ozA4GZNs.js.map → lifecycle-B0rL38D3.js.map} +1 -1
- package/dist/dashboard/{memory-governor-W8994ASc.js → memory-governor-A4O6vI9d.js} +3 -3
- package/dist/dashboard/{memory-governor-W8994ASc.js.map → memory-governor-A4O6vI9d.js.map} +1 -1
- package/dist/dashboard/{memory-pressure-patrol-D_T_QLFC.js → memory-pressure-patrol-BWlWywmA.js} +2 -2
- package/dist/dashboard/{memory-pressure-patrol-D_T_QLFC.js.map → memory-pressure-patrol-BWlWywmA.js.map} +1 -1
- package/dist/dashboard/{merge-agent-B8YsWRDu.js → merge-agent-BRSz26Oh.js} +1 -1
- package/dist/dashboard/{merge-agent-DxecsTre.js → merge-agent-GWhmnxFk.js} +2 -2
- package/dist/dashboard/{merge-agent-DxecsTre.js.map → merge-agent-GWhmnxFk.js.map} +1 -1
- package/dist/dashboard/merge-ops-DtHx17Vd.js +2 -0
- package/dist/dashboard/{post-merge-lifecycle-worker-DC-i1kqz.js → post-merge-lifecycle-worker-KK1RTKRE.js} +2 -2
- package/dist/dashboard/{post-merge-lifecycle-worker-DC-i1kqz.js.map → post-merge-lifecycle-worker-KK1RTKRE.js.map} +1 -1
- package/dist/dashboard/{resolver-BdHzKhNL.js → resolver-C8rooxoz.js} +2 -2
- package/dist/dashboard/{resolver-BdHzKhNL.js.map → resolver-C8rooxoz.js.map} +1 -1
- package/dist/dashboard/server.js +28 -28
- package/dist/dashboard/{service-0hbSVeHz.js → service-BLb_CyPL.js} +6 -6
- package/dist/dashboard/{service-0hbSVeHz.js.map → service-BLb_CyPL.js.map} +1 -1
- package/dist/dashboard/{specialists-C2ZVszIW.js → specialists-DocAK-7A.js} +5 -5
- package/dist/dashboard/{specialists-C2ZVszIW.js.map → specialists-DocAK-7A.js.map} +1 -1
- package/dist/dashboard/{specialists-DhLEuxVX.js → specialists-xXcJHAyg.js} +1 -1
- package/dist/dashboard/{stall-sweeper-o4-q0vqY.js → stall-sweeper-DOyIfeLR.js} +2 -2
- package/dist/dashboard/{stall-sweeper-o4-q0vqY.js.map → stall-sweeper-DOyIfeLR.js.map} +1 -1
- package/dist/dashboard/{uat-train-fK0FbCx7.js → uat-train-COSy-vEX.js} +1 -1
- package/dist/dashboard/{uat-train-CSOval9z.js → uat-train-DVUNW03P.js} +0 -0
- package/dist/dashboard/{uat-train-CSOval9z.js.map → uat-train-DVUNW03P.js.map} +1 -1
- package/dist/dashboard/{workflows-BnNc1QlT.js → workflows-BYwR2aIN.js} +2 -2
- package/dist/dashboard/{workflows-BnNc1QlT.js.map → workflows-BYwR2aIN.js.map} +1 -1
- package/dist/dashboard/workflows-Cf4LAnhg.js +2 -0
- package/dist/dashboard/{workspaces-CqeaoIK6.js → workspaces-BlpbOPZ7.js} +11 -11
- package/dist/dashboard/{workspaces-CqeaoIK6.js.map → workspaces-BlpbOPZ7.js.map} +1 -1
- package/dist/{lifecycle-Bhu9mEsV.js → lifecycle-BhAciIXh.js} +1 -1
- package/dist/{lifecycle-CMRdm3mR.js → lifecycle-D8m3w850.js} +2 -2
- package/dist/{lifecycle-CMRdm3mR.js.map → lifecycle-D8m3w850.js.map} +1 -1
- package/dist/{merge-agent-DQ7DOXE2.js → merge-agent-CUnIrr8R.js} +2 -2
- package/dist/{merge-agent-DQ7DOXE2.js.map → merge-agent-CUnIrr8R.js.map} +1 -1
- package/dist/{merge-agent-D33x_y_T.js → merge-agent-DwfVId_E.js} +1 -1
- package/package.json +1 -1
- package/dist/build-info-B9bbKbXz.js +0 -2
- package/dist/dashboard/build-info-CrBYH-L2.js +0 -2
- package/dist/dashboard/merge-ops-C9wpFz1G.js +0 -2
- package/dist/dashboard/workflows-C6MkcBR_.js +0 -2
|
@@ -15,7 +15,7 @@ async function drainQueue() {
|
|
|
15
15
|
continue;
|
|
16
16
|
}
|
|
17
17
|
try {
|
|
18
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
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-
|
|
50
|
+
//# sourceMappingURL=post-merge-lifecycle-worker-KK1RTKRE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-merge-lifecycle-worker-
|
|
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-
|
|
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-
|
|
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":";;;;;;;;;oBAiC4E;cACE;mBAIlB;aACL;eACsB;YAG/B;;;;;;;AAsB9C,MAAa,wBAAgD;CAC3D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;AAkBD,MAAM,oBAAsE;CAC1E,6BAA6B;EAC3B,MAAM;EACN,QAAQ;EACT;CACD,+BAA+B;EAC7B,MAAM;EACN,QAAQ;EACT;CACD,iCAAiC;EAC/B,MAAM;EACN,QAAQ;EACT;CACD,oBAAoB;EAClB,MAAM;EACN,QAAQ;EACT;CACD,oBAAoB;EAClB,MAAM;EACN,QAAQ;EACT;CACD,eAAe;EACb,MAAM;EACN,QAAQ;EACT;CACD,kBAAkB;EAChB,MAAM;EACN,QAAQ;EACT;CACD,aAAa;EACX,MAAM;EACN,QAAQ;EACT;CACD,kBAAkB;EAChB,MAAM;EACN,QAAQ;EACT;CACD,6BAA6B;EAC3B,MAAM;EACN,QAAQ;EACT;CACD,oBAAoB;EAClB,MAAM;EACN,QAAQ;EACT;CACD,yBAAyB;EACvB,MAAM;EACN,QAAQ;EACT;CACD,iCAAiC;EAC/B,MAAM;EACN,QAAQ;EACT;CACF;;;;;;;;;;AAcD,MAAa,oBAAyC,IAAI,IAAI;CAAC;CAAY;CAAa;CAAgB;CAAY,CAAC;AAiBrH,SAAS,MAAM,IAAwC,UAA0B;AAC/E,KAAI,OAAO,OAAO,YAAY,OAAO,SAAS,GAAG,CAAE,QAAO,IAAI,KAAK,GAAG,CAAC,aAAa;AACpF,KAAI,OAAO,OAAO,YAAY,IAAI;EAChC,MAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,MAAI,OAAO,SAAS,OAAO,CAAE,QAAO,IAAI,KAAK,OAAO,CAAC,aAAa;;AAEpE,QAAO,IAAI,KAAK,SAAS,CAAC,aAAa;;;;;;;;;;;AAYzC,SAAgB,0BAA0B,SAA0B;CAClE,MAAM,MAAM,KAAK,iBAAiB,EAAE,UAAU,QAAQ;AACtD,QAAO,WAAW,KAAK,KAAK,YAAY,CAAC,IAAI,WAAW,KAAK,KAAK,sBAAsB,CAAC;;;;;;;;AAS3F,SAAgB,uBAAuB,KAAqB;CAC1D,MAAM,QAAQ,IAAI,MAAM,CAAC,aAAa;AACtC,KAAI,CAAC,QAAQ,KAAK,MAAM,CAAE,QAAO;AACjC,KAAI,4BAA4B,MAAM,CAAE,QAAO;AAC/C,QAAO,OAAO;;AAGhB,SAAS,UAAU,QAA8D;AAC/E,KAAI,UAAU,kBAAkB,QAAS,QAAO,kBAAkB;AAClE,QAAO;EACL,MAAM,iBAAiB,SAAS,KAAK,OAAO,KAAK,GAAG;EACpD,QAAQ;EACT;;;;;;;;;AAUH,SAAgB,eAAe,GAA+B;CAC5D,MAAM,OAAoB,EAAE;CAC5B,MAAM,IAAI,EAAE;CACZ,MAAM,UAAU,EAAE;CAClB,MAAM,QAAQ,OAAoB,UAAkB,YAAoB,iBAAyB,YAAsC;AACrI,OAAK,KAAK;GAAE;GAAS;GAAO;GAAU;GAAY;GAAiB,GAAI,UAAU,EAAE,SAAS,GAAG,EAAE;GAAG,CAAC;;CAOvG,MAAM,SAAS,EAAE,gBAAgB;AAGjC,KAAI,CAAC,UAAU,GAAG,OAAO;EACvB,MAAM,OAAO,UAAU,EAAE,YAAY;AACrC,OAAK,cAAc,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,MAAM,KAAK,QAAQ,EAAE,aAAa,EAAE,eAAe,MAAM,CAAC;;AAI5H,KAAI,CAAC,OAAQ,MAAK,MAAM,QAAQ,EAAE,kBAChC,MACE,aACA,MAAM,KAAK,mBAAmB,EAAE,IAAI,EACpC,yCAAyC,KAAK,aAAa,kDAC3D,yGACA,EAAE,cAAc,KAAK,cAAc,CACpC;AAIH,KAAI,CAAC,UAAU,GAAG,cAChB,MACE,kBACA,MAAM,EAAE,mBAAmB,EAAE,WAAW,EAAE,IAAI,EAC9C,gCAAgC,EAAE,sBAAsB,MAAM,EAAE,wBAAwB,MACxF,gEACA,EAAE,QAAQ,EAAE,uBAAuB,MAAM,CAC1C;AAQH,KAAI,CAAC,QAAQ;EACX,MAAM,2BAAW,IAAI,KAA0H;AAC/I,OAAK,MAAM,SAAS,EAAE,OACpB,KAAI,MAAM,WAAW,QAAQ,MAAM,uBAAuB,MAAM;GAC9D,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI;IAAE,UAAU,MAAM,MAAM,UAAU,EAAE,IAAI;IAAE,UAAU,EAAE;IAAE,QAAQ;IAAI,QAAQ;IAAI;AACtH,OAAI,SAAS,KAAK,MAAM,GAAG;GAC3B,MAAM,KAAK,MAAM,MAAM,UAAU,EAAE,IAAI;AACvC,OAAI,KAAK,IAAI,SAAU,KAAI,WAAW;AACtC,OAAI,MAAM,gBAAgB,CAAC,IAAI,OAAQ,KAAI,SAAS,MAAM;AAC1D,YAAS,IAAI,UAAU,IAAI;aAClB,MAAM,aAAa,MAAM;GAClC,MAAM,MAAM,SAAS,IAAI,WAAW,IAAI;IAAE,UAAU,MAAM,MAAM,YAAY,EAAE,IAAI;IAAE,UAAU,EAAE;IAAE,QAAQ;IAAI,QAAQ;IAAI;AAC1H,OAAI,SAAS,KAAK,MAAM,GAAG;GAC3B,MAAM,KAAK,MAAM,MAAM,YAAY,EAAE,IAAI;AACzC,OAAI,KAAK,IAAI,SAAU,KAAI,WAAW;AACtC,YAAS,IAAI,YAAY,IAAI;aACpB,MAAM,kBAAkB,QAAQ,MAAM,WAAW,aAAa,CAAC,0BAA0B,MAAM,GAAG,EAAE;GAC7G,MAAM,MAAM,SAAS,IAAI,kBAAkB,IAAI;IAAE,UAAU,MAAM,MAAM,WAAW,EAAE,IAAI;IAAE,UAAU,EAAE;IAAE,QAAQ;IAAI,QAAQ;IAAI;AAChI,OAAI,SAAS,KAAK,MAAM,GAAG;GAC3B,MAAM,KAAK,MAAM,MAAM,WAAW,EAAE,IAAI;AACxC,OAAI,KAAK,IAAI,SAAU,KAAI,WAAW;AACtC,YAAS,IAAI,mBAAmB,IAAI;;AAGxC,OAAK,MAAM,CAAC,MAAM,QAAQ,UAAU;GAClC,MAAM,QAAQ,IAAI,SAAS,KAAK,KAAK;AACrC,OAAI,SAAS,SACX,MAAK,iBAAiB,IAAI,UAAU,GAAG,MAAM,kBAAkB,IAAI,SAAS,MAAM,IAAI,WAAW,MAAM,qFAAqF;IAAE;IAAM,UAAU,IAAI;IAAU,CAAC;YACpN,SAAS,WAClB,MAAK,iBAAiB,IAAI,UAAU,GAAG,MAAM,wDAAwD,6DAA6D;IAAE;IAAM,UAAU,IAAI;IAAU,CAAC;OAEnM,MAAK,iBAAiB,IAAI,UAAU,GAAG,MAAM,4EAA4E,uEAAuE;IAAE;IAAM,UAAU,IAAI;IAAU,CAAC;;;CAMvO,MAAM,mBAAmB,EAAE,WAAW,MAAM,UAAU,MAAM,SAAS,OAAO;AAC5E,KAAI,CAAC,UAAU,GAAG,cAAc,YAAY,EAAE,gBAAgB,YAAY,CAAC,EAAE,iBAAiB,CAAC,iBAC7F,MACE,cACA,MAAM,EAAE,WAAW,EAAE,IAAI,EACzB,iJACA,2GACA,EAAE,UAAU,EAAE,YAAY,MAAM,CACjC;AAIH,KAAI,CAAC,UAAU,GAAG,gBAAgB,UAAU;EAC1C,MAAM,UAAU,EAAE,mBAAmB;AACrC,OACE,gBACA,MAAM,EAAE,WAAW,EAAE,IAAI,EACzB,WAAA,IACI,2DACA,0CACJ,sHACA;GAAE,iBAAiB;GAAS,YAAY,EAAE,cAAc;GAAM,CAC/D;;AAIH,MAAK,MAAM,SAAS,EAAE,YAAY;AAEhC,MAAI,EADW,GAAG,gBAAgB,YAAY,EAAE,gBAAgB,MACnD;AACb,OACE,kBACA,MAAM,MAAM,gBAAgB,MAAM,WAAW,EAAE,IAAI,EACnD,GAAG,MAAM,GAAG,qCAAqC,GAAG,gBAAgB,WAAW,WAAW,SAAS,2DACnG,wEACA;GAAE,SAAS,MAAM;GAAI,aAAa,GAAG,eAAe;GAAM,CAC3D;;CAIH,MAAM,WAAW,GAAG,oBAAoB;AACxC,KAAI,CAAC,UAAU,YAAY,GACzB,MACE,mBACA,MAAM,GAAG,WAAW,EAAE,IAAI,EAC1B,8BAA8B,SAAS,yDACvC,yFACA,EAAE,kBAAkB,UAAU,CAC/B;AAKH,KAAI,CAAC,UAAU,KAAK,WAAW,EAC7B,MAAK,MAAM,SAAS,EAAE,YAAY;AAIhC,MAAI,kBAAkB,IAAI,OAAO,MAAM,QAAQ,GAAG,CAAC,CAAE;EACrD,MAAM,SAAS,KAAK,MAAM,MAAM,gBAAgB,MAAM,aAAa,GAAG;AACtE,MAAI,CAAC,OAAO,SAAS,OAAO,CAAE;EAC9B,MAAM,SAAS,EAAE,MAAM;AACvB,MAAI,SAAA,MAAoC;AAGxC,MAAI,uBAAuB,EAAE,CAAE;AAC/B,OACE,gBACA,IAAI,KAAK,OAAO,CAAC,aAAa,EAC9B,GAAG,MAAM,GAAG,qCAAqC,KAAK,MAAM,SAAS,IAAO,CAAC,oDAC7E,sGACA;GAAE,SAAS,MAAM;GAAI,aAAa,KAAK,MAAM,SAAS,IAAO;GAAE,CAChE;;AAIL,QAAO;;AAYT,eAAe,qBAAqB,SAAkF;AACpH,KAAI;EACF,MAAM,WAAW,4BAA4B,QAAQ;AACrD,MAAI,CAAC,SAAU,QAAO,EAAE;EACxB,MAAM,UAAU,eAAe,SAAS,WAAW;AACnD,MAAI,CAAC,QAAS,QAAO,EAAE;AAEvB,WAAQ,MADa,gBAAgB,SAAS,QAAQ,GACtC,iBAAiB,EAAE,EAChC,QAAQ,SAAS,KAAK,SAAS,KAAK,CACpC,KAAK,UAAU;GAAE,cAAc,KAAK;GAAc,GAAI,KAAK,oBAAoB,EAAE,mBAAmB,KAAK,mBAAmB,GAAG,EAAE;GAAG,EAAE;SACnI;AAGN,SAAO,EAAE;;;;;;;;;;;AAYb,eAAsB,wBAAwB,UAAgC,EAAE,EAAwB;CACtG,MAAM,MAAM,QAAQ,OAAO,KAAK,KAAK;CACrC,MAAM,YAAY,QAAQ,iBAAiB;CAC3C,MAAM,WAAW,QAAQ,YAAY;CAErC,MAAM,WAAW,oBAAoB;CACrC,MAAM,YAAY,iBAAiB;CACnC,MAAM,aAAa,uBAAuB,CAAC,QAAQ,MAAM,EAAE,eAAe,EAAE,WAAW,aAAa,EAAE,WAAW,YAAY;CAE7H,MAAM,gCAAgB,IAAI,KAA2B;AACrD,MAAK,MAAM,SAAS,WAAW;EAC7B,MAAM,UAAU,uBAAuB,MAAM,WAAW,GAAG;AAC3D,MAAI,CAAC,QAAS;EACd,MAAM,OAAO,cAAc,IAAI,QAAQ,IAAI,EAAE;AAC7C,OAAK,KAAK,MAAM;AAChB,gBAAc,IAAI,SAAS,KAAK;;CAElC,MAAM,8BAAc,IAAI,KAAuD;AAC/E,MAAK,MAAM,SAAS,YAAY;EAC9B,MAAM,UAAU,uBAAuB,MAAM,WAAW,GAAG;AAC3D,MAAI,CAAC,QAAS;EACd,MAAM,OAAO,YAAY,IAAI,QAAQ,IAAI,EAAE;AAC3C,OAAK,KAAK,MAAM;AAChB,cAAY,IAAI,SAAS,KAAK;;CAGhC,MAAM,eAAe,IAAI,IAAY;EAAC,GAAG,OAAO,KAAK,SAAS,CAAC,KAAK,OAAO,GAAG,aAAa,CAAC;EAAE,GAAG,cAAc,MAAM;EAAE,GAAG,YAAY,MAAM;EAAC,CAAC;CAO9I,MAAM,gCAAgB,IAAI,KAAsB;CAChD,MAAM,cAAc,OAAO,YAA0C;EAEnE,MAAM,eAAe,SADH,OAAO,KAAK,SAAS,CAAC,MAAM,QAAQ,IAAI,aAAa,KAAK,QAAQ,IAAI,YAC5C;EAC5C,MAAM,OAAO,YAAY,IAAI,QAAQ,IAAI,EAAE;EAC3C,IAAI,cAAc,cAAc,IAAI,QAAQ,IAAI;AAChD,MAAI,gBAAgB,QAAQ,KAAK,SAAS,KAAK,cAAc,gBAAgB,SAI3E,KAAI;AAAE,iBAAc,MAAM,SAAS,QAAQ;AAAE,iBAAc,IAAI,SAAS,YAAY;UAAU;AAAE,iBAAc;;EAEhH,MAAM,QAAQ,gBAAgB,OAAO,EAAE,GAAG,MAAM,UAAU,QAAQ;AAClE,SAAO,eAAe;GACpB;GACA;GACA,QAAQ,cAAc,IAAI,QAAQ,IAAI,EAAE;GACxC,YAAY;GACZ,mBAAmB;GACnB;GACA;GACD,CAAC;;CAGJ,MAAM,4BAAY,IAAI,KAA0B;AAChD,MAAK,MAAM,WAAW,cAAc;EAClC,MAAM,OAAO,MAAM,YAAY,QAAQ;AACvC,MAAI,KAAK,SAAS,EAAG,WAAU,IAAI,SAAS,KAAK;;CAEnD,MAAM,OAAoB,EAAE;AAC5B,MAAK,MAAM,CAAC,SAAS,aAAa,WAAW;AAC3C,MAAI,CAAC,cAAc,IAAI,QAAQ,CAC7B,KAAI;AAAE,iBAAc,IAAI,SAAS,MAAM,SAAS,QAAQ,CAAC;UAAU;AAErE,MAAI,cAAc,IAAI,QAAQ,KAAK,KAEjC,MAAK,KAAK,GAAG,SAAS,QAAQ,QAAQ,IAAI,UAAU,iBAAiB,CAAC;MAEtE,MAAK,KAAK,GAAG,SAAS;;AAI1B,QAAO,KAAK,MAAM,GAAG,MAAM,EAAE,SAAS,cAAc,EAAE,SAAS,IAAI,EAAE,QAAQ,cAAc,EAAE,QAAQ,CAAC;;;AAIxG,SAAgB,gBAAgB,MAA6H;CAC3J,MAAM,UAAkC,EAAE;CAC1C,MAAM,iBAA8C,EAAE;CACtD,MAAM,yBAAS,IAAI,KAAa;AAChC,MAAK,MAAM,OAAO,MAAM;AACtB,UAAQ,IAAI,UAAU,QAAQ,IAAI,UAAU,KAAK;AACjD,SAAO,IAAI,IAAI,QAAQ;EACvB,MAAM,UAAU,eAAe,IAAI;AACnC,MAAI,CAAC,WAAW,sBAAsB,QAAQ,IAAI,MAAM,GAAG,sBAAsB,QAAQ,QAAQ,CAC/F,gBAAe,IAAI,WAAW,IAAI;;AAGtC,QAAO;EAAE,OAAO,OAAO;EAAM;EAAS;EAAgB"}
|
|
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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"}
|
package/dist/dashboard/server.js
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
54007
|
-
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
4069
|
+
//# sourceMappingURL=service-BLb_CyPL.js.map
|