panopticon-cli 0.5.9 → 0.5.11
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-M2ZOZL3P.js → agents-RL2KUSP3.js} +3 -3
- package/dist/{archive-planning-U3AZAKWI.js → archive-planning-54J6EP6A.js} +3 -3
- package/dist/{chunk-WEQW3EAT.js → chunk-F4XS2FQN.js} +3 -2
- package/dist/chunk-F4XS2FQN.js.map +1 -0
- package/dist/{chunk-OJF4QS3S.js → chunk-GIW2TUWI.js} +2 -2
- package/dist/{chunk-GM22HPYS.js → chunk-H7T35QDO.js} +21 -3
- package/dist/chunk-H7T35QDO.js.map +1 -0
- package/dist/{chunk-MJXYTGK5.js → chunk-JZWCL5S5.js} +2 -2
- package/dist/{chunk-3WDSD2VK.js → chunk-NLN3ZLCN.js} +186 -88
- package/dist/chunk-NLN3ZLCN.js.map +1 -0
- package/dist/{chunk-QQ27EVBD.js → chunk-OMOEGJDB.js} +3 -3
- package/dist/{chunk-4R6ATXYI.js → chunk-PFA5XE2V.js} +1 -37
- package/dist/chunk-PFA5XE2V.js.map +1 -0
- package/dist/{chunk-6OYUJ4AJ.js → chunk-R47UJWF6.js} +2 -2
- package/dist/{chunk-KPGVCGST.js → chunk-S7EJ2OLR.js} +10 -4
- package/dist/chunk-S7EJ2OLR.js.map +1 -0
- package/dist/{chunk-R4KPLLRB.js → chunk-SFX3BG6N.js} +1 -1
- package/dist/chunk-SFX3BG6N.js.map +1 -0
- package/dist/clean-planning-V4SSVU26.js +9 -0
- package/dist/cli/index.js +1111 -901
- package/dist/cli/index.js.map +1 -1
- package/dist/close-issue-5OMOP2FU.js +9 -0
- package/dist/compact-beads-YQDVF6FQ.js +9 -0
- package/dist/dashboard/prompts/merge-agent.md +11 -0
- package/dist/dashboard/prompts/review-agent.md +9 -0
- package/dist/dashboard/prompts/test-agent.md +9 -0
- package/dist/dashboard/prompts/work-agent.md +10 -2
- package/dist/dashboard/public/assets/index-5hYjhhGn.js +826 -0
- package/dist/dashboard/public/assets/index-DIFh3T1V.css +32 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +2405 -1754
- package/dist/index.d.ts +8 -3
- package/dist/index.js +3 -3
- package/dist/{label-cleanup-4HJVX6NP.js → label-cleanup-4IVZIPGK.js} +2 -2
- package/dist/{merge-agent-756U4NPX.js → merge-agent-7L7MWJEC.js} +12 -12
- package/dist/{specialist-context-UBVUUFJV.js → specialist-context-L37RF6Z5.js} +3 -3
- package/dist/{specialist-logs-FQRI3AIS.js → specialist-logs-B7UC3UDO.js} +3 -3
- package/dist/{specialists-CXRGSJY3.js → specialists-X4OGA7WX.js} +3 -3
- package/dist/{workspace-manager-OWHLR5BL.js → workspace-manager-6RP5A5HF.js} +2 -2
- package/package.json +1 -1
- package/skills/pan-new-project/SKILL.md +1 -1
- package/skills/pan-oversee/SKILL.md +45 -10
- package/skills/plan/SKILL.md +336 -0
- package/dist/chunk-3WDSD2VK.js.map +0 -1
- package/dist/chunk-4R6ATXYI.js.map +0 -1
- package/dist/chunk-GM22HPYS.js.map +0 -1
- package/dist/chunk-KPGVCGST.js.map +0 -1
- package/dist/chunk-R4KPLLRB.js.map +0 -1
- package/dist/chunk-WEQW3EAT.js.map +0 -1
- package/dist/clean-planning-7Z5YY64X.js +0 -9
- package/dist/close-issue-CTZK777I.js +0 -9
- package/dist/compact-beads-72SHALOL.js +0 -9
- package/dist/dashboard/public/assets/index-Bx4NCn9A.css +0 -32
- package/dist/dashboard/public/assets/index-DqPey4Of.js +0 -756
- package/skills/opus-plan/SKILL.md +0 -400
- /package/dist/{agents-M2ZOZL3P.js.map → agents-RL2KUSP3.js.map} +0 -0
- /package/dist/{archive-planning-U3AZAKWI.js.map → archive-planning-54J6EP6A.js.map} +0 -0
- /package/dist/{chunk-OJF4QS3S.js.map → chunk-GIW2TUWI.js.map} +0 -0
- /package/dist/{chunk-MJXYTGK5.js.map → chunk-JZWCL5S5.js.map} +0 -0
- /package/dist/{chunk-QQ27EVBD.js.map → chunk-OMOEGJDB.js.map} +0 -0
- /package/dist/{chunk-6OYUJ4AJ.js.map → chunk-R47UJWF6.js.map} +0 -0
- /package/dist/{clean-planning-7Z5YY64X.js.map → clean-planning-V4SSVU26.js.map} +0 -0
- /package/dist/{close-issue-CTZK777I.js.map → close-issue-5OMOP2FU.js.map} +0 -0
- /package/dist/{compact-beads-72SHALOL.js.map → compact-beads-YQDVF6FQ.js.map} +0 -0
- /package/dist/{label-cleanup-4HJVX6NP.js.map → label-cleanup-4IVZIPGK.js.map} +0 -0
- /package/dist/{merge-agent-756U4NPX.js.map → merge-agent-7L7MWJEC.js.map} +0 -0
- /package/dist/{specialist-context-UBVUUFJV.js.map → specialist-context-L37RF6Z5.js.map} +0 -0
- /package/dist/{specialist-logs-FQRI3AIS.js.map → specialist-logs-B7UC3UDO.js.map} +0 -0
- /package/dist/{specialists-CXRGSJY3.js.map → specialists-X4OGA7WX.js.map} +0 -0
- /package/dist/{workspace-manager-OWHLR5BL.js.map → workspace-manager-6RP5A5HF.js.map} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
init_work_type_router,
|
|
10
10
|
popFromHook,
|
|
11
11
|
pushToHook
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PFA5XE2V.js";
|
|
13
13
|
import {
|
|
14
14
|
clearCredentialFileAuth,
|
|
15
15
|
getProviderEnv,
|
|
@@ -552,6 +552,80 @@ var init_specialist_handoff_logger = __esm({
|
|
|
552
552
|
}
|
|
553
553
|
});
|
|
554
554
|
|
|
555
|
+
// src/lib/vbrief/io.ts
|
|
556
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
557
|
+
import { join as join4 } from "path";
|
|
558
|
+
function findPlan(workspacePath) {
|
|
559
|
+
const planPath = join4(workspacePath, ".planning", PLAN_FILENAME);
|
|
560
|
+
return existsSync4(planPath) ? planPath : null;
|
|
561
|
+
}
|
|
562
|
+
function readPlan(planPath) {
|
|
563
|
+
const raw = readFileSync4(planPath, "utf-8");
|
|
564
|
+
return JSON.parse(raw);
|
|
565
|
+
}
|
|
566
|
+
function readWorkspacePlan(workspacePath) {
|
|
567
|
+
const planPath = findPlan(workspacePath);
|
|
568
|
+
if (!planPath) return null;
|
|
569
|
+
return readPlan(planPath);
|
|
570
|
+
}
|
|
571
|
+
function updateItemStatus(workspacePath, itemId, status) {
|
|
572
|
+
const planPath = findPlan(workspacePath);
|
|
573
|
+
if (!planPath) return;
|
|
574
|
+
const doc = readPlan(planPath);
|
|
575
|
+
const item = doc.plan.items.find((i) => i.id === itemId);
|
|
576
|
+
if (!item) return;
|
|
577
|
+
item.status = status;
|
|
578
|
+
const tempPath = planPath + ".tmp";
|
|
579
|
+
writeFileSync2(tempPath, JSON.stringify(doc, null, 2), "utf-8");
|
|
580
|
+
renameSync(tempPath, planPath);
|
|
581
|
+
}
|
|
582
|
+
function updateSubItemStatus(workspacePath, itemId, subItemId, status) {
|
|
583
|
+
const planPath = findPlan(workspacePath);
|
|
584
|
+
if (!planPath) return;
|
|
585
|
+
const doc = readPlan(planPath);
|
|
586
|
+
const item = doc.plan.items.find((i) => i.id === itemId);
|
|
587
|
+
if (!item?.subItems) return;
|
|
588
|
+
const subItem = item.subItems.find((s) => s.id === subItemId);
|
|
589
|
+
if (!subItem) return;
|
|
590
|
+
subItem.status = status;
|
|
591
|
+
const tempPath = planPath + ".tmp";
|
|
592
|
+
writeFileSync2(tempPath, JSON.stringify(doc, null, 2), "utf-8");
|
|
593
|
+
renameSync(tempPath, planPath);
|
|
594
|
+
}
|
|
595
|
+
var PLAN_FILENAME;
|
|
596
|
+
var init_io = __esm({
|
|
597
|
+
"src/lib/vbrief/io.ts"() {
|
|
598
|
+
"use strict";
|
|
599
|
+
init_esm_shims();
|
|
600
|
+
PLAN_FILENAME = "plan.vbrief.json";
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// src/lib/cloister/task-readiness.ts
|
|
605
|
+
function isTaskReady(itemId, workspacePath) {
|
|
606
|
+
const doc = readWorkspacePlan(workspacePath);
|
|
607
|
+
if (!doc) return true;
|
|
608
|
+
const itemExists = doc.plan.items.some((i) => i.id === itemId);
|
|
609
|
+
if (!itemExists) return true;
|
|
610
|
+
const blockerIds = doc.plan.edges.filter((e) => e.type === "blocks" && e.to === itemId).map((e) => e.from);
|
|
611
|
+
if (blockerIds.length === 0) return true;
|
|
612
|
+
const itemById = new Map(doc.plan.items.map((i) => [i.id, i]));
|
|
613
|
+
return blockerIds.every((blockerId) => {
|
|
614
|
+
const blocker = itemById.get(blockerId);
|
|
615
|
+
if (!blocker) return true;
|
|
616
|
+
return TERMINAL_STATUSES.includes(blocker.status);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
var TERMINAL_STATUSES;
|
|
620
|
+
var init_task_readiness = __esm({
|
|
621
|
+
"src/lib/cloister/task-readiness.ts"() {
|
|
622
|
+
"use strict";
|
|
623
|
+
init_esm_shims();
|
|
624
|
+
init_io();
|
|
625
|
+
TERMINAL_STATUSES = ["completed", "cancelled"];
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
|
|
555
629
|
// src/lib/cloister/specialists.ts
|
|
556
630
|
var specialists_exports = {};
|
|
557
631
|
__export(specialists_exports, {
|
|
@@ -611,8 +685,8 @@ __export(specialists_exports, {
|
|
|
611
685
|
wakeSpecialistOrQueue: () => wakeSpecialistOrQueue,
|
|
612
686
|
wakeSpecialistWithTask: () => wakeSpecialistWithTask
|
|
613
687
|
});
|
|
614
|
-
import { readFileSync as
|
|
615
|
-
import { join as
|
|
688
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync as readdirSync3, unlinkSync, appendFileSync as appendFileSync3 } from "fs";
|
|
689
|
+
import { join as join5, basename as basename2 } from "path";
|
|
616
690
|
import { homedir as homedir2 } from "os";
|
|
617
691
|
import { exec } from "child_process";
|
|
618
692
|
import { promisify } from "util";
|
|
@@ -623,14 +697,14 @@ async function resolveWorkspaceGitInfo(workspace, taskBranch) {
|
|
|
623
697
|
if (!workspace || workspace === "unknown") {
|
|
624
698
|
return { gitDirs, branch, isPolyrepo: false };
|
|
625
699
|
}
|
|
626
|
-
if (
|
|
700
|
+
if (existsSync5(join5(workspace, ".git"))) {
|
|
627
701
|
gitDirs.push(workspace);
|
|
628
702
|
} else {
|
|
629
703
|
try {
|
|
630
704
|
const entries = readdirSync3(workspace, { withFileTypes: true });
|
|
631
705
|
for (const entry of entries) {
|
|
632
|
-
if (entry.isDirectory() &&
|
|
633
|
-
gitDirs.push(
|
|
706
|
+
if (entry.isDirectory() && existsSync5(join5(workspace, entry.name, ".git"))) {
|
|
707
|
+
gitDirs.push(join5(workspace, entry.name));
|
|
634
708
|
}
|
|
635
709
|
}
|
|
636
710
|
} catch {
|
|
@@ -670,10 +744,10 @@ function buildTmuxEnvFlags(env) {
|
|
|
670
744
|
return flags;
|
|
671
745
|
}
|
|
672
746
|
function initSpecialistsDirectory() {
|
|
673
|
-
if (!
|
|
747
|
+
if (!existsSync5(SPECIALISTS_DIR)) {
|
|
674
748
|
mkdirSync3(SPECIALISTS_DIR, { recursive: true });
|
|
675
749
|
}
|
|
676
|
-
if (!
|
|
750
|
+
if (!existsSync5(REGISTRY_FILE)) {
|
|
677
751
|
const registry = {
|
|
678
752
|
version: "2.0",
|
|
679
753
|
// Updated for per-project structure
|
|
@@ -697,7 +771,7 @@ function initSpecialistsDirectory() {
|
|
|
697
771
|
}
|
|
698
772
|
function migrateRegistryIfNeeded() {
|
|
699
773
|
try {
|
|
700
|
-
const content =
|
|
774
|
+
const content = readFileSync5(REGISTRY_FILE, "utf-8");
|
|
701
775
|
const registry = JSON.parse(content);
|
|
702
776
|
if (registry.version === "2.0" || registry.projects) {
|
|
703
777
|
return;
|
|
@@ -727,7 +801,7 @@ function migrateRegistryIfNeeded() {
|
|
|
727
801
|
function loadRegistry() {
|
|
728
802
|
initSpecialistsDirectory();
|
|
729
803
|
try {
|
|
730
|
-
const content =
|
|
804
|
+
const content = readFileSync5(REGISTRY_FILE, "utf-8");
|
|
731
805
|
return JSON.parse(content);
|
|
732
806
|
} catch (error) {
|
|
733
807
|
console.error("Failed to load specialist registry:", error);
|
|
@@ -745,13 +819,13 @@ function loadRegistry() {
|
|
|
745
819
|
}
|
|
746
820
|
}
|
|
747
821
|
function saveRegistry(registry) {
|
|
748
|
-
if (!
|
|
822
|
+
if (!existsSync5(SPECIALISTS_DIR)) {
|
|
749
823
|
mkdirSync3(SPECIALISTS_DIR, { recursive: true });
|
|
750
824
|
}
|
|
751
825
|
registry.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
752
826
|
try {
|
|
753
827
|
const content = JSON.stringify(registry, null, 2);
|
|
754
|
-
|
|
828
|
+
writeFileSync3(REGISTRY_FILE, content, "utf-8");
|
|
755
829
|
} catch (error) {
|
|
756
830
|
console.error("Failed to save specialist registry:", error);
|
|
757
831
|
throw error;
|
|
@@ -763,17 +837,17 @@ function deterministicUUID(input) {
|
|
|
763
837
|
}
|
|
764
838
|
function getSessionFilePath(name, projectKey) {
|
|
765
839
|
if (projectKey) {
|
|
766
|
-
return
|
|
840
|
+
return join5(SPECIALISTS_DIR, "projects", projectKey, `${name}.session`);
|
|
767
841
|
}
|
|
768
|
-
return
|
|
842
|
+
return join5(SPECIALISTS_DIR, `${name}.session`);
|
|
769
843
|
}
|
|
770
844
|
function getSessionId(name, projectKey) {
|
|
771
845
|
const sessionFile = getSessionFilePath(name, projectKey);
|
|
772
|
-
if (!
|
|
846
|
+
if (!existsSync5(sessionFile)) {
|
|
773
847
|
return null;
|
|
774
848
|
}
|
|
775
849
|
try {
|
|
776
|
-
const sessionId =
|
|
850
|
+
const sessionId = readFileSync5(sessionFile, "utf-8").trim();
|
|
777
851
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
778
852
|
if (!uuidRegex.test(sessionId)) {
|
|
779
853
|
console.warn(`[specialist] Invalid session ID format for ${name} (${projectKey ?? "global"}): ${sessionId} \u2014 discarding`);
|
|
@@ -788,12 +862,12 @@ function getSessionId(name, projectKey) {
|
|
|
788
862
|
}
|
|
789
863
|
function setSessionId(name, sessionId, projectKey) {
|
|
790
864
|
const sessionFile = getSessionFilePath(name, projectKey);
|
|
791
|
-
const dir = projectKey ?
|
|
792
|
-
if (!
|
|
865
|
+
const dir = projectKey ? join5(SPECIALISTS_DIR, "projects", projectKey) : SPECIALISTS_DIR;
|
|
866
|
+
if (!existsSync5(dir)) {
|
|
793
867
|
mkdirSync3(dir, { recursive: true });
|
|
794
868
|
}
|
|
795
869
|
try {
|
|
796
|
-
|
|
870
|
+
writeFileSync3(sessionFile, sessionId.trim(), "utf-8");
|
|
797
871
|
} catch (error) {
|
|
798
872
|
console.error(`Failed to write session file for ${name} (${projectKey ?? "global"}):`, error);
|
|
799
873
|
throw error;
|
|
@@ -801,7 +875,7 @@ function setSessionId(name, sessionId, projectKey) {
|
|
|
801
875
|
}
|
|
802
876
|
function clearSessionId(name, projectKey) {
|
|
803
877
|
const sessionFile = getSessionFilePath(name, projectKey);
|
|
804
|
-
if (!
|
|
878
|
+
if (!existsSync5(sessionFile)) {
|
|
805
879
|
return false;
|
|
806
880
|
}
|
|
807
881
|
try {
|
|
@@ -859,9 +933,9 @@ function recordWake(name, sessionId) {
|
|
|
859
933
|
}
|
|
860
934
|
async function spawnEphemeralSpecialist(projectKey, specialistType, task) {
|
|
861
935
|
ensureProjectSpecialistDir(projectKey, specialistType);
|
|
862
|
-
const { loadContextDigest } = await import("./specialist-context-
|
|
936
|
+
const { loadContextDigest } = await import("./specialist-context-L37RF6Z5.js");
|
|
863
937
|
const contextDigest = loadContextDigest(projectKey, specialistType);
|
|
864
|
-
const { createRunLog: createRunLog2 } = await import("./specialist-logs-
|
|
938
|
+
const { createRunLog: createRunLog2 } = await import("./specialist-logs-B7UC3UDO.js");
|
|
865
939
|
const { runId, filePath: logFilePath } = createRunLog2(
|
|
866
940
|
projectKey,
|
|
867
941
|
specialistType,
|
|
@@ -881,7 +955,7 @@ ${basePrompt}`;
|
|
|
881
955
|
const project = getProject(projectKey);
|
|
882
956
|
const cwd = project?.path || getDevrootPath() || homedir2();
|
|
883
957
|
try {
|
|
884
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
958
|
+
const { preTrustDirectory } = await import("./workspace-manager-6RP5A5HF.js");
|
|
885
959
|
preTrustDirectory(cwd);
|
|
886
960
|
} catch {
|
|
887
961
|
}
|
|
@@ -889,7 +963,7 @@ ${basePrompt}`;
|
|
|
889
963
|
try {
|
|
890
964
|
const { stdout: sessions } = await execAsync('tmux list-sessions -F "#{session_name}" 2>/dev/null || echo ""', { encoding: "utf-8" });
|
|
891
965
|
if (sessions.split("\n").map((s) => s.trim()).includes(tmuxSession)) {
|
|
892
|
-
const { getAgentRuntimeState } = await import("./agents-
|
|
966
|
+
const { getAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
893
967
|
const existingState = getAgentRuntimeState(tmuxSession);
|
|
894
968
|
if (existingState?.state === "active") {
|
|
895
969
|
return {
|
|
@@ -926,17 +1000,17 @@ ${basePrompt}`;
|
|
|
926
1000
|
clearCredentialFileAuth(cwd);
|
|
927
1001
|
}
|
|
928
1002
|
const permissionFlags = specialistType === "merge-agent" ? "--dangerously-skip-permissions --permission-mode bypassPermissions" : "--dangerously-skip-permissions";
|
|
929
|
-
const agentDir =
|
|
1003
|
+
const agentDir = join5(homedir2(), ".panopticon", "agents", tmuxSession);
|
|
930
1004
|
await execAsync(`mkdir -p "${agentDir}"`, { encoding: "utf-8" });
|
|
931
|
-
const promptFile =
|
|
932
|
-
|
|
1005
|
+
const promptFile = join5(agentDir, "task-prompt.md");
|
|
1006
|
+
writeFileSync3(promptFile, taskPrompt);
|
|
933
1007
|
const sessionName = `specialist-${projectKey}-${specialistType}`;
|
|
934
1008
|
const sessionId = deterministicUUID(sessionName);
|
|
935
1009
|
setSessionId(specialistType, sessionId, projectKey);
|
|
936
1010
|
console.log(`[specialist] Dispatching ${specialistType} for ${projectKey}/${task.issueId} (session: ${sessionId.slice(0, 8)}...)`);
|
|
937
|
-
const launcherScript =
|
|
938
|
-
const innerScript =
|
|
939
|
-
|
|
1011
|
+
const launcherScript = join5(agentDir, "launcher.sh");
|
|
1012
|
+
const innerScript = join5(agentDir, "run-claude.sh");
|
|
1013
|
+
writeFileSync3(innerScript, `#!/bin/bash
|
|
940
1014
|
set -o pipefail
|
|
941
1015
|
cd "${cwd}"
|
|
942
1016
|
export PANOPTICON_AGENT_ID="${tmuxSession}"
|
|
@@ -958,14 +1032,14 @@ fi
|
|
|
958
1032
|
echo ""
|
|
959
1033
|
echo "## Specialist completed task"
|
|
960
1034
|
`, { mode: 493 });
|
|
961
|
-
|
|
1035
|
+
writeFileSync3(launcherScript, `#!/bin/bash
|
|
962
1036
|
script -qfec "bash '${innerScript}'" /dev/null 2>&1 | tee -a "${logFilePath}"
|
|
963
1037
|
`, { mode: 493 });
|
|
964
1038
|
await execAsync(
|
|
965
1039
|
`tmux new-session -d -s "${tmuxSession}" -c "${cwd}"${envFlags} "bash '${launcherScript}'"`,
|
|
966
1040
|
{ encoding: "utf-8" }
|
|
967
1041
|
);
|
|
968
|
-
const { saveAgentRuntimeState } = await import("./agents-
|
|
1042
|
+
const { saveAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
969
1043
|
saveAgentRuntimeState(tmuxSession, {
|
|
970
1044
|
state: "active",
|
|
971
1045
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1150,7 +1224,7 @@ async function terminateSpecialist(projectKey, specialistType) {
|
|
|
1150
1224
|
console.error(`[specialist] Failed to kill tmux session ${tmuxSession}:`, error);
|
|
1151
1225
|
}
|
|
1152
1226
|
if (metadata.currentRun) {
|
|
1153
|
-
const { finalizeRunLog: finalizeRunLog2 } = await import("./specialist-logs-
|
|
1227
|
+
const { finalizeRunLog: finalizeRunLog2 } = await import("./specialist-logs-B7UC3UDO.js");
|
|
1154
1228
|
try {
|
|
1155
1229
|
finalizeRunLog2(projectKey, specialistType, metadata.currentRun, {
|
|
1156
1230
|
status: metadata.lastRunStatus || "incomplete",
|
|
@@ -1163,19 +1237,19 @@ async function terminateSpecialist(projectKey, specialistType) {
|
|
|
1163
1237
|
}
|
|
1164
1238
|
const key = `${projectKey}-${specialistType}`;
|
|
1165
1239
|
gracePeriodStates.delete(key);
|
|
1166
|
-
const { saveAgentRuntimeState } = await import("./agents-
|
|
1240
|
+
const { saveAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
1167
1241
|
saveAgentRuntimeState(tmuxSession, {
|
|
1168
1242
|
state: "suspended",
|
|
1169
1243
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
1170
1244
|
});
|
|
1171
|
-
const { scheduleDigestGeneration } = await import("./specialist-context-
|
|
1245
|
+
const { scheduleDigestGeneration } = await import("./specialist-context-L37RF6Z5.js");
|
|
1172
1246
|
scheduleDigestGeneration(projectKey, specialistType);
|
|
1173
1247
|
scheduleLogCleanup(projectKey, specialistType);
|
|
1174
1248
|
}
|
|
1175
1249
|
function scheduleLogCleanup(projectKey, specialistType) {
|
|
1176
1250
|
Promise.resolve().then(async () => {
|
|
1177
1251
|
try {
|
|
1178
|
-
const { cleanupOldLogs: cleanupOldLogs2 } = await import("./specialist-logs-
|
|
1252
|
+
const { cleanupOldLogs: cleanupOldLogs2 } = await import("./specialist-logs-B7UC3UDO.js");
|
|
1179
1253
|
const { getSpecialistRetention } = await import("./projects-BPGM6IFB.js");
|
|
1180
1254
|
const retention = getSpecialistRetention(projectKey);
|
|
1181
1255
|
const deleted = cleanupOldLogs2(projectKey, specialistType, { maxDays: retention.max_days, maxRuns: retention.max_runs });
|
|
@@ -1188,16 +1262,16 @@ function scheduleLogCleanup(projectKey, specialistType) {
|
|
|
1188
1262
|
});
|
|
1189
1263
|
}
|
|
1190
1264
|
function getProjectSpecialistDir(projectKey, specialistType) {
|
|
1191
|
-
return
|
|
1265
|
+
return join5(SPECIALISTS_DIR, projectKey, specialistType);
|
|
1192
1266
|
}
|
|
1193
1267
|
function ensureProjectSpecialistDir(projectKey, specialistType) {
|
|
1194
1268
|
const specialistDir = getProjectSpecialistDir(projectKey, specialistType);
|
|
1195
|
-
const runsDir =
|
|
1196
|
-
const contextDir =
|
|
1197
|
-
if (!
|
|
1269
|
+
const runsDir = join5(specialistDir, "runs");
|
|
1270
|
+
const contextDir = join5(specialistDir, "context");
|
|
1271
|
+
if (!existsSync5(runsDir)) {
|
|
1198
1272
|
mkdirSync3(runsDir, { recursive: true });
|
|
1199
1273
|
}
|
|
1200
|
-
if (!
|
|
1274
|
+
if (!existsSync5(contextDir)) {
|
|
1201
1275
|
mkdirSync3(contextDir, { recursive: true });
|
|
1202
1276
|
}
|
|
1203
1277
|
}
|
|
@@ -1364,7 +1438,7 @@ async function getSpecialistStatus(name, projectKey) {
|
|
|
1364
1438
|
const sessionId = getSessionId(name, projectKey);
|
|
1365
1439
|
const running = await isRunning(name, projectKey);
|
|
1366
1440
|
const contextTokens = countContextTokens(name);
|
|
1367
|
-
const { getAgentRuntimeState } = await import("./agents-
|
|
1441
|
+
const { getAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
1368
1442
|
const tmuxSession = getTmuxSessionName(name, projectKey);
|
|
1369
1443
|
const runtimeState = getAgentRuntimeState(tmuxSession);
|
|
1370
1444
|
let state;
|
|
@@ -1445,13 +1519,13 @@ Say: "I am the ${name} specialist, ready and waiting for tasks."`;
|
|
|
1445
1519
|
} else {
|
|
1446
1520
|
clearCredentialFileAuth(cwd);
|
|
1447
1521
|
}
|
|
1448
|
-
const agentDir =
|
|
1522
|
+
const agentDir = join5(homedir2(), ".panopticon", "agents", tmuxSession);
|
|
1449
1523
|
await execAsync(`mkdir -p "${agentDir}"`, { encoding: "utf-8" });
|
|
1450
|
-
const promptFile =
|
|
1451
|
-
const launcherScript =
|
|
1452
|
-
|
|
1524
|
+
const promptFile = join5(agentDir, "identity-prompt.md");
|
|
1525
|
+
const launcherScript = join5(agentDir, "launcher.sh");
|
|
1526
|
+
writeFileSync3(promptFile, identityPrompt);
|
|
1453
1527
|
const newSessionId = randomUUID();
|
|
1454
|
-
|
|
1528
|
+
writeFileSync3(launcherScript, `#!/bin/bash
|
|
1455
1529
|
cd "${cwd}"
|
|
1456
1530
|
prompt=$(cat "${promptFile}")
|
|
1457
1531
|
exec claude --dangerously-skip-permissions --session-id "${newSessionId}" --model ${model} "$prompt"
|
|
@@ -1519,7 +1593,7 @@ async function wakeSpecialist(name, taskPrompt, options = {}) {
|
|
|
1519
1593
|
const sessionId = getSessionId(name);
|
|
1520
1594
|
const wasAlreadyRunning = await isRunning(name);
|
|
1521
1595
|
if (wasAlreadyRunning && !options.skipBusyGuard) {
|
|
1522
|
-
const { getAgentRuntimeState } = await import("./agents-
|
|
1596
|
+
const { getAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
1523
1597
|
const runtimeState = getAgentRuntimeState(tmuxSession);
|
|
1524
1598
|
if (runtimeState?.state === "active") {
|
|
1525
1599
|
console.warn(`[specialist] ${name} is busy (working on ${runtimeState.currentIssue}), refusing to interrupt`);
|
|
@@ -1541,9 +1615,9 @@ async function wakeSpecialist(name, taskPrompt, options = {}) {
|
|
|
1541
1615
|
error: "not_running"
|
|
1542
1616
|
};
|
|
1543
1617
|
}
|
|
1544
|
-
const cwd = getDevrootPath() ||
|
|
1618
|
+
const cwd = getDevrootPath() || join5(process.env.HOME || "/home/eltmon", "Projects");
|
|
1545
1619
|
try {
|
|
1546
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
1620
|
+
const { preTrustDirectory } = await import("./workspace-manager-6RP5A5HF.js");
|
|
1547
1621
|
preTrustDirectory(cwd);
|
|
1548
1622
|
} catch {
|
|
1549
1623
|
}
|
|
@@ -1610,11 +1684,11 @@ async function wakeSpecialist(name, taskPrompt, options = {}) {
|
|
|
1610
1684
|
const isLargePrompt = taskPrompt.length > 500 || taskPrompt.includes("\n");
|
|
1611
1685
|
let messageToSend;
|
|
1612
1686
|
if (isLargePrompt) {
|
|
1613
|
-
if (!
|
|
1687
|
+
if (!existsSync5(TASKS_DIR)) {
|
|
1614
1688
|
mkdirSync3(TASKS_DIR, { recursive: true });
|
|
1615
1689
|
}
|
|
1616
|
-
const taskFile =
|
|
1617
|
-
|
|
1690
|
+
const taskFile = join5(TASKS_DIR, `${name}-${Date.now()}.md`);
|
|
1691
|
+
writeFileSync3(taskFile, taskPrompt, "utf-8");
|
|
1618
1692
|
messageToSend = `Read and execute the task in: ${taskFile}`;
|
|
1619
1693
|
} else {
|
|
1620
1694
|
messageToSend = taskPrompt;
|
|
@@ -1638,7 +1712,7 @@ async function wakeSpecialist(name, taskPrompt, options = {}) {
|
|
|
1638
1712
|
}
|
|
1639
1713
|
}
|
|
1640
1714
|
recordWake(name, sessionId || void 0);
|
|
1641
|
-
const { saveAgentRuntimeState } = await import("./agents-
|
|
1715
|
+
const { saveAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
1642
1716
|
saveAgentRuntimeState(tmuxSession, {
|
|
1643
1717
|
state: "active",
|
|
1644
1718
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1696,7 +1770,7 @@ PHASE 1 \u2014 SYNC & BASELINE (before merge):
|
|
|
1696
1770
|
If rebase conflicts: abort and report failure.
|
|
1697
1771
|
5. Run tests on main to establish a baseline. Record BASELINE_PASS and BASELINE_FAIL.
|
|
1698
1772
|
|
|
1699
|
-
PHASE 2 \u2014 MERGE:
|
|
1773
|
+
PHASE 2 \u2014 MERGE (dry run):
|
|
1700
1774
|
6. git merge ${mergeBranch} --no-edit
|
|
1701
1775
|
7. If conflicts: resolve them intelligently, then git add and git commit
|
|
1702
1776
|
8. If clean merge: the merge commit is auto-created (or fast-forward)
|
|
@@ -1706,10 +1780,13 @@ PHASE 3 \u2014 VERIFY:
|
|
|
1706
1780
|
|
|
1707
1781
|
PHASE 4 \u2014 DECIDE:
|
|
1708
1782
|
10. Compare results:
|
|
1709
|
-
- If MERGE_FAIL > BASELINE_FAIL (NEW test failures): ROLLBACK with git reset --hard ORIG_HEAD
|
|
1710
|
-
- If MERGE_FAIL <= BASELINE_FAIL (no new failures):
|
|
1783
|
+
- If MERGE_FAIL > BASELINE_FAIL (NEW test failures): ROLLBACK with git reset --hard ORIG_HEAD and report FAILED
|
|
1784
|
+
- If MERGE_FAIL <= BASELINE_FAIL (no new failures): Report PASSED (merge is validated)
|
|
1711
1785
|
- Pre-existing failures on main are NOT a reason to rollback
|
|
1712
1786
|
|
|
1787
|
+
CRITICAL: Do NOT push to main. Do NOT run git push origin main.
|
|
1788
|
+
The merge validation stays LOCAL. A human will click Merge in the dashboard to push.
|
|
1789
|
+
|
|
1713
1790
|
PHASE 5 \u2014 REPORT:
|
|
1714
1791
|
11. Call the Panopticon API to report results:
|
|
1715
1792
|
curl -s -X POST ${apiUrl}/api/specialists/done \\
|
|
@@ -1717,6 +1794,7 @@ PHASE 5 \u2014 REPORT:
|
|
|
1717
1794
|
-d '{"specialist":"merge","issueId":"${task.issueId}","status":"passed|failed","notes":"<summary>"}'
|
|
1718
1795
|
|
|
1719
1796
|
CRITICAL: You MUST call the /api/specialists/done endpoint whether you succeed or fail.
|
|
1797
|
+
CRITICAL: NEVER push to main \u2014 only humans merge. Your job is to VALIDATE the merge, not execute it.
|
|
1720
1798
|
CRITICAL: NEVER use git push --force.
|
|
1721
1799
|
CRITICAL: Do NOT delete the feature branch.`;
|
|
1722
1800
|
break;
|
|
@@ -1747,7 +1825,7 @@ CRITICAL: Do NOT delete the feature branch.`;
|
|
|
1747
1825
|
});
|
|
1748
1826
|
console.log(`[specialist] review-agent: auto-passed ${task.issueId} (stale branch)`);
|
|
1749
1827
|
const tmuxSession = getTmuxSessionName("review-agent");
|
|
1750
|
-
const { saveAgentRuntimeState } = await import("./agents-
|
|
1828
|
+
const { saveAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
1751
1829
|
saveAgentRuntimeState(tmuxSession, {
|
|
1752
1830
|
state: "idle",
|
|
1753
1831
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -2013,8 +2091,23 @@ IMPORTANT: Do NOT hand off to merge-agent. Human clicks Merge button when ready.
|
|
|
2013
2091
|
}
|
|
2014
2092
|
async function wakeSpecialistOrQueue(name, task, options = {}) {
|
|
2015
2093
|
const { priority = "normal", source = "handoff" } = options;
|
|
2094
|
+
const vbriefItemId = task.context?.vbriefItemId;
|
|
2095
|
+
const workspacePath = task.workspace || task.context?.workspace;
|
|
2096
|
+
if (vbriefItemId && workspacePath) {
|
|
2097
|
+
try {
|
|
2098
|
+
if (!isTaskReady(vbriefItemId, workspacePath)) {
|
|
2099
|
+
return {
|
|
2100
|
+
success: false,
|
|
2101
|
+
queued: false,
|
|
2102
|
+
message: `Task "${vbriefItemId}" has incomplete blocking dependencies \u2014 not ready to schedule`
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
} catch (readinessErr) {
|
|
2106
|
+
console.warn(`[specialist] Task readiness check failed for ${vbriefItemId}: ${readinessErr.message}`);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2016
2109
|
const running = await isRunning(name);
|
|
2017
|
-
const { getAgentRuntimeState } = await import("./agents-
|
|
2110
|
+
const { getAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
2018
2111
|
const tmuxSession = getTmuxSessionName(name);
|
|
2019
2112
|
const runtimeState = getAgentRuntimeState(tmuxSession);
|
|
2020
2113
|
const idle = runtimeState?.state === "idle" || runtimeState?.state === "suspended";
|
|
@@ -2045,7 +2138,7 @@ async function wakeSpecialistOrQueue(name, task, options = {}) {
|
|
|
2045
2138
|
};
|
|
2046
2139
|
}
|
|
2047
2140
|
}
|
|
2048
|
-
const { saveAgentRuntimeState } = await import("./agents-
|
|
2141
|
+
const { saveAgentRuntimeState } = await import("./agents-RL2KUSP3.js");
|
|
2049
2142
|
saveAgentRuntimeState(tmuxSession, {
|
|
2050
2143
|
state: "active",
|
|
2051
2144
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2129,7 +2222,7 @@ function getNextSpecialistTask(specialistName) {
|
|
|
2129
2222
|
}
|
|
2130
2223
|
async function sendFeedbackToAgent(feedback) {
|
|
2131
2224
|
const { fromSpecialist, toIssueId, summary, details } = feedback;
|
|
2132
|
-
if (!
|
|
2225
|
+
if (!existsSync5(FEEDBACK_DIR)) {
|
|
2133
2226
|
mkdirSync3(FEEDBACK_DIR, { recursive: true });
|
|
2134
2227
|
}
|
|
2135
2228
|
const fullFeedback = {
|
|
@@ -2165,7 +2258,7 @@ async function sendFeedbackToAgent(feedback) {
|
|
|
2165
2258
|
return false;
|
|
2166
2259
|
}
|
|
2167
2260
|
try {
|
|
2168
|
-
const { messageAgent } = await import("./agents-
|
|
2261
|
+
const { messageAgent } = await import("./agents-RL2KUSP3.js");
|
|
2169
2262
|
const msg = `SPECIALIST FEEDBACK: ${fromSpecialist} reported ${feedback.feedbackType.toUpperCase()} for ${toIssueId}.
|
|
2170
2263
|
Read and address: ${fileResult.relativePath}`;
|
|
2171
2264
|
await messageAgent(agentSession, msg);
|
|
@@ -2224,11 +2317,11 @@ ${details}
|
|
|
2224
2317
|
return message;
|
|
2225
2318
|
}
|
|
2226
2319
|
function getPendingFeedback(issueId) {
|
|
2227
|
-
if (!
|
|
2320
|
+
if (!existsSync5(FEEDBACK_LOG)) {
|
|
2228
2321
|
return [];
|
|
2229
2322
|
}
|
|
2230
2323
|
try {
|
|
2231
|
-
const content =
|
|
2324
|
+
const content = readFileSync5(FEEDBACK_LOG, "utf-8");
|
|
2232
2325
|
const lines = content.trim().split("\n").filter((l) => l.length > 0);
|
|
2233
2326
|
const allFeedback = lines.map((line) => JSON.parse(line));
|
|
2234
2327
|
return allFeedback.filter((f) => f.toIssueId.toLowerCase() === issueId.toLowerCase());
|
|
@@ -2247,11 +2340,11 @@ function getFeedbackStats() {
|
|
|
2247
2340
|
byType: {},
|
|
2248
2341
|
total: 0
|
|
2249
2342
|
};
|
|
2250
|
-
if (!
|
|
2343
|
+
if (!existsSync5(FEEDBACK_LOG)) {
|
|
2251
2344
|
return stats;
|
|
2252
2345
|
}
|
|
2253
2346
|
try {
|
|
2254
|
-
const content =
|
|
2347
|
+
const content = readFileSync5(FEEDBACK_LOG, "utf-8");
|
|
2255
2348
|
const lines = content.trim().split("\n").filter((l) => l.length > 0);
|
|
2256
2349
|
for (const line of lines) {
|
|
2257
2350
|
const feedback = JSON.parse(line);
|
|
@@ -2278,11 +2371,12 @@ var init_specialists = __esm({
|
|
|
2278
2371
|
init_providers();
|
|
2279
2372
|
init_tmux();
|
|
2280
2373
|
init_pipeline_notifier();
|
|
2374
|
+
init_task_readiness();
|
|
2281
2375
|
init_hooks();
|
|
2282
2376
|
execAsync = promisify(exec);
|
|
2283
|
-
SPECIALISTS_DIR =
|
|
2284
|
-
REGISTRY_FILE =
|
|
2285
|
-
TASKS_DIR =
|
|
2377
|
+
SPECIALISTS_DIR = join5(PANOPTICON_HOME, "specialists");
|
|
2378
|
+
REGISTRY_FILE = join5(SPECIALISTS_DIR, "registry.json");
|
|
2379
|
+
TASKS_DIR = join5(SPECIALISTS_DIR, "tasks");
|
|
2286
2380
|
DEFAULT_SPECIALISTS = [
|
|
2287
2381
|
{
|
|
2288
2382
|
name: "merge-agent",
|
|
@@ -2307,8 +2401,8 @@ var init_specialists = __esm({
|
|
|
2307
2401
|
}
|
|
2308
2402
|
];
|
|
2309
2403
|
gracePeriodStates = /* @__PURE__ */ new Map();
|
|
2310
|
-
FEEDBACK_DIR =
|
|
2311
|
-
FEEDBACK_LOG =
|
|
2404
|
+
FEEDBACK_DIR = join5(PANOPTICON_HOME, "specialists", "feedback");
|
|
2405
|
+
FEEDBACK_LOG = join5(FEEDBACK_DIR, "feedback.jsonl");
|
|
2312
2406
|
}
|
|
2313
2407
|
});
|
|
2314
2408
|
|
|
@@ -2332,13 +2426,13 @@ __export(specialist_logs_exports, {
|
|
|
2332
2426
|
listRunLogs: () => listRunLogs,
|
|
2333
2427
|
parseLogMetadata: () => parseLogMetadata
|
|
2334
2428
|
});
|
|
2335
|
-
import { existsSync as
|
|
2336
|
-
import { join as
|
|
2429
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, appendFileSync as appendFileSync4, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
2430
|
+
import { join as join6, basename as basename3 } from "path";
|
|
2337
2431
|
function getSpecialistsDir() {
|
|
2338
|
-
return
|
|
2432
|
+
return join6(getPanopticonHome(), "specialists");
|
|
2339
2433
|
}
|
|
2340
2434
|
function getRunsDirectory(projectKey, specialistType) {
|
|
2341
|
-
return
|
|
2435
|
+
return join6(getSpecialistsDir(), projectKey, specialistType, "runs");
|
|
2342
2436
|
}
|
|
2343
2437
|
function generateRunId(issueId) {
|
|
2344
2438
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
@@ -2346,11 +2440,11 @@ function generateRunId(issueId) {
|
|
|
2346
2440
|
}
|
|
2347
2441
|
function getRunLogPath(projectKey, specialistType, runId) {
|
|
2348
2442
|
const runsDir = getRunsDirectory(projectKey, specialistType);
|
|
2349
|
-
return
|
|
2443
|
+
return join6(runsDir, `${runId}.log`);
|
|
2350
2444
|
}
|
|
2351
2445
|
function ensureRunsDirectory(projectKey, specialistType) {
|
|
2352
2446
|
const runsDir = getRunsDirectory(projectKey, specialistType);
|
|
2353
|
-
if (!
|
|
2447
|
+
if (!existsSync6(runsDir)) {
|
|
2354
2448
|
mkdirSync4(runsDir, { recursive: true });
|
|
2355
2449
|
}
|
|
2356
2450
|
}
|
|
@@ -2370,22 +2464,22 @@ ${contextSeed ? contextSeed : "[No context digest available]"}
|
|
|
2370
2464
|
|
|
2371
2465
|
## Session Transcript
|
|
2372
2466
|
`;
|
|
2373
|
-
|
|
2467
|
+
writeFileSync4(filePath, header, "utf-8");
|
|
2374
2468
|
return { runId, filePath };
|
|
2375
2469
|
}
|
|
2376
2470
|
function appendToRunLog(projectKey, specialistType, runId, content) {
|
|
2377
2471
|
const filePath = getRunLogPath(projectKey, specialistType, runId);
|
|
2378
|
-
if (!
|
|
2472
|
+
if (!existsSync6(filePath)) {
|
|
2379
2473
|
throw new Error(`Run log not found: ${filePath}`);
|
|
2380
2474
|
}
|
|
2381
2475
|
appendFileSync4(filePath, content, "utf-8");
|
|
2382
2476
|
}
|
|
2383
2477
|
function finalizeRunLog(projectKey, specialistType, runId, result) {
|
|
2384
2478
|
const filePath = getRunLogPath(projectKey, specialistType, runId);
|
|
2385
|
-
if (!
|
|
2479
|
+
if (!existsSync6(filePath)) {
|
|
2386
2480
|
throw new Error(`Run log not found: ${filePath}`);
|
|
2387
2481
|
}
|
|
2388
|
-
const content =
|
|
2482
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
2389
2483
|
const startMatch = content.match(/^Started: (.+)$/m);
|
|
2390
2484
|
const startedAt = startMatch ? new Date(startMatch[1]) : /* @__PURE__ */ new Date();
|
|
2391
2485
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
@@ -2406,11 +2500,11 @@ Finished: ${finishedAt.toISOString()}
|
|
|
2406
2500
|
}
|
|
2407
2501
|
function getRunLog(projectKey, specialistType, runId) {
|
|
2408
2502
|
const filePath = getRunLogPath(projectKey, specialistType, runId);
|
|
2409
|
-
if (!
|
|
2503
|
+
if (!existsSync6(filePath)) {
|
|
2410
2504
|
return null;
|
|
2411
2505
|
}
|
|
2412
2506
|
try {
|
|
2413
|
-
return
|
|
2507
|
+
return readFileSync6(filePath, "utf-8");
|
|
2414
2508
|
} catch (error) {
|
|
2415
2509
|
console.error(`Failed to read run log ${runId}:`, error);
|
|
2416
2510
|
return null;
|
|
@@ -2445,15 +2539,15 @@ function parseLogMetadata(logContent) {
|
|
|
2445
2539
|
}
|
|
2446
2540
|
function listRunLogs(projectKey, specialistType, options = {}) {
|
|
2447
2541
|
const runsDir = getRunsDirectory(projectKey, specialistType);
|
|
2448
|
-
if (!
|
|
2542
|
+
if (!existsSync6(runsDir)) {
|
|
2449
2543
|
return [];
|
|
2450
2544
|
}
|
|
2451
2545
|
try {
|
|
2452
2546
|
const files = readdirSync4(runsDir).filter((f) => f.endsWith(".log")).map((f) => {
|
|
2453
|
-
const filePath =
|
|
2547
|
+
const filePath = join6(runsDir, f);
|
|
2454
2548
|
const stats = statSync2(filePath);
|
|
2455
2549
|
const runId = basename3(f, ".log");
|
|
2456
|
-
const content =
|
|
2550
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
2457
2551
|
const metadata = parseLogMetadata(content);
|
|
2458
2552
|
return {
|
|
2459
2553
|
runId,
|
|
@@ -2526,7 +2620,7 @@ function isRunLogActive(projectKey, specialistType, runId) {
|
|
|
2526
2620
|
}
|
|
2527
2621
|
function getRunLogSize(projectKey, specialistType, runId) {
|
|
2528
2622
|
const filePath = getRunLogPath(projectKey, specialistType, runId);
|
|
2529
|
-
if (!
|
|
2623
|
+
if (!existsSync6(filePath)) {
|
|
2530
2624
|
return null;
|
|
2531
2625
|
}
|
|
2532
2626
|
try {
|
|
@@ -2583,6 +2677,10 @@ var init_specialist_logs = __esm({
|
|
|
2583
2677
|
});
|
|
2584
2678
|
|
|
2585
2679
|
export {
|
|
2680
|
+
readWorkspacePlan,
|
|
2681
|
+
updateItemStatus,
|
|
2682
|
+
updateSubItemStatus,
|
|
2683
|
+
init_io,
|
|
2586
2684
|
readTodayCosts,
|
|
2587
2685
|
readIssueCosts,
|
|
2588
2686
|
summarizeCosts,
|
|
@@ -2674,4 +2772,4 @@ export {
|
|
|
2674
2772
|
getFeedbackStats,
|
|
2675
2773
|
init_specialists
|
|
2676
2774
|
};
|
|
2677
|
-
//# sourceMappingURL=chunk-
|
|
2775
|
+
//# sourceMappingURL=chunk-NLN3ZLCN.js.map
|