agent-relay 2.1.2 → 2.1.4
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/bin/relay-pty-darwin-arm64 +0 -0
- package/bin/relay-pty-darwin-x64 +0 -0
- package/bin/relay-pty-linux-arm64 +0 -0
- package/bin/relay-pty-linux-x64 +0 -0
- package/dist/index.cjs +296 -177
- package/package.json +18 -18
- package/packages/api-types/package.json +1 -1
- package/packages/benchmark/package.json +4 -4
- package/packages/bridge/dist/cli-resolution.d.ts +32 -0
- package/packages/bridge/dist/cli-resolution.d.ts.map +1 -0
- package/packages/bridge/dist/cli-resolution.js +88 -0
- package/packages/bridge/dist/cli-resolution.js.map +1 -0
- package/packages/bridge/dist/index.d.ts +1 -0
- package/packages/bridge/dist/index.d.ts.map +1 -1
- package/packages/bridge/dist/index.js +2 -0
- package/packages/bridge/dist/index.js.map +1 -1
- package/packages/bridge/dist/spawner.d.ts.map +1 -1
- package/packages/bridge/dist/spawner.js +4 -12
- package/packages/bridge/dist/spawner.js.map +1 -1
- package/packages/bridge/package.json +8 -8
- package/packages/bridge/src/cli-resolution.test.ts +225 -0
- package/packages/bridge/src/cli-resolution.ts +100 -0
- package/packages/bridge/src/index.ts +9 -0
- package/packages/bridge/src/spawner.ts +4 -13
- package/packages/cli-tester/package.json +1 -1
- package/packages/config/package.json +2 -2
- package/packages/continuity/package.json +2 -2
- package/packages/daemon/package.json +12 -12
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/package.json +3 -3
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/package.json +1 -1
- package/packages/resiliency/package.json +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/spawner/package.json +1 -1
- package/packages/state/package.json +1 -1
- package/packages/storage/dist/adapter.d.ts +2 -0
- package/packages/storage/dist/adapter.d.ts.map +1 -1
- package/packages/storage/dist/adapter.js +7 -1
- package/packages/storage/dist/adapter.js.map +1 -1
- package/packages/storage/dist/jsonl-adapter.d.ts +14 -0
- package/packages/storage/dist/jsonl-adapter.d.ts.map +1 -1
- package/packages/storage/dist/jsonl-adapter.js +75 -0
- package/packages/storage/dist/jsonl-adapter.js.map +1 -1
- package/packages/storage/package.json +2 -2
- package/packages/storage/src/adapter.ts +9 -1
- package/packages/storage/src/jsonl-adapter.test.ts +31 -0
- package/packages/storage/src/jsonl-adapter.ts +86 -0
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +2 -2
- package/packages/wrapper/dist/shared.d.ts.map +1 -1
- package/packages/wrapper/dist/shared.js +5 -0
- package/packages/wrapper/dist/shared.js.map +1 -1
- package/packages/wrapper/package.json +6 -6
- package/packages/wrapper/src/shared.ts +5 -0
package/dist/index.cjs
CHANGED
|
@@ -3147,13 +3147,13 @@ var init_logger = __esm({
|
|
|
3147
3147
|
});
|
|
3148
3148
|
|
|
3149
3149
|
// packages/config/dist/bridge-utils.js
|
|
3150
|
-
var
|
|
3150
|
+
var import_node_child_process9, import_node_util3, execAsync2;
|
|
3151
3151
|
var init_bridge_utils = __esm({
|
|
3152
3152
|
"packages/config/dist/bridge-utils.js"() {
|
|
3153
3153
|
"use strict";
|
|
3154
|
-
|
|
3154
|
+
import_node_child_process9 = require("node:child_process");
|
|
3155
3155
|
import_node_util3 = require("node:util");
|
|
3156
|
-
execAsync2 = (0, import_node_util3.promisify)(
|
|
3156
|
+
execAsync2 = (0, import_node_util3.promisify)(import_node_child_process9.exec);
|
|
3157
3157
|
}
|
|
3158
3158
|
});
|
|
3159
3159
|
|
|
@@ -7441,11 +7441,11 @@ var require_core = __commonJS({
|
|
|
7441
7441
|
Ajv2.ValidationError = validation_error_1.default;
|
|
7442
7442
|
Ajv2.MissingRefError = ref_error_1.default;
|
|
7443
7443
|
exports2.default = Ajv2;
|
|
7444
|
-
function checkOptions(checkOpts, options, msg,
|
|
7444
|
+
function checkOptions(checkOpts, options, msg, log8 = "error") {
|
|
7445
7445
|
for (const key in checkOpts) {
|
|
7446
7446
|
const opt = key;
|
|
7447
7447
|
if (opt in options)
|
|
7448
|
-
this.logger[
|
|
7448
|
+
this.logger[log8](`${msg}: option ${key}. ${checkOpts[opt]}`);
|
|
7449
7449
|
}
|
|
7450
7450
|
}
|
|
7451
7451
|
function getSchEnv(keyRef) {
|
|
@@ -20852,7 +20852,7 @@ var require_node = __commonJS({
|
|
|
20852
20852
|
var tty = require("tty");
|
|
20853
20853
|
var util2 = require("util");
|
|
20854
20854
|
exports2.init = init;
|
|
20855
|
-
exports2.log =
|
|
20855
|
+
exports2.log = log8;
|
|
20856
20856
|
exports2.formatArgs = formatArgs;
|
|
20857
20857
|
exports2.save = save;
|
|
20858
20858
|
exports2.load = load;
|
|
@@ -20987,7 +20987,7 @@ var require_node = __commonJS({
|
|
|
20987
20987
|
}
|
|
20988
20988
|
return (/* @__PURE__ */ new Date()).toISOString() + " ";
|
|
20989
20989
|
}
|
|
20990
|
-
function
|
|
20990
|
+
function log8(...args) {
|
|
20991
20991
|
return process.stderr.write(util2.formatWithOptions(exports2.inspectOpts, ...args) + "\n");
|
|
20992
20992
|
}
|
|
20993
20993
|
function save(namespaces) {
|
|
@@ -26022,7 +26022,7 @@ var jsonl_adapter_exports = {};
|
|
|
26022
26022
|
__export(jsonl_adapter_exports, {
|
|
26023
26023
|
JsonlStorageAdapter: () => JsonlStorageAdapter
|
|
26024
26024
|
});
|
|
26025
|
-
var import_node_fs20, import_node_path22, DEFAULT_RETENTION_MS2, DEFAULT_CLEANUP_INTERVAL_MS2, JsonlStorageAdapter;
|
|
26025
|
+
var import_node_fs20, import_node_path22, DEFAULT_RETENTION_MS2, DEFAULT_CLEANUP_INTERVAL_MS2, DEFAULT_WATCH_DEBOUNCE_MS, JsonlStorageAdapter;
|
|
26026
26026
|
var init_jsonl_adapter = __esm({
|
|
26027
26027
|
"packages/storage/dist/jsonl-adapter.js"() {
|
|
26028
26028
|
"use strict";
|
|
@@ -26030,6 +26030,7 @@ var init_jsonl_adapter = __esm({
|
|
|
26030
26030
|
import_node_path22 = __toESM(require("node:path"), 1);
|
|
26031
26031
|
DEFAULT_RETENTION_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
26032
26032
|
DEFAULT_CLEANUP_INTERVAL_MS2 = 60 * 60 * 1e3;
|
|
26033
|
+
DEFAULT_WATCH_DEBOUNCE_MS = 100;
|
|
26033
26034
|
JsonlStorageAdapter = class {
|
|
26034
26035
|
baseDir;
|
|
26035
26036
|
messageDir;
|
|
@@ -26045,6 +26046,12 @@ var init_jsonl_adapter = __esm({
|
|
|
26045
26046
|
deletedMessages = /* @__PURE__ */ new Set();
|
|
26046
26047
|
sessions = /* @__PURE__ */ new Map();
|
|
26047
26048
|
resumeIndex = /* @__PURE__ */ new Map();
|
|
26049
|
+
watchForChanges;
|
|
26050
|
+
watchDebounceMs;
|
|
26051
|
+
messageWatcher;
|
|
26052
|
+
sessionWatcher;
|
|
26053
|
+
reloadDebounceTimer;
|
|
26054
|
+
sessionReloadDebounceTimer;
|
|
26048
26055
|
constructor(options) {
|
|
26049
26056
|
this.baseDir = options.baseDir;
|
|
26050
26057
|
this.messageDir = import_node_path22.default.join(this.baseDir, "messages");
|
|
@@ -26052,6 +26059,8 @@ var init_jsonl_adapter = __esm({
|
|
|
26052
26059
|
this.retentionMs = options.messageRetentionMs ?? DEFAULT_RETENTION_MS2;
|
|
26053
26060
|
this.cleanupIntervalMs = options.cleanupIntervalMs ?? DEFAULT_CLEANUP_INTERVAL_MS2;
|
|
26054
26061
|
this.fallbackReason = options.reason;
|
|
26062
|
+
this.watchForChanges = options.watchForChanges ?? false;
|
|
26063
|
+
this.watchDebounceMs = options.watchDebounceMs ?? DEFAULT_WATCH_DEBOUNCE_MS;
|
|
26055
26064
|
}
|
|
26056
26065
|
async init() {
|
|
26057
26066
|
await import_node_fs20.default.promises.mkdir(this.messageDir, { recursive: true });
|
|
@@ -26062,12 +26071,16 @@ var init_jsonl_adapter = __esm({
|
|
|
26062
26071
|
if (this.cleanupIntervalMs > 0) {
|
|
26063
26072
|
this.startCleanupTimer();
|
|
26064
26073
|
}
|
|
26074
|
+
if (this.watchForChanges) {
|
|
26075
|
+
this.startFileWatching();
|
|
26076
|
+
}
|
|
26065
26077
|
}
|
|
26066
26078
|
async close() {
|
|
26067
26079
|
if (this.cleanupTimer) {
|
|
26068
26080
|
clearInterval(this.cleanupTimer);
|
|
26069
26081
|
this.cleanupTimer = void 0;
|
|
26070
26082
|
}
|
|
26083
|
+
this.stopFileWatching();
|
|
26071
26084
|
this.messages.clear();
|
|
26072
26085
|
this.deletedMessages.clear();
|
|
26073
26086
|
this.sessions.clear();
|
|
@@ -26323,6 +26336,64 @@ var init_jsonl_adapter = __esm({
|
|
|
26323
26336
|
this.cleanupTimer.unref();
|
|
26324
26337
|
}
|
|
26325
26338
|
}
|
|
26339
|
+
startFileWatching() {
|
|
26340
|
+
try {
|
|
26341
|
+
this.messageWatcher = import_node_fs20.default.watch(this.messageDir, (eventType, filename) => {
|
|
26342
|
+
if (filename && filename.endsWith(".jsonl")) {
|
|
26343
|
+
this.debouncedReloadMessages();
|
|
26344
|
+
}
|
|
26345
|
+
});
|
|
26346
|
+
if (this.messageWatcher.unref) {
|
|
26347
|
+
this.messageWatcher.unref();
|
|
26348
|
+
}
|
|
26349
|
+
} catch {
|
|
26350
|
+
}
|
|
26351
|
+
try {
|
|
26352
|
+
this.sessionWatcher = import_node_fs20.default.watch(this.sessionFile, () => {
|
|
26353
|
+
this.debouncedReloadSessions();
|
|
26354
|
+
});
|
|
26355
|
+
if (this.sessionWatcher.unref) {
|
|
26356
|
+
this.sessionWatcher.unref();
|
|
26357
|
+
}
|
|
26358
|
+
} catch {
|
|
26359
|
+
}
|
|
26360
|
+
}
|
|
26361
|
+
stopFileWatching() {
|
|
26362
|
+
if (this.messageWatcher) {
|
|
26363
|
+
this.messageWatcher.close();
|
|
26364
|
+
this.messageWatcher = void 0;
|
|
26365
|
+
}
|
|
26366
|
+
if (this.sessionWatcher) {
|
|
26367
|
+
this.sessionWatcher.close();
|
|
26368
|
+
this.sessionWatcher = void 0;
|
|
26369
|
+
}
|
|
26370
|
+
if (this.reloadDebounceTimer) {
|
|
26371
|
+
clearTimeout(this.reloadDebounceTimer);
|
|
26372
|
+
this.reloadDebounceTimer = void 0;
|
|
26373
|
+
}
|
|
26374
|
+
if (this.sessionReloadDebounceTimer) {
|
|
26375
|
+
clearTimeout(this.sessionReloadDebounceTimer);
|
|
26376
|
+
this.sessionReloadDebounceTimer = void 0;
|
|
26377
|
+
}
|
|
26378
|
+
}
|
|
26379
|
+
debouncedReloadMessages() {
|
|
26380
|
+
if (this.reloadDebounceTimer) {
|
|
26381
|
+
clearTimeout(this.reloadDebounceTimer);
|
|
26382
|
+
}
|
|
26383
|
+
this.reloadDebounceTimer = setTimeout(() => {
|
|
26384
|
+
this.loadMessagesFromDisk().catch(() => {
|
|
26385
|
+
});
|
|
26386
|
+
}, this.watchDebounceMs);
|
|
26387
|
+
}
|
|
26388
|
+
debouncedReloadSessions() {
|
|
26389
|
+
if (this.sessionReloadDebounceTimer) {
|
|
26390
|
+
clearTimeout(this.sessionReloadDebounceTimer);
|
|
26391
|
+
}
|
|
26392
|
+
this.sessionReloadDebounceTimer = setTimeout(() => {
|
|
26393
|
+
this.loadSessionsFromDisk().catch(() => {
|
|
26394
|
+
});
|
|
26395
|
+
}, this.watchDebounceMs);
|
|
26396
|
+
}
|
|
26326
26397
|
async loadMessagesFromDisk() {
|
|
26327
26398
|
this.messages.clear();
|
|
26328
26399
|
this.deletedMessages.clear();
|
|
@@ -31548,13 +31619,13 @@ var channel_membership_store_exports = {};
|
|
|
31548
31619
|
__export(channel_membership_store_exports, {
|
|
31549
31620
|
CloudChannelMembershipStore: () => CloudChannelMembershipStore
|
|
31550
31621
|
});
|
|
31551
|
-
var
|
|
31622
|
+
var log7, CloudChannelMembershipStore;
|
|
31552
31623
|
var init_channel_membership_store = __esm({
|
|
31553
31624
|
"packages/daemon/dist/channel-membership-store.js"() {
|
|
31554
31625
|
"use strict";
|
|
31555
31626
|
init_esm();
|
|
31556
31627
|
init_logger();
|
|
31557
|
-
|
|
31628
|
+
log7 = createLogger2("channel-membership-store");
|
|
31558
31629
|
CloudChannelMembershipStore = class {
|
|
31559
31630
|
workspaceId;
|
|
31560
31631
|
pool;
|
|
@@ -31584,7 +31655,7 @@ var init_channel_membership_store = __esm({
|
|
|
31584
31655
|
member: row.member_id
|
|
31585
31656
|
})).filter((row) => Boolean(row.channel && row.member));
|
|
31586
31657
|
} catch (err) {
|
|
31587
|
-
|
|
31658
|
+
log7.error("Failed to load channel memberships from cloud DB", {
|
|
31588
31659
|
error: err instanceof Error ? err.message : String(err)
|
|
31589
31660
|
});
|
|
31590
31661
|
return [];
|
|
@@ -31607,7 +31678,7 @@ var init_channel_membership_store = __esm({
|
|
|
31607
31678
|
member: row.member_id
|
|
31608
31679
|
})).filter((row) => Boolean(row.channel && row.member));
|
|
31609
31680
|
} catch (err) {
|
|
31610
|
-
|
|
31681
|
+
log7.error("Failed to load channel memberships for agent from cloud DB", {
|
|
31611
31682
|
memberName,
|
|
31612
31683
|
error: err instanceof Error ? err.message : String(err)
|
|
31613
31684
|
});
|
|
@@ -31633,7 +31704,7 @@ var init_channel_membership_store = __esm({
|
|
|
31633
31704
|
ON CONFLICT (channel_id, member_id) DO NOTHING
|
|
31634
31705
|
`, [channelRowId, member]);
|
|
31635
31706
|
} catch (err) {
|
|
31636
|
-
|
|
31707
|
+
log7.error("Failed to add channel member in cloud DB", {
|
|
31637
31708
|
channel: normalized,
|
|
31638
31709
|
member,
|
|
31639
31710
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -31655,7 +31726,7 @@ var init_channel_membership_store = __esm({
|
|
|
31655
31726
|
try {
|
|
31656
31727
|
await this.pool.query("DELETE FROM channel_members WHERE channel_id = $1 AND member_id = $2", [channelRowId, member]);
|
|
31657
31728
|
} catch (err) {
|
|
31658
|
-
|
|
31729
|
+
log7.error("Failed to remove channel member in cloud DB", {
|
|
31659
31730
|
channel: normalized,
|
|
31660
31731
|
member,
|
|
31661
31732
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -31695,7 +31766,7 @@ var init_channel_membership_store = __esm({
|
|
|
31695
31766
|
LIMIT 1
|
|
31696
31767
|
`, [this.workspaceId, channelId]);
|
|
31697
31768
|
if (!result.rows[0]?.id) {
|
|
31698
|
-
|
|
31769
|
+
log7.warn("Channel not found in cloud DB for membership update", {
|
|
31699
31770
|
workspaceId: this.workspaceId,
|
|
31700
31771
|
channelId
|
|
31701
31772
|
});
|
|
@@ -31703,7 +31774,7 @@ var init_channel_membership_store = __esm({
|
|
|
31703
31774
|
}
|
|
31704
31775
|
return result.rows[0].id;
|
|
31705
31776
|
} catch (err) {
|
|
31706
|
-
|
|
31777
|
+
log7.error("Failed to look up channel row in cloud DB", {
|
|
31707
31778
|
channelId,
|
|
31708
31779
|
error: err instanceof Error ? err.message : String(err)
|
|
31709
31780
|
});
|
|
@@ -37327,6 +37398,7 @@ function createInjectionMetrics() {
|
|
|
37327
37398
|
}
|
|
37328
37399
|
function detectCliType(command) {
|
|
37329
37400
|
const cmdLower = command.toLowerCase();
|
|
37401
|
+
const cmdName = cmdLower.split(/[\s/\\]/).pop() || cmdLower;
|
|
37330
37402
|
if (cmdLower.includes("gemini"))
|
|
37331
37403
|
return "gemini";
|
|
37332
37404
|
if (cmdLower.includes("codex"))
|
|
@@ -37339,6 +37411,8 @@ function detectCliType(command) {
|
|
|
37339
37411
|
return "opencode";
|
|
37340
37412
|
if (cmdLower.includes("cursor"))
|
|
37341
37413
|
return "cursor";
|
|
37414
|
+
if (cmdName === "agent" || cmdName === "cursor-agent")
|
|
37415
|
+
return "cursor";
|
|
37342
37416
|
return "other";
|
|
37343
37417
|
}
|
|
37344
37418
|
function getDefaultRelayPrefix() {
|
|
@@ -43359,9 +43433,9 @@ var AgentHealthMonitor = class extends import_events.EventEmitter {
|
|
|
43359
43433
|
* Get memory and CPU usage for a process
|
|
43360
43434
|
*/
|
|
43361
43435
|
async getProcessUsage(pid) {
|
|
43362
|
-
const { execSync:
|
|
43436
|
+
const { execSync: execSync10 } = await import("child_process");
|
|
43363
43437
|
try {
|
|
43364
|
-
const output =
|
|
43438
|
+
const output = execSync10(`ps -o rss=,pcpu= -p ${pid}`, { encoding: "utf8" }).trim();
|
|
43365
43439
|
const [rss, cpu] = output.split(/\s+/);
|
|
43366
43440
|
return {
|
|
43367
43441
|
memory: parseInt(rss, 10) * 1024,
|
|
@@ -55101,9 +55175,55 @@ async function selectShadowCli(primaryCli, options) {
|
|
|
55101
55175
|
throw new Error("No shadow-capable CLI authenticated. Install Claude or OpenCode (codex) and try again.");
|
|
55102
55176
|
}
|
|
55103
55177
|
|
|
55178
|
+
// packages/bridge/dist/cli-resolution.js
|
|
55179
|
+
var import_node_child_process8 = require("node:child_process");
|
|
55180
|
+
init_logger();
|
|
55181
|
+
var log2 = createLogger2("cli-resolution");
|
|
55182
|
+
function commandExists2(cmd) {
|
|
55183
|
+
try {
|
|
55184
|
+
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
55185
|
+
(0, import_node_child_process8.execSync)(`${whichCmd} ${cmd}`, { stdio: "ignore" });
|
|
55186
|
+
return true;
|
|
55187
|
+
} catch {
|
|
55188
|
+
return false;
|
|
55189
|
+
}
|
|
55190
|
+
}
|
|
55191
|
+
var detectedCursorCli = null;
|
|
55192
|
+
function detectCursorCli() {
|
|
55193
|
+
if (detectedCursorCli !== null) {
|
|
55194
|
+
return detectedCursorCli;
|
|
55195
|
+
}
|
|
55196
|
+
if (commandExists2("agent")) {
|
|
55197
|
+
detectedCursorCli = "agent";
|
|
55198
|
+
log2.debug("Detected Cursor CLI: agent (newer version)");
|
|
55199
|
+
return "agent";
|
|
55200
|
+
}
|
|
55201
|
+
if (commandExists2("cursor-agent")) {
|
|
55202
|
+
detectedCursorCli = "cursor-agent";
|
|
55203
|
+
log2.debug("Detected Cursor CLI: cursor-agent (older version)");
|
|
55204
|
+
return "cursor-agent";
|
|
55205
|
+
}
|
|
55206
|
+
log2.debug("Cursor CLI not found (neither agent nor cursor-agent)");
|
|
55207
|
+
return null;
|
|
55208
|
+
}
|
|
55209
|
+
function resolveCli(rawCommand) {
|
|
55210
|
+
const cmdLower = rawCommand.toLowerCase();
|
|
55211
|
+
if (cmdLower === "cursor" || cmdLower === "cursor-agent") {
|
|
55212
|
+
const cursorCli = detectCursorCli();
|
|
55213
|
+
if (cursorCli) {
|
|
55214
|
+
return cursorCli;
|
|
55215
|
+
}
|
|
55216
|
+
return "agent";
|
|
55217
|
+
}
|
|
55218
|
+
if (cmdLower === "google") {
|
|
55219
|
+
return "gemini";
|
|
55220
|
+
}
|
|
55221
|
+
return rawCommand;
|
|
55222
|
+
}
|
|
55223
|
+
|
|
55104
55224
|
// packages/bridge/dist/spawner.js
|
|
55105
55225
|
var import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
55106
|
-
var
|
|
55226
|
+
var import_node_child_process12 = require("node:child_process");
|
|
55107
55227
|
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
55108
55228
|
var import_node_url3 = require("node:url");
|
|
55109
55229
|
|
|
@@ -63226,8 +63346,8 @@ var relayStatusSchema = external_exports.object({});
|
|
|
63226
63346
|
|
|
63227
63347
|
// packages/mcp/dist/tools/relay-logs.js
|
|
63228
63348
|
var import_node_util4 = require("node:util");
|
|
63229
|
-
var
|
|
63230
|
-
var execAsync3 = (0, import_node_util4.promisify)(
|
|
63349
|
+
var import_node_child_process10 = require("node:child_process");
|
|
63350
|
+
var execAsync3 = (0, import_node_util4.promisify)(import_node_child_process10.exec);
|
|
63231
63351
|
var relayLogsSchema = external_exports.object({
|
|
63232
63352
|
agent: external_exports.string().describe("Name of the agent to get logs for"),
|
|
63233
63353
|
lines: external_exports.number().optional().default(50).describe("Number of lines to retrieve (default: 50)")
|
|
@@ -63322,7 +63442,7 @@ var relayVoteSchema = external_exports.object({
|
|
|
63322
63442
|
var import_node_fs13 = require("node:fs");
|
|
63323
63443
|
var import_node_path16 = require("node:path");
|
|
63324
63444
|
var import_node_os9 = require("node:os");
|
|
63325
|
-
var
|
|
63445
|
+
var import_node_child_process11 = require("node:child_process");
|
|
63326
63446
|
|
|
63327
63447
|
// node_modules/smol-toml/dist/error.js
|
|
63328
63448
|
function getLineColFromPtr(string3, ptr) {
|
|
@@ -64230,7 +64350,7 @@ function getConfigPaths() {
|
|
|
64230
64350
|
}
|
|
64231
64351
|
function isUsingNvm() {
|
|
64232
64352
|
try {
|
|
64233
|
-
const nodePath = (0,
|
|
64353
|
+
const nodePath = (0, import_node_child_process11.execSync)("which node", { encoding: "utf-8" }).trim();
|
|
64234
64354
|
return nodePath.includes(".nvm");
|
|
64235
64355
|
} catch {
|
|
64236
64356
|
return false;
|
|
@@ -64238,14 +64358,14 @@ function isUsingNvm() {
|
|
|
64238
64358
|
}
|
|
64239
64359
|
function getNodePath() {
|
|
64240
64360
|
try {
|
|
64241
|
-
return (0,
|
|
64361
|
+
return (0, import_node_child_process11.execSync)("which node", { encoding: "utf-8" }).trim();
|
|
64242
64362
|
} catch {
|
|
64243
64363
|
return null;
|
|
64244
64364
|
}
|
|
64245
64365
|
}
|
|
64246
64366
|
function getGlobalMcpBinPath() {
|
|
64247
64367
|
try {
|
|
64248
|
-
const npmPrefix = (0,
|
|
64368
|
+
const npmPrefix = (0, import_node_child_process11.execSync)("npm prefix -g", { encoding: "utf-8" }).trim();
|
|
64249
64369
|
const binPath = (0, import_node_path16.join)(npmPrefix, "lib", "node_modules", "@agent-relay", "mcp", "dist", "bin.js");
|
|
64250
64370
|
if ((0, import_node_fs13.existsSync)(binPath)) {
|
|
64251
64371
|
return binPath;
|
|
@@ -64473,14 +64593,7 @@ function installMcpConfig(configPath, options = {}) {
|
|
|
64473
64593
|
// packages/bridge/dist/spawner.js
|
|
64474
64594
|
var __filename3 = (0, import_node_url3.fileURLToPath)(import_meta_url);
|
|
64475
64595
|
var __dirname3 = import_node_path17.default.dirname(__filename3);
|
|
64476
|
-
var
|
|
64477
|
-
var CLI_COMMAND_MAP = {
|
|
64478
|
-
cursor: "agent",
|
|
64479
|
-
// Cursor CLI installs as 'agent'
|
|
64480
|
-
google: "gemini"
|
|
64481
|
-
// Google provider uses 'gemini' CLI
|
|
64482
|
-
// Other providers use their name as the command (claude, codex, etc.)
|
|
64483
|
-
};
|
|
64596
|
+
var log3 = createLogger2("spawner");
|
|
64484
64597
|
function extractGhTokenFromHosts(content) {
|
|
64485
64598
|
const lines = content.split(/\r?\n/);
|
|
64486
64599
|
let inGithubSection = false;
|
|
@@ -64543,7 +64656,7 @@ function ensureMcpPermissions(projectRoot, cliType, debug = false) {
|
|
|
64543
64656
|
const config2 = configMap[effectiveCli];
|
|
64544
64657
|
if (!config2) {
|
|
64545
64658
|
if (debug)
|
|
64546
|
-
|
|
64659
|
+
log3.debug(`CLI ${cliType} uses flag-based permissions, skipping config setup`);
|
|
64547
64660
|
return;
|
|
64548
64661
|
}
|
|
64549
64662
|
const settingsPath = import_node_path17.default.join(config2.settingsDir, config2.settingsFile);
|
|
@@ -64563,7 +64676,7 @@ function ensureMcpPermissions(projectRoot, cliType, debug = false) {
|
|
|
64563
64676
|
if (config2.enableAllKey && settings[config2.enableAllKey] !== true) {
|
|
64564
64677
|
settings[config2.enableAllKey] = true;
|
|
64565
64678
|
if (debug)
|
|
64566
|
-
|
|
64679
|
+
log3.debug(`Setting ${config2.enableAllKey}: true`);
|
|
64567
64680
|
}
|
|
64568
64681
|
if (config2.permissionKey) {
|
|
64569
64682
|
const keyParts = config2.permissionKey.split(".");
|
|
@@ -64584,14 +64697,14 @@ function ensureMcpPermissions(projectRoot, cliType, debug = false) {
|
|
|
64584
64697
|
if (!allowList.includes(agentRelayPermission)) {
|
|
64585
64698
|
allowList.push(agentRelayPermission);
|
|
64586
64699
|
if (debug)
|
|
64587
|
-
|
|
64700
|
+
log3.debug(`Added MCP permission: ${agentRelayPermission}`);
|
|
64588
64701
|
}
|
|
64589
64702
|
}
|
|
64590
64703
|
import_node_fs14.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
64591
64704
|
if (debug)
|
|
64592
|
-
|
|
64705
|
+
log3.debug(`MCP permissions configured at ${settingsPath}`);
|
|
64593
64706
|
} catch (err) {
|
|
64594
|
-
|
|
64707
|
+
log3.warn("Failed to pre-configure MCP permissions", {
|
|
64595
64708
|
cli: cliType,
|
|
64596
64709
|
error: err instanceof Error ? err.message : String(err)
|
|
64597
64710
|
});
|
|
@@ -64641,9 +64754,9 @@ function hasRelayPtyBinary2() {
|
|
|
64641
64754
|
relayPtyBinaryChecked = true;
|
|
64642
64755
|
if (process.env.DEBUG_SPAWN === "1") {
|
|
64643
64756
|
if (relayPtyBinaryPath) {
|
|
64644
|
-
|
|
64757
|
+
log3.debug(`relay-pty binary found: ${relayPtyBinaryPath}`);
|
|
64645
64758
|
} else {
|
|
64646
|
-
|
|
64759
|
+
log3.debug("relay-pty binary not found, will use PtyWrapper fallback");
|
|
64647
64760
|
}
|
|
64648
64761
|
}
|
|
64649
64762
|
}
|
|
@@ -64672,7 +64785,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64672
64785
|
const effectiveTeamDir = options.teamDir ?? paths.teamDir;
|
|
64673
64786
|
this.agentsPath = import_node_path17.default.join(effectiveTeamDir, "connected-agents.json");
|
|
64674
64787
|
this.registryPath = import_node_path17.default.join(effectiveTeamDir, "agents.json");
|
|
64675
|
-
|
|
64788
|
+
log3.info(`AgentSpawner paths: projectRoot=${this.projectRoot} teamDir=${effectiveTeamDir} (explicit=${!!options.teamDir}) agentsPath=${this.agentsPath}`);
|
|
64676
64789
|
this.socketPath = options.socketPath ?? paths.socketPath;
|
|
64677
64790
|
this.logsDir = import_node_path17.default.join(effectiveTeamDir, "worker-logs");
|
|
64678
64791
|
this.workersPath = import_node_path17.default.join(effectiveTeamDir, "workers.json");
|
|
@@ -64687,7 +64800,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64687
64800
|
workspaceId: process.env.WORKSPACE_ID,
|
|
64688
64801
|
strictMode: process.env.AGENT_POLICY_STRICT === "1"
|
|
64689
64802
|
});
|
|
64690
|
-
|
|
64803
|
+
log3.info("Policy enforcement enabled");
|
|
64691
64804
|
}
|
|
64692
64805
|
}
|
|
64693
64806
|
/**
|
|
@@ -64729,7 +64842,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64729
64842
|
});
|
|
64730
64843
|
clearTimeout(timeoutId);
|
|
64731
64844
|
if (!response.ok) {
|
|
64732
|
-
|
|
64845
|
+
log3.warn(`Failed to fetch GH token from cloud: ${response.status} ${response.statusText}`);
|
|
64733
64846
|
return null;
|
|
64734
64847
|
}
|
|
64735
64848
|
const data = await response.json();
|
|
@@ -64737,9 +64850,9 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64737
64850
|
} catch (err) {
|
|
64738
64851
|
const message = err instanceof Error ? err.message : String(err);
|
|
64739
64852
|
if (message.includes("abort")) {
|
|
64740
|
-
|
|
64853
|
+
log3.info("Cloud API timeout (5s) - using local auth");
|
|
64741
64854
|
} else {
|
|
64742
|
-
|
|
64855
|
+
log3.warn("Failed to fetch GH token from cloud", { error: message });
|
|
64743
64856
|
}
|
|
64744
64857
|
return null;
|
|
64745
64858
|
}
|
|
@@ -64786,7 +64899,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64786
64899
|
return null;
|
|
64787
64900
|
}
|
|
64788
64901
|
return await new Promise((resolve5) => {
|
|
64789
|
-
(0,
|
|
64902
|
+
(0, import_node_child_process12.execFile)(ghPath, ["auth", "token", "--hostname", "github.com"], { timeout: 5e3 }, (err, stdout) => {
|
|
64790
64903
|
if (err) {
|
|
64791
64904
|
resolve5(null);
|
|
64792
64905
|
return;
|
|
@@ -64830,7 +64943,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64830
64943
|
* Called after the dashboard server starts and we know the actual port.
|
|
64831
64944
|
*/
|
|
64832
64945
|
setDashboardPort(port) {
|
|
64833
|
-
|
|
64946
|
+
log3.info(`Dashboard port set to ${port} - nested spawns now enabled`);
|
|
64834
64947
|
this.dashboardPort = port;
|
|
64835
64948
|
}
|
|
64836
64949
|
/**
|
|
@@ -64849,7 +64962,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64849
64962
|
*/
|
|
64850
64963
|
setCloudPersistence(handler) {
|
|
64851
64964
|
this.cloudPersistence = handler;
|
|
64852
|
-
|
|
64965
|
+
log3.info("Cloud persistence handler set");
|
|
64853
64966
|
}
|
|
64854
64967
|
/**
|
|
64855
64968
|
* Bind cloud persistence event handlers to a RelayPtyOrchestrator.
|
|
@@ -64862,14 +64975,14 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64862
64975
|
try {
|
|
64863
64976
|
await this.cloudPersistence.onSummary(name, event);
|
|
64864
64977
|
} catch (err) {
|
|
64865
|
-
|
|
64978
|
+
log3.error(`Cloud persistence summary error for ${name}`, { error: err instanceof Error ? err.message : String(err) });
|
|
64866
64979
|
}
|
|
64867
64980
|
};
|
|
64868
64981
|
const sessionEndListener = async (event) => {
|
|
64869
64982
|
try {
|
|
64870
64983
|
await this.cloudPersistence.onSessionEnd(name, event);
|
|
64871
64984
|
} catch (err) {
|
|
64872
|
-
|
|
64985
|
+
log3.error(`Cloud persistence session-end error for ${name}`, { error: err instanceof Error ? err.message : String(err) });
|
|
64873
64986
|
}
|
|
64874
64987
|
};
|
|
64875
64988
|
pty.on("summary", summaryListener);
|
|
@@ -64922,7 +65035,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64922
65035
|
const maxAgents = parseInt(process.env.MAX_AGENTS ?? "", 10) || 1e4;
|
|
64923
65036
|
const currentAgentCount = this.activeWorkers.size;
|
|
64924
65037
|
if (currentAgentCount >= maxAgents) {
|
|
64925
|
-
|
|
65038
|
+
log3.warn(`Agent limit reached: ${currentAgentCount}/${maxAgents}`);
|
|
64926
65039
|
return {
|
|
64927
65040
|
success: false,
|
|
64928
65041
|
name,
|
|
@@ -64932,7 +65045,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64932
65045
|
if (this.policyEnforcementEnabled && this.policyService && spawnerName) {
|
|
64933
65046
|
const decision = await this.policyService.canSpawn(spawnerName, name, cli);
|
|
64934
65047
|
if (!decision.allowed) {
|
|
64935
|
-
|
|
65048
|
+
log3.warn(`Policy blocked spawn: ${spawnerName} -> ${name}: ${decision.reason}`);
|
|
64936
65049
|
return {
|
|
64937
65050
|
success: false,
|
|
64938
65051
|
name,
|
|
@@ -64941,26 +65054,26 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64941
65054
|
};
|
|
64942
65055
|
}
|
|
64943
65056
|
if (debug) {
|
|
64944
|
-
|
|
65057
|
+
log3.debug(`Policy allowed spawn: ${spawnerName} -> ${name} (source: ${decision.policySource})`);
|
|
64945
65058
|
}
|
|
64946
65059
|
}
|
|
64947
65060
|
try {
|
|
64948
65061
|
const cliParts = cli.split(" ");
|
|
64949
65062
|
const rawCommandName = cliParts[0];
|
|
64950
|
-
const commandName =
|
|
65063
|
+
const commandName = resolveCli(rawCommandName);
|
|
64951
65064
|
const args = cliParts.slice(1);
|
|
64952
65065
|
if (commandName !== rawCommandName && debug) {
|
|
64953
|
-
|
|
65066
|
+
log3.debug(`Mapped CLI '${rawCommandName}' -> '${commandName}'`);
|
|
64954
65067
|
}
|
|
64955
65068
|
const command = resolveCommand(commandName);
|
|
64956
65069
|
if (debug)
|
|
64957
|
-
|
|
65070
|
+
log3.debug(`Resolved '${commandName}' -> '${command}'`);
|
|
64958
65071
|
if (command === commandName && !commandName.startsWith("/")) {
|
|
64959
|
-
|
|
65072
|
+
log3.warn(`Could not resolve path for '${commandName}', spawn may fail`);
|
|
64960
65073
|
}
|
|
64961
65074
|
ensureMcpPermissions(this.projectRoot, commandName, debug);
|
|
64962
65075
|
const isClaudeCli = commandName.startsWith("claude");
|
|
64963
|
-
const isCursorCli = commandName === "agent" || rawCommandName === "cursor";
|
|
65076
|
+
const isCursorCli = commandName === "agent" || rawCommandName === "cursor" || rawCommandName === "cursor-agent";
|
|
64964
65077
|
if (!interactive) {
|
|
64965
65078
|
if (isClaudeCli && !args.includes("--dangerously-skip-permissions")) {
|
|
64966
65079
|
args.push("--dangerously-skip-permissions");
|
|
@@ -64970,7 +65083,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64970
65083
|
}
|
|
64971
65084
|
} else {
|
|
64972
65085
|
if (debug)
|
|
64973
|
-
|
|
65086
|
+
log3.debug(`Interactive mode: skipping auto-accept flags for ${name}`);
|
|
64974
65087
|
}
|
|
64975
65088
|
if (isClaudeCli) {
|
|
64976
65089
|
const agentConfig = findAgentConfig(name, this.projectRoot);
|
|
@@ -64980,9 +65093,9 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
64980
65093
|
const configuredArgs = buildClaudeArgs(name, args, this.projectRoot);
|
|
64981
65094
|
args.length = 0;
|
|
64982
65095
|
args.push(...configuredArgs);
|
|
64983
|
-
|
|
65096
|
+
log3.info(`Agent ${name}: model=${effectiveModel}, cli=${cli}, variant=${cliVariant}`);
|
|
64984
65097
|
if (debug)
|
|
64985
|
-
|
|
65098
|
+
log3.debug(`Applied agent config for ${name}: ${args.join(" ")}`);
|
|
64986
65099
|
}
|
|
64987
65100
|
const isCodexCli = commandName.startsWith("codex");
|
|
64988
65101
|
const isGeminiCli = commandName === "gemini";
|
|
@@ -65008,12 +65121,12 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
65008
65121
|
});
|
|
65009
65122
|
if (result.success) {
|
|
65010
65123
|
if (debug)
|
|
65011
|
-
|
|
65124
|
+
log3.debug(`Auto-installed MCP config at ${projectMcpConfigPath}`);
|
|
65012
65125
|
} else {
|
|
65013
|
-
|
|
65126
|
+
log3.warn(`Failed to auto-install MCP config: ${result.error}`);
|
|
65014
65127
|
}
|
|
65015
65128
|
} catch (err) {
|
|
65016
|
-
|
|
65129
|
+
log3.warn("Failed to auto-install MCP config", {
|
|
65017
65130
|
error: err instanceof Error ? err.message : String(err)
|
|
65018
65131
|
});
|
|
65019
65132
|
}
|
|
@@ -65028,7 +65141,7 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
65028
65141
|
}
|
|
65029
65142
|
}
|
|
65030
65143
|
if (debug && hasMcp)
|
|
65031
|
-
|
|
65144
|
+
log3.debug(`MCP tools available for ${name} (MCP config found, socket ${relaySocket})`);
|
|
65032
65145
|
let relayInstructions = getRelayInstructions(name, { hasMcp, includeWorkflowConventions });
|
|
65033
65146
|
const agentConfigForRole = isClaudeCli ? findAgentConfig(name, this.projectRoot) : null;
|
|
65034
65147
|
if (agentConfigForRole?.role) {
|
|
@@ -65044,10 +65157,10 @@ var AgentSpawner = class _AgentSpawner {
|
|
|
65044
65157
|
|
|
65045
65158
|
${relayInstructions}`;
|
|
65046
65159
|
if (debug)
|
|
65047
|
-
|
|
65160
|
+
log3.debug(`Composed role prompt for ${name} (role: ${role})`);
|
|
65048
65161
|
}
|
|
65049
65162
|
} catch (err) {
|
|
65050
|
-
|
|
65163
|
+
log3.warn(`Failed to compose role prompt for ${name}: ${err.message}`);
|
|
65051
65164
|
}
|
|
65052
65165
|
}
|
|
65053
65166
|
}
|
|
@@ -65064,7 +65177,7 @@ ${relayInstructions}`;
|
|
|
65064
65177
|
args.unshift("login");
|
|
65065
65178
|
}
|
|
65066
65179
|
if (debug)
|
|
65067
|
-
|
|
65180
|
+
log3.debug(`Spawning ${name} with: ${command} ${args.join(" ")}`);
|
|
65068
65181
|
let agentCwd;
|
|
65069
65182
|
if (request.cwd && typeof request.cwd === "string") {
|
|
65070
65183
|
const resolvedCwd = import_node_path17.default.resolve(this.projectRoot, request.cwd);
|
|
@@ -65081,14 +65194,14 @@ ${relayInstructions}`;
|
|
|
65081
65194
|
} else {
|
|
65082
65195
|
agentCwd = this.projectRoot;
|
|
65083
65196
|
}
|
|
65084
|
-
|
|
65197
|
+
log3.info(`Spawning ${name}: dashboardPort=${this.dashboardPort || "none"} (${this.dashboardPort ? "nested spawns enabled" : "nested spawns disabled"})`);
|
|
65085
65198
|
let userEnv;
|
|
65086
65199
|
if (userId) {
|
|
65087
65200
|
try {
|
|
65088
65201
|
const userDirService = getUserDirectoryService();
|
|
65089
65202
|
userEnv = userDirService.getUserEnvironment(userId);
|
|
65090
65203
|
} catch (err) {
|
|
65091
|
-
|
|
65204
|
+
log3.warn("Failed to resolve user environment, using default", {
|
|
65092
65205
|
userId,
|
|
65093
65206
|
error: err instanceof Error ? err.message : String(err)
|
|
65094
65207
|
});
|
|
@@ -65105,7 +65218,7 @@ ${relayInstructions}`;
|
|
|
65105
65218
|
userEnv = mergedUserEnv;
|
|
65106
65219
|
}
|
|
65107
65220
|
if (debug)
|
|
65108
|
-
|
|
65221
|
+
log3.debug(`Socket path for ${name}: ${this.socketPath ?? "undefined"}`);
|
|
65109
65222
|
if (!hasRelayPtyBinary2()) {
|
|
65110
65223
|
const checkedPaths = getLastSearchPaths();
|
|
65111
65224
|
const tracedError = createTraceableError("relay-pty binary not found", {
|
|
@@ -65117,10 +65230,10 @@ ${relayInstructions}`;
|
|
|
65117
65230
|
totalPathsChecked: checkedPaths.length,
|
|
65118
65231
|
hint: "Set RELAY_PTY_BINARY env var to override, or reinstall: npm install agent-relay"
|
|
65119
65232
|
});
|
|
65120
|
-
|
|
65233
|
+
log3.error(tracedError.logMessage);
|
|
65121
65234
|
if (debug) {
|
|
65122
|
-
|
|
65123
|
-
checkedPaths.forEach((p, i) =>
|
|
65235
|
+
log3.debug("All paths checked for relay-pty binary:");
|
|
65236
|
+
checkedPaths.forEach((p, i) => log3.debug(` ${i + 1}. ${p}`));
|
|
65124
65237
|
}
|
|
65125
65238
|
return {
|
|
65126
65239
|
success: false,
|
|
@@ -65131,7 +65244,7 @@ ${relayInstructions}`;
|
|
|
65131
65244
|
}
|
|
65132
65245
|
const onExitHandler = (code) => {
|
|
65133
65246
|
if (debug)
|
|
65134
|
-
|
|
65247
|
+
log3.debug(`Worker ${name} exited with code ${code}`);
|
|
65135
65248
|
const worker = this.activeWorkers.get(name);
|
|
65136
65249
|
const agentId = worker?.pty?.getAgentId?.();
|
|
65137
65250
|
if (worker?.listeners) {
|
|
@@ -65141,7 +65254,7 @@ ${relayInstructions}`;
|
|
|
65141
65254
|
try {
|
|
65142
65255
|
this.saveWorkersMetadata();
|
|
65143
65256
|
} catch (err) {
|
|
65144
|
-
|
|
65257
|
+
log3.error("Failed to save metadata on exit", { error: err instanceof Error ? err.message : String(err) });
|
|
65145
65258
|
}
|
|
65146
65259
|
if (code !== 0 && code !== null && this.onAgentDeath) {
|
|
65147
65260
|
const crashError = createTraceableError("Agent crashed unexpectedly", {
|
|
@@ -65150,7 +65263,7 @@ ${relayInstructions}`;
|
|
|
65150
65263
|
cli,
|
|
65151
65264
|
agentId
|
|
65152
65265
|
});
|
|
65153
|
-
|
|
65266
|
+
log3.error(crashError.logMessage);
|
|
65154
65267
|
this.onAgentDeath({
|
|
65155
65268
|
name,
|
|
65156
65269
|
exitCode: code,
|
|
@@ -65162,7 +65275,7 @@ ${relayInstructions}`;
|
|
|
65162
65275
|
};
|
|
65163
65276
|
const onSpawnHandler = this.dashboardPort ? void 0 : async (workerName, workerCli, workerTask) => {
|
|
65164
65277
|
if (debug)
|
|
65165
|
-
|
|
65278
|
+
log3.debug(`Nested spawn: ${workerName}`);
|
|
65166
65279
|
await this.spawn({
|
|
65167
65280
|
name: workerName,
|
|
65168
65281
|
cli: workerCli,
|
|
@@ -65172,7 +65285,7 @@ ${relayInstructions}`;
|
|
|
65172
65285
|
};
|
|
65173
65286
|
const onReleaseHandler = this.dashboardPort ? void 0 : async (workerName) => {
|
|
65174
65287
|
if (debug)
|
|
65175
|
-
|
|
65288
|
+
log3.debug(`Release request: ${workerName}`);
|
|
65176
65289
|
await this.release(workerName);
|
|
65177
65290
|
};
|
|
65178
65291
|
if (isOpenCodeCli) {
|
|
@@ -65182,7 +65295,7 @@ ${relayInstructions}`;
|
|
|
65182
65295
|
const shouldUseHttpApi = serveAvailable || isCloudWorkspace2;
|
|
65183
65296
|
if (shouldUseHttpApi) {
|
|
65184
65297
|
if (debug)
|
|
65185
|
-
|
|
65298
|
+
log3.debug(`OpenCode: serve=${serveAvailable ? "available" : "will-auto-start"}, cloud=${isCloudWorkspace2}, using OpenCodeWrapper for ${name}`);
|
|
65186
65299
|
const openCodeConfig = {
|
|
65187
65300
|
name,
|
|
65188
65301
|
command,
|
|
@@ -65224,11 +65337,11 @@ ${relayInstructions}`;
|
|
|
65224
65337
|
if (this.onMarkSpawning) {
|
|
65225
65338
|
this.onMarkSpawning(name);
|
|
65226
65339
|
if (debug)
|
|
65227
|
-
|
|
65340
|
+
log3.debug(`Marked ${name} as spawning`);
|
|
65228
65341
|
}
|
|
65229
65342
|
await openCodeWrapper.start();
|
|
65230
65343
|
if (debug)
|
|
65231
|
-
|
|
65344
|
+
log3.debug(`OpenCodeWrapper started for ${name}, HTTP mode: ${openCodeWrapper.isHttpApiMode}`);
|
|
65232
65345
|
const registered2 = await this.waitForAgentRegistration(name, 3e4, 500);
|
|
65233
65346
|
if (!registered2) {
|
|
65234
65347
|
const tracedError = createTraceableError("Agent registration timeout", {
|
|
@@ -65237,7 +65350,7 @@ ${relayInstructions}`;
|
|
|
65237
65350
|
pid: openCodeWrapper.pid,
|
|
65238
65351
|
timeoutMs: 3e4
|
|
65239
65352
|
});
|
|
65240
|
-
|
|
65353
|
+
log3.error(tracedError.logMessage);
|
|
65241
65354
|
if (this.onClearSpawning) {
|
|
65242
65355
|
this.onClearSpawning(name);
|
|
65243
65356
|
}
|
|
@@ -65254,12 +65367,12 @@ ${relayInstructions}`;
|
|
|
65254
65367
|
if (ready) {
|
|
65255
65368
|
const taskSent = await openCodeWrapper.injectTask(task, spawnerName || "spawner");
|
|
65256
65369
|
if (!taskSent) {
|
|
65257
|
-
|
|
65370
|
+
log3.warn(`Failed to inject task for ${name} via OpenCodeWrapper`);
|
|
65258
65371
|
} else if (debug) {
|
|
65259
|
-
|
|
65372
|
+
log3.debug(`Task injected to ${name} via OpenCodeWrapper`);
|
|
65260
65373
|
}
|
|
65261
65374
|
} else {
|
|
65262
|
-
|
|
65375
|
+
log3.warn(`OpenCodeWrapper ${name} not ready for task injection`);
|
|
65263
65376
|
}
|
|
65264
65377
|
}
|
|
65265
65378
|
const workerInfo2 = {
|
|
@@ -65278,7 +65391,7 @@ ${relayInstructions}`;
|
|
|
65278
65391
|
this.saveWorkersMetadata();
|
|
65279
65392
|
const teamInfo2 = team ? ` [team: ${team}]` : "";
|
|
65280
65393
|
const shadowInfo2 = request.shadowOf ? ` [shadow of: ${request.shadowOf}]` : "";
|
|
65281
|
-
|
|
65394
|
+
log3.info(`Spawned ${name} (${cli}) via OpenCodeWrapper${teamInfo2}${shadowInfo2} [HTTP mode: ${openCodeWrapper.isHttpApiMode}]`);
|
|
65282
65395
|
return {
|
|
65283
65396
|
success: true,
|
|
65284
65397
|
name,
|
|
@@ -65286,7 +65399,7 @@ ${relayInstructions}`;
|
|
|
65286
65399
|
};
|
|
65287
65400
|
}
|
|
65288
65401
|
if (debug)
|
|
65289
|
-
|
|
65402
|
+
log3.debug(`OpenCode: serve not available, not cloud workspace, falling back to RelayPtyOrchestrator for ${name}`);
|
|
65290
65403
|
}
|
|
65291
65404
|
const ptyConfig = {
|
|
65292
65405
|
name,
|
|
@@ -65320,7 +65433,7 @@ ${relayInstructions}`;
|
|
|
65320
65433
|
};
|
|
65321
65434
|
const pty = new RelayPtyOrchestrator(ptyConfig);
|
|
65322
65435
|
if (debug)
|
|
65323
|
-
|
|
65436
|
+
log3.debug(`Using RelayPtyOrchestrator for ${name}`);
|
|
65324
65437
|
const listeners = {};
|
|
65325
65438
|
const outputListener = (data) => {
|
|
65326
65439
|
const broadcast = global.__broadcastLogOutput;
|
|
@@ -65338,19 +65451,19 @@ ${relayInstructions}`;
|
|
|
65338
65451
|
if (this.onMarkSpawning) {
|
|
65339
65452
|
this.onMarkSpawning(name);
|
|
65340
65453
|
if (debug)
|
|
65341
|
-
|
|
65454
|
+
log3.debug(`Marked ${name} as spawning`);
|
|
65342
65455
|
}
|
|
65343
65456
|
await pty.start();
|
|
65344
65457
|
if (debug)
|
|
65345
|
-
|
|
65458
|
+
log3.debug(`PTY started, pid: ${pty.pid}`);
|
|
65346
65459
|
if (isCursorCli && interactive) {
|
|
65347
65460
|
await sleep2(1500);
|
|
65348
65461
|
if (debug)
|
|
65349
|
-
|
|
65462
|
+
log3.debug(`Sending initial keystroke for Cursor setup to bypass "Press any key" prompt`);
|
|
65350
65463
|
try {
|
|
65351
65464
|
await pty.write("\r");
|
|
65352
65465
|
} catch (err) {
|
|
65353
|
-
|
|
65466
|
+
log3.warn(`Failed to send initial keystroke for Cursor: ${err}`);
|
|
65354
65467
|
}
|
|
65355
65468
|
}
|
|
65356
65469
|
const registered = await this.waitForAgentRegistration(name, 3e4, 500);
|
|
@@ -65361,7 +65474,7 @@ ${relayInstructions}`;
|
|
|
65361
65474
|
pid: pty.pid,
|
|
65362
65475
|
timeoutMs: 3e4
|
|
65363
65476
|
});
|
|
65364
|
-
|
|
65477
|
+
log3.error(tracedError.logMessage);
|
|
65365
65478
|
if (this.onClearSpawning) {
|
|
65366
65479
|
this.onClearSpawning(name);
|
|
65367
65480
|
}
|
|
@@ -65383,12 +65496,12 @@ ${relayInstructions}`;
|
|
|
65383
65496
|
const orchestrator = pty;
|
|
65384
65497
|
const ready = await orchestrator.waitUntilReadyForMessages(2e4, 100);
|
|
65385
65498
|
if (!ready) {
|
|
65386
|
-
|
|
65499
|
+
log3.debug(`Attempt ${attempt}/${maxRetries}: ${name} not ready for messages within timeout`);
|
|
65387
65500
|
if (attempt < maxRetries) {
|
|
65388
65501
|
await sleep2(retryDelayMs);
|
|
65389
65502
|
continue;
|
|
65390
65503
|
}
|
|
65391
|
-
|
|
65504
|
+
log3.error(`${name} failed to become ready after ${maxRetries} attempts - task may be lost`);
|
|
65392
65505
|
break;
|
|
65393
65506
|
}
|
|
65394
65507
|
} else if ("waitUntilCliReady" in pty) {
|
|
@@ -65398,13 +65511,13 @@ ${relayInstructions}`;
|
|
|
65398
65511
|
if (success) {
|
|
65399
65512
|
taskSent = true;
|
|
65400
65513
|
if (debug)
|
|
65401
|
-
|
|
65514
|
+
log3.debug(`Task injected to ${name} (attempt ${attempt})`);
|
|
65402
65515
|
break;
|
|
65403
65516
|
} else {
|
|
65404
65517
|
throw new Error("Task injection returned false");
|
|
65405
65518
|
}
|
|
65406
65519
|
} catch (err) {
|
|
65407
|
-
|
|
65520
|
+
log3.debug(`Attempt ${attempt}/${maxRetries}: Error injecting task for ${name}: ${err.message}`);
|
|
65408
65521
|
if (attempt < maxRetries) {
|
|
65409
65522
|
await sleep2(retryDelayMs);
|
|
65410
65523
|
}
|
|
@@ -65417,7 +65530,7 @@ ${relayInstructions}`;
|
|
|
65417
65530
|
attempts: maxRetries,
|
|
65418
65531
|
taskLength: task.length
|
|
65419
65532
|
});
|
|
65420
|
-
|
|
65533
|
+
log3.error(`CRITICAL: ${tracedError.logMessage}`);
|
|
65421
65534
|
}
|
|
65422
65535
|
}
|
|
65423
65536
|
const workerInfo = {
|
|
@@ -65437,7 +65550,7 @@ ${relayInstructions}`;
|
|
|
65437
65550
|
this.saveWorkersMetadata();
|
|
65438
65551
|
const teamInfo = team ? ` [team: ${team}]` : "";
|
|
65439
65552
|
const shadowInfo = request.shadowOf ? ` [shadow of: ${request.shadowOf}]` : "";
|
|
65440
|
-
|
|
65553
|
+
log3.info(`Spawned ${name} (${cli})${teamInfo}${shadowInfo} [pid: ${pty.pid}]`);
|
|
65441
65554
|
return {
|
|
65442
65555
|
success: true,
|
|
65443
65556
|
name,
|
|
@@ -65449,9 +65562,9 @@ ${relayInstructions}`;
|
|
|
65449
65562
|
cli,
|
|
65450
65563
|
task: task?.substring(0, 100)
|
|
65451
65564
|
}, err instanceof Error ? err : void 0);
|
|
65452
|
-
|
|
65565
|
+
log3.error(tracedError.logMessage);
|
|
65453
65566
|
if (debug)
|
|
65454
|
-
|
|
65567
|
+
log3.debug("Full error", { error: err?.stack || String(err) });
|
|
65455
65568
|
if (this.onClearSpawning) {
|
|
65456
65569
|
this.onClearSpawning(name);
|
|
65457
65570
|
}
|
|
@@ -65498,12 +65611,12 @@ ${relayInstructions}`;
|
|
|
65498
65611
|
preferredShadowCli: shadow.command
|
|
65499
65612
|
});
|
|
65500
65613
|
} catch (err) {
|
|
65501
|
-
|
|
65614
|
+
log3.warn(`Shadow CLI selection failed for ${shadow.name}: ${err.message}`);
|
|
65502
65615
|
}
|
|
65503
65616
|
if (debug) {
|
|
65504
65617
|
const mode = shadowSelection?.mode ?? "unknown";
|
|
65505
65618
|
const cli = shadowSelection?.command ?? shadow.command ?? primary.command ?? "claude";
|
|
65506
|
-
|
|
65619
|
+
log3.debug(`spawnWithShadow: primary=${primary.name}, shadow=${shadow.name}, mode=${mode}, cli=${cli}, speakOn=${speakOn.join(",")}`);
|
|
65507
65620
|
}
|
|
65508
65621
|
const primaryResult = await this.spawn({
|
|
65509
65622
|
name: primary.name,
|
|
@@ -65520,7 +65633,7 @@ ${relayInstructions}`;
|
|
|
65520
65633
|
}
|
|
65521
65634
|
await sleep2(1e3);
|
|
65522
65635
|
if (shadowSelection?.mode === "subagent") {
|
|
65523
|
-
|
|
65636
|
+
log3.info(`Shadow ${shadow.name} will run as ${shadowSelection.cli} subagent inside ${primary.name} (no separate process)`);
|
|
65524
65637
|
return {
|
|
65525
65638
|
success: true,
|
|
65526
65639
|
primary: primaryResult,
|
|
@@ -65531,7 +65644,7 @@ ${relayInstructions}`;
|
|
|
65531
65644
|
};
|
|
65532
65645
|
}
|
|
65533
65646
|
if (!shadowSelection) {
|
|
65534
|
-
|
|
65647
|
+
log3.warn(`No authenticated shadow CLI available; ${primary.name} will run without a shadow`);
|
|
65535
65648
|
return {
|
|
65536
65649
|
success: true,
|
|
65537
65650
|
primary: primaryResult,
|
|
@@ -65547,7 +65660,7 @@ ${relayInstructions}`;
|
|
|
65547
65660
|
shadowSpeakOn: speakOn
|
|
65548
65661
|
});
|
|
65549
65662
|
if (!shadowResult.success) {
|
|
65550
|
-
|
|
65663
|
+
log3.warn(`Shadow agent ${shadow.name} failed to spawn, primary ${primary.name} continues without shadow`);
|
|
65551
65664
|
return {
|
|
65552
65665
|
success: true,
|
|
65553
65666
|
// Primary succeeded, overall operation is partial success
|
|
@@ -65556,7 +65669,7 @@ ${relayInstructions}`;
|
|
|
65556
65669
|
error: `Shadow spawn failed: ${shadowResult.error}`
|
|
65557
65670
|
};
|
|
65558
65671
|
}
|
|
65559
|
-
|
|
65672
|
+
log3.info(`Spawned pair: ${primary.name} with shadow ${shadow.name} (speakOn: ${speakOn.join(",")})`);
|
|
65560
65673
|
return {
|
|
65561
65674
|
success: true,
|
|
65562
65675
|
primary: primaryResult,
|
|
@@ -65569,7 +65682,7 @@ ${relayInstructions}`;
|
|
|
65569
65682
|
async release(name) {
|
|
65570
65683
|
const worker = this.activeWorkers.get(name);
|
|
65571
65684
|
if (!worker) {
|
|
65572
|
-
|
|
65685
|
+
log3.debug(`Worker ${name} not found`);
|
|
65573
65686
|
return false;
|
|
65574
65687
|
}
|
|
65575
65688
|
try {
|
|
@@ -65580,10 +65693,10 @@ ${relayInstructions}`;
|
|
|
65580
65693
|
}
|
|
65581
65694
|
this.activeWorkers.delete(name);
|
|
65582
65695
|
this.saveWorkersMetadata();
|
|
65583
|
-
|
|
65696
|
+
log3.info(`Released ${name}`);
|
|
65584
65697
|
return true;
|
|
65585
65698
|
} catch (err) {
|
|
65586
|
-
|
|
65699
|
+
log3.error(`Failed to release ${name}: ${err.message}`);
|
|
65587
65700
|
this.unbindListeners(worker.pty, worker.listeners);
|
|
65588
65701
|
this.activeWorkers.delete(name);
|
|
65589
65702
|
this.saveWorkersMetadata();
|
|
@@ -65676,15 +65789,15 @@ ${relayInstructions}`;
|
|
|
65676
65789
|
const connected = this.isAgentConnected(name);
|
|
65677
65790
|
const recentlySeen = this.isAgentRecentlySeen(name);
|
|
65678
65791
|
if (pollCount <= 3 || pollCount % 10 === 0) {
|
|
65679
|
-
|
|
65792
|
+
log3.info(`Registration poll #${pollCount} for ${name}: connected=${connected} recentlySeen=${recentlySeen} agentsPath=${this.agentsPath}`);
|
|
65680
65793
|
}
|
|
65681
65794
|
if (connected && recentlySeen) {
|
|
65682
|
-
|
|
65795
|
+
log3.info(`Agent ${name} registered after ${pollCount} polls`);
|
|
65683
65796
|
return true;
|
|
65684
65797
|
}
|
|
65685
65798
|
await sleep2(pollIntervalMs);
|
|
65686
65799
|
}
|
|
65687
|
-
|
|
65800
|
+
log3.info(`Registration timeout for ${name} after ${pollCount} polls`);
|
|
65688
65801
|
return false;
|
|
65689
65802
|
}
|
|
65690
65803
|
isAgentRegistered(name) {
|
|
@@ -65694,12 +65807,12 @@ ${relayInstructions}`;
|
|
|
65694
65807
|
const debug = process.env.DEBUG_SPAWN === "1";
|
|
65695
65808
|
if (!this.agentsPath) {
|
|
65696
65809
|
if (debug)
|
|
65697
|
-
|
|
65810
|
+
log3.debug(`isAgentConnected(${name}): no agentsPath`);
|
|
65698
65811
|
return false;
|
|
65699
65812
|
}
|
|
65700
65813
|
if (!import_node_fs14.default.existsSync(this.agentsPath)) {
|
|
65701
65814
|
if (debug)
|
|
65702
|
-
|
|
65815
|
+
log3.debug(`isAgentConnected(${name}): file not found: ${this.agentsPath}`);
|
|
65703
65816
|
return false;
|
|
65704
65817
|
}
|
|
65705
65818
|
try {
|
|
@@ -65708,14 +65821,14 @@ ${relayInstructions}`;
|
|
|
65708
65821
|
const updatedAt = typeof raw?.updatedAt === "number" ? raw.updatedAt : 0;
|
|
65709
65822
|
const isFresh = Date.now() - updatedAt <= _AgentSpawner.ONLINE_THRESHOLD_MS;
|
|
65710
65823
|
if (debug) {
|
|
65711
|
-
|
|
65824
|
+
log3.debug(`isAgentConnected(${name}): path=${this.agentsPath} agents=${agents.join(",")} updatedAt=${updatedAt} isFresh=${isFresh}`);
|
|
65712
65825
|
}
|
|
65713
65826
|
if (!isFresh)
|
|
65714
65827
|
return false;
|
|
65715
65828
|
const lowerName = name.toLowerCase();
|
|
65716
65829
|
return agents.some((a) => typeof a === "string" && a.toLowerCase() === lowerName);
|
|
65717
65830
|
} catch (err) {
|
|
65718
|
-
|
|
65831
|
+
log3.error("Failed to read connected-agents.json", { error: err.message, path: this.agentsPath });
|
|
65719
65832
|
return false;
|
|
65720
65833
|
}
|
|
65721
65834
|
}
|
|
@@ -65733,7 +65846,7 @@ ${relayInstructions}`;
|
|
|
65733
65846
|
return false;
|
|
65734
65847
|
return Date.now() - new Date(agent.lastSeen).getTime() <= _AgentSpawner.ONLINE_THRESHOLD_MS;
|
|
65735
65848
|
} catch (err) {
|
|
65736
|
-
|
|
65849
|
+
log3.error("Failed to read agents.json", { error: err.message });
|
|
65737
65850
|
return false;
|
|
65738
65851
|
}
|
|
65739
65852
|
}
|
|
@@ -65754,7 +65867,7 @@ ${relayInstructions}`;
|
|
|
65754
65867
|
}));
|
|
65755
65868
|
import_node_fs14.default.writeFileSync(this.workersPath, JSON.stringify({ workers }, null, 2));
|
|
65756
65869
|
} catch (err) {
|
|
65757
|
-
|
|
65870
|
+
log3.error("Failed to save workers metadata", { error: err.message });
|
|
65758
65871
|
}
|
|
65759
65872
|
}
|
|
65760
65873
|
/**
|
|
@@ -70082,7 +70195,8 @@ async function createStorageAdapter(dbPath, config2) {
|
|
|
70082
70195
|
const finalConfig = {
|
|
70083
70196
|
type: config2?.type ?? envConfig.type ?? "jsonl",
|
|
70084
70197
|
path: config2?.path ?? envConfig.path ?? dbPath,
|
|
70085
|
-
url: config2?.url ?? envConfig.url
|
|
70198
|
+
url: config2?.url ?? envConfig.url,
|
|
70199
|
+
watchForChanges: config2?.watchForChanges
|
|
70086
70200
|
};
|
|
70087
70201
|
const storageType = finalConfig.type?.toLowerCase();
|
|
70088
70202
|
switch (storageType) {
|
|
@@ -70120,7 +70234,8 @@ async function createStorageAdapter(dbPath, config2) {
|
|
|
70120
70234
|
console.warn("[storage] \u26A0\uFE0F Falling back to JSONL storage (append-only files)");
|
|
70121
70235
|
const adapter2 = new JsonlStorageAdapter2({
|
|
70122
70236
|
baseDir,
|
|
70123
|
-
reason: "upgrade to Node.js 22+ or run: npm rebuild better-sqlite3"
|
|
70237
|
+
reason: "upgrade to Node.js 22+ or run: npm rebuild better-sqlite3",
|
|
70238
|
+
watchForChanges: finalConfig.watchForChanges
|
|
70124
70239
|
});
|
|
70125
70240
|
await adapter2.init();
|
|
70126
70241
|
return adapter2;
|
|
@@ -70141,7 +70256,10 @@ async function createStorageAdapter(dbPath, config2) {
|
|
|
70141
70256
|
const { JsonlStorageAdapter: JsonlStorageAdapter2 } = await Promise.resolve().then(() => (init_jsonl_adapter(), jsonl_adapter_exports));
|
|
70142
70257
|
const baseDir = import_node_path23.default.dirname(finalConfig.path);
|
|
70143
70258
|
console.error("[storage] Using JSONL storage");
|
|
70144
|
-
const adapter = new JsonlStorageAdapter2({
|
|
70259
|
+
const adapter = new JsonlStorageAdapter2({
|
|
70260
|
+
baseDir,
|
|
70261
|
+
watchForChanges: finalConfig.watchForChanges
|
|
70262
|
+
});
|
|
70145
70263
|
await adapter.init();
|
|
70146
70264
|
return adapter;
|
|
70147
70265
|
}
|
|
@@ -70161,7 +70279,8 @@ async function createStorageAdapter(dbPath, config2) {
|
|
|
70161
70279
|
console.warn("[storage] \u26A0\uFE0F Falling back to JSONL storage (append-only files)");
|
|
70162
70280
|
const adapter2 = new JsonlStorageAdapter2({
|
|
70163
70281
|
baseDir,
|
|
70164
|
-
reason: "upgrade to Node.js 22+ or run: npm rebuild better-sqlite3"
|
|
70282
|
+
reason: "upgrade to Node.js 22+ or run: npm rebuild better-sqlite3",
|
|
70283
|
+
watchForChanges: finalConfig.watchForChanges
|
|
70165
70284
|
});
|
|
70166
70285
|
await adapter2.init();
|
|
70167
70286
|
return adapter2;
|
|
@@ -70185,7 +70304,7 @@ async function createStorageAdapter(dbPath, config2) {
|
|
|
70185
70304
|
var import_node_fs21 = __toESM(require("node:fs"), 1);
|
|
70186
70305
|
var import_node_path24 = __toESM(require("node:path"), 1);
|
|
70187
70306
|
init_logger();
|
|
70188
|
-
var
|
|
70307
|
+
var log4 = createLogger2("registry");
|
|
70189
70308
|
var AgentRegistry = class {
|
|
70190
70309
|
registryPath;
|
|
70191
70310
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -70308,7 +70427,7 @@ var AgentRegistry = class {
|
|
|
70308
70427
|
if (lastSeenTime < cutoff) {
|
|
70309
70428
|
this.agents.delete(name);
|
|
70310
70429
|
removed++;
|
|
70311
|
-
|
|
70430
|
+
log4.info("Pruned stale agent", { name, lastSeen: record2.lastSeen });
|
|
70312
70431
|
}
|
|
70313
70432
|
}
|
|
70314
70433
|
if (removed > 0) {
|
|
@@ -70365,7 +70484,7 @@ var AgentRegistry = class {
|
|
|
70365
70484
|
this.agents.set(record2.name, record2);
|
|
70366
70485
|
}
|
|
70367
70486
|
} catch (err) {
|
|
70368
|
-
|
|
70487
|
+
log4.error("Failed to load agents.json", { error: String(err) });
|
|
70369
70488
|
}
|
|
70370
70489
|
}
|
|
70371
70490
|
save() {
|
|
@@ -70375,7 +70494,7 @@ var AgentRegistry = class {
|
|
|
70375
70494
|
import_node_fs21.default.writeFileSync(tempPath, data, "utf-8");
|
|
70376
70495
|
import_node_fs21.default.renameSync(tempPath, this.registryPath);
|
|
70377
70496
|
} catch (err) {
|
|
70378
|
-
|
|
70497
|
+
log4.error("Failed to write agents.json", { error: String(err) });
|
|
70379
70498
|
}
|
|
70380
70499
|
}
|
|
70381
70500
|
};
|
|
@@ -70399,7 +70518,7 @@ var import_node_zlib = require("node:zlib");
|
|
|
70399
70518
|
var import_node_util5 = require("node:util");
|
|
70400
70519
|
init_logger();
|
|
70401
70520
|
var gzipAsync = (0, import_node_util5.promisify)(import_node_zlib.gzip);
|
|
70402
|
-
var
|
|
70521
|
+
var log5 = createLogger2("sync-queue");
|
|
70403
70522
|
var DEFAULT_SYNC_QUEUE_CONFIG = {
|
|
70404
70523
|
cloudUrl: "https://agent-relay.com",
|
|
70405
70524
|
apiKey: "",
|
|
@@ -70455,7 +70574,7 @@ var SyncQueue = class {
|
|
|
70455
70574
|
} else if (!this.flushTimer) {
|
|
70456
70575
|
this.flushTimer = setTimeout(() => {
|
|
70457
70576
|
this.flush().catch((err) => {
|
|
70458
|
-
|
|
70577
|
+
log5.error("Timer flush failed", { error: String(err) });
|
|
70459
70578
|
});
|
|
70460
70579
|
}, this.config.batchDelayMs);
|
|
70461
70580
|
}
|
|
@@ -70517,7 +70636,7 @@ var SyncQueue = class {
|
|
|
70517
70636
|
if (attempt < this.config.maxRetries - 1) {
|
|
70518
70637
|
const delay = this.config.retryDelayMs * Math.pow(2, attempt);
|
|
70519
70638
|
if (this.config.verbose) {
|
|
70520
|
-
|
|
70639
|
+
log5.warn(`Sync attempt ${attempt + 1} failed, retrying in ${delay}ms`, {
|
|
70521
70640
|
error: lastError.message
|
|
70522
70641
|
});
|
|
70523
70642
|
}
|
|
@@ -70525,7 +70644,7 @@ var SyncQueue = class {
|
|
|
70525
70644
|
}
|
|
70526
70645
|
}
|
|
70527
70646
|
}
|
|
70528
|
-
|
|
70647
|
+
log5.error("Sync failed after retries, spilling to disk", {
|
|
70529
70648
|
count: messages.length,
|
|
70530
70649
|
error: lastError?.message
|
|
70531
70650
|
});
|
|
@@ -70569,7 +70688,7 @@ var SyncQueue = class {
|
|
|
70569
70688
|
contentEncoding = "gzip";
|
|
70570
70689
|
if (this.config.verbose) {
|
|
70571
70690
|
const ratio = ((1 - body.length / payloadBytes) * 100).toFixed(1);
|
|
70572
|
-
|
|
70691
|
+
log5.info(`Compressed ${payloadBytes} \u2192 ${body.length} bytes (${ratio}% reduction)`);
|
|
70573
70692
|
}
|
|
70574
70693
|
} else {
|
|
70575
70694
|
body = payloadJson;
|
|
@@ -70610,11 +70729,11 @@ var SyncQueue = class {
|
|
|
70610
70729
|
await fs25.writeFile(filepath, JSON.stringify(messages));
|
|
70611
70730
|
this.stats.spilledFiles++;
|
|
70612
70731
|
if (this.config.verbose) {
|
|
70613
|
-
|
|
70732
|
+
log5.info(`Spilled ${messages.length} messages to ${filename}`);
|
|
70614
70733
|
}
|
|
70615
70734
|
await this.cleanupSpillFiles();
|
|
70616
70735
|
} catch (err) {
|
|
70617
|
-
|
|
70736
|
+
log5.error("Failed to spill to disk", { error: String(err) });
|
|
70618
70737
|
}
|
|
70619
70738
|
}
|
|
70620
70739
|
/**
|
|
@@ -70638,23 +70757,23 @@ var SyncQueue = class {
|
|
|
70638
70757
|
recovered += messages.length;
|
|
70639
70758
|
this.stats.spilledFiles = Math.max(0, this.stats.spilledFiles - 1);
|
|
70640
70759
|
if (this.config.verbose) {
|
|
70641
|
-
|
|
70760
|
+
log5.info(`Recovered ${messages.length} messages from ${file}`);
|
|
70642
70761
|
}
|
|
70643
70762
|
} else {
|
|
70644
70763
|
failed += messages.length;
|
|
70645
70764
|
}
|
|
70646
70765
|
} catch (err) {
|
|
70647
|
-
|
|
70766
|
+
log5.warn(`Failed to recover ${file}`, { error: String(err) });
|
|
70648
70767
|
failed++;
|
|
70649
70768
|
}
|
|
70650
70769
|
}
|
|
70651
70770
|
} catch (err) {
|
|
70652
70771
|
if (err.code !== "ENOENT") {
|
|
70653
|
-
|
|
70772
|
+
log5.error("Failed to scan spill directory", { error: String(err) });
|
|
70654
70773
|
}
|
|
70655
70774
|
}
|
|
70656
70775
|
if (recovered > 0) {
|
|
70657
|
-
|
|
70776
|
+
log5.info(`Recovered ${recovered} messages from spill files`);
|
|
70658
70777
|
}
|
|
70659
70778
|
return { recovered, failed };
|
|
70660
70779
|
}
|
|
@@ -70672,7 +70791,7 @@ var SyncQueue = class {
|
|
|
70672
70791
|
});
|
|
70673
70792
|
}
|
|
70674
70793
|
if (this.config.verbose) {
|
|
70675
|
-
|
|
70794
|
+
log5.info(`Cleaned up ${toDelete.length} old spill files`);
|
|
70676
70795
|
}
|
|
70677
70796
|
}
|
|
70678
70797
|
} catch {
|
|
@@ -70722,7 +70841,7 @@ var SyncQueue = class {
|
|
|
70722
70841
|
// packages/utils/dist/git-remote.js
|
|
70723
70842
|
var fs26 = __toESM(require("node:fs"), 1);
|
|
70724
70843
|
var path27 = __toESM(require("node:path"), 1);
|
|
70725
|
-
var
|
|
70844
|
+
var import_node_child_process13 = require("node:child_process");
|
|
70726
70845
|
function parseGitRemoteUrl(url) {
|
|
70727
70846
|
if (!url)
|
|
70728
70847
|
return null;
|
|
@@ -70742,7 +70861,7 @@ function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
|
|
|
70742
70861
|
if (!fs26.existsSync(gitDir)) {
|
|
70743
70862
|
return null;
|
|
70744
70863
|
}
|
|
70745
|
-
const result = (0,
|
|
70864
|
+
const result = (0, import_node_child_process13.execSync)(`git remote get-url ${remoteName}`, {
|
|
70746
70865
|
cwd: workingDirectory,
|
|
70747
70866
|
encoding: "utf-8",
|
|
70748
70867
|
timeout: 5e3,
|
|
@@ -70795,7 +70914,7 @@ function getRepoFullNameFromPath(workingDirectory) {
|
|
|
70795
70914
|
}
|
|
70796
70915
|
|
|
70797
70916
|
// packages/daemon/dist/cloud-sync.js
|
|
70798
|
-
var
|
|
70917
|
+
var log6 = createLogger2("cloud-sync");
|
|
70799
70918
|
var CloudSyncService = class extends import_events7.EventEmitter {
|
|
70800
70919
|
config;
|
|
70801
70920
|
heartbeatTimer;
|
|
@@ -70830,7 +70949,7 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
70830
70949
|
this.projectDirectory = this.config.projectDirectory || process.cwd();
|
|
70831
70950
|
this.repoFullName = getRepoFullNameFromPath(this.projectDirectory);
|
|
70832
70951
|
if (this.repoFullName) {
|
|
70833
|
-
|
|
70952
|
+
log6.info("Detected git repository", { repoFullName: this.repoFullName });
|
|
70834
70953
|
}
|
|
70835
70954
|
if (this.config.useOptimizedSync && this.config.apiKey) {
|
|
70836
70955
|
this.syncQueue = new SyncQueue({
|
|
@@ -70863,19 +70982,19 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
70863
70982
|
*/
|
|
70864
70983
|
async start() {
|
|
70865
70984
|
if (!this.config.enabled || !this.config.apiKey) {
|
|
70866
|
-
|
|
70867
|
-
|
|
70985
|
+
log6.info("Disabled (no API key configured)");
|
|
70986
|
+
log6.info("Run `agent-relay cloud link` to connect to cloud");
|
|
70868
70987
|
return;
|
|
70869
70988
|
}
|
|
70870
|
-
|
|
70989
|
+
log6.info("Starting cloud sync", { url: this.config.cloudUrl });
|
|
70871
70990
|
if (this.syncQueue) {
|
|
70872
70991
|
const { recovered, failed } = await this.syncQueue.recoverSpilledMessages();
|
|
70873
70992
|
if (recovered > 0 || failed > 0) {
|
|
70874
|
-
|
|
70993
|
+
log6.info("Recovered spilled messages", { recovered, failed });
|
|
70875
70994
|
}
|
|
70876
70995
|
}
|
|
70877
70996
|
await this.sendHeartbeat();
|
|
70878
|
-
this.heartbeatTimer = setInterval(() => this.sendHeartbeat().catch((err) =>
|
|
70997
|
+
this.heartbeatTimer = setInterval(() => this.sendHeartbeat().catch((err) => log6.error("Heartbeat failed", { error: String(err) })), this.config.heartbeatInterval);
|
|
70879
70998
|
this.connected = true;
|
|
70880
70999
|
this.emit("connected");
|
|
70881
71000
|
}
|
|
@@ -70902,7 +71021,7 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
70902
71021
|
this.localAgents.set(agent.name, agent);
|
|
70903
71022
|
}
|
|
70904
71023
|
if (this.connected) {
|
|
70905
|
-
this.syncAgents().catch((err) =>
|
|
71024
|
+
this.syncAgents().catch((err) => log6.error("Agent sync failed", { error: String(err) }));
|
|
70906
71025
|
}
|
|
70907
71026
|
}
|
|
70908
71027
|
/**
|
|
@@ -70969,7 +71088,7 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
70969
71088
|
}).finally(() => clearTimeout(timeoutId));
|
|
70970
71089
|
if (!response.ok) {
|
|
70971
71090
|
if (response.status === 401) {
|
|
70972
|
-
|
|
71091
|
+
log6.error("Invalid API key. Run `agent-relay cloud link` to re-authenticate.");
|
|
70973
71092
|
this.stop();
|
|
70974
71093
|
return;
|
|
70975
71094
|
}
|
|
@@ -70990,18 +71109,18 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
70990
71109
|
} catch (error2) {
|
|
70991
71110
|
const errorMessage = String(error2);
|
|
70992
71111
|
if (error2 instanceof Error && error2.name === "AbortError") {
|
|
70993
|
-
|
|
71112
|
+
log6.error("Heartbeat timeout (10s)", { url: this.config.cloudUrl });
|
|
70994
71113
|
} else if (errorMessage.includes("fetch failed") || errorMessage.includes("ECONNREFUSED")) {
|
|
70995
|
-
|
|
71114
|
+
log6.error("Heartbeat network error - cloud server unreachable", {
|
|
70996
71115
|
url: this.config.cloudUrl,
|
|
70997
71116
|
error: errorMessage
|
|
70998
71117
|
});
|
|
70999
71118
|
} else if (errorMessage.includes("ENOTFOUND") || errorMessage.includes("getaddrinfo")) {
|
|
71000
|
-
|
|
71119
|
+
log6.error("Heartbeat DNS error - cannot resolve cloud server", {
|
|
71001
71120
|
url: this.config.cloudUrl
|
|
71002
71121
|
});
|
|
71003
71122
|
} else {
|
|
71004
|
-
|
|
71123
|
+
log6.error("Heartbeat error", { error: errorMessage });
|
|
71005
71124
|
}
|
|
71006
71125
|
this.emit("error", error2);
|
|
71007
71126
|
}
|
|
@@ -71091,14 +71210,14 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
71091
71210
|
*/
|
|
71092
71211
|
setStorage(storage) {
|
|
71093
71212
|
this.storage = storage;
|
|
71094
|
-
|
|
71213
|
+
log6.info("Storage adapter configured for message sync");
|
|
71095
71214
|
}
|
|
71096
71215
|
/**
|
|
71097
71216
|
* Set the metrics provider for agent metrics sync
|
|
71098
71217
|
*/
|
|
71099
71218
|
setMetricsProvider(provider) {
|
|
71100
71219
|
this.metricsProvider = provider;
|
|
71101
|
-
|
|
71220
|
+
log6.info("Metrics provider configured for agent metrics sync");
|
|
71102
71221
|
}
|
|
71103
71222
|
/**
|
|
71104
71223
|
* Push agent metrics to cloud monitoring API.
|
|
@@ -71145,11 +71264,11 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
71145
71264
|
}
|
|
71146
71265
|
const result = await response.json();
|
|
71147
71266
|
if (result.recorded > 0) {
|
|
71148
|
-
|
|
71267
|
+
log6.info(`Pushed ${result.recorded} agent metrics to cloud`);
|
|
71149
71268
|
}
|
|
71150
71269
|
return { recorded: result.recorded };
|
|
71151
71270
|
} catch (error2) {
|
|
71152
|
-
|
|
71271
|
+
log6.error("Failed to push agent metrics", { error: String(error2) });
|
|
71153
71272
|
return null;
|
|
71154
71273
|
}
|
|
71155
71274
|
}
|
|
@@ -71180,10 +71299,10 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
71180
71299
|
throw new Error(`Session create failed: ${response.status}`);
|
|
71181
71300
|
}
|
|
71182
71301
|
const result = await response.json();
|
|
71183
|
-
|
|
71302
|
+
log6.info(`Created session ${result.sessionId.substring(0, 8)} for ${agentName}`);
|
|
71184
71303
|
return result.sessionId;
|
|
71185
71304
|
} catch (error2) {
|
|
71186
|
-
|
|
71305
|
+
log6.error("Failed to create session", { agentName, error: String(error2) });
|
|
71187
71306
|
return null;
|
|
71188
71307
|
}
|
|
71189
71308
|
}
|
|
@@ -71211,10 +71330,10 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
71211
71330
|
throw new Error(`Summary add failed: ${response.status}`);
|
|
71212
71331
|
}
|
|
71213
71332
|
const result = await response.json();
|
|
71214
|
-
|
|
71333
|
+
log6.info(`Added summary for ${agentName}: ${summary.currentTask || "no task"}`);
|
|
71215
71334
|
return result.summaryId;
|
|
71216
71335
|
} catch (error2) {
|
|
71217
|
-
|
|
71336
|
+
log6.error("Failed to add summary", { sessionId, agentName, error: String(error2) });
|
|
71218
71337
|
return null;
|
|
71219
71338
|
}
|
|
71220
71339
|
}
|
|
@@ -71240,10 +71359,10 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
71240
71359
|
if (!response.ok) {
|
|
71241
71360
|
throw new Error(`Session end failed: ${response.status}`);
|
|
71242
71361
|
}
|
|
71243
|
-
|
|
71362
|
+
log6.info(`Ended session ${sessionId.substring(0, 8)}: ${endMarker?.summary || "no summary"}`);
|
|
71244
71363
|
return true;
|
|
71245
71364
|
} catch (error2) {
|
|
71246
|
-
|
|
71365
|
+
log6.error("Failed to end session", { sessionId, error: String(error2) });
|
|
71247
71366
|
return false;
|
|
71248
71367
|
}
|
|
71249
71368
|
}
|
|
@@ -71332,11 +71451,11 @@ var CloudSyncService = class extends import_events7.EventEmitter {
|
|
|
71332
71451
|
this.lastMessageSyncTs = Math.max(...messages.map((m) => m.ts));
|
|
71333
71452
|
}
|
|
71334
71453
|
if (result.synced > 0) {
|
|
71335
|
-
|
|
71454
|
+
log6.info(`Synced ${result.synced} messages to cloud`, { duplicates: result.duplicates });
|
|
71336
71455
|
}
|
|
71337
71456
|
return result;
|
|
71338
71457
|
} catch (error2) {
|
|
71339
|
-
|
|
71458
|
+
log6.error("Message sync error", { error: String(error2) });
|
|
71340
71459
|
return { synced: 0, duplicates: 0 };
|
|
71341
71460
|
} finally {
|
|
71342
71461
|
this.messageSyncInProgress = false;
|
|
@@ -71361,7 +71480,7 @@ function createCloudPersistenceHandler(cloudSync, workspaceId) {
|
|
|
71361
71480
|
sessionId = newSessionId;
|
|
71362
71481
|
agentSessions.set(agentName, sessionId);
|
|
71363
71482
|
} else {
|
|
71364
|
-
|
|
71483
|
+
log6.warn(`Failed to create session for ${agentName}, skipping summary`);
|
|
71365
71484
|
return;
|
|
71366
71485
|
}
|
|
71367
71486
|
}
|
|
@@ -71373,7 +71492,7 @@ function createCloudPersistenceHandler(cloudSync, workspaceId) {
|
|
|
71373
71492
|
await cloudSync.endSession(sessionId, event.marker);
|
|
71374
71493
|
agentSessions.delete(agentName);
|
|
71375
71494
|
} else {
|
|
71376
|
-
|
|
71495
|
+
log6.warn(`No session found for ${agentName} on session-end`);
|
|
71377
71496
|
}
|
|
71378
71497
|
},
|
|
71379
71498
|
destroy() {
|
|
@@ -74270,15 +74389,15 @@ var Orchestrator = class extends import_events8.EventEmitter {
|
|
|
74270
74389
|
*/
|
|
74271
74390
|
getGitInfo(workspacePath) {
|
|
74272
74391
|
try {
|
|
74273
|
-
const { execSync:
|
|
74274
|
-
const branch =
|
|
74392
|
+
const { execSync: execSync10 } = require("child_process");
|
|
74393
|
+
const branch = execSync10("git branch --show-current", {
|
|
74275
74394
|
cwd: workspacePath,
|
|
74276
74395
|
encoding: "utf8",
|
|
74277
74396
|
stdio: ["pipe", "pipe", "pipe"]
|
|
74278
74397
|
}).trim();
|
|
74279
74398
|
let remote;
|
|
74280
74399
|
try {
|
|
74281
|
-
remote =
|
|
74400
|
+
remote = execSync10("git remote get-url origin", {
|
|
74282
74401
|
cwd: workspacePath,
|
|
74283
74402
|
encoding: "utf8",
|
|
74284
74403
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -76762,7 +76881,7 @@ function manageContext(compactor, messages) {
|
|
|
76762
76881
|
}
|
|
76763
76882
|
|
|
76764
76883
|
// packages/daemon/dist/cli-auth.js
|
|
76765
|
-
var
|
|
76884
|
+
var import_node_child_process14 = require("node:child_process");
|
|
76766
76885
|
var fs33 = __toESM(require("fs/promises"), 1);
|
|
76767
76886
|
var os15 = __toESM(require("os"), 1);
|
|
76768
76887
|
var import_node_path27 = require("node:path");
|
|
@@ -76879,7 +76998,7 @@ async function startCLIAuth(provider, options = {}) {
|
|
|
76879
76998
|
config2.command,
|
|
76880
76999
|
...args
|
|
76881
77000
|
];
|
|
76882
|
-
const proc = (0,
|
|
77001
|
+
const proc = (0, import_node_child_process14.spawn)(relayPtyPath, relayArgs, {
|
|
76883
77002
|
cwd: process.cwd(),
|
|
76884
77003
|
env: {
|
|
76885
77004
|
...process.env,
|
|
@@ -78121,11 +78240,11 @@ var HookRegistry = class {
|
|
|
78121
78240
|
};
|
|
78122
78241
|
|
|
78123
78242
|
// packages/trajectory/dist/integration.js
|
|
78124
|
-
var
|
|
78243
|
+
var import_node_child_process15 = require("node:child_process");
|
|
78125
78244
|
async function runTrail2(args) {
|
|
78126
78245
|
return new Promise((resolve5) => {
|
|
78127
78246
|
const trajectoryEnv = getTrajectoryEnvVars();
|
|
78128
|
-
const proc = (0,
|
|
78247
|
+
const proc = (0, import_node_child_process15.spawn)("trail", args, {
|
|
78129
78248
|
cwd: getProjectPaths().projectRoot,
|
|
78130
78249
|
env: { ...process.env, ...trajectoryEnv },
|
|
78131
78250
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -78396,7 +78515,7 @@ var TrajectoryIntegration2 = class {
|
|
|
78396
78515
|
*/
|
|
78397
78516
|
isTrailInstalledSync() {
|
|
78398
78517
|
try {
|
|
78399
|
-
(0,
|
|
78518
|
+
(0, import_node_child_process15.execSync)("which trail", { stdio: "pipe" });
|
|
78400
78519
|
return true;
|
|
78401
78520
|
} catch {
|
|
78402
78521
|
return false;
|