@charzhu/openjaw-agent 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +1712 -667
- package/dist/main.js.map +4 -4
- package/package.json +33 -2
- package/prompts/IDENTITY.md +2 -2
- package/prompts/REASONING.md +17 -1
package/dist/main.js
CHANGED
|
@@ -19,22 +19,90 @@ var __export = (target, all) => {
|
|
|
19
19
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
// src/
|
|
22
|
+
// src/desktop/launcher.ts
|
|
23
|
+
var launcher_exports = {};
|
|
24
|
+
__export(launcher_exports, {
|
|
25
|
+
launchDesktop: () => launchDesktop
|
|
26
|
+
});
|
|
27
|
+
import { spawn } from "node:child_process";
|
|
23
28
|
import { existsSync } from "node:fs";
|
|
24
|
-
import {
|
|
29
|
+
import { createRequire } from "node:module";
|
|
30
|
+
import { dirname, resolve } from "node:path";
|
|
25
31
|
import { fileURLToPath } from "node:url";
|
|
26
|
-
function
|
|
32
|
+
async function launchDesktop(forwardedArgs) {
|
|
33
|
+
let electronBinary;
|
|
34
|
+
try {
|
|
35
|
+
const require2 = createRequire(import.meta.url);
|
|
36
|
+
electronBinary = require2("electron");
|
|
37
|
+
} catch (err) {
|
|
38
|
+
process.stderr.write(ELECTRON_MISSING_HINT);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
27
41
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
42
|
+
const candidates = [
|
|
43
|
+
resolve(here, "electronMain.js"),
|
|
44
|
+
// source layout / direct dist/desktop run
|
|
45
|
+
resolve(here, "desktop", "electronMain.js")
|
|
46
|
+
// dist/main.js → dist/desktop/electronMain.js
|
|
47
|
+
];
|
|
48
|
+
const electronEntry = candidates.find((p) => existsSync(p)) ?? candidates[0];
|
|
49
|
+
const child = spawn(electronBinary, [electronEntry, ...forwardedArgs], {
|
|
50
|
+
stdio: "inherit",
|
|
51
|
+
env: process.env,
|
|
52
|
+
windowsHide: false
|
|
53
|
+
});
|
|
54
|
+
await new Promise((resolve7) => {
|
|
55
|
+
child.on("exit", (code) => {
|
|
56
|
+
process.exit(code ?? 0);
|
|
57
|
+
resolve7();
|
|
58
|
+
});
|
|
59
|
+
child.on("error", (err) => {
|
|
60
|
+
process.stderr.write(`openjaw-agent app: failed to spawn electron: ${err.message}
|
|
61
|
+
`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
resolve7();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
var ELECTRON_MISSING_HINT;
|
|
68
|
+
var init_launcher = __esm({
|
|
69
|
+
"src/desktop/launcher.ts"() {
|
|
70
|
+
"use strict";
|
|
71
|
+
ELECTRON_MISSING_HINT = [
|
|
72
|
+
"",
|
|
73
|
+
"The desktop UI requires the optional `electron` peer dependency, which",
|
|
74
|
+
"is not currently installed.",
|
|
75
|
+
"",
|
|
76
|
+
"To install it globally with openjaw-agent:",
|
|
77
|
+
" npm install -g @charzhu/openjaw-agent --include=optional",
|
|
78
|
+
"",
|
|
79
|
+
"Or, if you are running from a local clone:",
|
|
80
|
+
" cd path/to/openjaw-agent && npm install electron",
|
|
81
|
+
"",
|
|
82
|
+
"CLI usage (no desktop UI) is unaffected: just run `openjaw-agent` without",
|
|
83
|
+
"the `app` subcommand.",
|
|
84
|
+
""
|
|
85
|
+
].join("\n");
|
|
86
|
+
__name(launchDesktop, "launchDesktop");
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// src/packageRoot.ts
|
|
91
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
92
|
+
import { dirname as dirname2, join } from "node:path";
|
|
93
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
94
|
+
function findPackageRoot() {
|
|
95
|
+
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
28
96
|
let dir2 = here;
|
|
29
97
|
for (let i = 0; i < 6; i++) {
|
|
30
|
-
if (
|
|
98
|
+
if (existsSync2(join(dir2, "package.json")) && existsSync2(join(dir2, "prompts"))) {
|
|
31
99
|
return dir2;
|
|
32
100
|
}
|
|
33
|
-
const parent =
|
|
101
|
+
const parent = dirname2(dir2);
|
|
34
102
|
if (parent === dir2) break;
|
|
35
103
|
dir2 = parent;
|
|
36
104
|
}
|
|
37
|
-
return
|
|
105
|
+
return dirname2(here);
|
|
38
106
|
}
|
|
39
107
|
function packageRoot() {
|
|
40
108
|
if (cached === null) {
|
|
@@ -73,8 +141,8 @@ __export(config_exports, {
|
|
|
73
141
|
saveAgentConfig: () => saveAgentConfig,
|
|
74
142
|
updateBridgeConfig: () => updateBridgeConfig
|
|
75
143
|
});
|
|
76
|
-
import { readFileSync, writeFileSync, existsSync as
|
|
77
|
-
import { join as join2, dirname as
|
|
144
|
+
import { readFileSync, writeFileSync, existsSync as existsSync3, mkdirSync } from "node:fs";
|
|
145
|
+
import { join as join2, dirname as dirname3 } from "node:path";
|
|
78
146
|
import { homedir } from "node:os";
|
|
79
147
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
80
148
|
function getConfigDir() {
|
|
@@ -88,10 +156,10 @@ function loadAgentConfig() {
|
|
|
88
156
|
const userConfigPath = getConfigPath();
|
|
89
157
|
const bundledConfigPath = packageBundledConfigPath();
|
|
90
158
|
let configPath = null;
|
|
91
|
-
if (
|
|
159
|
+
if (existsSync3(userConfigPath)) {
|
|
92
160
|
configPath = userConfigPath;
|
|
93
|
-
} else if (
|
|
94
|
-
if (!
|
|
161
|
+
} else if (existsSync3(bundledConfigPath)) {
|
|
162
|
+
if (!existsSync3(configDir2)) {
|
|
95
163
|
mkdirSync(configDir2, { recursive: true });
|
|
96
164
|
}
|
|
97
165
|
const bundledContent = readFileSync(bundledConfigPath, "utf8");
|
|
@@ -101,7 +169,7 @@ function loadAgentConfig() {
|
|
|
101
169
|
console.log(` Edit it to change provider/model settings.
|
|
102
170
|
`);
|
|
103
171
|
} else {
|
|
104
|
-
if (!
|
|
172
|
+
if (!existsSync3(configDir2)) {
|
|
105
173
|
mkdirSync(configDir2, { recursive: true });
|
|
106
174
|
}
|
|
107
175
|
writeFileSync(userConfigPath, stringifyYaml(DEFAULT_CONFIG), "utf8");
|
|
@@ -131,7 +199,8 @@ function loadAgentConfig() {
|
|
|
131
199
|
copilot_oauth_client_id: parsedLlm?.copilot_oauth_client_id ?? DEFAULT_CONFIG.llm.copilot_oauth_client_id,
|
|
132
200
|
context_compression: parsedLlm?.context_compression,
|
|
133
201
|
compression_threshold: parsedLlm?.compression_threshold,
|
|
134
|
-
compression_model: parsedLlm?.compression_model
|
|
202
|
+
compression_model: parsedLlm?.compression_model,
|
|
203
|
+
max_tool_rounds: parsedLlm?.max_tool_rounds
|
|
135
204
|
},
|
|
136
205
|
telegram: parsed?.telegram ?? void 0,
|
|
137
206
|
feishu: parsed?.feishu ?? void 0,
|
|
@@ -171,7 +240,7 @@ function saveAgentConfig(config) {
|
|
|
171
240
|
}
|
|
172
241
|
function loadRawConfigYaml() {
|
|
173
242
|
const path3 = getConfigPath();
|
|
174
|
-
if (!
|
|
243
|
+
if (!existsSync3(path3)) {
|
|
175
244
|
return { path: path3, yamlObj: void 0 };
|
|
176
245
|
}
|
|
177
246
|
const raw = readFileSync(path3, "utf8");
|
|
@@ -188,13 +257,13 @@ function updateBridgeConfig(name, values) {
|
|
|
188
257
|
next2[name] = values;
|
|
189
258
|
}
|
|
190
259
|
const tmpPath = `${path3}.tmp`;
|
|
191
|
-
const dir2 =
|
|
192
|
-
if (!
|
|
260
|
+
const dir2 = dirname3(path3);
|
|
261
|
+
if (!existsSync3(dir2)) {
|
|
193
262
|
mkdirSync(dir2, { recursive: true });
|
|
194
263
|
}
|
|
195
264
|
writeFileSync(tmpPath, stringifyYaml(next2), "utf8");
|
|
196
|
-
const { renameSync } = await import("node:fs");
|
|
197
|
-
|
|
265
|
+
const { renameSync: renameSync2 } = await import("node:fs");
|
|
266
|
+
renameSync2(tmpPath, path3);
|
|
198
267
|
}, "task");
|
|
199
268
|
const next = configWriteChain.then(task, task);
|
|
200
269
|
configWriteChain = next.then(
|
|
@@ -249,7 +318,7 @@ __export(image_resize_exports, {
|
|
|
249
318
|
resizeImageForAgent: () => resizeImageForAgent
|
|
250
319
|
});
|
|
251
320
|
import { execSync } from "node:child_process";
|
|
252
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync, existsSync as
|
|
321
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "node:fs";
|
|
253
322
|
import { join as join3 } from "node:path";
|
|
254
323
|
import { tmpdir } from "node:os";
|
|
255
324
|
import { randomUUID } from "node:crypto";
|
|
@@ -300,7 +369,7 @@ Write-Output "$newW x $newH"
|
|
|
300
369
|
`powershell -NoProfile -NonInteractive -EncodedCommand ${encoded}`,
|
|
301
370
|
{ timeout: 15e3, encoding: "utf-8" }
|
|
302
371
|
).trim();
|
|
303
|
-
if (!
|
|
372
|
+
if (!existsSync4(outputPath)) {
|
|
304
373
|
throw new Error(`Resize produced no output (PowerShell said: ${result})`);
|
|
305
374
|
}
|
|
306
375
|
const resizedBuffer = readFileSync2(outputPath);
|
|
@@ -310,17 +379,17 @@ Write-Output "$newW x $newH"
|
|
|
310
379
|
return { base64: resizedBase64, mimeType: actualMimeType };
|
|
311
380
|
} finally {
|
|
312
381
|
try {
|
|
313
|
-
if (
|
|
382
|
+
if (existsSync4(inputPath)) unlinkSync(inputPath);
|
|
314
383
|
} catch {
|
|
315
384
|
}
|
|
316
385
|
try {
|
|
317
|
-
if (
|
|
386
|
+
if (existsSync4(outputPath)) unlinkSync(outputPath);
|
|
318
387
|
} catch {
|
|
319
388
|
}
|
|
320
389
|
}
|
|
321
390
|
}
|
|
322
391
|
async function resizeImageFileForAgent(filePath) {
|
|
323
|
-
if (!
|
|
392
|
+
if (!existsSync4(filePath)) {
|
|
324
393
|
throw new Error(`Image file not found: ${filePath}`);
|
|
325
394
|
}
|
|
326
395
|
const buffer = readFileSync2(filePath);
|
|
@@ -868,7 +937,7 @@ Start-Sleep -Milliseconds 50
|
|
|
868
937
|
}
|
|
869
938
|
}
|
|
870
939
|
async function wait(duration) {
|
|
871
|
-
await new Promise((
|
|
940
|
+
await new Promise((resolve7) => setTimeout(resolve7, duration * 1e3));
|
|
872
941
|
return { output: `Waited ${duration} seconds` };
|
|
873
942
|
}
|
|
874
943
|
function getDisplayDimensions() {
|
|
@@ -1976,12 +2045,12 @@ var init_copilot_token = __esm({
|
|
|
1976
2045
|
});
|
|
1977
2046
|
|
|
1978
2047
|
// src/provider-auth.ts
|
|
1979
|
-
import { existsSync as
|
|
2048
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1980
2049
|
import { join as join5 } from "node:path";
|
|
1981
2050
|
import { homedir as homedir2 } from "node:os";
|
|
1982
2051
|
function getAuthDir() {
|
|
1983
2052
|
const dir2 = join5(homedir2(), ".openjaw-agent");
|
|
1984
|
-
if (!
|
|
2053
|
+
if (!existsSync5(dir2)) mkdirSync3(dir2, { recursive: true });
|
|
1985
2054
|
return dir2;
|
|
1986
2055
|
}
|
|
1987
2056
|
function getProviderAuthPath() {
|
|
@@ -1992,7 +2061,7 @@ function emptyFile() {
|
|
|
1992
2061
|
}
|
|
1993
2062
|
function loadProviderCredentials() {
|
|
1994
2063
|
const path3 = getProviderAuthPath();
|
|
1995
|
-
if (!
|
|
2064
|
+
if (!existsSync5(path3)) return emptyFile();
|
|
1996
2065
|
const parsed = JSON.parse(readFileSync3(path3, "utf8"));
|
|
1997
2066
|
return {
|
|
1998
2067
|
version: 1,
|
|
@@ -2205,8 +2274,8 @@ function safeJsonParse(value) {
|
|
|
2205
2274
|
}
|
|
2206
2275
|
}
|
|
2207
2276
|
async function loadWebSocket() {
|
|
2208
|
-
const { createRequire } = await import("node:module");
|
|
2209
|
-
return
|
|
2277
|
+
const { createRequire: createRequire3 } = await import("node:module");
|
|
2278
|
+
return createRequire3(import.meta.url)("ws");
|
|
2210
2279
|
}
|
|
2211
2280
|
function responsesWebSocketUrl(baseUrl) {
|
|
2212
2281
|
const url = new URL(`${baseUrl.replace(/\/+$/, "")}/responses`);
|
|
@@ -2563,7 +2632,7 @@ var init_copilot = __esm({
|
|
|
2563
2632
|
handshakeTimeout: RESPONSES_WEBSOCKET_CONNECT_TIMEOUT_MS
|
|
2564
2633
|
});
|
|
2565
2634
|
const request = JSON.stringify(this.buildResponsesWebSocketRequest(requestBody));
|
|
2566
|
-
return new Promise((
|
|
2635
|
+
return new Promise((resolve7, reject) => {
|
|
2567
2636
|
const accumulator = { sawTextDelta: false, text: null, toolCalls: [] };
|
|
2568
2637
|
let settled = false;
|
|
2569
2638
|
const timeout = setTimeout(() => {
|
|
@@ -2577,7 +2646,7 @@ var init_copilot = __esm({
|
|
|
2577
2646
|
settled = true;
|
|
2578
2647
|
clearTimeout(timeout);
|
|
2579
2648
|
ws.close();
|
|
2580
|
-
|
|
2649
|
+
resolve7(value);
|
|
2581
2650
|
}, "finish");
|
|
2582
2651
|
const fail = /* @__PURE__ */ __name((error) => {
|
|
2583
2652
|
if (settled) return;
|
|
@@ -2641,7 +2710,8 @@ var init_copilot = __esm({
|
|
|
2641
2710
|
messages.push({
|
|
2642
2711
|
role: "assistant",
|
|
2643
2712
|
content: msg.content,
|
|
2644
|
-
...toolCalls?.length ? { tool_calls: toolCalls } : {}
|
|
2713
|
+
...toolCalls?.length ? { tool_calls: toolCalls } : {},
|
|
2714
|
+
...msg.reasoningOpaque ? { reasoning_opaque: msg.reasoningOpaque } : {}
|
|
2645
2715
|
});
|
|
2646
2716
|
} else {
|
|
2647
2717
|
for (const result of msg.results) {
|
|
@@ -2671,11 +2741,12 @@ var init_copilot = __esm({
|
|
|
2671
2741
|
messages: this.buildChatMessages(options),
|
|
2672
2742
|
tools: options.tools.length > 0 ? options.tools.map(toChatTool) : void 0,
|
|
2673
2743
|
tool_choice: options.tools.length > 0 ? "auto" : void 0,
|
|
2674
|
-
temperature: this.config.temperature
|
|
2744
|
+
temperature: this.config.temperature,
|
|
2745
|
+
stream: true
|
|
2675
2746
|
};
|
|
2676
2747
|
const res = await fetch(`${await this.baseUrl(options.signal)}/chat/completions`, {
|
|
2677
2748
|
method: "POST",
|
|
2678
|
-
headers: await this.headers(options),
|
|
2749
|
+
headers: { ...await this.headers(options), Accept: "text/event-stream" },
|
|
2679
2750
|
body: JSON.stringify(requestBody),
|
|
2680
2751
|
signal: options.signal
|
|
2681
2752
|
});
|
|
@@ -2683,19 +2754,85 @@ var init_copilot = __esm({
|
|
|
2683
2754
|
const detail = await res.text();
|
|
2684
2755
|
throw new Error(`GitHub Copilot chat error: ${res.status} ${detail}`);
|
|
2685
2756
|
}
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2757
|
+
if (!res.body) throw new Error("GitHub Copilot chat: no response body for stream");
|
|
2758
|
+
let text = null;
|
|
2759
|
+
let finishReason;
|
|
2760
|
+
let reasoningOpaque;
|
|
2761
|
+
let promptTokens;
|
|
2762
|
+
let completionTokens;
|
|
2763
|
+
const toolSlots = [];
|
|
2764
|
+
const lastSlotByIndex = /* @__PURE__ */ new Map();
|
|
2765
|
+
const reader = res.body.getReader();
|
|
2766
|
+
const decoder = new TextDecoder();
|
|
2767
|
+
let buf = "";
|
|
2768
|
+
for (; ; ) {
|
|
2769
|
+
const { done, value } = await reader.read();
|
|
2770
|
+
if (done) break;
|
|
2771
|
+
buf += decoder.decode(value, { stream: true });
|
|
2772
|
+
let nl;
|
|
2773
|
+
while ((nl = buf.indexOf("\n")) !== -1) {
|
|
2774
|
+
const rawLine = buf.slice(0, nl).trim();
|
|
2775
|
+
buf = buf.slice(nl + 1);
|
|
2776
|
+
if (!rawLine.startsWith("data:")) continue;
|
|
2777
|
+
const payload = rawLine.slice(5).trim();
|
|
2778
|
+
if (payload === "[DONE]") continue;
|
|
2779
|
+
let evt;
|
|
2780
|
+
try {
|
|
2781
|
+
evt = JSON.parse(payload);
|
|
2782
|
+
} catch {
|
|
2783
|
+
continue;
|
|
2784
|
+
}
|
|
2785
|
+
const choice = evt.choices?.[0];
|
|
2786
|
+
if (choice) {
|
|
2787
|
+
const delta = choice.delta;
|
|
2788
|
+
if (delta) {
|
|
2789
|
+
if (typeof delta.content === "string") text = (text ?? "") + delta.content;
|
|
2790
|
+
if (typeof delta.reasoning_opaque === "string") {
|
|
2791
|
+
reasoningOpaque = (reasoningOpaque ?? "") + delta.reasoning_opaque;
|
|
2792
|
+
}
|
|
2793
|
+
const deltaToolCalls = delta.tool_calls;
|
|
2794
|
+
for (const tc of deltaToolCalls ?? []) {
|
|
2795
|
+
const idx = typeof tc.index === "number" ? tc.index : 0;
|
|
2796
|
+
const fn = tc.function;
|
|
2797
|
+
const startsNewCall = typeof tc.id === "string" || typeof fn?.name === "string";
|
|
2798
|
+
let slot;
|
|
2799
|
+
if (startsNewCall) {
|
|
2800
|
+
slot = { args: "" };
|
|
2801
|
+
if (typeof tc.id === "string") slot.id = tc.id;
|
|
2802
|
+
if (fn?.name) slot.name = fn.name;
|
|
2803
|
+
toolSlots.push(slot);
|
|
2804
|
+
lastSlotByIndex.set(idx, slot);
|
|
2805
|
+
} else {
|
|
2806
|
+
slot = lastSlotByIndex.get(idx) ?? { args: "" };
|
|
2807
|
+
if (!lastSlotByIndex.has(idx)) {
|
|
2808
|
+
toolSlots.push(slot);
|
|
2809
|
+
lastSlotByIndex.set(idx, slot);
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
if (typeof fn?.arguments === "string") slot.args += fn.arguments;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
if (typeof choice.finish_reason === "string") finishReason = choice.finish_reason;
|
|
2816
|
+
if (typeof choice.reasoning_opaque === "string") {
|
|
2817
|
+
reasoningOpaque = choice.reasoning_opaque;
|
|
2818
|
+
}
|
|
2819
|
+
const msg = choice.message;
|
|
2820
|
+
if (typeof msg?.reasoning_opaque === "string") reasoningOpaque = msg.reasoning_opaque;
|
|
2821
|
+
}
|
|
2822
|
+
const usage2 = evt.usage;
|
|
2823
|
+
if (usage2) {
|
|
2824
|
+
promptTokens = usage2.prompt_tokens;
|
|
2825
|
+
completionTokens = usage2.completion_tokens;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
const toolCalls = toolSlots.filter((slot) => slot.id && slot.name).map((slot) => ({ id: slot.id, name: slot.name, input: safeJsonParse(slot.args) }));
|
|
2694
2830
|
return {
|
|
2695
|
-
text
|
|
2831
|
+
text,
|
|
2696
2832
|
toolCalls,
|
|
2697
|
-
stopReason: toolCalls.length > 0 ? "tool_use" :
|
|
2698
|
-
usage: this.usage(
|
|
2833
|
+
stopReason: toolCalls.length > 0 ? "tool_use" : finishReason === "length" ? "max_tokens" : "end",
|
|
2834
|
+
usage: this.usage(promptTokens, completionTokens),
|
|
2835
|
+
reasoningOpaque
|
|
2699
2836
|
};
|
|
2700
2837
|
}
|
|
2701
2838
|
buildResponsesInput(options) {
|
|
@@ -2945,13 +3082,13 @@ var init_providers = __esm({
|
|
|
2945
3082
|
});
|
|
2946
3083
|
|
|
2947
3084
|
// src/session.ts
|
|
2948
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as
|
|
3085
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4, readdirSync, renameSync, unlinkSync as unlinkSync3 } from "node:fs";
|
|
2949
3086
|
import { join as join6 } from "node:path";
|
|
2950
3087
|
import { homedir as homedir3 } from "node:os";
|
|
2951
3088
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2952
3089
|
function getSessionsDir() {
|
|
2953
3090
|
const dir2 = join6(homedir3(), ".openjaw-agent", "sessions");
|
|
2954
|
-
if (!
|
|
3091
|
+
if (!existsSync6(dir2)) mkdirSync4(dir2, { recursive: true });
|
|
2955
3092
|
return dir2;
|
|
2956
3093
|
}
|
|
2957
3094
|
function sessionPath(id) {
|
|
@@ -2972,11 +3109,23 @@ function createSession(provider, model) {
|
|
|
2972
3109
|
function saveSession(session) {
|
|
2973
3110
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2974
3111
|
session.turnCount = session.messages.filter((m) => m.role === "user").length;
|
|
2975
|
-
|
|
3112
|
+
const finalPath = sessionPath(session.id);
|
|
3113
|
+
const tmpPath = `${finalPath}.tmp`;
|
|
3114
|
+
const payload = JSON.stringify(session, null, 2);
|
|
3115
|
+
try {
|
|
3116
|
+
writeFileSync5(tmpPath, payload, "utf8");
|
|
3117
|
+
renameSync(tmpPath, finalPath);
|
|
3118
|
+
} catch (err) {
|
|
3119
|
+
try {
|
|
3120
|
+
unlinkSync3(tmpPath);
|
|
3121
|
+
} catch {
|
|
3122
|
+
}
|
|
3123
|
+
throw err;
|
|
3124
|
+
}
|
|
2976
3125
|
}
|
|
2977
3126
|
function loadSession(id) {
|
|
2978
3127
|
const path3 = sessionPath(id);
|
|
2979
|
-
if (!
|
|
3128
|
+
if (!existsSync6(path3)) return null;
|
|
2980
3129
|
try {
|
|
2981
3130
|
return JSON.parse(readFileSync4(path3, "utf8"));
|
|
2982
3131
|
} catch {
|
|
@@ -3361,7 +3510,7 @@ var init_cache_monitor = __esm({
|
|
|
3361
3510
|
});
|
|
3362
3511
|
|
|
3363
3512
|
// src/telemetry.ts
|
|
3364
|
-
import { appendFileSync, existsSync as
|
|
3513
|
+
import { appendFileSync, existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
3365
3514
|
import { join as join7 } from "node:path";
|
|
3366
3515
|
import { homedir as homedir4 } from "node:os";
|
|
3367
3516
|
function now() {
|
|
@@ -3384,7 +3533,7 @@ var init_telemetry = __esm({
|
|
|
3384
3533
|
constructor(sessionId) {
|
|
3385
3534
|
this.sessionId = sessionId;
|
|
3386
3535
|
try {
|
|
3387
|
-
if (!
|
|
3536
|
+
if (!existsSync7(TELEMETRY_DIR)) {
|
|
3388
3537
|
mkdirSync5(TELEMETRY_DIR, { recursive: true });
|
|
3389
3538
|
}
|
|
3390
3539
|
} catch {
|
|
@@ -3415,7 +3564,7 @@ var init_telemetry = __esm({
|
|
|
3415
3564
|
getRecentEvents(limit = 20) {
|
|
3416
3565
|
try {
|
|
3417
3566
|
const todayFile = join7(TELEMETRY_DIR, `${today()}.jsonl`);
|
|
3418
|
-
if (!
|
|
3567
|
+
if (!existsSync7(todayFile)) return [];
|
|
3419
3568
|
const lines = readFileSync5(todayFile, "utf-8").trim().split("\n");
|
|
3420
3569
|
return lines.slice(-limit).map((l) => JSON.parse(l));
|
|
3421
3570
|
} catch {
|
|
@@ -3963,13 +4112,13 @@ function selectToolsForRequest(params) {
|
|
|
3963
4112
|
addByName(name);
|
|
3964
4113
|
}
|
|
3965
4114
|
const relevantCategories = categoriesForMessage(userMessage);
|
|
3966
|
-
|
|
3967
|
-
if (selected.size >= maxTools) break;
|
|
4115
|
+
const relevantTools = allTools.map((tool, index) => ({ index, score: toolRelevanceScore(tool.name, userMessage), tool })).filter(({ tool }) => {
|
|
3968
4116
|
const cat = categoryForTool(tool.name);
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
4117
|
+
return cat !== "mcp" && relevantCategories.has(cat) && !selected.has(tool.name);
|
|
4118
|
+
}).sort((a, b) => b.score - a.score || a.index - b.index);
|
|
4119
|
+
for (const { tool } of relevantTools) {
|
|
4120
|
+
if (selected.size >= maxTools) break;
|
|
4121
|
+
selected.set(tool.name, tool);
|
|
3973
4122
|
}
|
|
3974
4123
|
if (selected.size < maxTools && relevantCategories.size === 0) {
|
|
3975
4124
|
for (const tool of allTools) {
|
|
@@ -4000,6 +4149,20 @@ function categoriesForMessage(message) {
|
|
|
4000
4149
|
}
|
|
4001
4150
|
return categories;
|
|
4002
4151
|
}
|
|
4152
|
+
function preloadRelevantCategoriesForRequest(loader, message) {
|
|
4153
|
+
if (typeof loader.loadCategory !== "function") return [];
|
|
4154
|
+
const loaded = [];
|
|
4155
|
+
for (const category of categoriesForMessage(message)) {
|
|
4156
|
+
if (category === "mcp" || category === "meta" || category === "skill") continue;
|
|
4157
|
+
const added = loader.loadCategory(category);
|
|
4158
|
+
if (added > 0) loaded.push(category);
|
|
4159
|
+
}
|
|
4160
|
+
return loaded;
|
|
4161
|
+
}
|
|
4162
|
+
function toolOutputLooksFailed(output) {
|
|
4163
|
+
if (!output) return false;
|
|
4164
|
+
return /^\s*\{?"?(error|success)"?\s*:\s*("|false)/i.test(output) || /\b(error|not found|enoent|failed)\b/i.test(output.slice(0, 300));
|
|
4165
|
+
}
|
|
4003
4166
|
function normalizeCategory(value) {
|
|
4004
4167
|
const normalized = value.toLowerCase();
|
|
4005
4168
|
if (["browser", "email", "teams", "office", "wechat", "memory", "files", "system"].includes(normalized)) {
|
|
@@ -4020,6 +4183,20 @@ function categoryForTool(toolName) {
|
|
|
4020
4183
|
if (toolName.startsWith("system_") || toolName.startsWith("clipboard_") || ["code_execute", "web_fetch", "web_search", "web_extract", "notify", "sleep", "ask_user", "config"].includes(toolName)) return "system";
|
|
4021
4184
|
return "mcp";
|
|
4022
4185
|
}
|
|
4186
|
+
function toolRelevanceScore(toolName, message) {
|
|
4187
|
+
const lower = message.toLowerCase();
|
|
4188
|
+
const name = toolName.toLowerCase();
|
|
4189
|
+
if (/https?:\/\//i.test(message) && ["web_extract", "web_fetch", "web_search"].includes(name)) return 150;
|
|
4190
|
+
if (/(?:^|[\s"'`])(?:~|\.\.?|[A-Za-z]:)?[\\/][^\s"'`]+|\b[\w.-]+\.(html?|md|txt|json|ya?ml|ts|tsx|js|jsx|py|csv|xlsx?|pptx?|pdf)\b/i.test(message) && ["file_read", "file_info", "file_list"].includes(name)) return 145;
|
|
4191
|
+
if (/\b(repo|repository|source code|github|codebase)\b/.test(lower) && ["system_run", "code_execute", "grep", "glob", "web_extract", "web_fetch", "file_read"].includes(name)) return 140;
|
|
4192
|
+
if (/https?:\/\//i.test(message) && ["browser_navigate", "browser_extract", "browser_snapshot"].includes(name)) return 135;
|
|
4193
|
+
if (/\b(powerpoint|pptx?|presentation|slides?|deck)\b/.test(lower) && ["powerpoint_focus", "powerpoint_new_presentation", "powerpoint_new_slide", "powerpoint_read_content", "powerpoint_send_keys", "powerpoint_screenshot"].includes(name)) return 130;
|
|
4194
|
+
if (/\b(powerpoint|pptx?|presentation|slides?|deck)\b/.test(lower) && name.startsWith("powerpoint_")) return 85;
|
|
4195
|
+
if (/\b(excel|spreadsheet|xlsx?|csv|data analysis)\b/.test(lower) && ["excel_focus", "excel_new_workbook", "excel_read_content", "excel_enter_value", "excel_enter_formula"].includes(name)) return 95;
|
|
4196
|
+
if (/\b(word|docx?|document|report)\b/.test(lower) && ["word_focus", "word_new_document", "word_read_content", "word_insert_text", "word_save"].includes(name)) return 95;
|
|
4197
|
+
if (name === "openjaw_load_tools" || name === "invoke_skill") return 90;
|
|
4198
|
+
return 0;
|
|
4199
|
+
}
|
|
4023
4200
|
var DEFAULT_OPENAI_MAX_TOOLS, MCP_AUTO_GROW_HARD_CAP, BUILTIN_HEADROOM, FOUNDATION_TOOL_NAMES, PROFILE_CATEGORIES, CATEGORY_KEYWORDS;
|
|
4024
4201
|
var init_tool_exposure = __esm({
|
|
4025
4202
|
"src/tool-exposure.ts"() {
|
|
@@ -4043,10 +4220,10 @@ var init_tool_exposure = __esm({
|
|
|
4043
4220
|
CATEGORY_KEYWORDS = [
|
|
4044
4221
|
{ category: "email", patterns: [/\b(email|mail|outlook|inbox|calendar|schedule|meeting|invite|today|tomorrow)\b/i] },
|
|
4045
4222
|
{ category: "teams", patterns: [/\b(teams|chat|channel|message|dm|meeting|standup|today|mention)\b/i] },
|
|
4046
|
-
{ category: "browser", patterns: [/\b(browser|page|website|web|navigate|click|screenshot|snapshot|console|image|search online)\b/i] },
|
|
4047
|
-
{ category: "files", patterns: [/\b(file|folder|directory|read|write|edit|grep|glob|find in repo|codebase)\b/i] },
|
|
4223
|
+
{ category: "browser", patterns: [/\b(browser|page|website|web|navigate|click|screenshot|snapshot|console|image|search online)\b/i, /https?:\/\//i] },
|
|
4224
|
+
{ category: "files", patterns: [/\b(file|folder|directory|read|write|edit|grep|glob|find in repo|codebase|source code|repo|repository|downloads?)\b/i, /(?:^|[\s"'`])(?:~|\.\.?|[A-Za-z]:)?[\\/][^\s"'`]+/i, /\b[\w.-]+\.(html?|md|txt|json|ya?ml|ts|tsx|js|jsx|py|csv|xlsx?|pptx?|pdf)\b/i] },
|
|
4048
4225
|
{ category: "system", patterns: [/\b(shell|command|terminal|run|execute|clipboard|notify|sleep|web search|fetch url|extract url|read url|article|docs?|paper|source page|news|latest|headlines|current events|breaking news)\b/i] },
|
|
4049
|
-
{ category: "office", patterns: [/\b(word|excel|powerpoint|spreadsheet|document|presentation|slide)\b/i] },
|
|
4226
|
+
{ category: "office", patterns: [/\b(word|excel|powerpoint|pptx?|spreadsheet|document|presentation|slide|deck)\b/i] },
|
|
4050
4227
|
{ category: "wechat", patterns: [/\b(wechat|weixin)\b/i] },
|
|
4051
4228
|
{ category: "memory", patterns: [/\b(memory|remember|recall|todo|preference)\b/i] }
|
|
4052
4229
|
];
|
|
@@ -4058,8 +4235,245 @@ var init_tool_exposure = __esm({
|
|
|
4058
4235
|
__name(rememberLoadedToolExposure, "rememberLoadedToolExposure");
|
|
4059
4236
|
__name(selectToolsForRequest, "selectToolsForRequest");
|
|
4060
4237
|
__name(categoriesForMessage, "categoriesForMessage");
|
|
4238
|
+
__name(preloadRelevantCategoriesForRequest, "preloadRelevantCategoriesForRequest");
|
|
4239
|
+
__name(toolOutputLooksFailed, "toolOutputLooksFailed");
|
|
4061
4240
|
__name(normalizeCategory, "normalizeCategory");
|
|
4062
4241
|
__name(categoryForTool, "categoryForTool");
|
|
4242
|
+
__name(toolRelevanceScore, "toolRelevanceScore");
|
|
4243
|
+
}
|
|
4244
|
+
});
|
|
4245
|
+
|
|
4246
|
+
// src/turn-control.ts
|
|
4247
|
+
var DEFAULT_MAX_TOOL_ROUNDS, IterationBudget;
|
|
4248
|
+
var init_turn_control = __esm({
|
|
4249
|
+
"src/turn-control.ts"() {
|
|
4250
|
+
"use strict";
|
|
4251
|
+
DEFAULT_MAX_TOOL_ROUNDS = 100;
|
|
4252
|
+
IterationBudget = class {
|
|
4253
|
+
static {
|
|
4254
|
+
__name(this, "IterationBudget");
|
|
4255
|
+
}
|
|
4256
|
+
used = 0;
|
|
4257
|
+
graceUsed = false;
|
|
4258
|
+
max;
|
|
4259
|
+
constructor(max = DEFAULT_MAX_TOOL_ROUNDS) {
|
|
4260
|
+
this.max = Math.max(1, Math.floor(max));
|
|
4261
|
+
}
|
|
4262
|
+
get remaining() {
|
|
4263
|
+
return Math.max(0, this.max - this.used);
|
|
4264
|
+
}
|
|
4265
|
+
get consumed() {
|
|
4266
|
+
return this.used;
|
|
4267
|
+
}
|
|
4268
|
+
/** True while there is budget (or the one-time grace round) left to run. */
|
|
4269
|
+
canContinue() {
|
|
4270
|
+
return this.remaining > 0 || !this.graceUsed;
|
|
4271
|
+
}
|
|
4272
|
+
/** True only when the budget is spent and we are on the grace round. */
|
|
4273
|
+
isGraceRound() {
|
|
4274
|
+
return this.remaining === 0 && !this.graceUsed;
|
|
4275
|
+
}
|
|
4276
|
+
/** Consume one round. Returns false if nothing (not even grace) is left. */
|
|
4277
|
+
consume() {
|
|
4278
|
+
if (this.remaining > 0) {
|
|
4279
|
+
this.used += 1;
|
|
4280
|
+
return true;
|
|
4281
|
+
}
|
|
4282
|
+
if (!this.graceUsed) {
|
|
4283
|
+
this.graceUsed = true;
|
|
4284
|
+
return true;
|
|
4285
|
+
}
|
|
4286
|
+
return false;
|
|
4287
|
+
}
|
|
4288
|
+
/** Give a round back (e.g. a round that made no model-visible progress). */
|
|
4289
|
+
refund() {
|
|
4290
|
+
if (this.used > 0) this.used -= 1;
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
4293
|
+
}
|
|
4294
|
+
});
|
|
4295
|
+
|
|
4296
|
+
// src/tool-guardrails.ts
|
|
4297
|
+
function isNoProgressTracked(toolName) {
|
|
4298
|
+
if (MUTATING_TOOLS.has(toolName)) return false;
|
|
4299
|
+
if (toolName.startsWith("powerpoint_") || toolName.startsWith("word_") || toolName.startsWith("excel_")) {
|
|
4300
|
+
return false;
|
|
4301
|
+
}
|
|
4302
|
+
return true;
|
|
4303
|
+
}
|
|
4304
|
+
function signatureOf(toolName, args) {
|
|
4305
|
+
return `${toolName}\0${canonicalJson(args ?? {})}`;
|
|
4306
|
+
}
|
|
4307
|
+
function canonicalJson(value) {
|
|
4308
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
4309
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
4310
|
+
const obj = value;
|
|
4311
|
+
const keys = Object.keys(obj).sort();
|
|
4312
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`).join(",")}}`;
|
|
4313
|
+
}
|
|
4314
|
+
function hashOutput(output) {
|
|
4315
|
+
let h = 2166136261;
|
|
4316
|
+
const s = output ?? "";
|
|
4317
|
+
for (let i = 0; i < s.length; i++) {
|
|
4318
|
+
h ^= s.charCodeAt(i);
|
|
4319
|
+
h = Math.imul(h, 16777619);
|
|
4320
|
+
}
|
|
4321
|
+
return (h >>> 0).toString(16);
|
|
4322
|
+
}
|
|
4323
|
+
function appendGuardrailGuidance(result, decision) {
|
|
4324
|
+
if (decision.action !== "warn" && decision.action !== "halt" || !decision.message) return result;
|
|
4325
|
+
const label = decision.action === "halt" ? "Tool loop hard stop" : "Tool loop warning";
|
|
4326
|
+
return `${result || ""}
|
|
4327
|
+
|
|
4328
|
+
[${label}: ${decision.code}; count=${decision.count}; ${decision.message}]`;
|
|
4329
|
+
}
|
|
4330
|
+
function blockedToolResult(decision) {
|
|
4331
|
+
return JSON.stringify({ error: decision.message, guardrail: { code: decision.code, action: decision.action } });
|
|
4332
|
+
}
|
|
4333
|
+
var DEFAULT_GUARDRAIL_THRESHOLDS, MUTATING_TOOLS, ToolLoopGuardrails;
|
|
4334
|
+
var init_tool_guardrails = __esm({
|
|
4335
|
+
"src/tool-guardrails.ts"() {
|
|
4336
|
+
"use strict";
|
|
4337
|
+
DEFAULT_GUARDRAIL_THRESHOLDS = {
|
|
4338
|
+
hardStopEnabled: true,
|
|
4339
|
+
exactFailureWarnAfter: 2,
|
|
4340
|
+
exactFailureBlockAfter: 5,
|
|
4341
|
+
sameToolFailureWarnAfter: 3,
|
|
4342
|
+
sameToolFailureHaltAfter: 8,
|
|
4343
|
+
noProgressWarnAfter: 2,
|
|
4344
|
+
noProgressBlockAfter: 5
|
|
4345
|
+
};
|
|
4346
|
+
MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
4347
|
+
"file_write",
|
|
4348
|
+
"file_edit",
|
|
4349
|
+
"file_delete",
|
|
4350
|
+
"notify",
|
|
4351
|
+
"ask_user",
|
|
4352
|
+
"memory_append",
|
|
4353
|
+
"memory_save"
|
|
4354
|
+
]);
|
|
4355
|
+
__name(isNoProgressTracked, "isNoProgressTracked");
|
|
4356
|
+
__name(signatureOf, "signatureOf");
|
|
4357
|
+
__name(canonicalJson, "canonicalJson");
|
|
4358
|
+
__name(hashOutput, "hashOutput");
|
|
4359
|
+
ToolLoopGuardrails = class {
|
|
4360
|
+
static {
|
|
4361
|
+
__name(this, "ToolLoopGuardrails");
|
|
4362
|
+
}
|
|
4363
|
+
t;
|
|
4364
|
+
exactFailure = /* @__PURE__ */ new Map();
|
|
4365
|
+
sameToolFailure = /* @__PURE__ */ new Map();
|
|
4366
|
+
noProgress = /* @__PURE__ */ new Map();
|
|
4367
|
+
haltDecision = null;
|
|
4368
|
+
constructor(thresholds = {}) {
|
|
4369
|
+
this.t = { ...DEFAULT_GUARDRAIL_THRESHOLDS, ...thresholds };
|
|
4370
|
+
}
|
|
4371
|
+
/** Set once a block/halt has fired; the loop reads this to stop the turn. */
|
|
4372
|
+
get halted() {
|
|
4373
|
+
return this.haltDecision;
|
|
4374
|
+
}
|
|
4375
|
+
/**
|
|
4376
|
+
* Consult before (re-)executing a tool call. Returns `block` if this exact
|
|
4377
|
+
* call has already failed/no-progressed past the hard-stop threshold, so the
|
|
4378
|
+
* loop can skip execution and tell the model to change strategy.
|
|
4379
|
+
*/
|
|
4380
|
+
before(toolName, args) {
|
|
4381
|
+
if (!this.t.hardStopEnabled) return { action: "allow", toolName };
|
|
4382
|
+
const sig = signatureOf(toolName, args);
|
|
4383
|
+
const exact = this.exactFailure.get(sig) ?? 0;
|
|
4384
|
+
if (exact >= this.t.exactFailureBlockAfter) {
|
|
4385
|
+
return this.recordHalt({
|
|
4386
|
+
action: "block",
|
|
4387
|
+
code: "repeated_exact_failure_block",
|
|
4388
|
+
message: `Blocked ${toolName}: the same tool call failed ${exact} times with identical arguments. Stop retrying it unchanged; change strategy or explain the blocker.`,
|
|
4389
|
+
toolName,
|
|
4390
|
+
count: exact
|
|
4391
|
+
});
|
|
4392
|
+
}
|
|
4393
|
+
if (isNoProgressTracked(toolName)) {
|
|
4394
|
+
const rec = this.noProgress.get(sig);
|
|
4395
|
+
if (rec && rec.count >= this.t.noProgressBlockAfter) {
|
|
4396
|
+
return this.recordHalt({
|
|
4397
|
+
action: "block",
|
|
4398
|
+
code: "idempotent_no_progress_block",
|
|
4399
|
+
message: `Blocked ${toolName}: this call returned the same result ${rec.count} times. Stop repeating it unchanged; use the result already provided or try a different approach.`,
|
|
4400
|
+
toolName,
|
|
4401
|
+
count: rec.count
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
return { action: "allow", toolName };
|
|
4406
|
+
}
|
|
4407
|
+
/**
|
|
4408
|
+
* Record the outcome after a tool call. Returns a `warn` to append to the
|
|
4409
|
+
* tool result, or a `halt` to stop the turn. `failed` is derived by the
|
|
4410
|
+
* caller from the output shape (reuse tool-exposure's toolOutputLooksFailed).
|
|
4411
|
+
*/
|
|
4412
|
+
after(toolName, args, output, failed) {
|
|
4413
|
+
const sig = signatureOf(toolName, args);
|
|
4414
|
+
if (failed) {
|
|
4415
|
+
const exact = (this.exactFailure.get(sig) ?? 0) + 1;
|
|
4416
|
+
this.exactFailure.set(sig, exact);
|
|
4417
|
+
this.noProgress.delete(sig);
|
|
4418
|
+
const same = (this.sameToolFailure.get(toolName) ?? 0) + 1;
|
|
4419
|
+
this.sameToolFailure.set(toolName, same);
|
|
4420
|
+
if (this.t.hardStopEnabled && same >= this.t.sameToolFailureHaltAfter) {
|
|
4421
|
+
return this.recordHalt({
|
|
4422
|
+
action: "halt",
|
|
4423
|
+
code: "same_tool_failure_halt",
|
|
4424
|
+
message: `Stopped ${toolName}: it failed ${same} times this turn. Stop retrying the same failing tool path and choose a different approach.`,
|
|
4425
|
+
toolName,
|
|
4426
|
+
count: same
|
|
4427
|
+
});
|
|
4428
|
+
}
|
|
4429
|
+
if (exact >= this.t.exactFailureWarnAfter) {
|
|
4430
|
+
return {
|
|
4431
|
+
action: "warn",
|
|
4432
|
+
code: "repeated_exact_failure_warning",
|
|
4433
|
+
message: `${toolName} has failed ${exact} times with identical arguments. This looks like a loop; inspect the error and change strategy instead of retrying it unchanged.`,
|
|
4434
|
+
toolName,
|
|
4435
|
+
count: exact
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
if (same >= this.t.sameToolFailureWarnAfter) {
|
|
4439
|
+
return {
|
|
4440
|
+
action: "warn",
|
|
4441
|
+
code: "same_tool_failure_warning",
|
|
4442
|
+
message: `${toolName} has failed ${same} times this turn. This looks like a loop. Do not switch to text-only replies; keep using tools, but inspect the latest error and verify your assumptions before retrying.`,
|
|
4443
|
+
toolName,
|
|
4444
|
+
count: same
|
|
4445
|
+
};
|
|
4446
|
+
}
|
|
4447
|
+
return { action: "allow", toolName, count: exact };
|
|
4448
|
+
}
|
|
4449
|
+
this.exactFailure.delete(sig);
|
|
4450
|
+
this.sameToolFailure.delete(toolName);
|
|
4451
|
+
if (!isNoProgressTracked(toolName)) {
|
|
4452
|
+
this.noProgress.delete(sig);
|
|
4453
|
+
return { action: "allow", toolName };
|
|
4454
|
+
}
|
|
4455
|
+
const hash3 = hashOutput(output);
|
|
4456
|
+
const prev = this.noProgress.get(sig);
|
|
4457
|
+
const count = prev && prev.hash === hash3 ? prev.count + 1 : 1;
|
|
4458
|
+
this.noProgress.set(sig, { hash: hash3, count });
|
|
4459
|
+
if (count >= this.t.noProgressWarnAfter) {
|
|
4460
|
+
return {
|
|
4461
|
+
action: "warn",
|
|
4462
|
+
code: "idempotent_no_progress_warning",
|
|
4463
|
+
message: `${toolName} returned the same result ${count} times. Use the result already provided or change the approach instead of repeating it unchanged.`,
|
|
4464
|
+
toolName,
|
|
4465
|
+
count
|
|
4466
|
+
};
|
|
4467
|
+
}
|
|
4468
|
+
return { action: "allow", toolName, count };
|
|
4469
|
+
}
|
|
4470
|
+
recordHalt(decision) {
|
|
4471
|
+
this.haltDecision = decision;
|
|
4472
|
+
return decision;
|
|
4473
|
+
}
|
|
4474
|
+
};
|
|
4475
|
+
__name(appendGuardrailGuidance, "appendGuardrailGuidance");
|
|
4476
|
+
__name(blockedToolResult, "blockedToolResult");
|
|
4063
4477
|
}
|
|
4064
4478
|
});
|
|
4065
4479
|
|
|
@@ -4075,8 +4489,8 @@ function isOAuthAbortError(err) {
|
|
|
4075
4489
|
function oauthDomain(enterpriseUrl) {
|
|
4076
4490
|
return enterpriseUrl ? normalizeCopilotEnterpriseDomain(enterpriseUrl) : "github.com";
|
|
4077
4491
|
}
|
|
4078
|
-
async function startCopilotDeviceFlow(
|
|
4079
|
-
if (!
|
|
4492
|
+
async function startCopilotDeviceFlow(clientId2, enterpriseUrl) {
|
|
4493
|
+
if (!clientId2.trim()) {
|
|
4080
4494
|
throw new Error("GitHub OAuth client ID is required for Copilot login.");
|
|
4081
4495
|
}
|
|
4082
4496
|
const normalizedEnterpriseUrl = enterpriseUrl ? normalizeCopilotEnterpriseDomain(enterpriseUrl) : void 0;
|
|
@@ -4089,7 +4503,7 @@ async function startCopilotDeviceFlow(clientId, enterpriseUrl) {
|
|
|
4089
4503
|
"User-Agent": "openjaw-agent/0.1.0"
|
|
4090
4504
|
},
|
|
4091
4505
|
body: JSON.stringify({
|
|
4092
|
-
client_id:
|
|
4506
|
+
client_id: clientId2,
|
|
4093
4507
|
scope: "read:user"
|
|
4094
4508
|
})
|
|
4095
4509
|
});
|
|
@@ -4105,7 +4519,7 @@ async function startCopilotDeviceFlow(clientId, enterpriseUrl) {
|
|
|
4105
4519
|
verificationUri: body.verification_uri,
|
|
4106
4520
|
userCode: body.user_code,
|
|
4107
4521
|
deviceCode: body.device_code,
|
|
4108
|
-
clientId,
|
|
4522
|
+
clientId: clientId2,
|
|
4109
4523
|
intervalSeconds: body.interval ?? 5,
|
|
4110
4524
|
enterpriseUrl: normalizedEnterpriseUrl
|
|
4111
4525
|
};
|
|
@@ -4409,8 +4823,8 @@ For local proxy mode without API keys, use /connect maestro.`
|
|
|
4409
4823
|
}
|
|
4410
4824
|
};
|
|
4411
4825
|
}
|
|
4412
|
-
const
|
|
4413
|
-
if (!
|
|
4826
|
+
const clientId2 = resolveCopilotClientId();
|
|
4827
|
+
if (!clientId2) {
|
|
4414
4828
|
emit({
|
|
4415
4829
|
type: "error",
|
|
4416
4830
|
content: [
|
|
@@ -4426,7 +4840,7 @@ For local proxy mode without API keys, use /connect maestro.`
|
|
|
4426
4840
|
}
|
|
4427
4841
|
const label = enterpriseUrl ? `GitHub Enterprise (${enterpriseUrl})` : "GitHub.com";
|
|
4428
4842
|
try {
|
|
4429
|
-
const flow = await startCopilotDeviceFlow(
|
|
4843
|
+
const flow = await startCopilotDeviceFlow(clientId2, enterpriseUrl);
|
|
4430
4844
|
emit({
|
|
4431
4845
|
type: "system",
|
|
4432
4846
|
content: [
|
|
@@ -4612,6 +5026,8 @@ var init_agent_loop = __esm({
|
|
|
4612
5026
|
init_telemetry();
|
|
4613
5027
|
init_context_compressor();
|
|
4614
5028
|
init_tool_exposure();
|
|
5029
|
+
init_turn_control();
|
|
5030
|
+
init_tool_guardrails();
|
|
4615
5031
|
init_provider_auth();
|
|
4616
5032
|
init_connect();
|
|
4617
5033
|
AgentLoop = class {
|
|
@@ -4949,6 +5365,66 @@ var init_agent_loop = __esm({
|
|
|
4949
5365
|
this.conversationHistory = next.messages;
|
|
4950
5366
|
return { session_id: next.id, title: next.summary };
|
|
4951
5367
|
}
|
|
5368
|
+
/**
|
|
5369
|
+
* Create a brand-new empty session and switch this AgentLoop over to it.
|
|
5370
|
+
* Unlike branchSession, the new session starts with an empty history —
|
|
5371
|
+
* this is the "+" button / `/clear`-equivalent for users who want a
|
|
5372
|
+
* fresh conversation without affecting their current one.
|
|
5373
|
+
*
|
|
5374
|
+
* Persists the current session first (so any unsaved counters / summary
|
|
5375
|
+
* land on disk) before swapping. Returns null if a turn is currently
|
|
5376
|
+
* in flight (matching swapToSession's defense-in-depth posture); the
|
|
5377
|
+
* caller is responsible for interrupting first.
|
|
5378
|
+
*/
|
|
5379
|
+
createAndSwitchTo() {
|
|
5380
|
+
if (this.isRunning) return null;
|
|
5381
|
+
saveSession(this.session);
|
|
5382
|
+
const next = createSession(this.config.llm.provider, this.config.llm.model);
|
|
5383
|
+
saveSession(next);
|
|
5384
|
+
this.session = next;
|
|
5385
|
+
this.conversationHistory = next.messages;
|
|
5386
|
+
this._toolExposureState = createToolExposureState();
|
|
5387
|
+
this._compactedOnResume = false;
|
|
5388
|
+
this._toolRoundsInRun = 0;
|
|
5389
|
+
return next;
|
|
5390
|
+
}
|
|
5391
|
+
/**
|
|
5392
|
+
* Resume an existing on-disk session as the active session for this loop.
|
|
5393
|
+
* Persists the current session first, then loads the target's messages
|
|
5394
|
+
* into `conversationHistory` and rebinds `this.session` so subsequent
|
|
5395
|
+
* `prompt.submit` turns run against the resumed conversation.
|
|
5396
|
+
*
|
|
5397
|
+
* Returns the loaded `SessionData` on success, or `null` if:
|
|
5398
|
+
* - a turn is currently in flight (callers must abort or wait first);
|
|
5399
|
+
* - the target session id doesn't exist on disk.
|
|
5400
|
+
*
|
|
5401
|
+
* Provider/model are NOT switched. The session's recorded provider/model
|
|
5402
|
+
* fields are updated to whatever the loop is currently configured for —
|
|
5403
|
+
* matching the constructor's resume behaviour, which loads the messages
|
|
5404
|
+
* but keeps the AgentLoop's `config.llm.provider/model` as-is. A user
|
|
5405
|
+
* who wants the resumed session's original model must call `switchModel`
|
|
5406
|
+
* separately (or run via the `/model` slash command).
|
|
5407
|
+
*
|
|
5408
|
+
* Required by both A3 defer-on-switch and any future A2 concurrent-
|
|
5409
|
+
* streaming refactor (the desktop UI's `session.resume` RPC depends on
|
|
5410
|
+
* this method actually rebinding history — see the plan, section
|
|
5411
|
+
* "Multi-session story").
|
|
5412
|
+
*/
|
|
5413
|
+
swapToSession(targetId) {
|
|
5414
|
+
if (this.isRunning) return null;
|
|
5415
|
+
const target = loadSession(targetId);
|
|
5416
|
+
if (!target) return null;
|
|
5417
|
+
saveSession(this.session);
|
|
5418
|
+
target.provider = this.config.llm.provider;
|
|
5419
|
+
target.model = this.config.llm.model;
|
|
5420
|
+
this.session = target;
|
|
5421
|
+
this.conversationHistory = target.messages;
|
|
5422
|
+
this._toolExposureState = createToolExposureState();
|
|
5423
|
+
this._compactedOnResume = false;
|
|
5424
|
+
this._toolRoundsInRun = 0;
|
|
5425
|
+
saveSession(this.session);
|
|
5426
|
+
return target;
|
|
5427
|
+
}
|
|
4952
5428
|
/** Read-only access to the underlying session metadata. */
|
|
4953
5429
|
getSessionMeta() {
|
|
4954
5430
|
return {
|
|
@@ -5132,15 +5608,25 @@ ${summary}
|
|
|
5132
5608
|
const MAX_SAME_ACTIONS = 3;
|
|
5133
5609
|
let previousCacheReadTokens = 0;
|
|
5134
5610
|
let maxTokensContinuations = 0;
|
|
5611
|
+
const budget = new IterationBudget(this.config.llm.max_tool_rounds ?? DEFAULT_MAX_TOOL_ROUNDS);
|
|
5612
|
+
const guardrails = new ToolLoopGuardrails();
|
|
5135
5613
|
for (let step = 0; ; step++) {
|
|
5136
5614
|
if (signal.aborted) {
|
|
5137
5615
|
yield { type: "answer", content: "[Interrupted by user]" };
|
|
5138
5616
|
return;
|
|
5139
5617
|
}
|
|
5618
|
+
const forceFinalSummary = budget.isGraceRound();
|
|
5619
|
+
if (!budget.consume()) {
|
|
5620
|
+
const reason = "max_iterations";
|
|
5621
|
+
yield { type: "answer", content: `[Reached the maximum of ${budget.max} tool rounds. Stopping.]`, exitReason: reason };
|
|
5622
|
+
return;
|
|
5623
|
+
}
|
|
5140
5624
|
let responseText = null;
|
|
5141
5625
|
const responseToolCalls = [];
|
|
5142
5626
|
let responseStopReason = "end";
|
|
5627
|
+
let responseReasoningOpaque;
|
|
5143
5628
|
let responseUsage;
|
|
5629
|
+
preloadRelevantCategoriesForRequest(this.toolRegistry, userMessage);
|
|
5144
5630
|
const allTools = this.toolRegistry.listTools();
|
|
5145
5631
|
const exposure = selectToolsForRequest({
|
|
5146
5632
|
config: this.config,
|
|
@@ -5148,7 +5634,13 @@ ${summary}
|
|
|
5148
5634
|
userMessage,
|
|
5149
5635
|
state: this._toolExposureState
|
|
5150
5636
|
});
|
|
5151
|
-
const tools = exposure.tools;
|
|
5637
|
+
const tools = forceFinalSummary ? [] : exposure.tools;
|
|
5638
|
+
if (forceFinalSummary) {
|
|
5639
|
+
messages.push({
|
|
5640
|
+
role: "user",
|
|
5641
|
+
content: "[System: You've reached the maximum number of tool-calling rounds. Do not call any more tools. Summarize what you accomplished, what is still incomplete, and any blocker, as your final answer.]"
|
|
5642
|
+
});
|
|
5643
|
+
}
|
|
5152
5644
|
const chatOptions = {
|
|
5153
5645
|
systemPrompt,
|
|
5154
5646
|
messages,
|
|
@@ -5231,6 +5723,7 @@ ${summary}
|
|
|
5231
5723
|
responseToolCalls.push(...response.toolCalls);
|
|
5232
5724
|
responseStopReason = response.stopReason;
|
|
5233
5725
|
responseUsage = response.usage;
|
|
5726
|
+
responseReasoningOpaque = response.reasoningOpaque;
|
|
5234
5727
|
}
|
|
5235
5728
|
} catch (apiError) {
|
|
5236
5729
|
const errMsg = apiError instanceof Error ? apiError.message : String(apiError);
|
|
@@ -5357,10 +5850,11 @@ ${summary}
|
|
|
5357
5850
|
this.conversationHistory.push({ role: "assistant", content: responseText });
|
|
5358
5851
|
this.session.messages = this.conversationHistory;
|
|
5359
5852
|
saveSession(this.session);
|
|
5853
|
+
const exitReason = forceFinalSummary ? "max_iterations" : "completed";
|
|
5360
5854
|
if (!this.provider.chatStream) {
|
|
5361
|
-
yield { type: "answer", content: responseText ?? "" };
|
|
5855
|
+
yield { type: "answer", content: responseText ?? "", exitReason };
|
|
5362
5856
|
} else {
|
|
5363
|
-
yield { type: "answer", content: "" };
|
|
5857
|
+
yield { type: "answer", content: "", exitReason };
|
|
5364
5858
|
}
|
|
5365
5859
|
if (this._toolRoundsInRun >= 1 || responseText && responseText.length > 200) {
|
|
5366
5860
|
void this.postTurnMemorySave(systemPrompt, messages, tools, signal);
|
|
@@ -5392,7 +5886,8 @@ ${summary}
|
|
|
5392
5886
|
messages.push({
|
|
5393
5887
|
role: "assistant",
|
|
5394
5888
|
content: responseText,
|
|
5395
|
-
toolCalls: validToolCalls
|
|
5889
|
+
toolCalls: validToolCalls,
|
|
5890
|
+
reasoningOpaque: responseReasoningOpaque
|
|
5396
5891
|
});
|
|
5397
5892
|
const computerCalls = validToolCalls.filter((tc) => tc.name === "computer");
|
|
5398
5893
|
const otherCalls = validToolCalls.filter((tc) => tc.name !== "computer");
|
|
@@ -5400,6 +5895,10 @@ ${summary}
|
|
|
5400
5895
|
if (signal.aborted) {
|
|
5401
5896
|
return { id: tc.id, name: tc.name, output: "[Interrupted]", imageData: void 0 };
|
|
5402
5897
|
}
|
|
5898
|
+
const pre = guardrails.before(tc.name, tc.input);
|
|
5899
|
+
if (pre.action === "block") {
|
|
5900
|
+
return { id: tc.id, name: tc.name, output: blockedToolResult(pre), imageData: void 0 };
|
|
5901
|
+
}
|
|
5403
5902
|
let output;
|
|
5404
5903
|
let imageData2;
|
|
5405
5904
|
try {
|
|
@@ -5456,7 +5955,12 @@ ${summary}
|
|
|
5456
5955
|
}
|
|
5457
5956
|
} catch {
|
|
5458
5957
|
}
|
|
5459
|
-
|
|
5958
|
+
let outputStr = typeof output === "string" ? output : JSON.stringify(output ?? { error: "No output" });
|
|
5959
|
+
const failed = toolOutputLooksFailed(outputStr);
|
|
5960
|
+
const verdict = guardrails.after(tc.name, tc.input, outputStr, failed);
|
|
5961
|
+
if (verdict.action === "warn" || verdict.action === "halt") {
|
|
5962
|
+
outputStr = appendGuardrailGuidance(outputStr, verdict);
|
|
5963
|
+
}
|
|
5460
5964
|
return { id: tc.id, name: tc.name, output: outputStr, imageData: imageData2 };
|
|
5461
5965
|
}, "executeOne");
|
|
5462
5966
|
const results = [];
|
|
@@ -5484,18 +5988,18 @@ ${summary}
|
|
|
5484
5988
|
content: parsed.question,
|
|
5485
5989
|
choices: parsed.choices ?? void 0
|
|
5486
5990
|
};
|
|
5487
|
-
const userResponse = await new Promise((
|
|
5991
|
+
const userResponse = await new Promise((resolve7) => {
|
|
5488
5992
|
if (this._pendingAskUserResponse !== null) {
|
|
5489
5993
|
const buffered = this._pendingAskUserResponse;
|
|
5490
5994
|
this._pendingAskUserResponse = null;
|
|
5491
|
-
|
|
5995
|
+
resolve7(buffered);
|
|
5492
5996
|
return;
|
|
5493
5997
|
}
|
|
5494
|
-
this._askUserResolver =
|
|
5998
|
+
this._askUserResolver = resolve7;
|
|
5495
5999
|
setTimeout(() => {
|
|
5496
|
-
if (this._askUserResolver ===
|
|
6000
|
+
if (this._askUserResolver === resolve7) {
|
|
5497
6001
|
this._askUserResolver = null;
|
|
5498
|
-
|
|
6002
|
+
resolve7("[No response from user \u2014 timed out after 5 minutes]");
|
|
5499
6003
|
}
|
|
5500
6004
|
}, 5 * 60 * 1e3);
|
|
5501
6005
|
});
|
|
@@ -5516,6 +6020,15 @@ ${summary}
|
|
|
5516
6020
|
this.conversationHistory = [...messages];
|
|
5517
6021
|
this.session.messages = this.conversationHistory;
|
|
5518
6022
|
saveSession(this.session);
|
|
6023
|
+
if (guardrails.halted) {
|
|
6024
|
+
const reason = "guardrail_halt";
|
|
6025
|
+
yield {
|
|
6026
|
+
type: "answer",
|
|
6027
|
+
content: `[Stopped: ${guardrails.halted.message ?? "tool loop detected"}]`,
|
|
6028
|
+
exitReason: reason
|
|
6029
|
+
};
|
|
6030
|
+
return;
|
|
6031
|
+
}
|
|
5519
6032
|
if (this._toolRoundsInRun > 0 && this._toolRoundsInRun % 5 === 0) {
|
|
5520
6033
|
messages.push({
|
|
5521
6034
|
role: "user",
|
|
@@ -5590,14 +6103,14 @@ __export(settings_exports, {
|
|
|
5590
6103
|
});
|
|
5591
6104
|
import { z } from "zod";
|
|
5592
6105
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
5593
|
-
import { existsSync as
|
|
6106
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
5594
6107
|
import { join as join9 } from "node:path";
|
|
5595
6108
|
import { homedir as homedir6 } from "node:os";
|
|
5596
6109
|
import { parse as parseYaml2, stringify as stringifyYaml2 } from "yaml";
|
|
5597
6110
|
async function ensureDirectories() {
|
|
5598
6111
|
const dirs = [OPENJAW_DIR, SESSIONS_DIR, MEMORY_DIR];
|
|
5599
6112
|
for (const dir2 of dirs) {
|
|
5600
|
-
if (!
|
|
6113
|
+
if (!existsSync8(dir2)) {
|
|
5601
6114
|
await mkdir(dir2, { recursive: true });
|
|
5602
6115
|
}
|
|
5603
6116
|
}
|
|
@@ -5608,7 +6121,7 @@ async function loadConfig() {
|
|
|
5608
6121
|
}
|
|
5609
6122
|
await ensureDirectories();
|
|
5610
6123
|
let rawConfig = {};
|
|
5611
|
-
if (
|
|
6124
|
+
if (existsSync8(CONFIG_PATH)) {
|
|
5612
6125
|
const content = await readFile(CONFIG_PATH, "utf-8");
|
|
5613
6126
|
rawConfig = parseYaml2(content);
|
|
5614
6127
|
}
|
|
@@ -5658,7 +6171,13 @@ var init_settings = __esm({
|
|
|
5658
6171
|
MicrosoftConfigSchema = z.object({
|
|
5659
6172
|
tenant_id: z.string().optional(),
|
|
5660
6173
|
client_id: z.string().optional(),
|
|
5661
|
-
client_secret: z.string().optional()
|
|
6174
|
+
client_secret: z.string().optional(),
|
|
6175
|
+
// Graph token acquisition strategy:
|
|
6176
|
+
// 'auto' (default) — try the WAM broker first (reliable, browser-free on
|
|
6177
|
+
// Windows), fall back to CDP browser-token extraction.
|
|
6178
|
+
// 'wam' — broker only (no CDP fallback).
|
|
6179
|
+
// 'cdp' — legacy browser-token extraction only (disable WAM).
|
|
6180
|
+
auth_mode: z.enum(["auto", "wam", "cdp"]).optional()
|
|
5662
6181
|
});
|
|
5663
6182
|
BrowserConfigSchema = z.object({
|
|
5664
6183
|
executable: z.string().optional(),
|
|
@@ -6158,7 +6677,7 @@ var init_browser = __esm({
|
|
|
6158
6677
|
await Page.domContentEventFired();
|
|
6159
6678
|
} else if (options.waitFor === "networkidle") {
|
|
6160
6679
|
await Page.loadEventFired();
|
|
6161
|
-
await new Promise((
|
|
6680
|
+
await new Promise((resolve7) => setTimeout(resolve7, 1e3));
|
|
6162
6681
|
}
|
|
6163
6682
|
const result = await Runtime.evaluate({
|
|
6164
6683
|
expression: "document.title"
|
|
@@ -6929,7 +7448,7 @@ var init_browser = __esm({
|
|
|
6929
7448
|
if (exists) {
|
|
6930
7449
|
return true;
|
|
6931
7450
|
}
|
|
6932
|
-
await new Promise((
|
|
7451
|
+
await new Promise((resolve7) => setTimeout(resolve7, 200));
|
|
6933
7452
|
}
|
|
6934
7453
|
return false;
|
|
6935
7454
|
}
|
|
@@ -7157,10 +7676,10 @@ function createBrowseTools(config, sharedBrowser) {
|
|
|
7157
7676
|
}
|
|
7158
7677
|
},
|
|
7159
7678
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
7160
|
-
const { join:
|
|
7679
|
+
const { join: join49 } = await import("node:path");
|
|
7161
7680
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
7162
7681
|
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
7163
|
-
const screenshotPath =
|
|
7682
|
+
const screenshotPath = join49(tmpdir13(), `openjaw-browser-${randomUUID15().slice(0, 8)}.png`);
|
|
7164
7683
|
const screenshot = await browser.screenshot({ fullPage: false, path: screenshotPath });
|
|
7165
7684
|
const snapshot = await browser.snapshot({ full: false });
|
|
7166
7685
|
return {
|
|
@@ -7855,7 +8374,7 @@ var init_outlook_desktop = __esm({
|
|
|
7855
8374
|
}
|
|
7856
8375
|
}
|
|
7857
8376
|
sleep(ms) {
|
|
7858
|
-
return new Promise((
|
|
8377
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
7859
8378
|
}
|
|
7860
8379
|
};
|
|
7861
8380
|
}
|
|
@@ -8453,14 +8972,14 @@ var init_outlook_web = __esm({
|
|
|
8453
8972
|
await this.browser.typeChars(text);
|
|
8454
8973
|
}
|
|
8455
8974
|
sleep(ms) {
|
|
8456
|
-
return new Promise((
|
|
8975
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
8457
8976
|
}
|
|
8458
8977
|
};
|
|
8459
8978
|
}
|
|
8460
8979
|
});
|
|
8461
8980
|
|
|
8462
8981
|
// ../openjaw-mcp/dist/auth/token-pool.js
|
|
8463
|
-
import { existsSync as
|
|
8982
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
8464
8983
|
import { join as join10 } from "node:path";
|
|
8465
8984
|
import { homedir as homedir7 } from "node:os";
|
|
8466
8985
|
function decodeJwtPayload(jwt) {
|
|
@@ -8657,7 +9176,7 @@ var init_token_pool = __esm({
|
|
|
8657
9176
|
* Load pool from disk, including legacy token files.
|
|
8658
9177
|
*/
|
|
8659
9178
|
load() {
|
|
8660
|
-
if (
|
|
9179
|
+
if (existsSync9(POOL_FILE)) {
|
|
8661
9180
|
try {
|
|
8662
9181
|
const raw = readFileSync6(POOL_FILE, "utf-8");
|
|
8663
9182
|
const data = JSON.parse(raw);
|
|
@@ -8684,7 +9203,7 @@ var init_token_pool = __esm({
|
|
|
8684
9203
|
*/
|
|
8685
9204
|
loadLegacyFiles() {
|
|
8686
9205
|
const legacyDir = join10(POOL_DIR, "tokens");
|
|
8687
|
-
if (!
|
|
9206
|
+
if (!existsSync9(legacyDir))
|
|
8688
9207
|
return;
|
|
8689
9208
|
try {
|
|
8690
9209
|
const { readdirSync: readdirSync8 } = __require("node:fs");
|
|
@@ -8868,7 +9387,7 @@ var init_cdp_token_extractor = __esm({
|
|
|
8868
9387
|
}
|
|
8869
9388
|
logger_default.info("CDP: reloading tab for token refresh", { url: targetTab.url, audience });
|
|
8870
9389
|
await this.reloadTab(targetTab);
|
|
8871
|
-
await new Promise((
|
|
9390
|
+
await new Promise((resolve7) => setTimeout(resolve7, PAGE_RELOAD_WAIT_MS));
|
|
8872
9391
|
if (!targetTab.webSocketDebuggerUrl)
|
|
8873
9392
|
return [];
|
|
8874
9393
|
const freshPages = await this.listPages();
|
|
@@ -8985,19 +9504,19 @@ var init_cdp_token_extractor = __esm({
|
|
|
8985
9504
|
* Evaluate a JS expression in a tab and return the string result.
|
|
8986
9505
|
*/
|
|
8987
9506
|
async evaluateInTab(wsUrl, expression) {
|
|
8988
|
-
return new Promise((
|
|
9507
|
+
return new Promise((resolve7) => {
|
|
8989
9508
|
let ws;
|
|
8990
9509
|
try {
|
|
8991
9510
|
ws = new WebSocket(wsUrl);
|
|
8992
9511
|
} catch (err) {
|
|
8993
9512
|
logger_default.warn("CDP: WebSocket constructor failed", { wsUrl: wsUrl.substring(0, 60), error: String(err) });
|
|
8994
|
-
|
|
9513
|
+
resolve7(null);
|
|
8995
9514
|
return;
|
|
8996
9515
|
}
|
|
8997
9516
|
const timer = setTimeout(() => {
|
|
8998
9517
|
logger_default.warn("CDP: evaluateInTab timeout", { wsUrl: wsUrl.substring(0, 60) });
|
|
8999
9518
|
ws.close();
|
|
9000
|
-
|
|
9519
|
+
resolve7(null);
|
|
9001
9520
|
}, CDP_TIMEOUT_MS);
|
|
9002
9521
|
ws.on("open", () => {
|
|
9003
9522
|
ws.send(JSON.stringify({
|
|
@@ -9011,18 +9530,18 @@ var init_cdp_token_extractor = __esm({
|
|
|
9011
9530
|
if (resp.id === 1) {
|
|
9012
9531
|
clearTimeout(timer);
|
|
9013
9532
|
ws.close();
|
|
9014
|
-
|
|
9533
|
+
resolve7(resp.result?.result?.value ?? null);
|
|
9015
9534
|
}
|
|
9016
9535
|
});
|
|
9017
9536
|
ws.on("error", (err) => {
|
|
9018
9537
|
logger_default.warn("CDP: evaluateInTab WS error", { error: String(err), wsUrl: wsUrl.substring(0, 60) });
|
|
9019
9538
|
clearTimeout(timer);
|
|
9020
|
-
|
|
9539
|
+
resolve7(null);
|
|
9021
9540
|
});
|
|
9022
9541
|
});
|
|
9023
9542
|
}
|
|
9024
9543
|
async extractFromTab(wsUrl) {
|
|
9025
|
-
return new Promise((
|
|
9544
|
+
return new Promise((resolve7, reject) => {
|
|
9026
9545
|
const ws = new WebSocket(wsUrl);
|
|
9027
9546
|
const timer = setTimeout(() => {
|
|
9028
9547
|
ws.close();
|
|
@@ -9042,14 +9561,14 @@ var init_cdp_token_extractor = __esm({
|
|
|
9042
9561
|
ws.close();
|
|
9043
9562
|
const value = resp.result?.result?.value;
|
|
9044
9563
|
if (!value) {
|
|
9045
|
-
|
|
9564
|
+
resolve7([]);
|
|
9046
9565
|
return;
|
|
9047
9566
|
}
|
|
9048
9567
|
try {
|
|
9049
9568
|
const tokens = JSON.parse(value);
|
|
9050
|
-
|
|
9569
|
+
resolve7(tokens);
|
|
9051
9570
|
} catch {
|
|
9052
|
-
|
|
9571
|
+
resolve7([]);
|
|
9053
9572
|
}
|
|
9054
9573
|
}
|
|
9055
9574
|
});
|
|
@@ -9065,11 +9584,11 @@ var init_cdp_token_extractor = __esm({
|
|
|
9065
9584
|
async reloadTab(page) {
|
|
9066
9585
|
if (!page.webSocketDebuggerUrl)
|
|
9067
9586
|
return;
|
|
9068
|
-
return new Promise((
|
|
9587
|
+
return new Promise((resolve7, reject) => {
|
|
9069
9588
|
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
9070
9589
|
const timer = setTimeout(() => {
|
|
9071
9590
|
ws.close();
|
|
9072
|
-
|
|
9591
|
+
resolve7();
|
|
9073
9592
|
}, 1e4);
|
|
9074
9593
|
ws.on("open", () => {
|
|
9075
9594
|
ws.send(JSON.stringify({
|
|
@@ -9083,7 +9602,7 @@ var init_cdp_token_extractor = __esm({
|
|
|
9083
9602
|
if (resp.id === 1) {
|
|
9084
9603
|
clearTimeout(timer);
|
|
9085
9604
|
ws.close();
|
|
9086
|
-
|
|
9605
|
+
resolve7();
|
|
9087
9606
|
}
|
|
9088
9607
|
});
|
|
9089
9608
|
ws.on("error", (err) => {
|
|
@@ -9123,13 +9642,172 @@ var init_cdp_token_extractor = __esm({
|
|
|
9123
9642
|
}
|
|
9124
9643
|
});
|
|
9125
9644
|
|
|
9645
|
+
// ../openjaw-mcp/dist/auth/wam-token-provider.js
|
|
9646
|
+
var wam_token_provider_exports = {};
|
|
9647
|
+
__export(wam_token_provider_exports, {
|
|
9648
|
+
WAM_GRAPH_SCOPES: () => WAM_GRAPH_SCOPES,
|
|
9649
|
+
acquireGraphToken: () => acquireGraphToken,
|
|
9650
|
+
acquireTokenForAudience: () => acquireTokenForAudience,
|
|
9651
|
+
configureWam: () => configureWam,
|
|
9652
|
+
isWamAvailable: () => isWamAvailable,
|
|
9653
|
+
setWamWindowHandleProvider: () => setWamWindowHandleProvider
|
|
9654
|
+
});
|
|
9655
|
+
import { InteractionRequiredAuthError } from "@azure/msal-node";
|
|
9656
|
+
function configureWam(opts) {
|
|
9657
|
+
if (opts.clientId)
|
|
9658
|
+
clientId = opts.clientId;
|
|
9659
|
+
if (opts.tenant)
|
|
9660
|
+
tenant = opts.tenant;
|
|
9661
|
+
if (typeof opts.enabled === "boolean")
|
|
9662
|
+
wamEnabled = opts.enabled;
|
|
9663
|
+
}
|
|
9664
|
+
function setWamWindowHandleProvider(fn) {
|
|
9665
|
+
windowHandleProvider = fn;
|
|
9666
|
+
}
|
|
9667
|
+
async function getBrokerPlugin() {
|
|
9668
|
+
if (brokerLoadAttempted)
|
|
9669
|
+
return nativeBrokerPlugin;
|
|
9670
|
+
brokerLoadAttempted = true;
|
|
9671
|
+
if (process.platform !== "win32") {
|
|
9672
|
+
logger_default.debug("WAM: not win32, broker unavailable");
|
|
9673
|
+
return null;
|
|
9674
|
+
}
|
|
9675
|
+
try {
|
|
9676
|
+
const { NativeBrokerPlugin } = await import("@azure/msal-node-extensions");
|
|
9677
|
+
const plugin = new NativeBrokerPlugin();
|
|
9678
|
+
nativeBrokerPlugin = plugin;
|
|
9679
|
+
} catch (err) {
|
|
9680
|
+
logger_default.warn("WAM: failed to load NativeBrokerPlugin", { error: err instanceof Error ? err.message : String(err) });
|
|
9681
|
+
nativeBrokerPlugin = null;
|
|
9682
|
+
}
|
|
9683
|
+
return nativeBrokerPlugin;
|
|
9684
|
+
}
|
|
9685
|
+
async function getApp() {
|
|
9686
|
+
const plugin = await getBrokerPlugin();
|
|
9687
|
+
if (!plugin || !plugin.isBrokerAvailable)
|
|
9688
|
+
return null;
|
|
9689
|
+
if (!msalApp) {
|
|
9690
|
+
const { PublicClientApplication } = await import("@azure/msal-node");
|
|
9691
|
+
msalApp = new PublicClientApplication({
|
|
9692
|
+
auth: { clientId, authority: `https://login.microsoftonline.com/${tenant}` },
|
|
9693
|
+
broker: { nativeBrokerPlugin: plugin }
|
|
9694
|
+
});
|
|
9695
|
+
}
|
|
9696
|
+
return msalApp;
|
|
9697
|
+
}
|
|
9698
|
+
function withBrokerLock(fn) {
|
|
9699
|
+
const result = _brokerQueue.then(fn, fn);
|
|
9700
|
+
_brokerQueue = result.then(() => void 0, () => void 0);
|
|
9701
|
+
return result;
|
|
9702
|
+
}
|
|
9703
|
+
function isInteractionRequired(err) {
|
|
9704
|
+
if (err instanceof InteractionRequiredAuthError)
|
|
9705
|
+
return true;
|
|
9706
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9707
|
+
return /interaction[_\-\s]?required|no[_\-\s]?account/i.test(msg);
|
|
9708
|
+
}
|
|
9709
|
+
async function acquireUnlocked(app, scopes) {
|
|
9710
|
+
const accounts = await app.getAllAccounts();
|
|
9711
|
+
const account = selectedAccount ?? accounts.find((a) => a.tenantId === tenant) ?? (accounts.length === 1 ? accounts[0] : void 0);
|
|
9712
|
+
if (account) {
|
|
9713
|
+
try {
|
|
9714
|
+
return await app.acquireTokenSilent({ scopes, account });
|
|
9715
|
+
} catch (err) {
|
|
9716
|
+
if (!isInteractionRequired(err)) {
|
|
9717
|
+
logger_default.warn("WAM: silent acquire failed (non-interactive)", {
|
|
9718
|
+
error: err instanceof Error ? err.message.split("\n")[0] : String(err)
|
|
9719
|
+
});
|
|
9720
|
+
throw err;
|
|
9721
|
+
}
|
|
9722
|
+
logger_default.info("WAM: silent failed, interaction required");
|
|
9723
|
+
}
|
|
9724
|
+
}
|
|
9725
|
+
const windowHandle = windowHandleProvider?.() ?? void 0;
|
|
9726
|
+
const result = await app.acquireTokenInteractive({
|
|
9727
|
+
scopes,
|
|
9728
|
+
windowHandle,
|
|
9729
|
+
openBrowser: noop,
|
|
9730
|
+
prompt: "select_account",
|
|
9731
|
+
loginHint: account?.username
|
|
9732
|
+
});
|
|
9733
|
+
if (result.account)
|
|
9734
|
+
selectedAccount = result.account;
|
|
9735
|
+
return result;
|
|
9736
|
+
}
|
|
9737
|
+
async function acquireGraphToken(scopes = WAM_GRAPH_SCOPES) {
|
|
9738
|
+
return acquireTokenForScopes(scopes);
|
|
9739
|
+
}
|
|
9740
|
+
async function acquireTokenForAudience(audience, _perms = []) {
|
|
9741
|
+
const base = audience.endsWith("/") ? audience.slice(0, -1) : audience;
|
|
9742
|
+
return acquireTokenForScopes([`${base}/.default`]);
|
|
9743
|
+
}
|
|
9744
|
+
async function acquireTokenForScopes(scopes) {
|
|
9745
|
+
if (!wamEnabled || brokerPoisoned)
|
|
9746
|
+
return null;
|
|
9747
|
+
try {
|
|
9748
|
+
const app = await getApp();
|
|
9749
|
+
if (!app)
|
|
9750
|
+
return null;
|
|
9751
|
+
const result = await withBrokerLock(() => acquireUnlocked(app, scopes));
|
|
9752
|
+
return result?.accessToken ?? null;
|
|
9753
|
+
} catch (err) {
|
|
9754
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9755
|
+
if (/AccountUnusable|broker.*unavailable/i.test(msg)) {
|
|
9756
|
+
brokerPoisoned = true;
|
|
9757
|
+
logger_default.warn("WAM: broker poisoned, disabling for this session", { error: msg.split("\n")[0] });
|
|
9758
|
+
} else {
|
|
9759
|
+
logger_default.warn("WAM: acquire failed, will fall back", { error: msg.split("\n")[0] });
|
|
9760
|
+
}
|
|
9761
|
+
return null;
|
|
9762
|
+
}
|
|
9763
|
+
}
|
|
9764
|
+
async function isWamAvailable() {
|
|
9765
|
+
if (!wamEnabled || brokerPoisoned)
|
|
9766
|
+
return false;
|
|
9767
|
+
const plugin = await getBrokerPlugin();
|
|
9768
|
+
return !!plugin && plugin.isBrokerAvailable;
|
|
9769
|
+
}
|
|
9770
|
+
var CORP_TENANT, DEFAULT_CLIENT_ID, WAM_GRAPH_SCOPES, clientId, tenant, windowHandleProvider, wamEnabled, brokerLoadAttempted, nativeBrokerPlugin, msalApp, brokerPoisoned, selectedAccount, _brokerQueue, noop;
|
|
9771
|
+
var init_wam_token_provider = __esm({
|
|
9772
|
+
"../openjaw-mcp/dist/auth/wam-token-provider.js"() {
|
|
9773
|
+
"use strict";
|
|
9774
|
+
init_logger();
|
|
9775
|
+
CORP_TENANT = "72f988bf-86f1-41af-91ab-2d7cd011db47";
|
|
9776
|
+
DEFAULT_CLIENT_ID = "99fa64eb-feda-4f94-aecd-30637ca7bf2d";
|
|
9777
|
+
WAM_GRAPH_SCOPES = ["https://graph.microsoft.com/.default"];
|
|
9778
|
+
clientId = DEFAULT_CLIENT_ID;
|
|
9779
|
+
tenant = CORP_TENANT;
|
|
9780
|
+
windowHandleProvider = null;
|
|
9781
|
+
wamEnabled = true;
|
|
9782
|
+
__name(configureWam, "configureWam");
|
|
9783
|
+
__name(setWamWindowHandleProvider, "setWamWindowHandleProvider");
|
|
9784
|
+
brokerLoadAttempted = false;
|
|
9785
|
+
nativeBrokerPlugin = null;
|
|
9786
|
+
msalApp = null;
|
|
9787
|
+
brokerPoisoned = false;
|
|
9788
|
+
selectedAccount = null;
|
|
9789
|
+
__name(getBrokerPlugin, "getBrokerPlugin");
|
|
9790
|
+
__name(getApp, "getApp");
|
|
9791
|
+
_brokerQueue = Promise.resolve();
|
|
9792
|
+
__name(withBrokerLock, "withBrokerLock");
|
|
9793
|
+
noop = /* @__PURE__ */ __name(async () => {
|
|
9794
|
+
}, "noop");
|
|
9795
|
+
__name(isInteractionRequired, "isInteractionRequired");
|
|
9796
|
+
__name(acquireUnlocked, "acquireUnlocked");
|
|
9797
|
+
__name(acquireGraphToken, "acquireGraphToken");
|
|
9798
|
+
__name(acquireTokenForAudience, "acquireTokenForAudience");
|
|
9799
|
+
__name(acquireTokenForScopes, "acquireTokenForScopes");
|
|
9800
|
+
__name(isWamAvailable, "isWamAvailable");
|
|
9801
|
+
}
|
|
9802
|
+
});
|
|
9803
|
+
|
|
9126
9804
|
// ../openjaw-mcp/dist/auth/graph-token-provider.js
|
|
9127
|
-
import { existsSync as
|
|
9128
|
-
import { join as join11, dirname as
|
|
9805
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
9806
|
+
import { join as join11, dirname as dirname4 } from "node:path";
|
|
9129
9807
|
import { homedir as homedir8 } from "node:os";
|
|
9130
9808
|
import { exec as exec2 } from "node:child_process";
|
|
9131
9809
|
import { promisify as promisify2 } from "node:util";
|
|
9132
|
-
import { fileURLToPath as
|
|
9810
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
9133
9811
|
function getSharedPool() {
|
|
9134
9812
|
if (!sharedPool) {
|
|
9135
9813
|
sharedPool = new TokenPool();
|
|
@@ -9149,9 +9827,10 @@ var init_graph_token_provider = __esm({
|
|
|
9149
9827
|
init_logger();
|
|
9150
9828
|
init_token_pool();
|
|
9151
9829
|
init_cdp_token_extractor();
|
|
9830
|
+
init_wam_token_provider();
|
|
9152
9831
|
execAsync2 = promisify2(exec2);
|
|
9153
|
-
__filename =
|
|
9154
|
-
__dirname =
|
|
9832
|
+
__filename = fileURLToPath3(import.meta.url);
|
|
9833
|
+
__dirname = dirname4(__filename);
|
|
9155
9834
|
TOKEN_PROFILES = {
|
|
9156
9835
|
"graph-chat": {
|
|
9157
9836
|
scopes: ["Chat.Read"],
|
|
@@ -9225,6 +9904,23 @@ var init_graph_token_provider = __esm({
|
|
|
9225
9904
|
this.scheduleProactiveRefresh(pooled.expiresAt);
|
|
9226
9905
|
return pooled.secret;
|
|
9227
9906
|
}
|
|
9907
|
+
{
|
|
9908
|
+
const wamJwt = await acquireTokenForAudience(this.preferredAudience, this.requiredScopes);
|
|
9909
|
+
if (wamJwt) {
|
|
9910
|
+
const added = this.pool.addTokenFromJwt(wamJwt, "wam");
|
|
9911
|
+
const token = this.pool.getToken(this.requiredScopes, this.preferredAudience);
|
|
9912
|
+
if (token) {
|
|
9913
|
+
this.saveLegacyToken(token.secret);
|
|
9914
|
+
this.scheduleProactiveRefresh(token.expiresAt);
|
|
9915
|
+
logger_default.info("Token acquired via WAM broker", { tokenName: this.tokenName });
|
|
9916
|
+
return token.secret;
|
|
9917
|
+
}
|
|
9918
|
+
if (added) {
|
|
9919
|
+
this.scheduleProactiveRefresh(added.expiresAt);
|
|
9920
|
+
return added.secret;
|
|
9921
|
+
}
|
|
9922
|
+
}
|
|
9923
|
+
}
|
|
9228
9924
|
logger_default.info("Tier 1 (pool) empty \u2014 trying Tier 2 (CDP extraction)...", {
|
|
9229
9925
|
tokenName: this.tokenName,
|
|
9230
9926
|
audience: this.preferredAudience
|
|
@@ -9482,7 +10178,7 @@ var init_graph_token_provider = __esm({
|
|
|
9482
10178
|
* Tier 4: Legacy Python script fallback.
|
|
9483
10179
|
*/
|
|
9484
10180
|
async extractViaLegacyScript() {
|
|
9485
|
-
if (!
|
|
10181
|
+
if (!existsSync10(this.extractScript)) {
|
|
9486
10182
|
return false;
|
|
9487
10183
|
}
|
|
9488
10184
|
try {
|
|
@@ -9498,7 +10194,7 @@ var init_graph_token_provider = __esm({
|
|
|
9498
10194
|
*/
|
|
9499
10195
|
migrateLegacyToken(tokenName) {
|
|
9500
10196
|
const legacyPath = join11(homedir8(), ".graph-token", "tokens", `${tokenName}.json`);
|
|
9501
|
-
if (!
|
|
10197
|
+
if (!existsSync10(legacyPath))
|
|
9502
10198
|
return;
|
|
9503
10199
|
try {
|
|
9504
10200
|
const data = JSON.parse(readFileSync7(legacyPath, "utf-8"));
|
|
@@ -9757,9 +10453,9 @@ var init_outlook_graph = __esm({
|
|
|
9757
10453
|
const wellKnown = WELL_KNOWN_FOLDERS[lower];
|
|
9758
10454
|
if (wellKnown)
|
|
9759
10455
|
return wellKnown;
|
|
9760
|
-
const
|
|
9761
|
-
if (
|
|
9762
|
-
return
|
|
10456
|
+
const cached8 = this.folderIdCache.get(lower);
|
|
10457
|
+
if (cached8)
|
|
10458
|
+
return cached8;
|
|
9763
10459
|
try {
|
|
9764
10460
|
const result = await this.graphGet(`/me/mailFolders?$filter=displayName eq '${folderName.replace(/'/g, "''")}'&$top=1`);
|
|
9765
10461
|
if (result.value.length > 0) {
|
|
@@ -10017,7 +10713,7 @@ var init_outlook_graph = __esm({
|
|
|
10017
10713
|
import { DatabaseSync } from "node:sqlite";
|
|
10018
10714
|
import { join as join12 } from "node:path";
|
|
10019
10715
|
import { homedir as homedir9 } from "node:os";
|
|
10020
|
-
import { mkdirSync as mkdirSync8, existsSync as
|
|
10716
|
+
import { mkdirSync as mkdirSync8, existsSync as existsSync11 } from "node:fs";
|
|
10021
10717
|
function hasFts5() {
|
|
10022
10718
|
return _hasFts5;
|
|
10023
10719
|
}
|
|
@@ -10033,7 +10729,7 @@ function detectFts5(database) {
|
|
|
10033
10729
|
}
|
|
10034
10730
|
function getMemoryDb() {
|
|
10035
10731
|
if (!db) {
|
|
10036
|
-
if (!
|
|
10732
|
+
if (!existsSync11(DB_DIR)) {
|
|
10037
10733
|
mkdirSync8(DB_DIR, { recursive: true });
|
|
10038
10734
|
}
|
|
10039
10735
|
db = new DatabaseSync(DB_PATH);
|
|
@@ -10117,9 +10813,9 @@ var init_db = __esm({
|
|
|
10117
10813
|
import { createHash as createHash2 } from "node:crypto";
|
|
10118
10814
|
function encodeAtom(word, dim2 = HRR_DIM) {
|
|
10119
10815
|
const cacheKey = `${word}:${dim2}`;
|
|
10120
|
-
const
|
|
10121
|
-
if (
|
|
10122
|
-
return
|
|
10816
|
+
const cached8 = atomCache.get(cacheKey);
|
|
10817
|
+
if (cached8)
|
|
10818
|
+
return cached8;
|
|
10123
10819
|
const phases = new Float64Array(dim2);
|
|
10124
10820
|
const bytesNeeded = dim2 * 4;
|
|
10125
10821
|
const chunks = [];
|
|
@@ -10394,7 +11090,7 @@ __export(store_exports, {
|
|
|
10394
11090
|
MemoryStore: () => MemoryStore
|
|
10395
11091
|
});
|
|
10396
11092
|
import { readFile as readFile2, readdir } from "node:fs/promises";
|
|
10397
|
-
import { existsSync as
|
|
11093
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
10398
11094
|
import { join as join13 } from "node:path";
|
|
10399
11095
|
var MemoryStore;
|
|
10400
11096
|
var init_store = __esm({
|
|
@@ -10452,7 +11148,7 @@ var init_store = __esm({
|
|
|
10452
11148
|
const db2 = this.ensureDb();
|
|
10453
11149
|
let migrated = 0;
|
|
10454
11150
|
const insert = db2.prepare("INSERT INTO memories (content, source, created_at) VALUES (?, ?, ?)");
|
|
10455
|
-
if (
|
|
11151
|
+
if (existsSync12(this.memoryFile)) {
|
|
10456
11152
|
const content = await readFile2(this.memoryFile, "utf-8");
|
|
10457
11153
|
const entries = this.parseMarkdownToEntries(content, "MEMORY.md");
|
|
10458
11154
|
for (const entry of entries) {
|
|
@@ -10460,7 +11156,7 @@ var init_store = __esm({
|
|
|
10460
11156
|
migrated++;
|
|
10461
11157
|
}
|
|
10462
11158
|
}
|
|
10463
|
-
if (
|
|
11159
|
+
if (existsSync12(this.memoryDir)) {
|
|
10464
11160
|
const files = await readdir(this.memoryDir);
|
|
10465
11161
|
const mdFiles = files.filter((f) => f.endsWith(".md")).sort().reverse();
|
|
10466
11162
|
for (const file2 of mdFiles) {
|
|
@@ -10744,13 +11440,13 @@ function createMemoryTools(config) {
|
|
|
10744
11440
|
const todos = input.todos;
|
|
10745
11441
|
try {
|
|
10746
11442
|
const { appendFile: appendFile2, mkdir: mkdir5 } = await import("node:fs/promises");
|
|
10747
|
-
const { existsSync:
|
|
10748
|
-
const { join:
|
|
10749
|
-
const { homedir:
|
|
10750
|
-
const memoryDir =
|
|
10751
|
-
if (!
|
|
11443
|
+
const { existsSync: existsSync36 } = await import("node:fs");
|
|
11444
|
+
const { join: join49 } = await import("node:path");
|
|
11445
|
+
const { homedir: homedir33 } = await import("node:os");
|
|
11446
|
+
const memoryDir = join49(homedir33(), ".openjaw", "memory");
|
|
11447
|
+
if (!existsSync36(memoryDir))
|
|
10752
11448
|
await mkdir5(memoryDir, { recursive: true });
|
|
10753
|
-
const todoPath =
|
|
11449
|
+
const todoPath = join49(memoryDir, "TODOS.md");
|
|
10754
11450
|
const { writeFile: writeFile5 } = await import("node:fs/promises");
|
|
10755
11451
|
await writeFile5(todoPath, `# Session Todos
|
|
10756
11452
|
|
|
@@ -12071,7 +12767,7 @@ var init_teams_desktop = __esm({
|
|
|
12071
12767
|
}
|
|
12072
12768
|
}
|
|
12073
12769
|
sleep(ms) {
|
|
12074
|
-
return new Promise((
|
|
12770
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
12075
12771
|
}
|
|
12076
12772
|
/**
|
|
12077
12773
|
* Get the current Teams window state
|
|
@@ -12938,7 +13634,7 @@ var init_teams_web = __esm({
|
|
|
12938
13634
|
}
|
|
12939
13635
|
}
|
|
12940
13636
|
sleep(ms) {
|
|
12941
|
-
return new Promise((
|
|
13637
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
12942
13638
|
}
|
|
12943
13639
|
};
|
|
12944
13640
|
}
|
|
@@ -13335,9 +14031,9 @@ ${loopContent}` : loopContent;
|
|
|
13335
14031
|
*/
|
|
13336
14032
|
async findChannelByName(searchTerm) {
|
|
13337
14033
|
const searchLower = searchTerm.toLowerCase();
|
|
13338
|
-
const
|
|
13339
|
-
if (
|
|
13340
|
-
return { ...
|
|
14034
|
+
const cached8 = this.channelIdCache.get(searchLower);
|
|
14035
|
+
if (cached8) {
|
|
14036
|
+
return { ...cached8, displayName: searchTerm };
|
|
13341
14037
|
}
|
|
13342
14038
|
try {
|
|
13343
14039
|
const teamsData = await this.graphGet("/v1.0/me/joinedTeams");
|
|
@@ -13517,9 +14213,9 @@ ${loopContent}` : loopContent;
|
|
|
13517
14213
|
* Results are cached per chat ID.
|
|
13518
14214
|
*/
|
|
13519
14215
|
async getChatMembers(chatOrChannelId) {
|
|
13520
|
-
const
|
|
13521
|
-
if (
|
|
13522
|
-
return
|
|
14216
|
+
const cached8 = this.chatMembersCache.get(chatOrChannelId);
|
|
14217
|
+
if (cached8)
|
|
14218
|
+
return cached8;
|
|
13523
14219
|
try {
|
|
13524
14220
|
let endpoint;
|
|
13525
14221
|
if (this.contextType === "channel" && this.currentChannelTeamId && chatOrChannelId === this.currentChannelId) {
|
|
@@ -13757,9 +14453,9 @@ ${loopContent}` : loopContent;
|
|
|
13757
14453
|
*/
|
|
13758
14454
|
async resolveChannelIds(teamName, channelName) {
|
|
13759
14455
|
const cacheKey = `${teamName}/${channelName}`;
|
|
13760
|
-
const
|
|
13761
|
-
if (
|
|
13762
|
-
return
|
|
14456
|
+
const cached8 = this.channelIdCache.get(cacheKey);
|
|
14457
|
+
if (cached8)
|
|
14458
|
+
return cached8;
|
|
13763
14459
|
const teamsData = await this.graphGet("/v1.0/me/joinedTeams");
|
|
13764
14460
|
const team = teamsData.value?.find((t) => t.displayName.toLowerCase() === teamName.toLowerCase());
|
|
13765
14461
|
if (!team) {
|
|
@@ -14336,7 +15032,7 @@ var init_teams_chat_monitor = __esm({
|
|
|
14336
15032
|
return this.sentMessages.has(normalized);
|
|
14337
15033
|
}
|
|
14338
15034
|
sleep(ms) {
|
|
14339
|
-
return new Promise((
|
|
15035
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
14340
15036
|
}
|
|
14341
15037
|
/**
|
|
14342
15038
|
* Attempt to reconnect the browser after detecting a disconnection.
|
|
@@ -15123,7 +15819,7 @@ ${lines.join("\n")}`;
|
|
|
15123
15819
|
globalThis.__teamsSeenMessages.set(chatName, seenIds);
|
|
15124
15820
|
}
|
|
15125
15821
|
if (syncMode) {
|
|
15126
|
-
return new Promise((
|
|
15822
|
+
return new Promise((resolve7) => {
|
|
15127
15823
|
const timer2 = setInterval(async () => {
|
|
15128
15824
|
try {
|
|
15129
15825
|
const current = await channel.readCurrentChatMessages();
|
|
@@ -15132,7 +15828,7 @@ ${lines.join("\n")}`;
|
|
|
15132
15828
|
if (!seenIds.has(msgId) && msg.sender !== currentUserName) {
|
|
15133
15829
|
clearInterval(timer2);
|
|
15134
15830
|
seenIds.add(msgId);
|
|
15135
|
-
|
|
15831
|
+
resolve7({
|
|
15136
15832
|
success: true,
|
|
15137
15833
|
channel: channelType,
|
|
15138
15834
|
sync: true,
|
|
@@ -15209,7 +15905,7 @@ ${lines.join("\n")}`;
|
|
|
15209
15905
|
globalThis.__teamsSeenMessages.set(chatName, seenIds);
|
|
15210
15906
|
}
|
|
15211
15907
|
if (syncMode) {
|
|
15212
|
-
return new Promise((
|
|
15908
|
+
return new Promise((resolve7) => {
|
|
15213
15909
|
const timer2 = setInterval(async () => {
|
|
15214
15910
|
try {
|
|
15215
15911
|
const current = await channel.readCurrentChatMessages();
|
|
@@ -15218,7 +15914,7 @@ ${lines.join("\n")}`;
|
|
|
15218
15914
|
if (!seenIds.has(msgId) && msg.sender !== currentUserName) {
|
|
15219
15915
|
clearInterval(timer2);
|
|
15220
15916
|
seenIds.add(msgId);
|
|
15221
|
-
|
|
15917
|
+
resolve7({
|
|
15222
15918
|
success: true,
|
|
15223
15919
|
channel: channelType,
|
|
15224
15920
|
sync: true,
|
|
@@ -15576,7 +16272,7 @@ ${lines.join("\n")}`;
|
|
|
15576
16272
|
return allTools;
|
|
15577
16273
|
}
|
|
15578
16274
|
function sleep2(ms) {
|
|
15579
|
-
return new Promise((
|
|
16275
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
15580
16276
|
}
|
|
15581
16277
|
var MAX_STORED_ENTRIES, ENTRY_TTL_MS;
|
|
15582
16278
|
var init_chat = __esm({
|
|
@@ -15601,8 +16297,8 @@ var init_chat = __esm({
|
|
|
15601
16297
|
|
|
15602
16298
|
// ../openjaw-mcp/dist/tools/files.js
|
|
15603
16299
|
import { readFile as readFile3, writeFile as writeFile2, readdir as readdir2, stat, mkdir as mkdir2, unlink } from "node:fs/promises";
|
|
15604
|
-
import { existsSync as
|
|
15605
|
-
import { join as join15, dirname as
|
|
16300
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "node:fs";
|
|
16301
|
+
import { join as join15, dirname as dirname5, basename, extname } from "node:path";
|
|
15606
16302
|
import { execSync as execSync3 } from "node:child_process";
|
|
15607
16303
|
function createFileTools(_config) {
|
|
15608
16304
|
return [
|
|
@@ -15639,7 +16335,7 @@ function createFileTools(_config) {
|
|
|
15639
16335
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
15640
16336
|
const path3 = input.path;
|
|
15641
16337
|
const encoding = input.encoding ?? "utf-8";
|
|
15642
|
-
if (!
|
|
16338
|
+
if (!existsSync13(path3)) {
|
|
15643
16339
|
return { error: `File not found: ${path3}` };
|
|
15644
16340
|
}
|
|
15645
16341
|
const BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -15750,12 +16446,12 @@ function createFileTools(_config) {
|
|
|
15750
16446
|
const append2 = input.append ?? false;
|
|
15751
16447
|
const createDirs = input.create_dirs ?? true;
|
|
15752
16448
|
if (createDirs) {
|
|
15753
|
-
const dir2 =
|
|
15754
|
-
if (!
|
|
16449
|
+
const dir2 = dirname5(path3);
|
|
16450
|
+
if (!existsSync13(dir2)) {
|
|
15755
16451
|
await mkdir2(dir2, { recursive: true });
|
|
15756
16452
|
}
|
|
15757
16453
|
}
|
|
15758
|
-
if (append2 &&
|
|
16454
|
+
if (append2 && existsSync13(path3)) {
|
|
15759
16455
|
const existing = await readFile3(path3, "utf-8");
|
|
15760
16456
|
await writeFile2(path3, existing + content, "utf-8");
|
|
15761
16457
|
} else {
|
|
@@ -15802,7 +16498,7 @@ function createFileTools(_config) {
|
|
|
15802
16498
|
const recursive = input.recursive ?? false;
|
|
15803
16499
|
const includeHidden = input.include_hidden ?? false;
|
|
15804
16500
|
const pattern = input.pattern;
|
|
15805
|
-
if (!
|
|
16501
|
+
if (!existsSync13(dirPath)) {
|
|
15806
16502
|
return { error: `Directory not found: ${dirPath}` };
|
|
15807
16503
|
}
|
|
15808
16504
|
const results = [];
|
|
@@ -15850,7 +16546,7 @@ function createFileTools(_config) {
|
|
|
15850
16546
|
requiresConfirmation: true,
|
|
15851
16547
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
15852
16548
|
const path3 = input.path;
|
|
15853
|
-
if (!
|
|
16549
|
+
if (!existsSync13(path3)) {
|
|
15854
16550
|
return { error: `File not found: ${path3}` };
|
|
15855
16551
|
}
|
|
15856
16552
|
await unlink(path3);
|
|
@@ -15872,7 +16568,7 @@ function createFileTools(_config) {
|
|
|
15872
16568
|
},
|
|
15873
16569
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
15874
16570
|
const path3 = input.path;
|
|
15875
|
-
if (!
|
|
16571
|
+
if (!existsSync13(path3)) {
|
|
15876
16572
|
return { error: `Path not found: ${path3}` };
|
|
15877
16573
|
}
|
|
15878
16574
|
const stats = await stat(path3);
|
|
@@ -15902,7 +16598,7 @@ function createFileTools(_config) {
|
|
|
15902
16598
|
},
|
|
15903
16599
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
15904
16600
|
const filePath = input.path;
|
|
15905
|
-
if (!
|
|
16601
|
+
if (!existsSync13(filePath)) {
|
|
15906
16602
|
return { error: `Image not found: ${filePath}` };
|
|
15907
16603
|
}
|
|
15908
16604
|
const ext = extname(filePath).toLowerCase();
|
|
@@ -15948,7 +16644,7 @@ function createFileTools(_config) {
|
|
|
15948
16644
|
const path3 = input.path;
|
|
15949
16645
|
const oldStr = input.old_str;
|
|
15950
16646
|
const newStr = input.new_str;
|
|
15951
|
-
if (!
|
|
16647
|
+
if (!existsSync13(path3)) {
|
|
15952
16648
|
return { error: `File not found: ${path3}` };
|
|
15953
16649
|
}
|
|
15954
16650
|
const fileStats = await stat(path3);
|
|
@@ -16134,7 +16830,7 @@ var init_web_search_types = __esm({
|
|
|
16134
16830
|
});
|
|
16135
16831
|
|
|
16136
16832
|
// ../openjaw-mcp/dist/tools/shell.js
|
|
16137
|
-
import { spawn } from "node:child_process";
|
|
16833
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
16138
16834
|
import clipboardy from "clipboardy";
|
|
16139
16835
|
import notifier from "node-notifier";
|
|
16140
16836
|
function truncateOutput(text, maxLines = 200) {
|
|
@@ -16400,12 +17096,12 @@ function createShellTools(_config, hooks) {
|
|
|
16400
17096
|
const shell = input.shell ?? true;
|
|
16401
17097
|
if (input.background) {
|
|
16402
17098
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
16403
|
-
const { join:
|
|
17099
|
+
const { join: join49 } = await import("node:path");
|
|
16404
17100
|
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
16405
17101
|
const { createWriteStream: createWriteStream2 } = await import("node:fs");
|
|
16406
17102
|
const taskId = randomUUID15().slice(0, 8);
|
|
16407
|
-
const outputPath =
|
|
16408
|
-
const detached =
|
|
17103
|
+
const outputPath = join49(tmpdir13(), `oj-bg-${taskId}.log`);
|
|
17104
|
+
const detached = spawn2(command, [], {
|
|
16409
17105
|
shell,
|
|
16410
17106
|
cwd,
|
|
16411
17107
|
detached: true,
|
|
@@ -16424,8 +17120,8 @@ function createShellTools(_config, hooks) {
|
|
|
16424
17120
|
message: `Command started in background (PID: ${detached.pid}). Output: ${outputPath}`
|
|
16425
17121
|
};
|
|
16426
17122
|
}
|
|
16427
|
-
return new Promise((
|
|
16428
|
-
const proc =
|
|
17123
|
+
return new Promise((resolve7) => {
|
|
17124
|
+
const proc = spawn2(command, [], {
|
|
16429
17125
|
shell,
|
|
16430
17126
|
cwd,
|
|
16431
17127
|
timeout,
|
|
@@ -16442,7 +17138,7 @@ function createShellTools(_config, hooks) {
|
|
|
16442
17138
|
proc.on("close", (code) => {
|
|
16443
17139
|
const stdoutResult = truncateOutput(stdout.trim());
|
|
16444
17140
|
const stderrResult = truncateOutput(stderr.trim());
|
|
16445
|
-
|
|
17141
|
+
resolve7({
|
|
16446
17142
|
command,
|
|
16447
17143
|
exitCode: code,
|
|
16448
17144
|
stdout: stdoutResult.text,
|
|
@@ -16453,7 +17149,7 @@ function createShellTools(_config, hooks) {
|
|
|
16453
17149
|
});
|
|
16454
17150
|
});
|
|
16455
17151
|
proc.on("error", (error) => {
|
|
16456
|
-
|
|
17152
|
+
resolve7({
|
|
16457
17153
|
command,
|
|
16458
17154
|
exitCode: -1,
|
|
16459
17155
|
stdout: "",
|
|
@@ -16487,8 +17183,8 @@ function createShellTools(_config, hooks) {
|
|
|
16487
17183
|
},
|
|
16488
17184
|
requiresConfirmation: false,
|
|
16489
17185
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16490
|
-
const { writeFileSync: writeFileSync23, unlinkSync:
|
|
16491
|
-
const { join:
|
|
17186
|
+
const { writeFileSync: writeFileSync23, unlinkSync: unlinkSync10 } = await import("node:fs");
|
|
17187
|
+
const { join: join49 } = await import("node:path");
|
|
16492
17188
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
16493
17189
|
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
16494
17190
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
@@ -16507,14 +17203,14 @@ function createShellTools(_config, hooks) {
|
|
|
16507
17203
|
const interpreter = interpreterMap[language];
|
|
16508
17204
|
if (!interpreter)
|
|
16509
17205
|
return { error: `Unsupported language: ${language}` };
|
|
16510
|
-
const tmpFile =
|
|
17206
|
+
const tmpFile = join49(tmpdir13(), `oj-code-${randomUUID15().slice(0, 8)}${ext}`);
|
|
16511
17207
|
try {
|
|
16512
17208
|
writeFileSync23(tmpFile, code, "utf-8");
|
|
16513
17209
|
const startTime = Date.now();
|
|
16514
|
-
const result = await new Promise((
|
|
17210
|
+
const result = await new Promise((resolve7) => {
|
|
16515
17211
|
execFile3(interpreter.cmd, [...interpreter.args, tmpFile], { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout2, stderr2) => {
|
|
16516
17212
|
const exitCode = error ? typeof error.code === "number" ? error.code : 1 : 0;
|
|
16517
|
-
|
|
17213
|
+
resolve7({ exitCode, stdout: stdout2 ?? "", stderr: stderr2 ?? "" });
|
|
16518
17214
|
});
|
|
16519
17215
|
});
|
|
16520
17216
|
const executionTimeMs = Date.now() - startTime;
|
|
@@ -16540,7 +17236,7 @@ function createShellTools(_config, hooks) {
|
|
|
16540
17236
|
};
|
|
16541
17237
|
} finally {
|
|
16542
17238
|
try {
|
|
16543
|
-
|
|
17239
|
+
unlinkSync10(tmpFile);
|
|
16544
17240
|
} catch {
|
|
16545
17241
|
}
|
|
16546
17242
|
}
|
|
@@ -16607,7 +17303,7 @@ function createShellTools(_config, hooks) {
|
|
|
16607
17303
|
required: ["title", "message"]
|
|
16608
17304
|
},
|
|
16609
17305
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16610
|
-
return new Promise((
|
|
17306
|
+
return new Promise((resolve7) => {
|
|
16611
17307
|
notifier.notify({
|
|
16612
17308
|
title: input.title,
|
|
16613
17309
|
message: input.message,
|
|
@@ -16615,9 +17311,9 @@ function createShellTools(_config, hooks) {
|
|
|
16615
17311
|
sound: true
|
|
16616
17312
|
}, (err) => {
|
|
16617
17313
|
if (err) {
|
|
16618
|
-
|
|
17314
|
+
resolve7({ error: err.message });
|
|
16619
17315
|
} else {
|
|
16620
|
-
|
|
17316
|
+
resolve7({ success: true });
|
|
16621
17317
|
}
|
|
16622
17318
|
});
|
|
16623
17319
|
});
|
|
@@ -16721,7 +17417,7 @@ function createShellTools(_config, hooks) {
|
|
|
16721
17417
|
},
|
|
16722
17418
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16723
17419
|
const seconds = Math.min(Math.max(0.1, input.seconds), 60);
|
|
16724
|
-
await new Promise((
|
|
17420
|
+
await new Promise((resolve7) => setTimeout(resolve7, seconds * 1e3));
|
|
16725
17421
|
return { waited: seconds, message: `Waited ${seconds} seconds` };
|
|
16726
17422
|
}, "execute")
|
|
16727
17423
|
},
|
|
@@ -17833,7 +18529,7 @@ var init_office_desktop = __esm({
|
|
|
17833
18529
|
return Array.isArray(parsed) ? parsed : [parsed];
|
|
17834
18530
|
}
|
|
17835
18531
|
sleep(ms) {
|
|
17836
|
-
return new Promise((
|
|
18532
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
17837
18533
|
}
|
|
17838
18534
|
};
|
|
17839
18535
|
}
|
|
@@ -19514,7 +20210,7 @@ public class Win32Send {
|
|
|
19514
20210
|
}
|
|
19515
20211
|
}
|
|
19516
20212
|
sleep(ms) {
|
|
19517
|
-
return new Promise((
|
|
20213
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
19518
20214
|
}
|
|
19519
20215
|
};
|
|
19520
20216
|
}
|
|
@@ -19579,7 +20275,7 @@ function getActiveMonitors() {
|
|
|
19579
20275
|
return result;
|
|
19580
20276
|
}
|
|
19581
20277
|
function sleep3(ms) {
|
|
19582
|
-
return new Promise((
|
|
20278
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
19583
20279
|
}
|
|
19584
20280
|
async function fileHash(filePath) {
|
|
19585
20281
|
const data = fs.readFileSync(filePath);
|
|
@@ -20261,6 +20957,224 @@ var init_wechat = __esm({
|
|
|
20261
20957
|
}
|
|
20262
20958
|
});
|
|
20263
20959
|
|
|
20960
|
+
// ../openjaw-mcp/dist/tools/workiq.js
|
|
20961
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
20962
|
+
import { accessSync, chmodSync, constants, existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
|
|
20963
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
20964
|
+
import { homedir as homedir10 } from "node:os";
|
|
20965
|
+
import { dirname as dirname6, join as join16 } from "node:path";
|
|
20966
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
20967
|
+
function workiqStateFilePath() {
|
|
20968
|
+
return join16(homedir10(), ".work-iq-cli", ".workiq.json");
|
|
20969
|
+
}
|
|
20970
|
+
function workiqPlatformDir(pkgDir) {
|
|
20971
|
+
if (process.platform === "win32") {
|
|
20972
|
+
const nativeDir = join16(pkgDir, "bin", `win-${process.arch}`);
|
|
20973
|
+
if (!existsSync14(nativeDir) && process.arch !== "x64")
|
|
20974
|
+
return "win-x64";
|
|
20975
|
+
return `win-${process.arch}`;
|
|
20976
|
+
}
|
|
20977
|
+
if (process.platform === "darwin")
|
|
20978
|
+
return `osx-${process.arch}`;
|
|
20979
|
+
return `linux-${process.arch}`;
|
|
20980
|
+
}
|
|
20981
|
+
function ensureExecutable(binaryPath) {
|
|
20982
|
+
if (process.platform === "win32")
|
|
20983
|
+
return;
|
|
20984
|
+
try {
|
|
20985
|
+
accessSync(binaryPath, constants.X_OK);
|
|
20986
|
+
} catch {
|
|
20987
|
+
try {
|
|
20988
|
+
chmodSync(binaryPath, 493);
|
|
20989
|
+
} catch {
|
|
20990
|
+
}
|
|
20991
|
+
}
|
|
20992
|
+
}
|
|
20993
|
+
function resolveWorkIQBinaryInPackage(pkgDir) {
|
|
20994
|
+
const binaryName = process.platform === "win32" ? "workiq.exe" : "workiq";
|
|
20995
|
+
const binaryPath = join16(pkgDir, "bin", workiqPlatformDir(pkgDir), binaryName);
|
|
20996
|
+
if (!existsSync14(binaryPath))
|
|
20997
|
+
return null;
|
|
20998
|
+
ensureExecutable(binaryPath);
|
|
20999
|
+
return binaryPath;
|
|
21000
|
+
}
|
|
21001
|
+
function resolveWorkIQBinary(nodeModulesPath) {
|
|
21002
|
+
return resolveWorkIQBinaryInPackage(join16(nodeModulesPath, "@microsoft", "workiq"));
|
|
21003
|
+
}
|
|
21004
|
+
function isWorkIQEulaAccepted() {
|
|
21005
|
+
const path3 = workiqStateFilePath();
|
|
21006
|
+
if (!existsSync14(path3))
|
|
21007
|
+
return false;
|
|
21008
|
+
try {
|
|
21009
|
+
const parsed = JSON.parse(readFileSync9(path3, "utf-8"));
|
|
21010
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
21011
|
+
return false;
|
|
21012
|
+
const obj = parsed;
|
|
21013
|
+
const v = obj["I-accept-EULA"] ?? obj["i-accept-eula"] ?? obj.eulaAccepted ?? obj.eula_accepted ?? obj.acceptedEula ?? obj.eula;
|
|
21014
|
+
if (typeof v === "string")
|
|
21015
|
+
return v.trim().toLowerCase() === "true";
|
|
21016
|
+
return v === true || v === 1;
|
|
21017
|
+
} catch {
|
|
21018
|
+
return false;
|
|
21019
|
+
}
|
|
21020
|
+
}
|
|
21021
|
+
function findWorkIQPackageDir() {
|
|
21022
|
+
const anchors = [
|
|
21023
|
+
() => fileURLToPath4(import.meta.url),
|
|
21024
|
+
() => createRequire2(import.meta.url).resolve("@charzhu/openjaw/package.json"),
|
|
21025
|
+
() => join16(process.cwd(), "index.js")
|
|
21026
|
+
];
|
|
21027
|
+
for (const getAnchor of anchors) {
|
|
21028
|
+
try {
|
|
21029
|
+
const req = createRequire2(getAnchor());
|
|
21030
|
+
const pkgJson = req.resolve("@microsoft/workiq/package.json");
|
|
21031
|
+
return dirname6(pkgJson);
|
|
21032
|
+
} catch {
|
|
21033
|
+
}
|
|
21034
|
+
}
|
|
21035
|
+
return null;
|
|
21036
|
+
}
|
|
21037
|
+
function findWorkIQBinary() {
|
|
21038
|
+
const pkgDir = findWorkIQPackageDir();
|
|
21039
|
+
if (pkgDir) {
|
|
21040
|
+
const found = resolveWorkIQBinaryInPackage(pkgDir);
|
|
21041
|
+
if (found)
|
|
21042
|
+
return found;
|
|
21043
|
+
}
|
|
21044
|
+
for (const nm of [join16(process.cwd(), "node_modules")]) {
|
|
21045
|
+
const found = resolveWorkIQBinary(nm);
|
|
21046
|
+
if (found)
|
|
21047
|
+
return found;
|
|
21048
|
+
}
|
|
21049
|
+
return null;
|
|
21050
|
+
}
|
|
21051
|
+
function runWorkIQ(binaryPath, args, stdinText, timeoutMs) {
|
|
21052
|
+
return new Promise((resolve7) => {
|
|
21053
|
+
const proc = spawn3(binaryPath, args, {
|
|
21054
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
21055
|
+
windowsHide: true,
|
|
21056
|
+
timeout: timeoutMs
|
|
21057
|
+
});
|
|
21058
|
+
let stdout = "";
|
|
21059
|
+
let stderr = "";
|
|
21060
|
+
proc.stdout?.on("data", (d) => {
|
|
21061
|
+
stdout += d.toString();
|
|
21062
|
+
});
|
|
21063
|
+
proc.stderr?.on("data", (d) => {
|
|
21064
|
+
stderr += d.toString();
|
|
21065
|
+
});
|
|
21066
|
+
proc.on("error", (err) => {
|
|
21067
|
+
resolve7({ exitCode: -1, stdout, stderr, error: err.message });
|
|
21068
|
+
});
|
|
21069
|
+
proc.on("close", (code) => {
|
|
21070
|
+
resolve7({ exitCode: code, stdout: stdout.trim(), stderr: stderr.trim() });
|
|
21071
|
+
});
|
|
21072
|
+
if (stdinText !== void 0) {
|
|
21073
|
+
proc.stdin?.write(stdinText.endsWith("\n") ? stdinText : stdinText + "\n");
|
|
21074
|
+
}
|
|
21075
|
+
proc.stdin?.end();
|
|
21076
|
+
});
|
|
21077
|
+
}
|
|
21078
|
+
function createWorkIQTools(_config) {
|
|
21079
|
+
return [
|
|
21080
|
+
{
|
|
21081
|
+
name: "workiq_ask",
|
|
21082
|
+
description: 'Query Microsoft 365 work data (your emails, meetings, calendar, documents, people, projects) by asking a natural-language question. Backed by the WorkIQ CLI. Prefer this for "what/who/when" questions about your work context. First use requires accepting the WorkIQ license via workiq_accept_eula.',
|
|
21083
|
+
parameters: {
|
|
21084
|
+
type: "object",
|
|
21085
|
+
properties: {
|
|
21086
|
+
question: {
|
|
21087
|
+
type: "string",
|
|
21088
|
+
description: 'The natural-language question about your M365 work data, e.g. "what meetings do I have tomorrow?"'
|
|
21089
|
+
},
|
|
21090
|
+
timeout: {
|
|
21091
|
+
type: "number",
|
|
21092
|
+
description: "Timeout in milliseconds (default 120000, max 300000)."
|
|
21093
|
+
}
|
|
21094
|
+
},
|
|
21095
|
+
required: ["question"]
|
|
21096
|
+
},
|
|
21097
|
+
requiresConfirmation: false,
|
|
21098
|
+
execute: /* @__PURE__ */ __name(async (input) => {
|
|
21099
|
+
if (!isWorkIQEulaAccepted())
|
|
21100
|
+
return EULA_REFUSAL;
|
|
21101
|
+
const binary = findWorkIQBinary();
|
|
21102
|
+
if (!binary) {
|
|
21103
|
+
return {
|
|
21104
|
+
error: "WorkIQ CLI is unavailable: no @microsoft/workiq binary was found for this platform/arch. It ships as a bundled dependency \u2014 try reinstalling openjaw-mcp dependencies (`npm install`)."
|
|
21105
|
+
};
|
|
21106
|
+
}
|
|
21107
|
+
const question = String(input.question ?? "").trim();
|
|
21108
|
+
if (!question)
|
|
21109
|
+
return { error: "workiq_ask requires a non-empty question." };
|
|
21110
|
+
const timeout = Math.min(Number(input.timeout) || 12e4, 3e5);
|
|
21111
|
+
const result = await runWorkIQ(binary, ["ask"], question, timeout);
|
|
21112
|
+
if (result.error) {
|
|
21113
|
+
return { error: `WorkIQ failed to run: ${result.error}`, stderr: result.stderr };
|
|
21114
|
+
}
|
|
21115
|
+
return {
|
|
21116
|
+
answer: result.stdout,
|
|
21117
|
+
...result.stderr ? { stderr: result.stderr } : {},
|
|
21118
|
+
success: result.exitCode === 0,
|
|
21119
|
+
...result.exitCode !== 0 ? { exitCode: result.exitCode } : {}
|
|
21120
|
+
};
|
|
21121
|
+
}, "execute")
|
|
21122
|
+
},
|
|
21123
|
+
{
|
|
21124
|
+
name: "workiq_accept_eula",
|
|
21125
|
+
description: "Accept the WorkIQ CLI license agreement (one-time, required before workiq_ask works). Runs `workiq accept-eula`; the CLI records acceptance in ~/.work-iq-cli/.workiq.json and it persists across all apps on this machine.",
|
|
21126
|
+
parameters: {
|
|
21127
|
+
type: "object",
|
|
21128
|
+
properties: {}
|
|
21129
|
+
},
|
|
21130
|
+
requiresConfirmation: true,
|
|
21131
|
+
execute: /* @__PURE__ */ __name(async () => {
|
|
21132
|
+
const binary = findWorkIQBinary();
|
|
21133
|
+
if (!binary) {
|
|
21134
|
+
return {
|
|
21135
|
+
error: "WorkIQ CLI is unavailable: no @microsoft/workiq binary was found for this platform/arch. It ships as a bundled dependency \u2014 try reinstalling openjaw-mcp dependencies (`npm install`)."
|
|
21136
|
+
};
|
|
21137
|
+
}
|
|
21138
|
+
if (isWorkIQEulaAccepted()) {
|
|
21139
|
+
return { accepted: true, message: "WorkIQ license was already accepted." };
|
|
21140
|
+
}
|
|
21141
|
+
const result = await runWorkIQ(binary, ["accept-eula"], void 0, 6e4);
|
|
21142
|
+
if (result.error) {
|
|
21143
|
+
return { error: `Failed to run accept-eula: ${result.error}`, stderr: result.stderr };
|
|
21144
|
+
}
|
|
21145
|
+
const accepted = isWorkIQEulaAccepted();
|
|
21146
|
+
return {
|
|
21147
|
+
accepted,
|
|
21148
|
+
success: result.exitCode === 0 && accepted,
|
|
21149
|
+
...result.stdout ? { output: result.stdout } : {},
|
|
21150
|
+
...result.stderr ? { stderr: result.stderr } : {},
|
|
21151
|
+
...!accepted ? { message: "accept-eula ran but acceptance was not recorded; the user may have declined in the CLI." } : {}
|
|
21152
|
+
};
|
|
21153
|
+
}, "execute")
|
|
21154
|
+
}
|
|
21155
|
+
];
|
|
21156
|
+
}
|
|
21157
|
+
var EULA_REFUSAL;
|
|
21158
|
+
var init_workiq = __esm({
|
|
21159
|
+
"../openjaw-mcp/dist/tools/workiq.js"() {
|
|
21160
|
+
"use strict";
|
|
21161
|
+
__name(workiqStateFilePath, "workiqStateFilePath");
|
|
21162
|
+
__name(workiqPlatformDir, "workiqPlatformDir");
|
|
21163
|
+
__name(ensureExecutable, "ensureExecutable");
|
|
21164
|
+
__name(resolveWorkIQBinaryInPackage, "resolveWorkIQBinaryInPackage");
|
|
21165
|
+
__name(resolveWorkIQBinary, "resolveWorkIQBinary");
|
|
21166
|
+
__name(isWorkIQEulaAccepted, "isWorkIQEulaAccepted");
|
|
21167
|
+
__name(findWorkIQPackageDir, "findWorkIQPackageDir");
|
|
21168
|
+
__name(findWorkIQBinary, "findWorkIQBinary");
|
|
21169
|
+
__name(runWorkIQ, "runWorkIQ");
|
|
21170
|
+
EULA_REFUSAL = {
|
|
21171
|
+
eula_required: true,
|
|
21172
|
+
message: "WorkIQ requires a one-time license agreement before first use. Call the `workiq_accept_eula` tool to accept it (the user will be asked to confirm), then retry `workiq_ask`."
|
|
21173
|
+
};
|
|
21174
|
+
__name(createWorkIQTools, "createWorkIQTools");
|
|
21175
|
+
}
|
|
21176
|
+
});
|
|
21177
|
+
|
|
20264
21178
|
// ../openjaw-mcp/dist/tools/categories.js
|
|
20265
21179
|
function categoryForTool2(toolName) {
|
|
20266
21180
|
for (const [prefix, category] of TOOL_PREFIX_MAP) {
|
|
@@ -20282,12 +21196,16 @@ var init_categories = __esm({
|
|
|
20282
21196
|
init_memory();
|
|
20283
21197
|
init_office();
|
|
20284
21198
|
init_wechat();
|
|
21199
|
+
init_workiq();
|
|
20285
21200
|
TOOL_CATEGORIES = {
|
|
20286
21201
|
browser: /* @__PURE__ */ __name((config, browser) => createBrowseTools(config, browser), "browser"),
|
|
20287
21202
|
email: /* @__PURE__ */ __name((config, browser) => createEmailTools(config, browser), "email"),
|
|
20288
21203
|
teams: /* @__PURE__ */ __name((config, browser) => createChatTools(config, browser), "teams"),
|
|
20289
21204
|
files: /* @__PURE__ */ __name((config) => createFileTools(config), "files"),
|
|
20290
|
-
|
|
21205
|
+
// WorkIQ CLI tools (M365 natural-language query) ride the always-loaded
|
|
21206
|
+
// `system` category alongside shell tools — no separate profile wiring,
|
|
21207
|
+
// and they auth themselves so there's nothing to gate at load time.
|
|
21208
|
+
system: /* @__PURE__ */ __name((config, _browser, hooks) => [...createShellTools(config, hooks), ...createWorkIQTools(config)], "system"),
|
|
20291
21209
|
memory: /* @__PURE__ */ __name((config) => createMemoryTools(config), "memory"),
|
|
20292
21210
|
office: /* @__PURE__ */ __name((config) => createOfficeTools(config), "office"),
|
|
20293
21211
|
wechat: /* @__PURE__ */ __name((config) => createWeChatTools(config), "wechat")
|
|
@@ -20325,6 +21243,7 @@ var init_categories = __esm({
|
|
|
20325
21243
|
["sleep", "system"],
|
|
20326
21244
|
["ask_user", "system"],
|
|
20327
21245
|
["config", "system"],
|
|
21246
|
+
["workiq_", "system"],
|
|
20328
21247
|
["todo_write", "memory"]
|
|
20329
21248
|
];
|
|
20330
21249
|
__name(categoryForTool2, "categoryForTool");
|
|
@@ -20593,11 +21512,11 @@ var init_registry = __esm({
|
|
|
20593
21512
|
});
|
|
20594
21513
|
|
|
20595
21514
|
// src/prompts/identity.ts
|
|
20596
|
-
import { readFileSync as
|
|
20597
|
-
import { join as
|
|
21515
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
21516
|
+
import { join as join17 } from "node:path";
|
|
20598
21517
|
function getIdentitySection() {
|
|
20599
21518
|
if (cached2 === void 0) {
|
|
20600
|
-
cached2 =
|
|
21519
|
+
cached2 = readFileSync10(join17(packagePromptsDir(), "IDENTITY.md"), "utf8");
|
|
20601
21520
|
}
|
|
20602
21521
|
return cached2;
|
|
20603
21522
|
}
|
|
@@ -20611,11 +21530,11 @@ var init_identity = __esm({
|
|
|
20611
21530
|
});
|
|
20612
21531
|
|
|
20613
21532
|
// src/prompts/reasoning.ts
|
|
20614
|
-
import { readFileSync as
|
|
20615
|
-
import { join as
|
|
21533
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
21534
|
+
import { join as join18 } from "node:path";
|
|
20616
21535
|
function getReasoningSection() {
|
|
20617
21536
|
if (cached3 === void 0) {
|
|
20618
|
-
cached3 =
|
|
21537
|
+
cached3 = readFileSync11(join18(packagePromptsDir(), "REASONING.md"), "utf8");
|
|
20619
21538
|
}
|
|
20620
21539
|
return cached3;
|
|
20621
21540
|
}
|
|
@@ -20629,11 +21548,11 @@ var init_reasoning = __esm({
|
|
|
20629
21548
|
});
|
|
20630
21549
|
|
|
20631
21550
|
// src/prompts/safety.ts
|
|
20632
|
-
import { readFileSync as
|
|
20633
|
-
import { join as
|
|
21551
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
21552
|
+
import { join as join19 } from "node:path";
|
|
20634
21553
|
function getSafetySection() {
|
|
20635
21554
|
if (cached4 === void 0) {
|
|
20636
|
-
cached4 =
|
|
21555
|
+
cached4 = readFileSync12(join19(packagePromptsDir(), "SAFETY.md"), "utf8");
|
|
20637
21556
|
}
|
|
20638
21557
|
return cached4;
|
|
20639
21558
|
}
|
|
@@ -20647,11 +21566,11 @@ var init_safety = __esm({
|
|
|
20647
21566
|
});
|
|
20648
21567
|
|
|
20649
21568
|
// src/prompts/computerUse.ts
|
|
20650
|
-
import { readFileSync as
|
|
20651
|
-
import { join as
|
|
21569
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
21570
|
+
import { join as join20 } from "node:path";
|
|
20652
21571
|
function getComputerUseSection() {
|
|
20653
21572
|
if (cached5 === void 0) {
|
|
20654
|
-
cached5 =
|
|
21573
|
+
cached5 = readFileSync13(join20(packagePromptsDir(), "COMPUTER_USE.md"), "utf8");
|
|
20655
21574
|
}
|
|
20656
21575
|
return cached5;
|
|
20657
21576
|
}
|
|
@@ -20665,19 +21584,19 @@ var init_computerUse = __esm({
|
|
|
20665
21584
|
});
|
|
20666
21585
|
|
|
20667
21586
|
// src/prompts/user.ts
|
|
20668
|
-
import { readFileSync as
|
|
20669
|
-
import { join as
|
|
20670
|
-
import { homedir as
|
|
21587
|
+
import { readFileSync as readFileSync14, existsSync as existsSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10 } from "node:fs";
|
|
21588
|
+
import { join as join21 } from "node:path";
|
|
21589
|
+
import { homedir as homedir11 } from "node:os";
|
|
20671
21590
|
function getUserSection() {
|
|
20672
21591
|
if (cached6 === void 0) {
|
|
20673
|
-
if (!
|
|
20674
|
-
const bundledPath =
|
|
20675
|
-
if (
|
|
20676
|
-
if (!
|
|
20677
|
-
writeFileSync9(userOverridePath,
|
|
21592
|
+
if (!existsSync15(userOverridePath)) {
|
|
21593
|
+
const bundledPath = join21(packagePromptsDir(), "USER.md");
|
|
21594
|
+
if (existsSync15(bundledPath)) {
|
|
21595
|
+
if (!existsSync15(configDir)) mkdirSync10(configDir, { recursive: true });
|
|
21596
|
+
writeFileSync9(userOverridePath, readFileSync14(bundledPath, "utf8"), "utf8");
|
|
20678
21597
|
}
|
|
20679
21598
|
}
|
|
20680
|
-
cached6 =
|
|
21599
|
+
cached6 = existsSync15(userOverridePath) ? readFileSync14(userOverridePath, "utf8") : null;
|
|
20681
21600
|
}
|
|
20682
21601
|
return cached6;
|
|
20683
21602
|
}
|
|
@@ -20686,8 +21605,8 @@ var init_user = __esm({
|
|
|
20686
21605
|
"src/prompts/user.ts"() {
|
|
20687
21606
|
"use strict";
|
|
20688
21607
|
init_packageRoot();
|
|
20689
|
-
configDir =
|
|
20690
|
-
userOverridePath =
|
|
21608
|
+
configDir = join21(homedir11(), ".openjaw-agent");
|
|
21609
|
+
userOverridePath = join21(configDir, "USER.md");
|
|
20691
21610
|
__name(getUserSection, "getUserSection");
|
|
20692
21611
|
}
|
|
20693
21612
|
});
|
|
@@ -20699,8 +21618,8 @@ __export(memory_exports, {
|
|
|
20699
21618
|
setMemoryPrefetchQuery: () => setMemoryPrefetchQuery,
|
|
20700
21619
|
shouldSkipPrefetch: () => shouldSkipPrefetch
|
|
20701
21620
|
});
|
|
20702
|
-
import { join as
|
|
20703
|
-
import { homedir as
|
|
21621
|
+
import { join as join22 } from "node:path";
|
|
21622
|
+
import { homedir as homedir12 } from "node:os";
|
|
20704
21623
|
function setMemoryPrefetchQuery(query) {
|
|
20705
21624
|
currentQuery = query;
|
|
20706
21625
|
}
|
|
@@ -20751,7 +21670,7 @@ function getMemorySection() {
|
|
|
20751
21670
|
if (shouldSkipPrefetch(currentQuery)) return null;
|
|
20752
21671
|
try {
|
|
20753
21672
|
const { DatabaseSync: DatabaseSync2 } = __require("node:sqlite");
|
|
20754
|
-
const dbPath =
|
|
21673
|
+
const dbPath = join22(homedir12(), ".openjaw", "memory.db");
|
|
20755
21674
|
let db2;
|
|
20756
21675
|
try {
|
|
20757
21676
|
db2 = new DatabaseSync2(dbPath, { readOnly: true });
|
|
@@ -20966,9 +21885,9 @@ var init_frontmatter = __esm({
|
|
|
20966
21885
|
});
|
|
20967
21886
|
|
|
20968
21887
|
// src/skills/registry.ts
|
|
20969
|
-
import { existsSync as
|
|
20970
|
-
import { join as
|
|
20971
|
-
import { homedir as
|
|
21888
|
+
import { existsSync as existsSync16, readFileSync as readFileSync15, readdirSync as readdirSync2, statSync } from "node:fs";
|
|
21889
|
+
import { join as join23 } from "node:path";
|
|
21890
|
+
import { homedir as homedir13 } from "node:os";
|
|
20972
21891
|
function skillRoots() {
|
|
20973
21892
|
return rootsOverride ?? { bundledDir: packageSkillsDir(), userDir: DEFAULT_USER_DIR };
|
|
20974
21893
|
}
|
|
@@ -20988,7 +21907,7 @@ function loadSkillBody(skillName) {
|
|
|
20988
21907
|
const skill = findSkill(skillName);
|
|
20989
21908
|
if (!skill) return null;
|
|
20990
21909
|
try {
|
|
20991
|
-
const content =
|
|
21910
|
+
const content = readFileSync15(skill.filePath, "utf-8").trim();
|
|
20992
21911
|
const parsed = parseSkillFile(content, `${skill.name}.md`);
|
|
20993
21912
|
return parsed.body;
|
|
20994
21913
|
} catch {
|
|
@@ -21044,7 +21963,7 @@ function normalizeSkillName(name) {
|
|
|
21044
21963
|
function loadFlatSkillsFromDir(dir2, source, priority, out) {
|
|
21045
21964
|
for (const entry of safeReadDir(dir2)) {
|
|
21046
21965
|
if (!entry.isFile() || !isMarkdown(entry.name)) continue;
|
|
21047
|
-
const filePath =
|
|
21966
|
+
const filePath = join23(dir2, entry.name);
|
|
21048
21967
|
const skill = parseSkillAtPath(filePath, dir2, entry.name, source, entry.name);
|
|
21049
21968
|
if (skill) putSkill(out, skill, priority);
|
|
21050
21969
|
}
|
|
@@ -21052,10 +21971,10 @@ function loadFlatSkillsFromDir(dir2, source, priority, out) {
|
|
|
21052
21971
|
function loadPackagedSkillsFromDir(dir2, out) {
|
|
21053
21972
|
for (const entry of safeReadDir(dir2)) {
|
|
21054
21973
|
if (!entry.isDirectory()) continue;
|
|
21055
|
-
const rootDir2 =
|
|
21974
|
+
const rootDir2 = join23(dir2, entry.name);
|
|
21056
21975
|
const entrypoint = findPackageEntrypoint(rootDir2);
|
|
21057
21976
|
if (!entrypoint) continue;
|
|
21058
|
-
const filePath =
|
|
21977
|
+
const filePath = join23(rootDir2, entrypoint);
|
|
21059
21978
|
const skill = parseSkillAtPath(filePath, rootDir2, entrypoint, "user", `${entry.name}.md`);
|
|
21060
21979
|
if (skill) putSkill(out, skill, 2);
|
|
21061
21980
|
}
|
|
@@ -21071,7 +21990,7 @@ function findPackageEntrypoint(dir2) {
|
|
|
21071
21990
|
}
|
|
21072
21991
|
function parseSkillAtPath(filePath, rootDir2, entrypoint, source, fallbackFilename) {
|
|
21073
21992
|
try {
|
|
21074
|
-
const content =
|
|
21993
|
+
const content = readFileSync15(filePath, "utf-8").trim();
|
|
21075
21994
|
if (!content) return null;
|
|
21076
21995
|
const parsed = parseSkillFile(content, fallbackFilename);
|
|
21077
21996
|
const name = normalizeSkillName(parsed.meta.name);
|
|
@@ -21096,7 +22015,7 @@ function putSkill(out, skill, priority) {
|
|
|
21096
22015
|
}
|
|
21097
22016
|
}
|
|
21098
22017
|
function safeReadDir(dir2) {
|
|
21099
|
-
if (!
|
|
22018
|
+
if (!existsSync16(dir2)) return [];
|
|
21100
22019
|
try {
|
|
21101
22020
|
return readdirSync2(dir2, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
21102
22021
|
} catch {
|
|
@@ -21108,11 +22027,11 @@ function buildRegistrySignature() {
|
|
|
21108
22027
|
return [signatureForDir(roots.bundledDir), signatureForDir(roots.userDir)].join("|");
|
|
21109
22028
|
}
|
|
21110
22029
|
function signatureForDir(dir2) {
|
|
21111
|
-
if (!
|
|
22030
|
+
if (!existsSync16(dir2)) return `${dir2}:missing`;
|
|
21112
22031
|
const parts = [];
|
|
21113
22032
|
try {
|
|
21114
22033
|
for (const entry of safeReadDir(dir2)) {
|
|
21115
|
-
const fullPath =
|
|
22034
|
+
const fullPath = join23(dir2, entry.name);
|
|
21116
22035
|
if (entry.isFile()) {
|
|
21117
22036
|
if (!isMarkdown(entry.name)) continue;
|
|
21118
22037
|
parts.push(fileSignature(fullPath, `f:${entry.name}`));
|
|
@@ -21120,7 +22039,7 @@ function signatureForDir(dir2) {
|
|
|
21120
22039
|
parts.push(fileSignature(fullPath, `d:${entry.name}`));
|
|
21121
22040
|
for (const child of safeReadDir(fullPath)) {
|
|
21122
22041
|
if (child.isFile() && isMarkdown(child.name)) {
|
|
21123
|
-
parts.push(fileSignature(
|
|
22042
|
+
parts.push(fileSignature(join23(fullPath, child.name), `d:${entry.name}/${child.name}`));
|
|
21124
22043
|
}
|
|
21125
22044
|
}
|
|
21126
22045
|
}
|
|
@@ -21147,7 +22066,7 @@ var init_registry2 = __esm({
|
|
|
21147
22066
|
"use strict";
|
|
21148
22067
|
init_frontmatter();
|
|
21149
22068
|
init_packageRoot();
|
|
21150
|
-
DEFAULT_USER_DIR =
|
|
22069
|
+
DEFAULT_USER_DIR = join23(homedir13(), ".openjaw-agent", "skills");
|
|
21151
22070
|
ENTRYPOINT_NAMES = ["SKILL.md", "skill.md"];
|
|
21152
22071
|
cachedSkills = null;
|
|
21153
22072
|
rootsOverride = null;
|
|
@@ -21213,9 +22132,9 @@ __export(context_exports, {
|
|
|
21213
22132
|
getContextSection: () => getContextSection,
|
|
21214
22133
|
setActiveBridges: () => setActiveBridges
|
|
21215
22134
|
});
|
|
21216
|
-
import { existsSync as
|
|
22135
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, readdirSync as readdirSync3 } from "node:fs";
|
|
21217
22136
|
import { execSync as execSync4 } from "node:child_process";
|
|
21218
|
-
import { join as
|
|
22137
|
+
import { join as join24 } from "node:path";
|
|
21219
22138
|
function detectProjectInfo() {
|
|
21220
22139
|
const cwd = process.cwd();
|
|
21221
22140
|
const lines = [];
|
|
@@ -21229,9 +22148,9 @@ function detectProjectInfo() {
|
|
|
21229
22148
|
} catch {
|
|
21230
22149
|
}
|
|
21231
22150
|
try {
|
|
21232
|
-
const pkgPath =
|
|
21233
|
-
if (
|
|
21234
|
-
const pkg = JSON.parse(
|
|
22151
|
+
const pkgPath = join24(cwd, "package.json");
|
|
22152
|
+
if (existsSync17(pkgPath)) {
|
|
22153
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
21235
22154
|
const name = pkg.name || "unknown";
|
|
21236
22155
|
const desc = pkg.description ? ` \u2014 ${pkg.description}`.slice(0, 120) : "";
|
|
21237
22156
|
lines.push(`- Project: ${name}${desc}`);
|
|
@@ -21255,7 +22174,7 @@ function detectProjectInfo() {
|
|
|
21255
22174
|
["package.json", "JavaScript"]
|
|
21256
22175
|
];
|
|
21257
22176
|
for (const [file2, lang] of indicators) {
|
|
21258
|
-
if (
|
|
22177
|
+
if (existsSync17(join24(cwd, file2))) {
|
|
21259
22178
|
lines.push(`- Language: ${lang} (${file2})`);
|
|
21260
22179
|
break;
|
|
21261
22180
|
}
|
|
@@ -21269,9 +22188,9 @@ function detectProjectInfo() {
|
|
|
21269
22188
|
} catch {
|
|
21270
22189
|
}
|
|
21271
22190
|
try {
|
|
21272
|
-
const readmePath =
|
|
21273
|
-
if (
|
|
21274
|
-
let content =
|
|
22191
|
+
const readmePath = join24(cwd, "README.md");
|
|
22192
|
+
if (existsSync17(readmePath)) {
|
|
22193
|
+
let content = readFileSync16(readmePath, "utf8").slice(0, 500).replace(/\r?\n/g, " ").trim();
|
|
21275
22194
|
if (content.length > 300) content = content.slice(0, 297) + "...";
|
|
21276
22195
|
if (content) lines.push(`- README: ${content}`);
|
|
21277
22196
|
}
|
|
@@ -21380,6 +22299,30 @@ var init_mcp = __esm({
|
|
|
21380
22299
|
}
|
|
21381
22300
|
});
|
|
21382
22301
|
|
|
22302
|
+
// src/prompts/workiq.ts
|
|
22303
|
+
function getWorkIQSection() {
|
|
22304
|
+
if (cached7 === void 0) {
|
|
22305
|
+
cached7 = [
|
|
22306
|
+
"## Microsoft 365 work data (WorkIQ)",
|
|
22307
|
+
"",
|
|
22308
|
+
'You can answer questions about the user\'s work context \u2014 their emails, meetings, calendar, documents, people, and projects \u2014 using the `workiq_ask` tool. Pass a natural-language question (e.g. "what meetings do I have tomorrow?", "summarize my unread email from Alice") and it returns an answer from the WorkIQ CLI.',
|
|
22309
|
+
"",
|
|
22310
|
+
"Guidance:",
|
|
22311
|
+
"- Prefer `workiq_ask` over web search or guessing when the user asks about *their own* work data (meetings, emails, documents, people, projects).",
|
|
22312
|
+
"- First use requires a one-time license acceptance. If `workiq_ask` returns `eula_required`, call `workiq_accept_eula` (the user will be asked to confirm) and then retry the original question.",
|
|
22313
|
+
"- `workiq_ask` signs the user in on first use via the system account; you do not need to handle authentication."
|
|
22314
|
+
].join("\n");
|
|
22315
|
+
}
|
|
22316
|
+
return cached7;
|
|
22317
|
+
}
|
|
22318
|
+
var cached7;
|
|
22319
|
+
var init_workiq2 = __esm({
|
|
22320
|
+
"src/prompts/workiq.ts"() {
|
|
22321
|
+
"use strict";
|
|
22322
|
+
__name(getWorkIQSection, "getWorkIQSection");
|
|
22323
|
+
}
|
|
22324
|
+
});
|
|
22325
|
+
|
|
21383
22326
|
// src/prompts/index.ts
|
|
21384
22327
|
var prompts_exports = {};
|
|
21385
22328
|
__export(prompts_exports, {
|
|
@@ -21408,6 +22351,7 @@ var init_prompts = __esm({
|
|
|
21408
22351
|
init_skills();
|
|
21409
22352
|
init_context();
|
|
21410
22353
|
init_mcp();
|
|
22354
|
+
init_workiq2();
|
|
21411
22355
|
init_sections();
|
|
21412
22356
|
buildSections = /* @__PURE__ */ __name((opts = {}) => [
|
|
21413
22357
|
// Static sections (cached across calls)
|
|
@@ -21415,6 +22359,7 @@ var init_prompts = __esm({
|
|
|
21415
22359
|
systemPromptSection("reasoning", () => getReasoningSection()),
|
|
21416
22360
|
systemPromptSection("safety", () => getSafetySection()),
|
|
21417
22361
|
systemPromptSection("computerUse", () => getComputerUseSection()),
|
|
22362
|
+
systemPromptSection("workiq", () => getWorkIQSection()),
|
|
21418
22363
|
// Dynamic boundary marker
|
|
21419
22364
|
systemPromptSection("boundary", () => SYSTEM_PROMPT_DYNAMIC_BOUNDARY),
|
|
21420
22365
|
// Dynamic sections (memoized within a resolve cycle via section cache)
|
|
@@ -21534,9 +22479,9 @@ __export(telegram_exports, {
|
|
|
21534
22479
|
TelegramBridge: () => TelegramBridge
|
|
21535
22480
|
});
|
|
21536
22481
|
import TelegramBot from "node-telegram-bot-api";
|
|
21537
|
-
import { writeFileSync as writeFileSync10, unlinkSync as
|
|
21538
|
-
import { join as
|
|
21539
|
-
import { tmpdir as tmpdir4, homedir as
|
|
22482
|
+
import { writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, existsSync as existsSync18 } from "node:fs";
|
|
22483
|
+
import { join as join25 } from "node:path";
|
|
22484
|
+
import { tmpdir as tmpdir4, homedir as homedir14 } from "node:os";
|
|
21540
22485
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
21541
22486
|
var MAX_TELEGRAM_MSG, MIME_TYPES, TelegramBridge;
|
|
21542
22487
|
var init_telegram = __esm({
|
|
@@ -21737,12 +22682,12 @@ var init_telegram = __esm({
|
|
|
21737
22682
|
Options: ${chunk.choices.join(" | ")}` : "";
|
|
21738
22683
|
await this.bot.sendMessage(chatId, `\u2753 ${question}${choicesText}`);
|
|
21739
22684
|
updateStatus("\u2753 Waiting for your response...");
|
|
21740
|
-
const userReply = await new Promise((
|
|
21741
|
-
this._pendingReplyResolver =
|
|
22685
|
+
const userReply = await new Promise((resolve7) => {
|
|
22686
|
+
this._pendingReplyResolver = resolve7;
|
|
21742
22687
|
setTimeout(() => {
|
|
21743
|
-
if (this._pendingReplyResolver ===
|
|
22688
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
21744
22689
|
this._pendingReplyResolver = null;
|
|
21745
|
-
|
|
22690
|
+
resolve7("[No response \u2014 timed out]");
|
|
21746
22691
|
}
|
|
21747
22692
|
}, 5 * 60 * 1e3);
|
|
21748
22693
|
});
|
|
@@ -21779,7 +22724,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
21779
22724
|
try {
|
|
21780
22725
|
const fileId = voice.file_id;
|
|
21781
22726
|
const filePath = await this.bot.getFileLink(fileId);
|
|
21782
|
-
const tempFile =
|
|
22727
|
+
const tempFile = join25(tmpdir4(), `oj-tg-voice-${randomUUID4().slice(0, 8)}.ogg`);
|
|
21783
22728
|
const response = await fetch(filePath);
|
|
21784
22729
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
21785
22730
|
writeFileSync10(tempFile, buffer);
|
|
@@ -21795,7 +22740,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
21795
22740
|
transcription = "[Could not transcribe voice message. Please type your message instead.]";
|
|
21796
22741
|
}
|
|
21797
22742
|
try {
|
|
21798
|
-
if (
|
|
22743
|
+
if (existsSync18(tempFile)) unlinkSync4(tempFile);
|
|
21799
22744
|
} catch {
|
|
21800
22745
|
}
|
|
21801
22746
|
if (transcription.startsWith("[")) {
|
|
@@ -21853,7 +22798,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
21853
22798
|
const response = await fetch(filePath);
|
|
21854
22799
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
21855
22800
|
const ext = fileName.includes(".") ? "." + fileName.split(".").pop() : "";
|
|
21856
|
-
const tempPath =
|
|
22801
|
+
const tempPath = join25(tmpdir4(), `oj-tg-doc-${randomUUID4().slice(0, 8)}${ext}`);
|
|
21857
22802
|
writeFileSync10(tempPath, buffer);
|
|
21858
22803
|
const text = caption || `I've sent you a file: ${fileName}. It's saved at ${tempPath}. Please analyze it.`;
|
|
21859
22804
|
const fullText = `${text}
|
|
@@ -21861,7 +22806,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
21861
22806
|
[File received: ${fileName} (${buffer.length} bytes), saved to: ${tempPath}]`;
|
|
21862
22807
|
await this.handleText(chatId, fullText);
|
|
21863
22808
|
try {
|
|
21864
|
-
if (
|
|
22809
|
+
if (existsSync18(tempPath)) unlinkSync4(tempPath);
|
|
21865
22810
|
} catch {
|
|
21866
22811
|
}
|
|
21867
22812
|
} catch {
|
|
@@ -21887,12 +22832,12 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
21887
22832
|
let match;
|
|
21888
22833
|
while ((match = pattern.exec(normalized)) !== null) {
|
|
21889
22834
|
const filePath = match[1];
|
|
21890
|
-
const resolvedPath = filePath.startsWith("~") ?
|
|
22835
|
+
const resolvedPath = filePath.startsWith("~") ? join25(homedir14(), filePath.slice(1)) : filePath;
|
|
21891
22836
|
if (sentFiles.has(resolvedPath)) continue;
|
|
21892
22837
|
if (filePath.includes("http") || filePath.includes("node_modules")) continue;
|
|
21893
22838
|
const fileName = filePath.split(/[\\/]/).pop() || "";
|
|
21894
22839
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
21895
|
-
if (
|
|
22840
|
+
if (existsSync18(resolvedPath)) {
|
|
21896
22841
|
try {
|
|
21897
22842
|
const { statSync: statSync5 } = await import("node:fs");
|
|
21898
22843
|
const stat2 = statSync5(resolvedPath);
|
|
@@ -22056,26 +23001,27 @@ var init_meta = __esm({
|
|
|
22056
23001
|
// src/mcp-client.ts
|
|
22057
23002
|
var mcp_client_exports = {};
|
|
22058
23003
|
__export(mcp_client_exports, {
|
|
22059
|
-
MCPClientManager: () => MCPClientManager
|
|
23004
|
+
MCPClientManager: () => MCPClientManager,
|
|
23005
|
+
restoreStdinAfterReadlinePrompt: () => restoreStdinAfterReadlinePrompt
|
|
22060
23006
|
});
|
|
22061
23007
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
22062
23008
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
22063
23009
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
22064
23010
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
22065
|
-
import { existsSync as
|
|
22066
|
-
import { join as
|
|
22067
|
-
import { homedir as
|
|
23011
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, readdirSync as readdirSync4, writeFileSync as writeFileSync11, mkdirSync as mkdirSync11 } from "node:fs";
|
|
23012
|
+
import { join as join26, dirname as dirname7, resolve as resolve2 } from "node:path";
|
|
23013
|
+
import { homedir as homedir15 } from "node:os";
|
|
22068
23014
|
import { execSync as execSync5 } from "node:child_process";
|
|
22069
23015
|
import { EventEmitter } from "node:events";
|
|
22070
23016
|
import * as readline from "node:readline";
|
|
22071
23017
|
function findCopilotOAuthToken(serverUrl) {
|
|
22072
|
-
if (!
|
|
23018
|
+
if (!existsSync19(COPILOT_OAUTH_DIR)) return null;
|
|
22073
23019
|
try {
|
|
22074
23020
|
const files = readdirSync4(COPILOT_OAUTH_DIR).filter((f) => f.endsWith(".tokens.json"));
|
|
22075
23021
|
for (const file2 of files) {
|
|
22076
|
-
const filePath =
|
|
23022
|
+
const filePath = join26(COPILOT_OAUTH_DIR, file2);
|
|
22077
23023
|
try {
|
|
22078
|
-
const data = JSON.parse(
|
|
23024
|
+
const data = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
22079
23025
|
if (data.scope && data.accessToken) {
|
|
22080
23026
|
const urlDomain = new URL(serverUrl).hostname;
|
|
22081
23027
|
if (data.scope.includes(urlDomain)) {
|
|
@@ -22091,18 +23037,18 @@ function findCopilotOAuthToken(serverUrl) {
|
|
|
22091
23037
|
}
|
|
22092
23038
|
function refreshCopilotToken(refreshToken, tokenFilePath) {
|
|
22093
23039
|
try {
|
|
22094
|
-
const existing = JSON.parse(
|
|
23040
|
+
const existing = JSON.parse(readFileSync18(tokenFilePath, "utf-8"));
|
|
22095
23041
|
const jwtParts = existing.accessToken.split(".");
|
|
22096
23042
|
if (jwtParts.length < 2) return null;
|
|
22097
23043
|
const padded = jwtParts[1] + "=".repeat(4 - jwtParts[1].length % 4);
|
|
22098
23044
|
const claims = JSON.parse(Buffer.from(padded, "base64").toString("utf-8"));
|
|
22099
|
-
const
|
|
23045
|
+
const clientId2 = claims.azp;
|
|
22100
23046
|
const tid = claims.tid;
|
|
22101
23047
|
const aud = claims.aud;
|
|
22102
|
-
if (!
|
|
23048
|
+
if (!clientId2 || !tid || !aud) return null;
|
|
22103
23049
|
const scope = `${aud}/.default offline_access`;
|
|
22104
23050
|
const bodyParams = [
|
|
22105
|
-
`client_id=${
|
|
23051
|
+
`client_id=${clientId2}`,
|
|
22106
23052
|
`grant_type=refresh_token`,
|
|
22107
23053
|
`refresh_token=${encodeURIComponent(refreshToken)}`,
|
|
22108
23054
|
`scope=${encodeURIComponent(scope)}`
|
|
@@ -22162,7 +23108,7 @@ function discoverAllConfigs(cwd) {
|
|
|
22162
23108
|
for (const { name: pluginName, servers } of pluginConfigs) {
|
|
22163
23109
|
addServers(servers, `~/.copilot/.../plugins/${pluginName}/.mcp.json`, "plugin", false);
|
|
22164
23110
|
}
|
|
22165
|
-
const vscodeConfig = readVSCodeMcpConfig(
|
|
23111
|
+
const vscodeConfig = readVSCodeMcpConfig(join26(cwd, ".vscode", "mcp.json"), cwd);
|
|
22166
23112
|
if (vscodeConfig) {
|
|
22167
23113
|
addServers(vscodeConfig, ".vscode/mcp.json", "vscode", false);
|
|
22168
23114
|
}
|
|
@@ -22173,18 +23119,18 @@ function discoverAllConfigs(cwd) {
|
|
|
22173
23119
|
return result;
|
|
22174
23120
|
}
|
|
22175
23121
|
function readMcpConfig(filePath) {
|
|
22176
|
-
if (!
|
|
23122
|
+
if (!existsSync19(filePath)) return null;
|
|
22177
23123
|
try {
|
|
22178
|
-
const raw = JSON.parse(
|
|
23124
|
+
const raw = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
22179
23125
|
return raw.mcpServers || null;
|
|
22180
23126
|
} catch {
|
|
22181
23127
|
return null;
|
|
22182
23128
|
}
|
|
22183
23129
|
}
|
|
22184
23130
|
function readVSCodeMcpConfig(filePath, cwd) {
|
|
22185
|
-
if (!
|
|
23131
|
+
if (!existsSync19(filePath)) return null;
|
|
22186
23132
|
try {
|
|
22187
|
-
const raw = JSON.parse(
|
|
23133
|
+
const raw = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
22188
23134
|
const servers = raw.servers;
|
|
22189
23135
|
if (!servers || typeof servers !== "object") return null;
|
|
22190
23136
|
const result = {};
|
|
@@ -22205,10 +23151,10 @@ function readVSCodeMcpConfig(filePath, cwd) {
|
|
|
22205
23151
|
}
|
|
22206
23152
|
function walkParentsForMcpJson(startDir) {
|
|
22207
23153
|
const results = [];
|
|
22208
|
-
let dir2 =
|
|
22209
|
-
const root =
|
|
23154
|
+
let dir2 = resolve2(startDir);
|
|
23155
|
+
const root = dirname7(dir2) === dir2 ? dir2 : "";
|
|
22210
23156
|
while (dir2 && dir2 !== root) {
|
|
22211
|
-
const filePath =
|
|
23157
|
+
const filePath = join26(dir2, ".mcp.json");
|
|
22212
23158
|
const config = readMcpConfig(filePath);
|
|
22213
23159
|
if (config) {
|
|
22214
23160
|
const filtered = {};
|
|
@@ -22219,20 +23165,20 @@ function walkParentsForMcpJson(startDir) {
|
|
|
22219
23165
|
results.push({ path: filePath, servers: filtered });
|
|
22220
23166
|
}
|
|
22221
23167
|
}
|
|
22222
|
-
const parent =
|
|
23168
|
+
const parent = dirname7(dir2);
|
|
22223
23169
|
if (parent === dir2) break;
|
|
22224
23170
|
dir2 = parent;
|
|
22225
23171
|
}
|
|
22226
23172
|
return results;
|
|
22227
23173
|
}
|
|
22228
23174
|
function discoverCopilotPlugins() {
|
|
22229
|
-
if (!
|
|
23175
|
+
if (!existsSync19(COPILOT_PLUGINS_DIR)) return [];
|
|
22230
23176
|
const results = [];
|
|
22231
23177
|
try {
|
|
22232
23178
|
const entries = readdirSync4(COPILOT_PLUGINS_DIR, { withFileTypes: true });
|
|
22233
23179
|
for (const entry of entries) {
|
|
22234
23180
|
if (!entry.isDirectory()) continue;
|
|
22235
|
-
const mcpPath =
|
|
23181
|
+
const mcpPath = join26(COPILOT_PLUGINS_DIR, entry.name, ".mcp.json");
|
|
22236
23182
|
const config = readMcpConfig(mcpPath);
|
|
22237
23183
|
if (config) {
|
|
22238
23184
|
const filtered = {};
|
|
@@ -22249,9 +23195,9 @@ function discoverCopilotPlugins() {
|
|
|
22249
23195
|
return results;
|
|
22250
23196
|
}
|
|
22251
23197
|
function discoverAgencyBuiltins() {
|
|
22252
|
-
if (!
|
|
23198
|
+
if (!existsSync19(AGENCY_CONFIG) || !existsSync19(AGENCY_EXE)) return {};
|
|
22253
23199
|
try {
|
|
22254
|
-
const content =
|
|
23200
|
+
const content = readFileSync18(AGENCY_CONFIG, "utf-8");
|
|
22255
23201
|
const result = {};
|
|
22256
23202
|
const builtinsMatch = content.match(/\[mcps\.builtins\]([\s\S]*?)(?=\n\[|$)/);
|
|
22257
23203
|
if (!builtinsMatch) return {};
|
|
@@ -22319,17 +23265,17 @@ function truncateDescription(desc, maxLen) {
|
|
|
22319
23265
|
return desc.slice(0, maxLen - 3) + "...";
|
|
22320
23266
|
}
|
|
22321
23267
|
function loadConsent() {
|
|
22322
|
-
if (!
|
|
23268
|
+
if (!existsSync19(OJ_CONSENT_FILE)) {
|
|
22323
23269
|
return { approved: [], denied: [] };
|
|
22324
23270
|
}
|
|
22325
23271
|
try {
|
|
22326
|
-
return JSON.parse(
|
|
23272
|
+
return JSON.parse(readFileSync18(OJ_CONSENT_FILE, "utf-8"));
|
|
22327
23273
|
} catch {
|
|
22328
23274
|
return { approved: [], denied: [] };
|
|
22329
23275
|
}
|
|
22330
23276
|
}
|
|
22331
23277
|
function saveConsent(data) {
|
|
22332
|
-
if (!
|
|
23278
|
+
if (!existsSync19(OJ_AGENT_DIR)) {
|
|
22333
23279
|
mkdirSync11(OJ_AGENT_DIR, { recursive: true });
|
|
22334
23280
|
}
|
|
22335
23281
|
writeFileSync11(OJ_CONSENT_FILE, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
@@ -22340,66 +23286,82 @@ async function promptConsent(servers) {
|
|
|
22340
23286
|
input: process.stdin,
|
|
22341
23287
|
output: process.stderr
|
|
22342
23288
|
});
|
|
22343
|
-
|
|
22344
|
-
|
|
22345
|
-
|
|
22346
|
-
|
|
22347
|
-
|
|
22348
|
-
|
|
22349
|
-
console.error(` \x1B[36m\u256D${hLine}\u256E\x1B[0m`);
|
|
22350
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${pad("\x1B[36m\x1B[1m\u{1F50C} New MCP Servers Discovered\x1B[0m", inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22351
|
-
console.error(` \x1B[36m\u251C${hLine}\u2524\x1B[0m`);
|
|
22352
|
-
const bySource = /* @__PURE__ */ new Map();
|
|
22353
|
-
for (const s of servers) {
|
|
22354
|
-
const list = bySource.get(s.source) || [];
|
|
22355
|
-
list.push(s);
|
|
22356
|
-
bySource.set(s.source, list);
|
|
22357
|
-
}
|
|
22358
|
-
for (const [source, sourceServers] of bySource) {
|
|
22359
|
-
const srcLine = `\x1B[2m From ${source}\x1B[0m`;
|
|
22360
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${pad(srcLine, inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22361
|
-
for (const s of sourceServers) {
|
|
22362
|
-
const cmdParts = [s.def.command, ...(s.def.args || []).slice(0, 2)];
|
|
22363
|
-
const cmdStr = cmdParts.join(" ");
|
|
22364
|
-
const truncCmd = cmdStr.length > inner - s.name.length - 12 ? cmdStr.slice(0, inner - s.name.length - 15) + "..." : cmdStr;
|
|
22365
|
-
const serverLine = ` \x1B[33m\u25CB\x1B[0m \x1B[1m${s.name}\x1B[0m \x1B[2m${truncCmd}\x1B[0m`;
|
|
22366
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${pad(serverLine, inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22367
|
-
}
|
|
22368
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${" ".repeat(inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22369
|
-
}
|
|
22370
|
-
console.error(` \x1B[36m\u251C${hLine}\u2524\x1B[0m`);
|
|
22371
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${pad("\x1B[2m Y = enable all \xB7 N = skip all \xB7 S = select individually\x1B[0m", inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22372
|
-
console.error(` \x1B[36m\u2570${hLine}\u256F\x1B[0m`);
|
|
22373
|
-
console.error("");
|
|
22374
|
-
const answer = await ask(" \x1B[36m\u276F\x1B[0m Enable these servers? \x1B[2m(Y/n/s)\x1B[0m: ");
|
|
22375
|
-
const trimmed = answer.trim().toLowerCase();
|
|
22376
|
-
let approved;
|
|
22377
|
-
if (trimmed === "" || trimmed === "y" || trimmed === "yes") {
|
|
22378
|
-
approved = servers.map((s) => s.name);
|
|
22379
|
-
console.error(` \x1B[32m\u25CF All ${approved.length} servers enabled\x1B[0m`);
|
|
22380
|
-
} else if (trimmed === "n" || trimmed === "no") {
|
|
22381
|
-
approved = [];
|
|
22382
|
-
console.error(` \x1B[33m\u25CB All servers skipped\x1B[0m`);
|
|
22383
|
-
} else if (trimmed === "s" || trimmed === "select") {
|
|
22384
|
-
approved = [];
|
|
23289
|
+
try {
|
|
23290
|
+
const ask = /* @__PURE__ */ __name((question) => new Promise((resolve7) => rl.question(question, resolve7)), "ask");
|
|
23291
|
+
const w = process.stderr.columns || 80;
|
|
23292
|
+
const inner = w - 4;
|
|
23293
|
+
const hLine = "\u2500".repeat(inner);
|
|
23294
|
+
const pad = /* @__PURE__ */ __name((s, len) => s + " ".repeat(Math.max(0, len - stripAnsi(s).length)), "pad");
|
|
22385
23295
|
console.error("");
|
|
23296
|
+
console.error(` \x1B[36m\u256D${hLine}\u256E\x1B[0m`);
|
|
23297
|
+
console.error(` \x1B[36m\u2502\x1B[0m ${pad("\x1B[36m\x1B[1m\u{1F50C} New MCP Servers Discovered\x1B[0m", inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
23298
|
+
console.error(` \x1B[36m\u251C${hLine}\u2524\x1B[0m`);
|
|
23299
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
22386
23300
|
for (const s of servers) {
|
|
22387
|
-
const
|
|
22388
|
-
|
|
22389
|
-
|
|
22390
|
-
|
|
22391
|
-
|
|
22392
|
-
|
|
23301
|
+
const list = bySource.get(s.source) || [];
|
|
23302
|
+
list.push(s);
|
|
23303
|
+
bySource.set(s.source, list);
|
|
23304
|
+
}
|
|
23305
|
+
for (const [source, sourceServers] of bySource) {
|
|
23306
|
+
const srcLine = `\x1B[2m From ${source}\x1B[0m`;
|
|
23307
|
+
console.error(` \x1B[36m\u2502\x1B[0m ${pad(srcLine, inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
23308
|
+
for (const s of sourceServers) {
|
|
23309
|
+
const cmdParts = [s.def.command, ...(s.def.args || []).slice(0, 2)];
|
|
23310
|
+
const cmdStr = cmdParts.join(" ");
|
|
23311
|
+
const truncCmd = cmdStr.length > inner - s.name.length - 12 ? cmdStr.slice(0, inner - s.name.length - 15) + "..." : cmdStr;
|
|
23312
|
+
const serverLine = ` \x1B[33m\u25CB\x1B[0m \x1B[1m${s.name}\x1B[0m \x1B[2m${truncCmd}\x1B[0m`;
|
|
23313
|
+
console.error(` \x1B[36m\u2502\x1B[0m ${pad(serverLine, inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
23314
|
+
}
|
|
23315
|
+
console.error(` \x1B[36m\u2502\x1B[0m ${" ".repeat(inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
23316
|
+
}
|
|
23317
|
+
console.error(` \x1B[36m\u251C${hLine}\u2524\x1B[0m`);
|
|
23318
|
+
console.error(` \x1B[36m\u2502\x1B[0m ${pad("\x1B[2m Y = enable all \xB7 N = skip all \xB7 S = select individually\x1B[0m", inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
23319
|
+
console.error(` \x1B[36m\u2570${hLine}\u256F\x1B[0m`);
|
|
23320
|
+
console.error("");
|
|
23321
|
+
const answer = await ask(" \x1B[36m\u276F\x1B[0m Enable these servers? \x1B[2m(Y/n/s)\x1B[0m: ");
|
|
23322
|
+
const trimmed = answer.trim().toLowerCase();
|
|
23323
|
+
let approved;
|
|
23324
|
+
if (trimmed === "" || trimmed === "y" || trimmed === "yes") {
|
|
23325
|
+
approved = servers.map((s) => s.name);
|
|
23326
|
+
console.error(` \x1B[32m\u25CF All ${approved.length} servers enabled\x1B[0m`);
|
|
23327
|
+
} else if (trimmed === "n" || trimmed === "no") {
|
|
23328
|
+
approved = [];
|
|
23329
|
+
console.error(` \x1B[33m\u25CB All servers skipped\x1B[0m`);
|
|
23330
|
+
} else if (trimmed === "s" || trimmed === "select") {
|
|
23331
|
+
approved = [];
|
|
23332
|
+
console.error("");
|
|
23333
|
+
for (const s of servers) {
|
|
23334
|
+
const a = await ask(` \x1B[36m\u276F\x1B[0m Enable \x1B[33m\x1B[1m${s.name}\x1B[0m? \x1B[2m(y/N)\x1B[0m: `);
|
|
23335
|
+
if (a.trim().toLowerCase() === "y" || a.trim().toLowerCase() === "yes") {
|
|
23336
|
+
approved.push(s.name);
|
|
23337
|
+
console.error(` \x1B[32m\u25CF ${s.name} enabled\x1B[0m`);
|
|
23338
|
+
} else {
|
|
23339
|
+
console.error(` \x1B[2m\u25CB ${s.name} skipped\x1B[0m`);
|
|
23340
|
+
}
|
|
22393
23341
|
}
|
|
22394
|
-
|
|
22395
|
-
console.error(`
|
|
23342
|
+
console.error(`
|
|
22396
23343
|
\x1B[32m${approved.length}/${servers.length} servers enabled\x1B[0m`);
|
|
22397
|
-
|
|
22398
|
-
|
|
23344
|
+
} else {
|
|
23345
|
+
approved = servers.map((s) => s.name);
|
|
23346
|
+
}
|
|
23347
|
+
console.error("");
|
|
23348
|
+
return approved;
|
|
23349
|
+
} finally {
|
|
23350
|
+
rl.close();
|
|
23351
|
+
restoreStdinAfterReadlinePrompt();
|
|
23352
|
+
}
|
|
23353
|
+
}
|
|
23354
|
+
function restoreStdinAfterReadlinePrompt(input = process.stdin) {
|
|
23355
|
+
try {
|
|
23356
|
+
if (input.isTTY && input.setRawMode) {
|
|
23357
|
+
input.setRawMode(false);
|
|
23358
|
+
}
|
|
23359
|
+
} catch {
|
|
23360
|
+
}
|
|
23361
|
+
try {
|
|
23362
|
+
input.pause();
|
|
23363
|
+
} catch {
|
|
22399
23364
|
}
|
|
22400
|
-
console.error("");
|
|
22401
|
-
rl.close();
|
|
22402
|
-
return approved;
|
|
22403
23365
|
}
|
|
22404
23366
|
function stripAnsi(str) {
|
|
22405
23367
|
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -22408,14 +23370,14 @@ var OJ_AGENT_DIR, OJ_MCP_CONFIG, OJ_CONSENT_FILE, COPILOT_MCP_CONFIG, COPILOT_PL
|
|
|
22408
23370
|
var init_mcp_client = __esm({
|
|
22409
23371
|
"src/mcp-client.ts"() {
|
|
22410
23372
|
"use strict";
|
|
22411
|
-
OJ_AGENT_DIR =
|
|
22412
|
-
OJ_MCP_CONFIG =
|
|
22413
|
-
OJ_CONSENT_FILE =
|
|
22414
|
-
COPILOT_MCP_CONFIG =
|
|
22415
|
-
COPILOT_PLUGINS_DIR =
|
|
22416
|
-
COPILOT_OAUTH_DIR =
|
|
22417
|
-
AGENCY_CONFIG =
|
|
22418
|
-
AGENCY_EXE =
|
|
23373
|
+
OJ_AGENT_DIR = join26(homedir15(), ".openjaw-agent");
|
|
23374
|
+
OJ_MCP_CONFIG = join26(OJ_AGENT_DIR, "mcp.json");
|
|
23375
|
+
OJ_CONSENT_FILE = join26(OJ_AGENT_DIR, "mcp-consent.json");
|
|
23376
|
+
COPILOT_MCP_CONFIG = join26(homedir15(), ".copilot", "mcp-config.json");
|
|
23377
|
+
COPILOT_PLUGINS_DIR = join26(homedir15(), ".copilot", "installed-plugins", "copilot-plugins");
|
|
23378
|
+
COPILOT_OAUTH_DIR = join26(homedir15(), ".copilot", "mcp-oauth-config");
|
|
23379
|
+
AGENCY_CONFIG = join26(homedir15(), ".agency", "agency.toml");
|
|
23380
|
+
AGENCY_EXE = join26(process.env.APPDATA || join26(homedir15(), "AppData", "Roaming"), "agency", "CurrentVersion", "agency.exe");
|
|
22419
23381
|
SELF_PATTERNS = ["openjaw-mcp/dist/index.js", "openjaw-mcp\\dist\\index.js", "openjaw-agent"];
|
|
22420
23382
|
__name(findCopilotOAuthToken, "findCopilotOAuthToken");
|
|
22421
23383
|
__name(refreshCopilotToken, "refreshCopilotToken");
|
|
@@ -22615,11 +23577,11 @@ var init_mcp_client = __esm({
|
|
|
22615
23577
|
* Add a new MCP server at runtime. Saves to ~/.openjaw-agent/mcp.json and connects.
|
|
22616
23578
|
*/
|
|
22617
23579
|
async addServer(name, def) {
|
|
22618
|
-
if (!
|
|
23580
|
+
if (!existsSync19(OJ_AGENT_DIR)) mkdirSync11(OJ_AGENT_DIR, { recursive: true });
|
|
22619
23581
|
let config = {};
|
|
22620
|
-
if (
|
|
23582
|
+
if (existsSync19(OJ_MCP_CONFIG)) {
|
|
22621
23583
|
try {
|
|
22622
|
-
const raw = JSON.parse(
|
|
23584
|
+
const raw = JSON.parse(readFileSync18(OJ_MCP_CONFIG, "utf-8"));
|
|
22623
23585
|
config = raw.mcpServers || {};
|
|
22624
23586
|
} catch {
|
|
22625
23587
|
}
|
|
@@ -22727,6 +23689,7 @@ var init_mcp_client = __esm({
|
|
|
22727
23689
|
const headers = {};
|
|
22728
23690
|
if (def.env?.AUTHORIZATION) headers["Authorization"] = def.env.AUTHORIZATION;
|
|
22729
23691
|
if (def.env?.AUTH_TOKEN) headers["Authorization"] = `Bearer ${def.env.AUTH_TOKEN}`;
|
|
23692
|
+
if (def.headers) Object.assign(headers, def.headers);
|
|
22730
23693
|
transport = new SSEClientTransport(new URL(def.url), {
|
|
22731
23694
|
requestInit: Object.keys(headers).length > 0 ? { headers } : void 0
|
|
22732
23695
|
});
|
|
@@ -22747,10 +23710,10 @@ var init_mcp_client = __esm({
|
|
|
22747
23710
|
let tokenExpiry = 0;
|
|
22748
23711
|
if (copilotTokenFile) {
|
|
22749
23712
|
try {
|
|
22750
|
-
const
|
|
22751
|
-
cachedToken =
|
|
22752
|
-
cachedRefreshToken =
|
|
22753
|
-
tokenExpiry =
|
|
23713
|
+
const cached8 = JSON.parse(readFileSync18(copilotTokenFile, "utf-8"));
|
|
23714
|
+
cachedToken = cached8.accessToken;
|
|
23715
|
+
cachedRefreshToken = cached8.refreshToken;
|
|
23716
|
+
tokenExpiry = cached8.expiresAt || 0;
|
|
22754
23717
|
} catch {
|
|
22755
23718
|
}
|
|
22756
23719
|
}
|
|
@@ -22790,11 +23753,15 @@ var init_mcp_client = __esm({
|
|
|
22790
23753
|
return globalThis.fetch(url, { ...init, headers });
|
|
22791
23754
|
}, "customFetch");
|
|
22792
23755
|
}
|
|
23756
|
+
const requestHeaders = {};
|
|
23757
|
+
if (staticAuth) requestHeaders["Authorization"] = staticAuth;
|
|
23758
|
+
if (def.headers) Object.assign(requestHeaders, def.headers);
|
|
22793
23759
|
const transportOpts = {};
|
|
22794
23760
|
if (customFetch) {
|
|
22795
23761
|
transportOpts.fetch = customFetch;
|
|
22796
|
-
}
|
|
22797
|
-
|
|
23762
|
+
}
|
|
23763
|
+
if (Object.keys(requestHeaders).length > 0) {
|
|
23764
|
+
transportOpts.requestInit = { headers: requestHeaders };
|
|
22798
23765
|
}
|
|
22799
23766
|
transport = new StreamableHTTPClientTransport(new URL(def.url), transportOpts);
|
|
22800
23767
|
} else {
|
|
@@ -22855,6 +23822,7 @@ var init_mcp_client = __esm({
|
|
|
22855
23822
|
__name(loadConsent, "loadConsent");
|
|
22856
23823
|
__name(saveConsent, "saveConsent");
|
|
22857
23824
|
__name(promptConsent, "promptConsent");
|
|
23825
|
+
__name(restoreStdinAfterReadlinePrompt, "restoreStdinAfterReadlinePrompt");
|
|
22858
23826
|
__name(stripAnsi, "stripAnsi");
|
|
22859
23827
|
}
|
|
22860
23828
|
});
|
|
@@ -23185,13 +24153,13 @@ __export(scheduler_exports, {
|
|
|
23185
24153
|
stopAllTasks: () => stopAllTasks,
|
|
23186
24154
|
stopTask: () => stopTask
|
|
23187
24155
|
});
|
|
23188
|
-
import { readFileSync as
|
|
23189
|
-
import { join as
|
|
23190
|
-
import { homedir as
|
|
24156
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync12, existsSync as existsSync20, mkdirSync as mkdirSync12 } from "node:fs";
|
|
24157
|
+
import { join as join27 } from "node:path";
|
|
24158
|
+
import { homedir as homedir16 } from "node:os";
|
|
23191
24159
|
function getJobsPath() {
|
|
23192
|
-
const dir2 =
|
|
23193
|
-
if (!
|
|
23194
|
-
return
|
|
24160
|
+
const dir2 = join27(homedir16(), ".openjaw-agent");
|
|
24161
|
+
if (!existsSync20(dir2)) mkdirSync12(dir2, { recursive: true });
|
|
24162
|
+
return join27(dir2, "cron-jobs.json");
|
|
23195
24163
|
}
|
|
23196
24164
|
function parseInterval(input) {
|
|
23197
24165
|
const match = input.match(/^(\d+)\s*(s|sec|seconds?|m|min|minutes?|h|hr|hours?|d|day|days?)$/i);
|
|
@@ -23328,9 +24296,9 @@ function saveJobs() {
|
|
|
23328
24296
|
}
|
|
23329
24297
|
function loadJobs() {
|
|
23330
24298
|
const path3 = getJobsPath();
|
|
23331
|
-
if (!
|
|
24299
|
+
if (!existsSync20(path3)) return [];
|
|
23332
24300
|
try {
|
|
23333
|
-
const raw =
|
|
24301
|
+
const raw = readFileSync19(path3, "utf8");
|
|
23334
24302
|
return JSON.parse(raw);
|
|
23335
24303
|
} catch {
|
|
23336
24304
|
return [];
|
|
@@ -23562,10 +24530,10 @@ __export(repl_exports, {
|
|
|
23562
24530
|
});
|
|
23563
24531
|
import * as readline2 from "readline";
|
|
23564
24532
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
23565
|
-
import { existsSync as
|
|
23566
|
-
import { join as
|
|
23567
|
-
import { homedir as
|
|
23568
|
-
import { fileURLToPath as
|
|
24533
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
24534
|
+
import { join as join28, dirname as dirname8 } from "node:path";
|
|
24535
|
+
import { homedir as homedir17 } from "node:os";
|
|
24536
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
23569
24537
|
async function selectPrompt(message, choices, defaultIdx) {
|
|
23570
24538
|
const { default: select } = await import("@inquirer/select");
|
|
23571
24539
|
return select({ message, choices, default: defaultIdx });
|
|
@@ -23581,8 +24549,8 @@ async function loadPrompts(promptsDir) {
|
|
|
23581
24549
|
const files = ["IDENTITY.md", "REASONING.md", "COMPUTER_USE.md", "SAFETY.md", "USER.md"];
|
|
23582
24550
|
const parts = [];
|
|
23583
24551
|
for (const file2 of files) {
|
|
23584
|
-
const path3 =
|
|
23585
|
-
if (
|
|
24552
|
+
const path3 = join28(promptsDir, file2);
|
|
24553
|
+
if (existsSync21(path3)) {
|
|
23586
24554
|
const content = await readFile4(path3, "utf8");
|
|
23587
24555
|
parts.push(content);
|
|
23588
24556
|
}
|
|
@@ -23598,11 +24566,11 @@ async function loadPrompts(promptsDir) {
|
|
|
23598
24566
|
}
|
|
23599
24567
|
async function loadMemorySummary() {
|
|
23600
24568
|
const memoryPaths = [
|
|
23601
|
-
|
|
23602
|
-
|
|
24569
|
+
join28(homedir17(), ".openjaw", "MEMORY.md"),
|
|
24570
|
+
join28(homedir17(), ".openjaw", "memory", "MEMORY.md")
|
|
23603
24571
|
];
|
|
23604
24572
|
for (const memoryPath of memoryPaths) {
|
|
23605
|
-
if (
|
|
24573
|
+
if (existsSync21(memoryPath)) {
|
|
23606
24574
|
const content = await readFile4(memoryPath, "utf8");
|
|
23607
24575
|
return content.slice(0, 2e3);
|
|
23608
24576
|
}
|
|
@@ -23610,8 +24578,8 @@ async function loadMemorySummary() {
|
|
|
23610
24578
|
return "";
|
|
23611
24579
|
}
|
|
23612
24580
|
async function startREPL(resumeSessionId) {
|
|
23613
|
-
const promptsDir =
|
|
23614
|
-
const packagePromptsDir2 =
|
|
24581
|
+
const promptsDir = join28(__dirname2, "..", "prompts");
|
|
24582
|
+
const packagePromptsDir2 = existsSync21(promptsDir) ? promptsDir : join28(homedir17(), ".openjaw-agent", "prompts");
|
|
23615
24583
|
await ensureDirectories();
|
|
23616
24584
|
const config = await loadConfig();
|
|
23617
24585
|
const systemPrompt = await loadPrompts(packagePromptsDir2);
|
|
@@ -24175,8 +25143,8 @@ var init_repl = __esm({
|
|
|
24175
25143
|
init_connect();
|
|
24176
25144
|
init_scheduler();
|
|
24177
25145
|
__name(selectPrompt, "selectPrompt");
|
|
24178
|
-
__filename2 =
|
|
24179
|
-
__dirname2 =
|
|
25146
|
+
__filename2 = fileURLToPath5(import.meta.url);
|
|
25147
|
+
__dirname2 = dirname8(__filename2);
|
|
24180
25148
|
C = {
|
|
24181
25149
|
reset: "\x1B[0m",
|
|
24182
25150
|
dim: "\x1B[2m",
|
|
@@ -24201,9 +25169,9 @@ var init_repl = __esm({
|
|
|
24201
25169
|
});
|
|
24202
25170
|
|
|
24203
25171
|
// src/voice/tts.ts
|
|
24204
|
-
import { execSync as execSync6, spawn as
|
|
24205
|
-
import { existsSync as
|
|
24206
|
-
import { join as
|
|
25172
|
+
import { execSync as execSync6, spawn as spawn4 } from "node:child_process";
|
|
25173
|
+
import { existsSync as existsSync22, unlinkSync as unlinkSync5, mkdirSync as mkdirSync14 } from "node:fs";
|
|
25174
|
+
import { join as join29 } from "node:path";
|
|
24207
25175
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
24208
25176
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
24209
25177
|
function hasEdgeTts() {
|
|
@@ -24257,8 +25225,8 @@ async function listVoices() {
|
|
|
24257
25225
|
}
|
|
24258
25226
|
}
|
|
24259
25227
|
async function speakEdgeTts(text, voice, options) {
|
|
24260
|
-
if (!
|
|
24261
|
-
const audioFile =
|
|
25228
|
+
if (!existsSync22(TTS_TEMP_DIR)) mkdirSync14(TTS_TEMP_DIR, { recursive: true });
|
|
25229
|
+
const audioFile = join29(TTS_TEMP_DIR, `tts-${randomUUID5().slice(0, 8)}.mp3`);
|
|
24262
25230
|
let playerProc = null;
|
|
24263
25231
|
let stopped = false;
|
|
24264
25232
|
try {
|
|
@@ -24270,9 +25238,9 @@ async function speakEdgeTts(text, voice, options) {
|
|
|
24270
25238
|
timeout: 15e3,
|
|
24271
25239
|
stdio: ["pipe", "pipe", "pipe"]
|
|
24272
25240
|
});
|
|
24273
|
-
if (stopped || !
|
|
25241
|
+
if (stopped || !existsSync22(audioFile)) return { stop: /* @__PURE__ */ __name(() => {
|
|
24274
25242
|
}, "stop") };
|
|
24275
|
-
playerProc =
|
|
25243
|
+
playerProc = spawn4("powershell.exe", [
|
|
24276
25244
|
"-NoProfile",
|
|
24277
25245
|
"-Command",
|
|
24278
25246
|
`Add-Type -AssemblyName PresentationCore; $p = New-Object System.Windows.Media.MediaPlayer; $p.Open([Uri]"${audioFile}"); $p.Play(); Start-Sleep -Milliseconds 500; while($p.Position -lt $p.NaturalDuration.TimeSpan -and $p.HasAudio){ Start-Sleep -Milliseconds 200 }; $p.Close()`
|
|
@@ -24282,14 +25250,14 @@ async function speakEdgeTts(text, voice, options) {
|
|
|
24282
25250
|
});
|
|
24283
25251
|
playerProc.on("exit", () => {
|
|
24284
25252
|
try {
|
|
24285
|
-
if (
|
|
25253
|
+
if (existsSync22(audioFile)) unlinkSync5(audioFile);
|
|
24286
25254
|
} catch {
|
|
24287
25255
|
}
|
|
24288
25256
|
playerProc = null;
|
|
24289
25257
|
});
|
|
24290
25258
|
} catch {
|
|
24291
25259
|
try {
|
|
24292
|
-
if (
|
|
25260
|
+
if (existsSync22(audioFile)) unlinkSync5(audioFile);
|
|
24293
25261
|
} catch {
|
|
24294
25262
|
}
|
|
24295
25263
|
}
|
|
@@ -24301,7 +25269,7 @@ async function speakEdgeTts(text, voice, options) {
|
|
|
24301
25269
|
playerProc = null;
|
|
24302
25270
|
}
|
|
24303
25271
|
try {
|
|
24304
|
-
if (
|
|
25272
|
+
if (existsSync22(audioFile)) unlinkSync5(audioFile);
|
|
24305
25273
|
} catch {
|
|
24306
25274
|
}
|
|
24307
25275
|
}, "stop")
|
|
@@ -24318,7 +25286,7 @@ $synth.Speak('${safeText}')
|
|
|
24318
25286
|
$synth.Dispose()
|
|
24319
25287
|
`;
|
|
24320
25288
|
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
24321
|
-
const proc =
|
|
25289
|
+
const proc = spawn4("powershell.exe", ["-NoProfile", "-EncodedCommand", encoded], {
|
|
24322
25290
|
stdio: ["pipe", "pipe", "pipe"],
|
|
24323
25291
|
windowsHide: true
|
|
24324
25292
|
});
|
|
@@ -24340,7 +25308,7 @@ var init_tts = __esm({
|
|
|
24340
25308
|
"use strict";
|
|
24341
25309
|
DEFAULT_VOICE_EN = "en-US-AriaNeural";
|
|
24342
25310
|
DEFAULT_VOICE_ZH = "zh-CN-XiaoxiaoNeural";
|
|
24343
|
-
TTS_TEMP_DIR =
|
|
25311
|
+
TTS_TEMP_DIR = join29(tmpdir5(), "oj-tts");
|
|
24344
25312
|
edgeTtsAvailable = null;
|
|
24345
25313
|
__name(hasEdgeTts, "hasEdgeTts");
|
|
24346
25314
|
__name(ensureEdgeTts, "ensureEdgeTts");
|
|
@@ -24354,13 +25322,13 @@ var init_tts = __esm({
|
|
|
24354
25322
|
});
|
|
24355
25323
|
|
|
24356
25324
|
// src/voice/stt.ts
|
|
24357
|
-
import { spawn as
|
|
24358
|
-
import { join as
|
|
25325
|
+
import { spawn as spawn5, execSync as execSync7 } from "node:child_process";
|
|
25326
|
+
import { join as join30 } from "node:path";
|
|
24359
25327
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
24360
|
-
import { existsSync as
|
|
25328
|
+
import { existsSync as existsSync23, unlinkSync as unlinkSync6 } from "node:fs";
|
|
24361
25329
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
24362
25330
|
async function listenOnce(timeoutSeconds = 10, language = "en-US") {
|
|
24363
|
-
const resultFile =
|
|
25331
|
+
const resultFile = join30(tmpdir6(), `oj-stt-${randomUUID6().slice(0, 8)}.txt`);
|
|
24364
25332
|
const script = `
|
|
24365
25333
|
$ProgressPreference = 'SilentlyContinue'
|
|
24366
25334
|
$ErrorActionPreference = 'Stop'
|
|
@@ -24395,8 +25363,8 @@ try {
|
|
|
24395
25363
|
}
|
|
24396
25364
|
`;
|
|
24397
25365
|
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
24398
|
-
return new Promise((
|
|
24399
|
-
const proc =
|
|
25366
|
+
return new Promise((resolve7) => {
|
|
25367
|
+
const proc = spawn5("powershell.exe", ["-NoProfile", "-STA", "-EncodedCommand", encoded], {
|
|
24400
25368
|
stdio: ["pipe", "pipe", "pipe"],
|
|
24401
25369
|
windowsHide: true
|
|
24402
25370
|
});
|
|
@@ -24410,25 +25378,25 @@ try {
|
|
|
24410
25378
|
});
|
|
24411
25379
|
const timer = setTimeout(() => {
|
|
24412
25380
|
if (!proc.killed) proc.kill();
|
|
24413
|
-
|
|
25381
|
+
resolve7(null);
|
|
24414
25382
|
}, (timeoutSeconds + 5) * 1e3);
|
|
24415
25383
|
proc.on("exit", () => {
|
|
24416
25384
|
clearTimeout(timer);
|
|
24417
25385
|
const output = stdout.replace(/#< CLIXML[\s\S]*/m, "").trim();
|
|
24418
25386
|
if (output === "NO_SPEECH" || output.startsWith("ERROR") || !output) {
|
|
24419
|
-
|
|
25387
|
+
resolve7(null);
|
|
24420
25388
|
return;
|
|
24421
25389
|
}
|
|
24422
25390
|
const parts = output.split("|");
|
|
24423
25391
|
const text = parts[0]?.trim();
|
|
24424
25392
|
const confidence = parseFloat(parts[1] || "0");
|
|
24425
25393
|
if (text) {
|
|
24426
|
-
|
|
25394
|
+
resolve7({ text, confidence: isNaN(confidence) ? 0.5 : confidence });
|
|
24427
25395
|
} else {
|
|
24428
|
-
|
|
25396
|
+
resolve7(null);
|
|
24429
25397
|
}
|
|
24430
25398
|
try {
|
|
24431
|
-
if (
|
|
25399
|
+
if (existsSync23(resultFile)) unlinkSync6(resultFile);
|
|
24432
25400
|
} catch {
|
|
24433
25401
|
}
|
|
24434
25402
|
});
|
|
@@ -24662,9 +25630,9 @@ __export(clipboard_image_exports, {
|
|
|
24662
25630
|
readClipboardImage: () => readClipboardImage
|
|
24663
25631
|
});
|
|
24664
25632
|
import { execSync as execSync8 } from "node:child_process";
|
|
24665
|
-
import { join as
|
|
25633
|
+
import { join as join31 } from "node:path";
|
|
24666
25634
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
24667
|
-
import { readFileSync as
|
|
25635
|
+
import { readFileSync as readFileSync21, unlinkSync as unlinkSync7, existsSync as existsSync24 } from "node:fs";
|
|
24668
25636
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
24669
25637
|
function encodePS(script) {
|
|
24670
25638
|
return Buffer.from(script, "utf16le").toString("base64");
|
|
@@ -24689,7 +25657,7 @@ Add-Type -AssemblyName System.Windows.Forms
|
|
|
24689
25657
|
}
|
|
24690
25658
|
function readClipboardImage() {
|
|
24691
25659
|
try {
|
|
24692
|
-
const tempPath =
|
|
25660
|
+
const tempPath = join31(tmpdir7(), `oj-clip-${randomUUID7().slice(0, 8)}.png`);
|
|
24693
25661
|
const script = `
|
|
24694
25662
|
$ProgressPreference = 'SilentlyContinue'
|
|
24695
25663
|
$ErrorActionPreference = 'Stop'
|
|
@@ -24706,16 +25674,16 @@ $img.Dispose()
|
|
|
24706
25674
|
{ encoding: "utf-8", timeout: 8e3, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }
|
|
24707
25675
|
).trim();
|
|
24708
25676
|
const clean = output.replace(/#< CLIXML[\s\S]*/m, "").trim();
|
|
24709
|
-
if (clean === "NO_IMAGE" || !
|
|
25677
|
+
if (clean === "NO_IMAGE" || !existsSync24(tempPath)) {
|
|
24710
25678
|
return null;
|
|
24711
25679
|
}
|
|
24712
25680
|
const match = clean.match(/(\d+)x(\d+)/);
|
|
24713
25681
|
const width = match ? parseInt(match[1], 10) : 0;
|
|
24714
25682
|
const height = match ? parseInt(match[2], 10) : 0;
|
|
24715
|
-
const buffer =
|
|
25683
|
+
const buffer = readFileSync21(tempPath);
|
|
24716
25684
|
const base64 = buffer.toString("base64");
|
|
24717
25685
|
try {
|
|
24718
|
-
|
|
25686
|
+
unlinkSync7(tempPath);
|
|
24719
25687
|
} catch {
|
|
24720
25688
|
}
|
|
24721
25689
|
return { base64, mimeType: "image/png", width, height };
|
|
@@ -25541,9 +26509,9 @@ __export(pet_exports, {
|
|
|
25541
26509
|
getRandomReaction: () => getRandomReaction,
|
|
25542
26510
|
renamePet: () => renamePet
|
|
25543
26511
|
});
|
|
25544
|
-
import { existsSync as
|
|
25545
|
-
import { join as
|
|
25546
|
-
import { homedir as
|
|
26512
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15 } from "node:fs";
|
|
26513
|
+
import { join as join32 } from "node:path";
|
|
26514
|
+
import { homedir as homedir18 } from "node:os";
|
|
25547
26515
|
function hashCode(str) {
|
|
25548
26516
|
let hash3 = 0;
|
|
25549
26517
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -25561,20 +26529,20 @@ function seededRandom(seed) {
|
|
|
25561
26529
|
};
|
|
25562
26530
|
}
|
|
25563
26531
|
function getPetPath() {
|
|
25564
|
-
return
|
|
26532
|
+
return join32(homedir18(), ".openjaw-agent", "pet.json");
|
|
25565
26533
|
}
|
|
25566
26534
|
function loadStoredPet() {
|
|
25567
26535
|
const path3 = getPetPath();
|
|
25568
|
-
if (!
|
|
26536
|
+
if (!existsSync25(path3)) return null;
|
|
25569
26537
|
try {
|
|
25570
|
-
return JSON.parse(
|
|
26538
|
+
return JSON.parse(readFileSync22(path3, "utf-8"));
|
|
25571
26539
|
} catch {
|
|
25572
26540
|
return null;
|
|
25573
26541
|
}
|
|
25574
26542
|
}
|
|
25575
26543
|
function saveStoredPet(data) {
|
|
25576
|
-
const dir2 =
|
|
25577
|
-
if (!
|
|
26544
|
+
const dir2 = join32(homedir18(), ".openjaw-agent");
|
|
26545
|
+
if (!existsSync25(dir2)) mkdirSync15(dir2, { recursive: true });
|
|
25578
26546
|
writeFileSync14(getPetPath(), JSON.stringify(data, null, 2), "utf-8");
|
|
25579
26547
|
}
|
|
25580
26548
|
function generatePet(userId) {
|
|
@@ -26123,34 +27091,34 @@ ${output}
|
|
|
26123
27091
|
}
|
|
26124
27092
|
}
|
|
26125
27093
|
function expandUrl(ref, warnings) {
|
|
26126
|
-
return new Promise((
|
|
27094
|
+
return new Promise((resolve7) => {
|
|
26127
27095
|
const url = ref.target;
|
|
26128
27096
|
const mod = url.startsWith("https") ? https : http;
|
|
26129
27097
|
const req = mod.get(url, { timeout: 15e3 }, (res) => {
|
|
26130
27098
|
if (res.statusCode && (res.statusCode >= 300 && res.statusCode < 400) && res.headers.location) {
|
|
26131
27099
|
const redirectMod = res.headers.location.startsWith("https") ? https : http;
|
|
26132
27100
|
const req2 = redirectMod.get(res.headers.location, { timeout: 15e3 }, (res2) => {
|
|
26133
|
-
collectResponse(res2, ref, warnings,
|
|
27101
|
+
collectResponse(res2, ref, warnings, resolve7);
|
|
26134
27102
|
});
|
|
26135
27103
|
req2.on("error", (e) => {
|
|
26136
27104
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26137
|
-
|
|
27105
|
+
resolve7(null);
|
|
26138
27106
|
});
|
|
26139
27107
|
return;
|
|
26140
27108
|
}
|
|
26141
|
-
collectResponse(res, ref, warnings,
|
|
27109
|
+
collectResponse(res, ref, warnings, resolve7);
|
|
26142
27110
|
});
|
|
26143
27111
|
req.on("error", (e) => {
|
|
26144
27112
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26145
|
-
|
|
27113
|
+
resolve7(null);
|
|
26146
27114
|
});
|
|
26147
27115
|
});
|
|
26148
27116
|
}
|
|
26149
|
-
function collectResponse(res, ref, warnings,
|
|
27117
|
+
function collectResponse(res, ref, warnings, resolve7) {
|
|
26150
27118
|
if (res.statusCode && res.statusCode >= 400) {
|
|
26151
27119
|
warnings.push(`\u26A0\uFE0F @url returned HTTP ${res.statusCode}: ${ref.target}`);
|
|
26152
27120
|
res.resume();
|
|
26153
|
-
|
|
27121
|
+
resolve7(null);
|
|
26154
27122
|
return;
|
|
26155
27123
|
}
|
|
26156
27124
|
const chunks = [];
|
|
@@ -26162,14 +27130,14 @@ function collectResponse(res, ref, warnings, resolve6) {
|
|
|
26162
27130
|
text = text.slice(0, 5e4) + "\n\u2026 (truncated)";
|
|
26163
27131
|
}
|
|
26164
27132
|
const tokens = estimateTokens2(text);
|
|
26165
|
-
|
|
27133
|
+
resolve7(`\u{1F310} @url:${ref.target} (${tokens} tokens)
|
|
26166
27134
|
\`\`\`
|
|
26167
27135
|
${text}
|
|
26168
27136
|
\`\`\``);
|
|
26169
27137
|
});
|
|
26170
27138
|
res.on("error", (e) => {
|
|
26171
27139
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26172
|
-
|
|
27140
|
+
resolve7(null);
|
|
26173
27141
|
});
|
|
26174
27142
|
}
|
|
26175
27143
|
function stripHtml(html) {
|
|
@@ -26670,13 +27638,13 @@ Type /resume <id> to resume.` });
|
|
|
26670
27638
|
if (input === "/export") {
|
|
26671
27639
|
try {
|
|
26672
27640
|
const { writeFile: writeFile5, mkdir: mkdir5 } = await import("node:fs/promises");
|
|
26673
|
-
const { join:
|
|
26674
|
-
const { homedir:
|
|
26675
|
-
const { existsSync:
|
|
26676
|
-
const exportDir =
|
|
26677
|
-
if (!
|
|
27641
|
+
const { join: join49 } = await import("node:path");
|
|
27642
|
+
const { homedir: homedir33 } = await import("node:os");
|
|
27643
|
+
const { existsSync: existsSync36 } = await import("node:fs");
|
|
27644
|
+
const exportDir = join49(homedir33(), ".openjaw-agent", "exports");
|
|
27645
|
+
if (!existsSync36(exportDir)) await mkdir5(exportDir, { recursive: true });
|
|
26678
27646
|
const filename = `session-${agentLoop.sessionId}.md`;
|
|
26679
|
-
const filepath =
|
|
27647
|
+
const filepath = join49(exportDir, filename);
|
|
26680
27648
|
const lines = [
|
|
26681
27649
|
`# OpenJaw Agent Session ${agentLoop.sessionId}`,
|
|
26682
27650
|
`Date: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -26895,9 +27863,9 @@ ${list}` });
|
|
|
26895
27863
|
const cmd = lang === "python" ? "python" : lang === "node" ? "node" : "pwsh";
|
|
26896
27864
|
const args = lang === "python" ? ["-i", "-u"] : lang === "node" ? ["-i"] : ["-NoProfile", "-NoLogo"];
|
|
26897
27865
|
try {
|
|
26898
|
-
const { spawn:
|
|
27866
|
+
const { spawn: spawn10 } = await import("node:child_process");
|
|
26899
27867
|
if (replRef.current) replRef.current.kill();
|
|
26900
|
-
const proc =
|
|
27868
|
+
const proc = spawn10(cmd, args, {
|
|
26901
27869
|
stdio: ["pipe", "pipe", "pipe"],
|
|
26902
27870
|
windowsHide: true
|
|
26903
27871
|
});
|
|
@@ -26937,7 +27905,7 @@ ${list}` });
|
|
|
26937
27905
|
if (replRef.current && replLangRef.current && !input.startsWith("/")) {
|
|
26938
27906
|
const proc = replRef.current;
|
|
26939
27907
|
proc.stdin?.write(input + "\n");
|
|
26940
|
-
await new Promise((
|
|
27908
|
+
await new Promise((resolve7) => setTimeout(resolve7, 800));
|
|
26941
27909
|
const flush = proc._ojFlush;
|
|
26942
27910
|
const output = flush ? flush() : "";
|
|
26943
27911
|
if (output.trim()) {
|
|
@@ -27251,14 +28219,14 @@ Options: ${chunk.choices.join(" | ")}` : chunk.content;
|
|
|
27251
28219
|
waitingForAskUserRef.current = true;
|
|
27252
28220
|
setIsRunning(false);
|
|
27253
28221
|
setWaitingForAskUser(true);
|
|
27254
|
-
await new Promise((
|
|
28222
|
+
await new Promise((resolve7) => {
|
|
27255
28223
|
const checkInterval = setInterval(() => {
|
|
27256
28224
|
if (!waitingForAskUserRef.current || !agentLoop.isWaitingForAskUser) {
|
|
27257
28225
|
clearInterval(checkInterval);
|
|
27258
28226
|
waitingForAskUserRef.current = false;
|
|
27259
28227
|
setWaitingForAskUser(false);
|
|
27260
28228
|
setIsRunning(true);
|
|
27261
|
-
|
|
28229
|
+
resolve7();
|
|
27262
28230
|
}
|
|
27263
28231
|
}, 200);
|
|
27264
28232
|
});
|
|
@@ -27533,7 +28501,7 @@ var skill_tool_exports = {};
|
|
|
27533
28501
|
__export(skill_tool_exports, {
|
|
27534
28502
|
createSkillTool: () => createSkillTool
|
|
27535
28503
|
});
|
|
27536
|
-
import { readFileSync as
|
|
28504
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "node:fs";
|
|
27537
28505
|
function resolveSkillTimeoutMs() {
|
|
27538
28506
|
const raw = process.env["OPENJAW_SKILL_TIMEOUT_MS"];
|
|
27539
28507
|
const parsed = raw ? Number(raw) : NaN;
|
|
@@ -27554,8 +28522,8 @@ async function withTimeout(promise, ms) {
|
|
|
27554
28522
|
try {
|
|
27555
28523
|
return await Promise.race([
|
|
27556
28524
|
promise,
|
|
27557
|
-
new Promise((
|
|
27558
|
-
timeoutId = setTimeout(() =>
|
|
28525
|
+
new Promise((resolve7) => {
|
|
28526
|
+
timeoutId = setTimeout(() => resolve7(SKILL_TIMEOUT), ms);
|
|
27559
28527
|
})
|
|
27560
28528
|
]);
|
|
27561
28529
|
} finally {
|
|
@@ -27701,7 +28669,7 @@ function extractLessons(chunks) {
|
|
|
27701
28669
|
}
|
|
27702
28670
|
function appendLessonsLearned(skillPath, lessons) {
|
|
27703
28671
|
try {
|
|
27704
|
-
const content =
|
|
28672
|
+
const content = readFileSync24(skillPath, "utf8");
|
|
27705
28673
|
const datestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
27706
28674
|
if (content.includes("## Lessons Learned")) {
|
|
27707
28675
|
const updated = content.replace(
|
|
@@ -27746,9 +28714,9 @@ var teams_exports = {};
|
|
|
27746
28714
|
__export(teams_exports, {
|
|
27747
28715
|
TeamsBridge: () => TeamsBridge
|
|
27748
28716
|
});
|
|
27749
|
-
import { readFileSync as
|
|
27750
|
-
import { join as
|
|
27751
|
-
import { homedir as
|
|
28717
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync16, existsSync as existsSync27 } from "node:fs";
|
|
28718
|
+
import { join as join34 } from "node:path";
|
|
28719
|
+
import { homedir as homedir20, tmpdir as tmpdir8 } from "node:os";
|
|
27752
28720
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
27753
28721
|
var AGENT_PREFIX, POLL_INTERVAL, TeamsBridge;
|
|
27754
28722
|
var init_teams = __esm({
|
|
@@ -27836,7 +28804,7 @@ var init_teams = __esm({
|
|
|
27836
28804
|
const { resizeImageFileForAgent: resizeImageFileForAgent2 } = await Promise.resolve().then(() => (init_image_resize(), image_resize_exports));
|
|
27837
28805
|
imageData = await resizeImageFileForAgent2(imageFile);
|
|
27838
28806
|
} catch {
|
|
27839
|
-
const imgBuffer =
|
|
28807
|
+
const imgBuffer = readFileSync25(imageFile);
|
|
27840
28808
|
const ext = imageFile.split(".").pop()?.toLowerCase() || "png";
|
|
27841
28809
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : ext === "webp" ? "image/webp" : "image/png";
|
|
27842
28810
|
imageData = { base64: imgBuffer.toString("base64"), mimeType };
|
|
@@ -27912,7 +28880,7 @@ var init_teams = __esm({
|
|
|
27912
28880
|
const resp = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
27913
28881
|
if (!resp.ok) return null;
|
|
27914
28882
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
27915
|
-
const tempPath =
|
|
28883
|
+
const tempPath = join34(tmpdir8(), `oj-teams-${randomUUID8().slice(0, 6)}-${filename}`);
|
|
27916
28884
|
writeFileSync16(tempPath, buffer);
|
|
27917
28885
|
return tempPath;
|
|
27918
28886
|
} catch {
|
|
@@ -27927,7 +28895,7 @@ var init_teams = __esm({
|
|
|
27927
28895
|
const contentType = resp.headers.get("content-type") ?? "image/png";
|
|
27928
28896
|
const ext = contentType.includes("jpeg") ? ".jpg" : contentType.includes("gif") ? ".gif" : ".png";
|
|
27929
28897
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
27930
|
-
const tempPath =
|
|
28898
|
+
const tempPath = join34(tmpdir8(), `oj-teams-img-${randomUUID8().slice(0, 6)}${ext}`);
|
|
27931
28899
|
writeFileSync16(tempPath, buffer);
|
|
27932
28900
|
return tempPath;
|
|
27933
28901
|
} catch {
|
|
@@ -27968,7 +28936,7 @@ var init_teams = __esm({
|
|
|
27968
28936
|
async sendFileToSelfChat(filePath) {
|
|
27969
28937
|
const token = this.getGraphToken();
|
|
27970
28938
|
const fileName = filePath.split(/[\\/]/).pop() || "file";
|
|
27971
|
-
const fileBuffer =
|
|
28939
|
+
const fileBuffer = readFileSync25(filePath);
|
|
27972
28940
|
const uploadResp = await fetch(
|
|
27973
28941
|
`https://graph.microsoft.com/v1.0/me/drive/root:/OpenJaw-Shared/${fileName}:/content`,
|
|
27974
28942
|
{
|
|
@@ -28021,7 +28989,7 @@ var init_teams = __esm({
|
|
|
28021
28989
|
if (filePath.includes("http") || filePath.includes("node_modules")) continue;
|
|
28022
28990
|
const fileName = filePath.split(/[\\/]/).pop() || "";
|
|
28023
28991
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
28024
|
-
if (
|
|
28992
|
+
if (existsSync27(filePath)) {
|
|
28025
28993
|
try {
|
|
28026
28994
|
const { statSync: statSync5 } = await import("node:fs");
|
|
28027
28995
|
const stat2 = statSync5(filePath);
|
|
@@ -28039,9 +29007,9 @@ var init_teams = __esm({
|
|
|
28039
29007
|
}
|
|
28040
29008
|
/** Get Graph access token from disk. */
|
|
28041
29009
|
getGraphToken() {
|
|
28042
|
-
const tokenPath =
|
|
28043
|
-
if (!
|
|
28044
|
-
const data = JSON.parse(
|
|
29010
|
+
const tokenPath = join34(homedir20(), ".graph-token", "tokens", "graph-chat.json");
|
|
29011
|
+
if (!existsSync27(tokenPath)) throw new Error("Graph token not found");
|
|
29012
|
+
const data = JSON.parse(readFileSync25(tokenPath, "utf-8"));
|
|
28045
29013
|
if (!data.access_token) throw new Error("No access_token");
|
|
28046
29014
|
return data.access_token;
|
|
28047
29015
|
}
|
|
@@ -28165,12 +29133,12 @@ var init_teams = __esm({
|
|
|
28165
29133
|
Options: ${chunk.choices.join(" | ")}` : "";
|
|
28166
29134
|
await this.sendToSelfChat(`\u2753 ${question}${choicesText}`);
|
|
28167
29135
|
if (!answerSent) await updateStatus("\u{1F916} OpenJaw Agent \u2014 \u2753 Waiting for your response...");
|
|
28168
|
-
const userReply = await new Promise((
|
|
28169
|
-
this._pendingReplyResolver =
|
|
29136
|
+
const userReply = await new Promise((resolve7) => {
|
|
29137
|
+
this._pendingReplyResolver = resolve7;
|
|
28170
29138
|
setTimeout(() => {
|
|
28171
|
-
if (this._pendingReplyResolver ===
|
|
29139
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
28172
29140
|
this._pendingReplyResolver = null;
|
|
28173
|
-
|
|
29141
|
+
resolve7("[No response \u2014 timed out]");
|
|
28174
29142
|
}
|
|
28175
29143
|
}, 5 * 60 * 1e3);
|
|
28176
29144
|
});
|
|
@@ -28242,8 +29210,8 @@ __export(feishu_exports, {
|
|
|
28242
29210
|
FeishuBridge: () => FeishuBridge
|
|
28243
29211
|
});
|
|
28244
29212
|
import * as lark from "@larksuiteoapi/node-sdk";
|
|
28245
|
-
import { readFileSync as
|
|
28246
|
-
import { join as
|
|
29213
|
+
import { readFileSync as readFileSync26, existsSync as existsSync28 } from "node:fs";
|
|
29214
|
+
import { join as join35 } from "node:path";
|
|
28247
29215
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
28248
29216
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
28249
29217
|
var FeishuBridge;
|
|
@@ -28479,9 +29447,9 @@ var init_feishu = __esm({
|
|
|
28479
29447
|
params: { type: "image" }
|
|
28480
29448
|
});
|
|
28481
29449
|
if (resp) {
|
|
28482
|
-
const tempPath =
|
|
29450
|
+
const tempPath = join35(tmpdir9(), `oj-feishu-img-${randomUUID9().slice(0, 6)}.png`);
|
|
28483
29451
|
await resp.writeFile(tempPath);
|
|
28484
|
-
const buffer =
|
|
29452
|
+
const buffer = readFileSync26(tempPath);
|
|
28485
29453
|
let imageData;
|
|
28486
29454
|
try {
|
|
28487
29455
|
const { resizeImageFileForAgent: resizeImageFileForAgent2 } = await Promise.resolve().then(() => (init_image_resize(), image_resize_exports));
|
|
@@ -28502,7 +29470,7 @@ var init_feishu = __esm({
|
|
|
28502
29470
|
params: { type: "file" }
|
|
28503
29471
|
});
|
|
28504
29472
|
if (resp) {
|
|
28505
|
-
const tempPath =
|
|
29473
|
+
const tempPath = join35(tmpdir9(), `oj-feishu-file-${randomUUID9().slice(0, 6)}-${fileName}`);
|
|
28506
29474
|
await resp.writeFile(tempPath);
|
|
28507
29475
|
await this.handleMessage(chatId, `I've sent you a file: ${fileName}. It's saved at ${tempPath}. Please analyze it.`);
|
|
28508
29476
|
}
|
|
@@ -28579,7 +29547,7 @@ var init_feishu = __esm({
|
|
|
28579
29547
|
const fileName = filePath.split(/[\\/]/).pop() || "";
|
|
28580
29548
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
28581
29549
|
if (filePath.includes("http") || filePath.includes("node_modules")) continue;
|
|
28582
|
-
const exists =
|
|
29550
|
+
const exists = existsSync28(filePath);
|
|
28583
29551
|
this.emit({ type: "system", content: `\u{1F50D} Found path: ${filePath} (exists: ${exists})` });
|
|
28584
29552
|
if (exists) {
|
|
28585
29553
|
try {
|
|
@@ -28654,12 +29622,12 @@ ${err.stack?.split("\n").slice(0, 3).join("\n")}` : String(err);
|
|
|
28654
29622
|
}
|
|
28655
29623
|
/** Wait for the next user message (used by ask_user flow) */
|
|
28656
29624
|
waitForUserReply(_chatId) {
|
|
28657
|
-
return new Promise((
|
|
28658
|
-
this._pendingReplyResolver =
|
|
29625
|
+
return new Promise((resolve7) => {
|
|
29626
|
+
this._pendingReplyResolver = resolve7;
|
|
28659
29627
|
setTimeout(() => {
|
|
28660
|
-
if (this._pendingReplyResolver ===
|
|
29628
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
28661
29629
|
this._pendingReplyResolver = null;
|
|
28662
|
-
|
|
29630
|
+
resolve7("[No response \u2014 timed out]");
|
|
28663
29631
|
}
|
|
28664
29632
|
}, 5 * 60 * 1e3);
|
|
28665
29633
|
});
|
|
@@ -28680,10 +29648,10 @@ __export(wechat_exports, {
|
|
|
28680
29648
|
sniffMediaKind: () => sniffMediaKind,
|
|
28681
29649
|
validateMediaForUpload: () => validateMediaForUpload
|
|
28682
29650
|
});
|
|
28683
|
-
import { existsSync as
|
|
29651
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27, writeFileSync as writeFileSync18, unlinkSync as unlinkSync8, statSync as statSync3 } from "node:fs";
|
|
28684
29652
|
import { mkdirSync as mkdirSync16 } from "node:fs";
|
|
28685
|
-
import { extname as extname3, join as
|
|
28686
|
-
import { homedir as
|
|
29653
|
+
import { extname as extname3, join as join36 } from "node:path";
|
|
29654
|
+
import { homedir as homedir22 } from "node:os";
|
|
28687
29655
|
import { randomBytes, randomUUID as randomUUID10, createDecipheriv, createCipheriv, createHash as createHash3 } from "node:crypto";
|
|
28688
29656
|
function mimeFromFilename(fileName) {
|
|
28689
29657
|
return MIME_MAP[extname3(fileName).toLowerCase()] || "application/octet-stream";
|
|
@@ -28751,7 +29719,7 @@ function expandEnvVars(p) {
|
|
|
28751
29719
|
return v !== void 0 ? v : m;
|
|
28752
29720
|
});
|
|
28753
29721
|
if (out.startsWith("~")) {
|
|
28754
|
-
out =
|
|
29722
|
+
out = join36(homedir22(), out.slice(1).replace(/^[\\/]/, ""));
|
|
28755
29723
|
}
|
|
28756
29724
|
return out;
|
|
28757
29725
|
}
|
|
@@ -28901,15 +29869,15 @@ var init_wechat2 = __esm({
|
|
|
28901
29869
|
}
|
|
28902
29870
|
// ── Auth ──
|
|
28903
29871
|
getAccountPath() {
|
|
28904
|
-
const dir2 =
|
|
28905
|
-
if (!
|
|
28906
|
-
return
|
|
29872
|
+
const dir2 = join36(homedir22(), ".openjaw-agent");
|
|
29873
|
+
if (!existsSync29(dir2)) mkdirSync16(dir2, { recursive: true });
|
|
29874
|
+
return join36(dir2, "wechat-account.json");
|
|
28907
29875
|
}
|
|
28908
29876
|
loadAccount() {
|
|
28909
29877
|
const path3 = this.getAccountPath();
|
|
28910
|
-
if (!
|
|
29878
|
+
if (!existsSync29(path3)) return false;
|
|
28911
29879
|
try {
|
|
28912
|
-
this.account = JSON.parse(
|
|
29880
|
+
this.account = JSON.parse(readFileSync27(path3, "utf-8"));
|
|
28913
29881
|
return !!this.account?.token;
|
|
28914
29882
|
} catch {
|
|
28915
29883
|
return false;
|
|
@@ -28925,7 +29893,7 @@ var init_wechat2 = __esm({
|
|
|
28925
29893
|
/** Delete saved session and clear current account (for /wechat logout) */
|
|
28926
29894
|
logout() {
|
|
28927
29895
|
const path3 = this.getAccountPath();
|
|
28928
|
-
if (
|
|
29896
|
+
if (existsSync29(path3)) unlinkSync8(path3);
|
|
28929
29897
|
this.account = null;
|
|
28930
29898
|
this.emit({ type: "system", content: "\u{1F7E2} WeChat: \u5DF2\u767B\u51FA\uFF0C\u4E0B\u6B21\u6D88\u606F\u5C06\u91CD\u65B0\u626B\u7801" });
|
|
28931
29899
|
}
|
|
@@ -28950,9 +29918,9 @@ var init_wechat2 = __esm({
|
|
|
28950
29918
|
try {
|
|
28951
29919
|
const qrTerminal = await import("qrcode-terminal");
|
|
28952
29920
|
const mod = qrTerminal.default || qrTerminal;
|
|
28953
|
-
const qrAscii = await new Promise((
|
|
29921
|
+
const qrAscii = await new Promise((resolve7, reject) => {
|
|
28954
29922
|
try {
|
|
28955
|
-
mod.generate(qrUrl, { small: true }, (out) =>
|
|
29923
|
+
mod.generate(qrUrl, { small: true }, (out) => resolve7(out));
|
|
28956
29924
|
} catch (e) {
|
|
28957
29925
|
reject(e);
|
|
28958
29926
|
}
|
|
@@ -29218,12 +30186,12 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29218
30186
|
const choicesText = chunk.choices?.length ? `
|
|
29219
30187
|
\u9009\u9879: ${chunk.choices.join(" | ")}` : "";
|
|
29220
30188
|
await this.sendText(userId, `\u2753 ${question}${choicesText}`, contextToken);
|
|
29221
|
-
const userReply = await new Promise((
|
|
29222
|
-
this._pendingReplyResolver =
|
|
30189
|
+
const userReply = await new Promise((resolve7) => {
|
|
30190
|
+
this._pendingReplyResolver = resolve7;
|
|
29223
30191
|
setTimeout(() => {
|
|
29224
|
-
if (this._pendingReplyResolver ===
|
|
30192
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
29225
30193
|
this._pendingReplyResolver = null;
|
|
29226
|
-
|
|
30194
|
+
resolve7("[No response \u2014 timed out]");
|
|
29227
30195
|
}
|
|
29228
30196
|
}, 5 * 60 * 1e3);
|
|
29229
30197
|
});
|
|
@@ -29387,7 +30355,7 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29387
30355
|
*/
|
|
29388
30356
|
async uploadFile(filePath, fileName, toUserId) {
|
|
29389
30357
|
if (!this.account) return null;
|
|
29390
|
-
const plaintext =
|
|
30358
|
+
const plaintext = readFileSync27(filePath);
|
|
29391
30359
|
const rawsize = plaintext.length;
|
|
29392
30360
|
if (rawsize === 0) {
|
|
29393
30361
|
this.emit({ type: "system", content: `\u26A0 WeChat upload skipped (file is empty): ${fileName}` });
|
|
@@ -29547,7 +30515,7 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29547
30515
|
if (!fileName) continue;
|
|
29548
30516
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
29549
30517
|
if (filePath.includes("http://") || filePath.includes("https://") || filePath.includes("node_modules")) continue;
|
|
29550
|
-
if (!
|
|
30518
|
+
if (!existsSync29(filePath)) continue;
|
|
29551
30519
|
attemptedFiles.add(dedupKey);
|
|
29552
30520
|
attempted++;
|
|
29553
30521
|
try {
|
|
@@ -29669,9 +30637,9 @@ __export(legacy_ink_ui_exports, {
|
|
|
29669
30637
|
});
|
|
29670
30638
|
import React6 from "react";
|
|
29671
30639
|
import { render } from "ink";
|
|
29672
|
-
import { existsSync as
|
|
29673
|
-
import { join as
|
|
29674
|
-
import { homedir as
|
|
30640
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
30641
|
+
import { join as join37 } from "node:path";
|
|
30642
|
+
import { homedir as homedir23 } from "node:os";
|
|
29675
30643
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
29676
30644
|
async function startInkUI(resumeSessionId, bridges = []) {
|
|
29677
30645
|
await ensureDirectories();
|
|
@@ -29699,12 +30667,12 @@ async function startInkUI(resumeSessionId, bridges = []) {
|
|
|
29699
30667
|
});
|
|
29700
30668
|
const agentLoop = new AgentLoop(agentConfig, toolRegistry, resumeSessionId);
|
|
29701
30669
|
toolRegistry.setWebSearchExecutor(createWebSearchExecutor(agentLoop));
|
|
29702
|
-
const memoryDbPath =
|
|
30670
|
+
const memoryDbPath = join37(homedir23(), ".openjaw", "memory.db");
|
|
29703
30671
|
const memoryLegacyPaths = [
|
|
29704
|
-
|
|
29705
|
-
|
|
30672
|
+
join37(homedir23(), ".openjaw", "MEMORY.md"),
|
|
30673
|
+
join37(homedir23(), ".openjaw", "memory", "MEMORY.md")
|
|
29706
30674
|
];
|
|
29707
|
-
const memoryStatus =
|
|
30675
|
+
const memoryStatus = existsSync30(memoryDbPath) ? "loaded" : memoryLegacyPaths.some((p) => existsSync30(p)) ? "legacy" : "empty";
|
|
29708
30676
|
const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt({ mcpManager }), "systemPromptFn");
|
|
29709
30677
|
const { createSkillTool: createSkillTool2 } = await Promise.resolve().then(() => (init_skill_tool(), skill_tool_exports));
|
|
29710
30678
|
toolRegistry.registerTool(createSkillTool2(agentConfig, toolRegistry, systemPromptFn));
|
|
@@ -29971,6 +30939,15 @@ var init_agentBus = __esm({
|
|
|
29971
30939
|
hasRpc(method) {
|
|
29972
30940
|
return this.handlers.has(method);
|
|
29973
30941
|
}
|
|
30942
|
+
/**
|
|
30943
|
+
* Read the currently-registered handler for `method`, or undefined if
|
|
30944
|
+
* none. The desktop layer uses this to wrap an existing handler with
|
|
30945
|
+
* a lock-aware override (electronMain.ts registers `session.resume`
|
|
30946
|
+
* after registerRpcHandlers and needs to delegate to the original).
|
|
30947
|
+
*/
|
|
30948
|
+
getRpc(method) {
|
|
30949
|
+
return this.handlers.get(method);
|
|
30950
|
+
}
|
|
29974
30951
|
/**
|
|
29975
30952
|
* RPC dispatch entry point. Mirrors hermes's WebSocket `request(method, params)`
|
|
29976
30953
|
* but is a direct in-process function call. When no handler is registered,
|
|
@@ -30072,9 +31049,9 @@ var init_agentBus = __esm({
|
|
|
30072
31049
|
});
|
|
30073
31050
|
|
|
30074
31051
|
// src/bridges/registry.ts
|
|
30075
|
-
import { existsSync as
|
|
30076
|
-
import { homedir as
|
|
30077
|
-
import { join as
|
|
31052
|
+
import { existsSync as existsSync31, unlinkSync as unlinkSync9 } from "node:fs";
|
|
31053
|
+
import { homedir as homedir24 } from "node:os";
|
|
31054
|
+
import { join as join38 } from "node:path";
|
|
30078
31055
|
var BRIDGE_REGISTRY, BRIDGE_NAMES, isBridgeName, normalizeCredentialsForConfig, BridgeManager, parseListInput;
|
|
30079
31056
|
var init_registry3 = __esm({
|
|
30080
31057
|
"src/bridges/registry.ts"() {
|
|
@@ -30173,15 +31150,15 @@ var init_registry3 = __esm({
|
|
|
30173
31150
|
return { instance, stop: /* @__PURE__ */ __name(() => instance.stop(), "stop") };
|
|
30174
31151
|
},
|
|
30175
31152
|
async onForget(instance) {
|
|
30176
|
-
const wechatPath =
|
|
31153
|
+
const wechatPath = join38(homedir24(), ".openjaw-agent", "wechat-account.json");
|
|
30177
31154
|
if (instance && typeof instance.logout === "function") {
|
|
30178
31155
|
try {
|
|
30179
31156
|
instance.logout();
|
|
30180
31157
|
} catch {
|
|
30181
31158
|
}
|
|
30182
|
-
} else if (
|
|
31159
|
+
} else if (existsSync31(wechatPath)) {
|
|
30183
31160
|
try {
|
|
30184
|
-
|
|
31161
|
+
unlinkSync9(wechatPath);
|
|
30185
31162
|
} catch {
|
|
30186
31163
|
}
|
|
30187
31164
|
}
|
|
@@ -30454,12 +31431,19 @@ var init_registry3 = __esm({
|
|
|
30454
31431
|
|
|
30455
31432
|
// src/bootstrap.ts
|
|
30456
31433
|
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
30457
|
-
import { existsSync as
|
|
30458
|
-
import { homedir as
|
|
30459
|
-
import { join as
|
|
31434
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
31435
|
+
import { homedir as homedir25 } from "node:os";
|
|
31436
|
+
import { join as join39 } from "node:path";
|
|
30460
31437
|
async function bootstrapAgent(opts = {}) {
|
|
30461
31438
|
await ensureDirectories();
|
|
30462
31439
|
const config = await loadConfig();
|
|
31440
|
+
const { configureWam: configureWam2 } = await Promise.resolve().then(() => (init_wam_token_provider(), wam_token_provider_exports));
|
|
31441
|
+
const authMode = config.microsoft?.auth_mode ?? "auto";
|
|
31442
|
+
configureWam2({
|
|
31443
|
+
enabled: authMode !== "cdp",
|
|
31444
|
+
...config.microsoft?.client_id ? { clientId: config.microsoft.client_id } : {},
|
|
31445
|
+
...config.microsoft?.tenant_id ? { tenant: config.microsoft.tenant_id } : {}
|
|
31446
|
+
});
|
|
30463
31447
|
const toolRegistry = new ToolRegistry(config);
|
|
30464
31448
|
const memoryStore = new MemoryStore(config);
|
|
30465
31449
|
await toolRegistry.initializeProfile("core");
|
|
@@ -30467,9 +31451,10 @@ async function bootstrapAgent(opts = {}) {
|
|
|
30467
31451
|
const { createMetaTool: createMetaTool2 } = await Promise.resolve().then(() => (init_meta(), meta_exports));
|
|
30468
31452
|
toolRegistry.registerTool(createMetaTool2(toolRegistry));
|
|
30469
31453
|
const agentConfig = loadAgentConfig();
|
|
31454
|
+
const interactiveMcp = opts.interactiveMcp !== false;
|
|
30470
31455
|
const mcpManager = new MCPClientManager();
|
|
30471
31456
|
try {
|
|
30472
|
-
await mcpManager.prepare(process.cwd(),
|
|
31457
|
+
await mcpManager.prepare(process.cwd(), interactiveMcp);
|
|
30473
31458
|
} catch (err) {
|
|
30474
31459
|
process.stderr.write(
|
|
30475
31460
|
`\x1B[33m\u26A0 MCP discovery failed: ${err instanceof Error ? err.message : String(err)}\x1B[0m
|
|
@@ -30486,12 +31471,12 @@ async function bootstrapAgent(opts = {}) {
|
|
|
30486
31471
|
});
|
|
30487
31472
|
const agentLoop = new AgentLoop(agentConfig, toolRegistry, opts.resumeSessionId);
|
|
30488
31473
|
toolRegistry.setWebSearchExecutor(createWebSearchExecutor(agentLoop));
|
|
30489
|
-
const memoryDbPath =
|
|
31474
|
+
const memoryDbPath = join39(homedir25(), ".openjaw", "memory.db");
|
|
30490
31475
|
const memoryLegacyPaths = [
|
|
30491
|
-
|
|
30492
|
-
|
|
31476
|
+
join39(homedir25(), ".openjaw", "MEMORY.md"),
|
|
31477
|
+
join39(homedir25(), ".openjaw", "memory", "MEMORY.md")
|
|
30493
31478
|
];
|
|
30494
|
-
const memoryStatus =
|
|
31479
|
+
const memoryStatus = existsSync32(memoryDbPath) ? "loaded" : memoryLegacyPaths.some((p) => existsSync32(p)) ? "legacy" : "empty";
|
|
30495
31480
|
const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt({ mcpManager }), "systemPromptFn");
|
|
30496
31481
|
const { createSkillTool: createSkillTool2 } = await Promise.resolve().then(() => (init_skill_tool(), skill_tool_exports));
|
|
30497
31482
|
toolRegistry.registerTool(createSkillTool2(agentConfig, toolRegistry, systemPromptFn));
|
|
@@ -30724,8 +31709,8 @@ function createPromptCollector(bus, getSessionId) {
|
|
|
30724
31709
|
}, "emit");
|
|
30725
31710
|
const register = /* @__PURE__ */ __name((kind) => {
|
|
30726
31711
|
const requestId = randomUUID12();
|
|
30727
|
-
const promise = new Promise((
|
|
30728
|
-
pending.set(requestId, { kind, resolve:
|
|
31712
|
+
const promise = new Promise((resolve7) => {
|
|
31713
|
+
pending.set(requestId, { kind, resolve: resolve7 });
|
|
30729
31714
|
});
|
|
30730
31715
|
return { promise, requestId };
|
|
30731
31716
|
}, "register");
|
|
@@ -31283,7 +32268,7 @@ import { c as _c } from "react/compiler-runtime";
|
|
|
31283
32268
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
31284
32269
|
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
31285
32270
|
import { Buffer as Buffer2 } from "buffer";
|
|
31286
|
-
import { spawn as
|
|
32271
|
+
import { spawn as spawn6 } from "child_process";
|
|
31287
32272
|
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
31288
32273
|
import { ansiCodesToString, reduceAnsiCodes, tokenize as tokenize2, undoAnsiCodes } from "@alcalzone/ansi-tokenize";
|
|
31289
32274
|
import emojiRegex from "emoji-regex";
|
|
@@ -31353,7 +32338,7 @@ import { Buffer as Buffer3 } from "buffer";
|
|
|
31353
32338
|
import { createContext as createContext7, useEffect as useEffect4, useState as useState22 } from "react";
|
|
31354
32339
|
import { c as _c10 } from "react/compiler-runtime";
|
|
31355
32340
|
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
31356
|
-
import { readFileSync as
|
|
32341
|
+
import { readFileSync as readFileSync28 } from "fs";
|
|
31357
32342
|
import codeExcerpt from "code-excerpt";
|
|
31358
32343
|
import StackUtils from "stack-utils";
|
|
31359
32344
|
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
@@ -31361,7 +32346,7 @@ import { jsx as jsx14 } from "react/jsx-runtime";
|
|
|
31361
32346
|
import { ansiCodesToString as ansiCodesToString3, diffAnsiCodes as diffAnsiCodes2 } from "@alcalzone/ansi-tokenize";
|
|
31362
32347
|
import { styledCharsFromTokens, tokenize as tokenize3 } from "@alcalzone/ansi-tokenize";
|
|
31363
32348
|
import bidiFactory from "bidi-js";
|
|
31364
|
-
import
|
|
32349
|
+
import noop3 from "lodash-es/noop.js";
|
|
31365
32350
|
import { LegacyRoot } from "react-reconciler/constants.js";
|
|
31366
32351
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
31367
32352
|
import { default as default2, UncontrolledTextInput } from "ink-text-input";
|
|
@@ -31709,8 +32694,8 @@ function supportsOsc52Clipboard(terminal2 = env.terminal) {
|
|
|
31709
32694
|
return OSC52_CAPABLE_TERMINALS.includes(terminal2 ?? "");
|
|
31710
32695
|
}
|
|
31711
32696
|
function execFileNoThrow(file2, args, options = {}) {
|
|
31712
|
-
return new Promise((
|
|
31713
|
-
const child =
|
|
32697
|
+
return new Promise((resolve7) => {
|
|
32698
|
+
const child = spawn6(file2, args, {
|
|
31714
32699
|
cwd: options.useCwd ? process.cwd() : void 0,
|
|
31715
32700
|
env: options.env,
|
|
31716
32701
|
stdio: "pipe"
|
|
@@ -31732,13 +32717,13 @@ function execFileNoThrow(file2, args, options = {}) {
|
|
|
31732
32717
|
if (timer) {
|
|
31733
32718
|
clearTimeout(timer);
|
|
31734
32719
|
}
|
|
31735
|
-
|
|
32720
|
+
resolve7({ stdout, stderr, code: 1, error: String(error) });
|
|
31736
32721
|
});
|
|
31737
32722
|
child.on("close", (code) => {
|
|
31738
32723
|
if (timer) {
|
|
31739
32724
|
clearTimeout(timer);
|
|
31740
32725
|
}
|
|
31741
|
-
|
|
32726
|
+
resolve7({ stdout, stderr, code: timedOut ? 124 : code ?? 0 });
|
|
31742
32727
|
});
|
|
31743
32728
|
if (options.input) {
|
|
31744
32729
|
child.stdin?.write(options.input);
|
|
@@ -32950,11 +33935,11 @@ function sliceAnsi(str, start, end) {
|
|
|
32950
33935
|
}
|
|
32951
33936
|
if (end !== void 0) {
|
|
32952
33937
|
const key = `${start}|${end}|${str}`;
|
|
32953
|
-
const
|
|
32954
|
-
if (
|
|
33938
|
+
const cached8 = sliceCache.get(key);
|
|
33939
|
+
if (cached8 !== void 0) {
|
|
32955
33940
|
sliceCache.delete(key);
|
|
32956
|
-
sliceCache.set(key,
|
|
32957
|
-
return
|
|
33941
|
+
sliceCache.set(key, cached8);
|
|
33942
|
+
return cached8;
|
|
32958
33943
|
}
|
|
32959
33944
|
const result = computeSlice(str, start, end);
|
|
32960
33945
|
if (sliceCache.size >= SLICE_CACHE_LIMIT) {
|
|
@@ -33009,11 +33994,11 @@ function computeSlice(str, start, end) {
|
|
|
33009
33994
|
return result;
|
|
33010
33995
|
}
|
|
33011
33996
|
function lineWidth(line) {
|
|
33012
|
-
const
|
|
33013
|
-
if (
|
|
33997
|
+
const cached8 = cache.get(line);
|
|
33998
|
+
if (cached8 !== void 0) {
|
|
33014
33999
|
cache.delete(line);
|
|
33015
|
-
cache.set(line,
|
|
33016
|
-
return
|
|
34000
|
+
cache.set(line, cached8);
|
|
34001
|
+
return cached8;
|
|
33017
34002
|
}
|
|
33018
34003
|
const width = stringWidth(line);
|
|
33019
34004
|
if (cache.size >= MAX_CACHE_SIZE) {
|
|
@@ -33030,11 +34015,11 @@ function evictLineWidthCache(keepRatio = 0) {
|
|
|
33030
34015
|
}
|
|
33031
34016
|
function memoizedWrap(text, maxWidth, wrapType) {
|
|
33032
34017
|
const key = `${maxWidth}|${wrapType}|${text}`;
|
|
33033
|
-
const
|
|
33034
|
-
if (
|
|
34018
|
+
const cached8 = wrapCache.get(key);
|
|
34019
|
+
if (cached8 !== void 0) {
|
|
33035
34020
|
wrapCache.delete(key);
|
|
33036
|
-
wrapCache.set(key,
|
|
33037
|
-
return
|
|
34021
|
+
wrapCache.set(key, cached8);
|
|
34022
|
+
return cached8;
|
|
33038
34023
|
}
|
|
33039
34024
|
const result = computeWrap(text, maxWidth, wrapType);
|
|
33040
34025
|
if (wrapCache.size >= WRAP_CACHE_LIMIT) {
|
|
@@ -34994,9 +35979,9 @@ function collectRemovedRects(parent, removed, underAbsolute = false) {
|
|
|
34994
35979
|
}
|
|
34995
35980
|
const elem = removed;
|
|
34996
35981
|
const isAbsolute2 = underAbsolute || elem.style.position === "absolute";
|
|
34997
|
-
const
|
|
34998
|
-
if (
|
|
34999
|
-
addPendingClear(parent,
|
|
35982
|
+
const cached8 = nodeCache.get(elem);
|
|
35983
|
+
if (cached8) {
|
|
35984
|
+
addPendingClear(parent, cached8, isAbsolute2);
|
|
35000
35985
|
nodeCache.delete(elem);
|
|
35001
35986
|
}
|
|
35002
35987
|
for (const child of elem.childNodes) {
|
|
@@ -36711,8 +37696,8 @@ function setTerminalFocused(v) {
|
|
|
36711
37696
|
cb();
|
|
36712
37697
|
}
|
|
36713
37698
|
if (!v) {
|
|
36714
|
-
for (const
|
|
36715
|
-
|
|
37699
|
+
for (const resolve7 of resolvers) {
|
|
37700
|
+
resolve7();
|
|
36716
37701
|
}
|
|
36717
37702
|
resolvers.clear();
|
|
36718
37703
|
}
|
|
@@ -37116,31 +38101,31 @@ function renderNodeToOutput(node, output, {
|
|
|
37116
38101
|
if (y < 0 && node.style.position === "absolute") {
|
|
37117
38102
|
y = 0;
|
|
37118
38103
|
}
|
|
37119
|
-
const
|
|
37120
|
-
if (!node.dirty && !skipSelfBlit && node.pendingScrollDelta === void 0 &&
|
|
38104
|
+
const cached8 = nodeCache.get(node);
|
|
38105
|
+
if (!node.dirty && !skipSelfBlit && node.pendingScrollDelta === void 0 && cached8 && cached8.x === x && cached8.y === y && cached8.width === width && cached8.height === height && prevScreen) {
|
|
37121
38106
|
const fx = Math.floor(x);
|
|
37122
38107
|
const fy = Math.floor(y);
|
|
37123
38108
|
const fw = Math.floor(width);
|
|
37124
38109
|
const fh = Math.floor(height);
|
|
37125
38110
|
output.blit(prevScreen, fx, fy, fw, fh);
|
|
37126
38111
|
if (node.style.position === "absolute") {
|
|
37127
|
-
absoluteRectsCur.push(
|
|
38112
|
+
absoluteRectsCur.push(cached8);
|
|
37128
38113
|
}
|
|
37129
38114
|
blitEscapingAbsoluteDescendants(node, output, prevScreen, fx, fy, fw, fh);
|
|
37130
38115
|
return;
|
|
37131
38116
|
}
|
|
37132
|
-
const positionChanged =
|
|
38117
|
+
const positionChanged = cached8 !== void 0 && (cached8.x !== x || cached8.y !== y || cached8.width !== width || cached8.height !== height);
|
|
37133
38118
|
if (positionChanged) {
|
|
37134
38119
|
layoutShifted = true;
|
|
37135
38120
|
absoluteOverlayMoved ||= node.style.position === "absolute";
|
|
37136
38121
|
}
|
|
37137
|
-
if (
|
|
38122
|
+
if (cached8 && (node.dirty || positionChanged)) {
|
|
37138
38123
|
output.clear(
|
|
37139
38124
|
{
|
|
37140
|
-
x: Math.floor(
|
|
37141
|
-
y: Math.floor(
|
|
37142
|
-
width: Math.floor(
|
|
37143
|
-
height: Math.floor(
|
|
38125
|
+
x: Math.floor(cached8.x),
|
|
38126
|
+
y: Math.floor(cached8.y),
|
|
38127
|
+
width: Math.floor(cached8.width),
|
|
38128
|
+
height: Math.floor(cached8.height)
|
|
37144
38129
|
},
|
|
37145
38130
|
node.style.position === "absolute"
|
|
37146
38131
|
);
|
|
@@ -37315,7 +38300,7 @@ function renderNodeToOutput(node, output, {
|
|
|
37315
38300
|
const delta = contentCached.y - contentY;
|
|
37316
38301
|
const regionTop = Math.floor(y + contentYoga.getComputedTop());
|
|
37317
38302
|
const regionBottom = regionTop + innerHeight - 1;
|
|
37318
|
-
if (
|
|
38303
|
+
if (cached8?.y === y && cached8.height === height && innerHeight > 0 && Math.abs(delta) < innerHeight) {
|
|
37319
38304
|
hint = { top: regionTop, bottom: regionBottom, delta };
|
|
37320
38305
|
scrollHint = hint;
|
|
37321
38306
|
} else {
|
|
@@ -37615,13 +38600,13 @@ function blitEscapingAbsoluteDescendants(node, output, prevScreen, px, py, pw, p
|
|
|
37615
38600
|
}
|
|
37616
38601
|
const elem = child;
|
|
37617
38602
|
if (elem.style.position === "absolute") {
|
|
37618
|
-
const
|
|
37619
|
-
if (
|
|
37620
|
-
absoluteRectsCur.push(
|
|
37621
|
-
const cx = Math.floor(
|
|
37622
|
-
const cy = Math.floor(
|
|
37623
|
-
const cw = Math.floor(
|
|
37624
|
-
const ch = Math.floor(
|
|
38603
|
+
const cached8 = nodeCache.get(elem);
|
|
38604
|
+
if (cached8) {
|
|
38605
|
+
absoluteRectsCur.push(cached8);
|
|
38606
|
+
const cx = Math.floor(cached8.x);
|
|
38607
|
+
const cy = Math.floor(cached8.y);
|
|
38608
|
+
const cw = Math.floor(cached8.width);
|
|
38609
|
+
const ch = Math.floor(cached8.height);
|
|
37625
38610
|
if (cx < px || cy < py || cx + cw > pr || cy + ch > pb) {
|
|
37626
38611
|
output.blit(prevScreen, cx, cy, cw, ch);
|
|
37627
38612
|
}
|
|
@@ -37637,20 +38622,20 @@ function renderScrolledChildren(node, output, offsetX, offsetY, hasRemovedChild,
|
|
|
37637
38622
|
const childElem = childNode;
|
|
37638
38623
|
const cy = childElem.yogaNode;
|
|
37639
38624
|
if (cy) {
|
|
37640
|
-
const
|
|
38625
|
+
const cached8 = nodeCache.get(childElem);
|
|
37641
38626
|
let top;
|
|
37642
38627
|
let height;
|
|
37643
|
-
if (
|
|
37644
|
-
top =
|
|
37645
|
-
height =
|
|
38628
|
+
if (cached8?.top !== void 0 && !childElem.dirty && cumHeightShift === 0) {
|
|
38629
|
+
top = cached8.top;
|
|
38630
|
+
height = cached8.height;
|
|
37646
38631
|
} else {
|
|
37647
38632
|
top = cy.getComputedTop();
|
|
37648
38633
|
height = cy.getComputedHeight();
|
|
37649
38634
|
if (childElem.dirty) {
|
|
37650
|
-
cumHeightShift += height - (
|
|
38635
|
+
cumHeightShift += height - (cached8 ? cached8.height : 0);
|
|
37651
38636
|
}
|
|
37652
|
-
if (
|
|
37653
|
-
|
|
38637
|
+
if (cached8) {
|
|
38638
|
+
cached8.top = top;
|
|
37654
38639
|
}
|
|
37655
38640
|
}
|
|
37656
38641
|
const bottom = top + height;
|
|
@@ -38336,7 +39321,7 @@ function ErrorOverview({ error }) {
|
|
|
38336
39321
|
let lineWidth2 = 0;
|
|
38337
39322
|
if (filePath && origin?.line) {
|
|
38338
39323
|
try {
|
|
38339
|
-
const sourceCode =
|
|
39324
|
+
const sourceCode = readFileSync28(filePath, "utf8");
|
|
38340
39325
|
excerpt = codeExcerpt(sourceCode, origin.line);
|
|
38341
39326
|
if (excerpt) {
|
|
38342
39327
|
for (const { line } of excerpt) {
|
|
@@ -40060,11 +41045,11 @@ var init_entry_exports = __esm({
|
|
|
40060
41045
|
return rawStringWidth(str);
|
|
40061
41046
|
}
|
|
40062
41047
|
}
|
|
40063
|
-
const
|
|
40064
|
-
if (
|
|
41048
|
+
const cached8 = widthCache.get(str);
|
|
41049
|
+
if (cached8 !== void 0) {
|
|
40065
41050
|
widthCache.delete(str);
|
|
40066
|
-
widthCache.set(str,
|
|
40067
|
-
return
|
|
41051
|
+
widthCache.set(str, cached8);
|
|
41052
|
+
return cached8;
|
|
40068
41053
|
}
|
|
40069
41054
|
const w = rawStringWidth(str);
|
|
40070
41055
|
if (widthCache.size >= WIDTH_CACHE_LIMIT) {
|
|
@@ -42169,9 +43154,9 @@ $ npm install --save-dev react-devtools-core
|
|
|
42169
43154
|
if (char.length === 1) {
|
|
42170
43155
|
const code = char.charCodeAt(0);
|
|
42171
43156
|
if (code < 128) {
|
|
42172
|
-
const
|
|
42173
|
-
if (
|
|
42174
|
-
return
|
|
43157
|
+
const cached8 = this.ascii[code];
|
|
43158
|
+
if (cached8 !== -1) {
|
|
43159
|
+
return cached8;
|
|
42175
43160
|
}
|
|
42176
43161
|
const index2 = this.strings.length;
|
|
42177
43162
|
this.strings.push(char);
|
|
@@ -42950,11 +43935,11 @@ $ npm install --save-dev react-devtools-core
|
|
|
42950
43935
|
* and the terminal doesn't respond, the promise remains pending.
|
|
42951
43936
|
*/
|
|
42952
43937
|
send(query) {
|
|
42953
|
-
return new Promise((
|
|
43938
|
+
return new Promise((resolve7) => {
|
|
42954
43939
|
this.queue.push({
|
|
42955
43940
|
kind: "query",
|
|
42956
43941
|
match: query.match,
|
|
42957
|
-
resolve: /* @__PURE__ */ __name((r) =>
|
|
43942
|
+
resolve: /* @__PURE__ */ __name((r) => resolve7(r), "resolve")
|
|
42958
43943
|
});
|
|
42959
43944
|
this.stdout.write(query.request);
|
|
42960
43945
|
});
|
|
@@ -42969,8 +43954,8 @@ $ npm install --save-dev react-devtools-core
|
|
|
42969
43954
|
* Safe to call with no pending queries — still waits for a round-trip.
|
|
42970
43955
|
*/
|
|
42971
43956
|
flush() {
|
|
42972
|
-
return new Promise((
|
|
42973
|
-
this.queue.push({ kind: "sentinel", resolve:
|
|
43957
|
+
return new Promise((resolve7) => {
|
|
43958
|
+
this.queue.push({ kind: "sentinel", resolve: resolve7 });
|
|
42974
43959
|
this.stdout.write(SENTINEL);
|
|
42975
43960
|
});
|
|
42976
43961
|
}
|
|
@@ -45450,8 +46435,8 @@ $ npm install --save-dev react-devtools-core
|
|
|
45450
46435
|
}
|
|
45451
46436
|
}
|
|
45452
46437
|
async waitUntilExit() {
|
|
45453
|
-
this.exitPromise ||= new Promise((
|
|
45454
|
-
this.resolveExitPromise =
|
|
46438
|
+
this.exitPromise ||= new Promise((resolve7, reject) => {
|
|
46439
|
+
this.resolveExitPromise = resolve7;
|
|
45455
46440
|
this.rejectExitPromise = reject;
|
|
45456
46441
|
});
|
|
45457
46442
|
return this.exitPromise;
|
|
@@ -45865,7 +46850,7 @@ var init_details = __esm({
|
|
|
45865
46850
|
});
|
|
45866
46851
|
|
|
45867
46852
|
// src/lib/clipboard.ts
|
|
45868
|
-
import { execFile, spawn as
|
|
46853
|
+
import { execFile, spawn as spawn7 } from "node:child_process";
|
|
45869
46854
|
import { promisify as promisify6 } from "node:util";
|
|
45870
46855
|
function isUsableClipboardText(text) {
|
|
45871
46856
|
if (!text || !/[^\s]/.test(text)) {
|
|
@@ -45938,14 +46923,14 @@ function writeClipboardCommands(platform2, env2) {
|
|
|
45938
46923
|
attempts.push({ cmd: "xsel", args: ["--clipboard", "--input"] });
|
|
45939
46924
|
return attempts;
|
|
45940
46925
|
}
|
|
45941
|
-
async function writeClipboardText(text, platform2 = process.platform, start =
|
|
46926
|
+
async function writeClipboardText(text, platform2 = process.platform, start = spawn7, env2 = process.env) {
|
|
45942
46927
|
const candidates = writeClipboardCommands(platform2, env2);
|
|
45943
46928
|
for (const { cmd, args } of candidates) {
|
|
45944
46929
|
try {
|
|
45945
|
-
const ok = await new Promise((
|
|
46930
|
+
const ok = await new Promise((resolve7) => {
|
|
45946
46931
|
const child = start(cmd, [...args], { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
|
|
45947
|
-
child.once("error", () =>
|
|
45948
|
-
child.once("close", (code) =>
|
|
46932
|
+
child.once("error", () => resolve7(false));
|
|
46933
|
+
child.once("close", (code) => resolve7(code === 0));
|
|
45949
46934
|
child.stdin?.end(text);
|
|
45950
46935
|
});
|
|
45951
46936
|
if (ok) {
|
|
@@ -46004,8 +46989,8 @@ async function readOsc52Clipboard(querier, timeoutMs = 500) {
|
|
|
46004
46989
|
if (!querier) {
|
|
46005
46990
|
return null;
|
|
46006
46991
|
}
|
|
46007
|
-
const timeout = new Promise((
|
|
46008
|
-
setTimeout(() =>
|
|
46992
|
+
const timeout = new Promise((resolve7) => {
|
|
46993
|
+
setTimeout(() => resolve7(void 0), timeoutMs);
|
|
46009
46994
|
});
|
|
46010
46995
|
const query = querier.send({
|
|
46011
46996
|
request: buildOsc52ClipboardQuery(),
|
|
@@ -46035,8 +47020,8 @@ var init_osc52 = __esm({
|
|
|
46035
47020
|
|
|
46036
47021
|
// src/lib/terminalSetup.ts
|
|
46037
47022
|
import { copyFile, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
|
|
46038
|
-
import { homedir as
|
|
46039
|
-
import { join as
|
|
47023
|
+
import { homedir as homedir26 } from "node:os";
|
|
47024
|
+
import { join as join40 } from "node:path";
|
|
46040
47025
|
function detectVSCodeLikeTerminal(env2 = process.env) {
|
|
46041
47026
|
const askpass = env2["VSCODE_GIT_ASKPASS_MAIN"]?.toLowerCase() ?? "";
|
|
46042
47027
|
if (env2["CURSOR_TRACE_ID"] || askpass.includes("cursor")) {
|
|
@@ -46090,14 +47075,14 @@ function stripJsonComments(content) {
|
|
|
46090
47075
|
function isRemoteShellSession(env2) {
|
|
46091
47076
|
return Boolean(env2["SSH_CONNECTION"] || env2["SSH_TTY"] || env2["SSH_CLIENT"]);
|
|
46092
47077
|
}
|
|
46093
|
-
function getVSCodeStyleConfigDir(appName, platform2 = process.platform, env2 = process.env, homeDir =
|
|
47078
|
+
function getVSCodeStyleConfigDir(appName, platform2 = process.platform, env2 = process.env, homeDir = homedir26()) {
|
|
46094
47079
|
if (platform2 === "darwin") {
|
|
46095
|
-
return
|
|
47080
|
+
return join40(homeDir, "Library", "Application Support", appName, "User");
|
|
46096
47081
|
}
|
|
46097
47082
|
if (platform2 === "win32") {
|
|
46098
|
-
return env2["APPDATA"] ?
|
|
47083
|
+
return env2["APPDATA"] ? join40(env2["APPDATA"], appName, "User") : null;
|
|
46099
47084
|
}
|
|
46100
|
-
return
|
|
47085
|
+
return join40(homeDir, ".config", appName, "User");
|
|
46101
47086
|
}
|
|
46102
47087
|
function isKeybinding(value) {
|
|
46103
47088
|
return typeof value === "object" && value !== null;
|
|
@@ -46165,7 +47150,7 @@ async function backupFile(filePath, ops) {
|
|
|
46165
47150
|
async function configureTerminalKeybindings(terminal2, options) {
|
|
46166
47151
|
const env2 = options?.env ?? process.env;
|
|
46167
47152
|
const platform2 = options?.platform ?? process.platform;
|
|
46168
|
-
const homeDir = options?.homeDir ??
|
|
47153
|
+
const homeDir = options?.homeDir ?? homedir26();
|
|
46169
47154
|
const ops = { ...DEFAULT_FILE_OPS, ...options?.fileOps ?? {} };
|
|
46170
47155
|
const meta = TERMINAL_META[terminal2];
|
|
46171
47156
|
if (isRemoteShellSession(env2)) {
|
|
@@ -46181,7 +47166,7 @@ async function configureTerminalKeybindings(terminal2, options) {
|
|
|
46181
47166
|
message: `Could not determine ${meta.label} settings path on this platform.`
|
|
46182
47167
|
};
|
|
46183
47168
|
}
|
|
46184
|
-
const keybindingsFile =
|
|
47169
|
+
const keybindingsFile = join40(configDir2, "keybindings.json");
|
|
46185
47170
|
try {
|
|
46186
47171
|
await ops.mkdir(configDir2, { recursive: true });
|
|
46187
47172
|
let keybindings = [];
|
|
@@ -46264,7 +47249,7 @@ async function shouldPromptForTerminalSetup(options) {
|
|
|
46264
47249
|
return false;
|
|
46265
47250
|
}
|
|
46266
47251
|
const platform2 = options?.platform ?? process.platform;
|
|
46267
|
-
const homeDir = options?.homeDir ??
|
|
47252
|
+
const homeDir = options?.homeDir ?? homedir26();
|
|
46268
47253
|
const ops = { ...DEFAULT_FILE_OPS, ...options?.fileOps ?? {} };
|
|
46269
47254
|
const meta = TERMINAL_META[detected];
|
|
46270
47255
|
const configDir2 = getVSCodeStyleConfigDir(meta.appName, platform2, env2, homeDir);
|
|
@@ -46272,7 +47257,7 @@ async function shouldPromptForTerminalSetup(options) {
|
|
|
46272
47257
|
return false;
|
|
46273
47258
|
}
|
|
46274
47259
|
try {
|
|
46275
|
-
const content = await ops.readFile(
|
|
47260
|
+
const content = await ops.readFile(join40(configDir2, "keybindings.json"), "utf8");
|
|
46276
47261
|
const parsed = JSON.parse(stripJsonComments(content));
|
|
46277
47262
|
if (!Array.isArray(parsed)) {
|
|
46278
47263
|
return true;
|
|
@@ -46378,7 +47363,7 @@ var init_overlayStore = __esm({
|
|
|
46378
47363
|
$overlayState = atom2(buildOverlayState());
|
|
46379
47364
|
$isBlocked = computed2(
|
|
46380
47365
|
$overlayState,
|
|
46381
|
-
({ agents, approval, clarify, confirm, mcpHub,
|
|
47366
|
+
({ agents, approval, clarify, confirm, mcpHub, pager, picker, secret, skillsHub, sudo }) => Boolean(agents || approval || clarify || confirm || mcpHub || pager || picker || secret || skillsHub || sudo)
|
|
46382
47367
|
);
|
|
46383
47368
|
patchOverlayState = /* @__PURE__ */ __name((next) => $overlayState.set(typeof next === "function" ? next($overlayState.get()) : { ...$overlayState.get(), ...next }), "patchOverlayState");
|
|
46384
47369
|
resetFlowOverlays = /* @__PURE__ */ __name(() => $overlayState.set({
|
|
@@ -47023,8 +48008,8 @@ var init_bridges = __esm({
|
|
|
47023
48008
|
// src/lib/memory.ts
|
|
47024
48009
|
import { createWriteStream } from "node:fs";
|
|
47025
48010
|
import { mkdir as mkdir4, readdir as readdir3, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
47026
|
-
import { homedir as
|
|
47027
|
-
import { join as
|
|
48011
|
+
import { homedir as homedir27, tmpdir as tmpdir11 } from "node:os";
|
|
48012
|
+
import { join as join41 } from "node:path";
|
|
47028
48013
|
import { pipeline } from "node:stream/promises";
|
|
47029
48014
|
import { getHeapSnapshot, getHeapSpaceStatistics, getHeapStatistics } from "node:v8";
|
|
47030
48015
|
async function captureMemoryDiagnostics(trigger) {
|
|
@@ -47098,11 +48083,11 @@ async function captureMemoryDiagnostics(trigger) {
|
|
|
47098
48083
|
async function performHeapDump(trigger = "manual") {
|
|
47099
48084
|
try {
|
|
47100
48085
|
const diagnostics = await captureMemoryDiagnostics(trigger);
|
|
47101
|
-
const dir2 = process.env.OPENJAW_HEAPDUMP_DIR?.trim() ||
|
|
48086
|
+
const dir2 = process.env.OPENJAW_HEAPDUMP_DIR?.trim() || join41(homedir27() || tmpdir11(), ".openjaw-agent", "heapdumps");
|
|
47102
48087
|
await mkdir4(dir2, { recursive: true });
|
|
47103
48088
|
const base = `hermes-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${process.pid}-${trigger}`;
|
|
47104
|
-
const heapPath =
|
|
47105
|
-
const diagPath =
|
|
48089
|
+
const heapPath = join41(dir2, `${base}.heapsnapshot`);
|
|
48090
|
+
const diagPath = join41(dir2, `${base}.diagnostics.json`);
|
|
47106
48091
|
await writeFile4(diagPath, JSON.stringify(diagnostics, null, 2), { mode: 384 });
|
|
47107
48092
|
await pipeline(getHeapSnapshot(), createWriteStream(heapPath, { mode: 384 }));
|
|
47108
48093
|
return { diagPath, heapPath, success: true };
|
|
@@ -47959,15 +48944,15 @@ var init_ops = __esm({
|
|
|
47959
48944
|
}
|
|
47960
48945
|
const [a, b] = parts;
|
|
47961
48946
|
const history = getSpawnHistory();
|
|
47962
|
-
const
|
|
48947
|
+
const resolve7 = /* @__PURE__ */ __name((token) => {
|
|
47963
48948
|
const n = parseInt(token, 10);
|
|
47964
48949
|
if (Number.isFinite(n) && n >= 1 && n <= history.length) {
|
|
47965
48950
|
return history[n - 1] ?? null;
|
|
47966
48951
|
}
|
|
47967
48952
|
return null;
|
|
47968
48953
|
}, "resolve");
|
|
47969
|
-
const baseline =
|
|
47970
|
-
const candidate =
|
|
48954
|
+
const baseline = resolve7(a);
|
|
48955
|
+
const candidate = resolve7(b);
|
|
47971
48956
|
if (!baseline || !candidate) {
|
|
47972
48957
|
return ctx.transcript.sys(`replay-diff: could not resolve indices \xB7 history has ${history.length} entries`);
|
|
47973
48958
|
}
|
|
@@ -48861,8 +49846,8 @@ var init_setup = __esm({
|
|
|
48861
49846
|
|
|
48862
49847
|
// src/app/slash/catalog.ts
|
|
48863
49848
|
import { readdirSync as readdirSync6 } from "node:fs";
|
|
48864
|
-
import { homedir as
|
|
48865
|
-
import { isAbsolute, join as
|
|
49849
|
+
import { homedir as homedir28 } from "node:os";
|
|
49850
|
+
import { isAbsolute, join as join42, resolve as resolve4, sep } from "node:path";
|
|
48866
49851
|
function buildCommandsCatalog(extras = {}) {
|
|
48867
49852
|
const canon = {};
|
|
48868
49853
|
const pairs = [];
|
|
@@ -48964,7 +49949,7 @@ function buildPathCompletions(word) {
|
|
|
48964
49949
|
prefix = expanded.slice(lastSep + 1);
|
|
48965
49950
|
}
|
|
48966
49951
|
}
|
|
48967
|
-
const resolved = isAbsolute(dir2) ? dir2 :
|
|
49952
|
+
const resolved = isAbsolute(dir2) ? dir2 : resolve4(process.cwd(), dir2);
|
|
48968
49953
|
const entries = readdirSync6(resolved, { withFileTypes: true });
|
|
48969
49954
|
const items = entries.filter((e) => e.name.toLowerCase().startsWith(prefix.toLowerCase())).filter((e) => prefix || !e.name.startsWith(".")).slice(0, 50).map((e) => {
|
|
48970
49955
|
const full = dir2 + e.name + (e.isDirectory() ? sep : "");
|
|
@@ -49004,7 +49989,7 @@ var init_catalog = __esm({
|
|
|
49004
49989
|
slashifyPair = /* @__PURE__ */ __name((cmd) => [`/${cmd.name}`, cmd.help ?? ""], "slashifyPair");
|
|
49005
49990
|
__name(buildCommandsCatalog, "buildCommandsCatalog");
|
|
49006
49991
|
__name(buildSlashCompletions, "buildSlashCompletions");
|
|
49007
|
-
tildeExpand = /* @__PURE__ */ __name((p) => p.startsWith("~") ?
|
|
49992
|
+
tildeExpand = /* @__PURE__ */ __name((p) => p.startsWith("~") ? join42(homedir28(), p.slice(1).replace(/^[\\/]/, "")) : p, "tildeExpand");
|
|
49008
49993
|
__name(buildPathCompletions, "buildPathCompletions");
|
|
49009
49994
|
}
|
|
49010
49995
|
});
|
|
@@ -49169,39 +50154,39 @@ var init_planner = __esm({
|
|
|
49169
50154
|
});
|
|
49170
50155
|
|
|
49171
50156
|
// src/workflows/persistence.ts
|
|
49172
|
-
import { existsSync as
|
|
49173
|
-
import { homedir as
|
|
49174
|
-
import { basename as basename3, join as
|
|
50157
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync17, readdirSync as readdirSync7, readFileSync as readFileSync29, writeFileSync as writeFileSync19 } from "node:fs";
|
|
50158
|
+
import { homedir as homedir29 } from "node:os";
|
|
50159
|
+
import { basename as basename3, join as join43, resolve as resolve5 } from "node:path";
|
|
49175
50160
|
function ensureDir(path3) {
|
|
49176
|
-
if (!
|
|
50161
|
+
if (!existsSync33(path3)) mkdirSync17(path3, { recursive: true });
|
|
49177
50162
|
}
|
|
49178
50163
|
function safeSegment(value) {
|
|
49179
50164
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 80) || "default";
|
|
49180
50165
|
}
|
|
49181
50166
|
function readJson(path3) {
|
|
49182
50167
|
try {
|
|
49183
|
-
return JSON.parse(
|
|
50168
|
+
return JSON.parse(readFileSync29(path3, "utf8"));
|
|
49184
50169
|
} catch {
|
|
49185
50170
|
return null;
|
|
49186
50171
|
}
|
|
49187
50172
|
}
|
|
49188
50173
|
function saveWorkflowSnapshot(snapshot) {
|
|
49189
50174
|
ensureDir(workflowDir());
|
|
49190
|
-
const path3 =
|
|
50175
|
+
const path3 = join43(workflowDir(), `${safeSegment(snapshot.id)}.json`);
|
|
49191
50176
|
writeFileSync19(path3, `${JSON.stringify(snapshot, null, 2)}
|
|
49192
50177
|
`, "utf8");
|
|
49193
50178
|
return path3;
|
|
49194
50179
|
}
|
|
49195
50180
|
function loadWorkflowSnapshot(id) {
|
|
49196
|
-
const path3 =
|
|
50181
|
+
const path3 = join43(workflowDir(), `${safeSegment(id)}.json`);
|
|
49197
50182
|
return readJson(path3);
|
|
49198
50183
|
}
|
|
49199
50184
|
function listWorkflowSnapshots(limit = 30) {
|
|
49200
|
-
if (!
|
|
50185
|
+
if (!existsSync33(workflowDir())) return [];
|
|
49201
50186
|
const entries = [];
|
|
49202
50187
|
for (const entry of readdirSync7(workflowDir(), { withFileTypes: true })) {
|
|
49203
50188
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
49204
|
-
const path3 =
|
|
50189
|
+
const path3 = join43(workflowDir(), entry.name);
|
|
49205
50190
|
const snapshot = readJson(path3);
|
|
49206
50191
|
if (!snapshot) continue;
|
|
49207
50192
|
entries.push({
|
|
@@ -49219,10 +50204,10 @@ function listWorkflowSnapshots(limit = 30) {
|
|
|
49219
50204
|
}
|
|
49220
50205
|
function saveSpawnTreeSnapshot(input) {
|
|
49221
50206
|
const sessionId = safeSegment(input.session_id ?? "default");
|
|
49222
|
-
const dir2 =
|
|
50207
|
+
const dir2 = join43(spawnTreeDir(), sessionId);
|
|
49223
50208
|
ensureDir(dir2);
|
|
49224
50209
|
const stamp = new Date((input.finished_at ?? Date.now() / 1e3) * 1e3).toISOString().replace(/[:.]/g, "-");
|
|
49225
|
-
const path3 =
|
|
50210
|
+
const path3 = join43(dir2, `${stamp}-${Math.random().toString(36).slice(2, 8)}.json`);
|
|
49226
50211
|
const snapshot = {
|
|
49227
50212
|
count: input.subagents?.length ?? 0,
|
|
49228
50213
|
finished_at: input.finished_at,
|
|
@@ -49236,12 +50221,12 @@ function saveSpawnTreeSnapshot(input) {
|
|
|
49236
50221
|
return path3;
|
|
49237
50222
|
}
|
|
49238
50223
|
function listSpawnTreeSnapshots(sessionId = "default", limit = 30) {
|
|
49239
|
-
const dir2 =
|
|
49240
|
-
if (!
|
|
50224
|
+
const dir2 = join43(spawnTreeDir(), safeSegment(sessionId));
|
|
50225
|
+
if (!existsSync33(dir2)) return [];
|
|
49241
50226
|
const entries = [];
|
|
49242
50227
|
for (const entry of readdirSync7(dir2, { withFileTypes: true })) {
|
|
49243
50228
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
49244
|
-
const path3 =
|
|
50229
|
+
const path3 = join43(dir2, entry.name);
|
|
49245
50230
|
const snapshot = readJson(path3);
|
|
49246
50231
|
if (!snapshot) continue;
|
|
49247
50232
|
entries.push({
|
|
@@ -49256,8 +50241,8 @@ function listSpawnTreeSnapshots(sessionId = "default", limit = 30) {
|
|
|
49256
50241
|
return entries.sort((a, b) => (b.finished_at ?? 0) - (a.finished_at ?? 0)).slice(0, Math.max(1, limit));
|
|
49257
50242
|
}
|
|
49258
50243
|
function loadSpawnTreeSnapshot(path3) {
|
|
49259
|
-
const root =
|
|
49260
|
-
const resolved =
|
|
50244
|
+
const root = resolve5(spawnTreeDir());
|
|
50245
|
+
const resolved = resolve5(path3);
|
|
49261
50246
|
if (!resolved.startsWith(root)) return null;
|
|
49262
50247
|
const snapshot = readJson(resolved);
|
|
49263
50248
|
return snapshot ? { ...snapshot, path: resolved } : null;
|
|
@@ -49266,9 +50251,9 @@ var rootDir, workflowDir, spawnTreeDir;
|
|
|
49266
50251
|
var init_persistence = __esm({
|
|
49267
50252
|
"src/workflows/persistence.ts"() {
|
|
49268
50253
|
"use strict";
|
|
49269
|
-
rootDir = /* @__PURE__ */ __name(() =>
|
|
49270
|
-
workflowDir = /* @__PURE__ */ __name(() =>
|
|
49271
|
-
spawnTreeDir = /* @__PURE__ */ __name(() =>
|
|
50254
|
+
rootDir = /* @__PURE__ */ __name(() => join43(homedir29(), ".openjaw-agent"), "rootDir");
|
|
50255
|
+
workflowDir = /* @__PURE__ */ __name(() => join43(rootDir(), "workflows"), "workflowDir");
|
|
50256
|
+
spawnTreeDir = /* @__PURE__ */ __name(() => join43(rootDir(), "spawn-trees"), "spawnTreeDir");
|
|
49272
50257
|
__name(ensureDir, "ensureDir");
|
|
49273
50258
|
__name(safeSegment, "safeSegment");
|
|
49274
50259
|
__name(readJson, "readJson");
|
|
@@ -49848,11 +50833,11 @@ ${highlights}` : ""
|
|
|
49848
50833
|
});
|
|
49849
50834
|
|
|
49850
50835
|
// src/rpcHandlers.ts
|
|
49851
|
-
import { spawn as
|
|
50836
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
49852
50837
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
49853
|
-
import { existsSync as
|
|
49854
|
-
import { homedir as
|
|
49855
|
-
import { basename as basename4, extname as extname4, join as
|
|
50838
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync18, readFileSync as readFileSync30, rmSync, statSync as statSync4, writeFileSync as writeFileSync20 } from "node:fs";
|
|
50839
|
+
import { homedir as homedir30 } from "node:os";
|
|
50840
|
+
import { basename as basename4, extname as extname4, join as join44 } from "node:path";
|
|
49856
50841
|
function registerRpcHandlers(options) {
|
|
49857
50842
|
const { agentConfig, agentLoop, bridgeEmitter, bridgeManager, bus, mcpManager, systemPromptFn, toolRegistry, voiceManager } = options;
|
|
49858
50843
|
let currentRun = null;
|
|
@@ -50077,6 +51062,7 @@ ${helpMessage}` : field.label;
|
|
|
50077
51062
|
const modelInfo = agentLoop.getActiveModelMetadata();
|
|
50078
51063
|
const nextEffort = parsed.clear ? void 0 : modelInfo ? resolveReasoningEffortForModel(modelInfo, parsed.effort) : parsed.effort;
|
|
50079
51064
|
agentLoop.updateReasoningEffort(nextEffort);
|
|
51065
|
+
agentConfig.llm.model_reasoning_effort = nextEffort;
|
|
50080
51066
|
bus.emitEvent({
|
|
50081
51067
|
payload: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
50082
51068
|
session_id: agentLoop.sessionId,
|
|
@@ -50166,17 +51152,39 @@ ${helpMessage}` : field.label;
|
|
|
50166
51152
|
return { ok: false };
|
|
50167
51153
|
}
|
|
50168
51154
|
});
|
|
50169
|
-
bus.registerRpc("session.create", () =>
|
|
50170
|
-
|
|
50171
|
-
|
|
50172
|
-
|
|
51155
|
+
bus.registerRpc("session.create", () => {
|
|
51156
|
+
if (agentLoop.turnCount === 0 && agentLoop.history.length === 0) {
|
|
51157
|
+
return {
|
|
51158
|
+
info: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
51159
|
+
session_id: agentLoop.sessionId
|
|
51160
|
+
};
|
|
51161
|
+
}
|
|
51162
|
+
const created = agentLoop.createAndSwitchTo();
|
|
51163
|
+
if (!created) {
|
|
51164
|
+
return {
|
|
51165
|
+
error: "cannot create a new session while a turn is in flight",
|
|
51166
|
+
session_id: agentLoop.sessionId
|
|
51167
|
+
};
|
|
51168
|
+
}
|
|
51169
|
+
bus.emitEvent({
|
|
51170
|
+
payload: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
51171
|
+
session_id: agentLoop.sessionId,
|
|
51172
|
+
type: "session.info"
|
|
51173
|
+
});
|
|
51174
|
+
return {
|
|
51175
|
+
info: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
51176
|
+
session_id: agentLoop.sessionId
|
|
51177
|
+
};
|
|
51178
|
+
});
|
|
50173
51179
|
bus.registerRpc("session.resume", (params) => {
|
|
50174
51180
|
const id = String(params.session_id ?? agentLoop.sessionId);
|
|
50175
|
-
const
|
|
51181
|
+
const swapped = agentLoop.swapToSession(id);
|
|
51182
|
+
const data = swapped ?? loadSession(id);
|
|
51183
|
+
const visibleMessages = (data?.messages ?? []).filter((m) => !messageIsInternalSelfPrompt(m));
|
|
50176
51184
|
return {
|
|
50177
51185
|
info: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
50178
|
-
message_count:
|
|
50179
|
-
messages:
|
|
51186
|
+
message_count: visibleMessages.length,
|
|
51187
|
+
messages: visibleMessages.map((m) => {
|
|
50180
51188
|
if (m.role === "tool_result") {
|
|
50181
51189
|
return {
|
|
50182
51190
|
role: "tool",
|
|
@@ -50184,13 +51192,14 @@ ${helpMessage}` : field.label;
|
|
|
50184
51192
|
};
|
|
50185
51193
|
}
|
|
50186
51194
|
const content = m.content;
|
|
51195
|
+
const raw = typeof content === "string" ? content : Array.isArray(content) ? content.map((c) => c.type === "text" ? c.text : "[image]").join("") : "";
|
|
50187
51196
|
return {
|
|
50188
51197
|
role: m.role,
|
|
50189
|
-
text:
|
|
51198
|
+
text: stripDisplayPrefix(raw, m.role)
|
|
50190
51199
|
};
|
|
50191
51200
|
}),
|
|
50192
|
-
resumed:
|
|
50193
|
-
session_id:
|
|
51201
|
+
resumed: swapped ? id : void 0,
|
|
51202
|
+
session_id: agentLoop.sessionId
|
|
50194
51203
|
};
|
|
50195
51204
|
});
|
|
50196
51205
|
bus.registerRpc("session.list", () => ({
|
|
@@ -50200,6 +51209,10 @@ ${helpMessage}` : field.label;
|
|
|
50200
51209
|
preview: s.summary,
|
|
50201
51210
|
source: `${s.provider}/${s.model}`,
|
|
50202
51211
|
started_at: Date.parse(s.createdAt) || Date.now(),
|
|
51212
|
+
// updated_at drives the sidebar's "last activity" date grouping.
|
|
51213
|
+
// listSessions already sorts by updatedAt desc, so emitting it
|
|
51214
|
+
// here saves the renderer a second parse.
|
|
51215
|
+
updated_at: Date.parse(s.updatedAt) || Date.now(),
|
|
50203
51216
|
title: s.summary || s.id
|
|
50204
51217
|
}))
|
|
50205
51218
|
}));
|
|
@@ -50234,12 +51247,12 @@ ${helpMessage}` : field.label;
|
|
|
50234
51247
|
const id = String(params.session_id ?? agentLoop.sessionId) || agentLoop.sessionId;
|
|
50235
51248
|
const data = loadSession(id);
|
|
50236
51249
|
const messages = data?.messages ?? agentLoop.history;
|
|
50237
|
-
const exportDir =
|
|
50238
|
-
if (!
|
|
51250
|
+
const exportDir = join44(homedir30(), ".openjaw-agent", "exports");
|
|
51251
|
+
if (!existsSync34(exportDir)) {
|
|
50239
51252
|
mkdirSync18(exportDir, { recursive: true });
|
|
50240
51253
|
}
|
|
50241
51254
|
const safeId = id.replace(/[^a-zA-Z0-9_.-]/g, "_") || agentLoop.sessionId;
|
|
50242
|
-
const file2 =
|
|
51255
|
+
const file2 = join44(exportDir, `session-${safeId}.md`);
|
|
50243
51256
|
const lines = [
|
|
50244
51257
|
`# OpenJaw Agent Session ${id}`,
|
|
50245
51258
|
`Date: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -50269,8 +51282,8 @@ ${helpMessage}` : field.label;
|
|
|
50269
51282
|
return { deleted: "" };
|
|
50270
51283
|
}
|
|
50271
51284
|
try {
|
|
50272
|
-
const file2 =
|
|
50273
|
-
if (
|
|
51285
|
+
const file2 = join44(homedir30(), ".openjaw-agent", "sessions", `${id}.json`);
|
|
51286
|
+
if (existsSync34(file2)) {
|
|
50274
51287
|
rmSync(file2);
|
|
50275
51288
|
}
|
|
50276
51289
|
return { deleted: id };
|
|
@@ -50343,11 +51356,11 @@ ${helpMessage}` : field.label;
|
|
|
50343
51356
|
bus.registerRpc("shell.exec", async (params) => {
|
|
50344
51357
|
const command = String(params.command ?? "");
|
|
50345
51358
|
if (!command) return { code: -1, stderr: "empty command" };
|
|
50346
|
-
return await new Promise((
|
|
51359
|
+
return await new Promise((resolve7) => {
|
|
50347
51360
|
const isWin = process.platform === "win32";
|
|
50348
51361
|
const shell = isWin ? "powershell.exe" : "sh";
|
|
50349
51362
|
const args = isWin ? ["-NoProfile", "-Command", command] : ["-c", command];
|
|
50350
|
-
const child =
|
|
51363
|
+
const child = spawn8(shell, args, { timeout: 3e4 });
|
|
50351
51364
|
let stdout = "";
|
|
50352
51365
|
let stderr = "";
|
|
50353
51366
|
let truncated = false;
|
|
@@ -50370,10 +51383,10 @@ ${helpMessage}` : field.label;
|
|
|
50370
51383
|
if (truncated) {
|
|
50371
51384
|
stderr += "\n[output truncated to 1MB]";
|
|
50372
51385
|
}
|
|
50373
|
-
|
|
51386
|
+
resolve7({ code: code ?? -1, stderr, stdout });
|
|
50374
51387
|
});
|
|
50375
51388
|
child.on("error", (err) => {
|
|
50376
|
-
|
|
51389
|
+
resolve7({ code: -1, stderr: err.message });
|
|
50377
51390
|
});
|
|
50378
51391
|
});
|
|
50379
51392
|
});
|
|
@@ -50404,6 +51417,11 @@ ${helpMessage}` : field.label;
|
|
|
50404
51417
|
const modelInfo = agentLoop.getModelMetadata(provider, model);
|
|
50405
51418
|
const reasoningEffort = parsedEffort?.clear ? void 0 : parsedEffort?.effort ? modelInfo ? resolveReasoningEffortForModel(modelInfo, parsedEffort.effort) : parsedEffort.effort : modelInfo ? resolveReasoningEffortForModel(modelInfo, agentLoop.reasoningEffort) : agentLoop.reasoningEffort;
|
|
50406
51419
|
agentLoop.switchModel(provider, model, reasoningEffort);
|
|
51420
|
+
bus.emitEvent({
|
|
51421
|
+
payload: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
51422
|
+
session_id: agentLoop.sessionId,
|
|
51423
|
+
type: "session.info"
|
|
51424
|
+
});
|
|
50407
51425
|
return {
|
|
50408
51426
|
info: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
50409
51427
|
ok: true
|
|
@@ -50481,8 +51499,8 @@ ${helpMessage}` : field.label;
|
|
|
50481
51499
|
if (auth.auth_type !== "oauth") {
|
|
50482
51500
|
throw new Error(`${PROVIDER_LABELS[slug]} does not use OAuth (auth_type=${auth.auth_type})`);
|
|
50483
51501
|
}
|
|
50484
|
-
const
|
|
50485
|
-
if (!
|
|
51502
|
+
const clientId2 = resolveCopilotClientId();
|
|
51503
|
+
if (!clientId2) {
|
|
50486
51504
|
throw new Error(
|
|
50487
51505
|
"GitHub Copilot login needs a GitHub OAuth App client ID. Set GITHUB_COPILOT_CLIENT_ID or llm.copilot_oauth_client_id in ~/.openjaw-agent/config.yaml."
|
|
50488
51506
|
);
|
|
@@ -50494,7 +51512,7 @@ ${helpMessage}` : field.label;
|
|
|
50494
51512
|
}
|
|
50495
51513
|
return agentConfig.llm.copilot_enterprise_url;
|
|
50496
51514
|
})();
|
|
50497
|
-
const flow = await startCopilotDeviceFlow(
|
|
51515
|
+
const flow = await startCopilotDeviceFlow(clientId2, enterpriseUrl);
|
|
50498
51516
|
const flowId = randomUUID14();
|
|
50499
51517
|
const controller = new AbortController();
|
|
50500
51518
|
const timer = setTimeout(() => {
|
|
@@ -51015,13 +52033,13 @@ ${helpMessage}` : field.label;
|
|
|
51015
52033
|
const firstSpace = raw.search(/\s/);
|
|
51016
52034
|
const path3 = firstSpace > 0 ? raw.slice(0, firstSpace) : raw;
|
|
51017
52035
|
const remainder = firstSpace > 0 ? raw.slice(firstSpace).trim() : "";
|
|
51018
|
-
if (!
|
|
52036
|
+
if (!existsSync34(path3)) {
|
|
51019
52037
|
throw new Error(`image.attach: file not found: ${path3}`);
|
|
51020
52038
|
}
|
|
51021
52039
|
let buffer;
|
|
51022
52040
|
let fileSize = 0;
|
|
51023
52041
|
try {
|
|
51024
|
-
buffer =
|
|
52042
|
+
buffer = readFileSync30(path3);
|
|
51025
52043
|
fileSize = statSync4(path3).size;
|
|
51026
52044
|
} catch (err) {
|
|
51027
52045
|
throw new Error(`image.attach: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -51067,13 +52085,13 @@ ${helpMessage}` : field.label;
|
|
|
51067
52085
|
}
|
|
51068
52086
|
});
|
|
51069
52087
|
bus.registerRpc("reload.env", () => {
|
|
51070
|
-
const envPath =
|
|
51071
|
-
if (!
|
|
52088
|
+
const envPath = join44(homedir30(), ".openjaw-agent", ".env");
|
|
52089
|
+
if (!existsSync34(envPath)) {
|
|
51072
52090
|
return { updated: 0 };
|
|
51073
52091
|
}
|
|
51074
52092
|
let updated = 0;
|
|
51075
52093
|
try {
|
|
51076
|
-
const raw =
|
|
52094
|
+
const raw = readFileSync30(envPath, "utf-8");
|
|
51077
52095
|
for (const line of raw.split(/\r?\n/)) {
|
|
51078
52096
|
const trimmed = line.trim();
|
|
51079
52097
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -51252,7 +52270,7 @@ ${helpMessage}` : field.label;
|
|
|
51252
52270
|
}
|
|
51253
52271
|
};
|
|
51254
52272
|
}
|
|
51255
|
-
var PROVIDERS2, PROVIDER_LABELS, PROVIDER_AUTH, isProviderAuthenticated, buildProviderOption, fetchLiveModels, parseReasoningEffortInput, skillDescription, listRegistrySkills, registrySkillsByCategory, formatSkillExecutionResult, reasoningEffortsForModel, resolveReasoningEffortForModel, BRIDGE_SOURCES, isBridgeSource, inferBridgeSource, bridgeLabels, bridgeEventLabels, stripBridgeGlyph, firstLogLine, bridgeUser, formatBridgeText, runProcess, contentToText, sessionMessageToMarkdown, sessionInfoSnapshot, MCP_TOOL_PREFIX, MAX_TOTAL_TOOLS, syncMcpTools;
|
|
52273
|
+
var PROVIDERS2, PROVIDER_LABELS, PROVIDER_AUTH, isProviderAuthenticated, buildProviderOption, fetchLiveModels, parseReasoningEffortInput, skillDescription, listRegistrySkills, registrySkillsByCategory, formatSkillExecutionResult, reasoningEffortsForModel, resolveReasoningEffortForModel, BRIDGE_SOURCES, isBridgeSource, inferBridgeSource, bridgeLabels, bridgeEventLabels, stripBridgeGlyph, firstLogLine, bridgeUser, formatBridgeText, runProcess, contentToText, sessionMessageToMarkdown, DISPLAY_PREFIX_PATTERNS, stripDisplayPrefix, INTERNAL_SELF_PROMPT_PATTERNS, isInternalSelfPrompt, messageIsInternalSelfPrompt, sessionInfoSnapshot, MCP_TOOL_PREFIX, MAX_TOTAL_TOOLS, syncMcpTools;
|
|
51256
52274
|
var init_rpcHandlers = __esm({
|
|
51257
52275
|
"src/rpcHandlers.ts"() {
|
|
51258
52276
|
"use strict";
|
|
@@ -51462,8 +52480,8 @@ var init_rpcHandlers = __esm({
|
|
|
51462
52480
|
${raw}`;
|
|
51463
52481
|
return `${header}: ${raw}`;
|
|
51464
52482
|
}, "formatBridgeText");
|
|
51465
|
-
runProcess = /* @__PURE__ */ __name((command, args, timeout = 2e4) => new Promise((
|
|
51466
|
-
const child =
|
|
52483
|
+
runProcess = /* @__PURE__ */ __name((command, args, timeout = 2e4) => new Promise((resolve7) => {
|
|
52484
|
+
const child = spawn8(command, args, { timeout, windowsHide: true });
|
|
51467
52485
|
let stdout = "";
|
|
51468
52486
|
let stderr = "";
|
|
51469
52487
|
let truncated = false;
|
|
@@ -51486,9 +52504,9 @@ ${raw}`;
|
|
|
51486
52504
|
if (truncated) {
|
|
51487
52505
|
stderr += "\n[output truncated to 1MB]";
|
|
51488
52506
|
}
|
|
51489
|
-
|
|
52507
|
+
resolve7({ code: code ?? -1, stderr, stdout });
|
|
51490
52508
|
});
|
|
51491
|
-
child.on("error", (err) =>
|
|
52509
|
+
child.on("error", (err) => resolve7({ code: -1, stderr: err.message, stdout }));
|
|
51492
52510
|
}), "runProcess");
|
|
51493
52511
|
contentToText = /* @__PURE__ */ __name((content) => {
|
|
51494
52512
|
if (typeof content === "string") return content;
|
|
@@ -51512,6 +52530,27 @@ ${raw}`;
|
|
|
51512
52530
|
}
|
|
51513
52531
|
return [];
|
|
51514
52532
|
}, "sessionMessageToMarkdown");
|
|
52533
|
+
DISPLAY_PREFIX_PATTERNS = [
|
|
52534
|
+
/^\[USER TASK\]:\s*/
|
|
52535
|
+
];
|
|
52536
|
+
stripDisplayPrefix = /* @__PURE__ */ __name((text, role) => {
|
|
52537
|
+
if (role !== "user") return text;
|
|
52538
|
+
let out = text;
|
|
52539
|
+
for (const pattern of DISPLAY_PREFIX_PATTERNS) {
|
|
52540
|
+
out = out.replace(pattern, "");
|
|
52541
|
+
}
|
|
52542
|
+
return out;
|
|
52543
|
+
}, "stripDisplayPrefix");
|
|
52544
|
+
INTERNAL_SELF_PROMPT_PATTERNS = [
|
|
52545
|
+
/^\[System:\s/
|
|
52546
|
+
];
|
|
52547
|
+
isInternalSelfPrompt = /* @__PURE__ */ __name((rawText) => INTERNAL_SELF_PROMPT_PATTERNS.some((p) => p.test(rawText)), "isInternalSelfPrompt");
|
|
52548
|
+
messageIsInternalSelfPrompt = /* @__PURE__ */ __name((m) => {
|
|
52549
|
+
if (m.role !== "user") return false;
|
|
52550
|
+
const content = m.content;
|
|
52551
|
+
const raw = typeof content === "string" ? content : Array.isArray(content) ? content.map((c) => c.type === "text" ? c.text : "").join("") : "";
|
|
52552
|
+
return isInternalSelfPrompt(raw);
|
|
52553
|
+
}, "messageIsInternalSelfPrompt");
|
|
51515
52554
|
sessionInfoSnapshot = /* @__PURE__ */ __name((agentLoop, toolRegistry) => ({
|
|
51516
52555
|
cwd: process.cwd(),
|
|
51517
52556
|
model: agentLoop.model,
|
|
@@ -51646,14 +52685,14 @@ var init_memoryMonitor = __esm({
|
|
|
51646
52685
|
});
|
|
51647
52686
|
|
|
51648
52687
|
// src/lib/openExternalUrl.ts
|
|
51649
|
-
import { spawn as
|
|
52688
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
51650
52689
|
import { platform } from "node:os";
|
|
51651
52690
|
function openExternalUrl(rawUrl, dependencies = {}) {
|
|
51652
52691
|
const url = parseSafeUrl(rawUrl);
|
|
51653
52692
|
if (!url) {
|
|
51654
52693
|
return false;
|
|
51655
52694
|
}
|
|
51656
|
-
const spawnFn = dependencies.spawn ??
|
|
52695
|
+
const spawnFn = dependencies.spawn ?? spawn9;
|
|
51657
52696
|
const platformId = dependencies.platform?.() ?? platform();
|
|
51658
52697
|
const command = openCommand(platformId);
|
|
51659
52698
|
if (!command) {
|
|
@@ -52146,9 +53185,9 @@ var init_useVirtualHistory = __esm({
|
|
|
52146
53185
|
viewportHeight
|
|
52147
53186
|
}) => itemCount > 0 && viewportHeight > 0 && !sticky && !liveTailActive, "shouldSetVirtualClamp");
|
|
52148
53187
|
ensureVirtualItemHeight = /* @__PURE__ */ __name((heights, key, index, estimate, estimateHeight) => {
|
|
52149
|
-
const
|
|
52150
|
-
if (
|
|
52151
|
-
return Math.max(1, Math.floor(
|
|
53188
|
+
const cached8 = heights.get(key);
|
|
53189
|
+
if (cached8 !== void 0) {
|
|
53190
|
+
return Math.max(1, Math.floor(cached8));
|
|
52152
53191
|
}
|
|
52153
53192
|
const seeded = Math.max(1, Math.floor(estimateHeight?.(index, key) ?? estimate));
|
|
52154
53193
|
heights.set(key, seeded);
|
|
@@ -53586,7 +54625,7 @@ function createGatewayEventHandler(ctx) {
|
|
|
53586
54625
|
setTimeout(async () => {
|
|
53587
54626
|
let sid = getUiState().sid;
|
|
53588
54627
|
for (let i = 0; !sid && i < 40; i += 1) {
|
|
53589
|
-
await new Promise((
|
|
54628
|
+
await new Promise((resolve7) => setTimeout(resolve7, 100));
|
|
53590
54629
|
sid = getUiState().sid;
|
|
53591
54630
|
}
|
|
53592
54631
|
if (!sid) {
|
|
@@ -54333,21 +55372,21 @@ var init_useCompletion = __esm({
|
|
|
54333
55372
|
});
|
|
54334
55373
|
|
|
54335
55374
|
// src/lib/history.ts
|
|
54336
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
54337
|
-
import { homedir as
|
|
54338
|
-
import { join as
|
|
55375
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync35, mkdirSync as mkdirSync19, readFileSync as readFileSync31 } from "node:fs";
|
|
55376
|
+
import { homedir as homedir31 } from "node:os";
|
|
55377
|
+
import { join as join45 } from "node:path";
|
|
54339
55378
|
function load() {
|
|
54340
55379
|
if (cache3) {
|
|
54341
55380
|
return cache3;
|
|
54342
55381
|
}
|
|
54343
55382
|
try {
|
|
54344
|
-
if (!
|
|
55383
|
+
if (!existsSync35(file)) {
|
|
54345
55384
|
cache3 = [];
|
|
54346
55385
|
return cache3;
|
|
54347
55386
|
}
|
|
54348
55387
|
const entries = [];
|
|
54349
55388
|
let current = [];
|
|
54350
|
-
for (const line of
|
|
55389
|
+
for (const line of readFileSync31(file, "utf8").split("\n")) {
|
|
54351
55390
|
if (line.startsWith("+")) {
|
|
54352
55391
|
current.push(line.slice(1));
|
|
54353
55392
|
} else if (current.length) {
|
|
@@ -54378,7 +55417,7 @@ function append(line) {
|
|
|
54378
55417
|
items.splice(0, items.length - MAX);
|
|
54379
55418
|
}
|
|
54380
55419
|
try {
|
|
54381
|
-
if (!
|
|
55420
|
+
if (!existsSync35(dir)) {
|
|
54382
55421
|
mkdirSync19(dir, { recursive: true });
|
|
54383
55422
|
}
|
|
54384
55423
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace("Z", "");
|
|
@@ -54395,8 +55434,8 @@ var init_history = __esm({
|
|
|
54395
55434
|
"src/lib/history.ts"() {
|
|
54396
55435
|
"use strict";
|
|
54397
55436
|
MAX = 1e3;
|
|
54398
|
-
dir = process.env.OPENJAW_HOME ??
|
|
54399
|
-
file =
|
|
55437
|
+
dir = process.env.OPENJAW_HOME ?? join45(homedir31(), ".openjaw-agent");
|
|
55438
|
+
file = join45(dir, ".openjaw-agent_history");
|
|
54400
55439
|
cache3 = null;
|
|
54401
55440
|
__name(load, "load");
|
|
54402
55441
|
__name(append, "append");
|
|
@@ -54489,8 +55528,8 @@ var init_useQueue = __esm({
|
|
|
54489
55528
|
});
|
|
54490
55529
|
|
|
54491
55530
|
// src/lib/editor.ts
|
|
54492
|
-
import { accessSync, constants } from "node:fs";
|
|
54493
|
-
import { delimiter, join as
|
|
55531
|
+
import { accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
55532
|
+
import { delimiter, join as join46 } from "node:path";
|
|
54494
55533
|
var FALLBACKS, isExecutable, resolveEditor;
|
|
54495
55534
|
var init_editor = __esm({
|
|
54496
55535
|
"src/lib/editor.ts"() {
|
|
@@ -54498,7 +55537,7 @@ var init_editor = __esm({
|
|
|
54498
55537
|
FALLBACKS = ["editor", "nano", "pico", "vi", "emacs"];
|
|
54499
55538
|
isExecutable = /* @__PURE__ */ __name((path3) => {
|
|
54500
55539
|
try {
|
|
54501
|
-
|
|
55540
|
+
accessSync2(path3, constants2.X_OK);
|
|
54502
55541
|
return true;
|
|
54503
55542
|
} catch {
|
|
54504
55543
|
return false;
|
|
@@ -54513,7 +55552,7 @@ var init_editor = __esm({
|
|
|
54513
55552
|
return ["notepad.exe"];
|
|
54514
55553
|
}
|
|
54515
55554
|
const dirs = (env2.PATH ?? "").split(delimiter).filter(Boolean);
|
|
54516
|
-
const found = FALLBACKS.flatMap((name) => dirs.map((d) =>
|
|
55555
|
+
const found = FALLBACKS.flatMap((name) => dirs.map((d) => join46(d, name))).find(isExecutable);
|
|
54517
55556
|
return [found ?? "vi"];
|
|
54518
55557
|
}, "resolveEditor");
|
|
54519
55558
|
}
|
|
@@ -54521,9 +55560,9 @@ var init_editor = __esm({
|
|
|
54521
55560
|
|
|
54522
55561
|
// src/app/useComposerState.ts
|
|
54523
55562
|
import { spawnSync } from "node:child_process";
|
|
54524
|
-
import { mkdtempSync, readFileSync as
|
|
55563
|
+
import { mkdtempSync, readFileSync as readFileSync32, rmSync as rmSync2, writeFileSync as writeFileSync21 } from "node:fs";
|
|
54525
55564
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
54526
|
-
import { join as
|
|
55565
|
+
import { join as join47 } from "node:path";
|
|
54527
55566
|
import { useStore } from "@nanostores/react";
|
|
54528
55567
|
import { useCallback as useCallback7, useMemo as useMemo6, useState as useState12 } from "react";
|
|
54529
55568
|
function insertAtCursor(value, cursor, text) {
|
|
@@ -54680,8 +55719,8 @@ function useComposerState({
|
|
|
54680
55719
|
[handleResolvedPaste, onClipboardPaste, querier]
|
|
54681
55720
|
);
|
|
54682
55721
|
const openEditor = useCallback7(async () => {
|
|
54683
|
-
const dir2 = mkdtempSync(
|
|
54684
|
-
const file2 =
|
|
55722
|
+
const dir2 = mkdtempSync(join47(tmpdir12(), "hermes-"));
|
|
55723
|
+
const file2 = join47(dir2, "prompt.md");
|
|
54685
55724
|
const [cmd, ...args] = resolveEditor();
|
|
54686
55725
|
writeFileSync21(file2, [...inputBuf, input].join("\n"));
|
|
54687
55726
|
let exitCode = null;
|
|
@@ -54692,7 +55731,7 @@ function useComposerState({
|
|
|
54692
55731
|
if (exitCode !== 0) {
|
|
54693
55732
|
return;
|
|
54694
55733
|
}
|
|
54695
|
-
const text =
|
|
55734
|
+
const text = readFileSync32(file2, "utf8").trimEnd();
|
|
54696
55735
|
if (!text) {
|
|
54697
55736
|
return;
|
|
54698
55737
|
}
|
|
@@ -56774,8 +57813,8 @@ __export(perfPane_exports, {
|
|
|
56774
57813
|
logFrameEvent: () => logFrameEvent
|
|
56775
57814
|
});
|
|
56776
57815
|
import { appendFileSync as appendFileSync5, mkdirSync as mkdirSync20 } from "node:fs";
|
|
56777
|
-
import { homedir as
|
|
56778
|
-
import { dirname as
|
|
57816
|
+
import { homedir as homedir32 } from "node:os";
|
|
57817
|
+
import { dirname as dirname9, join as join48 } from "node:path";
|
|
56779
57818
|
import { Profiler } from "react";
|
|
56780
57819
|
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
56781
57820
|
function PerfPane({ children, id }) {
|
|
@@ -56791,13 +57830,13 @@ var init_perfPane = __esm({
|
|
|
56791
57830
|
init_entry_exports();
|
|
56792
57831
|
ENABLED = /^(?:1|true|yes|on)$/i.test((process.env.OPENJAW_DEV_PERF ?? "").trim());
|
|
56793
57832
|
THRESHOLD_MS = Number(process.env.OPENJAW_DEV_PERF_MS ?? "2") || 0;
|
|
56794
|
-
LOG_PATH2 = process.env.OPENJAW_DEV_PERF_LOG?.trim() ||
|
|
57833
|
+
LOG_PATH2 = process.env.OPENJAW_DEV_PERF_LOG?.trim() || join48(homedir32(), ".openjaw-agent", "perf.log");
|
|
56795
57834
|
logReady = false;
|
|
56796
57835
|
writeRow = /* @__PURE__ */ __name((row) => {
|
|
56797
57836
|
if (!logReady) {
|
|
56798
57837
|
logReady = true;
|
|
56799
57838
|
try {
|
|
56800
|
-
mkdirSync20(
|
|
57839
|
+
mkdirSync20(dirname9(LOG_PATH2), { recursive: true });
|
|
56801
57840
|
} catch {
|
|
56802
57841
|
}
|
|
56803
57842
|
}
|
|
@@ -62055,7 +63094,7 @@ var init_mathUnicode = __esm({
|
|
|
62055
63094
|
|
|
62056
63095
|
// src/lib/syntax.ts
|
|
62057
63096
|
function highlightLine(line, lang, t) {
|
|
62058
|
-
const spec =
|
|
63097
|
+
const spec = resolve6(lang);
|
|
62059
63098
|
if (!spec) {
|
|
62060
63099
|
return [["", line]];
|
|
62061
63100
|
}
|
|
@@ -62087,7 +63126,7 @@ function highlightLine(line, lang, t) {
|
|
|
62087
63126
|
}
|
|
62088
63127
|
return tokens;
|
|
62089
63128
|
}
|
|
62090
|
-
var KW, TS, PY, SH, GO, RUST, SQL, LANGS, ALIAS,
|
|
63129
|
+
var KW, TS, PY, SH, GO, RUST, SQL, LANGS, ALIAS, resolve6, isHighlightable, TOKEN_RE;
|
|
62091
63130
|
var init_syntax = __esm({
|
|
62092
63131
|
"src/lib/syntax.ts"() {
|
|
62093
63132
|
"use strict";
|
|
@@ -62141,8 +63180,8 @@ var init_syntax = __esm({
|
|
|
62141
63180
|
yml: "yaml",
|
|
62142
63181
|
zsh: "sh"
|
|
62143
63182
|
};
|
|
62144
|
-
|
|
62145
|
-
isHighlightable = /* @__PURE__ */ __name((lang) =>
|
|
63183
|
+
resolve6 = /* @__PURE__ */ __name((lang) => LANGS[ALIAS[lang] ?? lang] ?? null, "resolve");
|
|
63184
|
+
isHighlightable = /* @__PURE__ */ __name((lang) => resolve6(lang) !== null, "isHighlightable");
|
|
62146
63185
|
TOKEN_RE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`|\b\d+(?:\.\d+)?\b|[A-Za-z_$][\w$]*/g;
|
|
62147
63186
|
__name(highlightLine, "highlightLine");
|
|
62148
63187
|
}
|
|
@@ -62242,9 +63281,9 @@ function MdImpl({ compact, t, text }) {
|
|
|
62242
63281
|
const nodes = useMemo14(() => {
|
|
62243
63282
|
const bucket = cacheBucket(t);
|
|
62244
63283
|
const cacheKey = `${compact ? "1" : "0"}|${text}`;
|
|
62245
|
-
const
|
|
62246
|
-
if (
|
|
62247
|
-
return
|
|
63284
|
+
const cached8 = cacheGet(bucket, cacheKey);
|
|
63285
|
+
if (cached8) {
|
|
63286
|
+
return cached8;
|
|
62248
63287
|
}
|
|
62249
63288
|
const lines = ensureEmojiPresentation(text).split("\n");
|
|
62250
63289
|
const nodes2 = [];
|
|
@@ -64477,12 +65516,18 @@ var init_entry = __esm({
|
|
|
64477
65516
|
// src/main.ts
|
|
64478
65517
|
async function main() {
|
|
64479
65518
|
const args = process.argv.slice(2);
|
|
65519
|
+
if (args[0] === "app") {
|
|
65520
|
+
const { launchDesktop: launchDesktop2 } = await Promise.resolve().then(() => (init_launcher(), launcher_exports));
|
|
65521
|
+
await launchDesktop2(args.slice(1));
|
|
65522
|
+
return;
|
|
65523
|
+
}
|
|
64480
65524
|
if (args.includes("--help") || args.includes("-h")) {
|
|
64481
65525
|
console.log(`
|
|
64482
65526
|
OpenJaw Agent \u2014 Autonomous desktop AI assistant
|
|
64483
65527
|
|
|
64484
65528
|
Usage:
|
|
64485
65529
|
openjaw-agent Start new session (Ink UI)
|
|
65530
|
+
openjaw-agent app Start the Electron desktop UI (optional)
|
|
64486
65531
|
openjaw-agent --legacy-ui Start with the previous Ink UI (pre-rewrite)
|
|
64487
65532
|
openjaw-agent --telegram Ink UI + Telegram bridge (hybrid)
|
|
64488
65533
|
openjaw-agent --telegram --headless Telegram only (no desktop UI)
|