panopticon-cli 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/{agents-E43Y3HNU.js → agents-5OPQKM5K.js} +4 -3
  2. package/dist/{chunk-OMNXYPXC.js → chunk-2V4NF7J2.js} +14 -1
  3. package/dist/chunk-2V4NF7J2.js.map +1 -0
  4. package/dist/{chunk-WQG2TYCB.js → chunk-4YSYJ4HM.js} +2 -2
  5. package/dist/{chunk-NTO3EDB3.js → chunk-76F6DSVS.js} +47 -8
  6. package/dist/chunk-76F6DSVS.js.map +1 -0
  7. package/dist/{chunk-GR6ZZMCX.js → chunk-F5555J3A.js} +18 -1
  8. package/dist/chunk-F5555J3A.js.map +1 -0
  9. package/dist/{chunk-PPRFKTVC.js → chunk-NLQRED36.js} +2 -2
  10. package/dist/{chunk-AAFQANKW.js → chunk-OWHXCGVO.js} +29 -29
  11. package/dist/chunk-OWHXCGVO.js.map +1 -0
  12. package/dist/{chunk-HZT2AOPN.js → chunk-VHKSS7QX.js} +28 -5
  13. package/dist/chunk-VHKSS7QX.js.map +1 -0
  14. package/dist/{chunk-GFP3PIPB.js → chunk-YGJ54GW2.js} +1 -1
  15. package/dist/chunk-YGJ54GW2.js.map +1 -0
  16. package/dist/cli/index.js +401 -318
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/dashboard/public/assets/{index-DQHkwvvJ.js → index-Ce6q21Fm.js} +135 -135
  19. package/dist/dashboard/public/assets/{index-BxpjweAL.css → index-NzpI0ItZ.css} +1 -1
  20. package/dist/dashboard/public/index.html +2 -2
  21. package/dist/dashboard/server.js +1420 -1007
  22. package/dist/{feedback-writer-LVZ5TFYZ.js → feedback-writer-VRMMWWTW.js} +2 -2
  23. package/dist/git-utils-I2UDKNZH.js +131 -0
  24. package/dist/git-utils-I2UDKNZH.js.map +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.js +2 -2
  27. package/dist/{projects-JEIVIYC6.js → projects-CFX3RTDL.js} +4 -2
  28. package/dist/{remote-workspace-AHVHQEES.js → remote-workspace-7FPGF2RM.js} +2 -2
  29. package/dist/{review-status-EPFG4XM7.js → review-status-TDPSOU5J.js} +2 -2
  30. package/dist/{specialist-context-ZC6A4M3I.js → specialist-context-WGUUYDWY.js} +3 -3
  31. package/dist/{specialist-logs-KLGJCEUL.js → specialist-logs-XJB5TCKJ.js} +3 -3
  32. package/dist/{specialists-O4HWDJL5.js → specialists-5LBRHYFA.js} +3 -3
  33. package/dist/{traefik-QN7R5I6V.js → traefik-WFMQX2LY.js} +3 -3
  34. package/dist/{workspace-manager-IE4JL2JP.js → workspace-manager-E434Z45T.js} +2 -2
  35. package/package.json +1 -1
  36. package/scripts/record-cost-event.js +5 -5
  37. package/skills/pan-new-project/SKILL.md +304 -0
  38. package/dist/chunk-AAFQANKW.js.map +0 -1
  39. package/dist/chunk-GFP3PIPB.js.map +0 -1
  40. package/dist/chunk-GR6ZZMCX.js.map +0 -1
  41. package/dist/chunk-HZT2AOPN.js.map +0 -1
  42. package/dist/chunk-NTO3EDB3.js.map +0 -1
  43. package/dist/chunk-OMNXYPXC.js.map +0 -1
  44. /package/dist/{agents-E43Y3HNU.js.map → agents-5OPQKM5K.js.map} +0 -0
  45. /package/dist/{chunk-WQG2TYCB.js.map → chunk-4YSYJ4HM.js.map} +0 -0
  46. /package/dist/{chunk-PPRFKTVC.js.map → chunk-NLQRED36.js.map} +0 -0
  47. /package/dist/{feedback-writer-LVZ5TFYZ.js.map → feedback-writer-VRMMWWTW.js.map} +0 -0
  48. /package/dist/{projects-JEIVIYC6.js.map → projects-CFX3RTDL.js.map} +0 -0
  49. /package/dist/{remote-workspace-AHVHQEES.js.map → remote-workspace-7FPGF2RM.js.map} +0 -0
  50. /package/dist/{review-status-EPFG4XM7.js.map → review-status-TDPSOU5J.js.map} +0 -0
  51. /package/dist/{specialist-context-ZC6A4M3I.js.map → specialist-context-WGUUYDWY.js.map} +0 -0
  52. /package/dist/{specialist-logs-KLGJCEUL.js.map → specialist-logs-XJB5TCKJ.js.map} +0 -0
  53. /package/dist/{specialists-O4HWDJL5.js.map → specialists-5LBRHYFA.js.map} +0 -0
  54. /package/dist/{traefik-QN7R5I6V.js.map → traefik-WFMQX2LY.js.map} +0 -0
  55. /package/dist/{workspace-manager-IE4JL2JP.js.map → workspace-manager-E434Z45T.js.map} +0 -0
package/dist/cli/index.js CHANGED
@@ -1,18 +1,43 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ checkSpecialistQueue,
4
+ clearSessionId,
5
+ completeSpecialistTask,
6
+ getAllSpecialistStatus,
7
+ getEnabledSpecialists,
8
+ getNextSpecialistTask,
9
+ getProjectDirs,
10
+ getSessionFiles,
11
+ getSessionId,
12
+ getSpecialistMetadata,
13
+ getSpecialistStatus,
14
+ getTmuxSessionName,
15
+ init_jsonl_parser,
16
+ init_specialists,
17
+ initializeEnabledSpecialists,
18
+ isRunning,
19
+ parseClaudeSession,
20
+ recordWake,
21
+ setSessionId,
22
+ wakeSpecialist,
23
+ wakeSpecialistOrQueue,
24
+ wakeSpecialistWithTask
25
+ } from "../chunk-OWHXCGVO.js";
2
26
  import {
3
27
  cleanupTemplateFiles,
4
28
  ensureProjectCerts,
5
29
  generatePanopticonTraefikConfig,
6
30
  generateTlsConfig
7
- } from "../chunk-PPRFKTVC.js";
31
+ } from "../chunk-NLQRED36.js";
8
32
  import {
9
33
  applyProjectTemplateOverlay,
10
34
  createWorkspace,
11
35
  init_skills_merge,
12
36
  init_workspace_manager,
13
37
  mergeSkillsIntoWorkspace,
14
- removeWorkspace
15
- } from "../chunk-GR6ZZMCX.js";
38
+ removeWorkspace,
39
+ stopWorkspaceDocker
40
+ } from "../chunk-F5555J3A.js";
16
41
  import "../chunk-7SN4L4PH.js";
17
42
  import {
18
43
  init_remote_agents,
@@ -41,7 +66,24 @@ import {
41
66
  saveSessionId,
42
67
  spawnAgent,
43
68
  stopAgent
44
- } from "../chunk-HZT2AOPN.js";
69
+ } from "../chunk-VHKSS7QX.js";
70
+ import {
71
+ checkHook,
72
+ clearHook,
73
+ createSession,
74
+ generateFixedPointPrompt,
75
+ getModelId,
76
+ init_hooks,
77
+ init_tmux,
78
+ init_work_type_router,
79
+ killSession,
80
+ popFromHook,
81
+ pushToHook,
82
+ sendKeys,
83
+ sendKeysAsync,
84
+ sendMail,
85
+ sessionExists
86
+ } from "../chunk-FTCPTHIJ.js";
45
87
  import {
46
88
  createShadowState,
47
89
  getPendingSyncCount,
@@ -69,48 +111,7 @@ import {
69
111
  init_review_status,
70
112
  loadReviewStatuses,
71
113
  saveReviewStatuses
72
- } from "../chunk-GFP3PIPB.js";
73
- import {
74
- checkSpecialistQueue,
75
- clearSessionId,
76
- completeSpecialistTask,
77
- getAllSpecialistStatus,
78
- getEnabledSpecialists,
79
- getNextSpecialistTask,
80
- getProjectDirs,
81
- getSessionFiles,
82
- getSessionId,
83
- getSpecialistMetadata,
84
- getSpecialistStatus,
85
- getTmuxSessionName,
86
- init_jsonl_parser,
87
- init_specialists,
88
- initializeEnabledSpecialists,
89
- isRunning,
90
- parseClaudeSession,
91
- recordWake,
92
- setSessionId,
93
- wakeSpecialist,
94
- wakeSpecialistOrQueue,
95
- wakeSpecialistWithTask
96
- } from "../chunk-AAFQANKW.js";
97
- import {
98
- checkHook,
99
- clearHook,
100
- createSession,
101
- generateFixedPointPrompt,
102
- getModelId,
103
- init_hooks,
104
- init_tmux,
105
- init_work_type_router,
106
- killSession,
107
- popFromHook,
108
- pushToHook,
109
- sendKeys,
110
- sendKeysAsync,
111
- sendMail,
112
- sessionExists
113
- } from "../chunk-FTCPTHIJ.js";
114
+ } from "../chunk-YGJ54GW2.js";
114
115
  import "../chunk-JQBV3Q2W.js";
115
116
  import {
116
117
  addAlias,
@@ -128,13 +129,13 @@ import {
128
129
  restoreBackup,
129
130
  syncHooks,
130
131
  syncStatusline
131
- } from "../chunk-WQG2TYCB.js";
132
+ } from "../chunk-4YSYJ4HM.js";
132
133
  import "../chunk-AQXETQHW.js";
