@sailorbridge/client 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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/1784772051951-3107696/src/cli.js
5
+ // .dist-releases/1784809313131-4113078/src/cli.js
6
6
  import { hostname as hostname3 } from "node:os";
7
7
  import { writeSync } from "node:fs";
8
- // .dist-releases/1784772051951-3107696/src/auth/host-pairing.js
8
+ // .dist-releases/1784809313131-4113078/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,37 +220,82 @@ function _assertObject(value) {
220
220
  throw new Error("host pairing response must be an object");
221
221
  return value;
222
222
  }
223
- // .dist-releases/1784772051951-3107696/src/host/repo-tip-reporter.js
223
+ // .dist-releases/1784809313131-4113078/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";
227
227
  import path2 from "node:path";
228
228
  import { spawn } from "node:child_process";
229
229
  var COMMAND_TIMEOUT_MS = 120000;
230
+ var REPO_BACKOFF_INITIAL_MS = 60000;
231
+ var REPO_BACKOFF_MAX_MS = 60 * 60000;
230
232
  var SHA_RE = /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/;
231
233
  function defaultRepoMirrorRoot() {
232
234
  return path2.join(homedir2(), ".sailorbridge", "repo-mirrors");
233
235
  }
234
- async function reportRepoTipsOnce(options, deps = {}) {
235
- const logger = options.logger ?? (() => {});
236
+ function createRepoTipReporter(deps = {}) {
237
+ const backoffs = new Map;
238
+ return async (options) => _reportRepoTipsOnce(options, deps, backoffs);
239
+ }
240
+ async function _reportRepoTipsOnce(options, deps, backoffs) {
236
241
  const wanted = await options.relay.getTaskRepoTipWanted(options.captainId);
237
242
  const mirrorRoot = options.mirrorRoot ?? defaultRepoMirrorRoot();
238
243
  let reported = 0;
239
244
  for (const entry of wanted.wanted) {
240
- try {
241
- const report = await observeRepoTips(entry, mirrorRoot, deps);
242
- await options.relay.putTaskRepoTips(options.captainId, entry.session, report);
245
+ if (await _reportRepoTip(entry, mirrorRoot, options, deps, backoffs))
243
246
  reported += 1;
244
- } catch (error) {
245
- logger("host_repo_tip_report_failed", {
246
- session: entry.session,
247
- repo: entry.repo_path,
248
- error: error instanceof Error ? error.message : String(error)
249
- });
250
- }
251
247
  }
248
+ _forgetUnwantedBackoffs(backoffs, wanted.wanted);
252
249
  return { observed: wanted.wanted.length, reported };
253
250
  }
251
+ async function _reportRepoTip(entry, mirrorRoot, options, deps, backoffs) {
252
+ const backoff = backoffs.get(entry.repo_path);
253
+ if (backoff && _now(deps) < backoff.retryAt)
254
+ return false;
255
+ try {
256
+ const report = await observeRepoTips(entry, mirrorRoot, deps);
257
+ await options.relay.putTaskRepoTips(options.captainId, entry.session, report);
258
+ } catch (error) {
259
+ _backOffRepo(entry, error, options.logger, deps, backoffs);
260
+ return false;
261
+ }
262
+ if (backoff)
263
+ _recoverRepo(entry, backoff, options.logger, backoffs);
264
+ return true;
265
+ }
266
+ function _backOffRepo(entry, error, logger, deps, backoffs) {
267
+ const previous = backoffs.get(entry.repo_path);
268
+ const retryMs = previous ? Math.min(previous.retryMs * 2, REPO_BACKOFF_MAX_MS) : REPO_BACKOFF_INITIAL_MS;
269
+ const failures = (previous?.failures ?? 0) + 1;
270
+ backoffs.set(entry.repo_path, { failures, retryAt: _now(deps) + retryMs, retryMs });
271
+ if (previous)
272
+ return;
273
+ logger?.("host_repo_tip_backoff_started", {
274
+ session: entry.session,
275
+ repo: entry.repo_path,
276
+ error: error instanceof Error ? error.message : String(error),
277
+ failures,
278
+ retry_ms: retryMs
279
+ });
280
+ }
281
+ function _recoverRepo(entry, backoff, logger, backoffs) {
282
+ backoffs.delete(entry.repo_path);
283
+ logger?.("host_repo_tip_backoff_recovered", {
284
+ session: entry.session,
285
+ repo: entry.repo_path,
286
+ failures: backoff.failures
287
+ });
288
+ }
289
+ function _forgetUnwantedBackoffs(backoffs, wanted) {
290
+ const activeRepos = new Set(wanted.map((entry) => entry.repo_path));
291
+ for (const repo of backoffs.keys()) {
292
+ if (!activeRepos.has(repo))
293
+ backoffs.delete(repo);
294
+ }
295
+ }
296
+ function _now(deps) {
297
+ return deps.now?.() ?? Date.now();
298
+ }
254
299
  async function observeRepoTips(entry, mirrorRoot, deps) {
255
300
  const exec = deps.execCommand ?? execArgv;
256
301
  const mirror = mirrorPathFor(mirrorRoot, entry.repo_path);
@@ -357,10 +402,10 @@ ${error.message}`));
357
402
  proc.on("close", (code) => finish(code ?? 1));
358
403
  });
359
404
  }
360
- // .dist-releases/1784772051951-3107696/src/host/request-consumer.js
405
+ // .dist-releases/1784809313131-4113078/src/host/request-consumer.js
361
406
  import { hostname as hostname2 } from "node:os";
362
407
 
363
- // .dist-releases/1784772051951-3107696/src/driver/secrets.js
408
+ // .dist-releases/1784809313131-4113078/src/driver/secrets.js
364
409
  function redactSensitiveText(text, env = {}, explicitSecrets = []) {
365
410
  let redacted = text;
366
411
  for (const [key, value] of Object.entries(env)) {
@@ -379,16 +424,16 @@ function isSensitiveEnvKey(key) {
379
424
  return /(TOKEN|KEY|SECRET|AUTHORIZATION|PASSWORD)/i.test(key);
380
425
  }
381
426
 
382
- // .dist-releases/1784772051951-3107696/src/version.js
383
- var CLIENT_VERSION = "0.1.1";
384
- var CLIENT_GIT_SHA = "ba1bf5ddf9ff";
385
- var CLIENT_BUILD_DIRTY = false;
427
+ // .dist-releases/1784809313131-4113078/src/version.js
428
+ var CLIENT_VERSION = "0.2.0";
429
+ var CLIENT_GIT_SHA = "d1e5ed371492-dirty";
430
+ var CLIENT_BUILD_DIRTY = true;
386
431
  var CLIENT_VERSION_LABEL = formatClientVersion(CLIENT_VERSION, CLIENT_GIT_SHA);
387
432
  function formatClientVersion(version, gitSha) {
388
433
  return `${version}+git.${gitSha}`;
389
434
  }
390
435
 
391
- // .dist-releases/1784772051951-3107696/src/host/request-consumer.js
436
+ // .dist-releases/1784809313131-4113078/src/host/request-consumer.js
392
437
  var MAX_ERROR_LENGTH = 500;
393
438
  function defaultHostIdentity(config) {
394
439
  const captainId = config.captainId?.trim();
@@ -443,7 +488,7 @@ function limitErrorMessage(error, explicitSecrets) {
443
488
  const trimmed = redactSensitiveText(message, process.env, explicitSecrets).trim() || "host request starter failed";
444
489
  return trimmed.length <= MAX_ERROR_LENGTH ? trimmed : `${trimmed.slice(0, MAX_ERROR_LENGTH - 3)}...`;
445
490
  }
446
- // .dist-releases/1784772051951-3107696/src/product/start-request.js
491
+ // .dist-releases/1784809313131-4113078/src/product/start-request.js
447
492
  async function createAgentStartRequest(options) {
448
493
  const apiUrl = _required(options.apiUrl, "product API URL").replace(/\/+$/u, "");
449
494
  const accessToken = _required(options.accessToken, "product API bearer token");
@@ -503,7 +548,7 @@ function _string(value, label) {
503
548
  throw new Error(`${label} must be a non-empty string`);
504
549
  return value;
505
550
  }
506
- // .dist-releases/1784772051951-3107696/src/product/pair.js
551
+ // .dist-releases/1784809313131-4113078/src/product/pair.js
507
552
  async function createPair(options) {
508
553
  const apiUrl = _required2(options.apiUrl, "product API URL").replace(/\/+$/u, "");
509
554
  const accessToken = _required2(options.accessToken, "product API bearer token");
@@ -580,7 +625,7 @@ function _string2(value, label) {
580
625
  throw new Error(`${label} must be a non-empty string`);
581
626
  return value;
582
627
  }
583
- // .dist-releases/1784772051951-3107696/src/product/worker.js
628
+ // .dist-releases/1784809313131-4113078/src/product/worker.js
584
629
  async function createWorker(options) {
585
630
  const apiUrl = _required3(options.apiUrl, "product API URL").replace(/\/+$/u, "");
586
631
  const accessToken = _required3(options.accessToken, "product API bearer token");
@@ -644,7 +689,7 @@ function _string3(value, label) {
644
689
  throw new Error(`${label} must be a non-empty string`);
645
690
  return value;
646
691
  }
647
- // .dist-releases/1784772051951-3107696/src/driver/events.js
692
+ // .dist-releases/1784809313131-4113078/src/driver/events.js
648
693
  class DriverEventEmitter {
649
694
  callbacks = new Map;
650
695
  on(type, callback) {
@@ -659,7 +704,7 @@ class DriverEventEmitter {
659
704
  }
660
705
  }
661
706
  }
662
- // .dist-releases/1784772051951-3107696/src/driver/async-queue.js
707
+ // .dist-releases/1784809313131-4113078/src/driver/async-queue.js
663
708
  class AsyncQueue {
664
709
  values = [];
665
710
  waiters = [];
@@ -698,7 +743,7 @@ class AsyncQueue {
698
743
  }
699
744
  }
700
745
 
701
- // .dist-releases/1784772051951-3107696/src/driver/types.js
746
+ // .dist-releases/1784809313131-4113078/src/driver/types.js
702
747
  class DriverUnsupportedError extends Error {
703
748
  constructor(message) {
704
749
  super(message);
@@ -713,7 +758,7 @@ class DriverTargetNotReadyError extends Error {
713
758
  }
714
759
  }
715
760
 
716
- // .dist-releases/1784772051951-3107696/src/driver/sdk-loader.js
761
+ // .dist-releases/1784809313131-4113078/src/driver/sdk-loader.js
717
762
  async function loadSdk(loader, packageName, env = {}, installHint = `Install the optional SDK dependency ${packageName} and its peers for this transport.`) {
718
763
  try {
719
764
  return await loader();
@@ -723,7 +768,7 @@ async function loadSdk(loader, packageName, env = {}, installHint = `Install the
723
768
  }
724
769
  }
725
770
 
