panopticon-cli 0.6.7 → 0.6.9
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/{agents-D_2oRFVf.js → agents-BQOqo27C.js} +1 -1
- package/dist/{agents-CfFDs52G.js → agents-DezveQ1x.js} +4 -4
- package/dist/{agents-CfFDs52G.js.map → agents-DezveQ1x.js.map} +1 -1
- package/dist/cli/index.js +34 -34
- package/dist/{config-yaml-DGbLSMCa.js → config-yaml-BHD2Qdd8.js} +22 -1
- package/dist/config-yaml-BHD2Qdd8.js.map +1 -0
- package/dist/{config-yaml-Dqt4FWQH.js → config-yaml-IlSnFzJQ.js} +1 -1
- package/dist/dashboard/{agent-enrichment-DdO7ZqjI.js → agent-enrichment-BKZjVvlL.js} +3 -3
- package/dist/dashboard/{agent-enrichment-DdO7ZqjI.js.map → agent-enrichment-BKZjVvlL.js.map} +1 -1
- package/dist/dashboard/{agent-enrichment-dLeGE1fX.js → agent-enrichment-iY3_PylI.js} +1 -1
- package/dist/dashboard/{agents-DCpQQ_W5.js → agents-BQWA-Vps.js} +4 -4
- package/dist/dashboard/{agents-DCpQQ_W5.js.map → agents-BQWA-Vps.js.map} +1 -1
- package/dist/dashboard/{agents-Dgh2TjSp.js → agents-Dinc9j_8.js} +1 -1
- package/dist/dashboard/{config-yaml-DkresmrS.js → config-yaml-CNNnB4Mu.js} +1 -1
- package/dist/dashboard/{config-yaml-DSfYpzN6.js → config-yaml-DUu0JI25.js} +22 -1
- package/dist/dashboard/{config-yaml-DSfYpzN6.js.map → config-yaml-DUu0JI25.js.map} +1 -1
- package/dist/dashboard/{factory-C8nhLGHB.js → factory-CBY0WWeE.js} +2 -2
- package/dist/dashboard/{factory-C8nhLGHB.js.map → factory-CBY0WWeE.js.map} +1 -1
- package/dist/dashboard/{inspect-agent-7eour7EA.js → inspect-agent-KKOeNR7E.js} +3 -3
- package/dist/dashboard/{inspect-agent-7eour7EA.js.map → inspect-agent-KKOeNR7E.js.map} +1 -1
- package/dist/dashboard/{issue-service-singleton-Wv4xBm3y.js → issue-service-singleton-BCZ62hLj.js} +3 -3
- package/dist/dashboard/{issue-service-singleton-Wv4xBm3y.js.map → issue-service-singleton-BCZ62hLj.js.map} +1 -1
- package/dist/dashboard/{issue-service-singleton-Co__-6kL.js → issue-service-singleton-BGKf0A95.js} +1 -1
- package/dist/dashboard/{lifecycle-BcUmtkR4.js → lifecycle-Dpgg-IeP.js} +1 -1
- package/dist/dashboard/{merge-agent-CGN3TT0a.js → merge-agent-CqvQu-n_.js} +1 -1
- package/dist/dashboard/{merge-agent-yudQOPZc.js → merge-agent-Dxxc4JEE.js} +5 -5
- package/dist/dashboard/{merge-agent-yudQOPZc.js.map → merge-agent-Dxxc4JEE.js.map} +1 -1
- package/dist/dashboard/public/assets/{dist-CXaO6nOE.js → dist-DS1gmhe1.js} +1 -1
- package/dist/dashboard/public/assets/index-DjGsaJLv.js +212 -0
- package/dist/dashboard/public/index.html +1 -1
- package/dist/dashboard/{review-status-BtXqWBhS.js → review-status-Dww2OKUX.js} +1 -1
- package/dist/dashboard/{review-status-Bymwzh2i.js → review-status-d_wOE-XQ.js} +3 -3
- package/dist/dashboard/{review-status-Bymwzh2i.js.map → review-status-d_wOE-XQ.js.map} +1 -1
- package/dist/dashboard/server.js +97 -97
- package/dist/dashboard/settings-BHlDG7TK.js.map +1 -1
- package/dist/dashboard/{spawn-planning-session-D5hrVdWM.js → spawn-planning-session-D5uEpHzf.js} +1 -1
- package/dist/dashboard/{spawn-planning-session-33Jf-d5T.js → spawn-planning-session-DtbNfA2Q.js} +3 -3
- package/dist/dashboard/{spawn-planning-session-33Jf-d5T.js.map → spawn-planning-session-DtbNfA2Q.js.map} +1 -1
- package/dist/dashboard/{specialist-context-DGukHSn8.js → specialist-context-CEKqWqyF.js} +4 -4
- package/dist/dashboard/{specialist-context-DGukHSn8.js.map → specialist-context-CEKqWqyF.js.map} +1 -1
- package/dist/dashboard/{specialist-logs-CIw4qfTy.js → specialist-logs-CBGVRoQF.js} +1 -1
- package/dist/dashboard/{specialists-Cp-PgspS.js → specialists-sIFlMd3s.js} +1 -1
- package/dist/dashboard/{specialists-B_zrayaP.js → specialists-saEYE0-z.js} +20 -20
- package/dist/dashboard/{specialists-B_zrayaP.js.map → specialists-saEYE0-z.js.map} +1 -1
- package/dist/dashboard/{test-agent-queue-ypF_ecHo.js → test-agent-queue-7jXB2KkN.js} +3 -3
- package/dist/dashboard/{test-agent-queue-ypF_ecHo.js.map → test-agent-queue-7jXB2KkN.js.map} +1 -1
- package/dist/dashboard/{tracker-config-BP59uH4V.js → tracker-config-BX6ijWOc.js} +1 -1
- package/dist/dashboard/{tracker-config-e7ph1QqT.js → tracker-config-tD22z5sv.js} +2 -2
- package/dist/dashboard/{tracker-config-e7ph1QqT.js.map → tracker-config-tD22z5sv.js.map} +1 -1
- package/dist/dashboard/{work-agent-prompt-fCg67nyo.js → work-agent-prompt-D3tPzPvb.js} +2 -2
- package/dist/dashboard/{work-agent-prompt-fCg67nyo.js.map → work-agent-prompt-D3tPzPvb.js.map} +1 -1
- package/dist/dashboard/{work-type-router-CWVW2Wk_.js → work-type-router-7kwLSwrP.js} +4 -2
- package/dist/dashboard/work-type-router-7kwLSwrP.js.map +1 -0
- package/dist/dashboard/{work-type-router-Di5gCQwh.js → work-type-router-ByOOudGz.js} +1 -1
- package/dist/dashboard/workflows-BDpPjK18.js +2 -0
- package/dist/dashboard/{workflows-BSMipN07.js → workflows-DcEeDkbS.js} +3 -3
- package/dist/dashboard/{workflows-BSMipN07.js.map → workflows-DcEeDkbS.js.map} +1 -1
- package/dist/{factory-BRBGw6OB.js → factory-BR48tuUR.js} +1 -1
- package/dist/{factory-DzsOiZVc.js → factory-D6LJaZ__.js} +2 -2
- package/dist/{factory-DzsOiZVc.js.map → factory-D6LJaZ__.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/{merge-agent-DlUiUanN.js → merge-agent-BBwHwpn2.js} +3 -3
- package/dist/{merge-agent-DlUiUanN.js.map → merge-agent-BBwHwpn2.js.map} +1 -1
- package/dist/{review-status-DEDvCKMP.js → review-status-Ba6llgCb.js} +3 -3
- package/dist/{review-status-DEDvCKMP.js.map → review-status-Ba6llgCb.js.map} +1 -1
- package/dist/{review-status-D6H2WOw8.js → review-status-Chxzuwn2.js} +1 -1
- package/dist/{settings-BcWPTrua.js → settings-A-CWz_ph.js} +6 -2
- package/dist/{settings-BcWPTrua.js.map → settings-A-CWz_ph.js.map} +1 -1
- package/dist/{specialist-context-BAUWL1Fl.js → specialist-context-B3lknlwi.js} +4 -4
- package/dist/{specialist-context-BAUWL1Fl.js.map → specialist-context-B3lknlwi.js.map} +1 -1
- package/dist/{specialist-logs-DQKKQV9B.js → specialist-logs-DDyY4xqo.js} +1 -1
- package/dist/{specialists-D7Kj5o6s.js → specialists-DvTYu1VZ.js} +20 -20
- package/dist/{specialists-D7Kj5o6s.js.map → specialists-DvTYu1VZ.js.map} +1 -1
- package/dist/{specialists-Bfb9ATzw.js → specialists-DyB4IRlM.js} +1 -1
- package/dist/sync-CLVqiGl4.js +2 -0
- package/dist/{sync-DMfgd389.js → sync-DTHFlEc-.js} +2 -2
- package/dist/{sync-DMfgd389.js.map → sync-DTHFlEc-.js.map} +1 -1
- package/dist/{tracker-BhYYvU3p.js → tracker-CYpb7oUa.js} +2 -2
- package/dist/{tracker-BhYYvU3p.js.map → tracker-CYpb7oUa.js.map} +1 -1
- package/dist/{work-type-router-CHjciPyS.js → work-type-router-oCgTPXsP.js} +4 -2
- package/dist/work-type-router-oCgTPXsP.js.map +1 -0
- package/package.json +1 -1
- package/dist/config-yaml-DGbLSMCa.js.map +0 -1
- package/dist/dashboard/public/assets/index-CzFZIb87.js +0 -212
- package/dist/dashboard/work-type-router-CWVW2Wk_.js.map +0 -1
- package/dist/dashboard/workflows-DaYWQIS2.js +0 -2
- package/dist/sync-TL6y-8K6.js +0 -2
- package/dist/work-type-router-CHjciPyS.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflows-BSMipN07.js","names":["execAsync"],"sources":["../../src/lib/lifecycle/teardown-workspace.ts","../../src/lib/lifecycle/workflows.ts"],"sourcesContent":["/**\n * teardown-workspace — Full workspace cleanup.\n *\n * Consolidates workspace teardown from close-out.ts and workspace-manager.ts.\n * Handles: tmux sessions, TLDR daemon, Docker containers, git worktrees,\n * agent state directories, and (optionally) git branches.\n *\n * The workspace-manager's removeWorkspace() handles additional project-specific\n * cleanup (DNS, tunnels, Hume, ports) that this module does not cover.\n * In Phase 2, removeWorkspace() will delegate to this module for the common steps.\n */\n\nimport { existsSync, rmSync, unlinkSync } from 'fs';\nimport { join, basename, dirname } from 'path';\nimport { homedir } from 'os';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { AGENTS_DIR } from '../paths.js';\nimport { sessionExists } from '../tmux.js';\nimport type { LifecycleContext, StepResult, TeardownOptions } from './types.js';\nimport { stepOk, stepSkipped, stepFailed } from './types.js';\nimport { findWorkspacePath } from './archive-planning.js';\nimport { extractPrefix } from '../issue-id.js';\n\nconst execAsync = promisify(exec);\n\n/**\n * Kill tmux sessions associated with an issue.\n */\nasync function killTmuxSessions(issueLower: string): Promise<StepResult> {\n const step = 'teardown:tmux-sessions';\n // Legacy naming: agent-{issue}, review-{issue}, etc.\n const patterns = [\n `agent-${issueLower}`,\n `review-${issueLower}`,\n `test-${issueLower}`,\n `merge-${issueLower}`,\n `planning-${issueLower}`,\n ];\n\n let killed = 0;\n for (const session of patterns) {\n if (sessionExists(session)) {\n try {\n await execAsync(`tmux kill-session -t ${session}`);\n killed++;\n } catch {\n // session may have died between check and kill\n }\n }\n }\n\n // NOTE: Per-project ephemeral specialists (specialist-{project}-{type}) are NOT killed here.\n // They belong to the project, not the issue, and accumulate context across issues via --resume.\n // Their grace period / idle timeout handles cleanup when no new work arrives.\n\n if (killed > 0) {\n return stepOk(step, [`Killed ${killed} tmux session(s)`]);\n }\n return stepSkipped(step, ['No tmux sessions found']);\n}\n\n/**\n * Stop TLDR daemon if workspace has a .venv.\n */\nasync function stopTldrDaemon(workspacePath: string): Promise<StepResult> {\n const step = 'teardown:tldr-daemon';\n const venvPath = join(workspacePath, '.venv');\n if (!existsSync(venvPath)) {\n return stepSkipped(step, ['No .venv found']);\n }\n try {\n const { getTldrDaemonService } = await import('../tldr-daemon.js');\n const tldrService = getTldrDaemonService(workspacePath, venvPath);\n await tldrService.stop();\n return stepOk(step, ['Stopped TLDR daemon']);\n } catch {\n return stepSkipped(step, ['TLDR daemon not running or failed to stop (non-fatal)']);\n }\n}\n\n/**\n * Stop Docker containers for the workspace.\n */\nasync function stopDocker(\n workspacePath: string,\n projectName: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:docker';\n try {\n const { stopWorkspaceDocker } = await import('../workspace-manager.js');\n await stopWorkspaceDocker(workspacePath, projectName, issueLower);\n return stepOk(step, ['Stopped Docker containers']);\n } catch {\n return stepSkipped(step, ['Docker cleanup skipped (not running or failed)']);\n }\n}\n\n/**\n * Kill orphaned host processes for a workspace.\n *\n * When workspaces use `./dev all`, Vite/node processes run on the host (not in\n * containers). Docker compose down doesn't touch them, so they leak and exhaust\n * inotify watchers. This step finds and kills processes whose cwd or args\n * reference the workspace path.\n */\nasync function killOrphanedProcesses(workspacePath: string): Promise<StepResult> {\n const step = 'teardown:orphaned-processes';\n try {\n // Find PIDs with cwd matching the workspace path\n const { stdout } = await execAsync(\n `lsof +D \"${workspacePath}\" -t 2>/dev/null || true`,\n { encoding: 'utf-8', timeout: 10000 },\n );\n const pids = stdout.trim().split('\\n').filter(Boolean).map(p => p.trim()).filter(p => /^\\d+$/.test(p));\n\n if (pids.length === 0) {\n return stepSkipped(step, ['No orphaned processes found']);\n }\n\n // Don't kill our own process or the dashboard\n const myPid = String(process.pid);\n const safePids = pids.filter(p => p !== myPid);\n\n if (safePids.length === 0) {\n return stepSkipped(step, ['No orphaned processes to kill']);\n }\n\n await execAsync(`kill ${safePids.join(' ')} 2>/dev/null || true`, { encoding: 'utf-8', timeout: 5000 });\n return stepOk(step, [`Killed ${safePids.length} orphaned process(es)`]);\n } catch {\n return stepSkipped(step, ['Orphaned process cleanup failed (non-fatal)']);\n }\n}\n\n/**\n * Sync workspace beads to the project-root beads database before workspace deletion.\n * Without this, beads created in the workspace's .beads/dolt/ are lost when the worktree is removed.\n */\nasync function syncWorkspaceBeads(\n projectPath: string,\n workspacePath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:sync-beads';\n const workspaceBeadsDir = join(workspacePath, '.beads');\n\n if (!existsSync(workspaceBeadsDir)) {\n return stepSkipped(step, ['No .beads directory in workspace']);\n }\n\n try {\n // Export workspace beads to JSONL\n const { stdout: exportOutput } = await execAsync(\n 'bd export --output .beads/issues-export.jsonl 2>&1 || true',\n { cwd: workspacePath, encoding: 'utf-8', timeout: 15000 }\n );\n\n const exportPath = join(workspacePath, '.beads', 'issues-export.jsonl');\n if (!existsSync(exportPath)) {\n // Try syncing directly — bd sync exports to the standard JSONL\n await execAsync('bd sync 2>&1 || true', { cwd: workspacePath, encoding: 'utf-8', timeout: 15000 });\n }\n\n // Import workspace beads into project-root database\n // Use bd import if available, otherwise copy JSONL entries\n try {\n await execAsync(\n `bd import \"${join(workspacePath, '.beads', 'issues.jsonl')}\" 2>&1 || true`,\n { cwd: projectPath, encoding: 'utf-8', timeout: 15000 }\n );\n return stepOk(step, [`Synced workspace beads to project root for ${issueLower}`]);\n } catch {\n // bd import may not exist — try manual JSONL merge\n const { readFileSync, appendFileSync } = await import('fs');\n const wsJsonl = join(workspacePath, '.beads', 'issues.jsonl');\n const projJsonl = join(projectPath, '.beads', 'issues.jsonl');\n\n if (existsSync(wsJsonl) && existsSync(projJsonl)) {\n const wsContent = readFileSync(wsJsonl, 'utf-8');\n const issuePattern = issueLower.replace('-', '[-_]');\n const relevantLines = wsContent.split('\\n').filter(\n line => line.trim() && new RegExp(issuePattern, 'i').test(line)\n );\n if (relevantLines.length > 0) {\n appendFileSync(projJsonl, '\\n' + relevantLines.join('\\n'));\n return stepOk(step, [`Appended ${relevantLines.length} beads entries for ${issueLower} to project JSONL`]);\n }\n }\n return stepSkipped(step, ['No beads to sync or import not available']);\n }\n } catch (err) {\n return stepFailed(step, `Failed to sync workspace beads: ${(err as Error).message}`);\n }\n}\n\n/**\n * Clear beads for this issue from the project-root .beads/issues.jsonl.\n * On wipe, beads should be removed so the user starts fresh.\n */\nasync function clearProjectBeads(\n projectPath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:clear-beads';\n const projJsonl = join(projectPath, '.beads', 'issues.jsonl');\n\n if (!existsSync(projJsonl)) {\n return stepSkipped(step, ['No .beads/issues.jsonl in project root']);\n }\n\n try {\n const { readFileSync, writeFileSync } = await import('fs');\n const content = readFileSync(projJsonl, 'utf-8');\n const lines = content.split('\\n');\n const issueUpper = issueLower.toUpperCase();\n const before = lines.length;\n // Remove lines that reference this issue (by ID in the title or issue field)\n const filtered = lines.filter(line => {\n if (!line.trim()) return true; // keep blank lines\n try {\n const entry = JSON.parse(line);\n const title = (entry.title || '').toUpperCase();\n const issue = (entry.issue || '').toUpperCase();\n return !title.includes(issueUpper) && issue !== issueUpper;\n } catch {\n return true; // keep unparseable lines\n }\n });\n const removed = before - filtered.length;\n if (removed > 0) {\n writeFileSync(projJsonl, filtered.join('\\n'));\n return stepOk(step, [`Removed ${removed} beads entries for ${issueLower} from project JSONL`]);\n }\n return stepSkipped(step, [`No beads entries found for ${issueLower}`]);\n } catch (err) {\n return stepFailed(step, `Failed to clear beads: ${(err as Error).message}`);\n }\n}\n\n/**\n * Remove git worktree for the workspace.\n */\nasync function removeWorktree(\n projectPath: string,\n workspacePath: string,\n): Promise<StepResult> {\n const step = 'teardown:worktree';\n if (!existsSync(workspacePath)) {\n return stepSkipped(step, ['Workspace directory does not exist']);\n }\n\n try {\n await execAsync(`git worktree remove \"${workspacePath}\" --force`, { cwd: projectPath });\n return stepOk(step, ['Removed git worktree']);\n } catch {\n // worktree remove failed — try direct removal\n try {\n rmSync(workspacePath, { recursive: true, force: true });\n return stepOk(step, ['Removed workspace directory (worktree remove failed, used rmSync)']);\n } catch (err) {\n return stepFailed(step, `Failed to remove workspace: ${(err as Error).message}`);\n }\n }\n}\n\n/**\n * Remove agent state directories (~/.panopticon/agents/agent-<issue>/ and planning-<issue>/).\n */\nasync function removeAgentState(issueLower: string): Promise<StepResult> {\n const step = 'teardown:agent-state';\n const dirs = [\n join(AGENTS_DIR, `agent-${issueLower}`),\n join(AGENTS_DIR, `planning-${issueLower}`),\n ];\n\n let removed = 0;\n for (const dir of dirs) {\n if (existsSync(dir)) {\n rmSync(dir, { recursive: true, force: true });\n removed++;\n }\n }\n\n if (removed > 0) {\n return stepOk(step, [`Removed ${removed} agent state director${removed === 1 ? 'y' : 'ies'}`]);\n }\n return stepSkipped(step, ['No agent state directories found']);\n}\n\n/**\n * Delete feature branches (local + remote).\n */\nasync function deleteBranches(\n projectPath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:branches';\n const branchName = `feature/${issueLower}`;\n const details: string[] = [];\n\n // Delete local branch\n try {\n await execAsync(`git branch -D \"${branchName}\"`, { cwd: projectPath, encoding: 'utf-8' });\n details.push(`Deleted local branch ${branchName}`);\n } catch {\n details.push(`Local branch ${branchName} not found (already deleted)`);\n }\n\n // Delete remote branch\n try {\n await execAsync(`git push origin --delete \"${branchName}\"`, { cwd: projectPath, encoding: 'utf-8' });\n details.push(`Deleted remote branch ${branchName}`);\n } catch {\n details.push(`Remote branch ${branchName} not found (already deleted)`);\n }\n\n return stepOk(step, details);\n}\n\n/**\n * Clear shadow state for an issue.\n */\nasync function clearShadowState(issueId: string): Promise<StepResult> {\n const step = 'teardown:shadow-state';\n try {\n const { removeShadowState } = await import('../shadow-state.js');\n const result = removeShadowState(issueId);\n if (result.success) {\n return stepOk(step, [`Cleared shadow state for ${issueId}`]);\n }\n return stepSkipped(step, ['No shadow state found']);\n } catch {\n return stepSkipped(step, ['Shadow state cleanup skipped (non-fatal)']);\n }\n}\n\n/**\n * Remove legacy .planning/<issue>/ directory from project root.\n */\nasync function clearLegacyPlanningDir(\n projectPath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:legacy-planning-dir';\n const legacyDir = join(projectPath, '.planning', issueLower);\n if (existsSync(legacyDir)) {\n rmSync(legacyDir, { recursive: true, force: true });\n return stepOk(step, [`Deleted legacy planning dir: ${legacyDir}`]);\n }\n return stepSkipped(step, ['No legacy planning directory found']);\n}\n\n/**\n * Clear .planning/.planning-complete marker from workspace.\n * Only runs if workspace still exists (before worktree removal).\n */\nasync function clearPlanningMarker(workspacePath: string): Promise<StepResult> {\n const step = 'teardown:planning-marker';\n const markerPath = join(workspacePath, '.planning', '.planning-complete');\n if (existsSync(markerPath)) {\n unlinkSync(markerPath);\n return stepOk(step, ['Cleared .planning-complete marker']);\n }\n return stepSkipped(step, ['No .planning-complete marker found']);\n}\n\n/**\n * Build template placeholders for project-specific cleanup (tunnel, Hume).\n */\nfunction buildPlaceholders(\n ctx: LifecycleContext,\n opts: TeardownOptions,\n workspacePath: string,\n) {\n const issueLower = ctx.issueId.toLowerCase();\n const featureFolder = `feature-${issueLower}`;\n const projName = opts.projectName || ctx.projectName || basename(ctx.projectPath);\n const domain = opts.workspaceConfig?.dns?.domain || 'localhost';\n return {\n FEATURE_NAME: issueLower,\n FEATURE_FOLDER: featureFolder,\n BRANCH_NAME: `feature/${issueLower}`,\n COMPOSE_PROJECT: `${projName}-${featureFolder}`,\n DOMAIN: domain,\n PROJECT_NAME: projName,\n PROJECT_PATH: ctx.projectPath,\n WORKSPACE_PATH: workspacePath,\n };\n}\n\n/**\n * Remove Cloudflare tunnel ingress for workspace.\n */\nasync function removeTunnelConfig(\n tunnelConfig: any,\n placeholders: Record<string, string>,\n): Promise<StepResult> {\n const step = 'teardown:tunnel';\n try {\n const { removeTunnelIngress } = await import('../tunnel.js');\n const result = await removeTunnelIngress(tunnelConfig, placeholders as any);\n return stepOk(step, result.steps || ['Removed tunnel ingress']);\n } catch (err) {\n return stepSkipped(step, [`Tunnel cleanup warning: ${(err as Error).message}`]);\n }\n}\n\n/**\n * Remove Hume EVI config for workspace.\n */\nasync function removeHumeEviConfig(\n humeConfig: any,\n placeholders: Record<string, string>,\n): Promise<StepResult> {\n const step = 'teardown:hume';\n try {\n const { deleteHumeConfig } = await import('../hume.js');\n const result = await deleteHumeConfig(humeConfig, placeholders as any);\n return stepOk(step, result.steps || ['Removed Hume EVI config']);\n } catch (err) {\n return stepSkipped(step, [`Hume cleanup warning: ${(err as Error).message}`]);\n }\n}\n\n/**\n * Full workspace teardown.\n *\n * Steps (in order):\n * 1. Kill tmux sessions\n * 2. Clear shadow state\n * 3. Clear legacy planning directory\n * 4. Stop TLDR daemon (if workspace exists)\n * 5. Stop Docker containers (if workspace exists)\n * 6. Clear planning marker (if workspace exists, before deletion)\n * 7. Remove tunnel config (if workspace config provided)\n * 8. Remove Hume config (if workspace config provided)\n * 9. Remove git worktree + workspace directory\n * 10. Remove agent state directories\n * 11. (Optional) Delete feature branches\n */\nexport async function teardownWorkspace(\n ctx: LifecycleContext,\n opts: TeardownOptions = {},\n): Promise<StepResult[]> {\n const issueLower = ctx.issueId.toLowerCase();\n const projName = opts.projectName || ctx.projectName || (extractPrefix(ctx.issueId)?.toLowerCase() ?? ctx.issueId);\n const workspacePath = findWorkspacePath(ctx.projectPath, issueLower);\n const shouldDeleteWorkspace = opts.deleteWorkspace !== false; // default true\n const results: StepResult[] = [];\n\n // 1. Kill tmux sessions\n results.push(await killTmuxSessions(issueLower));\n\n // 2. Clear shadow state (always runs)\n results.push(await clearShadowState(ctx.issueId));\n\n // 3. Clear legacy planning directory (always runs)\n results.push(await clearLegacyPlanningDir(ctx.projectPath, issueLower));\n\n // 4-9: Workspace-specific cleanup\n if (workspacePath && existsSync(workspacePath)) {\n // 4. Stop TLDR daemon (only if deleting workspace)\n if (shouldDeleteWorkspace) {\n results.push(await stopTldrDaemon(workspacePath));\n }\n\n // 5. Stop Docker containers (only if deleting workspace)\n if (shouldDeleteWorkspace && !opts.skipDocker) {\n results.push(await stopDocker(workspacePath, projName, issueLower));\n }\n\n // 5b. Kill orphaned host processes (Vite, node) that survive Docker teardown\n if (shouldDeleteWorkspace) {\n results.push(await killOrphanedProcesses(workspacePath));\n }\n\n // 6. Clear planning marker (before workspace deletion, or when preserving workspace)\n results.push(await clearPlanningMarker(workspacePath));\n\n // 6b. Beads lifecycle: sync or clear depending on context (PAN-412)\n // Normal completion (approve/closeOut): sync beads to project root to preserve history.\n // Destructive wipe: clear beads so the user starts fresh.\n if (opts.clearBeads) {\n results.push(await clearProjectBeads(ctx.projectPath, issueLower));\n } else if (shouldDeleteWorkspace) {\n results.push(await syncWorkspaceBeads(ctx.projectPath, workspacePath, issueLower));\n }\n\n // 7-8: Project-specific cleanup (tunnel, Hume) — only when deleting workspace and config provided\n if (shouldDeleteWorkspace && (opts.workspaceConfig?.tunnel || opts.workspaceConfig?.hume)) {\n const placeholders = buildPlaceholders(ctx, opts, workspacePath);\n\n if (opts.workspaceConfig.tunnel) {\n results.push(await removeTunnelConfig(opts.workspaceConfig.tunnel, placeholders));\n }\n if (opts.workspaceConfig.hume) {\n results.push(await removeHumeEviConfig(opts.workspaceConfig.hume, placeholders));\n }\n }\n\n // 9. Remove worktree + workspace directory (only if deleting workspace)\n if (shouldDeleteWorkspace) {\n results.push(await removeWorktree(ctx.projectPath, workspacePath));\n }\n } else {\n results.push(stepSkipped('teardown:workspace', ['No workspace found to clean up']));\n }\n\n // 10. Remove agent state\n results.push(await removeAgentState(issueLower));\n\n // 11. Delete branches (only if explicitly requested)\n if (opts.deleteBranches) {\n results.push(await deleteBranches(ctx.projectPath, issueLower));\n }\n\n return results;\n}\n","/**\n * Lifecycle workflows — Compose atomic operations into complete workflows.\n *\n * approve() — Post-merge: archive + close + teardown + compact-beads\n * close() — Simple close: close-issue + teardown\n * closeOut() — Full ceremony: verify-merged + archive + teardown + close + label + clear-status\n * deepWipe() — Destructive: teardown(deleteBranches) + delete agent state + reset issue\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { PANOPTICON_HOME } from '../paths.js';\nimport type {\n LifecycleContext,\n WorkflowResult,\n StepResult,\n ApproveOptions,\n DeepWipeOptions,\n ArchiveOptions,\n} from './types.js';\nimport { stepOk, stepSkipped, stepFailed, getLinearApiKey } from './types.js';\nimport { archivePlanning, findWorkspacePath } from './archive-planning.js';\nimport { closeIssue, type CloseIssueOptions } from './close-issue.js';\nimport { teardownWorkspace } from './teardown-workspace.js';\nimport { compactBeads } from './compact-beads.js';\nimport { extractNumber, extractPrefix } from '../issue-id.js';\n\nconst execAsync = promisify(exec);\n\n/**\n * Build a WorkflowResult from collected steps.\n */\nfunction buildResult(\n workflow: WorkflowResult['workflow'],\n issueId: string,\n steps: StepResult[],\n startTime: number,\n): WorkflowResult {\n return {\n workflow,\n issueId,\n success: steps.every(s => s.success),\n steps,\n duration: Date.now() - startTime,\n };\n}\n\n/**\n * approve() — Post-merge lifecycle.\n *\n * 1. Archive planning artifacts (PRD move + .planning/ preservation)\n * 2. Close issue on tracker\n * 3. Teardown workspace\n * 4. Compact beads\n * 5. Clear review status\n *\n * Note: The actual merge step is NOT included here — the merge-agent\n * handles merge validation. This workflow runs AFTER merge completes.\n */\nexport async function approve(\n ctx: LifecycleContext,\n opts: ApproveOptions & CloseIssueOptions & ArchiveOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n\n // 1. Archive planning\n const archiveSteps = await archivePlanning(ctx, opts);\n allSteps.push(...archiveSteps);\n\n // If archive failed, stop — don't destroy unarchived artifacts\n const archiveFailed = archiveSteps.some(s => !s.success && !s.skipped);\n if (archiveFailed) {\n allSteps.push(stepFailed('approve:abort', 'Stopped — archiving failed, workspace preserved'));\n return buildResult('approve', ctx.issueId, allSteps, start);\n }\n\n // 2. Close issue\n const closeSteps = await closeIssue(ctx, {\n tracker: opts.tracker,\n comment: 'Merged to main via Panopticon lifecycle',\n applyLabel: true,\n });\n allSteps.push(...closeSteps);\n\n // 3. Teardown workspace\n const teardownSteps = await teardownWorkspace(ctx);\n allSteps.push(...teardownSteps);\n\n // 4. Compact beads (non-blocking — failure doesn't affect workflow success)\n if (!opts.skipBeadsCompaction) {\n const beadsResult = await compactBeads(ctx);\n allSteps.push(beadsResult);\n }\n\n // 5. Clear review status\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n\n return buildResult('approve', ctx.issueId, allSteps, start);\n}\n\n/**\n * close() — Simple issue close with teardown.\n *\n * Used when an issue is being closed without merge (canceled, won't-do, etc.)\n * Does NOT archive workspace artifacts.\n *\n * 1. Close issue on tracker\n * 2. Teardown workspace\n * 3. Clear review status\n */\nexport async function close(\n ctx: LifecycleContext,\n opts: CloseIssueOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n\n // 1. Close issue\n const closeSteps = await closeIssue(ctx, {\n tracker: opts.tracker,\n reason: opts.reason,\n applyLabel: false,\n });\n allSteps.push(...closeSteps);\n\n // 2. Teardown workspace\n const teardownSteps = await teardownWorkspace(ctx);\n allSteps.push(...teardownSteps);\n\n // 3. Clear review status\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n\n return buildResult('close', ctx.issueId, allSteps, start);\n}\n\n/**\n * closeOut() — Full close-out ceremony.\n *\n * This is the human-gated verification and cleanup workflow.\n * Replaces the monolithic executeCloseOut() function.\n *\n * 1. Verify branch merged (hard fail if not — must pass before any cleanup)\n * 2. Move PRD + archive workspace artifacts (hard fail if archiving fails)\n * 3. Clean up workspace (tmux, TLDR, Docker, worktree)\n * 4. Clean up agent state\n * 5. Close issue on tracker\n * 6. Apply closed-out label\n * 7. Clear review status\n */\nexport async function closeOut(\n ctx: LifecycleContext,\n opts: CloseIssueOptions & ArchiveOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n\n // 1. Verify branch merged (hard fail — must pass before we archive or clean up)\n const mergeVerify = await verifyBranchMerged(ctx);\n allSteps.push(mergeVerify);\n if (!mergeVerify.success && !mergeVerify.skipped) {\n return buildResult('close-out', ctx.issueId, allSteps, start);\n }\n\n // 2. Move PRD + archive workspace artifacts\n const archiveSteps = await archivePlanning(ctx, opts);\n allSteps.push(...archiveSteps);\n\n // Hard fail on archive failure — don't destroy unarchived artifacts\n const archiveFailed = archiveSteps.some(s => !s.success && !s.skipped);\n if (archiveFailed) {\n allSteps.push(stepFailed('close-out:abort', 'Stopped — archiving failed, workspace preserved'));\n return buildResult('close-out', ctx.issueId, allSteps, start);\n }\n\n // 4+5. Teardown workspace + agent state\n const teardownSteps = await teardownWorkspace(ctx);\n allSteps.push(...teardownSteps);\n\n // 6+7. Close issue + apply label\n const closeSteps = await closeIssue(ctx, {\n tracker: opts.tracker,\n comment: 'Closed via close-out ceremony',\n applyLabel: true,\n });\n allSteps.push(...closeSteps);\n\n // 8. Clear review status\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n\n return buildResult('close-out', ctx.issueId, allSteps, start);\n}\n\n/**\n * deepWipe() — Destructive cleanup for abandoned workspaces.\n *\n * 1. Teardown workspace (with branch deletion)\n * 2. (Optional) Reset issue to backlog/open\n * 3. Clear review status\n */\nexport async function deepWipe(\n ctx: LifecycleContext,\n opts: DeepWipeOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n const { deleteWorkspace = true, deleteBranches = true, resetIssue = true, onProgress } = opts;\n\n const TOTAL_STEPS = 3 + (resetIssue ? 1 : 0);\n let stepNum = 0;\n\n const progress = (label: string, detail: string, status: 'active' | 'complete' | 'error' = 'active') => {\n onProgress?.({ step: stepNum, total: TOTAL_STEPS, label, detail, status });\n };\n\n // 1. Teardown workspace (aggressive — delete branches, project-specific cleanup, clear beads)\n stepNum = 1;\n progress('Tearing down workspace', 'Killing agents, stopping services, removing files');\n const teardownSteps = await teardownWorkspace(ctx, {\n deleteWorkspace,\n deleteBranches,\n clearBeads: true,\n workspaceConfig: opts.workspaceConfig,\n projectName: opts.projectName,\n });\n allSteps.push(...teardownSteps);\n const teardownFailed = teardownSteps.some(s => !s.success && !s.skipped);\n progress('Tearing down workspace', teardownFailed ? 'Some steps failed' : 'Workspace torn down', teardownFailed ? 'error' : 'complete');\n\n // 2. Delete git branches\n stepNum = 2;\n progress('Deleting git branches', `feature/${ctx.issueId.toLowerCase()}`);\n // Branch deletion is already handled in teardownWorkspace when deleteBranches is true,\n // but we report it as a separate visible step\n progress('Deleting git branches', deleteBranches ? 'Branches removed' : 'Skipped', 'complete');\n\n // 3. Reset issue to open/backlog\n if (resetIssue) {\n stepNum = 3;\n progress('Resetting issue status', `${ctx.issueId} → Todo`);\n const resetResult = await resetIssueToTodo(ctx);\n allSteps.push(resetResult);\n progress('Resetting issue status', resetResult.success ? 'Issue reset to Todo' : (resetResult.error || 'Failed'), resetResult.success ? 'complete' : 'error');\n }\n\n // 4. Clear review status\n stepNum = resetIssue ? 4 : 3;\n progress('Clearing review status', 'Removing specialist state');\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n progress('Clearing review status', 'Review status cleared', 'complete');\n\n return buildResult('deep-wipe', ctx.issueId, allSteps, start);\n}\n\n// --- Internal helpers ---\n\n/**\n * Verify feature branch is merged into main.\n */\nasync function verifyBranchMerged(ctx: LifecycleContext): Promise<StepResult> {\n const step = 'close-out:verify-merged';\n const issueLower = ctx.issueId.toLowerCase();\n const branchName = `feature/${issueLower}`;\n\n try {\n // Check review-status first — the merge specialist validates before marking merged\n try {\n const { loadReviewStatuses } = await import('../review-status.js');\n const statuses = loadReviewStatuses();\n const issueKey = ctx.issueId.toUpperCase();\n if (statuses[issueKey]?.mergeStatus === 'merged') {\n return stepOk(step, ['Merge specialist confirmed merge completed']);\n }\n } catch {\n // review-status.json may not exist, continue with git checks\n }\n\n\n // Check if branch exists locally\n const { stdout: branchExists } = await execAsync(\n `git branch --list \"${branchName}\" 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n\n if (branchExists.trim()) {\n // Use merge-base --is-ancestor: checks if the branch tip is reachable from main\n // Note: does NOT detect squash merges — code-diff fallback handles those\n try {\n await execAsync(\n `git merge-base --is-ancestor ${branchName} main`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n return stepOk(step, ['All commits merged to main']);\n } catch {\n // --is-ancestor fails for squash merges where the branch still exists.\n // Check if the code diff (excluding planning artifacts) is empty — if so,\n // the code was squash-merged and only planning files remain on the branch.\n try {\n const { stdout: codeDiff } = await execAsync(\n `git diff main...${branchName} -- ':!.planning' ':!docs/prds' ':!.panopticon/prompts' 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n if (!codeDiff.trim()) {\n return stepOk(step, ['Code changes squash-merged to main (only planning artifacts remain on branch)']);\n }\n } catch {\n // diff failed — fall through to unmerged report\n }\n\n const { stdout: unmerged } = await execAsync(\n `git log main..${branchName} --oneline 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n const count = unmerged.trim() ? unmerged.trim().split('\\n').length : 0;\n return stepFailed(step, `${count} unmerged commit(s) on ${branchName}. Merge before closing out.`);\n }\n }\n\n // Check remote\n const { stdout: remoteBranch } = await execAsync(\n `git ls-remote --heads origin \"${branchName}\" 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n\n if (remoteBranch.trim()) {\n await execAsync(`git fetch origin ${branchName}`, { cwd: ctx.projectPath }).catch(() => {});\n try {\n await execAsync(\n `git merge-base --is-ancestor origin/${branchName} main`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n return stepOk(step, ['Remote branch fully merged']);\n } catch {\n // Squash-merge detection for remote branch\n try {\n const { stdout: codeDiff } = await execAsync(\n `git diff main...origin/${branchName} -- ':!.planning' ':!docs/prds' ':!.panopticon/prompts' 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n if (!codeDiff.trim()) {\n return stepOk(step, ['Remote code changes squash-merged to main (only planning artifacts remain on branch)']);\n }\n } catch {\n // diff failed — fall through\n }\n\n const { stdout: remoteUnmerged } = await execAsync(\n `git log main..origin/${branchName} --oneline 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n const count = remoteUnmerged.trim() ? remoteUnmerged.trim().split('\\n').length : 0;\n return stepFailed(step, `${count} unmerged commit(s) on remote ${branchName}.`);\n }\n }\n\n // No branch at all — assume squash-merged and branch deleted\n return stepOk(step, ['Branch already cleaned up (squash-merged)']);\n } catch (err) {\n return stepFailed(step, `Could not verify merge: ${(err as Error).message}`);\n }\n}\n\n/**\n * Reset issue back to open/backlog state (for deep-wipe).\n */\nasync function resetIssueToTodo(ctx: LifecycleContext): Promise<StepResult> {\n const step = 'deep-wipe:reset-issue';\n try {\n if (ctx.github) {\n const { owner, repo, number } = ctx.github;\n // Reopen the issue\n await execAsync(\n `gh issue reopen ${number} --repo ${owner}/${repo}`,\n { encoding: 'utf-8' },\n ).catch(() => {}); // May already be open\n // Remove lifecycle labels\n const labelsToRemove = ['in-review', 'in-progress', 'planned', 'planning', 'Review: Approved', 'Review: Failed', 'ready-for-merge'];\n for (const label of labelsToRemove) {\n await execAsync(\n `gh issue edit ${number} --repo ${owner}/${repo} --remove-label \"${label}\"`,\n { encoding: 'utf-8' },\n ).catch(() => {}); // Label may not exist\n }\n return stepOk(step, [`Reset GitHub issue #${number}: reopened and cleared labels`]);\n }\n\n // Linear: reopen to Todo\n const linearApiKey = getLinearApiKey();\n if (linearApiKey) {\n const { LinearClient } = await import('@linear/sdk');\n const client = new LinearClient({ apiKey: linearApiKey });\n const issueNum = extractNumber(ctx.issueId);\n const teamKey = extractPrefix(ctx.issueId);\n if (issueNum === null || teamKey === null) {\n return stepFailed(step, `Could not parse issue ID: ${ctx.issueId}`);\n }\n const results = await client.issues({\n filter: {\n number: { eq: issueNum },\n team: { key: { eq: teamKey } },\n },\n first: 1,\n });\n if (results.nodes.length > 0) {\n const issue = results.nodes[0];\n const team = await issue.team;\n if (team) {\n const states = await team.states();\n const todoState = states.nodes.find(s => s.type === 'unstarted' && s.name === 'Todo') ||\n states.nodes.find(s => s.type === 'unstarted');\n if (todoState) {\n await issue.update({ stateId: todoState.id });\n }\n }\n }\n return stepOk(step, [`Reset Linear issue ${ctx.issueId} to Todo`]);\n }\n\n return stepSkipped(step, ['No tracker available to reset issue']);\n } catch (err) {\n return stepFailed(step, `Failed to reset issue: ${(err as Error).message}`);\n }\n}\n\n/**\n * Clear review status for an issue.\n */\nasync function clearReviewStatusStep(issueId: string): Promise<StepResult> {\n const step = 'clear-review-status';\n try {\n const { clearReviewStatus } = await import('../review-status.js');\n clearReviewStatus(issueId.toUpperCase());\n return stepOk(step, ['Review status cleared']);\n } catch {\n // Fallback: direct file manipulation\n try {\n const statusFile = join(PANOPTICON_HOME, 'review-status.json');\n if (existsSync(statusFile)) {\n const data = JSON.parse(readFileSync(statusFile, 'utf-8'));\n const upperKey = issueId.toUpperCase();\n if (data[upperKey]) {\n delete data[upperKey];\n const { writeFileSync } = await import('fs');\n writeFileSync(statusFile, JSON.stringify(data, null, 2));\n }\n }\n return stepOk(step, ['Review status cleared (direct)']);\n } catch (innerErr) {\n return stepSkipped(step, [`Failed to clear review status (non-fatal): ${(innerErr as Error).message}`]);\n }\n }\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflows-DcEeDkbS.js","names":["execAsync"],"sources":["../../src/lib/lifecycle/teardown-workspace.ts","../../src/lib/lifecycle/workflows.ts"],"sourcesContent":["/**\n * teardown-workspace — Full workspace cleanup.\n *\n * Consolidates workspace teardown from close-out.ts and workspace-manager.ts.\n * Handles: tmux sessions, TLDR daemon, Docker containers, git worktrees,\n * agent state directories, and (optionally) git branches.\n *\n * The workspace-manager's removeWorkspace() handles additional project-specific\n * cleanup (DNS, tunnels, Hume, ports) that this module does not cover.\n * In Phase 2, removeWorkspace() will delegate to this module for the common steps.\n */\n\nimport { existsSync, rmSync, unlinkSync } from 'fs';\nimport { join, basename, dirname } from 'path';\nimport { homedir } from 'os';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { AGENTS_DIR } from '../paths.js';\nimport { sessionExists } from '../tmux.js';\nimport type { LifecycleContext, StepResult, TeardownOptions } from './types.js';\nimport { stepOk, stepSkipped, stepFailed } from './types.js';\nimport { findWorkspacePath } from './archive-planning.js';\nimport { extractPrefix } from '../issue-id.js';\n\nconst execAsync = promisify(exec);\n\n/**\n * Kill tmux sessions associated with an issue.\n */\nasync function killTmuxSessions(issueLower: string): Promise<StepResult> {\n const step = 'teardown:tmux-sessions';\n // Legacy naming: agent-{issue}, review-{issue}, etc.\n const patterns = [\n `agent-${issueLower}`,\n `review-${issueLower}`,\n `test-${issueLower}`,\n `merge-${issueLower}`,\n `planning-${issueLower}`,\n ];\n\n let killed = 0;\n for (const session of patterns) {\n if (sessionExists(session)) {\n try {\n await execAsync(`tmux kill-session -t ${session}`);\n killed++;\n } catch {\n // session may have died between check and kill\n }\n }\n }\n\n // NOTE: Per-project ephemeral specialists (specialist-{project}-{type}) are NOT killed here.\n // They belong to the project, not the issue, and accumulate context across issues via --resume.\n // Their grace period / idle timeout handles cleanup when no new work arrives.\n\n if (killed > 0) {\n return stepOk(step, [`Killed ${killed} tmux session(s)`]);\n }\n return stepSkipped(step, ['No tmux sessions found']);\n}\n\n/**\n * Stop TLDR daemon if workspace has a .venv.\n */\nasync function stopTldrDaemon(workspacePath: string): Promise<StepResult> {\n const step = 'teardown:tldr-daemon';\n const venvPath = join(workspacePath, '.venv');\n if (!existsSync(venvPath)) {\n return stepSkipped(step, ['No .venv found']);\n }\n try {\n const { getTldrDaemonService } = await import('../tldr-daemon.js');\n const tldrService = getTldrDaemonService(workspacePath, venvPath);\n await tldrService.stop();\n return stepOk(step, ['Stopped TLDR daemon']);\n } catch {\n return stepSkipped(step, ['TLDR daemon not running or failed to stop (non-fatal)']);\n }\n}\n\n/**\n * Stop Docker containers for the workspace.\n */\nasync function stopDocker(\n workspacePath: string,\n projectName: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:docker';\n try {\n const { stopWorkspaceDocker } = await import('../workspace-manager.js');\n await stopWorkspaceDocker(workspacePath, projectName, issueLower);\n return stepOk(step, ['Stopped Docker containers']);\n } catch {\n return stepSkipped(step, ['Docker cleanup skipped (not running or failed)']);\n }\n}\n\n/**\n * Kill orphaned host processes for a workspace.\n *\n * When workspaces use `./dev all`, Vite/node processes run on the host (not in\n * containers). Docker compose down doesn't touch them, so they leak and exhaust\n * inotify watchers. This step finds and kills processes whose cwd or args\n * reference the workspace path.\n */\nasync function killOrphanedProcesses(workspacePath: string): Promise<StepResult> {\n const step = 'teardown:orphaned-processes';\n try {\n // Find PIDs with cwd matching the workspace path\n const { stdout } = await execAsync(\n `lsof +D \"${workspacePath}\" -t 2>/dev/null || true`,\n { encoding: 'utf-8', timeout: 10000 },\n );\n const pids = stdout.trim().split('\\n').filter(Boolean).map(p => p.trim()).filter(p => /^\\d+$/.test(p));\n\n if (pids.length === 0) {\n return stepSkipped(step, ['No orphaned processes found']);\n }\n\n // Don't kill our own process or the dashboard\n const myPid = String(process.pid);\n const safePids = pids.filter(p => p !== myPid);\n\n if (safePids.length === 0) {\n return stepSkipped(step, ['No orphaned processes to kill']);\n }\n\n await execAsync(`kill ${safePids.join(' ')} 2>/dev/null || true`, { encoding: 'utf-8', timeout: 5000 });\n return stepOk(step, [`Killed ${safePids.length} orphaned process(es)`]);\n } catch {\n return stepSkipped(step, ['Orphaned process cleanup failed (non-fatal)']);\n }\n}\n\n/**\n * Sync workspace beads to the project-root beads database before workspace deletion.\n * Without this, beads created in the workspace's .beads/dolt/ are lost when the worktree is removed.\n */\nasync function syncWorkspaceBeads(\n projectPath: string,\n workspacePath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:sync-beads';\n const workspaceBeadsDir = join(workspacePath, '.beads');\n\n if (!existsSync(workspaceBeadsDir)) {\n return stepSkipped(step, ['No .beads directory in workspace']);\n }\n\n try {\n // Export workspace beads to JSONL\n const { stdout: exportOutput } = await execAsync(\n 'bd export --output .beads/issues-export.jsonl 2>&1 || true',\n { cwd: workspacePath, encoding: 'utf-8', timeout: 15000 }\n );\n\n const exportPath = join(workspacePath, '.beads', 'issues-export.jsonl');\n if (!existsSync(exportPath)) {\n // Try syncing directly — bd sync exports to the standard JSONL\n await execAsync('bd sync 2>&1 || true', { cwd: workspacePath, encoding: 'utf-8', timeout: 15000 });\n }\n\n // Import workspace beads into project-root database\n // Use bd import if available, otherwise copy JSONL entries\n try {\n await execAsync(\n `bd import \"${join(workspacePath, '.beads', 'issues.jsonl')}\" 2>&1 || true`,\n { cwd: projectPath, encoding: 'utf-8', timeout: 15000 }\n );\n return stepOk(step, [`Synced workspace beads to project root for ${issueLower}`]);\n } catch {\n // bd import may not exist — try manual JSONL merge\n const { readFileSync, appendFileSync } = await import('fs');\n const wsJsonl = join(workspacePath, '.beads', 'issues.jsonl');\n const projJsonl = join(projectPath, '.beads', 'issues.jsonl');\n\n if (existsSync(wsJsonl) && existsSync(projJsonl)) {\n const wsContent = readFileSync(wsJsonl, 'utf-8');\n const issuePattern = issueLower.replace('-', '[-_]');\n const relevantLines = wsContent.split('\\n').filter(\n line => line.trim() && new RegExp(issuePattern, 'i').test(line)\n );\n if (relevantLines.length > 0) {\n appendFileSync(projJsonl, '\\n' + relevantLines.join('\\n'));\n return stepOk(step, [`Appended ${relevantLines.length} beads entries for ${issueLower} to project JSONL`]);\n }\n }\n return stepSkipped(step, ['No beads to sync or import not available']);\n }\n } catch (err) {\n return stepFailed(step, `Failed to sync workspace beads: ${(err as Error).message}`);\n }\n}\n\n/**\n * Clear beads for this issue from the project-root .beads/issues.jsonl.\n * On wipe, beads should be removed so the user starts fresh.\n */\nasync function clearProjectBeads(\n projectPath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:clear-beads';\n const projJsonl = join(projectPath, '.beads', 'issues.jsonl');\n\n if (!existsSync(projJsonl)) {\n return stepSkipped(step, ['No .beads/issues.jsonl in project root']);\n }\n\n try {\n const { readFileSync, writeFileSync } = await import('fs');\n const content = readFileSync(projJsonl, 'utf-8');\n const lines = content.split('\\n');\n const issueUpper = issueLower.toUpperCase();\n const before = lines.length;\n // Remove lines that reference this issue (by ID in the title or issue field)\n const filtered = lines.filter(line => {\n if (!line.trim()) return true; // keep blank lines\n try {\n const entry = JSON.parse(line);\n const title = (entry.title || '').toUpperCase();\n const issue = (entry.issue || '').toUpperCase();\n return !title.includes(issueUpper) && issue !== issueUpper;\n } catch {\n return true; // keep unparseable lines\n }\n });\n const removed = before - filtered.length;\n if (removed > 0) {\n writeFileSync(projJsonl, filtered.join('\\n'));\n return stepOk(step, [`Removed ${removed} beads entries for ${issueLower} from project JSONL`]);\n }\n return stepSkipped(step, [`No beads entries found for ${issueLower}`]);\n } catch (err) {\n return stepFailed(step, `Failed to clear beads: ${(err as Error).message}`);\n }\n}\n\n/**\n * Remove git worktree for the workspace.\n */\nasync function removeWorktree(\n projectPath: string,\n workspacePath: string,\n): Promise<StepResult> {\n const step = 'teardown:worktree';\n if (!existsSync(workspacePath)) {\n return stepSkipped(step, ['Workspace directory does not exist']);\n }\n\n try {\n await execAsync(`git worktree remove \"${workspacePath}\" --force`, { cwd: projectPath });\n return stepOk(step, ['Removed git worktree']);\n } catch {\n // worktree remove failed — try direct removal\n try {\n rmSync(workspacePath, { recursive: true, force: true });\n return stepOk(step, ['Removed workspace directory (worktree remove failed, used rmSync)']);\n } catch (err) {\n return stepFailed(step, `Failed to remove workspace: ${(err as Error).message}`);\n }\n }\n}\n\n/**\n * Remove agent state directories (~/.panopticon/agents/agent-<issue>/ and planning-<issue>/).\n */\nasync function removeAgentState(issueLower: string): Promise<StepResult> {\n const step = 'teardown:agent-state';\n const dirs = [\n join(AGENTS_DIR, `agent-${issueLower}`),\n join(AGENTS_DIR, `planning-${issueLower}`),\n ];\n\n let removed = 0;\n for (const dir of dirs) {\n if (existsSync(dir)) {\n rmSync(dir, { recursive: true, force: true });\n removed++;\n }\n }\n\n if (removed > 0) {\n return stepOk(step, [`Removed ${removed} agent state director${removed === 1 ? 'y' : 'ies'}`]);\n }\n return stepSkipped(step, ['No agent state directories found']);\n}\n\n/**\n * Delete feature branches (local + remote).\n */\nasync function deleteBranches(\n projectPath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:branches';\n const branchName = `feature/${issueLower}`;\n const details: string[] = [];\n\n // Delete local branch\n try {\n await execAsync(`git branch -D \"${branchName}\"`, { cwd: projectPath, encoding: 'utf-8' });\n details.push(`Deleted local branch ${branchName}`);\n } catch {\n details.push(`Local branch ${branchName} not found (already deleted)`);\n }\n\n // Delete remote branch\n try {\n await execAsync(`git push origin --delete \"${branchName}\"`, { cwd: projectPath, encoding: 'utf-8' });\n details.push(`Deleted remote branch ${branchName}`);\n } catch {\n details.push(`Remote branch ${branchName} not found (already deleted)`);\n }\n\n return stepOk(step, details);\n}\n\n/**\n * Clear shadow state for an issue.\n */\nasync function clearShadowState(issueId: string): Promise<StepResult> {\n const step = 'teardown:shadow-state';\n try {\n const { removeShadowState } = await import('../shadow-state.js');\n const result = removeShadowState(issueId);\n if (result.success) {\n return stepOk(step, [`Cleared shadow state for ${issueId}`]);\n }\n return stepSkipped(step, ['No shadow state found']);\n } catch {\n return stepSkipped(step, ['Shadow state cleanup skipped (non-fatal)']);\n }\n}\n\n/**\n * Remove legacy .planning/<issue>/ directory from project root.\n */\nasync function clearLegacyPlanningDir(\n projectPath: string,\n issueLower: string,\n): Promise<StepResult> {\n const step = 'teardown:legacy-planning-dir';\n const legacyDir = join(projectPath, '.planning', issueLower);\n if (existsSync(legacyDir)) {\n rmSync(legacyDir, { recursive: true, force: true });\n return stepOk(step, [`Deleted legacy planning dir: ${legacyDir}`]);\n }\n return stepSkipped(step, ['No legacy planning directory found']);\n}\n\n/**\n * Clear .planning/.planning-complete marker from workspace.\n * Only runs if workspace still exists (before worktree removal).\n */\nasync function clearPlanningMarker(workspacePath: string): Promise<StepResult> {\n const step = 'teardown:planning-marker';\n const markerPath = join(workspacePath, '.planning', '.planning-complete');\n if (existsSync(markerPath)) {\n unlinkSync(markerPath);\n return stepOk(step, ['Cleared .planning-complete marker']);\n }\n return stepSkipped(step, ['No .planning-complete marker found']);\n}\n\n/**\n * Build template placeholders for project-specific cleanup (tunnel, Hume).\n */\nfunction buildPlaceholders(\n ctx: LifecycleContext,\n opts: TeardownOptions,\n workspacePath: string,\n) {\n const issueLower = ctx.issueId.toLowerCase();\n const featureFolder = `feature-${issueLower}`;\n const projName = opts.projectName || ctx.projectName || basename(ctx.projectPath);\n const domain = opts.workspaceConfig?.dns?.domain || 'localhost';\n return {\n FEATURE_NAME: issueLower,\n FEATURE_FOLDER: featureFolder,\n BRANCH_NAME: `feature/${issueLower}`,\n COMPOSE_PROJECT: `${projName}-${featureFolder}`,\n DOMAIN: domain,\n PROJECT_NAME: projName,\n PROJECT_PATH: ctx.projectPath,\n WORKSPACE_PATH: workspacePath,\n };\n}\n\n/**\n * Remove Cloudflare tunnel ingress for workspace.\n */\nasync function removeTunnelConfig(\n tunnelConfig: any,\n placeholders: Record<string, string>,\n): Promise<StepResult> {\n const step = 'teardown:tunnel';\n try {\n const { removeTunnelIngress } = await import('../tunnel.js');\n const result = await removeTunnelIngress(tunnelConfig, placeholders as any);\n return stepOk(step, result.steps || ['Removed tunnel ingress']);\n } catch (err) {\n return stepSkipped(step, [`Tunnel cleanup warning: ${(err as Error).message}`]);\n }\n}\n\n/**\n * Remove Hume EVI config for workspace.\n */\nasync function removeHumeEviConfig(\n humeConfig: any,\n placeholders: Record<string, string>,\n): Promise<StepResult> {\n const step = 'teardown:hume';\n try {\n const { deleteHumeConfig } = await import('../hume.js');\n const result = await deleteHumeConfig(humeConfig, placeholders as any);\n return stepOk(step, result.steps || ['Removed Hume EVI config']);\n } catch (err) {\n return stepSkipped(step, [`Hume cleanup warning: ${(err as Error).message}`]);\n }\n}\n\n/**\n * Full workspace teardown.\n *\n * Steps (in order):\n * 1. Kill tmux sessions\n * 2. Clear shadow state\n * 3. Clear legacy planning directory\n * 4. Stop TLDR daemon (if workspace exists)\n * 5. Stop Docker containers (if workspace exists)\n * 6. Clear planning marker (if workspace exists, before deletion)\n * 7. Remove tunnel config (if workspace config provided)\n * 8. Remove Hume config (if workspace config provided)\n * 9. Remove git worktree + workspace directory\n * 10. Remove agent state directories\n * 11. (Optional) Delete feature branches\n */\nexport async function teardownWorkspace(\n ctx: LifecycleContext,\n opts: TeardownOptions = {},\n): Promise<StepResult[]> {\n const issueLower = ctx.issueId.toLowerCase();\n const projName = opts.projectName || ctx.projectName || (extractPrefix(ctx.issueId)?.toLowerCase() ?? ctx.issueId);\n const workspacePath = findWorkspacePath(ctx.projectPath, issueLower);\n const shouldDeleteWorkspace = opts.deleteWorkspace !== false; // default true\n const results: StepResult[] = [];\n\n // 1. Kill tmux sessions\n results.push(await killTmuxSessions(issueLower));\n\n // 2. Clear shadow state (always runs)\n results.push(await clearShadowState(ctx.issueId));\n\n // 3. Clear legacy planning directory (always runs)\n results.push(await clearLegacyPlanningDir(ctx.projectPath, issueLower));\n\n // 4-9: Workspace-specific cleanup\n if (workspacePath && existsSync(workspacePath)) {\n // 4. Stop TLDR daemon (only if deleting workspace)\n if (shouldDeleteWorkspace) {\n results.push(await stopTldrDaemon(workspacePath));\n }\n\n // 5. Stop Docker containers (only if deleting workspace)\n if (shouldDeleteWorkspace && !opts.skipDocker) {\n results.push(await stopDocker(workspacePath, projName, issueLower));\n }\n\n // 5b. Kill orphaned host processes (Vite, node) that survive Docker teardown\n if (shouldDeleteWorkspace) {\n results.push(await killOrphanedProcesses(workspacePath));\n }\n\n // 6. Clear planning marker (before workspace deletion, or when preserving workspace)\n results.push(await clearPlanningMarker(workspacePath));\n\n // 6b. Beads lifecycle: sync or clear depending on context (PAN-412)\n // Normal completion (approve/closeOut): sync beads to project root to preserve history.\n // Destructive wipe: clear beads so the user starts fresh.\n if (opts.clearBeads) {\n results.push(await clearProjectBeads(ctx.projectPath, issueLower));\n } else if (shouldDeleteWorkspace) {\n results.push(await syncWorkspaceBeads(ctx.projectPath, workspacePath, issueLower));\n }\n\n // 7-8: Project-specific cleanup (tunnel, Hume) — only when deleting workspace and config provided\n if (shouldDeleteWorkspace && (opts.workspaceConfig?.tunnel || opts.workspaceConfig?.hume)) {\n const placeholders = buildPlaceholders(ctx, opts, workspacePath);\n\n if (opts.workspaceConfig.tunnel) {\n results.push(await removeTunnelConfig(opts.workspaceConfig.tunnel, placeholders));\n }\n if (opts.workspaceConfig.hume) {\n results.push(await removeHumeEviConfig(opts.workspaceConfig.hume, placeholders));\n }\n }\n\n // 9. Remove worktree + workspace directory (only if deleting workspace)\n if (shouldDeleteWorkspace) {\n results.push(await removeWorktree(ctx.projectPath, workspacePath));\n }\n } else {\n results.push(stepSkipped('teardown:workspace', ['No workspace found to clean up']));\n }\n\n // 10. Remove agent state\n results.push(await removeAgentState(issueLower));\n\n // 11. Delete branches (only if explicitly requested)\n if (opts.deleteBranches) {\n results.push(await deleteBranches(ctx.projectPath, issueLower));\n }\n\n return results;\n}\n","/**\n * Lifecycle workflows — Compose atomic operations into complete workflows.\n *\n * approve() — Post-merge: archive + close + teardown + compact-beads\n * close() — Simple close: close-issue + teardown\n * closeOut() — Full ceremony: verify-merged + archive + teardown + close + label + clear-status\n * deepWipe() — Destructive: teardown(deleteBranches) + delete agent state + reset issue\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { PANOPTICON_HOME } from '../paths.js';\nimport type {\n LifecycleContext,\n WorkflowResult,\n StepResult,\n ApproveOptions,\n DeepWipeOptions,\n ArchiveOptions,\n} from './types.js';\nimport { stepOk, stepSkipped, stepFailed, getLinearApiKey } from './types.js';\nimport { archivePlanning, findWorkspacePath } from './archive-planning.js';\nimport { closeIssue, type CloseIssueOptions } from './close-issue.js';\nimport { teardownWorkspace } from './teardown-workspace.js';\nimport { compactBeads } from './compact-beads.js';\nimport { extractNumber, extractPrefix } from '../issue-id.js';\n\nconst execAsync = promisify(exec);\n\n/**\n * Build a WorkflowResult from collected steps.\n */\nfunction buildResult(\n workflow: WorkflowResult['workflow'],\n issueId: string,\n steps: StepResult[],\n startTime: number,\n): WorkflowResult {\n return {\n workflow,\n issueId,\n success: steps.every(s => s.success),\n steps,\n duration: Date.now() - startTime,\n };\n}\n\n/**\n * approve() — Post-merge lifecycle.\n *\n * 1. Archive planning artifacts (PRD move + .planning/ preservation)\n * 2. Close issue on tracker\n * 3. Teardown workspace\n * 4. Compact beads\n * 5. Clear review status\n *\n * Note: The actual merge step is NOT included here — the merge-agent\n * handles merge validation. This workflow runs AFTER merge completes.\n */\nexport async function approve(\n ctx: LifecycleContext,\n opts: ApproveOptions & CloseIssueOptions & ArchiveOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n\n // 1. Archive planning\n const archiveSteps = await archivePlanning(ctx, opts);\n allSteps.push(...archiveSteps);\n\n // If archive failed, stop — don't destroy unarchived artifacts\n const archiveFailed = archiveSteps.some(s => !s.success && !s.skipped);\n if (archiveFailed) {\n allSteps.push(stepFailed('approve:abort', 'Stopped — archiving failed, workspace preserved'));\n return buildResult('approve', ctx.issueId, allSteps, start);\n }\n\n // 2. Close issue\n const closeSteps = await closeIssue(ctx, {\n tracker: opts.tracker,\n comment: 'Merged to main via Panopticon lifecycle',\n applyLabel: true,\n });\n allSteps.push(...closeSteps);\n\n // 3. Teardown workspace\n const teardownSteps = await teardownWorkspace(ctx);\n allSteps.push(...teardownSteps);\n\n // 4. Compact beads (non-blocking — failure doesn't affect workflow success)\n if (!opts.skipBeadsCompaction) {\n const beadsResult = await compactBeads(ctx);\n allSteps.push(beadsResult);\n }\n\n // 5. Clear review status\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n\n return buildResult('approve', ctx.issueId, allSteps, start);\n}\n\n/**\n * close() — Simple issue close with teardown.\n *\n * Used when an issue is being closed without merge (canceled, won't-do, etc.)\n * Does NOT archive workspace artifacts.\n *\n * 1. Close issue on tracker\n * 2. Teardown workspace\n * 3. Clear review status\n */\nexport async function close(\n ctx: LifecycleContext,\n opts: CloseIssueOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n\n // 1. Close issue\n const closeSteps = await closeIssue(ctx, {\n tracker: opts.tracker,\n reason: opts.reason,\n applyLabel: false,\n });\n allSteps.push(...closeSteps);\n\n // 2. Teardown workspace\n const teardownSteps = await teardownWorkspace(ctx);\n allSteps.push(...teardownSteps);\n\n // 3. Clear review status\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n\n return buildResult('close', ctx.issueId, allSteps, start);\n}\n\n/**\n * closeOut() — Full close-out ceremony.\n *\n * This is the human-gated verification and cleanup workflow.\n * Replaces the monolithic executeCloseOut() function.\n *\n * 1. Verify branch merged (hard fail if not — must pass before any cleanup)\n * 2. Move PRD + archive workspace artifacts (hard fail if archiving fails)\n * 3. Clean up workspace (tmux, TLDR, Docker, worktree)\n * 4. Clean up agent state\n * 5. Close issue on tracker\n * 6. Apply closed-out label\n * 7. Clear review status\n */\nexport async function closeOut(\n ctx: LifecycleContext,\n opts: CloseIssueOptions & ArchiveOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n\n // 1. Verify branch merged (hard fail — must pass before we archive or clean up)\n const mergeVerify = await verifyBranchMerged(ctx);\n allSteps.push(mergeVerify);\n if (!mergeVerify.success && !mergeVerify.skipped) {\n return buildResult('close-out', ctx.issueId, allSteps, start);\n }\n\n // 2. Move PRD + archive workspace artifacts\n const archiveSteps = await archivePlanning(ctx, opts);\n allSteps.push(...archiveSteps);\n\n // Hard fail on archive failure — don't destroy unarchived artifacts\n const archiveFailed = archiveSteps.some(s => !s.success && !s.skipped);\n if (archiveFailed) {\n allSteps.push(stepFailed('close-out:abort', 'Stopped — archiving failed, workspace preserved'));\n return buildResult('close-out', ctx.issueId, allSteps, start);\n }\n\n // 4+5. Teardown workspace + agent state\n const teardownSteps = await teardownWorkspace(ctx);\n allSteps.push(...teardownSteps);\n\n // 6+7. Close issue + apply label\n const closeSteps = await closeIssue(ctx, {\n tracker: opts.tracker,\n comment: 'Closed via close-out ceremony',\n applyLabel: true,\n });\n allSteps.push(...closeSteps);\n\n // 8. Clear review status\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n\n return buildResult('close-out', ctx.issueId, allSteps, start);\n}\n\n/**\n * deepWipe() — Destructive cleanup for abandoned workspaces.\n *\n * 1. Teardown workspace (with branch deletion)\n * 2. (Optional) Reset issue to backlog/open\n * 3. Clear review status\n */\nexport async function deepWipe(\n ctx: LifecycleContext,\n opts: DeepWipeOptions = {},\n): Promise<WorkflowResult> {\n const start = Date.now();\n const allSteps: StepResult[] = [];\n const { deleteWorkspace = true, deleteBranches = true, resetIssue = true, onProgress } = opts;\n\n const TOTAL_STEPS = 3 + (resetIssue ? 1 : 0);\n let stepNum = 0;\n\n const progress = (label: string, detail: string, status: 'active' | 'complete' | 'error' = 'active') => {\n onProgress?.({ step: stepNum, total: TOTAL_STEPS, label, detail, status });\n };\n\n // 1. Teardown workspace (aggressive — delete branches, project-specific cleanup, clear beads)\n stepNum = 1;\n progress('Tearing down workspace', 'Killing agents, stopping services, removing files');\n const teardownSteps = await teardownWorkspace(ctx, {\n deleteWorkspace,\n deleteBranches,\n clearBeads: true,\n workspaceConfig: opts.workspaceConfig,\n projectName: opts.projectName,\n });\n allSteps.push(...teardownSteps);\n const teardownFailed = teardownSteps.some(s => !s.success && !s.skipped);\n progress('Tearing down workspace', teardownFailed ? 'Some steps failed' : 'Workspace torn down', teardownFailed ? 'error' : 'complete');\n\n // 2. Delete git branches\n stepNum = 2;\n progress('Deleting git branches', `feature/${ctx.issueId.toLowerCase()}`);\n // Branch deletion is already handled in teardownWorkspace when deleteBranches is true,\n // but we report it as a separate visible step\n progress('Deleting git branches', deleteBranches ? 'Branches removed' : 'Skipped', 'complete');\n\n // 3. Reset issue to open/backlog\n if (resetIssue) {\n stepNum = 3;\n progress('Resetting issue status', `${ctx.issueId} → Todo`);\n const resetResult = await resetIssueToTodo(ctx);\n allSteps.push(resetResult);\n progress('Resetting issue status', resetResult.success ? 'Issue reset to Todo' : (resetResult.error || 'Failed'), resetResult.success ? 'complete' : 'error');\n }\n\n // 4. Clear review status\n stepNum = resetIssue ? 4 : 3;\n progress('Clearing review status', 'Removing specialist state');\n const clearResult = await clearReviewStatusStep(ctx.issueId);\n allSteps.push(clearResult);\n progress('Clearing review status', 'Review status cleared', 'complete');\n\n return buildResult('deep-wipe', ctx.issueId, allSteps, start);\n}\n\n// --- Internal helpers ---\n\n/**\n * Verify feature branch is merged into main.\n */\nasync function verifyBranchMerged(ctx: LifecycleContext): Promise<StepResult> {\n const step = 'close-out:verify-merged';\n const issueLower = ctx.issueId.toLowerCase();\n const branchName = `feature/${issueLower}`;\n\n try {\n // Check review-status first — the merge specialist validates before marking merged\n try {\n const { loadReviewStatuses } = await import('../review-status.js');\n const statuses = loadReviewStatuses();\n const issueKey = ctx.issueId.toUpperCase();\n if (statuses[issueKey]?.mergeStatus === 'merged') {\n return stepOk(step, ['Merge specialist confirmed merge completed']);\n }\n } catch {\n // review-status.json may not exist, continue with git checks\n }\n\n\n // Check if branch exists locally\n const { stdout: branchExists } = await execAsync(\n `git branch --list \"${branchName}\" 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n\n if (branchExists.trim()) {\n // Use merge-base --is-ancestor: checks if the branch tip is reachable from main\n // Note: does NOT detect squash merges — code-diff fallback handles those\n try {\n await execAsync(\n `git merge-base --is-ancestor ${branchName} main`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n return stepOk(step, ['All commits merged to main']);\n } catch {\n // --is-ancestor fails for squash merges where the branch still exists.\n // Check if the code diff (excluding planning artifacts) is empty — if so,\n // the code was squash-merged and only planning files remain on the branch.\n try {\n const { stdout: codeDiff } = await execAsync(\n `git diff main...${branchName} -- ':!.planning' ':!docs/prds' ':!.panopticon/prompts' 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n if (!codeDiff.trim()) {\n return stepOk(step, ['Code changes squash-merged to main (only planning artifacts remain on branch)']);\n }\n } catch {\n // diff failed — fall through to unmerged report\n }\n\n const { stdout: unmerged } = await execAsync(\n `git log main..${branchName} --oneline 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n const count = unmerged.trim() ? unmerged.trim().split('\\n').length : 0;\n return stepFailed(step, `${count} unmerged commit(s) on ${branchName}. Merge before closing out.`);\n }\n }\n\n // Check remote\n const { stdout: remoteBranch } = await execAsync(\n `git ls-remote --heads origin \"${branchName}\" 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n\n if (remoteBranch.trim()) {\n await execAsync(`git fetch origin ${branchName}`, { cwd: ctx.projectPath }).catch(() => {});\n try {\n await execAsync(\n `git merge-base --is-ancestor origin/${branchName} main`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n return stepOk(step, ['Remote branch fully merged']);\n } catch {\n // Squash-merge detection for remote branch\n try {\n const { stdout: codeDiff } = await execAsync(\n `git diff main...origin/${branchName} -- ':!.planning' ':!docs/prds' ':!.panopticon/prompts' 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n if (!codeDiff.trim()) {\n return stepOk(step, ['Remote code changes squash-merged to main (only planning artifacts remain on branch)']);\n }\n } catch {\n // diff failed — fall through\n }\n\n const { stdout: remoteUnmerged } = await execAsync(\n `git log main..origin/${branchName} --oneline 2>/dev/null || true`,\n { cwd: ctx.projectPath, encoding: 'utf-8' },\n );\n const count = remoteUnmerged.trim() ? remoteUnmerged.trim().split('\\n').length : 0;\n return stepFailed(step, `${count} unmerged commit(s) on remote ${branchName}.`);\n }\n }\n\n // No branch at all — assume squash-merged and branch deleted\n return stepOk(step, ['Branch already cleaned up (squash-merged)']);\n } catch (err) {\n return stepFailed(step, `Could not verify merge: ${(err as Error).message}`);\n }\n}\n\n/**\n * Reset issue back to open/backlog state (for deep-wipe).\n */\nasync function resetIssueToTodo(ctx: LifecycleContext): Promise<StepResult> {\n const step = 'deep-wipe:reset-issue';\n try {\n if (ctx.github) {\n const { owner, repo, number } = ctx.github;\n // Reopen the issue\n await execAsync(\n `gh issue reopen ${number} --repo ${owner}/${repo}`,\n { encoding: 'utf-8' },\n ).catch(() => {}); // May already be open\n // Remove lifecycle labels\n const labelsToRemove = ['in-review', 'in-progress', 'planned', 'planning', 'Review: Approved', 'Review: Failed', 'ready-for-merge'];\n for (const label of labelsToRemove) {\n await execAsync(\n `gh issue edit ${number} --repo ${owner}/${repo} --remove-label \"${label}\"`,\n { encoding: 'utf-8' },\n ).catch(() => {}); // Label may not exist\n }\n return stepOk(step, [`Reset GitHub issue #${number}: reopened and cleared labels`]);\n }\n\n // Linear: reopen to Todo\n const linearApiKey = getLinearApiKey();\n if (linearApiKey) {\n const { LinearClient } = await import('@linear/sdk');\n const client = new LinearClient({ apiKey: linearApiKey });\n const issueNum = extractNumber(ctx.issueId);\n const teamKey = extractPrefix(ctx.issueId);\n if (issueNum === null || teamKey === null) {\n return stepFailed(step, `Could not parse issue ID: ${ctx.issueId}`);\n }\n const results = await client.issues({\n filter: {\n number: { eq: issueNum },\n team: { key: { eq: teamKey } },\n },\n first: 1,\n });\n if (results.nodes.length > 0) {\n const issue = results.nodes[0];\n const team = await issue.team;\n if (team) {\n const states = await team.states();\n const todoState = states.nodes.find(s => s.type === 'unstarted' && s.name === 'Todo') ||\n states.nodes.find(s => s.type === 'unstarted');\n if (todoState) {\n await issue.update({ stateId: todoState.id });\n }\n }\n }\n return stepOk(step, [`Reset Linear issue ${ctx.issueId} to Todo`]);\n }\n\n return stepSkipped(step, ['No tracker available to reset issue']);\n } catch (err) {\n return stepFailed(step, `Failed to reset issue: ${(err as Error).message}`);\n }\n}\n\n/**\n * Clear review status for an issue.\n */\nasync function clearReviewStatusStep(issueId: string): Promise<StepResult> {\n const step = 'clear-review-status';\n try {\n const { clearReviewStatus } = await import('../review-status.js');\n clearReviewStatus(issueId.toUpperCase());\n return stepOk(step, ['Review status cleared']);\n } catch {\n // Fallback: direct file manipulation\n try {\n const statusFile = join(PANOPTICON_HOME, 'review-status.json');\n if (existsSync(statusFile)) {\n const data = JSON.parse(readFileSync(statusFile, 'utf-8'));\n const upperKey = issueId.toUpperCase();\n if (data[upperKey]) {\n delete data[upperKey];\n const { writeFileSync } = await import('fs');\n writeFileSync(statusFile, JSON.stringify(data, null, 2));\n }\n }\n return stepOk(step, ['Review status cleared (direct)']);\n } catch (innerErr) {\n return stepSkipped(step, [`Failed to clear review status (non-fatal): ${(innerErr as Error).message}`]);\n }\n }\n}\n\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __esmMin } from "./chunk-ruWRV7i3.js";
|
|
2
|
-
import { n as init_config_yaml, r as loadConfig } from "./config-yaml-
|
|
2
|
+
import { n as init_config_yaml, r as loadConfig } from "./config-yaml-BHD2Qdd8.js";
|
|
3
3
|
import { a as TrackerAuthError, i as NotImplementedError, n as init_rally, o as init_interface, r as IssueNotFoundError, t as RallyTracker } from "./rally-Dy00NElU.js";
|
|
4
4
|
import { LinearClient } from "@linear/sdk";
|
|
5
5
|
import { Octokit } from "@octokit/rest";
|
|
@@ -524,4 +524,4 @@ var init_factory = __esmMin((() => {
|
|
|
524
524
|
//#endregion
|
|
525
525
|
export { getSecondaryTracker as a, init_gitlab as c, LinearTracker as d, init_linear as f, getPrimaryTracker as i, GitHubTracker as l, createTrackerFromConfig as n, init_factory as o, getAllTrackers as r, GitLabTracker as s, createTracker as t, init_github as u };
|
|
526
526
|
|
|
527
|
-
//# sourceMappingURL=factory-
|
|
527
|
+
//# sourceMappingURL=factory-D6LJaZ__.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory-DzsOiZVc.js","names":["loadYamlConfig"],"sources":["../src/lib/tracker/linear.ts","../src/lib/tracker/github.ts","../src/lib/tracker/gitlab.ts","../src/lib/tracker/factory.ts"],"sourcesContent":["/**\n * Linear Issue Tracker Adapter\n *\n * Implements IssueTracker interface for Linear.\n */\n\nimport { LinearClient } from '@linear/sdk';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\n// Map Linear state types to our normalized states\nconst STATE_MAP: Record<string, IssueState> = {\n backlog: 'open',\n unstarted: 'open',\n started: 'in_progress',\n completed: 'closed',\n canceled: 'closed',\n};\n\nexport class LinearTracker implements IssueTracker {\n readonly name: TrackerType = 'linear';\n private client: LinearClient;\n private defaultTeam?: string;\n\n constructor(apiKey: string, options?: { team?: string }) {\n if (!apiKey) {\n throw new TrackerAuthError('linear', 'API key is required');\n }\n this.client = new LinearClient({ apiKey });\n this.defaultTeam = options?.team;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const team = filters?.team ?? this.defaultTeam;\n\n const result = await this.client.issues({\n first: filters?.limit ?? 50,\n filter: {\n team: team ? { key: { eq: team } } : undefined,\n state: filters?.state\n ? { type: { eq: this.reverseMapState(filters.state) } }\n : filters?.includeClosed\n ? undefined\n : { type: { neq: 'completed' } },\n labels: filters?.labels?.length\n ? { name: { in: filters.labels } }\n : undefined,\n assignee: filters?.assignee\n ? { name: { containsIgnoreCase: filters.assignee } }\n : undefined,\n },\n });\n\n const issues: Issue[] = [];\n for (const node of result.nodes) {\n issues.push(await this.normalizeIssue(node));\n }\n return issues;\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Check if it's a UUID (36 chars with hyphens)\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n\n if (isUuid) {\n // Fetch directly by UUID\n const issue = await this.client.issue(id);\n if (issue) {\n return this.normalizeIssue(issue);\n }\n } else {\n // Parse identifier (e.g., MIN-630) and search\n const match = id.match(/^([A-Z]+)-(\\d+)$/i);\n if (match) {\n const [, teamKey, number] = match;\n // Use searchIssues which supports identifier matching\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n return this.normalizeIssue(results.nodes[0]);\n }\n }\n }\n\n throw new IssueNotFoundError(id, 'linear');\n } catch (error) {\n if (error instanceof IssueNotFoundError) throw error;\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issue = await this.getIssue(id);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.description = update.description;\n }\n if (update.priority !== undefined) {\n updatePayload.priority = update.priority;\n }\n if (update.dueDate !== undefined) {\n updatePayload.dueDate = update.dueDate;\n }\n if (update.state !== undefined) {\n // Need to find the state ID - this is complex in Linear\n // For now, we'll use the transition method\n await this.transitionIssue(id, update.state);\n }\n if (update.labels !== undefined) {\n // Need to look up label IDs - complex operation\n // TODO: Implement label updates\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.client.updateIssue(issue.id, updatePayload);\n }\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const team = newIssue.team ?? this.defaultTeam;\n\n if (!team) {\n throw new Error('Team is required to create an issue');\n }\n\n // Get team ID from key\n const teams = await this.client.teams({\n filter: { key: { eq: team } },\n });\n\n if (teams.nodes.length === 0) {\n throw new Error(`Team not found: ${team}`);\n }\n\n const teamId = teams.nodes[0].id;\n\n const result = await this.client.createIssue({\n teamId,\n title: newIssue.title,\n description: newIssue.description,\n priority: newIssue.priority,\n dueDate: newIssue.dueDate,\n });\n\n const created = await result.issue;\n if (!created) {\n throw new Error('Failed to create issue');\n }\n\n return this.normalizeIssue(created);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issue = await this.client.issue(issueId);\n const comments = await issue.comments();\n\n return comments.nodes.map((c) => ({\n id: c.id,\n issueId,\n body: c.body,\n author: c.user?.then((u) => u?.name ?? 'Unknown') as unknown as string, // Simplified\n createdAt: c.createdAt.toISOString(),\n updatedAt: c.updatedAt.toISOString(),\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const result = await this.client.createComment({\n issueId,\n body,\n });\n\n const comment = await result.comment;\n if (!comment) {\n throw new Error('Failed to create comment');\n }\n\n return {\n id: comment.id,\n issueId,\n body: comment.body,\n author: 'Panopticon', // Simplified\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n // Resolve the Linear issue directly (avoid normalizeIssue which may fail on SDK edge cases)\n let linearIssue: any;\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n if (isUuid) {\n linearIssue = await this.client.issue(id);\n } else {\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n linearIssue = results.nodes[0];\n } else {\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n // Get workflow states for the issue's team\n const team = await linearIssue.team;\n if (!team) {\n throw new Error('Could not determine issue team');\n }\n\n const states = await team.states();\n\n let targetState: any;\n if (state === 'in_review') {\n // Find a state named \"In Review\" (case-insensitive) — more precise than matching by type,\n // since \"In Progress\" and \"In Review\" are both type \"started\" in Linear.\n targetState = states.nodes.find((s: any) => s.name.toLowerCase() === 'in review');\n if (!targetState) {\n // Fall back to lowest-position \"started\" state if no \"In Review\" state exists\n const startedStates = states.nodes\n .filter((s: any) => s.type === 'started')\n .sort((a: any, b: any) => (a.position ?? 0) - (b.position ?? 0));\n targetState = startedStates[0];\n if (!targetState) {\n throw new Error('No \"In Review\" or \"started\" state found in Linear');\n }\n }\n } else {\n const targetStateType = this.reverseMapState(state);\n\n // Find a state matching the target type.\n // Multiple states can share the same type (e.g., \"In Planning\", \"In Progress\", \"In Review\"\n // are all type \"started\"). Prefer the one with the lowest position (most basic/default state\n // for that type), which matches Linear's convention.\n const matchingStates = states.nodes\n .filter((s: any) => s.type === targetStateType)\n .sort((a: any, b: any) => (a.position ?? 0) - (b.position ?? 0));\n targetState = matchingStates[0];\n if (!targetState) {\n throw new Error(`No state found matching type: ${targetStateType}`);\n }\n }\n\n await this.client.updateIssue(linearIssue.id, {\n stateId: targetState.id,\n });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n const issue = await this.getIssue(issueId);\n\n await this.client.createAttachment({\n issueId: issue.id,\n title: 'Pull Request',\n url: prUrl,\n });\n }\n\n private async normalizeIssue(linearIssue: any): Promise<Issue> {\n const state = await linearIssue.state;\n const assignee = await linearIssue.assignee;\n const labels = await linearIssue.labels();\n\n // Handle dueDate - can be Date, string, or undefined\n let dueDate: string | undefined;\n if (linearIssue.dueDate) {\n dueDate = linearIssue.dueDate instanceof Date\n ? linearIssue.dueDate.toISOString()\n : String(linearIssue.dueDate);\n }\n\n return {\n id: linearIssue.id,\n ref: linearIssue.identifier,\n title: linearIssue.title,\n description: linearIssue.description ?? '',\n state: this.mapState(state?.type ?? 'backlog'),\n labels: labels?.nodes?.map((l: any) => l.name) ?? [],\n assignee: assignee?.name,\n url: linearIssue.url,\n tracker: 'linear',\n priority: linearIssue.priority,\n dueDate,\n createdAt: linearIssue.createdAt instanceof Date\n ? linearIssue.createdAt.toISOString()\n : String(linearIssue.createdAt),\n updatedAt: linearIssue.updatedAt instanceof Date\n ? linearIssue.updatedAt.toISOString()\n : String(linearIssue.updatedAt),\n };\n }\n\n private mapState(linearState: string): IssueState {\n return STATE_MAP[linearState] ?? 'open';\n }\n\n private reverseMapState(state: IssueState): string {\n switch (state) {\n case 'open':\n return 'unstarted';\n case 'in_progress':\n case 'in_review':\n return 'started';\n case 'closed':\n return 'completed';\n default:\n return 'unstarted';\n }\n }\n}\n","/**\n * GitHub Issues Tracker Adapter\n *\n * Implements IssueTracker interface for GitHub Issues.\n */\n\nimport { Octokit } from '@octokit/rest';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\n/**\n * Extract issue number from various formats: \"300\", \"#300\", \"PAN-300\"\n */\nfunction parseIssueNumber(id: string): number {\n const match = id.match(/(\\d+)$/);\n return match ? parseInt(match[1], 10) : NaN;\n}\n\nexport class GitHubTracker implements IssueTracker {\n readonly name: TrackerType = 'github';\n private octokit: Octokit;\n private owner: string;\n private repo: string;\n\n constructor(token: string, owner: string, repo: string) {\n if (!token) {\n throw new TrackerAuthError('github', 'Token is required');\n }\n if (!owner || !repo) {\n throw new Error('GitHub owner and repo are required');\n }\n\n this.octokit = new Octokit({ auth: token });\n this.owner = owner;\n this.repo = repo;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const state = this.mapStateToGitHub(filters?.state);\n\n const response = await this.octokit.issues.listForRepo({\n owner: this.owner,\n repo: this.repo,\n state: filters?.includeClosed ? 'all' : state,\n labels: filters?.labels?.join(',') || undefined,\n assignee: filters?.assignee || undefined,\n per_page: filters?.limit ?? 50,\n });\n\n // Filter out pull requests (GitHub API returns both)\n const issues = response.data.filter((item) => !item.pull_request);\n\n return issues.map((issue) => this.normalizeIssue(issue));\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Parse the issue number from refs like \"#42\" or just \"42\"\n const issueNumber = parseIssueNumber(id);\n\n if (isNaN(issueNumber)) {\n throw new IssueNotFoundError(id, 'github');\n }\n\n const { data: issue } = await this.octokit.issues.get({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return this.normalizeIssue(issue);\n } catch (error: any) {\n if (error?.status === 404) {\n throw new IssueNotFoundError(id, 'github');\n }\n throw error;\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issueNumber = parseIssueNumber(id);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.body = update.description;\n }\n if (update.state !== undefined) {\n updatePayload.state = update.state === 'closed' ? 'closed' : 'open';\n }\n if (update.labels !== undefined) {\n updatePayload.labels = update.labels;\n }\n if (update.assignee !== undefined) {\n updatePayload.assignees = update.assignee ? [update.assignee] : [];\n }\n\n await this.octokit.issues.update({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n ...updatePayload,\n });\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const { data: issue } = await this.octokit.issues.create({\n owner: this.owner,\n repo: this.repo,\n title: newIssue.title,\n body: newIssue.description,\n labels: newIssue.labels,\n assignees: newIssue.assignee ? [newIssue.assignee] : undefined,\n });\n\n return this.normalizeIssue(issue);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issueNumber = parseIssueNumber(issueId);\n\n const { data: comments } = await this.octokit.issues.listComments({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return comments.map((c) => ({\n id: String(c.id),\n issueId,\n body: c.body ?? '',\n author: c.user?.login ?? 'Unknown',\n createdAt: c.created_at,\n updatedAt: c.updated_at,\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const issueNumber = parseIssueNumber(issueId);\n\n const { data: comment } = await this.octokit.issues.createComment({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n body,\n });\n\n return {\n id: String(comment.id),\n issueId,\n body: comment.body ?? '',\n author: comment.user?.login ?? 'Unknown',\n createdAt: comment.created_at,\n updatedAt: comment.updated_at,\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n const issueNumber = parseIssueNumber(id);\n\n if (state === 'in_progress') {\n // GitHub has no native \"in progress\" state — use a label instead.\n await this.ensureLabelExists('in-progress', 'In progress', '0075ca');\n await this.octokit.issues.addLabels({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n labels: ['in-progress'],\n });\n } else if (state === 'in_review') {\n // Swap in-progress label for in-review label\n await this.ensureLabelExists('in-review', 'In review', 'e4e669');\n await this.octokit.issues.addLabels({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n labels: ['in-review'],\n });\n // Remove in-progress label if present\n await this.octokit.issues.removeLabel({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n name: 'in-progress',\n }).catch(() => {/* label may not exist, ignore */});\n } else {\n // Remove in-progress and in-review labels when moving to open or closed\n const issue = await this.getIssue(id);\n for (const label of ['in-progress', 'in-review']) {\n if (issue.labels?.includes(label)) {\n await this.octokit.issues.removeLabel({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n name: label,\n }).catch(() => {/* label may not exist, ignore */});\n }\n }\n await this.updateIssue(id, { state });\n }\n }\n\n /** Ensure a label exists in the repo, creating it if needed. */\n private async ensureLabelExists(name: string, description: string, color: string): Promise<void> {\n try {\n await this.octokit.issues.getLabel({ owner: this.owner, repo: this.repo, name });\n } catch {\n await this.octokit.issues.createLabel({\n owner: this.owner,\n repo: this.repo,\n name,\n description,\n color,\n }).catch(() => {/* race condition: another process created it first */});\n }\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n // GitHub auto-links PRs that mention issues\n // Add a comment with the PR link\n await this.addComment(\n issueId,\n `Linked Pull Request: ${prUrl}`\n );\n }\n\n private normalizeIssue(ghIssue: any): Issue {\n const labels: string[] = ghIssue.labels.map((l: any) =>\n typeof l === 'string' ? l : l.name\n );\n return {\n id: String(ghIssue.id),\n ref: `#${ghIssue.number}`,\n title: ghIssue.title,\n description: ghIssue.body ?? '',\n state: this.mapStateFromGitHub(ghIssue.state, labels),\n labels,\n assignee: ghIssue.assignee?.login,\n url: ghIssue.html_url,\n tracker: 'github',\n priority: undefined, // GitHub doesn't have priority\n dueDate: undefined, // GitHub doesn't have due dates on issues\n createdAt: ghIssue.created_at,\n updatedAt: ghIssue.updated_at,\n };\n }\n\n private mapStateFromGitHub(ghState: string, labels: string[] = []): IssueState {\n if (ghState === 'closed') return 'closed';\n if (labels.includes('in-progress')) return 'in_progress';\n return 'open';\n }\n\n private mapStateToGitHub(\n state?: IssueState\n ): 'open' | 'closed' | 'all' {\n if (!state) return 'open';\n if (state === 'closed') return 'closed';\n return 'open'; // Both 'open' and 'in_progress' map to 'open'\n }\n}\n","/**\n * GitLab Issues Tracker Adapter (Stub)\n *\n * Placeholder implementation for GitLab Issues support.\n * Full implementation will use @gitbeaker/rest.\n */\n\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { NotImplementedError } from './interface.js';\n\nexport class GitLabTracker implements IssueTracker {\n readonly name: TrackerType = 'gitlab';\n\n constructor(\n private token: string,\n private projectId: string\n ) {\n // Stub - will initialize @gitbeaker client when implemented\n }\n\n async listIssues(_filters?: IssueFilters): Promise<Issue[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getIssue(_id: string): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async updateIssue(_id: string, _update: IssueUpdate): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async createIssue(_issue: NewIssue): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getComments(_issueId: string): Promise<Comment[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async addComment(_issueId: string, _body: string): Promise<Comment> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async transitionIssue(_id: string, _state: IssueState): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async linkPR(_issueId: string, _prUrl: string): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n}\n","/**\n * Tracker Factory\n *\n * Creates appropriate tracker instances based on configuration.\n */\n\nimport type { IssueTracker, TrackerType } from './interface.js';\nimport { TrackerAuthError } from './interface.js';\nimport { LinearTracker } from './linear.js';\nimport { GitHubTracker } from './github.js';\nimport { GitLabTracker } from './gitlab.js';\nimport { RallyTracker } from './rally.js';\nimport type { TrackersConfig } from '../config.js';\nimport { loadConfig as loadYamlConfig } from '../config-yaml.js';\n\n// Configuration for a single tracker\nexport interface TrackerConfig {\n type: TrackerType;\n\n // Linear-specific\n apiKeyEnv?: string;\n team?: string;\n\n // GitHub-specific\n tokenEnv?: string;\n owner?: string;\n repo?: string;\n\n // GitLab-specific\n projectId?: string;\n\n // Rally-specific\n server?: string;\n workspace?: string;\n project?: string;\n}\n\n// Multi-tracker configuration (re-exported from config.ts)\n// Note: Use TrackersConfig from config.ts for full type with nested configs\n\n/**\n * Get tracker API key from config.yaml (Settings page).\n * This is checked FIRST — env vars are the fallback, not the other way around.\n */\nfunction getTrackerKeyFromConfig(trackerType: TrackerType): string | undefined {\n try {\n const { config: yamlConfig } = loadYamlConfig();\n return yamlConfig.trackerKeys[trackerType];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Create a tracker instance from configuration.\n * Priority: config.yaml (Settings) > environment variable > custom env var name\n */\nexport function createTracker(config: TrackerConfig): IssueTracker {\n switch (config.type) {\n case 'linear': {\n const configKey = getTrackerKeyFromConfig('linear');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.LINEAR_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'linear',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'LINEAR_API_KEY'} environment variable.`\n );\n }\n\n return new LinearTracker(apiKey, { team: config.team });\n }\n\n case 'github': {\n const configKey = getTrackerKeyFromConfig('github');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITHUB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'github',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITHUB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.owner || !config.repo) {\n throw new Error(\n 'GitHub tracker requires owner and repo configuration'\n );\n }\n\n return new GitHubTracker(token, config.owner, config.repo);\n }\n\n case 'gitlab': {\n const configKey = getTrackerKeyFromConfig('gitlab');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITLAB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'gitlab',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITLAB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.projectId) {\n throw new Error('GitLab tracker requires projectId configuration');\n }\n\n return new GitLabTracker(token, config.projectId);\n }\n\n case 'rally': {\n const configKey = getTrackerKeyFromConfig('rally');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.RALLY_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'rally',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'RALLY_API_KEY'} environment variable.`\n );\n }\n\n return new RallyTracker({\n apiKey,\n server: config.server,\n workspace: config.workspace,\n project: config.project,\n });\n }\n\n default:\n throw new Error(`Unknown tracker type: ${config.type}`);\n }\n}\n\n/**\n * Create tracker from trackers configuration section\n */\nexport function createTrackerFromConfig(\n trackersConfig: TrackersConfig,\n trackerType: TrackerType\n): IssueTracker {\n const config = trackersConfig[trackerType];\n\n if (!config) {\n throw new Error(\n `No configuration found for tracker: ${trackerType}. Add [trackers.${trackerType}] to config.`\n );\n }\n\n return createTracker({ ...config, type: trackerType });\n}\n\n/**\n * Get the primary tracker from configuration\n */\nexport function getPrimaryTracker(trackersConfig: TrackersConfig): IssueTracker {\n return createTrackerFromConfig(trackersConfig, trackersConfig.primary);\n}\n\n/**\n * Get the secondary tracker from configuration (if configured)\n */\nexport function getSecondaryTracker(\n trackersConfig: TrackersConfig\n): IssueTracker | null {\n if (!trackersConfig.secondary) {\n return null;\n }\n return createTrackerFromConfig(trackersConfig, trackersConfig.secondary);\n}\n\n/**\n * Get all configured trackers\n */\nexport function getAllTrackers(trackersConfig: TrackersConfig): IssueTracker[] {\n const trackers: IssueTracker[] = [getPrimaryTracker(trackersConfig)];\n\n const secondary = getSecondaryTracker(trackersConfig);\n if (secondary) {\n trackers.push(secondary);\n }\n\n return trackers;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"factory-D6LJaZ__.js","names":["loadYamlConfig"],"sources":["../src/lib/tracker/linear.ts","../src/lib/tracker/github.ts","../src/lib/tracker/gitlab.ts","../src/lib/tracker/factory.ts"],"sourcesContent":["/**\n * Linear Issue Tracker Adapter\n *\n * Implements IssueTracker interface for Linear.\n */\n\nimport { LinearClient } from '@linear/sdk';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\n// Map Linear state types to our normalized states\nconst STATE_MAP: Record<string, IssueState> = {\n backlog: 'open',\n unstarted: 'open',\n started: 'in_progress',\n completed: 'closed',\n canceled: 'closed',\n};\n\nexport class LinearTracker implements IssueTracker {\n readonly name: TrackerType = 'linear';\n private client: LinearClient;\n private defaultTeam?: string;\n\n constructor(apiKey: string, options?: { team?: string }) {\n if (!apiKey) {\n throw new TrackerAuthError('linear', 'API key is required');\n }\n this.client = new LinearClient({ apiKey });\n this.defaultTeam = options?.team;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const team = filters?.team ?? this.defaultTeam;\n\n const result = await this.client.issues({\n first: filters?.limit ?? 50,\n filter: {\n team: team ? { key: { eq: team } } : undefined,\n state: filters?.state\n ? { type: { eq: this.reverseMapState(filters.state) } }\n : filters?.includeClosed\n ? undefined\n : { type: { neq: 'completed' } },\n labels: filters?.labels?.length\n ? { name: { in: filters.labels } }\n : undefined,\n assignee: filters?.assignee\n ? { name: { containsIgnoreCase: filters.assignee } }\n : undefined,\n },\n });\n\n const issues: Issue[] = [];\n for (const node of result.nodes) {\n issues.push(await this.normalizeIssue(node));\n }\n return issues;\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Check if it's a UUID (36 chars with hyphens)\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n\n if (isUuid) {\n // Fetch directly by UUID\n const issue = await this.client.issue(id);\n if (issue) {\n return this.normalizeIssue(issue);\n }\n } else {\n // Parse identifier (e.g., MIN-630) and search\n const match = id.match(/^([A-Z]+)-(\\d+)$/i);\n if (match) {\n const [, teamKey, number] = match;\n // Use searchIssues which supports identifier matching\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n return this.normalizeIssue(results.nodes[0]);\n }\n }\n }\n\n throw new IssueNotFoundError(id, 'linear');\n } catch (error) {\n if (error instanceof IssueNotFoundError) throw error;\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issue = await this.getIssue(id);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.description = update.description;\n }\n if (update.priority !== undefined) {\n updatePayload.priority = update.priority;\n }\n if (update.dueDate !== undefined) {\n updatePayload.dueDate = update.dueDate;\n }\n if (update.state !== undefined) {\n // Need to find the state ID - this is complex in Linear\n // For now, we'll use the transition method\n await this.transitionIssue(id, update.state);\n }\n if (update.labels !== undefined) {\n // Need to look up label IDs - complex operation\n // TODO: Implement label updates\n }\n\n if (Object.keys(updatePayload).length > 0) {\n await this.client.updateIssue(issue.id, updatePayload);\n }\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const team = newIssue.team ?? this.defaultTeam;\n\n if (!team) {\n throw new Error('Team is required to create an issue');\n }\n\n // Get team ID from key\n const teams = await this.client.teams({\n filter: { key: { eq: team } },\n });\n\n if (teams.nodes.length === 0) {\n throw new Error(`Team not found: ${team}`);\n }\n\n const teamId = teams.nodes[0].id;\n\n const result = await this.client.createIssue({\n teamId,\n title: newIssue.title,\n description: newIssue.description,\n priority: newIssue.priority,\n dueDate: newIssue.dueDate,\n });\n\n const created = await result.issue;\n if (!created) {\n throw new Error('Failed to create issue');\n }\n\n return this.normalizeIssue(created);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issue = await this.client.issue(issueId);\n const comments = await issue.comments();\n\n return comments.nodes.map((c) => ({\n id: c.id,\n issueId,\n body: c.body,\n author: c.user?.then((u) => u?.name ?? 'Unknown') as unknown as string, // Simplified\n createdAt: c.createdAt.toISOString(),\n updatedAt: c.updatedAt.toISOString(),\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const result = await this.client.createComment({\n issueId,\n body,\n });\n\n const comment = await result.comment;\n if (!comment) {\n throw new Error('Failed to create comment');\n }\n\n return {\n id: comment.id,\n issueId,\n body: comment.body,\n author: 'Panopticon', // Simplified\n createdAt: comment.createdAt.toISOString(),\n updatedAt: comment.updatedAt.toISOString(),\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n // Resolve the Linear issue directly (avoid normalizeIssue which may fail on SDK edge cases)\n let linearIssue: any;\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);\n if (isUuid) {\n linearIssue = await this.client.issue(id);\n } else {\n const results = await this.client.searchIssues(id, { first: 1 });\n if (results.nodes.length > 0) {\n linearIssue = results.nodes[0];\n } else {\n throw new IssueNotFoundError(id, 'linear');\n }\n }\n\n // Get workflow states for the issue's team\n const team = await linearIssue.team;\n if (!team) {\n throw new Error('Could not determine issue team');\n }\n\n const states = await team.states();\n\n let targetState: any;\n if (state === 'in_review') {\n // Find a state named \"In Review\" (case-insensitive) — more precise than matching by type,\n // since \"In Progress\" and \"In Review\" are both type \"started\" in Linear.\n targetState = states.nodes.find((s: any) => s.name.toLowerCase() === 'in review');\n if (!targetState) {\n // Fall back to lowest-position \"started\" state if no \"In Review\" state exists\n const startedStates = states.nodes\n .filter((s: any) => s.type === 'started')\n .sort((a: any, b: any) => (a.position ?? 0) - (b.position ?? 0));\n targetState = startedStates[0];\n if (!targetState) {\n throw new Error('No \"In Review\" or \"started\" state found in Linear');\n }\n }\n } else {\n const targetStateType = this.reverseMapState(state);\n\n // Find a state matching the target type.\n // Multiple states can share the same type (e.g., \"In Planning\", \"In Progress\", \"In Review\"\n // are all type \"started\"). Prefer the one with the lowest position (most basic/default state\n // for that type), which matches Linear's convention.\n const matchingStates = states.nodes\n .filter((s: any) => s.type === targetStateType)\n .sort((a: any, b: any) => (a.position ?? 0) - (b.position ?? 0));\n targetState = matchingStates[0];\n if (!targetState) {\n throw new Error(`No state found matching type: ${targetStateType}`);\n }\n }\n\n await this.client.updateIssue(linearIssue.id, {\n stateId: targetState.id,\n });\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n const issue = await this.getIssue(issueId);\n\n await this.client.createAttachment({\n issueId: issue.id,\n title: 'Pull Request',\n url: prUrl,\n });\n }\n\n private async normalizeIssue(linearIssue: any): Promise<Issue> {\n const state = await linearIssue.state;\n const assignee = await linearIssue.assignee;\n const labels = await linearIssue.labels();\n\n // Handle dueDate - can be Date, string, or undefined\n let dueDate: string | undefined;\n if (linearIssue.dueDate) {\n dueDate = linearIssue.dueDate instanceof Date\n ? linearIssue.dueDate.toISOString()\n : String(linearIssue.dueDate);\n }\n\n return {\n id: linearIssue.id,\n ref: linearIssue.identifier,\n title: linearIssue.title,\n description: linearIssue.description ?? '',\n state: this.mapState(state?.type ?? 'backlog'),\n labels: labels?.nodes?.map((l: any) => l.name) ?? [],\n assignee: assignee?.name,\n url: linearIssue.url,\n tracker: 'linear',\n priority: linearIssue.priority,\n dueDate,\n createdAt: linearIssue.createdAt instanceof Date\n ? linearIssue.createdAt.toISOString()\n : String(linearIssue.createdAt),\n updatedAt: linearIssue.updatedAt instanceof Date\n ? linearIssue.updatedAt.toISOString()\n : String(linearIssue.updatedAt),\n };\n }\n\n private mapState(linearState: string): IssueState {\n return STATE_MAP[linearState] ?? 'open';\n }\n\n private reverseMapState(state: IssueState): string {\n switch (state) {\n case 'open':\n return 'unstarted';\n case 'in_progress':\n case 'in_review':\n return 'started';\n case 'closed':\n return 'completed';\n default:\n return 'unstarted';\n }\n }\n}\n","/**\n * GitHub Issues Tracker Adapter\n *\n * Implements IssueTracker interface for GitHub Issues.\n */\n\nimport { Octokit } from '@octokit/rest';\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { IssueNotFoundError, TrackerAuthError } from './interface.js';\n\n/**\n * Extract issue number from various formats: \"300\", \"#300\", \"PAN-300\"\n */\nfunction parseIssueNumber(id: string): number {\n const match = id.match(/(\\d+)$/);\n return match ? parseInt(match[1], 10) : NaN;\n}\n\nexport class GitHubTracker implements IssueTracker {\n readonly name: TrackerType = 'github';\n private octokit: Octokit;\n private owner: string;\n private repo: string;\n\n constructor(token: string, owner: string, repo: string) {\n if (!token) {\n throw new TrackerAuthError('github', 'Token is required');\n }\n if (!owner || !repo) {\n throw new Error('GitHub owner and repo are required');\n }\n\n this.octokit = new Octokit({ auth: token });\n this.owner = owner;\n this.repo = repo;\n }\n\n async listIssues(filters?: IssueFilters): Promise<Issue[]> {\n const state = this.mapStateToGitHub(filters?.state);\n\n const response = await this.octokit.issues.listForRepo({\n owner: this.owner,\n repo: this.repo,\n state: filters?.includeClosed ? 'all' : state,\n labels: filters?.labels?.join(',') || undefined,\n assignee: filters?.assignee || undefined,\n per_page: filters?.limit ?? 50,\n });\n\n // Filter out pull requests (GitHub API returns both)\n const issues = response.data.filter((item) => !item.pull_request);\n\n return issues.map((issue) => this.normalizeIssue(issue));\n }\n\n async getIssue(id: string): Promise<Issue> {\n try {\n // Parse the issue number from refs like \"#42\" or just \"42\"\n const issueNumber = parseIssueNumber(id);\n\n if (isNaN(issueNumber)) {\n throw new IssueNotFoundError(id, 'github');\n }\n\n const { data: issue } = await this.octokit.issues.get({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return this.normalizeIssue(issue);\n } catch (error: any) {\n if (error?.status === 404) {\n throw new IssueNotFoundError(id, 'github');\n }\n throw error;\n }\n }\n\n async updateIssue(id: string, update: IssueUpdate): Promise<Issue> {\n const issueNumber = parseIssueNumber(id);\n\n const updatePayload: Record<string, unknown> = {};\n\n if (update.title !== undefined) {\n updatePayload.title = update.title;\n }\n if (update.description !== undefined) {\n updatePayload.body = update.description;\n }\n if (update.state !== undefined) {\n updatePayload.state = update.state === 'closed' ? 'closed' : 'open';\n }\n if (update.labels !== undefined) {\n updatePayload.labels = update.labels;\n }\n if (update.assignee !== undefined) {\n updatePayload.assignees = update.assignee ? [update.assignee] : [];\n }\n\n await this.octokit.issues.update({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n ...updatePayload,\n });\n\n return this.getIssue(id);\n }\n\n async createIssue(newIssue: NewIssue): Promise<Issue> {\n const { data: issue } = await this.octokit.issues.create({\n owner: this.owner,\n repo: this.repo,\n title: newIssue.title,\n body: newIssue.description,\n labels: newIssue.labels,\n assignees: newIssue.assignee ? [newIssue.assignee] : undefined,\n });\n\n return this.normalizeIssue(issue);\n }\n\n async getComments(issueId: string): Promise<Comment[]> {\n const issueNumber = parseIssueNumber(issueId);\n\n const { data: comments } = await this.octokit.issues.listComments({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n });\n\n return comments.map((c) => ({\n id: String(c.id),\n issueId,\n body: c.body ?? '',\n author: c.user?.login ?? 'Unknown',\n createdAt: c.created_at,\n updatedAt: c.updated_at,\n }));\n }\n\n async addComment(issueId: string, body: string): Promise<Comment> {\n const issueNumber = parseIssueNumber(issueId);\n\n const { data: comment } = await this.octokit.issues.createComment({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n body,\n });\n\n return {\n id: String(comment.id),\n issueId,\n body: comment.body ?? '',\n author: comment.user?.login ?? 'Unknown',\n createdAt: comment.created_at,\n updatedAt: comment.updated_at,\n };\n }\n\n async transitionIssue(id: string, state: IssueState): Promise<void> {\n const issueNumber = parseIssueNumber(id);\n\n if (state === 'in_progress') {\n // GitHub has no native \"in progress\" state — use a label instead.\n await this.ensureLabelExists('in-progress', 'In progress', '0075ca');\n await this.octokit.issues.addLabels({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n labels: ['in-progress'],\n });\n } else if (state === 'in_review') {\n // Swap in-progress label for in-review label\n await this.ensureLabelExists('in-review', 'In review', 'e4e669');\n await this.octokit.issues.addLabels({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n labels: ['in-review'],\n });\n // Remove in-progress label if present\n await this.octokit.issues.removeLabel({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n name: 'in-progress',\n }).catch(() => {/* label may not exist, ignore */});\n } else {\n // Remove in-progress and in-review labels when moving to open or closed\n const issue = await this.getIssue(id);\n for (const label of ['in-progress', 'in-review']) {\n if (issue.labels?.includes(label)) {\n await this.octokit.issues.removeLabel({\n owner: this.owner,\n repo: this.repo,\n issue_number: issueNumber,\n name: label,\n }).catch(() => {/* label may not exist, ignore */});\n }\n }\n await this.updateIssue(id, { state });\n }\n }\n\n /** Ensure a label exists in the repo, creating it if needed. */\n private async ensureLabelExists(name: string, description: string, color: string): Promise<void> {\n try {\n await this.octokit.issues.getLabel({ owner: this.owner, repo: this.repo, name });\n } catch {\n await this.octokit.issues.createLabel({\n owner: this.owner,\n repo: this.repo,\n name,\n description,\n color,\n }).catch(() => {/* race condition: another process created it first */});\n }\n }\n\n async linkPR(issueId: string, prUrl: string): Promise<void> {\n // GitHub auto-links PRs that mention issues\n // Add a comment with the PR link\n await this.addComment(\n issueId,\n `Linked Pull Request: ${prUrl}`\n );\n }\n\n private normalizeIssue(ghIssue: any): Issue {\n const labels: string[] = ghIssue.labels.map((l: any) =>\n typeof l === 'string' ? l : l.name\n );\n return {\n id: String(ghIssue.id),\n ref: `#${ghIssue.number}`,\n title: ghIssue.title,\n description: ghIssue.body ?? '',\n state: this.mapStateFromGitHub(ghIssue.state, labels),\n labels,\n assignee: ghIssue.assignee?.login,\n url: ghIssue.html_url,\n tracker: 'github',\n priority: undefined, // GitHub doesn't have priority\n dueDate: undefined, // GitHub doesn't have due dates on issues\n createdAt: ghIssue.created_at,\n updatedAt: ghIssue.updated_at,\n };\n }\n\n private mapStateFromGitHub(ghState: string, labels: string[] = []): IssueState {\n if (ghState === 'closed') return 'closed';\n if (labels.includes('in-progress')) return 'in_progress';\n return 'open';\n }\n\n private mapStateToGitHub(\n state?: IssueState\n ): 'open' | 'closed' | 'all' {\n if (!state) return 'open';\n if (state === 'closed') return 'closed';\n return 'open'; // Both 'open' and 'in_progress' map to 'open'\n }\n}\n","/**\n * GitLab Issues Tracker Adapter (Stub)\n *\n * Placeholder implementation for GitLab Issues support.\n * Full implementation will use @gitbeaker/rest.\n */\n\nimport type {\n Issue,\n IssueFilters,\n IssueState,\n IssueTracker,\n IssueUpdate,\n NewIssue,\n Comment,\n TrackerType,\n} from './interface.js';\nimport { NotImplementedError } from './interface.js';\n\nexport class GitLabTracker implements IssueTracker {\n readonly name: TrackerType = 'gitlab';\n\n constructor(\n private token: string,\n private projectId: string\n ) {\n // Stub - will initialize @gitbeaker client when implemented\n }\n\n async listIssues(_filters?: IssueFilters): Promise<Issue[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getIssue(_id: string): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async updateIssue(_id: string, _update: IssueUpdate): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async createIssue(_issue: NewIssue): Promise<Issue> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async getComments(_issueId: string): Promise<Comment[]> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async addComment(_issueId: string, _body: string): Promise<Comment> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async transitionIssue(_id: string, _state: IssueState): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n\n async linkPR(_issueId: string, _prUrl: string): Promise<void> {\n throw new NotImplementedError(\n 'GitLab tracker is not yet implemented. Coming soon!'\n );\n }\n}\n","/**\n * Tracker Factory\n *\n * Creates appropriate tracker instances based on configuration.\n */\n\nimport type { IssueTracker, TrackerType } from './interface.js';\nimport { TrackerAuthError } from './interface.js';\nimport { LinearTracker } from './linear.js';\nimport { GitHubTracker } from './github.js';\nimport { GitLabTracker } from './gitlab.js';\nimport { RallyTracker } from './rally.js';\nimport type { TrackersConfig } from '../config.js';\nimport { loadConfig as loadYamlConfig } from '../config-yaml.js';\n\n// Configuration for a single tracker\nexport interface TrackerConfig {\n type: TrackerType;\n\n // Linear-specific\n apiKeyEnv?: string;\n team?: string;\n\n // GitHub-specific\n tokenEnv?: string;\n owner?: string;\n repo?: string;\n\n // GitLab-specific\n projectId?: string;\n\n // Rally-specific\n server?: string;\n workspace?: string;\n project?: string;\n}\n\n// Multi-tracker configuration (re-exported from config.ts)\n// Note: Use TrackersConfig from config.ts for full type with nested configs\n\n/**\n * Get tracker API key from config.yaml (Settings page).\n * This is checked FIRST — env vars are the fallback, not the other way around.\n */\nfunction getTrackerKeyFromConfig(trackerType: TrackerType): string | undefined {\n try {\n const { config: yamlConfig } = loadYamlConfig();\n return yamlConfig.trackerKeys[trackerType];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Create a tracker instance from configuration.\n * Priority: config.yaml (Settings) > environment variable > custom env var name\n */\nexport function createTracker(config: TrackerConfig): IssueTracker {\n switch (config.type) {\n case 'linear': {\n const configKey = getTrackerKeyFromConfig('linear');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.LINEAR_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'linear',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'LINEAR_API_KEY'} environment variable.`\n );\n }\n\n return new LinearTracker(apiKey, { team: config.team });\n }\n\n case 'github': {\n const configKey = getTrackerKeyFromConfig('github');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITHUB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'github',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITHUB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.owner || !config.repo) {\n throw new Error(\n 'GitHub tracker requires owner and repo configuration'\n );\n }\n\n return new GitHubTracker(token, config.owner, config.repo);\n }\n\n case 'gitlab': {\n const configKey = getTrackerKeyFromConfig('gitlab');\n const envToken = config.tokenEnv\n ? process.env[config.tokenEnv]\n : process.env.GITLAB_TOKEN;\n const token = configKey || envToken;\n\n if (!token) {\n throw new TrackerAuthError(\n 'gitlab',\n `Token not found. Configure in Settings or set ${config.tokenEnv ?? 'GITLAB_TOKEN'} environment variable.`\n );\n }\n\n if (!config.projectId) {\n throw new Error('GitLab tracker requires projectId configuration');\n }\n\n return new GitLabTracker(token, config.projectId);\n }\n\n case 'rally': {\n const configKey = getTrackerKeyFromConfig('rally');\n const envKey = config.apiKeyEnv\n ? process.env[config.apiKeyEnv]\n : process.env.RALLY_API_KEY;\n const apiKey = configKey || envKey;\n\n if (!apiKey) {\n throw new TrackerAuthError(\n 'rally',\n `API key not found. Configure in Settings or set ${config.apiKeyEnv ?? 'RALLY_API_KEY'} environment variable.`\n );\n }\n\n return new RallyTracker({\n apiKey,\n server: config.server,\n workspace: config.workspace,\n project: config.project,\n });\n }\n\n default:\n throw new Error(`Unknown tracker type: ${config.type}`);\n }\n}\n\n/**\n * Create tracker from trackers configuration section\n */\nexport function createTrackerFromConfig(\n trackersConfig: TrackersConfig,\n trackerType: TrackerType\n): IssueTracker {\n const config = trackersConfig[trackerType];\n\n if (!config) {\n throw new Error(\n `No configuration found for tracker: ${trackerType}. Add [trackers.${trackerType}] to config.`\n );\n }\n\n return createTracker({ ...config, type: trackerType });\n}\n\n/**\n * Get the primary tracker from configuration\n */\nexport function getPrimaryTracker(trackersConfig: TrackersConfig): IssueTracker {\n return createTrackerFromConfig(trackersConfig, trackersConfig.primary);\n}\n\n/**\n * Get the secondary tracker from configuration (if configured)\n */\nexport function getSecondaryTracker(\n trackersConfig: TrackersConfig\n): IssueTracker | null {\n if (!trackersConfig.secondary) {\n return null;\n }\n return createTrackerFromConfig(trackersConfig, trackersConfig.secondary);\n}\n\n/**\n * Get all configured trackers\n */\nexport function getAllTrackers(trackersConfig: TrackersConfig): IssueTracker[] {\n const trackers: IssueTracker[] = [getPrimaryTracker(trackersConfig)];\n\n const secondary = getSecondaryTracker(trackersConfig);\n if (secondary) {\n trackers.push(secondary);\n }\n\n return trackers;\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -685,7 +685,7 @@ declare function getLinkManager(): LinkManager;
|
|
|
685
685
|
type AnthropicModel = 'claude-opus-4-6' | 'claude-sonnet-4-6' | 'claude-sonnet-4-5' | 'claude-haiku-4-5';
|
|
686
686
|
type OpenAIModel = 'gpt-5.2-codex' | 'o3-deep-research' | 'gpt-4o' | 'gpt-4o-mini';
|
|
687
687
|
type GoogleModel = 'gemini-3-pro-preview' | 'gemini-3-flash-preview' | 'gemini-2.5-pro' | 'gemini-2.5-flash';
|
|
688
|
-
type ZAIModel = 'glm-4.7-flash';
|
|
688
|
+
type ZAIModel = 'glm-4.7' | 'glm-4.7-flash' | 'glm-5.1';
|
|
689
689
|
type KimiModel = 'kimi-k2' | 'kimi-k2.5';
|
|
690
690
|
type MiniMaxModel = 'minimax-m2.7' | 'minimax-m2.7-highspeed';
|
|
691
691
|
type ModelId = AnthropicModel | OpenAIModel | GoogleModel | ZAIModel | KimiModel | MiniMaxModel;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { A as SKILLS_DIR, B as TRAEFIK_CERTS_DIR, C as PRD_PUBLISHED_DIR, D as PROJECT_PRDS_PLANNED_SUBDIR, E as PROJECT_PRDS_COMPLETED_SUBDIR, F as SOURCE_SKILLS_DIR, G as init_paths, H as TRAEFIK_DYNAMIC_DIR, I as SOURCE_TEMPLATES_DIR, K as isDevMode, L as SOURCE_TRAEFIK_TEMPLATES, M as SOURCE_DEV_SKILLS_DIR, N as SOURCE_RULES_DIR, O as PROJECT_PRDS_SUBDIR, P as SOURCE_SCRIPTS_DIR, R as SYNC_TARGET, S as PRD_DRAFTS_DIR, T as PROJECT_PRDS_ACTIVE_SUBDIR, U as encodeClaudeProjectDir, V as TRAEFIK_DIR, W as getPanopticonHome, _ as HEARTBEATS_DIR, a as CACHE_AGENTS_DIR, b as PANOPTICON_HOME, c as CACHE_SKILLS_DIR, d as CLAUDE_MD_TEMPLATES, f as COMMANDS_DIR, g as DOCS_DIR, h as COSTS_DIR, i as BIN_DIR, j as SOURCE_AGENTS_DIR, k as SETTINGS_FILE, l as CERTS_DIR, m as CONFIG_FILE, n as ARCHIVES_DIR, o as CACHE_MANIFEST, p as CONFIG_DIR, r as BACKUPS_DIR, s as CACHE_RULES_DIR, t as AGENTS_DIR, u as CLAUDE_DIR, v as INIT_DIRS, w as PROJECT_DOCS_SUBDIR, x as PRDS_DIR, y as LEGACY_RUNTIME_DIRS, z as TEMPLATES_DIR } from "./paths-CDJ_HsbN.js";
|
|
2
2
|
import { a as init_config, i as getDevrootPath, n as getDashboardApiUrl, o as loadConfig, r as getDefaultConfig, s as saveConfig, t as findDevrootForProject } from "./config-BQNKsi9G.js";
|
|
3
|
-
import { a as addAlias, c as getShellRcFile, i as parseIssueRef, l as hasAlias, n as formatIssueRef, o as detectShell, r as getLinkManager, s as getAliasInstructions, t as LinkManager } from "./tracker-
|
|
4
|
-
import { _ as cleanOldBackups, a as isAnthropicModel, b as listBackups, c as validateSettings, d as migrateStalePersonalContent, f as planHooksSync, g as syncStatusline, h as syncHooks, i as getDefaultSettings, l as executeSync, m as refreshCache, n as getAvailableModels, o as loadSettings, p as planSync, r as getClaudeModelFlag, s as saveSettings, t as getAgentCommand, u as isPanopticonSymlink, v as createBackup, x as restoreBackup, y as createBackupTimestamp } from "./settings-
|
|
3
|
+
import { a as addAlias, c as getShellRcFile, i as parseIssueRef, l as hasAlias, n as formatIssueRef, o as detectShell, r as getLinkManager, s as getAliasInstructions, t as LinkManager } from "./tracker-CYpb7oUa.js";
|
|
4
|
+
import { _ as cleanOldBackups, a as isAnthropicModel, b as listBackups, c as validateSettings, d as migrateStalePersonalContent, f as planHooksSync, g as syncStatusline, h as syncHooks, i as getDefaultSettings, l as executeSync, m as refreshCache, n as getAvailableModels, o as loadSettings, p as planSync, r as getClaudeModelFlag, s as saveSettings, t as getAgentCommand, u as isPanopticonSymlink, v as createBackup, x as restoreBackup, y as createBackupTimestamp } from "./settings-A-CWz_ph.js";
|
|
5
5
|
import { a as getProviderForModel, c as needsRouter, i as getProviderEnv, l as requiresRouter, n as clearCredentialFileAuth, o as getRouterProviders, r as getDirectProviders, s as init_providers, t as PROVIDERS, u as setupCredentialFileAuth } from "./providers-DSU1vfQF.js";
|
|
6
6
|
import { a as TrackerAuthError, i as NotImplementedError, r as IssueNotFoundError } from "./rally-Dy00NElU.js";
|
|
7
|
-
import { a as getSecondaryTracker, d as LinearTracker, i as getPrimaryTracker, l as GitHubTracker, n as createTrackerFromConfig, r as getAllTrackers, s as GitLabTracker, t as createTracker } from "./factory-
|
|
7
|
+
import { a as getSecondaryTracker, d as LinearTracker, i as getPrimaryTracker, l as GitHubTracker, n as createTrackerFromConfig, r as getAllTrackers, s as GitLabTracker, t as createTracker } from "./factory-D6LJaZ__.js";
|
|
8
8
|
//#region src/index.ts
|
|
9
9
|
init_paths();
|
|
10
10
|
init_config();
|
|
@@ -3,7 +3,7 @@ import { a as init_config } from "./config-BQNKsi9G.js";
|
|
|
3
3
|
import { p as init_projects } from "./projects-Bk-5QhFQ.js";
|
|
4
4
|
import { o as init_tmux } from "./tmux-D6Ah4I8z.js";
|
|
5
5
|
import { n as resolveGitHubIssue } from "./tracker-utils-ChQyut8w.js";
|
|
6
|
-
import { j as init_specialists } from "./specialists-
|
|
6
|
+
import { j as init_specialists } from "./specialists-DvTYu1VZ.js";
|
|
7
7
|
import "fs";
|
|
8
8
|
import { basename, dirname, join } from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
@@ -200,7 +200,7 @@ async function postMergeLifecycle(issueId, projectPath, sourceBranch, options) {
|
|
|
200
200
|
console.warn(`[merge-agent] Beads compaction failed: ${err}`);
|
|
201
201
|
}
|
|
202
202
|
try {
|
|
203
|
-
const { getAgentState, saveAgentState } = await import("./agents-
|
|
203
|
+
const { getAgentState, saveAgentState } = await import("./agents-BQOqo27C.js");
|
|
204
204
|
const { killSession, sessionExists } = await import("./tmux-CBtui_Cl.js");
|
|
205
205
|
const agentId = `agent-${issueId.toLowerCase()}`;
|
|
206
206
|
const agentState = getAgentState(agentId);
|
|
@@ -302,4 +302,4 @@ function logActivity(action, details, issueId) {
|
|
|
302
302
|
//#endregion
|
|
303
303
|
export { postMergeLifecycle };
|
|
304
304
|
|
|
305
|
-
//# sourceMappingURL=merge-agent-
|
|
305
|
+
//# sourceMappingURL=merge-agent-BBwHwpn2.js.map
|