panopticon-cli 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agents-5HWTDR4S.js → agents-I6RAEGL5.js} +2 -2
- package/dist/{chunk-WJJ3ZIQ6.js → chunk-M6ZVVKZ3.js} +16 -16
- package/dist/{chunk-FUUP55PE.js → chunk-NYOGHGIW.js} +2 -1
- package/dist/chunk-NYOGHGIW.js.map +1 -0
- package/dist/cli/index.js +166 -195
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/public/assets/{index-Db9NOz4z.js → index-C7hJ5-o1.js} +56 -56
- package/dist/dashboard/public/index.html +1 -1
- package/dist/dashboard/server.js +6 -1
- package/dist/{merge-agent-WM7ZKUET.js → merge-agent-ZITLVF2B.js} +4 -4
- package/dist/{specialist-context-74RQF5SR.js → specialist-context-W25PPWM4.js} +2 -2
- package/dist/{specialist-logs-T5GW7CSU.js → specialist-logs-KPC45SZN.js} +2 -2
- package/dist/{specialists-HTYYFXHQ.js → specialists-H4LGYR7R.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-FUUP55PE.js.map +0 -1
- /package/dist/{agents-5HWTDR4S.js.map → agents-I6RAEGL5.js.map} +0 -0
- /package/dist/{chunk-WJJ3ZIQ6.js.map → chunk-M6ZVVKZ3.js.map} +0 -0
- /package/dist/{merge-agent-WM7ZKUET.js.map → merge-agent-ZITLVF2B.js.map} +0 -0
- /package/dist/{specialist-context-74RQF5SR.js.map → specialist-context-W25PPWM4.js.map} +0 -0
- /package/dist/{specialist-logs-T5GW7CSU.js.map → specialist-logs-KPC45SZN.js.map} +0 -0
- /package/dist/{specialists-HTYYFXHQ.js.map → specialists-H4LGYR7R.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
init_database,
|
|
17
17
|
init_review_status,
|
|
18
18
|
loadReviewStatuses,
|
|
19
|
-
saveReviewStatuses
|
|
19
|
+
saveReviewStatuses,
|
|
20
|
+
setReviewStatus
|
|
20
21
|
} from "../chunk-IZIXJYXZ.js";
|
|
21
22
|
import {
|
|
22
23
|
checkBudget,
|
|
@@ -49,7 +50,7 @@ import {
|
|
|
49
50
|
setSessionId,
|
|
50
51
|
summarizeCosts,
|
|
51
52
|
wakeSpecialistOrQueue
|
|
52
|
-
} from "../chunk-
|
|
53
|
+
} from "../chunk-M6ZVVKZ3.js";
|
|
53
54
|
import "../chunk-JQBV3Q2W.js";
|
|
54
55
|
import {
|
|
55
56
|
archivePlanning,
|
|
@@ -108,7 +109,7 @@ import {
|
|
|
108
109
|
saveSessionId,
|
|
109
110
|
spawnAgent,
|
|
110
111
|
stopAgent
|
|
111
|
-
} from "../chunk-
|
|
112
|
+
} from "../chunk-NYOGHGIW.js";
|
|
112
113
|
import {
|
|
113
114
|
checkHook,
|
|
114
115
|
clearHook,
|
|
@@ -244,9 +245,9 @@ import {
|
|
|
244
245
|
|
|
245
246
|
// src/cli/index.ts
|
|
246
247
|
init_esm_shims();
|
|
247
|
-
import { readFileSync as
|
|
248
|
-
import { join as
|
|
249
|
-
import { homedir as
|
|
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
251
|
import { Command as Command2 } from "commander";
|
|
251
252
|
import chalk62 from "chalk";
|
|
252
253
|
|
|
@@ -2557,7 +2558,7 @@ async function doneCommand(id, options = {}) {
|
|
|
2557
2558
|
const issueId = id.replace(/^agent-/i, "").toUpperCase();
|
|
2558
2559
|
const agentId = `agent-${issueId.toLowerCase()}`;
|
|
2559
2560
|
if (!options.force) {
|
|
2560
|
-
const { getAgentState: getAgentState2 } = await import("../agents-
|
|
2561
|
+
const { getAgentState: getAgentState2 } = await import("../agents-I6RAEGL5.js");
|
|
2561
2562
|
const agentState = getAgentState2(agentId);
|
|
2562
2563
|
const workspacePath = agentState?.workspace;
|
|
2563
2564
|
if (workspacePath && existsSync12(workspacePath)) {
|
|
@@ -2656,7 +2657,7 @@ async function doneCommand(id, options = {}) {
|
|
|
2656
2657
|
console.log(chalk12.dim(" LINEAR_API_KEY not set - skipping status update"));
|
|
2657
2658
|
}
|
|
2658
2659
|
}
|
|
2659
|
-
const { getAgentState: getAgentState2, saveAgentState: saveAgentState2 } = await import("../agents-
|
|
2660
|
+
const { getAgentState: getAgentState2, saveAgentState: saveAgentState2 } = await import("../agents-I6RAEGL5.js");
|
|
2660
2661
|
const existingState = getAgentState2(agentId);
|
|
2661
2662
|
if (existingState) {
|
|
2662
2663
|
existingState.status = "stopped";
|
|
@@ -5201,7 +5202,7 @@ Previous state: ${issue.state}`
|
|
|
5201
5202
|
console.log(chalk21.green(`\u2713 ${issue.identifier} reopened and ready for re-work`));
|
|
5202
5203
|
console.log("");
|
|
5203
5204
|
try {
|
|
5204
|
-
const { getAgentState: getAgentState2 } = await import("../agents-
|
|
5205
|
+
const { getAgentState: getAgentState2 } = await import("../agents-I6RAEGL5.js");
|
|
5205
5206
|
const agentId = `agent-${id.toLowerCase()}`;
|
|
5206
5207
|
const agentState = getAgentState2(agentId);
|
|
5207
5208
|
const agentRunning = agentState?.status === "running" || agentState?.status === "starting";
|
|
@@ -6523,8 +6524,8 @@ async function verifyBranchMerged(ctx) {
|
|
|
6523
6524
|
const branchName = `feature/${issueLower}`;
|
|
6524
6525
|
try {
|
|
6525
6526
|
try {
|
|
6526
|
-
const { loadReviewStatuses:
|
|
6527
|
-
const statuses =
|
|
6527
|
+
const { loadReviewStatuses: loadReviewStatuses2 } = await import("../review-status-J2YJGL3E.js");
|
|
6528
|
+
const statuses = loadReviewStatuses2();
|
|
6528
6529
|
const issueKey = ctx.issueId.toUpperCase();
|
|
6529
6530
|
if (statuses[issueKey]?.mergeStatus === "merged") {
|
|
6530
6531
|
return stepOk(step, ["Merge specialist confirmed merge completed"]);
|
|
@@ -6592,8 +6593,8 @@ async function clearReviewStatusStep(issueId) {
|
|
|
6592
6593
|
const upperKey = issueId.toUpperCase();
|
|
6593
6594
|
if (data[upperKey]) {
|
|
6594
6595
|
delete data[upperKey];
|
|
6595
|
-
const { writeFileSync:
|
|
6596
|
-
|
|
6596
|
+
const { writeFileSync: writeFileSync26 } = await import("fs");
|
|
6597
|
+
writeFileSync26(statusFile, JSON.stringify(data, null, 2));
|
|
6597
6598
|
}
|
|
6598
6599
|
}
|
|
6599
6600
|
return stepOk(step, ["Review status cleared (direct)"]);
|
|
@@ -10849,7 +10850,7 @@ async function checkOrphanedReviewStatuses() {
|
|
|
10849
10850
|
(h) => h.type === "review" && h.status === "passed"
|
|
10850
10851
|
);
|
|
10851
10852
|
const hasPassedTest = status.history?.some(
|
|
10852
|
-
(h) => h.type === "test" &&
|
|
10853
|
+
(h) => h.type === "test" && h.status === "passed"
|
|
10853
10854
|
);
|
|
10854
10855
|
const reviewAgentActive = activeReviewSessions.has(issueId.toUpperCase());
|
|
10855
10856
|
if (status.reviewStatus === "reviewing" && !reviewAgentActive && !hasPassedReview) {
|
|
@@ -10885,7 +10886,7 @@ async function checkOrphanedReviewStatuses() {
|
|
|
10885
10886
|
const { resolveProjectFromIssue: resolveProjectFromIssue2 } = await import("../projects-3CRF57ZU.js");
|
|
10886
10887
|
const resolved = resolveProjectFromIssue2(issueId);
|
|
10887
10888
|
if (resolved) {
|
|
10888
|
-
const { spawnEphemeralSpecialist } = await import("../specialists-
|
|
10889
|
+
const { spawnEphemeralSpecialist } = await import("../specialists-H4LGYR7R.js");
|
|
10889
10890
|
const result = await spawnEphemeralSpecialist(resolved.projectKey, "test-agent", {
|
|
10890
10891
|
issueId,
|
|
10891
10892
|
workspace,
|
|
@@ -11287,7 +11288,7 @@ async function runPatrol() {
|
|
|
11287
11288
|
statuses[issueId].mergeStatus = "merged";
|
|
11288
11289
|
statuses[issueId].readyForMerge = false;
|
|
11289
11290
|
writeFileSync19(REVIEW_STATUS_FILE, JSON.stringify(statuses, null, 2), "utf-8");
|
|
11290
|
-
const { postMergeLifecycle } = await import("../merge-agent-
|
|
11291
|
+
const { postMergeLifecycle } = await import("../merge-agent-ZITLVF2B.js");
|
|
11291
11292
|
postMergeLifecycle(issueId, resolved.projectPath).catch(
|
|
11292
11293
|
(err) => console.warn(`[deacon] postMergeLifecycle failed for ${issueId}: ${err}`)
|
|
11293
11294
|
);
|
|
@@ -11738,6 +11739,10 @@ var CloisterService = class {
|
|
|
11738
11739
|
console.log(`\u{1F514} Agent ${agentId} is suspended, skipping restart`);
|
|
11739
11740
|
return;
|
|
11740
11741
|
}
|
|
11742
|
+
if (runtimeState?.state === "stopped") {
|
|
11743
|
+
console.log(`\u{1F514} Agent ${agentId} runtime is stopped, skipping restart`);
|
|
11744
|
+
return;
|
|
11745
|
+
}
|
|
11741
11746
|
const now = /* @__PURE__ */ new Date();
|
|
11742
11747
|
this.deathTimestamps.push(now);
|
|
11743
11748
|
this.checkForMassDeaths();
|
|
@@ -13049,24 +13054,8 @@ function confirm2(question) {
|
|
|
13049
13054
|
|
|
13050
13055
|
// src/cli/commands/specialists/done.ts
|
|
13051
13056
|
init_esm_shims();
|
|
13057
|
+
init_review_status();
|
|
13052
13058
|
import chalk45 from "chalk";
|
|
13053
|
-
import { existsSync as existsSync44, readFileSync as readFileSync38, writeFileSync as writeFileSync24 } from "fs";
|
|
13054
|
-
import { join as join43 } from "path";
|
|
13055
|
-
import { homedir as homedir20 } from "os";
|
|
13056
|
-
var REVIEW_STATUS_FILE3 = join43(homedir20(), ".panopticon", "review-status.json");
|
|
13057
|
-
function loadReviewStatuses2() {
|
|
13058
|
-
try {
|
|
13059
|
-
if (existsSync44(REVIEW_STATUS_FILE3)) {
|
|
13060
|
-
return JSON.parse(readFileSync38(REVIEW_STATUS_FILE3, "utf-8"));
|
|
13061
|
-
}
|
|
13062
|
-
} catch (error) {
|
|
13063
|
-
console.error(chalk45.yellow("Warning: Could not load review statuses"));
|
|
13064
|
-
}
|
|
13065
|
-
return {};
|
|
13066
|
-
}
|
|
13067
|
-
function saveReviewStatuses2(statuses) {
|
|
13068
|
-
writeFileSync24(REVIEW_STATUS_FILE3, JSON.stringify(statuses, null, 2));
|
|
13069
|
-
}
|
|
13070
13059
|
async function doneCommand2(specialist, issueId, options) {
|
|
13071
13060
|
const validSpecialists = ["review", "test", "merge"];
|
|
13072
13061
|
if (!validSpecialists.includes(specialist)) {
|
|
@@ -13084,57 +13073,39 @@ async function doneCommand2(specialist, issueId, options) {
|
|
|
13084
13073
|
process.exit(1);
|
|
13085
13074
|
}
|
|
13086
13075
|
const normalizedIssueId = issueId.toUpperCase();
|
|
13087
|
-
const
|
|
13088
|
-
let status = statuses[normalizedIssueId];
|
|
13089
|
-
if (!status) {
|
|
13090
|
-
status = {
|
|
13091
|
-
issueId: normalizedIssueId,
|
|
13092
|
-
reviewStatus: "pending",
|
|
13093
|
-
testStatus: "pending",
|
|
13094
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13095
|
-
readyForMerge: false
|
|
13096
|
-
};
|
|
13097
|
-
}
|
|
13076
|
+
const update = {};
|
|
13098
13077
|
switch (specialist) {
|
|
13099
13078
|
case "review":
|
|
13100
|
-
|
|
13101
|
-
if (options.notes)
|
|
13102
|
-
status.reviewNotes = options.notes;
|
|
13103
|
-
}
|
|
13079
|
+
update.reviewStatus = options.status;
|
|
13080
|
+
if (options.notes) update.reviewNotes = options.notes;
|
|
13104
13081
|
console.log(chalk45.green(`\u2713 Review ${options.status} for ${normalizedIssueId}`));
|
|
13105
13082
|
if (options.status === "passed") {
|
|
13106
13083
|
console.log(chalk45.dim(" Test agent can now proceed"));
|
|
13107
13084
|
}
|
|
13108
13085
|
break;
|
|
13109
13086
|
case "test":
|
|
13110
|
-
|
|
13111
|
-
if (options.notes)
|
|
13112
|
-
|
|
13113
|
-
}
|
|
13114
|
-
if (options.status === "passed" && status.reviewStatus === "passed") {
|
|
13115
|
-
status.readyForMerge = true;
|
|
13116
|
-
console.log(chalk45.green(`\u2713 Tests ${options.status} for ${normalizedIssueId}`));
|
|
13117
|
-
console.log(chalk45.green("\u2713 Ready for merge!"));
|
|
13118
|
-
} else if (options.status === "passed") {
|
|
13087
|
+
update.testStatus = options.status;
|
|
13088
|
+
if (options.notes) update.testNotes = options.notes;
|
|
13089
|
+
if (options.status === "passed") {
|
|
13119
13090
|
console.log(chalk45.green(`\u2713 Tests ${options.status} for ${normalizedIssueId}`));
|
|
13120
13091
|
} else {
|
|
13121
13092
|
console.log(chalk45.yellow(`\u2717 Tests ${options.status} for ${normalizedIssueId}`));
|
|
13122
|
-
status.readyForMerge = false;
|
|
13123
13093
|
}
|
|
13124
13094
|
break;
|
|
13125
13095
|
case "merge":
|
|
13126
|
-
|
|
13096
|
+
update.mergeStatus = options.status === "passed" ? "merged" : "failed";
|
|
13127
13097
|
if (options.status === "passed") {
|
|
13098
|
+
update.readyForMerge = false;
|
|
13128
13099
|
console.log(chalk45.green(`\u2713 Merge completed for ${normalizedIssueId}`));
|
|
13129
|
-
status.readyForMerge = false;
|
|
13130
13100
|
} else {
|
|
13131
13101
|
console.log(chalk45.red(`\u2717 Merge failed for ${normalizedIssueId}`));
|
|
13132
13102
|
}
|
|
13133
13103
|
break;
|
|
13134
13104
|
}
|
|
13135
|
-
status
|
|
13136
|
-
|
|
13137
|
-
|
|
13105
|
+
const status = setReviewStatus(normalizedIssueId, update);
|
|
13106
|
+
if (specialist === "test" && status.readyForMerge) {
|
|
13107
|
+
console.log(chalk45.green("\u2713 Ready for merge!"));
|
|
13108
|
+
}
|
|
13138
13109
|
if (options.notes) {
|
|
13139
13110
|
console.log(chalk45.dim(` Notes: ${options.notes}`));
|
|
13140
13111
|
}
|
|
@@ -13166,13 +13137,13 @@ function formatStatus(status) {
|
|
|
13166
13137
|
|
|
13167
13138
|
// src/cli/commands/specialists/logs.ts
|
|
13168
13139
|
init_esm_shims();
|
|
13169
|
-
import { existsSync as
|
|
13140
|
+
import { existsSync as existsSync44 } from "fs";
|
|
13170
13141
|
import { exec as exec15 } from "child_process";
|
|
13171
13142
|
import { promisify as promisify15 } from "util";
|
|
13172
13143
|
var execAsync15 = promisify15(exec15);
|
|
13173
13144
|
async function listLogsCommand(project2, type, options) {
|
|
13174
13145
|
try {
|
|
13175
|
-
const { listRunLogs } = await import("../specialist-logs-
|
|
13146
|
+
const { listRunLogs } = await import("../specialist-logs-KPC45SZN.js");
|
|
13176
13147
|
const limit = options.limit ? parseInt(options.limit) : 10;
|
|
13177
13148
|
const runs = listRunLogs(project2, type, { limit });
|
|
13178
13149
|
if (options.json) {
|
|
@@ -13217,7 +13188,7 @@ View a specific run: pan specialists logs ${project2} ${type} <runId>
|
|
|
13217
13188
|
}
|
|
13218
13189
|
async function viewLogCommand(project2, type, runId, options) {
|
|
13219
13190
|
try {
|
|
13220
|
-
const { getRunLog, parseLogMetadata, getRunLogPath } = await import("../specialist-logs-
|
|
13191
|
+
const { getRunLog, parseLogMetadata, getRunLogPath } = await import("../specialist-logs-KPC45SZN.js");
|
|
13221
13192
|
const content = getRunLog(project2, type, runId);
|
|
13222
13193
|
if (!content) {
|
|
13223
13194
|
console.error(`\u274C Run log not found: ${runId}`);
|
|
@@ -13241,15 +13212,15 @@ async function viewLogCommand(project2, type, runId, options) {
|
|
|
13241
13212
|
}
|
|
13242
13213
|
async function tailLogCommand(project2, type) {
|
|
13243
13214
|
try {
|
|
13244
|
-
const { getRunLogPath } = await import("../specialist-logs-
|
|
13245
|
-
const { getProjectSpecialistMetadata } = await import("../specialists-
|
|
13215
|
+
const { getRunLogPath } = await import("../specialist-logs-KPC45SZN.js");
|
|
13216
|
+
const { getProjectSpecialistMetadata } = await import("../specialists-H4LGYR7R.js");
|
|
13246
13217
|
const metadata = getProjectSpecialistMetadata(project2, type);
|
|
13247
13218
|
if (!metadata.currentRun) {
|
|
13248
13219
|
console.error(`\u274C No active run for ${project2}/${type}`);
|
|
13249
13220
|
process.exit(1);
|
|
13250
13221
|
}
|
|
13251
13222
|
const logPath = getRunLogPath(project2, type, metadata.currentRun);
|
|
13252
|
-
if (!
|
|
13223
|
+
if (!existsSync44(logPath)) {
|
|
13253
13224
|
console.error(`\u274C Log file not found: ${logPath}`);
|
|
13254
13225
|
process.exit(1);
|
|
13255
13226
|
}
|
|
@@ -13311,7 +13282,7 @@ async function cleanupLogsCommand(projectOrAll, type, options) {
|
|
|
13311
13282
|
console.log(" Use --force to confirm.");
|
|
13312
13283
|
process.exit(1);
|
|
13313
13284
|
}
|
|
13314
|
-
const { cleanupAllLogs } = await import("../specialist-logs-
|
|
13285
|
+
const { cleanupAllLogs } = await import("../specialist-logs-KPC45SZN.js");
|
|
13315
13286
|
console.log("\u{1F9F9} Cleaning up old logs for all projects...\n");
|
|
13316
13287
|
const results = cleanupAllLogs();
|
|
13317
13288
|
console.log(`
|
|
@@ -13338,7 +13309,7 @@ async function cleanupLogsCommand(projectOrAll, type, options) {
|
|
|
13338
13309
|
console.log(" Use --force to confirm.");
|
|
13339
13310
|
process.exit(1);
|
|
13340
13311
|
}
|
|
13341
|
-
const { cleanupOldLogs } = await import("../specialist-logs-
|
|
13312
|
+
const { cleanupOldLogs } = await import("../specialist-logs-KPC45SZN.js");
|
|
13342
13313
|
const { getSpecialistRetention } = await import("../projects-3CRF57ZU.js");
|
|
13343
13314
|
const retention = getSpecialistRetention(projectOrAll);
|
|
13344
13315
|
console.log(`\u{1F9F9} Cleaning up old logs for ${projectOrAll}/${type}...`);
|
|
@@ -13377,9 +13348,9 @@ import ora19 from "ora";
|
|
|
13377
13348
|
// src/lib/convoy.ts
|
|
13378
13349
|
init_esm_shims();
|
|
13379
13350
|
init_tmux();
|
|
13380
|
-
import { existsSync as
|
|
13381
|
-
import { join as
|
|
13382
|
-
import { homedir as
|
|
13351
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync22, writeFileSync as writeFileSync24, readFileSync as readFileSync39, readdirSync as readdirSync19 } from "fs";
|
|
13352
|
+
import { join as join43 } from "path";
|
|
13353
|
+
import { homedir as homedir20 } from "os";
|
|
13383
13354
|
import { exec as exec16 } from "child_process";
|
|
13384
13355
|
import { promisify as promisify16 } from "util";
|
|
13385
13356
|
import { parse as parseYaml } from "yaml";
|
|
@@ -13487,25 +13458,25 @@ function getExecutionOrder(template) {
|
|
|
13487
13458
|
init_paths();
|
|
13488
13459
|
init_work_type_router();
|
|
13489
13460
|
var execAsync16 = promisify16(exec16);
|
|
13490
|
-
var CONVOY_DIR =
|
|
13461
|
+
var CONVOY_DIR = join43(homedir20(), ".panopticon", "convoys");
|
|
13491
13462
|
function getConvoyStateFile(convoyId) {
|
|
13492
|
-
return
|
|
13463
|
+
return join43(CONVOY_DIR, `${convoyId}.json`);
|
|
13493
13464
|
}
|
|
13494
13465
|
function getConvoyOutputDir(convoyId, template) {
|
|
13495
13466
|
const baseDir = template.config?.outputDir || ".panopticon/convoy-output";
|
|
13496
|
-
return
|
|
13467
|
+
return join43(process.cwd(), baseDir, convoyId);
|
|
13497
13468
|
}
|
|
13498
13469
|
function saveConvoyState(state) {
|
|
13499
13470
|
mkdirSync22(CONVOY_DIR, { recursive: true });
|
|
13500
|
-
|
|
13471
|
+
writeFileSync24(getConvoyStateFile(state.id), JSON.stringify(state, null, 2));
|
|
13501
13472
|
}
|
|
13502
13473
|
function loadConvoyState(convoyId) {
|
|
13503
13474
|
const stateFile = getConvoyStateFile(convoyId);
|
|
13504
|
-
if (!
|
|
13475
|
+
if (!existsSync45(stateFile)) {
|
|
13505
13476
|
return void 0;
|
|
13506
13477
|
}
|
|
13507
13478
|
try {
|
|
13508
|
-
const content =
|
|
13479
|
+
const content = readFileSync39(stateFile, "utf-8");
|
|
13509
13480
|
return JSON.parse(content);
|
|
13510
13481
|
} catch {
|
|
13511
13482
|
return void 0;
|
|
@@ -13515,7 +13486,7 @@ function getConvoyStatus(convoyId) {
|
|
|
13515
13486
|
return loadConvoyState(convoyId);
|
|
13516
13487
|
}
|
|
13517
13488
|
function listConvoys(filter) {
|
|
13518
|
-
if (!
|
|
13489
|
+
if (!existsSync45(CONVOY_DIR)) {
|
|
13519
13490
|
return [];
|
|
13520
13491
|
}
|
|
13521
13492
|
const files = readdirSync19(CONVOY_DIR).filter((f) => f.endsWith(".json"));
|
|
@@ -13534,10 +13505,10 @@ function listConvoys(filter) {
|
|
|
13534
13505
|
);
|
|
13535
13506
|
}
|
|
13536
13507
|
function parseAgentTemplate(templatePath) {
|
|
13537
|
-
if (!
|
|
13508
|
+
if (!existsSync45(templatePath)) {
|
|
13538
13509
|
throw new Error(`Agent template not found: ${templatePath}`);
|
|
13539
13510
|
}
|
|
13540
|
-
const content =
|
|
13511
|
+
const content = readFileSync39(templatePath, "utf-8");
|
|
13541
13512
|
const frontmatterMatch = content.match(/^---\n([\s\S]+?)\n---\n([\s\S]*)$/);
|
|
13542
13513
|
if (!frontmatterMatch) {
|
|
13543
13514
|
throw new Error(`Invalid agent template format (missing frontmatter): ${templatePath}`);
|
|
@@ -13563,7 +13534,7 @@ function mapConvoyRoleToWorkType(role) {
|
|
|
13563
13534
|
}
|
|
13564
13535
|
async function spawnConvoyAgent(convoy, agent, agentState, context) {
|
|
13565
13536
|
const { role, subagent } = agent;
|
|
13566
|
-
const templatePath =
|
|
13537
|
+
const templatePath = join43(AGENTS_DIR, `${subagent}.md`);
|
|
13567
13538
|
const template = parseAgentTemplate(templatePath);
|
|
13568
13539
|
let model = template.model;
|
|
13569
13540
|
try {
|
|
@@ -13602,8 +13573,8 @@ ${context.issueId ? `**Issue ID**: ${context.issueId}` : ""}
|
|
|
13602
13573
|
`;
|
|
13603
13574
|
prompt = contextInstructions + prompt;
|
|
13604
13575
|
mkdirSync22(convoy.outputDir, { recursive: true });
|
|
13605
|
-
const promptFile =
|
|
13606
|
-
|
|
13576
|
+
const promptFile = join43(convoy.outputDir, `${role}-prompt.md`);
|
|
13577
|
+
writeFileSync24(promptFile, prompt);
|
|
13607
13578
|
const claudeCmd = `claude --dangerously-skip-permissions --model ${model}`;
|
|
13608
13579
|
createSession(agentState.tmuxSession, convoy.context.projectPath, claudeCmd, {
|
|
13609
13580
|
env: {
|
|
@@ -13641,7 +13612,7 @@ async function startConvoy(templateName, context) {
|
|
|
13641
13612
|
};
|
|
13642
13613
|
for (const agent of template.agents) {
|
|
13643
13614
|
const tmuxSession = `${convoyId}-${agent.role}`;
|
|
13644
|
-
const outputFile =
|
|
13615
|
+
const outputFile = join43(outputDir, `${agent.role}.md`);
|
|
13645
13616
|
state.agents.push({
|
|
13646
13617
|
role: agent.role,
|
|
13647
13618
|
subagent: agent.subagent,
|
|
@@ -13676,8 +13647,8 @@ async function executePhase(convoy, template, phaseAgents, context) {
|
|
|
13676
13647
|
const agentContext = { ...context };
|
|
13677
13648
|
for (const depRole of deps) {
|
|
13678
13649
|
const depAgent = convoy.agents.find((a) => a.role === depRole);
|
|
13679
|
-
if (depAgent?.outputFile &&
|
|
13680
|
-
agentContext[`${depRole}_output`] =
|
|
13650
|
+
if (depAgent?.outputFile && existsSync45(depAgent.outputFile)) {
|
|
13651
|
+
agentContext[`${depRole}_output`] = readFileSync39(depAgent.outputFile, "utf-8");
|
|
13681
13652
|
}
|
|
13682
13653
|
}
|
|
13683
13654
|
spawnPromises.push(spawnConvoyAgent(convoy, agent, agentState, agentContext));
|
|
@@ -13740,7 +13711,7 @@ function updateAgentStatuses(convoy) {
|
|
|
13740
13711
|
agent.status = "completed";
|
|
13741
13712
|
agent.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13742
13713
|
updated = true;
|
|
13743
|
-
if (agent.outputFile &&
|
|
13714
|
+
if (agent.outputFile && existsSync45(agent.outputFile)) {
|
|
13744
13715
|
agent.exitCode = 0;
|
|
13745
13716
|
} else {
|
|
13746
13717
|
agent.exitCode = 1;
|
|
@@ -13986,30 +13957,30 @@ function registerConvoyCommands(program2) {
|
|
|
13986
13957
|
init_esm_shims();
|
|
13987
13958
|
init_projects();
|
|
13988
13959
|
import chalk50 from "chalk";
|
|
13989
|
-
import { existsSync as
|
|
13990
|
-
import { join as
|
|
13960
|
+
import { existsSync as existsSync46, readFileSync as readFileSync40, symlinkSync as symlinkSync2, mkdirSync as mkdirSync23, readdirSync as readdirSync20, statSync as statSync10 } from "fs";
|
|
13961
|
+
import { join as join44, resolve as resolve2, dirname as dirname13 } from "path";
|
|
13991
13962
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13992
13963
|
var __filename5 = fileURLToPath4(import.meta.url);
|
|
13993
13964
|
var __dirname5 = dirname13(__filename5);
|
|
13994
|
-
var BUNDLED_HOOKS_DIR =
|
|
13965
|
+
var BUNDLED_HOOKS_DIR = join44(__dirname5, "..", "..", "scripts", "git-hooks");
|
|
13995
13966
|
function installGitHooks(gitDir) {
|
|
13996
|
-
const hooksTarget =
|
|
13967
|
+
const hooksTarget = join44(gitDir, "hooks");
|
|
13997
13968
|
let installed = 0;
|
|
13998
|
-
if (!
|
|
13969
|
+
if (!existsSync46(hooksTarget)) {
|
|
13999
13970
|
mkdirSync23(hooksTarget, { recursive: true });
|
|
14000
13971
|
}
|
|
14001
|
-
if (!
|
|
13972
|
+
if (!existsSync46(BUNDLED_HOOKS_DIR)) {
|
|
14002
13973
|
return 0;
|
|
14003
13974
|
}
|
|
14004
13975
|
try {
|
|
14005
13976
|
const hooks = readdirSync20(BUNDLED_HOOKS_DIR).filter((f) => {
|
|
14006
|
-
const p =
|
|
14007
|
-
return
|
|
13977
|
+
const p = join44(BUNDLED_HOOKS_DIR, f);
|
|
13978
|
+
return existsSync46(p) && statSync10(p).isFile();
|
|
14008
13979
|
});
|
|
14009
13980
|
for (const hook of hooks) {
|
|
14010
|
-
const source =
|
|
14011
|
-
const target =
|
|
14012
|
-
if (
|
|
13981
|
+
const source = join44(BUNDLED_HOOKS_DIR, hook);
|
|
13982
|
+
const target = join44(hooksTarget, hook);
|
|
13983
|
+
if (existsSync46(target)) {
|
|
14013
13984
|
try {
|
|
14014
13985
|
const { readlinkSync: readlinkSync2 } = __require("fs");
|
|
14015
13986
|
if (readlinkSync2(target) === source) {
|
|
@@ -14018,7 +13989,7 @@ function installGitHooks(gitDir) {
|
|
|
14018
13989
|
} catch {
|
|
14019
13990
|
}
|
|
14020
13991
|
}
|
|
14021
|
-
if (
|
|
13992
|
+
if (existsSync46(target)) {
|
|
14022
13993
|
const { renameSync: renameSync4 } = __require("fs");
|
|
14023
13994
|
renameSync4(target, `${target}.backup`);
|
|
14024
13995
|
}
|
|
@@ -14031,7 +14002,7 @@ function installGitHooks(gitDir) {
|
|
|
14031
14002
|
}
|
|
14032
14003
|
async function projectAddCommand(projectPath, options = {}) {
|
|
14033
14004
|
const fullPath = resolve2(projectPath);
|
|
14034
|
-
if (!
|
|
14005
|
+
if (!existsSync46(fullPath)) {
|
|
14035
14006
|
console.log(chalk50.red(`Path does not exist: ${fullPath}`));
|
|
14036
14007
|
return;
|
|
14037
14008
|
}
|
|
@@ -14046,9 +14017,9 @@ async function projectAddCommand(projectPath, options = {}) {
|
|
|
14046
14017
|
}
|
|
14047
14018
|
let linearTeam = options.linearTeam;
|
|
14048
14019
|
if (!linearTeam) {
|
|
14049
|
-
const projectToml =
|
|
14050
|
-
if (
|
|
14051
|
-
const content =
|
|
14020
|
+
const projectToml = join44(fullPath, ".panopticon", "project.toml");
|
|
14021
|
+
if (existsSync46(projectToml)) {
|
|
14022
|
+
const content = readFileSync40(projectToml, "utf-8");
|
|
14052
14023
|
const match = content.match(/team\s*=\s*"([^"]+)"/);
|
|
14053
14024
|
if (match) linearTeam = match[1];
|
|
14054
14025
|
}
|
|
@@ -14074,19 +14045,19 @@ async function projectAddCommand(projectPath, options = {}) {
|
|
|
14074
14045
|
console.log(chalk50.dim(` Rally project: ${options.rallyProject}`));
|
|
14075
14046
|
}
|
|
14076
14047
|
console.log("");
|
|
14077
|
-
const hasDevcontainer =
|
|
14078
|
-
const hasInfra =
|
|
14079
|
-
const hasDevcontainerTemplate =
|
|
14080
|
-
const hasRootGit =
|
|
14048
|
+
const hasDevcontainer = existsSync46(join44(fullPath, ".devcontainer"));
|
|
14049
|
+
const hasInfra = existsSync46(join44(fullPath, "infra"));
|
|
14050
|
+
const hasDevcontainerTemplate = existsSync46(join44(fullPath, "infra", ".devcontainer-template")) || existsSync46(join44(fullPath, ".devcontainer-template"));
|
|
14051
|
+
const hasRootGit = existsSync46(join44(fullPath, ".git"));
|
|
14081
14052
|
const subRepos = [];
|
|
14082
14053
|
if (!hasRootGit) {
|
|
14083
14054
|
const { readdirSync: readdirSync22, statSync: statSync12 } = await import("fs");
|
|
14084
14055
|
try {
|
|
14085
14056
|
const entries = readdirSync22(fullPath);
|
|
14086
14057
|
for (const entry of entries) {
|
|
14087
|
-
const entryPath =
|
|
14058
|
+
const entryPath = join44(fullPath, entry);
|
|
14088
14059
|
try {
|
|
14089
|
-
if (statSync12(entryPath).isDirectory() &&
|
|
14060
|
+
if (statSync12(entryPath).isDirectory() && existsSync46(join44(entryPath, ".git"))) {
|
|
14090
14061
|
subRepos.push(entry);
|
|
14091
14062
|
}
|
|
14092
14063
|
} catch {
|
|
@@ -14103,13 +14074,13 @@ async function projectAddCommand(projectPath, options = {}) {
|
|
|
14103
14074
|
}
|
|
14104
14075
|
let hooksInstalled = 0;
|
|
14105
14076
|
if (hasRootGit) {
|
|
14106
|
-
hooksInstalled = installGitHooks(
|
|
14077
|
+
hooksInstalled = installGitHooks(join44(fullPath, ".git"));
|
|
14107
14078
|
if (hooksInstalled > 0) {
|
|
14108
14079
|
console.log(chalk50.green(`\u2713 Installed ${hooksInstalled} git hook(s) for branch protection`));
|
|
14109
14080
|
}
|
|
14110
14081
|
} else if (isPolyrepo) {
|
|
14111
14082
|
for (const repo of subRepos) {
|
|
14112
|
-
const count = installGitHooks(
|
|
14083
|
+
const count = installGitHooks(join44(fullPath, repo, ".git"));
|
|
14113
14084
|
hooksInstalled += count;
|
|
14114
14085
|
}
|
|
14115
14086
|
if (hooksInstalled > 0) {
|
|
@@ -14181,7 +14152,7 @@ async function projectListCommand(options = {}) {
|
|
|
14181
14152
|
}
|
|
14182
14153
|
console.log(chalk50.bold("\nRegistered Projects:\n"));
|
|
14183
14154
|
for (const { key, config: config2 } of projects) {
|
|
14184
|
-
const exists =
|
|
14155
|
+
const exists = existsSync46(config2.path);
|
|
14185
14156
|
const statusIcon = exists ? chalk50.green("\u2713") : chalk50.red("\u2717");
|
|
14186
14157
|
console.log(`${statusIcon} ${chalk50.bold(config2.name)} ${chalk50.dim(`(${key})`)}`);
|
|
14187
14158
|
console.log(` ${chalk50.dim(config2.path)}`);
|
|
@@ -14215,7 +14186,7 @@ async function projectRemoveCommand(nameOrPath) {
|
|
|
14215
14186
|
console.log(chalk50.dim(`Use 'pan project list' to see registered projects.`));
|
|
14216
14187
|
}
|
|
14217
14188
|
async function projectInitCommand() {
|
|
14218
|
-
if (
|
|
14189
|
+
if (existsSync46(PROJECTS_CONFIG_FILE)) {
|
|
14219
14190
|
console.log(chalk50.yellow(`Config already exists: ${PROJECTS_CONFIG_FILE}`));
|
|
14220
14191
|
return;
|
|
14221
14192
|
}
|
|
@@ -14249,7 +14220,7 @@ async function projectShowCommand(keyOrName) {
|
|
|
14249
14220
|
console.log(chalk50.dim(`Use 'pan project list' to see registered projects.`));
|
|
14250
14221
|
process.exit(1);
|
|
14251
14222
|
}
|
|
14252
|
-
const pathExists =
|
|
14223
|
+
const pathExists = existsSync46(found.path);
|
|
14253
14224
|
const pathStatus = pathExists ? chalk50.green("\u2713") : chalk50.red("\u2717");
|
|
14254
14225
|
console.log(chalk50.bold(`
|
|
14255
14226
|
Project: ${foundKey}
|
|
@@ -14281,10 +14252,10 @@ Project: ${foundKey}
|
|
|
14281
14252
|
init_esm_shims();
|
|
14282
14253
|
init_paths();
|
|
14283
14254
|
import chalk51 from "chalk";
|
|
14284
|
-
import { existsSync as
|
|
14255
|
+
import { existsSync as existsSync47, readdirSync as readdirSync21, readFileSync as readFileSync41 } from "fs";
|
|
14285
14256
|
import { execSync as execSync6 } from "child_process";
|
|
14286
|
-
import { homedir as
|
|
14287
|
-
import { join as
|
|
14257
|
+
import { homedir as homedir21 } from "os";
|
|
14258
|
+
import { join as join45 } from "path";
|
|
14288
14259
|
function checkCommand3(cmd) {
|
|
14289
14260
|
try {
|
|
14290
14261
|
execSync6(`which ${cmd}`, { encoding: "utf-8", stdio: "pipe" });
|
|
@@ -14294,10 +14265,10 @@ function checkCommand3(cmd) {
|
|
|
14294
14265
|
}
|
|
14295
14266
|
}
|
|
14296
14267
|
function checkDirectory(path) {
|
|
14297
|
-
return
|
|
14268
|
+
return existsSync47(path);
|
|
14298
14269
|
}
|
|
14299
14270
|
function countItems(path) {
|
|
14300
|
-
if (!
|
|
14271
|
+
if (!existsSync47(path)) return 0;
|
|
14301
14272
|
try {
|
|
14302
14273
|
return readdirSync21(path).length;
|
|
14303
14274
|
} catch {
|
|
@@ -14348,8 +14319,8 @@ async function doctorCommand() {
|
|
|
14348
14319
|
}
|
|
14349
14320
|
}
|
|
14350
14321
|
if (checkDirectory(CLAUDE_DIR)) {
|
|
14351
|
-
const skillsCount = countItems(
|
|
14352
|
-
const commandsCount = countItems(
|
|
14322
|
+
const skillsCount = countItems(join45(CLAUDE_DIR, "skills"));
|
|
14323
|
+
const commandsCount = countItems(join45(CLAUDE_DIR, "commands"));
|
|
14353
14324
|
checks.push({
|
|
14354
14325
|
name: "Claude Code Skills",
|
|
14355
14326
|
status: skillsCount > 0 ? "ok" : "warn",
|
|
@@ -14370,8 +14341,8 @@ async function doctorCommand() {
|
|
|
14370
14341
|
fix: "Install Claude Code first"
|
|
14371
14342
|
});
|
|
14372
14343
|
}
|
|
14373
|
-
const envFile =
|
|
14374
|
-
if (
|
|
14344
|
+
const envFile = join45(homedir21(), ".panopticon.env");
|
|
14345
|
+
if (existsSync47(envFile)) {
|
|
14375
14346
|
checks.push({ name: "Config File", status: "ok", message: "~/.panopticon.env exists" });
|
|
14376
14347
|
} else {
|
|
14377
14348
|
checks.push({
|
|
@@ -14383,8 +14354,8 @@ async function doctorCommand() {
|
|
|
14383
14354
|
}
|
|
14384
14355
|
if (process.env.LINEAR_API_KEY) {
|
|
14385
14356
|
checks.push({ name: "LINEAR_API_KEY", status: "ok", message: "Set in environment" });
|
|
14386
|
-
} else if (
|
|
14387
|
-
const content =
|
|
14357
|
+
} else if (existsSync47(envFile)) {
|
|
14358
|
+
const content = readFileSync41(envFile, "utf-8");
|
|
14388
14359
|
if (content.includes("LINEAR_API_KEY")) {
|
|
14389
14360
|
checks.push({ name: "LINEAR_API_KEY", status: "ok", message: "Set in config file" });
|
|
14390
14361
|
} else {
|
|
@@ -14452,15 +14423,15 @@ init_esm_shims();
|
|
|
14452
14423
|
init_config();
|
|
14453
14424
|
import { execSync as execSync7 } from "child_process";
|
|
14454
14425
|
import chalk52 from "chalk";
|
|
14455
|
-
import { readFileSync as
|
|
14426
|
+
import { readFileSync as readFileSync42 } from "fs";
|
|
14456
14427
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
14457
|
-
import { dirname as dirname14, join as
|
|
14428
|
+
import { dirname as dirname14, join as join46 } from "path";
|
|
14458
14429
|
function getCurrentVersion() {
|
|
14459
14430
|
try {
|
|
14460
14431
|
const __filename6 = fileURLToPath5(import.meta.url);
|
|
14461
14432
|
const __dirname6 = dirname14(__filename6);
|
|
14462
|
-
const pkgPath =
|
|
14463
|
-
const pkg = JSON.parse(
|
|
14433
|
+
const pkgPath = join46(__dirname6, "..", "..", "..", "package.json");
|
|
14434
|
+
const pkg = JSON.parse(readFileSync42(pkgPath, "utf-8"));
|
|
14464
14435
|
return pkg.version;
|
|
14465
14436
|
} catch {
|
|
14466
14437
|
return "unknown";
|
|
@@ -14546,8 +14517,8 @@ init_esm_shims();
|
|
|
14546
14517
|
init_projects();
|
|
14547
14518
|
import chalk53 from "chalk";
|
|
14548
14519
|
import ora21 from "ora";
|
|
14549
|
-
import { existsSync as
|
|
14550
|
-
import { join as
|
|
14520
|
+
import { existsSync as existsSync48, readFileSync as readFileSync43, writeFileSync as writeFileSync25, mkdirSync as mkdirSync24, statSync as statSync11 } from "fs";
|
|
14521
|
+
import { join as join47, dirname as dirname15 } from "path";
|
|
14551
14522
|
import { exec as exec17 } from "child_process";
|
|
14552
14523
|
import { promisify as promisify17 } from "util";
|
|
14553
14524
|
var execAsync17 = promisify17(exec17);
|
|
@@ -14609,9 +14580,9 @@ async function snapshotCommand(options) {
|
|
|
14609
14580
|
`));
|
|
14610
14581
|
return;
|
|
14611
14582
|
}
|
|
14612
|
-
const outputPath = options.output || dbConfig.seed_file ||
|
|
14583
|
+
const outputPath = options.output || dbConfig.seed_file || join47(projectConfig.path, "infra", "seed", "seed.sql");
|
|
14613
14584
|
const outputDir = dirname15(outputPath);
|
|
14614
|
-
if (!
|
|
14585
|
+
if (!existsSync48(outputDir)) {
|
|
14615
14586
|
mkdirSync24(outputDir, { recursive: true });
|
|
14616
14587
|
}
|
|
14617
14588
|
spinner.text = "Running snapshot command...";
|
|
@@ -14634,8 +14605,8 @@ async function snapshotCommand(options) {
|
|
|
14634
14605
|
try {
|
|
14635
14606
|
await execAsync17(fullCmd, { timeout: 3e5 });
|
|
14636
14607
|
} catch (error) {
|
|
14637
|
-
if (
|
|
14638
|
-
const content2 =
|
|
14608
|
+
if (existsSync48(outputPath)) {
|
|
14609
|
+
const content2 = readFileSync43(outputPath, "utf-8");
|
|
14639
14610
|
if (content2.includes("PostgreSQL database dump")) {
|
|
14640
14611
|
spinner.warn("Snapshot completed with warnings (stderr captured)");
|
|
14641
14612
|
console.log(chalk53.dim(" Run `pan db clean` to remove stderr noise from the file"));
|
|
@@ -14648,7 +14619,7 @@ async function snapshotCommand(options) {
|
|
|
14648
14619
|
return;
|
|
14649
14620
|
}
|
|
14650
14621
|
}
|
|
14651
|
-
const content =
|
|
14622
|
+
const content = readFileSync43(outputPath, "utf-8");
|
|
14652
14623
|
if (content.includes("Defaulted container") || content.includes("Unable to use a TTY")) {
|
|
14653
14624
|
spinner.text = "Cleaning kubectl output from snapshot...";
|
|
14654
14625
|
await cleanFile(outputPath);
|
|
@@ -14680,14 +14651,14 @@ async function seedCommand(workspaceOrIssue, options) {
|
|
|
14680
14651
|
spinner.fail("Could not find project workspace configuration");
|
|
14681
14652
|
return;
|
|
14682
14653
|
}
|
|
14683
|
-
const workspacePath =
|
|
14684
|
-
if (!
|
|
14654
|
+
const workspacePath = join47(projectConfig.path, projectConfig.workspace.workspaces_dir || "workspaces", folderName);
|
|
14655
|
+
if (!existsSync48(workspacePath)) {
|
|
14685
14656
|
spinner.fail(`Workspace not found: ${workspacePath}`);
|
|
14686
14657
|
return;
|
|
14687
14658
|
}
|
|
14688
14659
|
const dbConfig = projectConfig.workspace.database;
|
|
14689
14660
|
const seedFile = options.file || dbConfig?.seed_file;
|
|
14690
|
-
if (!seedFile || !
|
|
14661
|
+
if (!seedFile || !existsSync48(seedFile)) {
|
|
14691
14662
|
spinner.fail(`Seed file not found: ${seedFile || "(not configured)"}`);
|
|
14692
14663
|
console.log(chalk53.dim("\nConfigure seed_file in projects.yaml or use --file"));
|
|
14693
14664
|
return;
|
|
@@ -14829,11 +14800,11 @@ async function statusCommand5(workspaceOrIssue) {
|
|
|
14829
14800
|
async function cleanCommand(file, options) {
|
|
14830
14801
|
const spinner = ora21("Cleaning database dump file...").start();
|
|
14831
14802
|
try {
|
|
14832
|
-
if (!
|
|
14803
|
+
if (!existsSync48(file)) {
|
|
14833
14804
|
spinner.fail(`File not found: ${file}`);
|
|
14834
14805
|
return;
|
|
14835
14806
|
}
|
|
14836
|
-
const content =
|
|
14807
|
+
const content = readFileSync43(file, "utf-8");
|
|
14837
14808
|
const lines = content.split("\n");
|
|
14838
14809
|
const patternsToRemove = [
|
|
14839
14810
|
/^Defaulted container/,
|
|
@@ -14893,7 +14864,7 @@ async function cleanCommand(file, options) {
|
|
|
14893
14864
|
return;
|
|
14894
14865
|
}
|
|
14895
14866
|
const outputPath = options.output || file;
|
|
14896
|
-
|
|
14867
|
+
writeFileSync25(outputPath, cleanedContent);
|
|
14897
14868
|
spinner.succeed(`Cleaned ${removedLines} lines`);
|
|
14898
14869
|
console.log(chalk53.dim(` Output: ${outputPath}`));
|
|
14899
14870
|
console.log(chalk53.dim(` Original: ${lines.length} lines`));
|
|
@@ -14903,7 +14874,7 @@ async function cleanCommand(file, options) {
|
|
|
14903
14874
|
}
|
|
14904
14875
|
}
|
|
14905
14876
|
async function cleanFile(filePath) {
|
|
14906
|
-
const content =
|
|
14877
|
+
const content = readFileSync43(filePath, "utf-8");
|
|
14907
14878
|
const lines = content.split("\n");
|
|
14908
14879
|
let startIndex = 0;
|
|
14909
14880
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -14923,7 +14894,7 @@ async function cleanFile(filePath) {
|
|
|
14923
14894
|
/^error: timed out waiting/
|
|
14924
14895
|
];
|
|
14925
14896
|
const cleanedLines = lines.slice(startIndex).filter((line) => !patternsToRemove.some((p) => p.test(line)));
|
|
14926
|
-
|
|
14897
|
+
writeFileSync25(filePath, cleanedLines.join("\n"));
|
|
14927
14898
|
}
|
|
14928
14899
|
async function configCommand(project2) {
|
|
14929
14900
|
const projects = loadFullProjects();
|
|
@@ -14957,7 +14928,7 @@ async function configCommand(project2) {
|
|
|
14957
14928
|
return;
|
|
14958
14929
|
}
|
|
14959
14930
|
if (dbConfig.seed_file) {
|
|
14960
|
-
const exists =
|
|
14931
|
+
const exists = existsSync48(dbConfig.seed_file);
|
|
14961
14932
|
console.log(` Seed file: ${dbConfig.seed_file}`);
|
|
14962
14933
|
console.log(chalk53.dim(` Status: ${exists ? chalk53.green("exists") : chalk53.red("not found")}`));
|
|
14963
14934
|
if (exists) {
|
|
@@ -14986,8 +14957,8 @@ async function configCommand(project2) {
|
|
|
14986
14957
|
init_esm_shims();
|
|
14987
14958
|
import chalk54 from "chalk";
|
|
14988
14959
|
import ora22 from "ora";
|
|
14989
|
-
import { existsSync as
|
|
14990
|
-
import { join as
|
|
14960
|
+
import { existsSync as existsSync49, readFileSync as readFileSync44 } from "fs";
|
|
14961
|
+
import { join as join48 } from "path";
|
|
14991
14962
|
import { exec as exec18, execSync as execSync8 } from "child_process";
|
|
14992
14963
|
import { promisify as promisify18 } from "util";
|
|
14993
14964
|
import { platform } from "os";
|
|
@@ -14996,7 +14967,7 @@ function detectPlatform2() {
|
|
|
14996
14967
|
const os = platform();
|
|
14997
14968
|
if (os === "linux") {
|
|
14998
14969
|
try {
|
|
14999
|
-
const release =
|
|
14970
|
+
const release = readFileSync44("/proc/version", "utf8").toLowerCase();
|
|
15000
14971
|
if (release.includes("microsoft") || release.includes("wsl")) {
|
|
15001
14972
|
return "wsl";
|
|
15002
14973
|
}
|
|
@@ -15034,8 +15005,8 @@ async function compactCommand(options) {
|
|
|
15034
15005
|
console.log(chalk54.dim("Install beads: https://github.com/steveyegge/beads"));
|
|
15035
15006
|
process.exit(1);
|
|
15036
15007
|
}
|
|
15037
|
-
const beadsDir =
|
|
15038
|
-
if (!
|
|
15008
|
+
const beadsDir = join48(cwd, ".beads");
|
|
15009
|
+
if (!existsSync49(beadsDir)) {
|
|
15039
15010
|
console.error(chalk54.red("Error: No .beads directory found in current directory"));
|
|
15040
15011
|
console.log(chalk54.dim("Run bd init to initialize beads"));
|
|
15041
15012
|
process.exit(1);
|
|
@@ -15094,8 +15065,8 @@ async function statsCommand() {
|
|
|
15094
15065
|
console.error(chalk54.red("Error: bd (beads) CLI not found"));
|
|
15095
15066
|
process.exit(1);
|
|
15096
15067
|
}
|
|
15097
|
-
const beadsDir =
|
|
15098
|
-
if (!
|
|
15068
|
+
const beadsDir = join48(cwd, ".beads");
|
|
15069
|
+
if (!existsSync49(beadsDir)) {
|
|
15099
15070
|
console.error(chalk54.red("Error: No .beads directory found"));
|
|
15100
15071
|
process.exit(1);
|
|
15101
15072
|
}
|
|
@@ -15739,9 +15710,9 @@ import chalk60 from "chalk";
|
|
|
15739
15710
|
|
|
15740
15711
|
// src/lib/env-loader.ts
|
|
15741
15712
|
init_esm_shims();
|
|
15742
|
-
import { join as
|
|
15743
|
-
import { homedir as
|
|
15744
|
-
var ENV_FILE_PATH =
|
|
15713
|
+
import { join as join49 } from "path";
|
|
15714
|
+
import { homedir as homedir22 } from "os";
|
|
15715
|
+
var ENV_FILE_PATH = join49(homedir22(), ".panopticon.env");
|
|
15745
15716
|
function getShadowModeFromEnv() {
|
|
15746
15717
|
const value = process.env.SHADOW_MODE;
|
|
15747
15718
|
if (!value) return false;
|
|
@@ -15844,9 +15815,9 @@ import chalk61 from "chalk";
|
|
|
15844
15815
|
// src/lib/costs/sync-wal.ts
|
|
15845
15816
|
init_esm_shims();
|
|
15846
15817
|
init_projects();
|
|
15847
|
-
import { existsSync as
|
|
15818
|
+
import { existsSync as existsSync50 } from "fs";
|
|
15848
15819
|
import { readdir, readFile } from "fs/promises";
|
|
15849
|
-
import { join as
|
|
15820
|
+
import { join as join50 } from "path";
|
|
15850
15821
|
|
|
15851
15822
|
// src/lib/database/cost-events-db.ts
|
|
15852
15823
|
init_esm_shims();
|
|
@@ -15911,8 +15882,8 @@ async function syncWalFromAllProjects() {
|
|
|
15911
15882
|
for (const { key, config: config2 } of projects) {
|
|
15912
15883
|
const repoPath = config2.events_repo ?? config2.path;
|
|
15913
15884
|
const eventsSubdir = config2.events_path ?? DEFAULT_EVENTS_SUBDIR;
|
|
15914
|
-
const eventsDir =
|
|
15915
|
-
if (!
|
|
15885
|
+
const eventsDir = join50(repoPath, eventsSubdir);
|
|
15886
|
+
if (!existsSync50(eventsDir)) continue;
|
|
15916
15887
|
const projectStats = { imported: 0, duplicates: 0, files: 0 };
|
|
15917
15888
|
let files;
|
|
15918
15889
|
try {
|
|
@@ -15922,7 +15893,7 @@ async function syncWalFromAllProjects() {
|
|
|
15922
15893
|
continue;
|
|
15923
15894
|
}
|
|
15924
15895
|
for (const file of files) {
|
|
15925
|
-
const filePath =
|
|
15896
|
+
const filePath = join50(eventsDir, file);
|
|
15926
15897
|
const events = await parseWalFile(filePath, result.errors);
|
|
15927
15898
|
if (events.length === 0) continue;
|
|
15928
15899
|
try {
|
|
@@ -16249,10 +16220,10 @@ function createCostCommand() {
|
|
|
16249
16220
|
}
|
|
16250
16221
|
|
|
16251
16222
|
// src/cli/index.ts
|
|
16252
|
-
var PANOPTICON_ENV_FILE =
|
|
16253
|
-
if (
|
|
16223
|
+
var PANOPTICON_ENV_FILE = join51(homedir23(), ".panopticon.env");
|
|
16224
|
+
if (existsSync51(PANOPTICON_ENV_FILE)) {
|
|
16254
16225
|
try {
|
|
16255
|
-
const envContent =
|
|
16226
|
+
const envContent = readFileSync45(PANOPTICON_ENV_FILE, "utf-8");
|
|
16256
16227
|
for (const line of envContent.split("\n")) {
|
|
16257
16228
|
const trimmed = line.trim();
|
|
16258
16229
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -16269,7 +16240,7 @@ if (existsSync52(PANOPTICON_ENV_FILE)) {
|
|
|
16269
16240
|
}
|
|
16270
16241
|
}
|
|
16271
16242
|
var program = new Command2();
|
|
16272
|
-
program.name("pan").description("Multi-agent orchestration for AI coding assistants").version(JSON.parse(
|
|
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);
|
|
16273
16244
|
program.command("init").description("Initialize Panopticon (~/.panopticon/)").action(initCommand);
|
|
16274
16245
|
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);
|
|
16275
16246
|
program.command("restore [timestamp]").description("Restore from backup").action(restoreCommand);
|
|
@@ -16293,21 +16264,21 @@ program.command("migrate-config").description("Migrate from settings.json to con
|
|
|
16293
16264
|
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);
|
|
16294
16265
|
program.command("up").description("Start dashboard (and Traefik if enabled)").option("--detach", "Run in background").option("--skip-traefik", "Skip Traefik startup").action(async (options) => {
|
|
16295
16266
|
const { spawn: spawn2, execSync: execSync9 } = await import("child_process");
|
|
16296
|
-
const { join:
|
|
16267
|
+
const { join: join52, dirname: dirname16 } = await import("path");
|
|
16297
16268
|
const { fileURLToPath: fileURLToPath6 } = await import("url");
|
|
16298
|
-
const { readFileSync:
|
|
16269
|
+
const { readFileSync: readFileSync46, existsSync: existsSync52 } = await import("fs");
|
|
16299
16270
|
const { parse } = await import("@iarna/toml");
|
|
16300
16271
|
const __dirname6 = dirname16(fileURLToPath6(import.meta.url));
|
|
16301
|
-
const bundledServer =
|
|
16302
|
-
const srcDashboard =
|
|
16303
|
-
const configFile =
|
|
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");
|
|
16304
16275
|
let traefikEnabled = false;
|
|
16305
16276
|
let traefikDomain = "pan.localhost";
|
|
16306
16277
|
let dashboardPort = 3010;
|
|
16307
16278
|
let dashboardApiPort = 3011;
|
|
16308
|
-
if (
|
|
16279
|
+
if (existsSync52(configFile)) {
|
|
16309
16280
|
try {
|
|
16310
|
-
const configContent =
|
|
16281
|
+
const configContent = readFileSync46(configFile, "utf-8");
|
|
16311
16282
|
const config2 = parse(configContent);
|
|
16312
16283
|
traefikEnabled = config2.traefik?.enabled === true;
|
|
16313
16284
|
traefikDomain = config2.traefik?.domain || "pan.localhost";
|
|
@@ -16337,7 +16308,7 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
|
|
|
16337
16308
|
}
|
|
16338
16309
|
try {
|
|
16339
16310
|
const { ensureBaseDomain: ensureBaseDomain2, detectDnsSyncMethod: detectDnsSyncMethod2, syncDnsToWindows: syncDnsToWindows2 } = await import("../dns-7BDJSD3E.js");
|
|
16340
|
-
const dnsMethod = (
|
|
16311
|
+
const dnsMethod = (existsSync52(configFile) ? parse(readFileSync46(configFile, "utf-8")).traefik?.dns_sync_method : null) || detectDnsSyncMethod2();
|
|
16341
16312
|
ensureBaseDomain2(dnsMethod, traefikDomain);
|
|
16342
16313
|
if (dnsMethod === "wsl2hosts") {
|
|
16343
16314
|
syncDnsToWindows2().catch(() => {
|
|
@@ -16360,19 +16331,19 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
|
|
|
16360
16331
|
}
|
|
16361
16332
|
}
|
|
16362
16333
|
if (traefikEnabled && !options.skipTraefik) {
|
|
16363
|
-
const traefikDir =
|
|
16364
|
-
if (
|
|
16334
|
+
const traefikDir = join52(process.env.HOME || "", ".panopticon", "traefik");
|
|
16335
|
+
if (existsSync52(traefikDir)) {
|
|
16365
16336
|
try {
|
|
16366
|
-
const composeFile =
|
|
16367
|
-
if (
|
|
16368
|
-
const content =
|
|
16337
|
+
const composeFile = join52(traefikDir, "docker-compose.yml");
|
|
16338
|
+
if (existsSync52(composeFile)) {
|
|
16339
|
+
const content = readFileSync46(composeFile, "utf-8");
|
|
16369
16340
|
if (!content.includes("external: true") && content.includes("panopticon:")) {
|
|
16370
16341
|
const patched = content.replace(
|
|
16371
16342
|
/networks:\s*\n\s*panopticon:\s*\n\s*name: panopticon\s*\n\s*driver: bridge/,
|
|
16372
16343
|
"networks:\n panopticon:\n name: panopticon\n external: true # Network created by 'pan install'"
|
|
16373
16344
|
);
|
|
16374
|
-
const { writeFileSync:
|
|
16375
|
-
|
|
16345
|
+
const { writeFileSync: writeFileSync26 } = await import("fs");
|
|
16346
|
+
writeFileSync26(composeFile, patched);
|
|
16376
16347
|
console.log(chalk62.dim(" (migrated network config)"));
|
|
16377
16348
|
}
|
|
16378
16349
|
}
|
|
@@ -16390,8 +16361,8 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
|
|
|
16390
16361
|
}
|
|
16391
16362
|
}
|
|
16392
16363
|
}
|
|
16393
|
-
const isProduction =
|
|
16394
|
-
const isDevelopment =
|
|
16364
|
+
const isProduction = existsSync52(bundledServer);
|
|
16365
|
+
const isDevelopment = existsSync52(srcDashboard);
|
|
16395
16366
|
if (!isProduction && !isDevelopment) {
|
|
16396
16367
|
console.error(chalk62.red("Error: Dashboard not found"));
|
|
16397
16368
|
console.error(chalk62.dim("This may be a corrupted installation. Try reinstalling panopticon-cli."));
|
|
@@ -16466,8 +16437,8 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
|
|
|
16466
16437
|
try {
|
|
16467
16438
|
const { getTldrDaemonService: getTldrDaemonService2 } = await import("../tldr-daemon-T3THOUGT.js");
|
|
16468
16439
|
const projectRoot = process.cwd();
|
|
16469
|
-
const venvPath =
|
|
16470
|
-
if (
|
|
16440
|
+
const venvPath = join52(projectRoot, ".venv");
|
|
16441
|
+
if (existsSync52(venvPath)) {
|
|
16471
16442
|
console.log(chalk62.dim("\nStarting TLDR daemon for project root..."));
|
|
16472
16443
|
const tldrService = getTldrDaemonService2(projectRoot, venvPath);
|
|
16473
16444
|
await tldrService.start(true);
|
|
@@ -16483,17 +16454,17 @@ program.command("up").description("Start dashboard (and Traefik if enabled)").op
|
|
|
16483
16454
|
});
|
|
16484
16455
|
program.command("down").description("Stop dashboard (and Traefik if enabled)").option("--skip-traefik", "Skip Traefik shutdown").action(async (options) => {
|
|
16485
16456
|
const { execSync: execSync9 } = await import("child_process");
|
|
16486
|
-
const { join:
|
|
16487
|
-
const { readFileSync:
|
|
16457
|
+
const { join: join52 } = await import("path");
|
|
16458
|
+
const { readFileSync: readFileSync46, existsSync: existsSync52 } = await import("fs");
|
|
16488
16459
|
const { parse } = await import("@iarna/toml");
|
|
16489
16460
|
console.log(chalk62.bold("Stopping Panopticon...\n"));
|
|
16490
|
-
const configFile =
|
|
16461
|
+
const configFile = join52(process.env.HOME || "", ".panopticon", "config.toml");
|
|
16491
16462
|
let traefikEnabled = false;
|
|
16492
16463
|
let dashboardPort = 3010;
|
|
16493
16464
|
let dashboardApiPort = 3011;
|
|
16494
|
-
if (
|
|
16465
|
+
if (existsSync52(configFile)) {
|
|
16495
16466
|
try {
|
|
16496
|
-
const configContent =
|
|
16467
|
+
const configContent = readFileSync46(configFile, "utf-8");
|
|
16497
16468
|
const config2 = parse(configContent);
|
|
16498
16469
|
traefikEnabled = config2.traefik?.enabled === true;
|
|
16499
16470
|
dashboardPort = config2.dashboard?.port || 3010;
|
|
@@ -16510,8 +16481,8 @@ program.command("down").description("Stop dashboard (and Traefik if enabled)").o
|
|
|
16510
16481
|
console.log(chalk62.dim(" No dashboard processes found"));
|
|
16511
16482
|
}
|
|
16512
16483
|
if (traefikEnabled && !options.skipTraefik) {
|
|
16513
|
-
const traefikDir =
|
|
16514
|
-
if (
|
|
16484
|
+
const traefikDir = join52(process.env.HOME || "", ".panopticon", "traefik");
|
|
16485
|
+
if (existsSync52(traefikDir)) {
|
|
16515
16486
|
console.log(chalk62.dim("Stopping Traefik..."));
|
|
16516
16487
|
try {
|
|
16517
16488
|
execSync9("docker compose down", {
|
|
@@ -16530,8 +16501,8 @@ program.command("down").description("Stop dashboard (and Traefik if enabled)").o
|
|
|
16530
16501
|
const { promisify: promisify21 } = await import("util");
|
|
16531
16502
|
const execAsync21 = promisify21(exec21);
|
|
16532
16503
|
const projectRoot = process.cwd();
|
|
16533
|
-
const venvPath =
|
|
16534
|
-
if (
|
|
16504
|
+
const venvPath = join52(projectRoot, ".venv");
|
|
16505
|
+
if (existsSync52(venvPath)) {
|
|
16535
16506
|
console.log(chalk62.dim("\nStopping TLDR daemon..."));
|
|
16536
16507
|
const tldrService = getTldrDaemonService2(projectRoot, venvPath);
|
|
16537
16508
|
await tldrService.stop();
|