133
134
  import {
134
135
  createTracker,
135
136
  createTrackerFromConfig,
136
137
  init_factory
137
- } from "../chunk-NTO3EDB3.js";
138
+ } from "../chunk-76F6DSVS.js";
138
139
  import {
139
140
  init_config_yaml,
140
141
  init_settings,
@@ -162,7 +163,7 @@ import {
162
163
  registerProject,
163
164
  resolveProjectFromIssue,
164
165
  unregisterProject
165
- } from "../chunk-OMNXYPXC.js";
166
+ } from "../chunk-2V4NF7J2.js";
166
167
  import {
167
168
  NotImplementedError,
168
169
  init_interface
@@ -1556,7 +1557,7 @@ async function handleRemoteWorkspace(issueId, options, spinner) {
1556
1557
  if (!remoteMetadata) {
1557
1558
  spinner.text = "Remote workspace not found, creating...";
1558
1559
  try {
1559
- const { createRemoteWorkspace: createRemoteWorkspace2 } = await import("../remote-workspace-AHVHQEES.js");
1560
+ const { createRemoteWorkspace: createRemoteWorkspace2 } = await import("../remote-workspace-7FPGF2RM.js");
1560
1561
  remoteMetadata = await createRemoteWorkspace2(issueId, { spinner });
1561
1562
  } catch (error) {
1562
1563
  spinner.fail(`Failed to create remote workspace: ${error.message}`);
@@ -2289,9 +2290,9 @@ init_agents();
2289
2290
  init_paths();
2290
2291
  import chalk12 from "chalk";
2291
2292
  import ora6 from "ora";
2292
- import { existsSync as existsSync12, writeFileSync as writeFileSync4, readFileSync as readFileSync10, mkdirSync as mkdirSync4, readdirSync as readdirSync11 } from "fs";
2293
- import { join as join12 } from "path";
2294
- import { homedir as homedir5 } from "os";
2293
+ import { existsSync as existsSync13, writeFileSync as writeFileSync4, readFileSync as readFileSync11, mkdirSync as mkdirSync4, readdirSync as readdirSync11 } from "fs";
2294
+ import { join as join13 } from "path";
2295
+ import { homedir as homedir6 } from "os";
2295
2296
  import { exec } from "child_process";
2296
2297
  import { promisify } from "util";
2297
2298
 
@@ -2424,12 +2425,46 @@ function cleanupWorkflowLabels(currentLabels, targetState) {
2424
2425
  return cleaned;
2425
2426
  }
2426
2427
 
2428
+ // src/lib/tracker-utils.ts
2429
+ init_esm_shims();
2430
+ import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
2431
+ import { join as join12 } from "path";
2432
+ import { homedir as homedir5 } from "os";
2433
+ function parseGitHubRepos() {
2434
+ const envFile = join12(homedir5(), ".panopticon.env");
2435
+ if (!existsSync12(envFile)) return [];
2436
+ const content = readFileSync10(envFile, "utf-8");
2437
+ const reposMatch = content.match(/GITHUB_REPOS=(.+)/);
2438
+ if (!reposMatch) return [];
2439
+ return reposMatch[1].trim().split(",").map((r) => {
2440
+ const [repoPath, prefix] = r.trim().split(":");
2441
+ const [owner, repo] = (repoPath || "").split("/");
2442
+ return { owner: owner || "", repo: repo || "", prefix: (prefix || "").toUpperCase() };
2443
+ }).filter((r) => r.owner && r.repo && r.prefix);
2444
+ }
2445
+ function extractIssuePrefix(issueId) {
2446
+ return issueId.split("-")[0].toUpperCase();
2447
+ }
2448
+ function resolveGitHubIssue(issueId) {
2449
+ const prefix = extractIssuePrefix(issueId);
2450
+ const repos = parseGitHubRepos();
2451
+ for (const repoConfig of repos) {
2452
+ if (repoConfig.prefix === prefix) {
2453
+ const number = parseInt(issueId.split("-")[1], 10);
2454
+ if (!isNaN(number)) {
2455
+ return { isGitHub: true, ...repoConfig, number };
2456
+ }
2457
+ }
2458
+ }
2459
+ return { isGitHub: false };
2460
+ }
2461
+
2427
2462
  // src/cli/commands/work/done.ts
2428
2463
  var execAsync = promisify(exec);
2429
2464
  function getLinearApiKey3() {
2430
- const envFile = join12(homedir5(), ".panopticon.env");
2431
- if (existsSync12(envFile)) {
2432
- const content = readFileSync10(envFile, "utf-8");
2465
+ const envFile = join13(homedir6(), ".panopticon.env");
2466
+ if (existsSync13(envFile)) {
2467
+ const content = readFileSync11(envFile, "utf-8");
2433
2468
  const match = content.match(/LINEAR_API_KEY=(.+)/);
2434
2469
  if (match) return match[1].trim();
2435
2470
  }
@@ -2471,9 +2506,9 @@ ${comment}`
2471
2506
  }
2472
2507
  }
2473
2508
  function getGitHubConfig() {
2474
- const envFile = join12(homedir5(), ".panopticon.env");
2475
- if (!existsSync12(envFile)) return null;
2476
- const content = readFileSync10(envFile, "utf-8");
2509
+ const envFile = join13(homedir6(), ".panopticon.env");
2510
+ if (!existsSync13(envFile)) return null;
2511
+ const content = readFileSync11(envFile, "utf-8");
2477
2512
  const tokenMatch = content.match(/GITHUB_TOKEN=(.+)/);
2478
2513
  if (!tokenMatch) return null;
2479
2514
  const token = tokenMatch[1].trim();
@@ -2491,9 +2526,9 @@ async function updateGitHubToInReview(issueId, comment) {
2491
2526
  try {
2492
2527
  const ghConfig = getGitHubConfig();
2493
2528
  if (!ghConfig) return false;
2494
- const number = parseInt(issueId.split("-")[1], 10);
2495
- const repoConfig = ghConfig.repos.find((r) => r.prefix === "PAN") || ghConfig.repos[0];
2496
- const { owner, repo } = repoConfig;
2529
+ const resolved = resolveGitHubIssue(issueId);
2530
+ if (!resolved.isGitHub) return false;
2531
+ const { owner, repo, number } = resolved;
2497
2532
  const token = ghConfig.token;
2498
2533
  const headers = {
2499
2534
  "Authorization": `token ${token}`,
@@ -2529,10 +2564,59 @@ async function doneCommand(id, options = {}) {
2529
2564
  const issueId = id.replace(/^agent-/i, "").toUpperCase();
2530
2565
  const agentId = `agent-${issueId.toLowerCase()}`;
2531
2566
  if (!options.force) {
2532
- const { getAgentState: getAgentState2 } = await import("../agents-E43Y3HNU.js");
2567
+ const { getAgentState: getAgentState2 } = await import("../agents-5OPQKM5K.js");
2533
2568
  const agentState = getAgentState2(agentId);
2534
2569
  const workspacePath = agentState?.workspace;
2535
- if (workspacePath && existsSync12(workspacePath)) {
2570
+ if (workspacePath && existsSync13(workspacePath)) {
2571
+ try {
2572
+ const { getReviewStatus: getReviewStatus2 } = await import("../review-status-TDPSOU5J.js");
2573
+ const { getWorkspaceCommitHashes } = await import("../git-utils-I2UDKNZH.js");
2574
+ const { getDashboardApiUrl: getDashboardApiUrl2 } = await import("../config-4CJNUE3O.js");
2575
+ const reviewStatus = getReviewStatus2(issueId);
2576
+ if (reviewStatus) {
2577
+ const isBlockedOrFailed = ["blocked", "failed"].includes(reviewStatus.reviewStatus);
2578
+ if (isBlockedOrFailed) {
2579
+ const dashboardUrl = getDashboardApiUrl2();
2580
+ console.error(chalk12.red(`
2581
+ \u2716 Cannot mark work done \u2014 review is ${reviewStatus.reviewStatus} for ${issueId}
2582
+ `));
2583
+ console.error(" The review agent found issues that must be addressed before this issue can be completed.");
2584
+ console.error(" Fix the issues, commit your changes, then re-submit for review:\n");
2585
+ console.error(chalk12.cyan(` curl -X POST ${dashboardUrl}/api/workspaces/${issueId}/request-review \\`));
2586
+ console.error(chalk12.cyan(` -H "Content-Type: application/json" -d '{}'`));
2587
+ console.error("");
2588
+ console.error(chalk12.dim(" Use --force to skip this check."));
2589
+ console.error("");
2590
+ process.exit(1);
2591
+ }
2592
+ if (reviewStatus.lastReviewCommits) {
2593
+ const currentHashes = await getWorkspaceCommitHashes(workspacePath);
2594
+ const allKeys = /* @__PURE__ */ new Set([
2595
+ ...Object.keys(currentHashes),
2596
+ ...Object.keys(reviewStatus.lastReviewCommits)
2597
+ ]);
2598
+ const commitsChanged = [...allKeys].some(
2599
+ (k) => currentHashes[k] !== reviewStatus.lastReviewCommits[k]
2600
+ );
2601
+ if (commitsChanged) {
2602
+ const dashboardUrl = getDashboardApiUrl2();
2603
+ console.error(chalk12.red(`
2604
+ \u2716 Cannot mark work done \u2014 commits changed since last review for ${issueId}
2605
+ `));
2606
+ console.error(" New commits were added after the last review/test run. The specialists");
2607
+ console.error(" must review and test your latest code before work can be marked done.");
2608
+ console.error(" Re-submit for review:\n");
2609
+ console.error(chalk12.cyan(` curl -X POST ${dashboardUrl}/api/workspaces/${issueId}/request-review \\`));
2610
+ console.error(chalk12.cyan(` -H "Content-Type: application/json" -d '{}'`));
2611
+ console.error("");
2612
+ console.error(chalk12.dim(" Use --force to skip this check."));
2613
+ console.error("");
2614
+ process.exit(1);
2615
+ }
2616
+ }
2617
+ }
2618
+ } catch {
2619
+ }
2536
2620
  const failures = [];
2537
2621
  try {
2538
2622
  const { stdout } = await execAsync("bd list --status open --limit 0 --json", { cwd: workspacePath });
@@ -2547,7 +2631,7 @@ async function doneCommand(id, options = {}) {
2547
2631
  }
2548
2632
  } catch {
2549
2633
  }
2550
- const hasTopLevelGit = existsSync12(join12(workspacePath, ".git"));
2634
+ const hasTopLevelGit = existsSync13(join13(workspacePath, ".git"));
2551
2635
  if (hasTopLevelGit) {
2552
2636
  try {
2553
2637
  const { stdout } = await execAsync("git status --porcelain", { cwd: workspacePath });
@@ -2564,8 +2648,8 @@ async function doneCommand(id, options = {}) {
2564
2648
  const entries = readdirSync11(workspacePath, { withFileTypes: true });
2565
2649
  for (const entry of entries) {
2566
2650
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
2567
- const subPath = join12(workspacePath, entry.name);
2568
- if (!existsSync12(join12(subPath, ".git"))) continue;
2651
+ const subPath = join13(workspacePath, entry.name);
2652
+ if (!existsSync13(join13(subPath, ".git"))) continue;
2569
2653
  try {
2570
2654
  const { stdout } = await execAsync("git status --porcelain", { cwd: subPath });
2571
2655
  if (stdout.trim()) {
@@ -2599,14 +2683,14 @@ async function doneCommand(id, options = {}) {
2599
2683
  try {
2600
2684
  let trackerUpdated = false;
2601
2685
  let shadowModeActive = false;
2602
- const isGitHubIssue = issueId.startsWith("PAN-");
2686
+ const ghResolution = resolveGitHubIssue(issueId);
2603
2687
  const skipTrackerUpdate = shouldSkipTrackerUpdate(issueId, options.shadow);
2604
2688
  if (skipTrackerUpdate) {
2605
2689
  shadowModeActive = true;
2606
2690
  spinner.text = "Updating shadow state...";
2607
2691
  updateShadowState(issueId, "closed", "pan work done");
2608
2692
  console.log(chalk12.cyan(` \u{1F47B} Shadow mode: status updated locally`));
2609
- } else if (isGitHubIssue) {
2693
+ } else if (ghResolution.isGitHub) {
2610
2694
  spinner.text = "Updating GitHub labels...";
2611
2695
  trackerUpdated = await updateGitHubToInReview(issueId, options.comment);
2612
2696
  if (trackerUpdated) {
@@ -2628,7 +2712,7 @@ async function doneCommand(id, options = {}) {
2628
2712
  console.log(chalk12.dim(" LINEAR_API_KEY not set - skipping status update"));
2629
2713
  }
2630
2714
  }
2631
- const { getAgentState: getAgentState2, saveAgentState: saveAgentState2 } = await import("../agents-E43Y3HNU.js");
2715
+ const { getAgentState: getAgentState2, saveAgentState: saveAgentState2 } = await import("../agents-5OPQKM5K.js");
2632
2716
  const existingState = getAgentState2(agentId);
2633
2717
  if (existingState) {
2634
2718
  existingState.status = "stopped";
@@ -2639,8 +2723,8 @@ async function doneCommand(id, options = {}) {
2639
2723
  state: "idle",
2640
2724
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
2641
2725
  });
2642
- mkdirSync4(join12(AGENTS_DIR, agentId), { recursive: true });
2643
- const completedFile = join12(AGENTS_DIR, agentId, "completed");
2726
+ mkdirSync4(join13(AGENTS_DIR, agentId), { recursive: true });
2727
+ const completedFile = join13(AGENTS_DIR, agentId, "completed");
2644
2728
  writeFileSync4(completedFile, JSON.stringify({
2645
2729
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2646
2730
  trackerUpdated,
@@ -2767,14 +2851,14 @@ init_esm_shims();
2767
2851
  import chalk13 from "chalk";
2768
2852
  import ora7 from "ora";
2769
2853
  import inquirer2 from "inquirer";
2770
- import { readFileSync as readFileSync12, existsSync as existsSync14 } from "fs";
2771
- import { join as join14, dirname as dirname5 } from "path";
2772
- import { homedir as homedir6 } from "os";
2854
+ import { readFileSync as readFileSync13, existsSync as existsSync15 } from "fs";
2855
+ import { join as join15, dirname as dirname5 } from "path";
2856
+ import { homedir as homedir7 } from "os";
2773
2857
 
2774
2858
  // src/lib/planning/plan-utils.ts
2775
2859
  init_esm_shims();
2776
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
2777
- import { join as join13 } from "path";
2860
+ import { existsSync as existsSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
2861
+ import { join as join14 } from "path";
2778
2862
  import { exec as exec2, spawn } from "child_process";
2779
2863
  import { promisify as promisify2 } from "util";
2780
2864
  init_paths();
@@ -2786,17 +2870,17 @@ async function findPRDFiles(issueId, cwd) {
2786
2870
  found.push(getPRDDraftPath(issueId));
2787
2871
  }
2788
2872
  const searchPaths = [
2789
- join13(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR),
2790
- join13(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, "planned"),
2791
- join13(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR),
2792
- join13(PROJECT_DOCS_SUBDIR, "prd"),
2873
+ join14(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR),
2874
+ join14(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, "planned"),
2875
+ join14(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR),
2876
+ join14(PROJECT_DOCS_SUBDIR, "prd"),
2793
2877
  PROJECT_PRDS_SUBDIR,
2794
2878
  PROJECT_DOCS_SUBDIR
2795
2879
  ];
2796
2880
  const issueIdLower = issueId.toLowerCase();
2797
2881
  for (const searchPath of searchPaths) {
2798
- const fullPath = join13(searchRoot, searchPath);
2799
- if (!existsSync13(fullPath)) continue;
2882
+ const fullPath = join14(searchRoot, searchPath);
2883
+ if (!existsSync14(fullPath)) continue;
2800
2884
  try {
2801
2885
  const { stdout: result } = await execAsync2(
2802
2886
  `find "${fullPath}" -type f -name "*.md" 2>/dev/null | xargs grep -l -i "${issueIdLower}" 2>/dev/null || true`,
@@ -3039,25 +3123,25 @@ async function createBeadsTasks(issue, tasks, cwd) {
3039
3123
  return { success: errors.length === 0, created, errors };
3040
3124
  }
3041
3125
  function writePlanFiles(projectPath, stateContent, workspaceContent) {
3042
- const planningDir = join13(projectPath, ".planning");
3126
+ const planningDir = join14(projectPath, ".planning");
3043
3127
  mkdirSync5(planningDir, { recursive: true });
3044
- const statePath = join13(planningDir, "STATE.md");
3045
- const workspacePath = join13(planningDir, "WORKSPACE.md");
3128
+ const statePath = join14(planningDir, "STATE.md");
3129
+ const workspacePath = join14(planningDir, "WORKSPACE.md");
3046
3130
  writeFileSync5(statePath, stateContent);
3047
3131
  writeFileSync5(workspacePath, workspaceContent);
3048
3132
  return { statePath, workspacePath };
3049
3133
  }
3050
3134
  async function copyToPRDDirectory(projectPath, issue, content, options) {
3051
- const prdDir = join13(projectPath, PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR);
3135
+ const prdDir = join14(projectPath, PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR);
3052
3136
  try {
3053
3137
  mkdirSync5(prdDir, { recursive: true });
3054
3138
  const filename = `${issue.identifier.toLowerCase()}-plan.md`;
3055
- const prdPath = join13(prdDir, filename);
3139
+ const prdPath = join14(prdDir, filename);
3056
3140
  writeFileSync5(prdPath, content);
3057
3141
  let committed = false;
3058
3142
  if (options?.commitAndPush) {
3059
3143
  try {
3060
- const relativePrdPath = join13(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR, filename);
3144
+ const relativePrdPath = join14(PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR, filename);
3061
3145
  await execAsync2(`git add ${relativePrdPath}`, { cwd: projectPath, encoding: "utf-8" });
3062
3146
  try {
3063
3147
  await execAsync2("git diff --cached --quiet", { cwd: projectPath, encoding: "utf-8" });
@@ -3104,9 +3188,9 @@ async function executePlan(issue, tasks, decisions, projectPath, options) {
3104
3188
 
3105
3189
  // src/cli/commands/work/plan.ts
3106
3190
  function getLinearApiKey4() {
3107
- const envFile = join14(homedir6(), ".panopticon.env");
3108
- if (existsSync14(envFile)) {
3109
- const content = readFileSync12(envFile, "utf-8");
3191
+ const envFile = join15(homedir7(), ".panopticon.env");
3192
+ if (existsSync15(envFile)) {
3193
+ const content = readFileSync13(envFile, "utf-8");
3110
3194
  const match = content.match(/LINEAR_API_KEY=(.+)/);
3111
3195
  if (match) return match[1].trim();
3112
3196
  }
@@ -3589,9 +3673,9 @@ init_esm_shims();
3589
3673
  init_config();
3590
3674
  import chalk15 from "chalk";
3591
3675
  import ora9 from "ora";
3592
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync6, existsSync as existsSync15, mkdirSync as mkdirSync6 } from "fs";
3593
- import { join as join15 } from "path";
3594
- import { homedir as homedir7 } from "os";
3676
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync6, existsSync as existsSync16, mkdirSync as mkdirSync6 } from "fs";
3677
+ import { join as join16 } from "path";
3678
+ import { homedir as homedir8 } from "os";
3595
3679
  function getTrackerConfig2(trackerType) {
3596
3680
  const config2 = loadConfig();
3597
3681
  const trackerConfig = config2.trackers[trackerType];
@@ -3609,13 +3693,13 @@ function getTrackerConfig2(trackerType) {
3609
3693
  };
3610
3694
  }
3611
3695
  function getTriageStatePath() {
3612
- return join15(homedir7(), ".panopticon", "triage-state.json");
3696
+ return join16(homedir8(), ".panopticon", "triage-state.json");
3613
3697
  }
3614
3698
  function loadTriageState() {
3615
3699
  const path = getTriageStatePath();
3616
- if (existsSync15(path)) {
3700
+ if (existsSync16(path)) {
3617
3701
  try {
3618
- return JSON.parse(readFileSync13(path, "utf-8"));
3702
+ return JSON.parse(readFileSync14(path, "utf-8"));
3619
3703
  } catch {
3620
3704
  return { dismissed: [], created: {} };
3621
3705
  }
@@ -3623,8 +3707,8 @@ function loadTriageState() {
3623
3707
  return { dismissed: [], created: {} };
3624
3708
  }
3625
3709
  function saveTriageState(state) {
3626
- const dir = join15(homedir7(), ".panopticon");
3627
- if (!existsSync15(dir)) {
3710
+ const dir = join16(homedir8(), ".panopticon");
3711
+ if (!existsSync16(dir)) {
3628
3712
  mkdirSync6(dir, { recursive: true });
3629
3713
  }
3630
3714
  const path = getTriageStatePath();
@@ -4009,23 +4093,23 @@ import chalk19 from "chalk";
4009
4093
  // src/lib/context.ts
4010
4094
  init_esm_shims();
4011
4095
  init_paths();
4012
- import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, writeFileSync as writeFileSync7, appendFileSync, readdirSync as readdirSync12 } from "fs";
4013
- import { join as join16 } from "path";
4096
+ import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync7, appendFileSync, readdirSync as readdirSync12 } from "fs";
4097
+ import { join as join17 } from "path";
4014
4098
  function getStateFile(agentId) {
4015
- return join16(AGENTS_DIR, agentId, "STATE.md");
4099
+ return join17(AGENTS_DIR, agentId, "STATE.md");
4016
4100
  }
4017
4101
  function readAgentState(agentId) {
4018
4102
  const stateFile = getStateFile(agentId);
4019
- if (!existsSync16(stateFile)) return null;
4103
+ if (!existsSync17(stateFile)) return null;
4020
4104
  try {
4021
- const content = readFileSync14(stateFile, "utf-8");
4105
+ const content = readFileSync15(stateFile, "utf-8");
4022
4106
  return parseStateMd(content);
4023
4107
  } catch {
4024
4108
  return null;
4025
4109
  }
4026
4110
  }
4027
4111
  function writeAgentState(agentId, state) {
4028
- const dir = join16(AGENTS_DIR, agentId);
4112
+ const dir = join17(AGENTS_DIR, agentId);
4029
4113
  mkdirSync7(dir, { recursive: true });
4030
4114
  const content = generateStateMd(state);
4031
4115
  writeFileSync7(getStateFile(agentId), content);
@@ -4102,14 +4186,14 @@ function parseStateMd(content) {
4102
4186
  return state;
4103
4187
  }
4104
4188
  function getSummaryFile(agentId) {
4105
- return join16(AGENTS_DIR, agentId, "SUMMARY.md");
4189
+ return join17(AGENTS_DIR, agentId, "SUMMARY.md");
4106
4190
  }
4107
4191
  function appendSummary(agentId, summary) {
4108
- const dir = join16(AGENTS_DIR, agentId);
4192
+ const dir = join17(AGENTS_DIR, agentId);
4109
4193
  mkdirSync7(dir, { recursive: true });
4110
4194
  const summaryFile = getSummaryFile(agentId);
4111
4195
  const content = generateSummaryEntry(summary);
4112
- if (existsSync16(summaryFile)) {
4196
+ if (existsSync17(summaryFile)) {
4113
4197
  appendFileSync(summaryFile, "\n---\n\n" + content);
4114
4198
  } else {
4115
4199
  writeFileSync7(summaryFile, "# Work Summaries\n\n" + content);
@@ -4150,14 +4234,14 @@ function generateSummaryEntry(summary) {
4150
4234
  return lines.join("\n");
4151
4235
  }
4152
4236
  function getHistoryDir(agentId) {
4153
- return join16(AGENTS_DIR, agentId, "history");
4237
+ return join17(AGENTS_DIR, agentId, "history");
4154
4238
  }
4155
4239
  function logHistory(agentId, action, details) {
4156
4240
  const historyDir = getHistoryDir(agentId);
4157
4241
  mkdirSync7(historyDir, { recursive: true });
4158
4242
  const date = /* @__PURE__ */ new Date();
4159
4243
  const dateStr = date.toISOString().split("T")[0];
4160
- const historyFile = join16(historyDir, `${dateStr}.log`);
4244
+ const historyFile = join17(historyDir, `${dateStr}.log`);
4161
4245
  const timestamp = date.toISOString();
4162
4246
  const detailsStr = details ? ` ${JSON.stringify(details)}` : "";
4163
4247
  const logLine = `[${timestamp}] ${action}${detailsStr}
@@ -4166,13 +4250,13 @@ function logHistory(agentId, action, details) {
4166
4250
  }
4167
4251
  function searchHistory(agentId, pattern) {
4168
4252
  const historyDir = getHistoryDir(agentId);
4169
- if (!existsSync16(historyDir)) return [];
4253
+ if (!existsSync17(historyDir)) return [];
4170
4254
  const results = [];
4171
4255
  const regex = new RegExp(pattern, "i");
4172
4256
  const files = readdirSync12(historyDir).filter((f) => f.endsWith(".log"));
4173
4257
  files.sort().reverse();
4174
4258
  for (const file of files) {
4175
- const content = readFileSync14(join16(historyDir, file), "utf-8");
4259
+ const content = readFileSync15(join17(historyDir, file), "utf-8");
4176
4260
  const lines = content.split("\n");
4177
4261
  for (const line of lines) {
4178
4262
  if (regex.test(line)) {
@@ -4184,13 +4268,13 @@ function searchHistory(agentId, pattern) {
4184
4268
  }
4185
4269
  function getRecentHistory(agentId, limit = 20) {
4186
4270
  const historyDir = getHistoryDir(agentId);
4187
- if (!existsSync16(historyDir)) return [];
4271
+ if (!existsSync17(historyDir)) return [];
4188
4272
  const results = [];
4189
4273
  const files = readdirSync12(historyDir).filter((f) => f.endsWith(".log"));
4190
4274
  files.sort().reverse();
4191
4275
  for (const file of files) {
4192
4276
  if (results.length >= limit) break;
4193
- const content = readFileSync14(join16(historyDir, file), "utf-8");
4277
+ const content = readFileSync15(join17(historyDir, file), "utf-8");
4194
4278
  const lines = content.split("\n").filter((l) => l.trim());
4195
4279
  for (const line of lines.reverse()) {
4196
4280
  if (results.length >= limit) break;
@@ -4203,28 +4287,28 @@ function estimateTokens(text) {
4203
4287
  return Math.ceil(text.length / 4);
4204
4288
  }
4205
4289
  function getMaterializedDir(agentId) {
4206
- return join16(AGENTS_DIR, agentId, "materialized");
4290
+ return join17(AGENTS_DIR, agentId, "materialized");
4207
4291
  }
4208
4292
  function listMaterialized(agentId) {
4209
4293
  const dir = getMaterializedDir(agentId);
4210
- if (!existsSync16(dir)) return [];
4294
+ if (!existsSync17(dir)) return [];
4211
4295
  return readdirSync12(dir).filter((f) => f.endsWith(".md")).map((f) => {
4212
4296
  const match = f.match(/^(.+)-(\d+)\.md$/);
4213
4297
  if (!match) return null;
4214
4298
  return {
4215
4299
  tool: match[1],
4216
4300
  timestamp: parseInt(match[2], 10),
4217
- file: join16(dir, f)
4301
+ file: join17(dir, f)
4218
4302
  };
4219
4303
  }).filter(Boolean);
4220
4304
  }
4221
4305
  function readMaterialized(filepath) {
4222
- if (!existsSync16(filepath)) return null;
4223
- return readFileSync14(filepath, "utf-8");
4306
+ if (!existsSync17(filepath)) return null;
4307
+ return readFileSync15(filepath, "utf-8");
4224
4308
  }
4225
4309
 
4226
4310
  // src/cli/commands/work/context.ts
4227
- import { readFileSync as readFileSync15, existsSync as existsSync17 } from "fs";
4311
+ import { readFileSync as readFileSync16, existsSync as existsSync18 } from "fs";
4228
4312
  async function contextCommand(action, arg1, arg2, options = {}) {
4229
4313
  const agentId = process.env.PANOPTICON_AGENT_ID || arg1 || "default";
4230
4314
  switch (action) {
@@ -4340,7 +4424,7 @@ History matches for "${pattern}":
4340
4424
  }
4341
4425
  case "materialize": {
4342
4426
  const filepath = arg1;
4343
- if (filepath && existsSync17(filepath)) {
4427
+ if (filepath && existsSync18(filepath)) {
4344
4428
  const content = readMaterialized(filepath);
4345
4429
  if (content) {
4346
4430
  console.log(content);
@@ -4368,8 +4452,8 @@ History matches for "${pattern}":
4368
4452
  return;
4369
4453
  }
4370
4454
  let text = target;
4371
- if (existsSync17(target)) {
4372
- text = readFileSync15(target, "utf-8");
4455
+ if (existsSync18(target)) {
4456
+ text = readFileSync16(target, "utf-8");
4373
4457
  }
4374
4458
  const tokens = estimateTokens(text);
4375
4459
  console.log(`Estimated tokens: ${chalk19.cyan(tokens.toLocaleString())}`);
@@ -4397,8 +4481,8 @@ import chalk20 from "chalk";
4397
4481
  init_esm_shims();
4398
4482
  init_paths();
4399
4483
  init_agents();
4400
- import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync8 } from "fs";
4401
- import { join as join17 } from "path";
4484
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
4485
+ import { join as join18 } from "path";
4402
4486
  import { exec as exec3 } from "child_process";
4403
4487
  import { promisify as promisify3 } from "util";
4404
4488
  var execAsync3 = promisify3(exec3);
@@ -4407,7 +4491,7 @@ var DEFAULT_CONSECUTIVE_FAILURES = 3;
4407
4491
  var DEFAULT_COOLDOWN_MS = 5 * 60 * 1e3;
4408
4492
  var DEFAULT_CHECK_INTERVAL_MS = 30 * 1e3;
4409
4493
  function getHealthFile(agentId) {
4410
- return join17(AGENTS_DIR, agentId, "health.json");
4494
+ return join18(AGENTS_DIR, agentId, "health.json");
4411
4495
  }
4412
4496
  function getAgentHealth(agentId) {
4413
4497
  const healthFile = getHealthFile(agentId);
@@ -4419,9 +4503,9 @@ function getAgentHealth(agentId) {
4419
4503
  recoveryCount: 0,
4420
4504
  inCooldown: false
4421
4505
  };
4422
- if (existsSync18(healthFile)) {
4506
+ if (existsSync19(healthFile)) {
4423
4507
  try {
4424
- const stored = JSON.parse(readFileSync16(healthFile, "utf-8"));
4508
+ const stored = JSON.parse(readFileSync17(healthFile, "utf-8"));
4425
4509
  return { ...defaultHealth, ...stored };
4426
4510
  } catch {
4427
4511
  }
@@ -4429,7 +4513,7 @@ function getAgentHealth(agentId) {
4429
4513
  return defaultHealth;
4430
4514
  }
4431
4515
  function saveAgentHealth(health) {
4432
- const dir = join17(AGENTS_DIR, health.agentId);
4516
+ const dir = join18(AGENTS_DIR, health.agentId);
4433
4517
  mkdirSync8(dir, { recursive: true });
4434
4518
  writeFileSync8(getHealthFile(health.agentId), JSON.stringify(health, null, 2));
4435
4519
  }
@@ -4552,7 +4636,7 @@ async function runHealthCheck(config2 = {
4552
4636
  sessions = output.trim().split("\n").filter((s) => s.startsWith("agent-"));
4553
4637
  } catch {
4554
4638
  }
4555
- if (existsSync18(AGENTS_DIR)) {
4639
+ if (existsSync19(AGENTS_DIR)) {
4556
4640
  const { readdirSync: readdirSync22 } = await import("fs");
4557
4641
  const dirs = readdirSync22(AGENTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("agent-")).map((d) => d.name);
4558
4642
  for (const dir of dirs) {
@@ -4790,15 +4874,15 @@ init_esm_shims();
4790
4874
  import chalk21 from "chalk";
4791
4875
  import ora11 from "ora";
4792
4876
  import inquirer3 from "inquirer";
4793
- import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
4794
- import { join as join19, dirname as dirname6 } from "path";
4795
- import { homedir as homedir8 } from "os";
4877
+ import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
4878
+ import { join as join20, dirname as dirname6 } from "path";
4879
+ import { homedir as homedir9 } from "os";
4796
4880
  import { LinearClient } from "@linear/sdk";
4797
4881
 
4798
4882
  // src/lib/reopen.ts
4799
4883
  init_esm_shims();
4800
- import { existsSync as existsSync19, readFileSync as readFileSync17, appendFileSync as appendFileSync2 } from "fs";
4801
- import { join as join18 } from "path";
4884
+ import { existsSync as existsSync20, readFileSync as readFileSync18, appendFileSync as appendFileSync2 } from "fs";
4885
+ import { join as join19 } from "path";
4802
4886
 
4803
4887
  // src/dashboard/server/review-status.ts
4804
4888
  init_esm_shims();
@@ -4864,9 +4948,9 @@ function reopenWorkspaceState(issueId, workspacePath, options = {}) {
4864
4948
  result.queueItemsRemoved[specialistName] = removed;
4865
4949
  }
4866
4950
  }
4867
- const statePath = join18(workspacePath, ".planning", "STATE.md");
4868
- if (existsSync19(statePath)) {
4869
- const previousContent = readFileSync17(statePath, "utf-8");
4951
+ const statePath = join19(workspacePath, ".planning", "STATE.md");
4952
+ if (existsSync20(statePath)) {
4953
+ const previousContent = readFileSync18(statePath, "utf-8");
4870
4954
  const lastStatusMatch = previousContent.match(/\*\*STATUS:\s*([^*\n]+)\*\*/);
4871
4955
  const previousStatus = lastStatusMatch ? lastStatusMatch[1].trim() : "Unknown";
4872
4956
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4902,9 +4986,9 @@ function reopenWorkspaceState(issueId, workspacePath, options = {}) {
4902
4986
  // src/cli/commands/work/reopen.ts
4903
4987
  init_projects();
4904
4988
  function getLinearApiKey5() {
4905
- const envFile = join19(homedir8(), ".panopticon.env");
4906
- if (existsSync20(envFile)) {
4907
- const content = readFileSync18(envFile, "utf-8");
4989
+ const envFile = join20(homedir9(), ".panopticon.env");
4990
+ if (existsSync21(envFile)) {
4991
+ const content = readFileSync19(envFile, "utf-8");
4908
4992
  const match = content.match(/LINEAR_API_KEY=(.+)/);
4909
4993
  if (match) return match[1].trim();
4910
4994
  }
@@ -4977,15 +5061,15 @@ function findLocalWorkspace2(issueId, startDir) {
4977
5061
  const normalizedId = issueId.toLowerCase();
4978
5062
  const resolved = resolveProjectFromIssue(issueId, []);
4979
5063
  if (resolved) {
4980
- const workspacePath = join19(resolved.projectPath, "workspaces", `feature-${normalizedId}`);
4981
- if (existsSync20(workspacePath)) return workspacePath;
5064
+ const workspacePath = join20(resolved.projectPath, "workspaces", `feature-${normalizedId}`);
5065
+ if (existsSync21(workspacePath)) return workspacePath;
4982
5066
  }
4983
5067
  let dir = startDir ?? process.cwd();
4984
5068
  for (let i = 0; i < 10; i++) {
4985
- const workspacesDir = join19(dir, "workspaces");
4986
- if (existsSync20(workspacesDir)) {
4987
- const workspacePath = join19(workspacesDir, `feature-${normalizedId}`);
4988
- if (existsSync20(workspacePath)) return workspacePath;
5069
+ const workspacesDir = join20(dir, "workspaces");
5070
+ if (existsSync21(workspacesDir)) {
5071
+ const workspacePath = join20(workspacesDir, `feature-${normalizedId}`);
5072
+ if (existsSync21(workspacePath)) return workspacePath;
4989
5073
  }
4990
5074
  const parent = dirname6(dir);
4991
5075
  if (parent === dir) break;
@@ -5112,7 +5196,7 @@ Previous state: ${issue.state}`
5112
5196
  console.log(chalk21.green(`\u2713 ${issue.identifier} reopened and ready for re-work`));
5113
5197
  console.log("");
5114
5198
  try {
5115
- const { getAgentState: getAgentState2 } = await import("../agents-E43Y3HNU.js");
5199
+ const { getAgentState: getAgentState2 } = await import("../agents-5OPQKM5K.js");
5116
5200
  const agentId = `agent-${id.toLowerCase()}`;
5117
5201
  const agentState = getAgentState2(agentId);
5118
5202
  const agentRunning = agentState?.status === "active" || agentState?.status === "running";
@@ -5228,11 +5312,12 @@ init_esm_shims();
5228
5312
  init_agents();
5229
5313
  init_tmux();
5230
5314
  import chalk24 from "chalk";
5231
- import { homedir as homedir9 } from "os";
5232
- import { join as join20 } from "path";
5233
- import { existsSync as existsSync21, rmSync, readFileSync as readFileSync19 } from "fs";
5315
+ import { homedir as homedir10 } from "os";
5316
+ import { join as join21 } from "path";
5317
+ import { existsSync as existsSync22, rmSync, readFileSync as readFileSync20 } from "fs";
5234
5318
  import { exec as exec4 } from "child_process";
5235
5319
  import { promisify as promisify4 } from "util";
5320
+ init_workspace_manager();
5236
5321
  var execAsync4 = promisify4(exec4);
5237
5322
  async function wipeCommand(issueId, options) {
5238
5323
  const issueLower = issueId.toLowerCase();
@@ -5319,22 +5404,22 @@ async function wipeCommand(issueId, options) {
5319
5404
  }
5320
5405
  }
5321
5406
  const agentDirs = [
5322
- join20(homedir9(), ".panopticon", "agents", `agent-${issueLower}`)
5407
+ join21(homedir10(), ".panopticon", "agents", `agent-${issueLower}`)
5323
5408
  ];
5324
5409
  for (const dir of agentDirs) {
5325
- if (existsSync21(dir)) {
5410
+ if (existsSync22(dir)) {
5326
5411
  rmSync(dir, { recursive: true, force: true });
5327
5412
  cleanupLog.push(`Deleted agent state: ${dir}`);
5328
- console.log(chalk24.green(` \u2713 Deleted agent state: ${dir.replace(homedir9(), "~")}`));
5413
+ console.log(chalk24.green(` \u2713 Deleted agent state: ${dir.replace(homedir10(), "~")}`));
5329
5414
  }
5330
5415
  }
5331
5416
  let projectPath;
5332
5417
  const prefix = issueId.split("-")[0].toUpperCase();
5333
- const projectsYamlPath = join20(homedir9(), ".panopticon", "projects.yaml");
5334
- if (existsSync21(projectsYamlPath)) {
5418
+ const projectsYamlPath = join21(homedir10(), ".panopticon", "projects.yaml");
5419
+ if (existsSync22(projectsYamlPath)) {
5335
5420
  try {
5336
5421
  const yaml2 = await import("js-yaml");
5337
- const projectsConfig = yaml2.load(readFileSync19(projectsYamlPath, "utf-8"));
5422
+ const projectsConfig = yaml2.load(readFileSync20(projectsYamlPath, "utf-8"));
5338
5423
  for (const [, config2] of Object.entries(projectsConfig.projects || {})) {
5339
5424
  const projConfig = config2;
5340
5425
  if (projConfig.linear_team?.toUpperCase() === prefix) {
@@ -5345,20 +5430,37 @@ async function wipeCommand(issueId, options) {
5345
5430
  } catch (e) {
5346
5431
  }
5347
5432
  }
5433
+ if (projectPath) {
5434
+ const workspacePath = join21(projectPath, "workspaces", `feature-${issueLower}`);
5435
+ if (existsSync22(workspacePath)) {
5436
+ try {
5437
+ const projName = projectPath.split("/").pop() || "";
5438
+ const dockerResult = await stopWorkspaceDocker(workspacePath, projName, issueLower);
5439
+ if (dockerResult.steps.length > 0) {
5440
+ for (const step of dockerResult.steps) {
5441
+ cleanupLog.push(step);
5442
+ console.log(chalk24.green(` \u2713 ${step}`));
5443
+ }
5444
+ }
5445
+ } catch (e) {
5446
+ console.log(chalk24.yellow(` \u26A0 Docker cleanup: ${e.message}`));
5447
+ }
5448
+ }
5449
+ }
5348
5450
  if (options.workspace && projectPath) {
5349
- const workspacePath = join20(projectPath, "workspaces", `feature-${issueLower}`);
5350
- if (existsSync21(workspacePath)) {
5451
+ const workspacePath = join21(projectPath, "workspaces", `feature-${issueLower}`);
5452
+ if (existsSync22(workspacePath)) {
5351
5453
  try {
5352
5454
  const gitDirs = ["api", "frontend", "fe", "."];
5353
5455
  for (const gitDir of gitDirs) {
5354
- const gitPath = join20(projectPath, gitDir);
5355
- if (existsSync21(join20(gitPath, ".git"))) {
5456
+ const gitPath = join21(projectPath, gitDir);
5457
+ if (existsSync22(join21(gitPath, ".git"))) {
5356
5458
  await execAsync4(`cd "${gitPath}" && git worktree remove "${workspacePath}" --force 2>/dev/null || true`);
5357
5459
  }
5358
5460
  }
5359
5461
  } catch (e) {
5360
5462
  }
5361
- if (existsSync21(workspacePath)) {
5463
+ if (existsSync22(workspacePath)) {
5362
5464
  rmSync(workspacePath, { recursive: true, force: true });
5363
5465
  }
5364
5466
  cleanupLog.push(`Deleted workspace: ${workspacePath}`);
@@ -5416,14 +5518,14 @@ import ora12 from "ora";
5416
5518
 
5417
5519
  // src/lib/shadow-utils.ts
5418
5520
  init_esm_shims();
5419
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
5420
- import { join as join21 } from "path";
5421
- import { homedir as homedir10 } from "os";
5521
+ import { existsSync as existsSync23, readFileSync as readFileSync21 } from "fs";
5522
+ import { join as join22 } from "path";
5523
+ import { homedir as homedir11 } from "os";
5422
5524
  import chalk25 from "chalk";
5423
5525
  function getLinearApiKey6() {
5424
- const envFile = join21(homedir10(), ".panopticon.env");
5425
- if (existsSync22(envFile)) {
5426
- const content = readFileSync20(envFile, "utf-8");
5526
+ const envFile = join22(homedir11(), ".panopticon.env");
5527
+ if (existsSync23(envFile)) {
5528
+ const content = readFileSync21(envFile, "utf-8");
5427
5529
  const match = content.match(/LINEAR_API_KEY=(.+)/);
5428
5530
  if (match) return match[1].trim();
5429
5531
  }
@@ -5522,10 +5624,10 @@ init_esm_shims();
5522
5624
  import chalk27 from "chalk";
5523
5625
  import ora13 from "ora";
5524
5626
  import inquirer4 from "inquirer";
5525
- import { existsSync as existsSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "fs";
5526
- import { join as join22, dirname as dirname7 } from "path";
5527
- import { homedir as homedir11 } from "os";
5528
- var SYNC_QUEUE_FILE = join22(homedir11(), ".panopticon", "sync-queue.json");
5627
+ import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "fs";
5628
+ import { join as join23, dirname as dirname7 } from "path";
5629
+ import { homedir as homedir12 } from "os";
5630
+ var SYNC_QUEUE_FILE = join23(homedir12(), ".panopticon", "sync-queue.json");
5529
5631
  async function syncToLinear(apiKey, issueId, targetState) {
5530
5632
  try {
5531
5633
  const { LinearClient: LinearClient2 } = await import("@linear/sdk");
@@ -5697,11 +5799,11 @@ async function syncCommand2(id, options = {}) {
5697
5799
  }
5698
5800
  }
5699
5801
  function loadSyncQueue() {
5700
- if (!existsSync23(SYNC_QUEUE_FILE)) {
5802
+ if (!existsSync24(SYNC_QUEUE_FILE)) {
5701
5803
  return [];
5702
5804
  }
5703
5805
  try {
5704
- const content = readFileSync21(SYNC_QUEUE_FILE, "utf-8");
5806
+ const content = readFileSync22(SYNC_QUEUE_FILE, "utf-8");
5705
5807
  return JSON.parse(content);
5706
5808
  } catch (error) {
5707
5809
  console.error(chalk27.yellow("Warning: Failed to load sync queue"));
@@ -5710,7 +5812,7 @@ function loadSyncQueue() {
5710
5812
  }
5711
5813
  function saveSyncQueue(queue) {
5712
5814
  const dir = dirname7(SYNC_QUEUE_FILE);
5713
- if (!existsSync23(dir)) {
5815
+ if (!existsSync24(dir)) {
5714
5816
  mkdirSync9(dir, { recursive: true });
5715
5817
  }
5716
5818
  try {
@@ -5837,8 +5939,8 @@ async function refreshCommand(id, options = {}) {
5837
5939
  init_esm_shims();
5838
5940
  init_tldr_daemon();
5839
5941
  import chalk29 from "chalk";
5840
- import { existsSync as existsSync24, readdirSync as readdirSync14, readFileSync as readFileSync22, statSync as statSync5 } from "fs";
5841
- import { join as join23 } from "path";
5942
+ import { existsSync as existsSync25, readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync5 } from "fs";
5943
+ import { join as join24 } from "path";
5842
5944
  async function tldrCommand(action, workspace, options = {}) {
5843
5945
  switch (action) {
5844
5946
  case "status":
@@ -5861,19 +5963,19 @@ async function tldrCommand(action, workspace, options = {}) {
5861
5963
  }
5862
5964
  async function statusCommand2(options) {
5863
5965
  const projectRoot = process.cwd();
5864
- const venvPath = join23(projectRoot, ".venv");
5966
+ const venvPath = join24(projectRoot, ".venv");
5865
5967
  const results = [];
5866
- if (existsSync24(venvPath)) {
5968
+ if (existsSync25(venvPath)) {
5867
5969
  const service = getTldrDaemonService(projectRoot, venvPath);
5868
5970
  const status = await service.getStatus();
5869
- const tldrPath = join23(projectRoot, ".tldr");
5971
+ const tldrPath = join24(projectRoot, ".tldr");
5870
5972
  let indexAge = "N/A";
5871
5973
  let fileCount = "N/A";
5872
- if (existsSync24(tldrPath)) {
5974
+ if (existsSync25(tldrPath)) {
5873
5975
  try {
5874
- const langPath = join23(tldrPath, "languages.json");
5875
- if (existsSync24(langPath)) {
5876
- const langData = JSON.parse(readFileSync22(langPath, "utf-8"));
5976
+ const langPath = join24(tldrPath, "languages.json");
5977
+ if (existsSync25(langPath)) {
5978
+ const langData = JSON.parse(readFileSync23(langPath, "utf-8"));
5877
5979
  if (langData.timestamp) {
5878
5980
  const ageMs = Date.now() - langData.timestamp * 1e3;
5879
5981
  const ageDays = Math.floor(ageMs / (1e3 * 60 * 60 * 24));
@@ -5886,9 +5988,9 @@ async function statusCommand2(options) {
5886
5988
  const ageDays = Math.floor(ageMs / (1e3 * 60 * 60 * 24));
5887
5989
  indexAge = ageDays === 0 ? "today" : `${ageDays}d ago`;
5888
5990
  }
5889
- const cgPath = join23(tldrPath, "cache", "call_graph.json");
5890
- if (existsSync24(cgPath)) {
5891
- const cg = JSON.parse(readFileSync22(cgPath, "utf-8"));
5991
+ const cgPath = join24(tldrPath, "cache", "call_graph.json");
5992
+ if (existsSync25(cgPath)) {
5993
+ const cg = JSON.parse(readFileSync23(cgPath, "utf-8"));
5892
5994
  if (Array.isArray(cg.edges)) {
5893
5995
  const files = /* @__PURE__ */ new Set();
5894
5996
  for (const e of cg.edges) {
@@ -5910,23 +6012,23 @@ async function statusCommand2(options) {
5910
6012
  fileCount
5911
6013
  });
5912
6014
  }
5913
- const workspacesDir = join23(projectRoot, "workspaces");
5914
- if (existsSync24(workspacesDir)) {
6015
+ const workspacesDir = join24(projectRoot, "workspaces");
6016
+ if (existsSync25(workspacesDir)) {
5915
6017
  const workspaces = readdirSync14(workspacesDir, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("feature-"));
5916
6018
  for (const ws of workspaces) {
5917
- const wsPath = join23(workspacesDir, ws.name);
5918
- const wsVenvPath = join23(wsPath, ".venv");
5919
- if (existsSync24(wsVenvPath)) {
6019
+ const wsPath = join24(workspacesDir, ws.name);
6020
+ const wsVenvPath = join24(wsPath, ".venv");
6021
+ if (existsSync25(wsVenvPath)) {
5920
6022
  const service = getTldrDaemonService(wsPath, wsVenvPath);
5921
6023
  const status = await service.getStatus();
5922
- const tldrPath = join23(wsPath, ".tldr");
6024
+ const tldrPath = join24(wsPath, ".tldr");
5923
6025
  let indexAge = "N/A";
5924
6026
  let fileCount = "N/A";
5925
- if (existsSync24(tldrPath)) {
6027
+ if (existsSync25(tldrPath)) {
5926
6028
  try {
5927
- const langPath = join23(tldrPath, "languages.json");
5928
- if (existsSync24(langPath)) {
5929
- const langData = JSON.parse(readFileSync22(langPath, "utf-8"));
6029
+ const langPath = join24(tldrPath, "languages.json");
6030
+ if (existsSync25(langPath)) {
6031
+ const langData = JSON.parse(readFileSync23(langPath, "utf-8"));
5930
6032
  if (langData.timestamp) {
5931
6033
  const ageMs = Date.now() - langData.timestamp * 1e3;
5932
6034
  const ageHours = Math.floor(ageMs / (1e3 * 60 * 60));
@@ -5939,9 +6041,9 @@ async function statusCommand2(options) {
5939
6041
  const ageHours = Math.floor(ageMs / (1e3 * 60 * 60));
5940
6042
  indexAge = ageHours === 0 ? "now" : ageHours < 24 ? `${ageHours}h ago` : `${Math.floor(ageHours / 24)}d ago`;
5941
6043
  }
5942
- const cgPath = join23(tldrPath, "cache", "call_graph.json");
5943
- if (existsSync24(cgPath)) {
5944
- const cg = JSON.parse(readFileSync22(cgPath, "utf-8"));
6044
+ const cgPath = join24(tldrPath, "cache", "call_graph.json");
6045
+ if (existsSync25(cgPath)) {
6046
+ const cg = JSON.parse(readFileSync23(cgPath, "utf-8"));
5945
6047
  if (Array.isArray(cg.edges)) {
5946
6048
  const files = /* @__PURE__ */ new Set();
5947
6049
  for (const e of cg.edges) {
@@ -5991,13 +6093,13 @@ async function statusCommand2(options) {
5991
6093
  async function startCommand(workspace, options) {
5992
6094
  const projectRoot = process.cwd();
5993
6095
  if (workspace) {
5994
- const wsPath = join23(projectRoot, "workspaces", workspace);
5995
- const venvPath = join23(wsPath, ".venv");
5996
- if (!existsSync24(wsPath)) {
6096
+ const wsPath = join24(projectRoot, "workspaces", workspace);
6097
+ const venvPath = join24(wsPath, ".venv");
6098
+ if (!existsSync25(wsPath)) {
5997
6099
  console.error(chalk29.red(`Error: Workspace not found: ${workspace}`));
5998
6100
  process.exit(1);
5999
6101
  }
6000
- if (!existsSync24(venvPath)) {
6102
+ if (!existsSync25(venvPath)) {
6001
6103
  console.error(chalk29.red(`Error: No .venv found in workspace: ${workspace}`));
6002
6104
  console.error(chalk29.dim("Workspace needs to be recreated with TLDR support"));
6003
6105
  process.exit(1);
@@ -6008,8 +6110,8 @@ async function startCommand(workspace, options) {
6008
6110
  console.log(chalk29.green(`\u2713 Started TLDR daemon for ${workspace}`));
6009
6111
  }
6010
6112
  } else {
6011
- const venvPath = join23(projectRoot, ".venv");
6012
- if (!existsSync24(venvPath)) {
6113
+ const venvPath = join24(projectRoot, ".venv");
6114
+ if (!existsSync25(venvPath)) {
6013
6115
  console.error(chalk29.red("Error: No .venv found in project root"));
6014
6116
  console.error(chalk29.dim("Run `pan setup` to configure TLDR"));
6015
6117
  process.exit(1);
@@ -6024,13 +6126,13 @@ async function startCommand(workspace, options) {
6024
6126
  async function stopCommand(workspace, options) {
6025
6127
  const projectRoot = process.cwd();
6026
6128
  if (workspace) {
6027
- const wsPath = join23(projectRoot, "workspaces", workspace);
6028
- const venvPath = join23(wsPath, ".venv");
6029
- if (!existsSync24(wsPath)) {
6129
+ const wsPath = join24(projectRoot, "workspaces", workspace);
6130
+ const venvPath = join24(wsPath, ".venv");
6131
+ if (!existsSync25(wsPath)) {
6030
6132
  console.error(chalk29.red(`Error: Workspace not found: ${workspace}`));
6031
6133
  process.exit(1);
6032
6134
  }
6033
- if (!existsSync24(venvPath)) {
6135
+ if (!existsSync25(venvPath)) {
6034
6136
  console.error(chalk29.red(`Error: No .venv found in workspace: ${workspace}`));
6035
6137
  process.exit(1);
6036
6138
  }
@@ -6040,8 +6142,8 @@ async function stopCommand(workspace, options) {
6040
6142
  console.log(chalk29.green(`\u2713 Stopped TLDR daemon for ${workspace}`));
6041
6143
  }
6042
6144
  } else {
6043
- const venvPath = join23(projectRoot, ".venv");
6044
- if (!existsSync24(venvPath)) {
6145
+ const venvPath = join24(projectRoot, ".venv");
6146
+ if (!existsSync25(venvPath)) {
6045
6147
  console.error(chalk29.red("Error: No .venv found in project root"));
6046
6148
  process.exit(1);
6047
6149
  }
@@ -6055,13 +6157,13 @@ async function stopCommand(workspace, options) {
6055
6157
  async function warmCommand(workspace, options) {
6056
6158
  const projectRoot = process.cwd();
6057
6159
  if (workspace) {
6058
- const wsPath = join23(projectRoot, "workspaces", workspace);
6059
- const venvPath = join23(wsPath, ".venv");
6060
- if (!existsSync24(wsPath)) {
6160
+ const wsPath = join24(projectRoot, "workspaces", workspace);
6161
+ const venvPath = join24(wsPath, ".venv");
6162
+ if (!existsSync25(wsPath)) {
6061
6163
  console.error(chalk29.red(`Error: Workspace not found: ${workspace}`));
6062
6164
  process.exit(1);
6063
6165
  }
6064
- if (!existsSync24(venvPath)) {
6166
+ if (!existsSync25(venvPath)) {
6065
6167
  console.error(chalk29.red(`Error: No .venv found in workspace: ${workspace}`));
6066
6168
  process.exit(1);
6067
6169
  }
@@ -6075,8 +6177,8 @@ async function warmCommand(workspace, options) {
6075
6177
  console.log(chalk29.green(`\u2713 Index warming complete for ${workspace}`));
6076
6178
  }
6077
6179
  } else {
6078
- const venvPath = join23(projectRoot, ".venv");
6079
- if (!existsSync24(venvPath)) {
6180
+ const venvPath = join24(projectRoot, ".venv");
6181
+ if (!existsSync25(venvPath)) {
6080
6182
  console.error(chalk29.red("Error: No .venv found in project root"));
6081
6183
  console.error(chalk29.dim("Run `pan setup` to configure TLDR"));
6082
6184
  process.exit(1);
@@ -6159,18 +6261,15 @@ async function syncMainCommand(id) {
6159
6261
  // src/cli/commands/work/close-out.ts
6160
6262
  init_esm_shims();
6161
6263
  import chalk31 from "chalk";
6162
- import { existsSync as existsSync29, readFileSync as readFileSync25 } from "fs";
6163
- import { join as join28 } from "path";
6164
- import { homedir as homedir13 } from "os";
6165
6264
 
6166
6265
  // src/lib/lifecycle/index.ts
6167
6266
  init_esm_shims();
6168
6267
 
6169
6268
  // src/lib/lifecycle/types.ts
6170
6269
  init_esm_shims();
6171
- import { existsSync as existsSync25, readFileSync as readFileSync23 } from "fs";
6172
- import { join as join24 } from "path";
6173
- import { homedir as homedir12 } from "os";
6270
+ import { existsSync as existsSync26, readFileSync as readFileSync24 } from "fs";
6271
+ import { join as join25 } from "path";
6272
+ import { homedir as homedir13 } from "os";
6174
6273
  function stepOk(step, details) {
6175
6274
  return { step, success: true, skipped: false, details };
6176
6275
  }
@@ -6182,9 +6281,9 @@ function stepFailed(step, error, details) {
6182
6281
  }
6183
6282
  function getLinearApiKey7() {
6184
6283
  if (process.env.LINEAR_API_KEY) return process.env.LINEAR_API_KEY;
6185
- const envFile = join24(homedir12(), ".panopticon.env");
6186
- if (existsSync25(envFile)) {
6187
- const content = readFileSync23(envFile, "utf-8");
6284
+ const envFile = join25(homedir13(), ".panopticon.env");
6285
+ if (existsSync26(envFile)) {
6286
+ const content = readFileSync24(envFile, "utf-8");
6188
6287
  const match = content.match(/LINEAR_API_KEY=(.+)/);
6189
6288
  if (match) return match[1].trim();
6190
6289
  }
@@ -6194,20 +6293,20 @@ function getLinearApiKey7() {
6194
6293
  // src/lib/lifecycle/archive-planning.ts
6195
6294
  init_esm_shims();
6196
6295
  init_paths();
6197
- import { existsSync as existsSync26, mkdirSync as mkdirSync10, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
6198
- import { join as join25, dirname as dirname8 } from "path";
6296
+ import { existsSync as existsSync27, mkdirSync as mkdirSync10, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
6297
+ import { join as join26, dirname as dirname8 } from "path";
6199
6298
  import { exec as exec5 } from "child_process";
6200
6299
  import { promisify as promisify5 } from "util";
6201
6300
  var execAsync5 = promisify5(exec5);
6202
6301
  function findWorkspacePath(projectPath, issueLower) {
6203
6302
  const candidates = [
6204
- join25(projectPath, "workspaces", `feature-${issueLower}`),
6205
- join25(projectPath, "workspaces", issueLower),
6206
- join25(projectPath, ".worktrees", issueLower),
6207
- join25(dirname8(projectPath), `feature-${issueLower}`)
6303
+ join26(projectPath, "workspaces", `feature-${issueLower}`),
6304
+ join26(projectPath, "workspaces", issueLower),
6305
+ join26(projectPath, ".worktrees", issueLower),
6306
+ join26(dirname8(projectPath), `feature-${issueLower}`)
6208
6307
  ];
6209
6308
  for (const p of candidates) {
6210
- if (existsSync26(p)) return p;
6309
+ if (existsSync27(p)) return p;
6211
6310
  }
6212
6311
  return null;
6213
6312
  }
@@ -6215,28 +6314,28 @@ async function movePrd(ctx, opts = {}) {
6215
6314
  const { pushToRemote = true } = opts;
6216
6315
  const issueLower = ctx.issueId.toLowerCase();
6217
6316
  const step = "archive-planning:move-prd";
6218
- const completedPrdPath = join25(
6317
+ const completedPrdPath = join26(
6219
6318
  ctx.projectPath,
6220
6319
  PROJECT_DOCS_SUBDIR,
6221
6320
  PROJECT_PRDS_SUBDIR,
6222
6321
  PROJECT_PRDS_COMPLETED_SUBDIR,
6223
6322
  `${issueLower}-plan.md`
6224
6323
  );
6225
- const activePrdPath = join25(
6324
+ const activePrdPath = join26(
6226
6325
  ctx.projectPath,
6227
6326
  PROJECT_DOCS_SUBDIR,
6228
6327
  PROJECT_PRDS_SUBDIR,
6229
6328
  PROJECT_PRDS_ACTIVE_SUBDIR,
6230
6329
  `${issueLower}-plan.md`
6231
6330
  );
6232
- if (existsSync26(completedPrdPath)) {
6331
+ if (existsSync27(completedPrdPath)) {
6233
6332
  return stepSkipped(step, ["PRD already in completed/"]);
6234
6333
  }
6235
- if (!existsSync26(activePrdPath)) {
6334
+ if (!existsSync27(activePrdPath)) {
6236
6335
  return stepSkipped(step, ["No PRD found in active/ (may not have had one)"]);
6237
6336
  }
6238
6337
  const completedDir = dirname8(completedPrdPath);
6239
- if (!existsSync26(completedDir)) {
6338
+ if (!existsSync27(completedDir)) {
6240
6339
  mkdirSync10(completedDir, { recursive: true });
6241
6340
  }
6242
6341
  try {
@@ -6250,7 +6349,7 @@ async function movePrd(ctx, opts = {}) {
6250
6349
  }
6251
6350
  try {
6252
6351
  cpSync2(activePrdPath, completedPrdPath);
6253
- if (!existsSync26(completedPrdPath)) {
6352
+ if (!existsSync27(completedPrdPath)) {
6254
6353
  return stepFailed(step, "PRD copy appeared to succeed but file not found at destination");
6255
6354
  }
6256
6355
  return stepOk(step, ["Copied PRD to completed/ (git mv failed, plain copy succeeded)"]);
@@ -6262,14 +6361,14 @@ async function archiveWorkspaceArtifacts(ctx) {
6262
6361
  const issueLower = ctx.issueId.toLowerCase();
6263
6362
  const step = "archive-planning:archive-artifacts";
6264
6363
  const workspacePath = findWorkspacePath(ctx.projectPath, issueLower);
6265
- if (!workspacePath || !existsSync26(workspacePath)) {
6364
+ if (!workspacePath || !existsSync27(workspacePath)) {
6266
6365
  return stepSkipped(step, ["No workspace found to archive"]);
6267
6366
  }
6268
6367
  try {
6269
- let archiveDir = join25(ARCHIVES_DIR, issueLower);
6270
- if (existsSync26(archiveDir)) {
6368
+ let archiveDir = join26(ARCHIVES_DIR, issueLower);
6369
+ if (existsSync27(archiveDir)) {
6271
6370
  let version = 1;
6272
- while (existsSync26(`${archiveDir}.${version}`)) {
6371
+ while (existsSync27(`${archiveDir}.${version}`)) {
6273
6372
  version++;
6274
6373
  }
6275
6374
  const rotatedDir = `${archiveDir}.${version}`;
@@ -6278,24 +6377,24 @@ async function archiveWorkspaceArtifacts(ctx) {
6278
6377
  }
6279
6378
  mkdirSync10(archiveDir, { recursive: true });
6280
6379
  const details = [];
6281
- const feedbackDir = join25(workspacePath, ".planning", "feedback");
6282
- if (existsSync26(feedbackDir)) {
6283
- cpSync2(feedbackDir, join25(archiveDir, "feedback"), { recursive: true });
6380
+ const feedbackDir = join26(workspacePath, ".planning", "feedback");
6381
+ if (existsSync27(feedbackDir)) {
6382
+ cpSync2(feedbackDir, join26(archiveDir, "feedback"), { recursive: true });
6284
6383
  details.push("Archived feedback/");
6285
6384
  }
6286
- const stateMd = join25(workspacePath, ".planning", "STATE.md");
6287
- if (existsSync26(stateMd)) {
6288
- cpSync2(stateMd, join25(archiveDir, "STATE.md"));
6385
+ const stateMd = join26(workspacePath, ".planning", "STATE.md");
6386
+ if (existsSync27(stateMd)) {
6387
+ cpSync2(stateMd, join26(archiveDir, "STATE.md"));
6289
6388
  details.push("Archived STATE.md");
6290
6389
  }
6291
- const beadsDir = join25(workspacePath, ".planning", "beads");
6292
- if (existsSync26(beadsDir)) {
6293
- cpSync2(beadsDir, join25(archiveDir, "beads"), { recursive: true });
6390
+ const beadsDir = join26(workspacePath, ".planning", "beads");
6391
+ if (existsSync27(beadsDir)) {
6392
+ cpSync2(beadsDir, join26(archiveDir, "beads"), { recursive: true });
6294
6393
  details.push("Archived beads/");
6295
6394
  }
6296
- const prdMd = join25(workspacePath, ".planning", "PRD.md");
6297
- if (existsSync26(prdMd)) {
6298
- cpSync2(prdMd, join25(archiveDir, "PRD.md"));
6395
+ const prdMd = join26(workspacePath, ".planning", "PRD.md");
6396
+ if (existsSync27(prdMd)) {
6397
+ cpSync2(prdMd, join26(archiveDir, "PRD.md"));
6299
6398
  details.push("Archived workspace PRD.md");
6300
6399
  }
6301
6400
  details.push(`Archived to ${archiveDir}`);
@@ -6560,8 +6659,8 @@ async function applyLabelLinear(ctx, apiKey) {
6560
6659
  init_esm_shims();
6561
6660
  init_paths();
6562
6661
  init_tmux();
6563
- import { existsSync as existsSync27, rmSync as rmSync3, unlinkSync as unlinkSync2 } from "fs";
6564
- import { join as join26, basename as basename5 } from "path";
6662
+ import { existsSync as existsSync28, rmSync as rmSync3, unlinkSync as unlinkSync2 } from "fs";
6663
+ import { join as join27, basename as basename5 } from "path";
6565
6664
  import { exec as exec7 } from "child_process";
6566
6665
  import { promisify as promisify7 } from "util";
6567
6666
  var execAsync7 = promisify7(exec7);
@@ -6591,8 +6690,8 @@ async function killTmuxSessions(issueLower) {
6591
6690
  }
6592
6691
  async function stopTldrDaemon(workspacePath) {
6593
6692
  const step = "teardown:tldr-daemon";
6594
- const venvPath = join26(workspacePath, ".venv");
6595
- if (!existsSync27(venvPath)) {
6693
+ const venvPath = join27(workspacePath, ".venv");
6694
+ if (!existsSync28(venvPath)) {
6596
6695
  return stepSkipped(step, ["No .venv found"]);
6597
6696
  }
6598
6697
  try {
@@ -6607,8 +6706,8 @@ async function stopTldrDaemon(workspacePath) {
6607
6706
  async function stopDocker(workspacePath, projectName, issueLower) {
6608
6707
  const step = "teardown:docker";
6609
6708
  try {
6610
- const { stopWorkspaceDocker } = await import("../workspace-manager-IE4JL2JP.js");
6611
- await stopWorkspaceDocker(workspacePath, projectName, issueLower);
6709
+ const { stopWorkspaceDocker: stopWorkspaceDocker2 } = await import("../workspace-manager-E434Z45T.js");
6710
+ await stopWorkspaceDocker2(workspacePath, projectName, issueLower);
6612
6711
  return stepOk(step, ["Stopped Docker containers"]);
6613
6712
  } catch {
6614
6713
  return stepSkipped(step, ["Docker cleanup skipped (not running or failed)"]);
@@ -6616,7 +6715,7 @@ async function stopDocker(workspacePath, projectName, issueLower) {
6616
6715
  }
6617
6716
  async function removeWorktree(projectPath, workspacePath) {
6618
6717
  const step = "teardown:worktree";
6619
- if (!existsSync27(workspacePath)) {
6718
+ if (!existsSync28(workspacePath)) {
6620
6719
  return stepSkipped(step, ["Workspace directory does not exist"]);
6621
6720
  }
6622
6721
  try {
@@ -6634,12 +6733,12 @@ async function removeWorktree(projectPath, workspacePath) {
6634
6733
  async function removeAgentState(issueLower) {
6635
6734
  const step = "teardown:agent-state";
6636
6735
  const dirs = [
6637
- join26(AGENTS_DIR, `agent-${issueLower}`),
6638
- join26(AGENTS_DIR, `planning-${issueLower}`)
6736
+ join27(AGENTS_DIR, `agent-${issueLower}`),
6737
+ join27(AGENTS_DIR, `planning-${issueLower}`)
6639
6738
  ];
6640
6739
  let removed = 0;
6641
6740
  for (const dir of dirs) {
6642
- if (existsSync27(dir)) {
6741
+ if (existsSync28(dir)) {
6643
6742
  rmSync3(dir, { recursive: true, force: true });
6644
6743
  removed++;
6645
6744
  }
@@ -6682,8 +6781,8 @@ async function clearShadowState(issueId) {
6682
6781
  }
6683
6782
  async function clearLegacyPlanningDir(projectPath, issueLower) {
6684
6783
  const step = "teardown:legacy-planning-dir";
6685
- const legacyDir = join26(projectPath, ".planning", issueLower);
6686
- if (existsSync27(legacyDir)) {
6784
+ const legacyDir = join27(projectPath, ".planning", issueLower);
6785
+ if (existsSync28(legacyDir)) {
6687
6786
  rmSync3(legacyDir, { recursive: true, force: true });
6688
6787
  return stepOk(step, [`Deleted legacy planning dir: ${legacyDir}`]);
6689
6788
  }
@@ -6691,8 +6790,8 @@ async function clearLegacyPlanningDir(projectPath, issueLower) {
6691
6790
  }
6692
6791
  async function clearPlanningMarker(workspacePath) {
6693
6792
  const step = "teardown:planning-marker";
6694
- const markerPath = join26(workspacePath, ".planning", ".planning-complete");
6695
- if (existsSync27(markerPath)) {
6793
+ const markerPath = join27(workspacePath, ".planning", ".planning-complete");
6794
+ if (existsSync28(markerPath)) {
6696
6795
  unlinkSync2(markerPath);
6697
6796
  return stepOk(step, ["Cleared .planning-complete marker"]);
6698
6797
  }
@@ -6743,7 +6842,7 @@ async function teardownWorkspace(ctx, opts = {}) {
6743
6842
  results.push(await killTmuxSessions(issueLower));
6744
6843
  results.push(await clearShadowState(ctx.issueId));
6745
6844
  results.push(await clearLegacyPlanningDir(ctx.projectPath, issueLower));
6746
- if (workspacePath && existsSync27(workspacePath)) {
6845
+ if (workspacePath && existsSync28(workspacePath)) {
6747
6846
  if (shouldDeleteWorkspace) {
6748
6847
  results.push(await stopTldrDaemon(workspacePath));
6749
6848
  }
@@ -6782,8 +6881,8 @@ var execAsync8 = promisify8(exec8);
6782
6881
  // src/lib/lifecycle/workflows.ts
6783
6882
  init_esm_shims();
6784
6883
  init_paths();
6785
- import { existsSync as existsSync28, readFileSync as readFileSync24 } from "fs";
6786
- import { join as join27 } from "path";
6884
+ import { existsSync as existsSync29, readFileSync as readFileSync25 } from "fs";
6885
+ import { join as join28 } from "path";
6787
6886
  import { exec as exec9 } from "child_process";
6788
6887
  import { promisify as promisify9 } from "util";
6789
6888
  var execAsync9 = promisify9(exec9);
@@ -6829,7 +6928,7 @@ async function verifyBranchMerged(ctx) {
6829
6928
  const branchName = `feature/${issueLower}`;
6830
6929
  try {
6831
6930
  try {
6832
- const { loadReviewStatuses: loadReviewStatuses3 } = await import("../review-status-EPFG4XM7.js");
6931
+ const { loadReviewStatuses: loadReviewStatuses3 } = await import("../review-status-TDPSOU5J.js");
6833
6932
  const statuses = loadReviewStatuses3();
6834
6933
  const issueKey = ctx.issueId.toUpperCase();
6835
6934
  if (statuses[issueKey]?.mergeStatus === "merged") {
@@ -6887,14 +6986,14 @@ async function verifyBranchMerged(ctx) {
6887
6986
  async function clearReviewStatusStep(issueId) {
6888
6987
  const step = "clear-review-status";
6889
6988
  try {
6890
- const { clearReviewStatus: clearReviewStatus2 } = await import("../review-status-EPFG4XM7.js");
6989
+ const { clearReviewStatus: clearReviewStatus2 } = await import("../review-status-TDPSOU5J.js");
6891
6990
  clearReviewStatus2(issueId.toUpperCase());
6892
6991
  return stepOk(step, ["Review status cleared"]);
6893
6992
  } catch {
6894
6993
  try {
6895
- const statusFile = join27(PANOPTICON_HOME, "review-status.json");
6896
- if (existsSync28(statusFile)) {
6897
- const data = JSON.parse(readFileSync24(statusFile, "utf-8"));
6994
+ const statusFile = join28(PANOPTICON_HOME, "review-status.json");
6995
+ if (existsSync29(statusFile)) {
6996
+ const data = JSON.parse(readFileSync25(statusFile, "utf-8"));
6898
6997
  const upperKey = issueId.toUpperCase();
6899
6998
  if (data[upperKey]) {
6900
6999
  delete data[upperKey];
@@ -6911,20 +7010,6 @@ async function clearReviewStatusStep(issueId) {
6911
7010
 
6912
7011
  // src/cli/commands/work/close-out.ts
6913
7012
  init_projects();
6914
- function getGitHubConfig2() {
6915
- const envFile = join28(homedir13(), ".panopticon.env");
6916
- if (!existsSync29(envFile)) return null;
6917
- const content = readFileSync25(envFile, "utf-8");
6918
- const reposMatch = content.match(/GITHUB_REPOS=(.+)/);
6919
- if (!reposMatch) return null;
6920
- const repoStr = reposMatch[1].trim();
6921
- const parts = repoStr.split(",")[0];
6922
- if (!parts) return null;
6923
- const [ownerRepo, prefix] = parts.split(":");
6924
- const [owner, repo] = ownerRepo.split("/");
6925
- if (!owner || !repo) return null;
6926
- return { owner, repo, prefix: prefix || repo.toUpperCase().replace(/-CLI$/, "").replace(/-/g, "") };
6927
- }
6928
7013
  async function closeOutCommand(issueId, options) {
6929
7014
  if (process.env.PANOPTICON_AGENT_ID) {
6930
7015
  console.error(chalk31.red("Close-out is a human-only operation. Agents cannot close out issues."));
@@ -6947,22 +7032,11 @@ async function closeOutCommand(issueId, options) {
6947
7032
  console.error(chalk31.red(`Could not resolve project for ${issueId}`));
6948
7033
  process.exit(1);
6949
7034
  }
6950
- const isGitHub = issueUpper.startsWith("PAN-");
6951
- let owner;
6952
- let repo;
6953
- let number;
6954
- if (isGitHub) {
6955
- const ghConfig = getGitHubConfig2();
6956
- if (ghConfig) {
6957
- owner = ghConfig.owner;
6958
- repo = ghConfig.repo;
6959
- number = parseInt(issueId.replace(/^PAN-/i, ""), 10);
6960
- } else {
6961
- owner = "eltmon";
6962
- repo = "panopticon-cli";
6963
- number = parseInt(issueId.replace(/^PAN-/i, ""), 10);
6964
- }
6965
- }
7035
+ const ghResolution = resolveGitHubIssue(issueId);
7036
+ const isGitHub = ghResolution.isGitHub;
7037
+ const owner = ghResolution.isGitHub ? ghResolution.owner : void 0;
7038
+ const repo = ghResolution.isGitHub ? ghResolution.repo : void 0;
7039
+ const number = ghResolution.isGitHub ? ghResolution.number : void 0;
6966
7040
  if (!options.force) {
6967
7041
  console.log(chalk31.yellow(`
6968
7042
  Close-out ceremony for ${issueUpper}
@@ -7262,6 +7336,10 @@ function createWorktree(repoPath, targetPath, branchName) {
7262
7336
  stdio: "pipe"
7263
7337
  });
7264
7338
  }
7339
+ try {
7340
+ execSync3("git config beads.role agent", { cwd: targetPath, stdio: "pipe" });
7341
+ } catch {
7342
+ }
7265
7343
  }
7266
7344
  function removeWorktree2(repoPath, worktreePath) {
7267
7345
  execSync3(`git worktree remove "${worktreePath}" --force`, {
@@ -11669,7 +11747,7 @@ async function runPatrol() {
11669
11747
  if (nextTask) {
11670
11748
  console.log(`[deacon] Auto-resuming suspended ${specialist.name} for queued task: ${nextTask.payload.issueId}`);
11671
11749
  try {
11672
- const { resumeAgent } = await import("../agents-E43Y3HNU.js");
11750
+ const { resumeAgent } = await import("../agents-5OPQKM5K.js");
11673
11751
  const message = `# Queued Work
11674
11752
 
11675
11753
  Processing queued task: ${nextTask.payload.issueId}`;
@@ -13604,7 +13682,7 @@ import { promisify as promisify18 } from "util";
13604
13682
  var execAsync18 = promisify18(exec18);
13605
13683
  async function listLogsCommand(project2, type, options) {
13606
13684
  try {
13607
- const { listRunLogs } = await import("../specialist-logs-KLGJCEUL.js");
13685
+ const { listRunLogs } = await import("../specialist-logs-XJB5TCKJ.js");
13608
13686
  const limit = options.limit ? parseInt(options.limit) : 10;
13609
13687
  const runs = listRunLogs(project2, type, { limit });
13610
13688
  if (options.json) {
@@ -13649,7 +13727,7 @@ View a specific run: pan specialists logs ${project2} ${type} <runId>
13649
13727
  }
13650
13728
  async function viewLogCommand(project2, type, runId, options) {
13651
13729
  try {
13652
- const { getRunLog, parseLogMetadata, getRunLogPath } = await import("../specialist-logs-KLGJCEUL.js");
13730
+ const { getRunLog, parseLogMetadata, getRunLogPath } = await import("../specialist-logs-XJB5TCKJ.js");
13653
13731
  const content = getRunLog(project2, type, runId);
13654
13732
  if (!content) {
13655
13733
  console.error(`\u274C Run log not found: ${runId}`);
@@ -13673,8 +13751,8 @@ async function viewLogCommand(project2, type, runId, options) {
13673
13751
  }
13674
13752
  async function tailLogCommand(project2, type) {
13675
13753
  try {
13676
- const { getRunLogPath } = await import("../specialist-logs-KLGJCEUL.js");
13677
- const { getProjectSpecialistMetadata } = await import("../specialists-O4HWDJL5.js");
13754
+ const { getRunLogPath } = await import("../specialist-logs-XJB5TCKJ.js");
13755
+ const { getProjectSpecialistMetadata } = await import("../specialists-5LBRHYFA.js");
13678
13756
  const metadata = getProjectSpecialistMetadata(project2, type);
13679
13757
  if (!metadata.currentRun) {
13680
13758
  console.error(`\u274C No active run for ${project2}/${type}`);
@@ -13743,7 +13821,7 @@ async function cleanupLogsCommand(projectOrAll, type, options) {
13743
13821
  console.log(" Use --force to confirm.");
13744
13822
  process.exit(1);
13745
13823
  }
13746
- const { cleanupAllLogs } = await import("../specialist-logs-KLGJCEUL.js");
13824
+ const { cleanupAllLogs } = await import("../specialist-logs-XJB5TCKJ.js");
13747
13825
  console.log("\u{1F9F9} Cleaning up old logs for all projects...\n");
13748
13826
  const results = cleanupAllLogs();
13749
13827
  console.log(`
@@ -13770,8 +13848,8 @@ async function cleanupLogsCommand(projectOrAll, type, options) {
13770
13848
  console.log(" Use --force to confirm.");
13771
13849
  process.exit(1);
13772
13850
  }
13773
- const { cleanupOldLogs } = await import("../specialist-logs-KLGJCEUL.js");
13774
- const { getSpecialistRetention } = await import("../projects-JEIVIYC6.js");
13851
+ const { cleanupOldLogs } = await import("../specialist-logs-XJB5TCKJ.js");
13852
+ const { getSpecialistRetention } = await import("../projects-CFX3RTDL.js");
13775
13853
  const retention = getSpecialistRetention(projectOrAll);
13776
13854
  console.log(`\u{1F9F9} Cleaning up old logs for ${projectOrAll}/${type}...`);
13777
13855
  console.log(` Retention: ${retention.max_days} days or ${retention.max_runs} runs
@@ -14528,6 +14606,11 @@ async function projectAddCommand(projectPath, options = {}) {
14528
14606
  }
14529
14607
  }
14530
14608
  const isPolyrepo = !hasRootGit && subRepos.length > 0;
14609
+ try {
14610
+ const { preTrustDirectory } = await import("../workspace-manager-E434Z45T.js");
14611
+ preTrustDirectory(fullPath);
14612
+ } catch {
14613
+ }
14531
14614
  let hooksInstalled = 0;
14532
14615
  if (hasRootGit) {
14533
14616
  hooksInstalled = installGitHooks(join48(fullPath, ".git"));
@@ -16469,7 +16552,7 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
16469
16552
  console.log(chalk61.bold("Starting Panopticon...\n"));
16470
16553
  if (traefikEnabled && !options.skipTraefik) {
16471
16554
  try {
16472
- const { generatePanopticonTraefikConfig: generatePanopticonTraefikConfig2, ensureProjectCerts: ensureProjectCerts2, generateTlsConfig: generateTlsConfig2, cleanupStaleTlsSections } = await import("../traefik-QN7R5I6V.js");
16555
+ const { generatePanopticonTraefikConfig: generatePanopticonTraefikConfig2, ensureProjectCerts: ensureProjectCerts2, generateTlsConfig: generateTlsConfig2, cleanupStaleTlsSections } = await import("../traefik-WFMQX2LY.js");
16473
16556
  cleanupStaleTlsSections();
16474
16557
  if (generatePanopticonTraefikConfig2()) {
16475
16558
  console.log(chalk61.dim(" Regenerated Traefik config from template"));