@bastani/atomic 0.9.54-alpha.1 → 0.9.55-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/builtin/intercom/CHANGELOG.md +14 -0
- package/dist/builtin/intercom/README.md +2 -1
- package/dist/builtin/intercom/broker/announce-on-import.ts +5 -0
- package/dist/builtin/intercom/broker/broker.ts +28 -0
- package/dist/builtin/intercom/broker/client.ts +48 -3
- package/dist/builtin/intercom/broker/paths.ts +9 -0
- package/dist/builtin/intercom/broker/socket-writes.ts +5 -0
- package/dist/builtin/intercom/broker/spawn.ts +58 -6
- package/dist/builtin/intercom/broker/start-announcement.ts +77 -0
- package/dist/builtin/intercom/broker/startup-timeout.ts +23 -0
- package/dist/builtin/intercom/index.bundle.mjs +184 -73
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/recoverable-disconnect.ts +38 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +26 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +8458 -7874
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +687 -111
- package/dist/builtin/workflows/src/index.js +834 -264
- package/dist/builtin/workflows/src/local-worker-entry.mjs +687 -111
- package/dist/builtin/workflows/src/workers/public-options.d.ts +8 -0
- package/dist/core/extension-startup-failure.d.ts.map +1 -1
- package/dist/core/extension-startup-failure.js +1 -0
- package/dist/core/extension-startup-failure.js.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.d.ts +27 -0
- package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.js +99 -7
- package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
- package/docs/settings.md +2 -2
- package/docs/storage.md +2 -0
- package/docs/workflows/api-reference.md +3 -3
- package/docs/workflows/operations.md +3 -3
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
|
@@ -153,6 +153,8 @@ function isRecoverableIntercomDisconnect(error) {
|
|
|
153
153
|
return true;
|
|
154
154
|
if (current instanceof IntercomBrokerTimeoutError)
|
|
155
155
|
return true;
|
|
156
|
+
if (current instanceof IntercomBrokerRetiringError)
|
|
157
|
+
return true;
|
|
156
158
|
if (current instanceof IntercomLiveRouteRefusedError)
|
|
157
159
|
return current.transient;
|
|
158
160
|
current = current.cause;
|
|
@@ -170,7 +172,18 @@ function isIntercomBrokerTimeout(error) {
|
|
|
170
172
|
}
|
|
171
173
|
return false;
|
|
172
174
|
}
|
|
173
|
-
|
|
175
|
+
function isIntercomBrokerRetiring(error) {
|
|
176
|
+
let current = error;
|
|
177
|
+
for (let depth = 0;depth <= MAX_CAUSE_DEPTH; depth += 1) {
|
|
178
|
+
if (!(current instanceof Error))
|
|
179
|
+
return false;
|
|
180
|
+
if (current instanceof IntercomBrokerRetiringError)
|
|
181
|
+
return true;
|
|
182
|
+
current = current.cause;
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected", MAX_CAUSE_DEPTH = 8, IntercomClientDisconnectedError, IntercomBrokerTimeoutError, BROKER_RETIRING_CODE = "broker_retiring", BROKER_RETIRING_REASON = "Intercom broker is retiring; connect to its replacement", IntercomBrokerRetiringError;
|
|
174
187
|
var init_recoverable_disconnect = __esm(() => {
|
|
175
188
|
init_live_route_refusal();
|
|
176
189
|
IntercomClientDisconnectedError = class IntercomClientDisconnectedError extends Error {
|
|
@@ -187,6 +200,13 @@ var init_recoverable_disconnect = __esm(() => {
|
|
|
187
200
|
this.name = "IntercomBrokerTimeoutError";
|
|
188
201
|
}
|
|
189
202
|
};
|
|
203
|
+
IntercomBrokerRetiringError = class IntercomBrokerRetiringError extends Error {
|
|
204
|
+
intercomRecoverableDisconnect = true;
|
|
205
|
+
constructor(message = BROKER_RETIRING_REASON, options) {
|
|
206
|
+
super(message, options);
|
|
207
|
+
this.name = "IntercomBrokerRetiringError";
|
|
208
|
+
}
|
|
209
|
+
};
|
|
190
210
|
});
|
|
191
211
|
|
|
192
212
|
// dist/builtin/intercom/retry-policy.ts
|
|
@@ -208,7 +228,10 @@ function jitteredReconnectDelayMs(attempt, random = Math.random) {
|
|
|
208
228
|
const ceiling = reconnectDelayMs(attempt);
|
|
209
229
|
return Math.round(ceiling / 2 + ceiling / 2 * random());
|
|
210
230
|
}
|
|
211
|
-
|
|
231
|
+
function brokerRetiringRetryDelayMs(attempt) {
|
|
232
|
+
return Math.min(100 * 2 ** attempt, 1000);
|
|
233
|
+
}
|
|
234
|
+
var BACKOFF_MS, BROKER_RETIRING_RETRY_WINDOW_MS = 1e4;
|
|
212
235
|
var init_reconnect_backoff = __esm(() => {
|
|
213
236
|
BACKOFF_MS = [1000, 2000, 5000, 1e4, 30000];
|
|
214
237
|
});
|
|
@@ -702,6 +725,9 @@ function getBrokerSpawnLockPath(agentDir = getAgentDir()) {
|
|
|
702
725
|
function getBrokerLogPath(agentDir = getAgentDir()) {
|
|
703
726
|
return join(getIntercomDirPath(agentDir), "broker.log");
|
|
704
727
|
}
|
|
728
|
+
function getBrokerStartAnnouncementPath(agentDir = getAgentDir()) {
|
|
729
|
+
return join(getIntercomDirPath(agentDir), "broker.starting");
|
|
730
|
+
}
|
|
705
731
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir()) {
|
|
706
732
|
if (platform === "win32") {
|
|
707
733
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
@@ -940,9 +966,40 @@ var init_group = __esm(() => {
|
|
|
940
966
|
RESERVED_RUNTIME_GROUPS = new Set(["true", "auto"]);
|
|
941
967
|
});
|
|
942
968
|
|
|
969
|
+
// dist/builtin/intercom/broker/socket-liveness.ts
|
|
970
|
+
import net from "net";
|
|
971
|
+
function isSocketAnswering(socketPath, timeoutMs = SOCKET_PROBE_TIMEOUT_MS) {
|
|
972
|
+
return new Promise((resolve) => {
|
|
973
|
+
const socket = net.connect(socketPath);
|
|
974
|
+
const finish = (isConnected) => {
|
|
975
|
+
clearTimeout(timeout);
|
|
976
|
+
socket.off("connect", onConnect);
|
|
977
|
+
socket.off("error", onError);
|
|
978
|
+
resolve(isConnected);
|
|
979
|
+
};
|
|
980
|
+
const onConnect = () => {
|
|
981
|
+
socket.on("error", () => {});
|
|
982
|
+
socket.end();
|
|
983
|
+
finish(true);
|
|
984
|
+
};
|
|
985
|
+
const onError = () => {
|
|
986
|
+
socket.destroy();
|
|
987
|
+
finish(false);
|
|
988
|
+
};
|
|
989
|
+
socket.on("connect", onConnect);
|
|
990
|
+
socket.on("error", onError);
|
|
991
|
+
const timeout = setTimeout(() => {
|
|
992
|
+
socket.destroy();
|
|
993
|
+
finish(false);
|
|
994
|
+
}, timeoutMs);
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
var SOCKET_PROBE_TIMEOUT_MS = 1000;
|
|
998
|
+
var init_socket_liveness = () => {};
|
|
999
|
+
|
|
943
1000
|
// dist/builtin/intercom/broker/client.ts
|
|
944
1001
|
import { EventEmitter } from "events";
|
|
945
|
-
import
|
|
1002
|
+
import net2 from "net";
|
|
946
1003
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
947
1004
|
function connectAborted() {
|
|
948
1005
|
return new IntercomClientDisconnectedError({ cause: new Error("Disconnected before the broker connection registered") });
|
|
@@ -967,6 +1024,19 @@ function isBacklogRefusal(error) {
|
|
|
967
1024
|
const code = error.code;
|
|
968
1025
|
return code === "ECONNREFUSED" || code === "EAGAIN";
|
|
969
1026
|
}
|
|
1027
|
+
function isLostBrokerSignature(error) {
|
|
1028
|
+
if (error instanceof ConnectionClosedBeforeRegistrationError)
|
|
1029
|
+
return true;
|
|
1030
|
+
const code = error.code;
|
|
1031
|
+
return code === "ENOENT" || code === "ECONNRESET" || code === "EPIPE";
|
|
1032
|
+
}
|
|
1033
|
+
async function classifyRegistrationFailure(error) {
|
|
1034
|
+
if (!isLostBrokerSignature(error) || await isSocketAnswering(BROKER_SOCKET))
|
|
1035
|
+
return error;
|
|
1036
|
+
return new IntercomBrokerRetiringError(`Intercom broker went away before it registered this session: ${error.message}`, {
|
|
1037
|
+
cause: error
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
970
1040
|
function toError(error) {
|
|
971
1041
|
return error instanceof Error ? error : new Error(String(error));
|
|
972
1042
|
}
|
|
@@ -976,15 +1046,22 @@ function isWorkflowFutureStageRosterEntries(value) {
|
|
|
976
1046
|
function isWorkflowStageRosterEntries(value) {
|
|
977
1047
|
return Array.isArray(value) && value.every((entry) => typeof entry === "object" && entry !== null && entry.kind === "workflow-stage" && typeof entry.runId === "string" && typeof entry.stageId === "string" && typeof entry.stageName === "string" && typeof entry.target === "string" && (entry.lifecycle === "pending" || entry.lifecycle === "running") && typeof entry.group === "string" && (entry.sessionId === undefined || typeof entry.sessionId === "string"));
|
|
978
1048
|
}
|
|
979
|
-
var BROKER_SOCKET, BROKER_CONNECT_TIMEOUT_MS = 1e4, PENDING_STAGE_ROUTE_ACK_TIMEOUT_MS = 1e4, GROUP_REQUEST_TIMEOUT_MS = 5000, PRESENCE_ACK_TIMEOUT_MS = 5000, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS = 5000, BROKER_BACKLOG_RETRIES = 6, BROKER_BACKLOG_RETRY_BASE_MS = 25, HELD_SEND_GRACE_MS = 5000, IntercomPendingStageRouteRefusedError, PENDING_STAGE_ROUTE_REFUSAL_CODES, IntercomClient;
|
|
1049
|
+
var BROKER_SOCKET, BROKER_CONNECT_TIMEOUT_MS = 1e4, PENDING_STAGE_ROUTE_ACK_TIMEOUT_MS = 1e4, GROUP_REQUEST_TIMEOUT_MS = 5000, PRESENCE_ACK_TIMEOUT_MS = 5000, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS = 5000, BROKER_BACKLOG_RETRIES = 6, BROKER_BACKLOG_RETRY_BASE_MS = 25, ConnectionClosedBeforeRegistrationError, HELD_SEND_GRACE_MS = 5000, IntercomPendingStageRouteRefusedError, PENDING_STAGE_ROUTE_REFUSAL_CODES, IntercomClient;
|
|
980
1050
|
var init_client = __esm(() => {
|
|
981
1051
|
init_paths();
|
|
982
1052
|
init_pending_send_registry();
|
|
983
1053
|
init_group();
|
|
984
1054
|
init_recoverable_disconnect();
|
|
1055
|
+
init_socket_liveness();
|
|
985
1056
|
init_live_route_refusal();
|
|
986
1057
|
init_retry_policy();
|
|
987
1058
|
BROKER_SOCKET = getBrokerSocketPath();
|
|
1059
|
+
ConnectionClosedBeforeRegistrationError = class ConnectionClosedBeforeRegistrationError extends Error {
|
|
1060
|
+
constructor() {
|
|
1061
|
+
super("Connection closed before registration");
|
|
1062
|
+
this.name = "ConnectionClosedBeforeRegistrationError";
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
988
1065
|
IntercomPendingStageRouteRefusedError = class IntercomPendingStageRouteRefusedError extends Error {
|
|
989
1066
|
connectionKept;
|
|
990
1067
|
code;
|
|
@@ -1152,8 +1229,14 @@ var init_client = __esm(() => {
|
|
|
1152
1229
|
} catch (error) {
|
|
1153
1230
|
if (attempt.signal.aborted)
|
|
1154
1231
|
throw connectAborted();
|
|
1155
|
-
if (!(error instanceof Error)
|
|
1232
|
+
if (!(error instanceof Error))
|
|
1156
1233
|
throw error;
|
|
1234
|
+
if (!isBacklogRefusal(error) || retry >= BROKER_BACKLOG_RETRIES) {
|
|
1235
|
+
const classified = await classifyRegistrationFailure(error);
|
|
1236
|
+
if (attempt.signal.aborted)
|
|
1237
|
+
throw connectAborted();
|
|
1238
|
+
throw classified;
|
|
1239
|
+
}
|
|
1157
1240
|
const backoff = BROKER_BACKLOG_RETRY_BASE_MS * 2 ** retry;
|
|
1158
1241
|
await abortableDelay(backoff * (0.5 + Math.random() / 2), attempt.signal);
|
|
1159
1242
|
}
|
|
@@ -1170,7 +1253,7 @@ var init_client = __esm(() => {
|
|
|
1170
1253
|
this._messageSource = messageSource ?? readSubagentMessageSource();
|
|
1171
1254
|
this._groups = normalizeGroups(session.groups, session.group);
|
|
1172
1255
|
return new Promise((resolve, reject) => {
|
|
1173
|
-
const socket =
|
|
1256
|
+
const socket = net2.connect(BROKER_SOCKET);
|
|
1174
1257
|
this.socket = socket;
|
|
1175
1258
|
this.disconnectError = null;
|
|
1176
1259
|
let settled = false;
|
|
@@ -1228,7 +1311,7 @@ var init_client = __esm(() => {
|
|
|
1228
1311
|
this.emit("disconnected", disconnectError);
|
|
1229
1312
|
}
|
|
1230
1313
|
if (wasConnecting) {
|
|
1231
|
-
reject(new
|
|
1314
|
+
reject(new ConnectionClosedBeforeRegistrationError);
|
|
1232
1315
|
}
|
|
1233
1316
|
};
|
|
1234
1317
|
const onSocketError = (err) => {
|
|
@@ -1330,7 +1413,7 @@ var init_client = __esm(() => {
|
|
|
1330
1413
|
case "registration_failed": {
|
|
1331
1414
|
if (typeof brokerMessage.reason !== "string")
|
|
1332
1415
|
throw new Error("Invalid registration_failed message");
|
|
1333
|
-
const refusal = isLiveWorkflowStageRouteRefusalCode(brokerMessage.code) ? new IntercomLiveRouteRefusedError(brokerMessage.code, brokerMessage.reason) : new Error(brokerMessage.reason);
|
|
1416
|
+
const refusal = isLiveWorkflowStageRouteRefusalCode(brokerMessage.code) ? new IntercomLiveRouteRefusedError(brokerMessage.code, brokerMessage.reason) : brokerMessage.code === BROKER_RETIRING_CODE ? new IntercomBrokerRetiringError(brokerMessage.reason) : new Error(brokerMessage.reason);
|
|
1334
1417
|
if (this._sessionId === null) {
|
|
1335
1418
|
this.emit("_registration_failed", refusal);
|
|
1336
1419
|
break;
|
|
@@ -2225,40 +2308,34 @@ var init_client = __esm(() => {
|
|
|
2225
2308
|
};
|
|
2226
2309
|
});
|
|
2227
2310
|
|
|
2228
|
-
// dist/builtin/intercom/broker/
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
socket.on("connect", onConnect);
|
|
2249
|
-
socket.on("error", onError);
|
|
2250
|
-
const timeout = setTimeout(() => {
|
|
2251
|
-
socket.destroy();
|
|
2252
|
-
finish(false);
|
|
2253
|
-
}, timeoutMs);
|
|
2254
|
-
});
|
|
2311
|
+
// dist/builtin/intercom/broker/startup-timeout.ts
|
|
2312
|
+
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
2313
|
+
|
|
2314
|
+
// dist/builtin/intercom/broker/start-announcement.ts
|
|
2315
|
+
import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2316
|
+
function readBrokerStartAnnouncement(announcement) {
|
|
2317
|
+
let text;
|
|
2318
|
+
try {
|
|
2319
|
+
text = readFileSync(announcement.path, "utf-8");
|
|
2320
|
+
} catch {
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
if (!text.endsWith(`
|
|
2324
|
+
`))
|
|
2325
|
+
return;
|
|
2326
|
+
const [token, pid, ...rest] = text.trim().split(/\s+/u);
|
|
2327
|
+
if (token !== announcement.token || rest.length > 0)
|
|
2328
|
+
return;
|
|
2329
|
+
const parsed = Number(pid);
|
|
2330
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
2255
2331
|
}
|
|
2256
|
-
var
|
|
2257
|
-
var
|
|
2332
|
+
var BROKER_ANNOUNCE_PATH_ENV = "ATOMIC_INTERCOM_BROKER_ANNOUNCE_PATH", BROKER_ANNOUNCE_TOKEN_ENV = "ATOMIC_INTERCOM_BROKER_ANNOUNCE_TOKEN";
|
|
2333
|
+
var init_start_announcement = () => {};
|
|
2258
2334
|
|
|
2259
2335
|
// dist/builtin/intercom/broker/spawn.ts
|
|
2260
2336
|
import { spawn } from "child_process";
|
|
2261
|
-
import {
|
|
2337
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
2338
|
+
import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync as readFileSync2, readSync, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2262
2339
|
import { join as join2, dirname } from "path";
|
|
2263
2340
|
import { fileURLToPath } from "url";
|
|
2264
2341
|
import { createRequire } from "module";
|
|
@@ -2347,7 +2424,7 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
2347
2424
|
}
|
|
2348
2425
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
2349
2426
|
ensurePrivateDirectory(dirname(launcherPath));
|
|
2350
|
-
|
|
2427
|
+
writeFileSync2(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
2351
2428
|
return launcherPath;
|
|
2352
2429
|
}
|
|
2353
2430
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -2375,7 +2452,7 @@ function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir
|
|
|
2375
2452
|
args: [...brokerArgs, brokerPath]
|
|
2376
2453
|
};
|
|
2377
2454
|
}
|
|
2378
|
-
function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore") {
|
|
2455
|
+
function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore", announcement) {
|
|
2379
2456
|
const storage = processSharedStorageSelection();
|
|
2380
2457
|
return {
|
|
2381
2458
|
detached: true,
|
|
@@ -2383,7 +2460,8 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore")
|
|
|
2383
2460
|
cwd: extensionDir,
|
|
2384
2461
|
env: createChildProcessEnvironment({
|
|
2385
2462
|
NODE_NO_WARNINGS: "1",
|
|
2386
|
-
...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage }
|
|
2463
|
+
...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage },
|
|
2464
|
+
...announcement === undefined ? {} : { [BROKER_ANNOUNCE_PATH_ENV]: announcement.path, [BROKER_ANNOUNCE_TOKEN_ENV]: announcement.token }
|
|
2387
2465
|
}),
|
|
2388
2466
|
windowsHide: true
|
|
2389
2467
|
};
|
|
@@ -2396,7 +2474,7 @@ function resetBrokerLog(logPath = BROKER_LOG) {
|
|
|
2396
2474
|
if (previous.length > 0) {
|
|
2397
2475
|
try {
|
|
2398
2476
|
const previousPath = `${logPath}.previous`;
|
|
2399
|
-
|
|
2477
|
+
writeFileSync2(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
2400
2478
|
if (process.platform !== "win32")
|
|
2401
2479
|
chmodSync(previousPath, 384);
|
|
2402
2480
|
} catch {}
|
|
@@ -2458,6 +2536,12 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
|
|
|
2458
2536
|
}
|
|
2459
2537
|
const brokerPath = resolveBrokerEntrypoint(extensionDir);
|
|
2460
2538
|
const launch = getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir);
|
|
2539
|
+
const announcement = launch.kind === "windows-launcher" ? { path: BROKER_START_ANNOUNCEMENT, token: randomUUID3() } : undefined;
|
|
2540
|
+
if (announcement !== undefined) {
|
|
2541
|
+
try {
|
|
2542
|
+
unlinkSync2(announcement.path);
|
|
2543
|
+
} catch {}
|
|
2544
|
+
}
|
|
2461
2545
|
if (launch.kind === "windows-launcher") {
|
|
2462
2546
|
writeWindowsHiddenLauncher(launch.launcherCommandLine, launch.launcherPath);
|
|
2463
2547
|
}
|
|
@@ -2468,7 +2552,7 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
|
|
|
2468
2552
|
const logFd = launch.kind === "direct" ? openSync(BROKER_LOG, "a") : undefined;
|
|
2469
2553
|
let child;
|
|
2470
2554
|
try {
|
|
2471
|
-
child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore"));
|
|
2555
|
+
child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore", announcement));
|
|
2472
2556
|
} finally {
|
|
2473
2557
|
if (logFd !== undefined)
|
|
2474
2558
|
closeSync(logFd);
|
|
@@ -2504,7 +2588,7 @@ ${describeBrokerLog()}`);
|
|
|
2504
2588
|
};
|
|
2505
2589
|
child.once("error", onError);
|
|
2506
2590
|
child.once("exit", onExit);
|
|
2507
|
-
waitForBroker(readyTimeoutMs).then(() => {
|
|
2591
|
+
waitForBroker(readyTimeoutMs, announcement === undefined ? undefined : () => readBrokerStartAnnouncement(announcement)).then(() => {
|
|
2508
2592
|
cleanup();
|
|
2509
2593
|
resolve();
|
|
2510
2594
|
}, (error) => {
|
|
@@ -2525,7 +2609,7 @@ async function isBrokerRunning() {
|
|
|
2525
2609
|
if (!existsSync(BROKER_PID))
|
|
2526
2610
|
return false;
|
|
2527
2611
|
try {
|
|
2528
|
-
const pid = parseInt(
|
|
2612
|
+
const pid = parseInt(readFileSync2(BROKER_PID, "utf-8").trim(), 10);
|
|
2529
2613
|
if (!Number.isFinite(pid))
|
|
2530
2614
|
return false;
|
|
2531
2615
|
process.kill(pid, 0);
|
|
@@ -2550,7 +2634,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
2550
2634
|
}
|
|
2551
2635
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
2552
2636
|
try {
|
|
2553
|
-
return
|
|
2637
|
+
return readFileSync2(lockPath, "utf-8").startsWith(owner);
|
|
2554
2638
|
} catch {
|
|
2555
2639
|
return false;
|
|
2556
2640
|
}
|
|
@@ -2562,7 +2646,7 @@ function acquireSpawnLock() {
|
|
|
2562
2646
|
${Date.now()}
|
|
2563
2647
|
`;
|
|
2564
2648
|
try {
|
|
2565
|
-
|
|
2649
|
+
writeFileSync2(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
2566
2650
|
return owner;
|
|
2567
2651
|
} catch (error) {
|
|
2568
2652
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -2570,7 +2654,7 @@ ${Date.now()}
|
|
|
2570
2654
|
}
|
|
2571
2655
|
if (isSpawnLockStale()) {
|
|
2572
2656
|
try {
|
|
2573
|
-
|
|
2657
|
+
unlinkSync2(BROKER_SPAWN_LOCK);
|
|
2574
2658
|
} catch {}
|
|
2575
2659
|
continue;
|
|
2576
2660
|
}
|
|
@@ -2592,7 +2676,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
|
2592
2676
|
return false;
|
|
2593
2677
|
}
|
|
2594
2678
|
try {
|
|
2595
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
2679
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync2(lockPath, "utf-8").trim().split(`
|
|
2596
2680
|
`);
|
|
2597
2681
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
2598
2682
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -2610,25 +2694,34 @@ function releaseSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
|
2610
2694
|
if (!ownsSpawnLock(owner, lockPath))
|
|
2611
2695
|
return;
|
|
2612
2696
|
try {
|
|
2613
|
-
|
|
2697
|
+
unlinkSync2(lockPath);
|
|
2614
2698
|
} catch {}
|
|
2615
2699
|
}
|
|
2616
|
-
async function waitForBroker(timeoutMs = BROKER_READY_TIMEOUT_MS) {
|
|
2700
|
+
async function waitForBroker(timeoutMs = BROKER_READY_TIMEOUT_MS, announcedPid) {
|
|
2617
2701
|
const start = Date.now();
|
|
2618
2702
|
let interval = BROKER_POLL_INITIAL_INTERVAL_MS;
|
|
2619
2703
|
while (Date.now() - start < timeoutMs) {
|
|
2620
2704
|
if (await checkSocketConnectable()) {
|
|
2621
2705
|
return;
|
|
2622
2706
|
}
|
|
2707
|
+
const pid = announcedPid?.();
|
|
2708
|
+
if (pid !== undefined && !isProcessAlive(pid)) {
|
|
2709
|
+
if (await checkSocketConnectable())
|
|
2710
|
+
return;
|
|
2711
|
+
throw new Error(`Intercom broker exited before startup (pid ${pid})
|
|
2712
|
+
${describeBrokerLog()}`);
|
|
2713
|
+
}
|
|
2623
2714
|
await sleep(interval);
|
|
2624
2715
|
interval = Math.min(interval * 2, BROKER_POLL_MAX_INTERVAL_MS);
|
|
2625
2716
|
}
|
|
2626
|
-
throw new Error(`Broker failed to start within timeout
|
|
2717
|
+
throw new Error(`Broker failed to start within timeout (${timeoutMs} ms)
|
|
2718
|
+
` + "The broker did not answer on its socket in time; it may still be starting, which a busy machine or an empty jiti " + "cache slows. Try again, or raise `brokerStartupTimeoutMs` in the Intercom config.json (default " + `${BROKER_READY_TIMEOUT_MS} ms).
|
|
2627
2719
|
${describeBrokerLog()}`);
|
|
2628
2720
|
}
|
|
2629
|
-
var INTERCOM_DIR, EXTENSION_DIR, BROKER_SOCKET2, BROKER_PID, BROKER_SPAWN_LOCK, BROKER_LOG, BROKER_LOG_TAIL_BYTES, BROKER_POLL_INITIAL_INTERVAL_MS = 10, BROKER_POLL_MAX_INTERVAL_MS = 100,
|
|
2721
|
+
var INTERCOM_DIR, EXTENSION_DIR, BROKER_SOCKET2, BROKER_PID, BROKER_SPAWN_LOCK, BROKER_LOG, BROKER_START_ANNOUNCEMENT, BROKER_LOG_TAIL_BYTES, BROKER_POLL_INITIAL_INTERVAL_MS = 10, BROKER_POLL_MAX_INTERVAL_MS = 100, BROKER_SPAWN_LOCK_MAX_AGE_MS = 60000, INTERNAL_INTERCOM_BROKER_ARG = "--atomic-internal-intercom-broker";
|
|
2630
2722
|
var init_spawn = __esm(() => {
|
|
2631
2723
|
init_socket_liveness();
|
|
2724
|
+
init_start_announcement();
|
|
2632
2725
|
init_paths();
|
|
2633
2726
|
INTERCOM_DIR = getIntercomDirPath();
|
|
2634
2727
|
EXTENSION_DIR = resolveIntercomPackageRoot(import.meta.url);
|
|
@@ -2636,6 +2729,7 @@ var init_spawn = __esm(() => {
|
|
|
2636
2729
|
BROKER_PID = getBrokerPidPath();
|
|
2637
2730
|
BROKER_SPAWN_LOCK = getBrokerSpawnLockPath();
|
|
2638
2731
|
BROKER_LOG = getBrokerLogPath();
|
|
2732
|
+
BROKER_START_ANNOUNCEMENT = getBrokerStartAnnouncementPath();
|
|
2639
2733
|
BROKER_LOG_TAIL_BYTES = 8 * 1024;
|
|
2640
2734
|
});
|
|
2641
2735
|
|
|
@@ -2792,14 +2886,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
2792
2886
|
});
|
|
2793
2887
|
|
|
2794
2888
|
// dist/builtin/intercom/config.ts
|
|
2795
|
-
import { existsSync as existsSync2, readFileSync as
|
|
2889
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
2796
2890
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
2797
2891
|
function loadConfig() {
|
|
2798
2892
|
if (!existsSync2(CONFIG_PATH)) {
|
|
2799
2893
|
return { ...defaults };
|
|
2800
2894
|
}
|
|
2801
2895
|
try {
|
|
2802
|
-
const raw =
|
|
2896
|
+
const raw = readFileSync3(CONFIG_PATH, "utf-8");
|
|
2803
2897
|
const parsed = JSON.parse(raw);
|
|
2804
2898
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2805
2899
|
throw new Error("Config must be a JSON object");
|
|
@@ -2829,6 +2923,12 @@ function loadConfig() {
|
|
|
2829
2923
|
}
|
|
2830
2924
|
config.brokerArgs = brokerArgs;
|
|
2831
2925
|
}
|
|
2926
|
+
if (Object.hasOwn(parsedConfig, "brokerStartupTimeoutMs")) {
|
|
2927
|
+
if (!Number.isInteger(parsedConfig.brokerStartupTimeoutMs) || Number(parsedConfig.brokerStartupTimeoutMs) < MIN_BROKER_STARTUP_TIMEOUT_MS) {
|
|
2928
|
+
throw new Error(`"brokerStartupTimeoutMs" must be an integer of at least ${MIN_BROKER_STARTUP_TIMEOUT_MS}`);
|
|
2929
|
+
}
|
|
2930
|
+
config.brokerStartupTimeoutMs = Number(parsedConfig.brokerStartupTimeoutMs);
|
|
2931
|
+
}
|
|
2832
2932
|
if (Object.hasOwn(parsedConfig, "confirmSend")) {
|
|
2833
2933
|
if (typeof parsedConfig.confirmSend !== "boolean") {
|
|
2834
2934
|
throw new Error(`"confirmSend" must be a boolean`);
|
|
@@ -2876,6 +2976,7 @@ var init_config = __esm(() => {
|
|
|
2876
2976
|
defaults = {
|
|
2877
2977
|
brokerCommand: DEFAULT_BROKER_COMMAND,
|
|
2878
2978
|
brokerArgs: [...DEFAULT_BROKER_ARGS],
|
|
2979
|
+
brokerStartupTimeoutMs: BROKER_READY_TIMEOUT_MS,
|
|
2879
2980
|
confirmSend: false,
|
|
2880
2981
|
maxPendingAsks: DEFAULT_MAX_PENDING_REPLY_WAITS,
|
|
2881
2982
|
replyHint: true
|
|
@@ -3475,7 +3576,7 @@ var init_intercom_utils = __esm(() => {
|
|
|
3475
3576
|
});
|
|
3476
3577
|
|
|
3477
3578
|
// dist/builtin/intercom/contact-supervisor-tool.ts
|
|
3478
|
-
import { randomUUID as
|
|
3579
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
3479
3580
|
import { Type } from "typebox";
|
|
3480
3581
|
import { Text as Text2 } from "@earendil-works/pi-tui";
|
|
3481
3582
|
function registerContactSupervisorTool(pi, deps) {
|
|
@@ -3675,7 +3776,7 @@ function registerContactSupervisorTool(pi, deps) {
|
|
|
3675
3776
|
}
|
|
3676
3777
|
let wait = null;
|
|
3677
3778
|
try {
|
|
3678
|
-
const questionId =
|
|
3779
|
+
const questionId = randomUUID4();
|
|
3679
3780
|
const admission = beginReplyWait(sendTo, questionId, signal);
|
|
3680
3781
|
if (!admission.ok) {
|
|
3681
3782
|
return {
|
|
@@ -3797,7 +3898,7 @@ var init_workflow_stage_target = __esm(() => {
|
|
|
3797
3898
|
});
|
|
3798
3899
|
|
|
3799
3900
|
// dist/builtin/intercom/retry-identity.ts
|
|
3800
|
-
import { randomUUID as
|
|
3901
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
3801
3902
|
function operationKey(input) {
|
|
3802
3903
|
return JSON.stringify([
|
|
3803
3904
|
input.sessionId,
|
|
@@ -3825,8 +3926,8 @@ class RetryIdentityReservations {
|
|
|
3825
3926
|
this.maxEntries = options.maxEntries ?? RETRY_IDENTITY_MAX_ENTRIES;
|
|
3826
3927
|
this.maxReuses = options.maxReuses ?? RETRY_IDENTITY_MAX_REUSES;
|
|
3827
3928
|
this.now = options.now ?? Date.now;
|
|
3828
|
-
this.createId = options.createId ??
|
|
3829
|
-
this.createToken = options.createToken ??
|
|
3929
|
+
this.createId = options.createId ?? randomUUID5;
|
|
3930
|
+
this.createToken = options.createToken ?? randomUUID5;
|
|
3830
3931
|
}
|
|
3831
3932
|
begin(input, retryToken) {
|
|
3832
3933
|
const now = this.now();
|
|
@@ -5799,8 +5900,8 @@ import {
|
|
|
5799
5900
|
existsSync as existsSync3,
|
|
5800
5901
|
mkdirSync as mkdirSync2,
|
|
5801
5902
|
openSync as openSync2,
|
|
5802
|
-
readFileSync as
|
|
5803
|
-
writeFileSync as
|
|
5903
|
+
readFileSync as readFileSync4,
|
|
5904
|
+
writeFileSync as writeFileSync3
|
|
5804
5905
|
} from "node:fs";
|
|
5805
5906
|
import { dirname as dirname2 } from "node:path";
|
|
5806
5907
|
import { DatabaseSync } from "node:sqlite";
|
|
@@ -5865,13 +5966,13 @@ function prepareDurableAuthority(storagePath) {
|
|
|
5865
5966
|
return;
|
|
5866
5967
|
if (!databaseExists) {
|
|
5867
5968
|
const key = randomBytes(AUTHORITY_KEY_BYTES);
|
|
5868
|
-
|
|
5969
|
+
writeFileSync3(keyPath, key, { flag: "wx", mode: 384 });
|
|
5869
5970
|
const databaseDescriptor = openSync2(storagePath, "wx", 384);
|
|
5870
5971
|
closeSync2(databaseDescriptor);
|
|
5871
5972
|
restrictExistingAuthorityArtifacts(storagePath, keyPath);
|
|
5872
5973
|
return key;
|
|
5873
5974
|
}
|
|
5874
|
-
const key =
|
|
5975
|
+
const key = readFileSync4(keyPath);
|
|
5875
5976
|
if (key.length !== AUTHORITY_KEY_BYTES)
|
|
5876
5977
|
return;
|
|
5877
5978
|
return key;
|
|
@@ -6433,7 +6534,7 @@ var init_terminal_ordering_barrier = __esm(() => {
|
|
|
6433
6534
|
|
|
6434
6535
|
// dist/builtin/intercom/subagent-relay.ts
|
|
6435
6536
|
import { isStaleExtensionContextError as isStaleExtensionContextError4 } from "@bastani/atomic";
|
|
6436
|
-
import { randomUUID as
|
|
6537
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
6437
6538
|
async function dispatchRelayFallback(pi, prefix, terminalMessage, stageAdmissionKey) {
|
|
6438
6539
|
let delivered = 0;
|
|
6439
6540
|
try {
|
|
@@ -6465,7 +6566,7 @@ function registerSubagentRelay(pi, deps) {
|
|
|
6465
6566
|
status,
|
|
6466
6567
|
group: deps.homeGroup?.()
|
|
6467
6568
|
},
|
|
6468
|
-
message: { id:
|
|
6569
|
+
message: { id: randomUUID6(), timestamp: now, content: { text: messageText } },
|
|
6469
6570
|
bodyText: messageText
|
|
6470
6571
|
};
|
|
6471
6572
|
let dispatched = false;
|
|
@@ -7705,11 +7806,11 @@ var init_released_stage_peers = __esm(() => {
|
|
|
7705
7806
|
});
|
|
7706
7807
|
|
|
7707
7808
|
// dist/builtin/intercom/supervisor-authorization-registry.ts
|
|
7708
|
-
import { randomUUID as
|
|
7809
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
7709
7810
|
|
|
7710
7811
|
class SupervisorAuthorizationRegistry {
|
|
7711
7812
|
byCapability = new Map;
|
|
7712
|
-
ownerToken =
|
|
7813
|
+
ownerToken = randomUUID7();
|
|
7713
7814
|
async authorize(childName, connect) {
|
|
7714
7815
|
const client = await connect();
|
|
7715
7816
|
const authorization = await client.authorizeSupervisorChild(childName.trim());
|
|
@@ -7731,7 +7832,7 @@ __export(exports_index_heavy, {
|
|
|
7731
7832
|
default: () => piIntercomExtension
|
|
7732
7833
|
});
|
|
7733
7834
|
import { APP_NAME, sessionScopedExtensionState } from "@bastani/atomic";
|
|
7734
|
-
import { randomUUID as
|
|
7835
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
7735
7836
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
7736
7837
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
7737
7838
|
function isPendingStageUndeliverableEvent(value) {
|
|
@@ -7808,7 +7909,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
7808
7909
|
const launcherCapabilityFor = (runId) => {
|
|
7809
7910
|
let capability = launcherCapabilities.get(runId);
|
|
7810
7911
|
if (capability === undefined) {
|
|
7811
|
-
capability =
|
|
7912
|
+
capability = randomUUID8();
|
|
7812
7913
|
launcherCapabilities.set(runId, capability);
|
|
7813
7914
|
}
|
|
7814
7915
|
return capability;
|
|
@@ -7819,7 +7920,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
7819
7920
|
const routeClientConnectGate = createConcurrencyGate(ROUTE_CLIENT_CONNECT_CONCURRENCY);
|
|
7820
7921
|
const supervisorAuthorizations = new SupervisorAuthorizationRegistry;
|
|
7821
7922
|
const releasedStagePeers = new ReleasedStagePeers({
|
|
7822
|
-
prepare: () => spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs),
|
|
7923
|
+
prepare: () => spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs, config.brokerStartupTimeoutMs),
|
|
7823
7924
|
createClient: (returnAddress) => new IntercomClient(returnAddress),
|
|
7824
7925
|
cwd: () => getLiveContext()?.cwd ?? process.cwd(),
|
|
7825
7926
|
relay: (from, message, channel) => {
|
|
@@ -8490,7 +8591,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
8490
8591
|
return connection.promise;
|
|
8491
8592
|
const owner = connection;
|
|
8492
8593
|
const promise = routeClientConnectGate.run(async () => {
|
|
8493
|
-
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
|
|
8594
|
+
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs, config.brokerStartupTimeoutMs);
|
|
8494
8595
|
if (pendingStageRouteConnections.get(key) !== owner)
|
|
8495
8596
|
throw new IntercomClientDisconnectedError;
|
|
8496
8597
|
const routeReturnAddress = `${currentSessionId}:pending-stage-route:${key}`;
|
|
@@ -8697,6 +8798,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
8697
8798
|
let connectFailed = false;
|
|
8698
8799
|
await ownershipRecorded.promise;
|
|
8699
8800
|
const ownerWaitDeadline = Date.now() + LIVE_ROUTE_OWNER_WAIT_MS;
|
|
8801
|
+
let retiringRetries = 0;
|
|
8802
|
+
let retiringDeadline;
|
|
8700
8803
|
try {
|
|
8701
8804
|
for (let ownerWait = 0;; ownerWait += 1) {
|
|
8702
8805
|
const nextClient = new IntercomClient(sessionIdAtStart, {
|
|
@@ -8708,7 +8811,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
8708
8811
|
attachClientHandlers(nextClient);
|
|
8709
8812
|
try {
|
|
8710
8813
|
await testOverrides.beforeConnectAttempt?.(reason);
|
|
8711
|
-
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
|
|
8814
|
+
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs, config.brokerStartupTimeoutMs);
|
|
8712
8815
|
const childMetadata = currentChildOrchestratorMetadata();
|
|
8713
8816
|
await nextClient.connect(buildRegistration(), childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy), resolveSessionHomeGroup());
|
|
8714
8817
|
clientRegistrationGroup = resolveSessionHomeGroup();
|
|
@@ -8756,6 +8859,14 @@ function piIntercomExtension(pi, testOverrides = {}) {
|
|
|
8756
8859
|
await delay3(liveRouteOwnerRetryDelayMs(ownerWait));
|
|
8757
8860
|
continue;
|
|
8758
8861
|
}
|
|
8862
|
+
if (isIntercomBrokerRetiring(error)) {
|
|
8863
|
+
retiringDeadline ??= Date.now() + BROKER_RETIRING_RETRY_WINDOW_MS;
|
|
8864
|
+
if (Date.now() < retiringDeadline && !disposed && !shuttingDown && getLiveContext(contextAtStart, generationAtStart)) {
|
|
8865
|
+
await delay3(brokerRetiringRetryDelayMs(retiringRetries++));
|
|
8866
|
+
if (getLiveContext(contextAtStart, generationAtStart))
|
|
8867
|
+
continue;
|
|
8868
|
+
}
|
|
8869
|
+
}
|
|
8759
8870
|
connectFailed = true;
|
|
8760
8871
|
throw toError3(error);
|
|
8761
8872
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.55-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|