agent-relay 3.2.2 → 3.2.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/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/dist/index.cjs +1093 -833
- package/dist/src/cli/commands/agent-management.d.ts +2 -2
- package/dist/src/cli/commands/agent-management.d.ts.map +1 -1
- package/dist/src/cli/commands/agent-management.js +41 -240
- package/dist/src/cli/commands/agent-management.js.map +1 -1
- package/dist/src/cli/commands/messaging.d.ts +1 -1
- package/dist/src/cli/commands/messaging.d.ts.map +1 -1
- package/dist/src/cli/commands/messaging.js +14 -5
- package/dist/src/cli/commands/messaging.js.map +1 -1
- package/dist/src/cli/lib/agent-management-listing.d.ts +4 -1
- package/dist/src/cli/lib/agent-management-listing.d.ts.map +1 -1
- package/dist/src/cli/lib/agent-management-listing.js +27 -2
- package/dist/src/cli/lib/agent-management-listing.js.map +1 -1
- package/package.json +8 -8
- package/packages/acp-bridge/package.json +2 -2
- package/packages/config/package.json +1 -1
- package/packages/hooks/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/openclaw/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/sdk/dist/client.d.ts +66 -0
- package/packages/sdk/dist/client.d.ts.map +1 -1
- package/packages/sdk/dist/client.js +230 -0
- package/packages/sdk/dist/client.js.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/client.ts +301 -0
- package/packages/sdk-py/pyproject.toml +1 -1
- 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/dist/index.cjs
CHANGED
|
@@ -35,13 +35,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
35
35
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
36
36
|
|
|
37
37
|
// packages/config/src/bridge-utils.ts
|
|
38
|
-
var
|
|
38
|
+
var import_node_child_process, import_node_util, execAsync;
|
|
39
39
|
var init_bridge_utils = __esm({
|
|
40
40
|
"packages/config/src/bridge-utils.ts"() {
|
|
41
41
|
"use strict";
|
|
42
|
-
|
|
42
|
+
import_node_child_process = require("node:child_process");
|
|
43
43
|
import_node_util = require("node:util");
|
|
44
|
-
execAsync = (0, import_node_util.promisify)(
|
|
44
|
+
execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
@@ -6885,14 +6885,14 @@ var require_parser = __commonJS({
|
|
|
6885
6885
|
case "scalar":
|
|
6886
6886
|
case "single-quoted-scalar":
|
|
6887
6887
|
case "double-quoted-scalar": {
|
|
6888
|
-
const
|
|
6888
|
+
const fs10 = this.flowScalar(this.type);
|
|
6889
6889
|
if (atNextItem || it.value) {
|
|
6890
|
-
map2.items.push({ start, key:
|
|
6890
|
+
map2.items.push({ start, key: fs10, sep: [] });
|
|
6891
6891
|
this.onKeyLine = true;
|
|
6892
6892
|
} else if (it.sep) {
|
|
6893
|
-
this.stack.push(
|
|
6893
|
+
this.stack.push(fs10);
|
|
6894
6894
|
} else {
|
|
6895
|
-
Object.assign(it, { key:
|
|
6895
|
+
Object.assign(it, { key: fs10, sep: [] });
|
|
6896
6896
|
this.onKeyLine = true;
|
|
6897
6897
|
}
|
|
6898
6898
|
return;
|
|
@@ -7020,13 +7020,13 @@ var require_parser = __commonJS({
|
|
|
7020
7020
|
case "scalar":
|
|
7021
7021
|
case "single-quoted-scalar":
|
|
7022
7022
|
case "double-quoted-scalar": {
|
|
7023
|
-
const
|
|
7023
|
+
const fs10 = this.flowScalar(this.type);
|
|
7024
7024
|
if (!it || it.value)
|
|
7025
|
-
fc.items.push({ start: [], key:
|
|
7025
|
+
fc.items.push({ start: [], key: fs10, sep: [] });
|
|
7026
7026
|
else if (it.sep)
|
|
7027
|
-
this.stack.push(
|
|
7027
|
+
this.stack.push(fs10);
|
|
7028
7028
|
else
|
|
7029
|
-
Object.assign(it, { key:
|
|
7029
|
+
Object.assign(it, { key: fs10, sep: [] });
|
|
7030
7030
|
return;
|
|
7031
7031
|
}
|
|
7032
7032
|
case "flow-map-end":
|
|
@@ -7467,11 +7467,11 @@ var init_types = __esm({
|
|
|
7467
7467
|
});
|
|
7468
7468
|
|
|
7469
7469
|
// packages/memory/dist/adapters/inmemory.js
|
|
7470
|
-
var
|
|
7470
|
+
var import_node_crypto11, InMemoryAdapter;
|
|
7471
7471
|
var init_inmemory = __esm({
|
|
7472
7472
|
"packages/memory/dist/adapters/inmemory.js"() {
|
|
7473
7473
|
"use strict";
|
|
7474
|
-
|
|
7474
|
+
import_node_crypto11 = require("node:crypto");
|
|
7475
7475
|
InMemoryAdapter = class {
|
|
7476
7476
|
type = "inmemory";
|
|
7477
7477
|
memories = /* @__PURE__ */ new Map();
|
|
@@ -7486,7 +7486,7 @@ var init_inmemory = __esm({
|
|
|
7486
7486
|
async init() {
|
|
7487
7487
|
}
|
|
7488
7488
|
async add(content, options) {
|
|
7489
|
-
const id = (0,
|
|
7489
|
+
const id = (0, import_node_crypto11.randomUUID)();
|
|
7490
7490
|
const now = Date.now();
|
|
7491
7491
|
const entry = {
|
|
7492
7492
|
id,
|
|
@@ -8825,6 +8825,7 @@ __export(index_exports, {
|
|
|
8825
8825
|
HOOK_ABI_VERSION: () => HOOK_ABI_VERSION,
|
|
8826
8826
|
HookEmitter: () => HookEmitter,
|
|
8827
8827
|
HookRegistry: () => HookRegistry,
|
|
8828
|
+
HttpAgentRelayClient: () => HttpAgentRelayClient,
|
|
8828
8829
|
InMemoryAdapter: () => InMemoryAdapter,
|
|
8829
8830
|
InMemoryWorkflowDb: () => InMemoryWorkflowDb,
|
|
8830
8831
|
JsonFileWorkflowDb: () => JsonFileWorkflowDb,
|
|
@@ -8951,623 +8952,12 @@ var PROTOCOL_VERSION = 1;
|
|
|
8951
8952
|
|
|
8952
8953
|
// packages/sdk/dist/client.js
|
|
8953
8954
|
var import_node_events = require("node:events");
|
|
8954
|
-
var
|
|
8955
|
+
var import_node_child_process2 = require("node:child_process");
|
|
8955
8956
|
var import_node_readline = require("node:readline");
|
|
8956
|
-
var
|
|
8957
|
-
var
|
|
8958
|
-
var
|
|
8957
|
+
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
8958
|
+
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
8959
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
8959
8960
|
var import_node_url = require("node:url");
|
|
8960
|
-
var AgentRelayProtocolError = class extends Error {
|
|
8961
|
-
code;
|
|
8962
|
-
retryable;
|
|
8963
|
-
data;
|
|
8964
|
-
constructor(payload) {
|
|
8965
|
-
super(payload.message);
|
|
8966
|
-
this.name = "AgentRelayProtocolError";
|
|
8967
|
-
this.code = payload.code;
|
|
8968
|
-
this.retryable = payload.retryable;
|
|
8969
|
-
this.data = payload.data;
|
|
8970
|
-
}
|
|
8971
|
-
};
|
|
8972
|
-
var AgentRelayProcessError = class extends Error {
|
|
8973
|
-
constructor(message) {
|
|
8974
|
-
super(message);
|
|
8975
|
-
this.name = "AgentRelayProcessError";
|
|
8976
|
-
}
|
|
8977
|
-
};
|
|
8978
|
-
function isHeadlessProvider(value) {
|
|
8979
|
-
return value === "claude" || value === "opencode";
|
|
8980
|
-
}
|
|
8981
|
-
var AgentRelayClient = class _AgentRelayClient {
|
|
8982
|
-
options;
|
|
8983
|
-
child;
|
|
8984
|
-
stdoutRl;
|
|
8985
|
-
stderrRl;
|
|
8986
|
-
lastStderrLine;
|
|
8987
|
-
requestSeq = 0;
|
|
8988
|
-
pending = /* @__PURE__ */ new Map();
|
|
8989
|
-
startingPromise;
|
|
8990
|
-
eventListeners = /* @__PURE__ */ new Set();
|
|
8991
|
-
stderrListeners = /* @__PURE__ */ new Set();
|
|
8992
|
-
eventBuffer = [];
|
|
8993
|
-
maxBufferSize = 1e3;
|
|
8994
|
-
exitPromise;
|
|
8995
|
-
/** The workspace key returned by the broker in its hello_ack response. */
|
|
8996
|
-
workspaceKey;
|
|
8997
|
-
constructor(options = {}) {
|
|
8998
|
-
this.options = {
|
|
8999
|
-
binaryPath: options.binaryPath ?? resolveDefaultBinaryPath(),
|
|
9000
|
-
binaryArgs: options.binaryArgs ?? [],
|
|
9001
|
-
brokerName: options.brokerName ?? (import_node_path.default.basename(options.cwd ?? process.cwd()) || "project"),
|
|
9002
|
-
channels: options.channels ?? ["general"],
|
|
9003
|
-
cwd: options.cwd ?? process.cwd(),
|
|
9004
|
-
env: options.env ?? process.env,
|
|
9005
|
-
requestTimeoutMs: options.requestTimeoutMs ?? 1e4,
|
|
9006
|
-
shutdownTimeoutMs: options.shutdownTimeoutMs ?? 3e3,
|
|
9007
|
-
clientName: options.clientName ?? "@agent-relay/sdk",
|
|
9008
|
-
clientVersion: options.clientVersion ?? "0.1.0"
|
|
9009
|
-
};
|
|
9010
|
-
}
|
|
9011
|
-
static async start(options = {}) {
|
|
9012
|
-
const client = new _AgentRelayClient(options);
|
|
9013
|
-
await client.start();
|
|
9014
|
-
return client;
|
|
9015
|
-
}
|
|
9016
|
-
onEvent(listener) {
|
|
9017
|
-
this.eventListeners.add(listener);
|
|
9018
|
-
return () => {
|
|
9019
|
-
this.eventListeners.delete(listener);
|
|
9020
|
-
};
|
|
9021
|
-
}
|
|
9022
|
-
queryEvents(filter) {
|
|
9023
|
-
let events = [...this.eventBuffer];
|
|
9024
|
-
if (filter?.kind) {
|
|
9025
|
-
events = events.filter((event) => event.kind === filter.kind);
|
|
9026
|
-
}
|
|
9027
|
-
if (filter?.name) {
|
|
9028
|
-
events = events.filter((event) => "name" in event && event.name === filter.name);
|
|
9029
|
-
}
|
|
9030
|
-
const since = filter?.since;
|
|
9031
|
-
if (since !== void 0) {
|
|
9032
|
-
events = events.filter((event) => "timestamp" in event && typeof event.timestamp === "number" && event.timestamp >= since);
|
|
9033
|
-
}
|
|
9034
|
-
const limit = filter?.limit;
|
|
9035
|
-
if (limit !== void 0) {
|
|
9036
|
-
events = events.slice(-limit);
|
|
9037
|
-
}
|
|
9038
|
-
return events;
|
|
9039
|
-
}
|
|
9040
|
-
getLastEvent(kind, name) {
|
|
9041
|
-
for (let i = this.eventBuffer.length - 1; i >= 0; i -= 1) {
|
|
9042
|
-
const event = this.eventBuffer[i];
|
|
9043
|
-
if (event.kind === kind && (!name || "name" in event && event.name === name)) {
|
|
9044
|
-
return event;
|
|
9045
|
-
}
|
|
9046
|
-
}
|
|
9047
|
-
return void 0;
|
|
9048
|
-
}
|
|
9049
|
-
onBrokerStderr(listener) {
|
|
9050
|
-
this.stderrListeners.add(listener);
|
|
9051
|
-
return () => {
|
|
9052
|
-
this.stderrListeners.delete(listener);
|
|
9053
|
-
};
|
|
9054
|
-
}
|
|
9055
|
-
get brokerPid() {
|
|
9056
|
-
return this.child?.pid;
|
|
9057
|
-
}
|
|
9058
|
-
async start() {
|
|
9059
|
-
if (this.child) {
|
|
9060
|
-
return;
|
|
9061
|
-
}
|
|
9062
|
-
if (this.startingPromise) {
|
|
9063
|
-
return this.startingPromise;
|
|
9064
|
-
}
|
|
9065
|
-
this.startingPromise = this.startInternal();
|
|
9066
|
-
try {
|
|
9067
|
-
await this.startingPromise;
|
|
9068
|
-
} finally {
|
|
9069
|
-
this.startingPromise = void 0;
|
|
9070
|
-
}
|
|
9071
|
-
}
|
|
9072
|
-
/**
|
|
9073
|
-
* Pre-register a batch of agents with Relaycast before their steps execute.
|
|
9074
|
-
* The broker warms its token cache in parallel; subsequent spawn_agent calls
|
|
9075
|
-
* hit the cache rather than waiting on individual HTTP registrations.
|
|
9076
|
-
* Fire-and-forget from the caller's perspective — broker responds immediately
|
|
9077
|
-
* and registers in the background.
|
|
9078
|
-
*/
|
|
9079
|
-
async preflightAgents(agents) {
|
|
9080
|
-
if (agents.length === 0)
|
|
9081
|
-
return;
|
|
9082
|
-
await this.start();
|
|
9083
|
-
await this.requestOk("preflight_agents", { agents });
|
|
9084
|
-
}
|
|
9085
|
-
async spawnPty(input) {
|
|
9086
|
-
await this.start();
|
|
9087
|
-
const args = buildPtyArgsWithModel(input.cli, input.args ?? [], input.model);
|
|
9088
|
-
const agent = {
|
|
9089
|
-
name: input.name,
|
|
9090
|
-
runtime: "pty",
|
|
9091
|
-
cli: input.cli,
|
|
9092
|
-
args,
|
|
9093
|
-
channels: input.channels ?? [],
|
|
9094
|
-
model: input.model,
|
|
9095
|
-
cwd: input.cwd ?? this.options.cwd,
|
|
9096
|
-
team: input.team,
|
|
9097
|
-
shadow_of: input.shadowOf,
|
|
9098
|
-
shadow_mode: input.shadowMode,
|
|
9099
|
-
restart_policy: input.restartPolicy
|
|
9100
|
-
};
|
|
9101
|
-
const result = await this.requestOk("spawn_agent", {
|
|
9102
|
-
agent,
|
|
9103
|
-
...input.task != null ? { initial_task: input.task } : {},
|
|
9104
|
-
...input.idleThresholdSecs != null ? { idle_threshold_secs: input.idleThresholdSecs } : {},
|
|
9105
|
-
...input.continueFrom != null ? { continue_from: input.continueFrom } : {},
|
|
9106
|
-
...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
|
|
9107
|
-
});
|
|
9108
|
-
return result;
|
|
9109
|
-
}
|
|
9110
|
-
async spawnHeadless(input) {
|
|
9111
|
-
await this.start();
|
|
9112
|
-
const agent = {
|
|
9113
|
-
name: input.name,
|
|
9114
|
-
runtime: "headless",
|
|
9115
|
-
provider: input.provider,
|
|
9116
|
-
args: input.args ?? [],
|
|
9117
|
-
channels: input.channels ?? []
|
|
9118
|
-
};
|
|
9119
|
-
const result = await this.requestOk("spawn_agent", {
|
|
9120
|
-
agent,
|
|
9121
|
-
...input.task != null ? { initial_task: input.task } : {},
|
|
9122
|
-
...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
|
|
9123
|
-
});
|
|
9124
|
-
return result;
|
|
9125
|
-
}
|
|
9126
|
-
async spawnProvider(input) {
|
|
9127
|
-
const transport = input.transport ?? (input.provider === "opencode" ? "headless" : "pty");
|
|
9128
|
-
if (transport === "headless") {
|
|
9129
|
-
if (!isHeadlessProvider(input.provider)) {
|
|
9130
|
-
throw new AgentRelayProcessError(`provider '${input.provider}' does not support headless transport (supported: claude, opencode)`);
|
|
9131
|
-
}
|
|
9132
|
-
return this.spawnHeadless({
|
|
9133
|
-
name: input.name,
|
|
9134
|
-
provider: input.provider,
|
|
9135
|
-
args: input.args,
|
|
9136
|
-
channels: input.channels,
|
|
9137
|
-
task: input.task,
|
|
9138
|
-
skipRelayPrompt: input.skipRelayPrompt
|
|
9139
|
-
});
|
|
9140
|
-
}
|
|
9141
|
-
return this.spawnPty({
|
|
9142
|
-
name: input.name,
|
|
9143
|
-
cli: input.provider,
|
|
9144
|
-
args: input.args,
|
|
9145
|
-
channels: input.channels,
|
|
9146
|
-
task: input.task,
|
|
9147
|
-
model: input.model,
|
|
9148
|
-
cwd: input.cwd,
|
|
9149
|
-
team: input.team,
|
|
9150
|
-
shadowOf: input.shadowOf,
|
|
9151
|
-
shadowMode: input.shadowMode,
|
|
9152
|
-
idleThresholdSecs: input.idleThresholdSecs,
|
|
9153
|
-
restartPolicy: input.restartPolicy,
|
|
9154
|
-
continueFrom: input.continueFrom,
|
|
9155
|
-
skipRelayPrompt: input.skipRelayPrompt
|
|
9156
|
-
});
|
|
9157
|
-
}
|
|
9158
|
-
async spawnClaude(input) {
|
|
9159
|
-
return this.spawnProvider({ ...input, provider: "claude" });
|
|
9160
|
-
}
|
|
9161
|
-
async spawnOpencode(input) {
|
|
9162
|
-
return this.spawnProvider({ ...input, provider: "opencode" });
|
|
9163
|
-
}
|
|
9164
|
-
async release(name, reason) {
|
|
9165
|
-
await this.start();
|
|
9166
|
-
return this.requestOk("release_agent", { name, reason });
|
|
9167
|
-
}
|
|
9168
|
-
async sendInput(name, data) {
|
|
9169
|
-
await this.start();
|
|
9170
|
-
return this.requestOk("send_input", { name, data });
|
|
9171
|
-
}
|
|
9172
|
-
async setModel(name, model, opts) {
|
|
9173
|
-
await this.start();
|
|
9174
|
-
return this.requestOk("set_model", {
|
|
9175
|
-
name,
|
|
9176
|
-
model,
|
|
9177
|
-
timeout_ms: opts?.timeoutMs
|
|
9178
|
-
});
|
|
9179
|
-
}
|
|
9180
|
-
async getMetrics(agent) {
|
|
9181
|
-
await this.start();
|
|
9182
|
-
return this.requestOk("get_metrics", { agent });
|
|
9183
|
-
}
|
|
9184
|
-
async getCrashInsights() {
|
|
9185
|
-
await this.start();
|
|
9186
|
-
return this.requestOk("get_crash_insights", {});
|
|
9187
|
-
}
|
|
9188
|
-
async sendMessage(input) {
|
|
9189
|
-
await this.start();
|
|
9190
|
-
try {
|
|
9191
|
-
return await this.requestOk("send_message", {
|
|
9192
|
-
to: input.to,
|
|
9193
|
-
text: input.text,
|
|
9194
|
-
from: input.from,
|
|
9195
|
-
thread_id: input.threadId,
|
|
9196
|
-
workspace_id: input.workspaceId,
|
|
9197
|
-
workspace_alias: input.workspaceAlias,
|
|
9198
|
-
priority: input.priority,
|
|
9199
|
-
data: input.data
|
|
9200
|
-
});
|
|
9201
|
-
} catch (error48) {
|
|
9202
|
-
if (error48 instanceof AgentRelayProtocolError && error48.code === "unsupported_operation") {
|
|
9203
|
-
return { event_id: "unsupported_operation", targets: [] };
|
|
9204
|
-
}
|
|
9205
|
-
throw error48;
|
|
9206
|
-
}
|
|
9207
|
-
}
|
|
9208
|
-
async listAgents() {
|
|
9209
|
-
await this.start();
|
|
9210
|
-
const result = await this.requestOk("list_agents", {});
|
|
9211
|
-
return result.agents;
|
|
9212
|
-
}
|
|
9213
|
-
async getStatus() {
|
|
9214
|
-
await this.start();
|
|
9215
|
-
return this.requestOk("get_status", {});
|
|
9216
|
-
}
|
|
9217
|
-
async shutdown() {
|
|
9218
|
-
if (!this.child) {
|
|
9219
|
-
return;
|
|
9220
|
-
}
|
|
9221
|
-
void this.requestOk("shutdown", {}).catch(() => {
|
|
9222
|
-
});
|
|
9223
|
-
const child = this.child;
|
|
9224
|
-
const wait = this.exitPromise ?? Promise.resolve();
|
|
9225
|
-
const waitForExit = async (timeoutMs) => {
|
|
9226
|
-
let timer;
|
|
9227
|
-
const result = await Promise.race([
|
|
9228
|
-
wait.then(() => true),
|
|
9229
|
-
new Promise((resolve3) => {
|
|
9230
|
-
timer = setTimeout(() => resolve3(false), timeoutMs);
|
|
9231
|
-
})
|
|
9232
|
-
]);
|
|
9233
|
-
if (timer !== void 0)
|
|
9234
|
-
clearTimeout(timer);
|
|
9235
|
-
return result;
|
|
9236
|
-
};
|
|
9237
|
-
if (await waitForExit(this.options.shutdownTimeoutMs)) {
|
|
9238
|
-
return;
|
|
9239
|
-
}
|
|
9240
|
-
if (child.exitCode === null && child.signalCode === null) {
|
|
9241
|
-
child.kill("SIGTERM");
|
|
9242
|
-
}
|
|
9243
|
-
if (await waitForExit(1e3)) {
|
|
9244
|
-
return;
|
|
9245
|
-
}
|
|
9246
|
-
if (child.exitCode === null && child.signalCode === null) {
|
|
9247
|
-
child.kill("SIGKILL");
|
|
9248
|
-
}
|
|
9249
|
-
await waitForExit(1e3);
|
|
9250
|
-
}
|
|
9251
|
-
async waitForExit() {
|
|
9252
|
-
if (!this.child) {
|
|
9253
|
-
return;
|
|
9254
|
-
}
|
|
9255
|
-
await this.exitPromise;
|
|
9256
|
-
}
|
|
9257
|
-
async startInternal() {
|
|
9258
|
-
const resolvedBinary = expandTilde(this.options.binaryPath);
|
|
9259
|
-
if (isExplicitPath(this.options.binaryPath) && !import_node_fs.default.existsSync(resolvedBinary)) {
|
|
9260
|
-
throw new AgentRelayProcessError(`broker binary not found: ${this.options.binaryPath}`);
|
|
9261
|
-
}
|
|
9262
|
-
this.lastStderrLine = void 0;
|
|
9263
|
-
const args = [
|
|
9264
|
-
"init",
|
|
9265
|
-
"--name",
|
|
9266
|
-
this.options.brokerName,
|
|
9267
|
-
...this.options.channels.length > 0 ? ["--channels", this.options.channels.join(",")] : [],
|
|
9268
|
-
...this.options.binaryArgs
|
|
9269
|
-
];
|
|
9270
|
-
const env = { ...this.options.env };
|
|
9271
|
-
if (isExplicitPath(this.options.binaryPath)) {
|
|
9272
|
-
const binDir = import_node_path.default.dirname(import_node_path.default.resolve(resolvedBinary));
|
|
9273
|
-
const currentPath = env.PATH ?? env.Path ?? "";
|
|
9274
|
-
if (!currentPath.split(import_node_path.default.delimiter).includes(binDir)) {
|
|
9275
|
-
env.PATH = `${binDir}${import_node_path.default.delimiter}${currentPath}`;
|
|
9276
|
-
}
|
|
9277
|
-
}
|
|
9278
|
-
console.error(`[broker] Starting: ${resolvedBinary} ${args.join(" ")}`);
|
|
9279
|
-
const child = (0, import_node_child_process.spawn)(resolvedBinary, args, {
|
|
9280
|
-
cwd: this.options.cwd,
|
|
9281
|
-
env,
|
|
9282
|
-
stdio: "pipe"
|
|
9283
|
-
});
|
|
9284
|
-
this.child = child;
|
|
9285
|
-
this.stdoutRl = (0, import_node_readline.createInterface)({ input: child.stdout, crlfDelay: Infinity });
|
|
9286
|
-
this.stderrRl = (0, import_node_readline.createInterface)({ input: child.stderr, crlfDelay: Infinity });
|
|
9287
|
-
this.stdoutRl.on("line", (line) => {
|
|
9288
|
-
this.handleStdoutLine(line);
|
|
9289
|
-
});
|
|
9290
|
-
this.stderrRl.on("line", (line) => {
|
|
9291
|
-
const trimmed = line.trim();
|
|
9292
|
-
if (trimmed) {
|
|
9293
|
-
this.lastStderrLine = trimmed;
|
|
9294
|
-
}
|
|
9295
|
-
for (const listener of this.stderrListeners) {
|
|
9296
|
-
listener(line);
|
|
9297
|
-
}
|
|
9298
|
-
});
|
|
9299
|
-
this.exitPromise = new Promise((resolve3) => {
|
|
9300
|
-
child.once("close", (code, signal) => {
|
|
9301
|
-
const detail = this.lastStderrLine ? `: ${this.lastStderrLine}` : "";
|
|
9302
|
-
const error48 = new AgentRelayProcessError(`broker exited (code=${code ?? "null"}, signal=${signal ?? "null"})${detail}`);
|
|
9303
|
-
this.failAllPending(error48);
|
|
9304
|
-
this.disposeProcessHandles();
|
|
9305
|
-
resolve3();
|
|
9306
|
-
});
|
|
9307
|
-
child.once("error", (error48) => {
|
|
9308
|
-
this.failAllPending(error48);
|
|
9309
|
-
this.disposeProcessHandles();
|
|
9310
|
-
resolve3();
|
|
9311
|
-
});
|
|
9312
|
-
});
|
|
9313
|
-
const helloAck = await this.requestHello();
|
|
9314
|
-
console.error("[broker] Broker ready (hello handshake complete)");
|
|
9315
|
-
if (helloAck.workspace_key) {
|
|
9316
|
-
this.workspaceKey = helloAck.workspace_key;
|
|
9317
|
-
}
|
|
9318
|
-
}
|
|
9319
|
-
disposeProcessHandles() {
|
|
9320
|
-
this.stdoutRl?.close();
|
|
9321
|
-
this.stderrRl?.close();
|
|
9322
|
-
this.stdoutRl = void 0;
|
|
9323
|
-
this.stderrRl = void 0;
|
|
9324
|
-
this.lastStderrLine = void 0;
|
|
9325
|
-
this.child = void 0;
|
|
9326
|
-
this.exitPromise = void 0;
|
|
9327
|
-
}
|
|
9328
|
-
failAllPending(error48) {
|
|
9329
|
-
for (const pending of this.pending.values()) {
|
|
9330
|
-
clearTimeout(pending.timeout);
|
|
9331
|
-
pending.reject(error48);
|
|
9332
|
-
}
|
|
9333
|
-
this.pending.clear();
|
|
9334
|
-
}
|
|
9335
|
-
handleStdoutLine(line) {
|
|
9336
|
-
let parsed;
|
|
9337
|
-
try {
|
|
9338
|
-
parsed = JSON.parse(line);
|
|
9339
|
-
} catch {
|
|
9340
|
-
return;
|
|
9341
|
-
}
|
|
9342
|
-
if (!parsed || typeof parsed !== "object") {
|
|
9343
|
-
return;
|
|
9344
|
-
}
|
|
9345
|
-
if (parsed.v !== PROTOCOL_VERSION || typeof parsed.type !== "string") {
|
|
9346
|
-
return;
|
|
9347
|
-
}
|
|
9348
|
-
const envelope = {
|
|
9349
|
-
v: parsed.v,
|
|
9350
|
-
type: parsed.type,
|
|
9351
|
-
request_id: parsed.request_id,
|
|
9352
|
-
payload: parsed.payload
|
|
9353
|
-
};
|
|
9354
|
-
if (envelope.type === "event") {
|
|
9355
|
-
const payload = envelope.payload;
|
|
9356
|
-
this.eventBuffer.push(payload);
|
|
9357
|
-
if (this.eventBuffer.length > this.maxBufferSize) {
|
|
9358
|
-
this.eventBuffer.shift();
|
|
9359
|
-
}
|
|
9360
|
-
for (const listener of this.eventListeners) {
|
|
9361
|
-
listener(payload);
|
|
9362
|
-
}
|
|
9363
|
-
return;
|
|
9364
|
-
}
|
|
9365
|
-
if (!envelope.request_id) {
|
|
9366
|
-
return;
|
|
9367
|
-
}
|
|
9368
|
-
const pending = this.pending.get(envelope.request_id);
|
|
9369
|
-
if (!pending) {
|
|
9370
|
-
return;
|
|
9371
|
-
}
|
|
9372
|
-
if (envelope.type === "error") {
|
|
9373
|
-
clearTimeout(pending.timeout);
|
|
9374
|
-
this.pending.delete(envelope.request_id);
|
|
9375
|
-
pending.reject(new AgentRelayProtocolError(envelope.payload));
|
|
9376
|
-
return;
|
|
9377
|
-
}
|
|
9378
|
-
if (envelope.type !== pending.expectedType) {
|
|
9379
|
-
clearTimeout(pending.timeout);
|
|
9380
|
-
this.pending.delete(envelope.request_id);
|
|
9381
|
-
pending.reject(new AgentRelayProcessError(`unexpected response type '${envelope.type}' for request '${envelope.request_id}' (expected '${pending.expectedType}')`));
|
|
9382
|
-
return;
|
|
9383
|
-
}
|
|
9384
|
-
clearTimeout(pending.timeout);
|
|
9385
|
-
this.pending.delete(envelope.request_id);
|
|
9386
|
-
pending.resolve(envelope);
|
|
9387
|
-
}
|
|
9388
|
-
async requestHello() {
|
|
9389
|
-
const payload = {
|
|
9390
|
-
client_name: this.options.clientName,
|
|
9391
|
-
client_version: this.options.clientVersion
|
|
9392
|
-
};
|
|
9393
|
-
const frame = await this.sendRequest("hello", payload, "hello_ack");
|
|
9394
|
-
return frame.payload;
|
|
9395
|
-
}
|
|
9396
|
-
async requestOk(type, payload) {
|
|
9397
|
-
const frame = await this.sendRequest(type, payload, "ok");
|
|
9398
|
-
const result = frame.payload;
|
|
9399
|
-
return result.result;
|
|
9400
|
-
}
|
|
9401
|
-
async sendRequest(type, payload, expectedType) {
|
|
9402
|
-
if (!this.child) {
|
|
9403
|
-
throw new AgentRelayProcessError("broker is not running");
|
|
9404
|
-
}
|
|
9405
|
-
const requestId = `req_${++this.requestSeq}`;
|
|
9406
|
-
const message = {
|
|
9407
|
-
v: PROTOCOL_VERSION,
|
|
9408
|
-
type,
|
|
9409
|
-
request_id: requestId,
|
|
9410
|
-
payload
|
|
9411
|
-
};
|
|
9412
|
-
const responsePromise = new Promise((resolve3, reject) => {
|
|
9413
|
-
const timeout = setTimeout(() => {
|
|
9414
|
-
this.pending.delete(requestId);
|
|
9415
|
-
reject(new AgentRelayProcessError(`request timed out after ${this.options.requestTimeoutMs}ms (type='${type}', request_id='${requestId}')`));
|
|
9416
|
-
}, this.options.requestTimeoutMs);
|
|
9417
|
-
this.pending.set(requestId, {
|
|
9418
|
-
expectedType,
|
|
9419
|
-
resolve: resolve3,
|
|
9420
|
-
reject,
|
|
9421
|
-
timeout
|
|
9422
|
-
});
|
|
9423
|
-
});
|
|
9424
|
-
const line = `${JSON.stringify(message)}
|
|
9425
|
-
`;
|
|
9426
|
-
if (!this.child.stdin.write(line)) {
|
|
9427
|
-
await (0, import_node_events.once)(this.child.stdin, "drain");
|
|
9428
|
-
}
|
|
9429
|
-
return responsePromise;
|
|
9430
|
-
}
|
|
9431
|
-
};
|
|
9432
|
-
var CLI_MODEL_FLAG_CLIS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "goose", "aider"]);
|
|
9433
|
-
var CLI_DEFAULT_ARGS = {
|
|
9434
|
-
codex: ["-c", "check_for_update_on_startup=false"]
|
|
9435
|
-
};
|
|
9436
|
-
function buildPtyArgsWithModel(cli, args, model) {
|
|
9437
|
-
const cliName = cli.split(":")[0].trim().toLowerCase();
|
|
9438
|
-
const defaultArgs = CLI_DEFAULT_ARGS[cliName] ?? [];
|
|
9439
|
-
const baseArgs = [...defaultArgs, ...args];
|
|
9440
|
-
if (!model) {
|
|
9441
|
-
return baseArgs;
|
|
9442
|
-
}
|
|
9443
|
-
if (!CLI_MODEL_FLAG_CLIS.has(cliName)) {
|
|
9444
|
-
return baseArgs;
|
|
9445
|
-
}
|
|
9446
|
-
if (hasModelArg(baseArgs)) {
|
|
9447
|
-
return baseArgs;
|
|
9448
|
-
}
|
|
9449
|
-
return ["--model", model, ...baseArgs];
|
|
9450
|
-
}
|
|
9451
|
-
function hasModelArg(args) {
|
|
9452
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
9453
|
-
const arg = args[i];
|
|
9454
|
-
if (arg === "--model") {
|
|
9455
|
-
return true;
|
|
9456
|
-
}
|
|
9457
|
-
if (arg.startsWith("--model=")) {
|
|
9458
|
-
return true;
|
|
9459
|
-
}
|
|
9460
|
-
}
|
|
9461
|
-
return false;
|
|
9462
|
-
}
|
|
9463
|
-
function expandTilde(p) {
|
|
9464
|
-
if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
|
|
9465
|
-
const home = import_node_os.default.homedir();
|
|
9466
|
-
return import_node_path.default.join(home, p.slice(2));
|
|
9467
|
-
}
|
|
9468
|
-
return p;
|
|
9469
|
-
}
|
|
9470
|
-
function isExplicitPath(binaryPath) {
|
|
9471
|
-
return binaryPath.includes("/") || binaryPath.includes("\\") || binaryPath.startsWith(".") || binaryPath.startsWith("~");
|
|
9472
|
-
}
|
|
9473
|
-
function detectPlatformSuffix() {
|
|
9474
|
-
const platformMap = {
|
|
9475
|
-
darwin: { arm64: "darwin-arm64", x64: "darwin-x64" },
|
|
9476
|
-
linux: { arm64: "linux-arm64", x64: "linux-x64" },
|
|
9477
|
-
win32: { x64: "win32-x64" }
|
|
9478
|
-
};
|
|
9479
|
-
return platformMap[process.platform]?.[process.arch] ?? null;
|
|
9480
|
-
}
|
|
9481
|
-
function getLatestVersionSync() {
|
|
9482
|
-
try {
|
|
9483
|
-
const result = (0, import_node_child_process.execSync)("curl -fsSL https://api.github.com/repos/AgentWorkforce/relay/releases/latest", {
|
|
9484
|
-
timeout: 15e3,
|
|
9485
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9486
|
-
}).toString();
|
|
9487
|
-
const match = result.match(/"tag_name"\s*:\s*"([^"]+)"/);
|
|
9488
|
-
if (!match?.[1])
|
|
9489
|
-
return null;
|
|
9490
|
-
return match[1].replace(/^openclaw-/, "").replace(/^v/, "");
|
|
9491
|
-
} catch {
|
|
9492
|
-
return null;
|
|
9493
|
-
}
|
|
9494
|
-
}
|
|
9495
|
-
function installBrokerBinary() {
|
|
9496
|
-
const suffix = detectPlatformSuffix();
|
|
9497
|
-
if (!suffix) {
|
|
9498
|
-
throw new AgentRelayProcessError(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
9499
|
-
}
|
|
9500
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
9501
|
-
const installDir = import_node_path.default.join(homeDir, ".agent-relay", "bin");
|
|
9502
|
-
const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
|
|
9503
|
-
const targetPath = import_node_path.default.join(installDir, brokerExe);
|
|
9504
|
-
console.log(`[agent-relay] Broker binary not found, installing for ${suffix}...`);
|
|
9505
|
-
const version2 = getLatestVersionSync();
|
|
9506
|
-
if (!version2) {
|
|
9507
|
-
throw new AgentRelayProcessError("Failed to fetch latest agent-relay version from GitHub.\nInstall manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash");
|
|
9508
|
-
}
|
|
9509
|
-
const binaryName = `agent-relay-broker-${suffix}`;
|
|
9510
|
-
const downloadUrl = `https://github.com/AgentWorkforce/relay/releases/download/v${version2}/${binaryName}`;
|
|
9511
|
-
console.log(`[agent-relay] Downloading v${version2} from ${downloadUrl}`);
|
|
9512
|
-
try {
|
|
9513
|
-
import_node_fs.default.mkdirSync(installDir, { recursive: true });
|
|
9514
|
-
(0, import_node_child_process.execSync)(`curl -fsSL "${downloadUrl}" -o "${targetPath}"`, {
|
|
9515
|
-
timeout: 6e4,
|
|
9516
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9517
|
-
});
|
|
9518
|
-
import_node_fs.default.chmodSync(targetPath, 493);
|
|
9519
|
-
if (process.platform === "darwin") {
|
|
9520
|
-
try {
|
|
9521
|
-
(0, import_node_child_process.execSync)(`xattr -d com.apple.quarantine "${targetPath}" 2>/dev/null || true`, {
|
|
9522
|
-
timeout: 1e4,
|
|
9523
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9524
|
-
});
|
|
9525
|
-
} catch {
|
|
9526
|
-
}
|
|
9527
|
-
try {
|
|
9528
|
-
(0, import_node_child_process.execSync)(`codesign --force --sign - "${targetPath}"`, {
|
|
9529
|
-
timeout: 1e4,
|
|
9530
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9531
|
-
});
|
|
9532
|
-
} catch {
|
|
9533
|
-
}
|
|
9534
|
-
}
|
|
9535
|
-
(0, import_node_child_process.execSync)(`"${targetPath}" --help`, { timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
|
|
9536
|
-
} catch (err) {
|
|
9537
|
-
try {
|
|
9538
|
-
import_node_fs.default.unlinkSync(targetPath);
|
|
9539
|
-
} catch {
|
|
9540
|
-
}
|
|
9541
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
9542
|
-
throw new AgentRelayProcessError(`Failed to install broker binary: ${message}
|
|
9543
|
-
Install manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash`);
|
|
9544
|
-
}
|
|
9545
|
-
console.log(`[agent-relay] Broker installed to ${targetPath}`);
|
|
9546
|
-
return targetPath;
|
|
9547
|
-
}
|
|
9548
|
-
function resolveDefaultBinaryPath() {
|
|
9549
|
-
const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
|
|
9550
|
-
const moduleDir = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta_url));
|
|
9551
|
-
const workspaceRelease = import_node_path.default.resolve(moduleDir, "..", "..", "..", "target", "release", brokerExe);
|
|
9552
|
-
if (import_node_fs.default.existsSync(workspaceRelease)) {
|
|
9553
|
-
return workspaceRelease;
|
|
9554
|
-
}
|
|
9555
|
-
const binDir = import_node_path.default.resolve(moduleDir, "..", "bin");
|
|
9556
|
-
const suffix = detectPlatformSuffix();
|
|
9557
|
-
if (suffix) {
|
|
9558
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
9559
|
-
const platformBinary = import_node_path.default.join(binDir, `agent-relay-broker-${suffix}${ext}`);
|
|
9560
|
-
if (import_node_fs.default.existsSync(platformBinary)) {
|
|
9561
|
-
return platformBinary;
|
|
9562
|
-
}
|
|
9563
|
-
}
|
|
9564
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
9565
|
-
const standaloneBroker = import_node_path.default.join(homeDir, ".agent-relay", "bin", brokerExe);
|
|
9566
|
-
if (import_node_fs.default.existsSync(standaloneBroker)) {
|
|
9567
|
-
return standaloneBroker;
|
|
9568
|
-
}
|
|
9569
|
-
return installBrokerBinary();
|
|
9570
|
-
}
|
|
9571
8961
|
|
|
9572
8962
|
// packages/config/src/relay-config.ts
|
|
9573
8963
|
var DEFAULT_CONNECTION_CONFIG = {
|
|
@@ -9580,28 +8970,66 @@ var DEFAULT_CONNECTION_CONFIG = {
|
|
|
9580
8970
|
};
|
|
9581
8971
|
|
|
9582
8972
|
// packages/config/src/bridge-config.ts
|
|
9583
|
-
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
9584
|
-
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
9585
|
-
|
|
9586
|
-
// packages/config/src/project-namespace.ts
|
|
9587
8973
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
9588
8974
|
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
8975
|
+
|
|
8976
|
+
// packages/config/src/project-namespace.ts
|
|
8977
|
+
var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
8978
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
8979
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
8980
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
9589
8981
|
function getGlobalBaseDir() {
|
|
9590
8982
|
if (process.env.AGENT_RELAY_DATA_DIR) {
|
|
9591
8983
|
return process.env.AGENT_RELAY_DATA_DIR;
|
|
9592
8984
|
}
|
|
9593
8985
|
const xdgDataHome = process.env.XDG_DATA_HOME;
|
|
9594
8986
|
if (xdgDataHome) {
|
|
9595
|
-
return
|
|
8987
|
+
return import_node_path.default.join(xdgDataHome, "agent-relay");
|
|
9596
8988
|
}
|
|
9597
|
-
return
|
|
8989
|
+
return import_node_path.default.join(import_node_os.default.homedir(), ".agent-relay");
|
|
9598
8990
|
}
|
|
9599
8991
|
var GLOBAL_BASE_DIR = getGlobalBaseDir();
|
|
8992
|
+
var PROJECT_DATA_DIR = ".agent-relay";
|
|
8993
|
+
function hashPath(projectPath) {
|
|
8994
|
+
const normalized = import_node_path.default.resolve(projectPath);
|
|
8995
|
+
const hash2 = import_node_crypto.default.createHash("sha256").update(normalized).digest("hex");
|
|
8996
|
+
return hash2.substring(0, 12);
|
|
8997
|
+
}
|
|
8998
|
+
function findProjectRoot(startDir = process.cwd()) {
|
|
8999
|
+
if (process.env.AGENT_RELAY_PROJECT) {
|
|
9000
|
+
return import_node_path.default.resolve(process.env.AGENT_RELAY_PROJECT);
|
|
9001
|
+
}
|
|
9002
|
+
let current = import_node_path.default.resolve(startDir);
|
|
9003
|
+
const root = import_node_path.default.parse(current).root;
|
|
9004
|
+
const markers = [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".agent-relay"];
|
|
9005
|
+
while (current !== root) {
|
|
9006
|
+
for (const marker of markers) {
|
|
9007
|
+
if (import_node_fs.default.existsSync(import_node_path.default.join(current, marker))) {
|
|
9008
|
+
return current;
|
|
9009
|
+
}
|
|
9010
|
+
}
|
|
9011
|
+
current = import_node_path.default.dirname(current);
|
|
9012
|
+
}
|
|
9013
|
+
return import_node_path.default.resolve(startDir);
|
|
9014
|
+
}
|
|
9015
|
+
function getProjectPaths(projectRoot) {
|
|
9016
|
+
const root = projectRoot ?? findProjectRoot();
|
|
9017
|
+
const projectId = hashPath(root);
|
|
9018
|
+
const dataDir = import_node_path.default.join(root, PROJECT_DATA_DIR);
|
|
9019
|
+
return {
|
|
9020
|
+
dataDir,
|
|
9021
|
+
teamDir: import_node_path.default.join(dataDir, "team"),
|
|
9022
|
+
dbPath: import_node_path.default.join(dataDir, "messages.sqlite"),
|
|
9023
|
+
socketPath: import_node_path.default.join(dataDir, "relay.sock"),
|
|
9024
|
+
projectRoot: root,
|
|
9025
|
+
projectId
|
|
9026
|
+
};
|
|
9027
|
+
}
|
|
9600
9028
|
|
|
9601
9029
|
// packages/config/src/bridge-config.ts
|
|
9602
9030
|
var CONFIG_PATHS = [
|
|
9603
|
-
|
|
9604
|
-
|
|
9031
|
+
import_node_path2.default.join(import_node_os2.default.homedir(), ".agent-relay", "bridge.json"),
|
|
9032
|
+
import_node_path2.default.join(import_node_os2.default.homedir(), ".config", "agent-relay", "bridge.json")
|
|
9605
9033
|
];
|
|
9606
9034
|
|
|
9607
9035
|
// packages/config/src/index.ts
|
|
@@ -15501,93 +14929,924 @@ var ModelOptions = {
|
|
|
15501
14929
|
Droid: DROID_MODEL_OPTIONS,
|
|
15502
14930
|
Opencode: OPENCODE_MODEL_OPTIONS
|
|
15503
14931
|
};
|
|
15504
|
-
var SwarmPatterns = {
|
|
15505
|
-
/** Central coordinator distributes tasks to workers */
|
|
15506
|
-
HUB_SPOKE: "hub-spoke",
|
|
15507
|
-
/** Directed acyclic graph with dependencies */
|
|
15508
|
-
DAG: "dag",
|
|
15509
|
-
/** Parallel execution across multiple agents */
|
|
15510
|
-
FAN_OUT: "fan-out",
|
|
15511
|
-
/** Sequential processing through stages */
|
|
15512
|
-
PIPELINE: "pipeline",
|
|
15513
|
-
/** Agents reach agreement before proceeding */
|
|
15514
|
-
CONSENSUS: "consensus",
|
|
15515
|
-
/** Fully connected peer-to-peer communication */
|
|
15516
|
-
MESH: "mesh",
|
|
15517
|
-
/** Sequential handoff between agents */
|
|
15518
|
-
HANDOFF: "handoff",
|
|
15519
|
-
/** Cascading delegation */
|
|
15520
|
-
CASCADE: "cascade",
|
|
15521
|
-
/** Agents debate to reach conclusion */
|
|
15522
|
-
DEBATE: "debate",
|
|
15523
|
-
/** Tree-structured coordination */
|
|
15524
|
-
HIERARCHICAL: "hierarchical"
|
|
14932
|
+
var SwarmPatterns = {
|
|
14933
|
+
/** Central coordinator distributes tasks to workers */
|
|
14934
|
+
HUB_SPOKE: "hub-spoke",
|
|
14935
|
+
/** Directed acyclic graph with dependencies */
|
|
14936
|
+
DAG: "dag",
|
|
14937
|
+
/** Parallel execution across multiple agents */
|
|
14938
|
+
FAN_OUT: "fan-out",
|
|
14939
|
+
/** Sequential processing through stages */
|
|
14940
|
+
PIPELINE: "pipeline",
|
|
14941
|
+
/** Agents reach agreement before proceeding */
|
|
14942
|
+
CONSENSUS: "consensus",
|
|
14943
|
+
/** Fully connected peer-to-peer communication */
|
|
14944
|
+
MESH: "mesh",
|
|
14945
|
+
/** Sequential handoff between agents */
|
|
14946
|
+
HANDOFF: "handoff",
|
|
14947
|
+
/** Cascading delegation */
|
|
14948
|
+
CASCADE: "cascade",
|
|
14949
|
+
/** Agents debate to reach conclusion */
|
|
14950
|
+
DEBATE: "debate",
|
|
14951
|
+
/** Tree-structured coordination */
|
|
14952
|
+
HIERARCHICAL: "hierarchical"
|
|
14953
|
+
};
|
|
14954
|
+
var CLIRegistry = {
|
|
14955
|
+
claude: {
|
|
14956
|
+
name: "Claude Code",
|
|
14957
|
+
package: "@anthropic-ai/claude-code",
|
|
14958
|
+
version: "2.1.72",
|
|
14959
|
+
install: "npm install -g @anthropic-ai/claude-code",
|
|
14960
|
+
npmLink: "https://www.npmjs.com/package/@anthropic-ai"
|
|
14961
|
+
},
|
|
14962
|
+
codex: {
|
|
14963
|
+
name: "Codex CLI",
|
|
14964
|
+
package: "@openai/codex",
|
|
14965
|
+
version: "0.114.0",
|
|
14966
|
+
install: "npm install -g @openai/codex",
|
|
14967
|
+
npmLink: "https://www.npmjs.com/package/@openai/codex"
|
|
14968
|
+
},
|
|
14969
|
+
gemini: {
|
|
14970
|
+
name: "Gemini CLI",
|
|
14971
|
+
package: "@google/gemini-cli",
|
|
14972
|
+
version: "0.33.0",
|
|
14973
|
+
install: "npm install -g @google/gemini-cli",
|
|
14974
|
+
npmLink: "https://www.npmjs.com/package/@google/gemini-cli"
|
|
14975
|
+
},
|
|
14976
|
+
cursor: {
|
|
14977
|
+
name: "Cursor",
|
|
14978
|
+
package: "cursor",
|
|
14979
|
+
version: "2026.02.27-e7d2ef6",
|
|
14980
|
+
install: "Download from cursor.com",
|
|
14981
|
+
npmLink: void 0
|
|
14982
|
+
},
|
|
14983
|
+
droid: {
|
|
14984
|
+
name: "Droid",
|
|
14985
|
+
package: "droid",
|
|
14986
|
+
version: "0.1.0",
|
|
14987
|
+
install: "Download from droid.dev",
|
|
14988
|
+
npmLink: void 0
|
|
14989
|
+
},
|
|
14990
|
+
opencode: {
|
|
14991
|
+
name: "OpenCode",
|
|
14992
|
+
package: "opencode-ai",
|
|
14993
|
+
version: "1.2.24",
|
|
14994
|
+
install: "npm install -g opencode-ai",
|
|
14995
|
+
npmLink: "https://www.npmjs.com/package/opencode-ai"
|
|
14996
|
+
},
|
|
14997
|
+
aider: {
|
|
14998
|
+
name: "Aider",
|
|
14999
|
+
package: "aider-chat",
|
|
15000
|
+
version: "0.72.1",
|
|
15001
|
+
install: "pip install aider-chat",
|
|
15002
|
+
npmLink: void 0
|
|
15003
|
+
},
|
|
15004
|
+
goose: {
|
|
15005
|
+
name: "Goose",
|
|
15006
|
+
package: "goose-ai",
|
|
15007
|
+
version: "1.0.16",
|
|
15008
|
+
install: "pip install goose-ai",
|
|
15009
|
+
npmLink: void 0
|
|
15010
|
+
}
|
|
15011
|
+
};
|
|
15012
|
+
var DefaultModels = {
|
|
15013
|
+
claude: "sonnet",
|
|
15014
|
+
codex: "gpt-5.4",
|
|
15015
|
+
gemini: "gemini-3.1-pro-preview",
|
|
15016
|
+
cursor: "opus-4.6-thinking",
|
|
15017
|
+
droid: "opus-4.6-fast",
|
|
15018
|
+
opencode: "openai/gpt-5.2"
|
|
15019
|
+
};
|
|
15020
|
+
|
|
15021
|
+
// packages/sdk/dist/client.js
|
|
15022
|
+
var AgentRelayProtocolError = class extends Error {
|
|
15023
|
+
code;
|
|
15024
|
+
retryable;
|
|
15025
|
+
data;
|
|
15026
|
+
constructor(payload) {
|
|
15027
|
+
super(payload.message);
|
|
15028
|
+
this.name = "AgentRelayProtocolError";
|
|
15029
|
+
this.code = payload.code;
|
|
15030
|
+
this.retryable = payload.retryable;
|
|
15031
|
+
this.data = payload.data;
|
|
15032
|
+
}
|
|
15033
|
+
};
|
|
15034
|
+
var AgentRelayProcessError = class extends Error {
|
|
15035
|
+
constructor(message) {
|
|
15036
|
+
super(message);
|
|
15037
|
+
this.name = "AgentRelayProcessError";
|
|
15038
|
+
}
|
|
15039
|
+
};
|
|
15040
|
+
function isHeadlessProvider(value) {
|
|
15041
|
+
return value === "claude" || value === "opencode";
|
|
15042
|
+
}
|
|
15043
|
+
var AgentRelayClient = class _AgentRelayClient {
|
|
15044
|
+
options;
|
|
15045
|
+
child;
|
|
15046
|
+
stdoutRl;
|
|
15047
|
+
stderrRl;
|
|
15048
|
+
lastStderrLine;
|
|
15049
|
+
requestSeq = 0;
|
|
15050
|
+
pending = /* @__PURE__ */ new Map();
|
|
15051
|
+
startingPromise;
|
|
15052
|
+
eventListeners = /* @__PURE__ */ new Set();
|
|
15053
|
+
stderrListeners = /* @__PURE__ */ new Set();
|
|
15054
|
+
eventBuffer = [];
|
|
15055
|
+
maxBufferSize = 1e3;
|
|
15056
|
+
exitPromise;
|
|
15057
|
+
/** The workspace key returned by the broker in its hello_ack response. */
|
|
15058
|
+
workspaceKey;
|
|
15059
|
+
constructor(options = {}) {
|
|
15060
|
+
this.options = {
|
|
15061
|
+
binaryPath: options.binaryPath ?? resolveDefaultBinaryPath(),
|
|
15062
|
+
binaryArgs: options.binaryArgs ?? [],
|
|
15063
|
+
brokerName: options.brokerName ?? (import_node_path3.default.basename(options.cwd ?? process.cwd()) || "project"),
|
|
15064
|
+
channels: options.channels ?? ["general"],
|
|
15065
|
+
cwd: options.cwd ?? process.cwd(),
|
|
15066
|
+
env: options.env ?? process.env,
|
|
15067
|
+
requestTimeoutMs: options.requestTimeoutMs ?? 1e4,
|
|
15068
|
+
shutdownTimeoutMs: options.shutdownTimeoutMs ?? 3e3,
|
|
15069
|
+
clientName: options.clientName ?? "@agent-relay/sdk",
|
|
15070
|
+
clientVersion: options.clientVersion ?? "0.1.0"
|
|
15071
|
+
};
|
|
15072
|
+
}
|
|
15073
|
+
static async start(options = {}) {
|
|
15074
|
+
const client = new _AgentRelayClient(options);
|
|
15075
|
+
await client.start();
|
|
15076
|
+
return client;
|
|
15077
|
+
}
|
|
15078
|
+
onEvent(listener) {
|
|
15079
|
+
this.eventListeners.add(listener);
|
|
15080
|
+
return () => {
|
|
15081
|
+
this.eventListeners.delete(listener);
|
|
15082
|
+
};
|
|
15083
|
+
}
|
|
15084
|
+
queryEvents(filter) {
|
|
15085
|
+
let events = [...this.eventBuffer];
|
|
15086
|
+
if (filter?.kind) {
|
|
15087
|
+
events = events.filter((event) => event.kind === filter.kind);
|
|
15088
|
+
}
|
|
15089
|
+
if (filter?.name) {
|
|
15090
|
+
events = events.filter((event) => "name" in event && event.name === filter.name);
|
|
15091
|
+
}
|
|
15092
|
+
const since = filter?.since;
|
|
15093
|
+
if (since !== void 0) {
|
|
15094
|
+
events = events.filter((event) => "timestamp" in event && typeof event.timestamp === "number" && event.timestamp >= since);
|
|
15095
|
+
}
|
|
15096
|
+
const limit = filter?.limit;
|
|
15097
|
+
if (limit !== void 0) {
|
|
15098
|
+
events = events.slice(-limit);
|
|
15099
|
+
}
|
|
15100
|
+
return events;
|
|
15101
|
+
}
|
|
15102
|
+
getLastEvent(kind, name) {
|
|
15103
|
+
for (let i = this.eventBuffer.length - 1; i >= 0; i -= 1) {
|
|
15104
|
+
const event = this.eventBuffer[i];
|
|
15105
|
+
if (event.kind === kind && (!name || "name" in event && event.name === name)) {
|
|
15106
|
+
return event;
|
|
15107
|
+
}
|
|
15108
|
+
}
|
|
15109
|
+
return void 0;
|
|
15110
|
+
}
|
|
15111
|
+
onBrokerStderr(listener) {
|
|
15112
|
+
this.stderrListeners.add(listener);
|
|
15113
|
+
return () => {
|
|
15114
|
+
this.stderrListeners.delete(listener);
|
|
15115
|
+
};
|
|
15116
|
+
}
|
|
15117
|
+
get brokerPid() {
|
|
15118
|
+
return this.child?.pid;
|
|
15119
|
+
}
|
|
15120
|
+
async start() {
|
|
15121
|
+
if (this.child) {
|
|
15122
|
+
return;
|
|
15123
|
+
}
|
|
15124
|
+
if (this.startingPromise) {
|
|
15125
|
+
return this.startingPromise;
|
|
15126
|
+
}
|
|
15127
|
+
this.startingPromise = this.startInternal();
|
|
15128
|
+
try {
|
|
15129
|
+
await this.startingPromise;
|
|
15130
|
+
} finally {
|
|
15131
|
+
this.startingPromise = void 0;
|
|
15132
|
+
}
|
|
15133
|
+
}
|
|
15134
|
+
/**
|
|
15135
|
+
* Pre-register a batch of agents with Relaycast before their steps execute.
|
|
15136
|
+
* The broker warms its token cache in parallel; subsequent spawn_agent calls
|
|
15137
|
+
* hit the cache rather than waiting on individual HTTP registrations.
|
|
15138
|
+
* Fire-and-forget from the caller's perspective — broker responds immediately
|
|
15139
|
+
* and registers in the background.
|
|
15140
|
+
*/
|
|
15141
|
+
async preflightAgents(agents) {
|
|
15142
|
+
if (agents.length === 0)
|
|
15143
|
+
return;
|
|
15144
|
+
await this.start();
|
|
15145
|
+
await this.requestOk("preflight_agents", { agents });
|
|
15146
|
+
}
|
|
15147
|
+
async spawnPty(input) {
|
|
15148
|
+
await this.start();
|
|
15149
|
+
const args = buildPtyArgsWithModel(input.cli, input.args ?? [], input.model);
|
|
15150
|
+
const agent = {
|
|
15151
|
+
name: input.name,
|
|
15152
|
+
runtime: "pty",
|
|
15153
|
+
cli: input.cli,
|
|
15154
|
+
args,
|
|
15155
|
+
channels: input.channels ?? [],
|
|
15156
|
+
model: input.model,
|
|
15157
|
+
cwd: input.cwd ?? this.options.cwd,
|
|
15158
|
+
team: input.team,
|
|
15159
|
+
shadow_of: input.shadowOf,
|
|
15160
|
+
shadow_mode: input.shadowMode,
|
|
15161
|
+
restart_policy: input.restartPolicy
|
|
15162
|
+
};
|
|
15163
|
+
const result = await this.requestOk("spawn_agent", {
|
|
15164
|
+
agent,
|
|
15165
|
+
...input.task != null ? { initial_task: input.task } : {},
|
|
15166
|
+
...input.idleThresholdSecs != null ? { idle_threshold_secs: input.idleThresholdSecs } : {},
|
|
15167
|
+
...input.continueFrom != null ? { continue_from: input.continueFrom } : {},
|
|
15168
|
+
...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
|
|
15169
|
+
});
|
|
15170
|
+
return result;
|
|
15171
|
+
}
|
|
15172
|
+
async spawnHeadless(input) {
|
|
15173
|
+
await this.start();
|
|
15174
|
+
const agent = {
|
|
15175
|
+
name: input.name,
|
|
15176
|
+
runtime: "headless",
|
|
15177
|
+
provider: input.provider,
|
|
15178
|
+
args: input.args ?? [],
|
|
15179
|
+
channels: input.channels ?? []
|
|
15180
|
+
};
|
|
15181
|
+
const result = await this.requestOk("spawn_agent", {
|
|
15182
|
+
agent,
|
|
15183
|
+
...input.task != null ? { initial_task: input.task } : {},
|
|
15184
|
+
...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
|
|
15185
|
+
});
|
|
15186
|
+
return result;
|
|
15187
|
+
}
|
|
15188
|
+
async spawnProvider(input) {
|
|
15189
|
+
const transport = input.transport ?? (input.provider === "opencode" ? "headless" : "pty");
|
|
15190
|
+
if (transport === "headless") {
|
|
15191
|
+
if (!isHeadlessProvider(input.provider)) {
|
|
15192
|
+
throw new AgentRelayProcessError(`provider '${input.provider}' does not support headless transport (supported: claude, opencode)`);
|
|
15193
|
+
}
|
|
15194
|
+
return this.spawnHeadless({
|
|
15195
|
+
name: input.name,
|
|
15196
|
+
provider: input.provider,
|
|
15197
|
+
args: input.args,
|
|
15198
|
+
channels: input.channels,
|
|
15199
|
+
task: input.task,
|
|
15200
|
+
skipRelayPrompt: input.skipRelayPrompt
|
|
15201
|
+
});
|
|
15202
|
+
}
|
|
15203
|
+
return this.spawnPty({
|
|
15204
|
+
name: input.name,
|
|
15205
|
+
cli: input.provider,
|
|
15206
|
+
args: input.args,
|
|
15207
|
+
channels: input.channels,
|
|
15208
|
+
task: input.task,
|
|
15209
|
+
model: input.model,
|
|
15210
|
+
cwd: input.cwd,
|
|
15211
|
+
team: input.team,
|
|
15212
|
+
shadowOf: input.shadowOf,
|
|
15213
|
+
shadowMode: input.shadowMode,
|
|
15214
|
+
idleThresholdSecs: input.idleThresholdSecs,
|
|
15215
|
+
restartPolicy: input.restartPolicy,
|
|
15216
|
+
continueFrom: input.continueFrom,
|
|
15217
|
+
skipRelayPrompt: input.skipRelayPrompt
|
|
15218
|
+
});
|
|
15219
|
+
}
|
|
15220
|
+
async spawnClaude(input) {
|
|
15221
|
+
return this.spawnProvider({ ...input, provider: "claude" });
|
|
15222
|
+
}
|
|
15223
|
+
async spawnOpencode(input) {
|
|
15224
|
+
return this.spawnProvider({ ...input, provider: "opencode" });
|
|
15225
|
+
}
|
|
15226
|
+
async release(name, reason) {
|
|
15227
|
+
await this.start();
|
|
15228
|
+
return this.requestOk("release_agent", { name, reason });
|
|
15229
|
+
}
|
|
15230
|
+
async sendInput(name, data) {
|
|
15231
|
+
await this.start();
|
|
15232
|
+
return this.requestOk("send_input", { name, data });
|
|
15233
|
+
}
|
|
15234
|
+
async setModel(name, model, opts) {
|
|
15235
|
+
await this.start();
|
|
15236
|
+
return this.requestOk("set_model", {
|
|
15237
|
+
name,
|
|
15238
|
+
model,
|
|
15239
|
+
timeout_ms: opts?.timeoutMs
|
|
15240
|
+
});
|
|
15241
|
+
}
|
|
15242
|
+
async getMetrics(agent) {
|
|
15243
|
+
await this.start();
|
|
15244
|
+
return this.requestOk("get_metrics", { agent });
|
|
15245
|
+
}
|
|
15246
|
+
async getCrashInsights() {
|
|
15247
|
+
await this.start();
|
|
15248
|
+
return this.requestOk("get_crash_insights", {});
|
|
15249
|
+
}
|
|
15250
|
+
async sendMessage(input) {
|
|
15251
|
+
await this.start();
|
|
15252
|
+
try {
|
|
15253
|
+
return await this.requestOk("send_message", {
|
|
15254
|
+
to: input.to,
|
|
15255
|
+
text: input.text,
|
|
15256
|
+
from: input.from,
|
|
15257
|
+
thread_id: input.threadId,
|
|
15258
|
+
workspace_id: input.workspaceId,
|
|
15259
|
+
workspace_alias: input.workspaceAlias,
|
|
15260
|
+
priority: input.priority,
|
|
15261
|
+
data: input.data
|
|
15262
|
+
});
|
|
15263
|
+
} catch (error48) {
|
|
15264
|
+
if (error48 instanceof AgentRelayProtocolError && error48.code === "unsupported_operation") {
|
|
15265
|
+
return { event_id: "unsupported_operation", targets: [] };
|
|
15266
|
+
}
|
|
15267
|
+
throw error48;
|
|
15268
|
+
}
|
|
15269
|
+
}
|
|
15270
|
+
async listAgents() {
|
|
15271
|
+
await this.start();
|
|
15272
|
+
const result = await this.requestOk("list_agents", {});
|
|
15273
|
+
return result.agents;
|
|
15274
|
+
}
|
|
15275
|
+
async getStatus() {
|
|
15276
|
+
await this.start();
|
|
15277
|
+
return this.requestOk("get_status", {});
|
|
15278
|
+
}
|
|
15279
|
+
async shutdown() {
|
|
15280
|
+
if (!this.child) {
|
|
15281
|
+
return;
|
|
15282
|
+
}
|
|
15283
|
+
void this.requestOk("shutdown", {}).catch(() => {
|
|
15284
|
+
});
|
|
15285
|
+
const child = this.child;
|
|
15286
|
+
const wait = this.exitPromise ?? Promise.resolve();
|
|
15287
|
+
const waitForExit = async (timeoutMs) => {
|
|
15288
|
+
let timer;
|
|
15289
|
+
const result = await Promise.race([
|
|
15290
|
+
wait.then(() => true),
|
|
15291
|
+
new Promise((resolve3) => {
|
|
15292
|
+
timer = setTimeout(() => resolve3(false), timeoutMs);
|
|
15293
|
+
})
|
|
15294
|
+
]);
|
|
15295
|
+
if (timer !== void 0)
|
|
15296
|
+
clearTimeout(timer);
|
|
15297
|
+
return result;
|
|
15298
|
+
};
|
|
15299
|
+
if (await waitForExit(this.options.shutdownTimeoutMs)) {
|
|
15300
|
+
return;
|
|
15301
|
+
}
|
|
15302
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
15303
|
+
child.kill("SIGTERM");
|
|
15304
|
+
}
|
|
15305
|
+
if (await waitForExit(1e3)) {
|
|
15306
|
+
return;
|
|
15307
|
+
}
|
|
15308
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
15309
|
+
child.kill("SIGKILL");
|
|
15310
|
+
}
|
|
15311
|
+
await waitForExit(1e3);
|
|
15312
|
+
}
|
|
15313
|
+
async waitForExit() {
|
|
15314
|
+
if (!this.child) {
|
|
15315
|
+
return;
|
|
15316
|
+
}
|
|
15317
|
+
await this.exitPromise;
|
|
15318
|
+
}
|
|
15319
|
+
async startInternal() {
|
|
15320
|
+
const resolvedBinary = expandTilde(this.options.binaryPath);
|
|
15321
|
+
if (isExplicitPath(this.options.binaryPath) && !import_node_fs2.default.existsSync(resolvedBinary)) {
|
|
15322
|
+
throw new AgentRelayProcessError(`broker binary not found: ${this.options.binaryPath}`);
|
|
15323
|
+
}
|
|
15324
|
+
this.lastStderrLine = void 0;
|
|
15325
|
+
const args = [
|
|
15326
|
+
"init",
|
|
15327
|
+
"--name",
|
|
15328
|
+
this.options.brokerName,
|
|
15329
|
+
...this.options.channels.length > 0 ? ["--channels", this.options.channels.join(",")] : [],
|
|
15330
|
+
...this.options.binaryArgs
|
|
15331
|
+
];
|
|
15332
|
+
const env = { ...this.options.env };
|
|
15333
|
+
if (isExplicitPath(this.options.binaryPath)) {
|
|
15334
|
+
const binDir = import_node_path3.default.dirname(import_node_path3.default.resolve(resolvedBinary));
|
|
15335
|
+
const currentPath = env.PATH ?? env.Path ?? "";
|
|
15336
|
+
if (!currentPath.split(import_node_path3.default.delimiter).includes(binDir)) {
|
|
15337
|
+
env.PATH = `${binDir}${import_node_path3.default.delimiter}${currentPath}`;
|
|
15338
|
+
}
|
|
15339
|
+
}
|
|
15340
|
+
console.error(`[broker] Starting: ${resolvedBinary} ${args.join(" ")}`);
|
|
15341
|
+
const child = (0, import_node_child_process2.spawn)(resolvedBinary, args, {
|
|
15342
|
+
cwd: this.options.cwd,
|
|
15343
|
+
env,
|
|
15344
|
+
stdio: "pipe"
|
|
15345
|
+
});
|
|
15346
|
+
this.child = child;
|
|
15347
|
+
this.stdoutRl = (0, import_node_readline.createInterface)({ input: child.stdout, crlfDelay: Infinity });
|
|
15348
|
+
this.stderrRl = (0, import_node_readline.createInterface)({ input: child.stderr, crlfDelay: Infinity });
|
|
15349
|
+
this.stdoutRl.on("line", (line) => {
|
|
15350
|
+
this.handleStdoutLine(line);
|
|
15351
|
+
});
|
|
15352
|
+
this.stderrRl.on("line", (line) => {
|
|
15353
|
+
const trimmed = line.trim();
|
|
15354
|
+
if (trimmed) {
|
|
15355
|
+
this.lastStderrLine = trimmed;
|
|
15356
|
+
}
|
|
15357
|
+
for (const listener of this.stderrListeners) {
|
|
15358
|
+
listener(line);
|
|
15359
|
+
}
|
|
15360
|
+
});
|
|
15361
|
+
this.exitPromise = new Promise((resolve3) => {
|
|
15362
|
+
child.once("close", (code, signal) => {
|
|
15363
|
+
const detail = this.lastStderrLine ? `: ${this.lastStderrLine}` : "";
|
|
15364
|
+
const error48 = new AgentRelayProcessError(`broker exited (code=${code ?? "null"}, signal=${signal ?? "null"})${detail}`);
|
|
15365
|
+
this.failAllPending(error48);
|
|
15366
|
+
this.disposeProcessHandles();
|
|
15367
|
+
resolve3();
|
|
15368
|
+
});
|
|
15369
|
+
child.once("error", (error48) => {
|
|
15370
|
+
this.failAllPending(error48);
|
|
15371
|
+
this.disposeProcessHandles();
|
|
15372
|
+
resolve3();
|
|
15373
|
+
});
|
|
15374
|
+
});
|
|
15375
|
+
const helloAck = await this.requestHello();
|
|
15376
|
+
console.error("[broker] Broker ready (hello handshake complete)");
|
|
15377
|
+
if (helloAck.workspace_key) {
|
|
15378
|
+
this.workspaceKey = helloAck.workspace_key;
|
|
15379
|
+
}
|
|
15380
|
+
}
|
|
15381
|
+
disposeProcessHandles() {
|
|
15382
|
+
this.stdoutRl?.close();
|
|
15383
|
+
this.stderrRl?.close();
|
|
15384
|
+
this.stdoutRl = void 0;
|
|
15385
|
+
this.stderrRl = void 0;
|
|
15386
|
+
this.lastStderrLine = void 0;
|
|
15387
|
+
this.child = void 0;
|
|
15388
|
+
this.exitPromise = void 0;
|
|
15389
|
+
}
|
|
15390
|
+
failAllPending(error48) {
|
|
15391
|
+
for (const pending of this.pending.values()) {
|
|
15392
|
+
clearTimeout(pending.timeout);
|
|
15393
|
+
pending.reject(error48);
|
|
15394
|
+
}
|
|
15395
|
+
this.pending.clear();
|
|
15396
|
+
}
|
|
15397
|
+
handleStdoutLine(line) {
|
|
15398
|
+
let parsed;
|
|
15399
|
+
try {
|
|
15400
|
+
parsed = JSON.parse(line);
|
|
15401
|
+
} catch {
|
|
15402
|
+
return;
|
|
15403
|
+
}
|
|
15404
|
+
if (!parsed || typeof parsed !== "object") {
|
|
15405
|
+
return;
|
|
15406
|
+
}
|
|
15407
|
+
if (parsed.v !== PROTOCOL_VERSION || typeof parsed.type !== "string") {
|
|
15408
|
+
return;
|
|
15409
|
+
}
|
|
15410
|
+
const envelope = {
|
|
15411
|
+
v: parsed.v,
|
|
15412
|
+
type: parsed.type,
|
|
15413
|
+
request_id: parsed.request_id,
|
|
15414
|
+
payload: parsed.payload
|
|
15415
|
+
};
|
|
15416
|
+
if (envelope.type === "event") {
|
|
15417
|
+
const payload = envelope.payload;
|
|
15418
|
+
this.eventBuffer.push(payload);
|
|
15419
|
+
if (this.eventBuffer.length > this.maxBufferSize) {
|
|
15420
|
+
this.eventBuffer.shift();
|
|
15421
|
+
}
|
|
15422
|
+
for (const listener of this.eventListeners) {
|
|
15423
|
+
listener(payload);
|
|
15424
|
+
}
|
|
15425
|
+
return;
|
|
15426
|
+
}
|
|
15427
|
+
if (!envelope.request_id) {
|
|
15428
|
+
return;
|
|
15429
|
+
}
|
|
15430
|
+
const pending = this.pending.get(envelope.request_id);
|
|
15431
|
+
if (!pending) {
|
|
15432
|
+
return;
|
|
15433
|
+
}
|
|
15434
|
+
if (envelope.type === "error") {
|
|
15435
|
+
clearTimeout(pending.timeout);
|
|
15436
|
+
this.pending.delete(envelope.request_id);
|
|
15437
|
+
pending.reject(new AgentRelayProtocolError(envelope.payload));
|
|
15438
|
+
return;
|
|
15439
|
+
}
|
|
15440
|
+
if (envelope.type !== pending.expectedType) {
|
|
15441
|
+
clearTimeout(pending.timeout);
|
|
15442
|
+
this.pending.delete(envelope.request_id);
|
|
15443
|
+
pending.reject(new AgentRelayProcessError(`unexpected response type '${envelope.type}' for request '${envelope.request_id}' (expected '${pending.expectedType}')`));
|
|
15444
|
+
return;
|
|
15445
|
+
}
|
|
15446
|
+
clearTimeout(pending.timeout);
|
|
15447
|
+
this.pending.delete(envelope.request_id);
|
|
15448
|
+
pending.resolve(envelope);
|
|
15449
|
+
}
|
|
15450
|
+
async requestHello() {
|
|
15451
|
+
const payload = {
|
|
15452
|
+
client_name: this.options.clientName,
|
|
15453
|
+
client_version: this.options.clientVersion
|
|
15454
|
+
};
|
|
15455
|
+
const frame = await this.sendRequest("hello", payload, "hello_ack");
|
|
15456
|
+
return frame.payload;
|
|
15457
|
+
}
|
|
15458
|
+
async requestOk(type, payload) {
|
|
15459
|
+
const frame = await this.sendRequest(type, payload, "ok");
|
|
15460
|
+
const result = frame.payload;
|
|
15461
|
+
return result.result;
|
|
15462
|
+
}
|
|
15463
|
+
async sendRequest(type, payload, expectedType) {
|
|
15464
|
+
if (!this.child) {
|
|
15465
|
+
throw new AgentRelayProcessError("broker is not running");
|
|
15466
|
+
}
|
|
15467
|
+
const requestId = `req_${++this.requestSeq}`;
|
|
15468
|
+
const message = {
|
|
15469
|
+
v: PROTOCOL_VERSION,
|
|
15470
|
+
type,
|
|
15471
|
+
request_id: requestId,
|
|
15472
|
+
payload
|
|
15473
|
+
};
|
|
15474
|
+
const responsePromise = new Promise((resolve3, reject) => {
|
|
15475
|
+
const timeout = setTimeout(() => {
|
|
15476
|
+
this.pending.delete(requestId);
|
|
15477
|
+
reject(new AgentRelayProcessError(`request timed out after ${this.options.requestTimeoutMs}ms (type='${type}', request_id='${requestId}')`));
|
|
15478
|
+
}, this.options.requestTimeoutMs);
|
|
15479
|
+
this.pending.set(requestId, {
|
|
15480
|
+
expectedType,
|
|
15481
|
+
resolve: resolve3,
|
|
15482
|
+
reject,
|
|
15483
|
+
timeout
|
|
15484
|
+
});
|
|
15485
|
+
});
|
|
15486
|
+
const line = `${JSON.stringify(message)}
|
|
15487
|
+
`;
|
|
15488
|
+
if (!this.child.stdin.write(line)) {
|
|
15489
|
+
await (0, import_node_events.once)(this.child.stdin, "drain");
|
|
15490
|
+
}
|
|
15491
|
+
return responsePromise;
|
|
15492
|
+
}
|
|
15493
|
+
};
|
|
15494
|
+
var CLI_MODEL_FLAG_CLIS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "goose", "aider"]);
|
|
15495
|
+
var CLI_DEFAULT_ARGS = {
|
|
15496
|
+
codex: ["-c", "check_for_update_on_startup=false"]
|
|
15525
15497
|
};
|
|
15526
|
-
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
|
|
15540
|
-
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15549
|
-
|
|
15550
|
-
|
|
15551
|
-
|
|
15552
|
-
|
|
15553
|
-
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
|
|
15557
|
-
|
|
15558
|
-
|
|
15559
|
-
|
|
15560
|
-
|
|
15561
|
-
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15565
|
-
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
}
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
|
|
15572
|
-
|
|
15573
|
-
|
|
15574
|
-
|
|
15575
|
-
|
|
15576
|
-
|
|
15577
|
-
|
|
15578
|
-
|
|
15579
|
-
|
|
15580
|
-
|
|
15581
|
-
|
|
15498
|
+
function buildPtyArgsWithModel(cli, args, model) {
|
|
15499
|
+
const cliName = cli.split(":")[0].trim().toLowerCase();
|
|
15500
|
+
const defaultArgs = CLI_DEFAULT_ARGS[cliName] ?? [];
|
|
15501
|
+
const baseArgs = [...defaultArgs, ...args];
|
|
15502
|
+
if (!model) {
|
|
15503
|
+
return baseArgs;
|
|
15504
|
+
}
|
|
15505
|
+
if (!CLI_MODEL_FLAG_CLIS.has(cliName)) {
|
|
15506
|
+
return baseArgs;
|
|
15507
|
+
}
|
|
15508
|
+
if (hasModelArg(baseArgs)) {
|
|
15509
|
+
return baseArgs;
|
|
15510
|
+
}
|
|
15511
|
+
return ["--model", model, ...baseArgs];
|
|
15512
|
+
}
|
|
15513
|
+
function hasModelArg(args) {
|
|
15514
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
15515
|
+
const arg = args[i];
|
|
15516
|
+
if (arg === "--model") {
|
|
15517
|
+
return true;
|
|
15518
|
+
}
|
|
15519
|
+
if (arg.startsWith("--model=")) {
|
|
15520
|
+
return true;
|
|
15521
|
+
}
|
|
15522
|
+
}
|
|
15523
|
+
return false;
|
|
15524
|
+
}
|
|
15525
|
+
function expandTilde(p) {
|
|
15526
|
+
if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
|
|
15527
|
+
const home = import_node_os3.default.homedir();
|
|
15528
|
+
return import_node_path3.default.join(home, p.slice(2));
|
|
15529
|
+
}
|
|
15530
|
+
return p;
|
|
15531
|
+
}
|
|
15532
|
+
function isExplicitPath(binaryPath) {
|
|
15533
|
+
return binaryPath.includes("/") || binaryPath.includes("\\") || binaryPath.startsWith(".") || binaryPath.startsWith("~");
|
|
15534
|
+
}
|
|
15535
|
+
function detectPlatformSuffix() {
|
|
15536
|
+
const platformMap = {
|
|
15537
|
+
darwin: { arm64: "darwin-arm64", x64: "darwin-x64" },
|
|
15538
|
+
linux: { arm64: "linux-arm64", x64: "linux-x64" },
|
|
15539
|
+
win32: { x64: "win32-x64" }
|
|
15540
|
+
};
|
|
15541
|
+
return platformMap[process.platform]?.[process.arch] ?? null;
|
|
15542
|
+
}
|
|
15543
|
+
function getLatestVersionSync() {
|
|
15544
|
+
try {
|
|
15545
|
+
const result = (0, import_node_child_process2.execSync)("curl -fsSL https://api.github.com/repos/AgentWorkforce/relay/releases/latest", {
|
|
15546
|
+
timeout: 15e3,
|
|
15547
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15548
|
+
}).toString();
|
|
15549
|
+
const match = result.match(/"tag_name"\s*:\s*"([^"]+)"/);
|
|
15550
|
+
if (!match?.[1])
|
|
15551
|
+
return null;
|
|
15552
|
+
return match[1].replace(/^openclaw-/, "").replace(/^v/, "");
|
|
15553
|
+
} catch {
|
|
15554
|
+
return null;
|
|
15555
|
+
}
|
|
15556
|
+
}
|
|
15557
|
+
function installBrokerBinary() {
|
|
15558
|
+
const suffix = detectPlatformSuffix();
|
|
15559
|
+
if (!suffix) {
|
|
15560
|
+
throw new AgentRelayProcessError(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
15561
|
+
}
|
|
15562
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
15563
|
+
const installDir = import_node_path3.default.join(homeDir, ".agent-relay", "bin");
|
|
15564
|
+
const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
|
|
15565
|
+
const targetPath = import_node_path3.default.join(installDir, brokerExe);
|
|
15566
|
+
console.log(`[agent-relay] Broker binary not found, installing for ${suffix}...`);
|
|
15567
|
+
const version2 = getLatestVersionSync();
|
|
15568
|
+
if (!version2) {
|
|
15569
|
+
throw new AgentRelayProcessError("Failed to fetch latest agent-relay version from GitHub.\nInstall manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash");
|
|
15570
|
+
}
|
|
15571
|
+
const binaryName = `agent-relay-broker-${suffix}`;
|
|
15572
|
+
const downloadUrl = `https://github.com/AgentWorkforce/relay/releases/download/v${version2}/${binaryName}`;
|
|
15573
|
+
console.log(`[agent-relay] Downloading v${version2} from ${downloadUrl}`);
|
|
15574
|
+
try {
|
|
15575
|
+
import_node_fs2.default.mkdirSync(installDir, { recursive: true });
|
|
15576
|
+
(0, import_node_child_process2.execSync)(`curl -fsSL "${downloadUrl}" -o "${targetPath}"`, {
|
|
15577
|
+
timeout: 6e4,
|
|
15578
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15579
|
+
});
|
|
15580
|
+
import_node_fs2.default.chmodSync(targetPath, 493);
|
|
15581
|
+
if (process.platform === "darwin") {
|
|
15582
|
+
try {
|
|
15583
|
+
(0, import_node_child_process2.execSync)(`xattr -d com.apple.quarantine "${targetPath}" 2>/dev/null || true`, {
|
|
15584
|
+
timeout: 1e4,
|
|
15585
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15586
|
+
});
|
|
15587
|
+
} catch {
|
|
15588
|
+
}
|
|
15589
|
+
try {
|
|
15590
|
+
(0, import_node_child_process2.execSync)(`codesign --force --sign - "${targetPath}"`, {
|
|
15591
|
+
timeout: 1e4,
|
|
15592
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15593
|
+
});
|
|
15594
|
+
} catch {
|
|
15595
|
+
}
|
|
15596
|
+
}
|
|
15597
|
+
(0, import_node_child_process2.execSync)(`"${targetPath}" --help`, { timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
|
|
15598
|
+
} catch (err) {
|
|
15599
|
+
try {
|
|
15600
|
+
import_node_fs2.default.unlinkSync(targetPath);
|
|
15601
|
+
} catch {
|
|
15602
|
+
}
|
|
15603
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
15604
|
+
throw new AgentRelayProcessError(`Failed to install broker binary: ${message}
|
|
15605
|
+
Install manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash`);
|
|
15606
|
+
}
|
|
15607
|
+
console.log(`[agent-relay] Broker installed to ${targetPath}`);
|
|
15608
|
+
return targetPath;
|
|
15609
|
+
}
|
|
15610
|
+
function resolveDefaultBinaryPath() {
|
|
15611
|
+
const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
|
|
15612
|
+
const moduleDir = import_node_path3.default.dirname((0, import_node_url.fileURLToPath)(import_meta_url));
|
|
15613
|
+
const workspaceRelease = import_node_path3.default.resolve(moduleDir, "..", "..", "..", "target", "release", brokerExe);
|
|
15614
|
+
if (import_node_fs2.default.existsSync(workspaceRelease)) {
|
|
15615
|
+
return workspaceRelease;
|
|
15616
|
+
}
|
|
15617
|
+
const binDir = import_node_path3.default.resolve(moduleDir, "..", "bin");
|
|
15618
|
+
const suffix = detectPlatformSuffix();
|
|
15619
|
+
if (suffix) {
|
|
15620
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
15621
|
+
const platformBinary = import_node_path3.default.join(binDir, `agent-relay-broker-${suffix}${ext}`);
|
|
15622
|
+
if (import_node_fs2.default.existsSync(platformBinary)) {
|
|
15623
|
+
return platformBinary;
|
|
15624
|
+
}
|
|
15625
|
+
}
|
|
15626
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
15627
|
+
const standaloneBroker = import_node_path3.default.join(homeDir, ".agent-relay", "bin", brokerExe);
|
|
15628
|
+
if (import_node_fs2.default.existsSync(standaloneBroker)) {
|
|
15629
|
+
return standaloneBroker;
|
|
15630
|
+
}
|
|
15631
|
+
return installBrokerBinary();
|
|
15632
|
+
}
|
|
15633
|
+
var DEFAULT_DASHBOARD_PORT = (() => {
|
|
15634
|
+
const envPort = typeof process !== "undefined" ? process.env.AGENT_RELAY_DASHBOARD_PORT : void 0;
|
|
15635
|
+
if (envPort) {
|
|
15636
|
+
const parsed = Number.parseInt(envPort, 10);
|
|
15637
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
15638
|
+
return parsed;
|
|
15639
|
+
}
|
|
15640
|
+
return 3888;
|
|
15641
|
+
})();
|
|
15642
|
+
var HTTP_MAX_PORT_SCAN = 25;
|
|
15643
|
+
var HTTP_AUTOSTART_TIMEOUT_MS = 1e4;
|
|
15644
|
+
var HTTP_AUTOSTART_POLL_MS = 250;
|
|
15645
|
+
function sanitizeBrokerName(name) {
|
|
15646
|
+
return name.replace(/[^\p{L}\p{N}-]/gu, "-");
|
|
15647
|
+
}
|
|
15648
|
+
function brokerPidFilename(projectRoot) {
|
|
15649
|
+
const brokerName = import_node_path3.default.basename(projectRoot) || "project";
|
|
15650
|
+
return `broker-${sanitizeBrokerName(brokerName)}.pid`;
|
|
15651
|
+
}
|
|
15652
|
+
var HttpAgentRelayClient = class _HttpAgentRelayClient {
|
|
15653
|
+
port;
|
|
15654
|
+
apiKey;
|
|
15655
|
+
constructor(options) {
|
|
15656
|
+
this.port = options.port;
|
|
15657
|
+
this.apiKey = options.apiKey;
|
|
15658
|
+
}
|
|
15659
|
+
/**
|
|
15660
|
+
* Connect to an already-running broker on the given port.
|
|
15661
|
+
*/
|
|
15662
|
+
static async connectHttp(port, options) {
|
|
15663
|
+
const client = new _HttpAgentRelayClient({ port, apiKey: options?.apiKey });
|
|
15664
|
+
await client.healthCheck();
|
|
15665
|
+
return client;
|
|
15666
|
+
}
|
|
15667
|
+
/**
|
|
15668
|
+
* Discover a running broker for the current project and connect to it.
|
|
15669
|
+
* Reads the broker PID file, verifies the process is alive, scans ports
|
|
15670
|
+
* for the HTTP API, and returns a connected client.
|
|
15671
|
+
*/
|
|
15672
|
+
static async discoverAndConnect(options) {
|
|
15673
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
15674
|
+
const apiKey = options?.apiKey ?? process.env.RELAY_BROKER_API_KEY?.trim();
|
|
15675
|
+
const autoStart = options?.autoStart ?? false;
|
|
15676
|
+
const paths = getProjectPaths(cwd);
|
|
15677
|
+
const preferredApiPort = DEFAULT_DASHBOARD_PORT + 1;
|
|
15678
|
+
const pidFilePath = import_node_path3.default.join(paths.dataDir, brokerPidFilename(paths.projectRoot));
|
|
15679
|
+
const legacyPidPath = import_node_path3.default.join(paths.dataDir, "broker.pid");
|
|
15680
|
+
let brokerRunning = false;
|
|
15681
|
+
for (const pidPath of [pidFilePath, legacyPidPath]) {
|
|
15682
|
+
if (import_node_fs2.default.existsSync(pidPath)) {
|
|
15683
|
+
const pidStr = import_node_fs2.default.readFileSync(pidPath, "utf-8").trim();
|
|
15684
|
+
const pid = Number.parseInt(pidStr, 10);
|
|
15685
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
15686
|
+
try {
|
|
15687
|
+
process.kill(pid, 0);
|
|
15688
|
+
brokerRunning = true;
|
|
15689
|
+
break;
|
|
15690
|
+
} catch {
|
|
15691
|
+
}
|
|
15692
|
+
}
|
|
15693
|
+
}
|
|
15694
|
+
}
|
|
15695
|
+
if (brokerRunning) {
|
|
15696
|
+
const port = await _HttpAgentRelayClient.scanForBrokerPort(preferredApiPort);
|
|
15697
|
+
if (port !== null) {
|
|
15698
|
+
return new _HttpAgentRelayClient({ port, apiKey });
|
|
15699
|
+
}
|
|
15700
|
+
throw new AgentRelayProcessError("broker is running for this project, but its local API is unavailable");
|
|
15701
|
+
}
|
|
15702
|
+
if (!autoStart) {
|
|
15703
|
+
throw new AgentRelayProcessError("broker is not running for this project");
|
|
15704
|
+
}
|
|
15705
|
+
const brokerBinary = options?.brokerBinaryPath ?? resolveDefaultBinaryPath();
|
|
15706
|
+
const child = (0, import_node_child_process2.spawn)(brokerBinary, ["init", "--persist", "--api-port", String(preferredApiPort)], {
|
|
15707
|
+
cwd: paths.projectRoot,
|
|
15708
|
+
env: process.env,
|
|
15709
|
+
detached: true,
|
|
15710
|
+
stdio: "ignore"
|
|
15711
|
+
});
|
|
15712
|
+
child.unref();
|
|
15713
|
+
const startedAt = Date.now();
|
|
15714
|
+
while (Date.now() - startedAt < HTTP_AUTOSTART_TIMEOUT_MS) {
|
|
15715
|
+
const port = await _HttpAgentRelayClient.scanForBrokerPort(preferredApiPort);
|
|
15716
|
+
if (port !== null) {
|
|
15717
|
+
return new _HttpAgentRelayClient({ port, apiKey });
|
|
15718
|
+
}
|
|
15719
|
+
await new Promise((resolve3) => setTimeout(resolve3, HTTP_AUTOSTART_POLL_MS));
|
|
15720
|
+
}
|
|
15721
|
+
throw new AgentRelayProcessError(`broker did not become ready within ${HTTP_AUTOSTART_TIMEOUT_MS}ms`);
|
|
15722
|
+
}
|
|
15723
|
+
static async scanForBrokerPort(startPort) {
|
|
15724
|
+
for (let i = 0; i < HTTP_MAX_PORT_SCAN; i++) {
|
|
15725
|
+
const port = startPort + i;
|
|
15726
|
+
try {
|
|
15727
|
+
const res = await fetch(`http://127.0.0.1:${port}/health`);
|
|
15728
|
+
if (!res.ok)
|
|
15729
|
+
continue;
|
|
15730
|
+
const payload = await res.json().catch(() => null);
|
|
15731
|
+
if (payload?.service === "agent-relay-listen") {
|
|
15732
|
+
return port;
|
|
15733
|
+
}
|
|
15734
|
+
} catch {
|
|
15735
|
+
}
|
|
15736
|
+
}
|
|
15737
|
+
return null;
|
|
15738
|
+
}
|
|
15739
|
+
async request(pathname, init) {
|
|
15740
|
+
const headers = new Headers(init?.headers);
|
|
15741
|
+
if (this.apiKey && !headers.has("x-api-key") && !headers.has("authorization")) {
|
|
15742
|
+
headers.set("x-api-key", this.apiKey);
|
|
15743
|
+
}
|
|
15744
|
+
const response = await fetch(`http://127.0.0.1:${this.port}${pathname}`, {
|
|
15745
|
+
...init,
|
|
15746
|
+
headers
|
|
15747
|
+
});
|
|
15748
|
+
const text = await response.text();
|
|
15749
|
+
let payload;
|
|
15750
|
+
try {
|
|
15751
|
+
payload = text ? JSON.parse(text) : void 0;
|
|
15752
|
+
} catch {
|
|
15753
|
+
payload = text;
|
|
15754
|
+
}
|
|
15755
|
+
if (!response.ok) {
|
|
15756
|
+
const msg = _HttpAgentRelayClient.extractErrorMessage(response, payload);
|
|
15757
|
+
throw new AgentRelayProcessError(msg);
|
|
15758
|
+
}
|
|
15759
|
+
return payload;
|
|
15760
|
+
}
|
|
15761
|
+
static extractErrorMessage(response, payload) {
|
|
15762
|
+
if (typeof payload === "string" && payload.trim())
|
|
15763
|
+
return payload.trim();
|
|
15764
|
+
const p = payload;
|
|
15765
|
+
if (typeof p?.error === "string")
|
|
15766
|
+
return p.error;
|
|
15767
|
+
if (typeof p?.error?.message === "string")
|
|
15768
|
+
return p.error.message;
|
|
15769
|
+
if (typeof p?.message === "string" && p.message.trim())
|
|
15770
|
+
return p.message.trim();
|
|
15771
|
+
return `${response.status} ${response.statusText}`.trim();
|
|
15772
|
+
}
|
|
15773
|
+
async healthCheck() {
|
|
15774
|
+
return this.request("/health");
|
|
15775
|
+
}
|
|
15776
|
+
/** No-op — broker is already running. */
|
|
15777
|
+
async start() {
|
|
15778
|
+
}
|
|
15779
|
+
/** No-op — don't kill an externally-managed broker. */
|
|
15780
|
+
async shutdown() {
|
|
15781
|
+
}
|
|
15782
|
+
async spawnPty(input) {
|
|
15783
|
+
const payload = await this.request("/api/spawn", {
|
|
15784
|
+
method: "POST",
|
|
15785
|
+
headers: { "content-type": "application/json" },
|
|
15786
|
+
body: JSON.stringify({
|
|
15787
|
+
name: input.name,
|
|
15788
|
+
cli: input.cli,
|
|
15789
|
+
model: input.model,
|
|
15790
|
+
args: input.args ?? [],
|
|
15791
|
+
task: input.task,
|
|
15792
|
+
channels: input.channels ?? [],
|
|
15793
|
+
cwd: input.cwd,
|
|
15794
|
+
team: input.team,
|
|
15795
|
+
shadowOf: input.shadowOf,
|
|
15796
|
+
shadowMode: input.shadowMode,
|
|
15797
|
+
continueFrom: input.continueFrom,
|
|
15798
|
+
idleThresholdSecs: input.idleThresholdSecs,
|
|
15799
|
+
restartPolicy: input.restartPolicy,
|
|
15800
|
+
skipRelayPrompt: input.skipRelayPrompt
|
|
15801
|
+
})
|
|
15802
|
+
});
|
|
15803
|
+
return {
|
|
15804
|
+
name: typeof payload?.name === "string" ? payload.name : input.name,
|
|
15805
|
+
runtime: "pty"
|
|
15806
|
+
};
|
|
15807
|
+
}
|
|
15808
|
+
async sendMessage(input) {
|
|
15809
|
+
return this.request("/api/send", {
|
|
15810
|
+
method: "POST",
|
|
15811
|
+
headers: { "content-type": "application/json" },
|
|
15812
|
+
body: JSON.stringify({
|
|
15813
|
+
to: input.to,
|
|
15814
|
+
text: input.text,
|
|
15815
|
+
from: input.from,
|
|
15816
|
+
threadId: input.threadId,
|
|
15817
|
+
workspaceId: input.workspaceId,
|
|
15818
|
+
workspaceAlias: input.workspaceAlias,
|
|
15819
|
+
priority: input.priority,
|
|
15820
|
+
data: input.data
|
|
15821
|
+
})
|
|
15822
|
+
});
|
|
15823
|
+
}
|
|
15824
|
+
async listAgents() {
|
|
15825
|
+
const payload = await this.request("/api/spawned", { method: "GET" });
|
|
15826
|
+
return Array.isArray(payload?.agents) ? payload.agents : [];
|
|
15827
|
+
}
|
|
15828
|
+
async release(name, reason) {
|
|
15829
|
+
const payload = await this.request(`/api/spawned/${encodeURIComponent(name)}`, {
|
|
15830
|
+
method: "DELETE",
|
|
15831
|
+
...reason ? { headers: { "content-type": "application/json" }, body: JSON.stringify({ reason }) } : {}
|
|
15832
|
+
});
|
|
15833
|
+
return { name: typeof payload?.name === "string" ? payload.name : name };
|
|
15834
|
+
}
|
|
15835
|
+
async setModel(name, model, opts) {
|
|
15836
|
+
const payload = await this.request(`/api/spawned/${encodeURIComponent(name)}/model`, {
|
|
15837
|
+
method: "POST",
|
|
15838
|
+
headers: { "content-type": "application/json" },
|
|
15839
|
+
body: JSON.stringify({ model, timeoutMs: opts?.timeoutMs })
|
|
15840
|
+
});
|
|
15841
|
+
return {
|
|
15842
|
+
name,
|
|
15843
|
+
model: typeof payload?.model === "string" ? payload.model : model,
|
|
15844
|
+
success: payload?.success !== false
|
|
15845
|
+
};
|
|
15846
|
+
}
|
|
15847
|
+
async getConfig() {
|
|
15848
|
+
return this.request("/api/config");
|
|
15582
15849
|
}
|
|
15583
|
-
};
|
|
15584
|
-
var DefaultModels = {
|
|
15585
|
-
claude: "sonnet",
|
|
15586
|
-
codex: "gpt-5.4",
|
|
15587
|
-
gemini: "gemini-3.1-pro-preview",
|
|
15588
|
-
cursor: "opus-4.6-thinking",
|
|
15589
|
-
droid: "opus-4.6-fast",
|
|
15590
|
-
opencode: "openai/gpt-5.2"
|
|
15591
15850
|
};
|
|
15592
15851
|
|
|
15593
15852
|
// node_modules/@relaycast/sdk/dist/version.js
|
|
@@ -31425,7 +31684,7 @@ function cleanLines(raw) {
|
|
|
31425
31684
|
}
|
|
31426
31685
|
|
|
31427
31686
|
// packages/sdk/dist/relay.js
|
|
31428
|
-
var
|
|
31687
|
+
var import_node_crypto2 = require("node:crypto");
|
|
31429
31688
|
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
31430
31689
|
|
|
31431
31690
|
// packages/sdk/dist/logs.js
|
|
@@ -31843,7 +32102,7 @@ var AgentRelay = class {
|
|
|
31843
32102
|
if (result?.event_id === "unsupported_operation") {
|
|
31844
32103
|
return buildUnsupportedOperationMessage(opts.name, input);
|
|
31845
32104
|
}
|
|
31846
|
-
const eventId = result?.event_id ?? (0,
|
|
32105
|
+
const eventId = result?.event_id ?? (0, import_node_crypto2.randomBytes)(8).toString("hex");
|
|
31847
32106
|
const msg = {
|
|
31848
32107
|
eventId,
|
|
31849
32108
|
from: opts.name,
|
|
@@ -32505,7 +32764,7 @@ var AgentRelay = class {
|
|
|
32505
32764
|
if (result?.event_id === "unsupported_operation") {
|
|
32506
32765
|
return buildUnsupportedOperationMessage(name, input);
|
|
32507
32766
|
}
|
|
32508
|
-
const eventId = result?.event_id ?? (0,
|
|
32767
|
+
const eventId = result?.event_id ?? (0, import_node_crypto2.randomBytes)(8).toString("hex");
|
|
32509
32768
|
const msg = {
|
|
32510
32769
|
eventId,
|
|
32511
32770
|
from: name,
|
|
@@ -32622,7 +32881,7 @@ var AgentRelay = class {
|
|
|
32622
32881
|
};
|
|
32623
32882
|
|
|
32624
32883
|
// packages/sdk/dist/consensus.js
|
|
32625
|
-
var
|
|
32884
|
+
var import_node_crypto3 = require("node:crypto");
|
|
32626
32885
|
var import_node_events2 = require("node:events");
|
|
32627
32886
|
|
|
32628
32887
|
// packages/sdk/dist/consensus-helpers.js
|
|
@@ -32759,7 +33018,7 @@ var ConsensusEngine = class extends import_node_events2.EventEmitter {
|
|
|
32759
33018
|
}
|
|
32760
33019
|
// ── Proposal management ──────────────────────────────────────────────────
|
|
32761
33020
|
createProposal(options) {
|
|
32762
|
-
const id = `prop_${Date.now()}_${(0,
|
|
33021
|
+
const id = `prop_${Date.now()}_${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`;
|
|
32763
33022
|
const now = Date.now();
|
|
32764
33023
|
const timeoutMs = options.timeoutMs ?? this.config.defaultTimeoutMs;
|
|
32765
33024
|
const proposal = {
|
|
@@ -33427,8 +33686,8 @@ function isAgentStep(step) {
|
|
|
33427
33686
|
|
|
33428
33687
|
// packages/sdk/dist/workflows/runner.js
|
|
33429
33688
|
var import_node_child_process3 = require("node:child_process");
|
|
33430
|
-
var
|
|
33431
|
-
var
|
|
33689
|
+
var import_node_crypto5 = require("node:crypto");
|
|
33690
|
+
var import_node_fs5 = require("node:fs");
|
|
33432
33691
|
var import_promises3 = require("node:fs/promises");
|
|
33433
33692
|
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
33434
33693
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
@@ -33559,18 +33818,18 @@ async function spawnFromEnv(options = {}) {
|
|
|
33559
33818
|
}
|
|
33560
33819
|
|
|
33561
33820
|
// packages/sdk/dist/workflows/custom-steps.js
|
|
33562
|
-
var
|
|
33821
|
+
var import_node_fs3 = require("node:fs");
|
|
33563
33822
|
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
33564
33823
|
var import_yaml = __toESM(require_dist(), 1);
|
|
33565
33824
|
var CUSTOM_STEPS_FILE = ".relay/steps.yaml";
|
|
33566
33825
|
function loadCustomSteps(cwd) {
|
|
33567
33826
|
const stepsPath = import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE);
|
|
33568
33827
|
const steps = /* @__PURE__ */ new Map();
|
|
33569
|
-
if (!(0,
|
|
33828
|
+
if (!(0, import_node_fs3.existsSync)(stepsPath)) {
|
|
33570
33829
|
return steps;
|
|
33571
33830
|
}
|
|
33572
33831
|
try {
|
|
33573
|
-
const content = (0,
|
|
33832
|
+
const content = (0, import_node_fs3.readFileSync)(stepsPath, "utf-8");
|
|
33574
33833
|
if (!content.trim()) {
|
|
33575
33834
|
return steps;
|
|
33576
33835
|
}
|
|
@@ -33820,7 +34079,7 @@ function resolveAllCustomSteps(steps, customSteps) {
|
|
|
33820
34079
|
return steps.map((step) => resolveCustomStep(step, customSteps));
|
|
33821
34080
|
}
|
|
33822
34081
|
function customStepsFileExists(cwd) {
|
|
33823
|
-
return (0,
|
|
34082
|
+
return (0, import_node_fs3.existsSync)(import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE));
|
|
33824
34083
|
}
|
|
33825
34084
|
function getCustomStepsPath(cwd) {
|
|
33826
34085
|
return import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE);
|
|
@@ -33857,8 +34116,8 @@ var InMemoryWorkflowDb = class {
|
|
|
33857
34116
|
};
|
|
33858
34117
|
|
|
33859
34118
|
// packages/sdk/dist/workflows/trajectory.js
|
|
33860
|
-
var
|
|
33861
|
-
var
|
|
34119
|
+
var import_node_crypto4 = require("node:crypto");
|
|
34120
|
+
var import_node_fs4 = require("node:fs");
|
|
33862
34121
|
var import_promises2 = require("node:fs/promises");
|
|
33863
34122
|
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
33864
34123
|
function classifyFailure(error48) {
|
|
@@ -33921,7 +34180,7 @@ var WorkflowTrajectory = class {
|
|
|
33921
34180
|
return;
|
|
33922
34181
|
this.startTime = Date.now();
|
|
33923
34182
|
this.swarmPattern = pattern ?? "dag";
|
|
33924
|
-
const id = `traj_${Date.now()}_${(0,
|
|
34183
|
+
const id = `traj_${Date.now()}_${(0, import_node_crypto4.randomBytes)(4).toString("hex")}`;
|
|
33925
34184
|
this.trajectory = {
|
|
33926
34185
|
id,
|
|
33927
34186
|
version: 1,
|
|
@@ -34264,7 +34523,7 @@ var WorkflowTrajectory = class {
|
|
|
34264
34523
|
if (!this.trajectory)
|
|
34265
34524
|
return;
|
|
34266
34525
|
const chapter = {
|
|
34267
|
-
id: `ch_${(0,
|
|
34526
|
+
id: `ch_${(0, import_node_crypto4.randomBytes)(4).toString("hex")}`,
|
|
34268
34527
|
title,
|
|
34269
34528
|
agentName,
|
|
34270
34529
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -34337,7 +34596,7 @@ var WorkflowTrajectory = class {
|
|
|
34337
34596
|
await (0, import_promises2.mkdir)(completedDir, { recursive: true });
|
|
34338
34597
|
const activePath = import_node_path7.default.join(activeDir, `${this.trajectory.id}.json`);
|
|
34339
34598
|
const completedPath = import_node_path7.default.join(completedDir, `${this.trajectory.id}.json`);
|
|
34340
|
-
if ((0,
|
|
34599
|
+
if ((0, import_node_fs4.existsSync)(activePath)) {
|
|
34341
34600
|
await (0, import_promises2.rename)(activePath, completedPath);
|
|
34342
34601
|
}
|
|
34343
34602
|
} catch {
|
|
@@ -34475,7 +34734,7 @@ var WorkflowRunner = class _WorkflowRunner {
|
|
|
34475
34734
|
const abs = import_node_path8.default.resolve(baseCwd, expanded);
|
|
34476
34735
|
resolved.set(pd.name, abs);
|
|
34477
34736
|
const isRequired = pd.required !== false;
|
|
34478
|
-
if (!(0,
|
|
34737
|
+
if (!(0, import_node_fs5.existsSync)(abs)) {
|
|
34479
34738
|
if (isRequired) {
|
|
34480
34739
|
errors.push(`Path "${pd.name}" resolves to "${abs}" which does not exist (required)`);
|
|
34481
34740
|
} else {
|
|
@@ -34809,12 +35068,12 @@ ${next}` : next;
|
|
|
34809
35068
|
}
|
|
34810
35069
|
captureFileSnapshot(root) {
|
|
34811
35070
|
const snapshot = /* @__PURE__ */ new Map();
|
|
34812
|
-
if (!(0,
|
|
35071
|
+
if (!(0, import_node_fs5.existsSync)(root))
|
|
34813
35072
|
return snapshot;
|
|
34814
35073
|
const visit = (currentPath) => {
|
|
34815
35074
|
let entries;
|
|
34816
35075
|
try {
|
|
34817
|
-
entries = (0,
|
|
35076
|
+
entries = (0, import_node_fs5.readdirSync)(currentPath, { withFileTypes: true });
|
|
34818
35077
|
} catch {
|
|
34819
35078
|
return;
|
|
34820
35079
|
}
|
|
@@ -34828,7 +35087,7 @@ ${next}` : next;
|
|
|
34828
35087
|
continue;
|
|
34829
35088
|
}
|
|
34830
35089
|
try {
|
|
34831
|
-
const stats = (0,
|
|
35090
|
+
const stats = (0, import_node_fs5.statSync)(fullPath);
|
|
34832
35091
|
if (!stats.isFile())
|
|
34833
35092
|
continue;
|
|
34834
35093
|
snapshot.set(fullPath, { mtimeMs: stats.mtimeMs, size: stats.size });
|
|
@@ -34837,7 +35096,7 @@ ${next}` : next;
|
|
|
34837
35096
|
}
|
|
34838
35097
|
};
|
|
34839
35098
|
try {
|
|
34840
|
-
const stats = (0,
|
|
35099
|
+
const stats = (0, import_node_fs5.statSync)(root);
|
|
34841
35100
|
if (stats.isFile()) {
|
|
34842
35101
|
snapshot.set(root, { mtimeMs: stats.mtimeMs, size: stats.size });
|
|
34843
35102
|
return snapshot;
|
|
@@ -34958,7 +35217,7 @@ ${next}` : next;
|
|
|
34958
35217
|
this.relayApiKey = envKey;
|
|
34959
35218
|
return;
|
|
34960
35219
|
}
|
|
34961
|
-
const workspaceName = `relay-${channel}-${(0,
|
|
35220
|
+
const workspaceName = `relay-${channel}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`;
|
|
34962
35221
|
const baseUrl = this.relayOptions.env?.RELAYCAST_BASE_URL ?? process.env.RELAYCAST_BASE_URL ?? "https://api.relaycast.dev";
|
|
34963
35222
|
const res = await fetch(`${baseUrl}/v1/workspaces`, {
|
|
34964
35223
|
method: "POST",
|
|
@@ -35022,7 +35281,7 @@ ${next}` : next;
|
|
|
35022
35281
|
} catch (err) {
|
|
35023
35282
|
if (err instanceof RelayError && err.code === "name_conflict") {
|
|
35024
35283
|
registration = await rc.agents.register({
|
|
35025
|
-
name: `WorkflowRunner-${(0,
|
|
35284
|
+
name: `WorkflowRunner-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`,
|
|
35026
35285
|
type: "agent"
|
|
35027
35286
|
});
|
|
35028
35287
|
} else {
|
|
@@ -35239,14 +35498,14 @@ ${err.suggestion}`);
|
|
|
35239
35498
|
for (const agent of resolved.agents) {
|
|
35240
35499
|
if (agent.cwd) {
|
|
35241
35500
|
const resolvedCwd = import_node_path8.default.resolve(this.cwd, agent.cwd);
|
|
35242
|
-
if (!(0,
|
|
35501
|
+
if (!(0, import_node_fs5.existsSync)(resolvedCwd)) {
|
|
35243
35502
|
warnings.push(`Agent "${agent.name}" cwd "${agent.cwd}" resolves to "${resolvedCwd}" which does not exist`);
|
|
35244
35503
|
}
|
|
35245
35504
|
}
|
|
35246
35505
|
if (agent.additionalPaths) {
|
|
35247
35506
|
for (const ap of agent.additionalPaths) {
|
|
35248
35507
|
const resolvedPath = import_node_path8.default.resolve(this.cwd, ap);
|
|
35249
|
-
if (!(0,
|
|
35508
|
+
if (!(0, import_node_fs5.existsSync)(resolvedPath)) {
|
|
35250
35509
|
warnings.push(`Agent "${agent.name}" additionalPath "${ap}" resolves to "${resolvedPath}" which does not exist`);
|
|
35251
35510
|
}
|
|
35252
35511
|
}
|
|
@@ -37672,7 +37931,7 @@ DO NOT:
|
|
|
37672
37931
|
const { cmd, args } = _WorkflowRunner.buildNonInteractiveCommand(agentDef.cli, taskWithDeliverable, modelArgs);
|
|
37673
37932
|
const logsDir = this.getWorkerLogsDir();
|
|
37674
37933
|
const logPath = import_node_path8.default.join(logsDir, `${agentName}.log`);
|
|
37675
|
-
const logStream = (0,
|
|
37934
|
+
const logStream = (0, import_node_fs5.createWriteStream)(logPath, { flags: "a" });
|
|
37676
37935
|
this.registerWorker(agentName, agentDef.cli, step.task ?? "", void 0, false);
|
|
37677
37936
|
let stopHeartbeat;
|
|
37678
37937
|
if (this.relayApiKey) {
|
|
@@ -37808,7 +38067,7 @@ DO NOT:
|
|
|
37808
38067
|
const taskWithExit = step.task + (relayRegistrationNote ? "\n\n" + relayRegistrationNote : "") + (delegationGuidance ? "\n\n" + delegationGuidance + "\n" : "") + '\n\n---\nIMPORTANT: When you have fully completed this task, you MUST self-terminate by either: (a) calling remove_agent(name: "<your-agent-name>", reason: "task completed") \u2014 preferred, or (b) outputting the exact text "/exit" on its own line as a fallback. Do not wait for further input \u2014 terminate immediately after finishing. Do NOT spawn sub-agents unless the task explicitly requires it.';
|
|
37809
38068
|
this.ptyOutputBuffers.set(agentName, []);
|
|
37810
38069
|
const logsDir = this.getWorkerLogsDir();
|
|
37811
|
-
const logStream = (0,
|
|
38070
|
+
const logStream = (0, import_node_fs5.createWriteStream)(import_node_path8.default.join(logsDir, `${agentName}.log`), { flags: "a" });
|
|
37812
38071
|
this.ptyLogStreams.set(agentName, logStream);
|
|
37813
38072
|
this.ptyListeners.set(agentName, (chunk) => {
|
|
37814
38073
|
const stripped = _WorkflowRunner.stripAnsi(chunk);
|
|
@@ -37850,11 +38109,11 @@ DO NOT:
|
|
|
37850
38109
|
oldLogStream.end();
|
|
37851
38110
|
this.ptyLogStreams.delete(oldName);
|
|
37852
38111
|
try {
|
|
37853
|
-
(0,
|
|
38112
|
+
(0, import_node_fs5.renameSync)(oldLogPath, newLogPath);
|
|
37854
38113
|
} catch {
|
|
37855
38114
|
}
|
|
37856
38115
|
}
|
|
37857
|
-
const newLogStream = (0,
|
|
38116
|
+
const newLogStream = (0, import_node_fs5.createWriteStream)(newLogPath, { flags: "a" });
|
|
37858
38117
|
this.ptyLogStreams.set(agent.name, newLogStream);
|
|
37859
38118
|
const oldListener = this.ptyListeners.get(oldName);
|
|
37860
38119
|
if (oldListener) {
|
|
@@ -37959,7 +38218,7 @@ DO NOT:
|
|
|
37959
38218
|
output = ptyChunks.join("");
|
|
37960
38219
|
} else {
|
|
37961
38220
|
const summaryPath = import_node_path8.default.join(this.summaryDir, `${step.name}.md`);
|
|
37962
|
-
output = (0,
|
|
38221
|
+
output = (0, import_node_fs5.existsSync)(summaryPath) ? await (0, import_promises3.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (idle \u2014 treated as done)" : `Agent exited (${exitResult})`;
|
|
37963
38222
|
}
|
|
37964
38223
|
if (ptyChunks.length === 0) {
|
|
37965
38224
|
this.captureStepTerminalEvidence(evidenceStepName, { stdout: output, combined: output }, { exitCode: agent?.exitCode, exitSignal: agent?.exitSignal }, {
|
|
@@ -38210,7 +38469,7 @@ DO NOT:
|
|
|
38210
38469
|
case "exit_code":
|
|
38211
38470
|
break;
|
|
38212
38471
|
case "file_exists":
|
|
38213
|
-
if (!(0,
|
|
38472
|
+
if (!(0, import_node_fs5.existsSync)(import_node_path8.default.resolve(this.cwd, check2.value))) {
|
|
38214
38473
|
return fail(`Verification failed for "${stepName}": file "${check2.value}" does not exist`);
|
|
38215
38474
|
}
|
|
38216
38475
|
break;
|
|
@@ -38549,10 +38808,10 @@ ${excerpt}` : "";
|
|
|
38549
38808
|
}
|
|
38550
38809
|
// ── ID generation ─────────────────────────────────────────────────────
|
|
38551
38810
|
generateId() {
|
|
38552
|
-
return (0,
|
|
38811
|
+
return (0, import_node_crypto5.randomBytes)(12).toString("hex");
|
|
38553
38812
|
}
|
|
38554
38813
|
generateShortId() {
|
|
38555
|
-
return (0,
|
|
38814
|
+
return (0, import_node_crypto5.randomBytes)(4).toString("hex");
|
|
38556
38815
|
}
|
|
38557
38816
|
/** Strip ANSI escape codes from terminal output — delegates to pty.ts canonical regex. */
|
|
38558
38817
|
static stripAnsi(text) {
|
|
@@ -38653,7 +38912,7 @@ ${excerpt}` : "";
|
|
|
38653
38912
|
const outputPath = import_node_path8.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
|
|
38654
38913
|
try {
|
|
38655
38914
|
const dir = this.getStepOutputDir(runId);
|
|
38656
|
-
(0,
|
|
38915
|
+
(0, import_node_fs5.mkdirSync)(dir, { recursive: true });
|
|
38657
38916
|
const cleaned = _WorkflowRunner.stripAnsi(output);
|
|
38658
38917
|
await (0, import_promises3.writeFile)(outputPath, cleaned);
|
|
38659
38918
|
} catch {
|
|
@@ -38679,9 +38938,9 @@ ${preview}
|
|
|
38679
38938
|
loadStepOutput(runId, stepName) {
|
|
38680
38939
|
try {
|
|
38681
38940
|
const filePath = import_node_path8.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
|
|
38682
|
-
if (!(0,
|
|
38941
|
+
if (!(0, import_node_fs5.existsSync)(filePath))
|
|
38683
38942
|
return void 0;
|
|
38684
|
-
return (0,
|
|
38943
|
+
return (0, import_node_fs5.readFileSync)(filePath, "utf-8");
|
|
38685
38944
|
} catch {
|
|
38686
38945
|
return void 0;
|
|
38687
38946
|
}
|
|
@@ -38689,7 +38948,7 @@ ${preview}
|
|
|
38689
38948
|
/** Get or create the worker logs directory (.agent-relay/team/worker-logs) */
|
|
38690
38949
|
getWorkerLogsDir() {
|
|
38691
38950
|
const logsDir = import_node_path8.default.join(this.cwd, ".agent-relay", "team", "worker-logs");
|
|
38692
|
-
(0,
|
|
38951
|
+
(0, import_node_fs5.mkdirSync)(logsDir, { recursive: true });
|
|
38693
38952
|
return logsDir;
|
|
38694
38953
|
}
|
|
38695
38954
|
/** Register a spawned agent in workers.json so `agents:kill` can find it. */
|
|
@@ -38705,7 +38964,7 @@ ${preview}
|
|
|
38705
38964
|
this.activeWorkers.set(agentName, workerEntry);
|
|
38706
38965
|
this.workersFileLock = this.workersFileLock.then(() => {
|
|
38707
38966
|
try {
|
|
38708
|
-
(0,
|
|
38967
|
+
(0, import_node_fs5.mkdirSync)(import_node_path8.default.dirname(this.workersPath), { recursive: true });
|
|
38709
38968
|
const existing = this.readWorkers().filter((w) => w.name !== agentName);
|
|
38710
38969
|
existing.push({ name: agentName, ...workerEntry });
|
|
38711
38970
|
this.writeWorkers(existing);
|
|
@@ -38727,21 +38986,21 @@ ${preview}
|
|
|
38727
38986
|
}
|
|
38728
38987
|
readWorkers() {
|
|
38729
38988
|
try {
|
|
38730
|
-
if (!(0,
|
|
38989
|
+
if (!(0, import_node_fs5.existsSync)(this.workersPath))
|
|
38731
38990
|
return [];
|
|
38732
|
-
const raw = JSON.parse((0,
|
|
38991
|
+
const raw = JSON.parse((0, import_node_fs5.readFileSync)(this.workersPath, "utf-8"));
|
|
38733
38992
|
return Array.isArray(raw?.workers) ? raw.workers : [];
|
|
38734
38993
|
} catch {
|
|
38735
38994
|
return [];
|
|
38736
38995
|
}
|
|
38737
38996
|
}
|
|
38738
38997
|
writeWorkers(workers) {
|
|
38739
|
-
(0,
|
|
38998
|
+
(0, import_node_fs5.writeFileSync)(this.workersPath, JSON.stringify({ workers }, null, 2));
|
|
38740
38999
|
}
|
|
38741
39000
|
};
|
|
38742
39001
|
|
|
38743
39002
|
// packages/sdk/dist/workflows/file-db.js
|
|
38744
|
-
var
|
|
39003
|
+
var import_node_fs6 = require("node:fs");
|
|
38745
39004
|
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
38746
39005
|
var JsonFileWorkflowDb = class {
|
|
38747
39006
|
filePath;
|
|
@@ -38751,7 +39010,7 @@ var JsonFileWorkflowDb = class {
|
|
|
38751
39010
|
this.filePath = filePath;
|
|
38752
39011
|
let writable = false;
|
|
38753
39012
|
try {
|
|
38754
|
-
(0,
|
|
39013
|
+
(0, import_node_fs6.mkdirSync)(import_node_path9.default.dirname(filePath), { recursive: true });
|
|
38755
39014
|
writable = true;
|
|
38756
39015
|
} catch {
|
|
38757
39016
|
}
|
|
@@ -38766,7 +39025,7 @@ var JsonFileWorkflowDb = class {
|
|
|
38766
39025
|
if (!this.writable)
|
|
38767
39026
|
return;
|
|
38768
39027
|
try {
|
|
38769
|
-
(0,
|
|
39028
|
+
(0, import_node_fs6.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
38770
39029
|
} catch {
|
|
38771
39030
|
}
|
|
38772
39031
|
}
|
|
@@ -38776,7 +39035,7 @@ var JsonFileWorkflowDb = class {
|
|
|
38776
39035
|
const steps = /* @__PURE__ */ new Map();
|
|
38777
39036
|
let raw = "";
|
|
38778
39037
|
try {
|
|
38779
|
-
raw = (0,
|
|
39038
|
+
raw = (0, import_node_fs6.readFileSync)(this.filePath, "utf8");
|
|
38780
39039
|
} catch {
|
|
38781
39040
|
return { runs, steps };
|
|
38782
39041
|
}
|
|
@@ -39088,7 +39347,7 @@ function workflow(name) {
|
|
|
39088
39347
|
}
|
|
39089
39348
|
|
|
39090
39349
|
// packages/sdk/dist/workflows/coordinator.js
|
|
39091
|
-
var
|
|
39350
|
+
var import_node_crypto6 = require("node:crypto");
|
|
39092
39351
|
var import_node_events3 = require("node:events");
|
|
39093
39352
|
var PATTERN_HEURISTICS = [
|
|
39094
39353
|
// ── Dependency-based patterns (highest priority) ──────────────────────
|
|
@@ -39443,7 +39702,7 @@ var SwarmCoordinator = class extends import_node_events3.EventEmitter {
|
|
|
39443
39702
|
}
|
|
39444
39703
|
// ── Lifecycle: create run ───────────────────────────────────────────────
|
|
39445
39704
|
async createRun(workspaceId, config2) {
|
|
39446
|
-
const id = `run_${Date.now()}_${(0,
|
|
39705
|
+
const id = `run_${Date.now()}_${(0, import_node_crypto6.randomBytes)(4).toString("hex")}`;
|
|
39447
39706
|
const pattern = this.selectPattern(config2);
|
|
39448
39707
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
39449
39708
|
const { rows } = await this.db.query(`INSERT INTO workflow_runs (id, workspace_id, workflow_name, pattern, status, config, started_at, created_at, updated_at)
|
|
@@ -39482,7 +39741,7 @@ var SwarmCoordinator = class extends import_node_events3.EventEmitter {
|
|
|
39482
39741
|
const created = [];
|
|
39483
39742
|
for (const wf of workflows) {
|
|
39484
39743
|
for (const step of wf.steps) {
|
|
39485
|
-
const id = `step_${Date.now()}_${(0,
|
|
39744
|
+
const id = `step_${Date.now()}_${(0, import_node_crypto6.randomBytes)(4).toString("hex")}`;
|
|
39486
39745
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
39487
39746
|
const { rows } = await this.db.query(`INSERT INTO workflow_steps (id, run_id, step_name, agent_name, status, task, depends_on, created_at, updated_at)
|
|
39488
39747
|
VALUES ($1, $2, $3, $4, 'pending', $5, $6, $7, $7)
|
|
@@ -39659,7 +39918,7 @@ var SwarmCoordinator = class extends import_node_events3.EventEmitter {
|
|
|
39659
39918
|
};
|
|
39660
39919
|
|
|
39661
39920
|
// packages/sdk/dist/workflows/barrier.js
|
|
39662
|
-
var
|
|
39921
|
+
var import_node_crypto7 = require("node:crypto");
|
|
39663
39922
|
var import_node_events4 = require("node:events");
|
|
39664
39923
|
var BarrierManager = class extends import_node_events4.EventEmitter {
|
|
39665
39924
|
db;
|
|
@@ -39675,7 +39934,7 @@ var BarrierManager = class extends import_node_events4.EventEmitter {
|
|
|
39675
39934
|
* Create a barrier for a workflow run.
|
|
39676
39935
|
*/
|
|
39677
39936
|
async createBarrier(runId, definition) {
|
|
39678
|
-
const id = `bar_${Date.now()}_${(0,
|
|
39937
|
+
const id = `bar_${Date.now()}_${(0, import_node_crypto7.randomBytes)(4).toString("hex")}`;
|
|
39679
39938
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
39680
39939
|
const mode = definition.mode ?? "all";
|
|
39681
39940
|
const { rows } = await this.db.query(`INSERT INTO workflow_barriers (id, run_id, barrier_name, wait_for, resolved, is_satisfied, timeout_ms, created_at, updated_at)
|
|
@@ -39809,7 +40068,7 @@ var BarrierManager = class extends import_node_events4.EventEmitter {
|
|
|
39809
40068
|
};
|
|
39810
40069
|
|
|
39811
40070
|
// packages/sdk/dist/workflows/state.js
|
|
39812
|
-
var
|
|
40071
|
+
var import_node_crypto8 = require("node:crypto");
|
|
39813
40072
|
var import_node_events5 = require("node:events");
|
|
39814
40073
|
var StateStore = class extends import_node_events5.EventEmitter {
|
|
39815
40074
|
db;
|
|
@@ -39852,7 +40111,7 @@ var StateStore = class extends import_node_events5.EventEmitter {
|
|
|
39852
40111
|
const namespace = options.namespace ?? this.defaultNamespace;
|
|
39853
40112
|
const ttlMs = options.ttlMs ?? this.defaultTtlMs;
|
|
39854
40113
|
const expiresAt = ttlMs ? new Date(Date.now() + ttlMs).toISOString() : null;
|
|
39855
|
-
const id = `st_${Date.now()}_${(0,
|
|
40114
|
+
const id = `st_${Date.now()}_${(0, import_node_crypto8.randomBytes)(4).toString("hex")}`;
|
|
39856
40115
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
39857
40116
|
const { rows } = await this.db.query(`INSERT INTO swarm_state (id, run_id, namespace, key, value, expires_at, created_at, updated_at)
|
|
39858
40117
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $7)
|
|
@@ -39940,7 +40199,7 @@ var StateStore = class extends import_node_events5.EventEmitter {
|
|
|
39940
40199
|
};
|
|
39941
40200
|
|
|
39942
40201
|
// packages/sdk/dist/workflows/templates.js
|
|
39943
|
-
var
|
|
40202
|
+
var import_node_fs7 = require("node:fs");
|
|
39944
40203
|
var import_node_path10 = __toESM(require("node:path"), 1);
|
|
39945
40204
|
var import_node_url2 = require("node:url");
|
|
39946
40205
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
@@ -40044,9 +40303,9 @@ var TemplateRegistry = class {
|
|
|
40044
40303
|
throw new Error(`Invalid template name: "${templateName}" contains path separators or traversal sequences`);
|
|
40045
40304
|
}
|
|
40046
40305
|
this.validateRelayConfig(parsed, url2);
|
|
40047
|
-
await
|
|
40306
|
+
await import_node_fs7.promises.mkdir(this.customTemplatesDir, { recursive: true });
|
|
40048
40307
|
const targetPath = import_node_path10.default.join(this.customTemplatesDir, `${templateName}.yaml`);
|
|
40049
|
-
await
|
|
40308
|
+
await import_node_fs7.promises.writeFile(targetPath, (0, import_yaml4.stringify)(parsed), "utf-8");
|
|
40050
40309
|
return targetPath;
|
|
40051
40310
|
}
|
|
40052
40311
|
isTemplateShorthand(input) {
|
|
@@ -40075,7 +40334,7 @@ var TemplateRegistry = class {
|
|
|
40075
40334
|
import_node_path10.default.resolve(currentDir, "../workflows/builtin-templates")
|
|
40076
40335
|
];
|
|
40077
40336
|
for (const candidate of candidates) {
|
|
40078
|
-
if ((0,
|
|
40337
|
+
if ((0, import_node_fs7.existsSync)(candidate)) {
|
|
40079
40338
|
return candidate;
|
|
40080
40339
|
}
|
|
40081
40340
|
}
|
|
@@ -40097,7 +40356,7 @@ var TemplateRegistry = class {
|
|
|
40097
40356
|
for (const ext of YAML_EXTENSIONS) {
|
|
40098
40357
|
const candidate = import_node_path10.default.join(directory, `${templateName}${ext}`);
|
|
40099
40358
|
try {
|
|
40100
|
-
const stat2 = await
|
|
40359
|
+
const stat2 = await import_node_fs7.promises.stat(candidate);
|
|
40101
40360
|
if (stat2.isFile()) {
|
|
40102
40361
|
return candidate;
|
|
40103
40362
|
}
|
|
@@ -40107,7 +40366,7 @@ var TemplateRegistry = class {
|
|
|
40107
40366
|
return void 0;
|
|
40108
40367
|
}
|
|
40109
40368
|
async readTemplateFile(templatePath) {
|
|
40110
|
-
const raw = await
|
|
40369
|
+
const raw = await import_node_fs7.promises.readFile(templatePath, "utf-8");
|
|
40111
40370
|
const parsed = (0, import_yaml4.parse)(raw);
|
|
40112
40371
|
if (!isRecord(parsed)) {
|
|
40113
40372
|
throw new Error(`Template at ${templatePath} is not a YAML object`);
|
|
@@ -40300,7 +40559,7 @@ var TemplateRegistry = class {
|
|
|
40300
40559
|
}
|
|
40301
40560
|
async safeReadDir(directory) {
|
|
40302
40561
|
try {
|
|
40303
|
-
return await
|
|
40562
|
+
return await import_node_fs7.promises.readdir(directory);
|
|
40304
40563
|
} catch {
|
|
40305
40564
|
return [];
|
|
40306
40565
|
}
|
|
@@ -40464,7 +40723,7 @@ function isValidAgentName(name) {
|
|
|
40464
40723
|
}
|
|
40465
40724
|
|
|
40466
40725
|
// packages/utils/dist/logger.js
|
|
40467
|
-
var
|
|
40726
|
+
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
40468
40727
|
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
40469
40728
|
function getLogFile() {
|
|
40470
40729
|
return process.env.AGENT_RELAY_LOG_FILE;
|
|
@@ -40484,8 +40743,8 @@ var LEVEL_PRIORITY = {
|
|
|
40484
40743
|
var createdLogDirs = /* @__PURE__ */ new Set();
|
|
40485
40744
|
function ensureLogDir(logFile) {
|
|
40486
40745
|
const logDir = import_node_path11.default.dirname(logFile);
|
|
40487
|
-
if (!createdLogDirs.has(logDir) && !
|
|
40488
|
-
|
|
40746
|
+
if (!createdLogDirs.has(logDir) && !import_node_fs8.default.existsSync(logDir)) {
|
|
40747
|
+
import_node_fs8.default.mkdirSync(logDir, { recursive: true });
|
|
40489
40748
|
createdLogDirs.add(logDir);
|
|
40490
40749
|
}
|
|
40491
40750
|
}
|
|
@@ -40514,7 +40773,7 @@ function log(level, component, msg, extra) {
|
|
|
40514
40773
|
const logFile = getLogFile();
|
|
40515
40774
|
if (logFile) {
|
|
40516
40775
|
ensureLogDir(logFile);
|
|
40517
|
-
|
|
40776
|
+
import_node_fs8.default.appendFileSync(logFile, formatted + "\n");
|
|
40518
40777
|
return;
|
|
40519
40778
|
}
|
|
40520
40779
|
if (level === "ERROR" || level === "WARN") {
|
|
@@ -40785,7 +41044,7 @@ function benchmarkPatterns(iterations = 1e4) {
|
|
|
40785
41044
|
|
|
40786
41045
|
// packages/utils/dist/command-resolver.js
|
|
40787
41046
|
var import_node_child_process4 = require("node:child_process");
|
|
40788
|
-
var
|
|
41047
|
+
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
40789
41048
|
function resolveCommand(command) {
|
|
40790
41049
|
if (command.startsWith("/")) {
|
|
40791
41050
|
return resolveSymlinks(command);
|
|
@@ -40811,7 +41070,7 @@ function resolveCommand(command) {
|
|
|
40811
41070
|
}
|
|
40812
41071
|
function resolveSymlinks(filePath) {
|
|
40813
41072
|
try {
|
|
40814
|
-
const resolved =
|
|
41073
|
+
const resolved = import_node_fs9.default.realpathSync(filePath);
|
|
40815
41074
|
if (resolved !== filePath && process.env.DEBUG_SPAWN === "1") {
|
|
40816
41075
|
console.log(`[command-resolver] Resolved symlink: ${filePath} -> ${resolved}`);
|
|
40817
41076
|
}
|
|
@@ -40836,7 +41095,7 @@ function commandExists(command) {
|
|
|
40836
41095
|
}
|
|
40837
41096
|
|
|
40838
41097
|
// packages/utils/dist/git-remote.js
|
|
40839
|
-
var
|
|
41098
|
+
var fs6 = __toESM(require("node:fs"), 1);
|
|
40840
41099
|
var path11 = __toESM(require("node:path"), 1);
|
|
40841
41100
|
var import_node_child_process5 = require("node:child_process");
|
|
40842
41101
|
function parseGitRemoteUrl(url2) {
|
|
@@ -40855,7 +41114,7 @@ function parseGitRemoteUrl(url2) {
|
|
|
40855
41114
|
function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
|
|
40856
41115
|
try {
|
|
40857
41116
|
const gitDir = path11.join(workingDirectory, ".git");
|
|
40858
|
-
if (!
|
|
41117
|
+
if (!fs6.existsSync(gitDir)) {
|
|
40859
41118
|
return null;
|
|
40860
41119
|
}
|
|
40861
41120
|
const result = (0, import_node_child_process5.execSync)(`git remote get-url ${remoteName}`, {
|
|
@@ -40868,10 +41127,10 @@ function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
|
|
|
40868
41127
|
} catch {
|
|
40869
41128
|
try {
|
|
40870
41129
|
const configPath = path11.join(workingDirectory, ".git", "config");
|
|
40871
|
-
if (!
|
|
41130
|
+
if (!fs6.existsSync(configPath)) {
|
|
40872
41131
|
return null;
|
|
40873
41132
|
}
|
|
40874
|
-
const config2 =
|
|
41133
|
+
const config2 = fs6.readFileSync(configPath, "utf-8");
|
|
40875
41134
|
const remoteSection = new RegExp(`\\[remote\\s+"${remoteName}"\\][^\\[]*url\\s*=\\s*([^\\n]+)`, "i");
|
|
40876
41135
|
const match = config2.match(remoteSection);
|
|
40877
41136
|
return match?.[1]?.trim() || null;
|
|
@@ -40891,7 +41150,7 @@ function findGitRoot(startPath) {
|
|
|
40891
41150
|
let currentPath = path11.resolve(startPath);
|
|
40892
41151
|
const root = path11.parse(currentPath).root;
|
|
40893
41152
|
while (currentPath !== root) {
|
|
40894
|
-
if (
|
|
41153
|
+
if (fs6.existsSync(path11.join(currentPath, ".git"))) {
|
|
40895
41154
|
return currentPath;
|
|
40896
41155
|
}
|
|
40897
41156
|
currentPath = path11.dirname(currentPath);
|
|
@@ -40911,7 +41170,7 @@ function getRepoFullNameFromPath(workingDirectory) {
|
|
|
40911
41170
|
}
|
|
40912
41171
|
|
|
40913
41172
|
// packages/utils/dist/update-checker.js
|
|
40914
|
-
var
|
|
41173
|
+
var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
40915
41174
|
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
40916
41175
|
var import_node_https = __toESM(require("node:https"), 1);
|
|
40917
41176
|
var import_node_os4 = __toESM(require("node:os"), 1);
|
|
@@ -40926,9 +41185,9 @@ function getCachePath() {
|
|
|
40926
41185
|
function readCache() {
|
|
40927
41186
|
try {
|
|
40928
41187
|
const cachePath = getCachePath();
|
|
40929
|
-
if (!
|
|
41188
|
+
if (!import_node_fs10.default.existsSync(cachePath))
|
|
40930
41189
|
return null;
|
|
40931
|
-
const data =
|
|
41190
|
+
const data = import_node_fs10.default.readFileSync(cachePath, "utf-8");
|
|
40932
41191
|
return JSON.parse(data);
|
|
40933
41192
|
} catch {
|
|
40934
41193
|
return null;
|
|
@@ -40938,10 +41197,10 @@ function writeCache(cache) {
|
|
|
40938
41197
|
try {
|
|
40939
41198
|
const cachePath = getCachePath();
|
|
40940
41199
|
const cacheDir = import_node_path12.default.dirname(cachePath);
|
|
40941
|
-
if (!
|
|
40942
|
-
|
|
41200
|
+
if (!import_node_fs10.default.existsSync(cacheDir)) {
|
|
41201
|
+
import_node_fs10.default.mkdirSync(cacheDir, { recursive: true });
|
|
40943
41202
|
}
|
|
40944
|
-
|
|
41203
|
+
import_node_fs10.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
|
|
40945
41204
|
} catch {
|
|
40946
41205
|
}
|
|
40947
41206
|
}
|
|
@@ -41059,10 +41318,10 @@ function checkForUpdatesInBackground(currentVersion) {
|
|
|
41059
41318
|
}
|
|
41060
41319
|
|
|
41061
41320
|
// packages/utils/dist/error-tracking.js
|
|
41062
|
-
var
|
|
41321
|
+
var import_node_crypto9 = require("node:crypto");
|
|
41063
41322
|
function generateErrorId() {
|
|
41064
41323
|
const timestamp = Math.floor(Date.now() / 1e3);
|
|
41065
|
-
const random = (0,
|
|
41324
|
+
const random = (0, import_node_crypto9.randomBytes)(2).toString("hex");
|
|
41066
41325
|
return `ERR-${timestamp}-${random}`;
|
|
41067
41326
|
}
|
|
41068
41327
|
function createTraceableError(message, context = {}, originalError) {
|
|
@@ -41220,7 +41479,7 @@ function validateModelForCli(cli, model) {
|
|
|
41220
41479
|
}
|
|
41221
41480
|
|
|
41222
41481
|
// packages/utils/dist/relay-pty-path.js
|
|
41223
|
-
var
|
|
41482
|
+
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
41224
41483
|
var import_node_os5 = __toESM(require("node:os"), 1);
|
|
41225
41484
|
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
41226
41485
|
var SUPPORTED_PLATFORMS = {
|
|
@@ -41281,12 +41540,12 @@ function findRelayPtyBinary(callerDirname) {
|
|
|
41281
41540
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
41282
41541
|
if (home) {
|
|
41283
41542
|
const npxCacheBase = import_node_path13.default.join(home, ".npm", "_npx");
|
|
41284
|
-
if (
|
|
41543
|
+
if (import_node_fs11.default.existsSync(npxCacheBase)) {
|
|
41285
41544
|
try {
|
|
41286
|
-
const entries =
|
|
41545
|
+
const entries = import_node_fs11.default.readdirSync(npxCacheBase);
|
|
41287
41546
|
for (const entry of entries) {
|
|
41288
41547
|
const npxPackage = import_node_path13.default.join(npxCacheBase, entry, "node_modules", "agent-relay");
|
|
41289
|
-
if (
|
|
41548
|
+
if (import_node_fs11.default.existsSync(npxPackage)) {
|
|
41290
41549
|
packageRoots.push(npxPackage);
|
|
41291
41550
|
}
|
|
41292
41551
|
}
|
|
@@ -41344,7 +41603,7 @@ function findRelayPtyBinary(callerDirname) {
|
|
|
41344
41603
|
}
|
|
41345
41604
|
function isExecutable(filePath) {
|
|
41346
41605
|
try {
|
|
41347
|
-
|
|
41606
|
+
import_node_fs11.default.accessSync(filePath, import_node_fs11.default.constants.X_OK);
|
|
41348
41607
|
return true;
|
|
41349
41608
|
} catch {
|
|
41350
41609
|
return false;
|
|
@@ -41353,9 +41612,9 @@ function isExecutable(filePath) {
|
|
|
41353
41612
|
function isPlatformCompatibleBinary(filePath) {
|
|
41354
41613
|
let fd;
|
|
41355
41614
|
try {
|
|
41356
|
-
fd =
|
|
41615
|
+
fd = import_node_fs11.default.openSync(filePath, "r");
|
|
41357
41616
|
const header = Buffer.alloc(4);
|
|
41358
|
-
const bytesRead =
|
|
41617
|
+
const bytesRead = import_node_fs11.default.readSync(fd, header, 0, 4, 0);
|
|
41359
41618
|
if (bytesRead < 4) {
|
|
41360
41619
|
return false;
|
|
41361
41620
|
}
|
|
@@ -41373,7 +41632,7 @@ function isPlatformCompatibleBinary(filePath) {
|
|
|
41373
41632
|
} finally {
|
|
41374
41633
|
if (fd !== void 0) {
|
|
41375
41634
|
try {
|
|
41376
|
-
|
|
41635
|
+
import_node_fs11.default.closeSync(fd);
|
|
41377
41636
|
} catch {
|
|
41378
41637
|
}
|
|
41379
41638
|
}
|
|
@@ -41404,7 +41663,7 @@ function clearBinaryCache() {
|
|
|
41404
41663
|
|
|
41405
41664
|
// packages/utils/dist/client-helpers.js
|
|
41406
41665
|
var import_node_net = require("node:net");
|
|
41407
|
-
var
|
|
41666
|
+
var import_node_crypto10 = require("node:crypto");
|
|
41408
41667
|
|
|
41409
41668
|
// packages/utils/dist/legacy-protocol.js
|
|
41410
41669
|
var PROTOCOL_VERSION2 = 1;
|
|
@@ -41531,14 +41790,14 @@ function createRequestHandler(socketPath, envelope, options) {
|
|
|
41531
41790
|
});
|
|
41532
41791
|
}
|
|
41533
41792
|
function generateRequestId(prefix = "") {
|
|
41534
|
-
return `${prefix}${Date.now().toString(36)}-${(0,
|
|
41793
|
+
return `${prefix}${Date.now().toString(36)}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
|
|
41535
41794
|
}
|
|
41536
41795
|
|
|
41537
41796
|
// packages/hooks/dist/types.js
|
|
41538
41797
|
var HOOK_ABI_VERSION = PROTOCOL_VERSION;
|
|
41539
41798
|
|
|
41540
41799
|
// packages/hooks/dist/registry.js
|
|
41541
|
-
var
|
|
41800
|
+
var import_node_crypto12 = require("node:crypto");
|
|
41542
41801
|
var InMemoryHookMemory = class {
|
|
41543
41802
|
store = /* @__PURE__ */ new Map();
|
|
41544
41803
|
get(key) {
|
|
@@ -41587,8 +41846,8 @@ var HookRegistry = class {
|
|
|
41587
41846
|
injectFn;
|
|
41588
41847
|
sendFn;
|
|
41589
41848
|
constructor(options = {}) {
|
|
41590
|
-
this.sessionId = (0,
|
|
41591
|
-
this.agentId = options.agentId ?? (0,
|
|
41849
|
+
this.sessionId = (0, import_node_crypto12.randomUUID)();
|
|
41850
|
+
this.agentId = options.agentId ?? (0, import_node_crypto12.randomUUID)();
|
|
41592
41851
|
this.agentName = options.agentName ?? "agent";
|
|
41593
41852
|
this.workingDir = options.workingDir ?? process.cwd();
|
|
41594
41853
|
this.projectId = options.projectId ?? "default";
|
|
@@ -41992,9 +42251,9 @@ var HookRegistry = class {
|
|
|
41992
42251
|
var import_node_child_process6 = require("node:child_process");
|
|
41993
42252
|
|
|
41994
42253
|
// packages/config/dist/project-namespace.js
|
|
41995
|
-
var
|
|
42254
|
+
var import_node_crypto13 = __toESM(require("node:crypto"), 1);
|
|
41996
42255
|
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
41997
|
-
var
|
|
42256
|
+
var import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
41998
42257
|
var import_node_os6 = __toESM(require("node:os"), 1);
|
|
41999
42258
|
function getGlobalBaseDir2() {
|
|
42000
42259
|
if (process.env.AGENT_RELAY_DATA_DIR) {
|
|
@@ -42007,13 +42266,13 @@ function getGlobalBaseDir2() {
|
|
|
42007
42266
|
return import_node_path14.default.join(import_node_os6.default.homedir(), ".agent-relay");
|
|
42008
42267
|
}
|
|
42009
42268
|
var GLOBAL_BASE_DIR2 = getGlobalBaseDir2();
|
|
42010
|
-
var
|
|
42011
|
-
function
|
|
42269
|
+
var PROJECT_DATA_DIR2 = ".agent-relay";
|
|
42270
|
+
function hashPath2(projectPath) {
|
|
42012
42271
|
const normalized = import_node_path14.default.resolve(projectPath);
|
|
42013
|
-
const hash2 =
|
|
42272
|
+
const hash2 = import_node_crypto13.default.createHash("sha256").update(normalized).digest("hex");
|
|
42014
42273
|
return hash2.substring(0, 12);
|
|
42015
42274
|
}
|
|
42016
|
-
function
|
|
42275
|
+
function findProjectRoot2(startDir = process.cwd()) {
|
|
42017
42276
|
if (process.env.AGENT_RELAY_PROJECT) {
|
|
42018
42277
|
return import_node_path14.default.resolve(process.env.AGENT_RELAY_PROJECT);
|
|
42019
42278
|
}
|
|
@@ -42022,7 +42281,7 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
42022
42281
|
const markers = [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".agent-relay"];
|
|
42023
42282
|
while (current !== root) {
|
|
42024
42283
|
for (const marker of markers) {
|
|
42025
|
-
if (
|
|
42284
|
+
if (import_node_fs12.default.existsSync(import_node_path14.default.join(current, marker))) {
|
|
42026
42285
|
return current;
|
|
42027
42286
|
}
|
|
42028
42287
|
}
|
|
@@ -42031,9 +42290,9 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
42031
42290
|
return import_node_path14.default.resolve(startDir);
|
|
42032
42291
|
}
|
|
42033
42292
|
function getProjectPaths2(projectRoot) {
|
|
42034
|
-
const root = projectRoot ??
|
|
42035
|
-
const projectId =
|
|
42036
|
-
const dataDir = import_node_path14.default.join(root,
|
|
42293
|
+
const root = projectRoot ?? findProjectRoot2();
|
|
42294
|
+
const projectId = hashPath2(root);
|
|
42295
|
+
const dataDir = import_node_path14.default.join(root, PROJECT_DATA_DIR2);
|
|
42037
42296
|
return {
|
|
42038
42297
|
dataDir,
|
|
42039
42298
|
teamDir: import_node_path14.default.join(dataDir, "team"),
|
|
@@ -42045,10 +42304,10 @@ function getProjectPaths2(projectRoot) {
|
|
|
42045
42304
|
}
|
|
42046
42305
|
|
|
42047
42306
|
// packages/config/dist/trajectory-config.js
|
|
42048
|
-
var
|
|
42307
|
+
var import_node_fs13 = require("node:fs");
|
|
42049
42308
|
var import_node_path15 = require("node:path");
|
|
42050
42309
|
var import_node_os7 = require("node:os");
|
|
42051
|
-
var
|
|
42310
|
+
var import_node_crypto14 = require("node:crypto");
|
|
42052
42311
|
function getAgentRelayConfigDir() {
|
|
42053
42312
|
return process.env.AGENT_RELAY_CONFIG_DIR ?? (0, import_node_path15.join)((0, import_node_os7.homedir)(), ".config", "agent-relay");
|
|
42054
42313
|
}
|
|
@@ -42060,7 +42319,7 @@ function readRelayConfig(projectRoot) {
|
|
|
42060
42319
|
const configPath = getRelayConfigPath(projectRoot);
|
|
42061
42320
|
if (configCache && configCache.path === configPath) {
|
|
42062
42321
|
try {
|
|
42063
|
-
const stat2 = (0,
|
|
42322
|
+
const stat2 = (0, import_node_fs13.statSync)(configPath);
|
|
42064
42323
|
if (stat2.mtimeMs === configCache.mtime) {
|
|
42065
42324
|
return configCache.config;
|
|
42066
42325
|
}
|
|
@@ -42068,13 +42327,13 @@ function readRelayConfig(projectRoot) {
|
|
|
42068
42327
|
}
|
|
42069
42328
|
}
|
|
42070
42329
|
try {
|
|
42071
|
-
if (!(0,
|
|
42330
|
+
if (!(0, import_node_fs13.existsSync)(configPath)) {
|
|
42072
42331
|
return {};
|
|
42073
42332
|
}
|
|
42074
|
-
const content = (0,
|
|
42333
|
+
const content = (0, import_node_fs13.readFileSync)(configPath, "utf-8");
|
|
42075
42334
|
const config2 = JSON.parse(content);
|
|
42076
42335
|
try {
|
|
42077
|
-
const stat2 = (0,
|
|
42336
|
+
const stat2 = (0, import_node_fs13.statSync)(configPath);
|
|
42078
42337
|
configCache = { path: configPath, config: config2, mtime: stat2.mtimeMs };
|
|
42079
42338
|
} catch {
|
|
42080
42339
|
}
|
|
@@ -42090,7 +42349,7 @@ function shouldStoreInRepo(projectRoot) {
|
|
|
42090
42349
|
}
|
|
42091
42350
|
function getProjectHash(projectRoot) {
|
|
42092
42351
|
const root = projectRoot ?? getProjectPaths2().projectRoot;
|
|
42093
|
-
return (0,
|
|
42352
|
+
return (0, import_node_crypto14.createHash)("sha256").update(root).digest("hex").slice(0, 16);
|
|
42094
42353
|
}
|
|
42095
42354
|
function getUserTrajectoriesDir(projectRoot) {
|
|
42096
42355
|
const projectHash = getProjectHash(projectRoot);
|
|
@@ -42739,7 +42998,7 @@ var HookEmitter = class {
|
|
|
42739
42998
|
};
|
|
42740
42999
|
|
|
42741
43000
|
// packages/hooks/dist/inbox-check/utils.js
|
|
42742
|
-
var
|
|
43001
|
+
var import_node_fs14 = require("node:fs");
|
|
42743
43002
|
var import_node_path16 = require("node:path");
|
|
42744
43003
|
var DEFAULT_INBOX_DIR = "/tmp/agent-relay";
|
|
42745
43004
|
function getAgentName() {
|
|
@@ -42753,13 +43012,13 @@ function getInboxPath(config2) {
|
|
|
42753
43012
|
return (0, import_node_path16.join)(config2.inboxDir, agentName, "inbox.md");
|
|
42754
43013
|
}
|
|
42755
43014
|
function inboxExists(inboxPath) {
|
|
42756
|
-
return (0,
|
|
43015
|
+
return (0, import_node_fs14.existsSync)(inboxPath);
|
|
42757
43016
|
}
|
|
42758
43017
|
function readInbox(inboxPath) {
|
|
42759
43018
|
if (!inboxExists(inboxPath)) {
|
|
42760
43019
|
return "";
|
|
42761
43020
|
}
|
|
42762
|
-
return (0,
|
|
43021
|
+
return (0, import_node_fs14.readFileSync)(inboxPath, "utf-8");
|
|
42763
43022
|
}
|
|
42764
43023
|
function hasUnreadMessages(inboxPath) {
|
|
42765
43024
|
const content = readInbox(inboxPath);
|
|
@@ -42846,6 +43105,7 @@ init_dist();
|
|
|
42846
43105
|
HOOK_ABI_VERSION,
|
|
42847
43106
|
HookEmitter,
|
|
42848
43107
|
HookRegistry,
|
|
43108
|
+
HttpAgentRelayClient,
|
|
42849
43109
|
InMemoryAdapter,
|
|
42850
43110
|
InMemoryWorkflowDb,
|
|
42851
43111
|
JsonFileWorkflowDb,
|