panopticon-cli 0.5.8 → 0.5.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.
Files changed (61) hide show
  1. package/README.md +29 -83
  2. package/dist/{agents-I6RAEGL5.js → agents-M2ZOZL3P.js} +8 -6
  3. package/dist/{chunk-UKSGE6RH.js → chunk-3KYTNMSE.js} +1 -2
  4. package/dist/{chunk-UKSGE6RH.js.map → chunk-3KYTNMSE.js.map} +1 -1
  5. package/dist/{chunk-M6ZVVKZ3.js → chunk-3WDSD2VK.js} +52 -38
  6. package/dist/chunk-3WDSD2VK.js.map +1 -0
  7. package/dist/{chunk-ZN5RHWGR.js → chunk-4R6ATXYI.js} +5 -5
  8. package/dist/{chunk-ZMJFEHGF.js → chunk-7ZB5D46Y.js} +2 -2
  9. package/dist/{chunk-ZMJFEHGF.js.map → chunk-7ZB5D46Y.js.map} +1 -1
  10. package/dist/{chunk-SUM2WVPF.js → chunk-GM22HPYS.js} +10 -10
  11. package/dist/{chunk-BYWVPPAZ.js → chunk-KPGVCGST.js} +25 -2
  12. package/dist/{chunk-BYWVPPAZ.js.map → chunk-KPGVCGST.js.map} +1 -1
  13. package/dist/{chunk-NYOGHGIW.js → chunk-QQ27EVBD.js} +10 -9
  14. package/dist/chunk-QQ27EVBD.js.map +1 -0
  15. package/dist/{chunk-IZIXJYXZ.js → chunk-TA5X4QYQ.js} +6 -2
  16. package/dist/{chunk-IZIXJYXZ.js.map → chunk-TA5X4QYQ.js.map} +1 -1
  17. package/dist/{chunk-43F4LDZ4.js → chunk-VVTAPQOI.js} +2 -2
  18. package/dist/{chunk-YAAT66RT.js → chunk-WP6ZLWU3.js} +28 -3
  19. package/dist/chunk-WP6ZLWU3.js.map +1 -0
  20. package/dist/cli/index.js +667 -279
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/dashboard/prompts/inspect-agent.md +157 -0
  23. package/dist/dashboard/prompts/uat-agent.md +215 -0
  24. package/dist/dashboard/prompts/work-agent.md +45 -5
  25. package/dist/dashboard/public/assets/{index-C7hJ5-o1.js → index-DqPey4Of.js} +62 -62
  26. package/dist/dashboard/public/index.html +2 -5
  27. package/dist/dashboard/server.js +2031 -1375
  28. package/dist/factory-KKT7324R.js +20 -0
  29. package/dist/{feedback-writer-T2WCT6EZ.js → feedback-writer-IPPIUPDX.js} +2 -2
  30. package/dist/feedback-writer-IPPIUPDX.js.map +1 -0
  31. package/dist/index.js +17 -17
  32. package/dist/{merge-agent-ZITLVF2B.js → merge-agent-756U4NPX.js} +10 -10
  33. package/dist/{projects-3CRF57ZU.js → projects-BPGM6IFB.js} +2 -2
  34. package/dist/{remote-workspace-M4IULGFZ.js → remote-workspace-LKRDGYEB.js} +2 -2
  35. package/dist/{review-status-J2YJGL3E.js → review-status-E77PZZWG.js} +2 -2
  36. package/dist/{specialist-context-W25PPWM4.js → specialist-context-UBVUUFJV.js} +5 -5
  37. package/dist/{specialist-logs-KPC45SZN.js → specialist-logs-FQRI3AIS.js} +5 -5
  38. package/dist/{specialists-H4LGYR7R.js → specialists-CXRGSJY3.js} +5 -5
  39. package/dist/{traefik-QXLZ4PO2.js → traefik-X2IWTUHO.js} +3 -3
  40. package/dist/{workspace-manager-G6TTBPC3.js → workspace-manager-OWHLR5BL.js} +2 -2
  41. package/dist/workspace-manager-OWHLR5BL.js.map +1 -0
  42. package/package.json +1 -1
  43. package/scripts/inspect-on-bead-close +73 -0
  44. package/scripts/stop-hook +17 -0
  45. package/dist/chunk-M6ZVVKZ3.js.map +0 -1
  46. package/dist/chunk-NYOGHGIW.js.map +0 -1
  47. package/dist/chunk-YAAT66RT.js.map +0 -1
  48. package/dist/feedback-writer-T2WCT6EZ.js.map +0 -1
  49. /package/dist/{agents-I6RAEGL5.js.map → agents-M2ZOZL3P.js.map} +0 -0
  50. /package/dist/{chunk-ZN5RHWGR.js.map → chunk-4R6ATXYI.js.map} +0 -0
  51. /package/dist/{chunk-SUM2WVPF.js.map → chunk-GM22HPYS.js.map} +0 -0
  52. /package/dist/{chunk-43F4LDZ4.js.map → chunk-VVTAPQOI.js.map} +0 -0
  53. /package/dist/{projects-3CRF57ZU.js.map → factory-KKT7324R.js.map} +0 -0
  54. /package/dist/{merge-agent-ZITLVF2B.js.map → merge-agent-756U4NPX.js.map} +0 -0
  55. /package/dist/{review-status-J2YJGL3E.js.map → projects-BPGM6IFB.js.map} +0 -0
  56. /package/dist/{remote-workspace-M4IULGFZ.js.map → remote-workspace-LKRDGYEB.js.map} +0 -0
  57. /package/dist/{specialist-logs-KPC45SZN.js.map → review-status-E77PZZWG.js.map} +0 -0
  58. /package/dist/{specialist-context-W25PPWM4.js.map → specialist-context-UBVUUFJV.js.map} +0 -0
  59. /package/dist/{specialists-H4LGYR7R.js.map → specialist-logs-FQRI3AIS.js.map} +0 -0
  60. /package/dist/{traefik-QXLZ4PO2.js.map → specialists-CXRGSJY3.js.map} +0 -0
  61. /package/dist/{workspace-manager-G6TTBPC3.js.map → traefik-X2IWTUHO.js.map} +0 -0
package/dist/cli/index.js CHANGED
@@ -1,15 +1,28 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ closeIssue
4
+ } from "../chunk-OJF4QS3S.js";
2
5
  import "../chunk-MJXYTGK5.js";
3
6
  import {
4
7
  cleanupTemplateFiles,
5
8
  ensureProjectCerts,
6
9
  generatePanopticonTraefikConfig,
7
10
  generateTlsConfig
8
- } from "../chunk-43F4LDZ4.js";
11
+ } from "../chunk-VVTAPQOI.js";
9
12
  import {
10
13
  isGitHubIssue,
11
- resolveGitHubIssue
12
- } from "../chunk-YAAT66RT.js";
14
+ resolveGitHubIssue,
15
+ resolveTrackerType
16
+ } from "../chunk-WP6ZLWU3.js";
17
+ import {
18
+ WORKSPACES_DIR,
19
+ createFlyProviderFromConfig,
20
+ deleteWorkspaceMetadata,
21
+ findRemoteWorkspaceMetadata,
22
+ isRemoteAvailable,
23
+ loadWorkspaceMetadata,
24
+ saveWorkspaceMetadata
25
+ } from "../chunk-HHL3AWXA.js";
13
26
  import {
14
27
  closeDatabase,
15
28
  getDatabase,
@@ -18,7 +31,7 @@ import {
18
31
  loadReviewStatuses,
19
32
  saveReviewStatuses,
20
33
  setReviewStatus
21
- } from "../chunk-IZIXJYXZ.js";
34
+ } from "../chunk-TA5X4QYQ.js";
22
35
  import {
23
36
  checkBudget,
24
37
  checkSpecialistQueue,
@@ -48,23 +61,26 @@ import {
48
61
  readTodayCosts,
49
62
  recordWake,
50
63
  setSessionId,
64
+ spawnEphemeralSpecialist,
51
65
  summarizeCosts,
52
66
  wakeSpecialistOrQueue
53
- } from "../chunk-M6ZVVKZ3.js";
67
+ } from "../chunk-3WDSD2VK.js";
54
68
  import "../chunk-JQBV3Q2W.js";
55
69
  import {
56
70
  archivePlanning,
57
71
  findWorkspacePath
58
72
  } from "../chunk-6OYUJ4AJ.js";
59
73
  import "../chunk-WEQW3EAT.js";
60
- import {
61
- closeIssue
62
- } from "../chunk-OJF4QS3S.js";
63
74
  import {
64
75
  stepFailed,
65
76
  stepOk,
66
77
  stepSkipped
67
78
  } from "../chunk-R4KPLLRB.js";
