@rosthq/cli 0.7.29 → 0.7.31

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/index.js CHANGED
@@ -472,13 +472,13 @@ function __disposeResources(env) {
472
472
  }
473
473
  return next();
474
474
  }
475
- function __rewriteRelativeImportExtension(path5, preserveJsx) {
476
- if (typeof path5 === "string" && /^\.\.?\//.test(path5)) {
477
- return path5.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
475
+ function __rewriteRelativeImportExtension(path6, preserveJsx) {
476
+ if (typeof path6 === "string" && /^\.\.?\//.test(path6)) {
477
+ return path6.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
478
478
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
479
479
  });
480
480
  }
481
- return path5;
481
+ return path6;
482
482
  }
483
483
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
484
484
  var init_tslib_es6 = __esm({
@@ -13257,7 +13257,7 @@ var require_main3 = __commonJS({
13257
13257
  });
13258
13258
 
13259
13259
  // src/index.ts
13260
- import { realpathSync as realpathSync2 } from "node:fs";
13260
+ import { realpathSync as realpathSync3 } from "node:fs";
13261
13261
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
13262
13262
 
13263
13263
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
@@ -14026,10 +14026,10 @@ function mergeDefs(...defs) {
14026
14026
  function cloneDef(schema) {
14027
14027
  return mergeDefs(schema._zod.def);
14028
14028
  }
14029
- function getElementAtPath(obj, path5) {
14030
- if (!path5)
14029
+ function getElementAtPath(obj, path6) {
14030
+ if (!path6)
14031
14031
  return obj;
14032
- return path5.reduce((acc, key) => acc?.[key], obj);
14032
+ return path6.reduce((acc, key) => acc?.[key], obj);
14033
14033
  }
14034
14034
  function promiseAllObject(promisesObj) {
14035
14035
  const keys = Object.keys(promisesObj);
@@ -14438,11 +14438,11 @@ function explicitlyAborted(x, startIndex = 0) {
14438
14438
  }
14439
14439
  return false;
14440
14440
  }
14441
- function prefixIssues(path5, issues) {
14441
+ function prefixIssues(path6, issues) {
14442
14442
  return issues.map((iss) => {
14443
14443
  var _a3;
14444
14444
  (_a3 = iss).path ?? (_a3.path = []);
14445
- iss.path.unshift(path5);
14445
+ iss.path.unshift(path6);
14446
14446
  return iss;
14447
14447
  });
14448
14448
  }
@@ -14589,16 +14589,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
14589
14589
  }
14590
14590
  function formatError(error51, mapper = (issue2) => issue2.message) {
14591
14591
  const fieldErrors = { _errors: [] };
14592
- const processError = (error52, path5 = []) => {
14592
+ const processError = (error52, path6 = []) => {
14593
14593
  for (const issue2 of error52.issues) {
14594
14594
  if (issue2.code === "invalid_union" && issue2.errors.length) {
14595
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
14595
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
14596
14596
  } else if (issue2.code === "invalid_key") {
14597
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
14597
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
14598
14598
  } else if (issue2.code === "invalid_element") {
14599
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
14599
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
14600
14600
  } else {
14601
- const fullpath = [...path5, ...issue2.path];
14601
+ const fullpath = [...path6, ...issue2.path];
14602
14602
  if (fullpath.length === 0) {
14603
14603
  fieldErrors._errors.push(mapper(issue2));
14604
14604
  } else {
@@ -14625,17 +14625,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
14625
14625
  }
14626
14626
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
14627
14627
  const result = { errors: [] };
14628
- const processError = (error52, path5 = []) => {
14628
+ const processError = (error52, path6 = []) => {
14629
14629
  var _a3, _b;
14630
14630
  for (const issue2 of error52.issues) {
14631
14631
  if (issue2.code === "invalid_union" && issue2.errors.length) {
14632
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
14632
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
14633
14633
  } else if (issue2.code === "invalid_key") {
14634
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
14634
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
14635
14635
  } else if (issue2.code === "invalid_element") {
14636
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
14636
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
14637
14637
  } else {
14638
- const fullpath = [...path5, ...issue2.path];
14638
+ const fullpath = [...path6, ...issue2.path];
14639
14639
  if (fullpath.length === 0) {
14640
14640
  result.errors.push(mapper(issue2));
14641
14641
  continue;
@@ -14667,8 +14667,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
14667
14667
  }
14668
14668
  function toDotPath(_path) {
14669
14669
  const segs = [];
14670
- const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
14671
- for (const seg of path5) {
14670
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
14671
+ for (const seg of path6) {
14672
14672
  if (typeof seg === "number")
14673
14673
  segs.push(`[${seg}]`);
14674
14674
  else if (typeof seg === "symbol")
@@ -27360,13 +27360,13 @@ function resolveRef(ref, ctx) {
27360
27360
  if (!ref.startsWith("#")) {
27361
27361
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
27362
27362
  }
27363
- const path5 = ref.slice(1).split("/").filter(Boolean);
27364
- if (path5.length === 0) {
27363
+ const path6 = ref.slice(1).split("/").filter(Boolean);
27364
+ if (path6.length === 0) {
27365
27365
  return ctx.rootSchema;
27366
27366
  }
27367
27367
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
27368
- if (path5[0] === defsKey) {
27369
- const key = path5[1];
27368
+ if (path6[0] === defsKey) {
27369
+ const key = path6[1];
27370
27370
  if (!key || !ctx.defs[key]) {
27371
27371
  throw new Error(`Reference not found: ${ref}`);
27372
27372
  }
@@ -27828,7 +27828,7 @@ var CommandClient = class {
27828
27828
  this.fetchImpl = options.fetchImpl ?? fetch;
27829
27829
  }
27830
27830
  async execute(commandId, body = {}, options = {}) {
27831
- const path5 = `/api/commands/${encodeURIComponent(commandId)}`;
27831
+ const path6 = `/api/commands/${encodeURIComponent(commandId)}`;
27832
27832
  const headers = {
27833
27833
  authorization: `Bearer ${this.token}`,
27834
27834
  "content-type": "application/json"
@@ -27836,7 +27836,7 @@ var CommandClient = class {
27836
27836
  if (options.targetSeatId !== void 0 && options.targetSeatId.length > 0) {
27837
27837
  headers["x-rost-seat"] = options.targetSeatId;
27838
27838
  }
27839
- const response = await this.fetchImpl(`${this.appUrl}${path5}`, {
27839
+ const response = await this.fetchImpl(`${this.appUrl}${path6}`, {
27840
27840
  method: "POST",
27841
27841
  headers,
27842
27842
  body: JSON.stringify(body)
@@ -27849,7 +27849,7 @@ var CommandClient = class {
27849
27849
  const snippet = redactSecrets(text.replace(/\s+/g, " ").trim()).slice(0, 200);
27850
27850
  throw new CommandClientError(
27851
27851
  response.status,
27852
- `server returned HTTP ${response.status} (non-JSON) from ${path5}` + (snippet ? ` \u2014 ${snippet}` : "") + " \u2014 the deployment may be unhealthy"
27852
+ `server returned HTTP ${response.status} (non-JSON) from ${path6}` + (snippet ? ` \u2014 ${snippet}` : "") + " \u2014 the deployment may be unhealthy"
27853
27853
  );
27854
27854
  }
27855
27855
  const parsed = commandResponseSchema.parse(raw);
@@ -33064,8 +33064,8 @@ var IcebergError = class extends Error {
33064
33064
  return this.status === 419;
33065
33065
  }
33066
33066
  };
33067
- function buildUrl(baseUrl, path5, query) {
33068
- const url2 = new URL(path5, baseUrl);
33067
+ function buildUrl(baseUrl, path6, query) {
33068
+ const url2 = new URL(path6, baseUrl);
33069
33069
  if (query) {
33070
33070
  for (const [key, value] of Object.entries(query)) {
33071
33071
  if (value !== void 0) {
@@ -33095,12 +33095,12 @@ function createFetchClient(options) {
33095
33095
  return {
33096
33096
  async request({
33097
33097
  method,
33098
- path: path5,
33098
+ path: path6,
33099
33099
  query,
33100
33100
  body,
33101
33101
  headers
33102
33102
  }) {
33103
- const url2 = buildUrl(options.baseUrl, path5, query);
33103
+ const url2 = buildUrl(options.baseUrl, path6, query);
33104
33104
  const authHeaders = await buildAuthHeaders(options.auth);
33105
33105
  const res = await fetchFn(url2, {
33106
33106
  method,
@@ -33962,7 +33962,7 @@ var StorageFileApi = class extends BaseApiClient {
33962
33962
  * @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
33963
33963
  * @param fileBody The body of the file to be stored in the bucket.
33964
33964
  */
33965
- async uploadOrUpdate(method, path5, fileBody, fileOptions) {
33965
+ async uploadOrUpdate(method, path6, fileBody, fileOptions) {
33966
33966
  var _this = this;
33967
33967
  return _this.handleOperation(async () => {
33968
33968
  let body;
@@ -33986,7 +33986,7 @@ var StorageFileApi = class extends BaseApiClient {
33986
33986
  if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
33987
33987
  }
33988
33988
  if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) for (const [key, value] of Object.entries(fileOptions.headers)) headers = setHeader(headers, key, value);
33989
- const cleanPath = _this._removeEmptyFolders(path5);
33989
+ const cleanPath = _this._removeEmptyFolders(path6);
33990
33990
  const _path = _this._getFinalPath(cleanPath);
33991
33991
  const data = await (method == "PUT" ? put : post)(_this.fetch, `${_this.url}/object/${_path}`, body, _objectSpread22({ headers }, (options === null || options === void 0 ? void 0 : options.duplex) ? { duplex: options.duplex } : {}));
33992
33992
  return {
@@ -34063,8 +34063,8 @@ var StorageFileApi = class extends BaseApiClient {
34063
34063
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34064
34064
  * - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below.
34065
34065
  */
34066
- async upload(path5, fileBody, fileOptions) {
34067
- return this.uploadOrUpdate("POST", path5, fileBody, fileOptions);
34066
+ async upload(path6, fileBody, fileOptions) {
34067
+ return this.uploadOrUpdate("POST", path6, fileBody, fileOptions);
34068
34068
  }
34069
34069
  /**
34070
34070
  * Upload a file with a token generated from `createSignedUploadUrl`.
@@ -34104,9 +34104,9 @@ var StorageFileApi = class extends BaseApiClient {
34104
34104
  * - `objects` table permissions: none
34105
34105
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34106
34106
  */
34107
- async uploadToSignedUrl(path5, token, fileBody, fileOptions) {
34107
+ async uploadToSignedUrl(path6, token, fileBody, fileOptions) {
34108
34108
  var _this3 = this;
34109
- const cleanPath = _this3._removeEmptyFolders(path5);
34109
+ const cleanPath = _this3._removeEmptyFolders(path6);
34110
34110
  const _path = _this3._getFinalPath(cleanPath);
34111
34111
  const url2 = new URL(_this3.url + `/object/upload/sign/${_path}`);
34112
34112
  url2.searchParams.set("token", token);
@@ -34175,10 +34175,10 @@ var StorageFileApi = class extends BaseApiClient {
34175
34175
  * - `objects` table permissions: `insert`
34176
34176
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34177
34177
  */
34178
- async createSignedUploadUrl(path5, options) {
34178
+ async createSignedUploadUrl(path6, options) {
34179
34179
  var _this4 = this;
34180
34180
  return _this4.handleOperation(async () => {
34181
- let _path = _this4._getFinalPath(path5);
34181
+ let _path = _this4._getFinalPath(path6);
34182
34182
  const headers = _objectSpread22({}, _this4.headers);
34183
34183
  if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
34184
34184
  const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
@@ -34187,7 +34187,7 @@ var StorageFileApi = class extends BaseApiClient {
34187
34187
  if (!token) throw new StorageError("No token returned by API");
34188
34188
  return {
34189
34189
  signedUrl: url2.toString(),
34190
- path: path5,
34190
+ path: path6,
34191
34191
  token
34192
34192
  };
34193
34193
  });
@@ -34247,8 +34247,8 @@ var StorageFileApi = class extends BaseApiClient {
34247
34247
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34248
34248
  * - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below.
34249
34249
  */
34250
- async update(path5, fileBody, fileOptions) {
34251
- return this.uploadOrUpdate("PUT", path5, fileBody, fileOptions);
34250
+ async update(path6, fileBody, fileOptions) {
34251
+ return this.uploadOrUpdate("PUT", path6, fileBody, fileOptions);
34252
34252
  }
34253
34253
  /**
34254
34254
  * Moves an existing file to a new path in the same bucket.
@@ -34399,10 +34399,10 @@ var StorageFileApi = class extends BaseApiClient {
34399
34399
  * - `objects` table permissions: `select`
34400
34400
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34401
34401
  */
34402
- async createSignedUrl(path5, expiresIn, options) {
34402
+ async createSignedUrl(path6, expiresIn, options) {
34403
34403
  var _this8 = this;
34404
34404
  return _this8.handleOperation(async () => {
34405
- let _path = _this8._getFinalPath(path5);
34405
+ let _path = _this8._getFinalPath(path6);
34406
34406
  const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
34407
34407
  let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
34408
34408
  const query = new URLSearchParams();
@@ -34538,13 +34538,13 @@ var StorageFileApi = class extends BaseApiClient {
34538
34538
  * - `objects` table permissions: `select`
34539
34539
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34540
34540
  */
34541
- download(path5, options, parameters) {
34541
+ download(path6, options, parameters) {
34542
34542
  const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0 ? "render/image/authenticated" : "object";
34543
34543
  const query = new URLSearchParams();
34544
34544
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
34545
34545
  if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
34546
34546
  const queryString = query.toString();
34547
- const _path = this._getFinalPath(path5);
34547
+ const _path = this._getFinalPath(path6);
34548
34548
  const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
34549
34549
  headers: this.headers,
34550
34550
  noResolveJson: true
@@ -34575,9 +34575,9 @@ var StorageFileApi = class extends BaseApiClient {
34575
34575
  * }
34576
34576
  * ```
34577
34577
  */
34578
- async info(path5) {
34578
+ async info(path6) {
34579
34579
  var _this10 = this;
34580
- const _path = _this10._getFinalPath(path5);
34580
+ const _path = _this10._getFinalPath(path6);
34581
34581
  return _this10.handleOperation(async () => {
34582
34582
  return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
34583
34583
  });
@@ -34598,9 +34598,9 @@ var StorageFileApi = class extends BaseApiClient {
34598
34598
  * .exists('folder/avatar1.png')
34599
34599
  * ```
34600
34600
  */
34601
- async exists(path5) {
34601
+ async exists(path6) {
34602
34602
  var _this11 = this;
34603
- const _path = _this11._getFinalPath(path5);
34603
+ const _path = _this11._getFinalPath(path6);
34604
34604
  try {
34605
34605
  await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
34606
34606
  return {
@@ -34679,8 +34679,8 @@ var StorageFileApi = class extends BaseApiClient {
34679
34679
  * - `objects` table permissions: none
34680
34680
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34681
34681
  */
34682
- getPublicUrl(path5, options) {
34683
- const _path = this._getFinalPath(path5);
34682
+ getPublicUrl(path6, options) {
34683
+ const _path = this._getFinalPath(path6);
34684
34684
  const query = new URLSearchParams();
34685
34685
  if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
34686
34686
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
@@ -34819,10 +34819,10 @@ var StorageFileApi = class extends BaseApiClient {
34819
34819
  * - `objects` table permissions: `select`
34820
34820
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
34821
34821
  */
34822
- async list(path5, options, parameters) {
34822
+ async list(path6, options, parameters) {
34823
34823
  var _this13 = this;
34824
34824
  return _this13.handleOperation(async () => {
34825
- const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path5 || "" });
34825
+ const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path6 || "" });
34826
34826
  return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
34827
34827
  });
34828
34828
  }
@@ -34887,11 +34887,11 @@ var StorageFileApi = class extends BaseApiClient {
34887
34887
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
34888
34888
  return btoa(data);
34889
34889
  }
34890
- _getFinalPath(path5) {
34891
- return `${this.bucketId}/${path5.replace(/^\/+/, "")}`;
34890
+ _getFinalPath(path6) {
34891
+ return `${this.bucketId}/${path6.replace(/^\/+/, "")}`;
34892
34892
  }
34893
- _removeEmptyFolders(path5) {
34894
- return path5.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
34893
+ _removeEmptyFolders(path6) {
34894
+ return path6.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
34895
34895
  }
34896
34896
  /** Modifies the `query`, appending values the from `transform` */
34897
34897
  applyTransformOptsToQuery(query, transform2) {
@@ -42664,7 +42664,14 @@ var softwareCapacityObservationSummarySchema = external_exports.object({
42664
42664
  account_alias: external_exports.string().nullable()
42665
42665
  });
42666
42666
  var softwareRequestCreateInputSchema = external_exports.object({
42667
- software_project_id: uuid10,
42667
+ // DER-1310: the project the request opens against. Either identifier works —
42668
+ // the raw id (still fully supported) or `project`, the project's slug or name,
42669
+ // resolved server-side to the tenant's active project. The command layer (not
42670
+ // this schema) enforces that exactly one resolves, with an actionable error
42671
+ // when neither is given or neither matches — keeping this shape a plain
42672
+ // `z.object` so JSON-schema/CLI-flag projection stays simple (no `.refine`).
42673
+ software_project_id: uuid10.optional(),
42674
+ project: external_exports.string().trim().min(1).max(200).optional(),
42668
42675
  // Untrusted display text (ADR-0018 §5) — bounded, never treated as an instruction.
42669
42676
  title: external_exports.string().trim().min(1).max(500),
42670
42677
  source_channel: softwareSourceChannelSchema.optional(),
@@ -45125,7 +45132,7 @@ External connectors are being rolled out provider by provider, conservatively (r
45125
45132
  order: 48,
45126
45133
  title: "CLI and MCP installation guide",
45127
45134
  summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
45128
- version: "2026-07-04.21",
45135
+ version: "2026-07-05.1",
45129
45136
  public: true,
45130
45137
  audiences: ["human", "cli", "mcp", "in_app_agent"],
45131
45138
  stages: ["company_setup", "staffing"],
@@ -45604,7 +45611,7 @@ The signed-in app exposes the same Skill command surface at **Skills**, linked f
45604
45611
  | \`{{cli}} deliverable list|get|create|attach\` | \`deliverable.list\`, \`deliverable.get\`, \`deliverable.create\`, \`deliverable.attach\` | List, get, create, or attach agent deliverables for a seat. Deliverables are durable work outputs visible across UI, CLI, and MCP. | Tenant (list/get), Seat (create/attach) | \`{{cli}} deliverable list --seat-id <id> --json\`; \`{{cli}} deliverable create --title "Brief" --kind brief\` |
45605
45612
  | \`{{cli}} graph show\` | \`graph.get\` | Print a table view of the Responsibility Graph with explicit \`seat_id\` and \`parent_seat_id\` columns. | Tenant | \`{{cli}} graph show\` |
45606
45613
  | \`{{cli}} seat list|get|create|rename|reparent|decommission\` | \`graph.get\`, \`seat.get\`, \`seat.create\`, \`seat.rename\`, \`seat.reparent\`, \`seat.decommission\`, \`seat.decommission_preview\` | Work with seats as first-class CLI primitives. \`seat decommission --dry-run\` previews affected occupancies, agents, Charters, tokens, credentials, work orders, and schedules before the human-gated teardown. | Tenant / Seat for targeted mutations | \`{{cli}} seat list\`; \`{{cli}} seat decommission --seat-id <id> --dry-run\` |
45607
- | \`{{cli}} forge project-create|project-list|request-create|request-list|request-show|request-pause|request-cancel|request-resume\` | \`software_factory.project.create\`, \`software_factory.project.list\`, \`software_factory.request.create\`, \`software_factory.request.list\`, \`software_factory.request.show\`, \`software_factory.request.pause\`, \`software_factory.request.cancel\`, \`software_factory.request.resume\` | Create/list Forge projects, open/read governed Forge build requests, and control request lifecycle. Project creation plus pause/cancel/resume are tenant-admin, entitlement-gated, and human-gated; reads and request creation require the Forge add-on. Pause halts new runner claims at the next task checkpoint, cancel drives terminal canceled, and resume requeues from the last completed task checkpoint. | Tenant / Tenant-admin for create and lifecycle controls | \`{{cli}} forge project-create --name "Leiluna app" --base-branch main\`; \`{{cli}} forge request-create --software-project-id <id> --title "Add invoice export"\`; \`{{cli}} forge request-pause --build-request-id <id> --reason "Operator hold"\` |
45614
+ | \`{{cli}} forge project-create|project-list|request-create|request-list|request-show|request-pause|request-cancel|request-resume\` | \`software_factory.project.create\`, \`software_factory.project.list\`, \`software_factory.request.create\`, \`software_factory.request.list\`, \`software_factory.request.show\`, \`software_factory.request.pause\`, \`software_factory.request.cancel\`, \`software_factory.request.resume\` | Create/list Forge projects, open/read governed Forge build requests, and control request lifecycle. Project creation plus pause/cancel/resume are tenant-admin, entitlement-gated, and human-gated; reads and request creation require the Forge add-on. Pause halts new runner claims at the next task checkpoint, cancel drives terminal canceled, and resume requeues from the last completed task checkpoint. | Tenant / Tenant-admin for create and lifecycle controls | \`{{cli}} forge project-create --name "Leiluna app" --base-branch main\`; \`{{cli}} forge request-create --project <slug-or-name> --title "Add invoice export"\` (accepts \`--software-project-id <id>\` instead of \`--project\` too); \`{{cli}} forge request-pause --build-request-id <id> --reason "Operator hold"\` |
45608
45615
 
45609
45616
  Skills wrapper help:
45610
45617
 
@@ -45845,7 +45852,7 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
45845
45852
  | \`rost_revoke_skill_from_seat\` | \`skill.revoke_from_seat\` | Human-gated revocation that stops future Skill use without deleting historical activations. | Tenant-admin | Call with \`{"assignment_id":"<assignment-id>"}\`; non-interactive callers receive a confirmation handoff. |
45846
45853
  | \`rost_list_model_catalog\` | \`model.catalog\` | List guided model tiers \u2014 recommendations, token prices, cost bands, best-fit work, and model ids for \`--model\`. | Tenant | Call with \`{}\`. |
45847
45854
  | \`rost_create_a_forge_project\` | \`software_factory.project.create\` | Create an active Forge software project before binding repositories or opening build requests. Tenant-admin, human-gated, and entitlement-gated. | Tenant-admin | Call with \`{"name":"Leiluna app","slug":"leiluna-app","base_branch":"main"}\`; non-interactive callers receive a confirmation handoff. |
45848
- | \`rost_create_a_forge_build_request\` | \`software_factory.request.create\` | Open a governed Forge build request against a connected software project; records the request plus its initial intake phase run. Requires the Forge add-on; the title is untrusted display text. | Tenant | Call with \`{"software_project_id":"<project-id>","title":"Add invoice export"}\`. |
45855
+ | \`rost_create_a_forge_build_request\` | \`software_factory.request.create\` | Open a governed Forge build request against a connected software project; records the request plus its initial intake phase run. Requires the Forge add-on; the title is untrusted display text. | Tenant | Call with \`{"project":"<slug-or-name>","title":"Add invoice export"}\` (or \`{"software_project_id":"<project-id>", ...}\`). |
45849
45856
  | \`rost_pause_a_forge_build_request\` | \`software_factory.request.pause\` | Pause an in-flight Forge build request. New runner claims stop immediately; running work halts at the next task checkpoint. Human-gated. | Tenant-admin | Call with \`{"build_request_id":"<request-id>","reason":"Operator hold"}\`; non-interactive callers receive a confirmation handoff. |
45850
45857
  | \`rost_cancel_a_forge_build_request\` | \`software_factory.request.cancel\` | Cancel a Forge build request and expire active runner work orders. This is terminal; use pause for reversible holds. Human-gated. | Tenant-admin | Call with \`{"build_request_id":"<request-id>","reason":"Out of scope"}\`; non-interactive callers receive a confirmation handoff. |
45851
45858
  | \`rost_resume_a_forge_build_request\` | \`software_factory.request.resume\` | Resume a paused or human-blocked Forge build request from the last completed task checkpoint and requeue the current phase. Human-gated. | Tenant-admin | Call with \`{"build_request_id":"<request-id>","reason":"Budget raised"}\`; non-interactive callers receive a confirmation handoff. |
@@ -48819,21 +48826,32 @@ function helpText() {
48819
48826
  ].join("\n");
48820
48827
  }
48821
48828
 
48822
- // src/update-check.ts
48829
+ // src/cli-version.ts
48823
48830
  import { readFile as readFile2 } from "node:fs/promises";
48824
48831
  import { dirname as dirname2, resolve } from "node:path";
48825
48832
  import { fileURLToPath as fileURLToPath2 } from "node:url";
48826
- var latestPackageSchema = external_exports.object({
48833
+ var packageMetadataSchema = external_exports.object({
48827
48834
  version: external_exports.string()
48828
48835
  });
48829
- var packageMetadataSchema = external_exports.object({
48836
+ async function readCliVersion() {
48837
+ const packageJsonPath = resolve(dirname2(fileURLToPath2(import.meta.url)), "../package.json");
48838
+ try {
48839
+ const metadata = packageMetadataSchema.parse(JSON.parse(await readFile2(packageJsonPath, "utf8")));
48840
+ return metadata.version;
48841
+ } catch {
48842
+ return null;
48843
+ }
48844
+ }
48845
+
48846
+ // src/update-check.ts
48847
+ var latestPackageSchema = external_exports.object({
48830
48848
  version: external_exports.string()
48831
48849
  });
48832
48850
  async function maybePrintUpgradeNudge(io) {
48833
48851
  if (process.env.CI || process.env.VITEST || process.env.CLI_SKIP_UPDATE_CHECK === "1") {
48834
48852
  return;
48835
48853
  }
48836
- const currentVersion = await readCurrentVersion();
48854
+ const currentVersion = await readCliVersion();
48837
48855
  if (!currentVersion || currentVersion === "0.0.0") {
48838
48856
  return;
48839
48857
  }
@@ -48846,15 +48864,6 @@ async function maybePrintUpgradeNudge(io) {
48846
48864
  `
48847
48865
  );
48848
48866
  }
48849
- async function readCurrentVersion() {
48850
- const packageJsonPath = resolve(dirname2(fileURLToPath2(import.meta.url)), "../package.json");
48851
- try {
48852
- const metadata = packageMetadataSchema.parse(JSON.parse(await readFile2(packageJsonPath, "utf8")));
48853
- return metadata.version;
48854
- } catch {
48855
- return null;
48856
- }
48857
- }
48858
48867
  async function fetchLatestVersion(packageName) {
48859
48868
  const controller = new AbortController();
48860
48869
  const timeout = setTimeout(() => controller.abort(), 750);
@@ -49089,7 +49098,7 @@ var COMMAND_MANIFEST = [
49089
49098
  { "id": "software_factory.project.list", "namespace": "software_factory", "action": "project.list", "title": "List Forge projects", "description": "List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. Read-only and entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [], "hasComplexInput": false, "help": "List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. Read-only; requires the Forge add-on." },
49090
49099
  { "id": "software_factory.request.answer_clarification", "namespace": "software_factory", "action": "request.answer_clarification", "title": "Answer Forge plan clarifications", "description": "Write structured human answers to a draft plan's clarifying questions and optionally mark it ready for plan review. Answers append to the versioned planning artifact; this never widens authority or automation mode.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "mark_ready_for_plan_review", "flag": "mark-ready-for-plan-review", "type": "boolean", "required": false }], "hasComplexInput": true, "help": "Write structured human answers to a draft plan's clarifying questions and optionally mark it ready for plan review. Never widens authority or automation mode." },
49091
49100
  { "id": "software_factory.request.cancel", "namespace": "software_factory", "action": "request.cancel", "title": "Cancel a Forge build request", "description": "Cancel a Forge build request and expire active runner work orders. This is terminal; use pause for reversible holds. Human-gated and entitlement-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "reason", "flag": "reason", "type": "string", "required": false }], "hasComplexInput": false, "help": "Cancel a Forge build request, expire unstarted runner work, and terminalize active runner work. Terminal, tenant-admin, and human-gated." },
49092
- { "id": "software_factory.request.create", "namespace": "software_factory", "action": "request.create", "title": "Create a Forge build request", "description": "Open a governed Forge build request against a connected software project. Records the request plus its initial intake phase run. Entitlement-gated (Forge add-on); the title is untrusted display text, never an instruction.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "title", "flag": "title", "type": "string", "required": true }, { "name": "source_channel", "flag": "source-channel", "type": "enum", "required": false, "enumValues": ["ui", "cli", "github_issue", "linear", "api"] }, { "name": "source_ref", "flag": "source-ref", "type": "string", "required": false }], "hasComplexInput": true, "help": "Open a governed Forge build request against a connected software project; the title is untrusted display text. Requires the Forge add-on." },
49101
+ { "id": "software_factory.request.create", "namespace": "software_factory", "action": "request.create", "title": "Create a Forge build request", "description": "Open a governed Forge build request against a connected software project. Records the request plus its initial intake phase run. Entitlement-gated (Forge add-on); the title is untrusted display text, never an instruction.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": false }, { "name": "project", "flag": "project", "type": "string", "required": false }, { "name": "title", "flag": "title", "type": "string", "required": true }, { "name": "source_channel", "flag": "source-channel", "type": "enum", "required": false, "enumValues": ["ui", "cli", "github_issue", "linear", "api"] }, { "name": "source_ref", "flag": "source-ref", "type": "string", "required": false }], "hasComplexInput": true, "help": "Open a governed Forge build request against a connected software project; the title is untrusted display text. Requires the Forge add-on." },
49093
49102
  { "id": "software_factory.request.list", "namespace": "software_factory", "action": "request.list", "title": "List Forge build requests", "description": "The Forge control-room board: the tenant's build requests with status, current phase, and risk/automation mode. Read-only, entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "limit", "flag": "limit", "type": "integer", "required": false }], "hasComplexInput": false, "help": "List Forge build requests (the control-room board) with status, current phase, and risk. Read-only; requires the Forge add-on." },
49094
49103
  { "id": "software_factory.request.pause", "namespace": "software_factory", "action": "request.pause", "title": "Pause a Forge build request", "description": "Pause an in-flight Forge build request. New runner claims stop immediately; any running task halts at the next task checkpoint before resume. Human-gated and entitlement-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "reason", "flag": "reason", "type": "string", "required": false }], "hasComplexInput": false, "help": "Pause an in-flight Forge build request so no new runner work starts; running work stops at the next task checkpoint. Tenant-admin and human-gated." },
49095
49104
  { "id": "software_factory.request.resume", "namespace": "software_factory", "action": "request.resume", "title": "Resume a Forge build request", "description": "Resume a paused or human-blocked Forge build request from the last completed task checkpoint and requeue the current phase. Human-gated and entitlement-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "reason", "flag": "reason", "type": "string", "required": false }], "hasComplexInput": true, "help": "Resume a paused or blocked Forge build request from its last completed task checkpoint after human review. Tenant-admin and human-gated." },
@@ -49319,9 +49328,9 @@ function coerceScalar(field3, raw) {
49319
49328
  }
49320
49329
  }
49321
49330
  function rawValueForField(entry, field3, parsed, aliasFlags) {
49322
- const canonical = parsed.values.get(field3.flag);
49323
- if (canonical !== void 0) {
49324
- return canonical;
49331
+ const canonical2 = parsed.values.get(field3.flag);
49332
+ if (canonical2 !== void 0) {
49333
+ return canonical2;
49325
49334
  }
49326
49335
  for (const [aliasFlag, targetField] of aliasFlags) {
49327
49336
  if (targetField === field3.name) {
@@ -51533,7 +51542,7 @@ function pendingConfirmationFromError(error51) {
51533
51542
 
51534
51543
  // src/doctor.ts
51535
51544
  import { execFile as execFileCallback2 } from "node:child_process";
51536
- import { access, readFile as readFile3 } from "node:fs/promises";
51545
+ import { access } from "node:fs/promises";
51537
51546
  import { delimiter } from "node:path";
51538
51547
  import { promisify as promisify2 } from "node:util";
51539
51548
  var execFile2 = promisify2(execFileCallback2);
@@ -51544,7 +51553,7 @@ async function runDoctor(options) {
51544
51553
  const config2 = loadConfig(env);
51545
51554
  lines.push(`app_url: ${config2.appUrl}`);
51546
51555
  lines.push(`supabase_url: ${config2.supabaseUrl}`);
51547
- const currentVersion = await readCurrentVersion2();
51556
+ const currentVersion = await readCliVersion();
51548
51557
  lines.push(`version: ${currentVersion ?? "unknown"}`);
51549
51558
  const pathStatus = await checkPath(env);
51550
51559
  lines.push(pathStatus);
@@ -51591,15 +51600,6 @@ async function probeCli(command) {
51591
51600
  return "not found";
51592
51601
  }
51593
51602
  }
51594
- async function readCurrentVersion2() {
51595
- try {
51596
- const url2 = new URL("../package.json", import.meta.url);
51597
- const parsed = JSON.parse(await readFile3(url2, "utf8"));
51598
- return typeof parsed.version === "string" ? parsed.version : null;
51599
- } catch {
51600
- return null;
51601
- }
51602
- }
51603
51603
  async function fetchLatestVersion2(packageName, env) {
51604
51604
  if (env.CI || env.VITEST || env.CLI_SKIP_UPDATE_CHECK === "1" || env[`${cliBrand.envPrefix}_CLI_NO_UPDATE_CHECK`] === "1") {
51605
51605
  return null;
@@ -51655,11 +51655,247 @@ function parseSemver2(value) {
51655
51655
  // src/runner-serve.ts
51656
51656
  import { execFile as execFileCallback3, spawn } from "node:child_process";
51657
51657
  import { createHash } from "node:crypto";
51658
- import { chmod, mkdir as mkdir2, readFile as readFile4, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
51659
- import { cpus, hostname as hostname3, platform, totalmem, tmpdir } from "node:os";
51660
- import path3 from "node:path";
51658
+ import { chmod, mkdir as mkdir2, readFile as readFile3, rename, rm as rm3, statfs, writeFile as writeFile2 } from "node:fs/promises";
51659
+ import { cpus, homedir as homedir2, hostname as hostname3, platform, totalmem, tmpdir } from "node:os";
51660
+ import path4 from "node:path";
51661
51661
  import { setTimeout as sleep2 } from "node:timers/promises";
51662
51662
  import { promisify as promisify3 } from "node:util";
51663
+
51664
+ // src/runner-sandbox.ts
51665
+ import { existsSync as existsSync2, realpathSync } from "node:fs";
51666
+ import { readdir, rm as rm2, stat as stat2 } from "node:fs/promises";
51667
+ import path3 from "node:path";
51668
+ var SANDBOX_EXEC_PATH = "/usr/bin/sandbox-exec";
51669
+ var RUNNER_TEMP_PREFIXES = [
51670
+ "rost-runner-mcp-",
51671
+ "rost-runner-sandbox-",
51672
+ "rost-runner-askpass-"
51673
+ ];
51674
+ var SENSITIVE_READ_SUBPATHS = [
51675
+ ".ssh",
51676
+ ".aws",
51677
+ ".gnupg",
51678
+ ".config/gcloud",
51679
+ ".config/gh",
51680
+ ".kube",
51681
+ ".docker",
51682
+ ".npmrc"
51683
+ ];
51684
+ var SENSITIVE_READ_LITERALS = [".netrc"];
51685
+ var SENSITIVE_WRITE_SUBPATHS = [
51686
+ ".ssh",
51687
+ ".aws",
51688
+ ".gnupg",
51689
+ ".config/git",
51690
+ "bin",
51691
+ "Library/LaunchAgents"
51692
+ ];
51693
+ var SENSITIVE_WRITE_LITERALS = [
51694
+ ".gitconfig",
51695
+ ".zshrc",
51696
+ ".zprofile",
51697
+ ".zshenv",
51698
+ ".zlogin",
51699
+ ".bashrc",
51700
+ ".bash_profile",
51701
+ ".bash_login",
51702
+ ".profile"
51703
+ ];
51704
+ function parseSandboxMode(value) {
51705
+ const normalized = (value ?? "auto").trim().toLowerCase();
51706
+ if (normalized === "off" || normalized === "strict" || normalized === "auto" || normalized === "") {
51707
+ return normalized === "" ? "auto" : normalized;
51708
+ }
51709
+ return "auto";
51710
+ }
51711
+ function parseSandboxNetwork(value) {
51712
+ const normalized = (value ?? "").trim().toLowerCase();
51713
+ if (normalized === "" || normalized === "allow") {
51714
+ return { allowNetwork: true, unrecognized: null };
51715
+ }
51716
+ if (normalized === "deny") {
51717
+ return { allowNetwork: false, unrecognized: null };
51718
+ }
51719
+ return { allowNetwork: true, unrecognized: value ?? "" };
51720
+ }
51721
+ function sbplString(value) {
51722
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
51723
+ }
51724
+ function subpath(value) {
51725
+ return `(subpath ${sbplString(value)})`;
51726
+ }
51727
+ function literal2(value) {
51728
+ return `(literal ${sbplString(value)})`;
51729
+ }
51730
+ var STRICT_SYSTEM_READ_SUBPATHS = [
51731
+ "/usr",
51732
+ "/bin",
51733
+ "/sbin",
51734
+ "/System",
51735
+ "/Library",
51736
+ "/private/etc",
51737
+ "/private/var/db",
51738
+ "/dev",
51739
+ "/opt",
51740
+ "/nix"
51741
+ ];
51742
+ function buildSeatbeltProfile(input) {
51743
+ const home = input.homeDir.replace(/\/+$/, "");
51744
+ const lines = ["(version 1)"];
51745
+ const denyReadBaseSubpaths = input.denyReadPaths.filter((p) => p.endsWith("/")).map((p) => subpath(p.replace(/\/+$/, "")));
51746
+ const denyReadLiterals = input.denyReadPaths.filter((p) => !p.endsWith("/")).map(literal2);
51747
+ const credentialReadDenies = [
51748
+ ...SENSITIVE_READ_SUBPATHS.map((rel) => subpath(`${home}/${rel}`)),
51749
+ ...SENSITIVE_READ_LITERALS.map((rel) => literal2(`${home}/${rel}`))
51750
+ ];
51751
+ if (input.strict) {
51752
+ lines.push("(deny default)");
51753
+ lines.push("(allow process*)");
51754
+ lines.push("(allow sysctl-read)");
51755
+ lines.push("(allow mach-lookup)");
51756
+ lines.push("(allow iokit-open)");
51757
+ lines.push("(allow system-socket)");
51758
+ lines.push("(allow signal (target self))");
51759
+ lines.push("(allow file-read-metadata)");
51760
+ const strictReads = [
51761
+ ...STRICT_SYSTEM_READ_SUBPATHS.map(subpath),
51762
+ subpath(`${home}/.claude`),
51763
+ subpath(`${home}/.codex`),
51764
+ subpath(input.tmpDir)
51765
+ ];
51766
+ lines.push(`(allow file-read* ${strictReads.join(" ")})`);
51767
+ } else {
51768
+ lines.push("(allow default)");
51769
+ }
51770
+ lines.push("(deny appleevent-send)");
51771
+ if (denyReadBaseSubpaths.length > 0) {
51772
+ lines.push(`(deny file-read* ${denyReadBaseSubpaths.join(" ")})`);
51773
+ }
51774
+ const workspaceReads = [subpath(input.workspaceDir), ...input.allowWritePaths.map(subpath)];
51775
+ lines.push(`(allow file-read* ${workspaceReads.join(" ")})`);
51776
+ lines.push("(deny file-write*)");
51777
+ const allowWrites = [
51778
+ subpath(input.workspaceDir),
51779
+ subpath(input.tmpDir),
51780
+ subpath(`${home}/.claude`),
51781
+ subpath(`${home}/.codex`),
51782
+ ...input.allowWritePaths.map(subpath),
51783
+ subpath("/dev/fd"),
51784
+ literal2("/dev/null"),
51785
+ literal2("/dev/stdout"),
51786
+ literal2("/dev/stderr"),
51787
+ literal2("/dev/tty"),
51788
+ literal2("/dev/dtracehelper")
51789
+ ];
51790
+ lines.push(`(allow file-write* ${allowWrites.join(" ")})`);
51791
+ lines.push(`(deny file-read* ${[...credentialReadDenies, ...denyReadLiterals].join(" ")})`);
51792
+ const denyWrites = [
51793
+ ...SENSITIVE_WRITE_SUBPATHS.map((rel) => subpath(`${home}/${rel}`)),
51794
+ ...SENSITIVE_WRITE_LITERALS.map((rel) => literal2(`${home}/${rel}`))
51795
+ ];
51796
+ lines.push(`(deny file-write* ${denyWrites.join(" ")})`);
51797
+ lines.push('(deny mach-lookup (global-name "com.apple.coreservices.appleevents"))');
51798
+ if (!input.allowNetwork) {
51799
+ lines.push("(deny network*)");
51800
+ } else if (input.strict) {
51801
+ lines.push("(allow network*)");
51802
+ }
51803
+ return `${lines.join("\n")}
51804
+ `;
51805
+ }
51806
+ function canonical(p) {
51807
+ try {
51808
+ return realpathSync(p);
51809
+ } catch {
51810
+ return p;
51811
+ }
51812
+ }
51813
+ function canonicalFile(p) {
51814
+ return path3.join(canonical(path3.dirname(p)), path3.basename(p));
51815
+ }
51816
+ function isSandboxExecAvailable() {
51817
+ try {
51818
+ return existsSync2(SANDBOX_EXEC_PATH);
51819
+ } catch {
51820
+ return false;
51821
+ }
51822
+ }
51823
+ function resolveSandboxSpec(options) {
51824
+ if (options.mode === "off") {
51825
+ return { kind: "none", reason: "RUNNER_SANDBOX=off (loosened fallback - OS confinement disabled)" };
51826
+ }
51827
+ if (options.platform !== "darwin") {
51828
+ return { kind: "none", reason: `no OS sandbox on ${options.platform} (seatbelt is macOS-only; Linux confinement is a follow-up)` };
51829
+ }
51830
+ const available = options.sandboxExecAvailable ?? isSandboxExecAvailable();
51831
+ if (!available) {
51832
+ return { kind: "none", reason: `sandbox-exec not found at ${SANDBOX_EXEC_PATH}` };
51833
+ }
51834
+ const workspaceDir = canonical(options.workspaceDir);
51835
+ const tmpDir = canonical(options.tmpDir);
51836
+ const homeDir = canonical(options.homeDir);
51837
+ const allowNetwork = options.allowNetwork ?? true;
51838
+ const denyReadPaths = [canonicalFile(options.stateFile)];
51839
+ if (options.runnerBaseDir) {
51840
+ denyReadPaths.push(`${canonical(options.runnerBaseDir).replace(/\/+$/, "")}/`);
51841
+ }
51842
+ const profile = buildSeatbeltProfile({
51843
+ workspaceDir,
51844
+ tmpDir,
51845
+ homeDir,
51846
+ denyReadPaths,
51847
+ allowWritePaths: (options.allowWritePaths ?? []).map(canonical),
51848
+ allowNetwork,
51849
+ strict: options.mode === "strict"
51850
+ });
51851
+ return {
51852
+ kind: "seatbelt",
51853
+ reason: options.mode === "strict" ? "seatbelt (strict: deny-default reads + write confinement)" : "seatbelt (guard: deny sensitive reads/writes)",
51854
+ profile,
51855
+ allowNetwork
51856
+ };
51857
+ }
51858
+ function wrapCommandWithSandbox(spec, command, args, profilePath) {
51859
+ if (spec.kind === "none" || profilePath === null) {
51860
+ return { command, args, profilePath: null };
51861
+ }
51862
+ return {
51863
+ command: SANDBOX_EXEC_PATH,
51864
+ args: ["-f", profilePath, command, ...args],
51865
+ profilePath
51866
+ };
51867
+ }
51868
+ async function sweepStaleRunnerTempFiles(dir, options = {}) {
51869
+ const maxAgeMs = options.maxAgeMs ?? 60 * 60 * 1e3;
51870
+ const now = options.now ?? Date.now();
51871
+ let entries;
51872
+ try {
51873
+ entries = await readdir(dir);
51874
+ } catch {
51875
+ return [];
51876
+ }
51877
+ const removed = [];
51878
+ await Promise.all(
51879
+ entries.map(async (name) => {
51880
+ if (!RUNNER_TEMP_PREFIXES.some((prefix) => name.startsWith(prefix))) {
51881
+ return;
51882
+ }
51883
+ const full = path3.join(dir, name);
51884
+ try {
51885
+ const info = await stat2(full);
51886
+ if (now - info.mtimeMs < maxAgeMs) {
51887
+ return;
51888
+ }
51889
+ await rm2(full, { force: true });
51890
+ removed.push(name);
51891
+ } catch {
51892
+ }
51893
+ })
51894
+ );
51895
+ return removed;
51896
+ }
51897
+
51898
+ // src/runner-serve.ts
51663
51899
  var execFile3 = promisify3(execFileCallback3);
51664
51900
  var RUNNER_WORK_ORDER_TOOLS = [
51665
51901
  "mcp__rost__rost_get_context",
@@ -51674,6 +51910,8 @@ var RUNNER_AICOS_TURN_TOOLS = [
51674
51910
  async function runRunnerServe(options) {
51675
51911
  const env = options.env ?? process.env;
51676
51912
  const fetchImpl = options.fetchImpl ?? fetch;
51913
+ const cliVersion = await readCliVersion();
51914
+ const homeDir = options.homeDir ?? homedir2();
51677
51915
  let config2;
51678
51916
  try {
51679
51917
  config2 = parseServeArgs(options.args, options.appUrl, env);
@@ -51685,6 +51923,20 @@ ${usage()}
51685
51923
  }
51686
51924
  options.io.stdout.write(`runner serve: ${options.appUrl} name=${config2.name} execute=${config2.execute}
51687
51925
  `);
51926
+ options.io.stdout.write(`runner sandbox: ${config2.sandbox.kind} - ${config2.sandbox.reason}
51927
+ `);
51928
+ if (config2.sandboxNetworkWarning) {
51929
+ options.io.stderr.write(`warning: ${config2.sandboxNetworkWarning}
51930
+ `);
51931
+ }
51932
+ try {
51933
+ const swept = await sweepStaleRunnerTempFiles(tmpdir());
51934
+ if (swept.length > 0) {
51935
+ options.io.stdout.write(`swept ${swept.length} stale runner temp file(s)
51936
+ `);
51937
+ }
51938
+ } catch {
51939
+ }
51688
51940
  let state;
51689
51941
  try {
51690
51942
  state = await pairIfNeeded(options.client ?? null, fetchImpl, options.appUrl, config2, options.io);
@@ -51698,13 +51950,13 @@ ${usage()}
51698
51950
  let failed = false;
51699
51951
  let activeSessions = 0;
51700
51952
  do {
51701
- const detectedCapabilities = await detectCapabilities();
51953
+ const detectedCapabilities = await detectCapabilities(cliVersion, env, homeDir);
51702
51954
  const capabilities = capabilitiesForConfiguredRuntime(detectedCapabilities, config2.runtime);
51703
51955
  const localRuntime = config2.execute ? effectiveExecutionRuntime(config2.runtime, capabilities) : null;
51704
51956
  try {
51705
51957
  const heartbeat = await post2(fetchImpl, options.appUrl, "/api/runner/heartbeat", {
51706
51958
  capabilities,
51707
- telemetry: detectTelemetry(capabilities, env, activeSessions)
51959
+ telemetry: detectTelemetry(capabilities, env, activeSessions, cliVersion)
51708
51960
  }, state.runner_secret);
51709
51961
  if (heartbeat.status !== 200) {
51710
51962
  options.io.stderr.write(`heartbeat ${heartbeat.status}: ${redactForLog(JSON.stringify(heartbeat.json))}
@@ -51751,17 +52003,28 @@ async function waitForNextHeartbeat(fetchImpl, appUrl2, state, config2, io, runt
51751
52003
  }
51752
52004
  }
51753
52005
  }
51754
- function detectTelemetry(capabilities, env, activeSessions) {
51755
- const accountAlias = (env.RUNNER_MODEL_ACCOUNT_ALIAS ?? env.ROST_RUNNER_MODEL_ACCOUNT_ALIAS ?? "").trim() || "default";
52006
+ function resolveAccountAlias(env) {
52007
+ return (env.RUNNER_MODEL_ACCOUNT_ALIAS ?? env.ROST_RUNNER_MODEL_ACCOUNT_ALIAS ?? "").trim() || "default";
52008
+ }
52009
+ function capabilitiesForAnalytics(capabilities) {
52010
+ return {
52011
+ ...capabilities,
52012
+ claude: { ...capabilities.claude, account_alias: null },
52013
+ codex: { ...capabilities.codex, account_alias: null }
52014
+ };
52015
+ }
52016
+ function detectTelemetry(capabilities, env, activeSessions, cliVersion) {
51756
52017
  const usageState = env.RUNNER_MODEL_ACCOUNT_STATE ?? env.ROST_RUNNER_MODEL_ACCOUNT_STATE ?? "unknown";
51757
52018
  return {
51758
52019
  os: platform(),
51759
52020
  cpu_count: cpus().length,
51760
52021
  memory_mb: Math.round(totalmem() / (1024 * 1024)),
51761
- runner_version: env.npm_package_version ?? null,
52022
+ // DER-1319: sourced from the bundled package.json, not env.npm_package_version (undefined
52023
+ // under launchd — prod runners were silently reporting a null version).
52024
+ runner_version: cliVersion,
51762
52025
  active_sessions: activeSessions,
51763
- installed_runtimes: capabilities,
51764
- account_alias: accountAlias,
52026
+ installed_runtimes: capabilitiesForAnalytics(capabilities),
52027
+ account_alias: resolveAccountAlias(env),
51765
52028
  usage_limit_observation: {
51766
52029
  state: usageState,
51767
52030
  source: "runner_env_or_unknown"
@@ -51770,7 +52033,7 @@ function detectTelemetry(capabilities, env, activeSessions) {
51770
52033
  }
51771
52034
  function parseServeArgs(args, appUrl2, env) {
51772
52035
  let name = env.RUNNER_NAME ?? `headless-${hostname3()}`;
51773
- let stateFile = env.RUNNER_STATE_FILE ?? path3.join(tmpdir(), `rost-runner-${createHash("sha1").update(appUrl2).digest("hex").slice(0, 8)}.json`);
52036
+ let stateFile = env.RUNNER_STATE_FILE ?? path4.join(tmpdir(), `rost-runner-${createHash("sha1").update(appUrl2).digest("hex").slice(0, 8)}.json`);
51774
52037
  let heartbeatMs = Number(env.RUNNER_HEARTBEAT_MS ?? 3e4);
51775
52038
  let interactiveClaimMs = Number(env.RUNNER_INTERACTIVE_CLAIM_MS ?? 1e3);
51776
52039
  let execute2 = env.RUNNER_EXECUTE === "1";
@@ -51812,7 +52075,29 @@ function parseServeArgs(args, appUrl2, env) {
51812
52075
  throw new Error("--interactive-claim-ms must be an integer >= 250.");
51813
52076
  }
51814
52077
  interactiveClaimMs = Math.min(interactiveClaimMs, heartbeatMs);
51815
- return { name, stateFile, heartbeatMs, interactiveClaimMs, execute: execute2, once, runtime, ...userCode ? { userCode } : {} };
52078
+ const network = parseSandboxNetwork(env.RUNNER_SANDBOX_NETWORK);
52079
+ const sandbox = resolveSandboxSpec({
52080
+ mode: parseSandboxMode(env.RUNNER_SANDBOX),
52081
+ platform: process.platform,
52082
+ workspaceDir: tmpdir(),
52083
+ tmpDir: tmpdir(),
52084
+ homeDir: homedir2(),
52085
+ stateFile,
52086
+ runnerBaseDir: path4.join(homedir2(), ".rost"),
52087
+ allowNetwork: network.allowNetwork
52088
+ });
52089
+ return {
52090
+ name,
52091
+ stateFile,
52092
+ heartbeatMs,
52093
+ interactiveClaimMs,
52094
+ execute: execute2,
52095
+ once,
52096
+ runtime,
52097
+ sandbox,
52098
+ ...network.unrecognized !== null ? { sandboxNetworkWarning: `RUNNER_SANDBOX_NETWORK='${network.unrecognized}' not recognized (use allow|deny); defaulting to allow egress.` } : {},
52099
+ ...userCode ? { userCode } : {}
52100
+ };
51816
52101
  }
51817
52102
  function parseRuntime(value) {
51818
52103
  if (value === "auto" || value === "claude" || value === "codex") {
@@ -51901,7 +52186,7 @@ async function pairIfNeeded(client, fetchImpl, appUrl2, config2, io) {
51901
52186
  }
51902
52187
  async function loadState(filePath, expectedTenantId) {
51903
52188
  try {
51904
- const parsed = JSON.parse(await readFile4(filePath, "utf8"));
52189
+ const parsed = JSON.parse(await readFile3(filePath, "utf8"));
51905
52190
  if (typeof parsed.runner_id === "string" && typeof parsed.runner_secret === "string") {
51906
52191
  if (expectedTenantId && parsed.tenant_id !== expectedTenantId) {
51907
52192
  return null;
@@ -51932,7 +52217,7 @@ function isRuntimeSessionMap(value) {
51932
52217
  });
51933
52218
  }
51934
52219
  async function saveState(filePath, state) {
51935
- await mkdir2(path3.dirname(filePath), { recursive: true, mode: 448 });
52220
+ await mkdir2(path4.dirname(filePath), { recursive: true, mode: 448 });
51936
52221
  const tempPath = `${filePath}.${process.pid}.${createHash("sha1").update(`${Date.now()}:${Math.random()}`).digest("hex").slice(0, 8)}.tmp`;
51937
52222
  try {
51938
52223
  await writeFile2(tempPath, `${JSON.stringify(state)}
@@ -51940,7 +52225,7 @@ async function saveState(filePath, state) {
51940
52225
  await chmod(tempPath, 384);
51941
52226
  await rename(tempPath, filePath);
51942
52227
  } catch (error51) {
51943
- await rm2(tempPath, { force: true });
52228
+ await rm3(tempPath, { force: true });
51944
52229
  throw error51;
51945
52230
  }
51946
52231
  }
@@ -51952,9 +52237,25 @@ async function startPairing(client, config2) {
51952
52237
  }
51953
52238
  return userCode;
51954
52239
  }
51955
- async function detectCapabilities() {
51956
- const [claude, codex] = await Promise.all([probe("claude"), probe("codex")]);
51957
- return { claude, codex, turn_executions: { report_supported: true } };
52240
+ async function detectCapabilities(cliVersion, env, homeDir) {
52241
+ const [claude, codex, git, gh, forgeDiskFreeMb] = await Promise.all([
52242
+ probe("claude"),
52243
+ probe("codex"),
52244
+ probeGit(),
52245
+ probeGh(),
52246
+ probeForgeDiskFreeMb(homeDir)
52247
+ ]);
52248
+ const accountAlias = resolveAccountAlias(env);
52249
+ return {
52250
+ claude: { ...claude, account_alias: accountAlias, rate_limited_until: null },
52251
+ codex: { ...codex, account_alias: accountAlias, rate_limited_until: null },
52252
+ turn_executions: { report_supported: true },
52253
+ ...cliVersion ? { forge_build: cliVersion } : {},
52254
+ git,
52255
+ gh,
52256
+ scheduler: { max_parallel_sessions_estimate: null },
52257
+ host: { forge_disk_free_mb: forgeDiskFreeMb }
52258
+ };
51958
52259
  }
51959
52260
  async function probe(command) {
51960
52261
  try {
@@ -51964,6 +52265,43 @@ async function probe(command) {
51964
52265
  return { installed: false, version: null, auth_state: "unknown" };
51965
52266
  }
51966
52267
  }
52268
+ async function probeGit() {
52269
+ try {
52270
+ const { stdout, stderr } = await execFile3("git", ["--version"], { timeout: 1500 });
52271
+ const raw = (stdout || stderr).trim();
52272
+ return { installed: true, version: /(\d+\.\d+(?:\.\d+)?)/.exec(raw)?.[1] ?? (raw || null) };
52273
+ } catch {
52274
+ return { installed: false, version: null };
52275
+ }
52276
+ }
52277
+ async function probeGh() {
52278
+ try {
52279
+ const { stdout, stderr } = await execFile3("gh", ["--version"], { timeout: 1500 });
52280
+ const raw = (stdout || stderr).trim().split("\n")[0]?.trim() ?? "";
52281
+ const authenticated = await probeGhAuth();
52282
+ return { installed: true, version: /(\d+\.\d+\.\d+)/.exec(raw)?.[1] ?? (raw || null), authenticated };
52283
+ } catch {
52284
+ return { installed: false, version: null, authenticated: false };
52285
+ }
52286
+ }
52287
+ async function probeGhAuth() {
52288
+ try {
52289
+ await execFile3("gh", ["auth", "status"], { timeout: 1500 });
52290
+ return true;
52291
+ } catch {
52292
+ return false;
52293
+ }
52294
+ }
52295
+ async function probeForgeDiskFreeMb(homeDir) {
52296
+ const dir = path4.join(homeDir, ".rost", "forge");
52297
+ try {
52298
+ await mkdir2(dir, { recursive: true, mode: 448 });
52299
+ const stats = await statfs(dir);
52300
+ return Math.floor(stats.bavail * stats.bsize / (1024 * 1024));
52301
+ } catch {
52302
+ return null;
52303
+ }
52304
+ }
51967
52305
  async function post2(fetchImpl, appUrl2, pathName, body, token) {
51968
52306
  const headers = { "content-type": "application/json" };
51969
52307
  if (token) {
@@ -52026,7 +52364,7 @@ async function executeClaimedUnit(fetchImpl, appUrl2, state, config2, io, runtim
52026
52364
  throw new Error(`${claimedUnitLabel(input.kind)} start failed ${started.status}: ${redactForLog(JSON.stringify(started.json))}`);
52027
52365
  }
52028
52366
  const turnRuntime = runtimeForClaimedUnit(input.item, runtime, input.kind);
52029
- const result = turnRuntime ? await runLocalTurn(appUrl2, input.item, turnRuntime, input.kind, state) : {
52367
+ const result = turnRuntime ? await runLocalTurn(appUrl2, input.item, turnRuntime, input.kind, state, config2.sandbox) : {
52030
52368
  ok: false,
52031
52369
  summary: `Runner runtime ${runtime} cannot execute requested ${String(input.item.brain ?? "unknown")} turn.`
52032
52370
  };
@@ -52066,14 +52404,14 @@ function runtimeForClaimedUnit(item, fallback, kind) {
52066
52404
  }
52067
52405
  return fallback === "claude" ? "claude" : null;
52068
52406
  }
52069
- function runLocalTurn(appUrl2, workOrder, runtime, kind, state) {
52070
- return runtime === "codex" ? runCodexTurn(appUrl2, workOrder, kind) : runClaudeTurn(appUrl2, workOrder, kind, state);
52407
+ function runLocalTurn(appUrl2, workOrder, runtime, kind, state, sandbox) {
52408
+ return runtime === "codex" ? runCodexTurn(appUrl2, workOrder, kind, sandbox) : runClaudeTurn(appUrl2, workOrder, kind, state, sandbox);
52071
52409
  }
52072
- function runClaudeTurn(appUrl2, workOrder, kind, state) {
52073
- return spawnRunnerTurn(appUrl2, workOrder, "claude", kind, state);
52410
+ function runClaudeTurn(appUrl2, workOrder, kind, state, sandbox) {
52411
+ return spawnRunnerTurn(appUrl2, workOrder, "claude", kind, sandbox, state);
52074
52412
  }
52075
- function runCodexTurn(appUrl2, workOrder, kind) {
52076
- return spawnRunnerTurn(appUrl2, workOrder, "codex", kind);
52413
+ function runCodexTurn(appUrl2, workOrder, kind, sandbox) {
52414
+ return spawnRunnerTurn(appUrl2, workOrder, "codex", kind, sandbox);
52077
52415
  }
52078
52416
  function buildTurnCommand(runtime, prompt, configPath, kind, resumeSessionId) {
52079
52417
  if (runtime === "codex") {
@@ -52098,12 +52436,12 @@ function buildTurnCommand(runtime, prompt, configPath, kind, resumeSessionId) {
52098
52436
  ]
52099
52437
  };
52100
52438
  }
52101
- async function spawnRunnerTurn(appUrl2, workOrder, runtime, kind, state) {
52439
+ async function spawnRunnerTurn(appUrl2, workOrder, runtime, kind, sandbox, state) {
52102
52440
  const mcp = typeof workOrder.mcp === "object" && workOrder.mcp !== null ? workOrder.mcp : {};
52103
52441
  const token = typeof mcp.token === "string" ? mcp.token : "";
52104
52442
  const url2 = typeof mcp.url === "string" ? `${appUrl2.replace(/\/+$/, "")}${mcp.url}` : `${appUrl2.replace(/\/+$/, "")}/mcp`;
52105
52443
  const mcpConfig = JSON.stringify({ mcpServers: { rost: { type: "http", url: url2, headers: { Authorization: `Bearer ${token}` } } } });
52106
- const configPath = path3.join(tmpdir(), `rost-runner-mcp-${createHash("sha256").update(`${url2}:${Date.now()}:${Math.random()}`).digest("hex").slice(0, 16)}.json`);
52444
+ const configPath = path4.join(tmpdir(), `rost-runner-mcp-${createHash("sha256").update(`${url2}:${Date.now()}:${Math.random()}`).digest("hex").slice(0, 16)}.json`);
52107
52445
  const context = {
52108
52446
  work_order_id: kind === "work_order" ? workOrder.id : null,
52109
52447
  turn_execution_id: kind === "turn_execution" ? workOrder.id : null,
@@ -52133,7 +52471,17 @@ async function spawnRunnerTurn(appUrl2, workOrder, runtime, kind, state) {
52133
52471
  `, { mode: 384 });
52134
52472
  await chmod(configPath, 384);
52135
52473
  const resumeSessionId = runtime === "claude" ? getClaudeResumeSessionId(state, workOrder) : void 0;
52136
- const { command, args } = buildTurnCommand(runtime, prompt, configPath, kind, resumeSessionId);
52474
+ const built = buildTurnCommand(runtime, prompt, configPath, kind, resumeSessionId);
52475
+ let sandboxProfilePath = null;
52476
+ if (sandbox.kind === "seatbelt") {
52477
+ sandboxProfilePath = path4.join(
52478
+ tmpdir(),
52479
+ `rost-runner-sandbox-${createHash("sha256").update(`${configPath}:${Math.random()}`).digest("hex").slice(0, 16)}.sb`
52480
+ );
52481
+ await writeFile2(sandboxProfilePath, sandbox.profile, { mode: 384 });
52482
+ await chmod(sandboxProfilePath, 384);
52483
+ }
52484
+ const { command, args } = wrapCommandWithSandbox(sandbox, built.command, built.args, sandboxProfilePath);
52137
52485
  const expectSessionEnvelope = runtime === "claude" && kind === "turn_execution";
52138
52486
  return new Promise((resolve2) => {
52139
52487
  let settled = false;
@@ -52142,7 +52490,10 @@ async function spawnRunnerTurn(appUrl2, workOrder, runtime, kind, state) {
52142
52490
  return;
52143
52491
  }
52144
52492
  settled = true;
52145
- void rm2(configPath, { force: true });
52493
+ void rm3(configPath, { force: true });
52494
+ if (sandboxProfilePath) {
52495
+ void rm3(sandboxProfilePath, { force: true });
52496
+ }
52146
52497
  resolve2(resumeSessionId ? { ...result, resumedFromSessionId: resumeSessionId } : result);
52147
52498
  };
52148
52499
  const child = spawn(command, args, {
@@ -52275,10 +52626,10 @@ function usage() {
52275
52626
 
52276
52627
  // src/runner-service.ts
52277
52628
  import { execFile as execFileCallback4 } from "node:child_process";
52278
- import { realpathSync } from "node:fs";
52279
- import { access as access2, mkdir as mkdir3, readFile as readFile5, rm as rm3, writeFile as writeFile3 } from "node:fs/promises";
52280
- import { homedir as homedir2 } from "node:os";
52281
- import path4 from "node:path";
52629
+ import { realpathSync as realpathSync2 } from "node:fs";
52630
+ import { access as access2, mkdir as mkdir3, readFile as readFile4, rm as rm4, writeFile as writeFile3 } from "node:fs/promises";
52631
+ import { homedir as homedir3 } from "node:os";
52632
+ import path5 from "node:path";
52282
52633
  import { promisify as promisify4 } from "node:util";
52283
52634
  var execFile4 = promisify4(execFileCallback4);
52284
52635
  var SERVICE_VERBS = ["install-service", "start", "stop", "restart", "status", "logs", "uninstall"];
@@ -52295,9 +52646,9 @@ function isRunnerServiceInvocation(args) {
52295
52646
  function runnerServicePaths(homeDir, runnerName) {
52296
52647
  const safeName = safeRunnerName(runnerName);
52297
52648
  return {
52298
- launchAgentPath: path4.join(homeDir, "Library", "LaunchAgents", `${serviceLabel(safeName)}.plist`),
52299
- stateFile: path4.join(homeDir, "Library", "Application Support", cliBrand.name, `runner-${safeName}.json`),
52300
- logDir: path4.join(homeDir, "Library", "Logs", cliBrand.name, "runner", safeName)
52649
+ launchAgentPath: path5.join(homeDir, "Library", "LaunchAgents", `${serviceLabel(safeName)}.plist`),
52650
+ stateFile: path5.join(homeDir, "Library", "Application Support", cliBrand.name, `runner-${safeName}.json`),
52651
+ logDir: path5.join(homeDir, "Library", "Logs", cliBrand.name, "runner", safeName)
52301
52652
  };
52302
52653
  }
52303
52654
  function renderLaunchdPlist(config2) {
@@ -52337,9 +52688,9 @@ ${programArgsXml}
52337
52688
  <key>RunAtLoad</key>
52338
52689
  <true/>
52339
52690
  <key>StandardOutPath</key>
52340
- <string>${escapePlist(path4.join(config2.logDir, "stdout.log"))}</string>
52691
+ <string>${escapePlist(path5.join(config2.logDir, "stdout.log"))}</string>
52341
52692
  <key>StandardErrorPath</key>
52342
- <string>${escapePlist(path4.join(config2.logDir, "stderr.log"))}</string>
52693
+ <string>${escapePlist(path5.join(config2.logDir, "stderr.log"))}</string>
52343
52694
  </dict>
52344
52695
  </plist>
52345
52696
  `;
@@ -52374,7 +52725,7 @@ ${serviceUsage()}
52374
52725
  userCode: parsed.userCode,
52375
52726
  nodePath: options.nodePath ?? resolveNodePath(),
52376
52727
  binPath: options.binPath ?? resolveBinPath(),
52377
- homeDir: options.homeDir ?? homedir2(),
52728
+ homeDir: options.homeDir ?? homedir3(),
52378
52729
  platform: options.platform ?? process.platform,
52379
52730
  exec: options.exec ?? defaultExec,
52380
52731
  uid: options.uid ?? (process.getuid ? process.getuid() : 0)
@@ -52406,8 +52757,8 @@ async function installService(options) {
52406
52757
  const paths = runnerServicePaths(options.homeDir, safeName);
52407
52758
  const label = serviceLabel(safeName);
52408
52759
  await mkdir3(paths.logDir, { recursive: true });
52409
- await mkdir3(path4.dirname(paths.stateFile), { recursive: true });
52410
- await mkdir3(path4.dirname(paths.launchAgentPath), { recursive: true });
52760
+ await mkdir3(path5.dirname(paths.stateFile), { recursive: true });
52761
+ await mkdir3(path5.dirname(paths.launchAgentPath), { recursive: true });
52411
52762
  if (options.userCode !== void 0) {
52412
52763
  const paired = await pairRunnerOnce(options, safeName, paths.stateFile, options.userCode);
52413
52764
  if (!paired) {
@@ -52585,8 +52936,8 @@ async function logsService(options) {
52585
52936
  const safeName = safeRunnerName(options.runnerName);
52586
52937
  const paths = runnerServicePaths(options.homeDir, safeName);
52587
52938
  const label = serviceLabel(safeName);
52588
- const stdoutLog = path4.join(paths.logDir, "stdout.log");
52589
- const stderrLog = path4.join(paths.logDir, "stderr.log");
52939
+ const stdoutLog = path5.join(paths.logDir, "stdout.log");
52940
+ const stderrLog = path5.join(paths.logDir, "stderr.log");
52590
52941
  options.io.stdout.write(
52591
52942
  `${[
52592
52943
  `runner service logs for ${label}:`,
@@ -52617,7 +52968,7 @@ async function uninstallService(options) {
52617
52968
  await bootoutQuietly(options.exec, options.uid, paths.launchAgentPath);
52618
52969
  let removed = false;
52619
52970
  try {
52620
- await rm3(paths.launchAgentPath, { force: true });
52971
+ await rm4(paths.launchAgentPath, { force: true });
52621
52972
  removed = true;
52622
52973
  } catch (error51) {
52623
52974
  options.io.stderr.write(
@@ -52761,11 +53112,11 @@ function resolveNodePath() {
52761
53112
  }
52762
53113
  function buildServicePath(nodePath, homeDir) {
52763
53114
  const entries = [
52764
- path4.dirname(nodePath),
53115
+ path5.dirname(nodePath),
52765
53116
  "/opt/homebrew/bin",
52766
53117
  "/usr/local/bin",
52767
- path4.join(homeDir, ".local", "bin"),
52768
- path4.join(homeDir, "bin"),
53118
+ path5.join(homeDir, ".local", "bin"),
53119
+ path5.join(homeDir, "bin"),
52769
53120
  "/usr/bin",
52770
53121
  "/bin",
52771
53122
  "/usr/sbin",
@@ -52810,7 +53161,7 @@ function resolveBinPath() {
52810
53161
  return cliBrand.binName;
52811
53162
  }
52812
53163
  try {
52813
- return realpathSync(entry);
53164
+ return realpathSync2(entry);
52814
53165
  } catch {
52815
53166
  return entry;
52816
53167
  }
@@ -52829,7 +53180,7 @@ async function fileExists(file2) {
52829
53180
  }
52830
53181
  async function readTail(file2, maxBytes) {
52831
53182
  try {
52832
- const content = await readFile5(file2, "utf8");
53183
+ const content = await readFile4(file2, "utf8");
52833
53184
  return content.length > maxBytes ? content.slice(content.length - maxBytes) : content;
52834
53185
  } catch {
52835
53186
  return null;
@@ -53473,7 +53824,7 @@ function isCliEntrypoint(moduleUrl, argvPath) {
53473
53824
  return false;
53474
53825
  }
53475
53826
  try {
53476
- return realpathSync2(fileURLToPath3(moduleUrl)) === realpathSync2(argvPath);
53827
+ return realpathSync3(fileURLToPath3(moduleUrl)) === realpathSync3(argvPath);
53477
53828
  } catch {
53478
53829
  return moduleUrl === pathToFileURL(argvPath).href;
53479
53830
  }