panopticon-cli 0.4.24 → 0.4.26

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.
@@ -51320,6 +51320,7 @@ var init_rally = __esm({
51320
51320
  "CreationDate",
51321
51321
  "LastUpdateDate",
51322
51322
  "Parent",
51323
+ "PortfolioItem",
51323
51324
  "_type"
51324
51325
  ];
51325
51326
  PRIORITY_MAP = {
@@ -51665,7 +51666,13 @@ var init_rally = __esm({
51665
51666
  const baseUrl = this.restApi.server.replace("/slm/webservice/", "");
51666
51667
  const url = `${baseUrl}/#/detail/${artifactType.toLowerCase()}/${objectId}`;
51667
51668
  let parentRef;
51668
- if (rallyArtifact.Parent) {
51669
+ if (rallyArtifact.PortfolioItem) {
51670
+ if (rallyArtifact.PortfolioItem.FormattedID) {
51671
+ parentRef = rallyArtifact.PortfolioItem.FormattedID;
51672
+ } else if (rallyArtifact.PortfolioItem._refObjectName) {
51673
+ parentRef = rallyArtifact.PortfolioItem._refObjectName;
51674
+ }
51675
+ } else if (rallyArtifact.Parent) {
51669
51676
  if (rallyArtifact.Parent.FormattedID) {
51670
51677
  parentRef = rallyArtifact.Parent.FormattedID;
51671
51678
  } else if (rallyArtifact.Parent._refObjectName) {
@@ -65656,6 +65663,91 @@ var init_agents = __esm({
65656
65663
  }
65657
65664
  });
65658
65665
 
65666
+ // review-status.ts
65667
+ var review_status_exports = {};
65668
+ __export(review_status_exports, {
65669
+ clearReviewStatus: () => clearReviewStatus,
65670
+ getReviewStatus: () => getReviewStatus,
65671
+ loadReviewStatuses: () => loadReviewStatuses,
65672
+ saveReviewStatuses: () => saveReviewStatuses,
65673
+ setReviewStatus: () => setReviewStatus
65674
+ });
65675
+ import { existsSync as existsSync19, readFileSync as readFileSync16, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14 } from "fs";
65676
+ import { join as join20, dirname as dirname2 } from "path";
65677
+ import { homedir as homedir10 } from "os";
65678
+ function loadReviewStatuses(filePath = DEFAULT_STATUS_FILE) {
65679
+ try {
65680
+ if (existsSync19(filePath)) {
65681
+ return JSON.parse(readFileSync16(filePath, "utf-8"));
65682
+ }
65683
+ } catch (err) {
65684
+ console.error("Failed to load review statuses:", err);
65685
+ }
65686
+ return {};
65687
+ }
65688
+ function saveReviewStatuses(statuses, filePath = DEFAULT_STATUS_FILE) {
65689
+ try {
65690
+ const dir = dirname2(filePath);
65691
+ if (!existsSync19(dir)) {
65692
+ mkdirSync14(dir, { recursive: true });
65693
+ }
65694
+ writeFileSync12(filePath, JSON.stringify(statuses, null, 2));
65695
+ } catch (err) {
65696
+ console.error("Failed to save review statuses:", err);
65697
+ }
65698
+ }
65699
+ function setReviewStatus(issueId, update, filePath = DEFAULT_STATUS_FILE) {
65700
+ const statuses = loadReviewStatuses(filePath);
65701
+ const existing = statuses[issueId] || {
65702
+ issueId,
65703
+ reviewStatus: "pending",
65704
+ testStatus: "pending",
65705
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
65706
+ readyForMerge: false
65707
+ };
65708
+ const merged = { ...existing, ...update };
65709
+ const history = [...existing.history || []];
65710
+ const now = (/* @__PURE__ */ new Date()).toISOString();
65711
+ if (update.reviewStatus && update.reviewStatus !== existing.reviewStatus) {
65712
+ history.push({ type: "review", status: update.reviewStatus, timestamp: now, notes: update.reviewNotes });
65713
+ }
65714
+ if (update.testStatus && update.testStatus !== existing.testStatus) {
65715
+ history.push({ type: "test", status: update.testStatus, timestamp: now, notes: update.testNotes });
65716
+ }
65717
+ if (update.mergeStatus && update.mergeStatus !== existing.mergeStatus) {
65718
+ history.push({ type: "merge", status: update.mergeStatus, timestamp: now });
65719
+ }
65720
+ while (history.length > 10)
65721
+ history.shift();
65722
+ const readyForMerge = update.readyForMerge !== void 0 ? update.readyForMerge : merged.reviewStatus === "passed" && merged.testStatus === "passed" && merged.mergeStatus !== "merged";
65723
+ const updated = {
65724
+ ...merged,
65725
+ issueId,
65726
+ updatedAt: now,
65727
+ readyForMerge,
65728
+ history
65729
+ };
65730
+ statuses[issueId] = updated;
65731
+ saveReviewStatuses(statuses, filePath);
65732
+ return updated;
65733
+ }
65734
+ function getReviewStatus(issueId, filePath = DEFAULT_STATUS_FILE) {
65735
+ const statuses = loadReviewStatuses(filePath);
65736
+ return statuses[issueId] || null;
65737
+ }
65738
+ function clearReviewStatus(issueId, filePath = DEFAULT_STATUS_FILE) {
65739
+ const statuses = loadReviewStatuses(filePath);
65740
+ delete statuses[issueId];
65741
+ saveReviewStatuses(statuses, filePath);
65742
+ }
65743
+ var DEFAULT_STATUS_FILE;
65744
+ var init_review_status = __esm({
65745
+ "review-status.ts"() {
65746
+ "use strict";
65747
+ DEFAULT_STATUS_FILE = join20(homedir10(), ".panopticon", "review-status.json");
65748
+ }
65749
+ });
65750
+
65659
65751
  // ../../lib/cloister/specialists.ts
65660
65752
  var specialists_exports = {};
65661
65753
  __export(specialists_exports, {
@@ -65715,16 +65807,16 @@ __export(specialists_exports, {
65715
65807
  wakeSpecialistOrQueue: () => wakeSpecialistOrQueue,
65716
65808
  wakeSpecialistWithTask: () => wakeSpecialistWithTask
65717
65809
  });
65718
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync12, existsSync as existsSync19, mkdirSync as mkdirSync14, readdirSync as readdirSync8, unlinkSync as unlinkSync6, appendFileSync as appendFileSync5 } from "fs";
65719
- import { join as join20, basename as basename3 } from "path";
65720
- import { homedir as homedir10 } from "os";
65810
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync13, existsSync as existsSync20, mkdirSync as mkdirSync15, readdirSync as readdirSync8, unlinkSync as unlinkSync6, appendFileSync as appendFileSync5 } from "fs";
65811
+ import { join as join21, basename as basename3 } from "path";
65812
+ import { homedir as homedir11 } from "os";
65721
65813
  import { exec as exec4 } from "child_process";
65722
65814
  import { promisify as promisify4 } from "util";
65723
65815
  function initSpecialistsDirectory() {
65724
- if (!existsSync19(SPECIALISTS_DIR)) {
65725
- mkdirSync14(SPECIALISTS_DIR, { recursive: true });
65816
+ if (!existsSync20(SPECIALISTS_DIR)) {
65817
+ mkdirSync15(SPECIALISTS_DIR, { recursive: true });
65726
65818
  }
65727
- if (!existsSync19(REGISTRY_FILE)) {
65819
+ if (!existsSync20(REGISTRY_FILE)) {
65728
65820
  const registry = {
65729
65821
  version: "2.0",
65730
65822
  // Updated for per-project structure
@@ -65748,7 +65840,7 @@ function initSpecialistsDirectory() {
65748
65840
  }
65749
65841
  function migrateRegistryIfNeeded() {
65750
65842
  try {
65751
- const content = readFileSync16(REGISTRY_FILE, "utf-8");
65843
+ const content = readFileSync17(REGISTRY_FILE, "utf-8");
65752
65844
  const registry = JSON.parse(content);
65753
65845
  if (registry.version === "2.0" || registry.projects) {
65754
65846
  return;
@@ -65778,7 +65870,7 @@ function migrateRegistryIfNeeded() {
65778
65870
  function loadRegistry() {
65779
65871
  initSpecialistsDirectory();
65780
65872
  try {
65781
- const content = readFileSync16(REGISTRY_FILE, "utf-8");
65873
+ const content = readFileSync17(REGISTRY_FILE, "utf-8");
65782
65874
  return JSON.parse(content);
65783
65875
  } catch (error) {
65784
65876
  console.error("Failed to load specialist registry:", error);
@@ -65796,28 +65888,28 @@ function loadRegistry() {
65796
65888
  }
65797
65889
  }
65798
65890
  function saveRegistry(registry) {
65799
- if (!existsSync19(SPECIALISTS_DIR)) {
65800
- mkdirSync14(SPECIALISTS_DIR, { recursive: true });
65891
+ if (!existsSync20(SPECIALISTS_DIR)) {
65892
+ mkdirSync15(SPECIALISTS_DIR, { recursive: true });
65801
65893
  }
65802
65894
  registry.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
65803
65895
  try {
65804
65896
  const content = JSON.stringify(registry, null, 2);
65805
- writeFileSync12(REGISTRY_FILE, content, "utf-8");
65897
+ writeFileSync13(REGISTRY_FILE, content, "utf-8");
65806
65898
  } catch (error) {
65807
65899
  console.error("Failed to save specialist registry:", error);
65808
65900
  throw error;
65809
65901
  }
65810
65902
  }
65811
65903
  function getSessionFilePath(name) {
65812
- return join20(SPECIALISTS_DIR, `${name}.session`);
65904
+ return join21(SPECIALISTS_DIR, `${name}.session`);
65813
65905
  }
65814
65906
  function getSessionId2(name) {
65815
65907
  const sessionFile = getSessionFilePath(name);
65816
- if (!existsSync19(sessionFile)) {
65908
+ if (!existsSync20(sessionFile)) {
65817
65909
  return null;
65818
65910
  }
65819
65911
  try {
65820
- return readFileSync16(sessionFile, "utf-8").trim();
65912
+ return readFileSync17(sessionFile, "utf-8").trim();
65821
65913
  } catch (error) {
65822
65914
  console.error(`Failed to read session file for ${name}:`, error);
65823
65915
  return null;
@@ -65827,7 +65919,7 @@ function setSessionId(name, sessionId) {
65827
65919
  initSpecialistsDirectory();
65828
65920
  const sessionFile = getSessionFilePath(name);
65829
65921
  try {
65830
- writeFileSync12(sessionFile, sessionId.trim(), "utf-8");
65922
+ writeFileSync13(sessionFile, sessionId.trim(), "utf-8");
65831
65923
  } catch (error) {
65832
65924
  console.error(`Failed to write session file for ${name}:`, error);
65833
65925
  throw error;
@@ -65835,7 +65927,7 @@ function setSessionId(name, sessionId) {
65835
65927
  }
65836
65928
  function clearSessionId(name) {
65837
65929
  const sessionFile = getSessionFilePath(name);
65838
- if (!existsSync19(sessionFile)) {
65930
+ if (!existsSync20(sessionFile)) {
65839
65931
  return false;
65840
65932
  }
65841
65933
  try {
@@ -65916,12 +66008,12 @@ async function spawnEphemeralSpecialist(projectKey, specialistType, task) {
65916
66008
  console.warn(`Warning: Could not resolve model for ${specialistType}, using default`);
65917
66009
  }
65918
66010
  const permissionFlags = specialistType === "merge-agent" ? "--dangerously-skip-permissions --permission-mode bypassPermissions" : "--dangerously-skip-permissions";
65919
- const agentDir = join20(homedir10(), ".panopticon", "agents", tmuxSession);
66011
+ const agentDir = join21(homedir11(), ".panopticon", "agents", tmuxSession);
65920
66012
  await execAsync4(`mkdir -p "${agentDir}"`, { encoding: "utf-8" });
65921
- const promptFile = join20(agentDir, "task-prompt.md");
65922
- writeFileSync12(promptFile, taskPrompt);
65923
- const launcherScript = join20(agentDir, "launcher.sh");
65924
- writeFileSync12(launcherScript, `#!/bin/bash
66013
+ const promptFile = join21(agentDir, "task-prompt.md");
66014
+ writeFileSync13(promptFile, taskPrompt);
66015
+ const launcherScript = join21(agentDir, "launcher.sh");
66016
+ writeFileSync13(launcherScript, `#!/bin/bash
65925
66017
  cd "${cwd}"
65926
66018
  prompt=$(cat "${promptFile}")
65927
66019
 
@@ -65998,6 +66090,8 @@ ${customPrompt}
65998
66090
  switch (specialistType) {
65999
66091
  case "review-agent":
66000
66092
  prompt += `Your task:
66093
+ 0. FIRST: Check if branch has any changes vs main (git diff --name-only main...HEAD)
66094
+ - If 0 files changed: mark as passed with note "branch identical to main" and STOP
66001
66095
  1. Review all changes in the branch
66002
66096
  2. Check for code quality issues, security concerns, and best practices
66003
66097
  3. Verify test FILES exist for new code (DO NOT run tests)
@@ -66007,6 +66101,7 @@ ${customPrompt}
66007
66101
  IMPORTANT: DO NOT run tests. You are the REVIEW agent.
66008
66102
 
66009
66103
  Update status via API:
66104
+ - If no changes (stale branch): POST to /api/workspaces/${task.issueId}/review-status with {"reviewStatus":"passed","reviewNotes":"No changes \u2014 branch identical to main"}
66010
66105
  - If issues found: POST to /api/workspaces/${task.issueId}/review-status with {"reviewStatus":"blocked","reviewNotes":"..."}
66011
66106
  - If review passes: POST with {"reviewStatus":"passed"} then queue test-agent`;
66012
66107
  break;
@@ -66159,17 +66254,17 @@ function scheduleLogCleanup(projectKey, specialistType) {
66159
66254
  });
66160
66255
  }
66161
66256
  function getProjectSpecialistDir(projectKey, specialistType) {
66162
- return join20(SPECIALISTS_DIR, projectKey, specialistType);
66257
+ return join21(SPECIALISTS_DIR, projectKey, specialistType);
66163
66258
  }
66164
66259
  function ensureProjectSpecialistDir(projectKey, specialistType) {
66165
66260
  const specialistDir = getProjectSpecialistDir(projectKey, specialistType);
66166
- const runsDir = join20(specialistDir, "runs");
66167
- const contextDir = join20(specialistDir, "context");
66168
- if (!existsSync19(runsDir)) {
66169
- mkdirSync14(runsDir, { recursive: true });
66261
+ const runsDir = join21(specialistDir, "runs");
66262
+ const contextDir = join21(specialistDir, "context");
66263
+ if (!existsSync20(runsDir)) {
66264
+ mkdirSync15(runsDir, { recursive: true });
66170
66265
  }
66171
- if (!existsSync19(contextDir)) {
66172
- mkdirSync14(contextDir, { recursive: true });
66266
+ if (!existsSync20(contextDir)) {
66267
+ mkdirSync15(contextDir, { recursive: true });
66173
66268
  }
66174
66269
  }
66175
66270
  function getProjectSpecialistMetadata(projectKey, specialistType) {
@@ -66398,12 +66493,12 @@ Your role: ${name === "merge-agent" ? "Resolve merge conflicts and ensure clean
66398
66493
  You will be woken up when your services are needed. For now, acknowledge your initialization and wait.
66399
66494
  Say: "I am the ${name} specialist, ready and waiting for tasks."`;
66400
66495
  try {
66401
- const agentDir = join20(homedir10(), ".panopticon", "agents", tmuxSession);
66496
+ const agentDir = join21(homedir11(), ".panopticon", "agents", tmuxSession);
66402
66497
  await execAsync4(`mkdir -p "${agentDir}"`, { encoding: "utf-8" });
66403
- const promptFile = join20(agentDir, "identity-prompt.md");
66404
- const launcherScript = join20(agentDir, "launcher.sh");
66405
- writeFileSync12(promptFile, identityPrompt);
66406
- writeFileSync12(launcherScript, `#!/bin/bash
66498
+ const promptFile = join21(agentDir, "identity-prompt.md");
66499
+ const launcherScript = join21(agentDir, "launcher.sh");
66500
+ writeFileSync13(promptFile, identityPrompt);
66501
+ writeFileSync13(launcherScript, `#!/bin/bash
66407
66502
  cd "${cwd}"
66408
66503
  prompt=$(cat "${promptFile}")
66409
66504
  exec claude --dangerously-skip-permissions --model ${model} "$prompt"
@@ -66506,11 +66601,11 @@ async function wakeSpecialist(name, taskPrompt, options = {}) {
66506
66601
  try {
66507
66602
  const isLargePrompt = taskPrompt.length > 500 || taskPrompt.includes("\n");
66508
66603
  if (isLargePrompt) {
66509
- if (!existsSync19(TASKS_DIR)) {
66510
- mkdirSync14(TASKS_DIR, { recursive: true });
66604
+ if (!existsSync20(TASKS_DIR)) {
66605
+ mkdirSync15(TASKS_DIR, { recursive: true });
66511
66606
  }
66512
- const taskFile = join20(TASKS_DIR, `${name}-${Date.now()}.md`);
66513
- writeFileSync12(taskFile, taskPrompt, "utf-8");
66607
+ const taskFile = join21(TASKS_DIR, `${name}-${Date.now()}.md`);
66608
+ writeFileSync13(taskFile, taskPrompt, "utf-8");
66514
66609
  const shortMessage = `Read and execute the task in: ${taskFile}`;
66515
66610
  sendKeys(tmuxSession, shortMessage);
66516
66611
  } else {
@@ -66567,11 +66662,41 @@ When done, provide feedback on:
66567
66662
 
66568
66663
  Use the send-feedback-to-agent skill to report findings back to the issue agent.`;
66569
66664
  break;
66570
- case "review-agent":
66665
+ case "review-agent": {
66666
+ const workspace = task.workspace || "unknown";
66667
+ let staleBranch = false;
66668
+ if (workspace !== "unknown") {
66669
+ try {
66670
+ const { stdout: diffOutput } = await execAsync4(
66671
+ `cd "${workspace}" && git fetch origin main 2>/dev/null; git diff --name-only main...HEAD 2>/dev/null`,
66672
+ { encoding: "utf-8", timeout: 15e3 }
66673
+ );
66674
+ const changedFiles = diffOutput.trim().split("\n").filter((f) => f.length > 0);
66675
+ if (changedFiles.length === 0) {
66676
+ staleBranch = true;
66677
+ console.log(`[specialist] review-agent: stale branch detected for ${task.issueId} \u2014 0 files changed vs main`);
66678
+ const { setReviewStatus: setReviewStatus3 } = await Promise.resolve().then(() => (init_review_status(), review_status_exports));
66679
+ setReviewStatus3(task.issueId.toUpperCase(), {
66680
+ reviewStatus: "passed",
66681
+ reviewNotes: "No changes to review \u2014 branch identical to main (already merged or stale)"
66682
+ });
66683
+ console.log(`[specialist] review-agent: auto-passed ${task.issueId} (stale branch)`);
66684
+ const tmuxSession = getTmuxSessionName("review-agent");
66685
+ const { saveAgentRuntimeState: saveAgentRuntimeState2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
66686
+ saveAgentRuntimeState2(tmuxSession, {
66687
+ state: "idle",
66688
+ lastActivity: (/* @__PURE__ */ new Date()).toISOString()
66689
+ });
66690
+ return { success: true, message: `Stale branch auto-passed for ${task.issueId}`, wasAlreadyRunning: false, error: void 0 };
66691
+ }
66692
+ } catch (err) {
66693
+ console.warn(`[specialist] review-agent: stale branch pre-check failed for ${task.issueId}:`, err);
66694
+ }
66695
+ }
66571
66696
  prompt = `New review task for ${task.issueId}:
66572
66697
 
66573
66698
  Branch: ${task.branch || "unknown"}
66574
- Workspace: ${task.workspace || "unknown"}
66699
+ Workspace: ${workspace}
66575
66700
  ${task.prUrl ? `PR URL: ${task.prUrl}` : ""}
66576
66701
 
66577
66702
  Your task:
@@ -66585,9 +66710,26 @@ The TEST agent will run tests in the next step.
66585
66710
 
66586
66711
  ## How to Review Changes
66587
66712
 
66713
+ **Step 0 (CRITICAL):** First check if there are ANY changes to review:
66714
+ \`\`\`bash
66715
+ cd ${workspace} && git diff --name-only main...HEAD
66716
+ \`\`\`
66717
+
66718
+ **If the diff is EMPTY (0 files changed):** The branch is stale or already merged into main. In this case:
66719
+ 1. Do NOT attempt a full review
66720
+ 2. Update status as passed immediately:
66721
+ \`\`\`bash
66722
+ curl -s -X POST ${apiUrl}/api/workspaces/${task.issueId}/review-status -H "Content-Type: application/json" -d '{"reviewStatus":"passed","reviewNotes":"No changes to review \u2014 branch identical to main (already merged or stale)"}' | jq .
66723
+ \`\`\`
66724
+ 3. Tell the issue agent:
66725
+ \`\`\`bash
66726
+ pan work tell ${task.issueId} "Review complete: branch has 0 diff from main \u2014 already merged or stale. Marking as passed."
66727
+ \`\`\`
66728
+ 4. Stop here \u2014 you are done.
66729
+
66588
66730
  **Step 1:** Get the list of changed files:
66589
66731
  \`\`\`bash
66590
- cd ${task.workspace || "unknown"} && git diff --name-only main...HEAD
66732
+ cd ${workspace} && git diff --name-only main...HEAD
66591
66733
  \`\`\`
66592
66734
 
66593
66735
  **Step 2:** Read the CURRENT version of each changed file using the Read tool.
@@ -66595,7 +66737,7 @@ Review the actual file contents \u2014 do NOT rely solely on diff output.
66595
66737
 
66596
66738
  **Step 3:** If you need to see what specifically changed, use:
66597
66739
  \`\`\`bash
66598
- cd ${task.workspace || "unknown"} && git diff main...HEAD -- <file>
66740
+ cd ${workspace} && git diff main...HEAD -- <file>
66599
66741
  \`\`\`
66600
66742
 
66601
66743
  ## Avoiding False Positives
@@ -66635,6 +66777,7 @@ curl -s -X POST ${apiUrl}/api/specialists/test-agent/queue -H "Content-Type: app
66635
66777
 
66636
66778
  \u26A0\uFE0F VERIFICATION: After running each curl, confirm you see valid JSON output. If you get an error, report it.`;
66637
66779
  break;
66780
+ }
66638
66781
  case "test-agent":
66639
66782
  prompt = `New test task for ${task.issueId}:
66640
66783
 
@@ -66820,8 +66963,8 @@ function getNextSpecialistTask(specialistName) {
66820
66963
  }
66821
66964
  async function sendFeedbackToAgent(feedback) {
66822
66965
  const { fromSpecialist, toIssueId, summary, details } = feedback;
66823
- if (!existsSync19(FEEDBACK_DIR)) {
66824
- mkdirSync14(FEEDBACK_DIR, { recursive: true });
66966
+ if (!existsSync20(FEEDBACK_DIR)) {
66967
+ mkdirSync15(FEEDBACK_DIR, { recursive: true });
66825
66968
  }
66826
66969
  const fullFeedback = {
66827
66970
  ...feedback,
@@ -66894,11 +67037,11 @@ ${details}
66894
67037
  return message;
66895
67038
  }
66896
67039
  function getPendingFeedback(issueId) {
66897
- if (!existsSync19(FEEDBACK_LOG)) {
67040
+ if (!existsSync20(FEEDBACK_LOG)) {
66898
67041
  return [];
66899
67042
  }
66900
67043
  try {
66901
- const content = readFileSync16(FEEDBACK_LOG, "utf-8");
67044
+ const content = readFileSync17(FEEDBACK_LOG, "utf-8");
66902
67045
  const lines = content.trim().split("\n").filter((l) => l.length > 0);
66903
67046
  const allFeedback = lines.map((line) => JSON.parse(line));
66904
67047
  return allFeedback.filter((f) => f.toIssueId.toLowerCase() === issueId.toLowerCase());
@@ -66917,11 +67060,11 @@ function getFeedbackStats() {
66917
67060
  byType: {},
66918
67061
  total: 0
66919
67062
  };
66920
- if (!existsSync19(FEEDBACK_LOG)) {
67063
+ if (!existsSync20(FEEDBACK_LOG)) {
66921
67064
  return stats;
66922
67065
  }
66923
67066
  try {
66924
- const content = readFileSync16(FEEDBACK_LOG, "utf-8");
67067
+ const content = readFileSync17(FEEDBACK_LOG, "utf-8");
66925
67068
  const lines = content.trim().split("\n").filter((l) => l.length > 0);
66926
67069
  for (const line of lines) {
66927
67070
  const feedback = JSON.parse(line);
@@ -66945,9 +67088,9 @@ var init_specialists = __esm({
66945
67088
  init_tmux();
66946
67089
  init_hooks();
66947
67090
  execAsync4 = promisify4(exec4);
66948
- SPECIALISTS_DIR = join20(PANOPTICON_HOME2, "specialists");
66949
- REGISTRY_FILE = join20(SPECIALISTS_DIR, "registry.json");
66950
- TASKS_DIR = join20(SPECIALISTS_DIR, "tasks");
67091
+ SPECIALISTS_DIR = join21(PANOPTICON_HOME2, "specialists");
67092
+ REGISTRY_FILE = join21(SPECIALISTS_DIR, "registry.json");
67093
+ TASKS_DIR = join21(SPECIALISTS_DIR, "tasks");
66951
67094
  DEFAULT_SPECIALISTS = [
66952
67095
  {
66953
67096
  name: "merge-agent",
@@ -66972,16 +67115,16 @@ var init_specialists = __esm({
66972
67115
  }
66973
67116
  ];
66974
67117
  gracePeriodStates = /* @__PURE__ */ new Map();
66975
- FEEDBACK_DIR = join20(PANOPTICON_HOME2, "specialists", "feedback");
66976
- FEEDBACK_LOG = join20(FEEDBACK_DIR, "feedback.jsonl");
67118
+ FEEDBACK_DIR = join21(PANOPTICON_HOME2, "specialists", "feedback");
67119
+ FEEDBACK_LOG = join21(FEEDBACK_DIR, "feedback.jsonl");
66977
67120
  }
66978
67121
  });
66979
67122
 
66980
67123
  // ../../lib/cloister/validation.ts
66981
67124
  import { exec as exec8 } from "child_process";
66982
67125
  import { promisify as promisify8 } from "util";
66983
- import { join as join31 } from "path";
66984
- import { existsSync as existsSync30 } from "fs";
67126
+ import { join as join32 } from "path";
67127
+ import { existsSync as existsSync31 } from "fs";
66985
67128
  function parseValidationOutput(output, exitCode) {
66986
67129
  const lines = output.split("\n");
66987
67130
  const failures = [];
@@ -67068,8 +67211,8 @@ function parseValidationOutput(output, exitCode) {
67068
67211
  }
67069
67212
  async function runMergeValidation(context) {
67070
67213
  const { projectPath, validationScript } = context;
67071
- const scriptPath = validationScript || join31(projectPath, "scripts", "validate-merge.sh");
67072
- if (!existsSync30(scriptPath)) {
67214
+ const scriptPath = validationScript || join32(projectPath, "scripts", "validate-merge.sh");
67215
+ if (!existsSync31(scriptPath)) {
67073
67216
  return {
67074
67217
  success: false,
67075
67218
  valid: false,
@@ -67141,14 +67284,14 @@ var init_validation = __esm({
67141
67284
  });
67142
67285
 
67143
67286
  // ../../lib/git-utils.ts
67144
- import { existsSync as existsSync31, unlinkSync as unlinkSync10, readdirSync as readdirSync12 } from "fs";
67145
- import { join as join32 } from "path";
67287
+ import { existsSync as existsSync32, unlinkSync as unlinkSync10, readdirSync as readdirSync12 } from "fs";
67288
+ import { join as join33 } from "path";
67146
67289
  import { exec as exec9 } from "child_process";
67147
67290
  import { promisify as promisify9 } from "util";
67148
67291
  async function hasRunningGitProcesses(repoPath) {
67149
67292
  try {
67150
67293
  try {
67151
- const gitDir = join32(repoPath, ".git");
67294
+ const gitDir = join33(repoPath, ".git");
67152
67295
  const { stdout } = await execAsync9(`fuser "${gitDir}" 2>/dev/null`, {
67153
67296
  encoding: "utf-8"
67154
67297
  });
@@ -67170,16 +67313,16 @@ async function hasRunningGitProcesses(repoPath) {
67170
67313
  }
67171
67314
  function findGitLockFiles(repoPath) {
67172
67315
  const lockFiles = [];
67173
- const indexLock = join32(repoPath, ".git", "index.lock");
67174
- if (existsSync31(indexLock)) {
67316
+ const indexLock = join33(repoPath, ".git", "index.lock");
67317
+ if (existsSync32(indexLock)) {
67175
67318
  lockFiles.push(indexLock);
67176
67319
  }
67177
- const refsDir = join32(repoPath, ".git", "refs");
67178
- if (existsSync31(refsDir)) {
67320
+ const refsDir = join33(repoPath, ".git", "refs");
67321
+ if (existsSync32(refsDir)) {
67179
67322
  const findLocksRecursive = (dir) => {
67180
67323
  const entries = readdirSync12(dir, { withFileTypes: true });
67181
67324
  for (const entry of entries) {
67182
- const fullPath = join32(dir, entry.name);
67325
+ const fullPath = join33(dir, entry.name);
67183
67326
  if (entry.isDirectory()) {
67184
67327
  findLocksRecursive(fullPath);
67185
67328
  } else if (entry.name.endsWith(".lock")) {
@@ -67238,17 +67381,17 @@ __export(merge_agent_exports, {
67238
67381
  spawnMergeAgent: () => spawnMergeAgent,
67239
67382
  spawnMergeAgentForBranches: () => spawnMergeAgentForBranches
67240
67383
  });
67241
- import { readFileSync as readFileSync25, existsSync as existsSync32, mkdirSync as mkdirSync21, appendFileSync as appendFileSync7 } from "fs";
67242
- import { join as join33, dirname as dirname4 } from "path";
67384
+ import { readFileSync as readFileSync26, existsSync as existsSync33, mkdirSync as mkdirSync22, appendFileSync as appendFileSync7 } from "fs";
67385
+ import { join as join34, dirname as dirname5 } from "path";
67243
67386
  import { fileURLToPath as fileURLToPath2 } from "url";
67244
67387
  import { exec as exec10 } from "child_process";
67245
67388
  import { promisify as promisify10 } from "util";
67246
67389
  function buildMergePrompt(context) {
67247
- const templatePath = join33(__dirname2, "prompts", "merge-agent.md");
67248
- if (!existsSync32(templatePath)) {
67390
+ const templatePath = join34(__dirname2, "prompts", "merge-agent.md");
67391
+ if (!existsSync33(templatePath)) {
67249
67392
  throw new Error(`Merge agent prompt template not found at ${templatePath}`);
67250
67393
  }
67251
- const template = readFileSync25(templatePath, "utf-8");
67394
+ const template = readFileSync26(templatePath, "utf-8");
67252
67395
  const prompt = template.replace(/\{\{projectPath\}\}/g, context.projectPath).replace(/\{\{sourceBranch\}\}/g, context.sourceBranch).replace(/\{\{targetBranch\}\}/g, context.targetBranch).replace(/\{\{issueId\}\}/g, context.issueId).replace(
67253
67396
  /\{\{conflictFiles\}\}/g,
67254
67397
  context.conflictFiles.map((f) => ` - ${f}`).join("\n")
@@ -67256,23 +67399,23 @@ function buildMergePrompt(context) {
67256
67399
  return prompt;
67257
67400
  }
67258
67401
  function detectTestCommand(projectPath) {
67259
- const packageJsonPath = join33(projectPath, "package.json");
67260
- if (existsSync32(packageJsonPath)) {
67402
+ const packageJsonPath = join34(projectPath, "package.json");
67403
+ if (existsSync33(packageJsonPath)) {
67261
67404
  try {
67262
- const packageJson = JSON.parse(readFileSync25(packageJsonPath, "utf-8"));
67405
+ const packageJson = JSON.parse(readFileSync26(packageJsonPath, "utf-8"));
67263
67406
  if (packageJson.scripts?.test) {
67264
67407
  return "npm test";
67265
67408
  }
67266
67409
  } catch {
67267
67410
  }
67268
67411
  }
67269
- if (existsSync32(join33(projectPath, "pom.xml"))) {
67412
+ if (existsSync33(join34(projectPath, "pom.xml"))) {
67270
67413
  return "mvn test";
67271
67414
  }
67272
- if (existsSync32(join33(projectPath, "Cargo.toml"))) {
67415
+ if (existsSync33(join34(projectPath, "Cargo.toml"))) {
67273
67416
  return "cargo test";
67274
67417
  }
67275
- if (existsSync32(join33(projectPath, "pytest.ini")) || existsSync32(join33(projectPath, "setup.py"))) {
67418
+ if (existsSync33(join34(projectPath, "pytest.ini")) || existsSync33(join34(projectPath, "setup.py"))) {
67276
67419
  return "pytest";
67277
67420
  }
67278
67421
  return "skip";
@@ -67286,8 +67429,8 @@ async function conditionalBeadsCompaction(projectPath) {
67286
67429
  console.log(`[merge-agent] bd not available, skipping compaction`);
67287
67430
  return;
67288
67431
  }
67289
- const beadsDir = join33(projectPath, ".beads");
67290
- if (!existsSync32(beadsDir)) {
67432
+ const beadsDir = join34(projectPath, ".beads");
67433
+ if (!existsSync33(beadsDir)) {
67291
67434
  console.log(`[merge-agent] No .beads directory, skipping compaction`);
67292
67435
  return;
67293
67436
  }
@@ -67324,12 +67467,12 @@ async function conditionalBeadsCompaction(projectPath) {
67324
67467
  async function postMergeCleanup(issueId, projectPath) {
67325
67468
  console.log(`[merge-agent] Running post-merge cleanup for ${issueId}`);
67326
67469
  try {
67327
- const activePrdPath = join33(projectPath, "docs/prds/active", `${issueId.toLowerCase()}-plan.md`);
67328
- const completedPrdPath = join33(projectPath, "docs/prds/completed", `${issueId.toLowerCase()}-plan.md`);
67329
- if (existsSync32(activePrdPath)) {
67330
- const completedDir = dirname4(completedPrdPath);
67331
- if (!existsSync32(completedDir)) {
67332
- mkdirSync21(completedDir, { recursive: true });
67470
+ const activePrdPath = join34(projectPath, "docs/prds/active", `${issueId.toLowerCase()}-plan.md`);
67471
+ const completedPrdPath = join34(projectPath, "docs/prds/completed", `${issueId.toLowerCase()}-plan.md`);
67472
+ if (existsSync33(activePrdPath)) {
67473
+ const completedDir = dirname5(completedPrdPath);
67474
+ if (!existsSync33(completedDir)) {
67475
+ mkdirSync22(completedDir, { recursive: true });
67333
67476
  }
67334
67477
  await execAsync10(`git mv "${activePrdPath}" "${completedPrdPath}"`, { cwd: projectPath, encoding: "utf-8" });
67335
67478
  await execAsync10(`git commit -m "Move ${issueId} PRD to completed"`, { cwd: projectPath, encoding: "utf-8" });
@@ -67514,8 +67657,8 @@ function parseAgentOutput(output) {
67514
67657
  }
67515
67658
  }
67516
67659
  function logMergeHistory(context, result, sessionId) {
67517
- if (!existsSync32(MERGE_HISTORY_DIR)) {
67518
- mkdirSync21(MERGE_HISTORY_DIR, { recursive: true });
67660
+ if (!existsSync33(MERGE_HISTORY_DIR)) {
67661
+ mkdirSync22(MERGE_HISTORY_DIR, { recursive: true });
67519
67662
  }
67520
67663
  const entry = {
67521
67664
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -67970,10 +68113,10 @@ var init_merge_agent = __esm({
67970
68113
  init_git_utils();
67971
68114
  execAsync10 = promisify10(exec10);
67972
68115
  __filename = fileURLToPath2(import.meta.url);
67973
- __dirname2 = dirname4(__filename);
67974
- SPECIALISTS_DIR2 = join33(PANOPTICON_HOME2, "specialists");
67975
- MERGE_HISTORY_DIR = join33(SPECIALISTS_DIR2, "merge-agent");
67976
- MERGE_HISTORY_FILE = join33(MERGE_HISTORY_DIR, "history.jsonl");
68116
+ __dirname2 = dirname5(__filename);
68117
+ SPECIALISTS_DIR2 = join34(PANOPTICON_HOME2, "specialists");
68118
+ MERGE_HISTORY_DIR = join34(SPECIALISTS_DIR2, "merge-agent");
68119
+ MERGE_HISTORY_FILE = join34(MERGE_HISTORY_DIR, "history.jsonl");
67977
68120
  MERGE_TIMEOUT_MS = 15 * 60 * 1e3;
67978
68121
  }
67979
68122
  });
@@ -85980,10 +86123,10 @@ init_specialists();
85980
86123
  init_agents();
85981
86124
  init_tmux();
85982
86125
  init_jsonl_parser();
85983
- import { existsSync as existsSync20, readFileSync as readFileSync17, statSync as statSync4, mkdirSync as mkdirSync15, writeFileSync as writeFileSync13 } from "fs";
85984
- import { join as join21 } from "path";
85985
- import { homedir as homedir11 } from "os";
85986
- var CLAUDE_PROJECTS_DIR2 = join21(homedir11(), ".claude", "projects");
86126
+ import { existsSync as existsSync21, readFileSync as readFileSync18, statSync as statSync4, mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
86127
+ import { join as join22 } from "path";
86128
+ import { homedir as homedir12 } from "os";
86129
+ var CLAUDE_PROJECTS_DIR2 = join22(homedir12(), ".claude", "projects");
85987
86130
  var ClaudeCodeRuntime = class {
85988
86131
  name = "claude-code";
85989
86132
  /**
@@ -85993,15 +86136,15 @@ var ClaudeCodeRuntime = class {
85993
86136
  * We need to find the project directory that contains sessions for this workspace.
85994
86137
  */
85995
86138
  getProjectDirForWorkspace(workspace) {
85996
- if (!existsSync20(CLAUDE_PROJECTS_DIR2)) {
86139
+ if (!existsSync21(CLAUDE_PROJECTS_DIR2)) {
85997
86140
  return null;
85998
86141
  }
85999
86142
  const projectDirs = getProjectDirs();
86000
86143
  for (const projectDir of projectDirs) {
86001
- const indexPath = join21(projectDir, "sessions-index.json");
86002
- if (existsSync20(indexPath)) {
86144
+ const indexPath = join22(projectDir, "sessions-index.json");
86145
+ if (existsSync21(indexPath)) {
86003
86146
  try {
86004
- const indexContent = readFileSync17(indexPath, "utf-8");
86147
+ const indexContent = readFileSync18(indexPath, "utf-8");
86005
86148
  if (indexContent.includes(workspace)) {
86006
86149
  return projectDir;
86007
86150
  }
@@ -86015,12 +86158,12 @@ var ClaudeCodeRuntime = class {
86015
86158
  * Get the active session ID for an agent from the sessions index
86016
86159
  */
86017
86160
  getActiveSessionId(projectDir) {
86018
- const indexPath = join21(projectDir, "sessions-index.json");
86019
- if (!existsSync20(indexPath)) {
86161
+ const indexPath = join22(projectDir, "sessions-index.json");
86162
+ if (!existsSync21(indexPath)) {
86020
86163
  return null;
86021
86164
  }
86022
86165
  try {
86023
- const indexContent = readFileSync17(indexPath, "utf-8");
86166
+ const indexContent = readFileSync18(indexPath, "utf-8");
86024
86167
  const index = JSON.parse(indexContent);
86025
86168
  if (index.sessions && Array.isArray(index.sessions)) {
86026
86169
  const sessions = index.sessions;
@@ -86056,8 +86199,8 @@ var ClaudeCodeRuntime = class {
86056
86199
  }
86057
86200
  const sessionId = this.getActiveSessionId(projectDir);
86058
86201
  if (sessionId) {
86059
- const sessionPath = join21(projectDir, `${sessionId}.jsonl`);
86060
- if (existsSync20(sessionPath)) {
86202
+ const sessionPath = join22(projectDir, `${sessionId}.jsonl`);
86203
+ if (existsSync21(sessionPath)) {
86061
86204
  return sessionPath;
86062
86205
  }
86063
86206
  }
@@ -86070,7 +86213,7 @@ var ClaudeCodeRuntime = class {
86070
86213
  */
86071
86214
  getLastActivity(agentId) {
86072
86215
  const sessionPath = this.getSessionPath(agentId);
86073
- if (!sessionPath || !existsSync20(sessionPath)) {
86216
+ if (!sessionPath || !existsSync21(sessionPath)) {
86074
86217
  return null;
86075
86218
  }
86076
86219
  try {
@@ -86084,12 +86227,12 @@ var ClaudeCodeRuntime = class {
86084
86227
  * Read active heartbeat file if it exists
86085
86228
  */
86086
86229
  getActiveHeartbeat(agentId) {
86087
- const heartbeatPath = join21(homedir11(), ".panopticon", "heartbeats", `${agentId}.json`);
86088
- if (!existsSync20(heartbeatPath)) {
86230
+ const heartbeatPath = join22(homedir12(), ".panopticon", "heartbeats", `${agentId}.json`);
86231
+ if (!existsSync21(heartbeatPath)) {
86089
86232
  return null;
86090
86233
  }
86091
86234
  try {
86092
- const content = readFileSync17(heartbeatPath, "utf-8");
86235
+ const content = readFileSync18(heartbeatPath, "utf-8");
86093
86236
  const data = JSON.parse(content);
86094
86237
  const timestamp2 = new Date(data.timestamp);
86095
86238
  const now = /* @__PURE__ */ new Date();
@@ -86193,11 +86336,11 @@ var ClaudeCodeRuntime = class {
86193
86336
  throw new Error(`Agent ${agentId} is not running`);
86194
86337
  }
86195
86338
  sendKeys(agentId, message);
86196
- const mailDir = join21(getAgentDir(agentId), "mail");
86197
- mkdirSync15(mailDir, { recursive: true });
86339
+ const mailDir = join22(getAgentDir(agentId), "mail");
86340
+ mkdirSync16(mailDir, { recursive: true });
86198
86341
  const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
86199
- writeFileSync13(
86200
- join21(mailDir, `${timestamp2}.md`),
86342
+ writeFileSync14(
86343
+ join22(mailDir, `${timestamp2}.md`),
86201
86344
  `# Message
86202
86345
 
86203
86346
  ${message}
@@ -86368,8 +86511,8 @@ init_agents();
86368
86511
 
86369
86512
  // ../../lib/cloister/triggers.ts
86370
86513
  init_config();
86371
- import { existsSync as existsSync21 } from "fs";
86372
- import { join as join22 } from "path";
86514
+ import { existsSync as existsSync22 } from "fs";
86515
+ import { join as join23 } from "path";
86373
86516
  import { exec as exec5 } from "child_process";
86374
86517
  import { promisify as promisify5 } from "util";
86375
86518
  var execAsync5 = promisify5(exec5);
@@ -86461,8 +86604,8 @@ async function checkPlanningComplete(agentId, workspace, issueId, config2) {
86461
86604
  }
86462
86605
  } catch (error) {
86463
86606
  }
86464
- const prdPath = join22(workspace, `docs/prds/active/${issueId.toLowerCase()}-plan.md`);
86465
- if (existsSync21(prdPath)) {
86607
+ const prdPath = join23(workspace, `docs/prds/active/${issueId.toLowerCase()}-plan.md`);
86608
+ if (existsSync22(prdPath)) {
86466
86609
  signals.push("PRD file exists");
86467
86610
  signalCount++;
86468
86611
  }
@@ -86609,12 +86752,12 @@ async function checkAllTriggers(agentId, workspace, issueId, currentModel, healt
86609
86752
 
86610
86753
  // ../../lib/cloister/handoff.ts
86611
86754
  init_agents();
86612
- import { writeFileSync as writeFileSync14, mkdirSync as mkdirSync16 } from "fs";
86613
- import { join as join24 } from "path";
86755
+ import { writeFileSync as writeFileSync15, mkdirSync as mkdirSync17 } from "fs";
86756
+ import { join as join25 } from "path";
86614
86757
 
86615
86758
  // ../../lib/cloister/handoff-context.ts
86616
- import { existsSync as existsSync22, readFileSync as readFileSync18 } from "fs";
86617
- import { join as join23 } from "path";
86759
+ import { existsSync as existsSync23, readFileSync as readFileSync19 } from "fs";
86760
+ import { join as join24 } from "path";
86618
86761
  import { exec as exec6 } from "child_process";
86619
86762
  import { promisify as promisify6 } from "util";
86620
86763
  var execAsync6 = promisify6(exec6);
@@ -86638,13 +86781,13 @@ async function captureHandoffContext(agentState, targetModel, reason) {
86638
86781
  }
86639
86782
  async function captureFiles(context, workspace) {
86640
86783
  try {
86641
- const stateFile = join23(workspace, ".planning/STATE.md");
86642
- if (existsSync22(stateFile)) {
86643
- context.stateFile = readFileSync18(stateFile, "utf-8");
86784
+ const stateFile = join24(workspace, ".planning/STATE.md");
86785
+ if (existsSync23(stateFile)) {
86786
+ context.stateFile = readFileSync19(stateFile, "utf-8");
86644
86787
  }
86645
- const claudeMd = join23(workspace, "CLAUDE.md");
86646
- if (existsSync22(claudeMd)) {
86647
- context.claudeMd = readFileSync18(claudeMd, "utf-8");
86788
+ const claudeMd = join24(workspace, "CLAUDE.md");
86789
+ if (existsSync23(claudeMd)) {
86790
+ context.claudeMd = readFileSync19(claudeMd, "utf-8");
86648
86791
  }
86649
86792
  } catch (error) {
86650
86793
  console.error("Error capturing files:", error);
@@ -86835,10 +86978,10 @@ async function performKillAndSpawn(state, options) {
86835
86978
  const context = await captureHandoffContext(state, options.targetModel, options.reason);
86836
86979
  stopAgent(state.id);
86837
86980
  const prompt = buildHandoffPrompt(context, options.additionalInstructions);
86838
- const handoffDir = join24(getAgentDir(state.id), "handoffs");
86839
- mkdirSync16(handoffDir, { recursive: true });
86840
- const handoffFile = join24(handoffDir, `handoff-${Date.now()}.md`);
86841
- writeFileSync14(handoffFile, prompt);
86981
+ const handoffDir = join25(getAgentDir(state.id), "handoffs");
86982
+ mkdirSync17(handoffDir, { recursive: true });
86983
+ const handoffFile = join25(handoffDir, `handoff-${Date.now()}.md`);
86984
+ writeFileSync15(handoffFile, prompt);
86842
86985
  const newState = await spawnAgent({
86843
86986
  issueId: state.issueId,
86844
86987
  workspace: state.workspace,
@@ -86944,13 +87087,13 @@ function sleep(ms) {
86944
87087
 
86945
87088
  // ../../lib/cloister/handoff-logger.ts
86946
87089
  init_paths();
86947
- import { existsSync as existsSync24, mkdirSync as mkdirSync17, appendFileSync as appendFileSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync15 } from "fs";
86948
- import { join as join25 } from "path";
86949
- var HANDOFF_LOG_FILE = join25(PANOPTICON_HOME2, "logs", "handoffs.jsonl");
87090
+ import { existsSync as existsSync25, mkdirSync as mkdirSync18, appendFileSync as appendFileSync6, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "fs";
87091
+ import { join as join26 } from "path";
87092
+ var HANDOFF_LOG_FILE = join26(PANOPTICON_HOME2, "logs", "handoffs.jsonl");
86950
87093
  function ensureLogDir3() {
86951
- const logDir = join25(PANOPTICON_HOME2, "logs");
86952
- if (!existsSync24(logDir)) {
86953
- mkdirSync17(logDir, { recursive: true });
87094
+ const logDir = join26(PANOPTICON_HOME2, "logs");
87095
+ if (!existsSync25(logDir)) {
87096
+ mkdirSync18(logDir, { recursive: true });
86954
87097
  }
86955
87098
  }
86956
87099
  function logHandoffEvent(event) {
@@ -86991,10 +87134,10 @@ function createHandoffEvent(agentId, issueId, context, trigger, success, errorMe
86991
87134
  }
86992
87135
  function readHandoffEvents(limit) {
86993
87136
  ensureLogDir3();
86994
- if (!existsSync24(HANDOFF_LOG_FILE)) {
87137
+ if (!existsSync25(HANDOFF_LOG_FILE)) {
86995
87138
  return [];
86996
87139
  }
86997
- const content = readFileSync19(HANDOFF_LOG_FILE, "utf-8");
87140
+ const content = readFileSync20(HANDOFF_LOG_FILE, "utf-8");
86998
87141
  const lines = content.trim().split("\n").filter((line) => line.trim());
86999
87142
  const events = lines.map((line) => JSON.parse(line));
87000
87143
  events.reverse();
@@ -87052,8 +87195,8 @@ function getHandoffStats() {
87052
87195
 
87053
87196
  // ../../lib/cloister/fpp-violations.ts
87054
87197
  init_hooks();
87055
- import { readFileSync as readFileSync20, existsSync as existsSync25, writeFileSync as writeFileSync16, mkdirSync as mkdirSync18, unlinkSync as unlinkSync7 } from "fs";
87056
- import { join as join26, dirname as dirname2 } from "path";
87198
+ import { readFileSync as readFileSync21, existsSync as existsSync26, writeFileSync as writeFileSync17, mkdirSync as mkdirSync19, unlinkSync as unlinkSync7 } from "fs";
87199
+ import { join as join27, dirname as dirname3 } from "path";
87057
87200
  init_paths();
87058
87201
  var DEFAULT_FPP_CONFIG = {
87059
87202
  hook_idle_minutes: 5,
@@ -87061,13 +87204,13 @@ var DEFAULT_FPP_CONFIG = {
87061
87204
  review_pending_minutes: 15,
87062
87205
  max_nudges: 3
87063
87206
  };
87064
- var VIOLATIONS_DATA_FILE = join26(PANOPTICON_HOME2, "fpp-violations.json");
87207
+ var VIOLATIONS_DATA_FILE = join27(PANOPTICON_HOME2, "fpp-violations.json");
87065
87208
  function loadViolations() {
87066
- if (!existsSync25(VIOLATIONS_DATA_FILE)) {
87209
+ if (!existsSync26(VIOLATIONS_DATA_FILE)) {
87067
87210
  return /* @__PURE__ */ new Map();
87068
87211
  }
87069
87212
  try {
87070
- const fileContent = readFileSync20(VIOLATIONS_DATA_FILE, "utf-8");
87213
+ const fileContent = readFileSync21(VIOLATIONS_DATA_FILE, "utf-8");
87071
87214
  const persisted = JSON.parse(fileContent);
87072
87215
  return new Map(persisted.violations || []);
87073
87216
  } catch (error) {
@@ -87077,16 +87220,16 @@ function loadViolations() {
87077
87220
  }
87078
87221
  function saveViolations(violations) {
87079
87222
  try {
87080
- const dir = dirname2(VIOLATIONS_DATA_FILE);
87081
- if (!existsSync25(dir)) {
87082
- mkdirSync18(dir, { recursive: true });
87223
+ const dir = dirname3(VIOLATIONS_DATA_FILE);
87224
+ if (!existsSync26(dir)) {
87225
+ mkdirSync19(dir, { recursive: true });
87083
87226
  }
87084
87227
  const persisted = {
87085
87228
  violations: Array.from(violations.entries())
87086
87229
  };
87087
87230
  const tempFile = `${VIOLATIONS_DATA_FILE}.tmp`;
87088
- writeFileSync16(tempFile, JSON.stringify(persisted, null, 2));
87089
- writeFileSync16(VIOLATIONS_DATA_FILE, readFileSync20(tempFile));
87231
+ writeFileSync17(tempFile, JSON.stringify(persisted, null, 2));
87232
+ writeFileSync17(VIOLATIONS_DATA_FILE, readFileSync21(tempFile));
87090
87233
  try {
87091
87234
  unlinkSync7(tempFile);
87092
87235
  } catch (unlinkError) {
@@ -87179,11 +87322,11 @@ function clearOldViolations(hoursOld = 24) {
87179
87322
  // ../../lib/cloister/cost-monitor.ts
87180
87323
  init_paths();
87181
87324
  init_config();
87182
- import { readFileSync as readFileSync21, existsSync as existsSync26, writeFileSync as writeFileSync17, mkdirSync as mkdirSync19, unlinkSync as unlinkSync8 } from "fs";
87183
- import { join as join27, dirname as dirname3 } from "path";
87184
- var COST_DATA_FILE = join27(PANOPTICON_HOME2, "cost-data.json");
87325
+ import { readFileSync as readFileSync22, existsSync as existsSync27, writeFileSync as writeFileSync18, mkdirSync as mkdirSync20, unlinkSync as unlinkSync8 } from "fs";
87326
+ import { join as join28, dirname as dirname4 } from "path";
87327
+ var COST_DATA_FILE = join28(PANOPTICON_HOME2, "cost-data.json");
87185
87328
  function loadCostData() {
87186
- if (!existsSync26(COST_DATA_FILE)) {
87329
+ if (!existsSync27(COST_DATA_FILE)) {
87187
87330
  return {
87188
87331
  perAgent: /* @__PURE__ */ new Map(),
87189
87332
  perIssue: /* @__PURE__ */ new Map(),
@@ -87192,7 +87335,7 @@ function loadCostData() {
87192
87335
  };
87193
87336
  }
87194
87337
  try {
87195
- const fileContent = readFileSync21(COST_DATA_FILE, "utf-8");
87338
+ const fileContent = readFileSync22(COST_DATA_FILE, "utf-8");
87196
87339
  const persisted = JSON.parse(fileContent);
87197
87340
  return {
87198
87341
  perAgent: new Map(Object.entries(persisted.perAgent || {})),
@@ -87212,9 +87355,9 @@ function loadCostData() {
87212
87355
  }
87213
87356
  function saveCostData(data) {
87214
87357
  try {
87215
- const dir = dirname3(COST_DATA_FILE);
87216
- if (!existsSync26(dir)) {
87217
- mkdirSync19(dir, { recursive: true });
87358
+ const dir = dirname4(COST_DATA_FILE);
87359
+ if (!existsSync27(dir)) {
87360
+ mkdirSync20(dir, { recursive: true });
87218
87361
  }
87219
87362
  const persisted = {
87220
87363
  perAgent: Object.fromEntries(data.perAgent),
@@ -87223,8 +87366,8 @@ function saveCostData(data) {
87223
87366
  lastResetDate: data.lastResetDate
87224
87367
  };
87225
87368
  const tempFile = `${COST_DATA_FILE}.tmp`;
87226
- writeFileSync17(tempFile, JSON.stringify(persisted, null, 2));
87227
- writeFileSync17(COST_DATA_FILE, readFileSync21(tempFile));
87369
+ writeFileSync18(tempFile, JSON.stringify(persisted, null, 2));
87370
+ writeFileSync18(COST_DATA_FILE, readFileSync22(tempFile));
87228
87371
  try {
87229
87372
  unlinkSync8(tempFile);
87230
87373
  } catch (unlinkError) {
@@ -87343,8 +87486,8 @@ function getCostSummary() {
87343
87486
 
87344
87487
  // ../../lib/cloister/session-rotation.ts
87345
87488
  init_paths();
87346
- import { writeFileSync as writeFileSync18 } from "fs";
87347
- import { join as join28 } from "path";
87489
+ import { writeFileSync as writeFileSync19 } from "fs";
87490
+ import { join as join29 } from "path";
87348
87491
  import { execSync as execSync2 } from "child_process";
87349
87492
  init_agents();
87350
87493
  init_specialists();
@@ -87484,8 +87627,8 @@ async function rotateSpecialistSession(specialistName, workingDir) {
87484
87627
  let memoryFile;
87485
87628
  if (specialistName === "merge-agent" && workingDir) {
87486
87629
  memoryContent = buildMergeAgentMemory(workingDir);
87487
- memoryFile = join28(PANOPTICON_HOME2, `merge-agent-memory-${Date.now()}.md`);
87488
- writeFileSync18(memoryFile, memoryContent);
87630
+ memoryFile = join29(PANOPTICON_HOME2, `merge-agent-memory-${Date.now()}.md`);
87631
+ writeFileSync19(memoryFile, memoryContent);
87489
87632
  console.log(`Built memory file: ${memoryFile}`);
87490
87633
  }
87491
87634
  const tmuxSession = getTmuxSessionName(specialistName);
@@ -87536,13 +87679,13 @@ init_config();
87536
87679
  init_specialists();
87537
87680
  init_agents();
87538
87681
  init_tmux();
87539
- import { readFileSync as readFileSync23, writeFileSync as writeFileSync19, existsSync as existsSync28, mkdirSync as mkdirSync20, readdirSync as readdirSync10, statSync as statSync5, rmSync } from "fs";
87540
- import { join as join29 } from "path";
87682
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync20, existsSync as existsSync29, mkdirSync as mkdirSync21, readdirSync as readdirSync10, statSync as statSync5, rmSync } from "fs";
87683
+ import { join as join30 } from "path";
87541
87684
  import { exec as exec7 } from "child_process";
87542
87685
  import { promisify as promisify7 } from "util";
87543
- import { homedir as homedir12 } from "os";
87686
+ import { homedir as homedir13 } from "os";
87544
87687
  var execAsync7 = promisify7(exec7);
87545
- var REVIEW_STATUS_FILE = join29(homedir12(), ".panopticon", "review-status.json");
87688
+ var REVIEW_STATUS_FILE = join30(homedir13(), ".panopticon", "review-status.json");
87546
87689
  var DEFAULT_CONFIG2 = {
87547
87690
  pingTimeoutMs: 3e4,
87548
87691
  // How long to wait for response
@@ -87557,15 +87700,15 @@ var DEFAULT_CONFIG2 = {
87557
87700
  massDeathWindowMs: 6e4
87558
87701
  // 1 minute window for mass death detection
87559
87702
  };
87560
- var DEACON_DIR = join29(PANOPTICON_HOME2, "deacon");
87561
- var STATE_FILE = join29(DEACON_DIR, "health-state.json");
87562
- var CONFIG_FILE2 = join29(DEACON_DIR, "config.json");
87703
+ var DEACON_DIR = join30(PANOPTICON_HOME2, "deacon");
87704
+ var STATE_FILE = join30(DEACON_DIR, "health-state.json");
87705
+ var CONFIG_FILE2 = join30(DEACON_DIR, "config.json");
87563
87706
  var deaconInterval = null;
87564
87707
  var config = { ...DEFAULT_CONFIG2 };
87565
87708
  function loadConfig2() {
87566
87709
  try {
87567
- if (existsSync28(CONFIG_FILE2)) {
87568
- const content = readFileSync23(CONFIG_FILE2, "utf-8");
87710
+ if (existsSync29(CONFIG_FILE2)) {
87711
+ const content = readFileSync24(CONFIG_FILE2, "utf-8");
87569
87712
  const loaded = JSON.parse(content);
87570
87713
  config = { ...DEFAULT_CONFIG2, ...loaded };
87571
87714
  }
@@ -87575,15 +87718,15 @@ function loadConfig2() {
87575
87718
  return config;
87576
87719
  }
87577
87720
  function ensureDeaconDir() {
87578
- if (!existsSync28(DEACON_DIR)) {
87579
- mkdirSync20(DEACON_DIR, { recursive: true });
87721
+ if (!existsSync29(DEACON_DIR)) {
87722
+ mkdirSync21(DEACON_DIR, { recursive: true });
87580
87723
  }
87581
87724
  }
87582
87725
  function loadState() {
87583
87726
  ensureDeaconDir();
87584
87727
  try {
87585
- if (existsSync28(STATE_FILE)) {
87586
- const content = readFileSync23(STATE_FILE, "utf-8");
87728
+ if (existsSync29(STATE_FILE)) {
87729
+ const content = readFileSync24(STATE_FILE, "utf-8");
87587
87730
  return JSON.parse(content);
87588
87731
  }
87589
87732
  } catch (error) {
@@ -87598,7 +87741,7 @@ function loadState() {
87598
87741
  function saveState(state) {
87599
87742
  ensureDeaconDir();
87600
87743
  try {
87601
- writeFileSync19(STATE_FILE, JSON.stringify(state, null, 2), "utf-8");
87744
+ writeFileSync20(STATE_FILE, JSON.stringify(state, null, 2), "utf-8");
87602
87745
  } catch (error) {
87603
87746
  console.error("[deacon] Failed to save state:", error);
87604
87747
  }
@@ -87632,12 +87775,12 @@ function getCooldownRemaining(healthState) {
87632
87775
  }
87633
87776
  function checkHeartbeat(name) {
87634
87777
  const tmuxSession = getTmuxSessionName(name);
87635
- const heartbeatFile = join29(PANOPTICON_HOME2, "heartbeats", `${tmuxSession}.json`);
87778
+ const heartbeatFile = join30(PANOPTICON_HOME2, "heartbeats", `${tmuxSession}.json`);
87636
87779
  try {
87637
- if (!existsSync28(heartbeatFile)) {
87780
+ if (!existsSync29(heartbeatFile)) {
87638
87781
  return { isResponsive: false };
87639
87782
  }
87640
- const content = readFileSync23(heartbeatFile, "utf-8");
87783
+ const content = readFileSync24(heartbeatFile, "utf-8");
87641
87784
  const heartbeat = JSON.parse(content);
87642
87785
  const lastActivity = new Date(heartbeat.timestamp).getTime();
87643
87786
  const age = Date.now() - lastActivity;
@@ -87800,8 +87943,8 @@ async function checkAndSuspendIdleAgents() {
87800
87943
  const timeoutMinutes = isSpecialist ? 5 : 10;
87801
87944
  const isWorkAgent = agent.id.startsWith("agent-") && !isSpecialist;
87802
87945
  if (isWorkAgent) {
87803
- const completedFile = join29(getAgentDir(agent.id), "completed");
87804
- if (existsSync28(completedFile)) {
87946
+ const completedFile = join30(getAgentDir(agent.id), "completed");
87947
+ if (existsSync29(completedFile)) {
87805
87948
  continue;
87806
87949
  }
87807
87950
  }
@@ -87908,10 +88051,10 @@ function isIssueCompletedOrInReview(agentId) {
87908
88051
  if (!match)
87909
88052
  return false;
87910
88053
  const issueId = match[1].toUpperCase();
87911
- if (!existsSync28(REVIEW_STATUS_FILE)) {
88054
+ if (!existsSync29(REVIEW_STATUS_FILE)) {
87912
88055
  return false;
87913
88056
  }
87914
- const content = readFileSync23(REVIEW_STATUS_FILE, "utf-8");
88057
+ const content = readFileSync24(REVIEW_STATUS_FILE, "utf-8");
87915
88058
  const statuses = JSON.parse(content);
87916
88059
  const status = statuses[issueId];
87917
88060
  if (!status) {
@@ -87986,22 +88129,22 @@ async function cleanupStaleAgentState() {
87986
88129
  const retentionDays = cloisterConfig.retention?.agent_state_days ?? 30;
87987
88130
  const retentionMs = retentionDays * 24 * 60 * 60 * 1e3;
87988
88131
  const now = Date.now();
87989
- if (!existsSync28(AGENTS_DIR)) {
88132
+ if (!existsSync29(AGENTS_DIR)) {
87990
88133
  return actions;
87991
88134
  }
87992
88135
  try {
87993
88136
  const dirs = readdirSync10(AGENTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
87994
88137
  for (const dir of dirs) {
87995
- const agentDir = join29(AGENTS_DIR, dir.name);
88138
+ const agentDir = join30(AGENTS_DIR, dir.name);
87996
88139
  try {
87997
88140
  try {
87998
88141
  await execAsync7(`tmux has-session -t "${dir.name}" 2>/dev/null`);
87999
88142
  continue;
88000
88143
  } catch {
88001
88144
  }
88002
- const stateFile = join29(agentDir, "state.json");
88145
+ const stateFile = join30(agentDir, "state.json");
88003
88146
  let mtime;
88004
- if (existsSync28(stateFile)) {
88147
+ if (existsSync29(stateFile)) {
88005
88148
  mtime = statSync5(stateFile).mtimeMs;
88006
88149
  } else {
88007
88150
  mtime = statSync5(agentDir).mtimeMs;
@@ -88010,8 +88153,8 @@ async function cleanupStaleAgentState() {
88010
88153
  if (ageMs < retentionMs) {
88011
88154
  continue;
88012
88155
  }
88013
- const completedFile = join29(agentDir, "completed");
88014
- if (existsSync28(completedFile)) {
88156
+ const completedFile = join30(agentDir, "completed");
88157
+ if (existsSync29(completedFile)) {
88015
88158
  const completedAge = now - statSync5(completedFile).mtimeMs;
88016
88159
  if (completedAge < 7 * 24 * 60 * 60 * 1e3) {
88017
88160
  continue;
@@ -88038,10 +88181,10 @@ async function cleanupStaleAgentState() {
88038
88181
  async function checkOrphanedReviewStatuses() {
88039
88182
  const actions = [];
88040
88183
  try {
88041
- if (!existsSync28(REVIEW_STATUS_FILE)) {
88184
+ if (!existsSync29(REVIEW_STATUS_FILE)) {
88042
88185
  return actions;
88043
88186
  }
88044
- const content = readFileSync23(REVIEW_STATUS_FILE, "utf-8");
88187
+ const content = readFileSync24(REVIEW_STATUS_FILE, "utf-8");
88045
88188
  const statuses = JSON.parse(content);
88046
88189
  const reviewAgentSession = getTmuxSessionName("review-agent");
88047
88190
  const reviewAgentRunning = sessionExists(reviewAgentSession);
@@ -88067,7 +88210,7 @@ async function checkOrphanedReviewStatuses() {
88067
88210
  }
88068
88211
  }
88069
88212
  if (modified) {
88070
- writeFileSync19(REVIEW_STATUS_FILE, JSON.stringify(statuses, null, 2), "utf-8");
88213
+ writeFileSync20(REVIEW_STATUS_FILE, JSON.stringify(statuses, null, 2), "utf-8");
88071
88214
  }
88072
88215
  } catch (error) {
88073
88216
  const msg = error instanceof Error ? error.message : String(error);
@@ -88215,19 +88358,19 @@ function getDeaconStatus() {
88215
88358
  // ../../lib/cloister/service.ts
88216
88359
  init_paths();
88217
88360
  init_paths();
88218
- import { existsSync as existsSync29, writeFileSync as writeFileSync20, unlinkSync as unlinkSync9, readFileSync as readFileSync24, readdirSync as readdirSync11, renameSync } from "fs";
88219
- import { join as join30 } from "path";
88220
- var CLOISTER_STATE_FILE = join30(PANOPTICON_HOME2, "cloister.state");
88361
+ import { existsSync as existsSync30, writeFileSync as writeFileSync21, unlinkSync as unlinkSync9, readFileSync as readFileSync25, readdirSync as readdirSync11, renameSync } from "fs";
88362
+ import { join as join31 } from "path";
88363
+ var CLOISTER_STATE_FILE = join31(PANOPTICON_HOME2, "cloister.state");
88221
88364
  function writeStateFile(running, pid) {
88222
88365
  try {
88223
88366
  if (running) {
88224
- writeFileSync20(CLOISTER_STATE_FILE, JSON.stringify({
88367
+ writeFileSync21(CLOISTER_STATE_FILE, JSON.stringify({
88225
88368
  running: true,
88226
88369
  pid: pid || process.pid,
88227
88370
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
88228
88371
  }));
88229
88372
  } else {
88230
- if (existsSync29(CLOISTER_STATE_FILE)) {
88373
+ if (existsSync30(CLOISTER_STATE_FILE)) {
88231
88374
  unlinkSync9(CLOISTER_STATE_FILE);
88232
88375
  }
88233
88376
  }
@@ -88237,8 +88380,8 @@ function writeStateFile(running, pid) {
88237
88380
  }
88238
88381
  function readStateFile() {
88239
88382
  try {
88240
- if (existsSync29(CLOISTER_STATE_FILE)) {
88241
- const data = JSON.parse(readFileSync24(CLOISTER_STATE_FILE, "utf-8"));
88383
+ if (existsSync30(CLOISTER_STATE_FILE)) {
88384
+ const data = JSON.parse(readFileSync25(CLOISTER_STATE_FILE, "utf-8"));
88242
88385
  if (data.pid) {
88243
88386
  try {
88244
88387
  process.kill(data.pid, 0);
@@ -88457,16 +88600,16 @@ var CloisterService = class {
88457
88600
  */
88458
88601
  async checkCompletionMarkers() {
88459
88602
  try {
88460
- if (!existsSync29(AGENTS_DIR))
88603
+ if (!existsSync30(AGENTS_DIR))
88461
88604
  return;
88462
88605
  const agentDirs = readdirSync11(AGENTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("agent-"));
88463
88606
  for (const dir of agentDirs) {
88464
- const completedFile = join30(AGENTS_DIR, dir.name, "completed");
88465
- const processedFile = join30(AGENTS_DIR, dir.name, "completed.processed");
88466
- if (!existsSync29(completedFile) || existsSync29(processedFile))
88607
+ const completedFile = join31(AGENTS_DIR, dir.name, "completed");
88608
+ const processedFile = join31(AGENTS_DIR, dir.name, "completed.processed");
88609
+ if (!existsSync30(completedFile) || existsSync30(processedFile))
88467
88610
  continue;
88468
88611
  try {
88469
- const content = JSON.parse(readFileSync24(completedFile, "utf-8"));
88612
+ const content = JSON.parse(readFileSync25(completedFile, "utf-8"));
88470
88613
  const ageMs = Date.now() - new Date(content.timestamp).getTime();
88471
88614
  if (ageMs > 24 * 60 * 60 * 1e3) {
88472
88615
  console.log(`\u{1F514} Cloister: Skipping stale completion marker for ${dir.name} (${Math.floor(ageMs / 36e5)}h old)`);
@@ -89026,7 +89169,7 @@ init_settings();
89026
89169
  init_js_yaml();
89027
89170
  init_config_yaml();
89028
89171
  init_model_capabilities();
89029
- import { writeFileSync as writeFileSync21 } from "fs";
89172
+ import { writeFileSync as writeFileSync22 } from "fs";
89030
89173
  function getOptimalModelDefaults() {
89031
89174
  return {
89032
89175
  // High-complexity phases - Opus 4.6 for deep analysis
@@ -89102,7 +89245,7 @@ function saveSettingsApi(settings) {
89102
89245
  lineWidth: 120,
89103
89246
  noRefs: true
89104
89247
  });
89105
- writeFileSync21(getGlobalConfigPath(), yamlContent, "utf-8");
89248
+ writeFileSync22(getGlobalConfigPath(), yamlContent, "utf-8");
89106
89249
  }
89107
89250
  function validateSettingsApi(settings) {
89108
89251
  const errors = [];
@@ -89186,7 +89329,7 @@ init_merge_agent();
89186
89329
 
89187
89330
  // ../lib/health-filtering.ts
89188
89331
  init_config();
89189
- import { readFileSync as readFileSync26, existsSync as existsSync33 } from "fs";
89332
+ import { readFileSync as readFileSync27, existsSync as existsSync34 } from "fs";
89190
89333
  import { exec as exec11 } from "child_process";
89191
89334
  import { promisify as promisify11 } from "util";
89192
89335
  var execAsync11 = promisify11(exec11);
@@ -89206,9 +89349,9 @@ async function determineHealthStatusAsync(agentId, stateFile) {
89206
89349
  const health = await checkAgentHealthAsync(agentId);
89207
89350
  let agentStatus;
89208
89351
  let lastActivity = null;
89209
- if (existsSync33(stateFile)) {
89352
+ if (existsSync34(stateFile)) {
89210
89353
  try {
89211
- const state = JSON.parse(readFileSync26(stateFile, "utf-8"));
89354
+ const state = JSON.parse(readFileSync27(stateFile, "utf-8"));
89212
89355
  agentStatus = state.status;
89213
89356
  lastActivity = state.lastActivity ? new Date(state.lastActivity) : null;
89214
89357
  } catch {
@@ -89257,9 +89400,9 @@ init_jsonl_parser();
89257
89400
  // ../../lib/convoy.ts
89258
89401
  var import_yaml2 = __toESM(require_dist3(), 1);
89259
89402
  init_tmux();
89260
- import { existsSync as existsSync34, mkdirSync as mkdirSync22, writeFileSync as writeFileSync23, readFileSync as readFileSync27, readdirSync as readdirSync13 } from "fs";
89261
- import { join as join34 } from "path";
89262
- import { homedir as homedir13 } from "os";
89403
+ import { existsSync as existsSync35, mkdirSync as mkdirSync23, writeFileSync as writeFileSync24, readFileSync as readFileSync28, readdirSync as readdirSync13 } from "fs";
89404
+ import { join as join35 } from "path";
89405
+ import { homedir as homedir14 } from "os";
89263
89406
  import { exec as exec12 } from "child_process";
89264
89407
  import { promisify as promisify12 } from "util";
89265
89408
 
@@ -89382,25 +89525,25 @@ function getExecutionOrder(template) {
89382
89525
  init_paths();
89383
89526
  init_work_type_router();
89384
89527
  var execAsync12 = promisify12(exec12);
89385
- var CONVOY_DIR = join34(homedir13(), ".panopticon", "convoys");
89528
+ var CONVOY_DIR = join35(homedir14(), ".panopticon", "convoys");
89386
89529
  function getConvoyStateFile(convoyId) {
89387
- return join34(CONVOY_DIR, `${convoyId}.json`);
89530
+ return join35(CONVOY_DIR, `${convoyId}.json`);
89388
89531
  }
89389
89532
  function getConvoyOutputDir(convoyId, template) {
89390
89533
  const baseDir = template.config?.outputDir || ".panopticon/convoy-output";
89391
- return join34(process.cwd(), baseDir, convoyId);
89534
+ return join35(process.cwd(), baseDir, convoyId);
89392
89535
  }
89393
89536
  function saveConvoyState(state) {
89394
- mkdirSync22(CONVOY_DIR, { recursive: true });
89395
- writeFileSync23(getConvoyStateFile(state.id), JSON.stringify(state, null, 2));
89537
+ mkdirSync23(CONVOY_DIR, { recursive: true });
89538
+ writeFileSync24(getConvoyStateFile(state.id), JSON.stringify(state, null, 2));
89396
89539
  }
89397
89540
  function loadConvoyState(convoyId) {
89398
89541
  const stateFile = getConvoyStateFile(convoyId);
89399
- if (!existsSync34(stateFile)) {
89542
+ if (!existsSync35(stateFile)) {
89400
89543
  return void 0;
89401
89544
  }
89402
89545
  try {
89403
- const content = readFileSync27(stateFile, "utf-8");
89546
+ const content = readFileSync28(stateFile, "utf-8");
89404
89547
  return JSON.parse(content);
89405
89548
  } catch {
89406
89549
  return void 0;
@@ -89410,7 +89553,7 @@ function getConvoyStatus(convoyId) {
89410
89553
  return loadConvoyState(convoyId);
89411
89554
  }
89412
89555
  function listConvoys(filter) {
89413
- if (!existsSync34(CONVOY_DIR)) {
89556
+ if (!existsSync35(CONVOY_DIR)) {
89414
89557
  return [];
89415
89558
  }
89416
89559
  const files = readdirSync13(CONVOY_DIR).filter((f) => f.endsWith(".json"));
@@ -89429,10 +89572,10 @@ function listConvoys(filter) {
89429
89572
  );
89430
89573
  }
89431
89574
  function parseAgentTemplate(templatePath) {
89432
- if (!existsSync34(templatePath)) {
89575
+ if (!existsSync35(templatePath)) {
89433
89576
  throw new Error(`Agent template not found: ${templatePath}`);
89434
89577
  }
89435
- const content = readFileSync27(templatePath, "utf-8");
89578
+ const content = readFileSync28(templatePath, "utf-8");
89436
89579
  const frontmatterMatch = content.match(/^---\n([\s\S]+?)\n---\n([\s\S]*)$/);
89437
89580
  if (!frontmatterMatch) {
89438
89581
  throw new Error(`Invalid agent template format (missing frontmatter): ${templatePath}`);
@@ -89458,7 +89601,7 @@ function mapConvoyRoleToWorkType(role) {
89458
89601
  }
89459
89602
  async function spawnConvoyAgent(convoy, agent, agentState, context) {
89460
89603
  const { role, subagent } = agent;
89461
- const templatePath = join34(AGENTS_DIR, `${subagent}.md`);
89604
+ const templatePath = join35(AGENTS_DIR, `${subagent}.md`);
89462
89605
  const template = parseAgentTemplate(templatePath);
89463
89606
  let model = template.model;
89464
89607
  try {
@@ -89496,9 +89639,9 @@ ${context.issueId ? `**Issue ID**: ${context.issueId}` : ""}
89496
89639
 
89497
89640
  `;
89498
89641
  prompt = contextInstructions + prompt;
89499
- mkdirSync22(convoy.outputDir, { recursive: true });
89500
- const promptFile = join34(convoy.outputDir, `${role}-prompt.md`);
89501
- writeFileSync23(promptFile, prompt);
89642
+ mkdirSync23(convoy.outputDir, { recursive: true });
89643
+ const promptFile = join35(convoy.outputDir, `${role}-prompt.md`);
89644
+ writeFileSync24(promptFile, prompt);
89502
89645
  const claudeCmd = `claude --dangerously-skip-permissions --model ${model}`;
89503
89646
  createSession(agentState.tmuxSession, convoy.context.projectPath, claudeCmd, {
89504
89647
  env: {
@@ -89523,7 +89666,7 @@ async function startConvoy(templateName, context) {
89523
89666
  const timestamp2 = Date.now();
89524
89667
  const convoyId = `convoy-${templateName}-${timestamp2}`;
89525
89668
  const outputDir = getConvoyOutputDir(convoyId, template);
89526
- mkdirSync22(outputDir, { recursive: true });
89669
+ mkdirSync23(outputDir, { recursive: true });
89527
89670
  const state = {
89528
89671
  id: convoyId,
89529
89672
  template: templateName,
@@ -89535,7 +89678,7 @@ async function startConvoy(templateName, context) {
89535
89678
  };
89536
89679
  for (const agent of template.agents) {
89537
89680
  const tmuxSession = `${convoyId}-${agent.role}`;
89538
- const outputFile = join34(outputDir, `${agent.role}.md`);
89681
+ const outputFile = join35(outputDir, `${agent.role}.md`);
89539
89682
  state.agents.push({
89540
89683
  role: agent.role,
89541
89684
  subagent: agent.subagent,
@@ -89570,8 +89713,8 @@ async function executePhase(convoy, template, phaseAgents, context) {
89570
89713
  const agentContext = { ...context };
89571
89714
  for (const depRole of deps) {
89572
89715
  const depAgent = convoy.agents.find((a) => a.role === depRole);
89573
- if (depAgent?.outputFile && existsSync34(depAgent.outputFile)) {
89574
- agentContext[`${depRole}_output`] = readFileSync27(depAgent.outputFile, "utf-8");
89716
+ if (depAgent?.outputFile && existsSync35(depAgent.outputFile)) {
89717
+ agentContext[`${depRole}_output`] = readFileSync28(depAgent.outputFile, "utf-8");
89575
89718
  }
89576
89719
  }
89577
89720
  spawnPromises.push(spawnConvoyAgent(convoy, agent, agentState, agentContext));
@@ -89634,7 +89777,7 @@ function updateAgentStatuses(convoy) {
89634
89777
  agent.status = "completed";
89635
89778
  agent.completedAt = (/* @__PURE__ */ new Date()).toISOString();
89636
89779
  updated = true;
89637
- if (agent.outputFile && existsSync34(agent.outputFile)) {
89780
+ if (agent.outputFile && existsSync35(agent.outputFile)) {
89638
89781
  agent.exitCode = 0;
89639
89782
  } else {
89640
89783
  agent.exitCode = 1;
@@ -89662,10 +89805,10 @@ async function stopConvoy(convoyId) {
89662
89805
  }
89663
89806
 
89664
89807
  // ../../lib/env-loader.ts
89665
- import { readFileSync as readFileSync28, existsSync as existsSync35 } from "fs";
89666
- import { join as join35 } from "path";
89667
- import { homedir as homedir14 } from "os";
89668
- var ENV_FILE_PATH = join35(homedir14(), ".panopticon.env");
89808
+ import { readFileSync as readFileSync29, existsSync as existsSync36 } from "fs";
89809
+ import { join as join36 } from "path";
89810
+ import { homedir as homedir15 } from "os";
89811
+ var ENV_FILE_PATH = join36(homedir15(), ".panopticon.env");
89669
89812
  function parseEnvFile(content) {
89670
89813
  const result = {};
89671
89814
  for (const line of content.split("\n")) {
@@ -89687,11 +89830,11 @@ function loadPanopticonEnv() {
89687
89830
  loaded: [],
89688
89831
  skipped: []
89689
89832
  };
89690
- if (!existsSync35(ENV_FILE_PATH)) {
89833
+ if (!existsSync36(ENV_FILE_PATH)) {
89691
89834
  return { ...result, error: `Env file not found: ${ENV_FILE_PATH}` };
89692
89835
  }
89693
89836
  try {
89694
- const content = readFileSync28(ENV_FILE_PATH, "utf-8");
89837
+ const content = readFileSync29(ENV_FILE_PATH, "utf-8");
89695
89838
  const envVars = parseEnvFile(content);
89696
89839
  for (const [key, value] of Object.entries(envVars)) {
89697
89840
  if (process.env[key]) {
@@ -89708,21 +89851,21 @@ function loadPanopticonEnv() {
89708
89851
  }
89709
89852
 
89710
89853
  // ../../lib/costs/events.ts
89711
- import { existsSync as existsSync36, mkdirSync as mkdirSync23, readFileSync as readFileSync29, appendFileSync as appendFileSync8, writeFileSync as writeFileSync24, renameSync as renameSync2 } from "fs";
89712
- import { join as join36 } from "path";
89713
- import { homedir as homedir15 } from "os";
89854
+ import { existsSync as existsSync37, mkdirSync as mkdirSync24, readFileSync as readFileSync30, appendFileSync as appendFileSync8, writeFileSync as writeFileSync25, renameSync as renameSync2 } from "fs";
89855
+ import { join as join37 } from "path";
89856
+ import { homedir as homedir16 } from "os";
89714
89857
  function getCostsDir() {
89715
- return join36(process.env.HOME || homedir15(), ".panopticon", "costs");
89858
+ return join37(process.env.HOME || homedir16(), ".panopticon", "costs");
89716
89859
  }
89717
89860
  function getEventsFile() {
89718
- return join36(getCostsDir(), "events.jsonl");
89861
+ return join37(getCostsDir(), "events.jsonl");
89719
89862
  }
89720
89863
  function ensureEventsFile() {
89721
89864
  const costsDir = getCostsDir();
89722
89865
  const eventsFile = getEventsFile();
89723
- mkdirSync23(costsDir, { recursive: true });
89724
- if (!existsSync36(eventsFile)) {
89725
- writeFileSync24(eventsFile, "", "utf-8");
89866
+ mkdirSync24(costsDir, { recursive: true });
89867
+ if (!existsSync37(eventsFile)) {
89868
+ writeFileSync25(eventsFile, "", "utf-8");
89726
89869
  }
89727
89870
  }
89728
89871
  function appendCostEvent(event) {
@@ -89734,10 +89877,10 @@ function appendCostEvent(event) {
89734
89877
  appendFileSync8(getEventsFile(), line, "utf-8");
89735
89878
  }
89736
89879
  function readEvents(options = {}) {
89737
- if (!existsSync36(getEventsFile())) {
89880
+ if (!existsSync37(getEventsFile())) {
89738
89881
  return [];
89739
89882
  }
89740
- const content = readFileSync29(getEventsFile(), "utf-8");
89883
+ const content = readFileSync30(getEventsFile(), "utf-8");
89741
89884
  const lines = content.split("\n").filter((line) => line.trim());
89742
89885
  let events = [];
89743
89886
  for (const line of lines) {
@@ -89772,10 +89915,10 @@ function readEvents(options = {}) {
89772
89915
  return events;
89773
89916
  }
89774
89917
  function tailEvents(n) {
89775
- if (!existsSync36(getEventsFile())) {
89918
+ if (!existsSync37(getEventsFile())) {
89776
89919
  return [];
89777
89920
  }
89778
- const content = readFileSync29(getEventsFile(), "utf-8");
89921
+ const content = readFileSync30(getEventsFile(), "utf-8");
89779
89922
  const lines = content.split("\n").filter((line) => line.trim());
89780
89923
  const lastLines = lines.slice(-n);
89781
89924
  const events = [];
@@ -89788,10 +89931,10 @@ function tailEvents(n) {
89788
89931
  return events;
89789
89932
  }
89790
89933
  function readEventsFromLine(startLine) {
89791
- if (!existsSync36(getEventsFile())) {
89934
+ if (!existsSync37(getEventsFile())) {
89792
89935
  return { events: [], newLine: startLine };
89793
89936
  }
89794
- const content = readFileSync29(getEventsFile(), "utf-8");
89937
+ const content = readFileSync30(getEventsFile(), "utf-8");
89795
89938
  const lines = content.split("\n").filter((line) => line.trim());
89796
89939
  const events = [];
89797
89940
  for (let i = startLine; i < lines.length; i++) {
@@ -89804,14 +89947,14 @@ function readEventsFromLine(startLine) {
89804
89947
  return { events, newLine: lines.length };
89805
89948
  }
89806
89949
  function getLastEventMetadata() {
89807
- if (!existsSync36(getEventsFile())) {
89950
+ if (!existsSync37(getEventsFile())) {
89808
89951
  return {
89809
89952
  lastEventTs: null,
89810
89953
  lastEventLine: 0,
89811
89954
  totalEvents: 0
89812
89955
  };
89813
89956
  }
89814
- const content = readFileSync29(getEventsFile(), "utf-8");
89957
+ const content = readFileSync30(getEventsFile(), "utf-8");
89815
89958
  const lines = content.split("\n").filter((line) => line.trim());
89816
89959
  let lastEventTs = null;
89817
89960
  if (lines.length > 0) {
@@ -89828,28 +89971,28 @@ function getLastEventMetadata() {
89828
89971
  };
89829
89972
  }
89830
89973
  function eventsFileExists() {
89831
- return existsSync36(getEventsFile());
89974
+ return existsSync37(getEventsFile());
89832
89975
  }
89833
89976
 
89834
89977
  // ../../lib/costs/aggregator.ts
89835
- import { existsSync as existsSync37, mkdirSync as mkdirSync24, readFileSync as readFileSync30, writeFileSync as writeFileSync25, renameSync as renameSync3 } from "fs";
89836
- import { join as join37 } from "path";
89837
- import { homedir as homedir16 } from "os";
89978
+ import { existsSync as existsSync38, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync26, renameSync as renameSync3 } from "fs";
89979
+ import { join as join38 } from "path";
89980
+ import { homedir as homedir17 } from "os";
89838
89981
  var CACHE_VERSION = 3;
89839
89982
  var DEFAULT_RETENTION_DAYS = 90;
89840
89983
  function getCostsDir2() {
89841
- return join37(process.env.HOME || homedir16(), ".panopticon", "costs");
89984
+ return join38(process.env.HOME || homedir17(), ".panopticon", "costs");
89842
89985
  }
89843
89986
  function getCacheFile() {
89844
- return join37(getCostsDir2(), "by-issue.json");
89987
+ return join38(getCostsDir2(), "by-issue.json");
89845
89988
  }
89846
89989
  function loadCache() {
89847
89990
  const cacheFile = getCacheFile();
89848
- if (!existsSync37(cacheFile)) {
89991
+ if (!existsSync38(cacheFile)) {
89849
89992
  return createEmptyCache();
89850
89993
  }
89851
89994
  try {
89852
- const content = readFileSync30(cacheFile, "utf-8");
89995
+ const content = readFileSync31(cacheFile, "utf-8");
89853
89996
  const cache = JSON.parse(content);
89854
89997
  if (cache.version !== CACHE_VERSION) {
89855
89998
  console.warn(`Cache version mismatch: expected ${CACHE_VERSION}, got ${cache.version}. Rebuilding cache.`);
@@ -89874,10 +90017,10 @@ function createEmptyCache() {
89874
90017
  function saveCache(cache) {
89875
90018
  const costsDir = getCostsDir2();
89876
90019
  const cacheFile = getCacheFile();
89877
- mkdirSync24(costsDir, { recursive: true });
90020
+ mkdirSync25(costsDir, { recursive: true });
89878
90021
  const tempFile = cacheFile + ".tmp";
89879
90022
  const content = JSON.stringify(cache, null, 2);
89880
- writeFileSync25(tempFile, content, "utf-8");
90023
+ writeFileSync26(tempFile, content, "utf-8");
89881
90024
  renameSync3(tempFile, cacheFile);
89882
90025
  }
89883
90026
  function updateCacheFromEvents(events, newLineNumber) {
@@ -90012,18 +90155,18 @@ function getCacheStatus() {
90012
90155
  }
90013
90156
 
90014
90157
  // ../../lib/costs/migration.ts
90015
- import { existsSync as existsSync38, readdirSync as readdirSync14, readFileSync as readFileSync31 } from "fs";
90016
- import { join as join38 } from "path";
90017
- import { homedir as homedir17 } from "os";
90158
+ import { existsSync as existsSync39, readdirSync as readdirSync14, readFileSync as readFileSync32 } from "fs";
90159
+ import { join as join39 } from "path";
90160
+ import { homedir as homedir18 } from "os";
90018
90161
  init_cost();
90019
90162
  function getAgentsDir() {
90020
- return join38(process.env.HOME || homedir17(), ".panopticon", "agents");
90163
+ return join39(process.env.HOME || homedir18(), ".panopticon", "agents");
90021
90164
  }
90022
90165
  function getClaudeProjectsDir() {
90023
- return join38(process.env.HOME || homedir17(), ".claude", "projects");
90166
+ return join39(process.env.HOME || homedir18(), ".claude", "projects");
90024
90167
  }
90025
90168
  function getProjectsYamlPath() {
90026
- return join38(process.env.HOME || homedir17(), ".panopticon", "projects.yaml");
90169
+ return join39(process.env.HOME || homedir18(), ".panopticon", "projects.yaml");
90027
90170
  }
90028
90171
  function inferIssueId(agentDir) {
90029
90172
  const stripped = agentDir.replace(/^(agent|planning)-/, "");
@@ -90037,8 +90180,8 @@ function getProjectPaths() {
90037
90180
  const paths = [];
90038
90181
  try {
90039
90182
  const yamlPath = getProjectsYamlPath();
90040
- if (existsSync38(yamlPath)) {
90041
- const content = readFileSync31(yamlPath, "utf-8");
90183
+ if (existsSync39(yamlPath)) {
90184
+ const content = readFileSync32(yamlPath, "utf-8");
90042
90185
  const pathMatches = content.match(/^\s+path:\s+(.+)$/gm);
90043
90186
  if (pathMatches) {
90044
90187
  for (const m of pathMatches) {
@@ -90057,8 +90200,8 @@ function resolveWorkspace(issueId) {
90057
90200
  const issueLower = issueId.toLowerCase();
90058
90201
  const projectPaths = getProjectPaths();
90059
90202
  for (const projectPath of projectPaths) {
90060
- const wsPath = join38(projectPath, "workspaces", `feature-${issueLower}`);
90061
- if (existsSync38(wsPath)) {
90203
+ const wsPath = join39(projectPath, "workspaces", `feature-${issueLower}`);
90204
+ if (existsSync39(wsPath)) {
90062
90205
  return wsPath;
90063
90206
  }
90064
90207
  }
@@ -90072,7 +90215,7 @@ function findSessionDirsByIssue(issueId) {
90072
90215
  const entries = readdirSync14(claudeDir);
90073
90216
  for (const entry of entries) {
90074
90217
  if (entry.includes(`feature-${issueLower}`)) {
90075
- const fullPath = join38(claudeDir, entry);
90218
+ const fullPath = join39(claudeDir, entry);
90076
90219
  dirs.push(fullPath);
90077
90220
  }
90078
90221
  }
@@ -90083,7 +90226,7 @@ function findSessionDirsByIssue(issueId) {
90083
90226
  function parseSessionFile(filePath) {
90084
90227
  const usages = [];
90085
90228
  try {
90086
- const content = readFileSync31(filePath, "utf-8");
90229
+ const content = readFileSync32(filePath, "utf-8");
90087
90230
  const lines = content.split("\n").filter((l) => l.trim());
90088
90231
  for (const line of lines) {
90089
90232
  try {
@@ -90151,15 +90294,15 @@ function usageToCostEvents(usages, context) {
90151
90294
  }
90152
90295
  function getSessionDir(workspacePath) {
90153
90296
  const sessionDirName = `-${workspacePath.replace(/^\//, "").replace(/\//g, "-")}`;
90154
- const sessionDir = join38(getClaudeProjectsDir(), sessionDirName);
90155
- if (existsSync38(sessionDir)) {
90297
+ const sessionDir = join39(getClaudeProjectsDir(), sessionDirName);
90298
+ if (existsSync39(sessionDir)) {
90156
90299
  return sessionDir;
90157
90300
  }
90158
90301
  return null;
90159
90302
  }
90160
90303
  function migrateAgent(agentDir, stats) {
90161
- const stateFile = join38(getAgentsDir(), agentDir, "state.json");
90162
- if (!existsSync38(stateFile)) {
90304
+ const stateFile = join39(getAgentsDir(), agentDir, "state.json");
90305
+ if (!existsSync39(stateFile)) {
90163
90306
  stats.warnings.push({
90164
90307
  file: stateFile,
90165
90308
  message: "No state.json found"
@@ -90168,7 +90311,7 @@ function migrateAgent(agentDir, stats) {
90168
90311
  }
90169
90312
  let state;
90170
90313
  try {
90171
- state = JSON.parse(readFileSync31(stateFile, "utf-8"));
90314
+ state = JSON.parse(readFileSync32(stateFile, "utf-8"));
90172
90315
  } catch (err) {
90173
90316
  stats.errors.push({
90174
90317
  file: stateFile,
@@ -90206,7 +90349,7 @@ function migrateAgent(agentDir, stats) {
90206
90349
  try {
90207
90350
  const files = readdirSync14(sessionDir).filter((f) => f.endsWith(".jsonl"));
90208
90351
  for (const file of files) {
90209
- const filePath = join38(sessionDir, file);
90352
+ const filePath = join39(sessionDir, file);
90210
90353
  try {
90211
90354
  const usages = parseSessionFile(filePath);
90212
90355
  const events = usageToCostEvents(usages, context);
@@ -90230,12 +90373,12 @@ function migrateAgent(agentDir, stats) {
90230
90373
  error: `Failed to read session directory: ${err}`
90231
90374
  });
90232
90375
  }
90233
- const subagentsDir = join38(sessionDir, "subagents");
90234
- if (existsSync38(subagentsDir)) {
90376
+ const subagentsDir = join39(sessionDir, "subagents");
90377
+ if (existsSync39(subagentsDir)) {
90235
90378
  try {
90236
90379
  const subagentFiles = readdirSync14(subagentsDir).filter((f) => f.endsWith(".jsonl"));
90237
90380
  for (const file of subagentFiles) {
90238
- const filePath = join38(subagentsDir, file);
90381
+ const filePath = join39(subagentsDir, file);
90239
90382
  try {
90240
90383
  const usages = parseSessionFile(filePath);
90241
90384
  const subagentContext = {
@@ -90279,7 +90422,7 @@ function migrateAllSessions() {
90279
90422
  };
90280
90423
  console.log("Starting migration of historical session data...");
90281
90424
  const agentsDir = getAgentsDir();
90282
- if (!existsSync38(agentsDir)) {
90425
+ if (!existsSync39(agentsDir)) {
90283
90426
  console.log("No agents directory found - nothing to migrate");
90284
90427
  return stats;
90285
90428
  }
@@ -90326,71 +90469,8 @@ function migrateIfNeeded() {
90326
90469
  return migrateAllSessions();
90327
90470
  }
90328
90471
 
90329
- // review-status.ts
90330
- import { existsSync as existsSync39, readFileSync as readFileSync32, writeFileSync as writeFileSync26, mkdirSync as mkdirSync25 } from "fs";
90331
- import { join as join39, dirname as dirname5 } from "path";
90332
- import { homedir as homedir18 } from "os";
90333
- var DEFAULT_STATUS_FILE = join39(homedir18(), ".panopticon", "review-status.json");
90334
- function loadReviewStatuses(filePath = DEFAULT_STATUS_FILE) {
90335
- try {
90336
- if (existsSync39(filePath)) {
90337
- return JSON.parse(readFileSync32(filePath, "utf-8"));
90338
- }
90339
- } catch (err) {
90340
- console.error("Failed to load review statuses:", err);
90341
- }
90342
- return {};
90343
- }
90344
- function saveReviewStatuses(statuses, filePath = DEFAULT_STATUS_FILE) {
90345
- try {
90346
- const dir = dirname5(filePath);
90347
- if (!existsSync39(dir)) {
90348
- mkdirSync25(dir, { recursive: true });
90349
- }
90350
- writeFileSync26(filePath, JSON.stringify(statuses, null, 2));
90351
- } catch (err) {
90352
- console.error("Failed to save review statuses:", err);
90353
- }
90354
- }
90355
- function setReviewStatus(issueId, update, filePath = DEFAULT_STATUS_FILE) {
90356
- const statuses = loadReviewStatuses(filePath);
90357
- const existing = statuses[issueId] || {
90358
- issueId,
90359
- reviewStatus: "pending",
90360
- testStatus: "pending",
90361
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
90362
- readyForMerge: false
90363
- };
90364
- const merged = { ...existing, ...update };
90365
- const history = [...existing.history || []];
90366
- const now = (/* @__PURE__ */ new Date()).toISOString();
90367
- if (update.reviewStatus && update.reviewStatus !== existing.reviewStatus) {
90368
- history.push({ type: "review", status: update.reviewStatus, timestamp: now, notes: update.reviewNotes });
90369
- }
90370
- if (update.testStatus && update.testStatus !== existing.testStatus) {
90371
- history.push({ type: "test", status: update.testStatus, timestamp: now, notes: update.testNotes });
90372
- }
90373
- if (update.mergeStatus && update.mergeStatus !== existing.mergeStatus) {
90374
- history.push({ type: "merge", status: update.mergeStatus, timestamp: now });
90375
- }
90376
- while (history.length > 10)
90377
- history.shift();
90378
- const readyForMerge = update.readyForMerge !== void 0 ? update.readyForMerge : merged.reviewStatus === "passed" && merged.testStatus === "passed" && merged.mergeStatus !== "merged";
90379
- const updated = {
90380
- ...merged,
90381
- issueId,
90382
- updatedAt: now,
90383
- readyForMerge,
90384
- history
90385
- };
90386
- statuses[issueId] = updated;
90387
- saveReviewStatuses(statuses, filePath);
90388
- return updated;
90389
- }
90390
- function getReviewStatus(issueId, filePath = DEFAULT_STATUS_FILE) {
90391
- const statuses = loadReviewStatuses(filePath);
90392
- return statuses[issueId] || null;
90393
- }
90472
+ // index.ts
90473
+ init_review_status();
90394
90474
 
90395
90475
  // ../../lib/remote/index.ts
90396
90476
  init_exe_provider();