oh-my-opencode 3.15.2 → 3.15.3
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/cli/index.js +438 -187
- package/dist/cli/run/continuation-state.d.ts +2 -1
- package/dist/features/boulder-state/storage.d.ts +1 -1
- package/dist/features/boulder-state/types.d.ts +1 -0
- package/dist/hooks/atlas/background-launch-session-tracking.d.ts +11 -0
- package/dist/hooks/atlas/boulder-continuation-injector.d.ts +2 -1
- package/dist/hooks/atlas/task-context.d.ts +7 -0
- package/dist/hooks/atlas/types.d.ts +1 -0
- package/dist/index.js +646 -366
- package/dist/shared/agent-display-names.d.ts +1 -0
- package/dist/tools/delegate-task/resolve-call-id.d.ts +2 -0
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -60789,15 +60789,19 @@ function convertSDKMessageToStoredMessage(msg) {
|
|
|
60789
60789
|
async function findNearestMessageWithFieldsFromSDK(client, sessionID) {
|
|
60790
60790
|
try {
|
|
60791
60791
|
const response = await client.session.messages({ path: { id: sessionID } });
|
|
60792
|
-
const messages = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true })
|
|
60793
|
-
|
|
60794
|
-
|
|
60792
|
+
const messages = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true }).map((message) => ({
|
|
60793
|
+
stored: convertSDKMessageToStoredMessage(message),
|
|
60794
|
+
createdAt: message.info?.time?.created ?? Number.NEGATIVE_INFINITY,
|
|
60795
|
+
id: typeof message.id === "string" ? message.id : ""
|
|
60796
|
+
})).sort((left, right) => right.createdAt - left.createdAt || right.id.localeCompare(left.id));
|
|
60797
|
+
for (const message of messages) {
|
|
60798
|
+
const stored = message.stored;
|
|
60795
60799
|
if (stored?.agent && stored.model?.providerID && stored.model?.modelID) {
|
|
60796
60800
|
return stored;
|
|
60797
60801
|
}
|
|
60798
60802
|
}
|
|
60799
|
-
for (
|
|
60800
|
-
const stored =
|
|
60803
|
+
for (const message of messages) {
|
|
60804
|
+
const stored = message.stored;
|
|
60801
60805
|
if (stored?.agent || stored?.model?.providerID && stored?.model?.modelID) {
|
|
60802
60806
|
return stored;
|
|
60803
60807
|
}
|
|
@@ -60813,7 +60817,15 @@ async function findNearestMessageWithFieldsFromSDK(client, sessionID) {
|
|
|
60813
60817
|
async function findFirstMessageWithAgentFromSDK(client, sessionID) {
|
|
60814
60818
|
try {
|
|
60815
60819
|
const response = await client.session.messages({ path: { id: sessionID } });
|
|
60816
|
-
const messages = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true })
|
|
60820
|
+
const messages = normalizeSDKResponse(response, [], { preferResponseOnMissingData: true }).sort((left, right) => {
|
|
60821
|
+
const leftTime = left.info?.time?.created ?? Number.POSITIVE_INFINITY;
|
|
60822
|
+
const rightTime = right.info?.time?.created ?? Number.POSITIVE_INFINITY;
|
|
60823
|
+
if (leftTime !== rightTime)
|
|
60824
|
+
return leftTime - rightTime;
|
|
60825
|
+
const leftId = typeof left.id === "string" ? left.id : "";
|
|
60826
|
+
const rightId = typeof right.id === "string" ? right.id : "";
|
|
60827
|
+
return leftId.localeCompare(rightId);
|
|
60828
|
+
});
|
|
60817
60829
|
for (const msg of messages) {
|
|
60818
60830
|
const stored = convertSDKMessageToStoredMessage(msg);
|
|
60819
60831
|
if (stored?.agent) {
|
|
@@ -60833,27 +60845,27 @@ function findNearestMessageWithFields(messageDir) {
|
|
|
60833
60845
|
return null;
|
|
60834
60846
|
}
|
|
60835
60847
|
try {
|
|
60836
|
-
const
|
|
60837
|
-
for (const file of files) {
|
|
60848
|
+
const messages = readdirSync(messageDir).filter((f) => f.endsWith(".json")).map((fileName) => {
|
|
60838
60849
|
try {
|
|
60839
|
-
const content = readFileSync6(join12(messageDir,
|
|
60850
|
+
const content = readFileSync6(join12(messageDir, fileName), "utf-8");
|
|
60840
60851
|
const msg = JSON.parse(content);
|
|
60841
|
-
|
|
60842
|
-
|
|
60843
|
-
|
|
60852
|
+
return {
|
|
60853
|
+
fileName,
|
|
60854
|
+
msg,
|
|
60855
|
+
createdAt: typeof msg.time?.created === "number" ? msg.time.created : Number.NEGATIVE_INFINITY
|
|
60856
|
+
};
|
|
60844
60857
|
} catch {
|
|
60845
|
-
|
|
60858
|
+
return null;
|
|
60859
|
+
}
|
|
60860
|
+
}).filter((entry) => entry !== null).sort((left, right) => right.createdAt - left.createdAt || right.fileName.localeCompare(left.fileName));
|
|
60861
|
+
for (const entry of messages) {
|
|
60862
|
+
if (entry.msg.agent && entry.msg.model?.providerID && entry.msg.model?.modelID) {
|
|
60863
|
+
return entry.msg;
|
|
60846
60864
|
}
|
|
60847
60865
|
}
|
|
60848
|
-
for (const
|
|
60849
|
-
|
|
60850
|
-
|
|
60851
|
-
const msg = JSON.parse(content);
|
|
60852
|
-
if (msg.agent || msg.model?.providerID && msg.model?.modelID) {
|
|
60853
|
-
return msg;
|
|
60854
|
-
}
|
|
60855
|
-
} catch {
|
|
60856
|
-
continue;
|
|
60866
|
+
for (const entry of messages) {
|
|
60867
|
+
if (entry.msg.agent || entry.msg.model?.providerID && entry.msg.model?.modelID) {
|
|
60868
|
+
return entry.msg;
|
|
60857
60869
|
}
|
|
60858
60870
|
}
|
|
60859
60871
|
} catch {
|
|
@@ -60866,16 +60878,22 @@ function findFirstMessageWithAgent(messageDir) {
|
|
|
60866
60878
|
return null;
|
|
60867
60879
|
}
|
|
60868
60880
|
try {
|
|
60869
|
-
const
|
|
60870
|
-
for (const file of files) {
|
|
60881
|
+
const messages = readdirSync(messageDir).filter((f) => f.endsWith(".json")).map((fileName) => {
|
|
60871
60882
|
try {
|
|
60872
|
-
const content = readFileSync6(join12(messageDir,
|
|
60883
|
+
const content = readFileSync6(join12(messageDir, fileName), "utf-8");
|
|
60873
60884
|
const msg = JSON.parse(content);
|
|
60874
|
-
|
|
60875
|
-
|
|
60876
|
-
|
|
60885
|
+
return {
|
|
60886
|
+
fileName,
|
|
60887
|
+
msg,
|
|
60888
|
+
createdAt: typeof msg.time?.created === "number" ? msg.time.created : Number.POSITIVE_INFINITY
|
|
60889
|
+
};
|
|
60877
60890
|
} catch {
|
|
60878
|
-
|
|
60891
|
+
return null;
|
|
60892
|
+
}
|
|
60893
|
+
}).filter((entry) => entry !== null).sort((left, right) => left.createdAt - right.createdAt || left.fileName.localeCompare(right.fileName));
|
|
60894
|
+
for (const entry of messages) {
|
|
60895
|
+
if (entry.msg.agent) {
|
|
60896
|
+
return entry.msg.agent;
|
|
60879
60897
|
}
|
|
60880
60898
|
}
|
|
60881
60899
|
} catch {
|
|
@@ -60983,7 +61001,7 @@ function getAgentConfigKey(agentName) {
|
|
|
60983
61001
|
return lower;
|
|
60984
61002
|
return lower;
|
|
60985
61003
|
}
|
|
60986
|
-
function
|
|
61004
|
+
function normalizeAgentForPromptKey(agentName) {
|
|
60987
61005
|
if (typeof agentName !== "string") {
|
|
60988
61006
|
return;
|
|
60989
61007
|
}
|
|
@@ -60994,10 +61012,10 @@ function normalizeAgentForPrompt(agentName) {
|
|
|
60994
61012
|
const lower = trimmed.toLowerCase();
|
|
60995
61013
|
const reversed = REVERSE_DISPLAY_NAMES[lower];
|
|
60996
61014
|
if (reversed !== undefined) {
|
|
60997
|
-
return
|
|
61015
|
+
return reversed;
|
|
60998
61016
|
}
|
|
60999
61017
|
if (AGENT_DISPLAY_NAMES[lower] !== undefined) {
|
|
61000
|
-
return
|
|
61018
|
+
return lower;
|
|
61001
61019
|
}
|
|
61002
61020
|
return trimmed;
|
|
61003
61021
|
}
|
|
@@ -63497,11 +63515,12 @@ async function injectContinuation(args) {
|
|
|
63497
63515
|
} : undefined);
|
|
63498
63516
|
tools = tools ?? previousMessage?.tools;
|
|
63499
63517
|
}
|
|
63500
|
-
|
|
63518
|
+
const promptAgent = normalizeAgentForPromptKey(agentName);
|
|
63519
|
+
if (promptAgent && skipAgents.some((s) => getAgentConfigKey(s) === getAgentConfigKey(promptAgent))) {
|
|
63501
63520
|
log(`[${HOOK_NAME}] Skipped: agent in skipAgents list`, { sessionID, agent: agentName });
|
|
63502
63521
|
return;
|
|
63503
63522
|
}
|
|
63504
|
-
if (!
|
|
63523
|
+
if (!promptAgent) {
|
|
63505
63524
|
const compactionState = sessionStateStore.getExistingState(sessionID);
|
|
63506
63525
|
if (compactionState && isCompactionGuardActive(compactionState, Date.now())) {
|
|
63507
63526
|
log(`[${HOOK_NAME}] Skipped: agent unknown after compaction`, { sessionID });
|
|
@@ -63532,7 +63551,7 @@ ${todoList}`;
|
|
|
63532
63551
|
try {
|
|
63533
63552
|
log(`[${HOOK_NAME}] Injecting continuation`, {
|
|
63534
63553
|
sessionID,
|
|
63535
|
-
agent:
|
|
63554
|
+
agent: promptAgent,
|
|
63536
63555
|
model,
|
|
63537
63556
|
incompleteCount: freshIncompleteCount
|
|
63538
63557
|
});
|
|
@@ -63540,7 +63559,7 @@ ${todoList}`;
|
|
|
63540
63559
|
await ctx.client.session.promptAsync({
|
|
63541
63560
|
path: { id: sessionID },
|
|
63542
63561
|
body: {
|
|
63543
|
-
agent:
|
|
63562
|
+
agent: promptAgent,
|
|
63544
63563
|
...model !== undefined ? { model } : {},
|
|
63545
63564
|
...inheritedTools ? { tools: inheritedTools } : {},
|
|
63546
63565
|
parts: [createInternalAgentTextPart(prompt)]
|
|
@@ -94774,6 +94793,15 @@ function readBoulderState(directory) {
|
|
|
94774
94793
|
if (!Array.isArray(parsed.session_ids)) {
|
|
94775
94794
|
parsed.session_ids = [];
|
|
94776
94795
|
}
|
|
94796
|
+
if (!parsed.session_origins || typeof parsed.session_origins !== "object" || Array.isArray(parsed.session_origins)) {
|
|
94797
|
+
parsed.session_origins = {};
|
|
94798
|
+
}
|
|
94799
|
+
if (parsed.session_ids.length === 1) {
|
|
94800
|
+
const soleSessionId = parsed.session_ids[0];
|
|
94801
|
+
if (typeof soleSessionId === "string" && parsed.session_origins[soleSessionId] !== "appended" && parsed.session_origins[soleSessionId] !== "direct") {
|
|
94802
|
+
parsed.session_origins[soleSessionId] = "direct";
|
|
94803
|
+
}
|
|
94804
|
+
}
|
|
94777
94805
|
if (!parsed.task_sessions || typeof parsed.task_sessions !== "object" || Array.isArray(parsed.task_sessions)) {
|
|
94778
94806
|
parsed.task_sessions = {};
|
|
94779
94807
|
}
|
|
@@ -94795,22 +94823,34 @@ function writeBoulderState(directory, state3) {
|
|
|
94795
94823
|
return false;
|
|
94796
94824
|
}
|
|
94797
94825
|
}
|
|
94798
|
-
function appendSessionId(directory, sessionId) {
|
|
94826
|
+
function appendSessionId(directory, sessionId, origin = "direct") {
|
|
94799
94827
|
const state3 = readBoulderState(directory);
|
|
94800
94828
|
if (!state3)
|
|
94801
94829
|
return null;
|
|
94830
|
+
if (!state3.session_origins || typeof state3.session_origins !== "object" || Array.isArray(state3.session_origins)) {
|
|
94831
|
+
state3.session_origins = {};
|
|
94832
|
+
}
|
|
94802
94833
|
if (!state3.session_ids?.includes(sessionId)) {
|
|
94803
94834
|
if (!Array.isArray(state3.session_ids)) {
|
|
94804
94835
|
state3.session_ids = [];
|
|
94805
94836
|
}
|
|
94806
94837
|
const originalSessionIds = [...state3.session_ids];
|
|
94838
|
+
const originalSessionOrigins = { ...state3.session_origins };
|
|
94807
94839
|
state3.session_ids.push(sessionId);
|
|
94840
|
+
state3.session_origins[sessionId] = origin;
|
|
94808
94841
|
if (writeBoulderState(directory, state3)) {
|
|
94809
94842
|
return state3;
|
|
94810
94843
|
}
|
|
94811
94844
|
state3.session_ids = originalSessionIds;
|
|
94845
|
+
state3.session_origins = originalSessionOrigins;
|
|
94812
94846
|
return null;
|
|
94813
94847
|
}
|
|
94848
|
+
if (!state3.session_origins[sessionId]) {
|
|
94849
|
+
state3.session_origins[sessionId] = origin;
|
|
94850
|
+
if (!writeBoulderState(directory, state3)) {
|
|
94851
|
+
return null;
|
|
94852
|
+
}
|
|
94853
|
+
}
|
|
94814
94854
|
return state3;
|
|
94815
94855
|
}
|
|
94816
94856
|
function clearBoulderState(directory) {
|
|
@@ -94899,6 +94939,9 @@ function createBoulderState(planPath, sessionId, agent, worktreePath) {
|
|
|
94899
94939
|
active_plan: planPath,
|
|
94900
94940
|
started_at: new Date().toISOString(),
|
|
94901
94941
|
session_ids: [sessionId],
|
|
94942
|
+
session_origins: {
|
|
94943
|
+
[sessionId]: "direct"
|
|
94944
|
+
},
|
|
94902
94945
|
plan_name: getPlanName(planPath),
|
|
94903
94946
|
...agent !== undefined ? { agent } : {},
|
|
94904
94947
|
...worktreePath !== undefined ? { worktree_path: worktreePath } : {}
|
|
@@ -95530,6 +95573,100 @@ function isAbortError(error48) {
|
|
|
95530
95573
|
return false;
|
|
95531
95574
|
}
|
|
95532
95575
|
|
|
95576
|
+
// src/hooks/atlas/session-last-agent.ts
|
|
95577
|
+
import { readFileSync as readFileSync44, readdirSync as readdirSync17 } from "fs";
|
|
95578
|
+
import { join as join68 } from "path";
|
|
95579
|
+
function isCompactionAgent2(agent) {
|
|
95580
|
+
return typeof agent === "string" && agent.toLowerCase() === "compaction";
|
|
95581
|
+
}
|
|
95582
|
+
function getLastAgentFromMessageDir(messageDir) {
|
|
95583
|
+
try {
|
|
95584
|
+
const messages = readdirSync17(messageDir).filter((fileName) => fileName.endsWith(".json")).map((fileName) => {
|
|
95585
|
+
try {
|
|
95586
|
+
const content = readFileSync44(join68(messageDir, fileName), "utf-8");
|
|
95587
|
+
const parsed = JSON.parse(content);
|
|
95588
|
+
return {
|
|
95589
|
+
fileName,
|
|
95590
|
+
agent: parsed.agent,
|
|
95591
|
+
createdAt: typeof parsed.time?.created === "number" ? parsed.time.created : Number.NEGATIVE_INFINITY
|
|
95592
|
+
};
|
|
95593
|
+
} catch {
|
|
95594
|
+
return null;
|
|
95595
|
+
}
|
|
95596
|
+
}).filter((message) => message !== null).sort((left, right) => right.createdAt - left.createdAt || right.fileName.localeCompare(left.fileName));
|
|
95597
|
+
for (const message of messages) {
|
|
95598
|
+
if (typeof message.agent === "string" && !isCompactionAgent2(message.agent)) {
|
|
95599
|
+
return message.agent.toLowerCase();
|
|
95600
|
+
}
|
|
95601
|
+
}
|
|
95602
|
+
} catch {
|
|
95603
|
+
return null;
|
|
95604
|
+
}
|
|
95605
|
+
return null;
|
|
95606
|
+
}
|
|
95607
|
+
async function getLastAgentFromSession(sessionID, client) {
|
|
95608
|
+
if (isSqliteBackend() && client) {
|
|
95609
|
+
try {
|
|
95610
|
+
const response = await client.session.messages({ path: { id: sessionID } });
|
|
95611
|
+
const messages = normalizeSDKResponse(response, [], {
|
|
95612
|
+
preferResponseOnMissingData: true
|
|
95613
|
+
}).sort((left, right) => {
|
|
95614
|
+
const leftTime = left.info?.time?.created ?? Number.NEGATIVE_INFINITY;
|
|
95615
|
+
const rightTime = right.info?.time?.created ?? Number.NEGATIVE_INFINITY;
|
|
95616
|
+
if (leftTime !== rightTime) {
|
|
95617
|
+
return rightTime - leftTime;
|
|
95618
|
+
}
|
|
95619
|
+
const leftId = typeof left.id === "string" ? left.id : "";
|
|
95620
|
+
const rightId = typeof right.id === "string" ? right.id : "";
|
|
95621
|
+
return rightId.localeCompare(leftId);
|
|
95622
|
+
});
|
|
95623
|
+
for (const message of messages) {
|
|
95624
|
+
const agent = message.info?.agent;
|
|
95625
|
+
if (typeof agent === "string" && !isCompactionAgent2(agent)) {
|
|
95626
|
+
return agent.toLowerCase();
|
|
95627
|
+
}
|
|
95628
|
+
}
|
|
95629
|
+
} catch {
|
|
95630
|
+
return null;
|
|
95631
|
+
}
|
|
95632
|
+
return null;
|
|
95633
|
+
}
|
|
95634
|
+
const messageDir = getMessageDir(sessionID);
|
|
95635
|
+
if (!messageDir)
|
|
95636
|
+
return null;
|
|
95637
|
+
return getLastAgentFromMessageDir(messageDir);
|
|
95638
|
+
}
|
|
95639
|
+
|
|
95640
|
+
// src/hooks/atlas/boulder-session-lineage.ts
|
|
95641
|
+
init_logger();
|
|
95642
|
+
async function isSessionInBoulderLineage(input) {
|
|
95643
|
+
const visitedSessionIDs = new Set;
|
|
95644
|
+
let currentSessionID = input.sessionID;
|
|
95645
|
+
while (!visitedSessionIDs.has(currentSessionID)) {
|
|
95646
|
+
visitedSessionIDs.add(currentSessionID);
|
|
95647
|
+
const sessionResult = await input.client.session.get({ path: { id: currentSessionID } }).catch((error48) => {
|
|
95648
|
+
log(`[${HOOK_NAME7}] Failed to resolve session lineage`, {
|
|
95649
|
+
sessionID: input.sessionID,
|
|
95650
|
+
currentSessionID,
|
|
95651
|
+
error: error48
|
|
95652
|
+
});
|
|
95653
|
+
return null;
|
|
95654
|
+
});
|
|
95655
|
+
if (!sessionResult || sessionResult.error) {
|
|
95656
|
+
return false;
|
|
95657
|
+
}
|
|
95658
|
+
const parentSessionID = sessionResult.data?.parentID;
|
|
95659
|
+
if (!parentSessionID) {
|
|
95660
|
+
return false;
|
|
95661
|
+
}
|
|
95662
|
+
if (input.boulderSessionIDs.includes(parentSessionID)) {
|
|
95663
|
+
return true;
|
|
95664
|
+
}
|
|
95665
|
+
currentSessionID = parentSessionID;
|
|
95666
|
+
}
|
|
95667
|
+
return false;
|
|
95668
|
+
}
|
|
95669
|
+
|
|
95533
95670
|
// src/hooks/atlas/idle-event.ts
|
|
95534
95671
|
init_logger();
|
|
95535
95672
|
|
|
@@ -95726,9 +95863,17 @@ If you were given **multiple genuinely independent goals** (unrelated tasks, par
|
|
|
95726
95863
|
async function resolveRecentPromptContextForSession(ctx, sessionID) {
|
|
95727
95864
|
try {
|
|
95728
95865
|
const messagesResp = await ctx.client.session.messages({ path: { id: sessionID } });
|
|
95729
|
-
const messages = normalizeSDKResponse(messagesResp, [])
|
|
95730
|
-
|
|
95731
|
-
const
|
|
95866
|
+
const messages = normalizeSDKResponse(messagesResp, []).sort((left, right) => {
|
|
95867
|
+
const leftTime = left.info?.time?.created ?? Number.NEGATIVE_INFINITY;
|
|
95868
|
+
const rightTime = right.info?.time?.created ?? Number.NEGATIVE_INFINITY;
|
|
95869
|
+
if (leftTime !== rightTime)
|
|
95870
|
+
return rightTime - leftTime;
|
|
95871
|
+
const leftId = typeof left.id === "string" ? left.id : "";
|
|
95872
|
+
const rightId = typeof right.id === "string" ? right.id : "";
|
|
95873
|
+
return rightId.localeCompare(leftId);
|
|
95874
|
+
});
|
|
95875
|
+
for (const message of messages) {
|
|
95876
|
+
const info = message.info;
|
|
95732
95877
|
const model2 = info?.model;
|
|
95733
95878
|
const tools2 = normalizePromptTools(info?.tools);
|
|
95734
95879
|
if (model2?.providerID && model2?.modelID) {
|
|
@@ -95772,7 +95917,7 @@ async function injectBoulderContinuation(input) {
|
|
|
95772
95917
|
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
|
|
95773
95918
|
if (hasRunningBgTasks) {
|
|
95774
95919
|
log(`[${HOOK_NAME7}] Skipped injection: background tasks running`, { sessionID });
|
|
95775
|
-
return;
|
|
95920
|
+
return "skipped_background_tasks";
|
|
95776
95921
|
}
|
|
95777
95922
|
const worktreeContext = worktreePath ? `
|
|
95778
95923
|
|
|
@@ -95789,7 +95934,7 @@ async function injectBoulderContinuation(input) {
|
|
|
95789
95934
|
sessionID,
|
|
95790
95935
|
agent: continuationAgent ?? agent ?? "unknown"
|
|
95791
95936
|
});
|
|
95792
|
-
return;
|
|
95937
|
+
return "skipped_agent_unavailable";
|
|
95793
95938
|
}
|
|
95794
95939
|
try {
|
|
95795
95940
|
log(`[${HOOK_NAME7}] Injecting boulder continuation`, { sessionID, planName, remaining });
|
|
@@ -95798,7 +95943,7 @@ async function injectBoulderContinuation(input) {
|
|
|
95798
95943
|
await ctx.client.session.promptAsync({
|
|
95799
95944
|
path: { id: sessionID },
|
|
95800
95945
|
body: {
|
|
95801
|
-
agent:
|
|
95946
|
+
agent: continuationAgent,
|
|
95802
95947
|
...promptContext.model !== undefined ? { model: promptContext.model } : {},
|
|
95803
95948
|
...inheritedTools ? { tools: inheritedTools } : {},
|
|
95804
95949
|
parts: [createInternalAgentTextPart(prompt)]
|
|
@@ -95807,6 +95952,7 @@ async function injectBoulderContinuation(input) {
|
|
|
95807
95952
|
});
|
|
95808
95953
|
sessionState.promptFailureCount = 0;
|
|
95809
95954
|
log(`[${HOOK_NAME7}] Boulder continuation injected`, { sessionID });
|
|
95955
|
+
return "injected";
|
|
95810
95956
|
} catch (err) {
|
|
95811
95957
|
sessionState.promptFailureCount += 1;
|
|
95812
95958
|
sessionState.lastFailureAt = Date.now();
|
|
@@ -95815,72 +95961,24 @@ async function injectBoulderContinuation(input) {
|
|
|
95815
95961
|
error: String(err),
|
|
95816
95962
|
promptFailureCount: sessionState.promptFailureCount
|
|
95817
95963
|
});
|
|
95964
|
+
return "failed";
|
|
95818
95965
|
}
|
|
95819
95966
|
}
|
|
95820
95967
|
|
|
95821
|
-
// src/hooks/atlas/boulder-session-lineage.ts
|
|
95822
|
-
init_logger();
|
|
95823
|
-
async function isSessionInBoulderLineage(input) {
|
|
95824
|
-
const visitedSessionIDs = new Set;
|
|
95825
|
-
let currentSessionID = input.sessionID;
|
|
95826
|
-
while (!visitedSessionIDs.has(currentSessionID)) {
|
|
95827
|
-
visitedSessionIDs.add(currentSessionID);
|
|
95828
|
-
const sessionResult = await input.client.session.get({ path: { id: currentSessionID } }).catch((error48) => {
|
|
95829
|
-
log(`[${HOOK_NAME7}] Failed to resolve session lineage`, {
|
|
95830
|
-
sessionID: input.sessionID,
|
|
95831
|
-
currentSessionID,
|
|
95832
|
-
error: error48
|
|
95833
|
-
});
|
|
95834
|
-
return null;
|
|
95835
|
-
});
|
|
95836
|
-
if (!sessionResult || sessionResult.error) {
|
|
95837
|
-
return false;
|
|
95838
|
-
}
|
|
95839
|
-
const parentSessionID = sessionResult.data?.parentID;
|
|
95840
|
-
if (!parentSessionID) {
|
|
95841
|
-
return false;
|
|
95842
|
-
}
|
|
95843
|
-
if (input.boulderSessionIDs.includes(parentSessionID)) {
|
|
95844
|
-
return true;
|
|
95845
|
-
}
|
|
95846
|
-
currentSessionID = parentSessionID;
|
|
95847
|
-
}
|
|
95848
|
-
return false;
|
|
95849
|
-
}
|
|
95850
|
-
|
|
95851
95968
|
// src/hooks/atlas/resolve-active-boulder-session.ts
|
|
95852
95969
|
async function resolveActiveBoulderSession(input) {
|
|
95853
95970
|
const boulderState = readBoulderState(input.directory);
|
|
95854
95971
|
if (!boulderState) {
|
|
95855
95972
|
return null;
|
|
95856
95973
|
}
|
|
95974
|
+
if (!boulderState.session_ids.includes(input.sessionID)) {
|
|
95975
|
+
return null;
|
|
95976
|
+
}
|
|
95857
95977
|
const progress = getPlanProgress(boulderState.active_plan);
|
|
95858
95978
|
if (progress.isComplete) {
|
|
95859
95979
|
return { boulderState, progress, appendedSession: false };
|
|
95860
95980
|
}
|
|
95861
|
-
|
|
95862
|
-
return { boulderState, progress, appendedSession: false };
|
|
95863
|
-
}
|
|
95864
|
-
if (!subagentSessions.has(input.sessionID)) {
|
|
95865
|
-
return null;
|
|
95866
|
-
}
|
|
95867
|
-
const belongsToActiveBoulder = await isSessionInBoulderLineage({
|
|
95868
|
-
client: input.client,
|
|
95869
|
-
sessionID: input.sessionID,
|
|
95870
|
-
boulderSessionIDs: boulderState.session_ids
|
|
95871
|
-
});
|
|
95872
|
-
if (!belongsToActiveBoulder) {
|
|
95873
|
-
return null;
|
|
95874
|
-
}
|
|
95875
|
-
const updatedBoulderState = appendSessionId(input.directory, input.sessionID);
|
|
95876
|
-
if (!updatedBoulderState?.session_ids.includes(input.sessionID)) {
|
|
95877
|
-
return null;
|
|
95878
|
-
}
|
|
95879
|
-
return {
|
|
95880
|
-
boulderState: updatedBoulderState,
|
|
95881
|
-
progress,
|
|
95882
|
-
appendedSession: true
|
|
95883
|
-
};
|
|
95981
|
+
return { boulderState, progress, appendedSession: false };
|
|
95884
95982
|
}
|
|
95885
95983
|
|
|
95886
95984
|
// src/hooks/atlas/idle-event.ts
|
|
@@ -95894,12 +95992,38 @@ function hasRunningBackgroundTasks(sessionID, options) {
|
|
|
95894
95992
|
}
|
|
95895
95993
|
async function injectContinuation2(input) {
|
|
95896
95994
|
const remaining = input.progress.total - input.progress.completed;
|
|
95897
|
-
input.sessionState.
|
|
95995
|
+
if (input.sessionState.isInjectingContinuation) {
|
|
95996
|
+
scheduleRetry({
|
|
95997
|
+
ctx: input.ctx,
|
|
95998
|
+
sessionID: input.sessionID,
|
|
95999
|
+
sessionState: input.sessionState,
|
|
96000
|
+
options: input.options
|
|
96001
|
+
});
|
|
96002
|
+
return;
|
|
96003
|
+
}
|
|
96004
|
+
input.sessionState.isInjectingContinuation = true;
|
|
95898
96005
|
try {
|
|
95899
96006
|
const currentBoulder = readBoulderState(input.ctx.directory);
|
|
95900
96007
|
const currentTask = currentBoulder ? readCurrentTopLevelTask(currentBoulder.active_plan) : null;
|
|
95901
96008
|
const preferredTaskSession = currentTask ? getTaskSessionState(input.ctx.directory, currentTask.key) : null;
|
|
95902
|
-
|
|
96009
|
+
if (!currentBoulder) {
|
|
96010
|
+
return;
|
|
96011
|
+
}
|
|
96012
|
+
const canContinueSession = await canContinueTrackedBoulderSession({
|
|
96013
|
+
client: input.ctx.client,
|
|
96014
|
+
sessionID: input.sessionID,
|
|
96015
|
+
sessionOrigin: currentBoulder.session_origins?.[input.sessionID],
|
|
96016
|
+
boulderSessionIDs: currentBoulder.session_ids,
|
|
96017
|
+
requiredAgent: currentBoulder.agent
|
|
96018
|
+
});
|
|
96019
|
+
if (!canContinueSession) {
|
|
96020
|
+
log(`[${HOOK_NAME7}] Skipped: tracked descendant agent does not match boulder agent`, {
|
|
96021
|
+
sessionID: input.sessionID,
|
|
96022
|
+
requiredAgent: currentBoulder.agent ?? "atlas"
|
|
96023
|
+
});
|
|
96024
|
+
return;
|
|
96025
|
+
}
|
|
96026
|
+
const result = await injectBoulderContinuation({
|
|
95903
96027
|
ctx: input.ctx,
|
|
95904
96028
|
sessionID: input.sessionID,
|
|
95905
96029
|
planName: input.planName,
|
|
@@ -95912,9 +96036,43 @@ async function injectContinuation2(input) {
|
|
|
95912
96036
|
backgroundManager: input.options?.backgroundManager,
|
|
95913
96037
|
sessionState: input.sessionState
|
|
95914
96038
|
});
|
|
96039
|
+
if (result === "injected") {
|
|
96040
|
+
if (input.sessionState.pendingRetryTimer) {
|
|
96041
|
+
clearTimeout(input.sessionState.pendingRetryTimer);
|
|
96042
|
+
input.sessionState.pendingRetryTimer = undefined;
|
|
96043
|
+
}
|
|
96044
|
+
input.sessionState.lastContinuationInjectedAt = Date.now();
|
|
96045
|
+
return;
|
|
96046
|
+
}
|
|
96047
|
+
if (result === "skipped_background_tasks") {
|
|
96048
|
+
scheduleRetry({
|
|
96049
|
+
ctx: input.ctx,
|
|
96050
|
+
sessionID: input.sessionID,
|
|
96051
|
+
sessionState: input.sessionState,
|
|
96052
|
+
options: input.options
|
|
96053
|
+
});
|
|
96054
|
+
return;
|
|
96055
|
+
}
|
|
96056
|
+
if (result === "failed") {
|
|
96057
|
+
scheduleRetry({
|
|
96058
|
+
ctx: input.ctx,
|
|
96059
|
+
sessionID: input.sessionID,
|
|
96060
|
+
sessionState: input.sessionState,
|
|
96061
|
+
options: input.options
|
|
96062
|
+
});
|
|
96063
|
+
}
|
|
95915
96064
|
} catch (error48) {
|
|
95916
96065
|
log(`[${HOOK_NAME7}] Failed to inject boulder continuation`, { sessionID: input.sessionID, error: error48 });
|
|
95917
96066
|
input.sessionState.promptFailureCount += 1;
|
|
96067
|
+
input.sessionState.lastFailureAt = Date.now();
|
|
96068
|
+
scheduleRetry({
|
|
96069
|
+
ctx: input.ctx,
|
|
96070
|
+
sessionID: input.sessionID,
|
|
96071
|
+
sessionState: input.sessionState,
|
|
96072
|
+
options: input.options
|
|
96073
|
+
});
|
|
96074
|
+
} finally {
|
|
96075
|
+
input.sessionState.isInjectingContinuation = false;
|
|
95918
96076
|
}
|
|
95919
96077
|
}
|
|
95920
96078
|
function scheduleRetry(input) {
|
|
@@ -95928,6 +96086,10 @@ function scheduleRetry(input) {
|
|
|
95928
96086
|
return;
|
|
95929
96087
|
if (sessionState.waitingForFinalWaveApproval)
|
|
95930
96088
|
return;
|
|
96089
|
+
const now = Date.now();
|
|
96090
|
+
if (sessionState.lastContinuationInjectedAt && now - sessionState.lastContinuationInjectedAt < CONTINUATION_COOLDOWN_MS2) {
|
|
96091
|
+
return;
|
|
96092
|
+
}
|
|
95931
96093
|
const currentBoulder = readBoulderState(ctx.directory);
|
|
95932
96094
|
if (!currentBoulder)
|
|
95933
96095
|
return;
|
|
@@ -95938,8 +96100,19 @@ function scheduleRetry(input) {
|
|
|
95938
96100
|
return;
|
|
95939
96101
|
if (options?.isContinuationStopped?.(sessionID))
|
|
95940
96102
|
return;
|
|
95941
|
-
|
|
96103
|
+
const canContinueSession = await canContinueTrackedBoulderSession({
|
|
96104
|
+
client: ctx.client,
|
|
96105
|
+
sessionID,
|
|
96106
|
+
sessionOrigin: currentBoulder.session_origins?.[sessionID],
|
|
96107
|
+
boulderSessionIDs: currentBoulder.session_ids,
|
|
96108
|
+
requiredAgent: currentBoulder.agent
|
|
96109
|
+
});
|
|
96110
|
+
if (!canContinueSession)
|
|
96111
|
+
return;
|
|
96112
|
+
if (hasRunningBackgroundTasks(sessionID, options)) {
|
|
96113
|
+
scheduleRetry({ ctx, sessionID, sessionState, options });
|
|
95942
96114
|
return;
|
|
96115
|
+
}
|
|
95943
96116
|
await injectContinuation2({
|
|
95944
96117
|
ctx,
|
|
95945
96118
|
sessionID,
|
|
@@ -95975,27 +96148,19 @@ async function handleAtlasSessionIdle(input) {
|
|
|
95975
96148
|
plan: boulderState.plan_name
|
|
95976
96149
|
});
|
|
95977
96150
|
}
|
|
95978
|
-
|
|
95979
|
-
|
|
95980
|
-
|
|
95981
|
-
|
|
95982
|
-
|
|
95983
|
-
|
|
95984
|
-
|
|
95985
|
-
|
|
95986
|
-
|
|
95987
|
-
|
|
95988
|
-
|
|
95989
|
-
|
|
95990
|
-
|
|
95991
|
-
if (!agentMatches) {
|
|
95992
|
-
log(`[${HOOK_NAME7}] Skipped: subagent agent does not match boulder agent`, {
|
|
95993
|
-
sessionID,
|
|
95994
|
-
agent: sessionAgent ?? "unknown",
|
|
95995
|
-
requiredAgent: requiredAgentName
|
|
95996
|
-
});
|
|
95997
|
-
return;
|
|
95998
|
-
}
|
|
96151
|
+
const canContinueSession = await canContinueTrackedBoulderSession({
|
|
96152
|
+
client: ctx.client,
|
|
96153
|
+
sessionID,
|
|
96154
|
+
sessionOrigin: boulderState.session_origins?.[sessionID],
|
|
96155
|
+
boulderSessionIDs: boulderState.session_ids,
|
|
96156
|
+
requiredAgent: boulderState.agent
|
|
96157
|
+
});
|
|
96158
|
+
if (!canContinueSession) {
|
|
96159
|
+
log(`[${HOOK_NAME7}] Skipped: tracked descendant agent does not match boulder agent`, {
|
|
96160
|
+
sessionID,
|
|
96161
|
+
requiredAgent: boulderState.agent ?? "atlas"
|
|
96162
|
+
});
|
|
96163
|
+
return;
|
|
95999
96164
|
}
|
|
96000
96165
|
const sessionState = getState(sessionID);
|
|
96001
96166
|
const now = Date.now();
|
|
@@ -96022,6 +96187,7 @@ async function handleAtlasSessionIdle(input) {
|
|
|
96022
96187
|
sessionState.lastFailureAt = undefined;
|
|
96023
96188
|
}
|
|
96024
96189
|
if (hasRunningBackgroundTasks(sessionID, options)) {
|
|
96190
|
+
scheduleRetry({ ctx, sessionID, sessionState, options });
|
|
96025
96191
|
log(`[${HOOK_NAME7}] Skipped: background tasks running`, { sessionID });
|
|
96026
96192
|
return;
|
|
96027
96193
|
}
|
|
@@ -96049,6 +96215,30 @@ async function handleAtlasSessionIdle(input) {
|
|
|
96049
96215
|
worktreePath: boulderState.worktree_path
|
|
96050
96216
|
});
|
|
96051
96217
|
}
|
|
96218
|
+
async function canContinueTrackedBoulderSession(input) {
|
|
96219
|
+
const ancestorSessionIDs = input.boulderSessionIDs.filter((trackedSessionID) => trackedSessionID !== input.sessionID);
|
|
96220
|
+
if (ancestorSessionIDs.length === 0) {
|
|
96221
|
+
return true;
|
|
96222
|
+
}
|
|
96223
|
+
const isTrackedDescendant = await isSessionInBoulderLineage({
|
|
96224
|
+
client: input.client,
|
|
96225
|
+
sessionID: input.sessionID,
|
|
96226
|
+
boulderSessionIDs: ancestorSessionIDs
|
|
96227
|
+
});
|
|
96228
|
+
if (input.sessionOrigin === "direct") {
|
|
96229
|
+
return true;
|
|
96230
|
+
}
|
|
96231
|
+
if (!isTrackedDescendant) {
|
|
96232
|
+
return false;
|
|
96233
|
+
}
|
|
96234
|
+
const sessionAgent = await getLastAgentFromSession(input.sessionID, input.client) ?? getSessionAgent(input.sessionID);
|
|
96235
|
+
if (!sessionAgent) {
|
|
96236
|
+
return false;
|
|
96237
|
+
}
|
|
96238
|
+
const requiredAgentKey = getAgentConfigKey(input.requiredAgent ?? "atlas");
|
|
96239
|
+
const sessionAgentKey = getAgentConfigKey(sessionAgent);
|
|
96240
|
+
return sessionAgentKey === requiredAgentKey || requiredAgentKey === getAgentConfigKey("atlas") && sessionAgentKey === getAgentConfigKey("sisyphus");
|
|
96241
|
+
}
|
|
96052
96242
|
|
|
96053
96243
|
// src/hooks/atlas/event-handler.ts
|
|
96054
96244
|
function createAtlasEventHandler(input) {
|
|
@@ -96138,8 +96328,141 @@ function createAtlasEventHandler(input) {
|
|
|
96138
96328
|
// src/hooks/atlas/tool-execute-after.ts
|
|
96139
96329
|
init_logger();
|
|
96140
96330
|
|
|
96331
|
+
// src/hooks/atlas/background-launch-session-tracking.ts
|
|
96332
|
+
init_logger();
|
|
96333
|
+
|
|
96334
|
+
// src/hooks/atlas/subagent-session-id.ts
|
|
96335
|
+
init_logger();
|
|
96336
|
+
function extractSessionIdFromMetadata(metadata) {
|
|
96337
|
+
if (metadata && typeof metadata === "object" && "sessionId" in metadata) {
|
|
96338
|
+
const value = metadata.sessionId;
|
|
96339
|
+
if (typeof value === "string" && value.startsWith("ses_")) {
|
|
96340
|
+
return value;
|
|
96341
|
+
}
|
|
96342
|
+
}
|
|
96343
|
+
return;
|
|
96344
|
+
}
|
|
96345
|
+
function extractSessionIdFromOutput(output) {
|
|
96346
|
+
const taskMetadataBlocks = [...output.matchAll(/<task_metadata>([\s\S]*?)<\/task_metadata>/gi)];
|
|
96347
|
+
const lastTaskMetadataBlock = taskMetadataBlocks.at(-1)?.[1];
|
|
96348
|
+
if (lastTaskMetadataBlock) {
|
|
96349
|
+
const taskMetadataSessionMatch = lastTaskMetadataBlock.match(/session_id:\s*(ses_[a-zA-Z0-9_-]+)/i);
|
|
96350
|
+
if (taskMetadataSessionMatch) {
|
|
96351
|
+
return taskMetadataSessionMatch[1];
|
|
96352
|
+
}
|
|
96353
|
+
}
|
|
96354
|
+
const explicitSessionMatches = [...output.matchAll(/Session ID:\s*(ses_[a-zA-Z0-9_-]+)/g)];
|
|
96355
|
+
return explicitSessionMatches.at(-1)?.[1];
|
|
96356
|
+
}
|
|
96357
|
+
async function validateSubagentSessionId(input) {
|
|
96358
|
+
if (!input.sessionID || input.lineageSessionIDs.length === 0) {
|
|
96359
|
+
return;
|
|
96360
|
+
}
|
|
96361
|
+
const belongsToLineage = await isSessionInBoulderLineage({
|
|
96362
|
+
client: input.client,
|
|
96363
|
+
sessionID: input.sessionID,
|
|
96364
|
+
boulderSessionIDs: input.lineageSessionIDs
|
|
96365
|
+
});
|
|
96366
|
+
if (!belongsToLineage) {
|
|
96367
|
+
log(`[${HOOK_NAME7}] Ignoring extracted session id outside active lineage`, {
|
|
96368
|
+
sessionID: input.sessionID,
|
|
96369
|
+
lineageSessionIDs: input.lineageSessionIDs
|
|
96370
|
+
});
|
|
96371
|
+
return;
|
|
96372
|
+
}
|
|
96373
|
+
return input.sessionID;
|
|
96374
|
+
}
|
|
96375
|
+
|
|
96376
|
+
// src/hooks/atlas/task-context.ts
|
|
96377
|
+
function resolvePreferredSessionId(currentSessionId, trackedSessionId) {
|
|
96378
|
+
return currentSessionId ?? trackedSessionId ?? "<session_id>";
|
|
96379
|
+
}
|
|
96380
|
+
function resolveTaskContext(pendingTaskRef, planPath) {
|
|
96381
|
+
if (!pendingTaskRef) {
|
|
96382
|
+
return {
|
|
96383
|
+
currentTask: readCurrentTopLevelTask(planPath),
|
|
96384
|
+
shouldSkipTaskSessionUpdate: false,
|
|
96385
|
+
shouldIgnoreCurrentSessionId: false
|
|
96386
|
+
};
|
|
96387
|
+
}
|
|
96388
|
+
if (pendingTaskRef.kind === "track") {
|
|
96389
|
+
return {
|
|
96390
|
+
currentTask: pendingTaskRef.task,
|
|
96391
|
+
shouldSkipTaskSessionUpdate: false,
|
|
96392
|
+
shouldIgnoreCurrentSessionId: false
|
|
96393
|
+
};
|
|
96394
|
+
}
|
|
96395
|
+
if (pendingTaskRef.reason === "explicit_resume") {
|
|
96396
|
+
return {
|
|
96397
|
+
currentTask: readCurrentTopLevelTask(planPath),
|
|
96398
|
+
shouldSkipTaskSessionUpdate: true,
|
|
96399
|
+
shouldIgnoreCurrentSessionId: true
|
|
96400
|
+
};
|
|
96401
|
+
}
|
|
96402
|
+
return {
|
|
96403
|
+
currentTask: pendingTaskRef.task,
|
|
96404
|
+
shouldSkipTaskSessionUpdate: true,
|
|
96405
|
+
shouldIgnoreCurrentSessionId: true
|
|
96406
|
+
};
|
|
96407
|
+
}
|
|
96408
|
+
|
|
96409
|
+
// src/hooks/atlas/background-launch-session-tracking.ts
|
|
96410
|
+
async function syncBackgroundLaunchSessionTracking(input) {
|
|
96411
|
+
const { ctx, boulderState, toolInput, toolOutput, pendingTaskRef, metadataSessionId } = input;
|
|
96412
|
+
if (!boulderState) {
|
|
96413
|
+
return;
|
|
96414
|
+
}
|
|
96415
|
+
const extractedSessionId = metadataSessionId ?? extractSessionIdFromOutput(toolOutput.output);
|
|
96416
|
+
const lineageSessionIDs = boulderState.session_ids;
|
|
96417
|
+
const subagentSessionId = await validateSubagentSessionId({
|
|
96418
|
+
client: ctx.client,
|
|
96419
|
+
sessionID: extractedSessionId,
|
|
96420
|
+
lineageSessionIDs
|
|
96421
|
+
});
|
|
96422
|
+
const trackedSessionId = subagentSessionId ?? await resolveFallbackTrackedSessionId({
|
|
96423
|
+
ctx,
|
|
96424
|
+
extractedSessionId,
|
|
96425
|
+
lineageSessionIDs
|
|
96426
|
+
});
|
|
96427
|
+
if (!trackedSessionId) {
|
|
96428
|
+
return;
|
|
96429
|
+
}
|
|
96430
|
+
appendSessionId(ctx.directory, trackedSessionId, "appended");
|
|
96431
|
+
const { currentTask, shouldSkipTaskSessionUpdate } = resolveTaskContext(pendingTaskRef, boulderState.active_plan);
|
|
96432
|
+
if (currentTask && !shouldSkipTaskSessionUpdate) {
|
|
96433
|
+
upsertTaskSessionState(ctx.directory, {
|
|
96434
|
+
taskKey: currentTask.key,
|
|
96435
|
+
taskLabel: currentTask.label,
|
|
96436
|
+
taskTitle: currentTask.title,
|
|
96437
|
+
sessionId: trackedSessionId,
|
|
96438
|
+
agent: typeof toolOutput.metadata?.agent === "string" ? toolOutput.metadata.agent : undefined,
|
|
96439
|
+
category: typeof toolOutput.metadata?.category === "string" ? toolOutput.metadata.category : undefined
|
|
96440
|
+
});
|
|
96441
|
+
}
|
|
96442
|
+
log(`[${HOOK_NAME7}] Background launch session tracked`, {
|
|
96443
|
+
sessionID: toolInput.sessionID,
|
|
96444
|
+
subagentSessionId: trackedSessionId,
|
|
96445
|
+
taskKey: currentTask?.key
|
|
96446
|
+
});
|
|
96447
|
+
}
|
|
96448
|
+
async function resolveFallbackTrackedSessionId(input) {
|
|
96449
|
+
if (!input.extractedSessionId) {
|
|
96450
|
+
return;
|
|
96451
|
+
}
|
|
96452
|
+
try {
|
|
96453
|
+
const session = await input.ctx.client.session.get({ path: { id: input.extractedSessionId } });
|
|
96454
|
+
const parentSessionId = session.data?.parentID;
|
|
96455
|
+
if (typeof parentSessionId === "string" && input.lineageSessionIDs.includes(parentSessionId)) {
|
|
96456
|
+
return input.extractedSessionId;
|
|
96457
|
+
}
|
|
96458
|
+
return;
|
|
96459
|
+
} catch {
|
|
96460
|
+
return;
|
|
96461
|
+
}
|
|
96462
|
+
}
|
|
96463
|
+
|
|
96141
96464
|
// src/hooks/atlas/final-wave-plan-state.ts
|
|
96142
|
-
import { existsSync as existsSync61, readFileSync as
|
|
96465
|
+
import { existsSync as existsSync61, readFileSync as readFileSync45 } from "fs";
|
|
96143
96466
|
var TODO_HEADING_PATTERN2 = /^##\s+TODOs\b/i;
|
|
96144
96467
|
var FINAL_VERIFICATION_HEADING_PATTERN2 = /^##\s+Final Verification Wave\b/i;
|
|
96145
96468
|
var SECOND_LEVEL_HEADING_PATTERN2 = /^##\s+/;
|
|
@@ -96151,7 +96474,7 @@ function readFinalWavePlanState(planPath) {
|
|
|
96151
96474
|
return null;
|
|
96152
96475
|
}
|
|
96153
96476
|
try {
|
|
96154
|
-
const content =
|
|
96477
|
+
const content = readFileSync45(planPath, "utf-8");
|
|
96155
96478
|
const lines = content.split(/\r?\n/);
|
|
96156
96479
|
let section = "other";
|
|
96157
96480
|
let pendingImplementationTaskCount = 0;
|
|
@@ -96220,48 +96543,6 @@ function isSisyphusPath(filePath) {
|
|
|
96220
96543
|
return /\.sisyphus[/\\]/.test(filePath);
|
|
96221
96544
|
}
|
|
96222
96545
|
|
|
96223
|
-
// src/hooks/atlas/subagent-session-id.ts
|
|
96224
|
-
init_logger();
|
|
96225
|
-
function extractSessionIdFromMetadata(metadata) {
|
|
96226
|
-
if (metadata && typeof metadata === "object" && "sessionId" in metadata) {
|
|
96227
|
-
const value = metadata.sessionId;
|
|
96228
|
-
if (typeof value === "string" && value.startsWith("ses_")) {
|
|
96229
|
-
return value;
|
|
96230
|
-
}
|
|
96231
|
-
}
|
|
96232
|
-
return;
|
|
96233
|
-
}
|
|
96234
|
-
function extractSessionIdFromOutput(output) {
|
|
96235
|
-
const taskMetadataBlocks = [...output.matchAll(/<task_metadata>([\s\S]*?)<\/task_metadata>/gi)];
|
|
96236
|
-
const lastTaskMetadataBlock = taskMetadataBlocks.at(-1)?.[1];
|
|
96237
|
-
if (lastTaskMetadataBlock) {
|
|
96238
|
-
const taskMetadataSessionMatch = lastTaskMetadataBlock.match(/session_id:\s*(ses_[a-zA-Z0-9_-]+)/i);
|
|
96239
|
-
if (taskMetadataSessionMatch) {
|
|
96240
|
-
return taskMetadataSessionMatch[1];
|
|
96241
|
-
}
|
|
96242
|
-
}
|
|
96243
|
-
const explicitSessionMatches = [...output.matchAll(/Session ID:\s*(ses_[a-zA-Z0-9_-]+)/g)];
|
|
96244
|
-
return explicitSessionMatches.at(-1)?.[1];
|
|
96245
|
-
}
|
|
96246
|
-
async function validateSubagentSessionId(input) {
|
|
96247
|
-
if (!input.sessionID || input.lineageSessionIDs.length === 0) {
|
|
96248
|
-
return;
|
|
96249
|
-
}
|
|
96250
|
-
const belongsToLineage = await isSessionInBoulderLineage({
|
|
96251
|
-
client: input.client,
|
|
96252
|
-
sessionID: input.sessionID,
|
|
96253
|
-
boulderSessionIDs: input.lineageSessionIDs
|
|
96254
|
-
});
|
|
96255
|
-
if (!belongsToLineage) {
|
|
96256
|
-
log(`[${HOOK_NAME7}] Ignoring extracted session id outside active lineage`, {
|
|
96257
|
-
sessionID: input.sessionID,
|
|
96258
|
-
lineageSessionIDs: input.lineageSessionIDs
|
|
96259
|
-
});
|
|
96260
|
-
return;
|
|
96261
|
-
}
|
|
96262
|
-
return input.sessionID;
|
|
96263
|
-
}
|
|
96264
|
-
|
|
96265
96546
|
// src/hooks/atlas/verification-reminders.ts
|
|
96266
96547
|
function buildReuseHint(sessionId) {
|
|
96267
96548
|
return `
|
|
@@ -96442,37 +96723,6 @@ function isWriteOrEditToolName(toolName) {
|
|
|
96442
96723
|
}
|
|
96443
96724
|
|
|
96444
96725
|
// src/hooks/atlas/tool-execute-after.ts
|
|
96445
|
-
function resolvePreferredSessionId(currentSessionId, trackedSessionId) {
|
|
96446
|
-
return currentSessionId ?? trackedSessionId ?? "<session_id>";
|
|
96447
|
-
}
|
|
96448
|
-
function resolveTaskContext(pendingTaskRef, planPath) {
|
|
96449
|
-
if (!pendingTaskRef) {
|
|
96450
|
-
return {
|
|
96451
|
-
currentTask: readCurrentTopLevelTask(planPath),
|
|
96452
|
-
shouldSkipTaskSessionUpdate: false,
|
|
96453
|
-
shouldIgnoreCurrentSessionId: false
|
|
96454
|
-
};
|
|
96455
|
-
}
|
|
96456
|
-
if (pendingTaskRef.kind === "track") {
|
|
96457
|
-
return {
|
|
96458
|
-
currentTask: pendingTaskRef.task,
|
|
96459
|
-
shouldSkipTaskSessionUpdate: false,
|
|
96460
|
-
shouldIgnoreCurrentSessionId: false
|
|
96461
|
-
};
|
|
96462
|
-
}
|
|
96463
|
-
if (pendingTaskRef.reason === "explicit_resume") {
|
|
96464
|
-
return {
|
|
96465
|
-
currentTask: readCurrentTopLevelTask(planPath),
|
|
96466
|
-
shouldSkipTaskSessionUpdate: true,
|
|
96467
|
-
shouldIgnoreCurrentSessionId: true
|
|
96468
|
-
};
|
|
96469
|
-
}
|
|
96470
|
-
return {
|
|
96471
|
-
currentTask: pendingTaskRef.task,
|
|
96472
|
-
shouldSkipTaskSessionUpdate: true,
|
|
96473
|
-
shouldIgnoreCurrentSessionId: true
|
|
96474
|
-
};
|
|
96475
|
-
}
|
|
96476
96726
|
function createToolExecuteAfterHandler2(input) {
|
|
96477
96727
|
const { ctx, pendingFilePaths, pendingTaskRefs, autoCommit, getState } = input;
|
|
96478
96728
|
return async (toolInput, toolOutput) => {
|
|
@@ -96510,12 +96760,20 @@ function createToolExecuteAfterHandler2(input) {
|
|
|
96510
96760
|
if (toolInput.callID) {
|
|
96511
96761
|
pendingTaskRefs.delete(toolInput.callID);
|
|
96512
96762
|
}
|
|
96763
|
+
const boulderState = readBoulderState(ctx.directory);
|
|
96513
96764
|
const isBackgroundLaunch = outputStr.includes("Background task launched") || outputStr.includes("Background task continued") || outputStr.includes("Background delegate launched") || outputStr.includes("Background agent task launched");
|
|
96514
96765
|
if (isBackgroundLaunch) {
|
|
96766
|
+
await syncBackgroundLaunchSessionTracking({
|
|
96767
|
+
ctx,
|
|
96768
|
+
boulderState,
|
|
96769
|
+
toolInput,
|
|
96770
|
+
toolOutput,
|
|
96771
|
+
pendingTaskRef,
|
|
96772
|
+
metadataSessionId
|
|
96773
|
+
});
|
|
96515
96774
|
return;
|
|
96516
96775
|
}
|
|
96517
96776
|
if (toolOutput.output && typeof toolOutput.output === "string") {
|
|
96518
|
-
const boulderState = readBoulderState(ctx.directory);
|
|
96519
96777
|
const worktreePath = boulderState?.worktree_path?.trim();
|
|
96520
96778
|
const verificationDirectory = worktreePath ? worktreePath : ctx.directory;
|
|
96521
96779
|
const gitStats = collectGitDiffStats(verificationDirectory);
|
|
@@ -96530,14 +96788,7 @@ function createToolExecuteAfterHandler2(input) {
|
|
|
96530
96788
|
} = resolveTaskContext(pendingTaskRef, boulderState.active_plan);
|
|
96531
96789
|
const trackedTaskSession = currentTask ? getTaskSessionState(ctx.directory, currentTask.key) : null;
|
|
96532
96790
|
const sessionState = toolInput.sessionID ? getState(toolInput.sessionID) : undefined;
|
|
96533
|
-
|
|
96534
|
-
appendSessionId(ctx.directory, toolInput.sessionID);
|
|
96535
|
-
log(`[${HOOK_NAME7}] Appended session to boulder`, {
|
|
96536
|
-
sessionID: toolInput.sessionID,
|
|
96537
|
-
plan: boulderState.plan_name
|
|
96538
|
-
});
|
|
96539
|
-
}
|
|
96540
|
-
const lineageSessionIDs = toolInput.sessionID && !boulderState.session_ids.includes(toolInput.sessionID) ? [...boulderState.session_ids, toolInput.sessionID] : boulderState.session_ids;
|
|
96791
|
+
const lineageSessionIDs = boulderState.session_ids;
|
|
96541
96792
|
const subagentSessionId = await validateSubagentSessionId({
|
|
96542
96793
|
client: ctx.client,
|
|
96543
96794
|
sessionID: extractedSessionId,
|
|
@@ -97030,7 +97281,7 @@ function clearSessionModel(sessionID) {
|
|
|
97030
97281
|
}
|
|
97031
97282
|
|
|
97032
97283
|
// src/hooks/compaction-context-injector/session-id.ts
|
|
97033
|
-
function
|
|
97284
|
+
function isCompactionAgent3(agent) {
|
|
97034
97285
|
return agent?.trim().toLowerCase() === "compaction";
|
|
97035
97286
|
}
|
|
97036
97287
|
function resolveSessionID(props) {
|
|
@@ -97039,7 +97290,7 @@ function resolveSessionID(props) {
|
|
|
97039
97290
|
|
|
97040
97291
|
// src/hooks/compaction-context-injector/validated-model.ts
|
|
97041
97292
|
function resolveValidatedModel(info) {
|
|
97042
|
-
if (
|
|
97293
|
+
if (isCompactionAgent3(info?.agent)) {
|
|
97043
97294
|
return;
|
|
97044
97295
|
}
|
|
97045
97296
|
const providerID = info?.model?.providerID ?? info?.providerID;
|
|
@@ -97073,7 +97324,7 @@ async function resolveSessionPromptConfig(ctx, sessionID) {
|
|
|
97073
97324
|
});
|
|
97074
97325
|
for (let index = messages.length - 1;index >= 0; index--) {
|
|
97075
97326
|
const info = messages[index].info;
|
|
97076
|
-
if (!promptConfig.agent && info?.agent && !
|
|
97327
|
+
if (!promptConfig.agent && info?.agent && !isCompactionAgent3(info.agent)) {
|
|
97077
97328
|
promptConfig.agent = info.agent;
|
|
97078
97329
|
}
|
|
97079
97330
|
if (!promptConfig.model) {
|
|
@@ -97164,7 +97415,7 @@ function trackAssistantOutput(state3, messageID) {
|
|
|
97164
97415
|
init_logger();
|
|
97165
97416
|
|
|
97166
97417
|
// src/hooks/compaction-context-injector/recovery-prompt-config.ts
|
|
97167
|
-
function
|
|
97418
|
+
function isCompactionAgent4(agent) {
|
|
97168
97419
|
return agent?.trim().toLowerCase() === "compaction";
|
|
97169
97420
|
}
|
|
97170
97421
|
function matchesExpectedModel(actualModel, expectedModel) {
|
|
@@ -97197,7 +97448,7 @@ function createExpectedRecoveryPromptConfig(checkpoint, currentPromptConfig) {
|
|
|
97197
97448
|
}
|
|
97198
97449
|
function isPromptConfigRecovered(actualPromptConfig, expectedPromptConfig) {
|
|
97199
97450
|
const actualAgent = actualPromptConfig.agent;
|
|
97200
|
-
const agentMatches = typeof actualAgent === "string" && !
|
|
97451
|
+
const agentMatches = typeof actualAgent === "string" && !isCompactionAgent4(actualAgent) && actualAgent.toLowerCase() === expectedPromptConfig.agent.toLowerCase();
|
|
97201
97452
|
return agentMatches && matchesExpectedModel(actualPromptConfig.model, expectedPromptConfig.model) && matchesExpectedTools(actualPromptConfig.tools, expectedPromptConfig.tools);
|
|
97202
97453
|
}
|
|
97203
97454
|
|
|
@@ -98151,12 +98402,12 @@ import * as fs18 from "fs";
|
|
|
98151
98402
|
import * as path11 from "path";
|
|
98152
98403
|
// src/shared/migrate-legacy-config-file.ts
|
|
98153
98404
|
init_logger();
|
|
98154
|
-
import { existsSync as existsSync62, readFileSync as
|
|
98155
|
-
import { join as
|
|
98405
|
+
import { existsSync as existsSync62, readFileSync as readFileSync46, renameSync as renameSync4, rmSync as rmSync3 } from "fs";
|
|
98406
|
+
import { join as join69, dirname as dirname20, basename as basename9 } from "path";
|
|
98156
98407
|
function buildCanonicalPath(legacyPath) {
|
|
98157
98408
|
const dir = dirname20(legacyPath);
|
|
98158
98409
|
const ext = basename9(legacyPath).includes(".jsonc") ? ".jsonc" : ".json";
|
|
98159
|
-
return
|
|
98410
|
+
return join69(dir, `${CONFIG_BASENAME}${ext}`);
|
|
98160
98411
|
}
|
|
98161
98412
|
function archiveLegacyConfigFile(legacyPath) {
|
|
98162
98413
|
const backupPath = `${legacyPath}.bak`;
|
|
@@ -98196,7 +98447,7 @@ function migrateLegacyConfigFile(legacyPath) {
|
|
|
98196
98447
|
if (existsSync62(canonicalPath))
|
|
98197
98448
|
return false;
|
|
98198
98449
|
try {
|
|
98199
|
-
const content =
|
|
98450
|
+
const content = readFileSync46(legacyPath, "utf-8");
|
|
98200
98451
|
writeFileAtomically(canonicalPath, content);
|
|
98201
98452
|
const archivedLegacyConfig = archiveLegacyConfigFile(legacyPath);
|
|
98202
98453
|
log("[migrateLegacyConfigFile] Migrated legacy config to canonical path", {
|
|
@@ -99679,7 +99930,7 @@ function createRuntimeFallbackHook(ctx, options) {
|
|
|
99679
99930
|
}
|
|
99680
99931
|
// src/hooks/write-existing-file-guard/hook.ts
|
|
99681
99932
|
import { existsSync as existsSync65, realpathSync as realpathSync7 } from "fs";
|
|
99682
|
-
import { basename as basename11, dirname as dirname22, isAbsolute as isAbsolute10, join as
|
|
99933
|
+
import { basename as basename11, dirname as dirname22, isAbsolute as isAbsolute10, join as join71, normalize as normalize2, relative as relative8, resolve as resolve12 } from "path";
|
|
99683
99934
|
|
|
99684
99935
|
// src/hooks/write-existing-file-guard/tool-execute-before-handler.ts
|
|
99685
99936
|
import { existsSync as existsSync64 } from "fs";
|
|
@@ -99854,7 +100105,7 @@ function toCanonicalPath2(absolutePath) {
|
|
|
99854
100105
|
} else {
|
|
99855
100106
|
const absoluteDir = dirname22(absolutePath);
|
|
99856
100107
|
const resolvedDir = existsSync65(absoluteDir) ? realpathSync7.native(absoluteDir) : absoluteDir;
|
|
99857
|
-
canonicalPath =
|
|
100108
|
+
canonicalPath = join71(resolvedDir, basename11(absolutePath));
|
|
99858
100109
|
}
|
|
99859
100110
|
return normalize2(canonicalPath);
|
|
99860
100111
|
}
|
|
@@ -100869,12 +101120,12 @@ function createWebFetchRedirectGuardHook(_ctx) {
|
|
|
100869
101120
|
init_logger();
|
|
100870
101121
|
|
|
100871
101122
|
// src/hooks/legacy-plugin-toast/auto-migrate.ts
|
|
100872
|
-
import { existsSync as existsSync66, readFileSync as
|
|
100873
|
-
import { join as
|
|
101123
|
+
import { existsSync as existsSync66, readFileSync as readFileSync48 } from "fs";
|
|
101124
|
+
import { join as join72 } from "path";
|
|
100874
101125
|
function detectOpenCodeConfigPath(overrideConfigDir) {
|
|
100875
101126
|
if (overrideConfigDir) {
|
|
100876
|
-
const jsoncPath =
|
|
100877
|
-
const jsonPath =
|
|
101127
|
+
const jsoncPath = join72(overrideConfigDir, "opencode.jsonc");
|
|
101128
|
+
const jsonPath = join72(overrideConfigDir, "opencode.json");
|
|
100878
101129
|
if (existsSync66(jsoncPath))
|
|
100879
101130
|
return jsoncPath;
|
|
100880
101131
|
if (existsSync66(jsonPath))
|
|
@@ -100893,7 +101144,7 @@ function autoMigrateLegacyPluginEntry(overrideConfigDir) {
|
|
|
100893
101144
|
if (!configPath)
|
|
100894
101145
|
return { migrated: false, from: null, to: null, configPath: null };
|
|
100895
101146
|
try {
|
|
100896
|
-
const content =
|
|
101147
|
+
const content = readFileSync48(configPath, "utf-8");
|
|
100897
101148
|
const parseResult = parseJsoncSafe(content);
|
|
100898
101149
|
if (!parseResult.data?.plugin)
|
|
100899
101150
|
return { migrated: false, from: null, to: null, configPath };
|
|
@@ -101287,13 +101538,13 @@ var DEFAULT_MAX_SYMBOLS = 200;
|
|
|
101287
101538
|
var DEFAULT_MAX_DIAGNOSTICS = 200;
|
|
101288
101539
|
var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
101289
101540
|
// src/tools/lsp/server-config-loader.ts
|
|
101290
|
-
import { existsSync as existsSync67, readFileSync as
|
|
101291
|
-
import { join as
|
|
101541
|
+
import { existsSync as existsSync67, readFileSync as readFileSync49 } from "fs";
|
|
101542
|
+
import { join as join73 } from "path";
|
|
101292
101543
|
function loadJsonFile(path12) {
|
|
101293
101544
|
if (!existsSync67(path12))
|
|
101294
101545
|
return null;
|
|
101295
101546
|
try {
|
|
101296
|
-
return parseJsonc(
|
|
101547
|
+
return parseJsonc(readFileSync49(path12, "utf-8"));
|
|
101297
101548
|
} catch {
|
|
101298
101549
|
return null;
|
|
101299
101550
|
}
|
|
@@ -101302,9 +101553,9 @@ function getConfigPaths3() {
|
|
|
101302
101553
|
const cwd = process.cwd();
|
|
101303
101554
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
101304
101555
|
return {
|
|
101305
|
-
project: detectPluginConfigFile(
|
|
101556
|
+
project: detectPluginConfigFile(join73(cwd, ".opencode")).path,
|
|
101306
101557
|
user: detectPluginConfigFile(configDir).path,
|
|
101307
|
-
opencode: detectConfigFile(
|
|
101558
|
+
opencode: detectConfigFile(join73(configDir, "opencode")).path
|
|
101308
101559
|
};
|
|
101309
101560
|
}
|
|
101310
101561
|
function loadAllConfigs() {
|
|
@@ -101374,19 +101625,19 @@ function getMergedServers() {
|
|
|
101374
101625
|
|
|
101375
101626
|
// src/tools/lsp/server-installation.ts
|
|
101376
101627
|
import { existsSync as existsSync68 } from "fs";
|
|
101377
|
-
import { delimiter, join as
|
|
101628
|
+
import { delimiter, join as join75 } from "path";
|
|
101378
101629
|
|
|
101379
101630
|
// src/tools/lsp/server-path-bases.ts
|
|
101380
|
-
import { join as
|
|
101631
|
+
import { join as join74 } from "path";
|
|
101381
101632
|
function getLspServerAdditionalPathBases(workingDirectory) {
|
|
101382
101633
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
101383
|
-
const dataDir =
|
|
101634
|
+
const dataDir = join74(getDataDir(), "opencode");
|
|
101384
101635
|
return [
|
|
101385
|
-
|
|
101386
|
-
|
|
101387
|
-
|
|
101388
|
-
|
|
101389
|
-
|
|
101636
|
+
join74(workingDirectory, "node_modules", ".bin"),
|
|
101637
|
+
join74(configDir, "bin"),
|
|
101638
|
+
join74(configDir, "node_modules", ".bin"),
|
|
101639
|
+
join74(dataDir, "bin"),
|
|
101640
|
+
join74(dataDir, "bin", "node_modules", ".bin")
|
|
101390
101641
|
];
|
|
101391
101642
|
}
|
|
101392
101643
|
|
|
@@ -101417,14 +101668,14 @@ function isServerInstalled(command) {
|
|
|
101417
101668
|
const paths = pathEnv.split(delimiter);
|
|
101418
101669
|
for (const p of paths) {
|
|
101419
101670
|
for (const suffix of exts) {
|
|
101420
|
-
if (existsSync68(
|
|
101671
|
+
if (existsSync68(join75(p, cmd + suffix))) {
|
|
101421
101672
|
return true;
|
|
101422
101673
|
}
|
|
101423
101674
|
}
|
|
101424
101675
|
}
|
|
101425
101676
|
for (const base of getLspServerAdditionalPathBases(process.cwd())) {
|
|
101426
101677
|
for (const suffix of exts) {
|
|
101427
|
-
if (existsSync68(
|
|
101678
|
+
if (existsSync68(join75(base, cmd + suffix))) {
|
|
101428
101679
|
return true;
|
|
101429
101680
|
}
|
|
101430
101681
|
}
|
|
@@ -101620,7 +101871,7 @@ function spawnProcess(command, options) {
|
|
|
101620
101871
|
return proc;
|
|
101621
101872
|
}
|
|
101622
101873
|
// src/tools/lsp/lsp-client.ts
|
|
101623
|
-
import { readFileSync as
|
|
101874
|
+
import { readFileSync as readFileSync50 } from "fs";
|
|
101624
101875
|
import { extname as extname4, resolve as resolve13 } from "path";
|
|
101625
101876
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
101626
101877
|
|
|
@@ -101892,7 +102143,7 @@ class LSPClient extends LSPClientConnection {
|
|
|
101892
102143
|
async openFile(filePath) {
|
|
101893
102144
|
const absPath = resolve13(filePath);
|
|
101894
102145
|
const uri = pathToFileURL2(absPath).href;
|
|
101895
|
-
const text =
|
|
102146
|
+
const text = readFileSync50(absPath, "utf-8");
|
|
101896
102147
|
if (!this.openedFiles.has(absPath)) {
|
|
101897
102148
|
const ext = extname4(absPath);
|
|
101898
102149
|
const languageId = getLanguageId(ext);
|
|
@@ -102444,10 +102695,10 @@ function formatApplyResult(result) {
|
|
|
102444
102695
|
`);
|
|
102445
102696
|
}
|
|
102446
102697
|
// src/tools/lsp/workspace-edit.ts
|
|
102447
|
-
import { readFileSync as
|
|
102698
|
+
import { readFileSync as readFileSync51, writeFileSync as writeFileSync19 } from "fs";
|
|
102448
102699
|
function applyTextEditsToFile(filePath, edits) {
|
|
102449
102700
|
try {
|
|
102450
|
-
let content =
|
|
102701
|
+
let content = readFileSync51(filePath, "utf-8");
|
|
102451
102702
|
const lines = content.split(`
|
|
102452
102703
|
`);
|
|
102453
102704
|
const sortedEdits = [...edits].sort((a, b) => {
|
|
@@ -102513,7 +102764,7 @@ function applyWorkspaceEdit(edit) {
|
|
|
102513
102764
|
try {
|
|
102514
102765
|
const oldPath = uriToPath(change.oldUri);
|
|
102515
102766
|
const newPath = uriToPath(change.newUri);
|
|
102516
|
-
const content =
|
|
102767
|
+
const content = readFileSync51(oldPath, "utf-8");
|
|
102517
102768
|
writeFileSync19(newPath, content, "utf-8");
|
|
102518
102769
|
__require("fs").unlinkSync(oldPath);
|
|
102519
102770
|
result.filesModified.push(newPath);
|
|
@@ -114996,8 +115247,8 @@ var lsp_symbols = tool({
|
|
|
114996
115247
|
import { resolve as resolve16 } from "path";
|
|
114997
115248
|
|
|
114998
115249
|
// src/tools/lsp/directory-diagnostics.ts
|
|
114999
|
-
import { existsSync as existsSync71, lstatSync as lstatSync2, readdirSync as
|
|
115000
|
-
import { extname as extname6, join as
|
|
115250
|
+
import { existsSync as existsSync71, lstatSync as lstatSync2, readdirSync as readdirSync18 } from "fs";
|
|
115251
|
+
import { extname as extname6, join as join76, resolve as resolve15 } from "path";
|
|
115001
115252
|
var SKIP_DIRECTORIES = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
115002
115253
|
function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
115003
115254
|
const files = [];
|
|
@@ -115006,14 +115257,14 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
|
|
|
115006
115257
|
return;
|
|
115007
115258
|
let entries = [];
|
|
115008
115259
|
try {
|
|
115009
|
-
entries =
|
|
115260
|
+
entries = readdirSync18(currentDir);
|
|
115010
115261
|
} catch {
|
|
115011
115262
|
return;
|
|
115012
115263
|
}
|
|
115013
115264
|
for (const entry of entries) {
|
|
115014
115265
|
if (files.length >= maxFiles)
|
|
115015
115266
|
return;
|
|
115016
|
-
const fullPath =
|
|
115267
|
+
const fullPath = join76(currentDir, entry);
|
|
115017
115268
|
let stat;
|
|
115018
115269
|
try {
|
|
115019
115270
|
stat = lstatSync2(fullPath);
|
|
@@ -115115,8 +115366,8 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
115115
115366
|
}
|
|
115116
115367
|
|
|
115117
115368
|
// src/tools/lsp/infer-extension.ts
|
|
115118
|
-
import { readdirSync as
|
|
115119
|
-
import { extname as extname7, join as
|
|
115369
|
+
import { readdirSync as readdirSync19, lstatSync as lstatSync3 } from "fs";
|
|
115370
|
+
import { extname as extname7, join as join77 } from "path";
|
|
115120
115371
|
var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
|
|
115121
115372
|
var MAX_SCAN_ENTRIES = 500;
|
|
115122
115373
|
function inferExtensionFromDirectory(directory) {
|
|
@@ -115127,14 +115378,14 @@ function inferExtensionFromDirectory(directory) {
|
|
|
115127
115378
|
return;
|
|
115128
115379
|
let entries;
|
|
115129
115380
|
try {
|
|
115130
|
-
entries =
|
|
115381
|
+
entries = readdirSync19(dir);
|
|
115131
115382
|
} catch {
|
|
115132
115383
|
return;
|
|
115133
115384
|
}
|
|
115134
115385
|
for (const entry of entries) {
|
|
115135
115386
|
if (scanned >= MAX_SCAN_ENTRIES)
|
|
115136
115387
|
return;
|
|
115137
|
-
const fullPath =
|
|
115388
|
+
const fullPath = join77(dir, entry);
|
|
115138
115389
|
let stat;
|
|
115139
115390
|
try {
|
|
115140
115391
|
stat = lstatSync3(fullPath);
|
|
@@ -115299,12 +115550,12 @@ var DEFAULT_MAX_MATCHES = 500;
|
|
|
115299
115550
|
|
|
115300
115551
|
// src/tools/ast-grep/sg-cli-path.ts
|
|
115301
115552
|
import { createRequire as createRequire4 } from "module";
|
|
115302
|
-
import { dirname as dirname23, join as
|
|
115553
|
+
import { dirname as dirname23, join as join79 } from "path";
|
|
115303
115554
|
import { existsSync as existsSync73, statSync as statSync10 } from "fs";
|
|
115304
115555
|
|
|
115305
115556
|
// src/tools/ast-grep/downloader.ts
|
|
115306
115557
|
import { existsSync as existsSync72 } from "fs";
|
|
115307
|
-
import { join as
|
|
115558
|
+
import { join as join78 } from "path";
|
|
115308
115559
|
import { homedir as homedir14 } from "os";
|
|
115309
115560
|
import { createRequire as createRequire3 } from "module";
|
|
115310
115561
|
init_logger();
|
|
@@ -115331,12 +115582,12 @@ var PLATFORM_MAP2 = {
|
|
|
115331
115582
|
function getCacheDir3() {
|
|
115332
115583
|
if (process.platform === "win32") {
|
|
115333
115584
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
115334
|
-
const base2 = localAppData ||
|
|
115335
|
-
return
|
|
115585
|
+
const base2 = localAppData || join78(homedir14(), "AppData", "Local");
|
|
115586
|
+
return join78(base2, "oh-my-opencode", "bin");
|
|
115336
115587
|
}
|
|
115337
115588
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
115338
|
-
const base = xdgCache ||
|
|
115339
|
-
return
|
|
115589
|
+
const base = xdgCache || join78(homedir14(), ".cache");
|
|
115590
|
+
return join78(base, "oh-my-opencode", "bin");
|
|
115340
115591
|
}
|
|
115341
115592
|
function getBinaryName3() {
|
|
115342
115593
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
@@ -115353,7 +115604,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
|
|
|
115353
115604
|
}
|
|
115354
115605
|
const cacheDir = getCacheDir3();
|
|
115355
115606
|
const binaryName = getBinaryName3();
|
|
115356
|
-
const binaryPath =
|
|
115607
|
+
const binaryPath = join78(cacheDir, binaryName);
|
|
115357
115608
|
if (existsSync72(binaryPath)) {
|
|
115358
115609
|
return binaryPath;
|
|
115359
115610
|
}
|
|
@@ -115362,7 +115613,7 @@ async function downloadAstGrep(version3 = DEFAULT_VERSION) {
|
|
|
115362
115613
|
const downloadUrl = `https://github.com/${REPO2}/releases/download/${version3}/${assetName}`;
|
|
115363
115614
|
log(`[oh-my-opencode] Downloading ast-grep binary...`);
|
|
115364
115615
|
try {
|
|
115365
|
-
const archivePath =
|
|
115616
|
+
const archivePath = join78(cacheDir, assetName);
|
|
115366
115617
|
ensureCacheDir(cacheDir);
|
|
115367
115618
|
await downloadArchive(downloadUrl, archivePath);
|
|
115368
115619
|
await extractZipArchive(archivePath, cacheDir);
|
|
@@ -115416,7 +115667,7 @@ function findSgCliPathSync() {
|
|
|
115416
115667
|
const require2 = createRequire4(import.meta.url);
|
|
115417
115668
|
const cliPackageJsonPath = require2.resolve("@ast-grep/cli/package.json");
|
|
115418
115669
|
const cliDirectory = dirname23(cliPackageJsonPath);
|
|
115419
|
-
const sgPath =
|
|
115670
|
+
const sgPath = join79(cliDirectory, binaryName);
|
|
115420
115671
|
if (existsSync73(sgPath) && isValidBinary(sgPath)) {
|
|
115421
115672
|
return sgPath;
|
|
115422
115673
|
}
|
|
@@ -115428,7 +115679,7 @@ function findSgCliPathSync() {
|
|
|
115428
115679
|
const packageJsonPath = require2.resolve(`${platformPackage}/package.json`);
|
|
115429
115680
|
const packageDirectory = dirname23(packageJsonPath);
|
|
115430
115681
|
const astGrepBinaryName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
115431
|
-
const binaryPath =
|
|
115682
|
+
const binaryPath = join79(packageDirectory, astGrepBinaryName);
|
|
115432
115683
|
if (existsSync73(binaryPath) && isValidBinary(binaryPath)) {
|
|
115433
115684
|
return binaryPath;
|
|
115434
115685
|
}
|
|
@@ -115830,18 +116081,18 @@ var {spawn: spawn18 } = globalThis.Bun;
|
|
|
115830
116081
|
|
|
115831
116082
|
// src/tools/grep/constants.ts
|
|
115832
116083
|
import { existsSync as existsSync77 } from "fs";
|
|
115833
|
-
import { join as
|
|
116084
|
+
import { join as join81, dirname as dirname24 } from "path";
|
|
115834
116085
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
115835
116086
|
|
|
115836
116087
|
// src/tools/grep/downloader.ts
|
|
115837
|
-
import { existsSync as existsSync76, readdirSync as
|
|
115838
|
-
import { join as
|
|
116088
|
+
import { existsSync as existsSync76, readdirSync as readdirSync20 } from "fs";
|
|
116089
|
+
import { join as join80 } from "path";
|
|
115839
116090
|
function findFileRecursive(dir, filename) {
|
|
115840
116091
|
try {
|
|
115841
|
-
const entries =
|
|
116092
|
+
const entries = readdirSync20(dir, { withFileTypes: true, recursive: true });
|
|
115842
116093
|
for (const entry of entries) {
|
|
115843
116094
|
if (entry.isFile() && entry.name === filename) {
|
|
115844
|
-
return
|
|
116095
|
+
return join80(entry.parentPath ?? dir, entry.name);
|
|
115845
116096
|
}
|
|
115846
116097
|
}
|
|
115847
116098
|
} catch {
|
|
@@ -115862,11 +116113,11 @@ function getPlatformKey() {
|
|
|
115862
116113
|
}
|
|
115863
116114
|
function getInstallDir() {
|
|
115864
116115
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
115865
|
-
return
|
|
116116
|
+
return join80(homeDir, ".cache", "oh-my-opencode", "bin");
|
|
115866
116117
|
}
|
|
115867
116118
|
function getRgPath() {
|
|
115868
116119
|
const isWindows2 = process.platform === "win32";
|
|
115869
|
-
return
|
|
116120
|
+
return join80(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
|
|
115870
116121
|
}
|
|
115871
116122
|
async function extractTarGz2(archivePath, destDir) {
|
|
115872
116123
|
const platformKey = getPlatformKey();
|
|
@@ -115883,7 +116134,7 @@ async function extractZip2(archivePath, destDir) {
|
|
|
115883
116134
|
const binaryName = process.platform === "win32" ? "rg.exe" : "rg";
|
|
115884
116135
|
const foundPath = findFileRecursive(destDir, binaryName);
|
|
115885
116136
|
if (foundPath) {
|
|
115886
|
-
const destPath =
|
|
116137
|
+
const destPath = join80(destDir, binaryName);
|
|
115887
116138
|
if (foundPath !== destPath) {
|
|
115888
116139
|
const { renameSync: renameSync5 } = await import("fs");
|
|
115889
116140
|
renameSync5(foundPath, destPath);
|
|
@@ -115904,7 +116155,7 @@ async function downloadAndInstallRipgrep() {
|
|
|
115904
116155
|
ensureCacheDir(installDir);
|
|
115905
116156
|
const filename = `ripgrep-${RG_VERSION}-${config4.platform}.${config4.extension}`;
|
|
115906
116157
|
const url3 = `https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${filename}`;
|
|
115907
|
-
const archivePath =
|
|
116158
|
+
const archivePath = join80(installDir, filename);
|
|
115908
116159
|
try {
|
|
115909
116160
|
await downloadArchive(url3, archivePath);
|
|
115910
116161
|
if (config4.extension === "tar.gz") {
|
|
@@ -115950,11 +116201,11 @@ function getOpenCodeBundledRg() {
|
|
|
115950
116201
|
const isWindows2 = process.platform === "win32";
|
|
115951
116202
|
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
115952
116203
|
const candidates = [
|
|
115953
|
-
|
|
115954
|
-
|
|
115955
|
-
|
|
115956
|
-
|
|
115957
|
-
|
|
116204
|
+
join81(getDataDir(), "opencode", "bin", rgName),
|
|
116205
|
+
join81(execDir, rgName),
|
|
116206
|
+
join81(execDir, "bin", rgName),
|
|
116207
|
+
join81(execDir, "..", "bin", rgName),
|
|
116208
|
+
join81(execDir, "..", "libexec", rgName)
|
|
115958
116209
|
];
|
|
115959
116210
|
for (const candidate of candidates) {
|
|
115960
116211
|
if (existsSync77(candidate)) {
|
|
@@ -117066,9 +117317,9 @@ function createSkillTool(options = {}) {
|
|
|
117066
117317
|
}
|
|
117067
117318
|
var skill = createSkillTool();
|
|
117068
117319
|
// src/tools/session-manager/constants.ts
|
|
117069
|
-
import { join as
|
|
117070
|
-
var TODO_DIR2 =
|
|
117071
|
-
var TRANSCRIPT_DIR2 =
|
|
117320
|
+
import { join as join82 } from "path";
|
|
117321
|
+
var TODO_DIR2 = join82(getClaudeConfigDir(), "todos");
|
|
117322
|
+
var TRANSCRIPT_DIR2 = join82(getClaudeConfigDir(), "transcripts");
|
|
117072
117323
|
var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
|
117073
117324
|
|
|
117074
117325
|
Returns a list of available session IDs with metadata including message count, date range, and agents used.
|
|
@@ -117143,7 +117394,7 @@ Has Transcript: Yes (234 entries)`;
|
|
|
117143
117394
|
// src/tools/session-manager/file-storage.ts
|
|
117144
117395
|
import { existsSync as existsSync78 } from "fs";
|
|
117145
117396
|
import { readdir, readFile } from "fs/promises";
|
|
117146
|
-
import { join as
|
|
117397
|
+
import { join as join83 } from "path";
|
|
117147
117398
|
async function getFileMainSessions(directory) {
|
|
117148
117399
|
if (!existsSync78(SESSION_STORAGE))
|
|
117149
117400
|
return [];
|
|
@@ -117153,13 +117404,13 @@ async function getFileMainSessions(directory) {
|
|
|
117153
117404
|
for (const projectDir of projectDirs) {
|
|
117154
117405
|
if (!projectDir.isDirectory())
|
|
117155
117406
|
continue;
|
|
117156
|
-
const projectPath =
|
|
117407
|
+
const projectPath = join83(SESSION_STORAGE, projectDir.name);
|
|
117157
117408
|
const sessionFiles = await readdir(projectPath);
|
|
117158
117409
|
for (const file3 of sessionFiles) {
|
|
117159
117410
|
if (!file3.endsWith(".json"))
|
|
117160
117411
|
continue;
|
|
117161
117412
|
try {
|
|
117162
|
-
const content = await readFile(
|
|
117413
|
+
const content = await readFile(join83(projectPath, file3), "utf-8");
|
|
117163
117414
|
const meta3 = JSON.parse(content);
|
|
117164
117415
|
if (meta3.parentID)
|
|
117165
117416
|
continue;
|
|
@@ -117186,7 +117437,7 @@ async function getFileAllSessions() {
|
|
|
117186
117437
|
for (const entry of entries) {
|
|
117187
117438
|
if (!entry.isDirectory())
|
|
117188
117439
|
continue;
|
|
117189
|
-
const sessionPath =
|
|
117440
|
+
const sessionPath = join83(dir, entry.name);
|
|
117190
117441
|
const files = await readdir(sessionPath);
|
|
117191
117442
|
if (files.some((file3) => file3.endsWith(".json"))) {
|
|
117192
117443
|
sessions.push(entry.name);
|
|
@@ -117215,7 +117466,7 @@ async function getFileSessionMessages(sessionID) {
|
|
|
117215
117466
|
if (!file3.endsWith(".json"))
|
|
117216
117467
|
continue;
|
|
117217
117468
|
try {
|
|
117218
|
-
const content = await readFile(
|
|
117469
|
+
const content = await readFile(join83(messageDir, file3), "utf-8");
|
|
117219
117470
|
const meta3 = JSON.parse(content);
|
|
117220
117471
|
const parts = await readParts2(meta3.id);
|
|
117221
117472
|
messages.push({
|
|
@@ -117241,7 +117492,7 @@ async function getFileSessionMessages(sessionID) {
|
|
|
117241
117492
|
});
|
|
117242
117493
|
}
|
|
117243
117494
|
async function readParts2(messageID) {
|
|
117244
|
-
const partDir =
|
|
117495
|
+
const partDir = join83(PART_STORAGE, messageID);
|
|
117245
117496
|
if (!existsSync78(partDir))
|
|
117246
117497
|
return [];
|
|
117247
117498
|
const parts = [];
|
|
@@ -117251,7 +117502,7 @@ async function readParts2(messageID) {
|
|
|
117251
117502
|
if (!file3.endsWith(".json"))
|
|
117252
117503
|
continue;
|
|
117253
117504
|
try {
|
|
117254
|
-
const content = await readFile(
|
|
117505
|
+
const content = await readFile(join83(partDir, file3), "utf-8");
|
|
117255
117506
|
parts.push(JSON.parse(content));
|
|
117256
117507
|
} catch {
|
|
117257
117508
|
continue;
|
|
@@ -117270,7 +117521,7 @@ async function getFileSessionTodos(sessionID) {
|
|
|
117270
117521
|
const todoFiles = allFiles.filter((file3) => file3 === `${sessionID}.json`);
|
|
117271
117522
|
for (const file3 of todoFiles) {
|
|
117272
117523
|
try {
|
|
117273
|
-
const content = await readFile(
|
|
117524
|
+
const content = await readFile(join83(TODO_DIR2, file3), "utf-8");
|
|
117274
117525
|
const data = JSON.parse(content);
|
|
117275
117526
|
if (!Array.isArray(data))
|
|
117276
117527
|
continue;
|
|
@@ -117292,7 +117543,7 @@ async function getFileSessionTodos(sessionID) {
|
|
|
117292
117543
|
async function getFileSessionTranscript(sessionID) {
|
|
117293
117544
|
if (!existsSync78(TRANSCRIPT_DIR2))
|
|
117294
117545
|
return 0;
|
|
117295
|
-
const transcriptFile =
|
|
117546
|
+
const transcriptFile = join83(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
|
|
117296
117547
|
if (!existsSync78(transcriptFile))
|
|
117297
117548
|
return 0;
|
|
117298
117549
|
try {
|
|
@@ -119567,9 +119818,9 @@ async function resolveMultimodalLookerAgentMetadata(ctx) {
|
|
|
119567
119818
|
|
|
119568
119819
|
// src/tools/look-at/image-converter.ts
|
|
119569
119820
|
import * as childProcess from "child_process";
|
|
119570
|
-
import { existsSync as existsSync79, mkdtempSync, readFileSync as
|
|
119821
|
+
import { existsSync as existsSync79, mkdtempSync, readFileSync as readFileSync52, rmSync as rmSync4, unlinkSync as unlinkSync11, writeFileSync as writeFileSync20 } from "fs";
|
|
119571
119822
|
import { tmpdir as tmpdir7 } from "os";
|
|
119572
|
-
import { dirname as dirname27, join as
|
|
119823
|
+
import { dirname as dirname27, join as join84 } from "path";
|
|
119573
119824
|
var SUPPORTED_FORMATS = new Set([
|
|
119574
119825
|
"image/jpeg",
|
|
119575
119826
|
"image/png",
|
|
@@ -119610,8 +119861,8 @@ function convertImageToJpeg(inputPath, mimeType) {
|
|
|
119610
119861
|
if (!existsSync79(inputPath)) {
|
|
119611
119862
|
throw new Error(`File not found: ${inputPath}`);
|
|
119612
119863
|
}
|
|
119613
|
-
const tempDir = mkdtempSync(
|
|
119614
|
-
const outputPath =
|
|
119864
|
+
const tempDir = mkdtempSync(join84(tmpdir7(), "opencode-img-"));
|
|
119865
|
+
const outputPath = join84(tempDir, "converted.jpg");
|
|
119615
119866
|
log(`[image-converter] Converting ${mimeType} to JPEG: ${inputPath}`);
|
|
119616
119867
|
try {
|
|
119617
119868
|
if (process.platform === "darwin") {
|
|
@@ -119676,9 +119927,9 @@ function cleanupConvertedImage(filePath) {
|
|
|
119676
119927
|
}
|
|
119677
119928
|
}
|
|
119678
119929
|
function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
119679
|
-
const tempDir = mkdtempSync(
|
|
119930
|
+
const tempDir = mkdtempSync(join84(tmpdir7(), "opencode-b64-"));
|
|
119680
119931
|
const inputExt = mimeType.split("/")[1] || "bin";
|
|
119681
|
-
const inputPath =
|
|
119932
|
+
const inputPath = join84(tempDir, `input.${inputExt}`);
|
|
119682
119933
|
const tempFiles = [inputPath];
|
|
119683
119934
|
try {
|
|
119684
119935
|
const cleanBase64 = base64Data.replace(/^data:[^;]+;base64,/, "");
|
|
@@ -119687,7 +119938,7 @@ function convertBase64ImageToJpeg(base64Data, mimeType) {
|
|
|
119687
119938
|
log(`[image-converter] Converting Base64 ${mimeType} to JPEG`);
|
|
119688
119939
|
const outputPath = convertImageToJpeg(inputPath, mimeType);
|
|
119689
119940
|
tempFiles.push(outputPath);
|
|
119690
|
-
const convertedBuffer =
|
|
119941
|
+
const convertedBuffer = readFileSync52(outputPath);
|
|
119691
119942
|
const convertedBase64 = convertedBuffer.toString("base64");
|
|
119692
119943
|
log(`[image-converter] Base64 conversion successful`);
|
|
119693
119944
|
return { base64: convertedBase64, tempFiles };
|
|
@@ -120139,6 +120390,11 @@ function formatDetailedError(error92, ctx) {
|
|
|
120139
120390
|
`);
|
|
120140
120391
|
}
|
|
120141
120392
|
|
|
120393
|
+
// src/tools/delegate-task/resolve-call-id.ts
|
|
120394
|
+
function resolveCallID(ctx) {
|
|
120395
|
+
return ctx.callID ?? ctx.callId ?? ctx.call_id;
|
|
120396
|
+
}
|
|
120397
|
+
|
|
120142
120398
|
// src/tools/delegate-task/background-continuation.ts
|
|
120143
120399
|
async function executeBackgroundContinuation(args, ctx, executorCtx, parentContext) {
|
|
120144
120400
|
const { manager } = executorCtx;
|
|
@@ -120166,8 +120422,9 @@ async function executeBackgroundContinuation(args, ctx, executorCtx, parentConte
|
|
|
120166
120422
|
}
|
|
120167
120423
|
};
|
|
120168
120424
|
await ctx.metadata?.(bgContMeta);
|
|
120169
|
-
|
|
120170
|
-
|
|
120425
|
+
const callID = resolveCallID(ctx);
|
|
120426
|
+
if (callID) {
|
|
120427
|
+
storeToolMetadata(ctx.sessionID, callID, bgContMeta);
|
|
120171
120428
|
}
|
|
120172
120429
|
return `Background task continued.
|
|
120173
120430
|
|
|
@@ -120486,8 +120743,9 @@ async function executeSyncContinuation(args, ctx, executorCtx, deps = syncContin
|
|
|
120486
120743
|
}
|
|
120487
120744
|
};
|
|
120488
120745
|
await ctx.metadata?.(syncContMeta);
|
|
120489
|
-
|
|
120490
|
-
|
|
120746
|
+
const callID = resolveCallID(ctx);
|
|
120747
|
+
if (callID) {
|
|
120748
|
+
storeToolMetadata(ctx.sessionID, callID, syncContMeta);
|
|
120491
120749
|
}
|
|
120492
120750
|
const allowTask = isPlanFamily(resumeAgent);
|
|
120493
120751
|
const tddEnabled = sisyphusAgentConfig?.tdd;
|
|
@@ -120631,8 +120889,9 @@ Task ID: ${task.id}`;
|
|
|
120631
120889
|
}
|
|
120632
120890
|
};
|
|
120633
120891
|
await ctx.metadata?.(bgTaskMeta);
|
|
120634
|
-
|
|
120635
|
-
|
|
120892
|
+
const callID = resolveCallID(ctx);
|
|
120893
|
+
if (callID) {
|
|
120894
|
+
storeToolMetadata(ctx.sessionID, callID, bgTaskMeta);
|
|
120636
120895
|
}
|
|
120637
120896
|
const startTime = new Date;
|
|
120638
120897
|
const timingCfg = getTimingConfig();
|
|
@@ -120874,8 +121133,9 @@ Task ID: ${task.id}`;
|
|
|
120874
121133
|
metadata
|
|
120875
121134
|
};
|
|
120876
121135
|
await ctx.metadata?.(unstableMeta);
|
|
120877
|
-
|
|
120878
|
-
|
|
121136
|
+
const callID = resolveCallID(ctx);
|
|
121137
|
+
if (callID) {
|
|
121138
|
+
storeToolMetadata(ctx.sessionID, callID, unstableMeta);
|
|
120879
121139
|
}
|
|
120880
121140
|
const taskMetadataBlock = sessionId ? `
|
|
120881
121141
|
|
|
@@ -121103,8 +121363,9 @@ async function executeSyncTask(args, ctx, executorCtx, parentContext, agentToUse
|
|
|
121103
121363
|
}
|
|
121104
121364
|
};
|
|
121105
121365
|
await ctx.metadata?.(syncTaskMeta);
|
|
121106
|
-
|
|
121107
|
-
|
|
121366
|
+
const callID = resolveCallID(ctx);
|
|
121367
|
+
if (callID) {
|
|
121368
|
+
storeToolMetadata(ctx.sessionID, callID, syncTaskMeta);
|
|
121108
121369
|
}
|
|
121109
121370
|
const promptError = await deps.sendSyncPrompt(client2, {
|
|
121110
121371
|
sessionID,
|
|
@@ -121582,7 +121843,7 @@ Available categories: ${categoryNames.join(", ")}`
|
|
|
121582
121843
|
};
|
|
121583
121844
|
}
|
|
121584
121845
|
const resolvedModel = actualModel?.toLowerCase();
|
|
121585
|
-
const isUnstableAgent = resolved.config.is_unstable_agent ?? (resolvedModel ? resolvedModel.includes("gemini") || resolvedModel.includes("minimax")
|
|
121846
|
+
const isUnstableAgent = resolved.config.is_unstable_agent ?? (resolvedModel ? resolvedModel.includes("gemini") || resolvedModel.includes("minimax") : false);
|
|
121586
121847
|
const defaultProviderID = categoryModel?.providerID ?? parseModelString(actualModel ?? "")?.providerID ?? "opencode";
|
|
121587
121848
|
const configuredFallbackChain = buildFallbackChainFromModels(normalizedConfiguredFallbackModels, defaultProviderID);
|
|
121588
121849
|
const effectiveEntry = matchedFallback && categoryModel ? fallbackEntry ?? (configuredFallbackChain ? findMostSpecificFallbackEntry(categoryModel.providerID, categoryModel.modelID, configuredFallbackChain) : undefined) : undefined;
|
|
@@ -121846,6 +122107,9 @@ function createDelegateTask(options) {
|
|
|
121846
122107
|
await ctx.metadata?.({
|
|
121847
122108
|
title: args.description
|
|
121848
122109
|
});
|
|
122110
|
+
if (!args.description || typeof args.description !== "string") {
|
|
122111
|
+
throw new Error(`Invalid arguments: 'description' parameter is REQUIRED. Provide a short (3-5 words) task description.`);
|
|
122112
|
+
}
|
|
121849
122113
|
if (args.run_in_background === undefined) {
|
|
121850
122114
|
throw new Error(`Invalid arguments: 'run_in_background' parameter is REQUIRED. Specify run_in_background=false for task delegation, or run_in_background=true for parallel exploration.`);
|
|
121851
122115
|
}
|
|
@@ -121965,7 +122229,7 @@ function createDelegateTask(options) {
|
|
|
121965
122229
|
// src/tools/delegate-task/index.ts
|
|
121966
122230
|
init_constants();
|
|
121967
122231
|
// src/tools/task/task-create.ts
|
|
121968
|
-
import { join as
|
|
122232
|
+
import { join as join86 } from "path";
|
|
121969
122233
|
|
|
121970
122234
|
// src/tools/task/types.ts
|
|
121971
122235
|
var TaskStatusSchema = exports_external.enum(["pending", "in_progress", "completed", "deleted"]);
|
|
@@ -122019,18 +122283,18 @@ var TaskDeleteInputSchema = exports_external.object({
|
|
|
122019
122283
|
});
|
|
122020
122284
|
|
|
122021
122285
|
// src/features/claude-tasks/storage.ts
|
|
122022
|
-
import { join as
|
|
122023
|
-
import { existsSync as existsSync80, mkdirSync as mkdirSync16, readFileSync as
|
|
122286
|
+
import { join as join85, dirname as dirname28, basename as basename13, isAbsolute as isAbsolute11 } from "path";
|
|
122287
|
+
import { existsSync as existsSync80, mkdirSync as mkdirSync16, readFileSync as readFileSync53, writeFileSync as writeFileSync21, renameSync as renameSync5, unlinkSync as unlinkSync12, readdirSync as readdirSync21 } from "fs";
|
|
122024
122288
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
122025
122289
|
function getTaskDir(config4 = {}) {
|
|
122026
122290
|
const tasksConfig = config4.sisyphus?.tasks;
|
|
122027
122291
|
const storagePath = tasksConfig?.storage_path;
|
|
122028
122292
|
if (storagePath) {
|
|
122029
|
-
return isAbsolute11(storagePath) ? storagePath :
|
|
122293
|
+
return isAbsolute11(storagePath) ? storagePath : join85(process.cwd(), storagePath);
|
|
122030
122294
|
}
|
|
122031
122295
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" });
|
|
122032
122296
|
const listId = resolveTaskListId(config4);
|
|
122033
|
-
return
|
|
122297
|
+
return join85(configDir, "tasks", listId);
|
|
122034
122298
|
}
|
|
122035
122299
|
function sanitizePathSegment(value) {
|
|
122036
122300
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-") || "default";
|
|
@@ -122057,7 +122321,7 @@ function readJsonSafe(filePath, schema2) {
|
|
|
122057
122321
|
if (!existsSync80(filePath)) {
|
|
122058
122322
|
return null;
|
|
122059
122323
|
}
|
|
122060
|
-
const content =
|
|
122324
|
+
const content = readFileSync53(filePath, "utf-8");
|
|
122061
122325
|
const parsed = JSON.parse(content);
|
|
122062
122326
|
const result = schema2.safeParse(parsed);
|
|
122063
122327
|
if (!result.success) {
|
|
@@ -122089,7 +122353,7 @@ function generateTaskId() {
|
|
|
122089
122353
|
return `T-${randomUUID3()}`;
|
|
122090
122354
|
}
|
|
122091
122355
|
function acquireLock(dirPath) {
|
|
122092
|
-
const lockPath =
|
|
122356
|
+
const lockPath = join85(dirPath, ".lock");
|
|
122093
122357
|
const lockId = randomUUID3();
|
|
122094
122358
|
const createLock = (timestamp2) => {
|
|
122095
122359
|
writeFileSync21(lockPath, JSON.stringify({ id: lockId, timestamp: timestamp2 }), {
|
|
@@ -122099,7 +122363,7 @@ function acquireLock(dirPath) {
|
|
|
122099
122363
|
};
|
|
122100
122364
|
const isStale = () => {
|
|
122101
122365
|
try {
|
|
122102
|
-
const lockContent =
|
|
122366
|
+
const lockContent = readFileSync53(lockPath, "utf-8");
|
|
122103
122367
|
const lockData = JSON.parse(lockContent);
|
|
122104
122368
|
const lockAge = Date.now() - lockData.timestamp;
|
|
122105
122369
|
return lockAge > STALE_LOCK_THRESHOLD_MS;
|
|
@@ -122139,7 +122403,7 @@ function acquireLock(dirPath) {
|
|
|
122139
122403
|
try {
|
|
122140
122404
|
if (!existsSync80(lockPath))
|
|
122141
122405
|
return;
|
|
122142
|
-
const lockContent =
|
|
122406
|
+
const lockContent = readFileSync53(lockPath, "utf-8");
|
|
122143
122407
|
const lockData = JSON.parse(lockContent);
|
|
122144
122408
|
if (lockData.id !== lockId)
|
|
122145
122409
|
return;
|
|
@@ -122302,7 +122566,7 @@ async function handleCreate(args, config4, ctx, context) {
|
|
|
122302
122566
|
threadID: context.sessionID
|
|
122303
122567
|
};
|
|
122304
122568
|
const validatedTask = TaskObjectSchema.parse(task);
|
|
122305
|
-
writeJsonAtomic(
|
|
122569
|
+
writeJsonAtomic(join86(taskDir, `${taskId}.json`), validatedTask);
|
|
122306
122570
|
await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
|
|
122307
122571
|
return JSON.stringify({
|
|
122308
122572
|
task: {
|
|
@@ -122324,7 +122588,7 @@ async function handleCreate(args, config4, ctx, context) {
|
|
|
122324
122588
|
}
|
|
122325
122589
|
}
|
|
122326
122590
|
// src/tools/task/task-get.ts
|
|
122327
|
-
import { join as
|
|
122591
|
+
import { join as join87 } from "path";
|
|
122328
122592
|
var TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/;
|
|
122329
122593
|
function parseTaskId(id) {
|
|
122330
122594
|
if (!TASK_ID_PATTERN.test(id))
|
|
@@ -122349,7 +122613,7 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
122349
122613
|
return JSON.stringify({ error: "invalid_task_id" });
|
|
122350
122614
|
}
|
|
122351
122615
|
const taskDir = getTaskDir(config4);
|
|
122352
|
-
const taskPath =
|
|
122616
|
+
const taskPath = join87(taskDir, `${taskId}.json`);
|
|
122353
122617
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
122354
122618
|
return JSON.stringify({ task: task ?? null });
|
|
122355
122619
|
} catch (error92) {
|
|
@@ -122362,8 +122626,8 @@ Returns null if the task does not exist or the file is invalid.`,
|
|
|
122362
122626
|
});
|
|
122363
122627
|
}
|
|
122364
122628
|
// src/tools/task/task-list.ts
|
|
122365
|
-
import { join as
|
|
122366
|
-
import { existsSync as existsSync81, readdirSync as
|
|
122629
|
+
import { join as join88 } from "path";
|
|
122630
|
+
import { existsSync as existsSync81, readdirSync as readdirSync22 } from "fs";
|
|
122367
122631
|
function createTaskList(config4) {
|
|
122368
122632
|
return tool({
|
|
122369
122633
|
description: `List all active tasks with summary information.
|
|
@@ -122377,13 +122641,13 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
122377
122641
|
if (!existsSync81(taskDir)) {
|
|
122378
122642
|
return JSON.stringify({ tasks: [] });
|
|
122379
122643
|
}
|
|
122380
|
-
const files =
|
|
122644
|
+
const files = readdirSync22(taskDir).filter((f) => f.endsWith(".json") && f.startsWith("T-")).map((f) => f.replace(".json", ""));
|
|
122381
122645
|
if (files.length === 0) {
|
|
122382
122646
|
return JSON.stringify({ tasks: [] });
|
|
122383
122647
|
}
|
|
122384
122648
|
const allTasks = [];
|
|
122385
122649
|
for (const fileId of files) {
|
|
122386
|
-
const task = readJsonSafe(
|
|
122650
|
+
const task = readJsonSafe(join88(taskDir, `${fileId}.json`), TaskObjectSchema);
|
|
122387
122651
|
if (task) {
|
|
122388
122652
|
allTasks.push(task);
|
|
122389
122653
|
}
|
|
@@ -122411,7 +122675,7 @@ Returns summary format: id, subject, status, owner, blockedBy (not full descript
|
|
|
122411
122675
|
});
|
|
122412
122676
|
}
|
|
122413
122677
|
// src/tools/task/task-update.ts
|
|
122414
|
-
import { join as
|
|
122678
|
+
import { join as join89 } from "path";
|
|
122415
122679
|
var TASK_ID_PATTERN2 = /^T-[A-Za-z0-9-]+$/;
|
|
122416
122680
|
function parseTaskId2(id) {
|
|
122417
122681
|
if (!TASK_ID_PATTERN2.test(id))
|
|
@@ -122459,7 +122723,7 @@ async function handleUpdate(args, config4, ctx, context) {
|
|
|
122459
122723
|
return JSON.stringify({ error: "task_lock_unavailable" });
|
|
122460
122724
|
}
|
|
122461
122725
|
try {
|
|
122462
|
-
const taskPath =
|
|
122726
|
+
const taskPath = join89(taskDir, `${taskId}.json`);
|
|
122463
122727
|
const task = readJsonSafe(taskPath, TaskObjectSchema);
|
|
122464
122728
|
if (!task) {
|
|
122465
122729
|
return JSON.stringify({ error: "task_not_found" });
|
|
@@ -124883,14 +125147,15 @@ function formatDuration3(start, end) {
|
|
|
124883
125147
|
// src/features/background-agent/background-task-notification-template.ts
|
|
124884
125148
|
function buildBackgroundTaskNotificationText(input) {
|
|
124885
125149
|
const { task, duration: duration5, statusText, allComplete, remainingCount, completedTasks } = input;
|
|
125150
|
+
const safeDescription = (t) => t.description || t.id;
|
|
124886
125151
|
const errorInfo = task.error ? `
|
|
124887
125152
|
**Error:** ${task.error}` : "";
|
|
124888
125153
|
if (allComplete) {
|
|
124889
125154
|
const succeededTasks = completedTasks.filter((t) => t.status === "completed");
|
|
124890
125155
|
const failedTasks = completedTasks.filter((t) => t.status !== "completed");
|
|
124891
|
-
const succeededText = succeededTasks.length > 0 ? succeededTasks.map((t) => `- \`${t.id}\`: ${t
|
|
125156
|
+
const succeededText = succeededTasks.length > 0 ? succeededTasks.map((t) => `- \`${t.id}\`: ${safeDescription(t)}`).join(`
|
|
124892
125157
|
`) : "";
|
|
124893
|
-
const failedText = failedTasks.length > 0 ? failedTasks.map((t) => `- \`${t.id}\`: ${t
|
|
125158
|
+
const failedText = failedTasks.length > 0 ? failedTasks.map((t) => `- \`${t.id}\`: ${safeDescription(t)} [${t.status.toUpperCase()}]${t.error ? ` - ${t.error}` : ""}`).join(`
|
|
124894
125159
|
`) : "";
|
|
124895
125160
|
const hasFailures = failedTasks.length > 0;
|
|
124896
125161
|
const header = hasFailures ? `[ALL BACKGROUND TASKS FINISHED - ${failedTasks.length} FAILED]` : "[ALL BACKGROUND TASKS COMPLETE]";
|
|
@@ -124907,7 +125172,7 @@ ${failedText}
|
|
|
124907
125172
|
`;
|
|
124908
125173
|
}
|
|
124909
125174
|
if (!body) {
|
|
124910
|
-
body = `- \`${task.id}\`: ${task
|
|
125175
|
+
body = `- \`${task.id}\`: ${safeDescription(task)} [${task.status.toUpperCase()}]${task.error ? ` - ${task.error}` : ""}
|
|
124911
125176
|
`;
|
|
124912
125177
|
}
|
|
124913
125178
|
return `<system-reminder>
|
|
@@ -124924,7 +125189,7 @@ Use \`background_output(task_id="<id>")\` to retrieve each result.${hasFailures
|
|
|
124924
125189
|
return `<system-reminder>
|
|
124925
125190
|
[BACKGROUND TASK ${statusText}]
|
|
124926
125191
|
**ID:** \`${task.id}\`
|
|
124927
|
-
**Description:** ${task
|
|
125192
|
+
**Description:** ${safeDescription(task)}
|
|
124928
125193
|
**Duration:** ${duration5}${errorInfo}
|
|
124929
125194
|
|
|
124930
125195
|
**${remainingCount} task${remainingCount === 1 ? "" : "s"} still in progress.** You WILL be notified when ALL complete.
|
|
@@ -125202,16 +125467,16 @@ function unregisterManagerForCleanup(manager) {
|
|
|
125202
125467
|
}
|
|
125203
125468
|
|
|
125204
125469
|
// src/features/background-agent/compaction-aware-message-resolver.ts
|
|
125205
|
-
import { readdirSync as
|
|
125206
|
-
import { join as
|
|
125207
|
-
function
|
|
125470
|
+
import { readdirSync as readdirSync23, readFileSync as readFileSync54 } from "fs";
|
|
125471
|
+
import { join as join90 } from "path";
|
|
125472
|
+
function isCompactionAgent5(agent) {
|
|
125208
125473
|
return agent?.trim().toLowerCase() === "compaction";
|
|
125209
125474
|
}
|
|
125210
125475
|
function hasFullAgentAndModel(message) {
|
|
125211
|
-
return !!message.agent && !
|
|
125476
|
+
return !!message.agent && !isCompactionAgent5(message.agent) && !!message.model?.providerID && !!message.model?.modelID;
|
|
125212
125477
|
}
|
|
125213
125478
|
function hasPartialAgentOrModel(message) {
|
|
125214
|
-
const hasAgent = !!message.agent && !
|
|
125479
|
+
const hasAgent = !!message.agent && !isCompactionAgent5(message.agent);
|
|
125215
125480
|
const hasModel = !!message.model?.providerID && !!message.model?.modelID;
|
|
125216
125481
|
return hasAgent || hasModel || !!message.tools;
|
|
125217
125482
|
}
|
|
@@ -125237,7 +125502,7 @@ function convertSessionMessageToStoredMessage(message) {
|
|
|
125237
125502
|
function mergeStoredMessages(messages, sessionID) {
|
|
125238
125503
|
const merged = {};
|
|
125239
125504
|
for (const message of messages) {
|
|
125240
|
-
if (!message ||
|
|
125505
|
+
if (!message || isCompactionAgent5(message.agent)) {
|
|
125241
125506
|
continue;
|
|
125242
125507
|
}
|
|
125243
125508
|
if (!merged.agent && message.agent) {
|
|
@@ -125278,11 +125543,11 @@ function resolvePromptContextFromSessionMessages(messages, sessionID) {
|
|
|
125278
125543
|
}
|
|
125279
125544
|
function findNearestMessageExcludingCompaction(messageDir, sessionID) {
|
|
125280
125545
|
try {
|
|
125281
|
-
const files =
|
|
125546
|
+
const files = readdirSync23(messageDir).filter((name) => name.endsWith(".json")).sort().reverse();
|
|
125282
125547
|
const messages = [];
|
|
125283
125548
|
for (const file3 of files) {
|
|
125284
125549
|
try {
|
|
125285
|
-
const content =
|
|
125550
|
+
const content = readFileSync54(join90(messageDir, file3), "utf-8");
|
|
125286
125551
|
messages.push(JSON.parse(content));
|
|
125287
125552
|
} catch {
|
|
125288
125553
|
continue;
|
|
@@ -125368,7 +125633,7 @@ function handleSessionIdleBackgroundEvent(args) {
|
|
|
125368
125633
|
}
|
|
125369
125634
|
|
|
125370
125635
|
// src/features/background-agent/manager.ts
|
|
125371
|
-
import { join as
|
|
125636
|
+
import { join as join91 } from "path";
|
|
125372
125637
|
|
|
125373
125638
|
// src/features/background-agent/remove-task-toast-tracking.ts
|
|
125374
125639
|
function removeTaskToastTracking(taskId) {
|
|
@@ -127022,7 +127287,7 @@ ${originalText}`;
|
|
|
127022
127287
|
parentSessionID: task.parentSessionID
|
|
127023
127288
|
});
|
|
127024
127289
|
}
|
|
127025
|
-
const messageDir =
|
|
127290
|
+
const messageDir = join91(MESSAGE_STORAGE, task.parentSessionID);
|
|
127026
127291
|
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionID) : null;
|
|
127027
127292
|
agent = currentMessage?.agent ?? task.parentAgent;
|
|
127028
127293
|
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
@@ -127350,11 +127615,11 @@ ${originalText}`;
|
|
|
127350
127615
|
}
|
|
127351
127616
|
}
|
|
127352
127617
|
// src/features/mcp-oauth/storage.ts
|
|
127353
|
-
import { chmodSync as chmodSync2, existsSync as existsSync82, mkdirSync as mkdirSync17, readFileSync as
|
|
127354
|
-
import { dirname as dirname29, join as
|
|
127618
|
+
import { chmodSync as chmodSync2, existsSync as existsSync82, mkdirSync as mkdirSync17, readFileSync as readFileSync55, unlinkSync as unlinkSync13, writeFileSync as writeFileSync22 } from "fs";
|
|
127619
|
+
import { dirname as dirname29, join as join92 } from "path";
|
|
127355
127620
|
var STORAGE_FILE_NAME = "mcp-oauth.json";
|
|
127356
127621
|
function getMcpOauthStoragePath() {
|
|
127357
|
-
return
|
|
127622
|
+
return join92(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
|
|
127358
127623
|
}
|
|
127359
127624
|
function normalizeHost(serverHost) {
|
|
127360
127625
|
let host = serverHost.trim();
|
|
@@ -127395,7 +127660,7 @@ function readStore() {
|
|
|
127395
127660
|
return null;
|
|
127396
127661
|
}
|
|
127397
127662
|
try {
|
|
127398
|
-
const content =
|
|
127663
|
+
const content = readFileSync55(filePath, "utf-8");
|
|
127399
127664
|
return JSON.parse(content);
|
|
127400
127665
|
} catch {
|
|
127401
127666
|
return null;
|
|
@@ -133900,18 +134165,18 @@ class TmuxSessionManager {
|
|
|
133900
134165
|
var SESSION_TIMEOUT_MS3 = 10 * 60 * 1000;
|
|
133901
134166
|
var MIN_STABILITY_TIME_MS4 = 10 * 1000;
|
|
133902
134167
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
133903
|
-
import { existsSync as existsSync83, readFileSync as
|
|
133904
|
-
import { join as
|
|
134168
|
+
import { existsSync as existsSync83, readFileSync as readFileSync56 } from "fs";
|
|
134169
|
+
import { join as join93 } from "path";
|
|
133905
134170
|
import { homedir as homedir15 } from "os";
|
|
133906
134171
|
init_logger();
|
|
133907
134172
|
function getMcpConfigPaths() {
|
|
133908
134173
|
const claudeConfigDir = getClaudeConfigDir();
|
|
133909
134174
|
const cwd = process.cwd();
|
|
133910
134175
|
return [
|
|
133911
|
-
{ path:
|
|
133912
|
-
{ path:
|
|
133913
|
-
{ path:
|
|
133914
|
-
{ path:
|
|
134176
|
+
{ path: join93(homedir15(), ".claude.json"), scope: "user" },
|
|
134177
|
+
{ path: join93(claudeConfigDir, ".mcp.json"), scope: "user" },
|
|
134178
|
+
{ path: join93(cwd, ".mcp.json"), scope: "project" },
|
|
134179
|
+
{ path: join93(cwd, ".claude", ".mcp.json"), scope: "local" }
|
|
133915
134180
|
];
|
|
133916
134181
|
}
|
|
133917
134182
|
async function loadMcpConfigFile(filePath) {
|
|
@@ -133934,7 +134199,7 @@ function getSystemMcpServerNames() {
|
|
|
133934
134199
|
if (!existsSync83(path13))
|
|
133935
134200
|
continue;
|
|
133936
134201
|
try {
|
|
133937
|
-
const content =
|
|
134202
|
+
const content = readFileSync56(path13, "utf-8");
|
|
133938
134203
|
const config4 = JSON.parse(content);
|
|
133939
134204
|
if (!config4?.mcpServers)
|
|
133940
134205
|
continue;
|
|
@@ -138984,7 +139249,7 @@ function buildHephaestusPrompt3(availableAgents = [], availableTools = [], avail
|
|
|
138984
139249
|
const librarianSection = buildLibrarianSection(availableAgents);
|
|
138985
139250
|
const categorySkillsGuide = buildCategorySkillsDelegationGuide(availableCategories, availableSkills);
|
|
138986
139251
|
const delegationTable = buildDelegationTable(availableAgents);
|
|
138987
|
-
const
|
|
139252
|
+
const hasOracle = availableAgents.some((agent) => agent.name === "oracle");
|
|
138988
139253
|
const hardBlocks = buildHardBlocksSection();
|
|
138989
139254
|
const antiPatterns = buildAntiPatternsSection();
|
|
138990
139255
|
const antiDuplication = buildAntiDuplicationSection();
|
|
@@ -139193,8 +139458,23 @@ Every \`task()\` returns a session_id. Use it for all follow-ups:
|
|
|
139193
139458
|
|
|
139194
139459
|
This preserves full context, avoids repeated exploration, saves 70%+ tokens.
|
|
139195
139460
|
</session_continuity>
|
|
139196
|
-
${
|
|
139197
|
-
|
|
139461
|
+
${hasOracle ? `
|
|
139462
|
+
<oracle>
|
|
139463
|
+
Oracle is a read-only reasoning model, available as a last-resort escalation path when you are genuinely stuck.
|
|
139464
|
+
|
|
139465
|
+
Consult Oracle only when:
|
|
139466
|
+
- You have tried 2+ materially different approaches and all failed
|
|
139467
|
+
- You have documented what you tried and why each approach failed
|
|
139468
|
+
- The problem requires architectural insight beyond what codebase exploration provides
|
|
139469
|
+
|
|
139470
|
+
Do not consult Oracle:
|
|
139471
|
+
- Before attempting the fix yourself (try first, escalate later)
|
|
139472
|
+
- For questions answerable from code you have already read
|
|
139473
|
+
- For routine decisions, even complex ones you can reason through
|
|
139474
|
+
- On your first or second attempt at any task
|
|
139475
|
+
|
|
139476
|
+
If you do consult Oracle, announce "Consulting Oracle for [reason]" before invocation. Collect Oracle results before your final answer. Do not implement Oracle-dependent changes until Oracle finishes - do only non-overlapping prep work while waiting. Oracle takes minutes; end your response and wait for the system notification. Never poll, never cancel Oracle.
|
|
139477
|
+
</oracle>` : ""}
|
|
139198
139478
|
</delegation>`;
|
|
139199
139479
|
const communicationBlock = `<communication>
|
|
139200
139480
|
Your output is the one part the user actually sees. Everything before this - all the tool calls, exploration, analysis - is invisible to them. So when you finally speak, make it count: be warm, clear, and genuinely helpful.
|
|
@@ -139286,7 +139566,7 @@ function createHephaestusAgent2(model, availableAgents, availableToolNames, avai
|
|
|
139286
139566
|
}
|
|
139287
139567
|
createHephaestusAgent2.mode = MODE10;
|
|
139288
139568
|
// src/agents/builtin-agents/resolve-file-uri.ts
|
|
139289
|
-
import { existsSync as existsSync84, readFileSync as
|
|
139569
|
+
import { existsSync as existsSync84, readFileSync as readFileSync57 } from "fs";
|
|
139290
139570
|
import { homedir as homedir16 } from "os";
|
|
139291
139571
|
import { isAbsolute as isAbsolute12, resolve as resolve20 } from "path";
|
|
139292
139572
|
init_logger();
|
|
@@ -139315,7 +139595,7 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
139315
139595
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
139316
139596
|
}
|
|
139317
139597
|
try {
|
|
139318
|
-
return
|
|
139598
|
+
return readFileSync57(filePath, "utf8");
|
|
139319
139599
|
} catch {
|
|
139320
139600
|
return `[WARNING: Could not read file: ${promptAppend}]`;
|
|
139321
139601
|
}
|
|
@@ -140538,8 +140818,8 @@ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, dir
|
|
|
140538
140818
|
return result;
|
|
140539
140819
|
}
|
|
140540
140820
|
// src/features/claude-code-agent-loader/loader.ts
|
|
140541
|
-
import { existsSync as existsSync85, readdirSync as
|
|
140542
|
-
import { join as
|
|
140821
|
+
import { existsSync as existsSync85, readdirSync as readdirSync24, readFileSync as readFileSync58 } from "fs";
|
|
140822
|
+
import { join as join94, basename as basename14 } from "path";
|
|
140543
140823
|
function parseToolsConfig2(toolsStr) {
|
|
140544
140824
|
if (!toolsStr)
|
|
140545
140825
|
return;
|
|
@@ -140556,15 +140836,15 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
140556
140836
|
if (!existsSync85(agentsDir)) {
|
|
140557
140837
|
return [];
|
|
140558
140838
|
}
|
|
140559
|
-
const entries =
|
|
140839
|
+
const entries = readdirSync24(agentsDir, { withFileTypes: true });
|
|
140560
140840
|
const agents = [];
|
|
140561
140841
|
for (const entry of entries) {
|
|
140562
140842
|
if (!isMarkdownFile(entry))
|
|
140563
140843
|
continue;
|
|
140564
|
-
const agentPath =
|
|
140844
|
+
const agentPath = join94(agentsDir, entry.name);
|
|
140565
140845
|
const agentName = basename14(entry.name, ".md");
|
|
140566
140846
|
try {
|
|
140567
|
-
const content =
|
|
140847
|
+
const content = readFileSync58(agentPath, "utf-8");
|
|
140568
140848
|
const { data, body } = parseFrontmatter(content);
|
|
140569
140849
|
const name = data.name || agentName;
|
|
140570
140850
|
const originalDescription = data.description || "";
|
|
@@ -140594,7 +140874,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
140594
140874
|
return agents;
|
|
140595
140875
|
}
|
|
140596
140876
|
function loadUserAgents() {
|
|
140597
|
-
const userAgentsDir =
|
|
140877
|
+
const userAgentsDir = join94(getClaudeConfigDir(), "agents");
|
|
140598
140878
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
140599
140879
|
const result = {};
|
|
140600
140880
|
for (const agent of agents) {
|
|
@@ -140603,7 +140883,7 @@ function loadUserAgents() {
|
|
|
140603
140883
|
return result;
|
|
140604
140884
|
}
|
|
140605
140885
|
function loadProjectAgents(directory) {
|
|
140606
|
-
const projectAgentsDir =
|
|
140886
|
+
const projectAgentsDir = join94(directory ?? process.cwd(), ".claude", "agents");
|
|
140607
140887
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
140608
140888
|
const result = {};
|
|
140609
140889
|
for (const agent of agents) {
|
|
@@ -143093,7 +143373,7 @@ async function applyAgentConfig(params) {
|
|
|
143093
143373
|
}
|
|
143094
143374
|
// src/features/claude-code-command-loader/loader.ts
|
|
143095
143375
|
import { promises as fs19 } from "fs";
|
|
143096
|
-
import { join as
|
|
143376
|
+
import { join as join95, basename as basename15 } from "path";
|
|
143097
143377
|
init_logger();
|
|
143098
143378
|
async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix = "") {
|
|
143099
143379
|
try {
|
|
@@ -143124,7 +143404,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
143124
143404
|
if (entry.isDirectory()) {
|
|
143125
143405
|
if (entry.name.startsWith("."))
|
|
143126
143406
|
continue;
|
|
143127
|
-
const subDirPath =
|
|
143407
|
+
const subDirPath = join95(commandsDir, entry.name);
|
|
143128
143408
|
const subPrefix = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
143129
143409
|
const subCommands = await loadCommandsFromDir(subDirPath, scope, visited, subPrefix);
|
|
143130
143410
|
commands3.push(...subCommands);
|
|
@@ -143132,7 +143412,7 @@ async function loadCommandsFromDir(commandsDir, scope, visited = new Set, prefix
|
|
|
143132
143412
|
}
|
|
143133
143413
|
if (!isMarkdownFile(entry))
|
|
143134
143414
|
continue;
|
|
143135
|
-
const commandPath =
|
|
143415
|
+
const commandPath = join95(commandsDir, entry.name);
|
|
143136
143416
|
const baseCommandName = basename15(entry.name, ".md");
|
|
143137
143417
|
const commandName = prefix ? `${prefix}/${baseCommandName}` : baseCommandName;
|
|
143138
143418
|
try {
|
|
@@ -143191,12 +143471,12 @@ function commandsToRecord(commands3) {
|
|
|
143191
143471
|
return result;
|
|
143192
143472
|
}
|
|
143193
143473
|
async function loadUserCommands() {
|
|
143194
|
-
const userCommandsDir =
|
|
143474
|
+
const userCommandsDir = join95(getClaudeConfigDir(), "commands");
|
|
143195
143475
|
const commands3 = await loadCommandsFromDir(userCommandsDir, "user");
|
|
143196
143476
|
return commandsToRecord(commands3);
|
|
143197
143477
|
}
|
|
143198
143478
|
async function loadProjectCommands(directory) {
|
|
143199
|
-
const projectCommandsDir =
|
|
143479
|
+
const projectCommandsDir = join95(directory ?? process.cwd(), ".claude", "commands");
|
|
143200
143480
|
const commands3 = await loadCommandsFromDir(projectCommandsDir, "project");
|
|
143201
143481
|
return commandsToRecord(commands3);
|
|
143202
143482
|
}
|
|
@@ -144182,10 +144462,10 @@ function createChatHeadersHandler(args) {
|
|
|
144182
144462
|
|
|
144183
144463
|
// src/plugin/ultrawork-db-model-override.ts
|
|
144184
144464
|
import { Database } from "bun:sqlite";
|
|
144185
|
-
import { join as
|
|
144465
|
+
import { join as join96 } from "path";
|
|
144186
144466
|
import { existsSync as existsSync86 } from "fs";
|
|
144187
144467
|
function getDbPath() {
|
|
144188
|
-
return
|
|
144468
|
+
return join96(getDataDir(), "opencode", "opencode.db");
|
|
144189
144469
|
}
|
|
144190
144470
|
var MAX_MICROTASK_RETRIES = 10;
|
|
144191
144471
|
function tryUpdateMessageModel(db, messageId, targetModel, variant) {
|
|
@@ -144736,7 +145016,7 @@ function applyUserConfiguredFallbackChain(sessionID, agentName, currentProviderI
|
|
|
144736
145016
|
setSessionFallbackChain(sessionID, fallbackChain);
|
|
144737
145017
|
}
|
|
144738
145018
|
}
|
|
144739
|
-
function
|
|
145019
|
+
function isCompactionAgent6(agent) {
|
|
144740
145020
|
return agent.toLowerCase() === "compaction";
|
|
144741
145021
|
}
|
|
144742
145022
|
function createEventHandler2(args) {
|
|
@@ -144941,7 +145221,7 @@ function createEventHandler2(args) {
|
|
|
144941
145221
|
const agent = info?.agent;
|
|
144942
145222
|
const role = info?.role;
|
|
144943
145223
|
if (sessionID && role === "user") {
|
|
144944
|
-
const isCompactionMessage = agent ?
|
|
145224
|
+
const isCompactionMessage = agent ? isCompactionAgent6(agent) : false;
|
|
144945
145225
|
if (agent && !isCompactionMessage) {
|
|
144946
145226
|
updateSessionAgent(sessionID, agent);
|
|
144947
145227
|
}
|