@charzhu/openjaw-agent 0.3.2 → 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 +1309 -637
- package/dist/main.js.map +4 -4
- package/package.json +33 -2
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");
|
|
@@ -172,7 +240,7 @@ function saveAgentConfig(config) {
|
|
|
172
240
|
}
|
|
173
241
|
function loadRawConfigYaml() {
|
|
174
242
|
const path3 = getConfigPath();
|
|
175
|
-
if (!
|
|
243
|
+
if (!existsSync3(path3)) {
|
|
176
244
|
return { path: path3, yamlObj: void 0 };
|
|
177
245
|
}
|
|
178
246
|
const raw = readFileSync(path3, "utf8");
|
|
@@ -189,13 +257,13 @@ function updateBridgeConfig(name, values) {
|
|
|
189
257
|
next2[name] = values;
|
|
190
258
|
}
|
|
191
259
|
const tmpPath = `${path3}.tmp`;
|
|
192
|
-
const dir2 =
|
|
193
|
-
if (!
|
|
260
|
+
const dir2 = dirname3(path3);
|
|
261
|
+
if (!existsSync3(dir2)) {
|
|
194
262
|
mkdirSync(dir2, { recursive: true });
|
|
195
263
|
}
|
|
196
264
|
writeFileSync(tmpPath, stringifyYaml(next2), "utf8");
|
|
197
|
-
const { renameSync } = await import("node:fs");
|
|
198
|
-
|
|
265
|
+
const { renameSync: renameSync2 } = await import("node:fs");
|
|
266
|
+
renameSync2(tmpPath, path3);
|
|
199
267
|
}, "task");
|
|
200
268
|
const next = configWriteChain.then(task, task);
|
|
201
269
|
configWriteChain = next.then(
|
|
@@ -250,7 +318,7 @@ __export(image_resize_exports, {
|
|
|
250
318
|
resizeImageForAgent: () => resizeImageForAgent
|
|
251
319
|
});
|
|
252
320
|
import { execSync } from "node:child_process";
|
|
253
|
-
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";
|
|
254
322
|
import { join as join3 } from "node:path";
|
|
255
323
|
import { tmpdir } from "node:os";
|
|
256
324
|
import { randomUUID } from "node:crypto";
|
|
@@ -301,7 +369,7 @@ Write-Output "$newW x $newH"
|
|
|
301
369
|
`powershell -NoProfile -NonInteractive -EncodedCommand ${encoded}`,
|
|
302
370
|
{ timeout: 15e3, encoding: "utf-8" }
|
|
303
371
|
).trim();
|
|
304
|
-
if (!
|
|
372
|
+
if (!existsSync4(outputPath)) {
|
|
305
373
|
throw new Error(`Resize produced no output (PowerShell said: ${result})`);
|
|
306
374
|
}
|
|
307
375
|
const resizedBuffer = readFileSync2(outputPath);
|
|
@@ -311,17 +379,17 @@ Write-Output "$newW x $newH"
|
|
|
311
379
|
return { base64: resizedBase64, mimeType: actualMimeType };
|
|
312
380
|
} finally {
|
|
313
381
|
try {
|
|
314
|
-
if (
|
|
382
|
+
if (existsSync4(inputPath)) unlinkSync(inputPath);
|
|
315
383
|
} catch {
|
|
316
384
|
}
|
|
317
385
|
try {
|
|
318
|
-
if (
|
|
386
|
+
if (existsSync4(outputPath)) unlinkSync(outputPath);
|
|
319
387
|
} catch {
|
|
320
388
|
}
|
|
321
389
|
}
|
|
322
390
|
}
|
|
323
391
|
async function resizeImageFileForAgent(filePath) {
|
|
324
|
-
if (!
|
|
392
|
+
if (!existsSync4(filePath)) {
|
|
325
393
|
throw new Error(`Image file not found: ${filePath}`);
|
|
326
394
|
}
|
|
327
395
|
const buffer = readFileSync2(filePath);
|
|
@@ -869,7 +937,7 @@ Start-Sleep -Milliseconds 50
|
|
|
869
937
|
}
|
|
870
938
|
}
|
|
871
939
|
async function wait(duration) {
|
|
872
|
-
await new Promise((
|
|
940
|
+
await new Promise((resolve7) => setTimeout(resolve7, duration * 1e3));
|
|
873
941
|
return { output: `Waited ${duration} seconds` };
|
|
874
942
|
}
|
|
875
943
|
function getDisplayDimensions() {
|
|
@@ -1977,12 +2045,12 @@ var init_copilot_token = __esm({
|
|
|
1977
2045
|
});
|
|
1978
2046
|
|
|
1979
2047
|
// src/provider-auth.ts
|
|
1980
|
-
import { existsSync as
|
|
2048
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1981
2049
|
import { join as join5 } from "node:path";
|
|
1982
2050
|
import { homedir as homedir2 } from "node:os";
|
|
1983
2051
|
function getAuthDir() {
|
|
1984
2052
|
const dir2 = join5(homedir2(), ".openjaw-agent");
|
|
1985
|
-
if (!
|
|
2053
|
+
if (!existsSync5(dir2)) mkdirSync3(dir2, { recursive: true });
|
|
1986
2054
|
return dir2;
|
|
1987
2055
|
}
|
|
1988
2056
|
function getProviderAuthPath() {
|
|
@@ -1993,7 +2061,7 @@ function emptyFile() {
|
|
|
1993
2061
|
}
|
|
1994
2062
|
function loadProviderCredentials() {
|
|
1995
2063
|
const path3 = getProviderAuthPath();
|
|
1996
|
-
if (!
|
|
2064
|
+
if (!existsSync5(path3)) return emptyFile();
|
|
1997
2065
|
const parsed = JSON.parse(readFileSync3(path3, "utf8"));
|
|
1998
2066
|
return {
|
|
1999
2067
|
version: 1,
|
|
@@ -2206,8 +2274,8 @@ function safeJsonParse(value) {
|
|
|
2206
2274
|
}
|
|
2207
2275
|
}
|
|
2208
2276
|
async function loadWebSocket() {
|
|
2209
|
-
const { createRequire } = await import("node:module");
|
|
2210
|
-
return
|
|
2277
|
+
const { createRequire: createRequire3 } = await import("node:module");
|
|
2278
|
+
return createRequire3(import.meta.url)("ws");
|
|
2211
2279
|
}
|
|
2212
2280
|
function responsesWebSocketUrl(baseUrl) {
|
|
2213
2281
|
const url = new URL(`${baseUrl.replace(/\/+$/, "")}/responses`);
|
|
@@ -2564,7 +2632,7 @@ var init_copilot = __esm({
|
|
|
2564
2632
|
handshakeTimeout: RESPONSES_WEBSOCKET_CONNECT_TIMEOUT_MS
|
|
2565
2633
|
});
|
|
2566
2634
|
const request = JSON.stringify(this.buildResponsesWebSocketRequest(requestBody));
|
|
2567
|
-
return new Promise((
|
|
2635
|
+
return new Promise((resolve7, reject) => {
|
|
2568
2636
|
const accumulator = { sawTextDelta: false, text: null, toolCalls: [] };
|
|
2569
2637
|
let settled = false;
|
|
2570
2638
|
const timeout = setTimeout(() => {
|
|
@@ -2578,7 +2646,7 @@ var init_copilot = __esm({
|
|
|
2578
2646
|
settled = true;
|
|
2579
2647
|
clearTimeout(timeout);
|
|
2580
2648
|
ws.close();
|
|
2581
|
-
|
|
2649
|
+
resolve7(value);
|
|
2582
2650
|
}, "finish");
|
|
2583
2651
|
const fail = /* @__PURE__ */ __name((error) => {
|
|
2584
2652
|
if (settled) return;
|
|
@@ -3014,13 +3082,13 @@ var init_providers = __esm({
|
|
|
3014
3082
|
});
|
|
3015
3083
|
|
|
3016
3084
|
// src/session.ts
|
|
3017
|
-
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";
|
|
3018
3086
|
import { join as join6 } from "node:path";
|
|
3019
3087
|
import { homedir as homedir3 } from "node:os";
|
|
3020
3088
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3021
3089
|
function getSessionsDir() {
|
|
3022
3090
|
const dir2 = join6(homedir3(), ".openjaw-agent", "sessions");
|
|
3023
|
-
if (!
|
|
3091
|
+
if (!existsSync6(dir2)) mkdirSync4(dir2, { recursive: true });
|
|
3024
3092
|
return dir2;
|
|
3025
3093
|
}
|
|
3026
3094
|
function sessionPath(id) {
|
|
@@ -3041,11 +3109,23 @@ function createSession(provider, model) {
|
|
|
3041
3109
|
function saveSession(session) {
|
|
3042
3110
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3043
3111
|
session.turnCount = session.messages.filter((m) => m.role === "user").length;
|
|
3044
|
-
|
|
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
|
+
}
|
|
3045
3125
|
}
|
|
3046
3126
|
function loadSession(id) {
|
|
3047
3127
|
const path3 = sessionPath(id);
|
|
3048
|
-
if (!
|
|
3128
|
+
if (!existsSync6(path3)) return null;
|
|
3049
3129
|
try {
|
|
3050
3130
|
return JSON.parse(readFileSync4(path3, "utf8"));
|
|
3051
3131
|
} catch {
|
|
@@ -3430,7 +3510,7 @@ var init_cache_monitor = __esm({
|
|
|
3430
3510
|
});
|
|
3431
3511
|
|
|
3432
3512
|
// src/telemetry.ts
|
|
3433
|
-
import { appendFileSync, existsSync as
|
|
3513
|
+
import { appendFileSync, existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
3434
3514
|
import { join as join7 } from "node:path";
|
|
3435
3515
|
import { homedir as homedir4 } from "node:os";
|
|
3436
3516
|
function now() {
|
|
@@ -3453,7 +3533,7 @@ var init_telemetry = __esm({
|
|
|
3453
3533
|
constructor(sessionId) {
|
|
3454
3534
|
this.sessionId = sessionId;
|
|
3455
3535
|
try {
|
|
3456
|
-
if (!
|
|
3536
|
+
if (!existsSync7(TELEMETRY_DIR)) {
|
|
3457
3537
|
mkdirSync5(TELEMETRY_DIR, { recursive: true });
|
|
3458
3538
|
}
|
|
3459
3539
|
} catch {
|
|
@@ -3484,7 +3564,7 @@ var init_telemetry = __esm({
|
|
|
3484
3564
|
getRecentEvents(limit = 20) {
|
|
3485
3565
|
try {
|
|
3486
3566
|
const todayFile = join7(TELEMETRY_DIR, `${today()}.jsonl`);
|
|
3487
|
-
if (!
|
|
3567
|
+
if (!existsSync7(todayFile)) return [];
|
|
3488
3568
|
const lines = readFileSync5(todayFile, "utf-8").trim().split("\n");
|
|
3489
3569
|
return lines.slice(-limit).map((l) => JSON.parse(l));
|
|
3490
3570
|
} catch {
|
|
@@ -4409,8 +4489,8 @@ function isOAuthAbortError(err) {
|
|
|
4409
4489
|
function oauthDomain(enterpriseUrl) {
|
|
4410
4490
|
return enterpriseUrl ? normalizeCopilotEnterpriseDomain(enterpriseUrl) : "github.com";
|
|
4411
4491
|
}
|
|
4412
|
-
async function startCopilotDeviceFlow(
|
|
4413
|
-
if (!
|
|
4492
|
+
async function startCopilotDeviceFlow(clientId2, enterpriseUrl) {
|
|
4493
|
+
if (!clientId2.trim()) {
|
|
4414
4494
|
throw new Error("GitHub OAuth client ID is required for Copilot login.");
|
|
4415
4495
|
}
|
|
4416
4496
|
const normalizedEnterpriseUrl = enterpriseUrl ? normalizeCopilotEnterpriseDomain(enterpriseUrl) : void 0;
|
|
@@ -4423,7 +4503,7 @@ async function startCopilotDeviceFlow(clientId, enterpriseUrl) {
|
|
|
4423
4503
|
"User-Agent": "openjaw-agent/0.1.0"
|
|
4424
4504
|
},
|
|
4425
4505
|
body: JSON.stringify({
|
|
4426
|
-
client_id:
|
|
4506
|
+
client_id: clientId2,
|
|
4427
4507
|
scope: "read:user"
|
|
4428
4508
|
})
|
|
4429
4509
|
});
|
|
@@ -4439,7 +4519,7 @@ async function startCopilotDeviceFlow(clientId, enterpriseUrl) {
|
|
|
4439
4519
|
verificationUri: body.verification_uri,
|
|
4440
4520
|
userCode: body.user_code,
|
|
4441
4521
|
deviceCode: body.device_code,
|
|
4442
|
-
clientId,
|
|
4522
|
+
clientId: clientId2,
|
|
4443
4523
|
intervalSeconds: body.interval ?? 5,
|
|
4444
4524
|
enterpriseUrl: normalizedEnterpriseUrl
|
|
4445
4525
|
};
|
|
@@ -4743,8 +4823,8 @@ For local proxy mode without API keys, use /connect maestro.`
|
|
|
4743
4823
|
}
|
|
4744
4824
|
};
|
|
4745
4825
|
}
|
|
4746
|
-
const
|
|
4747
|
-
if (!
|
|
4826
|
+
const clientId2 = resolveCopilotClientId();
|
|
4827
|
+
if (!clientId2) {
|
|
4748
4828
|
emit({
|
|
4749
4829
|
type: "error",
|
|
4750
4830
|
content: [
|
|
@@ -4760,7 +4840,7 @@ For local proxy mode without API keys, use /connect maestro.`
|
|
|
4760
4840
|
}
|
|
4761
4841
|
const label = enterpriseUrl ? `GitHub Enterprise (${enterpriseUrl})` : "GitHub.com";
|
|
4762
4842
|
try {
|
|
4763
|
-
const flow = await startCopilotDeviceFlow(
|
|
4843
|
+
const flow = await startCopilotDeviceFlow(clientId2, enterpriseUrl);
|
|
4764
4844
|
emit({
|
|
4765
4845
|
type: "system",
|
|
4766
4846
|
content: [
|
|
@@ -5285,6 +5365,66 @@ var init_agent_loop = __esm({
|
|
|
5285
5365
|
this.conversationHistory = next.messages;
|
|
5286
5366
|
return { session_id: next.id, title: next.summary };
|
|
5287
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
|
+
}
|
|
5288
5428
|
/** Read-only access to the underlying session metadata. */
|
|
5289
5429
|
getSessionMeta() {
|
|
5290
5430
|
return {
|
|
@@ -5848,18 +5988,18 @@ ${summary}
|
|
|
5848
5988
|
content: parsed.question,
|
|
5849
5989
|
choices: parsed.choices ?? void 0
|
|
5850
5990
|
};
|
|
5851
|
-
const userResponse = await new Promise((
|
|
5991
|
+
const userResponse = await new Promise((resolve7) => {
|
|
5852
5992
|
if (this._pendingAskUserResponse !== null) {
|
|
5853
5993
|
const buffered = this._pendingAskUserResponse;
|
|
5854
5994
|
this._pendingAskUserResponse = null;
|
|
5855
|
-
|
|
5995
|
+
resolve7(buffered);
|
|
5856
5996
|
return;
|
|
5857
5997
|
}
|
|
5858
|
-
this._askUserResolver =
|
|
5998
|
+
this._askUserResolver = resolve7;
|
|
5859
5999
|
setTimeout(() => {
|
|
5860
|
-
if (this._askUserResolver ===
|
|
6000
|
+
if (this._askUserResolver === resolve7) {
|
|
5861
6001
|
this._askUserResolver = null;
|
|
5862
|
-
|
|
6002
|
+
resolve7("[No response from user \u2014 timed out after 5 minutes]");
|
|
5863
6003
|
}
|
|
5864
6004
|
}, 5 * 60 * 1e3);
|
|
5865
6005
|
});
|
|
@@ -5963,14 +6103,14 @@ __export(settings_exports, {
|
|
|
5963
6103
|
});
|
|
5964
6104
|
import { z } from "zod";
|
|
5965
6105
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
5966
|
-
import { existsSync as
|
|
6106
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
5967
6107
|
import { join as join9 } from "node:path";
|
|
5968
6108
|
import { homedir as homedir6 } from "node:os";
|
|
5969
6109
|
import { parse as parseYaml2, stringify as stringifyYaml2 } from "yaml";
|
|
5970
6110
|
async function ensureDirectories() {
|
|
5971
6111
|
const dirs = [OPENJAW_DIR, SESSIONS_DIR, MEMORY_DIR];
|
|
5972
6112
|
for (const dir2 of dirs) {
|
|
5973
|
-
if (!
|
|
6113
|
+
if (!existsSync8(dir2)) {
|
|
5974
6114
|
await mkdir(dir2, { recursive: true });
|
|
5975
6115
|
}
|
|
5976
6116
|
}
|
|
@@ -5981,7 +6121,7 @@ async function loadConfig() {
|
|
|
5981
6121
|
}
|
|
5982
6122
|
await ensureDirectories();
|
|
5983
6123
|
let rawConfig = {};
|
|
5984
|
-
if (
|
|
6124
|
+
if (existsSync8(CONFIG_PATH)) {
|
|
5985
6125
|
const content = await readFile(CONFIG_PATH, "utf-8");
|
|
5986
6126
|
rawConfig = parseYaml2(content);
|
|
5987
6127
|
}
|
|
@@ -6031,7 +6171,13 @@ var init_settings = __esm({
|
|
|
6031
6171
|
MicrosoftConfigSchema = z.object({
|
|
6032
6172
|
tenant_id: z.string().optional(),
|
|
6033
6173
|
client_id: z.string().optional(),
|
|
6034
|
-
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()
|
|
6035
6181
|
});
|
|
6036
6182
|
BrowserConfigSchema = z.object({
|
|
6037
6183
|
executable: z.string().optional(),
|
|
@@ -6531,7 +6677,7 @@ var init_browser = __esm({
|
|
|
6531
6677
|
await Page.domContentEventFired();
|
|
6532
6678
|
} else if (options.waitFor === "networkidle") {
|
|
6533
6679
|
await Page.loadEventFired();
|
|
6534
|
-
await new Promise((
|
|
6680
|
+
await new Promise((resolve7) => setTimeout(resolve7, 1e3));
|
|
6535
6681
|
}
|
|
6536
6682
|
const result = await Runtime.evaluate({
|
|
6537
6683
|
expression: "document.title"
|
|
@@ -7302,7 +7448,7 @@ var init_browser = __esm({
|
|
|
7302
7448
|
if (exists) {
|
|
7303
7449
|
return true;
|
|
7304
7450
|
}
|
|
7305
|
-
await new Promise((
|
|
7451
|
+
await new Promise((resolve7) => setTimeout(resolve7, 200));
|
|
7306
7452
|
}
|
|
7307
7453
|
return false;
|
|
7308
7454
|
}
|
|
@@ -7530,10 +7676,10 @@ function createBrowseTools(config, sharedBrowser) {
|
|
|
7530
7676
|
}
|
|
7531
7677
|
},
|
|
7532
7678
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
7533
|
-
const { join:
|
|
7679
|
+
const { join: join49 } = await import("node:path");
|
|
7534
7680
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
7535
7681
|
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
7536
|
-
const screenshotPath =
|
|
7682
|
+
const screenshotPath = join49(tmpdir13(), `openjaw-browser-${randomUUID15().slice(0, 8)}.png`);
|
|
7537
7683
|
const screenshot = await browser.screenshot({ fullPage: false, path: screenshotPath });
|
|
7538
7684
|
const snapshot = await browser.snapshot({ full: false });
|
|
7539
7685
|
return {
|
|
@@ -8228,7 +8374,7 @@ var init_outlook_desktop = __esm({
|
|
|
8228
8374
|
}
|
|
8229
8375
|
}
|
|
8230
8376
|
sleep(ms) {
|
|
8231
|
-
return new Promise((
|
|
8377
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
8232
8378
|
}
|
|
8233
8379
|
};
|
|
8234
8380
|
}
|
|
@@ -8826,14 +8972,14 @@ var init_outlook_web = __esm({
|
|
|
8826
8972
|
await this.browser.typeChars(text);
|
|
8827
8973
|
}
|
|
8828
8974
|
sleep(ms) {
|
|
8829
|
-
return new Promise((
|
|
8975
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
8830
8976
|
}
|
|
8831
8977
|
};
|
|
8832
8978
|
}
|
|
8833
8979
|
});
|
|
8834
8980
|
|
|
8835
8981
|
// ../openjaw-mcp/dist/auth/token-pool.js
|
|
8836
|
-
import { existsSync as
|
|
8982
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
8837
8983
|
import { join as join10 } from "node:path";
|
|
8838
8984
|
import { homedir as homedir7 } from "node:os";
|
|
8839
8985
|
function decodeJwtPayload(jwt) {
|
|
@@ -9030,7 +9176,7 @@ var init_token_pool = __esm({
|
|
|
9030
9176
|
* Load pool from disk, including legacy token files.
|
|
9031
9177
|
*/
|
|
9032
9178
|
load() {
|
|
9033
|
-
if (
|
|
9179
|
+
if (existsSync9(POOL_FILE)) {
|
|
9034
9180
|
try {
|
|
9035
9181
|
const raw = readFileSync6(POOL_FILE, "utf-8");
|
|
9036
9182
|
const data = JSON.parse(raw);
|
|
@@ -9057,7 +9203,7 @@ var init_token_pool = __esm({
|
|
|
9057
9203
|
*/
|
|
9058
9204
|
loadLegacyFiles() {
|
|
9059
9205
|
const legacyDir = join10(POOL_DIR, "tokens");
|
|
9060
|
-
if (!
|
|
9206
|
+
if (!existsSync9(legacyDir))
|
|
9061
9207
|
return;
|
|
9062
9208
|
try {
|
|
9063
9209
|
const { readdirSync: readdirSync8 } = __require("node:fs");
|
|
@@ -9241,7 +9387,7 @@ var init_cdp_token_extractor = __esm({
|
|
|
9241
9387
|
}
|
|
9242
9388
|
logger_default.info("CDP: reloading tab for token refresh", { url: targetTab.url, audience });
|
|
9243
9389
|
await this.reloadTab(targetTab);
|
|
9244
|
-
await new Promise((
|
|
9390
|
+
await new Promise((resolve7) => setTimeout(resolve7, PAGE_RELOAD_WAIT_MS));
|
|
9245
9391
|
if (!targetTab.webSocketDebuggerUrl)
|
|
9246
9392
|
return [];
|
|
9247
9393
|
const freshPages = await this.listPages();
|
|
@@ -9358,19 +9504,19 @@ var init_cdp_token_extractor = __esm({
|
|
|
9358
9504
|
* Evaluate a JS expression in a tab and return the string result.
|
|
9359
9505
|
*/
|
|
9360
9506
|
async evaluateInTab(wsUrl, expression) {
|
|
9361
|
-
return new Promise((
|
|
9507
|
+
return new Promise((resolve7) => {
|
|
9362
9508
|
let ws;
|
|
9363
9509
|
try {
|
|
9364
9510
|
ws = new WebSocket(wsUrl);
|
|
9365
9511
|
} catch (err) {
|
|
9366
9512
|
logger_default.warn("CDP: WebSocket constructor failed", { wsUrl: wsUrl.substring(0, 60), error: String(err) });
|
|
9367
|
-
|
|
9513
|
+
resolve7(null);
|
|
9368
9514
|
return;
|
|
9369
9515
|
}
|
|
9370
9516
|
const timer = setTimeout(() => {
|
|
9371
9517
|
logger_default.warn("CDP: evaluateInTab timeout", { wsUrl: wsUrl.substring(0, 60) });
|
|
9372
9518
|
ws.close();
|
|
9373
|
-
|
|
9519
|
+
resolve7(null);
|
|
9374
9520
|
}, CDP_TIMEOUT_MS);
|
|
9375
9521
|
ws.on("open", () => {
|
|
9376
9522
|
ws.send(JSON.stringify({
|
|
@@ -9384,18 +9530,18 @@ var init_cdp_token_extractor = __esm({
|
|
|
9384
9530
|
if (resp.id === 1) {
|
|
9385
9531
|
clearTimeout(timer);
|
|
9386
9532
|
ws.close();
|
|
9387
|
-
|
|
9533
|
+
resolve7(resp.result?.result?.value ?? null);
|
|
9388
9534
|
}
|
|
9389
9535
|
});
|
|
9390
9536
|
ws.on("error", (err) => {
|
|
9391
9537
|
logger_default.warn("CDP: evaluateInTab WS error", { error: String(err), wsUrl: wsUrl.substring(0, 60) });
|
|
9392
9538
|
clearTimeout(timer);
|
|
9393
|
-
|
|
9539
|
+
resolve7(null);
|
|
9394
9540
|
});
|
|
9395
9541
|
});
|
|
9396
9542
|
}
|
|
9397
9543
|
async extractFromTab(wsUrl) {
|
|
9398
|
-
return new Promise((
|
|
9544
|
+
return new Promise((resolve7, reject) => {
|
|
9399
9545
|
const ws = new WebSocket(wsUrl);
|
|
9400
9546
|
const timer = setTimeout(() => {
|
|
9401
9547
|
ws.close();
|
|
@@ -9415,14 +9561,14 @@ var init_cdp_token_extractor = __esm({
|
|
|
9415
9561
|
ws.close();
|
|
9416
9562
|
const value = resp.result?.result?.value;
|
|
9417
9563
|
if (!value) {
|
|
9418
|
-
|
|
9564
|
+
resolve7([]);
|
|
9419
9565
|
return;
|
|
9420
9566
|
}
|
|
9421
9567
|
try {
|
|
9422
9568
|
const tokens = JSON.parse(value);
|
|
9423
|
-
|
|
9569
|
+
resolve7(tokens);
|
|
9424
9570
|
} catch {
|
|
9425
|
-
|
|
9571
|
+
resolve7([]);
|
|
9426
9572
|
}
|
|
9427
9573
|
}
|
|
9428
9574
|
});
|
|
@@ -9438,11 +9584,11 @@ var init_cdp_token_extractor = __esm({
|
|
|
9438
9584
|
async reloadTab(page) {
|
|
9439
9585
|
if (!page.webSocketDebuggerUrl)
|
|
9440
9586
|
return;
|
|
9441
|
-
return new Promise((
|
|
9587
|
+
return new Promise((resolve7, reject) => {
|
|
9442
9588
|
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
9443
9589
|
const timer = setTimeout(() => {
|
|
9444
9590
|
ws.close();
|
|
9445
|
-
|
|
9591
|
+
resolve7();
|
|
9446
9592
|
}, 1e4);
|
|
9447
9593
|
ws.on("open", () => {
|
|
9448
9594
|
ws.send(JSON.stringify({
|
|
@@ -9456,7 +9602,7 @@ var init_cdp_token_extractor = __esm({
|
|
|
9456
9602
|
if (resp.id === 1) {
|
|
9457
9603
|
clearTimeout(timer);
|
|
9458
9604
|
ws.close();
|
|
9459
|
-
|
|
9605
|
+
resolve7();
|
|
9460
9606
|
}
|
|
9461
9607
|
});
|
|
9462
9608
|
ws.on("error", (err) => {
|
|
@@ -9496,13 +9642,172 @@ var init_cdp_token_extractor = __esm({
|
|
|
9496
9642
|
}
|
|
9497
9643
|
});
|
|
9498
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
|
+
|
|
9499
9804
|
// ../openjaw-mcp/dist/auth/graph-token-provider.js
|
|
9500
|
-
import { existsSync as
|
|
9501
|
-
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";
|
|
9502
9807
|
import { homedir as homedir8 } from "node:os";
|
|
9503
9808
|
import { exec as exec2 } from "node:child_process";
|
|
9504
9809
|
import { promisify as promisify2 } from "node:util";
|
|
9505
|
-
import { fileURLToPath as
|
|
9810
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
9506
9811
|
function getSharedPool() {
|
|
9507
9812
|
if (!sharedPool) {
|
|
9508
9813
|
sharedPool = new TokenPool();
|
|
@@ -9522,9 +9827,10 @@ var init_graph_token_provider = __esm({
|
|
|
9522
9827
|
init_logger();
|
|
9523
9828
|
init_token_pool();
|
|
9524
9829
|
init_cdp_token_extractor();
|
|
9830
|
+
init_wam_token_provider();
|
|
9525
9831
|
execAsync2 = promisify2(exec2);
|
|
9526
|
-
__filename =
|
|
9527
|
-
__dirname =
|
|
9832
|
+
__filename = fileURLToPath3(import.meta.url);
|
|
9833
|
+
__dirname = dirname4(__filename);
|
|
9528
9834
|
TOKEN_PROFILES = {
|
|
9529
9835
|
"graph-chat": {
|
|
9530
9836
|
scopes: ["Chat.Read"],
|
|
@@ -9598,6 +9904,23 @@ var init_graph_token_provider = __esm({
|
|
|
9598
9904
|
this.scheduleProactiveRefresh(pooled.expiresAt);
|
|
9599
9905
|
return pooled.secret;
|
|
9600
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
|
+
}
|
|
9601
9924
|
logger_default.info("Tier 1 (pool) empty \u2014 trying Tier 2 (CDP extraction)...", {
|
|
9602
9925
|
tokenName: this.tokenName,
|
|
9603
9926
|
audience: this.preferredAudience
|
|
@@ -9855,7 +10178,7 @@ var init_graph_token_provider = __esm({
|
|
|
9855
10178
|
* Tier 4: Legacy Python script fallback.
|
|
9856
10179
|
*/
|
|
9857
10180
|
async extractViaLegacyScript() {
|
|
9858
|
-
if (!
|
|
10181
|
+
if (!existsSync10(this.extractScript)) {
|
|
9859
10182
|
return false;
|
|
9860
10183
|
}
|
|
9861
10184
|
try {
|
|
@@ -9871,7 +10194,7 @@ var init_graph_token_provider = __esm({
|
|
|
9871
10194
|
*/
|
|
9872
10195
|
migrateLegacyToken(tokenName) {
|
|
9873
10196
|
const legacyPath = join11(homedir8(), ".graph-token", "tokens", `${tokenName}.json`);
|
|
9874
|
-
if (!
|
|
10197
|
+
if (!existsSync10(legacyPath))
|
|
9875
10198
|
return;
|
|
9876
10199
|
try {
|
|
9877
10200
|
const data = JSON.parse(readFileSync7(legacyPath, "utf-8"));
|
|
@@ -10130,9 +10453,9 @@ var init_outlook_graph = __esm({
|
|
|
10130
10453
|
const wellKnown = WELL_KNOWN_FOLDERS[lower];
|
|
10131
10454
|
if (wellKnown)
|
|
10132
10455
|
return wellKnown;
|
|
10133
|
-
const
|
|
10134
|
-
if (
|
|
10135
|
-
return
|
|
10456
|
+
const cached8 = this.folderIdCache.get(lower);
|
|
10457
|
+
if (cached8)
|
|
10458
|
+
return cached8;
|
|
10136
10459
|
try {
|
|
10137
10460
|
const result = await this.graphGet(`/me/mailFolders?$filter=displayName eq '${folderName.replace(/'/g, "''")}'&$top=1`);
|
|
10138
10461
|
if (result.value.length > 0) {
|
|
@@ -10390,7 +10713,7 @@ var init_outlook_graph = __esm({
|
|
|
10390
10713
|
import { DatabaseSync } from "node:sqlite";
|
|
10391
10714
|
import { join as join12 } from "node:path";
|
|
10392
10715
|
import { homedir as homedir9 } from "node:os";
|
|
10393
|
-
import { mkdirSync as mkdirSync8, existsSync as
|
|
10716
|
+
import { mkdirSync as mkdirSync8, existsSync as existsSync11 } from "node:fs";
|
|
10394
10717
|
function hasFts5() {
|
|
10395
10718
|
return _hasFts5;
|
|
10396
10719
|
}
|
|
@@ -10406,7 +10729,7 @@ function detectFts5(database) {
|
|
|
10406
10729
|
}
|
|
10407
10730
|
function getMemoryDb() {
|
|
10408
10731
|
if (!db) {
|
|
10409
|
-
if (!
|
|
10732
|
+
if (!existsSync11(DB_DIR)) {
|
|
10410
10733
|
mkdirSync8(DB_DIR, { recursive: true });
|
|
10411
10734
|
}
|
|
10412
10735
|
db = new DatabaseSync(DB_PATH);
|
|
@@ -10490,9 +10813,9 @@ var init_db = __esm({
|
|
|
10490
10813
|
import { createHash as createHash2 } from "node:crypto";
|
|
10491
10814
|
function encodeAtom(word, dim2 = HRR_DIM) {
|
|
10492
10815
|
const cacheKey = `${word}:${dim2}`;
|
|
10493
|
-
const
|
|
10494
|
-
if (
|
|
10495
|
-
return
|
|
10816
|
+
const cached8 = atomCache.get(cacheKey);
|
|
10817
|
+
if (cached8)
|
|
10818
|
+
return cached8;
|
|
10496
10819
|
const phases = new Float64Array(dim2);
|
|
10497
10820
|
const bytesNeeded = dim2 * 4;
|
|
10498
10821
|
const chunks = [];
|
|
@@ -10767,7 +11090,7 @@ __export(store_exports, {
|
|
|
10767
11090
|
MemoryStore: () => MemoryStore
|
|
10768
11091
|
});
|
|
10769
11092
|
import { readFile as readFile2, readdir } from "node:fs/promises";
|
|
10770
|
-
import { existsSync as
|
|
11093
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
10771
11094
|
import { join as join13 } from "node:path";
|
|
10772
11095
|
var MemoryStore;
|
|
10773
11096
|
var init_store = __esm({
|
|
@@ -10825,7 +11148,7 @@ var init_store = __esm({
|
|
|
10825
11148
|
const db2 = this.ensureDb();
|
|
10826
11149
|
let migrated = 0;
|
|
10827
11150
|
const insert = db2.prepare("INSERT INTO memories (content, source, created_at) VALUES (?, ?, ?)");
|
|
10828
|
-
if (
|
|
11151
|
+
if (existsSync12(this.memoryFile)) {
|
|
10829
11152
|
const content = await readFile2(this.memoryFile, "utf-8");
|
|
10830
11153
|
const entries = this.parseMarkdownToEntries(content, "MEMORY.md");
|
|
10831
11154
|
for (const entry of entries) {
|
|
@@ -10833,7 +11156,7 @@ var init_store = __esm({
|
|
|
10833
11156
|
migrated++;
|
|
10834
11157
|
}
|
|
10835
11158
|
}
|
|
10836
|
-
if (
|
|
11159
|
+
if (existsSync12(this.memoryDir)) {
|
|
10837
11160
|
const files = await readdir(this.memoryDir);
|
|
10838
11161
|
const mdFiles = files.filter((f) => f.endsWith(".md")).sort().reverse();
|
|
10839
11162
|
for (const file2 of mdFiles) {
|
|
@@ -11117,13 +11440,13 @@ function createMemoryTools(config) {
|
|
|
11117
11440
|
const todos = input.todos;
|
|
11118
11441
|
try {
|
|
11119
11442
|
const { appendFile: appendFile2, mkdir: mkdir5 } = await import("node:fs/promises");
|
|
11120
|
-
const { existsSync:
|
|
11121
|
-
const { join:
|
|
11122
|
-
const { homedir:
|
|
11123
|
-
const memoryDir =
|
|
11124
|
-
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))
|
|
11125
11448
|
await mkdir5(memoryDir, { recursive: true });
|
|
11126
|
-
const todoPath =
|
|
11449
|
+
const todoPath = join49(memoryDir, "TODOS.md");
|
|
11127
11450
|
const { writeFile: writeFile5 } = await import("node:fs/promises");
|
|
11128
11451
|
await writeFile5(todoPath, `# Session Todos
|
|
11129
11452
|
|
|
@@ -12444,7 +12767,7 @@ var init_teams_desktop = __esm({
|
|
|
12444
12767
|
}
|
|
12445
12768
|
}
|
|
12446
12769
|
sleep(ms) {
|
|
12447
|
-
return new Promise((
|
|
12770
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
12448
12771
|
}
|
|
12449
12772
|
/**
|
|
12450
12773
|
* Get the current Teams window state
|
|
@@ -13311,7 +13634,7 @@ var init_teams_web = __esm({
|
|
|
13311
13634
|
}
|
|
13312
13635
|
}
|
|
13313
13636
|
sleep(ms) {
|
|
13314
|
-
return new Promise((
|
|
13637
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
13315
13638
|
}
|
|
13316
13639
|
};
|
|
13317
13640
|
}
|
|
@@ -13708,9 +14031,9 @@ ${loopContent}` : loopContent;
|
|
|
13708
14031
|
*/
|
|
13709
14032
|
async findChannelByName(searchTerm) {
|
|
13710
14033
|
const searchLower = searchTerm.toLowerCase();
|
|
13711
|
-
const
|
|
13712
|
-
if (
|
|
13713
|
-
return { ...
|
|
14034
|
+
const cached8 = this.channelIdCache.get(searchLower);
|
|
14035
|
+
if (cached8) {
|
|
14036
|
+
return { ...cached8, displayName: searchTerm };
|
|
13714
14037
|
}
|
|
13715
14038
|
try {
|
|
13716
14039
|
const teamsData = await this.graphGet("/v1.0/me/joinedTeams");
|
|
@@ -13890,9 +14213,9 @@ ${loopContent}` : loopContent;
|
|
|
13890
14213
|
* Results are cached per chat ID.
|
|
13891
14214
|
*/
|
|
13892
14215
|
async getChatMembers(chatOrChannelId) {
|
|
13893
|
-
const
|
|
13894
|
-
if (
|
|
13895
|
-
return
|
|
14216
|
+
const cached8 = this.chatMembersCache.get(chatOrChannelId);
|
|
14217
|
+
if (cached8)
|
|
14218
|
+
return cached8;
|
|
13896
14219
|
try {
|
|
13897
14220
|
let endpoint;
|
|
13898
14221
|
if (this.contextType === "channel" && this.currentChannelTeamId && chatOrChannelId === this.currentChannelId) {
|
|
@@ -14130,9 +14453,9 @@ ${loopContent}` : loopContent;
|
|
|
14130
14453
|
*/
|
|
14131
14454
|
async resolveChannelIds(teamName, channelName) {
|
|
14132
14455
|
const cacheKey = `${teamName}/${channelName}`;
|
|
14133
|
-
const
|
|
14134
|
-
if (
|
|
14135
|
-
return
|
|
14456
|
+
const cached8 = this.channelIdCache.get(cacheKey);
|
|
14457
|
+
if (cached8)
|
|
14458
|
+
return cached8;
|
|
14136
14459
|
const teamsData = await this.graphGet("/v1.0/me/joinedTeams");
|
|
14137
14460
|
const team = teamsData.value?.find((t) => t.displayName.toLowerCase() === teamName.toLowerCase());
|
|
14138
14461
|
if (!team) {
|
|
@@ -14709,7 +15032,7 @@ var init_teams_chat_monitor = __esm({
|
|
|
14709
15032
|
return this.sentMessages.has(normalized);
|
|
14710
15033
|
}
|
|
14711
15034
|
sleep(ms) {
|
|
14712
|
-
return new Promise((
|
|
15035
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
14713
15036
|
}
|
|
14714
15037
|
/**
|
|
14715
15038
|
* Attempt to reconnect the browser after detecting a disconnection.
|
|
@@ -15496,7 +15819,7 @@ ${lines.join("\n")}`;
|
|
|
15496
15819
|
globalThis.__teamsSeenMessages.set(chatName, seenIds);
|
|
15497
15820
|
}
|
|
15498
15821
|
if (syncMode) {
|
|
15499
|
-
return new Promise((
|
|
15822
|
+
return new Promise((resolve7) => {
|
|
15500
15823
|
const timer2 = setInterval(async () => {
|
|
15501
15824
|
try {
|
|
15502
15825
|
const current = await channel.readCurrentChatMessages();
|
|
@@ -15505,7 +15828,7 @@ ${lines.join("\n")}`;
|
|
|
15505
15828
|
if (!seenIds.has(msgId) && msg.sender !== currentUserName) {
|
|
15506
15829
|
clearInterval(timer2);
|
|
15507
15830
|
seenIds.add(msgId);
|
|
15508
|
-
|
|
15831
|
+
resolve7({
|
|
15509
15832
|
success: true,
|
|
15510
15833
|
channel: channelType,
|
|
15511
15834
|
sync: true,
|
|
@@ -15582,7 +15905,7 @@ ${lines.join("\n")}`;
|
|
|
15582
15905
|
globalThis.__teamsSeenMessages.set(chatName, seenIds);
|
|
15583
15906
|
}
|
|
15584
15907
|
if (syncMode) {
|
|
15585
|
-
return new Promise((
|
|
15908
|
+
return new Promise((resolve7) => {
|
|
15586
15909
|
const timer2 = setInterval(async () => {
|
|
15587
15910
|
try {
|
|
15588
15911
|
const current = await channel.readCurrentChatMessages();
|
|
@@ -15591,7 +15914,7 @@ ${lines.join("\n")}`;
|
|
|
15591
15914
|
if (!seenIds.has(msgId) && msg.sender !== currentUserName) {
|
|
15592
15915
|
clearInterval(timer2);
|
|
15593
15916
|
seenIds.add(msgId);
|
|
15594
|
-
|
|
15917
|
+
resolve7({
|
|
15595
15918
|
success: true,
|
|
15596
15919
|
channel: channelType,
|
|
15597
15920
|
sync: true,
|
|
@@ -15949,7 +16272,7 @@ ${lines.join("\n")}`;
|
|
|
15949
16272
|
return allTools;
|
|
15950
16273
|
}
|
|
15951
16274
|
function sleep2(ms) {
|
|
15952
|
-
return new Promise((
|
|
16275
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
15953
16276
|
}
|
|
15954
16277
|
var MAX_STORED_ENTRIES, ENTRY_TTL_MS;
|
|
15955
16278
|
var init_chat = __esm({
|
|
@@ -15974,8 +16297,8 @@ var init_chat = __esm({
|
|
|
15974
16297
|
|
|
15975
16298
|
// ../openjaw-mcp/dist/tools/files.js
|
|
15976
16299
|
import { readFile as readFile3, writeFile as writeFile2, readdir as readdir2, stat, mkdir as mkdir2, unlink } from "node:fs/promises";
|
|
15977
|
-
import { existsSync as
|
|
15978
|
-
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";
|
|
15979
16302
|
import { execSync as execSync3 } from "node:child_process";
|
|
15980
16303
|
function createFileTools(_config) {
|
|
15981
16304
|
return [
|
|
@@ -16012,7 +16335,7 @@ function createFileTools(_config) {
|
|
|
16012
16335
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16013
16336
|
const path3 = input.path;
|
|
16014
16337
|
const encoding = input.encoding ?? "utf-8";
|
|
16015
|
-
if (!
|
|
16338
|
+
if (!existsSync13(path3)) {
|
|
16016
16339
|
return { error: `File not found: ${path3}` };
|
|
16017
16340
|
}
|
|
16018
16341
|
const BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -16123,12 +16446,12 @@ function createFileTools(_config) {
|
|
|
16123
16446
|
const append2 = input.append ?? false;
|
|
16124
16447
|
const createDirs = input.create_dirs ?? true;
|
|
16125
16448
|
if (createDirs) {
|
|
16126
|
-
const dir2 =
|
|
16127
|
-
if (!
|
|
16449
|
+
const dir2 = dirname5(path3);
|
|
16450
|
+
if (!existsSync13(dir2)) {
|
|
16128
16451
|
await mkdir2(dir2, { recursive: true });
|
|
16129
16452
|
}
|
|
16130
16453
|
}
|
|
16131
|
-
if (append2 &&
|
|
16454
|
+
if (append2 && existsSync13(path3)) {
|
|
16132
16455
|
const existing = await readFile3(path3, "utf-8");
|
|
16133
16456
|
await writeFile2(path3, existing + content, "utf-8");
|
|
16134
16457
|
} else {
|
|
@@ -16175,7 +16498,7 @@ function createFileTools(_config) {
|
|
|
16175
16498
|
const recursive = input.recursive ?? false;
|
|
16176
16499
|
const includeHidden = input.include_hidden ?? false;
|
|
16177
16500
|
const pattern = input.pattern;
|
|
16178
|
-
if (!
|
|
16501
|
+
if (!existsSync13(dirPath)) {
|
|
16179
16502
|
return { error: `Directory not found: ${dirPath}` };
|
|
16180
16503
|
}
|
|
16181
16504
|
const results = [];
|
|
@@ -16223,7 +16546,7 @@ function createFileTools(_config) {
|
|
|
16223
16546
|
requiresConfirmation: true,
|
|
16224
16547
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16225
16548
|
const path3 = input.path;
|
|
16226
|
-
if (!
|
|
16549
|
+
if (!existsSync13(path3)) {
|
|
16227
16550
|
return { error: `File not found: ${path3}` };
|
|
16228
16551
|
}
|
|
16229
16552
|
await unlink(path3);
|
|
@@ -16245,7 +16568,7 @@ function createFileTools(_config) {
|
|
|
16245
16568
|
},
|
|
16246
16569
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16247
16570
|
const path3 = input.path;
|
|
16248
|
-
if (!
|
|
16571
|
+
if (!existsSync13(path3)) {
|
|
16249
16572
|
return { error: `Path not found: ${path3}` };
|
|
16250
16573
|
}
|
|
16251
16574
|
const stats = await stat(path3);
|
|
@@ -16275,7 +16598,7 @@ function createFileTools(_config) {
|
|
|
16275
16598
|
},
|
|
16276
16599
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16277
16600
|
const filePath = input.path;
|
|
16278
|
-
if (!
|
|
16601
|
+
if (!existsSync13(filePath)) {
|
|
16279
16602
|
return { error: `Image not found: ${filePath}` };
|
|
16280
16603
|
}
|
|
16281
16604
|
const ext = extname(filePath).toLowerCase();
|
|
@@ -16321,7 +16644,7 @@ function createFileTools(_config) {
|
|
|
16321
16644
|
const path3 = input.path;
|
|
16322
16645
|
const oldStr = input.old_str;
|
|
16323
16646
|
const newStr = input.new_str;
|
|
16324
|
-
if (!
|
|
16647
|
+
if (!existsSync13(path3)) {
|
|
16325
16648
|
return { error: `File not found: ${path3}` };
|
|
16326
16649
|
}
|
|
16327
16650
|
const fileStats = await stat(path3);
|
|
@@ -16507,7 +16830,7 @@ var init_web_search_types = __esm({
|
|
|
16507
16830
|
});
|
|
16508
16831
|
|
|
16509
16832
|
// ../openjaw-mcp/dist/tools/shell.js
|
|
16510
|
-
import { spawn } from "node:child_process";
|
|
16833
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
16511
16834
|
import clipboardy from "clipboardy";
|
|
16512
16835
|
import notifier from "node-notifier";
|
|
16513
16836
|
function truncateOutput(text, maxLines = 200) {
|
|
@@ -16773,12 +17096,12 @@ function createShellTools(_config, hooks) {
|
|
|
16773
17096
|
const shell = input.shell ?? true;
|
|
16774
17097
|
if (input.background) {
|
|
16775
17098
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
16776
|
-
const { join:
|
|
17099
|
+
const { join: join49 } = await import("node:path");
|
|
16777
17100
|
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
16778
17101
|
const { createWriteStream: createWriteStream2 } = await import("node:fs");
|
|
16779
17102
|
const taskId = randomUUID15().slice(0, 8);
|
|
16780
|
-
const outputPath =
|
|
16781
|
-
const detached =
|
|
17103
|
+
const outputPath = join49(tmpdir13(), `oj-bg-${taskId}.log`);
|
|
17104
|
+
const detached = spawn2(command, [], {
|
|
16782
17105
|
shell,
|
|
16783
17106
|
cwd,
|
|
16784
17107
|
detached: true,
|
|
@@ -16797,8 +17120,8 @@ function createShellTools(_config, hooks) {
|
|
|
16797
17120
|
message: `Command started in background (PID: ${detached.pid}). Output: ${outputPath}`
|
|
16798
17121
|
};
|
|
16799
17122
|
}
|
|
16800
|
-
return new Promise((
|
|
16801
|
-
const proc =
|
|
17123
|
+
return new Promise((resolve7) => {
|
|
17124
|
+
const proc = spawn2(command, [], {
|
|
16802
17125
|
shell,
|
|
16803
17126
|
cwd,
|
|
16804
17127
|
timeout,
|
|
@@ -16815,7 +17138,7 @@ function createShellTools(_config, hooks) {
|
|
|
16815
17138
|
proc.on("close", (code) => {
|
|
16816
17139
|
const stdoutResult = truncateOutput(stdout.trim());
|
|
16817
17140
|
const stderrResult = truncateOutput(stderr.trim());
|
|
16818
|
-
|
|
17141
|
+
resolve7({
|
|
16819
17142
|
command,
|
|
16820
17143
|
exitCode: code,
|
|
16821
17144
|
stdout: stdoutResult.text,
|
|
@@ -16826,7 +17149,7 @@ function createShellTools(_config, hooks) {
|
|
|
16826
17149
|
});
|
|
16827
17150
|
});
|
|
16828
17151
|
proc.on("error", (error) => {
|
|
16829
|
-
|
|
17152
|
+
resolve7({
|
|
16830
17153
|
command,
|
|
16831
17154
|
exitCode: -1,
|
|
16832
17155
|
stdout: "",
|
|
@@ -16860,8 +17183,8 @@ function createShellTools(_config, hooks) {
|
|
|
16860
17183
|
},
|
|
16861
17184
|
requiresConfirmation: false,
|
|
16862
17185
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16863
|
-
const { writeFileSync: writeFileSync23, unlinkSync:
|
|
16864
|
-
const { join:
|
|
17186
|
+
const { writeFileSync: writeFileSync23, unlinkSync: unlinkSync10 } = await import("node:fs");
|
|
17187
|
+
const { join: join49 } = await import("node:path");
|
|
16865
17188
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
16866
17189
|
const { randomUUID: randomUUID15 } = await import("node:crypto");
|
|
16867
17190
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
@@ -16880,14 +17203,14 @@ function createShellTools(_config, hooks) {
|
|
|
16880
17203
|
const interpreter = interpreterMap[language];
|
|
16881
17204
|
if (!interpreter)
|
|
16882
17205
|
return { error: `Unsupported language: ${language}` };
|
|
16883
|
-
const tmpFile =
|
|
17206
|
+
const tmpFile = join49(tmpdir13(), `oj-code-${randomUUID15().slice(0, 8)}${ext}`);
|
|
16884
17207
|
try {
|
|
16885
17208
|
writeFileSync23(tmpFile, code, "utf-8");
|
|
16886
17209
|
const startTime = Date.now();
|
|
16887
|
-
const result = await new Promise((
|
|
17210
|
+
const result = await new Promise((resolve7) => {
|
|
16888
17211
|
execFile3(interpreter.cmd, [...interpreter.args, tmpFile], { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout2, stderr2) => {
|
|
16889
17212
|
const exitCode = error ? typeof error.code === "number" ? error.code : 1 : 0;
|
|
16890
|
-
|
|
17213
|
+
resolve7({ exitCode, stdout: stdout2 ?? "", stderr: stderr2 ?? "" });
|
|
16891
17214
|
});
|
|
16892
17215
|
});
|
|
16893
17216
|
const executionTimeMs = Date.now() - startTime;
|
|
@@ -16913,7 +17236,7 @@ function createShellTools(_config, hooks) {
|
|
|
16913
17236
|
};
|
|
16914
17237
|
} finally {
|
|
16915
17238
|
try {
|
|
16916
|
-
|
|
17239
|
+
unlinkSync10(tmpFile);
|
|
16917
17240
|
} catch {
|
|
16918
17241
|
}
|
|
16919
17242
|
}
|
|
@@ -16980,7 +17303,7 @@ function createShellTools(_config, hooks) {
|
|
|
16980
17303
|
required: ["title", "message"]
|
|
16981
17304
|
},
|
|
16982
17305
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
16983
|
-
return new Promise((
|
|
17306
|
+
return new Promise((resolve7) => {
|
|
16984
17307
|
notifier.notify({
|
|
16985
17308
|
title: input.title,
|
|
16986
17309
|
message: input.message,
|
|
@@ -16988,9 +17311,9 @@ function createShellTools(_config, hooks) {
|
|
|
16988
17311
|
sound: true
|
|
16989
17312
|
}, (err) => {
|
|
16990
17313
|
if (err) {
|
|
16991
|
-
|
|
17314
|
+
resolve7({ error: err.message });
|
|
16992
17315
|
} else {
|
|
16993
|
-
|
|
17316
|
+
resolve7({ success: true });
|
|
16994
17317
|
}
|
|
16995
17318
|
});
|
|
16996
17319
|
});
|
|
@@ -17094,7 +17417,7 @@ function createShellTools(_config, hooks) {
|
|
|
17094
17417
|
},
|
|
17095
17418
|
execute: /* @__PURE__ */ __name(async (input) => {
|
|
17096
17419
|
const seconds = Math.min(Math.max(0.1, input.seconds), 60);
|
|
17097
|
-
await new Promise((
|
|
17420
|
+
await new Promise((resolve7) => setTimeout(resolve7, seconds * 1e3));
|
|
17098
17421
|
return { waited: seconds, message: `Waited ${seconds} seconds` };
|
|
17099
17422
|
}, "execute")
|
|
17100
17423
|
},
|
|
@@ -18206,7 +18529,7 @@ var init_office_desktop = __esm({
|
|
|
18206
18529
|
return Array.isArray(parsed) ? parsed : [parsed];
|
|
18207
18530
|
}
|
|
18208
18531
|
sleep(ms) {
|
|
18209
|
-
return new Promise((
|
|
18532
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
18210
18533
|
}
|
|
18211
18534
|
};
|
|
18212
18535
|
}
|
|
@@ -19887,7 +20210,7 @@ public class Win32Send {
|
|
|
19887
20210
|
}
|
|
19888
20211
|
}
|
|
19889
20212
|
sleep(ms) {
|
|
19890
|
-
return new Promise((
|
|
20213
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
19891
20214
|
}
|
|
19892
20215
|
};
|
|
19893
20216
|
}
|
|
@@ -19952,7 +20275,7 @@ function getActiveMonitors() {
|
|
|
19952
20275
|
return result;
|
|
19953
20276
|
}
|
|
19954
20277
|
function sleep3(ms) {
|
|
19955
|
-
return new Promise((
|
|
20278
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
19956
20279
|
}
|
|
19957
20280
|
async function fileHash(filePath) {
|
|
19958
20281
|
const data = fs.readFileSync(filePath);
|
|
@@ -20634,6 +20957,224 @@ var init_wechat = __esm({
|
|
|
20634
20957
|
}
|
|
20635
20958
|
});
|
|
20636
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
|
+
|
|
20637
21178
|
// ../openjaw-mcp/dist/tools/categories.js
|
|
20638
21179
|
function categoryForTool2(toolName) {
|
|
20639
21180
|
for (const [prefix, category] of TOOL_PREFIX_MAP) {
|
|
@@ -20655,12 +21196,16 @@ var init_categories = __esm({
|
|
|
20655
21196
|
init_memory();
|
|
20656
21197
|
init_office();
|
|
20657
21198
|
init_wechat();
|
|
21199
|
+
init_workiq();
|
|
20658
21200
|
TOOL_CATEGORIES = {
|
|
20659
21201
|
browser: /* @__PURE__ */ __name((config, browser) => createBrowseTools(config, browser), "browser"),
|
|
20660
21202
|
email: /* @__PURE__ */ __name((config, browser) => createEmailTools(config, browser), "email"),
|
|
20661
21203
|
teams: /* @__PURE__ */ __name((config, browser) => createChatTools(config, browser), "teams"),
|
|
20662
21204
|
files: /* @__PURE__ */ __name((config) => createFileTools(config), "files"),
|
|
20663
|
-
|
|
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"),
|
|
20664
21209
|
memory: /* @__PURE__ */ __name((config) => createMemoryTools(config), "memory"),
|
|
20665
21210
|
office: /* @__PURE__ */ __name((config) => createOfficeTools(config), "office"),
|
|
20666
21211
|
wechat: /* @__PURE__ */ __name((config) => createWeChatTools(config), "wechat")
|
|
@@ -20698,6 +21243,7 @@ var init_categories = __esm({
|
|
|
20698
21243
|
["sleep", "system"],
|
|
20699
21244
|
["ask_user", "system"],
|
|
20700
21245
|
["config", "system"],
|
|
21246
|
+
["workiq_", "system"],
|
|
20701
21247
|
["todo_write", "memory"]
|
|
20702
21248
|
];
|
|
20703
21249
|
__name(categoryForTool2, "categoryForTool");
|
|
@@ -20966,11 +21512,11 @@ var init_registry = __esm({
|
|
|
20966
21512
|
});
|
|
20967
21513
|
|
|
20968
21514
|
// src/prompts/identity.ts
|
|
20969
|
-
import { readFileSync as
|
|
20970
|
-
import { join as
|
|
21515
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
21516
|
+
import { join as join17 } from "node:path";
|
|
20971
21517
|
function getIdentitySection() {
|
|
20972
21518
|
if (cached2 === void 0) {
|
|
20973
|
-
cached2 =
|
|
21519
|
+
cached2 = readFileSync10(join17(packagePromptsDir(), "IDENTITY.md"), "utf8");
|
|
20974
21520
|
}
|
|
20975
21521
|
return cached2;
|
|
20976
21522
|
}
|
|
@@ -20984,11 +21530,11 @@ var init_identity = __esm({
|
|
|
20984
21530
|
});
|
|
20985
21531
|
|
|
20986
21532
|
// src/prompts/reasoning.ts
|
|
20987
|
-
import { readFileSync as
|
|
20988
|
-
import { join as
|
|
21533
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
21534
|
+
import { join as join18 } from "node:path";
|
|
20989
21535
|
function getReasoningSection() {
|
|
20990
21536
|
if (cached3 === void 0) {
|
|
20991
|
-
cached3 =
|
|
21537
|
+
cached3 = readFileSync11(join18(packagePromptsDir(), "REASONING.md"), "utf8");
|
|
20992
21538
|
}
|
|
20993
21539
|
return cached3;
|
|
20994
21540
|
}
|
|
@@ -21002,11 +21548,11 @@ var init_reasoning = __esm({
|
|
|
21002
21548
|
});
|
|
21003
21549
|
|
|
21004
21550
|
// src/prompts/safety.ts
|
|
21005
|
-
import { readFileSync as
|
|
21006
|
-
import { join as
|
|
21551
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
21552
|
+
import { join as join19 } from "node:path";
|
|
21007
21553
|
function getSafetySection() {
|
|
21008
21554
|
if (cached4 === void 0) {
|
|
21009
|
-
cached4 =
|
|
21555
|
+
cached4 = readFileSync12(join19(packagePromptsDir(), "SAFETY.md"), "utf8");
|
|
21010
21556
|
}
|
|
21011
21557
|
return cached4;
|
|
21012
21558
|
}
|
|
@@ -21020,11 +21566,11 @@ var init_safety = __esm({
|
|
|
21020
21566
|
});
|
|
21021
21567
|
|
|
21022
21568
|
// src/prompts/computerUse.ts
|
|
21023
|
-
import { readFileSync as
|
|
21024
|
-
import { join as
|
|
21569
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
21570
|
+
import { join as join20 } from "node:path";
|
|
21025
21571
|
function getComputerUseSection() {
|
|
21026
21572
|
if (cached5 === void 0) {
|
|
21027
|
-
cached5 =
|
|
21573
|
+
cached5 = readFileSync13(join20(packagePromptsDir(), "COMPUTER_USE.md"), "utf8");
|
|
21028
21574
|
}
|
|
21029
21575
|
return cached5;
|
|
21030
21576
|
}
|
|
@@ -21038,19 +21584,19 @@ var init_computerUse = __esm({
|
|
|
21038
21584
|
});
|
|
21039
21585
|
|
|
21040
21586
|
// src/prompts/user.ts
|
|
21041
|
-
import { readFileSync as
|
|
21042
|
-
import { join as
|
|
21043
|
-
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";
|
|
21044
21590
|
function getUserSection() {
|
|
21045
21591
|
if (cached6 === void 0) {
|
|
21046
|
-
if (!
|
|
21047
|
-
const bundledPath =
|
|
21048
|
-
if (
|
|
21049
|
-
if (!
|
|
21050
|
-
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");
|
|
21051
21597
|
}
|
|
21052
21598
|
}
|
|
21053
|
-
cached6 =
|
|
21599
|
+
cached6 = existsSync15(userOverridePath) ? readFileSync14(userOverridePath, "utf8") : null;
|
|
21054
21600
|
}
|
|
21055
21601
|
return cached6;
|
|
21056
21602
|
}
|
|
@@ -21059,8 +21605,8 @@ var init_user = __esm({
|
|
|
21059
21605
|
"src/prompts/user.ts"() {
|
|
21060
21606
|
"use strict";
|
|
21061
21607
|
init_packageRoot();
|
|
21062
|
-
configDir =
|
|
21063
|
-
userOverridePath =
|
|
21608
|
+
configDir = join21(homedir11(), ".openjaw-agent");
|
|
21609
|
+
userOverridePath = join21(configDir, "USER.md");
|
|
21064
21610
|
__name(getUserSection, "getUserSection");
|
|
21065
21611
|
}
|
|
21066
21612
|
});
|
|
@@ -21072,8 +21618,8 @@ __export(memory_exports, {
|
|
|
21072
21618
|
setMemoryPrefetchQuery: () => setMemoryPrefetchQuery,
|
|
21073
21619
|
shouldSkipPrefetch: () => shouldSkipPrefetch
|
|
21074
21620
|
});
|
|
21075
|
-
import { join as
|
|
21076
|
-
import { homedir as
|
|
21621
|
+
import { join as join22 } from "node:path";
|
|
21622
|
+
import { homedir as homedir12 } from "node:os";
|
|
21077
21623
|
function setMemoryPrefetchQuery(query) {
|
|
21078
21624
|
currentQuery = query;
|
|
21079
21625
|
}
|
|
@@ -21124,7 +21670,7 @@ function getMemorySection() {
|
|
|
21124
21670
|
if (shouldSkipPrefetch(currentQuery)) return null;
|
|
21125
21671
|
try {
|
|
21126
21672
|
const { DatabaseSync: DatabaseSync2 } = __require("node:sqlite");
|
|
21127
|
-
const dbPath =
|
|
21673
|
+
const dbPath = join22(homedir12(), ".openjaw", "memory.db");
|
|
21128
21674
|
let db2;
|
|
21129
21675
|
try {
|
|
21130
21676
|
db2 = new DatabaseSync2(dbPath, { readOnly: true });
|
|
@@ -21339,9 +21885,9 @@ var init_frontmatter = __esm({
|
|
|
21339
21885
|
});
|
|
21340
21886
|
|
|
21341
21887
|
// src/skills/registry.ts
|
|
21342
|
-
import { existsSync as
|
|
21343
|
-
import { join as
|
|
21344
|
-
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";
|
|
21345
21891
|
function skillRoots() {
|
|
21346
21892
|
return rootsOverride ?? { bundledDir: packageSkillsDir(), userDir: DEFAULT_USER_DIR };
|
|
21347
21893
|
}
|
|
@@ -21361,7 +21907,7 @@ function loadSkillBody(skillName) {
|
|
|
21361
21907
|
const skill = findSkill(skillName);
|
|
21362
21908
|
if (!skill) return null;
|
|
21363
21909
|
try {
|
|
21364
|
-
const content =
|
|
21910
|
+
const content = readFileSync15(skill.filePath, "utf-8").trim();
|
|
21365
21911
|
const parsed = parseSkillFile(content, `${skill.name}.md`);
|
|
21366
21912
|
return parsed.body;
|
|
21367
21913
|
} catch {
|
|
@@ -21417,7 +21963,7 @@ function normalizeSkillName(name) {
|
|
|
21417
21963
|
function loadFlatSkillsFromDir(dir2, source, priority, out) {
|
|
21418
21964
|
for (const entry of safeReadDir(dir2)) {
|
|
21419
21965
|
if (!entry.isFile() || !isMarkdown(entry.name)) continue;
|
|
21420
|
-
const filePath =
|
|
21966
|
+
const filePath = join23(dir2, entry.name);
|
|
21421
21967
|
const skill = parseSkillAtPath(filePath, dir2, entry.name, source, entry.name);
|
|
21422
21968
|
if (skill) putSkill(out, skill, priority);
|
|
21423
21969
|
}
|
|
@@ -21425,10 +21971,10 @@ function loadFlatSkillsFromDir(dir2, source, priority, out) {
|
|
|
21425
21971
|
function loadPackagedSkillsFromDir(dir2, out) {
|
|
21426
21972
|
for (const entry of safeReadDir(dir2)) {
|
|
21427
21973
|
if (!entry.isDirectory()) continue;
|
|
21428
|
-
const rootDir2 =
|
|
21974
|
+
const rootDir2 = join23(dir2, entry.name);
|
|
21429
21975
|
const entrypoint = findPackageEntrypoint(rootDir2);
|
|
21430
21976
|
if (!entrypoint) continue;
|
|
21431
|
-
const filePath =
|
|
21977
|
+
const filePath = join23(rootDir2, entrypoint);
|
|
21432
21978
|
const skill = parseSkillAtPath(filePath, rootDir2, entrypoint, "user", `${entry.name}.md`);
|
|
21433
21979
|
if (skill) putSkill(out, skill, 2);
|
|
21434
21980
|
}
|
|
@@ -21444,7 +21990,7 @@ function findPackageEntrypoint(dir2) {
|
|
|
21444
21990
|
}
|
|
21445
21991
|
function parseSkillAtPath(filePath, rootDir2, entrypoint, source, fallbackFilename) {
|
|
21446
21992
|
try {
|
|
21447
|
-
const content =
|
|
21993
|
+
const content = readFileSync15(filePath, "utf-8").trim();
|
|
21448
21994
|
if (!content) return null;
|
|
21449
21995
|
const parsed = parseSkillFile(content, fallbackFilename);
|
|
21450
21996
|
const name = normalizeSkillName(parsed.meta.name);
|
|
@@ -21469,7 +22015,7 @@ function putSkill(out, skill, priority) {
|
|
|
21469
22015
|
}
|
|
21470
22016
|
}
|
|
21471
22017
|
function safeReadDir(dir2) {
|
|
21472
|
-
if (!
|
|
22018
|
+
if (!existsSync16(dir2)) return [];
|
|
21473
22019
|
try {
|
|
21474
22020
|
return readdirSync2(dir2, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
21475
22021
|
} catch {
|
|
@@ -21481,11 +22027,11 @@ function buildRegistrySignature() {
|
|
|
21481
22027
|
return [signatureForDir(roots.bundledDir), signatureForDir(roots.userDir)].join("|");
|
|
21482
22028
|
}
|
|
21483
22029
|
function signatureForDir(dir2) {
|
|
21484
|
-
if (!
|
|
22030
|
+
if (!existsSync16(dir2)) return `${dir2}:missing`;
|
|
21485
22031
|
const parts = [];
|
|
21486
22032
|
try {
|
|
21487
22033
|
for (const entry of safeReadDir(dir2)) {
|
|
21488
|
-
const fullPath =
|
|
22034
|
+
const fullPath = join23(dir2, entry.name);
|
|
21489
22035
|
if (entry.isFile()) {
|
|
21490
22036
|
if (!isMarkdown(entry.name)) continue;
|
|
21491
22037
|
parts.push(fileSignature(fullPath, `f:${entry.name}`));
|
|
@@ -21493,7 +22039,7 @@ function signatureForDir(dir2) {
|
|
|
21493
22039
|
parts.push(fileSignature(fullPath, `d:${entry.name}`));
|
|
21494
22040
|
for (const child of safeReadDir(fullPath)) {
|
|
21495
22041
|
if (child.isFile() && isMarkdown(child.name)) {
|
|
21496
|
-
parts.push(fileSignature(
|
|
22042
|
+
parts.push(fileSignature(join23(fullPath, child.name), `d:${entry.name}/${child.name}`));
|
|
21497
22043
|
}
|
|
21498
22044
|
}
|
|
21499
22045
|
}
|
|
@@ -21520,7 +22066,7 @@ var init_registry2 = __esm({
|
|
|
21520
22066
|
"use strict";
|
|
21521
22067
|
init_frontmatter();
|
|
21522
22068
|
init_packageRoot();
|
|
21523
|
-
DEFAULT_USER_DIR =
|
|
22069
|
+
DEFAULT_USER_DIR = join23(homedir13(), ".openjaw-agent", "skills");
|
|
21524
22070
|
ENTRYPOINT_NAMES = ["SKILL.md", "skill.md"];
|
|
21525
22071
|
cachedSkills = null;
|
|
21526
22072
|
rootsOverride = null;
|
|
@@ -21586,9 +22132,9 @@ __export(context_exports, {
|
|
|
21586
22132
|
getContextSection: () => getContextSection,
|
|
21587
22133
|
setActiveBridges: () => setActiveBridges
|
|
21588
22134
|
});
|
|
21589
|
-
import { existsSync as
|
|
22135
|
+
import { existsSync as existsSync17, readFileSync as readFileSync16, readdirSync as readdirSync3 } from "node:fs";
|
|
21590
22136
|
import { execSync as execSync4 } from "node:child_process";
|
|
21591
|
-
import { join as
|
|
22137
|
+
import { join as join24 } from "node:path";
|
|
21592
22138
|
function detectProjectInfo() {
|
|
21593
22139
|
const cwd = process.cwd();
|
|
21594
22140
|
const lines = [];
|
|
@@ -21602,9 +22148,9 @@ function detectProjectInfo() {
|
|
|
21602
22148
|
} catch {
|
|
21603
22149
|
}
|
|
21604
22150
|
try {
|
|
21605
|
-
const pkgPath =
|
|
21606
|
-
if (
|
|
21607
|
-
const pkg = JSON.parse(
|
|
22151
|
+
const pkgPath = join24(cwd, "package.json");
|
|
22152
|
+
if (existsSync17(pkgPath)) {
|
|
22153
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
21608
22154
|
const name = pkg.name || "unknown";
|
|
21609
22155
|
const desc = pkg.description ? ` \u2014 ${pkg.description}`.slice(0, 120) : "";
|
|
21610
22156
|
lines.push(`- Project: ${name}${desc}`);
|
|
@@ -21628,7 +22174,7 @@ function detectProjectInfo() {
|
|
|
21628
22174
|
["package.json", "JavaScript"]
|
|
21629
22175
|
];
|
|
21630
22176
|
for (const [file2, lang] of indicators) {
|
|
21631
|
-
if (
|
|
22177
|
+
if (existsSync17(join24(cwd, file2))) {
|
|
21632
22178
|
lines.push(`- Language: ${lang} (${file2})`);
|
|
21633
22179
|
break;
|
|
21634
22180
|
}
|
|
@@ -21642,9 +22188,9 @@ function detectProjectInfo() {
|
|
|
21642
22188
|
} catch {
|
|
21643
22189
|
}
|
|
21644
22190
|
try {
|
|
21645
|
-
const readmePath =
|
|
21646
|
-
if (
|
|
21647
|
-
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();
|
|
21648
22194
|
if (content.length > 300) content = content.slice(0, 297) + "...";
|
|
21649
22195
|
if (content) lines.push(`- README: ${content}`);
|
|
21650
22196
|
}
|
|
@@ -21753,6 +22299,30 @@ var init_mcp = __esm({
|
|
|
21753
22299
|
}
|
|
21754
22300
|
});
|
|
21755
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
|
+
|
|
21756
22326
|
// src/prompts/index.ts
|
|
21757
22327
|
var prompts_exports = {};
|
|
21758
22328
|
__export(prompts_exports, {
|
|
@@ -21781,6 +22351,7 @@ var init_prompts = __esm({
|
|
|
21781
22351
|
init_skills();
|
|
21782
22352
|
init_context();
|
|
21783
22353
|
init_mcp();
|
|
22354
|
+
init_workiq2();
|
|
21784
22355
|
init_sections();
|
|
21785
22356
|
buildSections = /* @__PURE__ */ __name((opts = {}) => [
|
|
21786
22357
|
// Static sections (cached across calls)
|
|
@@ -21788,6 +22359,7 @@ var init_prompts = __esm({
|
|
|
21788
22359
|
systemPromptSection("reasoning", () => getReasoningSection()),
|
|
21789
22360
|
systemPromptSection("safety", () => getSafetySection()),
|
|
21790
22361
|
systemPromptSection("computerUse", () => getComputerUseSection()),
|
|
22362
|
+
systemPromptSection("workiq", () => getWorkIQSection()),
|
|
21791
22363
|
// Dynamic boundary marker
|
|
21792
22364
|
systemPromptSection("boundary", () => SYSTEM_PROMPT_DYNAMIC_BOUNDARY),
|
|
21793
22365
|
// Dynamic sections (memoized within a resolve cycle via section cache)
|
|
@@ -21907,9 +22479,9 @@ __export(telegram_exports, {
|
|
|
21907
22479
|
TelegramBridge: () => TelegramBridge
|
|
21908
22480
|
});
|
|
21909
22481
|
import TelegramBot from "node-telegram-bot-api";
|
|
21910
|
-
import { writeFileSync as writeFileSync10, unlinkSync as
|
|
21911
|
-
import { join as
|
|
21912
|
-
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";
|
|
21913
22485
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
21914
22486
|
var MAX_TELEGRAM_MSG, MIME_TYPES, TelegramBridge;
|
|
21915
22487
|
var init_telegram = __esm({
|
|
@@ -22110,12 +22682,12 @@ var init_telegram = __esm({
|
|
|
22110
22682
|
Options: ${chunk.choices.join(" | ")}` : "";
|
|
22111
22683
|
await this.bot.sendMessage(chatId, `\u2753 ${question}${choicesText}`);
|
|
22112
22684
|
updateStatus("\u2753 Waiting for your response...");
|
|
22113
|
-
const userReply = await new Promise((
|
|
22114
|
-
this._pendingReplyResolver =
|
|
22685
|
+
const userReply = await new Promise((resolve7) => {
|
|
22686
|
+
this._pendingReplyResolver = resolve7;
|
|
22115
22687
|
setTimeout(() => {
|
|
22116
|
-
if (this._pendingReplyResolver ===
|
|
22688
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
22117
22689
|
this._pendingReplyResolver = null;
|
|
22118
|
-
|
|
22690
|
+
resolve7("[No response \u2014 timed out]");
|
|
22119
22691
|
}
|
|
22120
22692
|
}, 5 * 60 * 1e3);
|
|
22121
22693
|
});
|
|
@@ -22152,7 +22724,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
22152
22724
|
try {
|
|
22153
22725
|
const fileId = voice.file_id;
|
|
22154
22726
|
const filePath = await this.bot.getFileLink(fileId);
|
|
22155
|
-
const tempFile =
|
|
22727
|
+
const tempFile = join25(tmpdir4(), `oj-tg-voice-${randomUUID4().slice(0, 8)}.ogg`);
|
|
22156
22728
|
const response = await fetch(filePath);
|
|
22157
22729
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
22158
22730
|
writeFileSync10(tempFile, buffer);
|
|
@@ -22168,7 +22740,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
22168
22740
|
transcription = "[Could not transcribe voice message. Please type your message instead.]";
|
|
22169
22741
|
}
|
|
22170
22742
|
try {
|
|
22171
|
-
if (
|
|
22743
|
+
if (existsSync18(tempFile)) unlinkSync4(tempFile);
|
|
22172
22744
|
} catch {
|
|
22173
22745
|
}
|
|
22174
22746
|
if (transcription.startsWith("[")) {
|
|
@@ -22226,7 +22798,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
22226
22798
|
const response = await fetch(filePath);
|
|
22227
22799
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
22228
22800
|
const ext = fileName.includes(".") ? "." + fileName.split(".").pop() : "";
|
|
22229
|
-
const tempPath =
|
|
22801
|
+
const tempPath = join25(tmpdir4(), `oj-tg-doc-${randomUUID4().slice(0, 8)}${ext}`);
|
|
22230
22802
|
writeFileSync10(tempPath, buffer);
|
|
22231
22803
|
const text = caption || `I've sent you a file: ${fileName}. It's saved at ${tempPath}. Please analyze it.`;
|
|
22232
22804
|
const fullText = `${text}
|
|
@@ -22234,7 +22806,7 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
22234
22806
|
[File received: ${fileName} (${buffer.length} bytes), saved to: ${tempPath}]`;
|
|
22235
22807
|
await this.handleText(chatId, fullText);
|
|
22236
22808
|
try {
|
|
22237
|
-
if (
|
|
22809
|
+
if (existsSync18(tempPath)) unlinkSync4(tempPath);
|
|
22238
22810
|
} catch {
|
|
22239
22811
|
}
|
|
22240
22812
|
} catch {
|
|
@@ -22260,12 +22832,12 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
22260
22832
|
let match;
|
|
22261
22833
|
while ((match = pattern.exec(normalized)) !== null) {
|
|
22262
22834
|
const filePath = match[1];
|
|
22263
|
-
const resolvedPath = filePath.startsWith("~") ?
|
|
22835
|
+
const resolvedPath = filePath.startsWith("~") ? join25(homedir14(), filePath.slice(1)) : filePath;
|
|
22264
22836
|
if (sentFiles.has(resolvedPath)) continue;
|
|
22265
22837
|
if (filePath.includes("http") || filePath.includes("node_modules")) continue;
|
|
22266
22838
|
const fileName = filePath.split(/[\\/]/).pop() || "";
|
|
22267
22839
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
22268
|
-
if (
|
|
22840
|
+
if (existsSync18(resolvedPath)) {
|
|
22269
22841
|
try {
|
|
22270
22842
|
const { statSync: statSync5 } = await import("node:fs");
|
|
22271
22843
|
const stat2 = statSync5(resolvedPath);
|
|
@@ -22429,26 +23001,27 @@ var init_meta = __esm({
|
|
|
22429
23001
|
// src/mcp-client.ts
|
|
22430
23002
|
var mcp_client_exports = {};
|
|
22431
23003
|
__export(mcp_client_exports, {
|
|
22432
|
-
MCPClientManager: () => MCPClientManager
|
|
23004
|
+
MCPClientManager: () => MCPClientManager,
|
|
23005
|
+
restoreStdinAfterReadlinePrompt: () => restoreStdinAfterReadlinePrompt
|
|
22433
23006
|
});
|
|
22434
23007
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
22435
23008
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
22436
23009
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
22437
23010
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
22438
|
-
import { existsSync as
|
|
22439
|
-
import { join as
|
|
22440
|
-
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";
|
|
22441
23014
|
import { execSync as execSync5 } from "node:child_process";
|
|
22442
23015
|
import { EventEmitter } from "node:events";
|
|
22443
23016
|
import * as readline from "node:readline";
|
|
22444
23017
|
function findCopilotOAuthToken(serverUrl) {
|
|
22445
|
-
if (!
|
|
23018
|
+
if (!existsSync19(COPILOT_OAUTH_DIR)) return null;
|
|
22446
23019
|
try {
|
|
22447
23020
|
const files = readdirSync4(COPILOT_OAUTH_DIR).filter((f) => f.endsWith(".tokens.json"));
|
|
22448
23021
|
for (const file2 of files) {
|
|
22449
|
-
const filePath =
|
|
23022
|
+
const filePath = join26(COPILOT_OAUTH_DIR, file2);
|
|
22450
23023
|
try {
|
|
22451
|
-
const data = JSON.parse(
|
|
23024
|
+
const data = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
22452
23025
|
if (data.scope && data.accessToken) {
|
|
22453
23026
|
const urlDomain = new URL(serverUrl).hostname;
|
|
22454
23027
|
if (data.scope.includes(urlDomain)) {
|
|
@@ -22464,18 +23037,18 @@ function findCopilotOAuthToken(serverUrl) {
|
|
|
22464
23037
|
}
|
|
22465
23038
|
function refreshCopilotToken(refreshToken, tokenFilePath) {
|
|
22466
23039
|
try {
|
|
22467
|
-
const existing = JSON.parse(
|
|
23040
|
+
const existing = JSON.parse(readFileSync18(tokenFilePath, "utf-8"));
|
|
22468
23041
|
const jwtParts = existing.accessToken.split(".");
|
|
22469
23042
|
if (jwtParts.length < 2) return null;
|
|
22470
23043
|
const padded = jwtParts[1] + "=".repeat(4 - jwtParts[1].length % 4);
|
|
22471
23044
|
const claims = JSON.parse(Buffer.from(padded, "base64").toString("utf-8"));
|
|
22472
|
-
const
|
|
23045
|
+
const clientId2 = claims.azp;
|
|
22473
23046
|
const tid = claims.tid;
|
|
22474
23047
|
const aud = claims.aud;
|
|
22475
|
-
if (!
|
|
23048
|
+
if (!clientId2 || !tid || !aud) return null;
|
|
22476
23049
|
const scope = `${aud}/.default offline_access`;
|
|
22477
23050
|
const bodyParams = [
|
|
22478
|
-
`client_id=${
|
|
23051
|
+
`client_id=${clientId2}`,
|
|
22479
23052
|
`grant_type=refresh_token`,
|
|
22480
23053
|
`refresh_token=${encodeURIComponent(refreshToken)}`,
|
|
22481
23054
|
`scope=${encodeURIComponent(scope)}`
|
|
@@ -22535,7 +23108,7 @@ function discoverAllConfigs(cwd) {
|
|
|
22535
23108
|
for (const { name: pluginName, servers } of pluginConfigs) {
|
|
22536
23109
|
addServers(servers, `~/.copilot/.../plugins/${pluginName}/.mcp.json`, "plugin", false);
|
|
22537
23110
|
}
|
|
22538
|
-
const vscodeConfig = readVSCodeMcpConfig(
|
|
23111
|
+
const vscodeConfig = readVSCodeMcpConfig(join26(cwd, ".vscode", "mcp.json"), cwd);
|
|
22539
23112
|
if (vscodeConfig) {
|
|
22540
23113
|
addServers(vscodeConfig, ".vscode/mcp.json", "vscode", false);
|
|
22541
23114
|
}
|
|
@@ -22546,18 +23119,18 @@ function discoverAllConfigs(cwd) {
|
|
|
22546
23119
|
return result;
|
|
22547
23120
|
}
|
|
22548
23121
|
function readMcpConfig(filePath) {
|
|
22549
|
-
if (!
|
|
23122
|
+
if (!existsSync19(filePath)) return null;
|
|
22550
23123
|
try {
|
|
22551
|
-
const raw = JSON.parse(
|
|
23124
|
+
const raw = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
22552
23125
|
return raw.mcpServers || null;
|
|
22553
23126
|
} catch {
|
|
22554
23127
|
return null;
|
|
22555
23128
|
}
|
|
22556
23129
|
}
|
|
22557
23130
|
function readVSCodeMcpConfig(filePath, cwd) {
|
|
22558
|
-
if (!
|
|
23131
|
+
if (!existsSync19(filePath)) return null;
|
|
22559
23132
|
try {
|
|
22560
|
-
const raw = JSON.parse(
|
|
23133
|
+
const raw = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
22561
23134
|
const servers = raw.servers;
|
|
22562
23135
|
if (!servers || typeof servers !== "object") return null;
|
|
22563
23136
|
const result = {};
|
|
@@ -22578,10 +23151,10 @@ function readVSCodeMcpConfig(filePath, cwd) {
|
|
|
22578
23151
|
}
|
|
22579
23152
|
function walkParentsForMcpJson(startDir) {
|
|
22580
23153
|
const results = [];
|
|
22581
|
-
let dir2 =
|
|
22582
|
-
const root =
|
|
23154
|
+
let dir2 = resolve2(startDir);
|
|
23155
|
+
const root = dirname7(dir2) === dir2 ? dir2 : "";
|
|
22583
23156
|
while (dir2 && dir2 !== root) {
|
|
22584
|
-
const filePath =
|
|
23157
|
+
const filePath = join26(dir2, ".mcp.json");
|
|
22585
23158
|
const config = readMcpConfig(filePath);
|
|
22586
23159
|
if (config) {
|
|
22587
23160
|
const filtered = {};
|
|
@@ -22592,20 +23165,20 @@ function walkParentsForMcpJson(startDir) {
|
|
|
22592
23165
|
results.push({ path: filePath, servers: filtered });
|
|
22593
23166
|
}
|
|
22594
23167
|
}
|
|
22595
|
-
const parent =
|
|
23168
|
+
const parent = dirname7(dir2);
|
|
22596
23169
|
if (parent === dir2) break;
|
|
22597
23170
|
dir2 = parent;
|
|
22598
23171
|
}
|
|
22599
23172
|
return results;
|
|
22600
23173
|
}
|
|
22601
23174
|
function discoverCopilotPlugins() {
|
|
22602
|
-
if (!
|
|
23175
|
+
if (!existsSync19(COPILOT_PLUGINS_DIR)) return [];
|
|
22603
23176
|
const results = [];
|
|
22604
23177
|
try {
|
|
22605
23178
|
const entries = readdirSync4(COPILOT_PLUGINS_DIR, { withFileTypes: true });
|
|
22606
23179
|
for (const entry of entries) {
|
|
22607
23180
|
if (!entry.isDirectory()) continue;
|
|
22608
|
-
const mcpPath =
|
|
23181
|
+
const mcpPath = join26(COPILOT_PLUGINS_DIR, entry.name, ".mcp.json");
|
|
22609
23182
|
const config = readMcpConfig(mcpPath);
|
|
22610
23183
|
if (config) {
|
|
22611
23184
|
const filtered = {};
|
|
@@ -22622,9 +23195,9 @@ function discoverCopilotPlugins() {
|
|
|
22622
23195
|
return results;
|
|
22623
23196
|
}
|
|
22624
23197
|
function discoverAgencyBuiltins() {
|
|
22625
|
-
if (!
|
|
23198
|
+
if (!existsSync19(AGENCY_CONFIG) || !existsSync19(AGENCY_EXE)) return {};
|
|
22626
23199
|
try {
|
|
22627
|
-
const content =
|
|
23200
|
+
const content = readFileSync18(AGENCY_CONFIG, "utf-8");
|
|
22628
23201
|
const result = {};
|
|
22629
23202
|
const builtinsMatch = content.match(/\[mcps\.builtins\]([\s\S]*?)(?=\n\[|$)/);
|
|
22630
23203
|
if (!builtinsMatch) return {};
|
|
@@ -22692,17 +23265,17 @@ function truncateDescription(desc, maxLen) {
|
|
|
22692
23265
|
return desc.slice(0, maxLen - 3) + "...";
|
|
22693
23266
|
}
|
|
22694
23267
|
function loadConsent() {
|
|
22695
|
-
if (!
|
|
23268
|
+
if (!existsSync19(OJ_CONSENT_FILE)) {
|
|
22696
23269
|
return { approved: [], denied: [] };
|
|
22697
23270
|
}
|
|
22698
23271
|
try {
|
|
22699
|
-
return JSON.parse(
|
|
23272
|
+
return JSON.parse(readFileSync18(OJ_CONSENT_FILE, "utf-8"));
|
|
22700
23273
|
} catch {
|
|
22701
23274
|
return { approved: [], denied: [] };
|
|
22702
23275
|
}
|
|
22703
23276
|
}
|
|
22704
23277
|
function saveConsent(data) {
|
|
22705
|
-
if (!
|
|
23278
|
+
if (!existsSync19(OJ_AGENT_DIR)) {
|
|
22706
23279
|
mkdirSync11(OJ_AGENT_DIR, { recursive: true });
|
|
22707
23280
|
}
|
|
22708
23281
|
writeFileSync11(OJ_CONSENT_FILE, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
@@ -22713,66 +23286,82 @@ async function promptConsent(servers) {
|
|
|
22713
23286
|
input: process.stdin,
|
|
22714
23287
|
output: process.stderr
|
|
22715
23288
|
});
|
|
22716
|
-
|
|
22717
|
-
|
|
22718
|
-
|
|
22719
|
-
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
console.error(` \x1B[36m\u256D${hLine}\u256E\x1B[0m`);
|
|
22723
|
-
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`);
|
|
22724
|
-
console.error(` \x1B[36m\u251C${hLine}\u2524\x1B[0m`);
|
|
22725
|
-
const bySource = /* @__PURE__ */ new Map();
|
|
22726
|
-
for (const s of servers) {
|
|
22727
|
-
const list = bySource.get(s.source) || [];
|
|
22728
|
-
list.push(s);
|
|
22729
|
-
bySource.set(s.source, list);
|
|
22730
|
-
}
|
|
22731
|
-
for (const [source, sourceServers] of bySource) {
|
|
22732
|
-
const srcLine = `\x1B[2m From ${source}\x1B[0m`;
|
|
22733
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${pad(srcLine, inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22734
|
-
for (const s of sourceServers) {
|
|
22735
|
-
const cmdParts = [s.def.command, ...(s.def.args || []).slice(0, 2)];
|
|
22736
|
-
const cmdStr = cmdParts.join(" ");
|
|
22737
|
-
const truncCmd = cmdStr.length > inner - s.name.length - 12 ? cmdStr.slice(0, inner - s.name.length - 15) + "..." : cmdStr;
|
|
22738
|
-
const serverLine = ` \x1B[33m\u25CB\x1B[0m \x1B[1m${s.name}\x1B[0m \x1B[2m${truncCmd}\x1B[0m`;
|
|
22739
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${pad(serverLine, inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22740
|
-
}
|
|
22741
|
-
console.error(` \x1B[36m\u2502\x1B[0m ${" ".repeat(inner - 1)}\x1B[36m\u2502\x1B[0m`);
|
|
22742
|
-
}
|
|
22743
|
-
console.error(` \x1B[36m\u251C${hLine}\u2524\x1B[0m`);
|
|
22744
|
-
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`);
|
|
22745
|
-
console.error(` \x1B[36m\u2570${hLine}\u256F\x1B[0m`);
|
|
22746
|
-
console.error("");
|
|
22747
|
-
const answer = await ask(" \x1B[36m\u276F\x1B[0m Enable these servers? \x1B[2m(Y/n/s)\x1B[0m: ");
|
|
22748
|
-
const trimmed = answer.trim().toLowerCase();
|
|
22749
|
-
let approved;
|
|
22750
|
-
if (trimmed === "" || trimmed === "y" || trimmed === "yes") {
|
|
22751
|
-
approved = servers.map((s) => s.name);
|
|
22752
|
-
console.error(` \x1B[32m\u25CF All ${approved.length} servers enabled\x1B[0m`);
|
|
22753
|
-
} else if (trimmed === "n" || trimmed === "no") {
|
|
22754
|
-
approved = [];
|
|
22755
|
-
console.error(` \x1B[33m\u25CB All servers skipped\x1B[0m`);
|
|
22756
|
-
} else if (trimmed === "s" || trimmed === "select") {
|
|
22757
|
-
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");
|
|
22758
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();
|
|
22759
23300
|
for (const s of servers) {
|
|
22760
|
-
const
|
|
22761
|
-
|
|
22762
|
-
|
|
22763
|
-
|
|
22764
|
-
|
|
22765
|
-
|
|
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
|
+
}
|
|
22766
23341
|
}
|
|
22767
|
-
|
|
22768
|
-
console.error(`
|
|
23342
|
+
console.error(`
|
|
22769
23343
|
\x1B[32m${approved.length}/${servers.length} servers enabled\x1B[0m`);
|
|
22770
|
-
|
|
22771
|
-
|
|
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 {
|
|
22772
23364
|
}
|
|
22773
|
-
console.error("");
|
|
22774
|
-
rl.close();
|
|
22775
|
-
return approved;
|
|
22776
23365
|
}
|
|
22777
23366
|
function stripAnsi(str) {
|
|
22778
23367
|
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
@@ -22781,14 +23370,14 @@ var OJ_AGENT_DIR, OJ_MCP_CONFIG, OJ_CONSENT_FILE, COPILOT_MCP_CONFIG, COPILOT_PL
|
|
|
22781
23370
|
var init_mcp_client = __esm({
|
|
22782
23371
|
"src/mcp-client.ts"() {
|
|
22783
23372
|
"use strict";
|
|
22784
|
-
OJ_AGENT_DIR =
|
|
22785
|
-
OJ_MCP_CONFIG =
|
|
22786
|
-
OJ_CONSENT_FILE =
|
|
22787
|
-
COPILOT_MCP_CONFIG =
|
|
22788
|
-
COPILOT_PLUGINS_DIR =
|
|
22789
|
-
COPILOT_OAUTH_DIR =
|
|
22790
|
-
AGENCY_CONFIG =
|
|
22791
|
-
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");
|
|
22792
23381
|
SELF_PATTERNS = ["openjaw-mcp/dist/index.js", "openjaw-mcp\\dist\\index.js", "openjaw-agent"];
|
|
22793
23382
|
__name(findCopilotOAuthToken, "findCopilotOAuthToken");
|
|
22794
23383
|
__name(refreshCopilotToken, "refreshCopilotToken");
|
|
@@ -22988,11 +23577,11 @@ var init_mcp_client = __esm({
|
|
|
22988
23577
|
* Add a new MCP server at runtime. Saves to ~/.openjaw-agent/mcp.json and connects.
|
|
22989
23578
|
*/
|
|
22990
23579
|
async addServer(name, def) {
|
|
22991
|
-
if (!
|
|
23580
|
+
if (!existsSync19(OJ_AGENT_DIR)) mkdirSync11(OJ_AGENT_DIR, { recursive: true });
|
|
22992
23581
|
let config = {};
|
|
22993
|
-
if (
|
|
23582
|
+
if (existsSync19(OJ_MCP_CONFIG)) {
|
|
22994
23583
|
try {
|
|
22995
|
-
const raw = JSON.parse(
|
|
23584
|
+
const raw = JSON.parse(readFileSync18(OJ_MCP_CONFIG, "utf-8"));
|
|
22996
23585
|
config = raw.mcpServers || {};
|
|
22997
23586
|
} catch {
|
|
22998
23587
|
}
|
|
@@ -23100,6 +23689,7 @@ var init_mcp_client = __esm({
|
|
|
23100
23689
|
const headers = {};
|
|
23101
23690
|
if (def.env?.AUTHORIZATION) headers["Authorization"] = def.env.AUTHORIZATION;
|
|
23102
23691
|
if (def.env?.AUTH_TOKEN) headers["Authorization"] = `Bearer ${def.env.AUTH_TOKEN}`;
|
|
23692
|
+
if (def.headers) Object.assign(headers, def.headers);
|
|
23103
23693
|
transport = new SSEClientTransport(new URL(def.url), {
|
|
23104
23694
|
requestInit: Object.keys(headers).length > 0 ? { headers } : void 0
|
|
23105
23695
|
});
|
|
@@ -23120,10 +23710,10 @@ var init_mcp_client = __esm({
|
|
|
23120
23710
|
let tokenExpiry = 0;
|
|
23121
23711
|
if (copilotTokenFile) {
|
|
23122
23712
|
try {
|
|
23123
|
-
const
|
|
23124
|
-
cachedToken =
|
|
23125
|
-
cachedRefreshToken =
|
|
23126
|
-
tokenExpiry =
|
|
23713
|
+
const cached8 = JSON.parse(readFileSync18(copilotTokenFile, "utf-8"));
|
|
23714
|
+
cachedToken = cached8.accessToken;
|
|
23715
|
+
cachedRefreshToken = cached8.refreshToken;
|
|
23716
|
+
tokenExpiry = cached8.expiresAt || 0;
|
|
23127
23717
|
} catch {
|
|
23128
23718
|
}
|
|
23129
23719
|
}
|
|
@@ -23163,11 +23753,15 @@ var init_mcp_client = __esm({
|
|
|
23163
23753
|
return globalThis.fetch(url, { ...init, headers });
|
|
23164
23754
|
}, "customFetch");
|
|
23165
23755
|
}
|
|
23756
|
+
const requestHeaders = {};
|
|
23757
|
+
if (staticAuth) requestHeaders["Authorization"] = staticAuth;
|
|
23758
|
+
if (def.headers) Object.assign(requestHeaders, def.headers);
|
|
23166
23759
|
const transportOpts = {};
|
|
23167
23760
|
if (customFetch) {
|
|
23168
23761
|
transportOpts.fetch = customFetch;
|
|
23169
|
-
}
|
|
23170
|
-
|
|
23762
|
+
}
|
|
23763
|
+
if (Object.keys(requestHeaders).length > 0) {
|
|
23764
|
+
transportOpts.requestInit = { headers: requestHeaders };
|
|
23171
23765
|
}
|
|
23172
23766
|
transport = new StreamableHTTPClientTransport(new URL(def.url), transportOpts);
|
|
23173
23767
|
} else {
|
|
@@ -23228,6 +23822,7 @@ var init_mcp_client = __esm({
|
|
|
23228
23822
|
__name(loadConsent, "loadConsent");
|
|
23229
23823
|
__name(saveConsent, "saveConsent");
|
|
23230
23824
|
__name(promptConsent, "promptConsent");
|
|
23825
|
+
__name(restoreStdinAfterReadlinePrompt, "restoreStdinAfterReadlinePrompt");
|
|
23231
23826
|
__name(stripAnsi, "stripAnsi");
|
|
23232
23827
|
}
|
|
23233
23828
|
});
|
|
@@ -23558,13 +24153,13 @@ __export(scheduler_exports, {
|
|
|
23558
24153
|
stopAllTasks: () => stopAllTasks,
|
|
23559
24154
|
stopTask: () => stopTask
|
|
23560
24155
|
});
|
|
23561
|
-
import { readFileSync as
|
|
23562
|
-
import { join as
|
|
23563
|
-
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";
|
|
23564
24159
|
function getJobsPath() {
|
|
23565
|
-
const dir2 =
|
|
23566
|
-
if (!
|
|
23567
|
-
return
|
|
24160
|
+
const dir2 = join27(homedir16(), ".openjaw-agent");
|
|
24161
|
+
if (!existsSync20(dir2)) mkdirSync12(dir2, { recursive: true });
|
|
24162
|
+
return join27(dir2, "cron-jobs.json");
|
|
23568
24163
|
}
|
|
23569
24164
|
function parseInterval(input) {
|
|
23570
24165
|
const match = input.match(/^(\d+)\s*(s|sec|seconds?|m|min|minutes?|h|hr|hours?|d|day|days?)$/i);
|
|
@@ -23701,9 +24296,9 @@ function saveJobs() {
|
|
|
23701
24296
|
}
|
|
23702
24297
|
function loadJobs() {
|
|
23703
24298
|
const path3 = getJobsPath();
|
|
23704
|
-
if (!
|
|
24299
|
+
if (!existsSync20(path3)) return [];
|
|
23705
24300
|
try {
|
|
23706
|
-
const raw =
|
|
24301
|
+
const raw = readFileSync19(path3, "utf8");
|
|
23707
24302
|
return JSON.parse(raw);
|
|
23708
24303
|
} catch {
|
|
23709
24304
|
return [];
|
|
@@ -23935,10 +24530,10 @@ __export(repl_exports, {
|
|
|
23935
24530
|
});
|
|
23936
24531
|
import * as readline2 from "readline";
|
|
23937
24532
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
23938
|
-
import { existsSync as
|
|
23939
|
-
import { join as
|
|
23940
|
-
import { homedir as
|
|
23941
|
-
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";
|
|
23942
24537
|
async function selectPrompt(message, choices, defaultIdx) {
|
|
23943
24538
|
const { default: select } = await import("@inquirer/select");
|
|
23944
24539
|
return select({ message, choices, default: defaultIdx });
|
|
@@ -23954,8 +24549,8 @@ async function loadPrompts(promptsDir) {
|
|
|
23954
24549
|
const files = ["IDENTITY.md", "REASONING.md", "COMPUTER_USE.md", "SAFETY.md", "USER.md"];
|
|
23955
24550
|
const parts = [];
|
|
23956
24551
|
for (const file2 of files) {
|
|
23957
|
-
const path3 =
|
|
23958
|
-
if (
|
|
24552
|
+
const path3 = join28(promptsDir, file2);
|
|
24553
|
+
if (existsSync21(path3)) {
|
|
23959
24554
|
const content = await readFile4(path3, "utf8");
|
|
23960
24555
|
parts.push(content);
|
|
23961
24556
|
}
|
|
@@ -23971,11 +24566,11 @@ async function loadPrompts(promptsDir) {
|
|
|
23971
24566
|
}
|
|
23972
24567
|
async function loadMemorySummary() {
|
|
23973
24568
|
const memoryPaths = [
|
|
23974
|
-
|
|
23975
|
-
|
|
24569
|
+
join28(homedir17(), ".openjaw", "MEMORY.md"),
|
|
24570
|
+
join28(homedir17(), ".openjaw", "memory", "MEMORY.md")
|
|
23976
24571
|
];
|
|
23977
24572
|
for (const memoryPath of memoryPaths) {
|
|
23978
|
-
if (
|
|
24573
|
+
if (existsSync21(memoryPath)) {
|
|
23979
24574
|
const content = await readFile4(memoryPath, "utf8");
|
|
23980
24575
|
return content.slice(0, 2e3);
|
|
23981
24576
|
}
|
|
@@ -23983,8 +24578,8 @@ async function loadMemorySummary() {
|
|
|
23983
24578
|
return "";
|
|
23984
24579
|
}
|
|
23985
24580
|
async function startREPL(resumeSessionId) {
|
|
23986
|
-
const promptsDir =
|
|
23987
|
-
const packagePromptsDir2 =
|
|
24581
|
+
const promptsDir = join28(__dirname2, "..", "prompts");
|
|
24582
|
+
const packagePromptsDir2 = existsSync21(promptsDir) ? promptsDir : join28(homedir17(), ".openjaw-agent", "prompts");
|
|
23988
24583
|
await ensureDirectories();
|
|
23989
24584
|
const config = await loadConfig();
|
|
23990
24585
|
const systemPrompt = await loadPrompts(packagePromptsDir2);
|
|
@@ -24548,8 +25143,8 @@ var init_repl = __esm({
|
|
|
24548
25143
|
init_connect();
|
|
24549
25144
|
init_scheduler();
|
|
24550
25145
|
__name(selectPrompt, "selectPrompt");
|
|
24551
|
-
__filename2 =
|
|
24552
|
-
__dirname2 =
|
|
25146
|
+
__filename2 = fileURLToPath5(import.meta.url);
|
|
25147
|
+
__dirname2 = dirname8(__filename2);
|
|
24553
25148
|
C = {
|
|
24554
25149
|
reset: "\x1B[0m",
|
|
24555
25150
|
dim: "\x1B[2m",
|
|
@@ -24574,9 +25169,9 @@ var init_repl = __esm({
|
|
|
24574
25169
|
});
|
|
24575
25170
|
|
|
24576
25171
|
// src/voice/tts.ts
|
|
24577
|
-
import { execSync as execSync6, spawn as
|
|
24578
|
-
import { existsSync as
|
|
24579
|
-
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";
|
|
24580
25175
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
24581
25176
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
24582
25177
|
function hasEdgeTts() {
|
|
@@ -24630,8 +25225,8 @@ async function listVoices() {
|
|
|
24630
25225
|
}
|
|
24631
25226
|
}
|
|
24632
25227
|
async function speakEdgeTts(text, voice, options) {
|
|
24633
|
-
if (!
|
|
24634
|
-
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`);
|
|
24635
25230
|
let playerProc = null;
|
|
24636
25231
|
let stopped = false;
|
|
24637
25232
|
try {
|
|
@@ -24643,9 +25238,9 @@ async function speakEdgeTts(text, voice, options) {
|
|
|
24643
25238
|
timeout: 15e3,
|
|
24644
25239
|
stdio: ["pipe", "pipe", "pipe"]
|
|
24645
25240
|
});
|
|
24646
|
-
if (stopped || !
|
|
25241
|
+
if (stopped || !existsSync22(audioFile)) return { stop: /* @__PURE__ */ __name(() => {
|
|
24647
25242
|
}, "stop") };
|
|
24648
|
-
playerProc =
|
|
25243
|
+
playerProc = spawn4("powershell.exe", [
|
|
24649
25244
|
"-NoProfile",
|
|
24650
25245
|
"-Command",
|
|
24651
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()`
|
|
@@ -24655,14 +25250,14 @@ async function speakEdgeTts(text, voice, options) {
|
|
|
24655
25250
|
});
|
|
24656
25251
|
playerProc.on("exit", () => {
|
|
24657
25252
|
try {
|
|
24658
|
-
if (
|
|
25253
|
+
if (existsSync22(audioFile)) unlinkSync5(audioFile);
|
|
24659
25254
|
} catch {
|
|
24660
25255
|
}
|
|
24661
25256
|
playerProc = null;
|
|
24662
25257
|
});
|
|
24663
25258
|
} catch {
|
|
24664
25259
|
try {
|
|
24665
|
-
if (
|
|
25260
|
+
if (existsSync22(audioFile)) unlinkSync5(audioFile);
|
|
24666
25261
|
} catch {
|
|
24667
25262
|
}
|
|
24668
25263
|
}
|
|
@@ -24674,7 +25269,7 @@ async function speakEdgeTts(text, voice, options) {
|
|
|
24674
25269
|
playerProc = null;
|
|
24675
25270
|
}
|
|
24676
25271
|
try {
|
|
24677
|
-
if (
|
|
25272
|
+
if (existsSync22(audioFile)) unlinkSync5(audioFile);
|
|
24678
25273
|
} catch {
|
|
24679
25274
|
}
|
|
24680
25275
|
}, "stop")
|
|
@@ -24691,7 +25286,7 @@ $synth.Speak('${safeText}')
|
|
|
24691
25286
|
$synth.Dispose()
|
|
24692
25287
|
`;
|
|
24693
25288
|
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
24694
|
-
const proc =
|
|
25289
|
+
const proc = spawn4("powershell.exe", ["-NoProfile", "-EncodedCommand", encoded], {
|
|
24695
25290
|
stdio: ["pipe", "pipe", "pipe"],
|
|
24696
25291
|
windowsHide: true
|
|
24697
25292
|
});
|
|
@@ -24713,7 +25308,7 @@ var init_tts = __esm({
|
|
|
24713
25308
|
"use strict";
|
|
24714
25309
|
DEFAULT_VOICE_EN = "en-US-AriaNeural";
|
|
24715
25310
|
DEFAULT_VOICE_ZH = "zh-CN-XiaoxiaoNeural";
|
|
24716
|
-
TTS_TEMP_DIR =
|
|
25311
|
+
TTS_TEMP_DIR = join29(tmpdir5(), "oj-tts");
|
|
24717
25312
|
edgeTtsAvailable = null;
|
|
24718
25313
|
__name(hasEdgeTts, "hasEdgeTts");
|
|
24719
25314
|
__name(ensureEdgeTts, "ensureEdgeTts");
|
|
@@ -24727,13 +25322,13 @@ var init_tts = __esm({
|
|
|
24727
25322
|
});
|
|
24728
25323
|
|
|
24729
25324
|
// src/voice/stt.ts
|
|
24730
|
-
import { spawn as
|
|
24731
|
-
import { join as
|
|
25325
|
+
import { spawn as spawn5, execSync as execSync7 } from "node:child_process";
|
|
25326
|
+
import { join as join30 } from "node:path";
|
|
24732
25327
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
24733
|
-
import { existsSync as
|
|
25328
|
+
import { existsSync as existsSync23, unlinkSync as unlinkSync6 } from "node:fs";
|
|
24734
25329
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
24735
25330
|
async function listenOnce(timeoutSeconds = 10, language = "en-US") {
|
|
24736
|
-
const resultFile =
|
|
25331
|
+
const resultFile = join30(tmpdir6(), `oj-stt-${randomUUID6().slice(0, 8)}.txt`);
|
|
24737
25332
|
const script = `
|
|
24738
25333
|
$ProgressPreference = 'SilentlyContinue'
|
|
24739
25334
|
$ErrorActionPreference = 'Stop'
|
|
@@ -24768,8 +25363,8 @@ try {
|
|
|
24768
25363
|
}
|
|
24769
25364
|
`;
|
|
24770
25365
|
const encoded = Buffer.from(script, "utf16le").toString("base64");
|
|
24771
|
-
return new Promise((
|
|
24772
|
-
const proc =
|
|
25366
|
+
return new Promise((resolve7) => {
|
|
25367
|
+
const proc = spawn5("powershell.exe", ["-NoProfile", "-STA", "-EncodedCommand", encoded], {
|
|
24773
25368
|
stdio: ["pipe", "pipe", "pipe"],
|
|
24774
25369
|
windowsHide: true
|
|
24775
25370
|
});
|
|
@@ -24783,25 +25378,25 @@ try {
|
|
|
24783
25378
|
});
|
|
24784
25379
|
const timer = setTimeout(() => {
|
|
24785
25380
|
if (!proc.killed) proc.kill();
|
|
24786
|
-
|
|
25381
|
+
resolve7(null);
|
|
24787
25382
|
}, (timeoutSeconds + 5) * 1e3);
|
|
24788
25383
|
proc.on("exit", () => {
|
|
24789
25384
|
clearTimeout(timer);
|
|
24790
25385
|
const output = stdout.replace(/#< CLIXML[\s\S]*/m, "").trim();
|
|
24791
25386
|
if (output === "NO_SPEECH" || output.startsWith("ERROR") || !output) {
|
|
24792
|
-
|
|
25387
|
+
resolve7(null);
|
|
24793
25388
|
return;
|
|
24794
25389
|
}
|
|
24795
25390
|
const parts = output.split("|");
|
|
24796
25391
|
const text = parts[0]?.trim();
|
|
24797
25392
|
const confidence = parseFloat(parts[1] || "0");
|
|
24798
25393
|
if (text) {
|
|
24799
|
-
|
|
25394
|
+
resolve7({ text, confidence: isNaN(confidence) ? 0.5 : confidence });
|
|
24800
25395
|
} else {
|
|
24801
|
-
|
|
25396
|
+
resolve7(null);
|
|
24802
25397
|
}
|
|
24803
25398
|
try {
|
|
24804
|
-
if (
|
|
25399
|
+
if (existsSync23(resultFile)) unlinkSync6(resultFile);
|
|
24805
25400
|
} catch {
|
|
24806
25401
|
}
|
|
24807
25402
|
});
|
|
@@ -25035,9 +25630,9 @@ __export(clipboard_image_exports, {
|
|
|
25035
25630
|
readClipboardImage: () => readClipboardImage
|
|
25036
25631
|
});
|
|
25037
25632
|
import { execSync as execSync8 } from "node:child_process";
|
|
25038
|
-
import { join as
|
|
25633
|
+
import { join as join31 } from "node:path";
|
|
25039
25634
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
25040
|
-
import { readFileSync as
|
|
25635
|
+
import { readFileSync as readFileSync21, unlinkSync as unlinkSync7, existsSync as existsSync24 } from "node:fs";
|
|
25041
25636
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
25042
25637
|
function encodePS(script) {
|
|
25043
25638
|
return Buffer.from(script, "utf16le").toString("base64");
|
|
@@ -25062,7 +25657,7 @@ Add-Type -AssemblyName System.Windows.Forms
|
|
|
25062
25657
|
}
|
|
25063
25658
|
function readClipboardImage() {
|
|
25064
25659
|
try {
|
|
25065
|
-
const tempPath =
|
|
25660
|
+
const tempPath = join31(tmpdir7(), `oj-clip-${randomUUID7().slice(0, 8)}.png`);
|
|
25066
25661
|
const script = `
|
|
25067
25662
|
$ProgressPreference = 'SilentlyContinue'
|
|
25068
25663
|
$ErrorActionPreference = 'Stop'
|
|
@@ -25079,16 +25674,16 @@ $img.Dispose()
|
|
|
25079
25674
|
{ encoding: "utf-8", timeout: 8e3, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }
|
|
25080
25675
|
).trim();
|
|
25081
25676
|
const clean = output.replace(/#< CLIXML[\s\S]*/m, "").trim();
|
|
25082
|
-
if (clean === "NO_IMAGE" || !
|
|
25677
|
+
if (clean === "NO_IMAGE" || !existsSync24(tempPath)) {
|
|
25083
25678
|
return null;
|
|
25084
25679
|
}
|
|
25085
25680
|
const match = clean.match(/(\d+)x(\d+)/);
|
|
25086
25681
|
const width = match ? parseInt(match[1], 10) : 0;
|
|
25087
25682
|
const height = match ? parseInt(match[2], 10) : 0;
|
|
25088
|
-
const buffer =
|
|
25683
|
+
const buffer = readFileSync21(tempPath);
|
|
25089
25684
|
const base64 = buffer.toString("base64");
|
|
25090
25685
|
try {
|
|
25091
|
-
|
|
25686
|
+
unlinkSync7(tempPath);
|
|
25092
25687
|
} catch {
|
|
25093
25688
|
}
|
|
25094
25689
|
return { base64, mimeType: "image/png", width, height };
|
|
@@ -25914,9 +26509,9 @@ __export(pet_exports, {
|
|
|
25914
26509
|
getRandomReaction: () => getRandomReaction,
|
|
25915
26510
|
renamePet: () => renamePet
|
|
25916
26511
|
});
|
|
25917
|
-
import { existsSync as
|
|
25918
|
-
import { join as
|
|
25919
|
-
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";
|
|
25920
26515
|
function hashCode(str) {
|
|
25921
26516
|
let hash3 = 0;
|
|
25922
26517
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -25934,20 +26529,20 @@ function seededRandom(seed) {
|
|
|
25934
26529
|
};
|
|
25935
26530
|
}
|
|
25936
26531
|
function getPetPath() {
|
|
25937
|
-
return
|
|
26532
|
+
return join32(homedir18(), ".openjaw-agent", "pet.json");
|
|
25938
26533
|
}
|
|
25939
26534
|
function loadStoredPet() {
|
|
25940
26535
|
const path3 = getPetPath();
|
|
25941
|
-
if (!
|
|
26536
|
+
if (!existsSync25(path3)) return null;
|
|
25942
26537
|
try {
|
|
25943
|
-
return JSON.parse(
|
|
26538
|
+
return JSON.parse(readFileSync22(path3, "utf-8"));
|
|
25944
26539
|
} catch {
|
|
25945
26540
|
return null;
|
|
25946
26541
|
}
|
|
25947
26542
|
}
|
|
25948
26543
|
function saveStoredPet(data) {
|
|
25949
|
-
const dir2 =
|
|
25950
|
-
if (!
|
|
26544
|
+
const dir2 = join32(homedir18(), ".openjaw-agent");
|
|
26545
|
+
if (!existsSync25(dir2)) mkdirSync15(dir2, { recursive: true });
|
|
25951
26546
|
writeFileSync14(getPetPath(), JSON.stringify(data, null, 2), "utf-8");
|
|
25952
26547
|
}
|
|
25953
26548
|
function generatePet(userId) {
|
|
@@ -26496,34 +27091,34 @@ ${output}
|
|
|
26496
27091
|
}
|
|
26497
27092
|
}
|
|
26498
27093
|
function expandUrl(ref, warnings) {
|
|
26499
|
-
return new Promise((
|
|
27094
|
+
return new Promise((resolve7) => {
|
|
26500
27095
|
const url = ref.target;
|
|
26501
27096
|
const mod = url.startsWith("https") ? https : http;
|
|
26502
27097
|
const req = mod.get(url, { timeout: 15e3 }, (res) => {
|
|
26503
27098
|
if (res.statusCode && (res.statusCode >= 300 && res.statusCode < 400) && res.headers.location) {
|
|
26504
27099
|
const redirectMod = res.headers.location.startsWith("https") ? https : http;
|
|
26505
27100
|
const req2 = redirectMod.get(res.headers.location, { timeout: 15e3 }, (res2) => {
|
|
26506
|
-
collectResponse(res2, ref, warnings,
|
|
27101
|
+
collectResponse(res2, ref, warnings, resolve7);
|
|
26507
27102
|
});
|
|
26508
27103
|
req2.on("error", (e) => {
|
|
26509
27104
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26510
|
-
|
|
27105
|
+
resolve7(null);
|
|
26511
27106
|
});
|
|
26512
27107
|
return;
|
|
26513
27108
|
}
|
|
26514
|
-
collectResponse(res, ref, warnings,
|
|
27109
|
+
collectResponse(res, ref, warnings, resolve7);
|
|
26515
27110
|
});
|
|
26516
27111
|
req.on("error", (e) => {
|
|
26517
27112
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26518
|
-
|
|
27113
|
+
resolve7(null);
|
|
26519
27114
|
});
|
|
26520
27115
|
});
|
|
26521
27116
|
}
|
|
26522
|
-
function collectResponse(res, ref, warnings,
|
|
27117
|
+
function collectResponse(res, ref, warnings, resolve7) {
|
|
26523
27118
|
if (res.statusCode && res.statusCode >= 400) {
|
|
26524
27119
|
warnings.push(`\u26A0\uFE0F @url returned HTTP ${res.statusCode}: ${ref.target}`);
|
|
26525
27120
|
res.resume();
|
|
26526
|
-
|
|
27121
|
+
resolve7(null);
|
|
26527
27122
|
return;
|
|
26528
27123
|
}
|
|
26529
27124
|
const chunks = [];
|
|
@@ -26535,14 +27130,14 @@ function collectResponse(res, ref, warnings, resolve6) {
|
|
|
26535
27130
|
text = text.slice(0, 5e4) + "\n\u2026 (truncated)";
|
|
26536
27131
|
}
|
|
26537
27132
|
const tokens = estimateTokens2(text);
|
|
26538
|
-
|
|
27133
|
+
resolve7(`\u{1F310} @url:${ref.target} (${tokens} tokens)
|
|
26539
27134
|
\`\`\`
|
|
26540
27135
|
${text}
|
|
26541
27136
|
\`\`\``);
|
|
26542
27137
|
});
|
|
26543
27138
|
res.on("error", (e) => {
|
|
26544
27139
|
warnings.push(`\u26A0\uFE0F @url fetch error: ${e.message}`);
|
|
26545
|
-
|
|
27140
|
+
resolve7(null);
|
|
26546
27141
|
});
|
|
26547
27142
|
}
|
|
26548
27143
|
function stripHtml(html) {
|
|
@@ -27043,13 +27638,13 @@ Type /resume <id> to resume.` });
|
|
|
27043
27638
|
if (input === "/export") {
|
|
27044
27639
|
try {
|
|
27045
27640
|
const { writeFile: writeFile5, mkdir: mkdir5 } = await import("node:fs/promises");
|
|
27046
|
-
const { join:
|
|
27047
|
-
const { homedir:
|
|
27048
|
-
const { existsSync:
|
|
27049
|
-
const exportDir =
|
|
27050
|
-
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 });
|
|
27051
27646
|
const filename = `session-${agentLoop.sessionId}.md`;
|
|
27052
|
-
const filepath =
|
|
27647
|
+
const filepath = join49(exportDir, filename);
|
|
27053
27648
|
const lines = [
|
|
27054
27649
|
`# OpenJaw Agent Session ${agentLoop.sessionId}`,
|
|
27055
27650
|
`Date: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -27268,9 +27863,9 @@ ${list}` });
|
|
|
27268
27863
|
const cmd = lang === "python" ? "python" : lang === "node" ? "node" : "pwsh";
|
|
27269
27864
|
const args = lang === "python" ? ["-i", "-u"] : lang === "node" ? ["-i"] : ["-NoProfile", "-NoLogo"];
|
|
27270
27865
|
try {
|
|
27271
|
-
const { spawn:
|
|
27866
|
+
const { spawn: spawn10 } = await import("node:child_process");
|
|
27272
27867
|
if (replRef.current) replRef.current.kill();
|
|
27273
|
-
const proc =
|
|
27868
|
+
const proc = spawn10(cmd, args, {
|
|
27274
27869
|
stdio: ["pipe", "pipe", "pipe"],
|
|
27275
27870
|
windowsHide: true
|
|
27276
27871
|
});
|
|
@@ -27310,7 +27905,7 @@ ${list}` });
|
|
|
27310
27905
|
if (replRef.current && replLangRef.current && !input.startsWith("/")) {
|
|
27311
27906
|
const proc = replRef.current;
|
|
27312
27907
|
proc.stdin?.write(input + "\n");
|
|
27313
|
-
await new Promise((
|
|
27908
|
+
await new Promise((resolve7) => setTimeout(resolve7, 800));
|
|
27314
27909
|
const flush = proc._ojFlush;
|
|
27315
27910
|
const output = flush ? flush() : "";
|
|
27316
27911
|
if (output.trim()) {
|
|
@@ -27624,14 +28219,14 @@ Options: ${chunk.choices.join(" | ")}` : chunk.content;
|
|
|
27624
28219
|
waitingForAskUserRef.current = true;
|
|
27625
28220
|
setIsRunning(false);
|
|
27626
28221
|
setWaitingForAskUser(true);
|
|
27627
|
-
await new Promise((
|
|
28222
|
+
await new Promise((resolve7) => {
|
|
27628
28223
|
const checkInterval = setInterval(() => {
|
|
27629
28224
|
if (!waitingForAskUserRef.current || !agentLoop.isWaitingForAskUser) {
|
|
27630
28225
|
clearInterval(checkInterval);
|
|
27631
28226
|
waitingForAskUserRef.current = false;
|
|
27632
28227
|
setWaitingForAskUser(false);
|
|
27633
28228
|
setIsRunning(true);
|
|
27634
|
-
|
|
28229
|
+
resolve7();
|
|
27635
28230
|
}
|
|
27636
28231
|
}, 200);
|
|
27637
28232
|
});
|
|
@@ -27906,7 +28501,7 @@ var skill_tool_exports = {};
|
|
|
27906
28501
|
__export(skill_tool_exports, {
|
|
27907
28502
|
createSkillTool: () => createSkillTool
|
|
27908
28503
|
});
|
|
27909
|
-
import { readFileSync as
|
|
28504
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "node:fs";
|
|
27910
28505
|
function resolveSkillTimeoutMs() {
|
|
27911
28506
|
const raw = process.env["OPENJAW_SKILL_TIMEOUT_MS"];
|
|
27912
28507
|
const parsed = raw ? Number(raw) : NaN;
|
|
@@ -27927,8 +28522,8 @@ async function withTimeout(promise, ms) {
|
|
|
27927
28522
|
try {
|
|
27928
28523
|
return await Promise.race([
|
|
27929
28524
|
promise,
|
|
27930
|
-
new Promise((
|
|
27931
|
-
timeoutId = setTimeout(() =>
|
|
28525
|
+
new Promise((resolve7) => {
|
|
28526
|
+
timeoutId = setTimeout(() => resolve7(SKILL_TIMEOUT), ms);
|
|
27932
28527
|
})
|
|
27933
28528
|
]);
|
|
27934
28529
|
} finally {
|
|
@@ -28074,7 +28669,7 @@ function extractLessons(chunks) {
|
|
|
28074
28669
|
}
|
|
28075
28670
|
function appendLessonsLearned(skillPath, lessons) {
|
|
28076
28671
|
try {
|
|
28077
|
-
const content =
|
|
28672
|
+
const content = readFileSync24(skillPath, "utf8");
|
|
28078
28673
|
const datestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
28079
28674
|
if (content.includes("## Lessons Learned")) {
|
|
28080
28675
|
const updated = content.replace(
|
|
@@ -28119,9 +28714,9 @@ var teams_exports = {};
|
|
|
28119
28714
|
__export(teams_exports, {
|
|
28120
28715
|
TeamsBridge: () => TeamsBridge
|
|
28121
28716
|
});
|
|
28122
|
-
import { readFileSync as
|
|
28123
|
-
import { join as
|
|
28124
|
-
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";
|
|
28125
28720
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28126
28721
|
var AGENT_PREFIX, POLL_INTERVAL, TeamsBridge;
|
|
28127
28722
|
var init_teams = __esm({
|
|
@@ -28209,7 +28804,7 @@ var init_teams = __esm({
|
|
|
28209
28804
|
const { resizeImageFileForAgent: resizeImageFileForAgent2 } = await Promise.resolve().then(() => (init_image_resize(), image_resize_exports));
|
|
28210
28805
|
imageData = await resizeImageFileForAgent2(imageFile);
|
|
28211
28806
|
} catch {
|
|
28212
|
-
const imgBuffer =
|
|
28807
|
+
const imgBuffer = readFileSync25(imageFile);
|
|
28213
28808
|
const ext = imageFile.split(".").pop()?.toLowerCase() || "png";
|
|
28214
28809
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : ext === "webp" ? "image/webp" : "image/png";
|
|
28215
28810
|
imageData = { base64: imgBuffer.toString("base64"), mimeType };
|
|
@@ -28285,7 +28880,7 @@ var init_teams = __esm({
|
|
|
28285
28880
|
const resp = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
28286
28881
|
if (!resp.ok) return null;
|
|
28287
28882
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
28288
|
-
const tempPath =
|
|
28883
|
+
const tempPath = join34(tmpdir8(), `oj-teams-${randomUUID8().slice(0, 6)}-${filename}`);
|
|
28289
28884
|
writeFileSync16(tempPath, buffer);
|
|
28290
28885
|
return tempPath;
|
|
28291
28886
|
} catch {
|
|
@@ -28300,7 +28895,7 @@ var init_teams = __esm({
|
|
|
28300
28895
|
const contentType = resp.headers.get("content-type") ?? "image/png";
|
|
28301
28896
|
const ext = contentType.includes("jpeg") ? ".jpg" : contentType.includes("gif") ? ".gif" : ".png";
|
|
28302
28897
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
28303
|
-
const tempPath =
|
|
28898
|
+
const tempPath = join34(tmpdir8(), `oj-teams-img-${randomUUID8().slice(0, 6)}${ext}`);
|
|
28304
28899
|
writeFileSync16(tempPath, buffer);
|
|
28305
28900
|
return tempPath;
|
|
28306
28901
|
} catch {
|
|
@@ -28341,7 +28936,7 @@ var init_teams = __esm({
|
|
|
28341
28936
|
async sendFileToSelfChat(filePath) {
|
|
28342
28937
|
const token = this.getGraphToken();
|
|
28343
28938
|
const fileName = filePath.split(/[\\/]/).pop() || "file";
|
|
28344
|
-
const fileBuffer =
|
|
28939
|
+
const fileBuffer = readFileSync25(filePath);
|
|
28345
28940
|
const uploadResp = await fetch(
|
|
28346
28941
|
`https://graph.microsoft.com/v1.0/me/drive/root:/OpenJaw-Shared/${fileName}:/content`,
|
|
28347
28942
|
{
|
|
@@ -28394,7 +28989,7 @@ var init_teams = __esm({
|
|
|
28394
28989
|
if (filePath.includes("http") || filePath.includes("node_modules")) continue;
|
|
28395
28990
|
const fileName = filePath.split(/[\\/]/).pop() || "";
|
|
28396
28991
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
28397
|
-
if (
|
|
28992
|
+
if (existsSync27(filePath)) {
|
|
28398
28993
|
try {
|
|
28399
28994
|
const { statSync: statSync5 } = await import("node:fs");
|
|
28400
28995
|
const stat2 = statSync5(filePath);
|
|
@@ -28412,9 +29007,9 @@ var init_teams = __esm({
|
|
|
28412
29007
|
}
|
|
28413
29008
|
/** Get Graph access token from disk. */
|
|
28414
29009
|
getGraphToken() {
|
|
28415
|
-
const tokenPath =
|
|
28416
|
-
if (!
|
|
28417
|
-
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"));
|
|
28418
29013
|
if (!data.access_token) throw new Error("No access_token");
|
|
28419
29014
|
return data.access_token;
|
|
28420
29015
|
}
|
|
@@ -28538,12 +29133,12 @@ var init_teams = __esm({
|
|
|
28538
29133
|
Options: ${chunk.choices.join(" | ")}` : "";
|
|
28539
29134
|
await this.sendToSelfChat(`\u2753 ${question}${choicesText}`);
|
|
28540
29135
|
if (!answerSent) await updateStatus("\u{1F916} OpenJaw Agent \u2014 \u2753 Waiting for your response...");
|
|
28541
|
-
const userReply = await new Promise((
|
|
28542
|
-
this._pendingReplyResolver =
|
|
29136
|
+
const userReply = await new Promise((resolve7) => {
|
|
29137
|
+
this._pendingReplyResolver = resolve7;
|
|
28543
29138
|
setTimeout(() => {
|
|
28544
|
-
if (this._pendingReplyResolver ===
|
|
29139
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
28545
29140
|
this._pendingReplyResolver = null;
|
|
28546
|
-
|
|
29141
|
+
resolve7("[No response \u2014 timed out]");
|
|
28547
29142
|
}
|
|
28548
29143
|
}, 5 * 60 * 1e3);
|
|
28549
29144
|
});
|
|
@@ -28615,8 +29210,8 @@ __export(feishu_exports, {
|
|
|
28615
29210
|
FeishuBridge: () => FeishuBridge
|
|
28616
29211
|
});
|
|
28617
29212
|
import * as lark from "@larksuiteoapi/node-sdk";
|
|
28618
|
-
import { readFileSync as
|
|
28619
|
-
import { join as
|
|
29213
|
+
import { readFileSync as readFileSync26, existsSync as existsSync28 } from "node:fs";
|
|
29214
|
+
import { join as join35 } from "node:path";
|
|
28620
29215
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
28621
29216
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
28622
29217
|
var FeishuBridge;
|
|
@@ -28852,9 +29447,9 @@ var init_feishu = __esm({
|
|
|
28852
29447
|
params: { type: "image" }
|
|
28853
29448
|
});
|
|
28854
29449
|
if (resp) {
|
|
28855
|
-
const tempPath =
|
|
29450
|
+
const tempPath = join35(tmpdir9(), `oj-feishu-img-${randomUUID9().slice(0, 6)}.png`);
|
|
28856
29451
|
await resp.writeFile(tempPath);
|
|
28857
|
-
const buffer =
|
|
29452
|
+
const buffer = readFileSync26(tempPath);
|
|
28858
29453
|
let imageData;
|
|
28859
29454
|
try {
|
|
28860
29455
|
const { resizeImageFileForAgent: resizeImageFileForAgent2 } = await Promise.resolve().then(() => (init_image_resize(), image_resize_exports));
|
|
@@ -28875,7 +29470,7 @@ var init_feishu = __esm({
|
|
|
28875
29470
|
params: { type: "file" }
|
|
28876
29471
|
});
|
|
28877
29472
|
if (resp) {
|
|
28878
|
-
const tempPath =
|
|
29473
|
+
const tempPath = join35(tmpdir9(), `oj-feishu-file-${randomUUID9().slice(0, 6)}-${fileName}`);
|
|
28879
29474
|
await resp.writeFile(tempPath);
|
|
28880
29475
|
await this.handleMessage(chatId, `I've sent you a file: ${fileName}. It's saved at ${tempPath}. Please analyze it.`);
|
|
28881
29476
|
}
|
|
@@ -28952,7 +29547,7 @@ var init_feishu = __esm({
|
|
|
28952
29547
|
const fileName = filePath.split(/[\\/]/).pop() || "";
|
|
28953
29548
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
28954
29549
|
if (filePath.includes("http") || filePath.includes("node_modules")) continue;
|
|
28955
|
-
const exists =
|
|
29550
|
+
const exists = existsSync28(filePath);
|
|
28956
29551
|
this.emit({ type: "system", content: `\u{1F50D} Found path: ${filePath} (exists: ${exists})` });
|
|
28957
29552
|
if (exists) {
|
|
28958
29553
|
try {
|
|
@@ -29027,12 +29622,12 @@ ${err.stack?.split("\n").slice(0, 3).join("\n")}` : String(err);
|
|
|
29027
29622
|
}
|
|
29028
29623
|
/** Wait for the next user message (used by ask_user flow) */
|
|
29029
29624
|
waitForUserReply(_chatId) {
|
|
29030
|
-
return new Promise((
|
|
29031
|
-
this._pendingReplyResolver =
|
|
29625
|
+
return new Promise((resolve7) => {
|
|
29626
|
+
this._pendingReplyResolver = resolve7;
|
|
29032
29627
|
setTimeout(() => {
|
|
29033
|
-
if (this._pendingReplyResolver ===
|
|
29628
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
29034
29629
|
this._pendingReplyResolver = null;
|
|
29035
|
-
|
|
29630
|
+
resolve7("[No response \u2014 timed out]");
|
|
29036
29631
|
}
|
|
29037
29632
|
}, 5 * 60 * 1e3);
|
|
29038
29633
|
});
|
|
@@ -29053,10 +29648,10 @@ __export(wechat_exports, {
|
|
|
29053
29648
|
sniffMediaKind: () => sniffMediaKind,
|
|
29054
29649
|
validateMediaForUpload: () => validateMediaForUpload
|
|
29055
29650
|
});
|
|
29056
|
-
import { existsSync as
|
|
29651
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27, writeFileSync as writeFileSync18, unlinkSync as unlinkSync8, statSync as statSync3 } from "node:fs";
|
|
29057
29652
|
import { mkdirSync as mkdirSync16 } from "node:fs";
|
|
29058
|
-
import { extname as extname3, join as
|
|
29059
|
-
import { homedir as
|
|
29653
|
+
import { extname as extname3, join as join36 } from "node:path";
|
|
29654
|
+
import { homedir as homedir22 } from "node:os";
|
|
29060
29655
|
import { randomBytes, randomUUID as randomUUID10, createDecipheriv, createCipheriv, createHash as createHash3 } from "node:crypto";
|
|
29061
29656
|
function mimeFromFilename(fileName) {
|
|
29062
29657
|
return MIME_MAP[extname3(fileName).toLowerCase()] || "application/octet-stream";
|
|
@@ -29124,7 +29719,7 @@ function expandEnvVars(p) {
|
|
|
29124
29719
|
return v !== void 0 ? v : m;
|
|
29125
29720
|
});
|
|
29126
29721
|
if (out.startsWith("~")) {
|
|
29127
|
-
out =
|
|
29722
|
+
out = join36(homedir22(), out.slice(1).replace(/^[\\/]/, ""));
|
|
29128
29723
|
}
|
|
29129
29724
|
return out;
|
|
29130
29725
|
}
|
|
@@ -29274,15 +29869,15 @@ var init_wechat2 = __esm({
|
|
|
29274
29869
|
}
|
|
29275
29870
|
// ── Auth ──
|
|
29276
29871
|
getAccountPath() {
|
|
29277
|
-
const dir2 =
|
|
29278
|
-
if (!
|
|
29279
|
-
return
|
|
29872
|
+
const dir2 = join36(homedir22(), ".openjaw-agent");
|
|
29873
|
+
if (!existsSync29(dir2)) mkdirSync16(dir2, { recursive: true });
|
|
29874
|
+
return join36(dir2, "wechat-account.json");
|
|
29280
29875
|
}
|
|
29281
29876
|
loadAccount() {
|
|
29282
29877
|
const path3 = this.getAccountPath();
|
|
29283
|
-
if (!
|
|
29878
|
+
if (!existsSync29(path3)) return false;
|
|
29284
29879
|
try {
|
|
29285
|
-
this.account = JSON.parse(
|
|
29880
|
+
this.account = JSON.parse(readFileSync27(path3, "utf-8"));
|
|
29286
29881
|
return !!this.account?.token;
|
|
29287
29882
|
} catch {
|
|
29288
29883
|
return false;
|
|
@@ -29298,7 +29893,7 @@ var init_wechat2 = __esm({
|
|
|
29298
29893
|
/** Delete saved session and clear current account (for /wechat logout) */
|
|
29299
29894
|
logout() {
|
|
29300
29895
|
const path3 = this.getAccountPath();
|
|
29301
|
-
if (
|
|
29896
|
+
if (existsSync29(path3)) unlinkSync8(path3);
|
|
29302
29897
|
this.account = null;
|
|
29303
29898
|
this.emit({ type: "system", content: "\u{1F7E2} WeChat: \u5DF2\u767B\u51FA\uFF0C\u4E0B\u6B21\u6D88\u606F\u5C06\u91CD\u65B0\u626B\u7801" });
|
|
29304
29899
|
}
|
|
@@ -29323,9 +29918,9 @@ var init_wechat2 = __esm({
|
|
|
29323
29918
|
try {
|
|
29324
29919
|
const qrTerminal = await import("qrcode-terminal");
|
|
29325
29920
|
const mod = qrTerminal.default || qrTerminal;
|
|
29326
|
-
const qrAscii = await new Promise((
|
|
29921
|
+
const qrAscii = await new Promise((resolve7, reject) => {
|
|
29327
29922
|
try {
|
|
29328
|
-
mod.generate(qrUrl, { small: true }, (out) =>
|
|
29923
|
+
mod.generate(qrUrl, { small: true }, (out) => resolve7(out));
|
|
29329
29924
|
} catch (e) {
|
|
29330
29925
|
reject(e);
|
|
29331
29926
|
}
|
|
@@ -29591,12 +30186,12 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29591
30186
|
const choicesText = chunk.choices?.length ? `
|
|
29592
30187
|
\u9009\u9879: ${chunk.choices.join(" | ")}` : "";
|
|
29593
30188
|
await this.sendText(userId, `\u2753 ${question}${choicesText}`, contextToken);
|
|
29594
|
-
const userReply = await new Promise((
|
|
29595
|
-
this._pendingReplyResolver =
|
|
30189
|
+
const userReply = await new Promise((resolve7) => {
|
|
30190
|
+
this._pendingReplyResolver = resolve7;
|
|
29596
30191
|
setTimeout(() => {
|
|
29597
|
-
if (this._pendingReplyResolver ===
|
|
30192
|
+
if (this._pendingReplyResolver === resolve7) {
|
|
29598
30193
|
this._pendingReplyResolver = null;
|
|
29599
|
-
|
|
30194
|
+
resolve7("[No response \u2014 timed out]");
|
|
29600
30195
|
}
|
|
29601
30196
|
}, 5 * 60 * 1e3);
|
|
29602
30197
|
});
|
|
@@ -29760,7 +30355,7 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29760
30355
|
*/
|
|
29761
30356
|
async uploadFile(filePath, fileName, toUserId) {
|
|
29762
30357
|
if (!this.account) return null;
|
|
29763
|
-
const plaintext =
|
|
30358
|
+
const plaintext = readFileSync27(filePath);
|
|
29764
30359
|
const rawsize = plaintext.length;
|
|
29765
30360
|
if (rawsize === 0) {
|
|
29766
30361
|
this.emit({ type: "system", content: `\u26A0 WeChat upload skipped (file is empty): ${fileName}` });
|
|
@@ -29920,7 +30515,7 @@ Scan URL manually: ${qrUrl}` });
|
|
|
29920
30515
|
if (!fileName) continue;
|
|
29921
30516
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
29922
30517
|
if (filePath.includes("http://") || filePath.includes("https://") || filePath.includes("node_modules")) continue;
|
|
29923
|
-
if (!
|
|
30518
|
+
if (!existsSync29(filePath)) continue;
|
|
29924
30519
|
attemptedFiles.add(dedupKey);
|
|
29925
30520
|
attempted++;
|
|
29926
30521
|
try {
|
|
@@ -30042,9 +30637,9 @@ __export(legacy_ink_ui_exports, {
|
|
|
30042
30637
|
});
|
|
30043
30638
|
import React6 from "react";
|
|
30044
30639
|
import { render } from "ink";
|
|
30045
|
-
import { existsSync as
|
|
30046
|
-
import { join as
|
|
30047
|
-
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";
|
|
30048
30643
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
30049
30644
|
async function startInkUI(resumeSessionId, bridges = []) {
|
|
30050
30645
|
await ensureDirectories();
|
|
@@ -30072,12 +30667,12 @@ async function startInkUI(resumeSessionId, bridges = []) {
|
|
|
30072
30667
|
});
|
|
30073
30668
|
const agentLoop = new AgentLoop(agentConfig, toolRegistry, resumeSessionId);
|
|
30074
30669
|
toolRegistry.setWebSearchExecutor(createWebSearchExecutor(agentLoop));
|
|
30075
|
-
const memoryDbPath =
|
|
30670
|
+
const memoryDbPath = join37(homedir23(), ".openjaw", "memory.db");
|
|
30076
30671
|
const memoryLegacyPaths = [
|
|
30077
|
-
|
|
30078
|
-
|
|
30672
|
+
join37(homedir23(), ".openjaw", "MEMORY.md"),
|
|
30673
|
+
join37(homedir23(), ".openjaw", "memory", "MEMORY.md")
|
|
30079
30674
|
];
|
|
30080
|
-
const memoryStatus =
|
|
30675
|
+
const memoryStatus = existsSync30(memoryDbPath) ? "loaded" : memoryLegacyPaths.some((p) => existsSync30(p)) ? "legacy" : "empty";
|
|
30081
30676
|
const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt({ mcpManager }), "systemPromptFn");
|
|
30082
30677
|
const { createSkillTool: createSkillTool2 } = await Promise.resolve().then(() => (init_skill_tool(), skill_tool_exports));
|
|
30083
30678
|
toolRegistry.registerTool(createSkillTool2(agentConfig, toolRegistry, systemPromptFn));
|
|
@@ -30344,6 +30939,15 @@ var init_agentBus = __esm({
|
|
|
30344
30939
|
hasRpc(method) {
|
|
30345
30940
|
return this.handlers.has(method);
|
|
30346
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
|
+
}
|
|
30347
30951
|
/**
|
|
30348
30952
|
* RPC dispatch entry point. Mirrors hermes's WebSocket `request(method, params)`
|
|
30349
30953
|
* but is a direct in-process function call. When no handler is registered,
|
|
@@ -30445,9 +31049,9 @@ var init_agentBus = __esm({
|
|
|
30445
31049
|
});
|
|
30446
31050
|
|
|
30447
31051
|
// src/bridges/registry.ts
|
|
30448
|
-
import { existsSync as
|
|
30449
|
-
import { homedir as
|
|
30450
|
-
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";
|
|
30451
31055
|
var BRIDGE_REGISTRY, BRIDGE_NAMES, isBridgeName, normalizeCredentialsForConfig, BridgeManager, parseListInput;
|
|
30452
31056
|
var init_registry3 = __esm({
|
|
30453
31057
|
"src/bridges/registry.ts"() {
|
|
@@ -30546,15 +31150,15 @@ var init_registry3 = __esm({
|
|
|
30546
31150
|
return { instance, stop: /* @__PURE__ */ __name(() => instance.stop(), "stop") };
|
|
30547
31151
|
},
|
|
30548
31152
|
async onForget(instance) {
|
|
30549
|
-
const wechatPath =
|
|
31153
|
+
const wechatPath = join38(homedir24(), ".openjaw-agent", "wechat-account.json");
|
|
30550
31154
|
if (instance && typeof instance.logout === "function") {
|
|
30551
31155
|
try {
|
|
30552
31156
|
instance.logout();
|
|
30553
31157
|
} catch {
|
|
30554
31158
|
}
|
|
30555
|
-
} else if (
|
|
31159
|
+
} else if (existsSync31(wechatPath)) {
|
|
30556
31160
|
try {
|
|
30557
|
-
|
|
31161
|
+
unlinkSync9(wechatPath);
|
|
30558
31162
|
} catch {
|
|
30559
31163
|
}
|
|
30560
31164
|
}
|
|
@@ -30827,12 +31431,19 @@ var init_registry3 = __esm({
|
|
|
30827
31431
|
|
|
30828
31432
|
// src/bootstrap.ts
|
|
30829
31433
|
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
30830
|
-
import { existsSync as
|
|
30831
|
-
import { homedir as
|
|
30832
|
-
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";
|
|
30833
31437
|
async function bootstrapAgent(opts = {}) {
|
|
30834
31438
|
await ensureDirectories();
|
|
30835
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
|
+
});
|
|
30836
31447
|
const toolRegistry = new ToolRegistry(config);
|
|
30837
31448
|
const memoryStore = new MemoryStore(config);
|
|
30838
31449
|
await toolRegistry.initializeProfile("core");
|
|
@@ -30840,9 +31451,10 @@ async function bootstrapAgent(opts = {}) {
|
|
|
30840
31451
|
const { createMetaTool: createMetaTool2 } = await Promise.resolve().then(() => (init_meta(), meta_exports));
|
|
30841
31452
|
toolRegistry.registerTool(createMetaTool2(toolRegistry));
|
|
30842
31453
|
const agentConfig = loadAgentConfig();
|
|
31454
|
+
const interactiveMcp = opts.interactiveMcp !== false;
|
|
30843
31455
|
const mcpManager = new MCPClientManager();
|
|
30844
31456
|
try {
|
|
30845
|
-
await mcpManager.prepare(process.cwd(),
|
|
31457
|
+
await mcpManager.prepare(process.cwd(), interactiveMcp);
|
|
30846
31458
|
} catch (err) {
|
|
30847
31459
|
process.stderr.write(
|
|
30848
31460
|
`\x1B[33m\u26A0 MCP discovery failed: ${err instanceof Error ? err.message : String(err)}\x1B[0m
|
|
@@ -30859,12 +31471,12 @@ async function bootstrapAgent(opts = {}) {
|
|
|
30859
31471
|
});
|
|
30860
31472
|
const agentLoop = new AgentLoop(agentConfig, toolRegistry, opts.resumeSessionId);
|
|
30861
31473
|
toolRegistry.setWebSearchExecutor(createWebSearchExecutor(agentLoop));
|
|
30862
|
-
const memoryDbPath =
|
|
31474
|
+
const memoryDbPath = join39(homedir25(), ".openjaw", "memory.db");
|
|
30863
31475
|
const memoryLegacyPaths = [
|
|
30864
|
-
|
|
30865
|
-
|
|
31476
|
+
join39(homedir25(), ".openjaw", "MEMORY.md"),
|
|
31477
|
+
join39(homedir25(), ".openjaw", "memory", "MEMORY.md")
|
|
30866
31478
|
];
|
|
30867
|
-
const memoryStatus =
|
|
31479
|
+
const memoryStatus = existsSync32(memoryDbPath) ? "loaded" : memoryLegacyPaths.some((p) => existsSync32(p)) ? "legacy" : "empty";
|
|
30868
31480
|
const systemPromptFn = /* @__PURE__ */ __name(() => getSystemPrompt({ mcpManager }), "systemPromptFn");
|
|
30869
31481
|
const { createSkillTool: createSkillTool2 } = await Promise.resolve().then(() => (init_skill_tool(), skill_tool_exports));
|
|
30870
31482
|
toolRegistry.registerTool(createSkillTool2(agentConfig, toolRegistry, systemPromptFn));
|
|
@@ -31097,8 +31709,8 @@ function createPromptCollector(bus, getSessionId) {
|
|
|
31097
31709
|
}, "emit");
|
|
31098
31710
|
const register = /* @__PURE__ */ __name((kind) => {
|
|
31099
31711
|
const requestId = randomUUID12();
|
|
31100
|
-
const promise = new Promise((
|
|
31101
|
-
pending.set(requestId, { kind, resolve:
|
|
31712
|
+
const promise = new Promise((resolve7) => {
|
|
31713
|
+
pending.set(requestId, { kind, resolve: resolve7 });
|
|
31102
31714
|
});
|
|
31103
31715
|
return { promise, requestId };
|
|
31104
31716
|
}, "register");
|
|
@@ -31656,7 +32268,7 @@ import { c as _c } from "react/compiler-runtime";
|
|
|
31656
32268
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
31657
32269
|
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
31658
32270
|
import { Buffer as Buffer2 } from "buffer";
|
|
31659
|
-
import { spawn as
|
|
32271
|
+
import { spawn as spawn6 } from "child_process";
|
|
31660
32272
|
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
31661
32273
|
import { ansiCodesToString, reduceAnsiCodes, tokenize as tokenize2, undoAnsiCodes } from "@alcalzone/ansi-tokenize";
|
|
31662
32274
|
import emojiRegex from "emoji-regex";
|
|
@@ -31726,7 +32338,7 @@ import { Buffer as Buffer3 } from "buffer";
|
|
|
31726
32338
|
import { createContext as createContext7, useEffect as useEffect4, useState as useState22 } from "react";
|
|
31727
32339
|
import { c as _c10 } from "react/compiler-runtime";
|
|
31728
32340
|
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
31729
|
-
import { readFileSync as
|
|
32341
|
+
import { readFileSync as readFileSync28 } from "fs";
|
|
31730
32342
|
import codeExcerpt from "code-excerpt";
|
|
31731
32343
|
import StackUtils from "stack-utils";
|
|
31732
32344
|
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
@@ -31734,7 +32346,7 @@ import { jsx as jsx14 } from "react/jsx-runtime";
|
|
|
31734
32346
|
import { ansiCodesToString as ansiCodesToString3, diffAnsiCodes as diffAnsiCodes2 } from "@alcalzone/ansi-tokenize";
|
|
31735
32347
|
import { styledCharsFromTokens, tokenize as tokenize3 } from "@alcalzone/ansi-tokenize";
|
|
31736
32348
|
import bidiFactory from "bidi-js";
|
|
31737
|
-
import
|
|
32349
|
+
import noop3 from "lodash-es/noop.js";
|
|
31738
32350
|
import { LegacyRoot } from "react-reconciler/constants.js";
|
|
31739
32351
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
31740
32352
|
import { default as default2, UncontrolledTextInput } from "ink-text-input";
|
|
@@ -32082,8 +32694,8 @@ function supportsOsc52Clipboard(terminal2 = env.terminal) {
|
|
|
32082
32694
|
return OSC52_CAPABLE_TERMINALS.includes(terminal2 ?? "");
|
|
32083
32695
|
}
|
|
32084
32696
|
function execFileNoThrow(file2, args, options = {}) {
|
|
32085
|
-
return new Promise((
|
|
32086
|
-
const child =
|
|
32697
|
+
return new Promise((resolve7) => {
|
|
32698
|
+
const child = spawn6(file2, args, {
|
|
32087
32699
|
cwd: options.useCwd ? process.cwd() : void 0,
|
|
32088
32700
|
env: options.env,
|
|
32089
32701
|
stdio: "pipe"
|
|
@@ -32105,13 +32717,13 @@ function execFileNoThrow(file2, args, options = {}) {
|
|
|
32105
32717
|
if (timer) {
|
|
32106
32718
|
clearTimeout(timer);
|
|
32107
32719
|
}
|
|
32108
|
-
|
|
32720
|
+
resolve7({ stdout, stderr, code: 1, error: String(error) });
|
|
32109
32721
|
});
|
|
32110
32722
|
child.on("close", (code) => {
|
|
32111
32723
|
if (timer) {
|
|
32112
32724
|
clearTimeout(timer);
|
|
32113
32725
|
}
|
|
32114
|
-
|
|
32726
|
+
resolve7({ stdout, stderr, code: timedOut ? 124 : code ?? 0 });
|
|
32115
32727
|
});
|
|
32116
32728
|
if (options.input) {
|
|
32117
32729
|
child.stdin?.write(options.input);
|
|
@@ -33323,11 +33935,11 @@ function sliceAnsi(str, start, end) {
|
|
|
33323
33935
|
}
|
|
33324
33936
|
if (end !== void 0) {
|
|
33325
33937
|
const key = `${start}|${end}|${str}`;
|
|
33326
|
-
const
|
|
33327
|
-
if (
|
|
33938
|
+
const cached8 = sliceCache.get(key);
|
|
33939
|
+
if (cached8 !== void 0) {
|
|
33328
33940
|
sliceCache.delete(key);
|
|
33329
|
-
sliceCache.set(key,
|
|
33330
|
-
return
|
|
33941
|
+
sliceCache.set(key, cached8);
|
|
33942
|
+
return cached8;
|
|
33331
33943
|
}
|
|
33332
33944
|
const result = computeSlice(str, start, end);
|
|
33333
33945
|
if (sliceCache.size >= SLICE_CACHE_LIMIT) {
|
|
@@ -33382,11 +33994,11 @@ function computeSlice(str, start, end) {
|
|
|
33382
33994
|
return result;
|
|
33383
33995
|
}
|
|
33384
33996
|
function lineWidth(line) {
|
|
33385
|
-
const
|
|
33386
|
-
if (
|
|
33997
|
+
const cached8 = cache.get(line);
|
|
33998
|
+
if (cached8 !== void 0) {
|
|
33387
33999
|
cache.delete(line);
|
|
33388
|
-
cache.set(line,
|
|
33389
|
-
return
|
|
34000
|
+
cache.set(line, cached8);
|
|
34001
|
+
return cached8;
|
|
33390
34002
|
}
|
|
33391
34003
|
const width = stringWidth(line);
|
|
33392
34004
|
if (cache.size >= MAX_CACHE_SIZE) {
|
|
@@ -33403,11 +34015,11 @@ function evictLineWidthCache(keepRatio = 0) {
|
|
|
33403
34015
|
}
|
|
33404
34016
|
function memoizedWrap(text, maxWidth, wrapType) {
|
|
33405
34017
|
const key = `${maxWidth}|${wrapType}|${text}`;
|
|
33406
|
-
const
|
|
33407
|
-
if (
|
|
34018
|
+
const cached8 = wrapCache.get(key);
|
|
34019
|
+
if (cached8 !== void 0) {
|
|
33408
34020
|
wrapCache.delete(key);
|
|
33409
|
-
wrapCache.set(key,
|
|
33410
|
-
return
|
|
34021
|
+
wrapCache.set(key, cached8);
|
|
34022
|
+
return cached8;
|
|
33411
34023
|
}
|
|
33412
34024
|
const result = computeWrap(text, maxWidth, wrapType);
|
|
33413
34025
|
if (wrapCache.size >= WRAP_CACHE_LIMIT) {
|
|
@@ -35367,9 +35979,9 @@ function collectRemovedRects(parent, removed, underAbsolute = false) {
|
|
|
35367
35979
|
}
|
|
35368
35980
|
const elem = removed;
|
|
35369
35981
|
const isAbsolute2 = underAbsolute || elem.style.position === "absolute";
|
|
35370
|
-
const
|
|
35371
|
-
if (
|
|
35372
|
-
addPendingClear(parent,
|
|
35982
|
+
const cached8 = nodeCache.get(elem);
|
|
35983
|
+
if (cached8) {
|
|
35984
|
+
addPendingClear(parent, cached8, isAbsolute2);
|
|
35373
35985
|
nodeCache.delete(elem);
|
|
35374
35986
|
}
|
|
35375
35987
|
for (const child of elem.childNodes) {
|
|
@@ -37084,8 +37696,8 @@ function setTerminalFocused(v) {
|
|
|
37084
37696
|
cb();
|
|
37085
37697
|
}
|
|
37086
37698
|
if (!v) {
|
|
37087
|
-
for (const
|
|
37088
|
-
|
|
37699
|
+
for (const resolve7 of resolvers) {
|
|
37700
|
+
resolve7();
|
|
37089
37701
|
}
|
|
37090
37702
|
resolvers.clear();
|
|
37091
37703
|
}
|
|
@@ -37489,31 +38101,31 @@ function renderNodeToOutput(node, output, {
|
|
|
37489
38101
|
if (y < 0 && node.style.position === "absolute") {
|
|
37490
38102
|
y = 0;
|
|
37491
38103
|
}
|
|
37492
|
-
const
|
|
37493
|
-
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) {
|
|
37494
38106
|
const fx = Math.floor(x);
|
|
37495
38107
|
const fy = Math.floor(y);
|
|
37496
38108
|
const fw = Math.floor(width);
|
|
37497
38109
|
const fh = Math.floor(height);
|
|
37498
38110
|
output.blit(prevScreen, fx, fy, fw, fh);
|
|
37499
38111
|
if (node.style.position === "absolute") {
|
|
37500
|
-
absoluteRectsCur.push(
|
|
38112
|
+
absoluteRectsCur.push(cached8);
|
|
37501
38113
|
}
|
|
37502
38114
|
blitEscapingAbsoluteDescendants(node, output, prevScreen, fx, fy, fw, fh);
|
|
37503
38115
|
return;
|
|
37504
38116
|
}
|
|
37505
|
-
const positionChanged =
|
|
38117
|
+
const positionChanged = cached8 !== void 0 && (cached8.x !== x || cached8.y !== y || cached8.width !== width || cached8.height !== height);
|
|
37506
38118
|
if (positionChanged) {
|
|
37507
38119
|
layoutShifted = true;
|
|
37508
38120
|
absoluteOverlayMoved ||= node.style.position === "absolute";
|
|
37509
38121
|
}
|
|
37510
|
-
if (
|
|
38122
|
+
if (cached8 && (node.dirty || positionChanged)) {
|
|
37511
38123
|
output.clear(
|
|
37512
38124
|
{
|
|
37513
|
-
x: Math.floor(
|
|
37514
|
-
y: Math.floor(
|
|
37515
|
-
width: Math.floor(
|
|
37516
|
-
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)
|
|
37517
38129
|
},
|
|
37518
38130
|
node.style.position === "absolute"
|
|
37519
38131
|
);
|
|
@@ -37688,7 +38300,7 @@ function renderNodeToOutput(node, output, {
|
|
|
37688
38300
|
const delta = contentCached.y - contentY;
|
|
37689
38301
|
const regionTop = Math.floor(y + contentYoga.getComputedTop());
|
|
37690
38302
|
const regionBottom = regionTop + innerHeight - 1;
|
|
37691
|
-
if (
|
|
38303
|
+
if (cached8?.y === y && cached8.height === height && innerHeight > 0 && Math.abs(delta) < innerHeight) {
|
|
37692
38304
|
hint = { top: regionTop, bottom: regionBottom, delta };
|
|
37693
38305
|
scrollHint = hint;
|
|
37694
38306
|
} else {
|
|
@@ -37988,13 +38600,13 @@ function blitEscapingAbsoluteDescendants(node, output, prevScreen, px, py, pw, p
|
|
|
37988
38600
|
}
|
|
37989
38601
|
const elem = child;
|
|
37990
38602
|
if (elem.style.position === "absolute") {
|
|
37991
|
-
const
|
|
37992
|
-
if (
|
|
37993
|
-
absoluteRectsCur.push(
|
|
37994
|
-
const cx = Math.floor(
|
|
37995
|
-
const cy = Math.floor(
|
|
37996
|
-
const cw = Math.floor(
|
|
37997
|
-
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);
|
|
37998
38610
|
if (cx < px || cy < py || cx + cw > pr || cy + ch > pb) {
|
|
37999
38611
|
output.blit(prevScreen, cx, cy, cw, ch);
|
|
38000
38612
|
}
|
|
@@ -38010,20 +38622,20 @@ function renderScrolledChildren(node, output, offsetX, offsetY, hasRemovedChild,
|
|
|
38010
38622
|
const childElem = childNode;
|
|
38011
38623
|
const cy = childElem.yogaNode;
|
|
38012
38624
|
if (cy) {
|
|
38013
|
-
const
|
|
38625
|
+
const cached8 = nodeCache.get(childElem);
|
|
38014
38626
|
let top;
|
|
38015
38627
|
let height;
|
|
38016
|
-
if (
|
|
38017
|
-
top =
|
|
38018
|
-
height =
|
|
38628
|
+
if (cached8?.top !== void 0 && !childElem.dirty && cumHeightShift === 0) {
|
|
38629
|
+
top = cached8.top;
|
|
38630
|
+
height = cached8.height;
|
|
38019
38631
|
} else {
|
|
38020
38632
|
top = cy.getComputedTop();
|
|
38021
38633
|
height = cy.getComputedHeight();
|
|
38022
38634
|
if (childElem.dirty) {
|
|
38023
|
-
cumHeightShift += height - (
|
|
38635
|
+
cumHeightShift += height - (cached8 ? cached8.height : 0);
|
|
38024
38636
|
}
|
|
38025
|
-
if (
|
|
38026
|
-
|
|
38637
|
+
if (cached8) {
|
|
38638
|
+
cached8.top = top;
|
|
38027
38639
|
}
|
|
38028
38640
|
}
|
|
38029
38641
|
const bottom = top + height;
|
|
@@ -38709,7 +39321,7 @@ function ErrorOverview({ error }) {
|
|
|
38709
39321
|
let lineWidth2 = 0;
|
|
38710
39322
|
if (filePath && origin?.line) {
|
|
38711
39323
|
try {
|
|
38712
|
-
const sourceCode =
|
|
39324
|
+
const sourceCode = readFileSync28(filePath, "utf8");
|
|
38713
39325
|
excerpt = codeExcerpt(sourceCode, origin.line);
|
|
38714
39326
|
if (excerpt) {
|
|
38715
39327
|
for (const { line } of excerpt) {
|
|
@@ -40433,11 +41045,11 @@ var init_entry_exports = __esm({
|
|
|
40433
41045
|
return rawStringWidth(str);
|
|
40434
41046
|
}
|
|
40435
41047
|
}
|
|
40436
|
-
const
|
|
40437
|
-
if (
|
|
41048
|
+
const cached8 = widthCache.get(str);
|
|
41049
|
+
if (cached8 !== void 0) {
|
|
40438
41050
|
widthCache.delete(str);
|
|
40439
|
-
widthCache.set(str,
|
|
40440
|
-
return
|
|
41051
|
+
widthCache.set(str, cached8);
|
|
41052
|
+
return cached8;
|
|
40441
41053
|
}
|
|
40442
41054
|
const w = rawStringWidth(str);
|
|
40443
41055
|
if (widthCache.size >= WIDTH_CACHE_LIMIT) {
|
|
@@ -42542,9 +43154,9 @@ $ npm install --save-dev react-devtools-core
|
|
|
42542
43154
|
if (char.length === 1) {
|
|
42543
43155
|
const code = char.charCodeAt(0);
|
|
42544
43156
|
if (code < 128) {
|
|
42545
|
-
const
|
|
42546
|
-
if (
|
|
42547
|
-
return
|
|
43157
|
+
const cached8 = this.ascii[code];
|
|
43158
|
+
if (cached8 !== -1) {
|
|
43159
|
+
return cached8;
|
|
42548
43160
|
}
|
|
42549
43161
|
const index2 = this.strings.length;
|
|
42550
43162
|
this.strings.push(char);
|
|
@@ -43323,11 +43935,11 @@ $ npm install --save-dev react-devtools-core
|
|
|
43323
43935
|
* and the terminal doesn't respond, the promise remains pending.
|
|
43324
43936
|
*/
|
|
43325
43937
|
send(query) {
|
|
43326
|
-
return new Promise((
|
|
43938
|
+
return new Promise((resolve7) => {
|
|
43327
43939
|
this.queue.push({
|
|
43328
43940
|
kind: "query",
|
|
43329
43941
|
match: query.match,
|
|
43330
|
-
resolve: /* @__PURE__ */ __name((r) =>
|
|
43942
|
+
resolve: /* @__PURE__ */ __name((r) => resolve7(r), "resolve")
|
|
43331
43943
|
});
|
|
43332
43944
|
this.stdout.write(query.request);
|
|
43333
43945
|
});
|
|
@@ -43342,8 +43954,8 @@ $ npm install --save-dev react-devtools-core
|
|
|
43342
43954
|
* Safe to call with no pending queries — still waits for a round-trip.
|
|
43343
43955
|
*/
|
|
43344
43956
|
flush() {
|
|
43345
|
-
return new Promise((
|
|
43346
|
-
this.queue.push({ kind: "sentinel", resolve:
|
|
43957
|
+
return new Promise((resolve7) => {
|
|
43958
|
+
this.queue.push({ kind: "sentinel", resolve: resolve7 });
|
|
43347
43959
|
this.stdout.write(SENTINEL);
|
|
43348
43960
|
});
|
|
43349
43961
|
}
|
|
@@ -45823,8 +46435,8 @@ $ npm install --save-dev react-devtools-core
|
|
|
45823
46435
|
}
|
|
45824
46436
|
}
|
|
45825
46437
|
async waitUntilExit() {
|
|
45826
|
-
this.exitPromise ||= new Promise((
|
|
45827
|
-
this.resolveExitPromise =
|
|
46438
|
+
this.exitPromise ||= new Promise((resolve7, reject) => {
|
|
46439
|
+
this.resolveExitPromise = resolve7;
|
|
45828
46440
|
this.rejectExitPromise = reject;
|
|
45829
46441
|
});
|
|
45830
46442
|
return this.exitPromise;
|
|
@@ -46238,7 +46850,7 @@ var init_details = __esm({
|
|
|
46238
46850
|
});
|
|
46239
46851
|
|
|
46240
46852
|
// src/lib/clipboard.ts
|
|
46241
|
-
import { execFile, spawn as
|
|
46853
|
+
import { execFile, spawn as spawn7 } from "node:child_process";
|
|
46242
46854
|
import { promisify as promisify6 } from "node:util";
|
|
46243
46855
|
function isUsableClipboardText(text) {
|
|
46244
46856
|
if (!text || !/[^\s]/.test(text)) {
|
|
@@ -46311,14 +46923,14 @@ function writeClipboardCommands(platform2, env2) {
|
|
|
46311
46923
|
attempts.push({ cmd: "xsel", args: ["--clipboard", "--input"] });
|
|
46312
46924
|
return attempts;
|
|
46313
46925
|
}
|
|
46314
|
-
async function writeClipboardText(text, platform2 = process.platform, start =
|
|
46926
|
+
async function writeClipboardText(text, platform2 = process.platform, start = spawn7, env2 = process.env) {
|
|
46315
46927
|
const candidates = writeClipboardCommands(platform2, env2);
|
|
46316
46928
|
for (const { cmd, args } of candidates) {
|
|
46317
46929
|
try {
|
|
46318
|
-
const ok = await new Promise((
|
|
46930
|
+
const ok = await new Promise((resolve7) => {
|
|
46319
46931
|
const child = start(cmd, [...args], { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
|
|
46320
|
-
child.once("error", () =>
|
|
46321
|
-
child.once("close", (code) =>
|
|
46932
|
+
child.once("error", () => resolve7(false));
|
|
46933
|
+
child.once("close", (code) => resolve7(code === 0));
|
|
46322
46934
|
child.stdin?.end(text);
|
|
46323
46935
|
});
|
|
46324
46936
|
if (ok) {
|
|
@@ -46377,8 +46989,8 @@ async function readOsc52Clipboard(querier, timeoutMs = 500) {
|
|
|
46377
46989
|
if (!querier) {
|
|
46378
46990
|
return null;
|
|
46379
46991
|
}
|
|
46380
|
-
const timeout = new Promise((
|
|
46381
|
-
setTimeout(() =>
|
|
46992
|
+
const timeout = new Promise((resolve7) => {
|
|
46993
|
+
setTimeout(() => resolve7(void 0), timeoutMs);
|
|
46382
46994
|
});
|
|
46383
46995
|
const query = querier.send({
|
|
46384
46996
|
request: buildOsc52ClipboardQuery(),
|
|
@@ -46408,8 +47020,8 @@ var init_osc52 = __esm({
|
|
|
46408
47020
|
|
|
46409
47021
|
// src/lib/terminalSetup.ts
|
|
46410
47022
|
import { copyFile, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
|
|
46411
|
-
import { homedir as
|
|
46412
|
-
import { join as
|
|
47023
|
+
import { homedir as homedir26 } from "node:os";
|
|
47024
|
+
import { join as join40 } from "node:path";
|
|
46413
47025
|
function detectVSCodeLikeTerminal(env2 = process.env) {
|
|
46414
47026
|
const askpass = env2["VSCODE_GIT_ASKPASS_MAIN"]?.toLowerCase() ?? "";
|
|
46415
47027
|
if (env2["CURSOR_TRACE_ID"] || askpass.includes("cursor")) {
|
|
@@ -46463,14 +47075,14 @@ function stripJsonComments(content) {
|
|
|
46463
47075
|
function isRemoteShellSession(env2) {
|
|
46464
47076
|
return Boolean(env2["SSH_CONNECTION"] || env2["SSH_TTY"] || env2["SSH_CLIENT"]);
|
|
46465
47077
|
}
|
|
46466
|
-
function getVSCodeStyleConfigDir(appName, platform2 = process.platform, env2 = process.env, homeDir =
|
|
47078
|
+
function getVSCodeStyleConfigDir(appName, platform2 = process.platform, env2 = process.env, homeDir = homedir26()) {
|
|
46467
47079
|
if (platform2 === "darwin") {
|
|
46468
|
-
return
|
|
47080
|
+
return join40(homeDir, "Library", "Application Support", appName, "User");
|
|
46469
47081
|
}
|
|
46470
47082
|
if (platform2 === "win32") {
|
|
46471
|
-
return env2["APPDATA"] ?
|
|
47083
|
+
return env2["APPDATA"] ? join40(env2["APPDATA"], appName, "User") : null;
|
|
46472
47084
|
}
|
|
46473
|
-
return
|
|
47085
|
+
return join40(homeDir, ".config", appName, "User");
|
|
46474
47086
|
}
|
|
46475
47087
|
function isKeybinding(value) {
|
|
46476
47088
|
return typeof value === "object" && value !== null;
|
|
@@ -46538,7 +47150,7 @@ async function backupFile(filePath, ops) {
|
|
|
46538
47150
|
async function configureTerminalKeybindings(terminal2, options) {
|
|
46539
47151
|
const env2 = options?.env ?? process.env;
|
|
46540
47152
|
const platform2 = options?.platform ?? process.platform;
|
|
46541
|
-
const homeDir = options?.homeDir ??
|
|
47153
|
+
const homeDir = options?.homeDir ?? homedir26();
|
|
46542
47154
|
const ops = { ...DEFAULT_FILE_OPS, ...options?.fileOps ?? {} };
|
|
46543
47155
|
const meta = TERMINAL_META[terminal2];
|
|
46544
47156
|
if (isRemoteShellSession(env2)) {
|
|
@@ -46554,7 +47166,7 @@ async function configureTerminalKeybindings(terminal2, options) {
|
|
|
46554
47166
|
message: `Could not determine ${meta.label} settings path on this platform.`
|
|
46555
47167
|
};
|
|
46556
47168
|
}
|
|
46557
|
-
const keybindingsFile =
|
|
47169
|
+
const keybindingsFile = join40(configDir2, "keybindings.json");
|
|
46558
47170
|
try {
|
|
46559
47171
|
await ops.mkdir(configDir2, { recursive: true });
|
|
46560
47172
|
let keybindings = [];
|
|
@@ -46637,7 +47249,7 @@ async function shouldPromptForTerminalSetup(options) {
|
|
|
46637
47249
|
return false;
|
|
46638
47250
|
}
|
|
46639
47251
|
const platform2 = options?.platform ?? process.platform;
|
|
46640
|
-
const homeDir = options?.homeDir ??
|
|
47252
|
+
const homeDir = options?.homeDir ?? homedir26();
|
|
46641
47253
|
const ops = { ...DEFAULT_FILE_OPS, ...options?.fileOps ?? {} };
|
|
46642
47254
|
const meta = TERMINAL_META[detected];
|
|
46643
47255
|
const configDir2 = getVSCodeStyleConfigDir(meta.appName, platform2, env2, homeDir);
|
|
@@ -46645,7 +47257,7 @@ async function shouldPromptForTerminalSetup(options) {
|
|
|
46645
47257
|
return false;
|
|
46646
47258
|
}
|
|
46647
47259
|
try {
|
|
46648
|
-
const content = await ops.readFile(
|
|
47260
|
+
const content = await ops.readFile(join40(configDir2, "keybindings.json"), "utf8");
|
|
46649
47261
|
const parsed = JSON.parse(stripJsonComments(content));
|
|
46650
47262
|
if (!Array.isArray(parsed)) {
|
|
46651
47263
|
return true;
|
|
@@ -47396,8 +48008,8 @@ var init_bridges = __esm({
|
|
|
47396
48008
|
// src/lib/memory.ts
|
|
47397
48009
|
import { createWriteStream } from "node:fs";
|
|
47398
48010
|
import { mkdir as mkdir4, readdir as readdir3, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
47399
|
-
import { homedir as
|
|
47400
|
-
import { join as
|
|
48011
|
+
import { homedir as homedir27, tmpdir as tmpdir11 } from "node:os";
|
|
48012
|
+
import { join as join41 } from "node:path";
|
|
47401
48013
|
import { pipeline } from "node:stream/promises";
|
|
47402
48014
|
import { getHeapSnapshot, getHeapSpaceStatistics, getHeapStatistics } from "node:v8";
|
|
47403
48015
|
async function captureMemoryDiagnostics(trigger) {
|
|
@@ -47471,11 +48083,11 @@ async function captureMemoryDiagnostics(trigger) {
|
|
|
47471
48083
|
async function performHeapDump(trigger = "manual") {
|
|
47472
48084
|
try {
|
|
47473
48085
|
const diagnostics = await captureMemoryDiagnostics(trigger);
|
|
47474
|
-
const dir2 = process.env.OPENJAW_HEAPDUMP_DIR?.trim() ||
|
|
48086
|
+
const dir2 = process.env.OPENJAW_HEAPDUMP_DIR?.trim() || join41(homedir27() || tmpdir11(), ".openjaw-agent", "heapdumps");
|
|
47475
48087
|
await mkdir4(dir2, { recursive: true });
|
|
47476
48088
|
const base = `hermes-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${process.pid}-${trigger}`;
|
|
47477
|
-
const heapPath =
|
|
47478
|
-
const diagPath =
|
|
48089
|
+
const heapPath = join41(dir2, `${base}.heapsnapshot`);
|
|
48090
|
+
const diagPath = join41(dir2, `${base}.diagnostics.json`);
|
|
47479
48091
|
await writeFile4(diagPath, JSON.stringify(diagnostics, null, 2), { mode: 384 });
|
|
47480
48092
|
await pipeline(getHeapSnapshot(), createWriteStream(heapPath, { mode: 384 }));
|
|
47481
48093
|
return { diagPath, heapPath, success: true };
|
|
@@ -48332,15 +48944,15 @@ var init_ops = __esm({
|
|
|
48332
48944
|
}
|
|
48333
48945
|
const [a, b] = parts;
|
|
48334
48946
|
const history = getSpawnHistory();
|
|
48335
|
-
const
|
|
48947
|
+
const resolve7 = /* @__PURE__ */ __name((token) => {
|
|
48336
48948
|
const n = parseInt(token, 10);
|
|
48337
48949
|
if (Number.isFinite(n) && n >= 1 && n <= history.length) {
|
|
48338
48950
|
return history[n - 1] ?? null;
|
|
48339
48951
|
}
|
|
48340
48952
|
return null;
|
|
48341
48953
|
}, "resolve");
|
|
48342
|
-
const baseline =
|
|
48343
|
-
const candidate =
|
|
48954
|
+
const baseline = resolve7(a);
|
|
48955
|
+
const candidate = resolve7(b);
|
|
48344
48956
|
if (!baseline || !candidate) {
|
|
48345
48957
|
return ctx.transcript.sys(`replay-diff: could not resolve indices \xB7 history has ${history.length} entries`);
|
|
48346
48958
|
}
|
|
@@ -49234,8 +49846,8 @@ var init_setup = __esm({
|
|
|
49234
49846
|
|
|
49235
49847
|
// src/app/slash/catalog.ts
|
|
49236
49848
|
import { readdirSync as readdirSync6 } from "node:fs";
|
|
49237
|
-
import { homedir as
|
|
49238
|
-
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";
|
|
49239
49851
|
function buildCommandsCatalog(extras = {}) {
|
|
49240
49852
|
const canon = {};
|
|
49241
49853
|
const pairs = [];
|
|
@@ -49337,7 +49949,7 @@ function buildPathCompletions(word) {
|
|
|
49337
49949
|
prefix = expanded.slice(lastSep + 1);
|
|
49338
49950
|
}
|
|
49339
49951
|
}
|
|
49340
|
-
const resolved = isAbsolute(dir2) ? dir2 :
|
|
49952
|
+
const resolved = isAbsolute(dir2) ? dir2 : resolve4(process.cwd(), dir2);
|
|
49341
49953
|
const entries = readdirSync6(resolved, { withFileTypes: true });
|
|
49342
49954
|
const items = entries.filter((e) => e.name.toLowerCase().startsWith(prefix.toLowerCase())).filter((e) => prefix || !e.name.startsWith(".")).slice(0, 50).map((e) => {
|
|
49343
49955
|
const full = dir2 + e.name + (e.isDirectory() ? sep : "");
|
|
@@ -49377,7 +49989,7 @@ var init_catalog = __esm({
|
|
|
49377
49989
|
slashifyPair = /* @__PURE__ */ __name((cmd) => [`/${cmd.name}`, cmd.help ?? ""], "slashifyPair");
|
|
49378
49990
|
__name(buildCommandsCatalog, "buildCommandsCatalog");
|
|
49379
49991
|
__name(buildSlashCompletions, "buildSlashCompletions");
|
|
49380
|
-
tildeExpand = /* @__PURE__ */ __name((p) => p.startsWith("~") ?
|
|
49992
|
+
tildeExpand = /* @__PURE__ */ __name((p) => p.startsWith("~") ? join42(homedir28(), p.slice(1).replace(/^[\\/]/, "")) : p, "tildeExpand");
|
|
49381
49993
|
__name(buildPathCompletions, "buildPathCompletions");
|
|
49382
49994
|
}
|
|
49383
49995
|
});
|
|
@@ -49542,39 +50154,39 @@ var init_planner = __esm({
|
|
|
49542
50154
|
});
|
|
49543
50155
|
|
|
49544
50156
|
// src/workflows/persistence.ts
|
|
49545
|
-
import { existsSync as
|
|
49546
|
-
import { homedir as
|
|
49547
|
-
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";
|
|
49548
50160
|
function ensureDir(path3) {
|
|
49549
|
-
if (!
|
|
50161
|
+
if (!existsSync33(path3)) mkdirSync17(path3, { recursive: true });
|
|
49550
50162
|
}
|
|
49551
50163
|
function safeSegment(value) {
|
|
49552
50164
|
return value.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 80) || "default";
|
|
49553
50165
|
}
|
|
49554
50166
|
function readJson(path3) {
|
|
49555
50167
|
try {
|
|
49556
|
-
return JSON.parse(
|
|
50168
|
+
return JSON.parse(readFileSync29(path3, "utf8"));
|
|
49557
50169
|
} catch {
|
|
49558
50170
|
return null;
|
|
49559
50171
|
}
|
|
49560
50172
|
}
|
|
49561
50173
|
function saveWorkflowSnapshot(snapshot) {
|
|
49562
50174
|
ensureDir(workflowDir());
|
|
49563
|
-
const path3 =
|
|
50175
|
+
const path3 = join43(workflowDir(), `${safeSegment(snapshot.id)}.json`);
|
|
49564
50176
|
writeFileSync19(path3, `${JSON.stringify(snapshot, null, 2)}
|
|
49565
50177
|
`, "utf8");
|
|
49566
50178
|
return path3;
|
|
49567
50179
|
}
|
|
49568
50180
|
function loadWorkflowSnapshot(id) {
|
|
49569
|
-
const path3 =
|
|
50181
|
+
const path3 = join43(workflowDir(), `${safeSegment(id)}.json`);
|
|
49570
50182
|
return readJson(path3);
|
|
49571
50183
|
}
|
|
49572
50184
|
function listWorkflowSnapshots(limit = 30) {
|
|
49573
|
-
if (!
|
|
50185
|
+
if (!existsSync33(workflowDir())) return [];
|
|
49574
50186
|
const entries = [];
|
|
49575
50187
|
for (const entry of readdirSync7(workflowDir(), { withFileTypes: true })) {
|
|
49576
50188
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
49577
|
-
const path3 =
|
|
50189
|
+
const path3 = join43(workflowDir(), entry.name);
|
|
49578
50190
|
const snapshot = readJson(path3);
|
|
49579
50191
|
if (!snapshot) continue;
|
|
49580
50192
|
entries.push({
|
|
@@ -49592,10 +50204,10 @@ function listWorkflowSnapshots(limit = 30) {
|
|
|
49592
50204
|
}
|
|
49593
50205
|
function saveSpawnTreeSnapshot(input) {
|
|
49594
50206
|
const sessionId = safeSegment(input.session_id ?? "default");
|
|
49595
|
-
const dir2 =
|
|
50207
|
+
const dir2 = join43(spawnTreeDir(), sessionId);
|
|
49596
50208
|
ensureDir(dir2);
|
|
49597
50209
|
const stamp = new Date((input.finished_at ?? Date.now() / 1e3) * 1e3).toISOString().replace(/[:.]/g, "-");
|
|
49598
|
-
const path3 =
|
|
50210
|
+
const path3 = join43(dir2, `${stamp}-${Math.random().toString(36).slice(2, 8)}.json`);
|
|
49599
50211
|
const snapshot = {
|
|
49600
50212
|
count: input.subagents?.length ?? 0,
|
|
49601
50213
|
finished_at: input.finished_at,
|
|
@@ -49609,12 +50221,12 @@ function saveSpawnTreeSnapshot(input) {
|
|
|
49609
50221
|
return path3;
|
|
49610
50222
|
}
|
|
49611
50223
|
function listSpawnTreeSnapshots(sessionId = "default", limit = 30) {
|
|
49612
|
-
const dir2 =
|
|
49613
|
-
if (!
|
|
50224
|
+
const dir2 = join43(spawnTreeDir(), safeSegment(sessionId));
|
|
50225
|
+
if (!existsSync33(dir2)) return [];
|
|
49614
50226
|
const entries = [];
|
|
49615
50227
|
for (const entry of readdirSync7(dir2, { withFileTypes: true })) {
|
|
49616
50228
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
49617
|
-
const path3 =
|
|
50229
|
+
const path3 = join43(dir2, entry.name);
|
|
49618
50230
|
const snapshot = readJson(path3);
|
|
49619
50231
|
if (!snapshot) continue;
|
|
49620
50232
|
entries.push({
|
|
@@ -49629,8 +50241,8 @@ function listSpawnTreeSnapshots(sessionId = "default", limit = 30) {
|
|
|
49629
50241
|
return entries.sort((a, b) => (b.finished_at ?? 0) - (a.finished_at ?? 0)).slice(0, Math.max(1, limit));
|
|
49630
50242
|
}
|
|
49631
50243
|
function loadSpawnTreeSnapshot(path3) {
|
|
49632
|
-
const root =
|
|
49633
|
-
const resolved =
|
|
50244
|
+
const root = resolve5(spawnTreeDir());
|
|
50245
|
+
const resolved = resolve5(path3);
|
|
49634
50246
|
if (!resolved.startsWith(root)) return null;
|
|
49635
50247
|
const snapshot = readJson(resolved);
|
|
49636
50248
|
return snapshot ? { ...snapshot, path: resolved } : null;
|
|
@@ -49639,9 +50251,9 @@ var rootDir, workflowDir, spawnTreeDir;
|
|
|
49639
50251
|
var init_persistence = __esm({
|
|
49640
50252
|
"src/workflows/persistence.ts"() {
|
|
49641
50253
|
"use strict";
|
|
49642
|
-
rootDir = /* @__PURE__ */ __name(() =>
|
|
49643
|
-
workflowDir = /* @__PURE__ */ __name(() =>
|
|
49644
|
-
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");
|
|
49645
50257
|
__name(ensureDir, "ensureDir");
|
|
49646
50258
|
__name(safeSegment, "safeSegment");
|
|
49647
50259
|
__name(readJson, "readJson");
|
|
@@ -50221,11 +50833,11 @@ ${highlights}` : ""
|
|
|
50221
50833
|
});
|
|
50222
50834
|
|
|
50223
50835
|
// src/rpcHandlers.ts
|
|
50224
|
-
import { spawn as
|
|
50836
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
50225
50837
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
50226
|
-
import { existsSync as
|
|
50227
|
-
import { homedir as
|
|
50228
|
-
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";
|
|
50229
50841
|
function registerRpcHandlers(options) {
|
|
50230
50842
|
const { agentConfig, agentLoop, bridgeEmitter, bridgeManager, bus, mcpManager, systemPromptFn, toolRegistry, voiceManager } = options;
|
|
50231
50843
|
let currentRun = null;
|
|
@@ -50450,6 +51062,7 @@ ${helpMessage}` : field.label;
|
|
|
50450
51062
|
const modelInfo = agentLoop.getActiveModelMetadata();
|
|
50451
51063
|
const nextEffort = parsed.clear ? void 0 : modelInfo ? resolveReasoningEffortForModel(modelInfo, parsed.effort) : parsed.effort;
|
|
50452
51064
|
agentLoop.updateReasoningEffort(nextEffort);
|
|
51065
|
+
agentConfig.llm.model_reasoning_effort = nextEffort;
|
|
50453
51066
|
bus.emitEvent({
|
|
50454
51067
|
payload: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
50455
51068
|
session_id: agentLoop.sessionId,
|
|
@@ -50539,17 +51152,39 @@ ${helpMessage}` : field.label;
|
|
|
50539
51152
|
return { ok: false };
|
|
50540
51153
|
}
|
|
50541
51154
|
});
|
|
50542
|
-
bus.registerRpc("session.create", () =>
|
|
50543
|
-
|
|
50544
|
-
|
|
50545
|
-
|
|
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
|
+
});
|
|
50546
51179
|
bus.registerRpc("session.resume", (params) => {
|
|
50547
51180
|
const id = String(params.session_id ?? agentLoop.sessionId);
|
|
50548
|
-
const
|
|
51181
|
+
const swapped = agentLoop.swapToSession(id);
|
|
51182
|
+
const data = swapped ?? loadSession(id);
|
|
51183
|
+
const visibleMessages = (data?.messages ?? []).filter((m) => !messageIsInternalSelfPrompt(m));
|
|
50549
51184
|
return {
|
|
50550
51185
|
info: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
50551
|
-
message_count:
|
|
50552
|
-
messages:
|
|
51186
|
+
message_count: visibleMessages.length,
|
|
51187
|
+
messages: visibleMessages.map((m) => {
|
|
50553
51188
|
if (m.role === "tool_result") {
|
|
50554
51189
|
return {
|
|
50555
51190
|
role: "tool",
|
|
@@ -50557,13 +51192,14 @@ ${helpMessage}` : field.label;
|
|
|
50557
51192
|
};
|
|
50558
51193
|
}
|
|
50559
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("") : "";
|
|
50560
51196
|
return {
|
|
50561
51197
|
role: m.role,
|
|
50562
|
-
text:
|
|
51198
|
+
text: stripDisplayPrefix(raw, m.role)
|
|
50563
51199
|
};
|
|
50564
51200
|
}),
|
|
50565
|
-
resumed:
|
|
50566
|
-
session_id:
|
|
51201
|
+
resumed: swapped ? id : void 0,
|
|
51202
|
+
session_id: agentLoop.sessionId
|
|
50567
51203
|
};
|
|
50568
51204
|
});
|
|
50569
51205
|
bus.registerRpc("session.list", () => ({
|
|
@@ -50573,6 +51209,10 @@ ${helpMessage}` : field.label;
|
|
|
50573
51209
|
preview: s.summary,
|
|
50574
51210
|
source: `${s.provider}/${s.model}`,
|
|
50575
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(),
|
|
50576
51216
|
title: s.summary || s.id
|
|
50577
51217
|
}))
|
|
50578
51218
|
}));
|
|
@@ -50607,12 +51247,12 @@ ${helpMessage}` : field.label;
|
|
|
50607
51247
|
const id = String(params.session_id ?? agentLoop.sessionId) || agentLoop.sessionId;
|
|
50608
51248
|
const data = loadSession(id);
|
|
50609
51249
|
const messages = data?.messages ?? agentLoop.history;
|
|
50610
|
-
const exportDir =
|
|
50611
|
-
if (!
|
|
51250
|
+
const exportDir = join44(homedir30(), ".openjaw-agent", "exports");
|
|
51251
|
+
if (!existsSync34(exportDir)) {
|
|
50612
51252
|
mkdirSync18(exportDir, { recursive: true });
|
|
50613
51253
|
}
|
|
50614
51254
|
const safeId = id.replace(/[^a-zA-Z0-9_.-]/g, "_") || agentLoop.sessionId;
|
|
50615
|
-
const file2 =
|
|
51255
|
+
const file2 = join44(exportDir, `session-${safeId}.md`);
|
|
50616
51256
|
const lines = [
|
|
50617
51257
|
`# OpenJaw Agent Session ${id}`,
|
|
50618
51258
|
`Date: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -50642,8 +51282,8 @@ ${helpMessage}` : field.label;
|
|
|
50642
51282
|
return { deleted: "" };
|
|
50643
51283
|
}
|
|
50644
51284
|
try {
|
|
50645
|
-
const file2 =
|
|
50646
|
-
if (
|
|
51285
|
+
const file2 = join44(homedir30(), ".openjaw-agent", "sessions", `${id}.json`);
|
|
51286
|
+
if (existsSync34(file2)) {
|
|
50647
51287
|
rmSync(file2);
|
|
50648
51288
|
}
|
|
50649
51289
|
return { deleted: id };
|
|
@@ -50716,11 +51356,11 @@ ${helpMessage}` : field.label;
|
|
|
50716
51356
|
bus.registerRpc("shell.exec", async (params) => {
|
|
50717
51357
|
const command = String(params.command ?? "");
|
|
50718
51358
|
if (!command) return { code: -1, stderr: "empty command" };
|
|
50719
|
-
return await new Promise((
|
|
51359
|
+
return await new Promise((resolve7) => {
|
|
50720
51360
|
const isWin = process.platform === "win32";
|
|
50721
51361
|
const shell = isWin ? "powershell.exe" : "sh";
|
|
50722
51362
|
const args = isWin ? ["-NoProfile", "-Command", command] : ["-c", command];
|
|
50723
|
-
const child =
|
|
51363
|
+
const child = spawn8(shell, args, { timeout: 3e4 });
|
|
50724
51364
|
let stdout = "";
|
|
50725
51365
|
let stderr = "";
|
|
50726
51366
|
let truncated = false;
|
|
@@ -50743,10 +51383,10 @@ ${helpMessage}` : field.label;
|
|
|
50743
51383
|
if (truncated) {
|
|
50744
51384
|
stderr += "\n[output truncated to 1MB]";
|
|
50745
51385
|
}
|
|
50746
|
-
|
|
51386
|
+
resolve7({ code: code ?? -1, stderr, stdout });
|
|
50747
51387
|
});
|
|
50748
51388
|
child.on("error", (err) => {
|
|
50749
|
-
|
|
51389
|
+
resolve7({ code: -1, stderr: err.message });
|
|
50750
51390
|
});
|
|
50751
51391
|
});
|
|
50752
51392
|
});
|
|
@@ -50777,6 +51417,11 @@ ${helpMessage}` : field.label;
|
|
|
50777
51417
|
const modelInfo = agentLoop.getModelMetadata(provider, model);
|
|
50778
51418
|
const reasoningEffort = parsedEffort?.clear ? void 0 : parsedEffort?.effort ? modelInfo ? resolveReasoningEffortForModel(modelInfo, parsedEffort.effort) : parsedEffort.effort : modelInfo ? resolveReasoningEffortForModel(modelInfo, agentLoop.reasoningEffort) : agentLoop.reasoningEffort;
|
|
50779
51419
|
agentLoop.switchModel(provider, model, reasoningEffort);
|
|
51420
|
+
bus.emitEvent({
|
|
51421
|
+
payload: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
51422
|
+
session_id: agentLoop.sessionId,
|
|
51423
|
+
type: "session.info"
|
|
51424
|
+
});
|
|
50780
51425
|
return {
|
|
50781
51426
|
info: sessionInfoSnapshot(agentLoop, toolRegistry),
|
|
50782
51427
|
ok: true
|
|
@@ -50854,8 +51499,8 @@ ${helpMessage}` : field.label;
|
|
|
50854
51499
|
if (auth.auth_type !== "oauth") {
|
|
50855
51500
|
throw new Error(`${PROVIDER_LABELS[slug]} does not use OAuth (auth_type=${auth.auth_type})`);
|
|
50856
51501
|
}
|
|
50857
|
-
const
|
|
50858
|
-
if (!
|
|
51502
|
+
const clientId2 = resolveCopilotClientId();
|
|
51503
|
+
if (!clientId2) {
|
|
50859
51504
|
throw new Error(
|
|
50860
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."
|
|
50861
51506
|
);
|
|
@@ -50867,7 +51512,7 @@ ${helpMessage}` : field.label;
|
|
|
50867
51512
|
}
|
|
50868
51513
|
return agentConfig.llm.copilot_enterprise_url;
|
|
50869
51514
|
})();
|
|
50870
|
-
const flow = await startCopilotDeviceFlow(
|
|
51515
|
+
const flow = await startCopilotDeviceFlow(clientId2, enterpriseUrl);
|
|
50871
51516
|
const flowId = randomUUID14();
|
|
50872
51517
|
const controller = new AbortController();
|
|
50873
51518
|
const timer = setTimeout(() => {
|
|
@@ -51388,13 +52033,13 @@ ${helpMessage}` : field.label;
|
|
|
51388
52033
|
const firstSpace = raw.search(/\s/);
|
|
51389
52034
|
const path3 = firstSpace > 0 ? raw.slice(0, firstSpace) : raw;
|
|
51390
52035
|
const remainder = firstSpace > 0 ? raw.slice(firstSpace).trim() : "";
|
|
51391
|
-
if (!
|
|
52036
|
+
if (!existsSync34(path3)) {
|
|
51392
52037
|
throw new Error(`image.attach: file not found: ${path3}`);
|
|
51393
52038
|
}
|
|
51394
52039
|
let buffer;
|
|
51395
52040
|
let fileSize = 0;
|
|
51396
52041
|
try {
|
|
51397
|
-
buffer =
|
|
52042
|
+
buffer = readFileSync30(path3);
|
|
51398
52043
|
fileSize = statSync4(path3).size;
|
|
51399
52044
|
} catch (err) {
|
|
51400
52045
|
throw new Error(`image.attach: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -51440,13 +52085,13 @@ ${helpMessage}` : field.label;
|
|
|
51440
52085
|
}
|
|
51441
52086
|
});
|
|
51442
52087
|
bus.registerRpc("reload.env", () => {
|
|
51443
|
-
const envPath =
|
|
51444
|
-
if (!
|
|
52088
|
+
const envPath = join44(homedir30(), ".openjaw-agent", ".env");
|
|
52089
|
+
if (!existsSync34(envPath)) {
|
|
51445
52090
|
return { updated: 0 };
|
|
51446
52091
|
}
|
|
51447
52092
|
let updated = 0;
|
|
51448
52093
|
try {
|
|
51449
|
-
const raw =
|
|
52094
|
+
const raw = readFileSync30(envPath, "utf-8");
|
|
51450
52095
|
for (const line of raw.split(/\r?\n/)) {
|
|
51451
52096
|
const trimmed = line.trim();
|
|
51452
52097
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -51625,7 +52270,7 @@ ${helpMessage}` : field.label;
|
|
|
51625
52270
|
}
|
|
51626
52271
|
};
|
|
51627
52272
|
}
|
|
51628
|
-
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;
|
|
51629
52274
|
var init_rpcHandlers = __esm({
|
|
51630
52275
|
"src/rpcHandlers.ts"() {
|
|
51631
52276
|
"use strict";
|
|
@@ -51835,8 +52480,8 @@ var init_rpcHandlers = __esm({
|
|
|
51835
52480
|
${raw}`;
|
|
51836
52481
|
return `${header}: ${raw}`;
|
|
51837
52482
|
}, "formatBridgeText");
|
|
51838
|
-
runProcess = /* @__PURE__ */ __name((command, args, timeout = 2e4) => new Promise((
|
|
51839
|
-
const child =
|
|
52483
|
+
runProcess = /* @__PURE__ */ __name((command, args, timeout = 2e4) => new Promise((resolve7) => {
|
|
52484
|
+
const child = spawn8(command, args, { timeout, windowsHide: true });
|
|
51840
52485
|
let stdout = "";
|
|
51841
52486
|
let stderr = "";
|
|
51842
52487
|
let truncated = false;
|
|
@@ -51859,9 +52504,9 @@ ${raw}`;
|
|
|
51859
52504
|
if (truncated) {
|
|
51860
52505
|
stderr += "\n[output truncated to 1MB]";
|
|
51861
52506
|
}
|
|
51862
|
-
|
|
52507
|
+
resolve7({ code: code ?? -1, stderr, stdout });
|
|
51863
52508
|
});
|
|
51864
|
-
child.on("error", (err) =>
|
|
52509
|
+
child.on("error", (err) => resolve7({ code: -1, stderr: err.message, stdout }));
|
|
51865
52510
|
}), "runProcess");
|
|
51866
52511
|
contentToText = /* @__PURE__ */ __name((content) => {
|
|
51867
52512
|
if (typeof content === "string") return content;
|
|
@@ -51885,6 +52530,27 @@ ${raw}`;
|
|
|
51885
52530
|
}
|
|
51886
52531
|
return [];
|
|
51887
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");
|
|
51888
52554
|
sessionInfoSnapshot = /* @__PURE__ */ __name((agentLoop, toolRegistry) => ({
|
|
51889
52555
|
cwd: process.cwd(),
|
|
51890
52556
|
model: agentLoop.model,
|
|
@@ -52019,14 +52685,14 @@ var init_memoryMonitor = __esm({
|
|
|
52019
52685
|
});
|
|
52020
52686
|
|
|
52021
52687
|
// src/lib/openExternalUrl.ts
|
|
52022
|
-
import { spawn as
|
|
52688
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
52023
52689
|
import { platform } from "node:os";
|
|
52024
52690
|
function openExternalUrl(rawUrl, dependencies = {}) {
|
|
52025
52691
|
const url = parseSafeUrl(rawUrl);
|
|
52026
52692
|
if (!url) {
|
|
52027
52693
|
return false;
|
|
52028
52694
|
}
|
|
52029
|
-
const spawnFn = dependencies.spawn ??
|
|
52695
|
+
const spawnFn = dependencies.spawn ?? spawn9;
|
|
52030
52696
|
const platformId = dependencies.platform?.() ?? platform();
|
|
52031
52697
|
const command = openCommand(platformId);
|
|
52032
52698
|
if (!command) {
|
|
@@ -52519,9 +53185,9 @@ var init_useVirtualHistory = __esm({
|
|
|
52519
53185
|
viewportHeight
|
|
52520
53186
|
}) => itemCount > 0 && viewportHeight > 0 && !sticky && !liveTailActive, "shouldSetVirtualClamp");
|
|
52521
53187
|
ensureVirtualItemHeight = /* @__PURE__ */ __name((heights, key, index, estimate, estimateHeight) => {
|
|
52522
|
-
const
|
|
52523
|
-
if (
|
|
52524
|
-
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));
|
|
52525
53191
|
}
|
|
52526
53192
|
const seeded = Math.max(1, Math.floor(estimateHeight?.(index, key) ?? estimate));
|
|
52527
53193
|
heights.set(key, seeded);
|
|
@@ -53959,7 +54625,7 @@ function createGatewayEventHandler(ctx) {
|
|
|
53959
54625
|
setTimeout(async () => {
|
|
53960
54626
|
let sid = getUiState().sid;
|
|
53961
54627
|
for (let i = 0; !sid && i < 40; i += 1) {
|
|
53962
|
-
await new Promise((
|
|
54628
|
+
await new Promise((resolve7) => setTimeout(resolve7, 100));
|
|
53963
54629
|
sid = getUiState().sid;
|
|
53964
54630
|
}
|
|
53965
54631
|
if (!sid) {
|
|
@@ -54706,21 +55372,21 @@ var init_useCompletion = __esm({
|
|
|
54706
55372
|
});
|
|
54707
55373
|
|
|
54708
55374
|
// src/lib/history.ts
|
|
54709
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
54710
|
-
import { homedir as
|
|
54711
|
-
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";
|
|
54712
55378
|
function load() {
|
|
54713
55379
|
if (cache3) {
|
|
54714
55380
|
return cache3;
|
|
54715
55381
|
}
|
|
54716
55382
|
try {
|
|
54717
|
-
if (!
|
|
55383
|
+
if (!existsSync35(file)) {
|
|
54718
55384
|
cache3 = [];
|
|
54719
55385
|
return cache3;
|
|
54720
55386
|
}
|
|
54721
55387
|
const entries = [];
|
|
54722
55388
|
let current = [];
|
|
54723
|
-
for (const line of
|
|
55389
|
+
for (const line of readFileSync31(file, "utf8").split("\n")) {
|
|
54724
55390
|
if (line.startsWith("+")) {
|
|
54725
55391
|
current.push(line.slice(1));
|
|
54726
55392
|
} else if (current.length) {
|
|
@@ -54751,7 +55417,7 @@ function append(line) {
|
|
|
54751
55417
|
items.splice(0, items.length - MAX);
|
|
54752
55418
|
}
|
|
54753
55419
|
try {
|
|
54754
|
-
if (!
|
|
55420
|
+
if (!existsSync35(dir)) {
|
|
54755
55421
|
mkdirSync19(dir, { recursive: true });
|
|
54756
55422
|
}
|
|
54757
55423
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace("Z", "");
|
|
@@ -54768,8 +55434,8 @@ var init_history = __esm({
|
|
|
54768
55434
|
"src/lib/history.ts"() {
|
|
54769
55435
|
"use strict";
|
|
54770
55436
|
MAX = 1e3;
|
|
54771
|
-
dir = process.env.OPENJAW_HOME ??
|
|
54772
|
-
file =
|
|
55437
|
+
dir = process.env.OPENJAW_HOME ?? join45(homedir31(), ".openjaw-agent");
|
|
55438
|
+
file = join45(dir, ".openjaw-agent_history");
|
|
54773
55439
|
cache3 = null;
|
|
54774
55440
|
__name(load, "load");
|
|
54775
55441
|
__name(append, "append");
|
|
@@ -54862,8 +55528,8 @@ var init_useQueue = __esm({
|
|
|
54862
55528
|
});
|
|
54863
55529
|
|
|
54864
55530
|
// src/lib/editor.ts
|
|
54865
|
-
import { accessSync, constants } from "node:fs";
|
|
54866
|
-
import { delimiter, join as
|
|
55531
|
+
import { accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
55532
|
+
import { delimiter, join as join46 } from "node:path";
|
|
54867
55533
|
var FALLBACKS, isExecutable, resolveEditor;
|
|
54868
55534
|
var init_editor = __esm({
|
|
54869
55535
|
"src/lib/editor.ts"() {
|
|
@@ -54871,7 +55537,7 @@ var init_editor = __esm({
|
|
|
54871
55537
|
FALLBACKS = ["editor", "nano", "pico", "vi", "emacs"];
|
|
54872
55538
|
isExecutable = /* @__PURE__ */ __name((path3) => {
|
|
54873
55539
|
try {
|
|
54874
|
-
|
|
55540
|
+
accessSync2(path3, constants2.X_OK);
|
|
54875
55541
|
return true;
|
|
54876
55542
|
} catch {
|
|
54877
55543
|
return false;
|
|
@@ -54886,7 +55552,7 @@ var init_editor = __esm({
|
|
|
54886
55552
|
return ["notepad.exe"];
|
|
54887
55553
|
}
|
|
54888
55554
|
const dirs = (env2.PATH ?? "").split(delimiter).filter(Boolean);
|
|
54889
|
-
const found = FALLBACKS.flatMap((name) => dirs.map((d) =>
|
|
55555
|
+
const found = FALLBACKS.flatMap((name) => dirs.map((d) => join46(d, name))).find(isExecutable);
|
|
54890
55556
|
return [found ?? "vi"];
|
|
54891
55557
|
}, "resolveEditor");
|
|
54892
55558
|
}
|
|
@@ -54894,9 +55560,9 @@ var init_editor = __esm({
|
|
|
54894
55560
|
|
|
54895
55561
|
// src/app/useComposerState.ts
|
|
54896
55562
|
import { spawnSync } from "node:child_process";
|
|
54897
|
-
import { mkdtempSync, readFileSync as
|
|
55563
|
+
import { mkdtempSync, readFileSync as readFileSync32, rmSync as rmSync2, writeFileSync as writeFileSync21 } from "node:fs";
|
|
54898
55564
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
54899
|
-
import { join as
|
|
55565
|
+
import { join as join47 } from "node:path";
|
|
54900
55566
|
import { useStore } from "@nanostores/react";
|
|
54901
55567
|
import { useCallback as useCallback7, useMemo as useMemo6, useState as useState12 } from "react";
|
|
54902
55568
|
function insertAtCursor(value, cursor, text) {
|
|
@@ -55053,8 +55719,8 @@ function useComposerState({
|
|
|
55053
55719
|
[handleResolvedPaste, onClipboardPaste, querier]
|
|
55054
55720
|
);
|
|
55055
55721
|
const openEditor = useCallback7(async () => {
|
|
55056
|
-
const dir2 = mkdtempSync(
|
|
55057
|
-
const file2 =
|
|
55722
|
+
const dir2 = mkdtempSync(join47(tmpdir12(), "hermes-"));
|
|
55723
|
+
const file2 = join47(dir2, "prompt.md");
|
|
55058
55724
|
const [cmd, ...args] = resolveEditor();
|
|
55059
55725
|
writeFileSync21(file2, [...inputBuf, input].join("\n"));
|
|
55060
55726
|
let exitCode = null;
|
|
@@ -55065,7 +55731,7 @@ function useComposerState({
|
|
|
55065
55731
|
if (exitCode !== 0) {
|
|
55066
55732
|
return;
|
|
55067
55733
|
}
|
|
55068
|
-
const text =
|
|
55734
|
+
const text = readFileSync32(file2, "utf8").trimEnd();
|
|
55069
55735
|
if (!text) {
|
|
55070
55736
|
return;
|
|
55071
55737
|
}
|
|
@@ -57147,8 +57813,8 @@ __export(perfPane_exports, {
|
|
|
57147
57813
|
logFrameEvent: () => logFrameEvent
|
|
57148
57814
|
});
|
|
57149
57815
|
import { appendFileSync as appendFileSync5, mkdirSync as mkdirSync20 } from "node:fs";
|
|
57150
|
-
import { homedir as
|
|
57151
|
-
import { dirname as
|
|
57816
|
+
import { homedir as homedir32 } from "node:os";
|
|
57817
|
+
import { dirname as dirname9, join as join48 } from "node:path";
|
|
57152
57818
|
import { Profiler } from "react";
|
|
57153
57819
|
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
57154
57820
|
function PerfPane({ children, id }) {
|
|
@@ -57164,13 +57830,13 @@ var init_perfPane = __esm({
|
|
|
57164
57830
|
init_entry_exports();
|
|
57165
57831
|
ENABLED = /^(?:1|true|yes|on)$/i.test((process.env.OPENJAW_DEV_PERF ?? "").trim());
|
|
57166
57832
|
THRESHOLD_MS = Number(process.env.OPENJAW_DEV_PERF_MS ?? "2") || 0;
|
|
57167
|
-
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");
|
|
57168
57834
|
logReady = false;
|
|
57169
57835
|
writeRow = /* @__PURE__ */ __name((row) => {
|
|
57170
57836
|
if (!logReady) {
|
|
57171
57837
|
logReady = true;
|
|
57172
57838
|
try {
|
|
57173
|
-
mkdirSync20(
|
|
57839
|
+
mkdirSync20(dirname9(LOG_PATH2), { recursive: true });
|
|
57174
57840
|
} catch {
|
|
57175
57841
|
}
|
|
57176
57842
|
}
|
|
@@ -62428,7 +63094,7 @@ var init_mathUnicode = __esm({
|
|
|
62428
63094
|
|
|
62429
63095
|
// src/lib/syntax.ts
|
|
62430
63096
|
function highlightLine(line, lang, t) {
|
|
62431
|
-
const spec =
|
|
63097
|
+
const spec = resolve6(lang);
|
|
62432
63098
|
if (!spec) {
|
|
62433
63099
|
return [["", line]];
|
|
62434
63100
|
}
|
|
@@ -62460,7 +63126,7 @@ function highlightLine(line, lang, t) {
|
|
|
62460
63126
|
}
|
|
62461
63127
|
return tokens;
|
|
62462
63128
|
}
|
|
62463
|
-
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;
|
|
62464
63130
|
var init_syntax = __esm({
|
|
62465
63131
|
"src/lib/syntax.ts"() {
|
|
62466
63132
|
"use strict";
|
|
@@ -62514,8 +63180,8 @@ var init_syntax = __esm({
|
|
|
62514
63180
|
yml: "yaml",
|
|
62515
63181
|
zsh: "sh"
|
|
62516
63182
|
};
|
|
62517
|
-
|
|
62518
|
-
isHighlightable = /* @__PURE__ */ __name((lang) =>
|
|
63183
|
+
resolve6 = /* @__PURE__ */ __name((lang) => LANGS[ALIAS[lang] ?? lang] ?? null, "resolve");
|
|
63184
|
+
isHighlightable = /* @__PURE__ */ __name((lang) => resolve6(lang) !== null, "isHighlightable");
|
|
62519
63185
|
TOKEN_RE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`|\b\d+(?:\.\d+)?\b|[A-Za-z_$][\w$]*/g;
|
|
62520
63186
|
__name(highlightLine, "highlightLine");
|
|
62521
63187
|
}
|
|
@@ -62615,9 +63281,9 @@ function MdImpl({ compact, t, text }) {
|
|
|
62615
63281
|
const nodes = useMemo14(() => {
|
|
62616
63282
|
const bucket = cacheBucket(t);
|
|
62617
63283
|
const cacheKey = `${compact ? "1" : "0"}|${text}`;
|
|
62618
|
-
const
|
|
62619
|
-
if (
|
|
62620
|
-
return
|
|
63284
|
+
const cached8 = cacheGet(bucket, cacheKey);
|
|
63285
|
+
if (cached8) {
|
|
63286
|
+
return cached8;
|
|
62621
63287
|
}
|
|
62622
63288
|
const lines = ensureEmojiPresentation(text).split("\n");
|
|
62623
63289
|
const nodes2 = [];
|
|
@@ -64850,12 +65516,18 @@ var init_entry = __esm({
|
|
|
64850
65516
|
// src/main.ts
|
|
64851
65517
|
async function main() {
|
|
64852
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
|
+
}
|
|
64853
65524
|
if (args.includes("--help") || args.includes("-h")) {
|
|
64854
65525
|
console.log(`
|
|
64855
65526
|
OpenJaw Agent \u2014 Autonomous desktop AI assistant
|
|
64856
65527
|
|
|
64857
65528
|
Usage:
|
|
64858
65529
|
openjaw-agent Start new session (Ink UI)
|
|
65530
|
+
openjaw-agent app Start the Electron desktop UI (optional)
|
|
64859
65531
|
openjaw-agent --legacy-ui Start with the previous Ink UI (pre-rewrite)
|
|
64860
65532
|
openjaw-agent --telegram Ink UI + Telegram bridge (hybrid)
|
|
64861
65533
|
openjaw-agent --telegram --headless Telegram only (no desktop UI)
|