@sailorbridge/client 0.2.2 → 0.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/README.md +25 -0
- package/dist/src/cli.js +505 -243
- package/dist/src/cli.js.map +14 -12
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
|
-
// .dist-releases/
|
|
5
|
+
// .dist-releases/1784888160293-2271563/src/cli.js
|
|
6
6
|
import { hostname as hostname3 } from "node:os";
|
|
7
7
|
import { writeSync } from "node:fs";
|
|
8
|
-
// .dist-releases/
|
|
8
|
+
// .dist-releases/1784888160293-2271563/src/auth/host-pairing.js
|
|
9
9
|
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
10
10
|
import { homedir, hostname, platform } from "node:os";
|
|
11
11
|
import path from "node:path";
|
|
@@ -220,7 +220,7 @@ function _assertObject(value) {
|
|
|
220
220
|
throw new Error("host pairing response must be an object");
|
|
221
221
|
return value;
|
|
222
222
|
}
|
|
223
|
-
// .dist-releases/
|
|
223
|
+
// .dist-releases/1784888160293-2271563/src/host/repo-tip-reporter.js
|
|
224
224
|
import { createHash } from "node:crypto";
|
|
225
225
|
import { existsSync, mkdirSync } from "node:fs";
|
|
226
226
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -402,10 +402,10 @@ ${error.message}`));
|
|
|
402
402
|
proc.on("close", (code) => finish(code ?? 1));
|
|
403
403
|
});
|
|
404
404
|
}
|
|
405
|
-
// .dist-releases/
|
|
405
|
+
// .dist-releases/1784888160293-2271563/src/host/request-consumer.js
|
|
406
406
|
import { hostname as hostname2 } from "node:os";
|
|
407
407
|
|
|
408
|
-
// .dist-releases/
|
|
408
|
+
// .dist-releases/1784888160293-2271563/src/driver/secrets.js
|
|
409
409
|
function redactSensitiveText(text, env = {}, explicitSecrets = []) {
|
|
410
410
|
let redacted = text;
|
|
411
411
|
for (const [key, value] of Object.entries(env)) {
|
|
@@ -424,16 +424,16 @@ function isSensitiveEnvKey(key) {
|
|
|
424
424
|
return /(TOKEN|KEY|SECRET|AUTHORIZATION|PASSWORD)/i.test(key);
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
-
// .dist-releases/
|
|
428
|
-
var CLIENT_VERSION = "0.2.
|
|
429
|
-
var CLIENT_GIT_SHA = "
|
|
427
|
+
// .dist-releases/1784888160293-2271563/src/version.js
|
|
428
|
+
var CLIENT_VERSION = "0.2.3";
|
|
429
|
+
var CLIENT_GIT_SHA = "ed59f81313f2-dirty";
|
|
430
430
|
var CLIENT_BUILD_DIRTY = true;
|
|
431
431
|
var CLIENT_VERSION_LABEL = formatClientVersion(CLIENT_VERSION, CLIENT_GIT_SHA);
|
|
432
432
|
function formatClientVersion(version, gitSha) {
|
|
433
433
|
return `${version}+git.${gitSha}`;
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
-
// .dist-releases/
|
|
436
|
+
// .dist-releases/1784888160293-2271563/src/host/request-consumer.js
|
|
437
437
|
var MAX_ERROR_LENGTH = 500;
|
|
438
438
|
function defaultHostIdentity(config) {
|
|
439
439
|
const captainId = config.captainId?.trim();
|
|
@@ -455,7 +455,8 @@ async function runHostRequestOnce(options) {
|
|
|
455
455
|
hostId: options.hostId,
|
|
456
456
|
displayName: options.displayName,
|
|
457
457
|
clientVersion: CLIENT_VERSION,
|
|
458
|
-
clientGitSha: CLIENT_GIT_SHA
|
|
458
|
+
clientGitSha: CLIENT_GIT_SHA,
|
|
459
|
+
...options.updateError === undefined ? {} : { updateError: options.updateError }
|
|
459
460
|
});
|
|
460
461
|
if (options.workspaceInventory) {
|
|
461
462
|
try {
|
|
@@ -488,7 +489,7 @@ function limitErrorMessage(error, explicitSecrets) {
|
|
|
488
489
|
const trimmed = redactSensitiveText(message, process.env, explicitSecrets).trim() || "host request starter failed";
|
|
489
490
|
return trimmed.length <= MAX_ERROR_LENGTH ? trimmed : `${trimmed.slice(0, MAX_ERROR_LENGTH - 3)}...`;
|
|
490
491
|
}
|
|
491
|
-
// .dist-releases/
|
|
492
|
+
// .dist-releases/1784888160293-2271563/src/product/start-request.js
|
|
492
493
|
async function createAgentStartRequest(options) {
|
|
493
494
|
const apiUrl = _required(options.apiUrl, "product API URL").replace(/\/+$/u, "");
|
|
494
495
|
const accessToken = _required(options.accessToken, "product API bearer token");
|
|
@@ -548,7 +549,7 @@ function _string(value, label) {
|
|
|
548
549
|
throw new Error(`${label} must be a non-empty string`);
|
|
549
550
|
return value;
|
|
550
551
|
}
|
|
551
|
-
// .dist-releases/
|
|
552
|
+
// .dist-releases/1784888160293-2271563/src/product/pair.js
|
|
552
553
|
async function createPair(options) {
|
|
553
554
|
const apiUrl = _required2(options.apiUrl, "product API URL").replace(/\/+$/u, "");
|
|
554
555
|
const accessToken = _required2(options.accessToken, "product API bearer token");
|
|
@@ -625,7 +626,7 @@ function _string2(value, label) {
|
|
|
625
626
|
throw new Error(`${label} must be a non-empty string`);
|
|
626
627
|
return value;
|
|
627
628
|
}
|
|
628
|
-
// .dist-releases/
|
|
629
|
+
// .dist-releases/1784888160293-2271563/src/product/worker.js
|
|
629
630
|
async function createWorker(options) {
|
|
630
631
|
const apiUrl = _required3(options.apiUrl, "product API URL").replace(/\/+$/u, "");
|
|
631
632
|
const accessToken = _required3(options.accessToken, "product API bearer token");
|
|
@@ -689,7 +690,7 @@ function _string3(value, label) {
|
|
|
689
690
|
throw new Error(`${label} must be a non-empty string`);
|
|
690
691
|
return value;
|
|
691
692
|
}
|
|
692
|
-
// .dist-releases/
|
|
693
|
+
// .dist-releases/1784888160293-2271563/src/driver/events.js
|
|
693
694
|
class DriverEventEmitter {
|
|
694
695
|
callbacks = new Map;
|
|
695
696
|
on(type, callback) {
|
|
@@ -704,7 +705,7 @@ class DriverEventEmitter {
|
|
|
704
705
|
}
|
|
705
706
|
}
|
|
706
707
|
}
|
|
707
|
-
// .dist-releases/
|
|
708
|
+
// .dist-releases/1784888160293-2271563/src/driver/async-queue.js
|
|
708
709
|
class AsyncQueue {
|
|
709
710
|
values = [];
|
|
710
711
|
waiters = [];
|
|
@@ -743,7 +744,7 @@ class AsyncQueue {
|
|
|
743
744
|
}
|
|
744
745
|
}
|
|
745
746
|
|
|
746
|
-
// .dist-releases/
|
|
747
|
+
// .dist-releases/1784888160293-2271563/src/driver/types.js
|
|
747
748
|
class DriverUnsupportedError extends Error {
|
|
748
749
|
constructor(message) {
|
|
749
750
|
super(message);
|
|
@@ -758,7 +759,7 @@ class DriverTargetNotReadyError extends Error {
|
|
|
758
759
|
}
|
|
759
760
|
}
|
|
760
761
|
|
|
761
|
-
// .dist-releases/
|
|
762
|
+
// .dist-releases/1784888160293-2271563/src/driver/sdk-loader.js
|
|
762
763
|
async function loadSdk(loader, packageName, env = {}, installHint = `Install the optional SDK dependency ${packageName} and its peers for this transport.`) {
|
|
763
764
|
try {
|
|
764
765
|
return await loader();
|
|
@@ -768,7 +769,7 @@ async function loadSdk(loader, packageName, env = {}, installHint = `Install the
|
|
|
768
769
|
}
|
|
769
770
|
}
|
|
770
771
|
|
|
771
|
-
// .dist-releases/
|
|
772
|
+
// .dist-releases/1784888160293-2271563/src/driver/claude/driver.js
|
|
772
773
|
class ClaudeAgentSdkDriver {
|
|
773
774
|
options;
|
|
774
775
|
capabilities = { structured: true, resume: true, attach: false };
|
|
@@ -944,7 +945,7 @@ function asRecord(value) {
|
|
|
944
945
|
function stringValue(value) {
|
|
945
946
|
return typeof value === "string" ? value : undefined;
|
|
946
947
|
}
|
|
947
|
-
// .dist-releases/
|
|
948
|
+
// .dist-releases/1784888160293-2271563/src/driver/codex/driver.js
|
|
948
949
|
class CodexSdkDriver {
|
|
949
950
|
options;
|
|
950
951
|
capabilities = { structured: true, resume: true, attach: false };
|
|
@@ -1125,7 +1126,7 @@ function asRecord2(value) {
|
|
|
1125
1126
|
function stringValue2(value) {
|
|
1126
1127
|
return typeof value === "string" ? value : undefined;
|
|
1127
1128
|
}
|
|
1128
|
-
// .dist-releases/
|
|
1129
|
+
// .dist-releases/1784888160293-2271563/src/driver/liveness-heuristics.js
|
|
1129
1130
|
var BUSY_MARKERS = ["Working (", "Waiting for background", "Pasted Content", "tab to queue"];
|
|
1130
1131
|
var ANSI_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\)/g;
|
|
1131
1132
|
function stripAnsi(text) {
|
|
@@ -1152,7 +1153,7 @@ function classifyInteractiveOutput(input) {
|
|
|
1152
1153
|
function isOutputStable(now, lastOutputAt, idleStableMs) {
|
|
1153
1154
|
return Boolean(lastOutputAt && now.getTime() - lastOutputAt.getTime() >= idleStableMs);
|
|
1154
1155
|
}
|
|
1155
|
-
// .dist-releases/
|
|
1156
|
+
// .dist-releases/1784888160293-2271563/src/driver/pty/loader.js
|
|
1156
1157
|
async function loadNodePty(loader = defaultNodePtyLoader) {
|
|
1157
1158
|
try {
|
|
1158
1159
|
return await loader();
|
|
@@ -1178,7 +1179,7 @@ async function defaultNodePtyLoader() {
|
|
|
1178
1179
|
return loaded;
|
|
1179
1180
|
}
|
|
1180
1181
|
|
|
1181
|
-
// .dist-releases/
|
|
1182
|
+
// .dist-releases/1784888160293-2271563/src/driver/pty/driver.js
|
|
1182
1183
|
class PtyDriver {
|
|
1183
1184
|
options;
|
|
1184
1185
|
capabilities = { structured: false, resume: false, attach: false };
|
|
@@ -1330,12 +1331,12 @@ function tail(text, lines) {
|
|
|
1330
1331
|
function sleep(ms) {
|
|
1331
1332
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1332
1333
|
}
|
|
1333
|
-
// .dist-releases/
|
|
1334
|
+
// .dist-releases/1784888160293-2271563/src/driver/tmux/driver.js
|
|
1334
1335
|
import { mkdtemp, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
1335
1336
|
import { tmpdir } from "node:os";
|
|
1336
1337
|
import { join } from "node:path";
|
|
1337
1338
|
|
|
1338
|
-
// .dist-releases/
|
|
1339
|
+
// .dist-releases/1784888160293-2271563/src/driver/tmux/launch.js
|
|
1339
1340
|
var ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
1340
1341
|
var PANE_BOOTSTRAP_COMMAND = 'tmux set-option -t "$TMUX_PANE" remain-on-exit on >/dev/null 2>&1 || true; tmux wait-for -S "$1"; shift; exec "$@"';
|
|
1341
1342
|
function buildTmuxNewSessionArgs(input) {
|
|
@@ -1358,7 +1359,7 @@ function validateEnv(env) {
|
|
|
1358
1359
|
}
|
|
1359
1360
|
}
|
|
1360
1361
|
|
|
1361
|
-
// .dist-releases/
|
|
1362
|
+
// .dist-releases/1784888160293-2271563/src/driver/tmux/paste.js
|
|
1362
1363
|
function buildDispatchPlan(text, useTyping) {
|
|
1363
1364
|
return {
|
|
1364
1365
|
mode: useTyping ? "type-literal" : "paste-buffer",
|
|
@@ -1382,7 +1383,7 @@ function arraysEqual(left, right) {
|
|
|
1382
1383
|
return left.length === right.length && left.every((item, index) => item === right[index]);
|
|
1383
1384
|
}
|
|
1384
1385
|
|
|
1385
|
-
// .dist-releases/
|
|
1386
|
+
// .dist-releases/1784888160293-2271563/src/driver/tmux/liveness.js
|
|
1386
1387
|
var SHELL_COMMANDS = new Set(["", "bash", "zsh", "sh", "fish", "pwsh", "powershell"]);
|
|
1387
1388
|
function classifyTmuxLiveness(input) {
|
|
1388
1389
|
if (!input.hasSession) {
|
|
@@ -1402,7 +1403,7 @@ function isTmuxProcessAlive(command, runningCommands) {
|
|
|
1402
1403
|
return !SHELL_COMMANDS.has(command);
|
|
1403
1404
|
}
|
|
1404
1405
|
|
|
1405
|
-
// .dist-releases/
|
|
1406
|
+
// .dist-releases/1784888160293-2271563/src/driver/tmux/runner.js
|
|
1406
1407
|
import { spawn as spawn2 } from "node:child_process";
|
|
1407
1408
|
var DEFAULT_TIMEOUT_MS = 15000;
|
|
1408
1409
|
|
|
@@ -1527,7 +1528,7 @@ class TmuxClient {
|
|
|
1527
1528
|
}
|
|
1528
1529
|
}
|
|
1529
1530
|
|
|
1530
|
-
// .dist-releases/
|
|
1531
|
+
// .dist-releases/1784888160293-2271563/src/driver/tmux/driver.js
|
|
1531
1532
|
var ATTACHED_STOP_GRACE_MS = 1e4;
|
|
1532
1533
|
var DEFAULT_STOP_TIMEOUT_MS = 15000;
|
|
1533
1534
|
var DEFAULT_READY_TIMEOUT_MS = 90000;
|
|
@@ -1922,12 +1923,12 @@ function isMissingTmuxSessionError(error) {
|
|
|
1922
1923
|
${error.result.stderr}`.toLowerCase();
|
|
1923
1924
|
return text.includes("can't find session") || text.includes("cannot find session") || text.includes("no such session") || text.includes("session not found");
|
|
1924
1925
|
}
|
|
1925
|
-
// .dist-releases/
|
|
1926
|
+
// .dist-releases/1784888160293-2271563/src/relay/client.js
|
|
1926
1927
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
1927
1928
|
import http from "node:http";
|
|
1928
1929
|
import https from "node:https";
|
|
1929
1930
|
|
|
1930
|
-
// .dist-releases/
|
|
1931
|
+
// .dist-releases/1784888160293-2271563/src/relay/errors.js
|
|
1931
1932
|
class RelayError extends Error {
|
|
1932
1933
|
method;
|
|
1933
1934
|
path;
|
|
@@ -1964,7 +1965,7 @@ class RelayProtocolError extends RelayError {
|
|
|
1964
1965
|
}
|
|
1965
1966
|
}
|
|
1966
1967
|
|
|
1967
|
-
// .dist-releases/
|
|
1968
|
+
// .dist-releases/1784888160293-2271563/src/worker/protocol.js
|
|
1968
1969
|
var DEFAULT_RELAY_URL = DEFAULT_PRODUCT_API_URL;
|
|
1969
1970
|
var DEFAULT_WORKER = "host";
|
|
1970
1971
|
var DEFAULT_WORKDIR = "~/sailorbridge-workdir";
|
|
@@ -1994,7 +1995,7 @@ function effectiveJobKind(kind, spec) {
|
|
|
1994
1995
|
return kind === "stream" || spec.stream === true ? "stream" : kind;
|
|
1995
1996
|
}
|
|
1996
1997
|
|
|
1997
|
-
// .dist-releases/
|
|
1998
|
+
// .dist-releases/1784888160293-2271563/src/relay/client.js
|
|
1998
1999
|
var JSON_CONTENT_TYPE = "application/json";
|
|
1999
2000
|
var MAX_MAILBOX_LIMIT = 16;
|
|
2000
2001
|
var MAX_WAIT_TIMEOUT_SEC = 120;
|
|
@@ -2161,13 +2162,15 @@ class RelayClient {
|
|
|
2161
2162
|
}
|
|
2162
2163
|
return { status: "queued", ids: response.ids, recipients: response.recipients };
|
|
2163
2164
|
}
|
|
2164
|
-
async postSessionReply(session, text, target = { kind: "captain" }, inReplyToMessageId, tag = "REPLY") {
|
|
2165
|
+
async postSessionReply(session, text, target = { kind: "captain" }, inReplyToMessageId, tag = "REPLY", origin) {
|
|
2165
2166
|
requireSegment(session, "session");
|
|
2166
2167
|
const toAgent = target.kind === "captain" ? "captain" : target.agentName;
|
|
2167
2168
|
requireNonEmpty(toAgent, "reply target");
|
|
2168
2169
|
requireNonEmpty(tag, "reply tag");
|
|
2169
2170
|
if (inReplyToMessageId !== undefined)
|
|
2170
2171
|
requireNonEmpty(inReplyToMessageId, "in_reply_to_message_id");
|
|
2172
|
+
if (origin !== undefined && target.kind !== "captain")
|
|
2173
|
+
throw new Error("origin is only valid for captain replies");
|
|
2171
2174
|
const response = await this.requestJson("POST", `/api/v1/mailbox/session/${segment(session)}`, {
|
|
2172
2175
|
tag,
|
|
2173
2176
|
to_agents: [toAgent],
|
|
@@ -2175,13 +2178,18 @@ class RelayClient {
|
|
|
2175
2178
|
payload_json: text,
|
|
2176
2179
|
...inReplyToMessageId === undefined ? {} : {
|
|
2177
2180
|
in_reply_to_message_id: inReplyToMessageId
|
|
2178
|
-
}
|
|
2181
|
+
},
|
|
2182
|
+
...origin === undefined ? {} : { origin }
|
|
2179
2183
|
});
|
|
2180
|
-
const
|
|
2181
|
-
if (
|
|
2182
|
-
|
|
2184
|
+
const validRecipients = isStringArray(response.recipients) && response.recipients.length === 1 && response.recipients[0] === toAgent;
|
|
2185
|
+
if (origin !== undefined && response.status === "skipped") {
|
|
2186
|
+
if (!validRecipients || typeof response.reason !== "string" || !response.reason) {
|
|
2187
|
+
throw new RelayProtocolError("POST", `/api/v1/mailbox/session/${segment(session)}`, "invalid session reply skip response");
|
|
2188
|
+
}
|
|
2189
|
+
return { ids: [], recipients: response.recipients, skippedReason: response.reason };
|
|
2183
2190
|
}
|
|
2184
|
-
|
|
2191
|
+
const expectedStatus = target.kind === "captain" ? "recorded" : "queued";
|
|
2192
|
+
if (response.status !== expectedStatus || !isNonEmptyStringArray(response.ids) || !validRecipients) {
|
|
2185
2193
|
throw new RelayProtocolError("POST", `/api/v1/mailbox/session/${segment(session)}`, "invalid session reply response");
|
|
2186
2194
|
}
|
|
2187
2195
|
return { ids: response.ids, recipients: response.recipients };
|
|
@@ -2370,7 +2378,8 @@ class RelayClient {
|
|
|
2370
2378
|
host_id: body.hostId,
|
|
2371
2379
|
display_name: body.displayName,
|
|
2372
2380
|
...body.clientVersion === undefined ? {} : { client_version: body.clientVersion },
|
|
2373
|
-
...body.clientGitSha === undefined ? {} : { client_git_sha: body.clientGitSha }
|
|
2381
|
+
...body.clientGitSha === undefined ? {} : { client_git_sha: body.clientGitSha },
|
|
2382
|
+
...body.updateError === undefined ? {} : { update_error: body.updateError }
|
|
2374
2383
|
});
|
|
2375
2384
|
return parseClientHostReport(response, "POST", path3);
|
|
2376
2385
|
}
|
|
@@ -2384,7 +2393,8 @@ class RelayClient {
|
|
|
2384
2393
|
const response = await this.requestJson("POST", path3, {
|
|
2385
2394
|
...body.displayName === undefined ? {} : { display_name: body.displayName },
|
|
2386
2395
|
...body.clientVersion === undefined ? {} : { client_version: body.clientVersion },
|
|
2387
|
-
...body.clientGitSha === undefined ? {} : { client_git_sha: body.clientGitSha }
|
|
2396
|
+
...body.clientGitSha === undefined ? {} : { client_git_sha: body.clientGitSha },
|
|
2397
|
+
...body.updateError === undefined ? {} : { update_error: body.updateError }
|
|
2388
2398
|
});
|
|
2389
2399
|
return parseClientHostReport(response, "POST", path3);
|
|
2390
2400
|
}
|
|
@@ -3471,6 +3481,8 @@ function optionalClientHostMetadata(host, method, path3) {
|
|
|
3471
3481
|
const minimum = optionalClientHostString(host, "minimum_client_version", method, path3);
|
|
3472
3482
|
if (minimum === null)
|
|
3473
3483
|
throw new RelayProtocolError(method, path3, "host.minimum_client_version must be a string");
|
|
3484
|
+
const latest = optionalClientHostString(host, "latest_client_version", method, path3);
|
|
3485
|
+
const updateError = optionalClientHostString(host, "update_error", method, path3);
|
|
3474
3486
|
const compatibility = host.client_compatibility;
|
|
3475
3487
|
if (compatibility !== undefined && compatibility !== "current" && compatibility !== "outdated" && compatibility !== "unknown" && compatibility !== "development") {
|
|
3476
3488
|
throw new RelayProtocolError(method, path3, "host.client_compatibility is invalid");
|
|
@@ -3479,7 +3491,9 @@ function optionalClientHostMetadata(host, method, path3) {
|
|
|
3479
3491
|
...version === undefined ? {} : { client_version: version },
|
|
3480
3492
|
...gitSha === undefined ? {} : { client_git_sha: gitSha },
|
|
3481
3493
|
...minimum === undefined ? {} : { minimum_client_version: minimum },
|
|
3482
|
-
...
|
|
3494
|
+
...latest === undefined ? {} : { latest_client_version: latest },
|
|
3495
|
+
...compatibility === undefined ? {} : { client_compatibility: compatibility },
|
|
3496
|
+
...updateError === undefined ? {} : { update_error: updateError }
|
|
3483
3497
|
};
|
|
3484
3498
|
}
|
|
3485
3499
|
function optionalClientHostString(host, field, method, path3) {
|
|
@@ -4047,7 +4061,7 @@ function redact(value, token) {
|
|
|
4047
4061
|
function bytesToBase64(bytes) {
|
|
4048
4062
|
return Buffer2.from(bytes).toString("base64");
|
|
4049
4063
|
}
|
|
4050
|
-
// .dist-releases/
|
|
4064
|
+
// .dist-releases/1784888160293-2271563/src/relay/config.js
|
|
4051
4065
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
4052
4066
|
import { homedir as homedir3 } from "node:os";
|
|
4053
4067
|
import path3 from "node:path";
|
|
@@ -4122,7 +4136,7 @@ function storedCaptainId(value) {
|
|
|
4122
4136
|
}
|
|
4123
4137
|
return;
|
|
4124
4138
|
}
|
|
4125
|
-
// .dist-releases/
|
|
4139
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/retirement.js
|
|
4126
4140
|
var DEFAULT_THRESHOLD = 3;
|
|
4127
4141
|
var DEFAULT_WINDOW_MS = 30000;
|
|
4128
4142
|
var DEFAULT_COOLDOWN_MS = 1000;
|
|
@@ -4197,7 +4211,7 @@ function isAuthoritativeRetirementReason(reason) {
|
|
|
4197
4211
|
return reason === "monitor_fetch" || reason === "agent_session_patch";
|
|
4198
4212
|
}
|
|
4199
4213
|
|
|
4200
|
-
// .dist-releases/
|
|
4214
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/wait.js
|
|
4201
4215
|
async function waitForWakeableTimeout(ms, setWake, sleep3) {
|
|
4202
4216
|
if (sleep3) {
|
|
4203
4217
|
await Promise.race([
|
|
@@ -4228,7 +4242,7 @@ async function waitForWakeableTimeout(ms, setWake, sleep3) {
|
|
|
4228
4242
|
setWake(null);
|
|
4229
4243
|
}
|
|
4230
4244
|
|
|
4231
|
-
// .dist-releases/
|
|
4245
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/mailbox.js
|
|
4232
4246
|
var CLEAR_TAG = "CLEAR";
|
|
4233
4247
|
var REFRESH_TAG = "WORKFLOW-REFRESH";
|
|
4234
4248
|
var SYNC_TAG = "SYNC";
|
|
@@ -4299,7 +4313,9 @@ class MailboxSupervisor {
|
|
|
4299
4313
|
let handled = await this.dispatchBatch(controls, true);
|
|
4300
4314
|
if (this.stopped)
|
|
4301
4315
|
return handled;
|
|
4302
|
-
const
|
|
4316
|
+
const preview = await this.claimOwnedMessages(true);
|
|
4317
|
+
handled += await this.dispatchBatch(preview.filter(isControl));
|
|
4318
|
+
const messages = preview.filter((message) => !isControl(message));
|
|
4303
4319
|
this.restoreDoorbellAttempts(messages);
|
|
4304
4320
|
this.pruneDoorbellAttempts(messages);
|
|
4305
4321
|
if (messages.length === 0)
|
|
@@ -4722,7 +4738,7 @@ function doorbellToken(messageId) {
|
|
|
4722
4738
|
function refreshCue(_cli) {
|
|
4723
4739
|
return `${REFRESH_TAG}
|
|
4724
4740
|
|
|
4725
|
-
Run \`sail refresh\`
|
|
4741
|
+
Run \`sail refresh\` now to reload your role and instructions, then continue.`;
|
|
4726
4742
|
}
|
|
4727
4743
|
function saveContextCue(agentName, checkpointId) {
|
|
4728
4744
|
return [
|
|
@@ -4764,19 +4780,19 @@ function ordinaryDeliveryAttempt(error) {
|
|
|
4764
4780
|
function _isMissingModerator(error) {
|
|
4765
4781
|
return error instanceof RelayHttpError && error.status === 400 && error.body.includes("no agents match");
|
|
4766
4782
|
}
|
|
4767
|
-
// .dist-releases/
|
|
4783
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/runtime.js
|
|
4768
4784
|
import path9 from "node:path";
|
|
4769
4785
|
import { execFile } from "node:child_process";
|
|
4770
4786
|
import { promisify } from "node:util";
|
|
4771
4787
|
|
|
4772
|
-
// .dist-releases/
|
|
4788
|
+
// .dist-releases/1784888160293-2271563/src/host/managed-materialization.js
|
|
4773
4789
|
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
4774
4790
|
import { constants as fsConstants } from "node:fs";
|
|
4775
4791
|
import { lstat, mkdir as mkdir3, open, readdir, rename, rm as rm2 } from "node:fs/promises";
|
|
4776
4792
|
import { homedir as homedir5 } from "node:os";
|
|
4777
4793
|
import path5 from "node:path";
|
|
4778
4794
|
|
|
4779
|
-
// .dist-releases/
|
|
4795
|
+
// .dist-releases/1784888160293-2271563/src/host/memory-stub.js
|
|
4780
4796
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile3 } from "node:fs/promises";
|
|
4781
4797
|
import { homedir as homedir4 } from "node:os";
|
|
4782
4798
|
import path4 from "node:path";
|
|
@@ -4923,7 +4939,7 @@ function _safePathLabel(value, field) {
|
|
|
4923
4939
|
return trimmed;
|
|
4924
4940
|
}
|
|
4925
4941
|
|
|
4926
|
-
// .dist-releases/
|
|
4942
|
+
// .dist-releases/1784888160293-2271563/src/host/managed-materialization.js
|
|
4927
4943
|
var MANIFEST_FILE = ".sailorbridge-managed-manifest.json";
|
|
4928
4944
|
var BANNER_PREFIX = "# SailorBridge managed file";
|
|
4929
4945
|
var HASH_RE = /^sha256:[a-f0-9]{64}$/u;
|
|
@@ -5449,7 +5465,7 @@ function _expandHome2(value) {
|
|
|
5449
5465
|
return value;
|
|
5450
5466
|
}
|
|
5451
5467
|
|
|
5452
|
-
// .dist-releases/
|
|
5468
|
+
// .dist-releases/1784888160293-2271563/src/host/credential-guardian.js
|
|
5453
5469
|
import { lstat as lstat2, readFile as readFile3, rename as rename2, symlink, unlink, writeFile as writeFile4 } from "node:fs/promises";
|
|
5454
5470
|
import path6 from "node:path";
|
|
5455
5471
|
var DEFAULT_CREDENTIAL_SWEEP_INTERVAL_MS = 60000;
|
|
@@ -5595,7 +5611,7 @@ function _tmpSibling(filePath) {
|
|
|
5595
5611
|
return path6.join(path6.dirname(filePath), `.${path6.basename(filePath)}.sb-guardian.${process.pid}.${tmpSequence}.tmp`);
|
|
5596
5612
|
}
|
|
5597
5613
|
|
|
5598
|
-
// .dist-releases/
|
|
5614
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/resolve.js
|
|
5599
5615
|
var DEFAULT_CAPTURE_LINES = 200;
|
|
5600
5616
|
var MAX_CAPTURE_LINES = 1000;
|
|
5601
5617
|
|
|
@@ -5801,7 +5817,7 @@ function defaultSleep(ms) {
|
|
|
5801
5817
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5802
5818
|
}
|
|
5803
5819
|
|
|
5804
|
-
// .dist-releases/
|
|
5820
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/transcript-backfill.js
|
|
5805
5821
|
import { createHash as createHash3 } from "node:crypto";
|
|
5806
5822
|
import {
|
|
5807
5823
|
closeSync,
|
|
@@ -6220,6 +6236,17 @@ class TranscriptBackfillWorker {
|
|
|
6220
6236
|
store.rememberPostedEvent(source, event.eventId, item.nextOffset, fingerprint);
|
|
6221
6237
|
this.clearPendingIfUnchanged(pendingMessageId);
|
|
6222
6238
|
this.resetRetry();
|
|
6239
|
+
if (result.skippedReason !== undefined) {
|
|
6240
|
+
this.log("transcript_backfill_relay_skipped", {
|
|
6241
|
+
agent: this.options.agentName,
|
|
6242
|
+
engine: this.options.engine,
|
|
6243
|
+
source,
|
|
6244
|
+
offset: item.startOffset,
|
|
6245
|
+
eventId: event.eventId,
|
|
6246
|
+
reason: result.skippedReason
|
|
6247
|
+
});
|
|
6248
|
+
break;
|
|
6249
|
+
}
|
|
6223
6250
|
count += 1;
|
|
6224
6251
|
this.log("transcript_backfill_posted", {
|
|
6225
6252
|
agent: this.options.agentName,
|
|
@@ -6248,7 +6275,8 @@ class TranscriptBackfillWorker {
|
|
|
6248
6275
|
throw new Error("transcript backfill requires session");
|
|
6249
6276
|
const target = this.pending?.replyTarget ?? { kind: "captain" };
|
|
6250
6277
|
const inReplyToMessageId = target.kind === "captain" ? this.pending?.messageId : undefined;
|
|
6251
|
-
|
|
6278
|
+
const origin = target.kind === "captain" ? "transcript-backfill" : undefined;
|
|
6279
|
+
return this.options.relay.postSessionReply(this.options.session, event.text, target, inReplyToMessageId, "REPLY", origin);
|
|
6252
6280
|
}
|
|
6253
6281
|
clearPendingIfUnchanged(pendingMessageId) {
|
|
6254
6282
|
if (this.pending && this.pending.messageId === pendingMessageId)
|
|
@@ -6458,7 +6486,7 @@ function errorMessage4(error) {
|
|
|
6458
6486
|
return error instanceof Error ? error.message : String(error);
|
|
6459
6487
|
}
|
|
6460
6488
|
|
|
6461
|
-
// .dist-releases/
|
|
6489
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/usage-collector.js
|
|
6462
6490
|
import { statSync as statSync2 } from "node:fs";
|
|
6463
6491
|
import path8 from "node:path";
|
|
6464
6492
|
var SUPPORTED_USAGE_ENGINES = new Set(["claude", "codex"]);
|
|
@@ -6867,7 +6895,7 @@ function sourceUnreadableReason(source) {
|
|
|
6867
6895
|
}
|
|
6868
6896
|
}
|
|
6869
6897
|
|
|
6870
|
-
// .dist-releases/
|
|
6898
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/runtime.js
|
|
6871
6899
|
var RESOLVE_CAPTURE_LINES = 200;
|
|
6872
6900
|
var SHORT_LIVED_EXIT_MS = 5000;
|
|
6873
6901
|
var STARTUP_OBSERVATION_MS = 1e4;
|
|
@@ -7537,7 +7565,7 @@ function errorMessage5(error) {
|
|
|
7537
7565
|
function formatRestartCommand(command) {
|
|
7538
7566
|
return command.map((part) => /^[A-Za-z0-9_./:=@%+-]+$/.test(part) ? part : `'${part.replaceAll("'", "'\\''")}'`).join(" ");
|
|
7539
7567
|
}
|
|
7540
|
-
// .dist-releases/
|
|
7568
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/transport.js
|
|
7541
7569
|
var SUPPORTED_PHASE1_CLI_KINDS = ["claude", "codex"];
|
|
7542
7570
|
var PHASE1_ENGINE_GATE_MESSAGE = "Only claude and codex engines are available in this release; opencode and custom CLI engines will open in the next release.";
|
|
7543
7571
|
var PHASE1_TRANSPORT_GATE_MESSAGE = "Only tmux transport is available in this release; sdk, headless, and pty transports will open in the next release.";
|
|
@@ -7745,7 +7773,7 @@ function hasCodexSafetyDriverOptions(options) {
|
|
|
7745
7773
|
return options?.codex?.sandboxMode !== undefined || options?.codex?.approvalPolicy !== undefined || options?.codex?.yolo !== undefined;
|
|
7746
7774
|
}
|
|
7747
7775
|
|
|
7748
|
-
// .dist-releases/
|
|
7776
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/cli-options.js
|
|
7749
7777
|
function parseSuperviseArgs(argv) {
|
|
7750
7778
|
const split = argv.indexOf("--");
|
|
7751
7779
|
const flagArgs = split >= 0 ? argv.slice(0, split) : argv;
|
|
@@ -7897,7 +7925,7 @@ function optionalBoolean(value, label) {
|
|
|
7897
7925
|
return false;
|
|
7898
7926
|
throw new Error(`${label} must be true or false`);
|
|
7899
7927
|
}
|
|
7900
|
-
// .dist-releases/
|
|
7928
|
+
// .dist-releases/1784888160293-2271563/src/supervisor/tmux-availability.js
|
|
7901
7929
|
import { spawn as spawn3 } from "node:child_process";
|
|
7902
7930
|
import { createInterface } from "node:readline";
|
|
7903
7931
|
function isTmuxAvailable(spawnFn = spawn3) {
|
|
@@ -8014,7 +8042,7 @@ function _tmuxMissingMessage(platform2) {
|
|
|
8014
8042
|
const how = platform2 === "darwin" ? "brew install tmux" : platform2 === "linux" ? "install tmux via your package manager (e.g. sudo apt-get install -y tmux)" : "install tmux";
|
|
8015
8043
|
return `tmux is required in this release but was not found. Install tmux (${how}) and re-run.`;
|
|
8016
8044
|
}
|
|
8017
|
-
// .dist-releases/
|
|
8045
|
+
// .dist-releases/1784888160293-2271563/src/output-format.js
|
|
8018
8046
|
function parseOutputArgs(argv) {
|
|
8019
8047
|
const separator = argv.indexOf("--");
|
|
8020
8048
|
const localArgv = separator < 0 ? argv : argv.slice(0, separator);
|
|
@@ -8107,7 +8135,7 @@ ${normalized.split(`
|
|
|
8107
8135
|
`)}`;
|
|
8108
8136
|
}
|
|
8109
8137
|
|
|
8110
|
-
// .dist-releases/
|
|
8138
|
+
// .dist-releases/1784888160293-2271563/src/plain-output-fields.js
|
|
8111
8139
|
var PREVIEW_LIMIT = 20;
|
|
8112
8140
|
var UNSAFE_DISPLAY_CODE_POINT = /[\u007f-\u009f\u2028-\u202e\u2066-\u2069]/gu;
|
|
8113
8141
|
function renderTaskPlain(command, value) {
|
|
@@ -8515,7 +8543,7 @@ function _omissionLine(total) {
|
|
|
8515
8543
|
return total > PREVIEW_LIMIT ? `Omitted ${total - PREVIEW_LIMIT}; rerun with --format json for the complete response.` : undefined;
|
|
8516
8544
|
}
|
|
8517
8545
|
|
|
8518
|
-
// .dist-releases/
|
|
8546
|
+
// .dist-releases/1784888160293-2271563/src/host/cli.js
|
|
8519
8547
|
var HOST_RELAY_SUBCOMMANDS = new Set(["consume", "heartbeat", "list", "register"]);
|
|
8520
8548
|
async function runHostCommandFromCli(client, argv, config, io) {
|
|
8521
8549
|
const sub = argv[0] ?? "list";
|
|
@@ -8753,7 +8781,7 @@ function optionalDisplayName(value) {
|
|
|
8753
8781
|
const trimmed = value?.trim();
|
|
8754
8782
|
return trimmed || undefined;
|
|
8755
8783
|
}
|
|
8756
|
-
// .dist-releases/
|
|
8784
|
+
// .dist-releases/1784888160293-2271563/src/host/service.js
|
|
8757
8785
|
import { execFile as execFileCb } from "node:child_process";
|
|
8758
8786
|
import { createHash as createHash4 } from "node:crypto";
|
|
8759
8787
|
import { constants as fsConstants2 } from "node:fs";
|
|
@@ -8779,6 +8807,18 @@ async function installHostService(options, deps = {}) {
|
|
|
8779
8807
|
return installSystemd(flags, runtime, paths, command);
|
|
8780
8808
|
return installLaunchd(flags, runtime, paths, command);
|
|
8781
8809
|
}
|
|
8810
|
+
async function restartRunningHostService(deps = {}) {
|
|
8811
|
+
const runtime = serviceRuntime(deps);
|
|
8812
|
+
if (runtime.platform !== "linux" && runtime.platform !== "darwin") {
|
|
8813
|
+
return { restarted: false, reason: "unsupported-platform" };
|
|
8814
|
+
}
|
|
8815
|
+
const paths = servicePaths(runtime, { dryRun: false });
|
|
8816
|
+
if (!await _isManagedHostService(runtime, paths))
|
|
8817
|
+
return { restarted: false, reason: "not-managed" };
|
|
8818
|
+
if (runtime.platform === "linux")
|
|
8819
|
+
return _restartRunningSystemd(runtime, paths);
|
|
8820
|
+
return _restartRunningLaunchd(runtime, paths);
|
|
8821
|
+
}
|
|
8782
8822
|
var UNSUPPORTED_SERVICE_PLATFORM = "host service supports Linux systemd and macOS launchd only";
|
|
8783
8823
|
async function runHostServiceCommandFromCli(argv, io, deps = {}) {
|
|
8784
8824
|
const action = argv[0] ?? "status";
|
|
@@ -8968,6 +9008,32 @@ async function statusLaunchd(runtime, paths, io) {
|
|
|
8968
9008
|
const installed = await fileExists(runtime, paths.file);
|
|
8969
9009
|
_writeServiceOutput(io, { status: active ? "active" : "inactive", installed, platform: "launchd", file: paths.file, linger: "not-applicable" });
|
|
8970
9010
|
}
|
|
9011
|
+
async function _restartRunningSystemd(runtime, paths) {
|
|
9012
|
+
const active = await optionalExec(runtime, "systemctl", ["--user", "is-active", paths.serviceName]);
|
|
9013
|
+
if (active?.stdout.trim() !== "active")
|
|
9014
|
+
return { restarted: false, reason: "not-running" };
|
|
9015
|
+
await runtime.execFile("systemctl", ["--user", "restart", paths.serviceName]);
|
|
9016
|
+
return { restarted: true, platform: "systemd", target: paths.serviceName };
|
|
9017
|
+
}
|
|
9018
|
+
async function _restartRunningLaunchd(runtime, paths) {
|
|
9019
|
+
const target = launchdServiceTarget(runtime.uid, paths.launchdLabel);
|
|
9020
|
+
if (!await optionalExec(runtime, "launchctl", ["print", target])) {
|
|
9021
|
+
return { restarted: false, reason: "not-running" };
|
|
9022
|
+
}
|
|
9023
|
+
await runtime.execFile("launchctl", ["kickstart", "-k", target]);
|
|
9024
|
+
return { restarted: true, platform: "launchd", target: paths.launchdLabel };
|
|
9025
|
+
}
|
|
9026
|
+
async function _isManagedHostService(runtime, paths) {
|
|
9027
|
+
try {
|
|
9028
|
+
const definition = await _readDefinition(runtime, paths.file);
|
|
9029
|
+
if (!definition)
|
|
9030
|
+
return false;
|
|
9031
|
+
const manager = runtime.platform === "linux" ? "systemd" : "launchd";
|
|
9032
|
+
return _isLegacyHostDefinition(definition, manager);
|
|
9033
|
+
} catch {
|
|
9034
|
+
return false;
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
8971
9037
|
function serviceRuntime(deps) {
|
|
8972
9038
|
const info = userInfo();
|
|
8973
9039
|
return {
|
|
@@ -9105,8 +9171,8 @@ function _isLegacyHostDefinition(text, manager) {
|
|
|
9105
9171
|
function _isSailorBridgeEntry(value) {
|
|
9106
9172
|
if (!value)
|
|
9107
9173
|
return false;
|
|
9108
|
-
const
|
|
9109
|
-
return
|
|
9174
|
+
const normalized = `/${value.replace(/\\/gu, "/").split("/").filter(Boolean).join("/")}`;
|
|
9175
|
+
return normalized.endsWith("/@sailorbridge/client/dist/cli.js") || normalized.endsWith("/@sailorbridge/client/dist/src/cli.js");
|
|
9110
9176
|
}
|
|
9111
9177
|
function _systemdExecStart(text) {
|
|
9112
9178
|
const values = [...text.matchAll(/^\s*ExecStart\s*=(.*)$/gmu)].map((match) => match[1]?.trim() ?? "").filter(Boolean);
|
|
@@ -9236,7 +9302,7 @@ function writeServiceLog(io, event, fields) {
|
|
|
9236
9302
|
io.stderr.write(`${JSON.stringify({ ts: new Date().toISOString(), event, ...fields ?? {} })}
|
|
9237
9303
|
`);
|
|
9238
9304
|
}
|
|
9239
|
-
// .dist-releases/
|
|
9305
|
+
// .dist-releases/1784888160293-2271563/src/host/git-remote.js
|
|
9240
9306
|
var GIT_SECRET_PATH_MARKERS = [
|
|
9241
9307
|
"token",
|
|
9242
9308
|
"credential",
|
|
@@ -9328,7 +9394,7 @@ function looksLikeCredential(segment2) {
|
|
|
9328
9394
|
return value.length >= 32 && /^[A-Za-z0-9_-]+$/u.test(value);
|
|
9329
9395
|
}
|
|
9330
9396
|
|
|
9331
|
-
// .dist-releases/
|
|
9397
|
+
// .dist-releases/1784888160293-2271563/src/host/start-spec.js
|
|
9332
9398
|
var TRANSPORTS = ["auto", "sdk", "pty", "tmux", "headless"];
|
|
9333
9399
|
var SUPPORTED_PHASE1_ENGINES = ["claude", "codex"];
|
|
9334
9400
|
var ENGINE_PATTERN = /^[a-z][a-z0-9._-]{0,63}$/u;
|
|
@@ -9578,7 +9644,7 @@ function _trimmed(value, label) {
|
|
|
9578
9644
|
throw new Error(`${label} must not be empty`);
|
|
9579
9645
|
return trimmed;
|
|
9580
9646
|
}
|
|
9581
|
-
// .dist-releases/
|
|
9647
|
+
// .dist-releases/1784888160293-2271563/src/host/workspace.js
|
|
9582
9648
|
import { spawn as spawn4 } from "node:child_process";
|
|
9583
9649
|
import { existsSync as existsSync4 } from "node:fs";
|
|
9584
9650
|
import { mkdir as mkdir5, readdir as readdir2, rename as rename4, stat } from "node:fs/promises";
|
|
@@ -9809,7 +9875,7 @@ function _safeSegment(value) {
|
|
|
9809
9875
|
throw new Error("workspace path segment is empty after sanitizing");
|
|
9810
9876
|
return segment2;
|
|
9811
9877
|
}
|
|
9812
|
-
// .dist-releases/
|
|
9878
|
+
// .dist-releases/1784888160293-2271563/src/host/workspace-inventory.js
|
|
9813
9879
|
import { access as access2 } from "node:fs/promises";
|
|
9814
9880
|
import { constants } from "node:fs";
|
|
9815
9881
|
import { execFile as execFile2 } from "node:child_process";
|
|
@@ -9901,25 +9967,179 @@ async function canAccess(path12, mode, deps) {
|
|
|
9901
9967
|
return false;
|
|
9902
9968
|
}
|
|
9903
9969
|
}
|
|
9904
|
-
// .dist-releases/
|
|
9905
|
-
import {
|
|
9906
|
-
import {
|
|
9970
|
+
// .dist-releases/1784888160293-2271563/src/upgrade.js
|
|
9971
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
9972
|
+
import { execFile as execFileCb2 } from "node:child_process";
|
|
9973
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
9907
9974
|
import path12 from "node:path";
|
|
9975
|
+
import { promisify as promisify4 } from "node:util";
|
|
9976
|
+
var execFileDefault2 = promisify4(execFileCb2);
|
|
9977
|
+
var CLIENT_PACKAGE = "@sailorbridge/client";
|
|
9978
|
+
var LATEST_PACKAGE = `${CLIENT_PACKAGE}@latest`;
|
|
9979
|
+
async function runUpgradeFromCli(argv, io, deps = {}) {
|
|
9980
|
+
if (argv.length)
|
|
9981
|
+
throw new Error(`upgrade takes no arguments: ${argv.join(" ")}`);
|
|
9982
|
+
const before = deps.currentVersion ?? CLIENT_VERSION;
|
|
9983
|
+
await (deps.installLatest ?? installLatestClientPackage)();
|
|
9984
|
+
const after = await (deps.readInstalledVersion ?? readInstalledClientVersion)();
|
|
9985
|
+
if (before === after) {
|
|
9986
|
+
io.stdout.write(`SailorBridge client is already up to date (${after}).
|
|
9987
|
+
`);
|
|
9988
|
+
return;
|
|
9989
|
+
}
|
|
9990
|
+
const service = await (deps.restartHostService ?? restartRunningHostService)();
|
|
9991
|
+
_writeUpgradeResult(io.stdout, before, after, service);
|
|
9992
|
+
}
|
|
9993
|
+
function installLatestClientPackage() {
|
|
9994
|
+
return new Promise((resolve2, reject) => {
|
|
9995
|
+
const child = spawn5("npm", ["i", "-g", LATEST_PACKAGE], { stdio: "inherit" });
|
|
9996
|
+
child.once("error", reject);
|
|
9997
|
+
child.once("close", (code, signal) => {
|
|
9998
|
+
if (code === 0)
|
|
9999
|
+
resolve2();
|
|
10000
|
+
else
|
|
10001
|
+
reject(new Error(`npm i -g ${LATEST_PACKAGE} failed (${signal ?? `exit ${code ?? "unknown"}`})`));
|
|
10002
|
+
});
|
|
10003
|
+
});
|
|
10004
|
+
}
|
|
10005
|
+
async function readInstalledClientVersion() {
|
|
10006
|
+
const { stdout } = await execFileDefault2("npm", ["root", "-g"]);
|
|
10007
|
+
const root = String(stdout).trim();
|
|
10008
|
+
if (!root)
|
|
10009
|
+
throw new Error("npm root -g returned an empty path after upgrade");
|
|
10010
|
+
const packageJson = path12.join(root, "@sailorbridge", "client", "package.json");
|
|
10011
|
+
const parsed = JSON.parse(await readFile5(packageJson, "utf8"));
|
|
10012
|
+
const version = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "version") : undefined;
|
|
10013
|
+
if (typeof version !== "string" || !version.trim()) {
|
|
10014
|
+
throw new Error(`${packageJson} has no valid version after upgrade`);
|
|
10015
|
+
}
|
|
10016
|
+
return version.trim();
|
|
10017
|
+
}
|
|
10018
|
+
function _writeUpgradeResult(output, before, after, service) {
|
|
10019
|
+
if (service.restarted) {
|
|
10020
|
+
output.write(`Updated SailorBridge client from ${before} to ${after} and restarted ${service.target} (${service.platform}).
|
|
10021
|
+
`);
|
|
10022
|
+
return;
|
|
10023
|
+
}
|
|
10024
|
+
output.write(`Updated SailorBridge client from ${before} to ${after}. No running SailorBridge-managed host service was found; stop and rerun 'sailorbridge host run' to load ${after}.
|
|
10025
|
+
`);
|
|
10026
|
+
}
|
|
10027
|
+
|
|
10028
|
+
// .dist-releases/1784888160293-2271563/src/host/auto-update.js
|
|
10029
|
+
var AUTO_UPDATE_HARD_DEADLINE_MS = 24 * 60 * 60 * 1000;
|
|
10030
|
+
var AUTO_UPDATE_ATTEMPT_COOLDOWN_MS = 60 * 1000;
|
|
10031
|
+
var MAX_UPDATE_ERROR_LENGTH = 500;
|
|
10032
|
+
function createAutoUpdater(options) {
|
|
10033
|
+
const logger = options.logger ?? (() => {});
|
|
10034
|
+
const deps = options.deps ?? {};
|
|
10035
|
+
const now = deps.now ?? (() => Date.now());
|
|
10036
|
+
const currentVersion = deps.currentVersion ?? CLIENT_VERSION;
|
|
10037
|
+
const installLatest = deps.installLatest ?? installLatestClientPackage;
|
|
10038
|
+
const readInstalledVersion = deps.readInstalledVersion ?? readInstalledClientVersion;
|
|
10039
|
+
const restartHostService = deps.restartHostService ?? restartRunningHostService;
|
|
10040
|
+
let pendingSince;
|
|
10041
|
+
let lastAttemptAt;
|
|
10042
|
+
let updateError;
|
|
10043
|
+
let installedVersion;
|
|
10044
|
+
const _attempt = async (reason, target) => {
|
|
10045
|
+
if (lastAttemptAt !== undefined && now() - lastAttemptAt < AUTO_UPDATE_ATTEMPT_COOLDOWN_MS)
|
|
10046
|
+
return;
|
|
10047
|
+
lastAttemptAt = now();
|
|
10048
|
+
logger("host_auto_update_start", { reason, target, current: currentVersion });
|
|
10049
|
+
try {
|
|
10050
|
+
await installLatest();
|
|
10051
|
+
const after = await readInstalledVersion();
|
|
10052
|
+
updateError = undefined;
|
|
10053
|
+
installedVersion = after;
|
|
10054
|
+
if (after === currentVersion) {
|
|
10055
|
+
logger("host_auto_update_noop", { reason, target, installed: after });
|
|
10056
|
+
return;
|
|
10057
|
+
}
|
|
10058
|
+
const report = await restartHostService();
|
|
10059
|
+
if (report.restarted) {
|
|
10060
|
+
logger("host_auto_update_restarting", { from: currentVersion, to: after, platform: report.platform, target: report.target });
|
|
10061
|
+
} else {
|
|
10062
|
+
logger("host_auto_update_installed_pending_restart", { from: currentVersion, to: after, reason: report.reason });
|
|
10063
|
+
}
|
|
10064
|
+
} catch (error) {
|
|
10065
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10066
|
+
updateError = message.length <= MAX_UPDATE_ERROR_LENGTH ? message : `${message.slice(0, MAX_UPDATE_ERROR_LENGTH - 3)}...`;
|
|
10067
|
+
logger("host_auto_update_error", { reason, target, error: updateError });
|
|
10068
|
+
}
|
|
10069
|
+
};
|
|
10070
|
+
return {
|
|
10071
|
+
async onHostReport(host) {
|
|
10072
|
+
if (!options.enabled)
|
|
10073
|
+
return;
|
|
10074
|
+
const latest = host.latest_client_version;
|
|
10075
|
+
if (!latest || compareReleaseSemver(latest, currentVersion) !== 1) {
|
|
10076
|
+
pendingSince = undefined;
|
|
10077
|
+
return;
|
|
10078
|
+
}
|
|
10079
|
+
const installedCmp = installedVersion === undefined ? null : compareReleaseSemver(installedVersion, latest);
|
|
10080
|
+
if (installedCmp === 0 || installedCmp === 1)
|
|
10081
|
+
return;
|
|
10082
|
+
if (pendingSince === undefined) {
|
|
10083
|
+
pendingSince = now();
|
|
10084
|
+
logger("host_auto_update_pending", { latest, current: currentVersion });
|
|
10085
|
+
}
|
|
10086
|
+
const forced = now() - pendingSince >= AUTO_UPDATE_HARD_DEADLINE_MS;
|
|
10087
|
+
if (options.isActive() && !forced)
|
|
10088
|
+
return;
|
|
10089
|
+
if (options.isMidWork())
|
|
10090
|
+
return;
|
|
10091
|
+
await _attempt(forced ? "deadline-forced" : "scheduled", latest);
|
|
10092
|
+
},
|
|
10093
|
+
async onUpgradeRequired(detail) {
|
|
10094
|
+
if (!options.enabled) {
|
|
10095
|
+
logger("host_auto_update_disabled_upgrade_required", { detail });
|
|
10096
|
+
return;
|
|
10097
|
+
}
|
|
10098
|
+
if (options.isMidWork())
|
|
10099
|
+
return;
|
|
10100
|
+
await _attempt("relay-rejected", null);
|
|
10101
|
+
},
|
|
10102
|
+
pendingUpdateError() {
|
|
10103
|
+
return updateError;
|
|
10104
|
+
}
|
|
10105
|
+
};
|
|
10106
|
+
}
|
|
10107
|
+
function compareReleaseSemver(a, b) {
|
|
10108
|
+
const left = _releaseTuple(a);
|
|
10109
|
+
const right = _releaseTuple(b);
|
|
10110
|
+
if (left === null || right === null)
|
|
10111
|
+
return null;
|
|
10112
|
+
for (let i = 0;i < 3; i += 1) {
|
|
10113
|
+
if (left[i] !== right[i])
|
|
10114
|
+
return left[i] < right[i] ? -1 : 1;
|
|
10115
|
+
}
|
|
10116
|
+
return 0;
|
|
10117
|
+
}
|
|
10118
|
+
function _releaseTuple(value) {
|
|
10119
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(value);
|
|
10120
|
+
if (!match)
|
|
10121
|
+
return null;
|
|
10122
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
10123
|
+
}
|
|
10124
|
+
// .dist-releases/1784888160293-2271563/src/host/host-config.js
|
|
10125
|
+
import { chmod as chmod3, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile6 } from "node:fs/promises";
|
|
10126
|
+
import { homedir as homedir10 } from "node:os";
|
|
10127
|
+
import path13 from "node:path";
|
|
9908
10128
|
var HOST_CONFIG_KIND = "sailorbridge-host-config";
|
|
9909
10129
|
function defaultHostConfigPath() {
|
|
9910
|
-
return
|
|
10130
|
+
return path13.join(homedir10(), ".sailorbridge", "host-config.json");
|
|
9911
10131
|
}
|
|
9912
10132
|
function normalizeWorkspacePath(entry) {
|
|
9913
10133
|
const trimmed = entry.trim();
|
|
9914
10134
|
if (!trimmed)
|
|
9915
10135
|
throw new Error("workspace path must not be empty");
|
|
9916
10136
|
const expanded = trimmed === "~" ? homedir10() : trimmed.startsWith("~/") ? `${homedir10()}${trimmed.slice(1)}` : trimmed;
|
|
9917
|
-
return
|
|
10137
|
+
return path13.resolve(expanded);
|
|
9918
10138
|
}
|
|
9919
10139
|
async function loadHostConfig(configPath = defaultHostConfigPath()) {
|
|
9920
10140
|
let text;
|
|
9921
10141
|
try {
|
|
9922
|
-
text = await
|
|
10142
|
+
text = await readFile6(configPath, "utf8");
|
|
9923
10143
|
} catch (error) {
|
|
9924
10144
|
if (error.code === "ENOENT")
|
|
9925
10145
|
return { kind: HOST_CONFIG_KIND, workspaces: [] };
|
|
@@ -9928,8 +10148,8 @@ async function loadHostConfig(configPath = defaultHostConfigPath()) {
|
|
|
9928
10148
|
return _parseHostConfig(text, configPath);
|
|
9929
10149
|
}
|
|
9930
10150
|
async function saveHostConfig(configPath, config) {
|
|
9931
|
-
await mkdir6(
|
|
9932
|
-
await chmod3(
|
|
10151
|
+
await mkdir6(path13.dirname(configPath), { recursive: true, mode: 448 });
|
|
10152
|
+
await chmod3(path13.dirname(configPath), 448);
|
|
9933
10153
|
await writeFile6(configPath, `${JSON.stringify(config, null, 2)}
|
|
9934
10154
|
`, { mode: 384 });
|
|
9935
10155
|
await chmod3(configPath, 384);
|
|
@@ -9939,7 +10159,7 @@ async function addHostWorkspace(configPath, workspacePath) {
|
|
|
9939
10159
|
const config = await loadHostConfig(configPath);
|
|
9940
10160
|
if (config.workspaces.includes(normalized))
|
|
9941
10161
|
return { config, path: normalized, added: false };
|
|
9942
|
-
const next = {
|
|
10162
|
+
const next = { ...config, workspaces: [...config.workspaces, normalized] };
|
|
9943
10163
|
await saveHostConfig(configPath, next);
|
|
9944
10164
|
return { config: next, path: normalized, added: true };
|
|
9945
10165
|
}
|
|
@@ -9960,7 +10180,7 @@ async function removeHostWorkspace(configPath, workspacePath) {
|
|
|
9960
10180
|
const config = await loadHostConfig(configPath);
|
|
9961
10181
|
if (!config.workspaces.includes(normalized))
|
|
9962
10182
|
return { config, path: normalized, removed: false };
|
|
9963
|
-
const next = {
|
|
10183
|
+
const next = { ...config, workspaces: config.workspaces.filter((entry) => entry !== normalized) };
|
|
9964
10184
|
await saveHostConfig(configPath, next);
|
|
9965
10185
|
return { config: next, path: normalized, removed: true };
|
|
9966
10186
|
}
|
|
@@ -9984,9 +10204,16 @@ function _parseHostConfig(text, configPath) {
|
|
|
9984
10204
|
throw new Error(`host config workspaces[${index}] must be a non-empty string`);
|
|
9985
10205
|
return value.trim();
|
|
9986
10206
|
});
|
|
9987
|
-
|
|
10207
|
+
if (record.auto_update !== undefined && typeof record.auto_update !== "boolean") {
|
|
10208
|
+
throw new Error(`host config at ${configPath} auto_update must be a boolean`);
|
|
10209
|
+
}
|
|
10210
|
+
return {
|
|
10211
|
+
kind: HOST_CONFIG_KIND,
|
|
10212
|
+
workspaces,
|
|
10213
|
+
...record.auto_update === undefined ? {} : { auto_update: record.auto_update }
|
|
10214
|
+
};
|
|
9988
10215
|
}
|
|
9989
|
-
// .dist-releases/
|
|
10216
|
+
// .dist-releases/1784888160293-2271563/src/host/host-workspace-cli.js
|
|
9990
10217
|
async function runHostWorkspaceCommandFromCli(argv, io, deps = {}) {
|
|
9991
10218
|
const configPath = deps.configPath ?? defaultHostConfigPath();
|
|
9992
10219
|
const sub = argv[0] ?? "list";
|
|
@@ -10030,7 +10257,7 @@ function _renderAddPlain(result) {
|
|
|
10030
10257
|
return result.note ? `${status} ${result.path}
|
|
10031
10258
|
${result.note}` : `${status} ${result.path}`;
|
|
10032
10259
|
}
|
|
10033
|
-
// .dist-releases/
|
|
10260
|
+
// .dist-releases/1784888160293-2271563/src/host/agent-env.js
|
|
10034
10261
|
var RUNTIME_NATIVE_HOME_ENV = new Set(["CLAUDE_CONFIG_DIR", "CODEX_HOME"]);
|
|
10035
10262
|
function buildAgentEnv(options) {
|
|
10036
10263
|
const env = {};
|
|
@@ -10059,25 +10286,25 @@ function buildAgentEnv(options) {
|
|
|
10059
10286
|
}
|
|
10060
10287
|
return env;
|
|
10061
10288
|
}
|
|
10062
|
-
// .dist-releases/
|
|
10063
|
-
import
|
|
10289
|
+
// .dist-releases/1784888160293-2271563/src/host/runtime-env.js
|
|
10290
|
+
import path17 from "node:path";
|
|
10064
10291
|
|
|
10065
|
-
// .dist-releases/
|
|
10066
|
-
import { chmod as chmod4, mkdir as mkdir7, readFile as
|
|
10292
|
+
// .dist-releases/1784888160293-2271563/src/host/agent-defaults.js
|
|
10293
|
+
import { chmod as chmod4, mkdir as mkdir7, readFile as readFile8, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
|
|
10067
10294
|
import { homedir as homedir11 } from "node:os";
|
|
10068
|
-
import
|
|
10295
|
+
import path15 from "node:path";
|
|
10069
10296
|
|
|
10070
|
-
// .dist-releases/
|
|
10071
|
-
import { readFile as
|
|
10072
|
-
import
|
|
10297
|
+
// .dist-releases/1784888160293-2271563/src/host/claude-settings.js
|
|
10298
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
10299
|
+
import path14 from "node:path";
|
|
10073
10300
|
async function readHostClaudeSettings(claudeConfigDir) {
|
|
10074
|
-
const settings = await _readSettingsObject(
|
|
10301
|
+
const settings = await _readSettingsObject(path14.join(claudeConfigDir, "settings.json"));
|
|
10075
10302
|
return { env: _stringValues(settings.env), apiKeyHelper: _nonEmptyString(settings.apiKeyHelper) };
|
|
10076
10303
|
}
|
|
10077
10304
|
async function _readSettingsObject(filePath) {
|
|
10078
10305
|
let text;
|
|
10079
10306
|
try {
|
|
10080
|
-
text = await
|
|
10307
|
+
text = await readFile7(filePath, "utf8");
|
|
10081
10308
|
} catch (error) {
|
|
10082
10309
|
if (error.code === "ENOENT")
|
|
10083
10310
|
return {};
|
|
@@ -10108,7 +10335,7 @@ function _nonEmptyString(value) {
|
|
|
10108
10335
|
return typeof value === "string" && value.trim() ? value : null;
|
|
10109
10336
|
}
|
|
10110
10337
|
|
|
10111
|
-
// .dist-releases/
|
|
10338
|
+
// .dist-releases/1784888160293-2271563/src/host/agent-defaults.js
|
|
10112
10339
|
var CODEX_BLOCK_BEGIN = "# sailorbridge-terse-defaults:begin";
|
|
10113
10340
|
var CODEX_BLOCK_END = "# sailorbridge-terse-defaults:end";
|
|
10114
10341
|
var CODEX_MODEL_BLOCK_BEGIN = "# sailorbridge-host-model-settings:begin";
|
|
@@ -10760,23 +10987,23 @@ function _warnStatusLine(message) {
|
|
|
10760
10987
|
`);
|
|
10761
10988
|
}
|
|
10762
10989
|
function resolveClaudeStatusLineCommand(runtime = { execPath: process.execPath, argv1: process.argv[1] }) {
|
|
10763
|
-
const name =
|
|
10764
|
-
const prefix = name === "node" || name === "bun" ? [
|
|
10990
|
+
const name = path15.basename(runtime.execPath);
|
|
10991
|
+
const prefix = name === "node" || name === "bun" ? [path15.resolve(runtime.execPath), _requireEntry(runtime.argv1)] : [path15.resolve(runtime.execPath)];
|
|
10765
10992
|
return [...prefix.map(_shellSingleQuote), "host", "statusline"].join(" ");
|
|
10766
10993
|
}
|
|
10767
10994
|
function _requireEntry(argv1) {
|
|
10768
10995
|
const entry = argv1?.trim();
|
|
10769
10996
|
if (!entry)
|
|
10770
10997
|
throw new Error("cannot resolve claude statusline command: client entry point is unknown");
|
|
10771
|
-
return
|
|
10998
|
+
return path15.resolve(entry);
|
|
10772
10999
|
}
|
|
10773
11000
|
async function _materializeClaudeDefaults(homeDir, workspaceDir, statusLineCommand, warn = _warnStatusLine, sourceHomeDir) {
|
|
10774
|
-
const settingsPath =
|
|
10775
|
-
const stylePath =
|
|
10776
|
-
const hooksDir =
|
|
10777
|
-
const hygienePath =
|
|
10778
|
-
const refsPath =
|
|
10779
|
-
await mkdir7(
|
|
11001
|
+
const settingsPath = path15.join(homeDir, "settings.json");
|
|
11002
|
+
const stylePath = path15.join(homeDir, "output-styles", "sailorbridge-terse.md");
|
|
11003
|
+
const hooksDir = path15.join(homeDir, "hooks");
|
|
11004
|
+
const hygienePath = path15.join(hooksDir, "tool-output-hygiene.py");
|
|
11005
|
+
const refsPath = path15.join(hooksDir, "stale-refs-guard.py");
|
|
11006
|
+
await mkdir7(path15.dirname(stylePath), { recursive: true });
|
|
10780
11007
|
await _writeManagedFile(stylePath, CLAUDE_TERSE_STYLE, false);
|
|
10781
11008
|
await mkdir7(hooksDir, { recursive: true });
|
|
10782
11009
|
await _writeManagedFile(hygienePath, TOOL_OUTPUT_HYGIENE, true);
|
|
@@ -10791,7 +11018,7 @@ async function _materializeClaudeDefaults(homeDir, workspaceDir, statusLineComma
|
|
|
10791
11018
|
{ matcher: "Bash", command: `python3 ${_shellSingleQuote(refsPath)}` }
|
|
10792
11019
|
]);
|
|
10793
11020
|
_ensureClaudeStatusLine(settings, statusLineCommand ?? resolveClaudeStatusLineCommand(), warn);
|
|
10794
|
-
await mkdir7(
|
|
11021
|
+
await mkdir7(path15.dirname(settingsPath), { recursive: true });
|
|
10795
11022
|
await writeFile7(settingsPath, JSON.stringify(settings, null, 2) + `
|
|
10796
11023
|
`, { mode: 384 });
|
|
10797
11024
|
if (workspaceDir)
|
|
@@ -10806,10 +11033,10 @@ async function _mergeHostClaudeEnv(settings, sourceHomeDir) {
|
|
|
10806
11033
|
settings.env = { ..._jsonObject(settings.env, "Claude settings env"), ...hostEnv };
|
|
10807
11034
|
}
|
|
10808
11035
|
async function _trustClaudeWorkspace(homeDir, workspaceDir) {
|
|
10809
|
-
const configPath =
|
|
11036
|
+
const configPath = path15.join(homeDir, ".claude.json");
|
|
10810
11037
|
const config = await _readJsonObject(configPath);
|
|
10811
11038
|
const projects = _jsonObject(config.projects, "Claude config projects");
|
|
10812
|
-
const projectPath =
|
|
11039
|
+
const projectPath = path15.resolve(_expandHome3(workspaceDir));
|
|
10813
11040
|
for (const trustedPath of await _claudeTrustRoots(projectPath)) {
|
|
10814
11041
|
const project = _jsonObject(projects[trustedPath], `Claude config project ${trustedPath}`);
|
|
10815
11042
|
project.hasTrustDialogAccepted = true;
|
|
@@ -10817,12 +11044,12 @@ async function _trustClaudeWorkspace(homeDir, workspaceDir) {
|
|
|
10817
11044
|
}
|
|
10818
11045
|
config.projects = projects;
|
|
10819
11046
|
config.hasCompletedOnboarding = true;
|
|
10820
|
-
await mkdir7(
|
|
11047
|
+
await mkdir7(path15.dirname(configPath), { recursive: true });
|
|
10821
11048
|
await writeFile7(configPath, JSON.stringify(config, null, 2) + `
|
|
10822
11049
|
`, { mode: 384 });
|
|
10823
11050
|
}
|
|
10824
11051
|
async function _claudeTrustRoots(projectPath) {
|
|
10825
|
-
const pointer =
|
|
11052
|
+
const pointer = path15.join(projectPath, ".git");
|
|
10826
11053
|
let stats;
|
|
10827
11054
|
try {
|
|
10828
11055
|
stats = await stat2(pointer);
|
|
@@ -10831,12 +11058,12 @@ async function _claudeTrustRoots(projectPath) {
|
|
|
10831
11058
|
}
|
|
10832
11059
|
if (!stats.isFile())
|
|
10833
11060
|
return [projectPath];
|
|
10834
|
-
const gitdir = /^gitdir:\s*(.+)\s*$/m.exec(await
|
|
11061
|
+
const gitdir = /^gitdir:\s*(.+)\s*$/m.exec(await readFile8(pointer, "utf8"))?.[1];
|
|
10835
11062
|
if (!gitdir) {
|
|
10836
11063
|
throw new Error(`workspace ${projectPath} has an unreadable .git pointer — cannot pre-trust its main repository for claude`);
|
|
10837
11064
|
}
|
|
10838
|
-
const resolved =
|
|
10839
|
-
const marker = `${
|
|
11065
|
+
const resolved = path15.resolve(projectPath, gitdir);
|
|
11066
|
+
const marker = `${path15.sep}.git${path15.sep}worktrees${path15.sep}`;
|
|
10840
11067
|
const markerIndex = resolved.indexOf(marker);
|
|
10841
11068
|
if (markerIndex === -1)
|
|
10842
11069
|
return [projectPath];
|
|
@@ -10865,26 +11092,26 @@ function _claudeStatusLineShouldBeReplaced(command) {
|
|
|
10865
11092
|
if (CLAUDE_STATUSLINE_SUBCOMMAND_RE.test(trimmed))
|
|
10866
11093
|
return true;
|
|
10867
11094
|
const first = trimmed.split(/\s+/u)[0] ?? "";
|
|
10868
|
-
return SAIL_CLAUDE_STATUSLINE_BASENAMES.has(
|
|
11095
|
+
return SAIL_CLAUDE_STATUSLINE_BASENAMES.has(path15.basename(first));
|
|
10869
11096
|
}
|
|
10870
11097
|
function _claudeStatusLineConfig(command) {
|
|
10871
11098
|
return { type: "command", command, refreshInterval: 20 };
|
|
10872
11099
|
}
|
|
10873
11100
|
async function _materializeCodexDefaults(homeDir, workspaceDir, sourceHomeDir, warn = _warnStatusLine) {
|
|
10874
|
-
const configPath =
|
|
11101
|
+
const configPath = path15.join(homeDir, "config.toml");
|
|
10875
11102
|
let current = await _readTextIfExists2(configPath);
|
|
10876
11103
|
current = current.replace(new RegExp(`${_escapeRegExp(CODEX_BLOCK_BEGIN)}[\\s\\S]*?${_escapeRegExp(CODEX_BLOCK_END)}\\n?`, "u"), "");
|
|
10877
11104
|
current = current.replace(new RegExp(`${_escapeRegExp(CODEX_TRUST_BLOCK_BEGIN)}[\\s\\S]*?${_escapeRegExp(CODEX_TRUST_BLOCK_END)}\\n?`, "u"), "");
|
|
10878
11105
|
current = await _refreshCodexModelSettings(current, sourceHomeDir);
|
|
10879
11106
|
current = _removeTopLevelTomlKeys(current, CODEX_UPDATE_CHECK_KEYS);
|
|
10880
|
-
const trustedWorkspace = workspaceDir ?
|
|
11107
|
+
const trustedWorkspace = workspaceDir ? path15.resolve(_expandHome3(workspaceDir)) : undefined;
|
|
10881
11108
|
const trust = trustedWorkspace ? _setExistingCodexProjectTrust(current, trustedWorkspace) : { text: current, found: false };
|
|
10882
11109
|
current = trust.text;
|
|
10883
11110
|
const missing = Object.entries(CODEX_DEFAULTS).filter(([key]) => !_hasTopLevelTomlKey(current, key));
|
|
10884
11111
|
const defaultsBlock = _codexManagedBlock(missing);
|
|
10885
11112
|
const trustBlock = trustedWorkspace && !trust.found ? _codexTrustBlock(trustedWorkspace) : "";
|
|
10886
11113
|
const next = _ensureCodexStatusLine(_appendTomlBlock(_insertBeforeFirstTomlTable(current, defaultsBlock), trustBlock), warn);
|
|
10887
|
-
await mkdir7(
|
|
11114
|
+
await mkdir7(path15.dirname(configPath), { recursive: true });
|
|
10888
11115
|
await writeFile7(configPath, next, { mode: 384 });
|
|
10889
11116
|
}
|
|
10890
11117
|
function _ensureCodexStatusLine(text, warn) {
|
|
@@ -10934,7 +11161,7 @@ ${CODEX_CONTEXT_STATUS_LINE}`);
|
|
|
10934
11161
|
async function _refreshCodexModelSettings(current, sourceHomeDir) {
|
|
10935
11162
|
if (!sourceHomeDir)
|
|
10936
11163
|
return current;
|
|
10937
|
-
const source = await _readTextIfExists2(
|
|
11164
|
+
const source = await _readTextIfExists2(path15.join(sourceHomeDir, "config.toml"));
|
|
10938
11165
|
const entries = _codexModelEntries(source);
|
|
10939
11166
|
const withoutManaged = current.replace(new RegExp(`${_escapeRegExp(CODEX_MODEL_BLOCK_BEGIN)}[\\s\\S]*?${_escapeRegExp(CODEX_MODEL_BLOCK_END)}\\n?`, "u"), "");
|
|
10940
11167
|
const keys = new Set(entries.map(({ key }) => key));
|
|
@@ -11201,7 +11428,7 @@ async function _writeManagedFile(filePath, content, executable) {
|
|
|
11201
11428
|
if (existing && existing !== content && !existing.includes(MANAGED_MARKER2) && !_matchesMarkerlessManagedContent(existing, content)) {
|
|
11202
11429
|
throw new Error(`refusing to overwrite unmanaged file: ${filePath}`);
|
|
11203
11430
|
}
|
|
11204
|
-
await mkdir7(
|
|
11431
|
+
await mkdir7(path15.dirname(filePath), { recursive: true });
|
|
11205
11432
|
await writeFile7(filePath, content, { mode: executable ? 493 : 384 });
|
|
11206
11433
|
if (executable)
|
|
11207
11434
|
await chmod4(filePath, 493);
|
|
@@ -11217,13 +11444,13 @@ async function _readTextIfExists2(filePath) {
|
|
|
11217
11444
|
return "";
|
|
11218
11445
|
throw error;
|
|
11219
11446
|
}
|
|
11220
|
-
return
|
|
11447
|
+
return readFile8(filePath, "utf8");
|
|
11221
11448
|
}
|
|
11222
11449
|
function _expandHome3(value) {
|
|
11223
11450
|
if (value === "~")
|
|
11224
11451
|
return homedir11();
|
|
11225
11452
|
if (value.startsWith("~/"))
|
|
11226
|
-
return
|
|
11453
|
+
return path15.join(homedir11(), value.slice(2));
|
|
11227
11454
|
return value;
|
|
11228
11455
|
}
|
|
11229
11456
|
function _shellSingleQuote(value) {
|
|
@@ -11238,10 +11465,10 @@ function _escapeRegExp(value) {
|
|
|
11238
11465
|
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
11239
11466
|
}
|
|
11240
11467
|
|
|
11241
|
-
// .dist-releases/
|
|
11468
|
+
// .dist-releases/1784888160293-2271563/src/host/engine-auth.js
|
|
11242
11469
|
import { lstat as lstat4, mkdir as mkdir8, readlink, realpath, stat as stat3, symlink as symlink2, unlink as unlink2 } from "node:fs/promises";
|
|
11243
11470
|
import { homedir as homedir12 } from "node:os";
|
|
11244
|
-
import
|
|
11471
|
+
import path16 from "node:path";
|
|
11245
11472
|
class EngineNotLoggedInError extends Error {
|
|
11246
11473
|
constructor(engine, authPath) {
|
|
11247
11474
|
super(`engine-auth-missing[${engine}]: ${_notLoggedInMessage(engine, authPath)}`);
|
|
@@ -11256,9 +11483,9 @@ async function provisionEngineAuth(options) {
|
|
|
11256
11483
|
return null;
|
|
11257
11484
|
throw new EngineNotLoggedInError(options.engine, source);
|
|
11258
11485
|
}
|
|
11259
|
-
const target =
|
|
11486
|
+
const target = path16.join(options.homeDir, engineAuthFileName(options.engine));
|
|
11260
11487
|
const sharedTargetPath = await realpath(source);
|
|
11261
|
-
await mkdir8(
|
|
11488
|
+
await mkdir8(path16.dirname(target), { recursive: true });
|
|
11262
11489
|
await _ensureSymlink(target, source, sharedTargetPath);
|
|
11263
11490
|
return { linkPath: target, sharedTargetPath };
|
|
11264
11491
|
}
|
|
@@ -11267,7 +11494,7 @@ async function _hasEnvBasedAuth(engine, env) {
|
|
|
11267
11494
|
return _nonEmpty(env.OPENAI_API_KEY);
|
|
11268
11495
|
if (_nonEmpty(env.ANTHROPIC_AUTH_TOKEN) || _nonEmpty(env.ANTHROPIC_API_KEY))
|
|
11269
11496
|
return true;
|
|
11270
|
-
const settings = await readHostClaudeSettings(
|
|
11497
|
+
const settings = await readHostClaudeSettings(path16.dirname(engineAuthSourcePath("claude", env)));
|
|
11271
11498
|
return _nonEmpty(settings.env.ANTHROPIC_AUTH_TOKEN) || _nonEmpty(settings.env.ANTHROPIC_API_KEY) || settings.apiKeyHelper !== null;
|
|
11272
11499
|
}
|
|
11273
11500
|
function _nonEmpty(value) {
|
|
@@ -11277,12 +11504,12 @@ function _notLoggedInMessage(engine, authPath) {
|
|
|
11277
11504
|
if (engine === "codex") {
|
|
11278
11505
|
return `engine is not authenticated: codex has no usable credential source. Provide either (1) auth.json at ${authPath} via codex login, or (2) OPENAI_API_KEY in the process environment.`;
|
|
11279
11506
|
}
|
|
11280
|
-
const settingsPath =
|
|
11507
|
+
const settingsPath = path16.join(path16.dirname(authPath), "settings.json");
|
|
11281
11508
|
return `engine is not authenticated: claude has no usable credential source. Provide one of: (1) ${authPath} via claude login; ` + `(2) ANTHROPIC_AUTH_TOKEN/ANTHROPIC_API_KEY or apiKeyHelper in ${settingsPath}; ` + `(3) ANTHROPIC_AUTH_TOKEN/ANTHROPIC_API_KEY in the process environment.`;
|
|
11282
11509
|
}
|
|
11283
11510
|
function engineAuthSourcePath(engine, env = process.env) {
|
|
11284
11511
|
const spec = _engineAuthSpec(engine, env);
|
|
11285
|
-
return
|
|
11512
|
+
return path16.join(spec.sourceDir, spec.fileName);
|
|
11286
11513
|
}
|
|
11287
11514
|
function engineAuthFileName(engine) {
|
|
11288
11515
|
return _engineAuthSpec(engine, {}).fileName;
|
|
@@ -11290,9 +11517,9 @@ function engineAuthFileName(engine) {
|
|
|
11290
11517
|
function _engineAuthSpec(engine, env) {
|
|
11291
11518
|
const home = env.HOME?.trim() || homedir12();
|
|
11292
11519
|
if (engine === "codex") {
|
|
11293
|
-
return { sourceDir: env.CODEX_HOME?.trim() ||
|
|
11520
|
+
return { sourceDir: env.CODEX_HOME?.trim() || path16.join(home, ".codex"), fileName: "auth.json" };
|
|
11294
11521
|
}
|
|
11295
|
-
return { sourceDir: env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
11522
|
+
return { sourceDir: env.CLAUDE_CONFIG_DIR?.trim() || path16.join(home, ".claude"), fileName: ".credentials.json" };
|
|
11296
11523
|
}
|
|
11297
11524
|
async function _isReadableAuthFile(filePath) {
|
|
11298
11525
|
try {
|
|
@@ -11321,14 +11548,14 @@ async function _ensureSymlink(linkPath, targetPath, sharedTargetPath) {
|
|
|
11321
11548
|
return;
|
|
11322
11549
|
}
|
|
11323
11550
|
const current = await readlink(linkPath);
|
|
11324
|
-
const resolved =
|
|
11325
|
-
if (resolved ===
|
|
11551
|
+
const resolved = path16.resolve(path16.dirname(linkPath), current);
|
|
11552
|
+
if (resolved === path16.resolve(targetPath))
|
|
11326
11553
|
return;
|
|
11327
11554
|
await unlink2(linkPath);
|
|
11328
11555
|
await symlink2(targetPath, linkPath);
|
|
11329
11556
|
}
|
|
11330
11557
|
|
|
11331
|
-
// .dist-releases/
|
|
11558
|
+
// .dist-releases/1784888160293-2271563/src/host/runtime-env.js
|
|
11332
11559
|
async function materializeAgentRuntimeEnv(options) {
|
|
11333
11560
|
const env = buildAgentEnv({
|
|
11334
11561
|
hostEnv: options.hostEnv,
|
|
@@ -11347,7 +11574,7 @@ async function materializeAgentRuntimeEnv(options) {
|
|
|
11347
11574
|
agentName: options.agentName,
|
|
11348
11575
|
engine: memoryStub.engine,
|
|
11349
11576
|
homeDir: memoryStub.homeDir,
|
|
11350
|
-
sourceHomeDir:
|
|
11577
|
+
sourceHomeDir: path17.dirname(engineAuthSourcePath(memoryStub.engine, options.hostEnv))
|
|
11351
11578
|
});
|
|
11352
11579
|
const credentialGuard = await provisionEngineAuth({
|
|
11353
11580
|
engine: memoryStub.engine,
|
|
@@ -11368,7 +11595,7 @@ function _ensureRootSandboxEscape(env, engine, uid) {
|
|
|
11368
11595
|
function _currentUid() {
|
|
11369
11596
|
return typeof process.getuid === "function" ? process.getuid() : null;
|
|
11370
11597
|
}
|
|
11371
|
-
// .dist-releases/
|
|
11598
|
+
// .dist-releases/1784888160293-2271563/src/host/context-statusline.js
|
|
11372
11599
|
function renderClaudeContextStatusLine(payload) {
|
|
11373
11600
|
const percent = _usedPercentage(payload);
|
|
11374
11601
|
if (percent === null)
|
|
@@ -11406,12 +11633,12 @@ function _bar(percent) {
|
|
|
11406
11633
|
const filled = Math.min(10, Math.max(0, Math.trunc(percent / 10)));
|
|
11407
11634
|
return "█".repeat(filled) + "░".repeat(10 - filled);
|
|
11408
11635
|
}
|
|
11409
|
-
// .dist-releases/
|
|
11636
|
+
// .dist-releases/1784888160293-2271563/src/host/scratch-sweeper.js
|
|
11410
11637
|
import { execFile as execFile3 } from "node:child_process";
|
|
11411
11638
|
import { lstat as lstat5, readdir as readdir3, realpath as realpath2, unlink as unlink3 } from "node:fs/promises";
|
|
11412
|
-
import
|
|
11413
|
-
import { promisify as
|
|
11414
|
-
var execFileAsync3 =
|
|
11639
|
+
import path18 from "node:path";
|
|
11640
|
+
import { promisify as promisify5 } from "node:util";
|
|
11641
|
+
var execFileAsync3 = promisify5(execFile3);
|
|
11415
11642
|
var SCRATCH_SUBDIR = ".agent/tmp";
|
|
11416
11643
|
var SCRATCH_SWEEP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
11417
11644
|
var SCRATCH_SWEEP_MAX_BYTES = 512 * 1024 * 1024;
|
|
@@ -11423,8 +11650,8 @@ function scratchSweepEnabled(env) {
|
|
|
11423
11650
|
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
11424
11651
|
}
|
|
11425
11652
|
async function sweepWorkspaceScratch(options) {
|
|
11426
|
-
const root =
|
|
11427
|
-
const tmpDir =
|
|
11653
|
+
const root = path18.resolve(options.workspaceRoot);
|
|
11654
|
+
const tmpDir = path18.join(root, SCRATCH_SUBDIR);
|
|
11428
11655
|
const state = await _tmpDirState(root, tmpDir);
|
|
11429
11656
|
if (state === "missing")
|
|
11430
11657
|
return EMPTY;
|
|
@@ -11462,7 +11689,7 @@ async function _trackedScratchFiles(root, options) {
|
|
|
11462
11689
|
const tracked = new Set;
|
|
11463
11690
|
for (const rel of stdout.split("\x00"))
|
|
11464
11691
|
if (rel)
|
|
11465
|
-
tracked.add(
|
|
11692
|
+
tracked.add(path18.join(root, rel));
|
|
11466
11693
|
return tracked;
|
|
11467
11694
|
} catch (error) {
|
|
11468
11695
|
options.logger?.("host_scratch_sweep_git_failed", { workspace: root, error: _errno(error) });
|
|
@@ -11472,7 +11699,7 @@ async function _trackedScratchFiles(root, options) {
|
|
|
11472
11699
|
async function _collectScratchFiles(dir, root, logger) {
|
|
11473
11700
|
const out = [];
|
|
11474
11701
|
for (const entry of await readdir3(dir, { withFileTypes: true })) {
|
|
11475
|
-
const abs =
|
|
11702
|
+
const abs = path18.join(dir, entry.name);
|
|
11476
11703
|
if (!_within(root, abs)) {
|
|
11477
11704
|
logger?.("host_scratch_sweep_out_of_bounds", { workspace: root, path: abs });
|
|
11478
11705
|
continue;
|
|
@@ -11538,8 +11765,8 @@ async function _runGit2(root, args) {
|
|
|
11538
11765
|
return String(stdout);
|
|
11539
11766
|
}
|
|
11540
11767
|
function _within(root, target) {
|
|
11541
|
-
const rel =
|
|
11542
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
11768
|
+
const rel = path18.relative(root, target);
|
|
11769
|
+
return rel === "" || !rel.startsWith("..") && !path18.isAbsolute(rel);
|
|
11543
11770
|
}
|
|
11544
11771
|
function _isEnoent(error) {
|
|
11545
11772
|
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
@@ -11549,7 +11776,7 @@ function _errno(error) {
|
|
|
11549
11776
|
return String(error.code);
|
|
11550
11777
|
return error instanceof Error ? error.message : String(error);
|
|
11551
11778
|
}
|
|
11552
|
-
// .dist-releases/
|
|
11779
|
+
// .dist-releases/1784888160293-2271563/src/host/launcher.js
|
|
11553
11780
|
var MAX_TMUX_SESSION_SUFFIX = 100;
|
|
11554
11781
|
async function launchSupervisedAgent(input, deps = {}) {
|
|
11555
11782
|
const spec = parseAgentStartSpec(input.spec);
|
|
@@ -11700,10 +11927,10 @@ async function _tmuxSessionExists(session) {
|
|
|
11700
11927
|
throw error;
|
|
11701
11928
|
}
|
|
11702
11929
|
}
|
|
11703
|
-
// .dist-releases/
|
|
11930
|
+
// .dist-releases/1784888160293-2271563/src/worker/capability.js
|
|
11704
11931
|
import { accessSync, constants as constants2, mkdirSync as mkdirSync3, mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
11705
11932
|
import os from "node:os";
|
|
11706
|
-
import
|
|
11933
|
+
import path19 from "node:path";
|
|
11707
11934
|
import { spawnSync } from "node:child_process";
|
|
11708
11935
|
var TOOLS = ["podman", "git", "kubectl", "perf", "bpftrace"];
|
|
11709
11936
|
var GPU_TAGS = new Set(["intel-b60", "nvidia-h100", "none"]);
|
|
@@ -11803,10 +12030,10 @@ function parseOsReleaseLine(line) {
|
|
|
11803
12030
|
}
|
|
11804
12031
|
function isReadonly(dir) {
|
|
11805
12032
|
try {
|
|
11806
|
-
const root =
|
|
12033
|
+
const root = path19.resolve(dir);
|
|
11807
12034
|
mkdirSync3(root, { recursive: true });
|
|
11808
|
-
const temp = mkdtempSync(
|
|
11809
|
-
writeFileSync2(
|
|
12035
|
+
const temp = mkdtempSync(path19.join(root, ".sailorbridge-write-test-"));
|
|
12036
|
+
writeFileSync2(path19.join(temp, "probe"), "");
|
|
11810
12037
|
rmSync(temp, { recursive: true, force: true });
|
|
11811
12038
|
return false;
|
|
11812
12039
|
} catch {
|
|
@@ -11831,10 +12058,10 @@ function commandExists(command) {
|
|
|
11831
12058
|
return commandPath(command) !== null;
|
|
11832
12059
|
}
|
|
11833
12060
|
function commandPath(command) {
|
|
11834
|
-
if (command.includes(
|
|
12061
|
+
if (command.includes(path19.sep))
|
|
11835
12062
|
return command;
|
|
11836
|
-
for (const entry of (process.env.PATH ?? "").split(
|
|
11837
|
-
const candidate =
|
|
12063
|
+
for (const entry of (process.env.PATH ?? "").split(path19.delimiter)) {
|
|
12064
|
+
const candidate = path19.join(entry, command);
|
|
11838
12065
|
try {
|
|
11839
12066
|
accessSync(candidate, constants2.X_OK);
|
|
11840
12067
|
return candidate;
|
|
@@ -11843,7 +12070,7 @@ function commandPath(command) {
|
|
|
11843
12070
|
return null;
|
|
11844
12071
|
}
|
|
11845
12072
|
|
|
11846
|
-
// .dist-releases/
|
|
12073
|
+
// .dist-releases/1784888160293-2271563/src/host/worker-start-spec.js
|
|
11847
12074
|
var MAX_TAGS = 32;
|
|
11848
12075
|
var TAG_PATTERN = /^[a-z0-9][a-z0-9=._:/-]{0,63}$/iu;
|
|
11849
12076
|
var RESERVED_TAG_KEYS = new Set(["os", "kernel", "arch", "gpu", "mode", "role", "tool"]);
|
|
@@ -11903,16 +12130,16 @@ function _trimmed2(value, label) {
|
|
|
11903
12130
|
return trimmed;
|
|
11904
12131
|
}
|
|
11905
12132
|
|
|
11906
|
-
// .dist-releases/
|
|
12133
|
+
// .dist-releases/1784888160293-2271563/src/host/worker-launcher.js
|
|
11907
12134
|
import { statSync as statSync3 } from "node:fs";
|
|
11908
12135
|
import os4 from "node:os";
|
|
11909
|
-
import
|
|
11910
|
-
// .dist-releases/
|
|
12136
|
+
import path22 from "node:path";
|
|
12137
|
+
// .dist-releases/1784888160293-2271563/src/worker/client.js
|
|
11911
12138
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
11912
12139
|
import os3 from "node:os";
|
|
11913
|
-
import
|
|
12140
|
+
import path21 from "node:path";
|
|
11914
12141
|
|
|
11915
|
-
// .dist-releases/
|
|
12142
|
+
// .dist-releases/1784888160293-2271563/src/worker/errors.js
|
|
11916
12143
|
class LeaseFencingRejected extends Error {
|
|
11917
12144
|
status;
|
|
11918
12145
|
constructor(status, message) {
|
|
@@ -11926,10 +12153,10 @@ class WorkerHttpError extends Error {
|
|
|
11926
12153
|
method;
|
|
11927
12154
|
path;
|
|
11928
12155
|
status;
|
|
11929
|
-
constructor(method,
|
|
12156
|
+
constructor(method, path20, status, message) {
|
|
11930
12157
|
super(message || `HTTP ${status}`);
|
|
11931
12158
|
this.method = method;
|
|
11932
|
-
this.path =
|
|
12159
|
+
this.path = path20;
|
|
11933
12160
|
this.status = status;
|
|
11934
12161
|
this.name = "WorkerHttpError";
|
|
11935
12162
|
}
|
|
@@ -11938,10 +12165,10 @@ class WorkerHttpError extends Error {
|
|
|
11938
12165
|
class WorkerNetworkError extends Error {
|
|
11939
12166
|
method;
|
|
11940
12167
|
path;
|
|
11941
|
-
constructor(method,
|
|
12168
|
+
constructor(method, path20, message) {
|
|
11942
12169
|
super(message);
|
|
11943
12170
|
this.method = method;
|
|
11944
|
-
this.path =
|
|
12171
|
+
this.path = path20;
|
|
11945
12172
|
this.name = "WorkerNetworkError";
|
|
11946
12173
|
}
|
|
11947
12174
|
}
|
|
@@ -11949,14 +12176,14 @@ var LEASE_FENCING_BAD_REQUEST_MESSAGES = [
|
|
|
11949
12176
|
"lease_token is required",
|
|
11950
12177
|
"lease_token must be a non-empty string"
|
|
11951
12178
|
];
|
|
11952
|
-
function raiseForLeaseFencingOrStatus(method,
|
|
12179
|
+
function raiseForLeaseFencingOrStatus(method, path20, status, body) {
|
|
11953
12180
|
if (status === 409)
|
|
11954
12181
|
throw new LeaseFencingRejected(status, body);
|
|
11955
12182
|
if (status === 400 && LEASE_FENCING_BAD_REQUEST_MESSAGES.some((message) => body.includes(message))) {
|
|
11956
12183
|
throw new LeaseFencingRejected(status, body);
|
|
11957
12184
|
}
|
|
11958
12185
|
if (status >= 300)
|
|
11959
|
-
throw new WorkerHttpError(method,
|
|
12186
|
+
throw new WorkerHttpError(method, path20, status, body);
|
|
11960
12187
|
}
|
|
11961
12188
|
function isNetworkError(error) {
|
|
11962
12189
|
if (error instanceof WorkerNetworkError)
|
|
@@ -11968,23 +12195,23 @@ function isNetworkError(error) {
|
|
|
11968
12195
|
const code = error.code;
|
|
11969
12196
|
return code === "ECONNRESET" || code === "ECONNREFUSED" || code === "ETIMEDOUT" || code === "EPIPE" || error.name === "AbortError";
|
|
11970
12197
|
}
|
|
11971
|
-
function countsTowardWorkerSessionRebuild(
|
|
11972
|
-
if (
|
|
12198
|
+
function countsTowardWorkerSessionRebuild(path20) {
|
|
12199
|
+
if (path20 === "/api/v1/workers/register")
|
|
11973
12200
|
return false;
|
|
11974
|
-
if (/^\/api\/v1\/workers\/[^/]+\/heartbeat$/u.test(
|
|
12201
|
+
if (/^\/api\/v1\/workers\/[^/]+\/heartbeat$/u.test(path20))
|
|
11975
12202
|
return false;
|
|
11976
12203
|
return true;
|
|
11977
12204
|
}
|
|
11978
12205
|
|
|
11979
|
-
// .dist-releases/
|
|
11980
|
-
import { spawn as
|
|
12206
|
+
// .dist-releases/1784888160293-2271563/src/worker/executor.js
|
|
12207
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
11981
12208
|
import { mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, realpathSync, rmSync as rmSync2, statfsSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
11982
12209
|
import { tmpdir as tmpdir2, loadavg } from "node:os";
|
|
11983
12210
|
import os2 from "node:os";
|
|
11984
|
-
import
|
|
12211
|
+
import path20 from "node:path";
|
|
11985
12212
|
import { TextDecoder } from "node:util";
|
|
11986
12213
|
|
|
11987
|
-
// .dist-releases/
|
|
12214
|
+
// .dist-releases/1784888160293-2271563/src/worker/async-queue.js
|
|
11988
12215
|
class AsyncByteQueue {
|
|
11989
12216
|
maxSize;
|
|
11990
12217
|
values = [];
|
|
@@ -12044,7 +12271,7 @@ class AsyncByteQueue {
|
|
|
12044
12271
|
}
|
|
12045
12272
|
}
|
|
12046
12273
|
|
|
12047
|
-
// .dist-releases/
|
|
12274
|
+
// .dist-releases/1784888160293-2271563/src/worker/http.js
|
|
12048
12275
|
import { request as httpRequest } from "node:http";
|
|
12049
12276
|
import { request as httpsRequest } from "node:https";
|
|
12050
12277
|
import { URLSearchParams as URLSearchParams2 } from "node:url";
|
|
@@ -12074,27 +12301,27 @@ class WorkerHttpClient {
|
|
|
12074
12301
|
throw new Error("token is required");
|
|
12075
12302
|
this.relayUrl = relayUrl.replace(/\/+$/u, "");
|
|
12076
12303
|
}
|
|
12077
|
-
async getJson(
|
|
12304
|
+
async getJson(path20, query, timeouts, options = {}) {
|
|
12078
12305
|
const suffix = new URLSearchParams2(query).toString();
|
|
12079
|
-
return this.requestJson("GET", suffix ? `${
|
|
12306
|
+
return this.requestJson("GET", suffix ? `${path20}?${suffix}` : path20, undefined, timeouts, options);
|
|
12080
12307
|
}
|
|
12081
|
-
async postJson(
|
|
12082
|
-
return this.requestJson("POST",
|
|
12308
|
+
async postJson(path20, value, timeouts) {
|
|
12309
|
+
return this.requestJson("POST", path20, { type: "json", value }, timeouts, {});
|
|
12083
12310
|
}
|
|
12084
|
-
async postBytes(
|
|
12085
|
-
const response = await this.request("POST",
|
|
12086
|
-
raiseForLeaseFencingOrStatus("POST",
|
|
12311
|
+
async postBytes(path20, body, headers, timeouts) {
|
|
12312
|
+
const response = await this.request("POST", path20, { type: "bytes", value: body }, timeouts, headers);
|
|
12313
|
+
raiseForLeaseFencingOrStatus("POST", path20, response.status, response.text);
|
|
12087
12314
|
}
|
|
12088
|
-
async requestJson(method,
|
|
12089
|
-
const response = await this.request(method,
|
|
12090
|
-
const errorPath = pathOnly(
|
|
12315
|
+
async requestJson(method, path20, body, timeouts, options) {
|
|
12316
|
+
const response = await this.request(method, path20, body, timeouts, {});
|
|
12317
|
+
const errorPath = pathOnly(path20);
|
|
12091
12318
|
if (options.leaseFencing === false && response.status >= 300)
|
|
12092
12319
|
throw new WorkerHttpError(method, errorPath, response.status, response.text);
|
|
12093
12320
|
raiseForLeaseFencingOrStatus(method, errorPath, response.status, response.text);
|
|
12094
12321
|
return parseJson(method, errorPath, response.text);
|
|
12095
12322
|
}
|
|
12096
|
-
async request(method,
|
|
12097
|
-
const url = new URL(`${this.relayUrl}${
|
|
12323
|
+
async request(method, path20, body, timeouts, extraHeaders) {
|
|
12324
|
+
const url = new URL(`${this.relayUrl}${path20}`);
|
|
12098
12325
|
const headers = this.headers(body, extraHeaders);
|
|
12099
12326
|
return sendRequest(method, url, body, headers, timeouts, this.signal);
|
|
12100
12327
|
}
|
|
@@ -12221,7 +12448,7 @@ function waitForRequestDrain(req) {
|
|
|
12221
12448
|
req.once("close", onClose);
|
|
12222
12449
|
});
|
|
12223
12450
|
}
|
|
12224
|
-
function parseJson(method,
|
|
12451
|
+
function parseJson(method, path20, text) {
|
|
12225
12452
|
try {
|
|
12226
12453
|
const parsed = JSON.parse(text);
|
|
12227
12454
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -12230,15 +12457,15 @@ function parseJson(method, path19, text) {
|
|
|
12230
12457
|
return parsed;
|
|
12231
12458
|
} catch (error) {
|
|
12232
12459
|
if (error instanceof SyntaxError)
|
|
12233
|
-
throw new WorkerNetworkError(method,
|
|
12460
|
+
throw new WorkerNetworkError(method, path20, "response JSON is invalid");
|
|
12234
12461
|
throw error;
|
|
12235
12462
|
}
|
|
12236
12463
|
}
|
|
12237
|
-
function pathOnly(
|
|
12238
|
-
return
|
|
12464
|
+
function pathOnly(path20) {
|
|
12465
|
+
return path20.split("?", 1)[0] || path20;
|
|
12239
12466
|
}
|
|
12240
12467
|
|
|
12241
|
-
// .dist-releases/
|
|
12468
|
+
// .dist-releases/1784888160293-2271563/src/worker/stream-upload.js
|
|
12242
12469
|
async function uploadStream(session, jobId, stream, leaseToken, chunks, workerId) {
|
|
12243
12470
|
if (!leaseToken.trim())
|
|
12244
12471
|
throw new Error("lease_token is required");
|
|
@@ -12248,7 +12475,7 @@ async function uploadStream(session, jobId, stream, leaseToken, chunks, workerId
|
|
|
12248
12475
|
await session.http.postBytes(`/api/v1/jobs/${encodeURIComponent(jobId)}/stream-upload?${query.toString()}`, chunks, { "X-Lease-Token": leaseToken }, UPLOAD_TIMEOUTS);
|
|
12249
12476
|
}
|
|
12250
12477
|
|
|
12251
|
-
// .dist-releases/
|
|
12478
|
+
// .dist-releases/1784888160293-2271563/src/worker/executor.js
|
|
12252
12479
|
class StreamingProcessFailure extends Error {
|
|
12253
12480
|
exitCode;
|
|
12254
12481
|
stdout;
|
|
@@ -12320,8 +12547,8 @@ function sandboxPath(workdir, requested) {
|
|
|
12320
12547
|
if (requested.startsWith("/") || parts.length === 0 || parts.includes("..")) {
|
|
12321
12548
|
throw new Error("path must be a relative path inside the worker sandbox");
|
|
12322
12549
|
}
|
|
12323
|
-
const root = realpathSync(
|
|
12324
|
-
const target =
|
|
12550
|
+
const root = realpathSync(path20.resolve(workdir));
|
|
12551
|
+
const target = path20.resolve(root, ...parts);
|
|
12325
12552
|
if (!isPathInside(root, target)) {
|
|
12326
12553
|
throw new Error("path escapes worker sandbox");
|
|
12327
12554
|
}
|
|
@@ -12461,7 +12688,7 @@ async function collectAndUpload(session, jobId, stream, pipe, leaseToken, worker
|
|
|
12461
12688
|
return collected.join("");
|
|
12462
12689
|
}
|
|
12463
12690
|
function spawnProcess(argv, cwd) {
|
|
12464
|
-
return
|
|
12691
|
+
return spawn6(argv[0], argv.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
|
|
12465
12692
|
}
|
|
12466
12693
|
async function terminateProcess(proc) {
|
|
12467
12694
|
if (proc.pid === undefined)
|
|
@@ -12497,9 +12724,9 @@ function writeFileJob(workdir, spec, startedAt, started) {
|
|
|
12497
12724
|
if (typeof spec.content !== "string")
|
|
12498
12725
|
throw new Error("write_file spec.content must be a string");
|
|
12499
12726
|
const target = sandboxPath(workdir, String(spec.path ?? ""));
|
|
12500
|
-
mkdirSync4(
|
|
12727
|
+
mkdirSync4(path20.dirname(target), { recursive: true });
|
|
12501
12728
|
writeFileSync3(target, spec.content, "utf8");
|
|
12502
|
-
return output(0,
|
|
12729
|
+
return output(0, path20.relative(realpathSync(path20.resolve(workdir)), target), "", startedAt, started);
|
|
12503
12730
|
}
|
|
12504
12731
|
function readUtf8File(target) {
|
|
12505
12732
|
return decodeUtf8(readFileSync4(target));
|
|
@@ -12507,8 +12734,8 @@ function readUtf8File(target) {
|
|
|
12507
12734
|
async function applyDiff(workdir, spec, signal) {
|
|
12508
12735
|
if (typeof spec.diff_unified_text !== "string")
|
|
12509
12736
|
throw new Error("apply_diff spec.diff_unified_text must be a string");
|
|
12510
|
-
const dir = mkdtempSync2(
|
|
12511
|
-
const patch =
|
|
12737
|
+
const dir = mkdtempSync2(path20.join(tmpdir2(), "sailorbridge-patch-"));
|
|
12738
|
+
const patch = path20.join(dir, "change.patch");
|
|
12512
12739
|
writeFileSync3(patch, spec.diff_unified_text, "utf8");
|
|
12513
12740
|
try {
|
|
12514
12741
|
return await runArgv(["patch", "-p1", "-i", patch], workdir, coerceJobTimeoutSeconds(spec) * 1000, signal);
|
|
@@ -12748,24 +12975,24 @@ function resolveExistingTarget(target) {
|
|
|
12748
12975
|
let current = target;
|
|
12749
12976
|
while (true) {
|
|
12750
12977
|
try {
|
|
12751
|
-
return
|
|
12978
|
+
return path20.resolve(realpathSync(current), ...missingParts.reverse());
|
|
12752
12979
|
} catch (error) {
|
|
12753
12980
|
if (error.code !== "ENOENT")
|
|
12754
12981
|
throw error;
|
|
12755
|
-
const parent =
|
|
12982
|
+
const parent = path20.dirname(current);
|
|
12756
12983
|
if (parent === current)
|
|
12757
12984
|
throw error;
|
|
12758
|
-
missingParts.push(
|
|
12985
|
+
missingParts.push(path20.basename(current));
|
|
12759
12986
|
current = parent;
|
|
12760
12987
|
}
|
|
12761
12988
|
}
|
|
12762
12989
|
}
|
|
12763
12990
|
function isPathInside(root, target) {
|
|
12764
|
-
const relative =
|
|
12765
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
12991
|
+
const relative = path20.relative(root, target);
|
|
12992
|
+
return relative === "" || !relative.startsWith("..") && !path20.isAbsolute(relative);
|
|
12766
12993
|
}
|
|
12767
12994
|
function prepareWorkdir(workdir) {
|
|
12768
|
-
const resolved =
|
|
12995
|
+
const resolved = path20.resolve(workdir);
|
|
12769
12996
|
mkdirSync4(resolved, { recursive: true });
|
|
12770
12997
|
return resolved;
|
|
12771
12998
|
}
|
|
@@ -12780,7 +13007,7 @@ function errorMessage6(error) {
|
|
|
12780
13007
|
return error instanceof Error ? error.message : String(error);
|
|
12781
13008
|
}
|
|
12782
13009
|
|
|
12783
|
-
// .dist-releases/
|
|
13010
|
+
// .dist-releases/1784888160293-2271563/src/worker/client.js
|
|
12784
13011
|
var TOKEN_FILES = [
|
|
12785
13012
|
"~/.config/sailorbridge/token",
|
|
12786
13013
|
"/etc/sailorbridge/token"
|
|
@@ -13119,7 +13346,7 @@ ${JSON.stringify(result)}\r
|
|
|
13119
13346
|
`);
|
|
13120
13347
|
for (const file of attachments) {
|
|
13121
13348
|
yield Buffer.from(`--${multipartBoundary}\r
|
|
13122
|
-
Content-Disposition: form-data; name="files"; filename="${
|
|
13349
|
+
Content-Disposition: form-data; name="files"; filename="${path21.basename(file)}"\r
|
|
13123
13350
|
\r
|
|
13124
13351
|
`);
|
|
13125
13352
|
yield readFileSync5(file);
|
|
@@ -13153,7 +13380,7 @@ function parseFlags2(argv) {
|
|
|
13153
13380
|
return values;
|
|
13154
13381
|
}
|
|
13155
13382
|
function expandHome2(value) {
|
|
13156
|
-
return value === "~" || value.startsWith("~/") ?
|
|
13383
|
+
return value === "~" || value.startsWith("~/") ? path21.join(os3.homedir(), value.slice(2)) : value;
|
|
13157
13384
|
}
|
|
13158
13385
|
function _sleep(ms, signal) {
|
|
13159
13386
|
if (signal?.aborted)
|
|
@@ -13177,7 +13404,7 @@ function errorName2(error) {
|
|
|
13177
13404
|
function errorMessage7(error) {
|
|
13178
13405
|
return error instanceof Error ? error.message : String(error);
|
|
13179
13406
|
}
|
|
13180
|
-
// .dist-releases/
|
|
13407
|
+
// .dist-releases/1784888160293-2271563/src/host/worker-launcher.js
|
|
13181
13408
|
var DEFAULT_WORKER_READY_TIMEOUT_MS = 60000;
|
|
13182
13409
|
async function launchSupervisedWorker(input, deps = {}) {
|
|
13183
13410
|
const logger = input.logger ?? (() => {});
|
|
@@ -13260,7 +13487,7 @@ function _requireWorkerName(descriptor) {
|
|
|
13260
13487
|
return worker;
|
|
13261
13488
|
}
|
|
13262
13489
|
function _resolveWorkdir(workdir, homeDir) {
|
|
13263
|
-
return workdir === "~" || workdir.startsWith("~/") ?
|
|
13490
|
+
return workdir === "~" || workdir.startsWith("~/") ? path22.join(homeDir, workdir.slice(2)) : workdir;
|
|
13264
13491
|
}
|
|
13265
13492
|
function _assertWorkdir(workdir) {
|
|
13266
13493
|
let stat4;
|
|
@@ -13274,7 +13501,7 @@ function _assertWorkdir(workdir) {
|
|
|
13274
13501
|
return workdir;
|
|
13275
13502
|
}
|
|
13276
13503
|
|
|
13277
|
-
// .dist-releases/
|
|
13504
|
+
// .dist-releases/1784888160293-2271563/src/host/daemon.js
|
|
13278
13505
|
async function runHostDaemon(options) {
|
|
13279
13506
|
const logger = options.logger ?? (() => {});
|
|
13280
13507
|
const sleep3 = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
|
|
@@ -13302,6 +13529,13 @@ async function runHostDaemon(options) {
|
|
|
13302
13529
|
let lastRepoTipReportAt = now() - repoTipReportIntervalMs;
|
|
13303
13530
|
const reconcileIntervalMs = options.reconcileIntervalMs ?? 5 * 60 * 1000;
|
|
13304
13531
|
let lastReconcileAt = now() - reconcileIntervalMs;
|
|
13532
|
+
const autoUpdater = createAutoUpdater({
|
|
13533
|
+
enabled: options.autoUpdate !== false,
|
|
13534
|
+
isActive: () => runtimes.size > 0 || workerRuntimes.size > 0 || startLocks.size > 0 || cleanupLocks.size > 0,
|
|
13535
|
+
isMidWork: () => startLocks.size > 0 || cleanupLocks.size > 0,
|
|
13536
|
+
logger,
|
|
13537
|
+
deps: { now, ...options.autoUpdateDeps }
|
|
13538
|
+
});
|
|
13305
13539
|
const _startWorker = async (request, recoveredDescriptor) => {
|
|
13306
13540
|
const spec = parseWorkerStartSpec(request.spec);
|
|
13307
13541
|
const descriptor = recoveredDescriptor ?? await options.resolveCredential(request);
|
|
@@ -13452,7 +13686,7 @@ async function runHostDaemon(options) {
|
|
|
13452
13686
|
try {
|
|
13453
13687
|
await _recoverDurableRuntimes();
|
|
13454
13688
|
while (!options.signal?.aborted) {
|
|
13455
|
-
const drained = await _drainOnce(options, identity, starter, logger, redactSecrets);
|
|
13689
|
+
const drained = await _drainOnce(options, identity, starter, logger, redactSecrets, autoUpdater);
|
|
13456
13690
|
if (drained === "retired") {
|
|
13457
13691
|
logger("host_daemon_retired", { host_id: options.hostId, status: 401 });
|
|
13458
13692
|
break;
|
|
@@ -13588,7 +13822,7 @@ async function _loadHostConfigBestEffort(options, logger) {
|
|
|
13588
13822
|
return { kind: "sailorbridge-host-config", workspaces: [] };
|
|
13589
13823
|
}
|
|
13590
13824
|
}
|
|
13591
|
-
async function _drainOnce(options, identity, starter, logger, redactSecrets) {
|
|
13825
|
+
async function _drainOnce(options, identity, starter, logger, redactSecrets, autoUpdater) {
|
|
13592
13826
|
try {
|
|
13593
13827
|
const hostConfig = await _loadHostConfigBestEffort(options, logger);
|
|
13594
13828
|
const workspaceInventory = await discoverWorkspaceInventoryBestEffort(hostWorkspacePaths(hostConfig, options.hostEnv ?? process.env), {
|
|
@@ -13597,17 +13831,20 @@ async function _drainOnce(options, identity, starter, logger, redactSecrets) {
|
|
|
13597
13831
|
error: error instanceof Error ? error.message : String(error)
|
|
13598
13832
|
})
|
|
13599
13833
|
});
|
|
13834
|
+
const updateError = autoUpdater.pendingUpdateError();
|
|
13600
13835
|
const result = await runHostRequestOnce({
|
|
13601
13836
|
relay: options.relay,
|
|
13602
13837
|
...identity,
|
|
13603
13838
|
starter,
|
|
13604
13839
|
redactSecrets,
|
|
13605
13840
|
...workspaceInventory.length ? { workspaceInventory } : {},
|
|
13841
|
+
...updateError === undefined ? {} : { updateError },
|
|
13606
13842
|
onWorkspaceInventoryError: (error) => logger("host_workspace_inventory_error", {
|
|
13607
13843
|
error: error instanceof Error ? error.message : String(error)
|
|
13608
13844
|
}),
|
|
13609
13845
|
...options.signal ? { signal: options.signal } : {}
|
|
13610
13846
|
});
|
|
13847
|
+
await autoUpdater.onHostReport(result.host);
|
|
13611
13848
|
if (result.status === "idle")
|
|
13612
13849
|
return false;
|
|
13613
13850
|
logger(`host_request_${result.status}`, {
|
|
@@ -13619,11 +13856,16 @@ async function _drainOnce(options, identity, starter, logger, redactSecrets) {
|
|
|
13619
13856
|
} catch (error) {
|
|
13620
13857
|
if (error instanceof RelayHttpError && error.status === 401)
|
|
13621
13858
|
return "retired";
|
|
13859
|
+
if (error instanceof RelayHttpError && error.status === 426) {
|
|
13860
|
+
logger("host_daemon_upgrade_required", { error: error.message });
|
|
13861
|
+
await autoUpdater.onUpgradeRequired(error.body);
|
|
13862
|
+
return false;
|
|
13863
|
+
}
|
|
13622
13864
|
logger("host_daemon_poll_error", { error: error instanceof Error ? error.message : String(error) });
|
|
13623
13865
|
return false;
|
|
13624
13866
|
}
|
|
13625
13867
|
}
|
|
13626
|
-
// .dist-releases/
|
|
13868
|
+
// .dist-releases/1784888160293-2271563/src/host/enrollment-redeem.js
|
|
13627
13869
|
var DEFAULT_NOT_FOUND_RETRIES = 3;
|
|
13628
13870
|
var NOT_FOUND_RETRY_DELAY_MS = 500;
|
|
13629
13871
|
function createEnrollmentRedeemer(options) {
|
|
@@ -13760,7 +14002,7 @@ function _role2(enrollment) {
|
|
|
13760
14002
|
}
|
|
13761
14003
|
return _string4(enrollment.roles[0], "roles[0]").trim();
|
|
13762
14004
|
}
|
|
13763
|
-
// .dist-releases/
|
|
14005
|
+
// .dist-releases/1784888160293-2271563/src/host/tutorial.js
|
|
13764
14006
|
function buildTutorialSteps(state) {
|
|
13765
14007
|
const paired = state.hasCredential;
|
|
13766
14008
|
return [
|
|
@@ -13831,7 +14073,7 @@ async function runTutorial(options) {
|
|
|
13831
14073
|
}
|
|
13832
14074
|
return steps;
|
|
13833
14075
|
}
|
|
13834
|
-
// .dist-releases/
|
|
14076
|
+
// .dist-releases/1784888160293-2271563/src/events.js
|
|
13835
14077
|
var EVENT_COMMANDS = new Set(["add", "list", "enable", "disable", "rm"]);
|
|
13836
14078
|
var EVENT_FLAGS = new Set(["at", "days", "message", "run-date", "session", "tag", "tz"]);
|
|
13837
14079
|
var PRODUCT_DAYS_MODES = new Set(["once", "daily", "weekday"]);
|
|
@@ -13921,9 +14163,9 @@ function _assertListArgs(args) {
|
|
|
13921
14163
|
}
|
|
13922
14164
|
}
|
|
13923
14165
|
|
|
13924
|
-
// .dist-releases/
|
|
13925
|
-
import { readFile as
|
|
13926
|
-
var _readUtf8File = async (file) => await
|
|
14166
|
+
// .dist-releases/1784888160293-2271563/src/text-input.js
|
|
14167
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
14168
|
+
var _readUtf8File = async (file) => await readFile9(file, "utf8");
|
|
13927
14169
|
async function readTextInput(input) {
|
|
13928
14170
|
let content = "";
|
|
13929
14171
|
for await (const chunk of input)
|
|
@@ -13955,17 +14197,17 @@ async function rejectUnusedTextInput(input, message) {
|
|
|
13955
14197
|
input.unref?.();
|
|
13956
14198
|
}
|
|
13957
14199
|
}
|
|
13958
|
-
async function readTextFile(
|
|
13959
|
-
return await readUtf8File2(
|
|
14200
|
+
async function readTextFile(path23, readUtf8File2 = _readUtf8File) {
|
|
14201
|
+
return await readUtf8File2(path23);
|
|
13960
14202
|
}
|
|
13961
|
-
async function readTextFileOrStdin(
|
|
13962
|
-
if (
|
|
14203
|
+
async function readTextFileOrStdin(path23, input, unusedInputMessage, readUtf8File2 = _readUtf8File) {
|
|
14204
|
+
if (path23 === "-")
|
|
13963
14205
|
return await readTextInput(input);
|
|
13964
14206
|
await rejectUnusedTextInput(input, unusedInputMessage);
|
|
13965
|
-
return await readTextFile(
|
|
14207
|
+
return await readTextFile(path23, readUtf8File2);
|
|
13966
14208
|
}
|
|
13967
14209
|
|
|
13968
|
-
// .dist-releases/
|
|
14210
|
+
// .dist-releases/1784888160293-2271563/src/ask.js
|
|
13969
14211
|
var ASK_FLAGS = new Set(["body-file", "option", "reason", "recommend", "session", "title"]);
|
|
13970
14212
|
async function runAskFromCli(client2, argv, config, input) {
|
|
13971
14213
|
const args = _parseAskArgs(argv);
|
|
@@ -14080,8 +14322,8 @@ function _singleAskValue(values, name) {
|
|
|
14080
14322
|
return entries[0];
|
|
14081
14323
|
}
|
|
14082
14324
|
|
|
14083
|
-
// .dist-releases/
|
|
14084
|
-
import { readFile as
|
|
14325
|
+
// .dist-releases/1784888160293-2271563/src/task.js
|
|
14326
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
14085
14327
|
import { basename } from "node:path";
|
|
14086
14328
|
var TASK_FLAGS = new Set(["after", "all", "artifact-id", "before", "body-file", "commit", "depends", "description", "description-file", "draft", "findings", "image", "level", "limit", "owner-of-resume", "pair", "priority", "query", "reason", "resume-condition", "resume-dependency", "session", "status", "type", "version"]);
|
|
14087
14329
|
var TASK_BOOLEAN_FLAGS = new Set(["all", "draft"]);
|
|
@@ -14312,7 +14554,7 @@ async function _createTaskRequest(args, input) {
|
|
|
14312
14554
|
async function _uploadTaskImages(client2, captainId, session, imagePaths) {
|
|
14313
14555
|
const artifactIds = [];
|
|
14314
14556
|
for (const imagePath of imagePaths) {
|
|
14315
|
-
const content = await
|
|
14557
|
+
const content = await readFile10(imagePath);
|
|
14316
14558
|
const artifact = await client2.uploadSessionArtifact(captainId, session, {
|
|
14317
14559
|
name: basename(imagePath),
|
|
14318
14560
|
content_bytes_base64: bytesToBase64(content)
|
|
@@ -14570,7 +14812,7 @@ function _taskListFooter(shown, returned, total, hasMore, cursor) {
|
|
|
14570
14812
|
return `Shown ${shown} of ${total}${local}${next}`;
|
|
14571
14813
|
}
|
|
14572
14814
|
|
|
14573
|
-
// .dist-releases/
|
|
14815
|
+
// .dist-releases/1784888160293-2271563/src/team.js
|
|
14574
14816
|
var TEAM_BOOTSTRAP_ENGINES = new Set(["claude", "codex"]);
|
|
14575
14817
|
var SLOT_SPEC_RE = /^([^=\s]+)=([^:@\s]+):([^:@\s]+)$/;
|
|
14576
14818
|
var TEAM_PLAIN_LIMIT = 20;
|
|
@@ -14725,7 +14967,7 @@ function _slotTable(slots) {
|
|
|
14725
14967
|
Shown ${shown.length} of ${slots.length}${omitted ? `; ${omitted} omitted (use --format json)` : ""}`;
|
|
14726
14968
|
}
|
|
14727
14969
|
|
|
14728
|
-
// .dist-releases/
|
|
14970
|
+
// .dist-releases/1784888160293-2271563/src/memory.js
|
|
14729
14971
|
var VALUE_FLAGS = new Set(["file", "source"]);
|
|
14730
14972
|
var MEMORY_SEARCH_PLAIN_LIMIT = 20;
|
|
14731
14973
|
async function runMemoryFromCli(client2, argv, config, input, format) {
|
|
@@ -14860,7 +15102,7 @@ function _summary(value) {
|
|
|
14860
15102
|
return value.replace(/\s+/gu, " ").trim().slice(0, 180);
|
|
14861
15103
|
}
|
|
14862
15104
|
|
|
14863
|
-
// .dist-releases/
|
|
15105
|
+
// .dist-releases/1784888160293-2271563/src/mailbox-send.js
|
|
14864
15106
|
var SEND_FLAGS = new Set(["body-file", "commit", "session", "tag", "task-id", "task-version", "to-agents", "to-roles", "to-host"]);
|
|
14865
15107
|
function parseMailboxSendArgs(argv) {
|
|
14866
15108
|
const parsed = argsFromValues(parseFlagValues(argv));
|
|
@@ -14959,7 +15201,7 @@ function splitList(value) {
|
|
|
14959
15201
|
return list?.length ? list : undefined;
|
|
14960
15202
|
}
|
|
14961
15203
|
|
|
14962
|
-
// .dist-releases/
|
|
15204
|
+
// .dist-releases/1784888160293-2271563/src/reply.js
|
|
14963
15205
|
var REPLY_FLAGS = new Set(["agent", "body-file", "in-reply-to", "session"]);
|
|
14964
15206
|
async function sendReplyFromCli(client2, argv, config, io) {
|
|
14965
15207
|
const args = _parseReplyArgs(argv);
|
|
@@ -15016,7 +15258,7 @@ function _requiredReplyValue(values, name) {
|
|
|
15016
15258
|
return value;
|
|
15017
15259
|
}
|
|
15018
15260
|
|
|
15019
|
-
// .dist-releases/
|
|
15261
|
+
// .dist-releases/1784888160293-2271563/src/worker-command.js
|
|
15020
15262
|
async function runWorkerCommandFromCli(client2, argv, config, io, format = "plain") {
|
|
15021
15263
|
const captainId = config.captainId;
|
|
15022
15264
|
if (!captainId)
|
|
@@ -15197,7 +15439,7 @@ function _writeSignalStatus(remoteCode, localStatus, remoteStderr, io) {
|
|
|
15197
15439
|
`);
|
|
15198
15440
|
}
|
|
15199
15441
|
|
|
15200
|
-
// .dist-releases/
|
|
15442
|
+
// .dist-releases/1784888160293-2271563/src/create.js
|
|
15201
15443
|
var CREATE_ENGINES = new Set(["claude", "codex"]);
|
|
15202
15444
|
var DEFAULT_ENGINE = "claude";
|
|
15203
15445
|
var WORKSPACE_PLAIN_LIMIT = 20;
|
|
@@ -15251,9 +15493,9 @@ async function _startTeamSlots(deps, ctx, team, hostId, workspaceRoot, engine, s
|
|
|
15251
15493
|
}
|
|
15252
15494
|
return requests;
|
|
15253
15495
|
}
|
|
15254
|
-
async function _postConsoleJson(deps, ctx,
|
|
15496
|
+
async function _postConsoleJson(deps, ctx, path23, body) {
|
|
15255
15497
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
15256
|
-
const response = await fetchImpl(`${ctx.apiUrl.replace(/\/$/, "")}${
|
|
15498
|
+
const response = await fetchImpl(`${ctx.apiUrl.replace(/\/$/, "")}${path23}`, {
|
|
15257
15499
|
method: "POST",
|
|
15258
15500
|
headers: { Authorization: `Bearer ${ctx.token}`, "Content-Type": "application/json" },
|
|
15259
15501
|
body: JSON.stringify(body)
|
|
@@ -15266,9 +15508,9 @@ async function _postConsoleJson(deps, ctx, path22, body) {
|
|
|
15266
15508
|
throw new Error("SailorBridge API returned a malformed object");
|
|
15267
15509
|
return parsed;
|
|
15268
15510
|
}
|
|
15269
|
-
async function _getConsoleJson(deps, ctx,
|
|
15511
|
+
async function _getConsoleJson(deps, ctx, path23) {
|
|
15270
15512
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
15271
|
-
const response = await fetchImpl(`${ctx.apiUrl.replace(/\/$/, "")}${
|
|
15513
|
+
const response = await fetchImpl(`${ctx.apiUrl.replace(/\/$/, "")}${path23}`, {
|
|
15272
15514
|
headers: { Authorization: `Bearer ${ctx.token}` }
|
|
15273
15515
|
});
|
|
15274
15516
|
const text = await response.text();
|
|
@@ -15343,15 +15585,15 @@ function _rejectMemberFlags(role, flags) {
|
|
|
15343
15585
|
throw new Error(`create ${role} does not accept ${found[0]}`);
|
|
15344
15586
|
}
|
|
15345
15587
|
async function _memberSlotForCreate(deps, ctx, session, role) {
|
|
15346
|
-
const
|
|
15347
|
-
const slots = _responseMemberSlots(await _getConsoleJson(deps, ctx,
|
|
15588
|
+
const path23 = `/api/console/teams/${encodeURIComponent(session)}/agent-slots`;
|
|
15589
|
+
const slots = _responseMemberSlots(await _getConsoleJson(deps, ctx, path23));
|
|
15348
15590
|
const retryable = slots.find((slot) => _isRetryableMemberSlot(slot, role));
|
|
15349
15591
|
if (retryable)
|
|
15350
15592
|
return retryable;
|
|
15351
15593
|
if (role === "planner" && slots.some((slot) => slot.role === role)) {
|
|
15352
15594
|
throw new Error("duplicate-singleton-role: team already has a planner slot");
|
|
15353
15595
|
}
|
|
15354
|
-
const created = _responseMemberSlot(await _postConsoleJson(deps, ctx,
|
|
15596
|
+
const created = _responseMemberSlot(await _postConsoleJson(deps, ctx, path23, { role }));
|
|
15355
15597
|
if (created.role !== role)
|
|
15356
15598
|
throw new Error("SailorBridge API returned a member slot with the wrong role");
|
|
15357
15599
|
return created;
|
|
@@ -15587,7 +15829,7 @@ function _workerPlain(hostId, workdir, result) {
|
|
|
15587
15829
|
`);
|
|
15588
15830
|
}
|
|
15589
15831
|
|
|
15590
|
-
// .dist-releases/
|
|
15832
|
+
// .dist-releases/1784888160293-2271563/src/cli.js
|
|
15591
15833
|
var FORMATTED_COMMANDS = new Set([
|
|
15592
15834
|
"ask",
|
|
15593
15835
|
"create",
|
|
@@ -15647,6 +15889,10 @@ async function main(argv) {
|
|
|
15647
15889
|
});
|
|
15648
15890
|
return;
|
|
15649
15891
|
}
|
|
15892
|
+
if (command === "upgrade") {
|
|
15893
|
+
await runUpgradeFromCli(argv.slice(1), { stdout: process.stdout });
|
|
15894
|
+
return;
|
|
15895
|
+
}
|
|
15650
15896
|
if (command === "host" && argv[1] === "start-request") {
|
|
15651
15897
|
await runHostStartRequestCommandFromCli(argv.slice(2), { stdout: process.stdout, stderr: process.stderr, format: output2.format });
|
|
15652
15898
|
return;
|
|
@@ -15753,6 +15999,7 @@ var KNOWN_COMMANDS = new Set([
|
|
|
15753
15999
|
"task",
|
|
15754
16000
|
"team",
|
|
15755
16001
|
"tutorial",
|
|
16002
|
+
"upgrade",
|
|
15756
16003
|
"workflow",
|
|
15757
16004
|
"worker"
|
|
15758
16005
|
]);
|
|
@@ -15780,6 +16027,7 @@ var SUBCOMMANDS = {
|
|
|
15780
16027
|
"unpark"
|
|
15781
16028
|
]),
|
|
15782
16029
|
team: new Set(["bootstrap"]),
|
|
16030
|
+
upgrade: new Set,
|
|
15783
16031
|
worker: new Set(["job", "list", "run", "serve"])
|
|
15784
16032
|
};
|
|
15785
16033
|
function _assertKnownCommand(command, subcommand) {
|
|
@@ -15981,8 +16229,9 @@ function _resolveOptionalApiUrl(flag, env) {
|
|
|
15981
16229
|
}
|
|
15982
16230
|
return env?.trim() || undefined;
|
|
15983
16231
|
}
|
|
16232
|
+
var AUTO_UPDATE_SKIP_FLAG = "--disable-auto-update";
|
|
15984
16233
|
async function hostRun(argv) {
|
|
15985
|
-
const input = parseFlags3(argv);
|
|
16234
|
+
const input = parseFlags3(argv.filter((arg) => arg !== AUTO_UPDATE_SKIP_FLAG));
|
|
15986
16235
|
const credentialsPath = input["credentials-path"] ?? process.env.SAILORBRIDGE_CREDENTIALS_FILE ?? defaultHostCredentialsPath();
|
|
15987
16236
|
const credential = await loadHostCredential(credentialsPath);
|
|
15988
16237
|
const relayUrl = credential.relay_url ?? process.env.SAILORBRIDGE_RELAY_URL;
|
|
@@ -16000,6 +16249,7 @@ async function hostRun(argv) {
|
|
|
16000
16249
|
process.stderr.write(`${JSON.stringify({ ts: new Date().toISOString(), event, host_id: credential.host_id, ...fields })}
|
|
16001
16250
|
`);
|
|
16002
16251
|
};
|
|
16252
|
+
const autoUpdate = !argv.includes(AUTO_UPDATE_SKIP_FLAG) && await _hostConfigAllowsAutoUpdate(emit);
|
|
16003
16253
|
await runHostDaemon({
|
|
16004
16254
|
relay,
|
|
16005
16255
|
resolveCredential,
|
|
@@ -16010,9 +16260,19 @@ async function hostRun(argv) {
|
|
|
16010
16260
|
signal: controller.signal,
|
|
16011
16261
|
redactSecrets: [credential.token],
|
|
16012
16262
|
...input["workspace-root"] ? { workspaceRoot: input["workspace-root"] } : {},
|
|
16263
|
+
autoUpdate,
|
|
16013
16264
|
logger: emit
|
|
16014
16265
|
});
|
|
16015
16266
|
}
|
|
16267
|
+
async function _hostConfigAllowsAutoUpdate(emit) {
|
|
16268
|
+
try {
|
|
16269
|
+
const config = await loadHostConfig(process.env.SAILORBRIDGE_HOST_CONFIG_FILE ?? defaultHostConfigPath());
|
|
16270
|
+
return config.auto_update !== false;
|
|
16271
|
+
} catch (error) {
|
|
16272
|
+
emit("host_config_load_error", { error: error instanceof Error ? error.message : String(error) });
|
|
16273
|
+
return true;
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16016
16276
|
async function supervise(client2, argv, config) {
|
|
16017
16277
|
const parsed = parseSuperviseArgs(argv);
|
|
16018
16278
|
assertSingleOwnerConfirmed(parsed);
|
|
@@ -16234,6 +16494,8 @@ function _usageText() {
|
|
|
16234
16494
|
sailorbridge workflow
|
|
16235
16495
|
sailorbridge refresh
|
|
16236
16496
|
sailorbridge --version
|
|
16497
|
+
sailorbridge upgrade
|
|
16498
|
+
installs @sailorbridge/client@latest and restarts a running SailorBridge-managed host service.
|
|
16237
16499
|
sailorbridge tutorial [--check] [--api-url URL] [--credentials-path PATH] (default API: ${DEFAULT_PRODUCT_API_URL})
|
|
16238
16500
|
sailorbridge login [--api-url URL] [--host-id H] [--display-name N] [--credentials-path PATH] [--binary PATH] [${SERVICE_SKIP_FLAG}] [--service-dir DIR] [--service-name NAME] (default API: ${DEFAULT_PRODUCT_API_URL})
|
|
16239
16501
|
pairs this host, then installs and starts the host service so the console can start workers and agents here.
|
|
@@ -16283,7 +16545,7 @@ function _usageText() {
|
|
|
16283
16545
|
sailorbridge host consume --once --dry-run-start [--host-id H] [--display-name N]
|
|
16284
16546
|
sailorbridge host service install|uninstall|status [--binary PATH] [--credentials-path PATH] [--workspace-root DIR] [--service-dir DIR] [--service-name NAME]
|
|
16285
16547
|
sailorbridge host start-request [--credentials-path PATH] [--api-url URL] [--access-token TOKEN] --team T [--host-id H] --agent A --engine codex --roles operator --workspace-mode fresh|git [--git-url URL]
|
|
16286
|
-
sailorbridge host run [--credentials-path PATH] [--api-url URL] [--host-id H] [--display-name N] [--workspace-root DIR]
|
|
16548
|
+
sailorbridge host run [--credentials-path PATH] [--api-url URL] [--host-id H] [--display-name N] [--workspace-root DIR] [--disable-auto-update]
|
|
16287
16549
|
sailorbridge worker list [--format plain|json]
|
|
16288
16550
|
sailorbridge worker run [--detach] --worker NAME [--timeout SEC] [--format plain|json] -- ARGV...
|
|
16289
16551
|
sailorbridge worker job ID [--format plain|json]
|
|
@@ -16337,5 +16599,5 @@ function _looksLikeNetworkFailure(message) {
|
|
|
16337
16599
|
return /fetch failed|network|ECONN(?:REFUSED|RESET)|ENOTFOUND|ETIMEDOUT/iu.test(message);
|
|
16338
16600
|
}
|
|
16339
16601
|
|
|
16340
|
-
//# debugId=
|
|
16602
|
+
//# debugId=56B72B0801B5CDF264756E2164756E21
|
|
16341
16603
|
//# sourceMappingURL=cli.js.map
|