@charzhu/openjaw-agent 0.3.0 → 0.3.1
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/README.md +10 -0
- package/config.yaml +15 -0
- package/dist/main.js +1322 -326
- package/dist/main.js.map +4 -4
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -137,7 +137,11 @@ function loadAgentConfig() {
|
|
|
137
137
|
feishu: parsed?.feishu ?? void 0,
|
|
138
138
|
wechat: parsed?.wechat ?? void 0,
|
|
139
139
|
features: {
|
|
140
|
-
skill_auto_suggest: parsed?.features?.skill_auto_suggest ?? true
|
|
140
|
+
skill_auto_suggest: parsed?.features?.skill_auto_suggest ?? true,
|
|
141
|
+
dynamic_workflows: {
|
|
142
|
+
...DEFAULT_DYNAMIC_WORKFLOWS,
|
|
143
|
+
...parsed?.features?.dynamic_workflows ?? {}
|
|
144
|
+
}
|
|
141
145
|
}
|
|
142
146
|
};
|
|
143
147
|
if (config.llm.provider === "anthropic") {
|
|
@@ -199,12 +203,20 @@ function updateBridgeConfig(name, values) {
|
|
|
199
203
|
);
|
|
200
204
|
return next;
|
|
201
205
|
}
|
|
202
|
-
var DEFAULT_COPILOT_OAUTH_CLIENT_ID, DEFAULT_CONFIG, configWriteChain;
|
|
206
|
+
var DEFAULT_COPILOT_OAUTH_CLIENT_ID, DEFAULT_DYNAMIC_WORKFLOWS, DEFAULT_CONFIG, configWriteChain;
|
|
203
207
|
var init_config = __esm({
|
|
204
208
|
"src/config.ts"() {
|
|
205
209
|
"use strict";
|
|
206
210
|
init_packageRoot();
|
|
207
211
|
DEFAULT_COPILOT_OAUTH_CLIENT_ID = "Iv1.b507a08c87ecfe98";
|
|
212
|
+
DEFAULT_DYNAMIC_WORKFLOWS = {
|
|
213
|
+
enabled: true,
|
|
214
|
+
planner_mode: "adaptive",
|
|
215
|
+
hard_max_workers: 1024,
|
|
216
|
+
hard_max_concurrent_workers: 128,
|
|
217
|
+
worker_timeout_ms: 18e4,
|
|
218
|
+
persist_history: true
|
|
219
|
+
};
|
|
208
220
|
DEFAULT_CONFIG = {
|
|
209
221
|
llm: {
|
|
210
222
|
provider: "anthropic",
|
|
@@ -856,7 +868,7 @@ Start-Sleep -Milliseconds 50
|
|
|
856
868
|
}
|
|
857
869
|
}
|
|
858
870
|
async function wait(duration) {
|
|
859
|
-
await new Promise((
|
|
871
|
+
await new Promise((resolve6) => setTimeout(resolve6, duration * 1e3));
|
|
860
872
|
return { output: `Waited ${duration} seconds` };
|
|
861
873
|
}
|
|
862
874
|
function getDisplayDimensions() {
|
|
@@ -2551,7 +2563,7 @@ var init_copilot = __esm({
|
|
|
2551
2563
|
handshakeTimeout: RESPONSES_WEBSOCKET_CONNECT_TIMEOUT_MS
|
|
2552
2564
|
});
|
|
2553
2565
|
const request = JSON.stringify(this.buildResponsesWebSocketRequest(requestBody));
|
|
2554
|
-
return new Promise((
|
|
2566
|
+
return new Promise((resolve6, reject) => {
|
|
2555
2567
|
const accumulator = { sawTextDelta: false, text: null, toolCalls: [] };
|
|
2556
2568
|
let settled = false;
|
|
2557
2569
|
const timeout = setTimeout(() => {
|
|
@@ -2565,7 +2577,7 @@ var init_copilot = __esm({
|
|
|
2565
2577
|
settled = true;
|
|
2566
2578
|
clearTimeout(timeout);
|
|
2567
2579
|
ws.close();
|
|
2568
|
-
|
|
2580
|
+
resolve6(value);
|
|
2569
2581
|
}, "finish");
|
|
2570
2582
|
const fail = /* @__PURE__ */ __name((error) => {
|
|
2571
2583
|
if (settled) return;
|
|
@@ -5472,18 +5484,18 @@ ${summary}
|
|
|
5472
5484
|
content: parsed.question,
|
|
5473
5485
|
choices: parsed.choices ?? void 0
|
|
5474
5486
|
};
|
|
5475
|
-
const userResponse = await new Promise((
|
|
5487
|
+
const userResponse = await new Promise((resolve6) => {
|
|
5476
5488
|
if (this._pendingAskUserResponse !== null) {
|
|
5477
5489
|
const buffered = this._pendingAskUserResponse;
|
|
5478
5490
|
this._pendingAskUserResponse = null;
|
|
5479
|
-
|
|
5491
|
+
resolve6(buffered);
|
|
5480
5492
|
return;
|
|
5481
5493
|
}
|
|
5482
|
-
this._askUserResolver =
|
|
5494
|
+
this._askUserResolver = resolve6;
|
|
5483
5495
|
setTimeout(() => {
|
|
5484
|
-
if (this._askUserResolver ===
|
|
5496
|
+
if (this._askUserResolver === resolve6) {
|
|
5485
5497
|
this._askUserResolver = null;
|
|
5486
|
-
|
|
5498
|
+
resolve6("[No response from user \u2014 timed out after 5 minutes]");
|
|
5487
5499
|
}
|
|
5488
5500
|
}, 5 * 60 * 1e3);
|
|
5489
5501
|
});
|
|
@@ -6146,7 +6158,7 @@ var init_browser = __esm({
|
|
|
6146
6158
|
await Page.domContentEventFired();
|
|
6147
6159
|
} else if (options.waitFor === "networkidle") {
|
|
6148
6160
|
await Page.loadEventFired();
|
|
6149
|
-
await new Promise((
|
|
6161
|
+
await new Promise((resolve6) => setTimeout(resolve6, 1e3));
|
|
6150
6162
|
}
|
|
6151
6163
|
const result = await Runtime.evaluate({
|
|
6152
6164
|
expression: "document.title"
|
|
@@ -6917,7 +6929,7 @@ var init_browser = __esm({
|
|
|
6917
6929
|
if (exists) {
|
|
6918
6930
|
return true;
|
|
6919
6931
|
}
|
|
6920
|
-
await new Promise((
|
|
6932
|
+
await new Promise((resolve6) => setTimeout(resolve6, 200));
|
|
6921
6933
|
}
|
|
6922
6934
|
return false;
|
|
6923
6935
|
}
|
|
@@ -7145,10 +7157,10 @@ function createBrowseTools(config, sharedBrowser) {
|
|
|
7145
7157
|
}
|
|
7146
7158
|
},
|
|
7147
7159
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
7148
|
-
const { join:
|
|
7160
|
+
const { join: join48 } = await import("node:path");
|
|
7149
7161
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
7150
|
-
const { randomUUID:
|
|
7151
|
-
const screenshotPath =
|
|
7162
|
+
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
7163
|
+
const screenshotPath = join48(tmpdir13(), `openjaw-browser-${randomUUID15().slice(0, 8)}.png`);
|
|
7152
7164
|
const screenshot = await browser.screenshot({ fullPage: false, path: screenshotPath });
|
|
7153
7165
|
const snapshot = await browser.snapshot({ full: false });
|
|
7154
7166
|
return {
|
|
@@ -7843,7 +7855,7 @@ var init_outlook_desktop = __esm({
|
|
|
7843
7855
|
}
|
|
7844
7856
|
}
|
|
7845
7857
|
sleep(ms) {
|
|
7846
|
-
return new Promise((
|
|
7858
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
7847
7859
|
}
|
|
7848
7860
|
};
|
|
7849
7861
|
}
|
|
@@ -8441,7 +8453,7 @@ var init_outlook_web = __esm({
|
|
|
8441
8453
|
await this.browser.typeChars(text);
|
|
8442
8454
|
}
|
|
8443
8455
|
sleep(ms) {
|
|
8444
|
-
return new Promise((
|
|
8456
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
8445
8457
|
}
|
|
8446
8458
|
};
|
|
8447
8459
|
}
|
|
@@ -8675,8 +8687,8 @@ var init_token_pool = __esm({
|
|
|
8675
8687
|
if (!existsSync8(legacyDir))
|
|
8676
8688
|
return;
|
|
8677
8689
|
try {
|
|
8678
|
-
const { readdirSync:
|
|
8679
|
-
const files =
|
|
8690
|
+
const { readdirSync: readdirSync8 } = __require("node:fs");
|
|
8691
|
+
const files = readdirSync8(legacyDir);
|
|
8680
8692
|
for (const file2 of files) {
|
|
8681
8693
|
if (!file2.endsWith(".json"))
|
|
8682
8694
|
continue;
|
|
@@ -8856,7 +8868,7 @@ var init_cdp_token_extractor = __esm({
|
|
|
8856
8868
|
}
|
|
8857
8869
|
logger_default.info("CDP: reloading tab for token refresh", { url: targetTab.url, audience });
|
|
8858
8870
|
await this.reloadTab(targetTab);
|
|
8859
|
-
await new Promise((
|
|
8871
|
+
await new Promise((resolve6) => setTimeout(resolve6, PAGE_RELOAD_WAIT_MS));
|
|
8860
8872
|
if (!targetTab.webSocketDebuggerUrl)
|
|
8861
8873
|
return [];
|
|
8862
8874
|
const freshPages = await this.listPages();
|
|
@@ -8973,19 +8985,19 @@ var init_cdp_token_extractor = __esm({
|
|
|
8973
8985
|
* Evaluate a JS expression in a tab and return the string result.
|
|
8974
8986
|
*/
|
|
8975
8987
|
async evaluateInTab(wsUrl, expression) {
|
|
8976
|
-
return new Promise((
|
|
8988
|
+
return new Promise((resolve6) => {
|
|
8977
8989
|
let ws;
|
|
8978
8990
|
try {
|
|
8979
8991
|
ws = new WebSocket(wsUrl);
|
|
8980
8992
|
} catch (err) {
|
|
8981
8993
|
logger_default.warn("CDP: WebSocket constructor failed", { wsUrl: wsUrl.substring(0, 60), error: String(err) });
|
|
8982
|
-
|
|
8994
|
+
resolve6(null);
|
|
8983
8995
|
return;
|
|
8984
8996
|
}
|
|
8985
8997
|
const timer = setTimeout(() => {
|
|
8986
8998
|
logger_default.warn("CDP: evaluateInTab timeout", { wsUrl: wsUrl.substring(0, 60) });
|
|
8987
8999
|
ws.close();
|
|
8988
|
-
|
|
9000
|
+
resolve6(null);
|
|
8989
9001
|
}, CDP_TIMEOUT_MS);
|
|
8990
9002
|
ws.on("open", () => {
|
|
8991
9003
|
ws.send(JSON.stringify({
|
|
@@ -8999,18 +9011,18 @@ var init_cdp_token_extractor = __esm({
|
|
|
8999
9011
|
if (resp.id === 1) {
|
|
9000
9012
|
clearTimeout(timer);
|
|
9001
9013
|
ws.close();
|
|
9002
|
-
|
|
9014
|
+
resolve6(resp.result?.result?.value ?? null);
|
|
9003
9015
|
}
|
|
9004
9016
|
});
|
|
9005
9017
|
ws.on("error", (err) => {
|
|
9006
9018
|
logger_default.warn("CDP: evaluateInTab WS error", { error: String(err), wsUrl: wsUrl.substring(0, 60) });
|
|
9007
9019
|
clearTimeout(timer);
|
|
9008
|
-
|
|
9020
|
+
resolve6(null);
|
|
9009
9021
|
});
|
|
9010
9022
|
});
|
|
9011
9023
|
}
|
|
9012
9024
|
async extractFromTab(wsUrl) {
|
|
9013
|
-
return new Promise((
|
|
9025
|
+
return new Promise((resolve6, reject) => {
|
|
9014
9026
|
const ws = new WebSocket(wsUrl);
|
|
9015
9027
|
const timer = setTimeout(() => {
|
|
9016
9028
|
ws.close();
|
|
@@ -9030,14 +9042,14 @@ var init_cdp_token_extractor = __esm({
|
|
|
9030
9042
|
ws.close();
|
|
9031
9043
|
const value = resp.result?.result?.value;
|
|
9032
9044
|
if (!value) {
|
|
9033
|
-
|
|
9045
|
+
resolve6([]);
|
|
9034
9046
|
return;
|
|
9035
9047
|
}
|
|
9036
9048
|
try {
|
|
9037
9049
|
const tokens = JSON.parse(value);
|
|
9038
|
-
|
|
9050
|
+
resolve6(tokens);
|
|
9039
9051
|
} catch {
|
|
9040
|
-
|
|
9052
|
+
resolve6([]);
|
|
9041
9053
|
}
|
|
9042
9054
|
}
|
|
9043
9055
|
});
|
|
@@ -9053,11 +9065,11 @@ var init_cdp_token_extractor = __esm({
|
|
|
9053
9065
|
async reloadTab(page) {
|
|
9054
9066
|
if (!page.webSocketDebuggerUrl)
|
|
9055
9067
|
return;
|
|
9056
|
-
return new Promise((
|
|
9068
|
+
return new Promise((resolve6, reject) => {
|
|
9057
9069
|
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
9058
9070
|
const timer = setTimeout(() => {
|
|
9059
9071
|
ws.close();
|
|
9060
|
-
|
|
9072
|
+
resolve6();
|
|
9061
9073
|
}, 1e4);
|
|
9062
9074
|
ws.on("open", () => {
|
|
9063
9075
|
ws.send(JSON.stringify({
|
|
@@ -9071,7 +9083,7 @@ var init_cdp_token_extractor = __esm({
|
|
|
9071
9083
|
if (resp.id === 1) {
|
|
9072
9084
|
clearTimeout(timer);
|
|
9073
9085
|
ws.close();
|
|
9074
|
-
|
|
9086
|
+
resolve6();
|
|
9075
9087
|
}
|
|
9076
9088
|
});
|
|
9077
9089
|
ws.on("error", (err) => {
|
|
@@ -10732,13 +10744,13 @@ function createMemoryTools(config) {
|
|
|
10732
10744
|
const todos = input.todos;
|
|
10733
10745
|
try {
|
|
10734
10746
|
const { appendFile: appendFile2, mkdir: mkdir5 } = await import("node:fs/promises");
|
|
10735
|
-
const { existsSync:
|
|
10736
|
-
const { join:
|
|
10737
|
-
const { homedir:
|
|
10738
|
-
const memoryDir =
|
|
10739
|
-
if (!
|
|
10747
|
+
const { existsSync: existsSync34 } = await import("node:fs");
|
|
10748
|
+
const { join: join48 } = await import("node:path");
|
|
10749
|
+
const { homedir: homedir32 } = await import("node:os");
|
|
10750
|
+
const memoryDir = join48(homedir32(), ".openjaw", "memory");
|
|
10751
|
+
if (!existsSync34(memoryDir))
|
|
10740
10752
|
await mkdir5(memoryDir, { recursive: true });
|
|
10741
|
-
const todoPath =
|
|
10753
|
+
const todoPath = join48(memoryDir, "TODOS.md");
|
|
10742
10754
|
const { writeFile: writeFile5 } = await import("node:fs/promises");
|
|
10743
10755
|
await writeFile5(todoPath, `# Session Todos
|
|
10744
10756
|
|
|
@@ -12059,7 +12071,7 @@ var init_teams_desktop = __esm({
|
|
|
12059
12071
|
}
|
|
12060
12072
|
}
|
|
12061
12073
|
sleep(ms) {
|
|
12062
|
-
return new Promise((
|
|
12074
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
12063
12075
|
}
|
|
12064
12076
|
/**
|
|
12065
12077
|
* Get the current Teams window state
|
|
@@ -12926,7 +12938,7 @@ var init_teams_web = __esm({
|
|
|
12926
12938
|
}
|
|
12927
12939
|
}
|
|
12928
12940
|
sleep(ms) {
|
|
12929
|
-
return new Promise((
|
|
12941
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
12930
12942
|
}
|
|
12931
12943
|
};
|
|
12932
12944
|
}
|
|
@@ -14324,7 +14336,7 @@ var init_teams_chat_monitor = __esm({
|
|
|
14324
14336
|
return this.sentMessages.has(normalized);
|
|
14325
14337
|
}
|
|
14326
14338
|
sleep(ms) {
|
|
14327
|
-
return new Promise((
|
|
14339
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
14328
14340
|
}
|
|
14329
14341
|
/**
|
|
14330
14342
|
* Attempt to reconnect the browser after detecting a disconnection.
|
|
@@ -15111,7 +15123,7 @@ ${lines.join("\n")}`;
|
|
|
15111
15123
|
globalThis.__teamsSeenMessages.set(chatName, seenIds);
|
|
15112
15124
|
}
|
|
15113
15125
|
if (syncMode) {
|
|
15114
|
-
return new Promise((
|
|
15126
|
+
return new Promise((resolve6) => {
|
|
15115
15127
|
const timer2 = setInterval(async () => {
|
|
15116
15128
|
try {
|
|
15117
15129
|
const current = await channel.readCurrentChatMessages();
|
|
@@ -15120,7 +15132,7 @@ ${lines.join("\n")}`;
|
|
|
15120
15132
|
if (!seenIds.has(msgId) && msg.sender !== currentUserName) {
|
|
15121
15133
|
clearInterval(timer2);
|
|
15122
15134
|
seenIds.add(msgId);
|
|
15123
|
-
|
|
15135
|
+
resolve6({
|
|
15124
15136
|
success: true,
|
|
15125
15137
|
channel: channelType,
|
|
15126
15138
|
sync: true,
|
|
@@ -15197,7 +15209,7 @@ ${lines.join("\n")}`;
|
|
|
15197
15209
|
globalThis.__teamsSeenMessages.set(chatName, seenIds);
|
|
15198
15210
|
}
|
|
15199
15211
|
if (syncMode) {
|
|
15200
|
-
return new Promise((
|
|
15212
|
+
return new Promise((resolve6) => {
|
|
15201
15213
|
const timer2 = setInterval(async () => {
|
|
15202
15214
|
try {
|
|
15203
15215
|
const current = await channel.readCurrentChatMessages();
|
|
@@ -15206,7 +15218,7 @@ ${lines.join("\n")}`;
|
|
|
15206
15218
|
if (!seenIds.has(msgId) && msg.sender !== currentUserName) {
|
|
15207
15219
|
clearInterval(timer2);
|
|
15208
15220
|
seenIds.add(msgId);
|
|
15209
|
-
|
|
15221
|
+
resolve6({
|
|
15210
15222
|
success: true,
|
|
15211
15223
|
channel: channelType,
|
|
15212
15224
|
sync: true,
|
|
@@ -15564,7 +15576,7 @@ ${lines.join("\n")}`;
|
|
|
15564
15576
|
return allTools;
|
|
15565
15577
|
}
|
|
15566
15578
|
function sleep2(ms) {
|
|
15567
|
-
return new Promise((
|
|
15579
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
15568
15580
|
}
|
|
15569
15581
|
var MAX_STORED_ENTRIES, ENTRY_TTL_MS;
|
|
15570
15582
|
var init_chat = __esm({
|
|
@@ -16388,11 +16400,11 @@ function createShellTools(_config, hooks) {
|
|
|
16388
16400
|
const shell = input.shell ?? true;
|
|
16389
16401
|
if (input.background) {
|
|
16390
16402
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
16391
|
-
const { join:
|
|
16392
|
-
const { randomUUID:
|
|
16403
|
+
const { join: join48 } = await import("node:path");
|
|
16404
|
+
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
16393
16405
|
const { createWriteStream: createWriteStream2 } = await import("node:fs");
|
|
16394
|
-
const taskId =
|
|
16395
|
-
const outputPath =
|
|
16406
|
+
const taskId = randomUUID15().slice(0, 8);
|
|
16407
|
+
const outputPath = join48(tmpdir13(), `oj-bg-${taskId}.log`);
|
|
16396
16408
|
const detached = spawn(command, [], {
|
|
16397
16409
|
shell,
|
|
16398
16410
|
cwd,
|
|
@@ -16412,7 +16424,7 @@ function createShellTools(_config, hooks) {
|
|
|
16412
16424
|
message: `Command started in background (PID: ${detached.pid}). Output: ${outputPath}`
|
|
16413
16425
|
};
|
|
16414
16426
|
}
|
|
16415
|
-
return new Promise((
|
|
16427
|
+
return new Promise((resolve6) => {
|
|
16416
16428
|
const proc = spawn(command, [], {
|
|
16417
16429
|
shell,
|
|
16418
16430
|
cwd,
|
|
@@ -16430,7 +16442,7 @@ function createShellTools(_config, hooks) {
|
|
|
16430
16442
|
proc.on("close", (code) => {
|
|
16431
16443
|
const stdoutResult = truncateOutput(stdout.trim());
|
|
16432
16444
|
const stderrResult = truncateOutput(stderr.trim());
|
|
16433
|
-
|
|
16445
|
+
resolve6({
|
|
16434
16446
|
command,
|
|
16435
16447
|
exitCode: code,
|
|
16436
16448
|
stdout: stdoutResult.text,
|
|
@@ -16441,7 +16453,7 @@ function createShellTools(_config, hooks) {
|
|
|
16441
16453
|
});
|
|
16442
16454
|
});
|
|
16443
16455
|
proc.on("error", (error) => {
|
|
16444
|
-
|
|
16456
|
+
resolve6({
|
|
16445
16457
|
command,
|
|
16446
16458
|
exitCode: -1,
|
|
16447
16459
|
stdout: "",
|
|
@@ -16475,10 +16487,10 @@ function createShellTools(_config, hooks) {
|
|
|
16475
16487
|
},
|
|
16476
16488
|
requiresConfirmation: false,
|
|
16477
16489
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16478
|
-
const { writeFileSync:
|
|
16479
|
-
const { join:
|
|
16490
|
+
const { writeFileSync: writeFileSync23, unlinkSync: unlinkSync9 } = await import("node:fs");
|
|
16491
|
+
const { join: join48 } = await import("node:path");
|
|
16480
16492
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
16481
|
-
const { randomUUID:
|
|
16493
|
+
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
16482
16494
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
16483
16495
|
const code = input.code;
|
|
16484
16496
|
const language = input.language;
|
|
@@ -16495,14 +16507,14 @@ function createShellTools(_config, hooks) {
|
|
|
16495
16507
|
const interpreter = interpreterMap[language];
|
|
16496
16508
|
if (!interpreter)
|
|
16497
16509
|
return { error: `Unsupported language: ${language}` };
|
|
16498
|
-
const tmpFile =
|
|
16510
|
+
const tmpFile = join48(tmpdir13(), `oj-code-${randomUUID15().slice(0, 8)}${ext}`);
|
|
16499
16511
|
try {
|
|
16500
|
-
|
|
16512
|
+
writeFileSync23(tmpFile, code, "utf-8");
|
|
16501
16513
|
const startTime = Date.now();
|
|
16502
|
-
const result = await new Promise((
|
|
16514
|
+
const result = await new Promise((resolve6) => {
|
|
16503
16515
|
execFile3(interpreter.cmd, [...interpreter.args, tmpFile], { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout2, stderr2) => {
|
|
16504
16516
|
const exitCode = error ? typeof error.code === "number" ? error.code : 1 : 0;
|
|
16505
|
-
|
|
16517
|
+
resolve6({ exitCode, stdout: stdout2 ?? "", stderr: stderr2 ?? "" });
|
|
16506
16518
|
});
|
|
16507
16519
|
});
|
|
16508
16520
|
const executionTimeMs = Date.now() - startTime;
|
|
@@ -16595,7 +16607,7 @@ function createShellTools(_config, hooks) {
|
|
|
16595
16607
|
required: ["title", "message"]
|
|
16596
16608
|
},
|
|
16597
16609
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16598
|
-
return new Promise((
|
|
16610
|
+
return new Promise((resolve6) => {
|
|
16599
16611
|
notifier.notify({
|
|
16600
16612
|
title: input.title,
|
|
16601
16613
|
message: input.message,
|
|
@@ -16603,9 +16615,9 @@ function createShellTools(_config, hooks) {
|
|
|
16603
16615
|
sound: true
|
|
16604
16616
|
}, (err) => {
|
|
16605
16617
|
if (err) {
|
|
16606
|
-
|
|
16618
|
+
resolve6({ error: err.message });
|
|
16607
16619
|
} else {
|
|
16608
|
-
|
|
16620
|
+
resolve6({ success: true });
|
|
16609
16621
|
}
|
|
16610
16622
|
});
|
|
16611
16623
|
});
|
|
@@ -16709,7 +16721,7 @@ function createShellTools(_config, hooks) {
|
|
|
16709
16721
|
},
|
|
16710
16722
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16711
16723
|
const seconds = Math.min(Math.max(0.1, input.seconds), 60);
|
|
16712
|
-
await new Promise((
|
|
16724
|
+
await new Promise((resolve6) => setTimeout(resolve6, seconds * 1e3));
|
|
16713
16725
|
return { waited: seconds, message: `Waited ${seconds} seconds` };
|
|
16714
16726
|
}, "execute")
|
|
16715
16727
|
},
|
|
@@ -17821,7 +17833,7 @@ var init_office_desktop = __esm({
|
|
|
17821
17833
|
return Array.isArray(parsed) ? parsed : [parsed];
|
|
17822
17834
|
}
|
|
17823
17835
|
sleep(ms) {
|
|
17824
|
-
return new Promise((
|
|
17836
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
17825
17837
|
}
|
|
17826
17838
|
};
|
|
17827
17839
|
}
|
|
@@ -19502,7 +19514,7 @@ public class Win32Send {
|
|
|
19502
19514
|
}
|
|
19503
19515
|
}
|
|
19504
19516
|
sleep(ms) {
|
|
19505
|
-
return new Promise((
|
|
19517
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
19506
19518
|
}
|
|
19507
19519
|
};
|
|
19508
19520
|
}
|
|
@@ -19567,7 +19579,7 @@ function getActiveMonitors() {
|
|
|
19567
19579
|
return result;
|
|
19568
19580
|
}
|
|
19569
19581
|
function sleep3(ms) {
|
|
19570
|
-
return new Promise((
|
|
19582
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
19571
19583
|
}
|
|
19572
19584
|
async function fileHash(filePath) {
|
|
19573
19585
|
const data = fs.readFileSync(filePath);
|
|
@@ -21040,11 +21052,11 @@ function loadFlatSkillsFromDir(dir2, source, priority, out) {
|
|
|
21040
21052
|
function loadPackagedSkillsFromDir(dir2, out) {
|
|
21041
21053
|
for (const entry of safeReadDir(dir2)) {
|
|
21042
21054
|
if (!entry.isDirectory()) continue;
|
|
21043
|
-
const
|
|
21044
|
-
const entrypoint = findPackageEntrypoint(
|
|
21055
|
+
const rootDir2 = join22(dir2, entry.name);
|
|
21056
|
+
const entrypoint = findPackageEntrypoint(rootDir2);
|
|
21045
21057
|
if (!entrypoint) continue;
|
|
21046
|
-
const filePath = join22(
|
|
21047
|
-
const skill = parseSkillAtPath(filePath,
|
|
21058
|
+
const filePath = join22(rootDir2, entrypoint);
|
|
21059
|
+
const skill = parseSkillAtPath(filePath, rootDir2, entrypoint, "user", `${entry.name}.md`);
|
|
21048
21060
|
if (skill) putSkill(out, skill, 2);
|
|
21049
21061
|
}
|
|
21050
21062
|
}
|
|
@@ -21057,7 +21069,7 @@ function findPackageEntrypoint(dir2) {
|
|
|
21057
21069
|
const markdown = entries.filter((entry) => isMarkdown(entry.name));
|
|
21058
21070
|
return markdown.length === 1 ? markdown[0].name : null;
|
|
21059
21071
|
}
|
|
21060
|
-
function parseSkillAtPath(filePath,
|
|
21072
|
+
function parseSkillAtPath(filePath, rootDir2, entrypoint, source, fallbackFilename) {
|
|
21061
21073
|
try {
|
|
21062
21074
|
const content = readFileSync14(filePath, "utf-8").trim();
|
|
21063
21075
|
if (!content) return null;
|
|
@@ -21068,7 +21080,7 @@ function parseSkillAtPath(filePath, rootDir, entrypoint, source, fallbackFilenam
|
|
|
21068
21080
|
name,
|
|
21069
21081
|
meta: { ...parsed.meta, name },
|
|
21070
21082
|
filePath,
|
|
21071
|
-
rootDir,
|
|
21083
|
+
rootDir: rootDir2,
|
|
21072
21084
|
entrypoint,
|
|
21073
21085
|
source,
|
|
21074
21086
|
hasFrontmatter: parsed.hasFrontmatter
|
|
@@ -21725,12 +21737,12 @@ var init_telegram = __esm({
|
|
|
21725
21737
|
Options: ${chunk.choices.join(" | ")}` : "";
|
|
21726
21738
|
await this.bot.sendMessage(chatId, `\u2753 ${question}${choicesText}`);
|
|
21727
21739
|
updateStatus("\u2753 Waiting for your response...");
|
|
21728
|
-
const userReply = await new Promise((
|
|
21729
|
-
this._pendingReplyResolver =
|
|
21740
|
+
const userReply = await new Promise((resolve6) => {
|
|
21741
|
+
this._pendingReplyResolver = resolve6;
|
|
21730
21742
|
setTimeout(() => {
|
|
21731
|
-
if (this._pendingReplyResolver ===
|
|
21743
|
+
if (this._pendingReplyResolver === resolve6) {
|
|
21732
21744
|
this._pendingReplyResolver = null;
|
|
21733
|
-
|
|
21745
|
+
resolve6("[No response \u2014 timed out]");
|
|
21734
21746
|
}
|
|
21735
21747
|
}, 5 * 60 * 1e3);
|
|
21736
21748
|
});
|
|
@@ -22328,7 +22340,7 @@ async function promptConsent(servers) {
|
|
|
22328
22340
|
input: process.stdin,
|
|
22329
22341
|
output: process.stderr
|
|
22330
22342
|
});
|
|
22331
|
-
const ask = /* @__PURE__ */ __name((question) => new Promise((
|
|
22343
|
+
const ask = /* @__PURE__ */ __name((question) => new Promise((resolve6) => rl.question(question, resolve6)), "ask");
|
|
22332
22344
|
const w = process.stderr.columns || 80;
|
|
22333
22345
|
const inner = w - 4;
|
|
22334
22346
|
const hLine = "\u2500".repeat(inner);
|
|
@@ -24383,7 +24395,7 @@ try {
|
|
|
24383
24395
|
}
|
|
24384
24396
|
`;
|
|
24385
24397
|
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
24386
|
-
return new Promise((
|
|
24398
|
+
return new Promise((resolve6) => {
|
|
24387
24399
|
const proc = spawn3("powershell.exe", ["-NoProfile", "-STA", "-EncodedCommand", encoded], {
|
|
24388
24400
|
stdio: ["pipe", "pipe", "pipe"],
|
|
24389
24401
|
windowsHide: true
|
|
@@ -24398,22 +24410,22 @@ try {
|
|
|
24398
24410
|
});
|
|
24399
24411
|
const timer = setTimeout(() => {
|
|
24400
24412
|
if (!proc.killed) proc.kill();
|
|
24401
|
-
|
|
24413
|
+
resolve6(null);
|
|
24402
24414
|
}, (timeoutSeconds + 5) * 1e3);
|
|
24403
24415
|
proc.on("exit", () => {
|
|
24404
24416
|
clearTimeout(timer);
|
|
24405
24417
|
const output = stdout.replace(/#< CLIXML[\s\S]*/m, "").trim();
|
|
24406
24418
|
if (output === "NO_SPEECH" || output.startsWith("ERROR") || !output) {
|
|
24407
|
-
|
|
24419
|
+
resolve6(null);
|
|
24408
24420
|
return;
|
|
24409
24421
|
}
|
|
24410
24422
|
const parts = output.split("|");
|
|
24411
24423
|
const text = parts[0]?.trim();
|
|
24412
24424
|
const confidence = parseFloat(parts[1] || "0");
|
|
24413
24425
|
if (text) {
|
|
24414
|
-
|
|
24426
|
+
resolve6({ text, confidence: isNaN(confidence) ? 0.5 : confidence });
|
|
24415
24427
|
} else {
|
|
24416
|
-
|
|
24428
|
+
resolve6(null);
|
|
24417
24429
|
}
|
|
24418
24430
|
try {
|
|
24419
24431
|
if (existsSync21(resultFile)) unlinkSync5(resultFile);
|
|
@@ -24750,6 +24762,7 @@ var init_PromptInput = __esm({
|
|
|
24750
24762
|
{ name: "/repl", description: "\u{1F527} Start interactive code REPL" },
|
|
24751
24763
|
{ name: "/voice", description: "\u{1F50A} Toggle voice output (TTS)" },
|
|
24752
24764
|
{ name: "/fork", description: "\u{1F500} Spawn background sub-agent" },
|
|
24765
|
+
{ name: "/workflow", description: "\u{1F9ED} Run advisory dynamic workflow" },
|
|
24753
24766
|
{ name: "/tasks", description: "List background tasks" },
|
|
24754
24767
|
{ name: "/clear", description: "Clear conversation history" },
|
|
24755
24768
|
{ name: "/compact", description: "Summarize old messages to free context" },
|
|
@@ -24782,6 +24795,12 @@ var init_PromptInput = __esm({
|
|
|
24782
24795
|
{ name: "pause", description: "Pause a task: /schedule pause <id>" },
|
|
24783
24796
|
{ name: "resume", description: "Resume a task: /schedule resume <id>" }
|
|
24784
24797
|
],
|
|
24798
|
+
"/workflow": [
|
|
24799
|
+
{ name: "status", description: "Open live worker status" },
|
|
24800
|
+
{ name: "list", description: "List recent workflows" },
|
|
24801
|
+
{ name: "show <id>", description: "Show workflow summary" },
|
|
24802
|
+
{ name: "cancel <id>", description: "Cancel a run or worker" }
|
|
24803
|
+
],
|
|
24785
24804
|
"/repl": [
|
|
24786
24805
|
{ name: "python", description: "Python interactive shell" },
|
|
24787
24806
|
{ name: "node", description: "Node.js interactive shell" },
|
|
@@ -25985,8 +26004,8 @@ function isSensitivePath(resolved) {
|
|
|
25985
26004
|
if (re.test(normalized)) return true;
|
|
25986
26005
|
}
|
|
25987
26006
|
for (const re of SENSITIVE_FILE_PATTERNS) {
|
|
25988
|
-
const
|
|
25989
|
-
if (re.test(
|
|
26007
|
+
const basename5 = path2.basename(resolved);
|
|
26008
|
+
if (re.test(basename5)) return true;
|
|
25990
26009
|
}
|
|
25991
26010
|
return false;
|
|
25992
26011
|
}
|
|
@@ -26104,34 +26123,34 @@ ${output}
|
|
|
26104
26123
|
}
|
|
26105
26124
|
}
|
|
26106
26125
|
function expandUrl(ref, warnings) {
|
|
26107
|
-
return new Promise((
|
|
26126
|
+
return new Promise((resolve6) => {
|
|
26108
26127
|
const url = ref.target;
|
|
26109
26128
|
const mod = url.startsWith("https") ? https : http;
|
|
26110
26129
|
const req = mod.get(url, { timeout: 15e3 }, (res) => {
|
|
26111
26130
|
if (res.statusCode && (res.statusCode >= 300 && res.statusCode < 400) && res.headers.location) {
|
|
26112
26131
|
const redirectMod = res.headers.location.startsWith("https") ? https : http;
|
|
26113
26132
|
const req2 = redirectMod.get(res.headers.location, { timeout: 15e3 }, (res2) => {
|
|
26114
|
-
collectResponse(res2, ref, warnings,
|
|
26133
|
+
collectResponse(res2, ref, warnings, resolve6);
|
|
26115
26134
|
});
|
|
26116
26135
|
req2.on("error", (e) => {
|
|
26117
26136
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26118
|
-
|
|
26137
|
+
resolve6(null);
|
|
26119
26138
|
});
|
|
26120
26139
|
return;
|
|
26121
26140
|
}
|
|
26122
|
-
collectResponse(res, ref, warnings,
|
|
26141
|
+
collectResponse(res, ref, warnings, resolve6);
|
|
26123
26142
|
});
|
|
26124
26143
|
req.on("error", (e) => {
|
|
26125
26144
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26126
|
-
|
|
26145
|
+
resolve6(null);
|
|
26127
26146
|
});
|
|
26128
26147
|
});
|
|
26129
26148
|
}
|
|
26130
|
-
function collectResponse(res, ref, warnings,
|
|
26149
|
+
function collectResponse(res, ref, warnings, resolve6) {
|
|
26131
26150
|
if (res.statusCode && res.statusCode >= 400) {
|
|
26132
26151
|
warnings.push(`\u26A0\uFE0F @url returned HTTP ${res.statusCode}: ${ref.target}`);
|
|
26133
26152
|
res.resume();
|
|
26134
|
-
|
|
26153
|
+
resolve6(null);
|
|
26135
26154
|
return;
|
|
26136
26155
|
}
|
|
26137
26156
|
const chunks = [];
|
|
@@ -26143,14 +26162,14 @@ function collectResponse(res, ref, warnings, resolve5) {
|
|
|
26143
26162
|
text = text.slice(0, 5e4) + "\n\u2026 (truncated)";
|
|
26144
26163
|
}
|
|
26145
26164
|
const tokens = estimateTokens2(text);
|
|
26146
|
-
|
|
26165
|
+
resolve6(`\u{1F310} @url:${ref.target} (${tokens} tokens)
|
|
26147
26166
|
\`\`\`
|
|
26148
26167
|
${text}
|
|
26149
26168
|
\`\`\``);
|
|
26150
26169
|
});
|
|
26151
26170
|
res.on("error", (e) => {
|
|
26152
26171
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26153
|
-
|
|
26172
|
+
resolve6(null);
|
|
26154
26173
|
});
|
|
26155
26174
|
}
|
|
26156
26175
|
function stripHtml(html) {
|
|
@@ -26651,13 +26670,13 @@ Type /resume <id> to resume.` });
|
|
|
26651
26670
|
if (input === "/export") {
|
|
26652
26671
|
try {
|
|
26653
26672
|
const { writeFile: writeFile5, mkdir: mkdir5 } = await import("node:fs/promises");
|
|
26654
|
-
const { join:
|
|
26655
|
-
const { homedir:
|
|
26656
|
-
const { existsSync:
|
|
26657
|
-
const exportDir =
|
|
26658
|
-
if (!
|
|
26673
|
+
const { join: join48 } = await import("node:path");
|
|
26674
|
+
const { homedir: homedir32 } = await import("node:os");
|
|
26675
|
+
const { existsSync: existsSync34 } = await import("node:fs");
|
|
26676
|
+
const exportDir = join48(homedir32(), ".openjaw-agent", "exports");
|
|
26677
|
+
if (!existsSync34(exportDir)) await mkdir5(exportDir, { recursive: true });
|
|
26659
26678
|
const filename = `session-${agentLoop.sessionId}.md`;
|
|
26660
|
-
const filepath =
|
|
26679
|
+
const filepath = join48(exportDir, filename);
|
|
26661
26680
|
const lines = [
|
|
26662
26681
|
`# OpenJaw Agent Session ${agentLoop.sessionId}`,
|
|
26663
26682
|
`Date: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -26876,9 +26895,9 @@ ${list}` });
|
|
|
26876
26895
|
const cmd = lang === "python" ? "python" : lang === "node" ? "node" : "pwsh";
|
|
26877
26896
|
const args = lang === "python" ? ["-i", "-u"] : lang === "node" ? ["-i"] : ["-NoProfile", "-NoLogo"];
|
|
26878
26897
|
try {
|
|
26879
|
-
const { spawn:
|
|
26898
|
+
const { spawn: spawn8 } = await import("node:child_process");
|
|
26880
26899
|
if (replRef.current) replRef.current.kill();
|
|
26881
|
-
const proc =
|
|
26900
|
+
const proc = spawn8(cmd, args, {
|
|
26882
26901
|
stdio: ["pipe", "pipe", "pipe"],
|
|
26883
26902
|
windowsHide: true
|
|
26884
26903
|
});
|
|
@@ -26918,7 +26937,7 @@ ${list}` });
|
|
|
26918
26937
|
if (replRef.current && replLangRef.current && !input.startsWith("/")) {
|
|
26919
26938
|
const proc = replRef.current;
|
|
26920
26939
|
proc.stdin?.write(input + "\n");
|
|
26921
|
-
await new Promise((
|
|
26940
|
+
await new Promise((resolve6) => setTimeout(resolve6, 800));
|
|
26922
26941
|
const flush = proc._ojFlush;
|
|
26923
26942
|
const output = flush ? flush() : "";
|
|
26924
26943
|
if (output.trim()) {
|
|
@@ -27232,14 +27251,14 @@ Options: ${chunk.choices.join(" | ")}` : chunk.content;
|
|
|
27232
27251
|
waitingForAskUserRef.current = true;
|
|
27233
27252
|
setIsRunning(false);
|
|
27234
27253
|
setWaitingForAskUser(true);
|
|
27235
|
-
await new Promise((
|
|
27254
|
+
await new Promise((resolve6) => {
|
|
27236
27255
|
const checkInterval = setInterval(() => {
|
|
27237
27256
|
if (!waitingForAskUserRef.current || !agentLoop.isWaitingForAskUser) {
|
|
27238
27257
|
clearInterval(checkInterval);
|
|
27239
27258
|
waitingForAskUserRef.current = false;
|
|
27240
27259
|
setWaitingForAskUser(false);
|
|
27241
27260
|
setIsRunning(true);
|
|
27242
|
-
|
|
27261
|
+
resolve6();
|
|
27243
27262
|
}
|
|
27244
27263
|
}, 200);
|
|
27245
27264
|
});
|
|
@@ -27535,8 +27554,8 @@ async function withTimeout(promise, ms) {
|
|
|
27535
27554
|
try {
|
|
27536
27555
|
return await Promise.race([
|
|
27537
27556
|
promise,
|
|
27538
|
-
new Promise((
|
|
27539
|
-
timeoutId = setTimeout(() =>
|
|
27557
|
+
new Promise((resolve6) => {
|
|
27558
|
+
timeoutId = setTimeout(() => resolve6(SKILL_TIMEOUT), ms);
|
|
27540
27559
|
})
|
|
27541
27560
|
]);
|
|
27542
27561
|
} finally {
|
|
@@ -28146,12 +28165,12 @@ var init_teams = __esm({
|
|
|
28146
28165
|
Options: ${chunk.choices.join(" | ")}` : "";
|
|
28147
28166
|
await this.sendToSelfChat(`\u2753 ${question}${choicesText}`);
|
|
28148
28167
|
if (!answerSent) await updateStatus("\u{1F916} OpenJaw Agent \u2014 \u2753 Waiting for your response...");
|
|
28149
|
-
const userReply = await new Promise((
|
|
28150
|
-
this._pendingReplyResolver =
|
|
28168
|
+
const userReply = await new Promise((resolve6) => {
|
|
28169
|
+
this._pendingReplyResolver = resolve6;
|
|
28151
28170
|
setTimeout(() => {
|
|
28152
|
-
if (this._pendingReplyResolver ===
|
|
28171
|
+
if (this._pendingReplyResolver === resolve6) {
|
|
28153
28172
|
this._pendingReplyResolver = null;
|
|
28154
|
-
|
|
28173
|
+
resolve6("[No response \u2014 timed out]");
|
|
28155
28174
|
}
|
|
28156
28175
|
}, 5 * 60 * 1e3);
|
|
28157
28176
|
});
|
|
@@ -28635,12 +28654,12 @@ ${err.stack?.split("\n").slice(0, 3).join("\n")}` : String(err);
|
|
|
28635
28654
|
}
|
|
28636
28655
|
/** Wait for the next user message (used by ask_user flow) */
|
|
28637
28656
|
waitForUserReply(_chatId) {
|
|
28638
|
-
return new Promise((
|
|
28639
|
-
this._pendingReplyResolver =
|
|
28657
|
+
return new Promise((resolve6) => {
|
|
28658
|
+
this._pendingReplyResolver = resolve6;
|
|
28640
28659
|
setTimeout(() => {
|
|
28641
|
-
if (this._pendingReplyResolver ===
|
|
28660
|
+
if (this._pendingReplyResolver === resolve6) {
|
|
28642
28661
|
this._pendingReplyResolver = null;
|
|
28643
|
-
|
|
28662
|
+
resolve6("[No response \u2014 timed out]");
|
|
28644
28663
|
}
|
|
28645
28664
|
}, 5 * 60 * 1e3);
|
|
28646
28665
|
});
|
|
@@ -28931,9 +28950,9 @@ var init_wechat2 = __esm({
|
|
|
28931
28950
|
try {
|
|
28932
28951
|
const qrTerminal = await import("qrcode-terminal");
|
|
28933
28952
|
const mod = qrTerminal.default || qrTerminal;
|
|
28934
|
-
const qrAscii = await new Promise((
|
|
28953
|
+
const qrAscii = await new Promise((resolve6, reject) => {
|
|
28935
28954
|
try {
|
|
28936
|
-
mod.generate(qrUrl, { small: true }, (out) =>
|
|
28955
|
+
mod.generate(qrUrl, { small: true }, (out) => resolve6(out));
|
|
28937
28956
|
} catch (e) {
|
|
28938
28957
|
reject(e);
|
|
28939
28958
|
}
|
|
@@ -29199,12 +29218,12 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29199
29218
|
const choicesText = chunk.choices?.length ? `
|
|
29200
29219
|
\u9009\u9879: ${chunk.choices.join(" | ")}` : "";
|
|
29201
29220
|
await this.sendText(userId, `\u2753 ${question}${choicesText}`, contextToken);
|
|
29202
|
-
const userReply = await new Promise((
|
|
29203
|
-
this._pendingReplyResolver =
|
|
29221
|
+
const userReply = await new Promise((resolve6) => {
|
|
29222
|
+
this._pendingReplyResolver = resolve6;
|
|
29204
29223
|
setTimeout(() => {
|
|
29205
|
-
if (this._pendingReplyResolver ===
|
|
29224
|
+
if (this._pendingReplyResolver === resolve6) {
|
|
29206
29225
|
this._pendingReplyResolver = null;
|
|
29207
|
-
|
|
29226
|
+
resolve6("[No response \u2014 timed out]");
|
|
29208
29227
|
}
|
|
29209
29228
|
}, 5 * 60 * 1e3);
|
|
29210
29229
|
});
|
|
@@ -30705,8 +30724,8 @@ function createPromptCollector(bus, getSessionId) {
|
|
|
30705
30724
|
}, "emit");
|
|
30706
30725
|
const register = /* @__PURE__ */ __name((kind) => {
|
|
30707
30726
|
const requestId = randomUUID12();
|
|
30708
|
-
const promise = new Promise((
|
|
30709
|
-
pending.set(requestId, { kind, resolve:
|
|
30727
|
+
const promise = new Promise((resolve6) => {
|
|
30728
|
+
pending.set(requestId, { kind, resolve: resolve6 });
|
|
30710
30729
|
});
|
|
30711
30730
|
return { promise, requestId };
|
|
30712
30731
|
}, "register");
|
|
@@ -31686,11 +31705,11 @@ function detectTerminal() {
|
|
|
31686
31705
|
}
|
|
31687
31706
|
return process.env.TERM ?? null;
|
|
31688
31707
|
}
|
|
31689
|
-
function supportsOsc52Clipboard(
|
|
31690
|
-
return OSC52_CAPABLE_TERMINALS.includes(
|
|
31708
|
+
function supportsOsc52Clipboard(terminal2 = env.terminal) {
|
|
31709
|
+
return OSC52_CAPABLE_TERMINALS.includes(terminal2 ?? "");
|
|
31691
31710
|
}
|
|
31692
31711
|
function execFileNoThrow(file2, args, options = {}) {
|
|
31693
|
-
return new Promise((
|
|
31712
|
+
return new Promise((resolve6) => {
|
|
31694
31713
|
const child = spawn4(file2, args, {
|
|
31695
31714
|
cwd: options.useCwd ? process.cwd() : void 0,
|
|
31696
31715
|
env: options.env,
|
|
@@ -31713,13 +31732,13 @@ function execFileNoThrow(file2, args, options = {}) {
|
|
|
31713
31732
|
if (timer) {
|
|
31714
31733
|
clearTimeout(timer);
|
|
31715
31734
|
}
|
|
31716
|
-
|
|
31735
|
+
resolve6({ stdout, stderr, code: 1, error: String(error) });
|
|
31717
31736
|
});
|
|
31718
31737
|
child.on("close", (code) => {
|
|
31719
31738
|
if (timer) {
|
|
31720
31739
|
clearTimeout(timer);
|
|
31721
31740
|
}
|
|
31722
|
-
|
|
31741
|
+
resolve6({ stdout, stderr, code: timedOut ? 124 : code ?? 0 });
|
|
31723
31742
|
});
|
|
31724
31743
|
if (options.input) {
|
|
31725
31744
|
child.stdin?.write(options.input);
|
|
@@ -31751,7 +31770,7 @@ function shouldEmitClipboardSequence(env2 = process.env) {
|
|
|
31751
31770
|
}
|
|
31752
31771
|
return !!env2["SSH_CONNECTION"] || !env2["TMUX"] && !env2["STY"];
|
|
31753
31772
|
}
|
|
31754
|
-
function shouldUseNativeClipboard(env2 = process.env,
|
|
31773
|
+
function shouldUseNativeClipboard(env2 = process.env, terminal2 = env.terminal) {
|
|
31755
31774
|
if (env2.SSH_CONNECTION) {
|
|
31756
31775
|
return false;
|
|
31757
31776
|
}
|
|
@@ -31761,7 +31780,7 @@ function shouldUseNativeClipboard(env2 = process.env, terminal = env.terminal) {
|
|
|
31761
31780
|
if (!shouldEmitClipboardSequence(env2)) {
|
|
31762
31781
|
return true;
|
|
31763
31782
|
}
|
|
31764
|
-
return !supportsOsc52Clipboard(
|
|
31783
|
+
return !supportsOsc52Clipboard(terminal2);
|
|
31765
31784
|
}
|
|
31766
31785
|
function tmuxPassthrough(payload) {
|
|
31767
31786
|
return `${ESC}Ptmux;${payload.replaceAll(ESC, ESC + ESC)}${ST}`;
|
|
@@ -33197,7 +33216,7 @@ function needsAltScreenResizeScrollbackClear(env2 = process.env) {
|
|
|
33197
33216
|
function supportsExtendedKeys() {
|
|
33198
33217
|
return EXTENDED_KEYS_TERMINALS.includes(env.terminal ?? "");
|
|
33199
33218
|
}
|
|
33200
|
-
function writeDiffToTerminal(
|
|
33219
|
+
function writeDiffToTerminal(terminal2, diff2, skipSyncMarkers = false, onDrain) {
|
|
33201
33220
|
if (diff2.length === 0) {
|
|
33202
33221
|
return { bytes: 0, backpressure: false };
|
|
33203
33222
|
}
|
|
@@ -33242,7 +33261,7 @@ function writeDiffToTerminal(terminal, diff2, skipSyncMarkers = false, onDrain)
|
|
|
33242
33261
|
if (useSync) {
|
|
33243
33262
|
buffer += ESU;
|
|
33244
33263
|
}
|
|
33245
|
-
const wrote = onDrain ?
|
|
33264
|
+
const wrote = onDrain ? terminal2.stdout.write(buffer, () => onDrain()) : terminal2.stdout.write(buffer);
|
|
33246
33265
|
return { bytes: Buffer.byteLength(buffer, "utf8"), backpressure: !wrote };
|
|
33247
33266
|
}
|
|
33248
33267
|
function logForDebugging(_message, _options = {}) {
|
|
@@ -36692,8 +36711,8 @@ function setTerminalFocused(v) {
|
|
|
36692
36711
|
cb();
|
|
36693
36712
|
}
|
|
36694
36713
|
if (!v) {
|
|
36695
|
-
for (const
|
|
36696
|
-
|
|
36714
|
+
for (const resolve6 of resolvers) {
|
|
36715
|
+
resolve6();
|
|
36697
36716
|
}
|
|
36698
36717
|
resolvers.clear();
|
|
36699
36718
|
}
|
|
@@ -42931,11 +42950,11 @@ $ npm install --save-dev react-devtools-core
|
|
|
42931
42950
|
* and the terminal doesn't respond, the promise remains pending.
|
|
42932
42951
|
*/
|
|
42933
42952
|
send(query) {
|
|
42934
|
-
return new Promise((
|
|
42953
|
+
return new Promise((resolve6) => {
|
|
42935
42954
|
this.queue.push({
|
|
42936
42955
|
kind: "query",
|
|
42937
42956
|
match: query.match,
|
|
42938
|
-
resolve: /* @__PURE__ */ __name((r) =>
|
|
42957
|
+
resolve: /* @__PURE__ */ __name((r) => resolve6(r), "resolve")
|
|
42939
42958
|
});
|
|
42940
42959
|
this.stdout.write(query.request);
|
|
42941
42960
|
});
|
|
@@ -42950,8 +42969,8 @@ $ npm install --save-dev react-devtools-core
|
|
|
42950
42969
|
* Safe to call with no pending queries — still waits for a round-trip.
|
|
42951
42970
|
*/
|
|
42952
42971
|
flush() {
|
|
42953
|
-
return new Promise((
|
|
42954
|
-
this.queue.push({ kind: "sentinel", resolve:
|
|
42972
|
+
return new Promise((resolve6) => {
|
|
42973
|
+
this.queue.push({ kind: "sentinel", resolve: resolve6 });
|
|
42955
42974
|
this.stdout.write(SENTINEL);
|
|
42956
42975
|
});
|
|
42957
42976
|
}
|
|
@@ -45431,8 +45450,8 @@ $ npm install --save-dev react-devtools-core
|
|
|
45431
45450
|
}
|
|
45432
45451
|
}
|
|
45433
45452
|
async waitUntilExit() {
|
|
45434
|
-
this.exitPromise ||= new Promise((
|
|
45435
|
-
this.resolveExitPromise =
|
|
45453
|
+
this.exitPromise ||= new Promise((resolve6, reject) => {
|
|
45454
|
+
this.resolveExitPromise = resolve6;
|
|
45436
45455
|
this.rejectExitPromise = reject;
|
|
45437
45456
|
});
|
|
45438
45457
|
return this.exitPromise;
|
|
@@ -45923,10 +45942,10 @@ async function writeClipboardText(text, platform2 = process.platform, start = sp
|
|
|
45923
45942
|
const candidates = writeClipboardCommands(platform2, env2);
|
|
45924
45943
|
for (const { cmd, args } of candidates) {
|
|
45925
45944
|
try {
|
|
45926
|
-
const ok = await new Promise((
|
|
45945
|
+
const ok = await new Promise((resolve6) => {
|
|
45927
45946
|
const child = start(cmd, [...args], { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
|
|
45928
|
-
child.once("error", () =>
|
|
45929
|
-
child.once("close", (code) =>
|
|
45947
|
+
child.once("error", () => resolve6(false));
|
|
45948
|
+
child.once("close", (code) => resolve6(code === 0));
|
|
45930
45949
|
child.stdin?.end(text);
|
|
45931
45950
|
});
|
|
45932
45951
|
if (ok) {
|
|
@@ -45985,8 +46004,8 @@ async function readOsc52Clipboard(querier, timeoutMs = 500) {
|
|
|
45985
46004
|
if (!querier) {
|
|
45986
46005
|
return null;
|
|
45987
46006
|
}
|
|
45988
|
-
const timeout = new Promise((
|
|
45989
|
-
setTimeout(() =>
|
|
46007
|
+
const timeout = new Promise((resolve6) => {
|
|
46008
|
+
setTimeout(() => resolve6(void 0), timeoutMs);
|
|
45990
46009
|
});
|
|
45991
46010
|
const query = querier.send({
|
|
45992
46011
|
request: buildOsc52ClipboardQuery(),
|
|
@@ -46143,12 +46162,12 @@ async function backupFile(filePath, ops) {
|
|
|
46143
46162
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
46144
46163
|
await ops.copyFile(filePath, `${filePath}.backup.${stamp}`);
|
|
46145
46164
|
}
|
|
46146
|
-
async function configureTerminalKeybindings(
|
|
46165
|
+
async function configureTerminalKeybindings(terminal2, options) {
|
|
46147
46166
|
const env2 = options?.env ?? process.env;
|
|
46148
46167
|
const platform2 = options?.platform ?? process.platform;
|
|
46149
46168
|
const homeDir = options?.homeDir ?? homedir25();
|
|
46150
46169
|
const ops = { ...DEFAULT_FILE_OPS, ...options?.fileOps ?? {} };
|
|
46151
|
-
const meta = TERMINAL_META[
|
|
46170
|
+
const meta = TERMINAL_META[terminal2];
|
|
46152
46171
|
if (isRemoteShellSession(env2)) {
|
|
46153
46172
|
return {
|
|
46154
46173
|
success: false,
|
|
@@ -46343,6 +46362,7 @@ var init_overlayStore = __esm({
|
|
|
46343
46362
|
buildOverlayState = /* @__PURE__ */ __name(() => ({
|
|
46344
46363
|
agents: false,
|
|
46345
46364
|
agentsInitialHistoryIndex: 0,
|
|
46365
|
+
agentsWorkflowId: null,
|
|
46346
46366
|
approval: null,
|
|
46347
46367
|
clarify: null,
|
|
46348
46368
|
confirm: null,
|
|
@@ -46365,6 +46385,7 @@ var init_overlayStore = __esm({
|
|
|
46365
46385
|
...buildOverlayState(),
|
|
46366
46386
|
agents: $overlayState.get().agents,
|
|
46367
46387
|
agentsInitialHistoryIndex: $overlayState.get().agentsInitialHistoryIndex,
|
|
46388
|
+
agentsWorkflowId: $overlayState.get().agentsWorkflowId,
|
|
46368
46389
|
mcpHub: $overlayState.get().mcpHub,
|
|
46369
46390
|
modelPicker: $overlayState.get().modelPicker,
|
|
46370
46391
|
modelPickerMode: $overlayState.get().modelPickerMode,
|
|
@@ -47164,13 +47185,25 @@ var init_debug = __esm({
|
|
|
47164
47185
|
}
|
|
47165
47186
|
});
|
|
47166
47187
|
|
|
47188
|
+
// src/app/workflowStore.ts
|
|
47189
|
+
import { atom as atom3 } from "nanostores";
|
|
47190
|
+
var $workflowSnapshots, setWorkflowSnapshot;
|
|
47191
|
+
var init_workflowStore = __esm({
|
|
47192
|
+
"src/app/workflowStore.ts"() {
|
|
47193
|
+
"use strict";
|
|
47194
|
+
$workflowSnapshots = atom3({});
|
|
47195
|
+
setWorkflowSnapshot = /* @__PURE__ */ __name((snapshot) => $workflowSnapshots.set({ ...$workflowSnapshots.get(), [snapshot.id]: snapshot }), "setWorkflowSnapshot");
|
|
47196
|
+
}
|
|
47197
|
+
});
|
|
47198
|
+
|
|
47167
47199
|
// src/app/slash/commands/openjaw.ts
|
|
47168
|
-
var fmt, money, stub, eventLine, parseScheduleInput, showUsage, openjawCommands;
|
|
47200
|
+
var fmt, money, stub, eventLine, parseScheduleInput, asWorkflowSnapshot, workflowLine, workflowRows, showUsage, openjawCommands;
|
|
47169
47201
|
var init_openjaw = __esm({
|
|
47170
47202
|
"src/app/slash/commands/openjaw.ts"() {
|
|
47171
47203
|
"use strict";
|
|
47172
47204
|
init_usage();
|
|
47173
47205
|
init_overlayStore();
|
|
47206
|
+
init_workflowStore();
|
|
47174
47207
|
fmt = /* @__PURE__ */ __name((n) => (n ?? 0).toLocaleString(), "fmt");
|
|
47175
47208
|
money = /* @__PURE__ */ __name((n) => `$${(n ?? 0).toFixed(4)}`, "money");
|
|
47176
47209
|
stub = /* @__PURE__ */ __name((ctx, command, message) => {
|
|
@@ -47210,6 +47243,14 @@ var init_openjaw = __esm({
|
|
|
47210
47243
|
}
|
|
47211
47244
|
return null;
|
|
47212
47245
|
}, "parseScheduleInput");
|
|
47246
|
+
asWorkflowSnapshot = /* @__PURE__ */ __name((run) => run ? run : null, "asWorkflowSnapshot");
|
|
47247
|
+
workflowLine = /* @__PURE__ */ __name((run) => {
|
|
47248
|
+
const active = run.workers.filter((worker) => worker.status === "running" || worker.status === "queued").length;
|
|
47249
|
+
const done = run.workers.filter((worker) => worker.status === "completed").length;
|
|
47250
|
+
return `${run.id} \xB7 ${run.status} \xB7 ${done}/${run.workers.length} done${active ? ` \xB7 ${active} active` : ""} \xB7 ${run.goal}`;
|
|
47251
|
+
}, "workflowLine");
|
|
47252
|
+
workflowRows = /* @__PURE__ */ __name((runs) => runs.map((run) => [run.id, `${run.status} \xB7 ${run.workerCount}/${run.plannedWorkerCount} workers
|
|
47253
|
+
${run.goal}`]), "workflowRows");
|
|
47213
47254
|
showUsage = /* @__PURE__ */ __name((ctx, render2) => {
|
|
47214
47255
|
ctx.gateway.rpc("session.usage", { session_id: ctx.sid }).then(ctx.guarded(render2)).catch(ctx.guardedErr);
|
|
47215
47256
|
}, "showUsage");
|
|
@@ -47231,6 +47272,10 @@ var init_openjaw = __esm({
|
|
|
47231
47272
|
if (!r.messages?.length) {
|
|
47232
47273
|
ctx.transcript.sys("connect: no output");
|
|
47233
47274
|
}
|
|
47275
|
+
if (!ctx.sid && r.config_updates) {
|
|
47276
|
+
ctx.transcript.sys("provider connected \u2014 starting OpenJaw session\u2026");
|
|
47277
|
+
ctx.session.newSession();
|
|
47278
|
+
}
|
|
47234
47279
|
})
|
|
47235
47280
|
).catch(ctx.guardedErr);
|
|
47236
47281
|
}, "run")
|
|
@@ -47324,6 +47369,70 @@ var init_openjaw = __esm({
|
|
|
47324
47369
|
).catch(ctx.guardedErr);
|
|
47325
47370
|
}, "run")
|
|
47326
47371
|
},
|
|
47372
|
+
{
|
|
47373
|
+
aliases: ["wf"],
|
|
47374
|
+
help: "start or inspect an advisory dynamic workflow",
|
|
47375
|
+
name: "workflow",
|
|
47376
|
+
usage: "/workflow <goal> | /workflow status [id] | list | show [id] | cancel <id>",
|
|
47377
|
+
run: /* @__PURE__ */ __name((arg, ctx) => {
|
|
47378
|
+
const text = arg.trim();
|
|
47379
|
+
if (!text) {
|
|
47380
|
+
return ctx.transcript.sys("usage: /workflow <goal> | /workflow status [id] | list | show [id] | cancel <id>");
|
|
47381
|
+
}
|
|
47382
|
+
const [subRaw, ...rest] = text.split(/\s+/);
|
|
47383
|
+
const sub = subRaw?.toLowerCase() ?? "";
|
|
47384
|
+
const remainder = rest.join(" ").trim();
|
|
47385
|
+
if (sub === "status") {
|
|
47386
|
+
return ctx.gateway.rpc("workflow.status", { id: remainder, session_id: ctx.sid }).then(
|
|
47387
|
+
ctx.guarded((r) => {
|
|
47388
|
+
const snapshot = asWorkflowSnapshot(r.run);
|
|
47389
|
+
if (!snapshot) return ctx.transcript.sys(r.error || "no workflows yet");
|
|
47390
|
+
setWorkflowSnapshot(snapshot);
|
|
47391
|
+
patchOverlayState({ agents: true, agentsInitialHistoryIndex: 0, agentsWorkflowId: snapshot.id });
|
|
47392
|
+
ctx.transcript.sys(`workflow status \xB7 ${workflowLine(snapshot)}`);
|
|
47393
|
+
})
|
|
47394
|
+
).catch(ctx.guardedErr);
|
|
47395
|
+
}
|
|
47396
|
+
if (sub === "list" || sub === "ls") {
|
|
47397
|
+
return ctx.gateway.rpc("workflow.list", { limit: 30, session_id: ctx.sid }).then(
|
|
47398
|
+
ctx.guarded((r) => {
|
|
47399
|
+
const runs = r.runs ?? [];
|
|
47400
|
+
if (!runs.length) return ctx.transcript.sys("no workflows yet");
|
|
47401
|
+
ctx.transcript.panel("Workflows", [{ rows: workflowRows(runs) }]);
|
|
47402
|
+
})
|
|
47403
|
+
).catch(ctx.guardedErr);
|
|
47404
|
+
}
|
|
47405
|
+
if (sub === "show") {
|
|
47406
|
+
return ctx.gateway.rpc("workflow.show", { id: remainder, session_id: ctx.sid }).then(
|
|
47407
|
+
ctx.guarded((r) => {
|
|
47408
|
+
const snapshot = asWorkflowSnapshot(r.run);
|
|
47409
|
+
if (!snapshot) return ctx.transcript.sys(r.error || "no workflows yet");
|
|
47410
|
+
setWorkflowSnapshot(snapshot);
|
|
47411
|
+
ctx.transcript.page(snapshot.summary || workflowLine(snapshot), `Workflow ${snapshot.id}`);
|
|
47412
|
+
})
|
|
47413
|
+
).catch(ctx.guardedErr);
|
|
47414
|
+
}
|
|
47415
|
+
if (sub === "cancel" || sub === "stop") {
|
|
47416
|
+
if (!remainder) return ctx.transcript.sys("usage: /workflow cancel <runId|workerId>");
|
|
47417
|
+
return ctx.gateway.rpc("workflow.cancel", { id: remainder, session_id: ctx.sid }).then(
|
|
47418
|
+
ctx.guarded((r) => {
|
|
47419
|
+
const snapshot = asWorkflowSnapshot(r.run);
|
|
47420
|
+
if (snapshot) setWorkflowSnapshot(snapshot);
|
|
47421
|
+
ctx.transcript.sys(r.ok ? `workflow cancel requested: ${remainder}` : r.error || `not found: ${remainder}`);
|
|
47422
|
+
})
|
|
47423
|
+
).catch(ctx.guardedErr);
|
|
47424
|
+
}
|
|
47425
|
+
return ctx.gateway.rpc("workflow.start", { goal: text, session_id: ctx.sid }).then(
|
|
47426
|
+
ctx.guarded((r) => {
|
|
47427
|
+
const snapshot = asWorkflowSnapshot(r.run);
|
|
47428
|
+
if (!snapshot) return ctx.transcript.sys(r.error || "workflow failed to start");
|
|
47429
|
+
setWorkflowSnapshot(snapshot);
|
|
47430
|
+
patchOverlayState({ agents: true, agentsInitialHistoryIndex: 0, agentsWorkflowId: snapshot.id });
|
|
47431
|
+
ctx.transcript.sys(`workflow ${snapshot.id} started \xB7 ${snapshot.plannedWorkerCount} workers \xB7 concurrency ${snapshot.concurrency}`);
|
|
47432
|
+
})
|
|
47433
|
+
).catch(ctx.guardedErr);
|
|
47434
|
+
}, "run")
|
|
47435
|
+
},
|
|
47327
47436
|
{
|
|
47328
47437
|
help: "schedule a recurring prompt",
|
|
47329
47438
|
name: "schedule",
|
|
@@ -47456,7 +47565,7 @@ var init_openjaw = __esm({
|
|
|
47456
47565
|
});
|
|
47457
47566
|
|
|
47458
47567
|
// src/app/delegationStore.ts
|
|
47459
|
-
import { atom as
|
|
47568
|
+
import { atom as atom4 } from "nanostores";
|
|
47460
47569
|
var buildState, $delegationState, getDelegationState, patchDelegationState, $overlaySectionsOpen, toggleOverlaySection, applyDelegationStatus;
|
|
47461
47570
|
var init_delegationStore = __esm({
|
|
47462
47571
|
"src/app/delegationStore.ts"() {
|
|
@@ -47467,10 +47576,10 @@ var init_delegationStore = __esm({
|
|
|
47467
47576
|
paused: false,
|
|
47468
47577
|
updatedAt: null
|
|
47469
47578
|
}), "buildState");
|
|
47470
|
-
$delegationState =
|
|
47579
|
+
$delegationState = atom4(buildState());
|
|
47471
47580
|
getDelegationState = /* @__PURE__ */ __name(() => $delegationState.get(), "getDelegationState");
|
|
47472
47581
|
patchDelegationState = /* @__PURE__ */ __name((next) => $delegationState.set({ ...$delegationState.get(), ...next }), "patchDelegationState");
|
|
47473
|
-
$overlaySectionsOpen =
|
|
47582
|
+
$overlaySectionsOpen = atom4({});
|
|
47474
47583
|
toggleOverlaySection = /* @__PURE__ */ __name((title, defaultOpen) => {
|
|
47475
47584
|
const state = $overlaySectionsOpen.get();
|
|
47476
47585
|
const current = title in state ? state[title] : defaultOpen;
|
|
@@ -47496,7 +47605,7 @@ var init_delegationStore = __esm({
|
|
|
47496
47605
|
});
|
|
47497
47606
|
|
|
47498
47607
|
// src/app/spawnHistoryStore.ts
|
|
47499
|
-
import { atom as
|
|
47608
|
+
import { atom as atom5 } from "nanostores";
|
|
47500
47609
|
function summarizeLabel(subagents) {
|
|
47501
47610
|
const top = subagents.filter((s) => s.parentId == null || subagents.every((o) => o.id !== s.parentId)).slice(0, 2).map((s) => s.goal || "subagent").join(" \xB7 ");
|
|
47502
47611
|
return top || `${subagents.length} agent${subagents.length === 1 ? "" : "s"}`;
|
|
@@ -47539,8 +47648,8 @@ var init_spawnHistoryStore = __esm({
|
|
|
47539
47648
|
"src/app/spawnHistoryStore.ts"() {
|
|
47540
47649
|
"use strict";
|
|
47541
47650
|
HISTORY_LIMIT = 10;
|
|
47542
|
-
$spawnHistory =
|
|
47543
|
-
$spawnDiff =
|
|
47651
|
+
$spawnHistory = atom5([]);
|
|
47652
|
+
$spawnDiff = atom5(null);
|
|
47544
47653
|
getSpawnHistory = /* @__PURE__ */ __name(() => $spawnHistory.get(), "getSpawnHistory");
|
|
47545
47654
|
clearDiffPair = /* @__PURE__ */ __name(() => $spawnDiff.set(null), "clearDiffPair");
|
|
47546
47655
|
setDiffPair = /* @__PURE__ */ __name((pair) => $spawnDiff.set(pair), "setDiffPair");
|
|
@@ -47850,15 +47959,15 @@ var init_ops = __esm({
|
|
|
47850
47959
|
}
|
|
47851
47960
|
const [a, b] = parts;
|
|
47852
47961
|
const history = getSpawnHistory();
|
|
47853
|
-
const
|
|
47962
|
+
const resolve6 = /* @__PURE__ */ __name((token) => {
|
|
47854
47963
|
const n = parseInt(token, 10);
|
|
47855
47964
|
if (Number.isFinite(n) && n >= 1 && n <= history.length) {
|
|
47856
47965
|
return history[n - 1] ?? null;
|
|
47857
47966
|
}
|
|
47858
47967
|
return null;
|
|
47859
47968
|
}, "resolve");
|
|
47860
|
-
const baseline =
|
|
47861
|
-
const candidate =
|
|
47969
|
+
const baseline = resolve6(a);
|
|
47970
|
+
const candidate = resolve6(b);
|
|
47862
47971
|
if (!baseline || !candidate) {
|
|
47863
47972
|
return ctx.transcript.sys(`replay-diff: could not resolve indices \xB7 history has ${history.length} entries`);
|
|
47864
47973
|
}
|
|
@@ -48731,76 +48840,20 @@ var init_session2 = __esm({
|
|
|
48731
48840
|
}
|
|
48732
48841
|
});
|
|
48733
48842
|
|
|
48734
|
-
// src/lib/externalCli.ts
|
|
48735
|
-
import { spawn as spawn6 } from "node:child_process";
|
|
48736
|
-
var resolveHermesBin, launchHermesCommand;
|
|
48737
|
-
var init_externalCli = __esm({
|
|
48738
|
-
"src/lib/externalCli.ts"() {
|
|
48739
|
-
"use strict";
|
|
48740
|
-
resolveHermesBin = /* @__PURE__ */ __name(() => process.env.OPENJAW_BIN?.trim() || "hermes", "resolveHermesBin");
|
|
48741
|
-
launchHermesCommand = /* @__PURE__ */ __name((args) => new Promise((resolve5) => {
|
|
48742
|
-
const child = spawn6(resolveHermesBin(), args, { stdio: "inherit" });
|
|
48743
|
-
child.on("error", (err) => resolve5({ code: null, error: err.message }));
|
|
48744
|
-
child.on("exit", (code) => resolve5({ code }));
|
|
48745
|
-
}), "launchHermesCommand");
|
|
48746
|
-
}
|
|
48747
|
-
});
|
|
48748
|
-
|
|
48749
|
-
// src/app/setupHandoff.ts
|
|
48750
|
-
async function runExternalSetup({ args, ctx, done, launcher, suspend }) {
|
|
48751
|
-
const { gateway, session, transcript } = ctx;
|
|
48752
|
-
transcript.sys(`launching \`hermes ${args.join(" ")}\`\u2026`);
|
|
48753
|
-
patchUiState({ status: "setup running\u2026" });
|
|
48754
|
-
let result = { code: null };
|
|
48755
|
-
await suspend(async () => {
|
|
48756
|
-
result = await launcher(args);
|
|
48757
|
-
});
|
|
48758
|
-
if (result.error) {
|
|
48759
|
-
transcript.sys(`error launching hermes: ${result.error}`);
|
|
48760
|
-
patchUiState({ status: "setup required" });
|
|
48761
|
-
return;
|
|
48762
|
-
}
|
|
48763
|
-
if (result.code !== 0) {
|
|
48764
|
-
transcript.sys(`hermes ${args[0]} exited with code ${result.code}`);
|
|
48765
|
-
patchUiState({ status: "setup required" });
|
|
48766
|
-
return;
|
|
48767
|
-
}
|
|
48768
|
-
const setup = await gateway.rpc("setup.status", {});
|
|
48769
|
-
if (setup?.provider_configured === false) {
|
|
48770
|
-
transcript.sys("still no provider configured");
|
|
48771
|
-
patchUiState({ status: "setup required" });
|
|
48772
|
-
return;
|
|
48773
|
-
}
|
|
48774
|
-
transcript.sys(done);
|
|
48775
|
-
session.newSession();
|
|
48776
|
-
}
|
|
48777
|
-
var init_setupHandoff = __esm({
|
|
48778
|
-
"src/app/setupHandoff.ts"() {
|
|
48779
|
-
"use strict";
|
|
48780
|
-
init_uiStore();
|
|
48781
|
-
__name(runExternalSetup, "runExternalSetup");
|
|
48782
|
-
}
|
|
48783
|
-
});
|
|
48784
|
-
|
|
48785
48843
|
// src/app/slash/commands/setup.ts
|
|
48786
48844
|
var setupCommands;
|
|
48787
48845
|
var init_setup = __esm({
|
|
48788
48846
|
"src/app/slash/commands/setup.ts"() {
|
|
48789
48847
|
"use strict";
|
|
48790
|
-
|
|
48791
|
-
init_externalCli();
|
|
48792
|
-
init_setupHandoff();
|
|
48848
|
+
init_overlayStore();
|
|
48793
48849
|
setupCommands = [
|
|
48794
48850
|
{
|
|
48795
|
-
help: "run
|
|
48851
|
+
help: "first-run setup help; opens provider connection picker",
|
|
48796
48852
|
name: "setup",
|
|
48797
|
-
run: /* @__PURE__ */ __name((
|
|
48798
|
-
|
|
48799
|
-
|
|
48800
|
-
|
|
48801
|
-
launcher: launchHermesCommand,
|
|
48802
|
-
suspend: withInkSuspended
|
|
48803
|
-
}), "run")
|
|
48853
|
+
run: /* @__PURE__ */ __name((_arg, ctx) => {
|
|
48854
|
+
ctx.transcript.sys("OpenJaw setup: run /connect to set up a provider, then /model to choose a model.");
|
|
48855
|
+
patchOverlayState({ modelPicker: true, modelPickerMode: "connect" });
|
|
48856
|
+
}, "run")
|
|
48804
48857
|
}
|
|
48805
48858
|
];
|
|
48806
48859
|
}
|
|
@@ -48956,17 +49009,856 @@ var init_catalog = __esm({
|
|
|
48956
49009
|
}
|
|
48957
49010
|
});
|
|
48958
49011
|
|
|
48959
|
-
// src/
|
|
48960
|
-
|
|
48961
|
-
|
|
48962
|
-
|
|
49012
|
+
// src/workflows/planner.ts
|
|
49013
|
+
function resolveDynamicWorkflowConfig(config) {
|
|
49014
|
+
const raw = config.features?.dynamic_workflows ?? {};
|
|
49015
|
+
return {
|
|
49016
|
+
enabled: raw.enabled ?? DEFAULT_DYNAMIC_WORKFLOW_CONFIG.enabled,
|
|
49017
|
+
plannerMode: "adaptive",
|
|
49018
|
+
hardMaxWorkers: clampInt(raw.hard_max_workers, DEFAULT_DYNAMIC_WORKFLOW_CONFIG.hardMaxWorkers, 1, 1e4),
|
|
49019
|
+
hardMaxConcurrentWorkers: clampInt(
|
|
49020
|
+
raw.hard_max_concurrent_workers,
|
|
49021
|
+
DEFAULT_DYNAMIC_WORKFLOW_CONFIG.hardMaxConcurrentWorkers,
|
|
49022
|
+
1,
|
|
49023
|
+
2048
|
|
49024
|
+
),
|
|
49025
|
+
workerTimeoutMs: clampInt(raw.worker_timeout_ms, DEFAULT_DYNAMIC_WORKFLOW_CONFIG.workerTimeoutMs, 1e4, 36e5),
|
|
49026
|
+
persistHistory: raw.persist_history ?? DEFAULT_DYNAMIC_WORKFLOW_CONFIG.persistHistory
|
|
49027
|
+
};
|
|
49028
|
+
}
|
|
49029
|
+
function initialConcurrency(plannedWorkers, limits) {
|
|
49030
|
+
if (plannedWorkers <= 0) return 0;
|
|
49031
|
+
return Math.min(Math.ceil(Math.sqrt(plannedWorkers) * 2), plannedWorkers, limits.hardMaxConcurrentWorkers);
|
|
49032
|
+
}
|
|
49033
|
+
function adjustConcurrency(current, plannedWorkers, limits, event) {
|
|
49034
|
+
if (plannedWorkers <= 0) return 0;
|
|
49035
|
+
if (event === "rate_limited") return Math.max(1, Math.floor(current / 2));
|
|
49036
|
+
return Math.min(current + 1, plannedWorkers, limits.hardMaxConcurrentWorkers);
|
|
49037
|
+
}
|
|
49038
|
+
function planWorkflow(goal, runId, limits) {
|
|
49039
|
+
const taskGoals = deriveTaskGoals(goal);
|
|
49040
|
+
const specs = [];
|
|
49041
|
+
const maxWorkers = limits.hardMaxWorkers;
|
|
49042
|
+
for (const taskGoal of taskGoals) {
|
|
49043
|
+
if (specs.length >= maxWorkers) break;
|
|
49044
|
+
const id = `${runId}-w${specs.length + 1}`;
|
|
49045
|
+
specs.push({
|
|
49046
|
+
depth: 0,
|
|
49047
|
+
goal: taskGoal,
|
|
49048
|
+
id,
|
|
49049
|
+
index: specs.length,
|
|
49050
|
+
parentId: null,
|
|
49051
|
+
prompt: buildTaskPrompt(goal, taskGoal),
|
|
49052
|
+
role: "task"
|
|
49053
|
+
});
|
|
49054
|
+
}
|
|
49055
|
+
const taskSpecs = [...specs];
|
|
49056
|
+
const verifierEvery = taskSpecs.length >= 8 ? 4 : 3;
|
|
49057
|
+
for (let i = 0; i < taskSpecs.length && specs.length < maxWorkers; i += verifierEvery) {
|
|
49058
|
+
const batch = taskSpecs.slice(i, i + verifierEvery);
|
|
49059
|
+
const id = `${runId}-w${specs.length + 1}`;
|
|
49060
|
+
specs.push({
|
|
49061
|
+
depth: 1,
|
|
49062
|
+
dependsOn: batch.map((item) => item.id),
|
|
49063
|
+
goal: `Verify findings from workers ${batch.map((item) => item.index + 1).join(", ")}`,
|
|
49064
|
+
id,
|
|
49065
|
+
index: specs.length,
|
|
49066
|
+
parentId: batch[0]?.id ?? null,
|
|
49067
|
+
prompt: buildVerifierPrompt(goal, batch),
|
|
49068
|
+
role: "verifier"
|
|
49069
|
+
});
|
|
49070
|
+
}
|
|
49071
|
+
return { concurrency: initialConcurrency(specs.length, limits), specs };
|
|
49072
|
+
}
|
|
49073
|
+
function deriveTaskGoals(goal) {
|
|
49074
|
+
const explicit = extractExplicitTasks(goal);
|
|
49075
|
+
const words = goal.trim().split(/\s+/).filter(Boolean).length;
|
|
49076
|
+
const complexity = Math.min(12, Math.max(3, Math.ceil(words / 35)));
|
|
49077
|
+
const inferred = inferLanes(goal);
|
|
49078
|
+
const seeds = explicit.length > 1 ? explicit : inferred;
|
|
49079
|
+
const out = [];
|
|
49080
|
+
for (const item of seeds) {
|
|
49081
|
+
pushUnique(out, item);
|
|
49082
|
+
}
|
|
49083
|
+
while (out.length < complexity) {
|
|
49084
|
+
const next = DEFAULT_LANES[out.length % DEFAULT_LANES.length];
|
|
49085
|
+
pushUnique(out, next);
|
|
49086
|
+
if (out.length >= DEFAULT_LANES.length && explicit.length <= 1) break;
|
|
49087
|
+
}
|
|
49088
|
+
return out.slice(0, Math.max(1, out.length));
|
|
49089
|
+
}
|
|
49090
|
+
function extractExplicitTasks(goal) {
|
|
49091
|
+
return goal.split(/\r?\n/).map((line) => line.trim().replace(/^[-*+]\s+/, "").replace(/^\d+[.)]\s+/, "").trim()).filter((line) => line.length >= 12);
|
|
49092
|
+
}
|
|
49093
|
+
function inferLanes(goal) {
|
|
49094
|
+
const lower = goal.toLowerCase();
|
|
49095
|
+
const lanes = ["Map the current state and locate relevant files or evidence"];
|
|
49096
|
+
if (/code|repo|branch|test|build|bug|feature|implement/.test(lower)) {
|
|
49097
|
+
lanes.push("Review implementation risks, edge cases, and integration points");
|
|
49098
|
+
lanes.push("Inspect validation strategy and likely test coverage");
|
|
49099
|
+
}
|
|
49100
|
+
if (/research|latest|current|external|claude|compare|similar/.test(lower)) {
|
|
49101
|
+
lanes.push("Research external context and comparable workflow behavior");
|
|
49102
|
+
}
|
|
49103
|
+
if (/ui|status|overlay|navigate|progress|worker/.test(lower)) {
|
|
49104
|
+
lanes.push("Evaluate user experience, status visibility, and navigation requirements");
|
|
49105
|
+
}
|
|
49106
|
+
if (/security|safe|permission|mutat|write|approval/.test(lower)) {
|
|
49107
|
+
lanes.push("Analyze safety boundaries, permissions, and failure modes");
|
|
49108
|
+
}
|
|
49109
|
+
lanes.push("Draft concrete recommendations and acceptance criteria");
|
|
49110
|
+
return lanes;
|
|
49111
|
+
}
|
|
49112
|
+
function pushUnique(items, value) {
|
|
49113
|
+
const normalized = value.trim();
|
|
49114
|
+
if (!normalized) return;
|
|
49115
|
+
if (!items.some((item) => item.toLowerCase() === normalized.toLowerCase())) items.push(normalized);
|
|
49116
|
+
}
|
|
49117
|
+
function buildTaskPrompt(overallGoal, taskGoal) {
|
|
49118
|
+
return [
|
|
49119
|
+
`Overall workflow goal: ${overallGoal}`,
|
|
49120
|
+
`Your assigned read-only worker goal: ${taskGoal}`,
|
|
49121
|
+
"",
|
|
49122
|
+
"Work independently. Use only read/search/analysis tools. Do not modify files, send messages, update memory, or run shell/code execution.",
|
|
49123
|
+
"Return concise findings with evidence, confidence, and open questions."
|
|
49124
|
+
].join("\n");
|
|
49125
|
+
}
|
|
49126
|
+
function buildVerifierPrompt(overallGoal, batch) {
|
|
49127
|
+
return [
|
|
49128
|
+
`Overall workflow goal: ${overallGoal}`,
|
|
49129
|
+
`Verify the likely claims and gaps for these worker lanes: ${batch.map((item) => item.goal).join("; ")}`,
|
|
49130
|
+
"",
|
|
49131
|
+
"Use read-only checks. Label findings as verified, partially verified, or unverified. Do not modify anything."
|
|
49132
|
+
].join("\n");
|
|
49133
|
+
}
|
|
49134
|
+
var DEFAULT_DYNAMIC_WORKFLOW_CONFIG, clampInt, DEFAULT_LANES;
|
|
49135
|
+
var init_planner = __esm({
|
|
49136
|
+
"src/workflows/planner.ts"() {
|
|
49137
|
+
"use strict";
|
|
49138
|
+
DEFAULT_DYNAMIC_WORKFLOW_CONFIG = {
|
|
49139
|
+
enabled: true,
|
|
49140
|
+
plannerMode: "adaptive",
|
|
49141
|
+
hardMaxWorkers: 1024,
|
|
49142
|
+
hardMaxConcurrentWorkers: 128,
|
|
49143
|
+
workerTimeoutMs: 18e4,
|
|
49144
|
+
persistHistory: true
|
|
49145
|
+
};
|
|
49146
|
+
clampInt = /* @__PURE__ */ __name((value, fallback, min, max) => {
|
|
49147
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
49148
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
49149
|
+
return Math.min(max, Math.max(min, Math.floor(parsed)));
|
|
49150
|
+
}, "clampInt");
|
|
49151
|
+
__name(resolveDynamicWorkflowConfig, "resolveDynamicWorkflowConfig");
|
|
49152
|
+
__name(initialConcurrency, "initialConcurrency");
|
|
49153
|
+
__name(adjustConcurrency, "adjustConcurrency");
|
|
49154
|
+
__name(planWorkflow, "planWorkflow");
|
|
49155
|
+
__name(deriveTaskGoals, "deriveTaskGoals");
|
|
49156
|
+
__name(extractExplicitTasks, "extractExplicitTasks");
|
|
49157
|
+
__name(inferLanes, "inferLanes");
|
|
49158
|
+
DEFAULT_LANES = [
|
|
49159
|
+
"Map the current state and locate relevant files or evidence",
|
|
49160
|
+
"Review implementation risks, edge cases, and integration points",
|
|
49161
|
+
"Inspect validation strategy and likely test coverage",
|
|
49162
|
+
"Analyze safety boundaries, permissions, and failure modes",
|
|
49163
|
+
"Draft concrete recommendations and acceptance criteria"
|
|
49164
|
+
];
|
|
49165
|
+
__name(pushUnique, "pushUnique");
|
|
49166
|
+
__name(buildTaskPrompt, "buildTaskPrompt");
|
|
49167
|
+
__name(buildVerifierPrompt, "buildVerifierPrompt");
|
|
49168
|
+
}
|
|
49169
|
+
});
|
|
49170
|
+
|
|
49171
|
+
// src/workflows/persistence.ts
|
|
49172
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync17, readdirSync as readdirSync7, readFileSync as readFileSync28, writeFileSync as writeFileSync19 } from "node:fs";
|
|
48963
49173
|
import { homedir as homedir28 } from "node:os";
|
|
48964
|
-
import { basename as basename3,
|
|
49174
|
+
import { basename as basename3, join as join42, resolve as resolve4 } from "node:path";
|
|
49175
|
+
function ensureDir(path3) {
|
|
49176
|
+
if (!existsSync31(path3)) mkdirSync17(path3, { recursive: true });
|
|
49177
|
+
}
|
|
49178
|
+
function safeSegment(value) {
|
|
49179
|
+
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 80) || "default";
|
|
49180
|
+
}
|
|
49181
|
+
function readJson(path3) {
|
|
49182
|
+
try {
|
|
49183
|
+
return JSON.parse(readFileSync28(path3, "utf8"));
|
|
49184
|
+
} catch {
|
|
49185
|
+
return null;
|
|
49186
|
+
}
|
|
49187
|
+
}
|
|
49188
|
+
function saveWorkflowSnapshot(snapshot) {
|
|
49189
|
+
ensureDir(workflowDir());
|
|
49190
|
+
const path3 = join42(workflowDir(), `${safeSegment(snapshot.id)}.json`);
|
|
49191
|
+
writeFileSync19(path3, `${JSON.stringify(snapshot, null, 2)}
|
|
49192
|
+
`, "utf8");
|
|
49193
|
+
return path3;
|
|
49194
|
+
}
|
|
49195
|
+
function loadWorkflowSnapshot(id) {
|
|
49196
|
+
const path3 = join42(workflowDir(), `${safeSegment(id)}.json`);
|
|
49197
|
+
return readJson(path3);
|
|
49198
|
+
}
|
|
49199
|
+
function listWorkflowSnapshots(limit = 30) {
|
|
49200
|
+
if (!existsSync31(workflowDir())) return [];
|
|
49201
|
+
const entries = [];
|
|
49202
|
+
for (const entry of readdirSync7(workflowDir(), { withFileTypes: true })) {
|
|
49203
|
+
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
49204
|
+
const path3 = join42(workflowDir(), entry.name);
|
|
49205
|
+
const snapshot = readJson(path3);
|
|
49206
|
+
if (!snapshot) continue;
|
|
49207
|
+
entries.push({
|
|
49208
|
+
finishedAt: snapshot.finishedAt,
|
|
49209
|
+
goal: snapshot.goal,
|
|
49210
|
+
id: snapshot.id,
|
|
49211
|
+
path: path3,
|
|
49212
|
+
plannedWorkerCount: snapshot.plannedWorkerCount,
|
|
49213
|
+
startedAt: snapshot.startedAt,
|
|
49214
|
+
status: snapshot.status,
|
|
49215
|
+
workerCount: snapshot.workers.length
|
|
49216
|
+
});
|
|
49217
|
+
}
|
|
49218
|
+
return entries.sort((a, b) => (b.finishedAt ?? b.startedAt) - (a.finishedAt ?? a.startedAt)).slice(0, Math.max(1, limit));
|
|
49219
|
+
}
|
|
49220
|
+
function saveSpawnTreeSnapshot(input) {
|
|
49221
|
+
const sessionId = safeSegment(input.session_id ?? "default");
|
|
49222
|
+
const dir2 = join42(spawnTreeDir(), sessionId);
|
|
49223
|
+
ensureDir(dir2);
|
|
49224
|
+
const stamp = new Date((input.finished_at ?? Date.now() / 1e3) * 1e3).toISOString().replace(/[:.]/g, "-");
|
|
49225
|
+
const path3 = join42(dir2, `${stamp}-${Math.random().toString(36).slice(2, 8)}.json`);
|
|
49226
|
+
const snapshot = {
|
|
49227
|
+
count: input.subagents?.length ?? 0,
|
|
49228
|
+
finished_at: input.finished_at,
|
|
49229
|
+
label: input.label,
|
|
49230
|
+
session_id: input.session_id,
|
|
49231
|
+
started_at: input.started_at,
|
|
49232
|
+
subagents: input.subagents ?? []
|
|
49233
|
+
};
|
|
49234
|
+
writeFileSync19(path3, `${JSON.stringify(snapshot, null, 2)}
|
|
49235
|
+
`, "utf8");
|
|
49236
|
+
return path3;
|
|
49237
|
+
}
|
|
49238
|
+
function listSpawnTreeSnapshots(sessionId = "default", limit = 30) {
|
|
49239
|
+
const dir2 = join42(spawnTreeDir(), safeSegment(sessionId));
|
|
49240
|
+
if (!existsSync31(dir2)) return [];
|
|
49241
|
+
const entries = [];
|
|
49242
|
+
for (const entry of readdirSync7(dir2, { withFileTypes: true })) {
|
|
49243
|
+
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
49244
|
+
const path3 = join42(dir2, entry.name);
|
|
49245
|
+
const snapshot = readJson(path3);
|
|
49246
|
+
if (!snapshot) continue;
|
|
49247
|
+
entries.push({
|
|
49248
|
+
count: snapshot.count,
|
|
49249
|
+
finished_at: snapshot.finished_at,
|
|
49250
|
+
label: snapshot.label,
|
|
49251
|
+
path: path3,
|
|
49252
|
+
session_id: snapshot.session_id,
|
|
49253
|
+
started_at: snapshot.started_at
|
|
49254
|
+
});
|
|
49255
|
+
}
|
|
49256
|
+
return entries.sort((a, b) => (b.finished_at ?? 0) - (a.finished_at ?? 0)).slice(0, Math.max(1, limit));
|
|
49257
|
+
}
|
|
49258
|
+
function loadSpawnTreeSnapshot(path3) {
|
|
49259
|
+
const root = resolve4(spawnTreeDir());
|
|
49260
|
+
const resolved = resolve4(path3);
|
|
49261
|
+
if (!resolved.startsWith(root)) return null;
|
|
49262
|
+
const snapshot = readJson(resolved);
|
|
49263
|
+
return snapshot ? { ...snapshot, path: resolved } : null;
|
|
49264
|
+
}
|
|
49265
|
+
var rootDir, workflowDir, spawnTreeDir;
|
|
49266
|
+
var init_persistence = __esm({
|
|
49267
|
+
"src/workflows/persistence.ts"() {
|
|
49268
|
+
"use strict";
|
|
49269
|
+
rootDir = /* @__PURE__ */ __name(() => join42(homedir28(), ".openjaw-agent"), "rootDir");
|
|
49270
|
+
workflowDir = /* @__PURE__ */ __name(() => join42(rootDir(), "workflows"), "workflowDir");
|
|
49271
|
+
spawnTreeDir = /* @__PURE__ */ __name(() => join42(rootDir(), "spawn-trees"), "spawnTreeDir");
|
|
49272
|
+
__name(ensureDir, "ensureDir");
|
|
49273
|
+
__name(safeSegment, "safeSegment");
|
|
49274
|
+
__name(readJson, "readJson");
|
|
49275
|
+
__name(saveWorkflowSnapshot, "saveWorkflowSnapshot");
|
|
49276
|
+
__name(loadWorkflowSnapshot, "loadWorkflowSnapshot");
|
|
49277
|
+
__name(listWorkflowSnapshots, "listWorkflowSnapshots");
|
|
49278
|
+
__name(saveSpawnTreeSnapshot, "saveSpawnTreeSnapshot");
|
|
49279
|
+
__name(listSpawnTreeSnapshots, "listSpawnTreeSnapshots");
|
|
49280
|
+
__name(loadSpawnTreeSnapshot, "loadSpawnTreeSnapshot");
|
|
49281
|
+
}
|
|
49282
|
+
});
|
|
49283
|
+
|
|
49284
|
+
// src/workflows/readOnlyTools.ts
|
|
49285
|
+
function isWorkflowReadOnlyTool(name) {
|
|
49286
|
+
return READ_ONLY_TOOLS.has(name);
|
|
49287
|
+
}
|
|
49288
|
+
var READ_ONLY_TOOLS, ReadOnlyToolRuntime;
|
|
49289
|
+
var init_readOnlyTools = __esm({
|
|
49290
|
+
"src/workflows/readOnlyTools.ts"() {
|
|
49291
|
+
"use strict";
|
|
49292
|
+
READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
49293
|
+
"browser_snapshot",
|
|
49294
|
+
"browser_extract",
|
|
49295
|
+
"file_info",
|
|
49296
|
+
"file_list",
|
|
49297
|
+
"file_read",
|
|
49298
|
+
"glob",
|
|
49299
|
+
"grep",
|
|
49300
|
+
"image_view",
|
|
49301
|
+
"web_extract",
|
|
49302
|
+
"web_fetch",
|
|
49303
|
+
"web_search"
|
|
49304
|
+
]);
|
|
49305
|
+
__name(isWorkflowReadOnlyTool, "isWorkflowReadOnlyTool");
|
|
49306
|
+
ReadOnlyToolRuntime = class {
|
|
49307
|
+
constructor(inner) {
|
|
49308
|
+
this.inner = inner;
|
|
49309
|
+
}
|
|
49310
|
+
inner;
|
|
49311
|
+
static {
|
|
49312
|
+
__name(this, "ReadOnlyToolRuntime");
|
|
49313
|
+
}
|
|
49314
|
+
listTools() {
|
|
49315
|
+
return this.inner.listTools().filter((tool) => isWorkflowReadOnlyTool(tool.name));
|
|
49316
|
+
}
|
|
49317
|
+
async execute(name, input) {
|
|
49318
|
+
if (!isWorkflowReadOnlyTool(name)) {
|
|
49319
|
+
throw new Error(`Tool ${name} is not available in advisory workflow workers`);
|
|
49320
|
+
}
|
|
49321
|
+
return await this.inner.execute(name, input);
|
|
49322
|
+
}
|
|
49323
|
+
};
|
|
49324
|
+
}
|
|
49325
|
+
});
|
|
49326
|
+
|
|
49327
|
+
// src/workflows/manager.ts
|
|
49328
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
49329
|
+
function buildPlannerSystemPrompt(limits) {
|
|
49330
|
+
return [
|
|
49331
|
+
"You are the OpenJaw dynamic workflow planner.",
|
|
49332
|
+
"Return ONLY valid JSON. Do not include markdown fences or prose.",
|
|
49333
|
+
"Create a task graph for advisory read-only worker agents. Do not answer the user task.",
|
|
49334
|
+
"Use enough workers to represent genuinely different research lanes, viewpoints, critics, verifiers, and a final synthesizer. Do not default to a small fixed count.",
|
|
49335
|
+
"For panel-review prompts, create separate panelist workers for each requested philosophy and a critic/risk worker before the synthesizer.",
|
|
49336
|
+
`Physical caps: at most ${limits.hardMaxWorkers} total workers and ${limits.hardMaxConcurrentWorkers} concurrent workers. Normal plans should be smaller than the cap but may contain dozens of workers when useful.`,
|
|
49337
|
+
'Schema: {"language":"optional output language","workers":[{"id":"kebab-id","role":"researcher|panelist|critic|verifier|synthesizer","philosophy":"optional","goal":"specific worker goal","depends_on":["worker-id"]}]}',
|
|
49338
|
+
"Always include exactly one synthesizer worker that depends on the most important research, panelist, critic, and verifier workers."
|
|
49339
|
+
].join("\n");
|
|
49340
|
+
}
|
|
49341
|
+
function parseModelPlan(content, goal, runId, limits) {
|
|
49342
|
+
const parsed = JSON.parse(extractJsonObject(content));
|
|
49343
|
+
const workers = Array.isArray(parsed.workers) ? parsed.workers : [];
|
|
49344
|
+
const specs = [];
|
|
49345
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
49346
|
+
for (const worker of workers.slice(0, limits.hardMaxWorkers)) {
|
|
49347
|
+
const rawGoal = String(worker.goal ?? "").trim();
|
|
49348
|
+
if (!rawGoal) continue;
|
|
49349
|
+
const id = uniqueWorkerId(runId, worker.id || rawGoal, usedIds, specs.length + 1);
|
|
49350
|
+
const role = normalizeRole(worker.role);
|
|
49351
|
+
const dependsOn = Array.isArray(worker.depends_on) ? worker.depends_on.map(String).map((value) => scopedWorkerId(runId, value)).filter((value) => usedIds.has(value)) : [];
|
|
49352
|
+
specs.push({
|
|
49353
|
+
depth: dependsOn.length > 0 || role !== "task" ? 1 : 0,
|
|
49354
|
+
dependsOn,
|
|
49355
|
+
goal: rawGoal,
|
|
49356
|
+
id,
|
|
49357
|
+
index: specs.length,
|
|
49358
|
+
parentId: dependsOn[0] ?? null,
|
|
49359
|
+
prompt: buildModelWorkerPrompt(goal, rawGoal, worker.role, worker.philosophy, parsed.language),
|
|
49360
|
+
role
|
|
49361
|
+
});
|
|
49362
|
+
}
|
|
49363
|
+
return ensureSynthesizer({ concurrency: 0, specs }, goal, runId, limits);
|
|
49364
|
+
}
|
|
49365
|
+
function ensureSynthesizer(plan, goal, runId, limits) {
|
|
49366
|
+
const specs = plan.specs.slice(0, limits.hardMaxWorkers);
|
|
49367
|
+
const existing = specs.find((spec) => spec.role === "synthesizer");
|
|
49368
|
+
const dependencies = specs.filter((spec) => spec.role !== "synthesizer").map((spec) => spec.id);
|
|
49369
|
+
if (existing) {
|
|
49370
|
+
existing.dependsOn = existing.dependsOn?.length ? existing.dependsOn : dependencies;
|
|
49371
|
+
existing.depth = Math.max(existing.depth, 1);
|
|
49372
|
+
existing.parentId = existing.dependsOn[0] ?? null;
|
|
49373
|
+
} else if (specs.length < limits.hardMaxWorkers) {
|
|
49374
|
+
specs.push({
|
|
49375
|
+
depth: 1,
|
|
49376
|
+
dependsOn: dependencies,
|
|
49377
|
+
goal: "Synthesize the panel and research outputs into the final answer",
|
|
49378
|
+
id: `${runId}-synthesizer`,
|
|
49379
|
+
index: specs.length,
|
|
49380
|
+
parentId: dependencies[0] ?? null,
|
|
49381
|
+
prompt: buildModelWorkerPrompt(goal, "Synthesize all completed worker outputs into the final answer for the user.", "synthesizer", void 0, void 0),
|
|
49382
|
+
role: "synthesizer"
|
|
49383
|
+
});
|
|
49384
|
+
}
|
|
49385
|
+
return { concurrency: Math.min(Math.ceil(Math.sqrt(specs.length) * 2), specs.length, limits.hardMaxConcurrentWorkers), specs };
|
|
49386
|
+
}
|
|
49387
|
+
function buildModelWorkerPrompt(overallGoal, workerGoal, role, philosophy, language) {
|
|
49388
|
+
return [
|
|
49389
|
+
`Overall workflow goal: ${overallGoal}`,
|
|
49390
|
+
`Worker role: ${role || "researcher"}`,
|
|
49391
|
+
philosophy ? `Investment/work philosophy: ${philosophy}` : "",
|
|
49392
|
+
language ? `Final language preference: ${language}` : "",
|
|
49393
|
+
`Assigned goal: ${workerGoal}`,
|
|
49394
|
+
"",
|
|
49395
|
+
"Use only read/search/analysis tools. Do not modify files, send messages, update memory, or run shell/code execution.",
|
|
49396
|
+
"If prior worker outputs are provided below, use them as context and explicitly resolve agreements, disagreements, and uncertainty.",
|
|
49397
|
+
"Return evidence-backed findings. A synthesizer must produce the final answer directly for the user."
|
|
49398
|
+
].filter(Boolean).join("\n");
|
|
49399
|
+
}
|
|
49400
|
+
function normalizeRole(role) {
|
|
49401
|
+
const lower = String(role ?? "").toLowerCase();
|
|
49402
|
+
if (lower.includes("synth") || lower.includes("chair")) return "synthesizer";
|
|
49403
|
+
if (lower.includes("verify") || lower.includes("critic") || lower.includes("risk")) return "verifier";
|
|
49404
|
+
return "task";
|
|
49405
|
+
}
|
|
49406
|
+
function extractJsonObject(content) {
|
|
49407
|
+
const trimmed = content.trim().replace(/^```(?:json)?\s*/i, "").replace(/```$/i, "").trim();
|
|
49408
|
+
const start = trimmed.indexOf("{");
|
|
49409
|
+
const end = trimmed.lastIndexOf("}");
|
|
49410
|
+
if (start < 0 || end < start) throw new Error("planner response did not contain a JSON object");
|
|
49411
|
+
return trimmed.slice(start, end + 1);
|
|
49412
|
+
}
|
|
49413
|
+
function uniqueWorkerId(runId, value, used, index) {
|
|
49414
|
+
const base = scopedWorkerId(runId, value) || `${runId}-w${index}`;
|
|
49415
|
+
let candidate = base;
|
|
49416
|
+
let suffix = 2;
|
|
49417
|
+
while (used.has(candidate)) {
|
|
49418
|
+
candidate = `${base}-${suffix}`;
|
|
49419
|
+
suffix += 1;
|
|
49420
|
+
}
|
|
49421
|
+
used.add(candidate);
|
|
49422
|
+
return candidate;
|
|
49423
|
+
}
|
|
49424
|
+
function scopedWorkerId(runId, value) {
|
|
49425
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
49426
|
+
return slug.startsWith(`${runId}-`) ? slug : `${runId}-${slug || "worker"}`;
|
|
49427
|
+
}
|
|
49428
|
+
function firstParagraph(value) {
|
|
49429
|
+
return value.split(/\n\s*\n/)[0]?.trim().slice(0, 800) || value.trim().slice(0, 800);
|
|
49430
|
+
}
|
|
49431
|
+
function inferVerificationState(value) {
|
|
49432
|
+
const lower = value.toLowerCase();
|
|
49433
|
+
if (lower.includes("partially verified") || lower.includes("partial")) return "partial";
|
|
49434
|
+
if (lower.includes("unverified") || lower.includes("not verified")) return "unverified";
|
|
49435
|
+
if (lower.includes("verified")) return "verified";
|
|
49436
|
+
return "pending";
|
|
49437
|
+
}
|
|
49438
|
+
function dependencyOutputContext(run, spec) {
|
|
49439
|
+
const dependencyIds = spec.dependsOn ?? [];
|
|
49440
|
+
if (dependencyIds.length === 0) return "";
|
|
49441
|
+
const blocks = dependencyIds.map((id) => run.workers.find((worker) => worker.id === id)).filter((worker) => Boolean(worker)).map((worker) => [
|
|
49442
|
+
`## Worker ${worker.id}`,
|
|
49443
|
+
`Role: ${worker.workerRole ?? "task"}`,
|
|
49444
|
+
`Goal: ${worker.goal}`,
|
|
49445
|
+
`Status: ${worker.status}`,
|
|
49446
|
+
worker.summary ? `Summary: ${worker.summary}` : "",
|
|
49447
|
+
worker.details ? `Details:
|
|
49448
|
+
${worker.details}` : ""
|
|
49449
|
+
].filter(Boolean).join("\n"));
|
|
49450
|
+
return blocks.length ? `# Prior worker outputs
|
|
49451
|
+
${blocks.join("\n\n")}` : "";
|
|
49452
|
+
}
|
|
49453
|
+
var terminal, WorkflowManager;
|
|
49454
|
+
var init_manager = __esm({
|
|
49455
|
+
"src/workflows/manager.ts"() {
|
|
49456
|
+
"use strict";
|
|
49457
|
+
init_agent_loop();
|
|
49458
|
+
init_providers();
|
|
49459
|
+
init_planner();
|
|
49460
|
+
init_persistence();
|
|
49461
|
+
init_readOnlyTools();
|
|
49462
|
+
terminal = /* @__PURE__ */ new Set(["cancelled", "completed", "failed"]);
|
|
49463
|
+
WorkflowManager = class {
|
|
49464
|
+
constructor(config, toolRuntime, systemPromptFn, bus, options = {}) {
|
|
49465
|
+
this.config = config;
|
|
49466
|
+
this.toolRuntime = toolRuntime;
|
|
49467
|
+
this.systemPromptFn = systemPromptFn;
|
|
49468
|
+
this.bus = bus;
|
|
49469
|
+
this.planner = options.planner;
|
|
49470
|
+
this.runner = options.runner ?? this.defaultRunner;
|
|
49471
|
+
}
|
|
49472
|
+
config;
|
|
49473
|
+
toolRuntime;
|
|
49474
|
+
systemPromptFn;
|
|
49475
|
+
bus;
|
|
49476
|
+
static {
|
|
49477
|
+
__name(this, "WorkflowManager");
|
|
49478
|
+
}
|
|
49479
|
+
runs = /* @__PURE__ */ new Map();
|
|
49480
|
+
planner;
|
|
49481
|
+
runner;
|
|
49482
|
+
async start(goal, sessionId) {
|
|
49483
|
+
const limits = resolveDynamicWorkflowConfig(this.config);
|
|
49484
|
+
if (!limits.enabled) {
|
|
49485
|
+
throw new Error("dynamic workflows are disabled in config");
|
|
49486
|
+
}
|
|
49487
|
+
const id = `wf-${randomUUID13().slice(0, 8)}`;
|
|
49488
|
+
const plan = await this.buildPlan(goal, id, limits);
|
|
49489
|
+
const now2 = Date.now();
|
|
49490
|
+
const run = {
|
|
49491
|
+
abortController: new AbortController(),
|
|
49492
|
+
activeAborts: /* @__PURE__ */ new Map(),
|
|
49493
|
+
concurrency: plan.concurrency,
|
|
49494
|
+
config: limits,
|
|
49495
|
+
goal,
|
|
49496
|
+
id,
|
|
49497
|
+
plannedWorkerCount: plan.specs.length,
|
|
49498
|
+
startedAt: now2,
|
|
49499
|
+
status: "running",
|
|
49500
|
+
workers: plan.specs.map((spec) => this.workerFromSpec(spec, id, plan.specs.length, now2))
|
|
49501
|
+
};
|
|
49502
|
+
this.runs.set(id, run);
|
|
49503
|
+
this.emitWorkflow("workflow.start", run, sessionId);
|
|
49504
|
+
for (const worker of run.workers) {
|
|
49505
|
+
this.emitSubagent("subagent.spawn_requested", run, worker, sessionId);
|
|
49506
|
+
}
|
|
49507
|
+
void this.executeRun(run, plan.specs, sessionId);
|
|
49508
|
+
return { run: this.snapshot(run), started: true };
|
|
49509
|
+
}
|
|
49510
|
+
status(id) {
|
|
49511
|
+
const run = id ? this.runs.get(id) : this.latestRun();
|
|
49512
|
+
if (run) return this.snapshot(run);
|
|
49513
|
+
if (id) return loadWorkflowSnapshot(id);
|
|
49514
|
+
const first = listWorkflowSnapshots(1)[0];
|
|
49515
|
+
return first ? loadWorkflowSnapshot(first.id) : null;
|
|
49516
|
+
}
|
|
49517
|
+
list(limit = 30) {
|
|
49518
|
+
const live = [...this.runs.values()].map((run) => ({
|
|
49519
|
+
finishedAt: run.finishedAt,
|
|
49520
|
+
goal: run.goal,
|
|
49521
|
+
id: run.id,
|
|
49522
|
+
plannedWorkerCount: run.plannedWorkerCount,
|
|
49523
|
+
startedAt: run.startedAt,
|
|
49524
|
+
status: run.status,
|
|
49525
|
+
workerCount: run.workers.length
|
|
49526
|
+
}));
|
|
49527
|
+
const persisted = listWorkflowSnapshots(limit);
|
|
49528
|
+
const seen = new Set(live.map((entry) => entry.id));
|
|
49529
|
+
return [...live, ...persisted.filter((entry) => !seen.has(entry.id))].sort((a, b) => (b.finishedAt ?? b.startedAt) - (a.finishedAt ?? a.startedAt)).slice(0, Math.max(1, limit));
|
|
49530
|
+
}
|
|
49531
|
+
cancel(id) {
|
|
49532
|
+
const run = this.runs.get(id);
|
|
49533
|
+
if (run) {
|
|
49534
|
+
this.cancelRun(run);
|
|
49535
|
+
return { found: true, run: this.snapshot(run) };
|
|
49536
|
+
}
|
|
49537
|
+
for (const candidate of this.runs.values()) {
|
|
49538
|
+
const worker = candidate.workers.find((item) => item.id === id);
|
|
49539
|
+
if (!worker) continue;
|
|
49540
|
+
candidate.activeAborts.get(worker.id)?.();
|
|
49541
|
+
this.updateWorker(candidate, worker.id, {
|
|
49542
|
+
currentStep: "cancel requested",
|
|
49543
|
+
status: "interrupted"
|
|
49544
|
+
});
|
|
49545
|
+
return { found: true, run: this.snapshot(candidate), workerId: worker.id };
|
|
49546
|
+
}
|
|
49547
|
+
return { found: false };
|
|
49548
|
+
}
|
|
49549
|
+
async buildPlan(goal, runId, limits) {
|
|
49550
|
+
if (this.planner) {
|
|
49551
|
+
return ensureSynthesizer(await this.planner(goal, runId, limits), goal, runId, limits);
|
|
49552
|
+
}
|
|
49553
|
+
try {
|
|
49554
|
+
const provider = createProvider(this.config);
|
|
49555
|
+
const controller = new AbortController();
|
|
49556
|
+
const timer = setTimeout(() => controller.abort(), Math.min(6e4, limits.workerTimeoutMs));
|
|
49557
|
+
try {
|
|
49558
|
+
const result = await provider.chat({
|
|
49559
|
+
systemPrompt: buildPlannerSystemPrompt(limits),
|
|
49560
|
+
messages: [{ role: "user", content: goal }],
|
|
49561
|
+
tools: [],
|
|
49562
|
+
signal: controller.signal
|
|
49563
|
+
});
|
|
49564
|
+
const parsed = parseModelPlan(result.text ?? "", goal, runId, limits);
|
|
49565
|
+
if (parsed.specs.length > 0) return parsed;
|
|
49566
|
+
} finally {
|
|
49567
|
+
clearTimeout(timer);
|
|
49568
|
+
}
|
|
49569
|
+
} catch {
|
|
49570
|
+
}
|
|
49571
|
+
return ensureSynthesizer(planWorkflow(goal, runId, limits), goal, runId, limits);
|
|
49572
|
+
}
|
|
49573
|
+
async executeRun(run, specs, sessionId) {
|
|
49574
|
+
const queue = [...specs];
|
|
49575
|
+
const active = /* @__PURE__ */ new Map();
|
|
49576
|
+
let stableCompletions = 0;
|
|
49577
|
+
try {
|
|
49578
|
+
while ((queue.length > 0 || active.size > 0) && !run.abortController.signal.aborted) {
|
|
49579
|
+
const ready = queue.filter((spec) => this.dependenciesFinished(run, spec));
|
|
49580
|
+
while (ready.length > 0 && active.size < run.concurrency && !run.abortController.signal.aborted) {
|
|
49581
|
+
const spec = ready.shift();
|
|
49582
|
+
queue.splice(queue.indexOf(spec), 1);
|
|
49583
|
+
const promise = this.executeWorker(run, spec, sessionId).then(() => {
|
|
49584
|
+
stableCompletions += 1;
|
|
49585
|
+
if (stableCompletions % Math.max(2, run.concurrency) === 0) {
|
|
49586
|
+
run.concurrency = adjustConcurrency(run.concurrency, run.plannedWorkerCount, run.config, "stable_completion");
|
|
49587
|
+
}
|
|
49588
|
+
}).catch((err) => {
|
|
49589
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
49590
|
+
if (/rate|429|quota|throttle/i.test(message)) {
|
|
49591
|
+
run.concurrency = adjustConcurrency(run.concurrency, run.plannedWorkerCount, run.config, "rate_limited");
|
|
49592
|
+
}
|
|
49593
|
+
}).finally(() => active.delete(spec.id));
|
|
49594
|
+
active.set(spec.id, promise);
|
|
49595
|
+
}
|
|
49596
|
+
if (active.size === 0) break;
|
|
49597
|
+
await Promise.race(active.values());
|
|
49598
|
+
}
|
|
49599
|
+
if (run.abortController.signal.aborted) {
|
|
49600
|
+
for (const worker of run.workers) {
|
|
49601
|
+
if (worker.status === "queued" || worker.status === "running") {
|
|
49602
|
+
this.updateWorker(run, worker.id, { currentStep: "cancelled", status: "interrupted" });
|
|
49603
|
+
}
|
|
49604
|
+
}
|
|
49605
|
+
run.status = "cancelled";
|
|
49606
|
+
run.summary = this.summarize(run, "cancelled");
|
|
49607
|
+
} else if (run.workers.some((worker) => worker.status === "failed")) {
|
|
49608
|
+
run.status = "failed";
|
|
49609
|
+
run.summary = this.summarize(run, "failed");
|
|
49610
|
+
} else {
|
|
49611
|
+
run.status = "completed";
|
|
49612
|
+
run.summary = this.summarize(run, "completed");
|
|
49613
|
+
}
|
|
49614
|
+
} catch (err) {
|
|
49615
|
+
run.status = "failed";
|
|
49616
|
+
run.summary = `Workflow failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
49617
|
+
} finally {
|
|
49618
|
+
run.finishedAt = Date.now();
|
|
49619
|
+
if (run.config.persistHistory) saveWorkflowSnapshot(this.snapshot(run));
|
|
49620
|
+
this.emitWorkflow(run.status === "failed" ? "workflow.error" : "workflow.complete", run, sessionId);
|
|
49621
|
+
}
|
|
49622
|
+
}
|
|
49623
|
+
async executeWorker(run, spec, sessionId) {
|
|
49624
|
+
if (run.abortController.signal.aborted) return;
|
|
49625
|
+
this.updateWorker(run, spec.id, {
|
|
49626
|
+
currentStep: "starting",
|
|
49627
|
+
startedAt: Date.now(),
|
|
49628
|
+
status: "running"
|
|
49629
|
+
});
|
|
49630
|
+
this.emitSubagent("subagent.start", run, this.worker(run, spec.id), sessionId);
|
|
49631
|
+
const controller = new AbortController();
|
|
49632
|
+
const timeoutMs = spec.role === "synthesizer" ? run.config.workerTimeoutMs * 3 : run.config.workerTimeoutMs;
|
|
49633
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
49634
|
+
run.activeAborts.set(spec.id, () => controller.abort());
|
|
49635
|
+
const signal = AbortSignal.any([controller.signal, run.abortController.signal]);
|
|
49636
|
+
try {
|
|
49637
|
+
const result = await this.runner({
|
|
49638
|
+
config: this.config,
|
|
49639
|
+
run: this.snapshot(run),
|
|
49640
|
+
signal,
|
|
49641
|
+
spec,
|
|
49642
|
+
systemPromptFn: this.systemPromptFn,
|
|
49643
|
+
toolRuntime: new ReadOnlyToolRuntime(this.toolRuntime),
|
|
49644
|
+
update: /* @__PURE__ */ __name((patch) => {
|
|
49645
|
+
this.updateWorker(run, spec.id, patch);
|
|
49646
|
+
this.emitSubagent("subagent.progress", run, this.worker(run, spec.id), sessionId);
|
|
49647
|
+
}, "update")
|
|
49648
|
+
});
|
|
49649
|
+
this.updateWorker(run, spec.id, {
|
|
49650
|
+
currentStep: "complete",
|
|
49651
|
+
details: result,
|
|
49652
|
+
durationSeconds: (Date.now() - (this.worker(run, spec.id).startedAt ?? Date.now())) / 1e3,
|
|
49653
|
+
status: signal.aborted ? "interrupted" : "completed",
|
|
49654
|
+
summary: firstParagraph(result),
|
|
49655
|
+
verificationState: spec.role === "verifier" ? inferVerificationState(result) : "not_applicable"
|
|
49656
|
+
});
|
|
49657
|
+
} catch (err) {
|
|
49658
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
49659
|
+
this.updateWorker(run, spec.id, {
|
|
49660
|
+
currentStep: signal.aborted ? "interrupted" : "failed",
|
|
49661
|
+
details: message,
|
|
49662
|
+
durationSeconds: (Date.now() - (this.worker(run, spec.id).startedAt ?? Date.now())) / 1e3,
|
|
49663
|
+
status: signal.aborted ? "interrupted" : "failed",
|
|
49664
|
+
summary: message,
|
|
49665
|
+
verificationState: "unverified"
|
|
49666
|
+
});
|
|
49667
|
+
if (!signal.aborted) throw err;
|
|
49668
|
+
} finally {
|
|
49669
|
+
clearTimeout(timeout);
|
|
49670
|
+
run.activeAborts.delete(spec.id);
|
|
49671
|
+
this.emitSubagent("subagent.complete", run, this.worker(run, spec.id), sessionId);
|
|
49672
|
+
if (run.config.persistHistory) saveWorkflowSnapshot(this.snapshot(run));
|
|
49673
|
+
}
|
|
49674
|
+
}
|
|
49675
|
+
defaultRunner = /* @__PURE__ */ __name(async (ctx) => {
|
|
49676
|
+
const workerConfig = {
|
|
49677
|
+
...ctx.config,
|
|
49678
|
+
features: { ...ctx.config.features, skill_auto_suggest: false }
|
|
49679
|
+
};
|
|
49680
|
+
const loop = new AgentLoop(workerConfig, ctx.toolRuntime);
|
|
49681
|
+
const sections = await ctx.systemPromptFn();
|
|
49682
|
+
const systemPrompt = [
|
|
49683
|
+
...sections,
|
|
49684
|
+
"# Advisory Workflow Worker Rules",
|
|
49685
|
+
"You are a read-only workflow worker. Never modify files, execute shell/code, send messages, update memory, or perform browser actions that change state.",
|
|
49686
|
+
"Use available read/search tools only. Return concise evidence-backed findings."
|
|
49687
|
+
].filter(Boolean).join("\n\n");
|
|
49688
|
+
ctx.signal.addEventListener("abort", () => loop.abort(), { once: true });
|
|
49689
|
+
let answer = "";
|
|
49690
|
+
let streamedText = "";
|
|
49691
|
+
let outputTail = [];
|
|
49692
|
+
let toolCount = 0;
|
|
49693
|
+
const userPrompt = [ctx.spec.prompt, dependencyOutputContext(ctx.run, ctx.spec)].filter(Boolean).join("\n\n");
|
|
49694
|
+
for await (const chunk of loop.run(userPrompt, systemPrompt)) {
|
|
49695
|
+
if (ctx.signal.aborted) {
|
|
49696
|
+
loop.abort();
|
|
49697
|
+
break;
|
|
49698
|
+
}
|
|
49699
|
+
if (chunk.type === "thinking" && chunk.content.trim()) {
|
|
49700
|
+
streamedText += chunk.content;
|
|
49701
|
+
ctx.update({ currentStep: chunk.content.trim().slice(0, 180), thinking: [chunk.content.trim().slice(0, 500)] });
|
|
49702
|
+
}
|
|
49703
|
+
if (chunk.type === "tool_call") {
|
|
49704
|
+
toolCount += 1;
|
|
49705
|
+
ctx.update({ currentStep: `using ${chunk.toolName ?? "tool"}`, toolCount, tools: [`${chunk.toolName ?? "tool"}(...)`] });
|
|
49706
|
+
}
|
|
49707
|
+
if (chunk.type === "tool_result") {
|
|
49708
|
+
outputTail = [...outputTail, { isError: /error/i.test(chunk.content), preview: chunk.content.slice(0, 240), tool: chunk.toolName ?? "tool" }].slice(-8);
|
|
49709
|
+
ctx.update({ outputTail });
|
|
49710
|
+
}
|
|
49711
|
+
if (chunk.type === "answer" && chunk.content.trim()) answer = chunk.content.trim();
|
|
49712
|
+
}
|
|
49713
|
+
const result = answer || streamedText.trim();
|
|
49714
|
+
if (ctx.signal.aborted) {
|
|
49715
|
+
if (result) {
|
|
49716
|
+
return `${result}
|
|
49717
|
+
|
|
49718
|
+
[Partial output preserved after worker interruption.]`;
|
|
49719
|
+
}
|
|
49720
|
+
throw new Error("worker interrupted");
|
|
49721
|
+
}
|
|
49722
|
+
return result || "Worker completed with no final answer.";
|
|
49723
|
+
}, "defaultRunner");
|
|
49724
|
+
workerFromSpec(spec, workflowId, taskCount, now2) {
|
|
49725
|
+
return {
|
|
49726
|
+
currentStep: "queued",
|
|
49727
|
+
depth: spec.depth,
|
|
49728
|
+
goal: spec.goal,
|
|
49729
|
+
id: spec.id,
|
|
49730
|
+
index: spec.index,
|
|
49731
|
+
notes: [],
|
|
49732
|
+
parentId: spec.parentId,
|
|
49733
|
+
startedAt: now2,
|
|
49734
|
+
status: "queued",
|
|
49735
|
+
taskCount,
|
|
49736
|
+
thinking: [],
|
|
49737
|
+
toolCount: 0,
|
|
49738
|
+
tools: [],
|
|
49739
|
+
verificationState: spec.role === "verifier" ? "pending" : "not_applicable",
|
|
49740
|
+
workflowId,
|
|
49741
|
+
workerRole: spec.role
|
|
49742
|
+
};
|
|
49743
|
+
}
|
|
49744
|
+
dependenciesFinished(run, spec) {
|
|
49745
|
+
return (spec.dependsOn ?? []).every((id) => {
|
|
49746
|
+
const status = run.workers.find((worker) => worker.id === id)?.status;
|
|
49747
|
+
return status === "completed" || status === "failed" || status === "interrupted";
|
|
49748
|
+
});
|
|
49749
|
+
}
|
|
49750
|
+
updateWorker(run, id, patch) {
|
|
49751
|
+
run.workers = run.workers.map((worker) => worker.id === id ? { ...worker, ...patch } : worker);
|
|
49752
|
+
}
|
|
49753
|
+
worker(run, id) {
|
|
49754
|
+
return run.workers.find((worker) => worker.id === id) ?? run.workers[0];
|
|
49755
|
+
}
|
|
49756
|
+
snapshot(run) {
|
|
49757
|
+
return {
|
|
49758
|
+
concurrency: run.concurrency,
|
|
49759
|
+
finishedAt: run.finishedAt,
|
|
49760
|
+
goal: run.goal,
|
|
49761
|
+
id: run.id,
|
|
49762
|
+
plannedWorkerCount: run.plannedWorkerCount,
|
|
49763
|
+
startedAt: run.startedAt,
|
|
49764
|
+
status: run.status,
|
|
49765
|
+
summary: run.summary,
|
|
49766
|
+
workers: run.workers.map((worker) => ({ ...worker }))
|
|
49767
|
+
};
|
|
49768
|
+
}
|
|
49769
|
+
latestRun() {
|
|
49770
|
+
const runs = [...this.runs.values()].sort((a, b) => b.startedAt - a.startedAt);
|
|
49771
|
+
return runs[0] ?? null;
|
|
49772
|
+
}
|
|
49773
|
+
cancelRun(run) {
|
|
49774
|
+
if (terminal.has(run.status)) return;
|
|
49775
|
+
run.abortController.abort();
|
|
49776
|
+
for (const abort of run.activeAborts.values()) abort();
|
|
49777
|
+
run.status = "cancelled";
|
|
49778
|
+
}
|
|
49779
|
+
summarize(run, status) {
|
|
49780
|
+
const synthesizer = run.workers.find((worker) => worker.workerRole === "synthesizer" && worker.details && worker.details !== "worker interrupted");
|
|
49781
|
+
if ((status === "completed" || status === "cancelled" || status === "failed") && synthesizer?.details) {
|
|
49782
|
+
return [synthesizer.details, "No files were modified by advisory workflow workers."].join("\n\n");
|
|
49783
|
+
}
|
|
49784
|
+
const counts = run.workers.reduce((acc, worker) => {
|
|
49785
|
+
acc[worker.status] = (acc[worker.status] ?? 0) + 1;
|
|
49786
|
+
return acc;
|
|
49787
|
+
}, {});
|
|
49788
|
+
const highlights = run.workers.filter((worker) => worker.summary).slice(0, 8).map((worker) => `- ${worker.goal}: ${worker.summary}`).join("\n");
|
|
49789
|
+
return [
|
|
49790
|
+
`Workflow ${status}: ${run.goal}`,
|
|
49791
|
+
`Workers: ${run.workers.length} planned \xB7 ${counts.completed ?? 0} completed \xB7 ${counts.failed ?? 0} failed \xB7 ${counts.interrupted ?? 0} interrupted.`,
|
|
49792
|
+
"No files were modified by advisory workflow workers.",
|
|
49793
|
+
highlights ? `
|
|
49794
|
+
Key worker summaries:
|
|
49795
|
+
${highlights}` : ""
|
|
49796
|
+
].filter(Boolean).join("\n");
|
|
49797
|
+
}
|
|
49798
|
+
emitWorkflow(type, run, sessionId) {
|
|
49799
|
+
this.bus.emitEvent({
|
|
49800
|
+
payload: this.snapshot(run),
|
|
49801
|
+
session_id: sessionId ?? void 0,
|
|
49802
|
+
type
|
|
49803
|
+
});
|
|
49804
|
+
}
|
|
49805
|
+
emitSubagent(type, run, worker, sessionId) {
|
|
49806
|
+
this.bus.emitEvent({
|
|
49807
|
+
payload: {
|
|
49808
|
+
cost_usd: worker.costUsd,
|
|
49809
|
+
current_step: worker.currentStep,
|
|
49810
|
+
depth: worker.depth,
|
|
49811
|
+
details: worker.details,
|
|
49812
|
+
duration_seconds: worker.durationSeconds,
|
|
49813
|
+
files_read: worker.filesRead,
|
|
49814
|
+
files_written: worker.filesWritten,
|
|
49815
|
+
goal: worker.goal,
|
|
49816
|
+
input_tokens: worker.inputTokens,
|
|
49817
|
+
output_tail: worker.outputTail?.map((entry) => ({ is_error: entry.isError, preview: entry.preview, tool: entry.tool })),
|
|
49818
|
+
output_tokens: worker.outputTokens,
|
|
49819
|
+
parent_id: worker.parentId,
|
|
49820
|
+
status: worker.status,
|
|
49821
|
+
subagent_id: worker.id,
|
|
49822
|
+
summary: worker.summary,
|
|
49823
|
+
task_count: worker.taskCount,
|
|
49824
|
+
task_index: worker.index,
|
|
49825
|
+
text: worker.currentStep ?? worker.summary,
|
|
49826
|
+
tool_count: worker.toolCount,
|
|
49827
|
+
verification_state: worker.verificationState,
|
|
49828
|
+
workflow_id: run.id,
|
|
49829
|
+
worker_role: worker.workerRole
|
|
49830
|
+
},
|
|
49831
|
+
session_id: sessionId ?? void 0,
|
|
49832
|
+
type
|
|
49833
|
+
});
|
|
49834
|
+
}
|
|
49835
|
+
};
|
|
49836
|
+
__name(buildPlannerSystemPrompt, "buildPlannerSystemPrompt");
|
|
49837
|
+
__name(parseModelPlan, "parseModelPlan");
|
|
49838
|
+
__name(ensureSynthesizer, "ensureSynthesizer");
|
|
49839
|
+
__name(buildModelWorkerPrompt, "buildModelWorkerPrompt");
|
|
49840
|
+
__name(normalizeRole, "normalizeRole");
|
|
49841
|
+
__name(extractJsonObject, "extractJsonObject");
|
|
49842
|
+
__name(uniqueWorkerId, "uniqueWorkerId");
|
|
49843
|
+
__name(scopedWorkerId, "scopedWorkerId");
|
|
49844
|
+
__name(firstParagraph, "firstParagraph");
|
|
49845
|
+
__name(inferVerificationState, "inferVerificationState");
|
|
49846
|
+
__name(dependencyOutputContext, "dependencyOutputContext");
|
|
49847
|
+
}
|
|
49848
|
+
});
|
|
49849
|
+
|
|
49850
|
+
// src/rpcHandlers.ts
|
|
49851
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
49852
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
49853
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync18, readFileSync as readFileSync29, rmSync, statSync as statSync4, writeFileSync as writeFileSync20 } from "node:fs";
|
|
49854
|
+
import { homedir as homedir29 } from "node:os";
|
|
49855
|
+
import { basename as basename4, extname as extname4, join as join43 } from "node:path";
|
|
48965
49856
|
function registerRpcHandlers(options) {
|
|
48966
49857
|
const { agentConfig, agentLoop, bridgeEmitter, bridgeManager, bus, mcpManager, systemPromptFn, toolRegistry, voiceManager } = options;
|
|
48967
49858
|
let currentRun = null;
|
|
48968
49859
|
const pendingResponders = /* @__PURE__ */ new Map();
|
|
48969
49860
|
const promptCollector = createPromptCollector(bus, () => agentLoop.sessionId);
|
|
49861
|
+
const workflowManager = new WorkflowManager(agentConfig, toolRegistry, systemPromptFn, bus);
|
|
48970
49862
|
const OAUTH_FLOW_TTL_MS = 15 * 60 * 1e3;
|
|
48971
49863
|
const oauthFlows = /* @__PURE__ */ new Map();
|
|
48972
49864
|
const cleanupOAuthFlow = /* @__PURE__ */ __name((flowId, abort) => {
|
|
@@ -48985,7 +49877,7 @@ function registerRpcHandlers(options) {
|
|
|
48985
49877
|
const user = bridgeUser(rawEvent, source);
|
|
48986
49878
|
const text = formatBridgeText(rawEvent, source, user);
|
|
48987
49879
|
bus.emitEvent({
|
|
48988
|
-
payload: { source, task_id:
|
|
49880
|
+
payload: { source, task_id: randomUUID14(), text, user },
|
|
48989
49881
|
session_id: agentLoop.sessionId,
|
|
48990
49882
|
type: "bridge.message"
|
|
48991
49883
|
});
|
|
@@ -48994,7 +49886,7 @@ function registerRpcHandlers(options) {
|
|
|
48994
49886
|
bus.registerRpc("setup.status", () => {
|
|
48995
49887
|
const hasConfigKey = Boolean(agentConfig.llm.api_key && agentConfig.llm.api_key !== "proxy-token");
|
|
48996
49888
|
const hasEnvKey = Boolean(
|
|
48997
|
-
process.env.ANTHROPIC_AUTH_TOKEN || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GITHUB_TOKEN
|
|
49889
|
+
process.env.ANTHROPIC_AUTH_TOKEN || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GITHUB_COPILOT_TOKEN || process.env.GITHUB_TOKEN
|
|
48998
49890
|
);
|
|
48999
49891
|
const hasStoredCredential = PROVIDERS2.some((p) => {
|
|
49000
49892
|
try {
|
|
@@ -49342,12 +50234,12 @@ ${helpMessage}` : field.label;
|
|
|
49342
50234
|
const id = String(params.session_id ?? agentLoop.sessionId) || agentLoop.sessionId;
|
|
49343
50235
|
const data = loadSession(id);
|
|
49344
50236
|
const messages = data?.messages ?? agentLoop.history;
|
|
49345
|
-
const exportDir =
|
|
49346
|
-
if (!
|
|
49347
|
-
|
|
50237
|
+
const exportDir = join43(homedir29(), ".openjaw-agent", "exports");
|
|
50238
|
+
if (!existsSync32(exportDir)) {
|
|
50239
|
+
mkdirSync18(exportDir, { recursive: true });
|
|
49348
50240
|
}
|
|
49349
50241
|
const safeId = id.replace(/[^a-zA-Z0-9_.-]/g, "_") || agentLoop.sessionId;
|
|
49350
|
-
const file2 =
|
|
50242
|
+
const file2 = join43(exportDir, `session-${safeId}.md`);
|
|
49351
50243
|
const lines = [
|
|
49352
50244
|
`# OpenJaw Agent Session ${id}`,
|
|
49353
50245
|
`Date: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -49360,7 +50252,7 @@ ${helpMessage}` : field.label;
|
|
|
49360
50252
|
for (const message of messages) {
|
|
49361
50253
|
lines.push(...sessionMessageToMarkdown(message));
|
|
49362
50254
|
}
|
|
49363
|
-
|
|
50255
|
+
writeFileSync20(file2, lines.join("\n"), "utf-8");
|
|
49364
50256
|
return { file: file2, message_count: messages.length };
|
|
49365
50257
|
});
|
|
49366
50258
|
bus.registerRpc("session.interrupt", () => {
|
|
@@ -49377,8 +50269,8 @@ ${helpMessage}` : field.label;
|
|
|
49377
50269
|
return { deleted: "" };
|
|
49378
50270
|
}
|
|
49379
50271
|
try {
|
|
49380
|
-
const file2 =
|
|
49381
|
-
if (
|
|
50272
|
+
const file2 = join43(homedir29(), ".openjaw-agent", "sessions", `${id}.json`);
|
|
50273
|
+
if (existsSync32(file2)) {
|
|
49382
50274
|
rmSync(file2);
|
|
49383
50275
|
}
|
|
49384
50276
|
return { deleted: id };
|
|
@@ -49451,11 +50343,11 @@ ${helpMessage}` : field.label;
|
|
|
49451
50343
|
bus.registerRpc("shell.exec", async (params) => {
|
|
49452
50344
|
const command = String(params.command ?? "");
|
|
49453
50345
|
if (!command) return { code: -1, stderr: "empty command" };
|
|
49454
|
-
return await new Promise((
|
|
50346
|
+
return await new Promise((resolve6) => {
|
|
49455
50347
|
const isWin = process.platform === "win32";
|
|
49456
50348
|
const shell = isWin ? "powershell.exe" : "sh";
|
|
49457
50349
|
const args = isWin ? ["-NoProfile", "-Command", command] : ["-c", command];
|
|
49458
|
-
const child =
|
|
50350
|
+
const child = spawn6(shell, args, { timeout: 3e4 });
|
|
49459
50351
|
let stdout = "";
|
|
49460
50352
|
let stderr = "";
|
|
49461
50353
|
let truncated = false;
|
|
@@ -49478,10 +50370,10 @@ ${helpMessage}` : field.label;
|
|
|
49478
50370
|
if (truncated) {
|
|
49479
50371
|
stderr += "\n[output truncated to 1MB]";
|
|
49480
50372
|
}
|
|
49481
|
-
|
|
50373
|
+
resolve6({ code: code ?? -1, stderr, stdout });
|
|
49482
50374
|
});
|
|
49483
50375
|
child.on("error", (err) => {
|
|
49484
|
-
|
|
50376
|
+
resolve6({ code: -1, stderr: err.message });
|
|
49485
50377
|
});
|
|
49486
50378
|
});
|
|
49487
50379
|
});
|
|
@@ -49603,7 +50495,7 @@ ${helpMessage}` : field.label;
|
|
|
49603
50495
|
return agentConfig.llm.copilot_enterprise_url;
|
|
49604
50496
|
})();
|
|
49605
50497
|
const flow = await startCopilotDeviceFlow(clientId, enterpriseUrl);
|
|
49606
|
-
const flowId =
|
|
50498
|
+
const flowId = randomUUID14();
|
|
49607
50499
|
const controller = new AbortController();
|
|
49608
50500
|
const timer = setTimeout(() => {
|
|
49609
50501
|
cleanupOAuthFlow(flowId, true);
|
|
@@ -49767,7 +50659,7 @@ ${helpMessage}` : field.label;
|
|
|
49767
50659
|
Object.assign(agentConfig.llm, result.configUpdates);
|
|
49768
50660
|
bus.emitEvent({ payload: sessionInfoSnapshot(agentLoop, toolRegistry), session_id: agentLoop.sessionId, type: "session.info" });
|
|
49769
50661
|
}
|
|
49770
|
-
return { messages };
|
|
50662
|
+
return { config_updates: result.configUpdates, messages };
|
|
49771
50663
|
});
|
|
49772
50664
|
bus.registerRpc("provider.disconnect", (params) => {
|
|
49773
50665
|
const provider = String(params.provider ?? "").trim();
|
|
@@ -49827,6 +50719,32 @@ ${helpMessage}` : field.label;
|
|
|
49827
50719
|
tasks: forks.map((task) => ({ id: task.id, prompt: task.prompt, status: task.status }))
|
|
49828
50720
|
};
|
|
49829
50721
|
});
|
|
50722
|
+
bus.registerRpc("workflow.start", async (params) => {
|
|
50723
|
+
const goal = String(params.goal ?? params.prompt ?? "").trim();
|
|
50724
|
+
if (!goal) return { error: "usage: /workflow <goal>", ok: false };
|
|
50725
|
+
const result = await workflowManager.start(goal, agentLoop.sessionId);
|
|
50726
|
+
return { ok: true, run: result.run };
|
|
50727
|
+
});
|
|
50728
|
+
bus.registerRpc("workflow.status", (params) => {
|
|
50729
|
+
const id = String(params.id ?? params.run_id ?? "").trim();
|
|
50730
|
+
const run = workflowManager.status(id || void 0);
|
|
50731
|
+
return run ? { ok: true, run } : { error: id ? `workflow not found: ${id}` : "no workflows yet", ok: false };
|
|
50732
|
+
});
|
|
50733
|
+
bus.registerRpc("workflow.list", (params) => {
|
|
50734
|
+
const limit = Number(params.limit ?? 30);
|
|
50735
|
+
return { ok: true, runs: workflowManager.list(Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 30) };
|
|
50736
|
+
});
|
|
50737
|
+
bus.registerRpc("workflow.show", (params) => {
|
|
50738
|
+
const id = String(params.id ?? params.run_id ?? "").trim();
|
|
50739
|
+
const run = workflowManager.status(id || void 0);
|
|
50740
|
+
return run ? { ok: true, run, summary: run.summary ?? "" } : { error: id ? `workflow not found: ${id}` : "no workflows yet", ok: false };
|
|
50741
|
+
});
|
|
50742
|
+
bus.registerRpc("workflow.cancel", (params) => {
|
|
50743
|
+
const id = String(params.id ?? params.run_id ?? params.worker_id ?? "").trim();
|
|
50744
|
+
if (!id) return { error: "usage: /workflow cancel <runId|workerId>", ok: false };
|
|
50745
|
+
const result = workflowManager.cancel(id);
|
|
50746
|
+
return result.found ? { ok: true, ...result } : { error: `workflow or worker not found: ${id}`, ok: false };
|
|
50747
|
+
});
|
|
49830
50748
|
bus.registerRpc("schedule.add", (params) => {
|
|
49831
50749
|
const prompt = String(params.prompt ?? "").trim();
|
|
49832
50750
|
const raw = String(params.schedule ?? "").trim();
|
|
@@ -50097,13 +51015,13 @@ ${helpMessage}` : field.label;
|
|
|
50097
51015
|
const firstSpace = raw.search(/\s/);
|
|
50098
51016
|
const path3 = firstSpace > 0 ? raw.slice(0, firstSpace) : raw;
|
|
50099
51017
|
const remainder = firstSpace > 0 ? raw.slice(firstSpace).trim() : "";
|
|
50100
|
-
if (!
|
|
51018
|
+
if (!existsSync32(path3)) {
|
|
50101
51019
|
throw new Error(`image.attach: file not found: ${path3}`);
|
|
50102
51020
|
}
|
|
50103
51021
|
let buffer;
|
|
50104
51022
|
let fileSize = 0;
|
|
50105
51023
|
try {
|
|
50106
|
-
buffer =
|
|
51024
|
+
buffer = readFileSync29(path3);
|
|
50107
51025
|
fileSize = statSync4(path3).size;
|
|
50108
51026
|
} catch (err) {
|
|
50109
51027
|
throw new Error(`image.attach: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -50113,12 +51031,12 @@ ${helpMessage}` : field.label;
|
|
|
50113
51031
|
pendingImage = {
|
|
50114
51032
|
base64: buffer.toString("base64"),
|
|
50115
51033
|
mimeType,
|
|
50116
|
-
name:
|
|
51034
|
+
name: basename4(path3)
|
|
50117
51035
|
};
|
|
50118
51036
|
const tokenEstimate = Math.max(1, Math.ceil(buffer.byteLength / 750));
|
|
50119
51037
|
return {
|
|
50120
51038
|
height: 0,
|
|
50121
|
-
name:
|
|
51039
|
+
name: basename4(path3),
|
|
50122
51040
|
remainder,
|
|
50123
51041
|
token_estimate: tokenEstimate,
|
|
50124
51042
|
width: 0
|
|
@@ -50149,13 +51067,13 @@ ${helpMessage}` : field.label;
|
|
|
50149
51067
|
}
|
|
50150
51068
|
});
|
|
50151
51069
|
bus.registerRpc("reload.env", () => {
|
|
50152
|
-
const envPath =
|
|
50153
|
-
if (!
|
|
51070
|
+
const envPath = join43(homedir29(), ".openjaw-agent", ".env");
|
|
51071
|
+
if (!existsSync32(envPath)) {
|
|
50154
51072
|
return { updated: 0 };
|
|
50155
51073
|
}
|
|
50156
51074
|
let updated = 0;
|
|
50157
51075
|
try {
|
|
50158
|
-
const raw =
|
|
51076
|
+
const raw = readFileSync29(envPath, "utf-8");
|
|
50159
51077
|
for (const line of raw.split(/\r?\n/)) {
|
|
50160
51078
|
const trimmed = line.trim();
|
|
50161
51079
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -50195,8 +51113,25 @@ ${helpMessage}` : field.label;
|
|
|
50195
51113
|
error: "checkpoints are not enabled in this build",
|
|
50196
51114
|
success: false
|
|
50197
51115
|
}));
|
|
50198
|
-
bus.registerRpc("spawn_tree.
|
|
50199
|
-
|
|
51116
|
+
bus.registerRpc("spawn_tree.save", (params) => ({
|
|
51117
|
+
path: saveSpawnTreeSnapshot({
|
|
51118
|
+
finished_at: typeof params.finished_at === "number" ? params.finished_at : Date.now() / 1e3,
|
|
51119
|
+
label: typeof params.label === "string" ? params.label : void 0,
|
|
51120
|
+
session_id: typeof params.session_id === "string" ? params.session_id : agentLoop.sessionId ?? "default",
|
|
51121
|
+
started_at: typeof params.started_at === "number" || params.started_at === null ? params.started_at : null,
|
|
51122
|
+
subagents: Array.isArray(params.subagents) ? params.subagents : []
|
|
51123
|
+
})
|
|
51124
|
+
}));
|
|
51125
|
+
bus.registerRpc("spawn_tree.list", (params) => ({
|
|
51126
|
+
entries: listSpawnTreeSnapshots(
|
|
51127
|
+
typeof params.session_id === "string" ? params.session_id : agentLoop.sessionId ?? "default",
|
|
51128
|
+
typeof params.limit === "number" ? params.limit : 30
|
|
51129
|
+
)
|
|
51130
|
+
}));
|
|
51131
|
+
bus.registerRpc("spawn_tree.load", (params) => {
|
|
51132
|
+
const path3 = String(params.path ?? "").trim();
|
|
51133
|
+
return path3 ? loadSpawnTreeSnapshot(path3) ?? { subagents: [] } : { subagents: [] };
|
|
51134
|
+
});
|
|
50200
51135
|
bus.registerRpc("skills.reload", async () => {
|
|
50201
51136
|
try {
|
|
50202
51137
|
clearSkillsCache();
|
|
@@ -50280,9 +51215,19 @@ ${helpMessage}` : field.label;
|
|
|
50280
51215
|
}
|
|
50281
51216
|
return { output: name ? `unknown command: /${name}` : "(no command)", type: "exec" };
|
|
50282
51217
|
});
|
|
50283
|
-
bus.registerRpc("delegation.status", () => ({
|
|
51218
|
+
bus.registerRpc("delegation.status", () => ({
|
|
51219
|
+
active: [],
|
|
51220
|
+
max_concurrent_children: agentConfig.features?.dynamic_workflows?.hard_max_concurrent_workers ?? 128,
|
|
51221
|
+
max_spawn_depth: agentConfig.features?.dynamic_workflows?.hard_max_workers ?? 1024,
|
|
51222
|
+
paused: false
|
|
51223
|
+
}));
|
|
50284
51224
|
bus.registerRpc("delegation.pause", (params) => ({ paused: Boolean(params.paused) }));
|
|
50285
|
-
bus.registerRpc("subagent.interrupt", () =>
|
|
51225
|
+
bus.registerRpc("subagent.interrupt", (params) => {
|
|
51226
|
+
const id = String(params.subagent_id ?? "").trim();
|
|
51227
|
+
if (!id) return { found: false };
|
|
51228
|
+
const result = workflowManager.cancel(id);
|
|
51229
|
+
return { found: result.found, subagent_id: id };
|
|
51230
|
+
});
|
|
50286
51231
|
syncMcpTools(mcpManager, toolRegistry);
|
|
50287
51232
|
bus.emitEvent({
|
|
50288
51233
|
payload: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
@@ -50330,6 +51275,8 @@ var init_rpcHandlers = __esm({
|
|
|
50330
51275
|
init_registry2();
|
|
50331
51276
|
init_usage();
|
|
50332
51277
|
init_usageSnapshot();
|
|
51278
|
+
init_manager();
|
|
51279
|
+
init_persistence();
|
|
50333
51280
|
init_registry3();
|
|
50334
51281
|
PROVIDERS2 = ["anthropic", "openai", "github-copilot"];
|
|
50335
51282
|
PROVIDER_LABELS = {
|
|
@@ -50515,8 +51462,8 @@ var init_rpcHandlers = __esm({
|
|
|
50515
51462
|
${raw}`;
|
|
50516
51463
|
return `${header}: ${raw}`;
|
|
50517
51464
|
}, "formatBridgeText");
|
|
50518
|
-
runProcess = /* @__PURE__ */ __name((command, args, timeout = 2e4) => new Promise((
|
|
50519
|
-
const child =
|
|
51465
|
+
runProcess = /* @__PURE__ */ __name((command, args, timeout = 2e4) => new Promise((resolve6) => {
|
|
51466
|
+
const child = spawn6(command, args, { timeout, windowsHide: true });
|
|
50520
51467
|
let stdout = "";
|
|
50521
51468
|
let stderr = "";
|
|
50522
51469
|
let truncated = false;
|
|
@@ -50539,9 +51486,9 @@ ${raw}`;
|
|
|
50539
51486
|
if (truncated) {
|
|
50540
51487
|
stderr += "\n[output truncated to 1MB]";
|
|
50541
51488
|
}
|
|
50542
|
-
|
|
51489
|
+
resolve6({ code: code ?? -1, stderr, stdout });
|
|
50543
51490
|
});
|
|
50544
|
-
child.on("error", (err) =>
|
|
51491
|
+
child.on("error", (err) => resolve6({ code: -1, stderr: err.message, stdout }));
|
|
50545
51492
|
}), "runProcess");
|
|
50546
51493
|
contentToText = /* @__PURE__ */ __name((content) => {
|
|
50547
51494
|
if (typeof content === "string") return content;
|
|
@@ -50699,14 +51646,14 @@ var init_memoryMonitor = __esm({
|
|
|
50699
51646
|
});
|
|
50700
51647
|
|
|
50701
51648
|
// src/lib/openExternalUrl.ts
|
|
50702
|
-
import { spawn as
|
|
51649
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
50703
51650
|
import { platform } from "node:os";
|
|
50704
51651
|
function openExternalUrl(rawUrl, dependencies = {}) {
|
|
50705
51652
|
const url = parseSafeUrl(rawUrl);
|
|
50706
51653
|
if (!url) {
|
|
50707
51654
|
return false;
|
|
50708
51655
|
}
|
|
50709
|
-
const spawnFn = dependencies.spawn ??
|
|
51656
|
+
const spawnFn = dependencies.spawn ?? spawn7;
|
|
50710
51657
|
const platformId = dependencies.platform?.() ?? platform();
|
|
50711
51658
|
const command = openCommand(platformId);
|
|
50712
51659
|
if (!command) {
|
|
@@ -51496,7 +52443,7 @@ async function terminalParityHints(env2 = process.env, options) {
|
|
|
51496
52443
|
hints.push({
|
|
51497
52444
|
key: "remote",
|
|
51498
52445
|
tone: "warn",
|
|
51499
|
-
message: "SSH session detected \xB7 text clipboard can bridge via OSC52, but image clipboard and local screenshot paths still depend on the machine running
|
|
52446
|
+
message: "SSH session detected \xB7 text clipboard can bridge via OSC52, but image clipboard and local screenshot paths still depend on the machine running OpenJaw"
|
|
51500
52447
|
});
|
|
51501
52448
|
}
|
|
51502
52449
|
return hints;
|
|
@@ -51601,13 +52548,13 @@ var init_setup2 = __esm({
|
|
|
51601
52548
|
SETUP_REQUIRED_TITLE = "Setup Required";
|
|
51602
52549
|
buildSetupRequiredSections = /* @__PURE__ */ __name(() => [
|
|
51603
52550
|
{
|
|
51604
|
-
text: "
|
|
52551
|
+
text: "OpenJaw needs a model provider before the TUI can start a session. Run /connect to set up a provider, then /model to choose a model."
|
|
51605
52552
|
},
|
|
51606
52553
|
{
|
|
51607
52554
|
rows: [
|
|
51608
|
-
["/
|
|
51609
|
-
["/
|
|
51610
|
-
["Ctrl+C", "exit and
|
|
52555
|
+
["/connect", "set up provider credentials in-place"],
|
|
52556
|
+
["/model", "choose or switch model after connecting"],
|
|
52557
|
+
["Ctrl+C", "exit and restart OpenJaw after setup if needed"]
|
|
51611
52558
|
],
|
|
51612
52559
|
title: "Actions"
|
|
51613
52560
|
}
|
|
@@ -51910,7 +52857,7 @@ var init_reasoning2 = __esm({
|
|
|
51910
52857
|
});
|
|
51911
52858
|
|
|
51912
52859
|
// src/app/turnStore.ts
|
|
51913
|
-
import { atom as
|
|
52860
|
+
import { atom as atom6 } from "nanostores";
|
|
51914
52861
|
import { useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
51915
52862
|
var buildTurnState, $turnState, getTurnState, subscribeTurn, useTurnSelector, patchTurnState, toggleTodoCollapsed, archiveDoneTodos, archiveTodosAtTurnEnd, resetTurnState;
|
|
51916
52863
|
var init_turnStore = __esm({
|
|
@@ -51934,7 +52881,7 @@ var init_turnStore = __esm({
|
|
|
51934
52881
|
tools: [],
|
|
51935
52882
|
turnTrail: []
|
|
51936
52883
|
}), "buildTurnState");
|
|
51937
|
-
$turnState =
|
|
52884
|
+
$turnState = atom6(buildTurnState());
|
|
51938
52885
|
getTurnState = /* @__PURE__ */ __name(() => $turnState.get(), "getTurnState");
|
|
51939
52886
|
subscribeTurn = /* @__PURE__ */ __name((cb) => $turnState.listen(() => cb()), "subscribeTurn");
|
|
51940
52887
|
useTurnSelector = /* @__PURE__ */ __name((selector) => useSyncExternalStore4(
|
|
@@ -52534,7 +53481,9 @@ ${stripped}
|
|
|
52534
53481
|
...base,
|
|
52535
53482
|
apiCalls: p.api_calls ?? base.apiCalls,
|
|
52536
53483
|
costUsd: p.cost_usd ?? base.costUsd,
|
|
53484
|
+
currentStep: p.current_step ?? base.currentStep,
|
|
52537
53485
|
depth: p.depth ?? base.depth,
|
|
53486
|
+
details: p.details ?? base.details,
|
|
52538
53487
|
filesRead: p.files_read ?? base.filesRead,
|
|
52539
53488
|
filesWritten: p.files_written ?? base.filesWritten,
|
|
52540
53489
|
goal: p.goal || base.goal,
|
|
@@ -52548,6 +53497,9 @@ ${stripped}
|
|
|
52548
53497
|
taskCount: p.task_count ?? base.taskCount,
|
|
52549
53498
|
toolCount: p.tool_count ?? base.toolCount,
|
|
52550
53499
|
toolsets: p.toolsets ?? base.toolsets,
|
|
53500
|
+
verificationState: p.verification_state ?? base.verificationState,
|
|
53501
|
+
workflowId: p.workflow_id ?? base.workflowId,
|
|
53502
|
+
workerRole: p.worker_role ?? base.workerRole,
|
|
52551
53503
|
...patch(base)
|
|
52552
53504
|
};
|
|
52553
53505
|
const subagents = existing ? state.subagents.map((item) => item.id === id ? next : item) : [...state.subagents, next].sort((a, b) => a.depth - b.depth || a.index - b.index);
|
|
@@ -52634,7 +53586,7 @@ function createGatewayEventHandler(ctx) {
|
|
|
52634
53586
|
setTimeout(async () => {
|
|
52635
53587
|
let sid = getUiState().sid;
|
|
52636
53588
|
for (let i = 0; !sid && i < 40; i += 1) {
|
|
52637
|
-
await new Promise((
|
|
53589
|
+
await new Promise((resolve6) => setTimeout(resolve6, 100));
|
|
52638
53590
|
sid = getUiState().sid;
|
|
52639
53591
|
}
|
|
52640
53592
|
if (!sid) {
|
|
@@ -52981,6 +53933,26 @@ function createGatewayEventHandler(ctx) {
|
|
|
52981
53933
|
{ createIfMissing: false }
|
|
52982
53934
|
);
|
|
52983
53935
|
return;
|
|
53936
|
+
case "workflow.start":
|
|
53937
|
+
case "workflow.progress":
|
|
53938
|
+
setWorkflowSnapshot(ev.payload);
|
|
53939
|
+
return;
|
|
53940
|
+
case "workflow.complete": {
|
|
53941
|
+
setWorkflowSnapshot(ev.payload);
|
|
53942
|
+
const text = String(ev.payload?.summary ?? "").trim();
|
|
53943
|
+
if (text) {
|
|
53944
|
+
appendMessage({ role: "assistant", text });
|
|
53945
|
+
}
|
|
53946
|
+
return;
|
|
53947
|
+
}
|
|
53948
|
+
case "workflow.error": {
|
|
53949
|
+
setWorkflowSnapshot(ev.payload);
|
|
53950
|
+
const text = String(ev.payload?.summary ?? "").trim();
|
|
53951
|
+
if (text) {
|
|
53952
|
+
sys(text);
|
|
53953
|
+
}
|
|
53954
|
+
return;
|
|
53955
|
+
}
|
|
52984
53956
|
case "message.delta":
|
|
52985
53957
|
turnController.recordMessageDelta(ev.payload ?? {});
|
|
52986
53958
|
return;
|
|
@@ -53015,7 +53987,7 @@ function createGatewayEventHandler(ctx) {
|
|
|
53015
53987
|
}
|
|
53016
53988
|
};
|
|
53017
53989
|
}
|
|
53018
|
-
var NO_PROVIDER_RE, statusFromBusy, applySkin, dropBgTask,
|
|
53990
|
+
var NO_PROVIDER_RE, statusFromBusy, applySkin, dropBgTask, pushUnique2, pushThinking, pushNote, pushTool;
|
|
53019
53991
|
var init_createGatewayEventHandler = __esm({
|
|
53020
53992
|
"src/app/createGatewayEventHandler.ts"() {
|
|
53021
53993
|
"use strict";
|
|
@@ -53030,6 +54002,7 @@ var init_createGatewayEventHandler = __esm({
|
|
|
53030
54002
|
init_overlayStore();
|
|
53031
54003
|
init_turnController();
|
|
53032
54004
|
init_uiStore();
|
|
54005
|
+
init_workflowStore();
|
|
53033
54006
|
NO_PROVIDER_RE = /\bNo (?:LLM|inference) provider configured\b/i;
|
|
53034
54007
|
statusFromBusy = /* @__PURE__ */ __name(() => getUiState().busy ? "running\u2026" : "ready", "statusFromBusy");
|
|
53035
54008
|
applySkin = /* @__PURE__ */ __name((s) => patchUiState({
|
|
@@ -53047,10 +54020,10 @@ var init_createGatewayEventHandler = __esm({
|
|
|
53047
54020
|
next.delete(taskId);
|
|
53048
54021
|
return { ...state, bgTasks: next };
|
|
53049
54022
|
}), "dropBgTask");
|
|
53050
|
-
|
|
53051
|
-
pushThinking =
|
|
53052
|
-
pushNote =
|
|
53053
|
-
pushTool =
|
|
54023
|
+
pushUnique2 = /* @__PURE__ */ __name((max) => (xs, x) => xs.at(-1) === x ? xs : [...xs, x].slice(-max), "pushUnique");
|
|
54024
|
+
pushThinking = pushUnique2(6);
|
|
54025
|
+
pushNote = pushUnique2(6);
|
|
54026
|
+
pushTool = pushUnique2(8);
|
|
53054
54027
|
__name(createGatewayEventHandler, "createGatewayEventHandler");
|
|
53055
54028
|
}
|
|
53056
54029
|
});
|
|
@@ -53194,12 +54167,12 @@ var init_createSlashHandler = __esm({
|
|
|
53194
54167
|
});
|
|
53195
54168
|
|
|
53196
54169
|
// src/app/inputSelectionStore.ts
|
|
53197
|
-
import { atom as
|
|
54170
|
+
import { atom as atom7 } from "nanostores";
|
|
53198
54171
|
var $inputSelection, setInputSelection, getInputSelection;
|
|
53199
54172
|
var init_inputSelectionStore = __esm({
|
|
53200
54173
|
"src/app/inputSelectionStore.ts"() {
|
|
53201
54174
|
"use strict";
|
|
53202
|
-
$inputSelection =
|
|
54175
|
+
$inputSelection = atom7(null);
|
|
53203
54176
|
setInputSelection = /* @__PURE__ */ __name((next) => $inputSelection.set(next), "setInputSelection");
|
|
53204
54177
|
getInputSelection = /* @__PURE__ */ __name(() => $inputSelection.get(), "getInputSelection");
|
|
53205
54178
|
}
|
|
@@ -53360,21 +54333,21 @@ var init_useCompletion = __esm({
|
|
|
53360
54333
|
});
|
|
53361
54334
|
|
|
53362
54335
|
// src/lib/history.ts
|
|
53363
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
53364
|
-
import { homedir as
|
|
53365
|
-
import { join as
|
|
54336
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync33, mkdirSync as mkdirSync19, readFileSync as readFileSync30 } from "node:fs";
|
|
54337
|
+
import { homedir as homedir30 } from "node:os";
|
|
54338
|
+
import { join as join44 } from "node:path";
|
|
53366
54339
|
function load() {
|
|
53367
54340
|
if (cache3) {
|
|
53368
54341
|
return cache3;
|
|
53369
54342
|
}
|
|
53370
54343
|
try {
|
|
53371
|
-
if (!
|
|
54344
|
+
if (!existsSync33(file)) {
|
|
53372
54345
|
cache3 = [];
|
|
53373
54346
|
return cache3;
|
|
53374
54347
|
}
|
|
53375
54348
|
const entries = [];
|
|
53376
54349
|
let current = [];
|
|
53377
|
-
for (const line of
|
|
54350
|
+
for (const line of readFileSync30(file, "utf8").split("\n")) {
|
|
53378
54351
|
if (line.startsWith("+")) {
|
|
53379
54352
|
current.push(line.slice(1));
|
|
53380
54353
|
} else if (current.length) {
|
|
@@ -53405,8 +54378,8 @@ function append(line) {
|
|
|
53405
54378
|
items.splice(0, items.length - MAX);
|
|
53406
54379
|
}
|
|
53407
54380
|
try {
|
|
53408
|
-
if (!
|
|
53409
|
-
|
|
54381
|
+
if (!existsSync33(dir)) {
|
|
54382
|
+
mkdirSync19(dir, { recursive: true });
|
|
53410
54383
|
}
|
|
53411
54384
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace("Z", "");
|
|
53412
54385
|
const encoded = trimmed.split("\n").map((l) => `+${l}`).join("\n");
|
|
@@ -53422,8 +54395,8 @@ var init_history = __esm({
|
|
|
53422
54395
|
"src/lib/history.ts"() {
|
|
53423
54396
|
"use strict";
|
|
53424
54397
|
MAX = 1e3;
|
|
53425
|
-
dir = process.env.OPENJAW_HOME ??
|
|
53426
|
-
file =
|
|
54398
|
+
dir = process.env.OPENJAW_HOME ?? join44(homedir30(), ".openjaw-agent");
|
|
54399
|
+
file = join44(dir, ".openjaw-agent_history");
|
|
53427
54400
|
cache3 = null;
|
|
53428
54401
|
__name(load, "load");
|
|
53429
54402
|
__name(append, "append");
|
|
@@ -53517,7 +54490,7 @@ var init_useQueue = __esm({
|
|
|
53517
54490
|
|
|
53518
54491
|
// src/lib/editor.ts
|
|
53519
54492
|
import { accessSync, constants } from "node:fs";
|
|
53520
|
-
import { delimiter, join as
|
|
54493
|
+
import { delimiter, join as join45 } from "node:path";
|
|
53521
54494
|
var FALLBACKS, isExecutable, resolveEditor;
|
|
53522
54495
|
var init_editor = __esm({
|
|
53523
54496
|
"src/lib/editor.ts"() {
|
|
@@ -53540,7 +54513,7 @@ var init_editor = __esm({
|
|
|
53540
54513
|
return ["notepad.exe"];
|
|
53541
54514
|
}
|
|
53542
54515
|
const dirs = (env2.PATH ?? "").split(delimiter).filter(Boolean);
|
|
53543
|
-
const found = FALLBACKS.flatMap((name) => dirs.map((d) =>
|
|
54516
|
+
const found = FALLBACKS.flatMap((name) => dirs.map((d) => join45(d, name))).find(isExecutable);
|
|
53544
54517
|
return [found ?? "vi"];
|
|
53545
54518
|
}, "resolveEditor");
|
|
53546
54519
|
}
|
|
@@ -53548,9 +54521,9 @@ var init_editor = __esm({
|
|
|
53548
54521
|
|
|
53549
54522
|
// src/app/useComposerState.ts
|
|
53550
54523
|
import { spawnSync } from "node:child_process";
|
|
53551
|
-
import { mkdtempSync, readFileSync as
|
|
54524
|
+
import { mkdtempSync, readFileSync as readFileSync31, rmSync as rmSync2, writeFileSync as writeFileSync21 } from "node:fs";
|
|
53552
54525
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
53553
|
-
import { join as
|
|
54526
|
+
import { join as join46 } from "node:path";
|
|
53554
54527
|
import { useStore } from "@nanostores/react";
|
|
53555
54528
|
import { useCallback as useCallback7, useMemo as useMemo6, useState as useState12 } from "react";
|
|
53556
54529
|
function insertAtCursor(value, cursor, text) {
|
|
@@ -53707,10 +54680,10 @@ function useComposerState({
|
|
|
53707
54680
|
[handleResolvedPaste, onClipboardPaste, querier]
|
|
53708
54681
|
);
|
|
53709
54682
|
const openEditor = useCallback7(async () => {
|
|
53710
|
-
const dir2 = mkdtempSync(
|
|
53711
|
-
const file2 =
|
|
54683
|
+
const dir2 = mkdtempSync(join46(tmpdir12(), "hermes-"));
|
|
54684
|
+
const file2 = join46(dir2, "prompt.md");
|
|
53712
54685
|
const [cmd, ...args] = resolveEditor();
|
|
53713
|
-
|
|
54686
|
+
writeFileSync21(file2, [...inputBuf, input].join("\n"));
|
|
53714
54687
|
let exitCode = null;
|
|
53715
54688
|
await withInkSuspended(async () => {
|
|
53716
54689
|
exitCode = spawnSync(cmd, [...args, file2], { stdio: "inherit" }).status;
|
|
@@ -53719,7 +54692,7 @@ function useComposerState({
|
|
|
53719
54692
|
if (exitCode !== 0) {
|
|
53720
54693
|
return;
|
|
53721
54694
|
}
|
|
53722
|
-
const text =
|
|
54695
|
+
const text = readFileSync31(file2, "utf8").trimEnd();
|
|
53723
54696
|
if (!text) {
|
|
53724
54697
|
return;
|
|
53725
54698
|
}
|
|
@@ -54137,11 +55110,11 @@ function applyVoiceRecordResponse(response, starting, voice, sys) {
|
|
|
54137
55110
|
}
|
|
54138
55111
|
}
|
|
54139
55112
|
function useInputHandlers(ctx) {
|
|
54140
|
-
const { actions, composer, gateway, terminal, voice, wheelStep } = ctx;
|
|
55113
|
+
const { actions, composer, gateway, terminal: terminal2, voice, wheelStep } = ctx;
|
|
54141
55114
|
const { actions: cActions, refs: cRefs, state: cState } = composer;
|
|
54142
55115
|
const overlay = useStore2($overlayState);
|
|
54143
55116
|
const isBlocked = useStore2($isBlocked);
|
|
54144
|
-
const pagerPageSize = Math.max(5, (
|
|
55117
|
+
const pagerPageSize = Math.max(5, (terminal2.stdout?.rows ?? 24) - 6);
|
|
54145
55118
|
const scrollIdleTimer = useRef10(null);
|
|
54146
55119
|
const wheelAccelRef = useRef10(initWheelAccelForHost());
|
|
54147
55120
|
const precisionWheelRef = useRef10(initPrecisionWheel());
|
|
@@ -54156,13 +55129,13 @@ function useInputHandlers(ctx) {
|
|
|
54156
55129
|
turnController.relaxStreaming();
|
|
54157
55130
|
}, TYPING_IDLE_MS);
|
|
54158
55131
|
}
|
|
54159
|
-
|
|
55132
|
+
terminal2.scrollWithSelection(delta);
|
|
54160
55133
|
}, "scrollTranscript");
|
|
54161
55134
|
const copySelection = /* @__PURE__ */ __name(() => {
|
|
54162
|
-
|
|
55135
|
+
terminal2.selection.copySelection();
|
|
54163
55136
|
}, "copySelection");
|
|
54164
55137
|
const clearSelection2 = /* @__PURE__ */ __name(() => {
|
|
54165
|
-
|
|
55138
|
+
terminal2.selection.clearSelection();
|
|
54166
55139
|
}, "clearSelection");
|
|
54167
55140
|
const cancelOverlayFromCtrlC = /* @__PURE__ */ __name(() => {
|
|
54168
55141
|
if (overlay.clarify) {
|
|
@@ -54361,7 +55334,7 @@ function useInputHandlers(ctx) {
|
|
|
54361
55334
|
return scrollTranscript(1);
|
|
54362
55335
|
}
|
|
54363
55336
|
if (key.pageUp || key.pageDown) {
|
|
54364
|
-
const viewport =
|
|
55337
|
+
const viewport = terminal2.scrollRef.current?.getViewportHeight() ?? Math.max(6, (terminal2.stdout?.rows ?? 24) - 8);
|
|
54365
55338
|
const step = Math.max(4, Math.floor(viewport / 2));
|
|
54366
55339
|
return scrollTranscript(key.pageUp ? -step : step);
|
|
54367
55340
|
}
|
|
@@ -54371,7 +55344,7 @@ function useInputHandlers(ctx) {
|
|
|
54371
55344
|
if (key.escape && cState.queueEditIdx !== null) {
|
|
54372
55345
|
return cActions.clearIn();
|
|
54373
55346
|
}
|
|
54374
|
-
if (key.escape &&
|
|
55347
|
+
if (key.escape && terminal2.hasSelection) {
|
|
54375
55348
|
return clearSelection2();
|
|
54376
55349
|
}
|
|
54377
55350
|
if (key.escape && live.focusedPane === "transcript") {
|
|
@@ -54397,7 +55370,7 @@ function useInputHandlers(ctx) {
|
|
|
54397
55370
|
}
|
|
54398
55371
|
}
|
|
54399
55372
|
if (isCopyShortcut(key, ch)) {
|
|
54400
|
-
if (
|
|
55373
|
+
if (terminal2.hasSelection) {
|
|
54401
55374
|
return copySelection();
|
|
54402
55375
|
}
|
|
54403
55376
|
const inputSel = getInputSelection();
|
|
@@ -54432,7 +55405,7 @@ function useInputHandlers(ctx) {
|
|
|
54432
55405
|
}
|
|
54433
55406
|
if (isAction(key, ch, "l")) {
|
|
54434
55407
|
clearSelection2();
|
|
54435
|
-
forceRedraw(
|
|
55408
|
+
forceRedraw(terminal2.stdout ?? process.stdout);
|
|
54436
55409
|
return;
|
|
54437
55410
|
}
|
|
54438
55411
|
if (isVoiceToggleKey(key, ch, voice.recordKey)) {
|
|
@@ -54582,7 +55555,7 @@ var init_useLongRunToolCharms = __esm({
|
|
|
54582
55555
|
});
|
|
54583
55556
|
|
|
54584
55557
|
// src/app/useSessionLifecycle.ts
|
|
54585
|
-
import { writeFileSync as
|
|
55558
|
+
import { writeFileSync as writeFileSync22 } from "node:fs";
|
|
54586
55559
|
import { useCallback as useCallback8 } from "react";
|
|
54587
55560
|
function useSessionLifecycle(opts) {
|
|
54588
55561
|
const {
|
|
@@ -54765,7 +55738,7 @@ var init_useSessionLifecycle = __esm({
|
|
|
54765
55738
|
return;
|
|
54766
55739
|
}
|
|
54767
55740
|
try {
|
|
54768
|
-
|
|
55741
|
+
writeFileSync22(file2, JSON.stringify({ session_id: sessionId }), { mode: 384 });
|
|
54769
55742
|
} catch {
|
|
54770
55743
|
}
|
|
54771
55744
|
}, "writeActiveSessionFile");
|
|
@@ -55622,8 +56595,13 @@ function useMainApp(gw) {
|
|
|
55622
56595
|
);
|
|
55623
56596
|
const onModelSelect = useCallback10((value) => {
|
|
55624
56597
|
patchOverlayState({ modelPicker: false });
|
|
56598
|
+
if (value === "__openjaw_connect_complete__") {
|
|
56599
|
+
sys("provider connected \u2014 starting OpenJaw session\u2026");
|
|
56600
|
+
session.newSession();
|
|
56601
|
+
return;
|
|
56602
|
+
}
|
|
55625
56603
|
slashRef.current(`/model ${value}`);
|
|
55626
|
-
}, []);
|
|
56604
|
+
}, [session, sys]);
|
|
55627
56605
|
const hasReasoning = useTurnSelector((state) => Boolean(state.reasoning.trim()));
|
|
55628
56606
|
const anyPanelVisible = SECTION_NAMES.some(
|
|
55629
56607
|
(s) => sectionMode(s, ui.detailsMode, ui.sections, ui.detailsModeCommandOverride) !== "hidden"
|
|
@@ -55795,9 +56773,9 @@ __export(perfPane_exports, {
|
|
|
55795
56773
|
PerfPane: () => PerfPane,
|
|
55796
56774
|
logFrameEvent: () => logFrameEvent
|
|
55797
56775
|
});
|
|
55798
|
-
import { appendFileSync as appendFileSync5, mkdirSync as
|
|
55799
|
-
import { homedir as
|
|
55800
|
-
import { dirname as dirname7, join as
|
|
56776
|
+
import { appendFileSync as appendFileSync5, mkdirSync as mkdirSync20 } from "node:fs";
|
|
56777
|
+
import { homedir as homedir31 } from "node:os";
|
|
56778
|
+
import { dirname as dirname7, join as join47 } from "node:path";
|
|
55801
56779
|
import { Profiler } from "react";
|
|
55802
56780
|
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
55803
56781
|
function PerfPane({ children, id }) {
|
|
@@ -55813,13 +56791,13 @@ var init_perfPane = __esm({
|
|
|
55813
56791
|
init_entry_exports();
|
|
55814
56792
|
ENABLED = /^(?:1|true|yes|on)$/i.test((process.env.OPENJAW_DEV_PERF ?? "").trim());
|
|
55815
56793
|
THRESHOLD_MS = Number(process.env.OPENJAW_DEV_PERF_MS ?? "2") || 0;
|
|
55816
|
-
LOG_PATH2 = process.env.OPENJAW_DEV_PERF_LOG?.trim() ||
|
|
56794
|
+
LOG_PATH2 = process.env.OPENJAW_DEV_PERF_LOG?.trim() || join47(homedir31(), ".openjaw-agent", "perf.log");
|
|
55817
56795
|
logReady = false;
|
|
55818
56796
|
writeRow = /* @__PURE__ */ __name((row) => {
|
|
55819
56797
|
if (!logReady) {
|
|
55820
56798
|
logReady = true;
|
|
55821
56799
|
try {
|
|
55822
|
-
|
|
56800
|
+
mkdirSync20(dirname7(LOG_PATH2), { recursive: true });
|
|
55823
56801
|
} catch {
|
|
55824
56802
|
}
|
|
55825
56803
|
}
|
|
@@ -56072,6 +57050,10 @@ function Detail({ id, node, t }) {
|
|
|
56072
57050
|
] }),
|
|
56073
57051
|
/* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
56074
57052
|
/* @__PURE__ */ jsx18(Field, { name: "depth", t, value: `${item.depth} \xB7 ${item.status}` }),
|
|
57053
|
+
item.workflowId ? /* @__PURE__ */ jsx18(Field, { name: "workflow", t, value: item.workflowId }) : null,
|
|
57054
|
+
item.workerRole ? /* @__PURE__ */ jsx18(Field, { name: "role", t, value: item.workerRole }) : null,
|
|
57055
|
+
item.verificationState ? /* @__PURE__ */ jsx18(Field, { name: "verification", t, value: item.verificationState }) : null,
|
|
57056
|
+
item.currentStep ? /* @__PURE__ */ jsx18(Field, { name: "current", t, value: item.currentStep }) : null,
|
|
56075
57057
|
item.model ? /* @__PURE__ */ jsx18(Field, { name: "model", t, value: item.model }) : null,
|
|
56076
57058
|
item.toolsets?.length ? /* @__PURE__ */ jsx18(Field, { name: "toolsets", t, value: item.toolsets.join(", ") }) : null,
|
|
56077
57059
|
/* @__PURE__ */ jsx18(Field, { name: "tools", t, value: `${item.toolCount ?? 0} (subtree ${agg.totalTools})` }),
|
|
@@ -56146,7 +57128,8 @@ function Detail({ id, node, t }) {
|
|
|
56146
57128
|
" ",
|
|
56147
57129
|
line
|
|
56148
57130
|
] }, i)) }) : null,
|
|
56149
|
-
item.summary ? /* @__PURE__ */ jsx18(OverlaySection, { defaultOpen: true, t, title: "Summary", children: /* @__PURE__ */ jsx18(Text9, { color: t.color.text, wrap: "wrap", children: item.summary }) }) : null
|
|
57131
|
+
item.summary ? /* @__PURE__ */ jsx18(OverlaySection, { defaultOpen: true, t, title: "Summary", children: /* @__PURE__ */ jsx18(Text9, { color: t.color.text, wrap: "wrap", children: item.summary }) }) : null,
|
|
57132
|
+
item.details && item.details !== item.summary ? /* @__PURE__ */ jsx18(OverlaySection, { defaultOpen: true, t, title: "Details", children: /* @__PURE__ */ jsx18(Text9, { color: t.color.text, wrap: "wrap", children: item.details }) }) : null
|
|
56150
57133
|
] });
|
|
56151
57134
|
}
|
|
56152
57135
|
function ListRow({
|
|
@@ -56246,12 +57229,23 @@ function DiffView({
|
|
|
56246
57229
|
] })
|
|
56247
57230
|
] });
|
|
56248
57231
|
}
|
|
56249
|
-
function AgentsOverlay({ gw, initialHistoryIndex = 0, onClose, t }) {
|
|
56250
|
-
const
|
|
57232
|
+
function AgentsOverlay({ gw, initialHistoryIndex = 0, onClose, t, workflowId = null }) {
|
|
57233
|
+
const allLiveSubagents = useTurnSelector((state) => state.subagents);
|
|
56251
57234
|
const delegation = useStore4($delegationState);
|
|
56252
57235
|
const history = useStore4($spawnHistory);
|
|
56253
57236
|
const diffPair = useStore4($spawnDiff);
|
|
57237
|
+
const workflowSnapshots = useStore4($workflowSnapshots);
|
|
56254
57238
|
const { stdout } = useStdout();
|
|
57239
|
+
const liveSubagents = workflowId ? allLiveSubagents.filter((item) => item.workflowId === workflowId) : allLiveSubagents;
|
|
57240
|
+
const workflowSnapshot = workflowId ? workflowSnapshots[workflowId] ?? null : null;
|
|
57241
|
+
const workflowReplaySnapshot = workflowSnapshot && liveSubagents.length === 0 ? {
|
|
57242
|
+
finishedAt: workflowSnapshot.finishedAt ?? Date.now(),
|
|
57243
|
+
id: workflowSnapshot.id,
|
|
57244
|
+
label: workflowSnapshot.goal,
|
|
57245
|
+
sessionId: workflowSnapshot.id,
|
|
57246
|
+
startedAt: workflowSnapshot.startedAt,
|
|
57247
|
+
subagents: workflowSnapshot.workers
|
|
57248
|
+
} : null;
|
|
56255
57249
|
const [historyIndex, setHistoryIndex] = useState14(
|
|
56256
57250
|
() => Math.max(0, Math.min(history.length, Math.floor(initialHistoryIndex)))
|
|
56257
57251
|
);
|
|
@@ -56263,9 +57257,9 @@ function AgentsOverlay({ gw, initialHistoryIndex = 0, onClose, t }) {
|
|
|
56263
57257
|
const [mode, setMode] = useState14("list");
|
|
56264
57258
|
const detailScrollRef = useRef14(null);
|
|
56265
57259
|
const prevLiveCountRef = useRef14(liveSubagents.length);
|
|
56266
|
-
const activeSnapshot = historyIndex > 0 ? history[historyIndex - 1] : null;
|
|
56267
|
-
const justFinishedSnapshot = historyIndex === 0 && liveSubagents.length === 0 ? history[0] ?? null : null;
|
|
56268
|
-
const effectiveSnapshot = activeSnapshot ?? justFinishedSnapshot;
|
|
57260
|
+
const activeSnapshot = !workflowId && historyIndex > 0 ? history[historyIndex - 1] : null;
|
|
57261
|
+
const justFinishedSnapshot = !workflowId && historyIndex === 0 && liveSubagents.length === 0 ? history[0] ?? null : null;
|
|
57262
|
+
const effectiveSnapshot = workflowReplaySnapshot ?? activeSnapshot ?? justFinishedSnapshot;
|
|
56269
57263
|
const replayMode = effectiveSnapshot != null;
|
|
56270
57264
|
const subagents = replayMode ? effectiveSnapshot.subagents : liveSubagents;
|
|
56271
57265
|
const tree = useMemo8(() => buildSubagentTree(subagents), [subagents]);
|
|
@@ -56434,7 +57428,7 @@ function AgentsOverlay({ gw, initialHistoryIndex = 0, onClose, t }) {
|
|
|
56434
57428
|
const capsLabel = delegation.maxSpawnDepth ? `caps d${delegation.maxSpawnDepth}/${delegation.maxConcurrentChildren ?? "?"}` : "";
|
|
56435
57429
|
const title = replayMode && effectiveSnapshot ? `${historyIndex > 0 ? `Replay ${historyIndex}/${history.length}` : "Last turn"} \xB7 finished ${new Date(
|
|
56436
57430
|
effectiveSnapshot.finishedAt
|
|
56437
|
-
).toLocaleTimeString()}` : `Spawn tree${delegation.paused ? " \xB7 \u23F8 paused" : ""}`;
|
|
57431
|
+
).toLocaleTimeString()}` : workflowId ? `Workflow ${workflowId}${delegation.paused ? " \xB7 \u23F8 paused" : ""}` : `Spawn tree${delegation.paused ? " \xB7 \u23F8 paused" : ""}`;
|
|
56438
57432
|
const metaLine = [formatSummary(totals), spark, capsLabel, mix2 ? `\xB7 ${mix2}` : ""].filter(Boolean).join(" ");
|
|
56439
57433
|
const controlsHint = replayMode ? " \xB7 controls locked" : ` \xB7 x kill \xB7 X subtree \xB7 p ${delegation.paused ? "resume" : "pause"}`;
|
|
56440
57434
|
if (diffPair) {
|
|
@@ -56448,7 +57442,7 @@ function AgentsOverlay({ gw, initialHistoryIndex = 0, onClose, t }) {
|
|
|
56448
57442
|
metaLine
|
|
56449
57443
|
] }) : null
|
|
56450
57444
|
] }) }),
|
|
56451
|
-
rows.length === 0 ? /* @__PURE__ */ jsx18(Box_default, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx18(Text9, { color: t.color.muted, children: "No subagents this turn. Trigger delegate_task to populate the tree." }) }) : mode === "list" ? /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, flexShrink: 1, minHeight: 0, children: [
|
|
57445
|
+
rows.length === 0 ? /* @__PURE__ */ jsx18(Box_default, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx18(Text9, { color: t.color.muted, children: workflowId ? "No workers for this workflow yet." : "No subagents this turn. Trigger delegate_task to populate the tree." }) }) : mode === "list" ? /* @__PURE__ */ jsxs9(Box_default, { flexDirection: "column", flexGrow: 1, flexShrink: 1, minHeight: 0, children: [
|
|
56452
57446
|
/* @__PURE__ */ jsx18(GanttStrip, { cols, cursor, flatNodes: rows, maxRows: 6, now: now2, t }),
|
|
56453
57447
|
/* @__PURE__ */ jsx18(Box_default, { flexDirection: "column", flexGrow: 0, flexShrink: 0, overflow: "hidden", children: rows.slice(listWindowStart, listWindowStart + rowsH).map((node, i) => /* @__PURE__ */ jsx18(
|
|
56454
57448
|
ListRow,
|
|
@@ -56494,6 +57488,7 @@ var init_agentsOverlay = __esm({
|
|
|
56494
57488
|
init_overlayStore();
|
|
56495
57489
|
init_spawnHistoryStore();
|
|
56496
57490
|
init_turnStore();
|
|
57491
|
+
init_workflowStore();
|
|
56497
57492
|
init_rpc();
|
|
56498
57493
|
init_subagentTree();
|
|
56499
57494
|
init_text();
|
|
@@ -58422,7 +59417,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
|
|
|
58422
59417
|
refreshProviders();
|
|
58423
59418
|
}
|
|
58424
59419
|
if (mode === "connect") {
|
|
58425
|
-
|
|
59420
|
+
onSelect("__openjaw_connect_complete__");
|
|
58426
59421
|
return;
|
|
58427
59422
|
}
|
|
58428
59423
|
setStage("model");
|
|
@@ -58518,7 +59513,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
|
|
|
58518
59513
|
setKeyInput("");
|
|
58519
59514
|
setKeySaving(false);
|
|
58520
59515
|
if (mode === "connect") {
|
|
58521
|
-
|
|
59516
|
+
onSelect("__openjaw_connect_complete__");
|
|
58522
59517
|
return;
|
|
58523
59518
|
}
|
|
58524
59519
|
setStage("model");
|
|
@@ -58557,7 +59552,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
|
|
|
58557
59552
|
if (r?.disconnected) {
|
|
58558
59553
|
setProviders(
|
|
58559
59554
|
(prev) => prev.map(
|
|
58560
|
-
(p) => p.slug === provider.slug ? { ...p, authenticated: false, models: [], model_options: [], total_models: 0, warning: p.key_env ? `paste ${p.key_env} to activate` : "run
|
|
59555
|
+
(p) => p.slug === provider.slug ? { ...p, authenticated: false, models: [], model_options: [], total_models: 0, warning: p.key_env ? `paste ${p.key_env} to activate` : "run /connect to configure" } : p
|
|
58561
59556
|
)
|
|
58562
59557
|
);
|
|
58563
59558
|
}
|
|
@@ -58605,7 +59600,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
|
|
|
58605
59600
|
return;
|
|
58606
59601
|
}
|
|
58607
59602
|
if (mode === "connect") {
|
|
58608
|
-
|
|
59603
|
+
onSelect("__openjaw_connect_complete__");
|
|
58609
59604
|
return;
|
|
58610
59605
|
}
|
|
58611
59606
|
setStage("model");
|
|
@@ -58693,7 +59688,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
|
|
|
58693
59688
|
"Configure ",
|
|
58694
59689
|
provider.name
|
|
58695
59690
|
] }),
|
|
58696
|
-
/* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: "Paste your API key below (saved to
|
|
59691
|
+
/* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: "Paste your API key below (saved to OpenJaw credentials)" }),
|
|
58697
59692
|
/* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: " " }),
|
|
58698
59693
|
/* @__PURE__ */ jsxs13(Text9, { color: t.color.muted, wrap: "truncate-end", children: [
|
|
58699
59694
|
provider.key_env,
|
|
@@ -59889,14 +60884,14 @@ __export(fpsStore_exports, {
|
|
|
59889
60884
|
$fpsState: () => $fpsState,
|
|
59890
60885
|
trackFrame: () => trackFrame
|
|
59891
60886
|
});
|
|
59892
|
-
import { atom as
|
|
60887
|
+
import { atom as atom8 } from "nanostores";
|
|
59893
60888
|
var WINDOW_SIZE, $fpsState, timestamps, totalFrames, trackFrame;
|
|
59894
60889
|
var init_fpsStore = __esm({
|
|
59895
60890
|
"src/lib/fpsStore.ts"() {
|
|
59896
60891
|
"use strict";
|
|
59897
60892
|
init_env();
|
|
59898
60893
|
WINDOW_SIZE = 30;
|
|
59899
|
-
$fpsState =
|
|
60894
|
+
$fpsState = atom8({ fps: 0, lastDurationMs: 0, totalFrames: 0 });
|
|
59900
60895
|
timestamps = [];
|
|
59901
60896
|
totalFrames = 0;
|
|
59902
60897
|
trackFrame = SHOW_FPS ? (durationMs) => {
|
|
@@ -61060,7 +62055,7 @@ var init_mathUnicode = __esm({
|
|
|
61060
62055
|
|
|
61061
62056
|
// src/lib/syntax.ts
|
|
61062
62057
|
function highlightLine(line, lang, t) {
|
|
61063
|
-
const spec =
|
|
62058
|
+
const spec = resolve5(lang);
|
|
61064
62059
|
if (!spec) {
|
|
61065
62060
|
return [["", line]];
|
|
61066
62061
|
}
|
|
@@ -61092,7 +62087,7 @@ function highlightLine(line, lang, t) {
|
|
|
61092
62087
|
}
|
|
61093
62088
|
return tokens;
|
|
61094
62089
|
}
|
|
61095
|
-
var KW, TS, PY, SH, GO, RUST, SQL, LANGS, ALIAS,
|
|
62090
|
+
var KW, TS, PY, SH, GO, RUST, SQL, LANGS, ALIAS, resolve5, isHighlightable, TOKEN_RE;
|
|
61096
62091
|
var init_syntax = __esm({
|
|
61097
62092
|
"src/lib/syntax.ts"() {
|
|
61098
62093
|
"use strict";
|
|
@@ -61146,8 +62141,8 @@ var init_syntax = __esm({
|
|
|
61146
62141
|
yml: "yaml",
|
|
61147
62142
|
zsh: "sh"
|
|
61148
62143
|
};
|
|
61149
|
-
|
|
61150
|
-
isHighlightable = /* @__PURE__ */ __name((lang) =>
|
|
62144
|
+
resolve5 = /* @__PURE__ */ __name((lang) => LANGS[ALIAS[lang] ?? lang] ?? null, "resolve");
|
|
62145
|
+
isHighlightable = /* @__PURE__ */ __name((lang) => resolve5(lang) !== null, "isHighlightable");
|
|
61151
62146
|
TOKEN_RE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`|\b\d+(?:\.\d+)?\b|[A-Za-z_$][\w$]*/g;
|
|
61152
62147
|
__name(highlightLine, "highlightLine");
|
|
61153
62148
|
}
|
|
@@ -63271,8 +64266,9 @@ var init_appLayout = __esm({
|
|
|
63271
64266
|
{
|
|
63272
64267
|
gw,
|
|
63273
64268
|
initialHistoryIndex: overlay.agentsInitialHistoryIndex,
|
|
63274
|
-
onClose: () => patchOverlayState({ agents: false, agentsInitialHistoryIndex: 0 }),
|
|
63275
|
-
t: ui.theme
|
|
64269
|
+
onClose: () => patchOverlayState({ agents: false, agentsInitialHistoryIndex: 0, agentsWorkflowId: null }),
|
|
64270
|
+
t: ui.theme,
|
|
64271
|
+
workflowId: overlay.agentsWorkflowId
|
|
63276
64272
|
}
|
|
63277
64273
|
);
|
|
63278
64274
|
}, "AgentsOverlayPane"));
|