79
+ import {
80
+ getTldrDaemonService,
81
+ getTldrMetrics,
82
+ init_tldr_daemon
83
+ } from "../chunk-DI7ABPNQ.js";
68
84
  import {
69
85
  applyProjectTemplateOverlay,
70
86
  createWorkspace,
@@ -72,7 +88,7 @@ import {
72
88
  init_workspace_manager,
73
89
  mergeSkillsIntoWorkspace,
74
90
  removeWorkspace
75
- } from "../chunk-BYWVPPAZ.js";
91
+ } from "../chunk-KPGVCGST.js";
76
92
  import {
77
93
  detectDnsSyncMethod,
78
94
  detectPlatform,
@@ -87,6 +103,11 @@ import {
87
103
  init_workspace_config,
88
104
  replacePlaceholders
89
105
  } from "../chunk-AAP4G6U7.js";
106
+ import {
107
+ createFlyProvider,
108
+ isRemoteAgentRunning,
109
+ spawnRemoteAgent
110
+ } from "../chunk-GUV2EPBG.js";
90
111
  import {
91
112
  autoRecoverAgents,
92
113
  detectCrashedAgents,
@@ -109,7 +130,7 @@ import {
109
130
  saveSessionId,
110
131
  spawnAgent,
111
132
  stopAgent
112
- } from "../chunk-NYOGHGIW.js";
133
+ } from "../chunk-QQ27EVBD.js";
113
134
  import {
114
135
  checkHook,
115
136
  clearHook,
@@ -120,7 +141,7 @@ import {
120
141
  popFromHook,
121
142
  pushToHook,
122
143
  sendMail
123
- } from "../chunk-ZN5RHWGR.js";
144
+ } from "../chunk-4R6ATXYI.js";
124
145
  import {
125
146
  createShadowState,
126
147
  getPendingSyncCount,
@@ -133,20 +154,6 @@ import {
133
154
  updateShadowState,
134
155
  updateTrackerStatusCache
135
156
  } from "../chunk-B3PF6JPQ.js";
136
- import {
137
- WORKSPACES_DIR,
138
- createFlyProviderFromConfig,
139
- deleteWorkspaceMetadata,
140
- findRemoteWorkspaceMetadata,
141
- isRemoteAvailable,
142
- loadWorkspaceMetadata,
143
- saveWorkspaceMetadata
144
- } from "../chunk-HHL3AWXA.js";
145
- import {
146
- createFlyProvider,
147
- isRemoteAgentRunning,
148
- spawnRemoteAgent
149
- } from "../chunk-GUV2EPBG.js";
150
157
  import {
151
158
  addAlias,
152
159
  cleanOldBackups,
@@ -163,13 +170,8 @@ import {
163
170
  restoreBackup,
164
171
  syncHooks,
165
172
  syncStatusline
166
- } from "../chunk-SUM2WVPF.js";
173
+ } from "../chunk-GM22HPYS.js";
167
174
  import "../chunk-AQXETQHW.js";
168
- import {
169
- createTracker,
170
- createTrackerFromConfig,
171
- init_factory
172
- } from "../chunk-UKSGE6RH.js";
173
175
  import {
174
176
  init_settings,
175
177
  loadSettings
@@ -195,7 +197,7 @@ import {
195
197
  registerProject,
196
198
  resolveProjectFromIssue,
197
199
  unregisterProject
198
- } from "../chunk-ZMJFEHGF.js";
200
+ } from "../chunk-7ZB5D46Y.js";
199
201
  import {
200
202
  createSession,
201
203
  init_tmux,
@@ -204,19 +206,6 @@ import {
204
206
  sendKeysAsync,
205
207
  sessionExists
206
208
  } from "../chunk-W2OTF6OS.js";
207
- import {
208
- init_config_yaml,
209
- loadConfig as loadConfig2
210
- } from "../chunk-ZP6EWSZV.js";
211
- import {
212
- NotImplementedError,
213
- init_interface
214
- } from "../chunk-DMRTN432.js";
215
- import {
216
- getTldrDaemonService,
217
- getTldrMetrics,
218
- init_tldr_daemon
219
- } from "../chunk-DI7ABPNQ.js";
220
209
  import {
221
210
  AGENTS_DIR,
222
211
  CERTS_DIR,
@@ -238,6 +227,19 @@ import {
238
227
  init_paths,
239
228
  isDevMode
240
229
  } from "../chunk-ZTFNYOC7.js";
230
+ import {
231
+ createTracker,
232
+ createTrackerFromConfig,
233
+ init_factory
234
+ } from "../chunk-3KYTNMSE.js";
235
+ import {
236
+ init_config_yaml,
237
+ loadConfig as loadConfig2
238
+ } from "../chunk-ZP6EWSZV.js";
239
+ import {
240
+ NotImplementedError,
241
+ init_interface
242
+ } from "../chunk-DMRTN432.js";
241
243
  import {
242
244
  __require,
243
245
  init_esm_shims
@@ -245,11 +247,11 @@ import {
245
247
 
246
248
  // src/cli/index.ts
247
249
  init_esm_shims();
248
- import { readFileSync as readFileSync45, existsSync as existsSync51 } from "fs";
249
- import { join as join51 } from "path";
250
- import { homedir as homedir23 } from "os";
250
+ import { readFileSync as readFileSync47, existsSync as existsSync53 } from "fs";
251
+ import { join as join53 } from "path";
252
+ import { homedir as homedir24 } from "os";
251
253
  import { Command as Command2 } from "commander";
252
- import chalk62 from "chalk";
254
+ import chalk63 from "chalk";
253
255
 
254
256
  // src/cli/commands/init.ts
255
257
  init_esm_shims();
@@ -1562,7 +1564,7 @@ async function handleRemoteWorkspace(issueId, options, spinner) {
1562
1564
  if (!remoteMetadata) {
1563
1565
  spinner.text = "Remote workspace not found, creating...";
1564
1566
  try {
1565
- const { createRemoteWorkspace: createRemoteWorkspace2 } = await import("../remote-workspace-M4IULGFZ.js");
1567
+ const { createRemoteWorkspace: createRemoteWorkspace2 } = await import("../remote-workspace-LKRDGYEB.js");
1566
1568
  remoteMetadata = await createRemoteWorkspace2(issueId, { spinner });
1567
1569
  } catch (error) {
1568
1570
  spinner.fail(`Failed to create remote workspace: ${error.message}`);
@@ -1685,7 +1687,19 @@ function findProjectRoot(issueId, labels = []) {
1685
1687
  return process.cwd();
1686
1688
  }
1687
1689
  function hasBeadsTasks(workspacePath) {
1688
- return existsSync8(join8(workspacePath, ".beads", "issues.jsonl"));
1690
+ try {
1691
+ const { execSync: execSync10 } = __require("child_process");
1692
+ const output = execSync10("bd list --json --limit 1", {
1693
+ cwd: workspacePath,
1694
+ encoding: "utf-8",
1695
+ timeout: 1e4,
1696
+ stdio: ["pipe", "pipe", "pipe"]
1697
+ });
1698
+ const tasks = JSON.parse(output.trim() || "[]");
1699
+ return tasks.length > 0;
1700
+ } catch {
1701
+ return existsSync8(join8(workspacePath, ".beads"));
1702
+ }
1689
1703
  }
1690
1704
  function validateAndCleanStateFile(workspacePath, issueId) {
1691
1705
  const statePath = join8(workspacePath, ".planning", "STATE.md");
@@ -1742,8 +1756,8 @@ async function issueCommand(id, options) {
1742
1756
  process.exit(1);
1743
1757
  }
1744
1758
  try {
1745
- const { execSync: execSync9 } = await import("child_process");
1746
- const branch = execSync9("git branch --show-current", {
1759
+ const { execSync: execSync10 } = await import("child_process");
1760
+ const branch = execSync10("git branch --show-current", {
1747
1761
  cwd: workspace,
1748
1762
  encoding: "utf8"
1749
1763
  }).trim();
@@ -1788,14 +1802,31 @@ async function issueCommand(id, options) {
1788
1802
  spinner.warn(`Cleaned stale planning state from ${stateValidation.wrongIssue}`);
1789
1803
  }
1790
1804
  if (!hasBeadsTasks(workspace)) {
1791
- spinner.fail(`No beads tasks found for ${id}`);
1792
- console.log("");
1793
- console.log(chalk6.red(`Planning must create a task breakdown before work begins.`));
1794
- console.log(chalk6.dim(`Run planning again and ensure it creates beads with "bd create".`));
1795
- console.log("");
1796
- console.log(chalk6.bold("To re-run planning:"));
1797
- console.log(` ${chalk6.cyan(`pan work plan ${id}`)}`);
1798
- process.exit(1);
1805
+ const hasPlanningDir = existsSync8(join8(workspace, ".planning"));
1806
+ if (!hasPlanningDir) {
1807
+ spinner.text = `Auto-creating bead for simple issue ${id}...`;
1808
+ try {
1809
+ const { execSync: execSync10 } = __require("child_process");
1810
+ execSync10(`bd create "${id}: Implement issue" --type task -l "${id.toLowerCase()},difficulty:simple"`, {
1811
+ cwd: workspace,
1812
+ encoding: "utf-8",
1813
+ timeout: 1e4,
1814
+ stdio: ["pipe", "pipe", "pipe"]
1815
+ });
1816
+ } catch (bdErr) {
1817
+ spinner.fail(`No beads tasks found for ${id} and auto-create failed`);
1818
+ process.exit(1);
1819
+ }
1820
+ } else {
1821
+ spinner.fail(`No beads tasks found for ${id}`);
1822
+ console.log("");
1823
+ console.log(chalk6.red(`Planning must create a task breakdown before work begins.`));
1824
+ console.log(chalk6.dim(`Run planning again and ensure it creates beads with "bd create".`));
1825
+ console.log("");
1826
+ console.log(chalk6.bold("To re-run planning:"));
1827
+ console.log(` ${chalk6.cyan(`pan work plan ${id}`)}`);
1828
+ process.exit(1);
1829
+ }
1799
1830
  }
1800
1831
  spinner.text = "Building agent prompt with planning context...";
1801
1832
  const trackerContext = await getTrackerContext(id, workspace);
@@ -2201,15 +2232,14 @@ async function updateLinearStatus(apiKey, issueIdentifier) {
2201
2232
  try {
2202
2233
  const { LinearClient: LinearClient2 } = await import("@linear/sdk");
2203
2234
  const client = new LinearClient2({ apiKey });
2204
- const me = await client.viewer;
2205
- const teams = await me.teams();
2206
- const team = teams.nodes[0];
2207
- if (!team) return false;
2208
- const issues = await team.issues({ first: 100 });
2209
- const issue = issues.nodes.find(
2235
+ const searchResults = await client.searchIssues(issueIdentifier, { first: 1 });
2236
+ const searchHit = searchResults.nodes.find(
2210
2237
  (i) => i.identifier.toUpperCase() === issueIdentifier.toUpperCase()
2211
2238
  );
2212
- if (!issue) return false;
2239
+ if (!searchHit) return false;
2240
+ const issue = await client.issue(searchHit.id);
2241
+ const team = await issue.team;
2242
+ if (!team) return false;
2213
2243
  const states = await team.states();
2214
2244
  const doneState = states.nodes.find((s) => s.type === "completed" && s.name === "Done");
2215
2245
  if (!doneState) return false;
@@ -2468,15 +2498,14 @@ async function updateLinearToInReview(apiKey, issueIdentifier, comment) {
2468
2498
  try {
2469
2499
  const { LinearClient: LinearClient2 } = await import("@linear/sdk");
2470
2500
  const client = new LinearClient2({ apiKey });
2471
- const me = await client.viewer;
2472
- const teams = await me.teams();
2473
- const team = teams.nodes[0];
2474
- if (!team) return false;
2475
- const issues = await team.issues({ first: 100 });
2476
- const issue = issues.nodes.find(
2501
+ const searchResults = await client.searchIssues(issueIdentifier, { first: 1 });
2502
+ const searchHit = searchResults.nodes.find(
2477
2503
  (i) => i.identifier.toUpperCase() === issueIdentifier.toUpperCase()
2478
2504
  );
2479
- if (!issue) return false;
2505
+ if (!searchHit) return false;
2506
+ const issue = await client.issue(searchHit.id);
2507
+ const team = await issue.team;
2508
+ if (!team) return false;
2480
2509
  const states = await team.states();
2481
2510
  const targetStateName = getLinearStateName("in_review");
2482
2511
  const targetState = findLinearStateByName(states.nodes, targetStateName);
@@ -2558,13 +2587,16 @@ async function doneCommand(id, options = {}) {
2558
2587
  const issueId = id.replace(/^agent-/i, "").toUpperCase();
2559
2588
  const agentId = `agent-${issueId.toLowerCase()}`;
2560
2589
  if (!options.force) {
2561
- const { getAgentState: getAgentState2 } = await import("../agents-I6RAEGL5.js");
2590
+ const { getAgentState: getAgentState2 } = await import("../agents-M2ZOZL3P.js");
2562
2591
  const agentState = getAgentState2(agentId);
2563
2592
  const workspacePath = agentState?.workspace;
2564
2593
  if (workspacePath && existsSync12(workspacePath)) {
2565
2594
  const failures = [];
2566
2595
  try {
2567
- const { stdout } = await execAsync("bd list --status open --limit 0 --json", { cwd: workspacePath });
2596
+ const { stdout } = await execAsync(
2597
+ `bd list --status open -l "${issueId.toLowerCase()}" --limit 0 --json`,
2598
+ { cwd: workspacePath }
2599
+ );
2568
2600
  const beads = JSON.parse(stdout);
2569
2601
  if (Array.isArray(beads) && beads.length > 0) {
2570
2602
  failures.push(` Open beads (${beads.length}):`);
@@ -2657,7 +2689,7 @@ async function doneCommand(id, options = {}) {
2657
2689
  console.log(chalk12.dim(" LINEAR_API_KEY not set - skipping status update"));
2658
2690
  }
2659
2691
  }
2660
- const { getAgentState: getAgentState2, saveAgentState: saveAgentState2 } = await import("../agents-I6RAEGL5.js");
2692
+ const { getAgentState: getAgentState2, saveAgentState: saveAgentState2 } = await import("../agents-M2ZOZL3P.js");
2661
2693
  const existingState = getAgentState2(agentId);
2662
2694
  if (existingState) {
2663
2695
  existingState.status = "stopped";
@@ -3275,9 +3307,10 @@ async function runDiscoveryPhase(issue, complexity, prdContent) {
3275
3307
  async function planCommand(id, options = {}) {
3276
3308
  const spinner = ora7(`Creating execution plan for ${id}...`).start();
3277
3309
  try {
3310
+ const trackerType = resolveTrackerType(id);
3278
3311
  const ghResolution = resolveGitHubIssue(id);
3279
3312
  let issueData;
3280
- if (ghResolution.isGitHub) {
3313
+ if (trackerType === "github" && ghResolution.isGitHub) {
3281
3314
  spinner.text = "Fetching issue from GitHub...";
3282
3315
  const { loadConfig: loadYamlConfig } = await import("../config-yaml-OVZLKFMA.js");
3283
3316
  const yamlConfig = loadYamlConfig();
@@ -3304,6 +3337,33 @@ async function planCommand(id, options = {}) {
3304
3337
  labels: (ghIssue.labels || []).map((l) => ({ name: typeof l === "string" ? l : l.name || "" })),
3305
3338
  assignee: ghIssue.assignee ? { name: ghIssue.assignee.login } : void 0
3306
3339
  };
3340
+ } else if (trackerType === "rally") {
3341
+ spinner.text = "Fetching issue from Rally...";
3342
+ const { createTracker: createTracker2 } = await import("../factory-KKT7324R.js");
3343
+ const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-BPGM6IFB.js");
3344
+ const project2 = resolveProjectFromIssue2(id);
3345
+ const rallyProject = project2 ? (await import("../projects-BPGM6IFB.js")).getProject(project2.projectKey)?.rally_project : void 0;
3346
+ try {
3347
+ const tracker = createTracker2({
3348
+ type: "rally",
3349
+ project: rallyProject || void 0
3350
+ });
3351
+ const rallyIssue = await tracker.getIssue(id);
3352
+ issueData = {
3353
+ id: rallyIssue.id,
3354
+ identifier: rallyIssue.ref,
3355
+ title: rallyIssue.title,
3356
+ description: rallyIssue.description || void 0,
3357
+ url: rallyIssue.url,
3358
+ state: { name: rallyIssue.state === "open" ? "Todo" : rallyIssue.state === "closed" ? "Done" : "In Progress" },
3359
+ priority: rallyIssue.priority || 0,
3360
+ labels: rallyIssue.labels.map((l) => ({ name: l })),
3361
+ assignee: rallyIssue.assignee ? { name: rallyIssue.assignee } : void 0
3362
+ };
3363
+ } catch (err) {
3364
+ spinner.fail(`Rally error: ${err.message}`);
3365
+ process.exit(1);
3366
+ }
3307
3367
  } else {
3308
3368
  const apiKey = getLinearApiKey4();
3309
3369
  if (!apiKey) {
@@ -5202,7 +5262,7 @@ Previous state: ${issue.state}`
5202
5262
  console.log(chalk21.green(`\u2713 ${issue.identifier} reopened and ready for re-work`));
5203
5263
  console.log("");
5204
5264
  try {
5205
- const { getAgentState: getAgentState2 } = await import("../agents-I6RAEGL5.js");
5265
+ const { getAgentState: getAgentState2 } = await import("../agents-M2ZOZL3P.js");
5206
5266
  const agentId = `agent-${id.toLowerCase()}`;
5207
5267
  const agentState = getAgentState2(agentId);
5208
5268
  const agentRunning = agentState?.status === "running" || agentState?.status === "starting";
@@ -5621,21 +5681,20 @@ async function syncToLinear(apiKey, issueId, targetState) {
5621
5681
  try {
5622
5682
  const { LinearClient: LinearClient2 } = await import("@linear/sdk");
5623
5683
  const client = new LinearClient2({ apiKey });
5624
- const me = await client.viewer;
5625
- const teams = await me.teams();
5626
- const team = teams.nodes[0];
5627
- if (!team) {
5628
- return { success: false, error: "No Linear team found" };
5629
- }
5630
- const issues = await team.issues({ first: 100 });
5631
- const issue = issues.nodes.find(
5684
+ const searchResults = await client.searchIssues(issueId, { first: 1 });
5685
+ const searchHit = searchResults.nodes.find(
5632
5686
  (i) => i.identifier.toUpperCase() === issueId.toUpperCase()
5633
5687
  );
5634
- if (!issue) {
5688
+ if (!searchHit) {
5635
5689
  return { success: false, error: `Issue ${issueId} not found in Linear` };
5636
5690
  }
5691
+ const issue = await client.issue(searchHit.id);
5637
5692
  const currentState = await issue.state;
5638
5693
  const previousState = currentState?.type === "completed" ? "closed" : currentState?.type === "started" ? "in_progress" : "open";
5694
+ const team = await issue.team;
5695
+ if (!team) {
5696
+ return { success: false, error: "Could not resolve team from issue" };
5697
+ }
5639
5698
  const states = await team.states();
5640
5699
  let targetLinearState = null;
5641
5700
  switch (targetState) {
@@ -6308,7 +6367,7 @@ async function stopTldrDaemon(workspacePath) {
6308
6367
  async function stopDocker(workspacePath, projectName, issueLower) {
6309
6368
  const step = "teardown:docker";
6310
6369
  try {
6311
- const { stopWorkspaceDocker } = await import("../workspace-manager-G6TTBPC3.js");
6370
+ const { stopWorkspaceDocker } = await import("../workspace-manager-OWHLR5BL.js");
6312
6371
  await stopWorkspaceDocker(workspacePath, projectName, issueLower);
6313
6372
  return stepOk(step, ["Stopped Docker containers"]);
6314
6373
  } catch {
@@ -6524,7 +6583,7 @@ async function verifyBranchMerged(ctx) {
6524
6583
  const branchName = `feature/${issueLower}`;
6525
6584
  try {
6526
6585
  try {
6527
- const { loadReviewStatuses: loadReviewStatuses2 } = await import("../review-status-J2YJGL3E.js");
6586
+ const { loadReviewStatuses: loadReviewStatuses2 } = await import("../review-status-E77PZZWG.js");
6528
6587
  const statuses = loadReviewStatuses2();
6529
6588
  const issueKey = ctx.issueId.toUpperCase();
6530
6589
  if (statuses[issueKey]?.mergeStatus === "merged") {
@@ -6582,7 +6641,7 @@ async function verifyBranchMerged(ctx) {
6582
6641
  async function clearReviewStatusStep(issueId) {
6583
6642
  const step = "clear-review-status";
6584
6643
  try {
6585
- const { clearReviewStatus: clearReviewStatus2 } = await import("../review-status-J2YJGL3E.js");
6644
+ const { clearReviewStatus: clearReviewStatus2 } = await import("../review-status-E77PZZWG.js");
6586
6645
  clearReviewStatus2(issueId.toUpperCase());
6587
6646
  return stepOk(step, ["Review status cleared"]);
6588
6647
  } catch {
@@ -6593,8 +6652,8 @@ async function clearReviewStatusStep(issueId) {
6593
6652
  const upperKey = issueId.toUpperCase();
6594
6653
  if (data[upperKey]) {
6595
6654
  delete data[upperKey];
6596
- const { writeFileSync: writeFileSync26 } = await import("fs");
6597
- writeFileSync26(statusFile, JSON.stringify(data, null, 2));
6655
+ const { writeFileSync: writeFileSync27 } = await import("fs");
6656
+ writeFileSync27(statusFile, JSON.stringify(data, null, 2));
6598
6657
  }
6599
6658
  }
6600
6659
  return stepOk(step, ["Review status cleared (direct)"]);
@@ -9695,7 +9754,7 @@ async function performHandoff(agentId, options) {
9695
9754
  }
9696
9755
  }
9697
9756
  function detectHandoffMethod(agentId) {
9698
- const specialists = ["merge-agent", "review-agent", "test-agent"];
9757
+ const specialists = ["merge-agent", "review-agent", "test-agent", "inspect-agent", "uat-agent"];
9699
9758
  if (specialists.some((s) => agentId.includes(s))) {
9700
9759
  return "specialist-wake";
9701
9760
  }
@@ -9809,7 +9868,7 @@ async function waitForIdle(agentId, timeoutMs) {
9809
9868
  return false;
9810
9869
  }
9811
9870
  function extractSpecialistName(agentId) {
9812
- const specialists = ["merge-agent", "review-agent", "test-agent"];
9871
+ const specialists = ["merge-agent", "review-agent", "test-agent", "inspect-agent", "uat-agent"];
9813
9872
  for (const specialist of specialists) {
9814
9873
  if (agentId.includes(specialist.replace("-agent", ""))) {
9815
9874
  return specialist;
@@ -10883,11 +10942,11 @@ async function checkOrphanedReviewStatuses() {
10883
10942
  const workspace = agentState?.workspace;
10884
10943
  if (workspace) {
10885
10944
  const branch = `feature/${issueId.toLowerCase()}`;
10886
- const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-3CRF57ZU.js");
10945
+ const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-BPGM6IFB.js");
10887
10946
  const resolved = resolveProjectFromIssue2(issueId);
10888
10947
  if (resolved) {
10889
- const { spawnEphemeralSpecialist } = await import("../specialists-H4LGYR7R.js");
10890
- const result = await spawnEphemeralSpecialist(resolved.projectKey, "test-agent", {
10948
+ const { spawnEphemeralSpecialist: spawnEphemeralSpecialist2 } = await import("../specialists-CXRGSJY3.js");
10949
+ const result = await spawnEphemeralSpecialist2(resolved.projectKey, "test-agent", {
10891
10950
  issueId,
10892
10951
  workspace,
10893
10952
  branch
@@ -11214,6 +11273,68 @@ async function patrolWorkAgentResolutions() {
11214
11273
  }
11215
11274
  return actions;
11216
11275
  }
11276
+ async function checkSpecialistQueues() {
11277
+ const actions = [];
11278
+ try {
11279
+ const {
11280
+ checkSpecialistQueue: checkSpecialistQueue2,
11281
+ spawnEphemeralSpecialist: spawnEphemeralSpecialist2,
11282
+ getTmuxSessionName: getTmuxSessionName2,
11283
+ isRunning: isRunning3
11284
+ } = await import("../specialists-CXRGSJY3.js");
11285
+ const { getAgentRuntimeState: getAgentRuntimeState2 } = await import("../agents-M2ZOZL3P.js");
11286
+ const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-BPGM6IFB.js");
11287
+ const specialistTypes = ["review-agent", "test-agent", "inspect-agent", "uat-agent"];
11288
+ for (const specialistType of specialistTypes) {
11289
+ const queue = checkSpecialistQueue2(specialistType);
11290
+ if (!queue.hasWork) continue;
11291
+ const item = queue.items[0];
11292
+ const issueId = item.payload?.issueId || "";
11293
+ console.log(`[deacon] Queue check: ${specialistType} has ${queue.items.length} items, first issue: ${issueId || "none"}`);
11294
+ if (!issueId) continue;
11295
+ const resolved = resolveProjectFromIssue2(issueId);
11296
+ if (!resolved) continue;
11297
+ const tmuxSession = getTmuxSessionName2(specialistType, resolved.projectKey);
11298
+ const running = await isRunning3(specialistType, resolved.projectKey);
11299
+ const state = getAgentRuntimeState2(tmuxSession);
11300
+ let isIdle = state?.state === "idle" || state?.state === "suspended" || !running;
11301
+ if (!isIdle && running && state?.lastActivity) {
11302
+ const lastActivityAge = Date.now() - new Date(state.lastActivity).getTime();
11303
+ const tenMinutes = 10 * 60 * 1e3;
11304
+ if (lastActivityAge > tenMinutes) {
11305
+ console.log(`[deacon] Stale specialist detected: ${tmuxSession} (last activity: ${Math.round(lastActivityAge / 6e4)}m ago) \u2014 killing and treating as idle`);
11306
+ try {
11307
+ const { exec: exec22 } = await import("child_process");
11308
+ const { promisify: promisify22 } = await import("util");
11309
+ const execAsync22 = promisify22(exec22);
11310
+ await execAsync22(`tmux kill-session -t "${tmuxSession}"`, { encoding: "utf-8" }).catch(() => {
11311
+ });
11312
+ } catch {
11313
+ }
11314
+ isIdle = true;
11315
+ }
11316
+ }
11317
+ if (!isIdle) continue;
11318
+ console.log(`[deacon] Dispatching queued ${specialistType} work for ${issueId} (project: ${resolved.projectKey})`);
11319
+ try {
11320
+ const { findWorkspacePath: findWorkspacePath3 } = await import("../archive-planning-U3AZAKWI.js");
11321
+ const workspacePath = findWorkspacePath3(resolved.projectPath, issueId.toLowerCase());
11322
+ const queuePayload = item.payload;
11323
+ await spawnEphemeralSpecialist2(resolved.projectKey, specialistType, {
11324
+ issueId,
11325
+ workspace: workspacePath || queuePayload.workspace || void 0,
11326
+ branch: queuePayload.branch
11327
+ });
11328
+ actions.push(`Dispatched queued ${specialistType} for ${issueId}`);
11329
+ } catch (err) {
11330
+ console.error(`[deacon] Failed to dispatch ${specialistType} for ${issueId}:`, err.message);
11331
+ }
11332
+ }
11333
+ } catch (err) {
11334
+ console.error("[deacon] checkSpecialistQueues error:", err.message);
11335
+ }
11336
+ return actions;
11337
+ }
11217
11338
  async function runPatrol() {
11218
11339
  const state = loadState();
11219
11340
  state.patrolCycle++;
@@ -11228,6 +11349,9 @@ async function runPatrol() {
11228
11349
  const orphanActions = await checkOrphanedReviewStatuses();
11229
11350
  actions.push(...orphanActions);
11230
11351
  for (const a of orphanActions) addLog("action", a, state.patrolCycle);
11352
+ const queueActions = await checkSpecialistQueues();
11353
+ actions.push(...queueActions);
11354
+ for (const a of queueActions) addLog("action", a, state.patrolCycle);
11231
11355
  const deadEndActions = await checkDeadEndAgents();
11232
11356
  actions.push(...deadEndActions);
11233
11357
  for (const a of deadEndActions) addLog("action", a, state.patrolCycle);
@@ -11275,7 +11399,7 @@ async function runPatrol() {
11275
11399
  const statuses = JSON.parse(readFileSync34(REVIEW_STATUS_FILE, "utf-8"));
11276
11400
  const rs = statuses[issueId];
11277
11401
  if (rs?.mergeStatus === "merging") {
11278
- const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-3CRF57ZU.js");
11402
+ const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-BPGM6IFB.js");
11279
11403
  const resolved = resolveProjectFromIssue2(issueId);
11280
11404
  if (resolved) {
11281
11405
  const branch = `feature/${issueId.toLowerCase()}`;
@@ -11288,7 +11412,7 @@ async function runPatrol() {
11288
11412
  statuses[issueId].mergeStatus = "merged";
11289
11413
  statuses[issueId].readyForMerge = false;
11290
11414
  writeFileSync19(REVIEW_STATUS_FILE, JSON.stringify(statuses, null, 2), "utf-8");
11291
- const { postMergeLifecycle } = await import("../merge-agent-ZITLVF2B.js");
11415
+ const { postMergeLifecycle } = await import("../merge-agent-756U4NPX.js");
11292
11416
  postMergeLifecycle(issueId, resolved.projectPath).catch(
11293
11417
  (err) => console.warn(`[deacon] postMergeLifecycle failed for ${issueId}: ${err}`)
11294
11418
  );
@@ -11642,6 +11766,17 @@ var CloisterService = class {
11642
11766
  const retryCount = this.processedCompletions.get(dir.name) || 0;
11643
11767
  if (retryCount >= 3) continue;
11644
11768
  const issueId = dir.name.replace("agent-", "").toUpperCase();
11769
+ const { getReviewStatus: getReviewStatus3 } = await import("../review-status-E77PZZWG.js");
11770
+ const existingReview = getReviewStatus3(issueId);
11771
+ if (existingReview && ["reviewing", "passed"].includes(existingReview.reviewStatus || "")) {
11772
+ console.log(`\u{1F514} Cloister: Completion marker for ${issueId} \u2014 review already ${existingReview.reviewStatus}, marking processed`);
11773
+ try {
11774
+ renameSync3(completedFile, processedFile);
11775
+ } catch {
11776
+ }
11777
+ this.processedCompletions.set(dir.name, Infinity);
11778
+ continue;
11779
+ }
11645
11780
  console.log(`\u{1F514} Cloister: Found completion marker for ${issueId}, triggering review...${retryCount > 0 ? ` (retry ${retryCount}/3)` : ""}`);
11646
11781
  try {
11647
11782
  const http = await import("http");
@@ -11994,6 +12129,11 @@ var CloisterService = class {
11994
12129
  );
11995
12130
  if (triggers.length > 0) {
11996
12131
  const trigger = triggers[0];
12132
+ const specialistNames = ["review-agent", "test-agent", "merge-agent", "inspect-agent", "uat-agent"];
12133
+ if (trigger.type === "task_complete" && specialistNames.includes(trigger.suggestedModel || "")) {
12134
+ console.log(`[cloister] Skipping handoff for ${health.agentId}: task_complete triggers specialist dispatch via completion marker, not model swap`);
12135
+ continue;
12136
+ }
11997
12137
  this.emit({ type: "handoff_triggered", agentId: health.agentId, trigger });
11998
12138
  console.log(`\u{1F514} Handoff triggered for ${health.agentId}: ${trigger.reason}`);
11999
12139
  const result = await performHandoff(health.agentId, {
@@ -12376,12 +12516,12 @@ async function setupHooksCommand() {
12376
12516
  console.log(chalk39.green("\u2713 Created ~/.panopticon/heartbeats/"));
12377
12517
  }
12378
12518
  const hookScripts = ["pre-tool-hook", "heartbeat-hook", "stop-hook", "specialist-stop-hook", "record-cost-event.js"];
12379
- const { fileURLToPath: fileURLToPath6 } = await import("url");
12380
- const { dirname: dirname16 } = await import("path");
12381
- const __dirname6 = dirname16(fileURLToPath6(import.meta.url));
12519
+ const { fileURLToPath: fileURLToPath7 } = await import("url");
12520
+ const { dirname: dirname17 } = await import("path");
12521
+ const __dirname7 = dirname17(fileURLToPath7(import.meta.url));
12382
12522
  for (const scriptName of hookScripts) {
12383
12523
  const devSource = join40(process.cwd(), "scripts", scriptName);
12384
- const installedSource = join40(__dirname6, "..", "..", "..", "scripts", scriptName);
12524
+ const installedSource = join40(__dirname7, "..", "..", "..", "scripts", scriptName);
12385
12525
  const scriptDest = join40(binDir, scriptName);
12386
12526
  let sourcePath = null;
12387
12527
  if (existsSync41(devSource)) {
@@ -12427,7 +12567,7 @@ async function setupHooksCommand() {
12427
12567
  console.log(chalk39.dim(" Install Python3 to enable token-efficient code analysis\n"));
12428
12568
  }
12429
12569
  if (python3Available) {
12430
- const mcpPath = join40(dirname16(settingsPath), "mcp.json");
12570
+ const mcpPath = join40(dirname17(settingsPath), "mcp.json");
12431
12571
  let mcpConfig = {};
12432
12572
  try {
12433
12573
  if (existsSync41(mcpPath)) {
@@ -12644,7 +12784,7 @@ function sendTask(tmuxSession, specialistName, task) {
12644
12784
  }
12645
12785
  }
12646
12786
  async function wakeCommand(name, options) {
12647
- const validNames = ["merge-agent", "review-agent", "test-agent"];
12787
+ const validNames = ["merge-agent", "review-agent", "test-agent", "inspect-agent", "uat-agent"];
12648
12788
  if (!validNames.includes(name)) {
12649
12789
  console.log(chalk41.red(`
12650
12790
  Error: Unknown specialist '${name}'`));
@@ -12716,7 +12856,7 @@ init_esm_shims();
12716
12856
  init_specialists();
12717
12857
  import chalk42 from "chalk";
12718
12858
  function queueCommand(name, options) {
12719
- const validNames = ["merge-agent", "review-agent", "test-agent"];
12859
+ const validNames = ["merge-agent", "review-agent", "test-agent", "inspect-agent", "uat-agent"];
12720
12860
  if (!validNames.includes(name)) {
12721
12861
  console.log(chalk42.red(`
12722
12862
  Error: Unknown specialist '${name}'`));
@@ -12817,7 +12957,7 @@ import { exec as exec14 } from "child_process";
12817
12957
  import { promisify as promisify14 } from "util";
12818
12958
  import * as readline from "readline";
12819
12959
  var execAsync14 = promisify14(exec14);
12820
- var ALL_SPECIALISTS = ["merge-agent", "review-agent", "test-agent"];
12960
+ var ALL_SPECIALISTS = ["merge-agent", "review-agent", "test-agent", "inspect-agent", "uat-agent"];
12821
12961
  async function resetCommand(name, options) {
12822
12962
  if (options.all) {
12823
12963
  await resetAllSpecialists(options);
@@ -12946,7 +13086,7 @@ import chalk44 from "chalk";
12946
13086
  import { existsSync as existsSync43, readFileSync as readFileSync37, writeFileSync as writeFileSync23 } from "fs";
12947
13087
  import { join as join42 } from "path";
12948
13088
  import * as readline2 from "readline";
12949
- var ALL_SPECIALISTS2 = ["merge-agent", "review-agent", "test-agent"];
13089
+ var ALL_SPECIALISTS2 = ["merge-agent", "review-agent", "test-agent", "inspect-agent", "uat-agent"];
12950
13090
  var REVIEW_STATUS_FILE2 = join42(PANOPTICON_HOME, "review-status.json");
12951
13091
  async function clearQueueCommand(name, options) {
12952
13092
  if (!ALL_SPECIALISTS2.includes(name)) {
@@ -13057,7 +13197,7 @@ init_esm_shims();
13057
13197
  init_review_status();
13058
13198
  import chalk45 from "chalk";
13059
13199
  async function doneCommand2(specialist, issueId, options) {
13060
- const validSpecialists = ["review", "test", "merge"];
13200
+ const validSpecialists = ["review", "test", "merge", "inspect", "uat"];
13061
13201
  if (!validSpecialists.includes(specialist)) {
13062
13202
  console.error(chalk45.red(`Invalid specialist: ${specialist}`));
13063
13203
  console.error(chalk45.dim(`Valid options: ${validSpecialists.join(", ")}`));
@@ -13101,6 +13241,29 @@ async function doneCommand2(specialist, issueId, options) {
13101
13241
  console.log(chalk45.red(`\u2717 Merge failed for ${normalizedIssueId}`));
13102
13242
  }
13103
13243
  break;
13244
+ case "inspect":
13245
+ update.inspectStatus = options.status;
13246
+ if (options.notes) update.inspectNotes = options.notes;
13247
+ if (options.status === "passed") {
13248
+ console.log(chalk45.green(`\u2713 Inspection passed for ${normalizedIssueId}`));
13249
+ console.log(chalk45.dim(" Agent can proceed to next bead"));
13250
+ } else {
13251
+ console.log(chalk45.yellow(`\u2717 Inspection blocked for ${normalizedIssueId}`));
13252
+ console.log(chalk45.dim(" Agent must fix issues and re-request inspection"));
13253
+ }
13254
+ break;
13255
+ case "uat":
13256
+ update.uatStatus = options.status;
13257
+ if (options.notes) update.uatNotes = options.notes;
13258
+ if (options.status === "passed") {
13259
+ update.readyForMerge = true;
13260
+ console.log(chalk45.green(`\u2713 UAT passed for ${normalizedIssueId}`));
13261
+ console.log(chalk45.dim(" Ready for merge"));
13262
+ } else {
13263
+ console.log(chalk45.yellow(`\u2717 UAT blocked for ${normalizedIssueId}`));
13264
+ console.log(chalk45.dim(" Agent must fix issues \u2014 visual/functional verification failed"));
13265
+ }
13266
+ break;
13104
13267
  }
13105
13268
  const status = setReviewStatus(normalizedIssueId, update);
13106
13269
  if (specialist === "test" && status.readyForMerge) {
@@ -13111,8 +13274,14 @@ async function doneCommand2(specialist, issueId, options) {
13111
13274
  }
13112
13275
  console.log("");
13113
13276
  console.log(chalk45.bold("Current Status:"));
13277
+ if (status.inspectStatus) {
13278
+ console.log(` Inspect: ${formatStatus(status.inspectStatus)}`);
13279
+ }
13114
13280
  console.log(` Review: ${formatStatus(status.reviewStatus)}`);
13115
13281
  console.log(` Test: ${formatStatus(status.testStatus)}`);
13282
+ if (status.uatStatus) {
13283
+ console.log(` UAT: ${formatStatus(status.uatStatus)}`);
13284
+ }
13116
13285
  if (status.mergeStatus) {
13117
13286
  console.log(` Merge: ${formatStatus(status.mergeStatus)}`);
13118
13287
  }
@@ -13143,7 +13312,7 @@ import { promisify as promisify15 } from "util";
13143
13312
  var execAsync15 = promisify15(exec15);
13144
13313
  async function listLogsCommand(project2, type, options) {
13145
13314
  try {
13146
- const { listRunLogs } = await import("../specialist-logs-KPC45SZN.js");
13315
+ const { listRunLogs } = await import("../specialist-logs-FQRI3AIS.js");
13147
13316
  const limit = options.limit ? parseInt(options.limit) : 10;
13148
13317
  const runs = listRunLogs(project2, type, { limit });
13149
13318
  if (options.json) {
@@ -13188,7 +13357,7 @@ View a specific run: pan specialists logs ${project2} ${type} <runId>
13188
13357
  }
13189
13358
  async function viewLogCommand(project2, type, runId, options) {
13190
13359
  try {
13191
- const { getRunLog, parseLogMetadata, getRunLogPath } = await import("../specialist-logs-KPC45SZN.js");
13360
+ const { getRunLog, parseLogMetadata, getRunLogPath } = await import("../specialist-logs-FQRI3AIS.js");
13192
13361
  const content = getRunLog(project2, type, runId);
13193
13362
  if (!content) {
13194
13363
  console.error(`\u274C Run log not found: ${runId}`);
@@ -13212,8 +13381,8 @@ async function viewLogCommand(project2, type, runId, options) {
13212
13381
  }
13213
13382
  async function tailLogCommand(project2, type) {
13214
13383
  try {
13215
- const { getRunLogPath } = await import("../specialist-logs-KPC45SZN.js");
13216
- const { getProjectSpecialistMetadata } = await import("../specialists-H4LGYR7R.js");
13384
+ const { getRunLogPath } = await import("../specialist-logs-FQRI3AIS.js");
13385
+ const { getProjectSpecialistMetadata } = await import("../specialists-CXRGSJY3.js");
13217
13386
  const metadata = getProjectSpecialistMetadata(project2, type);
13218
13387
  if (!metadata.currentRun) {
13219
13388
  console.error(`\u274C No active run for ${project2}/${type}`);
@@ -13282,7 +13451,7 @@ async function cleanupLogsCommand(projectOrAll, type, options) {
13282
13451
  console.log(" Use --force to confirm.");
13283
13452
  process.exit(1);
13284
13453
  }
13285
- const { cleanupAllLogs } = await import("../specialist-logs-KPC45SZN.js");
13454
+ const { cleanupAllLogs } = await import("../specialist-logs-FQRI3AIS.js");
13286
13455
  console.log("\u{1F9F9} Cleaning up old logs for all projects...\n");
13287
13456
  const results = cleanupAllLogs();
13288
13457
  console.log(`
@@ -13309,8 +13478,8 @@ async function cleanupLogsCommand(projectOrAll, type, options) {
13309
13478
  console.log(" Use --force to confirm.");
13310
13479
  process.exit(1);
13311
13480
  }
13312
- const { cleanupOldLogs } = await import("../specialist-logs-KPC45SZN.js");
13313
- const { getSpecialistRetention } = await import("../projects-3CRF57ZU.js");
13481
+ const { cleanupOldLogs } = await import("../specialist-logs-FQRI3AIS.js");
13482
+ const { getSpecialistRetention } = await import("../projects-BPGM6IFB.js");
13314
13483
  const retention = getSpecialistRetention(projectOrAll);
13315
13484
  console.log(`\u{1F9F9} Cleaning up old logs for ${projectOrAll}/${type}...`);
13316
13485
  console.log(` Retention: ${retention.max_days} days or ${retention.max_runs} runs
@@ -14068,7 +14237,7 @@ async function projectAddCommand(projectPath, options = {}) {
14068
14237
  }
14069
14238
  const isPolyrepo = !hasRootGit && subRepos.length > 0;
14070
14239
  try {
14071
- const { preTrustDirectory } = await import("../workspace-manager-G6TTBPC3.js");
14240
+ const { preTrustDirectory } = await import("../workspace-manager-OWHLR5BL.js");
14072
14241
  preTrustDirectory(fullPath);
14073
14242
  } catch {
14074
14243
  }
@@ -14428,9 +14597,9 @@ import { fileURLToPath as fileURLToPath5 } from "url";
14428
14597
  import { dirname as dirname14, join as join46 } from "path";
14429
14598
  function getCurrentVersion() {
14430
14599
  try {
14431
- const __filename6 = fileURLToPath5(import.meta.url);
14432
- const __dirname6 = dirname14(__filename6);
14433
- const pkgPath = join46(__dirname6, "..", "..", "..", "package.json");
14600
+ const __filename7 = fileURLToPath5(import.meta.url);
14601
+ const __dirname7 = dirname14(__filename7);
14602
+ const pkgPath = join46(__dirname7, "..", "..", "..", "package.json");
14434
14603
  const pkg = JSON.parse(readFileSync42(pkgPath, "utf-8"));
14435
14604
  return pkg.version;
14436
14605
  } catch {
@@ -15806,18 +15975,236 @@ Shadowed issues: ${shadowedIssues.length}`));
15806
15975
  }
15807
15976
  }
15808
15977
 
15978
+ // src/cli/commands/inspect.ts
15979
+ init_esm_shims();
15980
+ init_projects();
15981
+ import chalk61 from "chalk";
15982
+
15983
+ // src/lib/cloister/inspect-agent.ts
15984
+ init_esm_shims();
15985
+ import { readFileSync as readFileSync46, existsSync as existsSync51 } from "fs";
15986
+ import { join as join51, dirname as dirname16 } from "path";
15987
+ import { fileURLToPath as fileURLToPath6 } from "url";
15988
+ import { exec as exec21 } from "child_process";
15989
+ import { promisify as promisify21 } from "util";
15990
+
15991
+ // src/lib/cloister/inspect-checkpoints.ts
15992
+ init_esm_shims();
15993
+ import { existsSync as existsSync50, readFileSync as readFileSync45, writeFileSync as writeFileSync26, mkdirSync as mkdirSync25 } from "fs";
15994
+ import { join as join50 } from "path";
15995
+ import { homedir as homedir23 } from "os";
15996
+ import { execSync as execSync9 } from "child_process";
15997
+ var PANOPTICON_HOME2 = join50(homedir23(), ".panopticon");
15998
+ function getCheckpointDir(projectKey) {
15999
+ return join50(PANOPTICON_HOME2, "specialists", projectKey, "inspect-agent", "checkpoints");
16000
+ }
16001
+ function getCheckpointPath(projectKey, issueId) {
16002
+ return join50(getCheckpointDir(projectKey), `${issueId.toUpperCase()}.json`);
16003
+ }
16004
+ function loadCheckpoints(projectKey, issueId) {
16005
+ const filePath = getCheckpointPath(projectKey, issueId);
16006
+ if (!existsSync50(filePath)) return null;
16007
+ try {
16008
+ return JSON.parse(readFileSync45(filePath, "utf-8"));
16009
+ } catch {
16010
+ return null;
16011
+ }
16012
+ }
16013
+ function getLastCheckpoint(projectKey, issueId) {
16014
+ const data = loadCheckpoints(projectKey, issueId);
16015
+ if (!data || data.checkpoints.length === 0) return null;
16016
+ return data.checkpoints[data.checkpoints.length - 1];
16017
+ }
16018
+ function getDiffBase(projectKey, issueId, workspacePath) {
16019
+ const lastCheckpoint = getLastCheckpoint(projectKey, issueId);
16020
+ if (lastCheckpoint) {
16021
+ return lastCheckpoint.commitSha;
16022
+ }
16023
+ try {
16024
+ const mergeBase = execSync9("git merge-base main HEAD", {
16025
+ cwd: workspacePath,
16026
+ encoding: "utf-8"
16027
+ }).trim();
16028
+ return mergeBase;
16029
+ } catch {
16030
+ return "main";
16031
+ }
16032
+ }
16033
+ function getDiffStats(workspacePath, diffBase) {
16034
+ try {
16035
+ const stats = execSync9(`git diff --stat ${diffBase}...HEAD`, {
16036
+ cwd: workspacePath,
16037
+ encoding: "utf-8"
16038
+ }).trim();
16039
+ return stats || "No changes detected";
16040
+ } catch {
16041
+ return "Unable to compute diff stats";
16042
+ }
16043
+ }
16044
+
16045
+ // src/lib/cloister/inspect-agent.ts
16046
+ init_specialists();
16047
+ init_review_status();
16048
+ var execAsync21 = promisify21(exec21);
16049
+ var __filename6 = fileURLToPath6(import.meta.url);
16050
+ var __dirname6 = dirname16(__filename6);
16051
+ async function getBeadDescription(beadId, workspacePath) {
16052
+ try {
16053
+ const { stdout } = await execAsync21(`bd show ${beadId} --json`, {
16054
+ cwd: workspacePath,
16055
+ encoding: "utf-8"
16056
+ });
16057
+ const bead = JSON.parse(stdout);
16058
+ const parts = [];
16059
+ if (bead.title) parts.push(`**Title:** ${bead.title}`);
16060
+ if (bead.description) parts.push(`**Description:** ${bead.description}`);
16061
+ if (bead.acceptance) parts.push(`**Acceptance Criteria:** ${bead.acceptance}`);
16062
+ if (bead.notes) parts.push(`**Notes:** ${bead.notes}`);
16063
+ if (bead.labels?.length) parts.push(`**Labels:** ${bead.labels.join(", ")}`);
16064
+ return parts.join("\n\n") || `Bead ${beadId} (no description available)`;
16065
+ } catch {
16066
+ try {
16067
+ const { stdout } = await execAsync21(`bd show ${beadId}`, {
16068
+ cwd: workspacePath,
16069
+ encoding: "utf-8"
16070
+ });
16071
+ return stdout.trim() || `Bead ${beadId} (no description available)`;
16072
+ } catch {
16073
+ return `Bead ${beadId} (unable to read bead description)`;
16074
+ }
16075
+ }
16076
+ }
16077
+ function detectCompileCommand(workspacePath) {
16078
+ const checks = [
16079
+ { file: "tsconfig.json", command: "npx tsc --noEmit && npx eslint . --max-warnings=0 2>/dev/null || npx eslint ." },
16080
+ { file: "package.json", command: "npm run build 2>&1 | tail -20" },
16081
+ { file: "pom.xml", command: "./mvnw compile -q" },
16082
+ { file: "Cargo.toml", command: "cargo check" },
16083
+ { file: "go.mod", command: "go build ./..." }
16084
+ ];
16085
+ for (const check of checks) {
16086
+ for (const subdir of ["", "fe", "api", "frontend", "backend"]) {
16087
+ const checkPath = subdir ? join51(workspacePath, subdir, check.file) : join51(workspacePath, check.file);
16088
+ if (existsSync51(checkPath)) {
16089
+ const cwd = subdir ? `cd ${subdir} && ` : "";
16090
+ return `${cwd}${check.command}`;
16091
+ }
16092
+ }
16093
+ }
16094
+ return 'echo "No compile command detected \u2014 skipping compile check"';
16095
+ }
16096
+ async function buildInspectPrompt(context) {
16097
+ const templatePath = join51(__dirname6, "prompts", "inspect-agent.md");
16098
+ if (!existsSync51(templatePath)) {
16099
+ throw new Error(`Inspect agent prompt template not found at ${templatePath}`);
16100
+ }
16101
+ const template = readFileSync46(templatePath, "utf-8");
16102
+ const beadDescription = await getBeadDescription(context.beadId, context.workspace);
16103
+ const diffBase = getDiffBase(context.projectKey, context.issueId, context.workspace);
16104
+ const diffStats = getDiffStats(context.workspace, diffBase);
16105
+ const compileCommand = detectCompileCommand(context.workspace);
16106
+ const apiUrl = process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || "3011"}`;
16107
+ const prompt = template.replace(/\{\{apiUrl\}\}/g, apiUrl).replace(/\{\{projectPath\}\}/g, context.projectPath).replace(/\{\{issueId\}\}/g, context.issueId).replace(/\{\{beadId\}\}/g, context.beadId).replace(/\{\{workspacePath\}\}/g, context.workspace).replace(/\{\{checkpoint\}\}/g, diffBase.substring(0, 8)).replace(/\{\{diffBase\}\}/g, diffBase).replace(/\{\{diffStats\}\}/g, diffStats).replace(/\{\{beadDescription\}\}/g, beadDescription).replace(/\{\{compileCommand\}\}/g, compileCommand).replace(/\{\{resultStatus\}\}/g, "${RESULT_STATUS}").replace(/\{\{resultNotes\}\}/g, "${RESULT_NOTES}");
16108
+ return `<!-- panopticon:orchestration-context-start -->
16109
+ ${prompt}
16110
+ <!-- panopticon:orchestration-context-end -->`;
16111
+ }
16112
+ async function spawnInspectAgent(context) {
16113
+ const prompt = await buildInspectPrompt(context);
16114
+ setReviewStatus(context.issueId.toUpperCase(), {
16115
+ inspectStatus: "inspecting",
16116
+ inspectNotes: `Inspecting bead ${context.beadId}`
16117
+ });
16118
+ return spawnEphemeralSpecialist(context.projectKey, "inspect-agent", {
16119
+ issueId: context.issueId,
16120
+ branch: context.branch,
16121
+ workspace: context.workspace,
16122
+ promptOverride: prompt
16123
+ });
16124
+ }
16125
+
16126
+ // src/cli/commands/inspect.ts
16127
+ function registerInspectCommand(program2) {
16128
+ program2.command("inspect <issueId>").description("Request inspection of a completed bead before proceeding to the next").requiredOption("--bead <beadId>", "Bead ID to inspect").option("--workspace <path>", "Workspace path (auto-detected if not provided)").action(async (issueId, options) => {
16129
+ try {
16130
+ await inspectCommand(issueId, options);
16131
+ } catch (error) {
16132
+ console.error(chalk61.red(`Error: ${error.message}`));
16133
+ process.exit(1);
16134
+ }
16135
+ });
16136
+ }
16137
+ async function inspectCommand(issueId, options) {
16138
+ const normalizedIssueId = issueId.toUpperCase();
16139
+ const project2 = resolveProjectFromIssue(normalizedIssueId);
16140
+ if (!project2) {
16141
+ console.error(chalk61.red(`Could not resolve project for issue ${normalizedIssueId}`));
16142
+ console.error(chalk61.dim("Make sure the issue prefix matches a registered project"));
16143
+ process.exit(1);
16144
+ }
16145
+ let workspacePath = options.workspace;
16146
+ if (!workspacePath) {
16147
+ const { join: join54 } = await import("path");
16148
+ const { existsSync: existsSync54 } = await import("fs");
16149
+ const candidatePath = join54(project2.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
16150
+ if (existsSync54(candidatePath)) {
16151
+ workspacePath = candidatePath;
16152
+ }
16153
+ }
16154
+ if (!workspacePath) {
16155
+ console.error(chalk61.red(`Could not find workspace for ${normalizedIssueId}`));
16156
+ console.error(chalk61.dim("Provide --workspace <path> or ensure a workspace exists for this issue"));
16157
+ process.exit(1);
16158
+ }
16159
+ const diffBase = getDiffBase(project2.projectKey, normalizedIssueId, workspacePath);
16160
+ const diffStats = getDiffStats(workspacePath, diffBase);
16161
+ console.log("");
16162
+ console.log(chalk61.bold("Requesting inspection"));
16163
+ console.log(chalk61.dim(` Issue: ${normalizedIssueId}`));
16164
+ console.log(chalk61.dim(` Bead: ${options.bead}`));
16165
+ console.log(chalk61.dim(` Workspace: ${workspacePath}`));
16166
+ console.log(chalk61.dim(` Diff from: ${diffBase.substring(0, 8)}`));
16167
+ console.log("");
16168
+ console.log(chalk61.dim("Diff scope:"));
16169
+ console.log(chalk61.dim(diffStats.split("\n").map((l) => ` ${l}`).join("\n")));
16170
+ console.log("");
16171
+ const context = {
16172
+ projectKey: project2.projectKey,
16173
+ projectPath: project2.projectPath,
16174
+ issueId: normalizedIssueId,
16175
+ beadId: options.bead,
16176
+ workspace: workspacePath,
16177
+ branch: `feature/${normalizedIssueId.toLowerCase()}`
16178
+ };
16179
+ const result = await spawnInspectAgent(context);
16180
+ if (result.success) {
16181
+ console.log(chalk61.green("\u2713 Inspect specialist spawned"));
16182
+ console.log(chalk61.dim(` Session: ${result.tmuxSession}`));
16183
+ console.log(chalk61.dim(` Run ID: ${result.runId}`));
16184
+ console.log("");
16185
+ console.log(chalk61.yellow("The inspect specialist is reviewing your bead."));
16186
+ console.log(chalk61.yellow("Wait for the result \u2014 it will be delivered to your session via pan work tell."));
16187
+ } else {
16188
+ console.error(chalk61.red(`\u2717 Failed to spawn inspect specialist: ${result.message}`));
16189
+ if (result.error) {
16190
+ console.error(chalk61.dim(result.error));
16191
+ }
16192
+ process.exit(1);
16193
+ }
16194
+ }
16195
+
15809
16196
  // src/cli/commands/cost.ts
15810
16197
  init_esm_shims();
15811
16198
  init_cost();
15812
16199
  import { Command } from "commander";
15813
- import chalk61 from "chalk";
16200
+ import chalk62 from "chalk";
15814
16201
 
15815
16202
  // src/lib/costs/sync-wal.ts
15816
16203
  init_esm_shims();
15817
16204
  init_projects();
15818
- import { existsSync as existsSync50 } from "fs";
16205
+ import { existsSync as existsSync52 } from "fs";
15819
16206
  import { readdir, readFile } from "fs/promises";
15820
- import { join as join50 } from "path";
16207
+ import { join as join52 } from "path";
15821
16208
 
15822
16209
  // src/lib/database/cost-events-db.ts
15823
16210
  init_esm_shims();
@@ -15882,8 +16269,8 @@ async function syncWalFromAllProjects() {
15882
16269
  for (const { key, config: config2 } of projects) {
15883
16270
  const repoPath = config2.events_repo ?? config2.path;
15884
16271
  const eventsSubdir = config2.events_path ?? DEFAULT_EVENTS_SUBDIR;
15885
- const eventsDir = join50(repoPath, eventsSubdir);
15886
- if (!existsSync50(eventsDir)) continue;
16272
+ const eventsDir = join52(repoPath, eventsSubdir);
16273
+ if (!existsSync52(eventsDir)) continue;
15887
16274
  const projectStats = { imported: 0, duplicates: 0, files: 0 };
15888
16275
  let files;
15889
16276
  try {
@@ -15893,7 +16280,7 @@ async function syncWalFromAllProjects() {
15893
16280
  continue;
15894
16281
  }
15895
16282
  for (const file of files) {
15896
- const filePath = join50(eventsDir, file);
16283
+ const filePath = join52(eventsDir, file);
15897
16284
  const events = await parseWalFile(filePath, result.errors);
15898
16285
  if (events.length === 0) continue;
15899
16286
  try {
@@ -15939,32 +16326,32 @@ async function parseWalFile(filePath, errors) {
15939
16326
  // src/cli/commands/cost.ts
15940
16327
  async function runCostSync() {
15941
16328
  try {
15942
- console.log(chalk61.bold("Syncing cost events from project WAL files..."));
16329
+ console.log(chalk62.bold("Syncing cost events from project WAL files..."));
15943
16330
  const result = await syncWalFromAllProjects();
15944
16331
  if (result.filesScanned === 0) {
15945
- console.log(chalk61.yellow("No WAL files found. Make sure projects are registered and have cost events."));
16332
+ console.log(chalk62.yellow("No WAL files found. Make sure projects are registered and have cost events."));
15946
16333
  return;
15947
16334
  }
15948
16335
  console.log();
15949
16336
  console.log(`Files scanned: ${result.filesScanned}`);
15950
- console.log(`Imported: ${chalk61.green(result.imported)} new events`);
15951
- console.log(`Duplicates: ${chalk61.dim(result.duplicates)} skipped`);
16337
+ console.log(`Imported: ${chalk62.green(result.imported)} new events`);
16338
+ console.log(`Duplicates: ${chalk62.dim(result.duplicates)} skipped`);
15952
16339
  if (Object.keys(result.byProject).length > 0) {
15953
16340
  console.log();
15954
- console.log(chalk61.bold("By Project:"));
16341
+ console.log(chalk62.bold("By Project:"));
15955
16342
  for (const [project2, stats] of Object.entries(result.byProject)) {
15956
- console.log(` ${project2}: ${chalk61.green(stats.imported)} imported, ${stats.files} file(s)`);
16343
+ console.log(` ${project2}: ${chalk62.green(stats.imported)} imported, ${stats.files} file(s)`);
15957
16344
  }
15958
16345
  }
15959
16346
  if (result.errors.length > 0) {
15960
16347
  console.log();
15961
- console.log(chalk61.yellow(`Warnings (${result.errors.length}):`));
16348
+ console.log(chalk62.yellow(`Warnings (${result.errors.length}):`));
15962
16349
  for (const err of result.errors) {
15963
- console.log(` ${chalk61.dim(err)}`);
16350
+ console.log(` ${chalk62.dim(err)}`);
15964
16351
  }
15965
16352
  }
15966
16353
  } catch (error) {
15967
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16354
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
15968
16355
  process.exit(1);
15969
16356
  }
15970
16357
  }
@@ -15973,23 +16360,23 @@ function createCostCommand() {
15973
16360
  cost.command("today").description("Show today's cost summary").option("-d, --detail", "Show individual entries").action((options) => {
15974
16361
  try {
15975
16362
  const summary = getDailySummary();
15976
- console.log(chalk61.bold("Today's Cost Summary"));
16363
+ console.log(chalk62.bold("Today's Cost Summary"));
15977
16364
  console.log();
15978
- console.log(`Total Cost: ${chalk61.green(formatCost(summary.totalCost))}`);
16365
+ console.log(`Total Cost: ${chalk62.green(formatCost(summary.totalCost))}`);
15979
16366
  console.log(`API Calls: ${summary.entryCount}`);
15980
16367
  console.log(`Tokens: ${summary.totalTokens.total.toLocaleString()}`);
15981
16368
  console.log(` Input: ${summary.totalTokens.input.toLocaleString()}`);
15982
16369
  console.log(` Output: ${summary.totalTokens.output.toLocaleString()}`);
15983
16370
  console.log();
15984
16371
  if (Object.keys(summary.byProvider).length > 0) {
15985
- console.log(chalk61.bold("By Provider"));
16372
+ console.log(chalk62.bold("By Provider"));
15986
16373
  for (const [provider, cost2] of Object.entries(summary.byProvider)) {
15987
16374
  console.log(` ${provider}: ${formatCost(cost2)}`);
15988
16375
  }
15989
16376
  console.log();
15990
16377
  }
15991
16378
  if (Object.keys(summary.byModel).length > 0) {
15992
- console.log(chalk61.bold("By Model"));
16379
+ console.log(chalk62.bold("By Model"));
15993
16380
  for (const [model, cost2] of Object.entries(summary.byModel)) {
15994
16381
  console.log(` ${model}: ${formatCost(cost2)}`);
15995
16382
  }
@@ -15998,83 +16385,83 @@ function createCostCommand() {
15998
16385
  if (options.detail) {
15999
16386
  const entries = readTodayCosts();
16000
16387
  if (entries.length > 0) {
16001
- console.log(chalk61.bold("Entries"));
16388
+ console.log(chalk62.bold("Entries"));
16002
16389
  for (const entry of entries.slice(-10)) {
16003
16390
  const time = new Date(entry.timestamp).toLocaleTimeString();
16004
- console.log(` ${chalk61.dim(time)} ${entry.model} ${formatCost(entry.cost)} ${entry.operation}`);
16391
+ console.log(` ${chalk62.dim(time)} ${entry.model} ${formatCost(entry.cost)} ${entry.operation}`);
16005
16392
  }
16006
16393
  if (entries.length > 10) {
16007
- console.log(chalk61.dim(` ... and ${entries.length - 10} more`));
16394
+ console.log(chalk62.dim(` ... and ${entries.length - 10} more`));
16008
16395
  }
16009
16396
  }
16010
16397
  }
16011
16398
  } catch (error) {
16012
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16399
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16013
16400
  process.exit(1);
16014
16401
  }
16015
16402
  });
16016
16403
  cost.command("week").description("Show weekly cost summary").action(() => {
16017
16404
  try {
16018
16405
  const summary = getWeeklySummary();
16019
- console.log(chalk61.bold("Weekly Cost Summary"));
16020
- console.log(chalk61.dim(`${summary.period.start} to ${summary.period.end}`));
16406
+ console.log(chalk62.bold("Weekly Cost Summary"));
16407
+ console.log(chalk62.dim(`${summary.period.start} to ${summary.period.end}`));
16021
16408
  console.log();
16022
- console.log(`Total Cost: ${chalk61.green(formatCost(summary.totalCost))}`);
16409
+ console.log(`Total Cost: ${chalk62.green(formatCost(summary.totalCost))}`);
16023
16410
  console.log(`API Calls: ${summary.entryCount}`);
16024
16411
  console.log(`Tokens: ${summary.totalTokens.total.toLocaleString()}`);
16025
16412
  console.log();
16026
16413
  if (Object.keys(summary.byProvider).length > 0) {
16027
- console.log(chalk61.bold("By Provider"));
16414
+ console.log(chalk62.bold("By Provider"));
16028
16415
  for (const [provider, cost2] of Object.entries(summary.byProvider)) {
16029
16416
  console.log(` ${provider}: ${formatCost(cost2)}`);
16030
16417
  }
16031
16418
  console.log();
16032
16419
  }
16033
16420
  if (Object.keys(summary.byIssue).length > 0) {
16034
- console.log(chalk61.bold("Top Issues by Cost"));
16421
+ console.log(chalk62.bold("Top Issues by Cost"));
16035
16422
  const sorted = Object.entries(summary.byIssue).sort(([, a], [, b]) => b - a).slice(0, 5);
16036
16423
  for (const [issue, cost2] of sorted) {
16037
16424
  console.log(` ${issue}: ${formatCost(cost2)}`);
16038
16425
  }
16039
16426
  }
16040
16427
  } catch (error) {
16041
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16428
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16042
16429
  process.exit(1);
16043
16430
  }
16044
16431
  });
16045
16432
  cost.command("month").description("Show monthly cost summary").action(() => {
16046
16433
  try {
16047
16434
  const summary = getMonthlySummary();
16048
- console.log(chalk61.bold("Monthly Cost Summary"));
16049
- console.log(chalk61.dim(`${summary.period.start} to ${summary.period.end}`));
16435
+ console.log(chalk62.bold("Monthly Cost Summary"));
16436
+ console.log(chalk62.dim(`${summary.period.start} to ${summary.period.end}`));
16050
16437
  console.log();
16051
- console.log(`Total Cost: ${chalk61.green(formatCost(summary.totalCost))}`);
16438
+ console.log(`Total Cost: ${chalk62.green(formatCost(summary.totalCost))}`);
16052
16439
  console.log(`API Calls: ${summary.entryCount}`);
16053
16440
  console.log(`Tokens: ${summary.totalTokens.total.toLocaleString()}`);
16054
16441
  console.log();
16055
16442
  if (Object.keys(summary.byProvider).length > 0) {
16056
- console.log(chalk61.bold("By Provider"));
16443
+ console.log(chalk62.bold("By Provider"));
16057
16444
  for (const [provider, cost2] of Object.entries(summary.byProvider)) {
16058
16445
  console.log(` ${provider}: ${formatCost(cost2)}`);
16059
16446
  }
16060
16447
  console.log();
16061
16448
  }
16062
16449
  if (Object.keys(summary.byModel).length > 0) {
16063
- console.log(chalk61.bold("By Model"));
16450
+ console.log(chalk62.bold("By Model"));
16064
16451
  for (const [model, cost2] of Object.entries(summary.byModel)) {
16065
16452
  console.log(` ${model}: ${formatCost(cost2)}`);
16066
16453
  }
16067
16454
  console.log();
16068
16455
  }
16069
16456
  if (Object.keys(summary.byIssue).length > 0) {
16070
- console.log(chalk61.bold("Top 10 Issues by Cost"));
16457
+ console.log(chalk62.bold("Top 10 Issues by Cost"));
16071
16458
  const sorted = Object.entries(summary.byIssue).sort(([, a], [, b]) => b - a).slice(0, 10);
16072
16459
  for (const [issue, cost2] of sorted) {
16073
16460
  console.log(` ${issue}: ${formatCost(cost2)}`);
16074
16461
  }
16075
16462
  }
16076
16463
  } catch (error) {
16077
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16464
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16078
16465
  process.exit(1);
16079
16466
  }
16080
16467
  });
@@ -16089,7 +16476,7 @@ function createCostCommand() {
16089
16476
  const report = generateReport(start, end);
16090
16477
  console.log(report);
16091
16478
  } catch (error) {
16092
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16479
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16093
16480
  process.exit(1);
16094
16481
  }
16095
16482
  });
@@ -16097,24 +16484,24 @@ function createCostCommand() {
16097
16484
  try {
16098
16485
  const entries = readIssueCosts(issueId, parseInt(options.days, 10));
16099
16486
  if (entries.length === 0) {
16100
- console.log(chalk61.dim("No costs found for issue:"), issueId);
16487
+ console.log(chalk62.dim("No costs found for issue:"), issueId);
16101
16488
  return;
16102
16489
  }
16103
16490
  const summary = summarizeCosts(entries);
16104
- console.log(chalk61.bold(`Costs for ${issueId}`));
16491
+ console.log(chalk62.bold(`Costs for ${issueId}`));
16105
16492
  console.log();
16106
- console.log(`Total Cost: ${chalk61.green(formatCost(summary.totalCost))}`);
16493
+ console.log(`Total Cost: ${chalk62.green(formatCost(summary.totalCost))}`);
16107
16494
  console.log(`API Calls: ${summary.entryCount}`);
16108
16495
  console.log(`Tokens: ${summary.totalTokens.total.toLocaleString()}`);
16109
16496
  console.log();
16110
16497
  if (Object.keys(summary.byModel).length > 0) {
16111
- console.log(chalk61.bold("By Model"));
16498
+ console.log(chalk62.bold("By Model"));
16112
16499
  for (const [model, cost2] of Object.entries(summary.byModel)) {
16113
16500
  console.log(` ${model}: ${formatCost(cost2)}`);
16114
16501
  }
16115
16502
  }
16116
16503
  } catch (error) {
16117
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16504
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16118
16505
  process.exit(1);
16119
16506
  }
16120
16507
  });
@@ -16129,14 +16516,14 @@ function createCostCommand() {
16129
16516
  alertThreshold: parseFloat(options.alert),
16130
16517
  enabled: true
16131
16518
  });
16132
- console.log(chalk61.green("\u2713 Budget created"));
16133
- console.log(` ID: ${chalk61.cyan(newBudget.id)}`);
16519
+ console.log(chalk62.green("\u2713 Budget created"));
16520
+ console.log(` ID: ${chalk62.cyan(newBudget.id)}`);
16134
16521
  console.log(` Name: ${newBudget.name}`);
16135
16522
  console.log(` Type: ${newBudget.type}`);
16136
16523
  console.log(` Limit: ${formatCost(newBudget.limit)}`);
16137
16524
  console.log(` Alert at: ${(newBudget.alertThreshold * 100).toFixed(0)}%`);
16138
16525
  } catch (error) {
16139
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16526
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16140
16527
  process.exit(1);
16141
16528
  }
16142
16529
  });
@@ -16144,22 +16531,22 @@ function createCostCommand() {
16144
16531
  try {
16145
16532
  const budgets = getAllBudgets();
16146
16533
  if (budgets.length === 0) {
16147
- console.log(chalk61.dim("No budgets configured"));
16148
- console.log(chalk61.dim('Create one with: pan cost budget create "Monthly Limit" --limit 100'));
16534
+ console.log(chalk62.dim("No budgets configured"));
16535
+ console.log(chalk62.dim('Create one with: pan cost budget create "Monthly Limit" --limit 100'));
16149
16536
  return;
16150
16537
  }
16151
- console.log(chalk61.bold("Budgets"));
16538
+ console.log(chalk62.bold("Budgets"));
16152
16539
  console.log();
16153
16540
  for (const b of budgets) {
16154
16541
  const status = checkBudget(b.id);
16155
16542
  const percentStr = `${(status.percentUsed * 100).toFixed(0)}%`;
16156
- let statusColor = chalk61.green;
16543
+ let statusColor = chalk62.green;
16157
16544
  if (status.exceeded) {
16158
- statusColor = chalk61.red;
16545
+ statusColor = chalk62.red;
16159
16546
  } else if (status.alert) {
16160
- statusColor = chalk61.yellow;
16547
+ statusColor = chalk62.yellow;
16161
16548
  }
16162
- console.log(`${b.enabled ? "\u25CF" : "\u25CB"} ${chalk61.cyan(b.id)} ${b.name}`);
16549
+ console.log(`${b.enabled ? "\u25CF" : "\u25CB"} ${chalk62.cyan(b.id)} ${b.name}`);
16163
16550
  console.log(` Type: ${b.type}`);
16164
16551
  console.log(` Limit: ${formatCost(b.limit)}`);
16165
16552
  console.log(` Spent: ${statusColor(formatCost(b.spent))} (${statusColor(percentStr)})`);
@@ -16167,7 +16554,7 @@ function createCostCommand() {
16167
16554
  console.log();
16168
16555
  }
16169
16556
  } catch (error) {
16170
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16557
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16171
16558
  process.exit(1);
16172
16559
  }
16173
16560
  });
@@ -16175,21 +16562,21 @@ function createCostCommand() {
16175
16562
  try {
16176
16563
  const status = checkBudget(id);
16177
16564
  if (!status.budget) {
16178
- console.log(chalk61.red("Budget not found:"), id);
16565
+ console.log(chalk62.red("Budget not found:"), id);
16179
16566
  process.exit(1);
16180
16567
  }
16181
16568
  const b = status.budget;
16182
16569
  const percentStr = `${(status.percentUsed * 100).toFixed(0)}%`;
16183
- let statusColor = chalk61.green;
16570
+ let statusColor = chalk62.green;
16184
16571
  let statusText = "OK";
16185
16572
  if (status.exceeded) {
16186
- statusColor = chalk61.red;
16573
+ statusColor = chalk62.red;
16187
16574
  statusText = "EXCEEDED";
16188
16575
  } else if (status.alert) {
16189
- statusColor = chalk61.yellow;
16576
+ statusColor = chalk62.yellow;
16190
16577
  statusText = "WARNING";
16191
16578
  }
16192
- console.log(chalk61.bold(b.name));
16579
+ console.log(chalk62.bold(b.name));
16193
16580
  console.log();
16194
16581
  console.log(`Status: ${statusColor(statusText)}`);
16195
16582
  console.log(`Limit: ${formatCost(b.limit)}`);
@@ -16197,7 +16584,7 @@ function createCostCommand() {
16197
16584
  console.log(`Remaining: ${formatCost(status.remaining)}`);
16198
16585
  console.log(`Alert Threshold: ${(b.alertThreshold * 100).toFixed(0)}%`);
16199
16586
  } catch (error) {
16200
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16587
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16201
16588
  process.exit(1);
16202
16589
  }
16203
16590
  });
@@ -16205,13 +16592,13 @@ function createCostCommand() {
16205
16592
  try {
16206
16593
  const success = deleteBudget(id);
16207
16594
  if (success) {
16208
- console.log(chalk61.green("\u2713 Budget deleted"));
16595
+ console.log(chalk62.green("\u2713 Budget deleted"));
16209
16596
  } else {
16210
- console.log(chalk61.red("Budget not found:"), id);
16597
+ console.log(chalk62.red("Budget not found:"), id);
16211
16598
  process.exit(1);
16212
16599
  }
16213
16600
  } catch (error) {
16214
- console.error(chalk61.red("Error:"), error instanceof Error ? error.message : String(error));
16601
+ console.error(chalk62.red("Error:"), error instanceof Error ? error.message : String(error));
16215
16602
  process.exit(1);
16216
16603
  }
16217
16604
  });
@@ -16220,10 +16607,10 @@ function createCostCommand() {
16220
16607
  }
16221
16608
 
16222
16609
  // src/cli/index.ts
16223
- var PANOPTICON_ENV_FILE = join51(homedir23(), ".panopticon.env");
16224
- if (existsSync51(PANOPTICON_ENV_FILE)) {
16610
+ var PANOPTICON_ENV_FILE = join53(homedir24(), ".panopticon.env");
16611
+ if (existsSync53(PANOPTICON_ENV_FILE)) {
16225
16612
  try {
16226
- const envContent = readFileSync45(PANOPTICON_ENV_FILE, "utf-8");
16613
+ const envContent = readFileSync47(PANOPTICON_ENV_FILE, "utf-8");
16227
16614
  for (const line of envContent.split("\n")) {
16228
16615
  const trimmed = line.trim();
16229
16616
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -16240,7 +16627,7 @@ if (existsSync51(PANOPTICON_ENV_FILE)) {
16240
16627
  }
16241
16628
  }
16242
16629
  var program = new Command2();
16243
- program.name("pan").description("Multi-agent orchestration for AI coding assistants").version(JSON.parse(readFileSync45(join51(import.meta.dirname, "../../package.json"), "utf-8")).version);
16630
+ program.name("pan").description("Multi-agent orchestration for AI coding assistants").version(JSON.parse(readFileSync47(join53(import.meta.dirname, "../../package.json"), "utf-8")).version);
16244
16631
  program.command("init").description("Initialize Panopticon (~/.panopticon/)").action(initCommand);
16245
16632
  program.command("sync").description("Sync skills/agents/rules to devroot").option("--dry-run", "Show what would be synced").option("--force", "Overwrite files modified since Panopticon installed them").option("--diff", "Show diff for modified files").option("--backup-only", "Only create backup").action(syncCommand);
16246
16633
  program.command("restore [timestamp]").description("Restore from backup").action(restoreCommand);
@@ -16260,127 +16647,128 @@ registerDbCommands(program);
16260
16647
  registerBeadsCommands(program);
16261
16648
  registerRemoteCommands(program);
16262
16649
  registerConfigCommand(program);
16650
+ registerInspectCommand(program);
16263
16651
  program.command("migrate-config").description("Migrate from settings.json to config.yaml").option("--force", "Force migration even if config.yaml exists").option("--preview", "Preview migration without applying changes").option("--no-backup", "Do not back up settings.json").option("--delete-legacy", "Delete settings.json after migration").action(migrateConfigCommand);
16264
16652
  program.command("status").description("Show running agents (shorthand for work status)").option("--json", "Output as JSON").option("--tldr", "Show TLDR index health across all workspaces").option("--context", "Show context window usage % for each agent").action(statusCommand);
16265
16653
  program.command("up").description("Start dashboard (and Traefik if enabled)").option("--detach", "Run in background").option("--skip-traefik", "Skip Traefik startup").action(async (options) => {
16266
- const { spawn: spawn2, execSync: execSync9 } = await import("child_process");
16267
- const { join: join52, dirname: dirname16 } = await import("path");
16268
- const { fileURLToPath: fileURLToPath6 } = await import("url");
16269
- const { readFileSync: readFileSync46, existsSync: existsSync52 } = await import("fs");
16654
+ const { spawn: spawn2, execSync: execSync10 } = await import("child_process");
16655
+ const { join: join54, dirname: dirname17 } = await import("path");
16656
+ const { fileURLToPath: fileURLToPath7 } = await import("url");
16657
+ const { readFileSync: readFileSync48, existsSync: existsSync54 } = await import("fs");
16270
16658
  const { parse } = await import("@iarna/toml");
16271
- const __dirname6 = dirname16(fileURLToPath6(import.meta.url));
16272
- const bundledServer = join52(__dirname6, "..", "dashboard", "server.js");
16273
- const srcDashboard = join52(__dirname6, "..", "..", "src", "dashboard");
16274
- const configFile = join52(process.env.HOME || "", ".panopticon", "config.toml");
16659
+ const __dirname7 = dirname17(fileURLToPath7(import.meta.url));
16660
+ const bundledServer = join54(__dirname7, "..", "dashboard", "server.js");
16661
+ const srcDashboard = join54(__dirname7, "..", "..", "src", "dashboard");
16662
+ const configFile = join54(process.env.HOME || "", ".panopticon", "config.toml");
16275
16663
  let traefikEnabled = false;
16276
16664
  let traefikDomain = "pan.localhost";
16277
16665
  let dashboardPort = 3010;
16278
16666
  let dashboardApiPort = 3011;
16279
- if (existsSync52(configFile)) {
16667
+ if (existsSync54(configFile)) {
16280
16668
  try {
16281
- const configContent = readFileSync46(configFile, "utf-8");
16669
+ const configContent = readFileSync48(configFile, "utf-8");
16282
16670
  const config2 = parse(configContent);
16283
16671
  traefikEnabled = config2.traefik?.enabled === true;
16284
16672
  traefikDomain = config2.traefik?.domain || "pan.localhost";
16285
16673
  dashboardPort = config2.dashboard?.port || 3010;
16286
16674
  dashboardApiPort = config2.dashboard?.api_port || 3011;
16287
16675
  } catch (error) {
16288
- console.log(chalk62.yellow("Warning: Could not read config.toml"));
16676
+ console.log(chalk63.yellow("Warning: Could not read config.toml"));
16289
16677
  }
16290
16678
  }
16291
- console.log(chalk62.bold("Starting Panopticon...\n"));
16679
+ console.log(chalk63.bold("Starting Panopticon...\n"));
16292
16680
  if (traefikEnabled && !options.skipTraefik) {
16293
16681
  try {
16294
- const { generatePanopticonTraefikConfig: generatePanopticonTraefikConfig2, ensureProjectCerts: ensureProjectCerts2, generateTlsConfig: generateTlsConfig2, cleanupStaleTlsSections } = await import("../traefik-QXLZ4PO2.js");
16682
+ const { generatePanopticonTraefikConfig: generatePanopticonTraefikConfig2, ensureProjectCerts: ensureProjectCerts2, generateTlsConfig: generateTlsConfig2, cleanupStaleTlsSections } = await import("../traefik-X2IWTUHO.js");
16295
16683
  cleanupStaleTlsSections();
16296
16684
  if (generatePanopticonTraefikConfig2()) {
16297
- console.log(chalk62.dim(" Regenerated Traefik config from template"));
16685
+ console.log(chalk63.dim(" Regenerated Traefik config from template"));
16298
16686
  }
16299
16687
  const generatedDomains = ensureProjectCerts2();
16300
16688
  for (const domain of generatedDomains) {
16301
- console.log(chalk62.dim(` Generated wildcard cert for *.${domain}`));
16689
+ console.log(chalk63.dim(` Generated wildcard cert for *.${domain}`));
16302
16690
  }
16303
16691
  if (generateTlsConfig2()) {
16304
- console.log(chalk62.dim(" Generated TLS config (tls.yml)"));
16692
+ console.log(chalk63.dim(" Generated TLS config (tls.yml)"));
16305
16693
  }
16306
16694
  } catch {
16307
- console.log(chalk62.yellow("Warning: Could not regenerate Traefik config"));
16695
+ console.log(chalk63.yellow("Warning: Could not regenerate Traefik config"));
16308
16696
  }
16309
16697
  try {
16310
16698
  const { ensureBaseDomain: ensureBaseDomain2, detectDnsSyncMethod: detectDnsSyncMethod2, syncDnsToWindows: syncDnsToWindows2 } = await import("../dns-7BDJSD3E.js");
16311
- const dnsMethod = (existsSync52(configFile) ? parse(readFileSync46(configFile, "utf-8")).traefik?.dns_sync_method : null) || detectDnsSyncMethod2();
16699
+ const dnsMethod = (existsSync54(configFile) ? parse(readFileSync48(configFile, "utf-8")).traefik?.dns_sync_method : null) || detectDnsSyncMethod2();
16312
16700
  ensureBaseDomain2(dnsMethod, traefikDomain);
16313
16701
  if (dnsMethod === "wsl2hosts") {
16314
16702
  syncDnsToWindows2().catch(() => {
16315
16703
  });
16316
16704
  }
16317
16705
  } catch {
16318
- console.log(chalk62.yellow(`Warning: Could not ensure DNS for ${traefikDomain}`));
16706
+ console.log(chalk63.yellow(`Warning: Could not ensure DNS for ${traefikDomain}`));
16319
16707
  }
16320
16708
  } else if (!traefikEnabled) {
16321
16709
  try {
16322
- const containerCheck = execSync9(
16710
+ const containerCheck = execSync10(
16323
16711
  'docker ps --filter "name=panopticon-traefik" --format "{{.Names}}" 2>/dev/null',
16324
16712
  { encoding: "utf-8" }
16325
16713
  ).trim();
16326
16714
  if (containerCheck.includes("panopticon-traefik")) {
16327
- console.log(chalk62.yellow("\u26A0 Traefik container is running but traefik.enabled is not set in config"));
16328
- console.log(chalk62.yellow(" Run `pan install` to configure Traefik, or `pan down` to stop it\n"));
16715
+ console.log(chalk63.yellow("\u26A0 Traefik container is running but traefik.enabled is not set in config"));
16716
+ console.log(chalk63.yellow(" Run `pan install` to configure Traefik, or `pan down` to stop it\n"));
16329
16717
  }
16330
16718
  } catch {
16331
16719
  }
16332
16720
  }
16333
16721
  if (traefikEnabled && !options.skipTraefik) {
16334
- const traefikDir = join52(process.env.HOME || "", ".panopticon", "traefik");
16335
- if (existsSync52(traefikDir)) {
16722
+ const traefikDir = join54(process.env.HOME || "", ".panopticon", "traefik");
16723
+ if (existsSync54(traefikDir)) {
16336
16724
  try {
16337
- const composeFile = join52(traefikDir, "docker-compose.yml");
16338
- if (existsSync52(composeFile)) {
16339
- const content = readFileSync46(composeFile, "utf-8");
16725
+ const composeFile = join54(traefikDir, "docker-compose.yml");
16726
+ if (existsSync54(composeFile)) {
16727
+ const content = readFileSync48(composeFile, "utf-8");
16340
16728
  if (!content.includes("external: true") && content.includes("panopticon:")) {
16341
16729
  const patched = content.replace(
16342
16730
  /networks:\s*\n\s*panopticon:\s*\n\s*name: panopticon\s*\n\s*driver: bridge/,
16343
16731
  "networks:\n panopticon:\n name: panopticon\n external: true # Network created by 'pan install'"
16344
16732
  );
16345
- const { writeFileSync: writeFileSync26 } = await import("fs");
16346
- writeFileSync26(composeFile, patched);
16347
- console.log(chalk62.dim(" (migrated network config)"));
16733
+ const { writeFileSync: writeFileSync27 } = await import("fs");
16734
+ writeFileSync27(composeFile, patched);
16735
+ console.log(chalk63.dim(" (migrated network config)"));
16348
16736
  }
16349
16737
  }
16350
- console.log(chalk62.dim("Starting Traefik..."));
16351
- execSync9("docker compose up -d", {
16738
+ console.log(chalk63.dim("Starting Traefik..."));
16739
+ execSync10("docker compose up -d", {
16352
16740
  cwd: traefikDir,
16353
16741
  stdio: "pipe"
16354
16742
  });
16355
- console.log(chalk62.green("\u2713 Traefik started"));
16356
- console.log(chalk62.dim(` Dashboard: https://traefik.${traefikDomain}:8080
16743
+ console.log(chalk63.green("\u2713 Traefik started"));
16744
+ console.log(chalk63.dim(` Dashboard: https://traefik.${traefikDomain}:8080
16357
16745
  `));
16358
16746
  } catch (error) {
16359
- console.log(chalk62.yellow("\u26A0 Failed to start Traefik (continuing anyway)"));
16360
- console.log(chalk62.dim(" Run with --skip-traefik to suppress this message\n"));
16747
+ console.log(chalk63.yellow("\u26A0 Failed to start Traefik (continuing anyway)"));
16748
+ console.log(chalk63.dim(" Run with --skip-traefik to suppress this message\n"));
16361
16749
  }
16362
16750
  }
16363
16751
  }
16364
- const isProduction = existsSync52(bundledServer);
16365
- const isDevelopment = existsSync52(srcDashboard);
16752
+ const isProduction = existsSync54(bundledServer);
16753
+ const isDevelopment = existsSync54(srcDashboard);
16366
16754
  if (!isProduction && !isDevelopment) {
16367
- console.error(chalk62.red("Error: Dashboard not found"));
16368
- console.error(chalk62.dim("This may be a corrupted installation. Try reinstalling panopticon-cli."));
16755
+ console.error(chalk63.red("Error: Dashboard not found"));
16756
+ console.error(chalk63.dim("This may be a corrupted installation. Try reinstalling panopticon-cli."));
16369
16757
  process.exit(1);
16370
16758
  }
16371
16759
  if (isDevelopment && !isProduction) {
16372
16760
  try {
16373
- execSync9("npm --version", { stdio: "pipe" });
16761
+ execSync10("npm --version", { stdio: "pipe" });
16374
16762
  } catch {
16375
- console.error(chalk62.red("Error: npm not found in PATH"));
16376
- console.error(chalk62.dim("Make sure Node.js and npm are installed and in your PATH"));
16763
+ console.error(chalk63.red("Error: npm not found in PATH"));
16764
+ console.error(chalk63.dim("Make sure Node.js and npm are installed and in your PATH"));
16377
16765
  process.exit(1);
16378
16766
  }
16379
16767
  }
16380
16768
  if (isProduction) {
16381
- console.log(chalk62.dim("Starting dashboard (bundled mode)..."));
16769
+ console.log(chalk63.dim("Starting dashboard (bundled mode)..."));
16382
16770
  } else {
16383
- console.log(chalk62.dim("Starting dashboard (development mode)..."));
16771
+ console.log(chalk63.dim("Starting dashboard (development mode)..."));
16384
16772
  }
16385
16773
  if (options.detach) {
16386
16774
  const child = isProduction ? spawn2("node", [bundledServer], {
@@ -16396,7 +16784,7 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
16396
16784
  let hasError = false;
16397
16785
  child.on("error", (err) => {
16398
16786
  hasError = true;
16399
- console.error(chalk62.red("Failed to start dashboard in background:"), err.message);
16787
+ console.error(chalk63.red("Failed to start dashboard in background:"), err.message);
16400
16788
  process.exit(1);
16401
16789
  });
16402
16790
  setTimeout(() => {
@@ -16404,23 +16792,23 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
16404
16792
  child.unref();
16405
16793
  }
16406
16794
  }, 100);
16407
- console.log(chalk62.green("\u2713 Dashboard started in background"));
16795
+ console.log(chalk63.green("\u2713 Dashboard started in background"));
16408
16796
  if (traefikEnabled) {
16409
- console.log(` Frontend: ${chalk62.cyan(`https://${traefikDomain}`)}`);
16410
- console.log(` API: ${chalk62.cyan(`https://${traefikDomain}/api`)}`);
16797
+ console.log(` Frontend: ${chalk63.cyan(`https://${traefikDomain}`)}`);
16798
+ console.log(` API: ${chalk63.cyan(`https://${traefikDomain}/api`)}`);
16411
16799
  } else {
16412
- console.log(` Frontend: ${chalk62.cyan(`http://localhost:${dashboardPort}`)}`);
16413
- console.log(` API: ${chalk62.cyan(`http://localhost:${dashboardApiPort}`)}`);
16800
+ console.log(` Frontend: ${chalk63.cyan(`http://localhost:${dashboardPort}`)}`);
16801
+ console.log(` API: ${chalk63.cyan(`http://localhost:${dashboardApiPort}`)}`);
16414
16802
  }
16415
16803
  } else {
16416
16804
  if (traefikEnabled) {
16417
- console.log(` Frontend: ${chalk62.cyan(`https://${traefikDomain}`)}`);
16418
- console.log(` API: ${chalk62.cyan(`https://${traefikDomain}/api`)}`);
16805
+ console.log(` Frontend: ${chalk63.cyan(`https://${traefikDomain}`)}`);
16806
+ console.log(` API: ${chalk63.cyan(`https://${traefikDomain}/api`)}`);
16419
16807
  } else {
16420
- console.log(` Frontend: ${chalk62.cyan(`http://localhost:${dashboardPort}`)}`);
16421
- console.log(` API: ${chalk62.cyan(`http://localhost:${dashboardApiPort}`)}`);
16808
+ console.log(` Frontend: ${chalk63.cyan(`http://localhost:${dashboardPort}`)}`);
16809
+ console.log(` API: ${chalk63.cyan(`http://localhost:${dashboardApiPort}`)}`);
16422
16810
  }
16423
- console.log(chalk62.dim("\nPress Ctrl+C to stop\n"));
16811
+ console.log(chalk63.dim("\nPress Ctrl+C to stop\n"));
16424
16812
  const child = isProduction ? spawn2("node", [bundledServer], {
16425
16813
  stdio: "inherit",
16426
16814
  env: { ...process.env, DASHBOARD_PORT: String(dashboardPort) }
@@ -16430,41 +16818,41 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
16430
16818
  shell: true
16431
16819
  });
16432
16820
  child.on("error", (err) => {
16433
- console.error(chalk62.red("Failed to start dashboard:"), err.message);
16821
+ console.error(chalk63.red("Failed to start dashboard:"), err.message);
16434
16822
  process.exit(1);
16435
16823
  });
16436
16824
  }
16437
16825
  try {
16438
16826
  const { getTldrDaemonService: getTldrDaemonService2 } = await import("../tldr-daemon-T3THOUGT.js");
16439
16827
  const projectRoot = process.cwd();
16440
- const venvPath = join52(projectRoot, ".venv");
16441
- if (existsSync52(venvPath)) {
16442
- console.log(chalk62.dim("\nStarting TLDR daemon for project root..."));
16828
+ const venvPath = join54(projectRoot, ".venv");
16829
+ if (existsSync54(venvPath)) {
16830
+ console.log(chalk63.dim("\nStarting TLDR daemon for project root..."));
16443
16831
  const tldrService = getTldrDaemonService2(projectRoot, venvPath);
16444
16832
  await tldrService.start(true);
16445
- console.log(chalk62.green("\u2713 TLDR daemon started"));
16833
+ console.log(chalk63.green("\u2713 TLDR daemon started"));
16446
16834
  } else {
16447
- console.log(chalk62.dim("\nSkipping TLDR daemon (no .venv found)"));
16448
- console.log(chalk62.dim(" Run setup to create venv with llm-tldr"));
16835
+ console.log(chalk63.dim("\nSkipping TLDR daemon (no .venv found)"));
16836
+ console.log(chalk63.dim(" Run setup to create venv with llm-tldr"));
16449
16837
  }
16450
16838
  } catch (error) {
16451
- console.log(chalk62.yellow("\u26A0 Failed to start TLDR daemon:"), error?.message || String(error));
16452
- console.log(chalk62.dim(" TLDR will be unavailable but dashboard will work normally"));
16839
+ console.log(chalk63.yellow("\u26A0 Failed to start TLDR daemon:"), error?.message || String(error));
16840
+ console.log(chalk63.dim(" TLDR will be unavailable but dashboard will work normally"));
16453
16841
  }
16454
16842
  });
16455
16843
  program.command("down").description("Stop dashboard (and Traefik if enabled)").option("--skip-traefik", "Skip Traefik shutdown").action(async (options) => {
16456
- const { execSync: execSync9 } = await import("child_process");
16457
- const { join: join52 } = await import("path");
16458
- const { readFileSync: readFileSync46, existsSync: existsSync52 } = await import("fs");
16844
+ const { execSync: execSync10 } = await import("child_process");
16845
+ const { join: join54 } = await import("path");
16846
+ const { readFileSync: readFileSync48, existsSync: existsSync54 } = await import("fs");
16459
16847
  const { parse } = await import("@iarna/toml");
16460
- console.log(chalk62.bold("Stopping Panopticon...\n"));
16461
- const configFile = join52(process.env.HOME || "", ".panopticon", "config.toml");
16848
+ console.log(chalk63.bold("Stopping Panopticon...\n"));
16849
+ const configFile = join54(process.env.HOME || "", ".panopticon", "config.toml");
16462
16850
  let traefikEnabled = false;
16463
16851
  let dashboardPort = 3010;
16464
16852
  let dashboardApiPort = 3011;
16465
- if (existsSync52(configFile)) {
16853
+ if (existsSync54(configFile)) {
16466
16854
  try {
16467
- const configContent = readFileSync46(configFile, "utf-8");
16855
+ const configContent = readFileSync48(configFile, "utf-8");
16468
16856
  const config2 = parse(configContent);
16469
16857
  traefikEnabled = config2.traefik?.enabled === true;
16470
16858
  dashboardPort = config2.dashboard?.port || 3010;
@@ -16472,44 +16860,44 @@ program.command("down").description("Stop dashboard (and Traefik if enabled)").o
16472
16860
  } catch (error) {
16473
16861
  }
16474
16862
  }
16475
- console.log(chalk62.dim("Stopping dashboard..."));
16863
+ console.log(chalk63.dim("Stopping dashboard..."));
16476
16864
  try {
16477
- execSync9(`lsof -ti:${dashboardPort} | xargs kill -9 2>/dev/null || true`, { stdio: "pipe" });
16478
- execSync9(`lsof -ti:${dashboardApiPort} | xargs kill -9 2>/dev/null || true`, { stdio: "pipe" });
16479
- console.log(chalk62.green("\u2713 Dashboard stopped"));
16865
+ execSync10(`lsof -ti:${dashboardPort} | xargs kill -9 2>/dev/null || true`, { stdio: "pipe" });
16866
+ execSync10(`lsof -ti:${dashboardApiPort} | xargs kill -9 2>/dev/null || true`, { stdio: "pipe" });
16867
+ console.log(chalk63.green("\u2713 Dashboard stopped"));
16480
16868
  } catch {
16481
- console.log(chalk62.dim(" No dashboard processes found"));
16869
+ console.log(chalk63.dim(" No dashboard processes found"));
16482
16870
  }
16483
16871
  if (traefikEnabled && !options.skipTraefik) {
16484
- const traefikDir = join52(process.env.HOME || "", ".panopticon", "traefik");
16485
- if (existsSync52(traefikDir)) {
16486
- console.log(chalk62.dim("Stopping Traefik..."));
16872
+ const traefikDir = join54(process.env.HOME || "", ".panopticon", "traefik");
16873
+ if (existsSync54(traefikDir)) {
16874
+ console.log(chalk63.dim("Stopping Traefik..."));
16487
16875
  try {
16488
- execSync9("docker compose down", {
16876
+ execSync10("docker compose down", {
16489
16877
  cwd: traefikDir,
16490
16878
  stdio: "pipe"
16491
16879
  });
16492
- console.log(chalk62.green("\u2713 Traefik stopped"));
16880
+ console.log(chalk63.green("\u2713 Traefik stopped"));
16493
16881
  } catch (error) {
16494
- console.log(chalk62.yellow("\u26A0 Failed to stop Traefik"));
16882
+ console.log(chalk63.yellow("\u26A0 Failed to stop Traefik"));
16495
16883
  }
16496
16884
  }
16497
16885
  }
16498
16886
  try {
16499
16887
  const { getTldrDaemonService: getTldrDaemonService2 } = await import("../tldr-daemon-T3THOUGT.js");
16500
- const { exec: exec21 } = await import("child_process");
16501
- const { promisify: promisify21 } = await import("util");
16502
- const execAsync21 = promisify21(exec21);
16888
+ const { exec: exec22 } = await import("child_process");
16889
+ const { promisify: promisify22 } = await import("util");
16890
+ const execAsync22 = promisify22(exec22);
16503
16891
  const projectRoot = process.cwd();
16504
- const venvPath = join52(projectRoot, ".venv");
16505
- if (existsSync52(venvPath)) {
16506
- console.log(chalk62.dim("\nStopping TLDR daemon..."));
16892
+ const venvPath = join54(projectRoot, ".venv");
16893
+ if (existsSync54(venvPath)) {
16894
+ console.log(chalk63.dim("\nStopping TLDR daemon..."));
16507
16895
  const tldrService = getTldrDaemonService2(projectRoot, venvPath);
16508
16896
  await tldrService.stop();
16509
- console.log(chalk62.green("\u2713 TLDR daemon stopped"));
16897
+ console.log(chalk63.green("\u2713 TLDR daemon stopped"));
16510
16898
  }
16511
16899
  } catch (error) {
16512
- console.log(chalk62.dim(" (TLDR daemon not running)"));
16900
+ console.log(chalk63.dim(" (TLDR daemon not running)"));
16513
16901
  }
16514
16902
  console.log("");
16515
16903
  });