726
- // .dist-releases/1784772051951-3107696/src/driver/claude/driver.js
771
+ // .dist-releases/1784809313131-4113078/src/driver/claude/driver.js
727
772
  class ClaudeAgentSdkDriver {
728
773
  options;
729
774
  capabilities = { structured: true, resume: true, attach: false };
@@ -899,7 +944,7 @@ function asRecord(value) {
899
944
  function stringValue(value) {
900
945
  return typeof value === "string" ? value : undefined;
901
946
  }
902
- // .dist-releases/1784772051951-3107696/src/driver/codex/driver.js
947
+ // .dist-releases/1784809313131-4113078/src/driver/codex/driver.js
903
948
  class CodexSdkDriver {
904
949
  options;
905
950
  capabilities = { structured: true, resume: true, attach: false };
@@ -1080,7 +1125,7 @@ function asRecord2(value) {
1080
1125
  function stringValue2(value) {
1081
1126
  return typeof value === "string" ? value : undefined;
1082
1127
  }
1083
- // .dist-releases/1784772051951-3107696/src/driver/liveness-heuristics.js
1128
+ // .dist-releases/1784809313131-4113078/src/driver/liveness-heuristics.js
1084
1129
  var BUSY_MARKERS = ["Working (", "Waiting for background", "Pasted Content", "tab to queue"];
1085
1130
  var ANSI_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\)|[PX^_][\s\S]*?\x1B\\)/g;
1086
1131
  function stripAnsi(text) {
@@ -1107,7 +1152,7 @@ function classifyInteractiveOutput(input) {
1107
1152
  function isOutputStable(now, lastOutputAt, idleStableMs) {
1108
1153
  return Boolean(lastOutputAt && now.getTime() - lastOutputAt.getTime() >= idleStableMs);
1109
1154
  }
1110
- // .dist-releases/1784772051951-3107696/src/driver/pty/loader.js
1155
+ // .dist-releases/1784809313131-4113078/src/driver/pty/loader.js
1111
1156
  async function loadNodePty(loader = defaultNodePtyLoader) {
1112
1157
  try {
1113
1158
  return await loader();
@@ -1133,7 +1178,7 @@ async function defaultNodePtyLoader() {
1133
1178
  return loaded;
1134
1179
  }
1135
1180
 
1136
- // .dist-releases/1784772051951-3107696/src/driver/pty/driver.js
1181
+ // .dist-releases/1784809313131-4113078/src/driver/pty/driver.js
1137
1182
  class PtyDriver {
1138
1183
  options;
1139
1184
  capabilities = { structured: false, resume: false, attach: false };
@@ -1285,12 +1330,12 @@ function tail(text, lines) {
1285
1330
  function sleep(ms) {
1286
1331
  return new Promise((resolve) => setTimeout(resolve, ms));
1287
1332
  }
1288
- // .dist-releases/1784772051951-3107696/src/driver/tmux/driver.js
1333
+ // .dist-releases/1784809313131-4113078/src/driver/tmux/driver.js
1289
1334
  import { mkdtemp, rm, writeFile as writeFile2 } from "node:fs/promises";
1290
1335
  import { tmpdir } from "node:os";
1291
1336
  import { join } from "node:path";
1292
1337
 
1293
- // .dist-releases/1784772051951-3107696/src/driver/tmux/launch.js
1338
+ // .dist-releases/1784809313131-4113078/src/driver/tmux/launch.js
1294
1339
  var ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
1295
1340
  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 "$@"';
1296
1341
  function buildTmuxNewSessionArgs(input) {
@@ -1313,7 +1358,7 @@ function validateEnv(env) {
1313
1358
  }
1314
1359
  }
1315
1360
 
1316
- // .dist-releases/1784772051951-3107696/src/driver/tmux/paste.js
1361
+ // .dist-releases/1784809313131-4113078/src/driver/tmux/paste.js
1317
1362
  function buildDispatchPlan(text, useTyping) {
1318
1363
  return {
1319
1364
  mode: useTyping ? "type-literal" : "paste-buffer",
@@ -1337,7 +1382,7 @@ function arraysEqual(left, right) {
1337
1382
  return left.length === right.length && left.every((item, index) => item === right[index]);
1338
1383
  }
1339
1384
 
1340
- // .dist-releases/1784772051951-3107696/src/driver/tmux/liveness.js
1385
+ // .dist-releases/1784809313131-4113078/src/driver/tmux/liveness.js
1341
1386
  var SHELL_COMMANDS = new Set(["", "bash", "zsh", "sh", "fish", "pwsh", "powershell"]);
1342
1387
  function classifyTmuxLiveness(input) {
1343
1388
  if (!input.hasSession) {
@@ -1357,7 +1402,7 @@ function isTmuxProcessAlive(command, runningCommands) {
1357
1402
  return !SHELL_COMMANDS.has(command);
1358
1403
  }
1359
1404
 
1360
- // .dist-releases/1784772051951-3107696/src/driver/tmux/runner.js
1405
+ // .dist-releases/1784809313131-4113078/src/driver/tmux/runner.js
1361
1406
  import { spawn as spawn2 } from "node:child_process";
1362
1407
  var DEFAULT_TIMEOUT_MS = 15000;
1363
1408
 
@@ -1482,7 +1527,7 @@ class TmuxClient {
1482
1527
  }
1483
1528
  }
1484
1529
 
1485
- // .dist-releases/1784772051951-3107696/src/driver/tmux/driver.js
1530
+ // .dist-releases/1784809313131-4113078/src/driver/tmux/driver.js
1486
1531
  var ATTACHED_STOP_GRACE_MS = 1e4;
1487
1532
  var DEFAULT_STOP_TIMEOUT_MS = 15000;
1488
1533
  var DEFAULT_READY_TIMEOUT_MS = 90000;
@@ -1877,12 +1922,12 @@ function isMissingTmuxSessionError(error) {
1877
1922
  ${error.result.stderr}`.toLowerCase();
1878
1923
  return text.includes("can't find session") || text.includes("cannot find session") || text.includes("no such session") || text.includes("session not found");
1879
1924
  }
1880
- // .dist-releases/1784772051951-3107696/src/relay/client.js
1925
+ // .dist-releases/1784809313131-4113078/src/relay/client.js
1881
1926
  import { Buffer as Buffer2 } from "node:buffer";
1882
1927
  import http from "node:http";
1883
1928
  import https from "node:https";
1884
1929
 
1885
- // .dist-releases/1784772051951-3107696/src/relay/errors.js
1930
+ // .dist-releases/1784809313131-4113078/src/relay/errors.js
1886
1931
  class RelayError extends Error {
1887
1932
  method;
1888
1933
  path;
@@ -1919,7 +1964,7 @@ class RelayProtocolError extends RelayError {
1919
1964
  }
1920
1965
  }
1921
1966
 
1922
- // .dist-releases/1784772051951-3107696/src/relay/client.js
1967
+ // .dist-releases/1784809313131-4113078/src/relay/client.js
1923
1968
  var JSON_CONTENT_TYPE = "application/json";
1924
1969
  var MAX_MAILBOX_LIMIT = 16;
1925
1970
  var MAX_WAIT_TIMEOUT_SEC = 120;
@@ -2206,29 +2251,6 @@ class RelayClient {
2206
2251
  const response = await this.requestJson("POST", path3, body);
2207
2252
  return _parseTeamAgentSlot(response.agent_slot, "POST", path3);
2208
2253
  }
2209
- async getTeamRepository(captainId, session) {
2210
- const path3 = `/api/v1/captains/${segment(captainId)}/sessions`;
2211
- const response = await this.requestJson("GET", path3);
2212
- if (!Array.isArray(response.sessions))
2213
- throw new RelayProtocolError("GET", path3, "sessions must be an array");
2214
- const rows = response.sessions.map((row) => _parseTeamRepository(row, "GET", path3));
2215
- const repository = rows.find((row) => row.team_id === session);
2216
- if (!repository)
2217
- throw new RelayProtocolError("GET", path3, `team ${session} is missing`);
2218
- return repository;
2219
- }
2220
- async setTeamRepositoryState(captainId, session, body) {
2221
- const path3 = `${_captainSessionPath(captainId, session)}/repo-verification-state`;
2222
- const response = await this.requestJson("PATCH", path3, body);
2223
- return _parseTeamRepository(response.session, "PATCH", path3);
2224
- }
2225
- async createRepoVerificationRequest(captainId, session, hostId, gitRepoUrl) {
2226
- const path3 = `${_captainSessionPath(captainId, session)}/repo-verification-requests`;
2227
- const response = await this.requestJson("POST", path3, { host_id: hostId, git_repo_url: gitRepoUrl });
2228
- const request = parseAgentStartRequest(response.request, "POST", path3);
2229
- _requireRepoVerificationRequest(request, "POST", path3, session, hostId);
2230
- return request;
2231
- }
2232
2254
  async getAgentStartRequest(captainId, session, requestId, timeoutMs) {
2233
2255
  const path3 = `${_captainSessionPath(captainId, session)}/agent-start-requests/${segment(requestId)}`;
2234
2256
  const response = await this.requestJson("GET", path3, undefined, timeoutMs);
@@ -2403,6 +2425,12 @@ class RelayClient {
2403
2425
  const path3 = `/api/v1/rag/captains/${segment(captainId)}/teams/${segment(teamId)}/index`;
2404
2426
  return parseRagMemoryIndex(await this.requestJson("GET", path3), "GET", path3);
2405
2427
  }
2428
+ async getRagEntitlement(captainId, teamId) {
2429
+ requireCaptainId(captainId);
2430
+ requireSegment(teamId, "teamId");
2431
+ const path3 = `/api/v1/rag/captains/${segment(captainId)}/teams/${segment(teamId)}/entitlement`;
2432
+ return parseRagEntitlement(await this.requestJson("GET", path3), "GET", path3);
2433
+ }
2406
2434
  async setRagCardPin(captainId, teamId, key, pinned) {
2407
2435
  requireCaptainId(captainId);
2408
2436
  requireSegment(teamId, "teamId");
@@ -2966,34 +2994,6 @@ function _parseTeamAgentSlot(value, method, path3) {
2966
2994
  template_id: slot.template_id ?? null
2967
2995
  };
2968
2996
  }
2969
- function _parseTeamRepository(value, method, path3) {
2970
- if (!value || typeof value !== "object" || Array.isArray(value))
2971
- throw new RelayProtocolError(method, path3, "session must be an object");
2972
- const session = value;
2973
- if (typeof session.id !== "string" || !session.id)
2974
- throw new RelayProtocolError(method, path3, "session.id must be a non-empty string");
2975
- if (session.git_repo_url !== null && typeof session.git_repo_url !== "string")
2976
- throw new RelayProtocolError(method, path3, "session.git_repo_url must be a string or null");
2977
- if (!_isTeamRepositoryStatus(session.git_repo_verification_status))
2978
- throw new RelayProtocolError(method, path3, "session.git_repo_verification_status is invalid");
2979
- if (session.git_repo_verification_reason !== null && typeof session.git_repo_verification_reason !== "string")
2980
- throw new RelayProtocolError(method, path3, "session.git_repo_verification_reason must be a string or null");
2981
- return {
2982
- team_id: session.id,
2983
- git_repo_url: session.git_repo_url,
2984
- git_repo_verification_status: session.git_repo_verification_status,
2985
- git_repo_verification_reason: session.git_repo_verification_reason
2986
- };
2987
- }
2988
- function _isTeamRepositoryStatus(value) {
2989
- return value === "unverified" || value === "pending" || value === "verified" || value === "failed";
2990
- }
2991
- function _requireRepoVerificationRequest(request, method, path3, session, hostId) {
2992
- if (request.request_kind !== "repo_verification")
2993
- throw new RelayProtocolError(method, path3, "request_kind must be repo_verification");
2994
- if (request.session !== session || request.host_id !== hostId)
2995
- throw new RelayProtocolError(method, path3, "request identity does not match repository verification target");
2996
- }
2997
2997
  function _parseSessionArtifact(value, method, path3) {
2998
2998
  for (const field of ["id", "name", "sha256", "content_url"]) {
2999
2999
  if (typeof value[field] !== "string" || !value[field])
@@ -3357,7 +3357,7 @@ function parseAgentStartRequest(value, method, path3) {
3357
3357
  }
3358
3358
  if (request.request_kind === undefined)
3359
3359
  request.request_kind = "agent_start";
3360
- if (request.request_kind !== "agent_start" && request.request_kind !== "repo_verification" && request.request_kind !== "worker_start") {
3360
+ if (request.request_kind !== "agent_start" && request.request_kind !== "worker_start") {
3361
3361
  throw new RelayProtocolError(method, path3, "request.request_kind is invalid");
3362
3362
  }
3363
3363
  if (request.result !== undefined && (!request.result || typeof request.result !== "object" || Array.isArray(request.result))) {
@@ -3520,6 +3520,11 @@ function parseRagMemoryIndex(value, method, path3) {
3520
3520
  }));
3521
3521
  return { enabled: value.enabled, degraded: value.degraded, text: value.text, budget_tokens: value.budget_tokens, total_cards: value.total_cards, omitted_cards: value.omitted_cards, sections };
3522
3522
  }
3523
+ function parseRagEntitlement(value, method, path3) {
3524
+ if (typeof value.enabled !== "boolean")
3525
+ throw new RelayProtocolError(method, path3, "entitlement.enabled must be a boolean");
3526
+ return { enabled: value.enabled };
3527
+ }
3523
3528
  function parseManagedMaterializationResponse(value, method, path3, cursor) {
3524
3529
  if (value === "not_modified_304") {
3525
3530
  if (!cursor?.trim())
@@ -3849,12 +3854,12 @@ function redact(value, token) {
3849
3854
  function bytesToBase64(bytes) {
3850
3855
  return Buffer2.from(bytes).toString("base64");
3851
3856
  }
3852
- // .dist-releases/1784772051951-3107696/src/relay/config.js
3857
+ // .dist-releases/1784809313131-4113078/src/relay/config.js
3853
3858
  import { existsSync as existsSync2, readFileSync } from "node:fs";
3854
3859
  import { homedir as homedir3 } from "node:os";
3855
3860
  import path3 from "node:path";
3856
3861
 
3857
- // .dist-releases/1784772051951-3107696/src/worker/protocol.js
3862
+ // .dist-releases/1784809313131-4113078/src/worker/protocol.js
3858
3863
  var DEFAULT_RELAY_URL = DEFAULT_PRODUCT_API_URL;
3859
3864
  var DEFAULT_WORKER = "host";
3860
3865
  var DEFAULT_WORKDIR = "~/sailorbridge-workdir";
@@ -3883,7 +3888,7 @@ function effectiveJobKind(kind, spec) {
3883
3888
  return kind === "stream" || spec.stream === true ? "stream" : kind;
3884
3889
  }
3885
3890
 
3886
- // .dist-releases/1784772051951-3107696/src/relay/config.js
3891
+ // .dist-releases/1784809313131-4113078/src/relay/config.js
3887
3892
  function loadRelayConfig(env = process.env) {
3888
3893
  const envRelayUrl = nonEmpty(env.SAILORBRIDGE_RELAY_URL);
3889
3894
  const envBearerToken = nonEmpty(env.SAILORBRIDGE_TOKEN);
@@ -3955,7 +3960,7 @@ function storedCaptainId(value) {
3955
3960
  }
3956
3961
  return;
3957
3962
  }
3958
- // .dist-releases/1784772051951-3107696/src/supervisor/retirement.js
3963
+ // .dist-releases/1784809313131-4113078/src/supervisor/retirement.js
3959
3964
  var DEFAULT_THRESHOLD = 3;
3960
3965
  var DEFAULT_WINDOW_MS = 30000;
3961
3966
  var DEFAULT_COOLDOWN_MS = 1000;
@@ -4030,7 +4035,7 @@ function isAuthoritativeRetirementReason(reason) {
4030
4035
  return reason === "monitor_fetch" || reason === "agent_session_patch";
4031
4036
  }
4032
4037
 
4033
- // .dist-releases/1784772051951-3107696/src/supervisor/wait.js
4038
+ // .dist-releases/1784809313131-4113078/src/supervisor/wait.js
4034
4039
  async function waitForWakeableTimeout(ms, setWake, sleep3) {
4035
4040
  if (sleep3) {
4036
4041
  await Promise.race([
@@ -4061,7 +4066,7 @@ async function waitForWakeableTimeout(ms, setWake, sleep3) {
4061
4066
  setWake(null);
4062
4067
  }
4063
4068
 
4064
- // .dist-releases/1784772051951-3107696/src/supervisor/mailbox.js
4069
+ // .dist-releases/1784809313131-4113078/src/supervisor/mailbox.js
4065
4070
  var CLEAR_TAG = "CLEAR";
4066
4071
  var REFRESH_TAG = "WORKFLOW-REFRESH";
4067
4072
  var SYNC_TAG = "SYNC";
@@ -4597,38 +4602,79 @@ function ordinaryDeliveryAttempt(error) {
4597
4602
  function _isMissingModerator(error) {
4598
4603
  return error instanceof RelayHttpError && error.status === 400 && error.body.includes("no agents match");
4599
4604
  }
4600
- // .dist-releases/1784772051951-3107696/src/supervisor/runtime.js
4605
+ // .dist-releases/1784809313131-4113078/src/supervisor/runtime.js
4601
4606
  import path9 from "node:path";
4602
4607
  import { execFile } from "node:child_process";
4603
4608
  import { promisify } from "node:util";
4604
4609
 
4605
- // .dist-releases/1784772051951-3107696/src/host/managed-materialization.js
4610
+ // .dist-releases/1784809313131-4113078/src/host/managed-materialization.js
4606
4611
  import { createHash as createHash2, randomBytes } from "node:crypto";
4607
4612
  import { constants as fsConstants } from "node:fs";
4608
4613
  import { lstat, mkdir as mkdir3, open, readdir, rename, rm as rm2 } from "node:fs/promises";
4609
4614
  import { homedir as homedir5 } from "node:os";
4610
4615
  import path5 from "node:path";
4611
4616
 
4612
- // .dist-releases/1784772051951-3107696/src/host/memory-stub.js
4613
- import { mkdir as mkdir2, writeFile as writeFile3 } from "node:fs/promises";
4617
+ // .dist-releases/1784809313131-4113078/src/host/memory-stub.js
4618
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile3 } from "node:fs/promises";
4614
4619
  import { homedir as homedir4 } from "node:os";
4615
4620
  import path4 from "node:path";
4616
- var RAG_MEMORY_STUB_BEGIN = "<!-- sailorbridge-rag-memory-stub:begin -->";
4617
- var RAG_MEMORY_STUB_END = "<!-- sailorbridge-rag-memory-stub:end -->";
4618
- var RAG_MEMORY_STUB = [
4619
- "# SailorBridge RAG Memory Protocol",
4621
+ var TEAM_MEMORY_STUB_BEGIN = "<!-- sailorbridge-team-memory-stub:begin -->";
4622
+ var TEAM_MEMORY_STUB_END = "<!-- sailorbridge-team-memory-stub:end -->";
4623
+ var LEGACY_STUB_BEGIN = "<!-- sailorbridge-rag-memory-stub:begin -->";
4624
+ var LEGACY_STUB_END = "<!-- sailorbridge-rag-memory-stub:end -->";
4625
+ var STUB_LOCAL_MEMORY = [
4626
+ "- Your local memory files are yours: the product never collects, rewrites, or deletes them.",
4627
+ " Keep working notes and everything tied to your own role in local memory.",
4628
+ "- Role-bound and personal content must stay local. Never publish it to shared team stores:",
4629
+ " another member recalling your role's private memory is an identity mix-up."
4630
+ ];
4631
+ var TEAM_MEMORY_STUB_ENTITLED = [
4632
+ "# SailorBridge Team Memory Protocol",
4620
4633
  "",
4621
- "- Memory is service-only with zero synchronization: store durable facts only in the relay RAG card store, never in local memory files.",
4622
- "- Run `sail rag search` before recall; treat returned RAG cards as authoritative and never override them from local memory.",
4623
- "- Write learned durable facts back with `sail rag set <key> --stdin --source <source>` or `sail rag set <key> --file <path> --source <source>`.",
4624
- "- Keep only this protocol stub in local memory files: query RAG first, trust the cards, and write learned facts back to RAG.",
4625
- "- Never write durable facts to CLAUDE.md, AGENTS.md, MEMORY.md, or engine-native local memory directories; RAG is the only write channel.",
4626
- "- Fail fast when the service is unavailable; never present stale local content as a successful result.",
4627
- "- Optional read-only snapshots must be clearly marked as disaster recovery.",
4634
+ ...STUB_LOCAL_MEMORY,
4635
+ "- Team memory is the team's shared knowledge and experience. Before a non-trivial",
4636
+ " question, run `sail memory search <query>` someone may already know.",
4637
+ "- When you learn something the whole team benefits from, save it with",
4638
+ " `sail memory set <key> --stdin --source <source>` (or `--file <path>`).",
4639
+ "- Prefer team memory over rules when saving: rules are behavior norms; knowledge",
4640
+ " and experience belong in team memory.",
4641
+ "- If the memory service is unavailable, fail fast and say so; never present stale",
4642
+ " local content as the team's shared truth.",
4628
4643
  ""
4629
4644
  ].join(`
4630
4645
  `);
4631
- var RAG_MEMORY_STUB_MARKED = _markedStub(RAG_MEMORY_STUB);
4646
+ var TEAM_MEMORY_STUB_UNENTITLED = [
4647
+ "# SailorBridge Team Memory Protocol",
4648
+ "",
4649
+ ...STUB_LOCAL_MEMORY,
4650
+ "- Share lessons and working norms through team rules: propose a rule to your",
4651
+ " captain or moderator so the whole team inherits it.",
4652
+ "- The Team Memory add-on adds shared cross-member memory with corrections",
4653
+ " (`sail memory` commands); the captain can enable it from the console.",
4654
+ ""
4655
+ ].join(`
4656
+ `);
4657
+ function teamMemoryStub(entitled) {
4658
+ return entitled ? TEAM_MEMORY_STUB_ENTITLED : TEAM_MEMORY_STUB_UNENTITLED;
4659
+ }
4660
+ function teamMemoryStubMarked(entitled) {
4661
+ return `${TEAM_MEMORY_STUB_BEGIN}
4662
+ ${teamMemoryStub(entitled)}${TEAM_MEMORY_STUB_END}
4663
+ `;
4664
+ }
4665
+ async function resolveTeamMemoryEntitlement(relay, captainId, teamId) {
4666
+ const captain = captainId?.trim();
4667
+ const team = teamId?.trim();
4668
+ if (!captain || !team)
4669
+ throw new Error("team memory entitlement requires captain_id and session");
4670
+ try {
4671
+ return (await relay.getRagEntitlement(captain, team)).enabled;
4672
+ } catch (error) {
4673
+ if (error instanceof RelayHttpError && error.status === 402)
4674
+ return false;
4675
+ throw error;
4676
+ }
4677
+ }
4632
4678
  async function materializeAgentMemoryStub(options) {
4633
4679
  const engine = _memoryStubEngine(options.engine);
4634
4680
  const homeDir = options.homeDir ? path4.resolve(_expandHome(options.homeDir)) : agentSandboxHome(options.agentName, engine, options.env ?? process.env);
@@ -4637,7 +4683,10 @@ async function materializeAgentMemoryStub(options) {
4637
4683
  const mkdirFn = options.mkdir ?? mkdir2;
4638
4684
  const writeFileFn = options.writeFile ?? writeFile3;
4639
4685
  await mkdirFn(homeDir, { recursive: true });
4640
- await writeFileFn(filePath, RAG_MEMORY_STUB_MARKED, { mode: 384 });
4686
+ const existing = await _readIfPresent(filePath, options.readFile ?? readFile2);
4687
+ const next = _spliceStubBlock(existing, teamMemoryStubMarked(options.teamMemoryEntitled));
4688
+ if (next !== existing)
4689
+ await writeFileFn(filePath, next, { mode: 384 });
4641
4690
  return {
4642
4691
  engine,
4643
4692
  homeDir,
@@ -4652,6 +4701,38 @@ function agentSandboxHome(agentName, engine, env = process.env) {
4652
4701
  function memoryStubFileName(engine) {
4653
4702
  return engine === "claude" ? "CLAUDE.md" : "AGENTS.md";
4654
4703
  }
4704
+ function _spliceStubBlock(existing, block) {
4705
+ if (existing === null || !existing.trim())
4706
+ return block;
4707
+ const current = _replaceMarkedBlock(existing, TEAM_MEMORY_STUB_BEGIN, TEAM_MEMORY_STUB_END, block) ?? _replaceMarkedBlock(existing, LEGACY_STUB_BEGIN, LEGACY_STUB_END, block);
4708
+ if (current !== undefined)
4709
+ return current;
4710
+ const cleaned = _dropStrayMarkers(existing);
4711
+ if (!cleaned.trim())
4712
+ return block;
4713
+ return `${block}
4714
+ ${cleaned.replace(/^\n+/u, "")}`;
4715
+ }
4716
+ function _replaceMarkedBlock(content, begin, end, block) {
4717
+ const start = content.indexOf(begin);
4718
+ const stop = content.indexOf(end);
4719
+ if (start < 0 || stop < start)
4720
+ return;
4721
+ const after = content.slice(stop + end.length).replace(/^\n/u, "");
4722
+ return `${content.slice(0, start)}${block}${after}`;
4723
+ }
4724
+ function _dropStrayMarkers(content) {
4725
+ return [TEAM_MEMORY_STUB_BEGIN, TEAM_MEMORY_STUB_END, LEGACY_STUB_BEGIN, LEGACY_STUB_END].reduce((text, marker) => text.split(marker).join(""), content);
4726
+ }
4727
+ async function _readIfPresent(filePath, readFileFn) {
4728
+ try {
4729
+ return await readFileFn(filePath, "utf8");
4730
+ } catch (error) {
4731
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT")
4732
+ return null;
4733
+ throw error;
4734
+ }
4735
+ }
4655
4736
  function _memoryStubEngine(value) {
4656
4737
  if (value !== "claude" && value !== "codex") {
4657
4738
  throw new Error("memory stub engine must be claude or codex");
@@ -4679,13 +4760,8 @@ function _safePathLabel(value, field) {
4679
4760
  }
4680
4761
  return trimmed;
4681
4762
  }
4682
- function _markedStub(body) {
4683
- return `${RAG_MEMORY_STUB_BEGIN}
4684
- ${body}${RAG_MEMORY_STUB_END}
4685
- `;
4686
- }
4687
4763
 
4688
- // .dist-releases/1784772051951-3107696/src/host/managed-materialization.js
4764
+ // .dist-releases/1784809313131-4113078/src/host/managed-materialization.js
4689
4765
  var MANIFEST_FILE = ".sailorbridge-managed-manifest.json";
4690
4766
  var BANNER_PREFIX = "# SailorBridge managed file";
4691
4767
  var HASH_RE = /^sha256:[a-f0-9]{64}$/u;
@@ -5211,14 +5287,14 @@ function _expandHome2(value) {
5211
5287
  return value;
5212
5288
  }
5213
5289
 
5214
- // .dist-releases/1784772051951-3107696/src/host/credential-guardian.js
5215
- import { lstat as lstat2, readFile as readFile2, rename as rename2, symlink, unlink, writeFile as writeFile4 } from "node:fs/promises";
5290
+ // .dist-releases/1784809313131-4113078/src/host/credential-guardian.js
5291
+ import { lstat as lstat2, readFile as readFile3, rename as rename2, symlink, unlink, writeFile as writeFile4 } from "node:fs/promises";
5216
5292
  import path6 from "node:path";
5217
5293
  var DEFAULT_CREDENTIAL_SWEEP_INTERVAL_MS = 60000;
5218
5294
  var DEFAULT_FAILURE_ALERT_THRESHOLD = 3;
5219
5295
  var defaultFs = {
5220
5296
  lstat: lstat2,
5221
- readFile: (filePath) => readFile2(filePath),
5297
+ readFile: (filePath) => readFile3(filePath),
5222
5298
  writeFile: (filePath, data, options) => writeFile4(filePath, data, options),
5223
5299
  rename: rename2,
5224
5300
  symlink: (target, linkPath) => symlink(target, linkPath),
@@ -5357,7 +5433,7 @@ function _tmpSibling(filePath) {
5357
5433
  return path6.join(path6.dirname(filePath), `.${path6.basename(filePath)}.sb-guardian.${process.pid}.${tmpSequence}.tmp`);
5358
5434
  }
5359
5435
 
5360
- // .dist-releases/1784772051951-3107696/src/supervisor/resolve.js
5436
+ // .dist-releases/1784809313131-4113078/src/supervisor/resolve.js
5361
5437
  var DEFAULT_CAPTURE_LINES = 200;
5362
5438
  var MAX_CAPTURE_LINES = 1000;
5363
5439
 
@@ -5563,7 +5639,7 @@ function defaultSleep(ms) {
5563
5639
  return new Promise((resolve) => setTimeout(resolve, ms));
5564
5640
  }
5565
5641
 
5566
- // .dist-releases/1784772051951-3107696/src/supervisor/transcript-backfill.js
5642
+ // .dist-releases/1784809313131-4113078/src/supervisor/transcript-backfill.js
5567
5643
  import { createHash as createHash3 } from "node:crypto";
5568
5644
  import {
5569
5645
  closeSync,
@@ -6220,7 +6296,7 @@ function errorMessage4(error) {
6220
6296
  return error instanceof Error ? error.message : String(error);
6221
6297
  }
6222
6298
 
6223
- // .dist-releases/1784772051951-3107696/src/supervisor/usage-collector.js
6299
+ // .dist-releases/1784809313131-4113078/src/supervisor/usage-collector.js
6224
6300
  import { statSync as statSync2 } from "node:fs";
6225
6301
  import path8 from "node:path";
6226
6302
  var SUPPORTED_USAGE_ENGINES = new Set(["claude", "codex"]);
@@ -6629,7 +6705,7 @@ function sourceUnreadableReason(source) {
6629
6705
  }
6630
6706
  }
6631
6707
 
6632
- // .dist-releases/1784772051951-3107696/src/supervisor/runtime.js
6708
+ // .dist-releases/1784809313131-4113078/src/supervisor/runtime.js
6633
6709
  var RESOLVE_CAPTURE_LINES = 200;
6634
6710
  var SHORT_LIVED_EXIT_MS = 5000;
6635
6711
  var STARTUP_OBSERVATION_MS = 1e4;
@@ -7299,7 +7375,7 @@ function errorMessage5(error) {
7299
7375
  function formatRestartCommand(command) {
7300
7376
  return command.map((part) => /^[A-Za-z0-9_./:=@%+-]+$/.test(part) ? part : `'${part.replaceAll("'", "'\\''")}'`).join(" ");
7301
7377
  }
7302
- // .dist-releases/1784772051951-3107696/src/supervisor/transport.js
7378
+ // .dist-releases/1784809313131-4113078/src/supervisor/transport.js
7303
7379
  var SUPPORTED_PHASE1_CLI_KINDS = ["claude", "codex"];
7304
7380
  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.";
7305
7381
  var PHASE1_TRANSPORT_GATE_MESSAGE = "Only tmux transport is available in this release; sdk, headless, and pty transports will open in the next release.";
@@ -7507,7 +7583,7 @@ function hasCodexSafetyDriverOptions(options) {
7507
7583
  return options?.codex?.sandboxMode !== undefined || options?.codex?.approvalPolicy !== undefined || options?.codex?.yolo !== undefined;
7508
7584
  }
7509
7585
 
7510
- // .dist-releases/1784772051951-3107696/src/supervisor/cli-options.js
7586
+ // .dist-releases/1784809313131-4113078/src/supervisor/cli-options.js
7511
7587
  function parseSuperviseArgs(argv) {
7512
7588
  const split = argv.indexOf("--");
7513
7589
  const flagArgs = split >= 0 ? argv.slice(0, split) : argv;
@@ -7659,7 +7735,7 @@ function optionalBoolean(value, label) {
7659
7735
  return false;
7660
7736
  throw new Error(`${label} must be true or false`);
7661
7737
  }
7662
- // .dist-releases/1784772051951-3107696/src/supervisor/tmux-availability.js
7738
+ // .dist-releases/1784809313131-4113078/src/supervisor/tmux-availability.js
7663
7739
  import { spawn as spawn3 } from "node:child_process";
7664
7740
  import { createInterface } from "node:readline";
7665
7741
  function isTmuxAvailable(spawnFn = spawn3) {
@@ -7776,7 +7852,7 @@ function _tmuxMissingMessage(platform2) {
7776
7852
  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";
7777
7853
  return `tmux is required in this release but was not found. Install tmux (${how}) and re-run.`;
7778
7854
  }
7779
- // .dist-releases/1784772051951-3107696/src/output-format.js
7855
+ // .dist-releases/1784809313131-4113078/src/output-format.js
7780
7856
  function parseOutputArgs(argv) {
7781
7857
  const cleaned = [];
7782
7858
  let format = "plain";
@@ -7866,7 +7942,7 @@ ${normalized.split(`
7866
7942
  `)}`;
7867
7943
  }
7868
7944
 
7869
- // .dist-releases/1784772051951-3107696/src/plain-output-fields.js
7945
+ // .dist-releases/1784809313131-4113078/src/plain-output-fields.js
7870
7946
  var PREVIEW_LIMIT = 20;
7871
7947
  var UNSAFE_DISPLAY_CODE_POINT = /[\u007f-\u009f\u2028-\u202e\u2066-\u2069]/gu;
7872
7948
  function renderTaskPlain(command, value) {
@@ -8274,7 +8350,7 @@ function _omissionLine(total) {
8274
8350
  return total > PREVIEW_LIMIT ? `Omitted ${total - PREVIEW_LIMIT}; rerun with --format json for the complete response.` : undefined;
8275
8351
  }
8276
8352
 
8277
- // .dist-releases/1784772051951-3107696/src/host/cli.js
8353
+ // .dist-releases/1784809313131-4113078/src/host/cli.js
8278
8354
  var HOST_RELAY_SUBCOMMANDS = new Set(["consume", "heartbeat", "list", "register"]);
8279
8355
  async function runHostCommandFromCli(client, argv, config, io) {
8280
8356
  const sub = argv[0] ?? "list";
@@ -8512,11 +8588,11 @@ function optionalDisplayName(value) {
8512
8588
  const trimmed = value?.trim();
8513
8589
  return trimmed || undefined;
8514
8590
  }
8515
- // .dist-releases/1784772051951-3107696/src/host/service.js
8591
+ // .dist-releases/1784809313131-4113078/src/host/service.js
8516
8592
  import { execFile as execFileCb } from "node:child_process";
8517
8593
  import { createHash as createHash4 } from "node:crypto";
8518
8594
  import { constants as fsConstants2 } from "node:fs";
8519
- import { access, chmod as chmod2, lstat as lstat3, mkdir as mkdir4, readFile as readFile3, rename as rename3, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
8595
+ import { access, chmod as chmod2, lstat as lstat3, mkdir as mkdir4, readFile as readFile4, rename as rename3, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
8520
8596
  import { homedir as homedir7, platform as platform2, userInfo } from "node:os";
8521
8597
  import path10 from "node:path";
8522
8598
  import { promisify as promisify2 } from "node:util";
@@ -8736,7 +8812,7 @@ function serviceRuntime(deps) {
8736
8812
  username: deps.username ?? info.username,
8737
8813
  execFile: deps.execFile ?? execFileDefault,
8738
8814
  writeFile: deps.writeFile ?? writeFile5,
8739
- readFile: deps.readFile ?? readFile3,
8815
+ readFile: deps.readFile ?? readFile4,
8740
8816
  mkdir: deps.mkdir ?? mkdir4,
8741
8817
  rm: deps.rm ?? rm3,
8742
8818
  access: deps.access ?? access,
@@ -8995,7 +9071,7 @@ function writeServiceLog(io, event, fields) {
8995
9071
  io.stderr.write(`${JSON.stringify({ ts: new Date().toISOString(), event, ...fields ?? {} })}
8996
9072
  `);
8997
9073
  }
8998
- // .dist-releases/1784772051951-3107696/src/host/git-remote.js
9074
+ // .dist-releases/1784809313131-4113078/src/host/git-remote.js
8999
9075
  var GIT_SECRET_PATH_MARKERS = [
9000
9076
  "token",
9001
9077
  "credential",
@@ -9047,16 +9123,6 @@ function sanitizeGitOrigin(value) {
9047
9123
  }
9048
9124
  return hasCredentialPath(origin) ? null : origin;
9049
9125
  }
9050
- function gitRemoteRequiresGitHubAuth(value) {
9051
- const remote = value.trim();
9052
- if (remote.startsWith("git@"))
9053
- return /^git@github\.com:/iu.test(remote);
9054
- try {
9055
- return new URL(remote).hostname.toLowerCase() === "github.com";
9056
- } catch {
9057
- return false;
9058
- }
9059
- }
9060
9126
  function isAcceptedRemote(value, allowLocalPath) {
9061
9127
  const remote = value.trim();
9062
9128
  if (!remote || remote.length > 2048 || GIT_REMOTE_UNSAFE_RE.test(remote))
@@ -9097,7 +9163,7 @@ function looksLikeCredential(segment2) {
9097
9163
  return value.length >= 32 && /^[A-Za-z0-9_-]+$/u.test(value);
9098
9164
  }
9099
9165
 
9100
- // .dist-releases/1784772051951-3107696/src/host/start-spec.js
9166
+ // .dist-releases/1784809313131-4113078/src/host/start-spec.js
9101
9167
  var TRANSPORTS = ["auto", "sdk", "pty", "tmux", "headless"];
9102
9168
  var SUPPORTED_PHASE1_ENGINES = ["claude", "codex"];
9103
9169
  var ENGINE_PATTERN = /^[a-z][a-z0-9._-]{0,63}$/u;
@@ -9347,7 +9413,7 @@ function _trimmed(value, label) {
9347
9413
  throw new Error(`${label} must not be empty`);
9348
9414
  return trimmed;
9349
9415
  }
9350
- // .dist-releases/1784772051951-3107696/src/host/workspace.js
9416
+ // .dist-releases/1784809313131-4113078/src/host/workspace.js
9351
9417
  import { spawn as spawn4 } from "node:child_process";
9352
9418
  import { existsSync as existsSync4 } from "node:fs";
9353
9419
  import { mkdir as mkdir5, readdir as readdir2, rename as rename4, stat } from "node:fs/promises";
@@ -9578,7 +9644,7 @@ function _safeSegment(value) {
9578
9644
  throw new Error("workspace path segment is empty after sanitizing");
9579
9645
  return segment2;
9580
9646
  }
9581
- // .dist-releases/1784772051951-3107696/src/host/workspace-inventory.js
9647
+ // .dist-releases/1784809313131-4113078/src/host/workspace-inventory.js
9582
9648
  import { access as access2 } from "node:fs/promises";
9583
9649
  import { constants } from "node:fs";
9584
9650
  import { execFile as execFile2 } from "node:child_process";
@@ -9670,8 +9736,8 @@ async function canAccess(path12, mode, deps) {
9670
9736
  return false;
9671
9737
  }
9672
9738
  }
9673
- // .dist-releases/1784772051951-3107696/src/host/host-config.js
9674
- import { chmod as chmod3, mkdir as mkdir6, readFile as readFile4, writeFile as writeFile6 } from "node:fs/promises";
9739
+ // .dist-releases/1784809313131-4113078/src/host/host-config.js
9740
+ import { chmod as chmod3, mkdir as mkdir6, readFile as readFile5, writeFile as writeFile6 } from "node:fs/promises";
9675
9741
  import { homedir as homedir10 } from "node:os";
9676
9742
  import path12 from "node:path";
9677
9743
  var HOST_CONFIG_KIND = "sailorbridge-host-config";
@@ -9688,7 +9754,7 @@ function normalizeWorkspacePath(entry) {
9688
9754
  async function loadHostConfig(configPath = defaultHostConfigPath()) {
9689
9755
  let text;
9690
9756
  try {
9691
- text = await readFile4(configPath, "utf8");
9757
+ text = await readFile5(configPath, "utf8");
9692
9758
  } catch (error) {
9693
9759
  if (error.code === "ENOENT")
9694
9760
  return { kind: HOST_CONFIG_KIND, workspaces: [] };
@@ -9755,7 +9821,7 @@ function _parseHostConfig(text, configPath) {
9755
9821
  });
9756
9822
  return { kind: HOST_CONFIG_KIND, workspaces };
9757
9823
  }
9758
- // .dist-releases/1784772051951-3107696/src/host/host-workspace-cli.js
9824
+ // .dist-releases/1784809313131-4113078/src/host/host-workspace-cli.js
9759
9825
  async function runHostWorkspaceCommandFromCli(argv, io, deps = {}) {
9760
9826
  const configPath = deps.configPath ?? defaultHostConfigPath();
9761
9827
  const sub = argv[0] ?? "list";
@@ -9799,7 +9865,7 @@ function _renderAddPlain(result) {
9799
9865
  return result.note ? `${status} ${result.path}
9800
9866
  ${result.note}` : `${status} ${result.path}`;
9801
9867
  }
9802
- // .dist-releases/1784772051951-3107696/src/host/agent-env.js
9868
+ // .dist-releases/1784809313131-4113078/src/host/agent-env.js
9803
9869
  var RUNTIME_NATIVE_HOME_ENV = new Set(["CLAUDE_CONFIG_DIR", "CODEX_HOME"]);
9804
9870
  function buildAgentEnv(options) {
9805
9871
  const env = {};
@@ -9828,16 +9894,16 @@ function buildAgentEnv(options) {
9828
9894
  }
9829
9895
  return env;
9830
9896
  }
9831
- // .dist-releases/1784772051951-3107696/src/host/runtime-env.js
9897
+ // .dist-releases/1784809313131-4113078/src/host/runtime-env.js
9832
9898
  import path16 from "node:path";
9833
9899
 
9834
- // .dist-releases/1784772051951-3107696/src/host/agent-defaults.js
9835
- import { chmod as chmod4, mkdir as mkdir7, readFile as readFile6, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
9900
+ // .dist-releases/1784809313131-4113078/src/host/agent-defaults.js
9901
+ import { chmod as chmod4, mkdir as mkdir7, readFile as readFile7, stat as stat2, writeFile as writeFile7 } from "node:fs/promises";
9836
9902
  import { homedir as homedir11 } from "node:os";
9837
9903
  import path14 from "node:path";
9838
9904
 
9839
- // .dist-releases/1784772051951-3107696/src/host/claude-settings.js
9840
- import { readFile as readFile5 } from "node:fs/promises";
9905
+ // .dist-releases/1784809313131-4113078/src/host/claude-settings.js
9906
+ import { readFile as readFile6 } from "node:fs/promises";
9841
9907
  import path13 from "node:path";
9842
9908
  async function readHostClaudeSettings(claudeConfigDir) {
9843
9909
  const settings = await _readSettingsObject(path13.join(claudeConfigDir, "settings.json"));
@@ -9846,7 +9912,7 @@ async function readHostClaudeSettings(claudeConfigDir) {
9846
9912
  async function _readSettingsObject(filePath) {
9847
9913
  let text;
9848
9914
  try {
9849
- text = await readFile5(filePath, "utf8");
9915
+ text = await readFile6(filePath, "utf8");
9850
9916
  } catch (error) {
9851
9917
  if (error.code === "ENOENT")
9852
9918
  return {};
@@ -9877,7 +9943,7 @@ function _nonEmptyString(value) {
9877
9943
  return typeof value === "string" && value.trim() ? value : null;
9878
9944
  }
9879
9945
 
9880
- // .dist-releases/1784772051951-3107696/src/host/agent-defaults.js
9946
+ // .dist-releases/1784809313131-4113078/src/host/agent-defaults.js
9881
9947
  var CODEX_BLOCK_BEGIN = "# sailorbridge-terse-defaults:begin";
9882
9948
  var CODEX_BLOCK_END = "# sailorbridge-terse-defaults:end";
9883
9949
  var CODEX_MODEL_BLOCK_BEGIN = "# sailorbridge-host-model-settings:begin";
@@ -10600,7 +10666,7 @@ async function _claudeTrustRoots(projectPath) {
10600
10666
  }
10601
10667
  if (!stats.isFile())
10602
10668
  return [projectPath];
10603
- const gitdir = /^gitdir:\s*(.+)\s*$/m.exec(await readFile6(pointer, "utf8"))?.[1];
10669
+ const gitdir = /^gitdir:\s*(.+)\s*$/m.exec(await readFile7(pointer, "utf8"))?.[1];
10604
10670
  if (!gitdir) {
10605
10671
  throw new Error(`workspace ${projectPath} has an unreadable .git pointer — cannot pre-trust its main repository for claude`);
10606
10672
  }
@@ -10986,7 +11052,7 @@ async function _readTextIfExists2(filePath) {
10986
11052
  return "";
10987
11053
  throw error;
10988
11054
  }
10989
- return readFile6(filePath, "utf8");
11055
+ return readFile7(filePath, "utf8");
10990
11056
  }
10991
11057
  function _expandHome3(value) {
10992
11058
  if (value === "~")
@@ -11007,7 +11073,7 @@ function _escapeRegExp(value) {
11007
11073
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
11008
11074
  }
11009
11075
 
11010
- // .dist-releases/1784772051951-3107696/src/host/engine-auth.js
11076
+ // .dist-releases/1784809313131-4113078/src/host/engine-auth.js
11011
11077
  import { lstat as lstat4, mkdir as mkdir8, readlink, realpath, stat as stat3, symlink as symlink2, unlink as unlink2 } from "node:fs/promises";
11012
11078
  import { homedir as homedir12 } from "node:os";
11013
11079
  import path15 from "node:path";
@@ -11097,7 +11163,7 @@ async function _ensureSymlink(linkPath, targetPath, sharedTargetPath) {
11097
11163
  await symlink2(targetPath, linkPath);
11098
11164
  }
11099
11165
 
11100
- // .dist-releases/1784772051951-3107696/src/host/runtime-env.js
11166
+ // .dist-releases/1784809313131-4113078/src/host/runtime-env.js
11101
11167
  async function materializeAgentRuntimeEnv(options) {
11102
11168
  const env = buildAgentEnv({
11103
11169
  hostEnv: options.hostEnv,
@@ -11108,6 +11174,7 @@ async function materializeAgentRuntimeEnv(options) {
11108
11174
  const memoryStub = await materializeAgentMemoryStub({
11109
11175
  agentName: options.agentName,
11110
11176
  engine: options.engine,
11177
+ teamMemoryEntitled: options.teamMemoryEntitled,
11111
11178
  env: options.hostEnv,
11112
11179
  homeDir
11113
11180
  });
@@ -11136,7 +11203,7 @@ function _ensureRootSandboxEscape(env, engine, uid) {
11136
11203
  function _currentUid() {
11137
11204
  return typeof process.getuid === "function" ? process.getuid() : null;
11138
11205
  }
11139
- // .dist-releases/1784772051951-3107696/src/host/context-statusline.js
11206
+ // .dist-releases/1784809313131-4113078/src/host/context-statusline.js
11140
11207
  function renderClaudeContextStatusLine(payload) {
11141
11208
  const percent = _usedPercentage(payload);
11142
11209
  if (percent === null)
@@ -11174,179 +11241,10 @@ function _bar(percent) {
11174
11241
  const filled = Math.min(10, Math.max(0, Math.trunc(percent / 10)));
11175
11242
  return "█".repeat(filled) + "░".repeat(10 - filled);
11176
11243
  }
11177
- // .dist-releases/1784772051951-3107696/src/host/memory-sweeper.js
11178
- import { createHash as createHash5 } from "node:crypto";
11179
- import { readdir as readdir3, readFile as readFile7, stat as stat4, writeFile as writeFile8 } from "node:fs/promises";
11180
- import path17 from "node:path";
11181
- function createMemorySweepState() {
11182
- return { completedFingerprints: new Map };
11183
- }
11184
- async function sweepAgentMemory(options) {
11185
- const captainId = _captainId2(options.captainId);
11186
- const engine = _memoryEngine(options.engine);
11187
- const sandbox = agentSandboxHome(options.agentName, engine, options.env ?? process.env);
11188
- const candidates = await _memoryCandidates(sandbox, engine, options);
11189
- let ingested = 0;
11190
- let skipped = 0;
11191
- for (const candidate of candidates) {
11192
- const changed = await _sweepCandidate(candidate, { ...options, captainId, engine });
11193
- if (changed)
11194
- ingested += 1;
11195
- else
11196
- skipped += 1;
11197
- }
11198
- return { scanned: candidates.length, ingested, skipped };
11199
- }
11200
- async function _sweepCandidate(candidate, options) {
11201
- const content = await (options.readFile ?? readFile7)(candidate.filePath, "utf8");
11202
- const spill = _spillContent(content);
11203
- if (spill.malformedStub) {
11204
- options.logger?.("host_memory_spill_malformed_marker", {
11205
- agent_name: options.agentName,
11206
- engine: options.engine,
11207
- mode: options.mode ?? "runtime",
11208
- path: candidate.relativePath
11209
- });
11210
- return false;
11211
- }
11212
- if (!spill.text.trim())
11213
- return false;
11214
- const fingerprint = _fingerprint(candidate.filePath, spill.text, await (options.stat ?? stat4)(candidate.filePath));
11215
- if (options.state?.completedFingerprints.get(candidate.filePath) === fingerprint)
11216
- return false;
11217
- const response = await options.relay.ingestRagDocument(options.captainId, options.teamId, _ingestBody(candidate, options, spill.text));
11218
- await _verifyCards(options.relay, options.captainId, options.teamId, response);
11219
- const latestContent = await (options.readFile ?? readFile7)(candidate.filePath, "utf8");
11220
- if (latestContent !== content) {
11221
- options.logger?.("host_memory_spill_changed_before_slim", {
11222
- agent_name: options.agentName,
11223
- engine: options.engine,
11224
- mode: options.mode ?? "runtime",
11225
- path: candidate.relativePath,
11226
- cards: response.cards
11227
- });
11228
- return true;
11229
- }
11230
- await (options.writeFile ?? writeFile8)(candidate.filePath, RAG_MEMORY_STUB_MARKED, { mode: 384 });
11231
- options.state?.completedFingerprints.set(candidate.filePath, fingerprint);
11232
- options.logger?.("host_memory_spill_ingested", {
11233
- agent_name: options.agentName,
11234
- engine: options.engine,
11235
- mode: options.mode ?? "runtime",
11236
- path: candidate.relativePath,
11237
- cards: response.cards
11238
- });
11239
- return true;
11240
- }
11241
- async function _memoryCandidates(sandbox, engine, deps) {
11242
- const canonical = path17.join(sandbox, memoryStubFileName(engine));
11243
- const candidates = await _fileExists(canonical, deps) ? [_candidate(sandbox, canonical)] : [];
11244
- const projectRoot = path17.join(sandbox, "projects");
11245
- for (const filePath of await _walkMemoryFiles(projectRoot, deps)) {
11246
- if (filePath !== canonical)
11247
- candidates.push(_candidate(sandbox, filePath));
11248
- }
11249
- return candidates;
11250
- }
11251
- async function _walkMemoryFiles(root, deps) {
11252
- if (!await _dirExists(root, deps))
11253
- return [];
11254
- const out = [];
11255
- for (const entry of await (deps.readdir ?? readdir3)(root, { withFileTypes: true })) {
11256
- const filePath = path17.join(root, entry.name);
11257
- if (entry.isDirectory())
11258
- out.push(...await _walkMemoryFiles(filePath, deps));
11259
- if (entry.isFile() && path17.basename(filePath) === "MEMORY.md" && path17.basename(path17.dirname(filePath)) === "memory") {
11260
- out.push(filePath);
11261
- }
11262
- }
11263
- return out;
11264
- }
11265
- function _spillContent(content) {
11266
- const start = content.indexOf(RAG_MEMORY_STUB_BEGIN);
11267
- const stop = content.indexOf(RAG_MEMORY_STUB_END);
11268
- if (start < 0 && stop < 0)
11269
- return { text: content, malformedStub: false };
11270
- if (start < 0 || stop < start)
11271
- return { text: "", malformedStub: true };
11272
- return {
11273
- text: _joinSpillParts(content.slice(0, start), content.slice(stop + RAG_MEMORY_STUB_END.length)),
11274
- malformedStub: false
11275
- };
11276
- }
11277
- function _joinSpillParts(beforeStub, afterStub) {
11278
- const before = beforeStub.trim();
11279
- const after = afterStub.trim();
11280
- if (!before)
11281
- return after ? `${after}
11282
- ` : "";
11283
- if (!after)
11284
- return `${before}
11285
- `;
11286
- return `${before}
11287
- ${after}
11288
- `;
11289
- }
11290
- function _ingestBody(candidate, options, text) {
11291
- return {
11292
- name: `agent-memory/${options.agentName}/${options.engine}/${candidate.relativePath}`,
11293
- text,
11294
- type: "memory",
11295
- max_chars: 800,
11296
- citation: { agent: options.agentName, engine: options.engine, file: candidate.relativePath }
11297
- };
11298
- }
11299
- async function _verifyCards(relay, captainId, teamId, response) {
11300
- if (response.cards < 1)
11301
- throw new Error("RAG ingest returned no cards for non-empty memory spill");
11302
- const cards = [];
11303
- for (let index = 0;index < response.cards; index += 1) {
11304
- cards.push(await relay.getRagCurrentCard(captainId, teamId, `${response.doc_id}#${String(index).padStart(2, "0")}`));
11305
- }
11306
- return cards;
11307
- }
11308
- function _candidate(sandbox, filePath) {
11309
- return { filePath, relativePath: path17.relative(sandbox, filePath).split(path17.sep).join("/") };
11310
- }
11311
- function _fingerprint(filePath, content, stats) {
11312
- const digest = createHash5("sha256").update(content).digest("hex");
11313
- return `${filePath}:${stats.size}:${stats.mtimeMs}:${digest}`;
11314
- }
11315
- async function _fileExists(filePath, deps) {
11316
- try {
11317
- return (await (deps.stat ?? stat4)(filePath)).isFile();
11318
- } catch (error) {
11319
- if (_notFound(error))
11320
- return false;
11321
- throw error;
11322
- }
11323
- }
11324
- async function _dirExists(filePath, deps) {
11325
- try {
11326
- return (await (deps.stat ?? stat4)(filePath)).isDirectory();
11327
- } catch (error) {
11328
- if (_notFound(error))
11329
- return false;
11330
- throw error;
11331
- }
11332
- }
11333
- function _captainId2(value) {
11334
- if (value?.trim())
11335
- return value.trim();
11336
- throw new Error("memory sweep requires descriptor captain_id");
11337
- }
11338
- function _memoryEngine(value) {
11339
- if (value === "claude" || value === "codex")
11340
- return value;
11341
- throw new Error("memory sweep engine must be claude or codex");
11342
- }
11343
- function _notFound(error) {
11344
- return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
11345
- }
11346
- // .dist-releases/1784772051951-3107696/src/host/scratch-sweeper.js
11244
+ // .dist-releases/1784809313131-4113078/src/host/scratch-sweeper.js
11347
11245
  import { execFile as execFile3 } from "node:child_process";
11348
- import { lstat as lstat5, readdir as readdir4, realpath as realpath2, unlink as unlink3 } from "node:fs/promises";
11349
- import path18 from "node:path";
11246
+ import { lstat as lstat5, readdir as readdir3, realpath as realpath2, unlink as unlink3 } from "node:fs/promises";
11247
+ import path17 from "node:path";
11350
11248
  import { promisify as promisify4 } from "node:util";
11351
11249
  var execFileAsync3 = promisify4(execFile3);
11352
11250
  var SCRATCH_SUBDIR = ".agent/tmp";
@@ -11360,8 +11258,8 @@ function scratchSweepEnabled(env) {
11360
11258
  return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
11361
11259
  }
11362
11260
  async function sweepWorkspaceScratch(options) {
11363
- const root = path18.resolve(options.workspaceRoot);
11364
- const tmpDir = path18.join(root, SCRATCH_SUBDIR);
11261
+ const root = path17.resolve(options.workspaceRoot);
11262
+ const tmpDir = path17.join(root, SCRATCH_SUBDIR);
11365
11263
  const state = await _tmpDirState(root, tmpDir);
11366
11264
  if (state === "missing")
11367
11265
  return EMPTY;
@@ -11399,7 +11297,7 @@ async function _trackedScratchFiles(root, options) {
11399
11297
  const tracked = new Set;
11400
11298
  for (const rel of stdout.split("\x00"))
11401
11299
  if (rel)
11402
- tracked.add(path18.join(root, rel));
11300
+ tracked.add(path17.join(root, rel));
11403
11301
  return tracked;
11404
11302
  } catch (error) {
11405
11303
  options.logger?.("host_scratch_sweep_git_failed", { workspace: root, error: _errno(error) });
@@ -11408,8 +11306,8 @@ async function _trackedScratchFiles(root, options) {
11408
11306
  }
11409
11307
  async function _collectScratchFiles(dir, root, logger) {
11410
11308
  const out = [];
11411
- for (const entry of await readdir4(dir, { withFileTypes: true })) {
11412
- const abs = path18.join(dir, entry.name);
11309
+ for (const entry of await readdir3(dir, { withFileTypes: true })) {
11310
+ const abs = path17.join(dir, entry.name);
11413
11311
  if (!_within(root, abs)) {
11414
11312
  logger?.("host_scratch_sweep_out_of_bounds", { workspace: root, path: abs });
11415
11313
  continue;
@@ -11475,8 +11373,8 @@ async function _runGit2(root, args) {
11475
11373
  return String(stdout);
11476
11374
  }
11477
11375
  function _within(root, target) {
11478
- const rel = path18.relative(root, target);
11479
- return rel === "" || !rel.startsWith("..") && !path18.isAbsolute(rel);
11376
+ const rel = path17.relative(root, target);
11377
+ return rel === "" || !rel.startsWith("..") && !path17.isAbsolute(rel);
11480
11378
  }
11481
11379
  function _isEnoent(error) {
11482
11380
  return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
@@ -11486,16 +11384,22 @@ function _errno(error) {
11486
11384
  return String(error.code);
11487
11385
  return error instanceof Error ? error.message : String(error);
11488
11386
  }
11489
- // .dist-releases/1784772051951-3107696/src/host/launcher.js
11387
+ // .dist-releases/1784809313131-4113078/src/host/launcher.js
11490
11388
  var MAX_TMUX_SESSION_SUFFIX = 100;
11491
11389
  async function launchSupervisedAgent(input, deps = {}) {
11492
11390
  const spec = parseAgentStartSpec(input.spec);
11493
11391
  const logger = input.logger ?? (() => {});
11392
+ const relay = new RelayClient({
11393
+ relayUrl: input.descriptor.relay_url,
11394
+ bearerToken: input.descriptor.token,
11395
+ ...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}
11396
+ });
11494
11397
  const { env, credentialGuard } = await materializeAgentRuntimeEnv({
11495
11398
  agentName: input.descriptor.agent_name,
11496
11399
  engine: spec.engine,
11497
11400
  hostEnv: input.hostEnv ?? process.env,
11498
11401
  descriptor: input.descriptor,
11402
+ teamMemoryEntitled: await (deps.resolveTeamMemoryEntitlementFn ?? resolveTeamMemoryEntitlement)(relay, input.captainId, input.descriptor.session),
11499
11403
  specEnv: spec.env
11500
11404
  });
11501
11405
  const cwd = await (deps.prepareWorkspaceFn ?? prepareWorkspace)({
@@ -11508,11 +11412,6 @@ async function launchSupervisedAgent(input, deps = {}) {
11508
11412
  });
11509
11413
  await _trustPreparedWorkspace(input.descriptor.agent_name, spec.engine, env, cwd);
11510
11414
  const resolved = await _resolveTransport(spec, input.descriptor, cwd, logger, deps.ensureTmuxTransportFn, deps.tmuxSessionExistsFn, input.recoveryTmuxSession);
11511
- const relay = new RelayClient({
11512
- relayUrl: input.descriptor.relay_url,
11513
- bearerToken: input.descriptor.token,
11514
- ...deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}
11515
- });
11516
11415
  const runtime = (deps.createRuntime ?? ((options) => new AgentSupervisorRuntime(options)))({
11517
11416
  agentName: input.descriptor.agent_name,
11518
11417
  displayName: input.descriptor.agent_name,
@@ -11636,90 +11535,10 @@ async function _tmuxSessionExists(session) {
11636
11535
  throw error;
11637
11536
  }
11638
11537
  }
11639
- // .dist-releases/1784772051951-3107696/src/host/repo-verification.js
11640
- import { mkdtempSync, rmSync } from "node:fs";
11641
- import { tmpdir as tmpdir2 } from "node:os";
11642
- import path19 from "node:path";
11643
- import { spawn as spawn5 } from "node:child_process";
11644
- var COMMAND_TIMEOUT_MS2 = 30000;
11645
- async function verifyTeamRepository(gitRepoUrl, hostId, deps = {}) {
11646
- const command = deps.runCommand ?? runCommand;
11647
- const commandOutput = deps.runCommandOutput ?? runCommandOutput;
11648
- const trimmed = gitRepoUrl.trim();
11649
- if (!isAcceptedTeamGitRemote(trimmed))
11650
- throw new Error("git repository URL is not accepted by SailorBridge hardening rules");
11651
- if (gitRemoteRequiresGitHubAuth(trimmed)) {
11652
- await command(["gh", "auth", "status"], process.cwd(), "gh auth status failed; install and authenticate GitHub CLI on the Moderator host");
11653
- }
11654
- const readProbe = await commandOutput(["git", "ls-remote", "--symref", trimmed, "HEAD"], process.cwd(), "git read probe failed");
11655
- const mainRef = _defaultBranchFromSymrefProbe(readProbe);
11656
- const temp = mkdtempSync(path19.join(tmpdir2(), "sailorbridge-repo-verify-"));
11657
- try {
11658
- await command(["git", "init"], temp, "git init failed for write probe");
11659
- await command(["git", "config", "user.email", "sailorbridge-verify@example.invalid"], temp, "git config failed for write probe");
11660
- await command(["git", "config", "user.name", "SailorBridge Verify"], temp, "git config failed for write probe");
11661
- await command(["git", "commit", "--allow-empty", "-m", "sailorbridge verify"], temp, "git commit failed for write probe");
11662
- await command(["git", "push", "--dry-run", trimmed, "HEAD:refs/heads/sailorbridge-verify"], temp, "git write probe failed");
11663
- } finally {
11664
- rmSync(temp, { recursive: true, force: true });
11665
- }
11666
- return {
11667
- verified: true,
11668
- reason: "git read and dry-run write probes succeeded",
11669
- verified_at: (deps.now ?? (() => new Date))().toISOString(),
11670
- verification_host_id: hostId,
11671
- ...mainRef ? { main_ref: mainRef } : {}
11672
- };
11673
- }
11674
- function _defaultBranchFromSymrefProbe(output) {
11675
- const match = /^ref:\s+refs\/heads\/(\S+)\s+HEAD$/mu.exec(output);
11676
- return match ? match[1] : null;
11677
- }
11678
- async function runCommand(argv, cwd, failurePrefix) {
11679
- await runCommandOutput(argv, cwd, failurePrefix);
11680
- }
11681
- async function runCommandOutput(argv, cwd, failurePrefix) {
11682
- const result = await execArgv2(argv, cwd);
11683
- if (result.exitCode === 0)
11684
- return result.stdout;
11685
- const detail = [result.stderr.trim(), result.stdout.trim()].filter(Boolean).join(`
11686
- `).slice(0, 500);
11687
- throw new Error(detail ? `${failurePrefix}: ${detail}` : failurePrefix);
11688
- }
11689
- function execArgv2(argv, cwd) {
11690
- return new Promise((resolve2) => {
11691
- const proc = spawn5(argv[0], argv.slice(1), { cwd, stdio: ["ignore", "pipe", "pipe"] });
11692
- const stdout = [];
11693
- const stderr = [];
11694
- let settled = false;
11695
- const finish = (exitCode, extraStderr = "") => {
11696
- if (settled)
11697
- return;
11698
- settled = true;
11699
- clearTimeout(timer);
11700
- resolve2({
11701
- exitCode,
11702
- stdout: Buffer.concat(stdout).toString("utf8"),
11703
- stderr: `${Buffer.concat(stderr).toString("utf8")}${extraStderr}`
11704
- });
11705
- };
11706
- const timer = setTimeout(() => {
11707
- proc.kill("SIGTERM");
11708
- finish(124, `
11709
- timeout expired`);
11710
- }, COMMAND_TIMEOUT_MS2);
11711
- proc.stdout.on("data", (chunk) => stdout.push(chunk));
11712
- proc.stderr.on("data", (chunk) => stderr.push(chunk));
11713
- proc.on("error", (error) => finish(127, `
11714
- ${error.message}`));
11715
- proc.on("close", (code) => finish(code ?? 1));
11716
- });
11717
- }
11718
-
11719
- // .dist-releases/1784772051951-3107696/src/worker/capability.js
11720
- import { accessSync, constants as constants2, mkdirSync as mkdirSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
11538
+ // .dist-releases/1784809313131-4113078/src/worker/capability.js
11539
+ import { accessSync, constants as constants2, mkdirSync as mkdirSync3, mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
11721
11540
  import os from "node:os";
11722
- import path20 from "node:path";
11541
+ import path18 from "node:path";
11723
11542
  import { spawnSync } from "node:child_process";
11724
11543
  var TOOLS = ["podman", "git", "kubectl", "perf", "bpftrace"];
11725
11544
  var GPU_TAGS = new Set(["intel-b60", "nvidia-h100", "none"]);
@@ -11819,11 +11638,11 @@ function parseOsReleaseLine(line) {
11819
11638
  }
11820
11639
  function isReadonly(dir) {
11821
11640
  try {
11822
- const root = path20.resolve(dir);
11641
+ const root = path18.resolve(dir);
11823
11642
  mkdirSync3(root, { recursive: true });
11824
- const temp = mkdtempSync2(path20.join(root, ".sailorbridge-write-test-"));
11825
- writeFileSync2(path20.join(temp, "probe"), "");
11826
- rmSync2(temp, { recursive: true, force: true });
11643
+ const temp = mkdtempSync(path18.join(root, ".sailorbridge-write-test-"));
11644
+ writeFileSync2(path18.join(temp, "probe"), "");
11645
+ rmSync(temp, { recursive: true, force: true });
11827
11646
  return false;
11828
11647
  } catch {
11829
11648
  return true;
@@ -11847,10 +11666,10 @@ function commandExists(command) {
11847
11666
  return commandPath(command) !== null;
11848
11667
  }
11849
11668
  function commandPath(command) {
11850
- if (command.includes(path20.sep))
11669
+ if (command.includes(path18.sep))
11851
11670
  return command;
11852
- for (const entry of (process.env.PATH ?? "").split(path20.delimiter)) {
11853
- const candidate = path20.join(entry, command);
11671
+ for (const entry of (process.env.PATH ?? "").split(path18.delimiter)) {
11672
+ const candidate = path18.join(entry, command);
11854
11673
  try {
11855
11674
  accessSync(candidate, constants2.X_OK);
11856
11675
  return candidate;
@@ -11859,7 +11678,7 @@ function commandPath(command) {
11859
11678
  return null;
11860
11679
  }
11861
11680
 
11862
- // .dist-releases/1784772051951-3107696/src/host/worker-start-spec.js
11681
+ // .dist-releases/1784809313131-4113078/src/host/worker-start-spec.js
11863
11682
  var MAX_TAGS = 32;
11864
11683
  var TAG_PATTERN = /^[a-z0-9][a-z0-9=._:/-]{0,63}$/iu;
11865
11684
  var RESERVED_TAG_KEYS = new Set(["os", "kernel", "arch", "gpu", "mode", "role", "tool"]);
@@ -11919,16 +11738,16 @@ function _trimmed2(value, label) {
11919
11738
  return trimmed;
11920
11739
  }
11921
11740
 
11922
- // .dist-releases/1784772051951-3107696/src/host/worker-launcher.js
11741
+ // .dist-releases/1784809313131-4113078/src/host/worker-launcher.js
11923
11742
  import { statSync as statSync3 } from "node:fs";
11924
11743
  import os4 from "node:os";
11925
- import path23 from "node:path";
11926
- // .dist-releases/1784772051951-3107696/src/worker/client.js
11744
+ import path21 from "node:path";
11745
+ // .dist-releases/1784809313131-4113078/src/worker/client.js
11927
11746
  import { readFileSync as readFileSync5 } from "node:fs";
11928
11747
  import os3 from "node:os";
11929
- import path22 from "node:path";
11748
+ import path20 from "node:path";
11930
11749
 
11931
- // .dist-releases/1784772051951-3107696/src/worker/errors.js
11750
+ // .dist-releases/1784809313131-4113078/src/worker/errors.js
11932
11751
  class LeaseFencingRejected extends Error {
11933
11752
  status;
11934
11753
  constructor(status, message) {
@@ -11942,10 +11761,10 @@ class WorkerHttpError extends Error {
11942
11761
  method;
11943
11762
  path;
11944
11763
  status;
11945
- constructor(method, path21, status, message) {
11764
+ constructor(method, path19, status, message) {
11946
11765
  super(message || `HTTP ${status}`);
11947
11766
  this.method = method;
11948
- this.path = path21;
11767
+ this.path = path19;
11949
11768
  this.status = status;
11950
11769
  this.name = "WorkerHttpError";
11951
11770
  }
@@ -11954,10 +11773,10 @@ class WorkerHttpError extends Error {
11954
11773
  class WorkerNetworkError extends Error {
11955
11774
  method;
11956
11775
  path;
11957
- constructor(method, path21, message) {
11776
+ constructor(method, path19, message) {
11958
11777
  super(message);
11959
11778
  this.method = method;
11960
- this.path = path21;
11779
+ this.path = path19;
11961
11780
  this.name = "WorkerNetworkError";
11962
11781
  }
11963
11782
  }
@@ -11965,14 +11784,14 @@ var LEASE_FENCING_BAD_REQUEST_MESSAGES = [
11965
11784
  "lease_token is required",
11966
11785
  "lease_token must be a non-empty string"
11967
11786
  ];
11968
- function raiseForLeaseFencingOrStatus(method, path21, status, body) {
11787
+ function raiseForLeaseFencingOrStatus(method, path19, status, body) {
11969
11788
  if (status === 409)
11970
11789
  throw new LeaseFencingRejected(status, body);
11971
11790
  if (status === 400 && LEASE_FENCING_BAD_REQUEST_MESSAGES.some((message) => body.includes(message))) {
11972
11791
  throw new LeaseFencingRejected(status, body);
11973
11792
  }
11974
11793
  if (status >= 300)
11975
- throw new WorkerHttpError(method, path21, status, body);
11794
+ throw new WorkerHttpError(method, path19, status, body);
11976
11795
  }
11977
11796
  function isNetworkError(error) {
11978
11797
  if (error instanceof WorkerNetworkError)
@@ -11984,23 +11803,23 @@ function isNetworkError(error) {
11984
11803
  const code = error.code;
11985
11804
  return code === "ECONNRESET" || code === "ECONNREFUSED" || code === "ETIMEDOUT" || code === "EPIPE" || error.name === "AbortError";
11986
11805
  }
11987
- function countsTowardWorkerSessionRebuild(path21) {
11988
- if (path21 === "/api/v1/workers/register")
11806
+ function countsTowardWorkerSessionRebuild(path19) {
11807
+ if (path19 === "/api/v1/workers/register")
11989
11808
  return false;
11990
- if (/^\/api\/v1\/workers\/[^/]+\/heartbeat$/u.test(path21))
11809
+ if (/^\/api\/v1\/workers\/[^/]+\/heartbeat$/u.test(path19))
11991
11810
  return false;
11992
11811
  return true;
11993
11812
  }
11994
11813
 
11995
- // .dist-releases/1784772051951-3107696/src/worker/executor.js
11996
- import { spawn as spawn6 } from "node:child_process";
11997
- import { mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync3, readFileSync as readFileSync4, realpathSync, rmSync as rmSync3, statfsSync, writeFileSync as writeFileSync3 } from "node:fs";
11998
- import { tmpdir as tmpdir3, loadavg } from "node:os";
11814
+ // .dist-releases/1784809313131-4113078/src/worker/executor.js
11815
+ import { spawn as spawn5 } from "node:child_process";
11816
+ import { mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, realpathSync, rmSync as rmSync2, statfsSync, writeFileSync as writeFileSync3 } from "node:fs";
11817
+ import { tmpdir as tmpdir2, loadavg } from "node:os";
11999
11818
  import os2 from "node:os";
12000
- import path21 from "node:path";
11819
+ import path19 from "node:path";
12001
11820
  import { TextDecoder } from "node:util";
12002
11821
 
12003
- // .dist-releases/1784772051951-3107696/src/worker/async-queue.js
11822
+ // .dist-releases/1784809313131-4113078/src/worker/async-queue.js
12004
11823
  class AsyncByteQueue {
12005
11824
  maxSize;
12006
11825
  values = [];
@@ -12060,7 +11879,7 @@ class AsyncByteQueue {
12060
11879
  }
12061
11880
  }
12062
11881
 
12063
- // .dist-releases/1784772051951-3107696/src/worker/http.js
11882
+ // .dist-releases/1784809313131-4113078/src/worker/http.js
12064
11883
  import { request as httpRequest } from "node:http";
12065
11884
  import { request as httpsRequest } from "node:https";
12066
11885
  import { URLSearchParams as URLSearchParams2 } from "node:url";
@@ -12090,27 +11909,27 @@ class WorkerHttpClient {
12090
11909
  throw new Error("token is required");
12091
11910
  this.relayUrl = relayUrl.replace(/\/+$/u, "");
12092
11911
  }
12093
- async getJson(path21, query, timeouts, options = {}) {
11912
+ async getJson(path19, query, timeouts, options = {}) {
12094
11913
  const suffix = new URLSearchParams2(query).toString();
12095
- return this.requestJson("GET", suffix ? `${path21}?${suffix}` : path21, undefined, timeouts, options);
11914
+ return this.requestJson("GET", suffix ? `${path19}?${suffix}` : path19, undefined, timeouts, options);
12096
11915
  }
12097
- async postJson(path21, value, timeouts) {
12098
- return this.requestJson("POST", path21, { type: "json", value }, timeouts, {});
11916
+ async postJson(path19, value, timeouts) {
11917
+ return this.requestJson("POST", path19, { type: "json", value }, timeouts, {});
12099
11918
  }
12100
- async postBytes(path21, body, headers, timeouts) {
12101
- const response = await this.request("POST", path21, { type: "bytes", value: body }, timeouts, headers);
12102
- raiseForLeaseFencingOrStatus("POST", path21, response.status, response.text);
11919
+ async postBytes(path19, body, headers, timeouts) {
11920
+ const response = await this.request("POST", path19, { type: "bytes", value: body }, timeouts, headers);
11921
+ raiseForLeaseFencingOrStatus("POST", path19, response.status, response.text);
12103
11922
  }
12104
- async requestJson(method, path21, body, timeouts, options) {
12105
- const response = await this.request(method, path21, body, timeouts, {});
12106
- const errorPath = pathOnly(path21);
11923
+ async requestJson(method, path19, body, timeouts, options) {
11924
+ const response = await this.request(method, path19, body, timeouts, {});
11925
+ const errorPath = pathOnly(path19);
12107
11926
  if (options.leaseFencing === false && response.status >= 300)
12108
11927
  throw new WorkerHttpError(method, errorPath, response.status, response.text);
12109
11928
  raiseForLeaseFencingOrStatus(method, errorPath, response.status, response.text);
12110
11929
  return parseJson(method, errorPath, response.text);
12111
11930
  }
12112
- async request(method, path21, body, timeouts, extraHeaders) {
12113
- const url = new URL(`${this.relayUrl}${path21}`);
11931
+ async request(method, path19, body, timeouts, extraHeaders) {
11932
+ const url = new URL(`${this.relayUrl}${path19}`);
12114
11933
  const headers = this.headers(body, extraHeaders);
12115
11934
  return sendRequest(method, url, body, headers, timeouts, this.signal);
12116
11935
  }
@@ -12237,7 +12056,7 @@ function waitForRequestDrain(req) {
12237
12056
  req.once("close", onClose);
12238
12057
  });
12239
12058
  }
12240
- function parseJson(method, path21, text) {
12059
+ function parseJson(method, path19, text) {
12241
12060
  try {
12242
12061
  const parsed = JSON.parse(text);
12243
12062
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -12246,15 +12065,15 @@ function parseJson(method, path21, text) {
12246
12065
  return parsed;
12247
12066
  } catch (error) {
12248
12067
  if (error instanceof SyntaxError)
12249
- throw new WorkerNetworkError(method, path21, "response JSON is invalid");
12068
+ throw new WorkerNetworkError(method, path19, "response JSON is invalid");
12250
12069
  throw error;
12251
12070
  }
12252
12071
  }
12253
- function pathOnly(path21) {
12254
- return path21.split("?", 1)[0] || path21;
12072
+ function pathOnly(path19) {
12073
+ return path19.split("?", 1)[0] || path19;
12255
12074
  }
12256
12075
 
12257
- // .dist-releases/1784772051951-3107696/src/worker/stream-upload.js
12076
+ // .dist-releases/1784809313131-4113078/src/worker/stream-upload.js
12258
12077
  async function uploadStream(session, jobId, stream, leaseToken, chunks, workerId) {
12259
12078
  if (!leaseToken.trim())
12260
12079
  throw new Error("lease_token is required");
@@ -12264,7 +12083,7 @@ async function uploadStream(session, jobId, stream, leaseToken, chunks, workerId
12264
12083
  await session.http.postBytes(`/api/v1/jobs/${encodeURIComponent(jobId)}/stream-upload?${query.toString()}`, chunks, { "X-Lease-Token": leaseToken }, UPLOAD_TIMEOUTS);
12265
12084
  }
12266
12085
 
12267
- // .dist-releases/1784772051951-3107696/src/worker/executor.js
12086
+ // .dist-releases/1784809313131-4113078/src/worker/executor.js
12268
12087
  class StreamingProcessFailure extends Error {
12269
12088
  exitCode;
12270
12089
  stdout;
@@ -12336,8 +12155,8 @@ function sandboxPath(workdir, requested) {
12336
12155
  if (requested.startsWith("/") || parts.length === 0 || parts.includes("..")) {
12337
12156
  throw new Error("path must be a relative path inside the worker sandbox");
12338
12157
  }
12339
- const root = realpathSync(path21.resolve(workdir));
12340
- const target = path21.resolve(root, ...parts);
12158
+ const root = realpathSync(path19.resolve(workdir));
12159
+ const target = path19.resolve(root, ...parts);
12341
12160
  if (!isPathInside(root, target)) {
12342
12161
  throw new Error("path escapes worker sandbox");
12343
12162
  }
@@ -12477,7 +12296,7 @@ async function collectAndUpload(session, jobId, stream, pipe, leaseToken, worker
12477
12296
  return collected.join("");
12478
12297
  }
12479
12298
  function spawnProcess(argv, cwd) {
12480
- return spawn6(argv[0], argv.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
12299
+ return spawn5(argv[0], argv.slice(1), { cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
12481
12300
  }
12482
12301
  async function terminateProcess(proc) {
12483
12302
  if (proc.pid === undefined)
@@ -12513,9 +12332,9 @@ function writeFileJob(workdir, spec, startedAt, started) {
12513
12332
  if (typeof spec.content !== "string")
12514
12333
  throw new Error("write_file spec.content must be a string");
12515
12334
  const target = sandboxPath(workdir, String(spec.path ?? ""));
12516
- mkdirSync4(path21.dirname(target), { recursive: true });
12335
+ mkdirSync4(path19.dirname(target), { recursive: true });
12517
12336
  writeFileSync3(target, spec.content, "utf8");
12518
- return output(0, path21.relative(realpathSync(path21.resolve(workdir)), target), "", startedAt, started);
12337
+ return output(0, path19.relative(realpathSync(path19.resolve(workdir)), target), "", startedAt, started);
12519
12338
  }
12520
12339
  function readUtf8File(target) {
12521
12340
  return decodeUtf8(readFileSync4(target));
@@ -12523,13 +12342,13 @@ function readUtf8File(target) {
12523
12342
  async function applyDiff(workdir, spec, signal) {
12524
12343
  if (typeof spec.diff_unified_text !== "string")
12525
12344
  throw new Error("apply_diff spec.diff_unified_text must be a string");
12526
- const dir = mkdtempSync3(path21.join(tmpdir3(), "sailorbridge-patch-"));
12527
- const patch = path21.join(dir, "change.patch");
12345
+ const dir = mkdtempSync2(path19.join(tmpdir2(), "sailorbridge-patch-"));
12346
+ const patch = path19.join(dir, "change.patch");
12528
12347
  writeFileSync3(patch, spec.diff_unified_text, "utf8");
12529
12348
  try {
12530
12349
  return await runArgv(["patch", "-p1", "-i", patch], workdir, coerceJobTimeoutSeconds(spec) * 1000, signal);
12531
12350
  } finally {
12532
- rmSync3(dir, { recursive: true, force: true });
12351
+ rmSync2(dir, { recursive: true, force: true });
12533
12352
  }
12534
12353
  }
12535
12354
  async function executeCompose(spec, workdir, startedAt, started, signal) {
@@ -12764,24 +12583,24 @@ function resolveExistingTarget(target) {
12764
12583
  let current = target;
12765
12584
  while (true) {
12766
12585
  try {
12767
- return path21.resolve(realpathSync(current), ...missingParts.reverse());
12586
+ return path19.resolve(realpathSync(current), ...missingParts.reverse());
12768
12587
  } catch (error) {
12769
12588
  if (error.code !== "ENOENT")
12770
12589
  throw error;
12771
- const parent = path21.dirname(current);
12590
+ const parent = path19.dirname(current);
12772
12591
  if (parent === current)
12773
12592
  throw error;
12774
- missingParts.push(path21.basename(current));
12593
+ missingParts.push(path19.basename(current));
12775
12594
  current = parent;
12776
12595
  }
12777
12596
  }
12778
12597
  }
12779
12598
  function isPathInside(root, target) {
12780
- const relative = path21.relative(root, target);
12781
- return relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative);
12599
+ const relative = path19.relative(root, target);
12600
+ return relative === "" || !relative.startsWith("..") && !path19.isAbsolute(relative);
12782
12601
  }
12783
12602
  function prepareWorkdir(workdir) {
12784
- const resolved = path21.resolve(workdir);
12603
+ const resolved = path19.resolve(workdir);
12785
12604
  mkdirSync4(resolved, { recursive: true });
12786
12605
  return resolved;
12787
12606
  }
@@ -12796,7 +12615,7 @@ function errorMessage6(error) {
12796
12615
  return error instanceof Error ? error.message : String(error);
12797
12616
  }
12798
12617
 
12799
- // .dist-releases/1784772051951-3107696/src/worker/client.js
12618
+ // .dist-releases/1784809313131-4113078/src/worker/client.js
12800
12619
  var TOKEN_FILES = [
12801
12620
  "~/.config/sailorbridge/token",
12802
12621
  "/etc/sailorbridge/token"
@@ -13135,7 +12954,7 @@ ${JSON.stringify(result)}\r
13135
12954
  `);
13136
12955
  for (const file of attachments) {
13137
12956
  yield Buffer.from(`--${multipartBoundary}\r
13138
- Content-Disposition: form-data; name="files"; filename="${path22.basename(file)}"\r
12957
+ Content-Disposition: form-data; name="files"; filename="${path20.basename(file)}"\r
13139
12958
  \r
13140
12959
  `);
13141
12960
  yield readFileSync5(file);
@@ -13169,7 +12988,7 @@ function parseFlags2(argv) {
13169
12988
  return values;
13170
12989
  }
13171
12990
  function expandHome2(value) {
13172
- return value === "~" || value.startsWith("~/") ? path22.join(os3.homedir(), value.slice(2)) : value;
12991
+ return value === "~" || value.startsWith("~/") ? path20.join(os3.homedir(), value.slice(2)) : value;
13173
12992
  }
13174
12993
  function _sleep(ms, signal) {
13175
12994
  if (signal?.aborted)
@@ -13193,7 +13012,7 @@ function errorName2(error) {
13193
13012
  function errorMessage7(error) {
13194
13013
  return error instanceof Error ? error.message : String(error);
13195
13014
  }
13196
- // .dist-releases/1784772051951-3107696/src/host/worker-launcher.js
13015
+ // .dist-releases/1784809313131-4113078/src/host/worker-launcher.js
13197
13016
  var DEFAULT_WORKER_READY_TIMEOUT_MS = 60000;
13198
13017
  async function launchSupervisedWorker(input, deps = {}) {
13199
13018
  const logger = input.logger ?? (() => {});
@@ -13276,21 +13095,21 @@ function _requireWorkerName(descriptor) {
13276
13095
  return worker;
13277
13096
  }
13278
13097
  function _resolveWorkdir(workdir, homeDir) {
13279
- return workdir === "~" || workdir.startsWith("~/") ? path23.join(homeDir, workdir.slice(2)) : workdir;
13098
+ return workdir === "~" || workdir.startsWith("~/") ? path21.join(homeDir, workdir.slice(2)) : workdir;
13280
13099
  }
13281
13100
  function _assertWorkdir(workdir) {
13282
- let stat5;
13101
+ let stat4;
13283
13102
  try {
13284
- stat5 = statSync3(workdir);
13103
+ stat4 = statSync3(workdir);
13285
13104
  } catch {
13286
13105
  throw new Error(`worker workdir does not exist: ${workdir}`);
13287
13106
  }
13288
- if (!stat5.isDirectory())
13107
+ if (!stat4.isDirectory())
13289
13108
  throw new Error(`worker workdir is not a directory: ${workdir}`);
13290
13109
  return workdir;
13291
13110
  }
13292
13111
 
13293
- // .dist-releases/1784772051951-3107696/src/host/daemon.js
13112
+ // .dist-releases/1784809313131-4113078/src/host/daemon.js
13294
13113
  async function runHostDaemon(options) {
13295
13114
  const logger = options.logger ?? (() => {});
13296
13115
  const sleep3 = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
@@ -13299,7 +13118,6 @@ async function runHostDaemon(options) {
13299
13118
  const workerRuntimes = new Map;
13300
13119
  const cleanupLocks = new Map;
13301
13120
  const startLocks = new Map;
13302
- const memorySweepTargets = new Map;
13303
13121
  const managedTargets = new Map;
13304
13122
  const launch = options.launch ?? launchSupervisedAgent;
13305
13123
  const launchWorker = options.launchWorker ?? launchSupervisedWorker;
@@ -13307,15 +13125,14 @@ async function runHostDaemon(options) {
13307
13125
  const reclaim = options.reclaimOrphanWorkspaces ?? reclaimOrphanWorkspaces;
13308
13126
  const identity = { captainId: options.captainId, hostId: options.hostId, displayName: options.displayName };
13309
13127
  const redactSecrets = [...options.redactSecrets ?? []];
13310
- const sweep = options.sweepAgentMemory ?? sweepAgentMemory;
13311
13128
  const materializeManaged = options.materializeManagedFiles ?? materializeManagedFiles;
13312
13129
  const now = options.now ?? (() => Date.now());
13313
- const memorySweepIntervalMs = options.memorySweepIntervalMs ?? 6 * 60 * 60 * 1000;
13314
- let lastRuntimeMemorySweepAt = now();
13130
+ const managedSyncIntervalMs = options.managedSyncIntervalMs ?? 6 * 60 * 60 * 1000;
13131
+ let lastManagedSyncAt = now();
13315
13132
  const scratchSweep = options.sweepWorkspaceScratch ?? sweepWorkspaceScratch;
13316
13133
  const scratchSweepIntervalMs = options.scratchSweepIntervalMs ?? 6 * 60 * 60 * 1000;
13317
13134
  let lastScratchSweepAt = now();
13318
- const reportRepoTips = options.reportRepoTips ?? reportRepoTipsOnce;
13135
+ const reportRepoTips = options.reportRepoTips ?? createRepoTipReporter();
13319
13136
  const repoTipReportIntervalMs = options.repoTipReportIntervalMs ?? 60 * 1000;
13320
13137
  let lastRepoTipReportAt = now() - repoTipReportIntervalMs;
13321
13138
  const reconcileIntervalMs = options.reconcileIntervalMs ?? 5 * 60 * 1000;
@@ -13360,9 +13177,7 @@ async function runHostDaemon(options) {
13360
13177
  await waitForAgentCleanup(cleanupLocks, request.agent_name);
13361
13178
  const spec = parseAgentStartSpec(request.spec);
13362
13179
  const agentRelay = agentRelayClient(descriptor, options);
13363
- const memoryTarget = memorySweepTarget(descriptor, spec.engine, options, agentRelay);
13364
13180
  const managedTarget = managedMaterializationTarget(descriptor, spec.engine, options, agentRelay);
13365
- await runMemorySweep(sweep, memoryTarget, "pre-start", logger, true);
13366
13181
  await runManagedMaterialization(materializeManaged, managedTarget, "pre-start", logger, true);
13367
13182
  await waitForAgentCleanup(cleanupLocks, request.agent_name);
13368
13183
  let runtime = null;
@@ -13379,10 +13194,8 @@ async function runHostDaemon(options) {
13379
13194
  return;
13380
13195
  }
13381
13196
  const cleanupTask = Promise.resolve().then(async () => {
13382
- await runMemorySweep(sweep, memoryTarget, "runtime", logger, false);
13383
13197
  await runManagedMaterialization(materializeManaged, managedTarget, "runtime", logger, false);
13384
13198
  runtimes.delete(request.agent_name);
13385
- memorySweepTargets.delete(request.agent_name);
13386
13199
  managedTargets.delete(request.agent_name);
13387
13200
  try {
13388
13201
  await cleanup({
@@ -13426,7 +13239,6 @@ async function runHostDaemon(options) {
13426
13239
  }, options.launchDeps);
13427
13240
  previous = runtimes.get(request.agent_name);
13428
13241
  runtimes.set(request.agent_name, runtime);
13429
- memorySweepTargets.set(request.agent_name, memoryTarget);
13430
13242
  managedTargets.set(request.agent_name, managedTarget);
13431
13243
  } finally {
13432
13244
  finishStart();
@@ -13438,14 +13250,6 @@ async function runHostDaemon(options) {
13438
13250
  await previous.stop().catch(() => {});
13439
13251
  };
13440
13252
  const starter = async (request) => {
13441
- if (request.request_kind === "repo_verification") {
13442
- const gitRepoUrl = request.spec.git_repo_url;
13443
- if (typeof gitRepoUrl !== "string" || !gitRepoUrl.trim()) {
13444
- throw new Error("repo verification request requires spec.git_repo_url");
13445
- }
13446
- const verifyRepository = options.verifyRepository ?? verifyTeamRepository;
13447
- return { ...await verifyRepository(gitRepoUrl, options.hostId) };
13448
- }
13449
13253
  if (request.request_kind === "worker_start")
13450
13254
  return _startWorker(request);
13451
13255
  await startAgent(request, await options.resolveCredential(request));
@@ -13462,7 +13266,9 @@ async function runHostDaemon(options) {
13462
13266
  const _recoverDurableRuntimes = async () => {
13463
13267
  if (!options.recoverRuntimes)
13464
13268
  return;
13465
- for (const recovery of await options.recoverRuntimes()) {
13269
+ const recoveries = await options.recoverRuntimes();
13270
+ const workers = recoveries.filter(({ request }) => request.request_kind === "worker_start").length;
13271
+ for (const recovery of recoveries) {
13466
13272
  if (options.signal?.aborted)
13467
13273
  return;
13468
13274
  try {
@@ -13475,6 +13281,7 @@ async function runHostDaemon(options) {
13475
13281
  });
13476
13282
  }
13477
13283
  }
13284
+ logger("host_runtime_recovery_completed", { agents: recoveries.length - workers, workers });
13478
13285
  };
13479
13286
  logger("host_daemon_start", { host_id: options.hostId, captain_id: options.captainId });
13480
13287
  try {
@@ -13500,9 +13307,8 @@ async function runHostDaemon(options) {
13500
13307
  logger("host_workspace_reconcile_failed", { error: errorMessage8(error) });
13501
13308
  }
13502
13309
  }
13503
- if (now() - lastRuntimeMemorySweepAt >= memorySweepIntervalMs) {
13504
- lastRuntimeMemorySweepAt = now();
13505
- await sweepRuntimeMemory(sweep, memorySweepTargets, logger);
13310
+ if (now() - lastManagedSyncAt >= managedSyncIntervalMs) {
13311
+ lastManagedSyncAt = now();
13506
13312
  await syncRuntimeManagedMaterialization(materializeManaged, managedTargets, logger);
13507
13313
  }
13508
13314
  if (now() - lastScratchSweepAt >= scratchSweepIntervalMs) {
@@ -13530,7 +13336,6 @@ async function runHostDaemon(options) {
13530
13336
  } finally {
13531
13337
  logger("host_daemon_stopping", { agents: runtimes.size, workers: workerRuntimes.size });
13532
13338
  try {
13533
- await sweepRuntimeMemory(sweep, memorySweepTargets, logger);
13534
13339
  await syncRuntimeManagedMaterialization(materializeManaged, managedTargets, logger);
13535
13340
  } finally {
13536
13341
  await Promise.allSettled([
@@ -13540,17 +13345,6 @@ async function runHostDaemon(options) {
13540
13345
  }
13541
13346
  }
13542
13347
  }
13543
- function memorySweepTarget(descriptor, engine, options, relay) {
13544
- return {
13545
- agentName: descriptor.agent_name,
13546
- engine,
13547
- captainId: descriptor.captain_id,
13548
- teamId: descriptor.session,
13549
- env: options.hostEnv ?? process.env,
13550
- relay,
13551
- state: createMemorySweepState()
13552
- };
13553
- }
13554
13348
  function managedMaterializationTarget(descriptor, engine, options, relay) {
13555
13349
  return {
13556
13350
  agentName: descriptor.agent_name,
@@ -13569,11 +13363,6 @@ function agentRelayClient(descriptor, options) {
13569
13363
  ...options.launchDeps?.fetchImpl ? { fetchImpl: options.launchDeps.fetchImpl } : {}
13570
13364
  });
13571
13365
  }
13572
- async function sweepRuntimeMemory(sweep, targets, logger) {
13573
- for (const target of targets.values()) {
13574
- await runMemorySweep(sweep, target, "runtime", logger, false);
13575
- }
13576
- }
13577
13366
  async function sweepWorkspaceScratchRoots(scratchSweep, env, logger) {
13578
13367
  if (!scratchSweepEnabled(env))
13579
13368
  return;
@@ -13590,15 +13379,6 @@ async function syncRuntimeManagedMaterialization(materialize, targets, logger) {
13590
13379
  await runManagedMaterialization(materialize, target, "runtime", logger, false);
13591
13380
  }
13592
13381
  }
13593
- async function runMemorySweep(sweep, target, mode, logger, failFast) {
13594
- try {
13595
- await sweep({ ...target, mode, logger });
13596
- } catch (error) {
13597
- logger("host_memory_sweep_failed", { agent_name: target.agentName, mode, error: errorMessage8(error) });
13598
- if (failFast)
13599
- throw error;
13600
- }
13601
- }
13602
13382
  async function runManagedMaterialization(materialize, target, mode, logger, failFast) {
13603
13383
  try {
13604
13384
  await materialize({ ...target, logger });
@@ -13678,7 +13458,7 @@ async function _drainOnce(options, identity, starter, logger, redactSecrets) {
13678
13458
  return false;
13679
13459
  }
13680
13460
  }
13681
- // .dist-releases/1784772051951-3107696/src/host/enrollment-redeem.js
13461
+ // .dist-releases/1784809313131-4113078/src/host/enrollment-redeem.js
13682
13462
  var DEFAULT_NOT_FOUND_RETRIES = 3;
13683
13463
  var NOT_FOUND_RETRY_DELAY_MS = 500;
13684
13464
  function createEnrollmentRedeemer(options) {
@@ -13815,7 +13595,7 @@ function _role2(enrollment) {
13815
13595
  }
13816
13596
  return _string4(enrollment.roles[0], "roles[0]").trim();
13817
13597
  }
13818
- // .dist-releases/1784772051951-3107696/src/host/tutorial.js
13598
+ // .dist-releases/1784809313131-4113078/src/host/tutorial.js
13819
13599
  function buildTutorialSteps(state) {
13820
13600
  const paired = state.hasCredential;
13821
13601
  return [
@@ -13886,7 +13666,7 @@ async function runTutorial(options) {
13886
13666
  }
13887
13667
  return steps;
13888
13668
  }
13889
- // .dist-releases/1784772051951-3107696/src/events.js
13669
+ // .dist-releases/1784809313131-4113078/src/events.js
13890
13670
  var EVENT_COMMANDS = new Set(["add", "list", "enable", "disable", "rm"]);
13891
13671
  var EVENT_FLAGS = new Set(["at", "days", "message", "run-date", "session", "tag", "tz"]);
13892
13672
  var PRODUCT_DAYS_MODES = new Set(["once", "daily", "weekday"]);
@@ -13976,7 +13756,7 @@ function _assertListArgs(args) {
13976
13756
  }
13977
13757
  }
13978
13758
 
13979
- // .dist-releases/1784772051951-3107696/src/text-input.js
13759
+ // .dist-releases/1784809313131-4113078/src/text-input.js
13980
13760
  import { readFile as readFile8 } from "node:fs/promises";
13981
13761
  var _readUtf8File = async (file) => await readFile8(file, "utf8");
13982
13762
  async function readTextInput(input) {
@@ -14010,17 +13790,17 @@ async function rejectUnusedTextInput(input, message) {
14010
13790
  input.unref?.();
14011
13791
  }
14012
13792
  }
14013
- async function readTextFile(path24, readUtf8File2 = _readUtf8File) {
14014
- return await readUtf8File2(path24);
13793
+ async function readTextFile(path22, readUtf8File2 = _readUtf8File) {
13794
+ return await readUtf8File2(path22);
14015
13795
  }
14016
- async function readTextFileOrStdin(path24, input, unusedInputMessage, readUtf8File2 = _readUtf8File) {
14017
- if (path24 === "-")
13796
+ async function readTextFileOrStdin(path22, input, unusedInputMessage, readUtf8File2 = _readUtf8File) {
13797
+ if (path22 === "-")
14018
13798
  return await readTextInput(input);
14019
13799
  await rejectUnusedTextInput(input, unusedInputMessage);
14020
- return await readTextFile(path24, readUtf8File2);
13800
+ return await readTextFile(path22, readUtf8File2);
14021
13801
  }
14022
13802
 
14023
- // .dist-releases/1784772051951-3107696/src/ask.js
13803
+ // .dist-releases/1784809313131-4113078/src/ask.js
14024
13804
  var ASK_FLAGS = new Set(["body-file", "option", "reason", "recommend", "session", "title"]);
14025
13805
  async function runAskFromCli(client2, argv, config, input) {
14026
13806
  const args = _parseAskArgs(argv);
@@ -14135,7 +13915,7 @@ function _singleAskValue(values, name) {
14135
13915
  return entries[0];
14136
13916
  }
14137
13917
 
14138
- // .dist-releases/1784772051951-3107696/src/task.js
13918
+ // .dist-releases/1784809313131-4113078/src/task.js
14139
13919
  import { readFile as readFile9 } from "node:fs/promises";
14140
13920
  import { basename } from "node:path";
14141
13921
  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"]);
@@ -14625,13 +14405,9 @@ function _taskListFooter(shown, returned, total, hasMore, cursor) {
14625
14405
  return `Shown ${shown} of ${total}${local}${next}`;
14626
14406
  }
14627
14407
 
14628
- // .dist-releases/1784772051951-3107696/src/team.js
14629
- import { setTimeout as sleep3 } from "node:timers/promises";
14408
+ // .dist-releases/1784809313131-4113078/src/team.js
14630
14409
  var TEAM_BOOTSTRAP_ENGINES = new Set(["claude", "codex"]);
14631
14410
  var SLOT_SPEC_RE = /^([^=\s]+)=([^:@\s]+):([^:@\s]+)$/;
14632
- var REPO_WAIT_DEFAULT_SECONDS = 60;
14633
- var REPO_WAIT_MAX_SECONDS = 300;
14634
- var REPO_POLL_INTERVAL_MS = 250;
14635
14411
  var TEAM_PLAIN_LIMIT = 20;
14636
14412
 
14637
14413
  class TeamBootstrapError extends Error {
@@ -14642,20 +14418,9 @@ class TeamBootstrapError extends Error {
14642
14418
  this.kind = kind;
14643
14419
  }
14644
14420
  }
14645
-
14646
- class TeamRepoError extends Error {
14647
- kind;
14648
- constructor(kind, message) {
14649
- super(message);
14650
- this.name = "TeamRepoError";
14651
- this.kind = kind;
14652
- }
14653
- }
14654
14421
  async function runTeamFromCli(client2, argv, config, format) {
14655
- if (argv[0] === "repo")
14656
- return await _runTeamRepoFromCli(client2, argv.slice(1), config, format);
14657
14422
  if (argv[0] !== "bootstrap")
14658
- throw new TeamBootstrapError("usage", "team command must be bootstrap or repo");
14423
+ throw new TeamBootstrapError("usage", "team command must be bootstrap");
14659
14424
  const captainId = config.captainId;
14660
14425
  if (!captainId)
14661
14426
  throw new TeamBootstrapError("usage", "team bootstrap requires SAILORBRIDGE_CAPTAIN_ID");
@@ -14668,173 +14433,6 @@ async function runTeamFromCli(client2, argv, config, format) {
14668
14433
  const finalSlots = (await client2.getTeamAgentSlots(captainId, args.session)).agent_slots;
14669
14434
  return format === "json" ? { agent_slots: finalSlots } : _auditFinalState(finalSlots);
14670
14435
  }
14671
- async function _runTeamRepoFromCli(client2, argv, config, format) {
14672
- const captainId = config.captainId;
14673
- if (!captainId)
14674
- throw new TeamRepoError("usage", "team repo requires SAILORBRIDGE_CAPTAIN_ID");
14675
- if (argv[0] === "status") {
14676
- const repository = await client2.getTeamRepository(captainId, _parseRepoStatusArgs(argv.slice(1), config));
14677
- return format === "json" ? repository : _formatRepository(repository);
14678
- }
14679
- if (argv[0] !== "set")
14680
- throw new TeamRepoError("usage", "team repo command must be set or status");
14681
- return await _setTeamRepository(client2, captainId, _parseRepoSetArgs(argv.slice(1), config), format);
14682
- }
14683
- function _parseRepoStatusArgs(tokens, config) {
14684
- if (!tokens.length)
14685
- return _requiredRepoSession(undefined, config);
14686
- if (tokens.length !== 2 || tokens[0] !== "--session")
14687
- throw new TeamRepoError("usage", "team repo status accepts only --session TEAM");
14688
- return _requiredRepoSession(tokens[1], config);
14689
- }
14690
- function _parseRepoSetArgs(tokens, config) {
14691
- const gitRepoUrl = tokens[0]?.trim();
14692
- if (!gitRepoUrl || gitRepoUrl.startsWith("--"))
14693
- throw new TeamRepoError("usage", "team repo set requires GIT_URL");
14694
- if (!isAcceptedTeamGitRemote(gitRepoUrl))
14695
- throw new TeamRepoError("usage", "GIT_URL must be an accepted git remote without embedded credentials");
14696
- const flags = _parseRepoSetFlags(tokens.slice(1));
14697
- return {
14698
- gitRepoUrl,
14699
- session: _requiredRepoSession(flags.session, config),
14700
- wait: flags.wait,
14701
- timeoutSeconds: flags.timeoutSeconds
14702
- };
14703
- }
14704
- function _parseRepoSetFlags(tokens) {
14705
- const flags = { wait: false, timeoutSet: false, timeoutSeconds: REPO_WAIT_DEFAULT_SECONDS };
14706
- for (let index = 0;index < tokens.length; index += 1) {
14707
- index += _applyRepoSetFlag(tokens, index, flags);
14708
- }
14709
- if (flags.timeoutSet && !flags.wait)
14710
- throw new TeamRepoError("usage", "--timeout-sec requires --wait");
14711
- return flags;
14712
- }
14713
- function _applyRepoSetFlag(tokens, index, flags) {
14714
- const token = tokens[index];
14715
- if (token === "--wait") {
14716
- if (flags.wait)
14717
- throw new TeamRepoError("usage", "--wait may only be provided once");
14718
- flags.wait = true;
14719
- return 0;
14720
- }
14721
- if (token === "--session") {
14722
- flags.session = _singleRepoFlagValue(tokens, index + 1, token, flags.session);
14723
- return 1;
14724
- }
14725
- if (token !== "--timeout-sec")
14726
- throw new TeamRepoError("usage", `unknown team repo set flag: ${token}`);
14727
- if (flags.timeoutSet)
14728
- throw new TeamRepoError("usage", "--timeout-sec may only be provided once");
14729
- flags.timeoutSet = true;
14730
- flags.timeoutSeconds = _repoTimeoutSeconds(_singleRepoFlagValue(tokens, index + 1, token));
14731
- return 1;
14732
- }
14733
- function _singleRepoFlagValue(tokens, index, flag, previous) {
14734
- if (previous !== undefined)
14735
- throw new TeamRepoError("usage", `${flag} may only be provided once`);
14736
- const value = tokens[index]?.trim();
14737
- if (!value || value.startsWith("--"))
14738
- throw new TeamRepoError("usage", `${flag} requires a value`);
14739
- return value;
14740
- }
14741
- function _repoTimeoutSeconds(value) {
14742
- const seconds = Number(value);
14743
- if (!Number.isInteger(seconds) || seconds < 1 || seconds > REPO_WAIT_MAX_SECONDS) {
14744
- throw new TeamRepoError("usage", `--timeout-sec must be an integer from 1 to ${REPO_WAIT_MAX_SECONDS}`);
14745
- }
14746
- return seconds;
14747
- }
14748
- function _requiredRepoSession(value, config) {
14749
- const session = (value ?? config.session)?.trim();
14750
- if (!session)
14751
- throw new TeamRepoError("usage", "team repo requires --session or SAILORBRIDGE_SESSION");
14752
- return session;
14753
- }
14754
- async function _setTeamRepository(client2, captainId, args, format) {
14755
- const hostId = _moderatorHostId((await client2.getTeamAgentSlots(captainId, args.session)).agent_slots);
14756
- const pending = await client2.setTeamRepositoryState(captainId, args.session, _repoState(args.gitRepoUrl, "pending", null));
14757
- const request = await _queueRepoVerification(client2, captainId, args, hostId);
14758
- if (!args.wait) {
14759
- if (format === "json")
14760
- return { repository: pending, verification_request: request };
14761
- return `${_formatRepository(pending)}
14762
- Verification request: ${request.id}`;
14763
- }
14764
- const terminal = await _waitForRepoVerification(client2, captainId, args, request.id);
14765
- const repository = await _persistRepoTerminal(client2, captainId, args, terminal);
14766
- return format === "json" ? { repository, verification_request: terminal } : _formatRepository(repository);
14767
- }
14768
- function _moderatorHostId(slots) {
14769
- const moderator = slots.find((slot) => slot.slot_id === "moderator" && slot.status === "materialized");
14770
- if (!moderator?.host_id) {
14771
- throw new TeamRepoError("moderator-unavailable", "team repo verification requires a materialized Moderator slot with a host");
14772
- }
14773
- return moderator.host_id;
14774
- }
14775
- async function _queueRepoVerification(client2, captainId, args, hostId) {
14776
- try {
14777
- return await client2.createRepoVerificationRequest(captainId, args.session, hostId, args.gitRepoUrl);
14778
- } catch (error) {
14779
- await client2.setTeamRepositoryState(captainId, args.session, _repoState(args.gitRepoUrl, "failed", "Repository verification could not be queued on the Moderator host"));
14780
- throw error;
14781
- }
14782
- }
14783
- async function _waitForRepoVerification(client2, captainId, args, requestId) {
14784
- const deadline = Date.now() + args.timeoutSeconds * 1000;
14785
- while (Date.now() < deadline) {
14786
- let request;
14787
- try {
14788
- request = await client2.getAgentStartRequest(captainId, args.session, requestId, Math.max(1, deadline - Date.now()));
14789
- } catch (error) {
14790
- if (Date.now() < deadline)
14791
- throw error;
14792
- break;
14793
- }
14794
- if (request.status !== "queued" && request.status !== "claimed")
14795
- return request;
14796
- await sleep3(Math.min(REPO_POLL_INTERVAL_MS, Math.max(1, deadline - Date.now())));
14797
- }
14798
- throw new TeamRepoError("verification-timeout", `repository verification timed out after ${args.timeoutSeconds} second${args.timeoutSeconds === 1 ? "" : "s"}`);
14799
- }
14800
- async function _persistRepoTerminal(client2, captainId, args, request) {
14801
- if (request.status === "started") {
14802
- try {
14803
- const reason2 = _verifiedRepoReason(request);
14804
- return await client2.setTeamRepositoryState(captainId, args.session, _repoState(args.gitRepoUrl, "verified", reason2));
14805
- } catch (error) {
14806
- const reason2 = error instanceof Error ? error.message : "Moderator host returned an invalid repository verification result";
14807
- await client2.setTeamRepositoryState(captainId, args.session, _repoState(args.gitRepoUrl, "failed", reason2));
14808
- throw error;
14809
- }
14810
- }
14811
- const reason = request.error?.trim() || `Repository verification request ended as ${request.status}`;
14812
- await client2.setTeamRepositoryState(captainId, args.session, _repoState(args.gitRepoUrl, "failed", reason));
14813
- throw new TeamRepoError("verification-failed", reason);
14814
- }
14815
- function _verifiedRepoReason(request) {
14816
- const result = request.result;
14817
- if (result?.verified !== true || typeof result.reason !== "string" || !result.reason.trim()) {
14818
- throw new TeamRepoError("verification-failed", "Moderator host returned an invalid repository verification result");
14819
- }
14820
- if (typeof result.verified_at !== "string" || !result.verified_at || typeof result.verification_host_id !== "string" || !result.verification_host_id) {
14821
- throw new TeamRepoError("verification-failed", "Moderator host returned an incomplete repository verification result");
14822
- }
14823
- if (!Number.isFinite(Date.parse(result.verified_at)) || result.verification_host_id !== request.host_id) {
14824
- throw new TeamRepoError("verification-failed", "Moderator host returned an inconsistent repository verification result");
14825
- }
14826
- return result.reason.trim();
14827
- }
14828
- function _repoState(gitRepoUrl, status, reason) {
14829
- return { git_repo_url: gitRepoUrl, git_repo_verification_status: status, git_repo_verification_reason: reason };
14830
- }
14831
- function _formatRepository(repository) {
14832
- const url = repository.git_repo_url ?? "not configured";
14833
- const reason = repository.git_repo_verification_reason ?? "-";
14834
- return `Repository: ${url}
14835
- Status: ${repository.git_repo_verification_status}
14836
- Reason: ${reason}`;
14837
- }
14838
14436
  function _parseBootstrapArgs(tokens, config) {
14839
14437
  const values = {};
14840
14438
  for (let index = 0;index < tokens.length; index += 1) {
@@ -14962,11 +14560,11 @@ function _slotTable(slots) {
14962
14560
  Shown ${shown.length} of ${slots.length}${omitted ? `; ${omitted} omitted (use --format json)` : ""}`;
14963
14561
  }
14964
14562
 
14965
- // .dist-releases/1784772051951-3107696/src/rag.js
14563
+ // .dist-releases/1784809313131-4113078/src/memory.js
14966
14564
  var VALUE_FLAGS = new Set(["file", "source"]);
14967
- var RAG_SEARCH_PLAIN_LIMIT = 20;
14968
- async function runRagFromCli(client2, argv, config, input, format) {
14969
- const args = _parseRagArgs(argv);
14565
+ var MEMORY_SEARCH_PLAIN_LIMIT = 20;
14566
+ async function runMemoryFromCli(client2, argv, config, input, format) {
14567
+ const args = _parseMemoryCliArgs(argv);
14970
14568
  const captainId = _requireConfig(config.captainId, "SAILORBRIDGE_CAPTAIN_ID");
14971
14569
  const teamId = _requireConfig(config.session, "SAILORBRIDGE_SESSION");
14972
14570
  if (args.command === "set")
@@ -14977,14 +14575,14 @@ async function runRagFromCli(client2, argv, config, input, format) {
14977
14575
  return await _currentMemory(client2, captainId, teamId, args, format);
14978
14576
  if (args.command === "pin" || args.command === "unpin")
14979
14577
  return await _pinMemory(client2, captainId, teamId, args, format);
14980
- _assertRagShape(args, "rag index", 0, []);
14578
+ _assertMemoryShape(args, "memory index", 0, []);
14981
14579
  const result = await client2.getRagMemoryIndex(captainId, teamId);
14982
14580
  return format === "json" ? result : result.text;
14983
14581
  }
14984
- function _parseRagArgs(argv) {
14582
+ function _parseMemoryCliArgs(argv) {
14985
14583
  const command = argv[0];
14986
14584
  if (command !== "set" && command !== "search" && command !== "current" && command !== "index" && command !== "pin" && command !== "unpin") {
14987
- throw new Error("rag command must be set, search, current, index, pin, or unpin");
14585
+ throw new Error("memory command must be set, search, current, index, pin, or unpin");
14988
14586
  }
14989
14587
  const positionals = [];
14990
14588
  const flags = {};
@@ -14993,14 +14591,14 @@ function _parseRagArgs(argv) {
14993
14591
  if (!token.startsWith("--"))
14994
14592
  positionals.push(token);
14995
14593
  else
14996
- _addRagFlag(flags, token, VALUE_FLAGS.has(token.slice(2)) ? argv[++index] : undefined);
14594
+ _addMemoryFlag(flags, token, VALUE_FLAGS.has(token.slice(2)) ? argv[++index] : undefined);
14997
14595
  }
14998
14596
  return { command, positionals, flags };
14999
14597
  }
15000
- function _addRagFlag(flags, token, value) {
14598
+ function _addMemoryFlag(flags, token, value) {
15001
14599
  const name = token.slice(2);
15002
14600
  if (name !== "stdin" && !VALUE_FLAGS.has(name))
15003
- throw new Error(`unknown rag flag: ${token}`);
14601
+ throw new Error(`unknown memory flag: ${token}`);
15004
14602
  if (flags[name] !== undefined)
15005
14603
  throw new Error(`${token} may only be provided once`);
15006
14604
  if (name === "stdin")
@@ -15011,7 +14609,7 @@ function _addRagFlag(flags, token, value) {
15011
14609
  flags[name] = value;
15012
14610
  }
15013
14611
  async function _setMemory(client2, captainId, teamId, args, input, format) {
15014
- _assertRagShape(args, "rag set", 1, ["stdin", "file", "source"]);
14612
+ _assertMemoryShape(args, "memory set", 1, ["stdin", "file", "source"]);
15015
14613
  const key = args.positionals[0];
15016
14614
  const source = _requiredFlag(args, "source");
15017
14615
  const value = await _payload(args, input);
@@ -15024,26 +14622,26 @@ async function _setMemory(client2, captainId, teamId, args, input, format) {
15024
14622
  return `${result.card.key} v${result.card.version ?? 1} ${result.card.status ?? "active"}${suffix}`;
15025
14623
  }
15026
14624
  async function _searchMemory(client2, captainId, teamId, args, input, format) {
15027
- _assertRagShape(args, "rag search", 1, []);
14625
+ _assertMemoryShape(args, "memory search", 1, []);
15028
14626
  if (args.positionals[0] !== undefined)
15029
- await rejectUnusedTextInput(input, "rag search received stdin that its query argument does not consume; omit the query argument to read stdin");
14627
+ await rejectUnusedTextInput(input, "memory search received stdin that its query argument does not consume; omit the query argument to read stdin");
15030
14628
  const text = args.positionals[0] ?? await readTextInput(input);
15031
14629
  if (!text.trim())
15032
- throw new Error("rag search requires a query argument or stdin");
14630
+ throw new Error("memory search requires a query argument or stdin");
15033
14631
  const result = await client2.searchRag(captainId, teamId, text);
15034
14632
  if (format === "json")
15035
14633
  return result;
15036
14634
  const { cards } = result;
15037
14635
  if (!cards.length)
15038
14636
  return "No matching memory cards.";
15039
- const shown = cards.slice(0, RAG_SEARCH_PLAIN_LIMIT);
14637
+ const shown = cards.slice(0, MEMORY_SEARCH_PLAIN_LIMIT);
15040
14638
  const lines = shown.map((card) => `${card.key} ${card.score} ${_summary(card.value)}`);
15041
14639
  const omitted = cards.length - shown.length;
15042
14640
  return [...lines, `Shown ${shown.length} of ${cards.length}${omitted ? `; ${omitted} omitted (use --format json)` : ""}`].join(`
15043
14641
  `);
15044
14642
  }
15045
14643
  async function _currentMemory(client2, captainId, teamId, args, format) {
15046
- _assertRagShape(args, "rag current", 1, []);
14644
+ _assertMemoryShape(args, "memory current", 1, []);
15047
14645
  const card = await client2.getRagCurrentCard(captainId, teamId, args.positionals[0]);
15048
14646
  if (format === "json")
15049
14647
  return card;
@@ -15053,14 +14651,14 @@ ${card.value}`;
15053
14651
  }
15054
14652
  async function _pinMemory(client2, captainId, teamId, args, format) {
15055
14653
  const pinned = args.command === "pin";
15056
- _assertRagShape(args, `rag ${args.command}`, 1, []);
14654
+ _assertMemoryShape(args, `memory ${args.command}`, 1, []);
15057
14655
  const card = await client2.setRagCardPin(captainId, teamId, args.positionals[0], pinned);
15058
14656
  if (format === "json")
15059
14657
  return card;
15060
14658
  return `${card.key} v${card.version ?? 1} ${pinned ? "pinned" : "unpinned"}`;
15061
14659
  }
15062
- function _assertRagShape(args, name, maxPositionals, allowedFlags) {
15063
- const requiresKey = name !== "rag search" && name !== "rag index";
14660
+ function _assertMemoryShape(args, name, maxPositionals, allowedFlags) {
14661
+ const requiresKey = name !== "memory search" && name !== "memory index";
15064
14662
  if (args.positionals.length > maxPositionals) {
15065
14663
  const requirement = maxPositionals ? requiresKey ? "requires one key" : "accepts at most one positional argument" : "requires no positional arguments";
15066
14664
  throw new Error(`${name} ${requirement}`);
@@ -15074,12 +14672,12 @@ async function _payload(args, input) {
15074
14672
  const fromStdin = args.flags.stdin === true;
15075
14673
  const file = args.flags.file;
15076
14674
  if (fromStdin === (typeof file === "string"))
15077
- throw new Error("rag set requires exactly one of --stdin or --file");
14675
+ throw new Error("memory set requires exactly one of --stdin or --file");
15078
14676
  if (!fromStdin)
15079
- await rejectUnusedTextInput(input, "rag set received stdin that --file does not consume; use --stdin");
14677
+ await rejectUnusedTextInput(input, "memory set received stdin that --file does not consume; use --stdin");
15080
14678
  const value = fromStdin ? await readTextInput(input) : await readTextFile(file);
15081
14679
  if (!value.trim())
15082
- throw new Error("rag set payload must not be empty");
14680
+ throw new Error("memory set payload must not be empty");
15083
14681
  return value;
15084
14682
  }
15085
14683
  function _requiredFlag(args, name) {
@@ -15090,14 +14688,14 @@ function _requiredFlag(args, name) {
15090
14688
  }
15091
14689
  function _requireConfig(value, name) {
15092
14690
  if (!value?.trim())
15093
- throw new Error(`rag requires ${name}`);
14691
+ throw new Error(`memory requires ${name}`);
15094
14692
  return value;
15095
14693
  }
15096
14694
  function _summary(value) {
15097
14695
  return value.replace(/\s+/gu, " ").trim().slice(0, 180);
15098
14696
  }
15099
14697
 
15100
- // .dist-releases/1784772051951-3107696/src/mailbox-send.js
14698
+ // .dist-releases/1784809313131-4113078/src/mailbox-send.js
15101
14699
  var SEND_FLAGS = new Set(["body-file", "commit", "session", "tag", "task-id", "task-version", "to-agents", "to-roles", "to-host"]);
15102
14700
  function parseMailboxSendArgs(argv) {
15103
14701
  const parsed = argsFromValues(parseFlagValues(argv));
@@ -15196,7 +14794,7 @@ function splitList(value) {
15196
14794
  return list?.length ? list : undefined;
15197
14795
  }
15198
14796
 
15199
- // .dist-releases/1784772051951-3107696/src/reply.js
14797
+ // .dist-releases/1784809313131-4113078/src/reply.js
15200
14798
  var REPLY_FLAGS = new Set(["agent", "body-file", "in-reply-to", "session"]);
15201
14799
  async function sendReplyFromCli(client2, argv, config, io) {
15202
14800
  const args = _parseReplyArgs(argv);
@@ -15253,7 +14851,7 @@ function _requiredReplyValue(values, name) {
15253
14851
  return value;
15254
14852
  }
15255
14853
 
15256
- // .dist-releases/1784772051951-3107696/src/create.js
14854
+ // .dist-releases/1784809313131-4113078/src/create.js
15257
14855
  var CREATE_ENGINES = new Set(["claude", "codex"]);
15258
14856
  var DEFAULT_ENGINE = "claude";
15259
14857
  var WORKSPACE_PLAIN_LIMIT = 20;
@@ -15305,9 +14903,9 @@ async function _startTeamSlots(deps, ctx, team, hostId, workspaceRoot, engine, s
15305
14903
  }
15306
14904
  return requests;
15307
14905
  }
15308
- async function _postConsoleJson(deps, ctx, path24, body) {
14906
+ async function _postConsoleJson(deps, ctx, path22, body) {
15309
14907
  const fetchImpl = deps.fetchImpl ?? fetch;
15310
- const response = await fetchImpl(`${ctx.apiUrl.replace(/\/$/, "")}${path24}`, {
14908
+ const response = await fetchImpl(`${ctx.apiUrl.replace(/\/$/, "")}${path22}`, {
15311
14909
  method: "POST",
15312
14910
  headers: { Authorization: `Bearer ${ctx.token}`, "Content-Type": "application/json" },
15313
14911
  body: JSON.stringify(body)
@@ -15545,7 +15143,7 @@ function _workerPlain(hostId, workdir, result) {
15545
15143
  `);
15546
15144
  }
15547
15145
 
15548
- // .dist-releases/1784772051951-3107696/src/cli.js
15146
+ // .dist-releases/1784809313131-4113078/src/cli.js
15549
15147
  var FORMATTED_COMMANDS = new Set([
15550
15148
  "ask",
15551
15149
  "create",
@@ -15554,7 +15152,7 @@ var FORMATTED_COMMANDS = new Set([
15554
15152
  "host",
15555
15153
  "login",
15556
15154
  "mailbox",
15557
- "rag",
15155
+ "memory",
15558
15156
  "reply",
15559
15157
  "task",
15560
15158
  "team",
@@ -15664,8 +15262,8 @@ async function main(argv) {
15664
15262
  writeOutput(process.stdout, await runTeamFromCli(client2, argv.slice(1), config, output2.format), output2.format);
15665
15263
  return;
15666
15264
  }
15667
- if (command === "rag") {
15668
- writeOutput(process.stdout, await runRagFromCli(client2, argv.slice(1), config, process.stdin, output2.format), output2.format);
15265
+ if (command === "memory") {
15266
+ writeOutput(process.stdout, await runMemoryFromCli(client2, argv.slice(1), config, process.stdin, output2.format), output2.format);
15669
15267
  return;
15670
15268
  }
15671
15269
  if (command === "enrollment") {
@@ -15690,7 +15288,7 @@ var KNOWN_COMMANDS = new Set([
15690
15288
  "host",
15691
15289
  "login",
15692
15290
  "mailbox",
15693
- "rag",
15291
+ "memory",
15694
15292
  "refresh",
15695
15293
  "reply",
15696
15294
  "supervise",
@@ -15707,7 +15305,7 @@ var SUBCOMMANDS = {
15707
15305
  event: new Set(["add", "disable", "enable", "list", "rm"]),
15708
15306
  host: new Set([...HOST_RELAY_SUBCOMMANDS, "run", "service", "start-request", "statusline", "workspace"]),
15709
15307
  mailbox: new Set(["ack", "claim", "peek", "send"]),
15710
- rag: new Set(["current", "index", "pin", "search", "set", "unpin"]),
15308
+ memory: new Set(["current", "index", "pin", "search", "set", "unpin"]),
15711
15309
  supervise: new Set,
15712
15310
  task: new Set([
15713
15311
  "activate",
@@ -15723,7 +15321,7 @@ var SUBCOMMANDS = {
15723
15321
  "ready",
15724
15322
  "unpark"
15725
15323
  ]),
15726
- team: new Set(["bootstrap", "repo"]),
15324
+ team: new Set(["bootstrap"]),
15727
15325
  worker: new Set(["serve"])
15728
15326
  };
15729
15327
  function _assertKnownCommand(command, subcommand) {
@@ -15740,7 +15338,7 @@ function _assertKnownCommand(command, subcommand) {
15740
15338
  }
15741
15339
  async function _rejectUnsupportedCliInput(command, args, input) {
15742
15340
  const subcommand = args[0];
15743
- const acceptsInput = command === "reply" || command === "host" && subcommand === "statusline" || command === "mailbox" && subcommand === "send" || command === "task" && subcommand === "create" || command === "ask" && subcommand !== "list" && subcommand !== "get" && subcommand !== "status" || command === "rag" && (subcommand === "set" || subcommand === "search");
15341
+ const acceptsInput = command === "reply" || command === "host" && subcommand === "statusline" || command === "mailbox" && subcommand === "send" || command === "task" && subcommand === "create" || command === "ask" && subcommand !== "list" && subcommand !== "get" && subcommand !== "status" || command === "memory" && (subcommand === "set" || subcommand === "search");
15744
15342
  if (!acceptsInput)
15745
15343
  await rejectUnusedTextInput(input, `${command}${subcommand ? ` ${subcommand}` : ""} does not accept stdin`);
15746
15344
  }
@@ -15986,6 +15584,7 @@ async function supervise(client2, argv, config) {
15986
15584
  agentName: parsed.agentName,
15987
15585
  engine: parsed.cli,
15988
15586
  hostEnv: process.env,
15587
+ teamMemoryEntitled: await resolveTeamMemoryEntitlement(client2, config.captainId, config.session),
15989
15588
  descriptor: {
15990
15589
  key_id: "direct-supervise",
15991
15590
  relay_url: config.relayUrl,
@@ -16211,14 +15810,12 @@ function _usageText() {
16211
15810
  sailorbridge create worker --name N --concurrency N [--host H] [--workspace PATH] [--session S]
16212
15811
  starts a worker on a paired online host. All create commands: [--api-url URL] [--credentials-path PATH] [--format plain|json]
16213
15812
  sailorbridge team bootstrap --template classic3 --slot SLOT=HOST:claude|codex [--slot ...] [--session S]
16214
- sailorbridge team repo set GIT_URL [--wait] [--timeout-sec 1..300] [--session S]
16215
- sailorbridge team repo status [--session S]
16216
- sail rag set KEY (--stdin | --file PATH) --source SOURCE
16217
- sail rag search [QUERY]
16218
- sail rag current KEY
16219
- sail rag pin KEY (moderator/captain only)
16220
- sail rag unpin KEY (moderator/captain only)
16221
- sail rag index
15813
+ sail memory set KEY (--stdin | --file PATH) --source SOURCE
15814
+ sail memory search [QUERY]
15815
+ sail memory current KEY
15816
+ sail memory pin KEY (moderator/captain only)
15817
+ sail memory unpin KEY (moderator/captain only)
15818
+ sail memory index
16222
15819
  sailorbridge enrollment --session S --agent A --roles operator [--host H] [--name N]
16223
15820
  sailorbridge host list|register|heartbeat [--host-id H] [--display-name N]
16224
15821
  sailorbridge host consume --once --dry-run-start [--host-id H] [--display-name N]
@@ -16272,5 +15869,5 @@ function _looksLikeNetworkFailure(message) {
16272
15869
  return /fetch failed|network|ECONN(?:REFUSED|RESET)|ENOTFOUND|ETIMEDOUT/iu.test(message);
16273
15870
  }
16274
15871
 
16275
- //# debugId=97C757320E29169264756E2164756E21
15872
+ //# debugId=D1FAA8446085164F64756E2164756E21
16276
15873
  //# sourceMappingURL=cli.js.map