@rosthq/cli 0.5.27 → 0.5.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +763 -108
- package/dist/index.js.map +4 -4
- package/dist/operations.d.ts +2 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/runner-serve.d.ts +17 -0
- package/dist/runner-serve.d.ts.map +1 -0
- package/package.json +1 -1
- package/prompts/how-tos/human-confirmations.md +2 -0
package/dist/index.js
CHANGED
|
@@ -472,13 +472,13 @@ function __disposeResources(env) {
|
|
|
472
472
|
}
|
|
473
473
|
return next();
|
|
474
474
|
}
|
|
475
|
-
function __rewriteRelativeImportExtension(
|
|
476
|
-
if (typeof
|
|
477
|
-
return
|
|
475
|
+
function __rewriteRelativeImportExtension(path4, preserveJsx) {
|
|
476
|
+
if (typeof path4 === "string" && /^\.\.?\//.test(path4)) {
|
|
477
|
+
return path4.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
|
|
481
|
+
return path4;
|
|
482
482
|
}
|
|
483
483
|
var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
|
|
484
484
|
var init_tslib_es6 = __esm({
|
|
@@ -5471,7 +5471,7 @@ var require_helpers = __commonJS({
|
|
|
5471
5471
|
exports.generateCallbackId = generateCallbackId;
|
|
5472
5472
|
exports.parseParametersFromURL = parseParametersFromURL;
|
|
5473
5473
|
exports.decodeJWT = decodeJWT;
|
|
5474
|
-
exports.sleep =
|
|
5474
|
+
exports.sleep = sleep3;
|
|
5475
5475
|
exports.retryable = retryable;
|
|
5476
5476
|
exports.generatePKCEVerifier = generatePKCEVerifier;
|
|
5477
5477
|
exports.generatePKCEChallenge = generatePKCEChallenge;
|
|
@@ -5609,7 +5609,7 @@ var require_helpers = __commonJS({
|
|
|
5609
5609
|
};
|
|
5610
5610
|
return data;
|
|
5611
5611
|
}
|
|
5612
|
-
async function
|
|
5612
|
+
async function sleep3(time3) {
|
|
5613
5613
|
return await new Promise((accept) => {
|
|
5614
5614
|
setTimeout(() => accept(null), time3);
|
|
5615
5615
|
});
|
|
@@ -7718,10 +7718,10 @@ var require_webauthn = __commonJS({
|
|
|
7718
7718
|
authenticatorAttachment: (_a3 = credentialWithAttachment.authenticatorAttachment) !== null && _a3 !== void 0 ? _a3 : void 0
|
|
7719
7719
|
};
|
|
7720
7720
|
}
|
|
7721
|
-
function isValidDomain(
|
|
7721
|
+
function isValidDomain(hostname4) {
|
|
7722
7722
|
return (
|
|
7723
7723
|
// Consider localhost valid as well since it's okay wrt Secure Contexts
|
|
7724
|
-
|
|
7724
|
+
hostname4 === "localhost" || /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(hostname4)
|
|
7725
7725
|
);
|
|
7726
7726
|
}
|
|
7727
7727
|
function browserSupportsWebAuthn() {
|
|
@@ -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,
|
|
14030
|
-
if (!
|
|
14029
|
+
function getElementAtPath(obj, path4) {
|
|
14030
|
+
if (!path4)
|
|
14031
14031
|
return obj;
|
|
14032
|
-
return
|
|
14032
|
+
return path4.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(
|
|
14441
|
+
function prefixIssues(path4, issues) {
|
|
14442
14442
|
return issues.map((iss) => {
|
|
14443
14443
|
var _a3;
|
|
14444
14444
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
14445
|
-
iss.path.unshift(
|
|
14445
|
+
iss.path.unshift(path4);
|
|
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,
|
|
14592
|
+
const processError = (error52, path4 = []) => {
|
|
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 }, [...
|
|
14595
|
+
issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
|
|
14596
14596
|
} else if (issue2.code === "invalid_key") {
|
|
14597
|
-
processError({ issues: issue2.issues }, [...
|
|
14597
|
+
processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
|
|
14598
14598
|
} else if (issue2.code === "invalid_element") {
|
|
14599
|
-
processError({ issues: issue2.issues }, [...
|
|
14599
|
+
processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
|
|
14600
14600
|
} else {
|
|
14601
|
-
const fullpath = [...
|
|
14601
|
+
const fullpath = [...path4, ...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,
|
|
14628
|
+
const processError = (error52, path4 = []) => {
|
|
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 }, [...
|
|
14632
|
+
issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
|
|
14633
14633
|
} else if (issue2.code === "invalid_key") {
|
|
14634
|
-
processError({ issues: issue2.issues }, [...
|
|
14634
|
+
processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
|
|
14635
14635
|
} else if (issue2.code === "invalid_element") {
|
|
14636
|
-
processError({ issues: issue2.issues }, [...
|
|
14636
|
+
processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
|
|
14637
14637
|
} else {
|
|
14638
|
-
const fullpath = [...
|
|
14638
|
+
const fullpath = [...path4, ...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
|
|
14671
|
-
for (const seg of
|
|
14670
|
+
const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
14671
|
+
for (const seg of path4) {
|
|
14672
14672
|
if (typeof seg === "number")
|
|
14673
14673
|
segs.push(`[${seg}]`);
|
|
14674
14674
|
else if (typeof seg === "symbol")
|
|
@@ -14874,8 +14874,8 @@ function emoji() {
|
|
|
14874
14874
|
}
|
|
14875
14875
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
14876
14876
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
14877
|
-
var mac = (
|
|
14878
|
-
const escapedDelim = escapeRegex(
|
|
14877
|
+
var mac = (delimiter2) => {
|
|
14878
|
+
const escapedDelim = escapeRegex(delimiter2 ?? ":");
|
|
14879
14879
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
14880
14880
|
};
|
|
14881
14881
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -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
|
|
27364
|
-
if (
|
|
27363
|
+
const path4 = ref.slice(1).split("/").filter(Boolean);
|
|
27364
|
+
if (path4.length === 0) {
|
|
27365
27365
|
return ctx.rootSchema;
|
|
27366
27366
|
}
|
|
27367
27367
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
27368
|
-
if (
|
|
27369
|
-
const key =
|
|
27368
|
+
if (path4[0] === defsKey) {
|
|
27369
|
+
const key = path4[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
|
|
27831
|
+
const path4 = `/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}${
|
|
27839
|
+
const response = await this.fetchImpl(`${this.appUrl}${path4}`, {
|
|
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 ${
|
|
27852
|
+
`server returned HTTP ${response.status} (non-JSON) from ${path4}` + (snippet ? ` \u2014 ${snippet}` : "") + " \u2014 the deployment may be unhealthy"
|
|
27853
27853
|
);
|
|
27854
27854
|
}
|
|
27855
27855
|
const parsed = commandResponseSchema.parse(raw);
|
|
@@ -33056,8 +33056,8 @@ var IcebergError = class extends Error {
|
|
|
33056
33056
|
return this.status === 419;
|
|
33057
33057
|
}
|
|
33058
33058
|
};
|
|
33059
|
-
function buildUrl(baseUrl,
|
|
33060
|
-
const url2 = new URL(
|
|
33059
|
+
function buildUrl(baseUrl, path4, query) {
|
|
33060
|
+
const url2 = new URL(path4, baseUrl);
|
|
33061
33061
|
if (query) {
|
|
33062
33062
|
for (const [key, value] of Object.entries(query)) {
|
|
33063
33063
|
if (value !== void 0) {
|
|
@@ -33087,12 +33087,12 @@ function createFetchClient(options) {
|
|
|
33087
33087
|
return {
|
|
33088
33088
|
async request({
|
|
33089
33089
|
method,
|
|
33090
|
-
path:
|
|
33090
|
+
path: path4,
|
|
33091
33091
|
query,
|
|
33092
33092
|
body,
|
|
33093
33093
|
headers
|
|
33094
33094
|
}) {
|
|
33095
|
-
const url2 = buildUrl(options.baseUrl,
|
|
33095
|
+
const url2 = buildUrl(options.baseUrl, path4, query);
|
|
33096
33096
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
33097
33097
|
const res = await fetchFn(url2, {
|
|
33098
33098
|
method,
|
|
@@ -33954,7 +33954,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
33954
33954
|
* @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
|
|
33955
33955
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
33956
33956
|
*/
|
|
33957
|
-
async uploadOrUpdate(method,
|
|
33957
|
+
async uploadOrUpdate(method, path4, fileBody, fileOptions) {
|
|
33958
33958
|
var _this = this;
|
|
33959
33959
|
return _this.handleOperation(async () => {
|
|
33960
33960
|
let body;
|
|
@@ -33978,7 +33978,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
33978
33978
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
33979
33979
|
}
|
|
33980
33980
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) for (const [key, value] of Object.entries(fileOptions.headers)) headers = setHeader(headers, key, value);
|
|
33981
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
33981
|
+
const cleanPath = _this._removeEmptyFolders(path4);
|
|
33982
33982
|
const _path = _this._getFinalPath(cleanPath);
|
|
33983
33983
|
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 } : {}));
|
|
33984
33984
|
return {
|
|
@@ -34055,8 +34055,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34055
34055
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34056
34056
|
* - 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.
|
|
34057
34057
|
*/
|
|
34058
|
-
async upload(
|
|
34059
|
-
return this.uploadOrUpdate("POST",
|
|
34058
|
+
async upload(path4, fileBody, fileOptions) {
|
|
34059
|
+
return this.uploadOrUpdate("POST", path4, fileBody, fileOptions);
|
|
34060
34060
|
}
|
|
34061
34061
|
/**
|
|
34062
34062
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -34096,9 +34096,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34096
34096
|
* - `objects` table permissions: none
|
|
34097
34097
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34098
34098
|
*/
|
|
34099
|
-
async uploadToSignedUrl(
|
|
34099
|
+
async uploadToSignedUrl(path4, token, fileBody, fileOptions) {
|
|
34100
34100
|
var _this3 = this;
|
|
34101
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
34101
|
+
const cleanPath = _this3._removeEmptyFolders(path4);
|
|
34102
34102
|
const _path = _this3._getFinalPath(cleanPath);
|
|
34103
34103
|
const url2 = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
34104
34104
|
url2.searchParams.set("token", token);
|
|
@@ -34167,10 +34167,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34167
34167
|
* - `objects` table permissions: `insert`
|
|
34168
34168
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34169
34169
|
*/
|
|
34170
|
-
async createSignedUploadUrl(
|
|
34170
|
+
async createSignedUploadUrl(path4, options) {
|
|
34171
34171
|
var _this4 = this;
|
|
34172
34172
|
return _this4.handleOperation(async () => {
|
|
34173
|
-
let _path = _this4._getFinalPath(
|
|
34173
|
+
let _path = _this4._getFinalPath(path4);
|
|
34174
34174
|
const headers = _objectSpread22({}, _this4.headers);
|
|
34175
34175
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
34176
34176
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -34179,7 +34179,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34179
34179
|
if (!token) throw new StorageError("No token returned by API");
|
|
34180
34180
|
return {
|
|
34181
34181
|
signedUrl: url2.toString(),
|
|
34182
|
-
path:
|
|
34182
|
+
path: path4,
|
|
34183
34183
|
token
|
|
34184
34184
|
};
|
|
34185
34185
|
});
|
|
@@ -34239,8 +34239,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34239
34239
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34240
34240
|
* - 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.
|
|
34241
34241
|
*/
|
|
34242
|
-
async update(
|
|
34243
|
-
return this.uploadOrUpdate("PUT",
|
|
34242
|
+
async update(path4, fileBody, fileOptions) {
|
|
34243
|
+
return this.uploadOrUpdate("PUT", path4, fileBody, fileOptions);
|
|
34244
34244
|
}
|
|
34245
34245
|
/**
|
|
34246
34246
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -34391,10 +34391,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34391
34391
|
* - `objects` table permissions: `select`
|
|
34392
34392
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34393
34393
|
*/
|
|
34394
|
-
async createSignedUrl(
|
|
34394
|
+
async createSignedUrl(path4, expiresIn, options) {
|
|
34395
34395
|
var _this8 = this;
|
|
34396
34396
|
return _this8.handleOperation(async () => {
|
|
34397
|
-
let _path = _this8._getFinalPath(
|
|
34397
|
+
let _path = _this8._getFinalPath(path4);
|
|
34398
34398
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
34399
34399
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
34400
34400
|
const query = new URLSearchParams();
|
|
@@ -34530,13 +34530,13 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34530
34530
|
* - `objects` table permissions: `select`
|
|
34531
34531
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34532
34532
|
*/
|
|
34533
|
-
download(
|
|
34533
|
+
download(path4, options, parameters) {
|
|
34534
34534
|
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";
|
|
34535
34535
|
const query = new URLSearchParams();
|
|
34536
34536
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
34537
34537
|
if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
|
|
34538
34538
|
const queryString = query.toString();
|
|
34539
|
-
const _path = this._getFinalPath(
|
|
34539
|
+
const _path = this._getFinalPath(path4);
|
|
34540
34540
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
|
|
34541
34541
|
headers: this.headers,
|
|
34542
34542
|
noResolveJson: true
|
|
@@ -34567,9 +34567,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34567
34567
|
* }
|
|
34568
34568
|
* ```
|
|
34569
34569
|
*/
|
|
34570
|
-
async info(
|
|
34570
|
+
async info(path4) {
|
|
34571
34571
|
var _this10 = this;
|
|
34572
|
-
const _path = _this10._getFinalPath(
|
|
34572
|
+
const _path = _this10._getFinalPath(path4);
|
|
34573
34573
|
return _this10.handleOperation(async () => {
|
|
34574
34574
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
34575
34575
|
});
|
|
@@ -34590,9 +34590,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34590
34590
|
* .exists('folder/avatar1.png')
|
|
34591
34591
|
* ```
|
|
34592
34592
|
*/
|
|
34593
|
-
async exists(
|
|
34593
|
+
async exists(path4) {
|
|
34594
34594
|
var _this11 = this;
|
|
34595
|
-
const _path = _this11._getFinalPath(
|
|
34595
|
+
const _path = _this11._getFinalPath(path4);
|
|
34596
34596
|
try {
|
|
34597
34597
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
34598
34598
|
return {
|
|
@@ -34671,8 +34671,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34671
34671
|
* - `objects` table permissions: none
|
|
34672
34672
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34673
34673
|
*/
|
|
34674
|
-
getPublicUrl(
|
|
34675
|
-
const _path = this._getFinalPath(
|
|
34674
|
+
getPublicUrl(path4, options) {
|
|
34675
|
+
const _path = this._getFinalPath(path4);
|
|
34676
34676
|
const query = new URLSearchParams();
|
|
34677
34677
|
if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
|
|
34678
34678
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
@@ -34811,10 +34811,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34811
34811
|
* - `objects` table permissions: `select`
|
|
34812
34812
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
34813
34813
|
*/
|
|
34814
|
-
async list(
|
|
34814
|
+
async list(path4, options, parameters) {
|
|
34815
34815
|
var _this13 = this;
|
|
34816
34816
|
return _this13.handleOperation(async () => {
|
|
34817
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
34817
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path4 || "" });
|
|
34818
34818
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
34819
34819
|
});
|
|
34820
34820
|
}
|
|
@@ -34879,11 +34879,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
34879
34879
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
34880
34880
|
return btoa(data);
|
|
34881
34881
|
}
|
|
34882
|
-
_getFinalPath(
|
|
34883
|
-
return `${this.bucketId}/${
|
|
34882
|
+
_getFinalPath(path4) {
|
|
34883
|
+
return `${this.bucketId}/${path4.replace(/^\/+/, "")}`;
|
|
34884
34884
|
}
|
|
34885
|
-
_removeEmptyFolders(
|
|
34886
|
-
return
|
|
34885
|
+
_removeEmptyFolders(path4) {
|
|
34886
|
+
return path4.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
34887
34887
|
}
|
|
34888
34888
|
/** Modifies the `query`, appending values the from `transform` */
|
|
34889
34889
|
applyTransformOptsToQuery(query, transform2) {
|
|
@@ -36381,12 +36381,12 @@ function shouldPropagateToTarget(targetUrl, targets) {
|
|
|
36381
36381
|
}
|
|
36382
36382
|
return false;
|
|
36383
36383
|
}
|
|
36384
|
-
function matchStringTarget(
|
|
36385
|
-
if (target ===
|
|
36384
|
+
function matchStringTarget(hostname4, target) {
|
|
36385
|
+
if (target === hostname4) return true;
|
|
36386
36386
|
if (target.startsWith("*.")) {
|
|
36387
36387
|
const domain2 = target.slice(2);
|
|
36388
|
-
if (
|
|
36389
|
-
if (
|
|
36388
|
+
if (hostname4.endsWith(domain2)) {
|
|
36389
|
+
if (hostname4 === domain2 || hostname4.endsWith("." + domain2)) return true;
|
|
36390
36390
|
}
|
|
36391
36391
|
}
|
|
36392
36392
|
return false;
|
|
@@ -37172,7 +37172,7 @@ async function defaultVerifyOtp(config2, input) {
|
|
|
37172
37172
|
}
|
|
37173
37173
|
async function loginWithDeviceCode(config2, io, deps = {}) {
|
|
37174
37174
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
37175
|
-
const
|
|
37175
|
+
const sleep3 = deps.sleep ?? defaultSleep;
|
|
37176
37176
|
const openBrowser2 = deps.openBrowser ?? tryOpenBrowser;
|
|
37177
37177
|
const verifyOtp = deps.verifyOtp ?? defaultVerifyOtp;
|
|
37178
37178
|
const now = deps.now ?? Date.now;
|
|
@@ -37206,7 +37206,7 @@ async function loginWithDeviceCode(config2, io, deps = {}) {
|
|
|
37206
37206
|
`The code expired before it was approved. Run '${cliBrand.binName} login --device' again.`
|
|
37207
37207
|
);
|
|
37208
37208
|
}
|
|
37209
|
-
await
|
|
37209
|
+
await sleep3(intervalMs);
|
|
37210
37210
|
const poll = await postJson(fetchImpl, `${baseUrl}/api/auth/device/token`, {
|
|
37211
37211
|
device_code: session.device_code
|
|
37212
37212
|
});
|
|
@@ -37359,8 +37359,8 @@ var FileTokenStore = class {
|
|
|
37359
37359
|
return `plain file fallback at ${this.filePath}`;
|
|
37360
37360
|
}
|
|
37361
37361
|
async chmodOwnerOnly() {
|
|
37362
|
-
const { chmod } = await import("node:fs/promises");
|
|
37363
|
-
await
|
|
37362
|
+
const { chmod: chmod2 } = await import("node:fs/promises");
|
|
37363
|
+
await chmod2(this.filePath, 384);
|
|
37364
37364
|
}
|
|
37365
37365
|
};
|
|
37366
37366
|
function createTokenStore(options = {}) {
|
|
@@ -37920,8 +37920,8 @@ function getErrorMap2() {
|
|
|
37920
37920
|
|
|
37921
37921
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
37922
37922
|
var makeIssue = (params) => {
|
|
37923
|
-
const { data, path:
|
|
37924
|
-
const fullPath = [...
|
|
37923
|
+
const { data, path: path4, errorMaps, issueData } = params;
|
|
37924
|
+
const fullPath = [...path4, ...issueData.path || []];
|
|
37925
37925
|
const fullIssue = {
|
|
37926
37926
|
...issueData,
|
|
37927
37927
|
path: fullPath
|
|
@@ -38037,11 +38037,11 @@ var errorUtil;
|
|
|
38037
38037
|
|
|
38038
38038
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
38039
38039
|
var ParseInputLazyPath = class {
|
|
38040
|
-
constructor(parent, value,
|
|
38040
|
+
constructor(parent, value, path4, key) {
|
|
38041
38041
|
this._cachedPath = [];
|
|
38042
38042
|
this.parent = parent;
|
|
38043
38043
|
this.data = value;
|
|
38044
|
-
this._path =
|
|
38044
|
+
this._path = path4;
|
|
38045
38045
|
this._key = key;
|
|
38046
38046
|
}
|
|
38047
38047
|
get path() {
|
|
@@ -42085,6 +42085,7 @@ The dry run is a real sandbox rehearsal, not a stamp. It executes a mock-provide
|
|
|
42085
42085
|
"sync.run.start",
|
|
42086
42086
|
"sync.run.complete",
|
|
42087
42087
|
"sync.item.assign",
|
|
42088
|
+
"coach.draft_guide",
|
|
42088
42089
|
"confirmation.approve"
|
|
42089
42090
|
],
|
|
42090
42091
|
legal: {
|
|
@@ -42156,6 +42157,7 @@ Decisions should be recorded as human decisions. Handoffs should attach to seats
|
|
|
42156
42157
|
"agent.list_fleet",
|
|
42157
42158
|
"agent.fleet_digest",
|
|
42158
42159
|
"system.health",
|
|
42160
|
+
"team.health_score",
|
|
42159
42161
|
"agent_setup.get",
|
|
42160
42162
|
"agent_setup.update",
|
|
42161
42163
|
"agent.decommission",
|
|
@@ -42255,7 +42257,7 @@ Use the lower-level commands after health names a finding: \`agent.get_run\` for
|
|
|
42255
42257
|
order: 46,
|
|
42256
42258
|
title: "Tool access and vault",
|
|
42257
42259
|
summary: "How to give agents access to tools without exposing raw credentials or expanding authority by accident.",
|
|
42258
|
-
version: "2026-06-
|
|
42260
|
+
version: "2026-06-27.6",
|
|
42259
42261
|
public: true,
|
|
42260
42262
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
42261
42263
|
stages: ["staffing"],
|
|
@@ -42303,9 +42305,13 @@ For an API with no dedicated connector, the generic REST tool lets a seat call a
|
|
|
42303
42305
|
|
|
42304
42306
|
\`slack.post_message\` reuses the connected Slack workspace credential and the seat's Slack channel binding. A live call posts only to that bound channel, through the server-side guard and vault-bound bot token. If the bound channel is marked sensitive, the handler escalates for human approval instead of posting. A sandbox dry run makes no Slack request and does not open the vault.
|
|
42305
42307
|
|
|
42308
|
+
## Gmail connector
|
|
42309
|
+
|
|
42310
|
+
The native Gmail handlers run inside the same broker boundary as the REST and Slack connectors: every call passes the server guard and writes an audit row, and the vaulted Google OAuth token is bound only inside a credential closure \u2014 the agent never sees it, and both the access and refresh tokens are redacted from anything a handler returns. \`gmail.read\` (read scoped inbox) and \`gmail.draft\` (compose a draft, never send) are autonomous-eligible. \`gmail.send\` is approval-gated: it never sends autonomously \u2014 it holds the action for steward approval. A sandbox dry run previews the intended read/draft/held-send with no Gmail request and without opening the vault. Live external Gmail send stays gated on Google verification and domain cutover (DER-880 / DER-881); the draft and send-with-approval paths are live now.
|
|
42311
|
+
|
|
42306
42312
|
## Google connector status
|
|
42307
42313
|
|
|
42308
|
-
Google can be connected from Settings once the workspace OAuth app is configured. The connection flow requests offline access for Gmail read/compose and Sheets, stores the returned credential in the vault, and records only account and scope metadata in the integration row. The test action refreshes the vaulted credential and performs a minimal Gmail profile read.
|
|
42314
|
+
Google can be connected from Settings once the workspace OAuth app is configured. The connection flow requests offline access for Gmail read/compose and Sheets, stores the returned credential in the vault, and records only account and scope metadata in the integration row. The test action refreshes the vaulted credential and performs a minimal Gmail profile read. Sheets agent tools remain configuration-only until their guarded handlers ship; connecting Google does not by itself let an agent edit a sheet.
|
|
42309
42315
|
|
|
42310
42316
|
CLI and MCP can inspect connector readiness without seeing secrets: \`integration.list\` / \`rost_list_integrations\` lists connected providers and health metadata, \`integration.status\` / \`rost_get_integration_status\` reads one provider by id or name, and \`integration.test\` / \`rost_test_integration_connection\` runs the installed provider-specific health check. For Google, the test refreshes the vaulted OAuth credential and reads the Gmail profile, then records only account, scope, and health metadata.
|
|
42311
42317
|
|
|
@@ -42340,7 +42346,7 @@ There is exactly one way to give a connected tool its credential, and it is the
|
|
|
42340
42346
|
order: 47,
|
|
42341
42347
|
title: "Available tools guide",
|
|
42342
42348
|
summary: "How to think about tool categories available to seats and what each category should be used for.",
|
|
42343
|
-
version: "2026-06-
|
|
42349
|
+
version: "2026-06-27.2",
|
|
42344
42350
|
public: true,
|
|
42345
42351
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
42346
42352
|
stages: ["staffing"],
|
|
@@ -42386,14 +42392,14 @@ Agents should explain the job, the required tool category, the minimum permissio
|
|
|
42386
42392
|
|
|
42387
42393
|
Every tool call passes the server-side guard first: the guard checks the call against the seat's signed permission manifest and records a tool-call audit row for **every** call \u2014 allowed, denied, or escalated. Tool selection is never authorization. Only an allowed call reaches its handler. A connected credential is bound into the handler for the duration of the call only; the secret never appears in the result, the audit summary, logs, or the model's context.
|
|
42388
42394
|
|
|
42389
|
-
External connectors are being rolled out provider by provider, conservatively (read and draft before send; write behind approval). A selected tool is only a permission until a live handler exists and the seat has the required credential or binding. Today the built-in execution path supports internal status reporting, the generic REST connector when a signed host/method/path allowlist and credential exist,
|
|
42395
|
+
External connectors are being rolled out provider by provider, conservatively (read and draft before send; write behind approval). A selected tool is only a permission until a live handler exists and the seat has the required credential or binding. Today the built-in execution path supports internal status reporting, the generic REST connector when a signed host/method/path allowlist and credential exist, \`slack.post_message\` for a bound Slack channel, and the Gmail handlers (\`gmail.read\`/\`gmail.draft\` autonomous-eligible, \`gmail.send\` held for approval) when Google is connected. Other provider entries remain configuration-only until their connector ships, so nothing runs silently.`
|
|
42390
42396
|
},
|
|
42391
42397
|
{
|
|
42392
42398
|
slug: "mcp-and-cli-guide",
|
|
42393
42399
|
order: 48,
|
|
42394
42400
|
title: "CLI and MCP installation guide",
|
|
42395
42401
|
summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
|
|
42396
|
-
version: "2026-06-
|
|
42402
|
+
version: "2026-06-28.3",
|
|
42397
42403
|
public: true,
|
|
42398
42404
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
42399
42405
|
stages: ["company_setup", "staffing"],
|
|
@@ -42459,6 +42465,9 @@ External connectors are being rolled out provider by provider, conservatively (r
|
|
|
42459
42465
|
"deliverable.get",
|
|
42460
42466
|
"deliverable.create",
|
|
42461
42467
|
"deliverable.attach",
|
|
42468
|
+
"deliverable.accept",
|
|
42469
|
+
"usage.report",
|
|
42470
|
+
"usage.snapshot",
|
|
42462
42471
|
"error_log.list",
|
|
42463
42472
|
"error_log.resolve",
|
|
42464
42473
|
"error_log.supersede",
|
|
@@ -42789,6 +42798,7 @@ These are the security posture rules for operating after install \u2014 a checkl
|
|
|
42789
42798
|
| Command | Purpose | Scope | Safe example |
|
|
42790
42799
|
|---|---|---|---|
|
|
42791
42800
|
| \`{{cli}} docs\` | Print the agent-facing how-to summary. | Public reference | \`{{cli}} docs\` |
|
|
42801
|
+
| \`{{cli}} doctor\` | Diagnose local CLI configuration: app URL, Supabase URL, installed version, PATH, session store, local Claude/Codex availability, and update status without printing tokens. | Local environment | \`{{cli}} doctor\` |
|
|
42792
42802
|
| \`{{cli}} help [group]\` | Print top-level usage, or one operation group's usage; \`{{cli}} <group> --help\` works too. | Public reference | \`{{cli}} help agent\` |
|
|
42793
42803
|
| \`{{cli}} reference <list|search|get> [options]\` | Help syntax for public reference commands. \`--audience <human|cli|mcp|in_app_agent>\` filters to one audience (omit for all). | Public reference | \`{{cli}} reference search "onboarding" --audience cli\` |
|
|
42794
42804
|
| \`{{cli}} reference list\` | List public reference guides. | Public reference | \`{{cli}} reference list --audience cli\` |
|
|
@@ -42838,11 +42848,12 @@ The signed-in app exposes the same Skill command surface under **Skills** in the
|
|
|
42838
42848
|
| \`{{cli}} escalation list|get|resolve|reject\` | \`escalation.list\`, \`escalation.get\`, \`escalation.resolve\`, \`escalation.reject\` | Work the steward escalation queue. | Steward | \`{{cli}} escalation list --json\` |
|
|
42839
42849
|
| \`{{cli}} error list|resolve|supersede\` | \`error_log.list\`, \`error_log.resolve\`, \`error_log.supersede\` | List active, acknowledged, resolved, or superseded product error logs and let a human acknowledge, resolve, or supersede stale errors with evidence links. | Tenant | \`{{cli}} error list --resolved active --json\`; \`{{cli}} error resolve --error-log-id <id> --reason "Fixed in PR #123"\` |
|
|
42840
42850
|
| \`{{cli}} sync brief|compile|complete\` | \`sync.brief.get\`, \`sync.brief.compile\`, \`sync.run.complete\` | Compile, read, and complete a weekly Sync. | Tenant | \`{{cli}} sync brief --json\` |
|
|
42841
|
-
| \`{{cli}} runner list|status|diagnose|repair|work-orders|revoke\` | \`runner.list\`, \`runner.status\`, \`runner.diagnose\`, \`runner.repair\`, \`work_order.list\`, \`runner.revoke
|
|
42851
|
+
| \`{{cli}} runner list|status|diagnose|repair|work-orders|revoke|serve\` | \`runner.list\`, \`runner.status\`, \`runner.diagnose\`, \`runner.repair\`, \`work_order.list\`, \`runner.revoke\`, runner endpoint APIs | Inspect runners and work orders, diagnose offline runners, get repair guidance, revoke a runner, or run the headless local runner loop. | Tenant | \`{{cli}} runner diagnose --runner-id <id> --json\`; \`{{cli}} runner serve --once\` |
|
|
42842
42852
|
| \`{{cli}} notification settings|test|errors\` | \`notification.settings.get\`, \`notification.test\`, \`notification.list_errors\` | Read notification settings, send a test, and list failed deliveries with linked product error source, seat id, and run id when available. | Tenant | \`{{cli}} notification errors --limit 10 --json\` |
|
|
42843
42853
|
| \`{{cli}} integration list|readiness|status|test\` | \`integration.list\`, \`integration.readiness\`, \`integration.status\`, \`integration.test\` | List connector metadata, read the setup-readiness checklist, read one connector's health, and run the provider-specific connection test without exposing credentials. | Tenant | \`{{cli}} integration readiness --provider google --json\` |
|
|
42844
42854
|
| \`{{cli}} system health\` | \`system.health\` | Read the scoped system-health snapshot across agent runs, unresolved errors, Signals, Cascade setup, work loop, integrations, runners, notifications, and Sync Brief readiness. | Tenant, member, or seat token | \`{{cli}} system health --json\`; \`{{cli}} system health --seat <id> --json\` |
|
|
42845
|
-
| \`{{cli}}
|
|
42855
|
+
| \`{{cli}} command usage.report|usage.snapshot\` | \`usage.report\`, \`usage.snapshot\` | Read the AI-workforce ROI report (per-period agent turns, token/run cost, human-accepted value, exceptions, approvals) from immutable usage snapshots, and freeze a period's totals into a new snapshot (insert-only, idempotent). | Tenant | \`{{cli}} command usage.report --json\`; \`{{cli}} command usage.snapshot --json\` |
|
|
42856
|
+
| \`{{cli}} settings get|update|product-learning|agent-policy|rename\` | \`settings.get\`, \`settings.update\`, \`settings.product_learning.get\`, \`settings.product_learning.update\`, \`settings.agent_policy.get\`, \`settings.agent_policy.update\`, \`tenant.rename\` | Read tenant settings, update budget caps, read or update product-learning participation, read or set the company autonomy ceiling, and rename the company. Budget, product-learning, and policy updates stop at human confirmation in non-interactive CLI/MCP sessions; company rename is owner-only and human-gated. | Tenant / Tenant-admin for updates | \`{{cli}} settings product-learning get --json\`; \`{{cli}} settings agent-policy get --json\`; \`{{cli}} settings rename --company "Acme Operations"\` |
|
|
42846
42857
|
| \`{{cli}} member invite|update|remove\` | \`member.invite\`, \`member.update\`, \`member.remove\` | Manage tenant members. | Tenant | \`{{cli}} member invite --email ops@example.com --role member\` |
|
|
42847
42858
|
| \`{{cli}} agent templates|create|setup|tools|dry-run|go-live|status|run-now|fleet-digest|get-run|show\` | \`agent_template.list\`, \`agent.create_from_template\`, \`agent.create_custom\`, \`agent_setup.get\`, \`agent_setup.update\`, \`agent.configure_tools\`, \`agent.run_dry_run\`, \`agent.go_live\`, \`agent.status\`, \`agent.run_now\`, \`agent.fleet_digest\`, \`agent.get_run\`, \`agent.show_markdown\` | Run the full agent setup and operation flow: list templates, create a draft from a template or guided custom answers (with \`--model\` and \`--effort\`), read or answer setup state, connect or decline tools, dry-run, go live, run on demand, capture the fleet-health digest, read one run's transcript/error diagnostics, and show a markdown readout. Human CLI dry-runs print the rehearsal transcript and, when present, the per-tool preview labels (\`Would run\`, \`Blocked\`, \`Escalated\`) before go-live. Create and go-live stop at human gates; the dry-run is ungated by human approval but requires a signed manifest first. | Tenant and seat | \`{{cli}} agent fleet-digest --json\` |
|
|
42848
42859
|
| \`{{cli}} tools list\` | \`tool.catalog\` | List the discoverable tool catalog the builder reads (id, scope tiers, credential requirement, access policy, and execution-boundary guidance). | Tenant | \`{{cli}} tools list --json\` |
|
|
@@ -42853,6 +42864,8 @@ The signed-in app exposes the same Skill command surface under **Skills** in the
|
|
|
42853
42864
|
| \`{{cli}} compass show\` | \`compass.show_markdown\` | Render the current Compass as a clean markdown card for review. | Tenant | \`{{cli}} compass show --markdown\` |
|
|
42854
42865
|
| \`{{cli}} charter show\` | \`charter.show_markdown\` | Render a seat's Charter as a clean markdown card for review. | Tenant | \`{{cli}} charter show --seat-id <id> --markdown\` |
|
|
42855
42866
|
| \`{{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\` |
|
|
42867
|
+
| \`{{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\` |
|
|
42868
|
+
| \`{{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\` |
|
|
42856
42869
|
|
|
42857
42870
|
Skills wrapper help:
|
|
42858
42871
|
|
|
@@ -42935,6 +42948,7 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
42935
42948
|
| \`rost_rename_seat\` | \`seat.rename\` | Rename a seat. | Seat or tenant-admin | Call with \`seat_id\` and \`name\`. |
|
|
42936
42949
|
| \`rost_reparent_seat\` | \`seat.reparent\` | Move a seat under a new parent. | Seat or tenant-admin | Call with \`seat_id\` and \`parent_seat_id\`. |
|
|
42937
42950
|
| \`rost_set_seat_type\` | \`seat.set_type\` | Set a seat type. | Seat or tenant-admin | Call with \`seat_id\` and \`seat_type\`. |
|
|
42951
|
+
| \`rost_preview_seat_decommission\` | \`seat.decommission_preview\` | Preview retiring a seat: affected occupancies, agents, Charters, MCP tokens, credentials, work orders, and schedules. No mutation. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`; no confirmation. |
|
|
42938
42952
|
| \`rost_decommission_seat\` | \`seat.decommission\` | Retire a seat: end occupancies, archive the Charter, revoke tokens/credentials, cancel schedules, tombstone event. No-orphan guarded. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`; expect confirmation. |
|
|
42939
42953
|
| \`rost_draft_charter\` | \`charter.draft\` | Create or fetch a draft Charter. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`. |
|
|
42940
42954
|
| \`rost_draft_all_charters\` | \`charter.draft_all\` | Draft Charters for every eligible seat. | Tenant | Call after initial graph creation. |
|
|
@@ -42977,6 +42991,9 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
42977
42991
|
| \`rost_get_agent_deliverable\` | \`deliverable.get\` | Read one durable agent deliverable by id for a seat. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>","deliverable_id":"<id>"}\`. |
|
|
42978
42992
|
| \`rost_create_agent_deliverable\` | \`deliverable.create\` | Create a scrubbed durable work output for the acting seat. | Seat | Call with title, kind, summary/content, and optional safe links. |
|
|
42979
42993
|
| \`rost_attach_agent_deliverable\` | \`deliverable.attach\` | Attach a scrubbed deliverable to a source run, task, or work order after server-side seat validation. | Seat | Call with title, kind, and the source ids that belong to the acting seat. |
|
|
42994
|
+
| \`rost_accept_deliverable_value\` | \`deliverable.accept\` | Record a human-confirmed accepted value (USD) on a deliverable; owner-only and human-gated. Humans decide \u2014 agents cannot self-accept. Re-accepting records a correction as a new event. | Tenant-admin | Call with \`{"deliverable_id":"<id>","impact_value_usd":<number>}\`; expect human confirmation. |
|
|
42995
|
+
| \`rost_ai_workforce_roi_report\` | \`usage.report\` | Read the AI-workforce ROI report \u2014 per-period agent turns, token/run cost, human-accepted value, exceptions, and approvals \u2014 from immutable usage snapshots. | Tenant | Call with \`{}\` or \`{"limit":<n>}\`. |
|
|
42996
|
+
| \`rost_capture_usage_period_snapshot\` | \`usage.snapshot\` | Freeze the current (or a given) period's usage and accepted-value totals into an immutable snapshot; insert-only and idempotent. | Tenant | Call with \`{}\` or \`{"period":"YYYY-MM-DD"}\`. |
|
|
42980
42997
|
| \`rost_list_agent_templates\` | \`agent_template.list\` | List stock agent templates and metadata. | Tenant | Call with \`{}\`. |
|
|
42981
42998
|
| \`rost_create_agent_from_template\` | \`agent.create_from_template\` | Create a draft stock agent and draft Charter from a template (draft-only; occupancy needs a human steward). | Tenant | Call with \`seat_id\` and \`template_slug\`; expect human confirmation. |
|
|
42982
42999
|
| \`rost_start_agent_setup\` | \`agent_setup.start\` | Start an agent setup draft for template, custom, or existing mode. | Tenant | Call with \`mode\` and seat placement. |
|
|
@@ -43031,9 +43048,12 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
43031
43048
|
| \`rost_create_cascade_goal\` | \`goal.create\` | Create a cycle goal under an objective. | Tenant | Call with cycle, seat, parent, title, definition of done. |
|
|
43032
43049
|
| \`rost_update_cascade_goal\` | \`goal.update\` | Update a goal's title or definition of done. | Tenant | Call with \`goal_id\` and the changed fields. |
|
|
43033
43050
|
| \`rost_set_cascade_goal_status\` | \`goal.set_status\` | Set a goal's status (on/off/done). | Seat or tenant-admin | Seats may set only their own goals. |
|
|
43051
|
+
| \`rost_set_cascade_goal_progress\` | \`goal.set_progress\` | Report a goal's quantified progress (0-100). An agent's progress is a proposal a human approves before the goal moves. | Seat or tenant-admin | Seats set only their own goals; expect confirmation. |
|
|
43052
|
+
| \`rost_list_at_risk_cascade_goals\` | \`goal.list_at_risk\` | List goals projected off pace (at-risk or projected-miss) with days behind pace. Read-only; status-only goals excluded. | Tenant | Call with \`{}\`. |
|
|
43034
43053
|
| \`rost_reparent_cascade_goal\` | \`goal.reparent\` | Move a goal under a new parent. | Tenant | Authority change; expect confirmation. |
|
|
43035
43054
|
| \`rost_drop_cascade_goal\` | \`goal.drop\` | Drop (retire) a goal, retained for audit. | Tenant | Expect confirmation. |
|
|
43036
43055
|
| \`rost_list_friction_issues\` | \`friction.list\` | List Friction issues ranked by impact and severity. | Seat or tenant-admin | Call with \`{}\` or \`{"status":"active"}\`. |
|
|
43056
|
+
| \`rost_assist_friction_issue\` | \`friction.assist\` | Advisory IDS assist: the most-similar prior resolved issues with their root causes and decisions, a recurring-pattern flag, and recommended options. Read-only \u2014 it never resolves the issue. | Tenant | Call with \`{"issue_id":"<id>"}\`. |
|
|
43037
43057
|
| \`rost_update_friction_issue_status\` | \`friction.update_status\` | Move a non-terminal issue between open and diagnosing. | Seat or tenant-admin | Call with \`issue_id\` and \`status\`. |
|
|
43038
43058
|
| \`rost_resolve_friction_issue\` | \`friction.resolve\` | Resolve an issue with a root cause and remediation task. | Tenant | Human decision; expect confirmation. |
|
|
43039
43059
|
| \`rost_link_task_to_friction_issue\` | \`friction.link_task\` | Attach an existing task as an issue's action task. | Seat or tenant-admin | Call with \`issue_id\` and \`task_id\`. |
|
|
@@ -43045,6 +43065,8 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
43045
43065
|
| \`rost_assign_sync_follow_up\` | \`sync.item.assign\` | Create a follow-up task from a Sync agenda item. | Tenant | Call with brief, owner seat, title, description. |
|
|
43046
43066
|
| \`rost_list_escalations\` | \`escalation.list\` | List Steward queue escalations (own steward chain for humans, own seat for agents). | Seat or tenant-admin | Call with \`{}\` or \`{"include_decided":true}\`. |
|
|
43047
43067
|
| \`rost_get_escalation\` | \`escalation.get\` | Read one escalation's evidence, recommendation, and decision state. | Seat or tenant-admin | Call with \`{"id":"<escalation-id>"}\`. Resolve/reject are human-only and not exposed over MCP. |
|
|
43068
|
+
| \`rost_check_compass_alignment\` | \`compass.alignment\` | Advisory drift check: scores whether cycle goals still ladder to the active vision and flags orphan/contradictory goals. Read-only \u2014 it never edits the Compass or any goal. | Tenant | Call with \`{}\`. |
|
|
43069
|
+
| \`rost_team_health_score\` | \`team.health_score\` | Read the single rolled-up 0-100 team-health score (latest month) with its band and label. | Tenant | Call with \`{}\`. |
|
|
43048
43070
|
| \`rost_show_compass_as_markdown\` | \`compass.show_markdown\` | Render the current Compass and its open gaps as a clean markdown card for review. | Tenant | Call with \`{}\`. |
|
|
43049
43071
|
| \`rost_show_charter_as_markdown\` | \`charter.show_markdown\` | Render a seat's active or latest Charter as a clean markdown card for review. | Tenant | Call with \`{"seat_id":"<seat-id>"}\`. |
|
|
43050
43072
|
| \`rost_show_agent_setup_as_markdown\` | \`agent.show_markdown\` | Render a seat's agent setup, model, steward, tools, and Charter as a clean markdown card for review. | Tenant | Call with \`{"seat_id":"<seat-id>"}\`. |
|
|
@@ -43532,7 +43554,7 @@ Retrieve the narrowest relevant guide before making a setup recommendation. Pref
|
|
|
43532
43554
|
order: 60,
|
|
43533
43555
|
title: "Cascade guide",
|
|
43534
43556
|
summary: "How to connect company goals to seat-level work without turning {{brand}} into a project-management tool.",
|
|
43535
|
-
version: "2026-06-
|
|
43557
|
+
version: "2026-06-28.1",
|
|
43536
43558
|
public: true,
|
|
43537
43559
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
43538
43560
|
stages: ["operating_rhythm"],
|
|
@@ -43544,8 +43566,11 @@ Retrieve the narrowest relevant guide before making a setup recommendation. Pref
|
|
|
43544
43566
|
"goal.create",
|
|
43545
43567
|
"goal.update",
|
|
43546
43568
|
"goal.set_status",
|
|
43569
|
+
"goal.set_progress",
|
|
43570
|
+
"goal.list_at_risk",
|
|
43547
43571
|
"goal.reparent",
|
|
43548
43572
|
"goal.drop",
|
|
43573
|
+
"compass.alignment",
|
|
43549
43574
|
"confirmation.approve"
|
|
43550
43575
|
],
|
|
43551
43576
|
legal: {
|
|
@@ -43587,6 +43612,10 @@ Cascade warnings are advisory, not blockers. They point to setup that should be
|
|
|
43587
43612
|
|
|
43588
43613
|
On \`/cascade\`, the screen renders the full goal depth, not just one or two levels. Off-track descendant branches stay open so the operator can see why a parent rolled up to risk.
|
|
43589
43614
|
|
|
43615
|
+
## Goal progress and at-risk goals
|
|
43616
|
+
|
|
43617
|
+
A goal can carry a quantified progress (0-100) distinct from its on/off/done status. Report it with \`goal.set_progress\`; when an agent reports progress it lands as a proposal a human approves before the goal moves. \`goal.list_at_risk\` projects which goals are off pace by comparing progress against the elapsed fraction of the cycle window (deterministic date math, no forecast model). Off-pace goals surface on \`/cascade\`, on the owner home, in the weekly Sync Brief, and as a weekly owner alert. Status-only goals (no progress recorded) are simply excluded from the projection.
|
|
43618
|
+
|
|
43590
43619
|
On human and function seat pages, goal visibility includes both direct goals and descendant seat goals from the Responsibility Graph subtree, so a manager can review team progress without double-owning the agent's work.
|
|
43591
43620
|
|
|
43592
43621
|
## What does not belong
|
|
@@ -43689,6 +43718,7 @@ Agents may record readings when the Charter allows it. Agent-reported readings s
|
|
|
43689
43718
|
"compass.answer_gap",
|
|
43690
43719
|
"friction.file_issue",
|
|
43691
43720
|
"friction.list",
|
|
43721
|
+
"friction.assist",
|
|
43692
43722
|
"friction.update_status",
|
|
43693
43723
|
"friction.resolve",
|
|
43694
43724
|
"friction.link_task",
|
|
@@ -43752,7 +43782,7 @@ Resolving Friction should produce one of four outcomes: a decision, a task, a Ch
|
|
|
43752
43782
|
order: 70,
|
|
43753
43783
|
title: "Steward queue guide",
|
|
43754
43784
|
summary: "How Stewards review escalations, approve agent boundaries, and keep agents accountable.",
|
|
43755
|
-
version: "2026-06-27.
|
|
43785
|
+
version: "2026-06-27.2",
|
|
43756
43786
|
public: true,
|
|
43757
43787
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
43758
43788
|
stages: ["staffing", "operating_rhythm"],
|
|
@@ -43795,6 +43825,10 @@ When nothing is waiting, the Steward page still proves the governance loop. It s
|
|
|
43795
43825
|
|
|
43796
43826
|
An escalation reaches you the same way no matter how the agent raised it \u2014 in a chat or CLI session, or on its own scheduled cloud run. When the agent stops at a boundary it opens the queue item and sends a notification to the accountable human along the steward chain, preferring a connected Slack channel and falling back to email. If no human occupies the agent's seat, the chain walks up to the next Steward. Delivery is idempotent: a retried run never notifies you twice for the same escalation, and the notification carries only summarized, redacted evidence \u2014 never secret material.
|
|
43797
43827
|
|
|
43828
|
+
## Where notifications land
|
|
43829
|
+
|
|
43830
|
+
Every notification sent to you \u2014 escalations, approval requests, sync briefs, and your daily digest \u2014 also appears in your in-app Inbox, with unread state you can clear. A Slack or email delivery that fails is retried automatically on a bounded schedule; once it can no longer be delivered it stays visible in the Inbox rather than being lost. A once-a-day digest rolls up the day's deliverables, open approvals, and exceptions into a single message, so a quiet day stays quiet and a busy one is summarized in one place.
|
|
43831
|
+
|
|
43798
43832
|
## Work the queue from CLI or MCP
|
|
43799
43833
|
|
|
43800
43834
|
The Steward reads the queue from any surface but decides as a human.
|
|
@@ -45947,12 +45981,12 @@ function resolveModelConfig(model, effort) {
|
|
|
45947
45981
|
...resolvedEffort ? { effort: resolvedEffort } : {}
|
|
45948
45982
|
};
|
|
45949
45983
|
}
|
|
45950
|
-
function usageWithSchemaFooter(
|
|
45951
|
-
return `${
|
|
45984
|
+
function usageWithSchemaFooter(usage2, bin) {
|
|
45985
|
+
return `${usage2}
|
|
45952
45986
|
discover a command's exact input with: ${bin} command schema <id>`;
|
|
45953
45987
|
}
|
|
45954
|
-
async function dispatch(context, group, args, actions,
|
|
45955
|
-
const usageText = usageWithSchemaFooter(
|
|
45988
|
+
async function dispatch(context, group, args, actions, usage2) {
|
|
45989
|
+
const usageText = usageWithSchemaFooter(usage2, context.binName);
|
|
45956
45990
|
const action = args[0];
|
|
45957
45991
|
if (action === "--help" || action === "-h" || action === "help") {
|
|
45958
45992
|
context.io.stdout.write(`${usageText}
|
|
@@ -45978,12 +46012,137 @@ ${usageText}
|
|
|
45978
46012
|
}
|
|
45979
46013
|
}
|
|
45980
46014
|
function execute(context, parsed, commandId, body, format) {
|
|
45981
|
-
const
|
|
46015
|
+
const autoConfirm = parsed.flags.has("yes") || parsed.flags.has("y");
|
|
46016
|
+
const options = {
|
|
46017
|
+
...parsed.seat === void 0 ? {} : { targetSeatId: parsed.seat },
|
|
46018
|
+
...autoConfirm ? { autoConfirm: true } : {}
|
|
46019
|
+
};
|
|
45982
46020
|
if (parsed.json) {
|
|
45983
46021
|
return context.run(context.client, commandId, body, void 0, options);
|
|
45984
46022
|
}
|
|
45985
46023
|
return context.run(context.client, commandId, body, format, options);
|
|
45986
46024
|
}
|
|
46025
|
+
var graphWrapper = (context, args) => dispatch(context, "graph", args, {
|
|
46026
|
+
show: (ctx, rest) => {
|
|
46027
|
+
const parsed = parseFlags(rest);
|
|
46028
|
+
return execute(ctx, parsed, "graph.get", {}, formatGraph);
|
|
46029
|
+
},
|
|
46030
|
+
get: (ctx, rest) => {
|
|
46031
|
+
const parsed = parseFlags(rest);
|
|
46032
|
+
return execute(ctx, parsed, "graph.get", {}, formatGraph);
|
|
46033
|
+
}
|
|
46034
|
+
}, graphUsage(context.binName));
|
|
46035
|
+
function formatGraph(output) {
|
|
46036
|
+
const record2 = asRecord(output);
|
|
46037
|
+
const nodes = asArray(record2.nodes);
|
|
46038
|
+
if (nodes.length === 0) {
|
|
46039
|
+
return "No seats in the Responsibility Graph.";
|
|
46040
|
+
}
|
|
46041
|
+
const lines = [
|
|
46042
|
+
`root_seat_id=${field(record2, "root_seat_id")}`,
|
|
46043
|
+
"seat_id parent_seat_id type status name"
|
|
46044
|
+
];
|
|
46045
|
+
for (const node of nodes) {
|
|
46046
|
+
const row = asRecord(node);
|
|
46047
|
+
lines.push(`${field(row, "seat_id")} ${field(row, "parent_seat_id")} ${field(row, "seat_type")} ${field(row, "status")} ${field(row, "name")}`);
|
|
46048
|
+
}
|
|
46049
|
+
return lines.join("\n");
|
|
46050
|
+
}
|
|
46051
|
+
function graphUsage(bin) {
|
|
46052
|
+
return `Usage: ${bin} graph show|get [--json]
|
|
46053
|
+
${bin} graph show`;
|
|
46054
|
+
}
|
|
46055
|
+
var seatWrapper = (context, args) => dispatch(context, "seat", args, {
|
|
46056
|
+
list: (ctx, rest) => {
|
|
46057
|
+
const parsed = parseFlags(rest);
|
|
46058
|
+
return execute(ctx, parsed, "graph.get", {}, formatSeatList);
|
|
46059
|
+
},
|
|
46060
|
+
get: (ctx, rest) => {
|
|
46061
|
+
const parsed = parseFlags(rest);
|
|
46062
|
+
const seatId = requireValue2(parsed, "seat-id");
|
|
46063
|
+
return execute(ctx, parsed, "seat.get", { seat_id: seatId }, formatSeatDetail);
|
|
46064
|
+
},
|
|
46065
|
+
create: (ctx, rest) => {
|
|
46066
|
+
const parsed = parseFlags(rest);
|
|
46067
|
+
const body = withOptional({
|
|
46068
|
+
name: requireValue2(parsed, "name"),
|
|
46069
|
+
seat_type: requireValue2(parsed, "type")
|
|
46070
|
+
}, {
|
|
46071
|
+
parent_seat_id: optionalValue(parsed, "parent-seat-id")
|
|
46072
|
+
});
|
|
46073
|
+
return execute(ctx, parsed, "seat.create", body, formatSeatMutation);
|
|
46074
|
+
},
|
|
46075
|
+
rename: (ctx, rest) => {
|
|
46076
|
+
const parsed = parseFlags(rest);
|
|
46077
|
+
return execute(ctx, parsed, "seat.rename", {
|
|
46078
|
+
seat_id: requireValue2(parsed, "seat-id"),
|
|
46079
|
+
name: requireValue2(parsed, "name")
|
|
46080
|
+
}, formatSeatMutation);
|
|
46081
|
+
},
|
|
46082
|
+
reparent: (ctx, rest) => {
|
|
46083
|
+
const parsed = parseFlags(rest);
|
|
46084
|
+
return execute(ctx, parsed, "seat.reparent", {
|
|
46085
|
+
seat_id: requireValue2(parsed, "seat-id"),
|
|
46086
|
+
new_parent_seat_id: requireValue2(parsed, "parent-seat-id")
|
|
46087
|
+
}, formatSeatMutation);
|
|
46088
|
+
},
|
|
46089
|
+
decommission: (ctx, rest) => {
|
|
46090
|
+
const parsed = parseFlags(rest, /* @__PURE__ */ new Set(["dry-run", "preview"]));
|
|
46091
|
+
if (parsed.flags.has("dry-run") || parsed.flags.has("preview")) {
|
|
46092
|
+
return execute(ctx, parsed, "seat.decommission_preview", {
|
|
46093
|
+
seat_id: requireValue2(parsed, "seat-id")
|
|
46094
|
+
}, formatSeatDecommissionPreview);
|
|
46095
|
+
}
|
|
46096
|
+
return execute(ctx, parsed, "seat.decommission", {
|
|
46097
|
+
seat_id: requireValue2(parsed, "seat-id")
|
|
46098
|
+
}, formatSeatMutation);
|
|
46099
|
+
}
|
|
46100
|
+
}, seatUsage(context.binName));
|
|
46101
|
+
function formatSeatList(output) {
|
|
46102
|
+
const nodes = asArray(asRecord(output).nodes);
|
|
46103
|
+
if (nodes.length === 0) {
|
|
46104
|
+
return "No seats.";
|
|
46105
|
+
}
|
|
46106
|
+
return nodes.map((node) => {
|
|
46107
|
+
const row = asRecord(node);
|
|
46108
|
+
return `seat_id=${field(row, "seat_id")} parent_seat_id=${field(row, "parent_seat_id")} type=${field(row, "seat_type")} status=${field(row, "status")} name=${field(row, "name")}`;
|
|
46109
|
+
}).join("\n");
|
|
46110
|
+
}
|
|
46111
|
+
function formatSeatDetail(output) {
|
|
46112
|
+
const record2 = asRecord(output);
|
|
46113
|
+
const counts = asRecord(record2.counts);
|
|
46114
|
+
return [
|
|
46115
|
+
`seat_id=${field(record2, "seat_id")} name=${field(record2, "name")} type=${field(record2, "seat_type")} status=${field(record2, "status")}`,
|
|
46116
|
+
`parent_seat_id=${field(record2, "parent_seat_id")} active_charter_version_id=${field(record2, "active_charter_version_id")} draft_charter_version_id=${field(record2, "draft_charter_version_id")}`,
|
|
46117
|
+
`agent_status=${field(record2, "agent_status")} agent_lane=${field(record2, "agent_lane")}`,
|
|
46118
|
+
`counts: open_tasks=${field(counts, "open_tasks")} owned_goals=${field(counts, "owned_goals")} active_measurables=${field(counts, "active_measurables")} open_issues=${field(counts, "open_issues")}`
|
|
46119
|
+
].join("\n");
|
|
46120
|
+
}
|
|
46121
|
+
function formatSeatMutation(output) {
|
|
46122
|
+
const record2 = asRecord(output);
|
|
46123
|
+
return `seat_id=${field(record2, "seat_id")}`;
|
|
46124
|
+
}
|
|
46125
|
+
function formatSeatDecommissionPreview(output) {
|
|
46126
|
+
const record2 = asRecord(output);
|
|
46127
|
+
const effects = asArray(record2.effects).map((effect) => `- ${String(effect)}`);
|
|
46128
|
+
return [
|
|
46129
|
+
`seat_id=${field(record2, "seat_id")} name=${field(record2, "seat_name")} status=${field(record2, "previous_status")}`,
|
|
46130
|
+
`active_occupancies=${field(record2, "active_occupancy_count")} active_agents=${field(record2, "active_agent_ids")}`,
|
|
46131
|
+
`active_charters=${field(record2, "active_charter_count")} mcp_tokens=${field(record2, "active_mcp_token_count")} credentials=${field(record2, "active_credential_count")}`,
|
|
46132
|
+
`open_work_orders=${field(record2, "open_work_order_count")} schedules=${field(record2, "schedule_count")} no_orphan_steward_guard=${field(record2, "no_orphan_steward_guard")}`,
|
|
46133
|
+
"effects:",
|
|
46134
|
+
...effects
|
|
46135
|
+
].join("\n");
|
|
46136
|
+
}
|
|
46137
|
+
function seatUsage(bin) {
|
|
46138
|
+
return `Usage: ${bin} seat list|get|create|rename|reparent|decommission [--json] [--yes]
|
|
46139
|
+
${bin} seat list
|
|
46140
|
+
${bin} seat get --seat-id <id>
|
|
46141
|
+
${bin} seat create --name <text> --type human|agent|hybrid [--parent-seat-id <id>]
|
|
46142
|
+
${bin} seat rename --seat-id <id> --name <text>
|
|
46143
|
+
${bin} seat reparent --seat-id <id> --parent-seat-id <id> [--yes]
|
|
46144
|
+
${bin} seat decommission --seat-id <id> [--dry-run] [--yes]`;
|
|
46145
|
+
}
|
|
45987
46146
|
var taskWrapper = (context, args) => dispatch(context, "task", args, {
|
|
45988
46147
|
list: (ctx, rest) => {
|
|
45989
46148
|
const parsed = parseFlags(rest);
|
|
@@ -46496,13 +46655,14 @@ var runnerWrapper = (context, args) => dispatch(context, "runner", args, {
|
|
|
46496
46655
|
}
|
|
46497
46656
|
}, runnerUsage(context.binName));
|
|
46498
46657
|
function runnerUsage(bin) {
|
|
46499
|
-
return `Usage: ${bin} runner list|status|diagnose|repair|work-orders|revoke [--json]
|
|
46658
|
+
return `Usage: ${bin} runner list|status|diagnose|repair|work-orders|revoke|serve [--json]
|
|
46500
46659
|
${bin} runner list [--include-revoked]
|
|
46501
46660
|
${bin} runner status --runner-id <id>
|
|
46502
46661
|
${bin} runner diagnose --runner-id <id>
|
|
46503
46662
|
${bin} runner repair --runner-id <id> [--issue restart|re_pair|revoke_stale|missing_cli_runtime]
|
|
46504
46663
|
${bin} runner work-orders [--status <s>] [--agent-id <id>] [--runner-id <id>] [--limit <n>]
|
|
46505
|
-
${bin} runner revoke --runner-id <id
|
|
46664
|
+
${bin} runner revoke --runner-id <id>
|
|
46665
|
+
${bin} runner serve [--name <text>] [--state-file <path>] [--heartbeat-ms <n>] [--once] [--execute]`;
|
|
46506
46666
|
}
|
|
46507
46667
|
var notificationWrapper = (context, args) => dispatch(context, "notification", args, {
|
|
46508
46668
|
settings: (ctx, rest) => {
|
|
@@ -47487,7 +47647,9 @@ var OPERATION_GROUPS = [
|
|
|
47487
47647
|
"compass",
|
|
47488
47648
|
"charter",
|
|
47489
47649
|
"deliverable",
|
|
47490
|
-
"system"
|
|
47650
|
+
"system",
|
|
47651
|
+
"graph",
|
|
47652
|
+
"seat"
|
|
47491
47653
|
];
|
|
47492
47654
|
var wrappers = {
|
|
47493
47655
|
task: taskWrapper,
|
|
@@ -47510,7 +47672,9 @@ var wrappers = {
|
|
|
47510
47672
|
compass: compassWrapper,
|
|
47511
47673
|
charter: charterWrapper,
|
|
47512
47674
|
deliverable: deliverableWrapper,
|
|
47513
|
-
system: systemWrapper
|
|
47675
|
+
system: systemWrapper,
|
|
47676
|
+
graph: graphWrapper,
|
|
47677
|
+
seat: seatWrapper
|
|
47514
47678
|
};
|
|
47515
47679
|
function isOperationGroup(value) {
|
|
47516
47680
|
return value !== void 0 && OPERATION_GROUPS.includes(value);
|
|
@@ -47536,7 +47700,9 @@ var groupUsageBuilders = {
|
|
|
47536
47700
|
compass: compassUsage,
|
|
47537
47701
|
charter: charterUsage,
|
|
47538
47702
|
deliverable: deliverableUsage,
|
|
47539
|
-
system: systemUsage
|
|
47703
|
+
system: systemUsage,
|
|
47704
|
+
graph: graphUsage,
|
|
47705
|
+
seat: seatUsage
|
|
47540
47706
|
};
|
|
47541
47707
|
function operationGroupUsage(group, bin) {
|
|
47542
47708
|
return usageWithSchemaFooter(groupUsageBuilders[group](bin), bin);
|
|
@@ -47559,9 +47725,9 @@ function operationUsageLines(bin) {
|
|
|
47559
47725
|
`${bin} escalation list|get|resolve|reject`,
|
|
47560
47726
|
`${bin} error list|resolve|supersede`,
|
|
47561
47727
|
`${bin} sync brief|compile|complete`,
|
|
47562
|
-
`${bin} runner list|status|diagnose|repair|work-orders|revoke`,
|
|
47728
|
+
`${bin} runner list|status|diagnose|repair|work-orders|revoke|serve`,
|
|
47563
47729
|
`${bin} notification settings|test|errors`,
|
|
47564
|
-
`${bin} settings get|update|product-learning|rename`,
|
|
47730
|
+
`${bin} settings get|update|product-learning|agent-policy|rename`,
|
|
47565
47731
|
`${bin} member invite|update|remove`,
|
|
47566
47732
|
`${bin} agent templates|create|setup|tools|dry-run|go-live|status|run-now|fleet-digest|get-run|show`,
|
|
47567
47733
|
`${bin} tools list`,
|
|
@@ -47569,7 +47735,9 @@ function operationUsageLines(bin) {
|
|
|
47569
47735
|
`${bin} model list`,
|
|
47570
47736
|
`${bin} compass show`,
|
|
47571
47737
|
`${bin} charter show`,
|
|
47572
|
-
`${bin} deliverable list|get|create|attach
|
|
47738
|
+
`${bin} deliverable list|get|create|attach`,
|
|
47739
|
+
`${bin} graph show`,
|
|
47740
|
+
`${bin} seat list|get|create|rename|reparent|decommission`
|
|
47573
47741
|
];
|
|
47574
47742
|
}
|
|
47575
47743
|
|
|
@@ -48064,6 +48232,424 @@ function pendingConfirmationFromError(error51) {
|
|
|
48064
48232
|
return { confirmationId, commandId };
|
|
48065
48233
|
}
|
|
48066
48234
|
|
|
48235
|
+
// src/doctor.ts
|
|
48236
|
+
import { execFile as execFileCallback2 } from "node:child_process";
|
|
48237
|
+
import { access, readFile as readFile3 } from "node:fs/promises";
|
|
48238
|
+
import { delimiter } from "node:path";
|
|
48239
|
+
import { promisify as promisify3 } from "node:util";
|
|
48240
|
+
var execFile3 = promisify3(execFileCallback2);
|
|
48241
|
+
async function runDoctor(options) {
|
|
48242
|
+
const env = options.env ?? process.env;
|
|
48243
|
+
const store = options.store ?? createTokenStore();
|
|
48244
|
+
const lines = [`${cliBrand.name} CLI doctor`];
|
|
48245
|
+
const config2 = loadConfig(env);
|
|
48246
|
+
lines.push(`app_url: ${config2.appUrl}`);
|
|
48247
|
+
lines.push(`supabase_url: ${config2.supabaseUrl}`);
|
|
48248
|
+
const currentVersion = await readCurrentVersion2();
|
|
48249
|
+
lines.push(`version: ${currentVersion ?? "unknown"}`);
|
|
48250
|
+
const pathStatus = await checkPath(env);
|
|
48251
|
+
lines.push(pathStatus);
|
|
48252
|
+
try {
|
|
48253
|
+
const session = await store.read();
|
|
48254
|
+
lines.push(`session: ${session ? `present (${store.describe()})` : `missing - run ${cliBrand.binName} login --device`}`);
|
|
48255
|
+
} catch (error51) {
|
|
48256
|
+
lines.push(`session: unreadable - ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}`);
|
|
48257
|
+
}
|
|
48258
|
+
const [claude, codex] = await Promise.all([probeCli("claude"), probeCli("codex")]);
|
|
48259
|
+
lines.push(`claude: ${claude}`);
|
|
48260
|
+
lines.push(`codex: ${codex}`);
|
|
48261
|
+
const latest = await fetchLatestVersion2(cliBrand.packageName, env);
|
|
48262
|
+
if (currentVersion && latest && isSemverBehind2(currentVersion, latest)) {
|
|
48263
|
+
lines.push(`update: ${currentVersion} -> ${latest}; run npm i -g ${cliBrand.packageName}@latest`);
|
|
48264
|
+
} else if (latest) {
|
|
48265
|
+
lines.push(`update: current (${latest})`);
|
|
48266
|
+
} else {
|
|
48267
|
+
lines.push("update: skipped or unavailable");
|
|
48268
|
+
}
|
|
48269
|
+
options.io.stdout.write(`${lines.join("\n")}
|
|
48270
|
+
`);
|
|
48271
|
+
return 0;
|
|
48272
|
+
}
|
|
48273
|
+
async function checkPath(env) {
|
|
48274
|
+
const pathValue = env.PATH ?? "";
|
|
48275
|
+
const candidates = pathValue.split(delimiter).filter(Boolean).map((entry) => `${entry}/${cliBrand.binName}`);
|
|
48276
|
+
for (const candidate of candidates) {
|
|
48277
|
+
try {
|
|
48278
|
+
await access(candidate);
|
|
48279
|
+
return `path: found ${candidate}`;
|
|
48280
|
+
} catch {
|
|
48281
|
+
continue;
|
|
48282
|
+
}
|
|
48283
|
+
}
|
|
48284
|
+
return `path: ${cliBrand.binName} not found on PATH - use npx ${cliBrand.packageName}@latest or add your npm global bin directory`;
|
|
48285
|
+
}
|
|
48286
|
+
async function probeCli(command) {
|
|
48287
|
+
try {
|
|
48288
|
+
const { stdout, stderr } = await execFile3(command, ["--version"], { timeout: 1500 });
|
|
48289
|
+
const version4 = (stdout || stderr).trim().split("\n")[0]?.trim();
|
|
48290
|
+
return version4 ? `installed (${version4})` : "installed";
|
|
48291
|
+
} catch {
|
|
48292
|
+
return "not found";
|
|
48293
|
+
}
|
|
48294
|
+
}
|
|
48295
|
+
async function readCurrentVersion2() {
|
|
48296
|
+
try {
|
|
48297
|
+
const url2 = new URL("../package.json", import.meta.url);
|
|
48298
|
+
const parsed = JSON.parse(await readFile3(url2, "utf8"));
|
|
48299
|
+
return typeof parsed.version === "string" ? parsed.version : null;
|
|
48300
|
+
} catch {
|
|
48301
|
+
return null;
|
|
48302
|
+
}
|
|
48303
|
+
}
|
|
48304
|
+
async function fetchLatestVersion2(packageName, env) {
|
|
48305
|
+
if (env.CI || env.VITEST || env.CLI_SKIP_UPDATE_CHECK === "1" || env[`${cliBrand.envPrefix}_CLI_NO_UPDATE_CHECK`] === "1") {
|
|
48306
|
+
return null;
|
|
48307
|
+
}
|
|
48308
|
+
const controller = new AbortController();
|
|
48309
|
+
const timeout = setTimeout(() => controller.abort(), 750);
|
|
48310
|
+
try {
|
|
48311
|
+
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`, {
|
|
48312
|
+
headers: { accept: "application/json" },
|
|
48313
|
+
signal: controller.signal
|
|
48314
|
+
});
|
|
48315
|
+
if (!response.ok) {
|
|
48316
|
+
return null;
|
|
48317
|
+
}
|
|
48318
|
+
const body = await response.json();
|
|
48319
|
+
return typeof body.version === "string" ? body.version : null;
|
|
48320
|
+
} catch {
|
|
48321
|
+
return null;
|
|
48322
|
+
} finally {
|
|
48323
|
+
clearTimeout(timeout);
|
|
48324
|
+
}
|
|
48325
|
+
}
|
|
48326
|
+
function isSemverBehind2(currentVersion, latestVersion) {
|
|
48327
|
+
const current = parseSemver2(currentVersion);
|
|
48328
|
+
const latest = parseSemver2(latestVersion);
|
|
48329
|
+
if (!current || !latest) {
|
|
48330
|
+
return currentVersion !== latestVersion;
|
|
48331
|
+
}
|
|
48332
|
+
if (current.major !== latest.major) {
|
|
48333
|
+
return current.major < latest.major;
|
|
48334
|
+
}
|
|
48335
|
+
if (current.minor !== latest.minor) {
|
|
48336
|
+
return current.minor < latest.minor;
|
|
48337
|
+
}
|
|
48338
|
+
return current.patch < latest.patch;
|
|
48339
|
+
}
|
|
48340
|
+
function parseSemver2(value) {
|
|
48341
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(value);
|
|
48342
|
+
if (!match) {
|
|
48343
|
+
return null;
|
|
48344
|
+
}
|
|
48345
|
+
const [, major, minor, patch] = match;
|
|
48346
|
+
if (major === void 0 || minor === void 0 || patch === void 0) {
|
|
48347
|
+
return null;
|
|
48348
|
+
}
|
|
48349
|
+
return {
|
|
48350
|
+
major: Number.parseInt(major, 10),
|
|
48351
|
+
minor: Number.parseInt(minor, 10),
|
|
48352
|
+
patch: Number.parseInt(patch, 10)
|
|
48353
|
+
};
|
|
48354
|
+
}
|
|
48355
|
+
|
|
48356
|
+
// src/runner-serve.ts
|
|
48357
|
+
import { execFile as execFileCallback3, spawn } from "node:child_process";
|
|
48358
|
+
import { createHash } from "node:crypto";
|
|
48359
|
+
import { chmod, mkdir as mkdir2, readFile as readFile4, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
48360
|
+
import { hostname as hostname3, tmpdir } from "node:os";
|
|
48361
|
+
import path3 from "node:path";
|
|
48362
|
+
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
48363
|
+
import { promisify as promisify4 } from "node:util";
|
|
48364
|
+
var execFile4 = promisify4(execFileCallback3);
|
|
48365
|
+
async function runRunnerServe(options) {
|
|
48366
|
+
const env = options.env ?? process.env;
|
|
48367
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
48368
|
+
let config2;
|
|
48369
|
+
try {
|
|
48370
|
+
config2 = parseServeArgs(options.args, options.appUrl, env);
|
|
48371
|
+
} catch (error51) {
|
|
48372
|
+
options.io.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
|
|
48373
|
+
${usage()}
|
|
48374
|
+
`);
|
|
48375
|
+
return 1;
|
|
48376
|
+
}
|
|
48377
|
+
options.io.stdout.write(`runner serve: ${options.appUrl} name=${config2.name} execute=${config2.execute}
|
|
48378
|
+
`);
|
|
48379
|
+
let state;
|
|
48380
|
+
try {
|
|
48381
|
+
state = await pairIfNeeded(options.client ?? null, fetchImpl, options.appUrl, config2, options.io);
|
|
48382
|
+
} catch (error51) {
|
|
48383
|
+
options.io.stderr.write(`${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
48384
|
+
`);
|
|
48385
|
+
return 1;
|
|
48386
|
+
}
|
|
48387
|
+
let beat = 0;
|
|
48388
|
+
let heartbeatSucceeded = false;
|
|
48389
|
+
let failed = false;
|
|
48390
|
+
do {
|
|
48391
|
+
const capabilities = await detectCapabilities();
|
|
48392
|
+
try {
|
|
48393
|
+
const heartbeat = await post2(fetchImpl, options.appUrl, "/api/runner/heartbeat", { capabilities }, state.runner_secret);
|
|
48394
|
+
if (heartbeat.status !== 200) {
|
|
48395
|
+
options.io.stderr.write(`heartbeat ${heartbeat.status}: ${redactForLog(JSON.stringify(heartbeat.json))}
|
|
48396
|
+
`);
|
|
48397
|
+
failed = true;
|
|
48398
|
+
} else {
|
|
48399
|
+
heartbeatSucceeded = true;
|
|
48400
|
+
options.io.stdout.write(`heartbeat ok #${beat} runner_id=${state.runner_id} claude=${capabilities.claude.installed} codex=${capabilities.codex.installed}
|
|
48401
|
+
`);
|
|
48402
|
+
}
|
|
48403
|
+
if (config2.execute && capabilities.claude.installed) {
|
|
48404
|
+
await claimAndExecute(fetchImpl, options.appUrl, state, options.io);
|
|
48405
|
+
}
|
|
48406
|
+
} catch (error51) {
|
|
48407
|
+
failed = true;
|
|
48408
|
+
options.io.stderr.write(`transient runner error (continuing): ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
48409
|
+
`);
|
|
48410
|
+
}
|
|
48411
|
+
beat += 1;
|
|
48412
|
+
if (!config2.once) {
|
|
48413
|
+
await sleep2(config2.heartbeatMs);
|
|
48414
|
+
}
|
|
48415
|
+
} while (!config2.once);
|
|
48416
|
+
return heartbeatSucceeded && !failed ? 0 : 1;
|
|
48417
|
+
}
|
|
48418
|
+
function parseServeArgs(args, appUrl2, env) {
|
|
48419
|
+
let name = env.RUNNER_NAME ?? `headless-${hostname3()}`;
|
|
48420
|
+
let stateFile = env.RUNNER_STATE_FILE ?? path3.join(tmpdir(), `rost-runner-${createHash("sha1").update(appUrl2).digest("hex").slice(0, 8)}.json`);
|
|
48421
|
+
let heartbeatMs = Number(env.RUNNER_HEARTBEAT_MS ?? 3e4);
|
|
48422
|
+
let execute2 = env.RUNNER_EXECUTE === "1";
|
|
48423
|
+
let once = false;
|
|
48424
|
+
let userCode = env.RUNNER_USER_CODE;
|
|
48425
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
48426
|
+
const token = args[index];
|
|
48427
|
+
if (token === "--name") {
|
|
48428
|
+
name = requiredValue(args, index);
|
|
48429
|
+
index += 1;
|
|
48430
|
+
} else if (token === "--state-file") {
|
|
48431
|
+
stateFile = requiredValue(args, index);
|
|
48432
|
+
index += 1;
|
|
48433
|
+
} else if (token === "--heartbeat-ms") {
|
|
48434
|
+
heartbeatMs = Number(requiredValue(args, index));
|
|
48435
|
+
index += 1;
|
|
48436
|
+
} else if (token === "--user-code") {
|
|
48437
|
+
userCode = requiredValue(args, index);
|
|
48438
|
+
index += 1;
|
|
48439
|
+
} else if (token === "--execute") {
|
|
48440
|
+
execute2 = true;
|
|
48441
|
+
} else if (token === "--once") {
|
|
48442
|
+
once = true;
|
|
48443
|
+
} else {
|
|
48444
|
+
throw new Error(`Unexpected runner serve argument: ${token ?? ""}`);
|
|
48445
|
+
}
|
|
48446
|
+
}
|
|
48447
|
+
if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1e3) {
|
|
48448
|
+
throw new Error("--heartbeat-ms must be an integer >= 1000.");
|
|
48449
|
+
}
|
|
48450
|
+
return { name, stateFile, heartbeatMs, execute: execute2, once, ...userCode ? { userCode } : {} };
|
|
48451
|
+
}
|
|
48452
|
+
function requiredValue(args, index) {
|
|
48453
|
+
const value = args[index + 1];
|
|
48454
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
48455
|
+
throw new Error(`${args[index] ?? "flag"} requires a value.`);
|
|
48456
|
+
}
|
|
48457
|
+
return value;
|
|
48458
|
+
}
|
|
48459
|
+
async function resolveRunnerServeTenant(client) {
|
|
48460
|
+
try {
|
|
48461
|
+
const response = await client.execute("user.whoami", {});
|
|
48462
|
+
const output = response.output && typeof response.output === "object" && !Array.isArray(response.output) ? response.output : {};
|
|
48463
|
+
const activeTenantId = output.active_tenant_id ?? output.current_tenant_id ?? output.tenant_id;
|
|
48464
|
+
return typeof activeTenantId === "string" && activeTenantId.length > 0 ? activeTenantId : null;
|
|
48465
|
+
} catch {
|
|
48466
|
+
return null;
|
|
48467
|
+
}
|
|
48468
|
+
}
|
|
48469
|
+
async function pairIfNeeded(client, fetchImpl, appUrl2, config2, io) {
|
|
48470
|
+
if (client) {
|
|
48471
|
+
const expectedTenantId = await resolveRunnerServeTenant(client);
|
|
48472
|
+
if (expectedTenantId) {
|
|
48473
|
+
config2.expectedTenantId = expectedTenantId;
|
|
48474
|
+
}
|
|
48475
|
+
}
|
|
48476
|
+
const existing = await loadState(config2.stateFile, config2.expectedTenantId);
|
|
48477
|
+
if (existing) {
|
|
48478
|
+
io.stdout.write(`reusing paired runner ${existing.runner_id}
|
|
48479
|
+
`);
|
|
48480
|
+
return existing;
|
|
48481
|
+
}
|
|
48482
|
+
if (!client) {
|
|
48483
|
+
throw new Error(`No paired runner state at ${config2.stateFile}. Run with a CLI login once to pair this runner before starting without a CLI session.`);
|
|
48484
|
+
}
|
|
48485
|
+
const userCode = config2.userCode ?? await startPairing(client, config2);
|
|
48486
|
+
const claim = await post2(fetchImpl, appUrl2, "/api/runner/pairing/claim", { user_code: userCode });
|
|
48487
|
+
const runnerSecret = claim.json.runner_secret;
|
|
48488
|
+
const runnerId = claim.json.runner_id;
|
|
48489
|
+
const tenantId = claim.json.tenant_id;
|
|
48490
|
+
if (claim.status !== 200 || typeof runnerSecret !== "string" || typeof runnerId !== "string") {
|
|
48491
|
+
throw new Error(`pairing claim failed ${claim.status}: ${redactForLog(JSON.stringify(claim.json))}`);
|
|
48492
|
+
}
|
|
48493
|
+
const state = {
|
|
48494
|
+
runner_id: runnerId,
|
|
48495
|
+
runner_secret: runnerSecret,
|
|
48496
|
+
...typeof tenantId === "string" ? { tenant_id: tenantId } : config2.expectedTenantId ? { tenant_id: config2.expectedTenantId } : {},
|
|
48497
|
+
name: typeof claim.json.name === "string" ? claim.json.name : config2.name
|
|
48498
|
+
};
|
|
48499
|
+
await mkdir2(path3.dirname(config2.stateFile), { recursive: true, mode: 448 });
|
|
48500
|
+
await writeFile2(config2.stateFile, `${JSON.stringify(state)}
|
|
48501
|
+
`, { mode: 384 });
|
|
48502
|
+
await chmod(config2.stateFile, 384);
|
|
48503
|
+
io.stdout.write(`paired runner_id=${runnerId} state_file=${config2.stateFile}
|
|
48504
|
+
`);
|
|
48505
|
+
return state;
|
|
48506
|
+
}
|
|
48507
|
+
async function loadState(filePath, expectedTenantId) {
|
|
48508
|
+
try {
|
|
48509
|
+
const parsed = JSON.parse(await readFile4(filePath, "utf8"));
|
|
48510
|
+
if (typeof parsed.runner_id === "string" && typeof parsed.runner_secret === "string") {
|
|
48511
|
+
if (expectedTenantId && parsed.tenant_id !== expectedTenantId) {
|
|
48512
|
+
return null;
|
|
48513
|
+
}
|
|
48514
|
+
return {
|
|
48515
|
+
runner_id: parsed.runner_id,
|
|
48516
|
+
runner_secret: parsed.runner_secret,
|
|
48517
|
+
...typeof parsed.tenant_id === "string" ? { tenant_id: parsed.tenant_id } : {},
|
|
48518
|
+
...typeof parsed.name === "string" ? { name: parsed.name } : {}
|
|
48519
|
+
};
|
|
48520
|
+
}
|
|
48521
|
+
} catch {
|
|
48522
|
+
return null;
|
|
48523
|
+
}
|
|
48524
|
+
return null;
|
|
48525
|
+
}
|
|
48526
|
+
async function startPairing(client, config2) {
|
|
48527
|
+
const response = await client.execute("runner.pairing.start", { name: config2.name, platform: process.platform });
|
|
48528
|
+
const userCode = response.output && typeof response.output === "object" ? response.output.user_code : void 0;
|
|
48529
|
+
if (typeof userCode !== "string" || userCode.length === 0) {
|
|
48530
|
+
throw new Error("runner.pairing.start did not return a user_code.");
|
|
48531
|
+
}
|
|
48532
|
+
return userCode;
|
|
48533
|
+
}
|
|
48534
|
+
async function detectCapabilities() {
|
|
48535
|
+
const [claude, codex] = await Promise.all([probe("claude"), probe("codex")]);
|
|
48536
|
+
return { claude, codex };
|
|
48537
|
+
}
|
|
48538
|
+
async function probe(command) {
|
|
48539
|
+
try {
|
|
48540
|
+
const { stdout, stderr } = await execFile4(command, ["--version"], { timeout: 1500 });
|
|
48541
|
+
return { installed: true, version: (stdout || stderr).trim() || null, auth_state: "ready" };
|
|
48542
|
+
} catch {
|
|
48543
|
+
return { installed: false, version: null, auth_state: "unknown" };
|
|
48544
|
+
}
|
|
48545
|
+
}
|
|
48546
|
+
async function post2(fetchImpl, appUrl2, pathName, body, token) {
|
|
48547
|
+
const headers = { "content-type": "application/json" };
|
|
48548
|
+
if (token) {
|
|
48549
|
+
headers.authorization = `Bearer ${token}`;
|
|
48550
|
+
}
|
|
48551
|
+
const response = await fetchImpl(`${appUrl2.replace(/\/+$/, "")}${pathName}`, {
|
|
48552
|
+
method: "POST",
|
|
48553
|
+
headers,
|
|
48554
|
+
body: JSON.stringify(body)
|
|
48555
|
+
});
|
|
48556
|
+
const text = await response.text();
|
|
48557
|
+
let json2;
|
|
48558
|
+
try {
|
|
48559
|
+
json2 = JSON.parse(text);
|
|
48560
|
+
} catch {
|
|
48561
|
+
json2 = { raw: text.slice(0, 300) };
|
|
48562
|
+
}
|
|
48563
|
+
return { status: response.status, json: json2 };
|
|
48564
|
+
}
|
|
48565
|
+
async function claimAndExecute(fetchImpl, appUrl2, state, io) {
|
|
48566
|
+
const claimed = await post2(fetchImpl, appUrl2, "/api/runner/work-orders/claim", {}, state.runner_secret);
|
|
48567
|
+
const workOrder = claimed.json.work_order;
|
|
48568
|
+
if (claimed.status !== 200 || !workOrder || typeof workOrder !== "object") {
|
|
48569
|
+
return;
|
|
48570
|
+
}
|
|
48571
|
+
const workOrderId = workOrder.id;
|
|
48572
|
+
if (typeof workOrderId !== "string") {
|
|
48573
|
+
return;
|
|
48574
|
+
}
|
|
48575
|
+
const started = await post2(fetchImpl, appUrl2, `/api/runner/work-orders/${encodeURIComponent(workOrderId)}/start`, {}, state.runner_secret);
|
|
48576
|
+
if (started.status !== 200) {
|
|
48577
|
+
throw new Error(`work order start failed ${started.status}: ${redactForLog(JSON.stringify(started.json))}`);
|
|
48578
|
+
}
|
|
48579
|
+
const result = await runClaudeTurn(appUrl2, workOrder);
|
|
48580
|
+
const reported = await post2(fetchImpl, appUrl2, `/api/runner/work-orders/${encodeURIComponent(workOrderId)}/result`, {
|
|
48581
|
+
status: result.ok ? "succeeded" : "failed",
|
|
48582
|
+
summary: result.summary,
|
|
48583
|
+
log_ref: `runner-local:${workOrderId}`,
|
|
48584
|
+
model: "claude-cli"
|
|
48585
|
+
}, state.runner_secret);
|
|
48586
|
+
if (reported.status !== 200) {
|
|
48587
|
+
throw new Error(`work order result failed ${reported.status}: ${redactForLog(JSON.stringify(reported.json))}`);
|
|
48588
|
+
}
|
|
48589
|
+
io.stdout.write(`work_order_id=${workOrderId} status=${result.ok ? "succeeded" : "failed"}
|
|
48590
|
+
`);
|
|
48591
|
+
}
|
|
48592
|
+
async function runClaudeTurn(appUrl2, workOrder) {
|
|
48593
|
+
const mcp = typeof workOrder.mcp === "object" && workOrder.mcp !== null ? workOrder.mcp : {};
|
|
48594
|
+
const token = typeof mcp.token === "string" ? mcp.token : "";
|
|
48595
|
+
const url2 = typeof mcp.url === "string" ? `${appUrl2.replace(/\/+$/, "")}${mcp.url}` : `${appUrl2.replace(/\/+$/, "")}/mcp`;
|
|
48596
|
+
const mcpConfig = JSON.stringify({ mcpServers: { rost: { type: "http", url: url2, headers: { Authorization: `Bearer ${token}` } } } });
|
|
48597
|
+
const configPath = path3.join(tmpdir(), `rost-runner-mcp-${createHash("sha256").update(`${url2}:${Date.now()}:${Math.random()}`).digest("hex").slice(0, 16)}.json`);
|
|
48598
|
+
const context = {
|
|
48599
|
+
work_order_id: workOrder.id,
|
|
48600
|
+
task_id: workOrder.task_id ?? null,
|
|
48601
|
+
seat: workOrder.seat ?? null,
|
|
48602
|
+
charter: workOrder.charter ?? null,
|
|
48603
|
+
permission_manifest: workOrder.permission_manifest ?? null
|
|
48604
|
+
};
|
|
48605
|
+
const prompt = [
|
|
48606
|
+
`Load your ${cliBrand.name} context, report one read-only status, and stop.`,
|
|
48607
|
+
"Do not call external systems or mutating tools.",
|
|
48608
|
+
`Claimed work order context: ${JSON.stringify(context).slice(0, 8e3)}`
|
|
48609
|
+
].join("\n");
|
|
48610
|
+
await writeFile2(configPath, `${mcpConfig}
|
|
48611
|
+
`, { mode: 384 });
|
|
48612
|
+
await chmod(configPath, 384);
|
|
48613
|
+
return new Promise((resolve2) => {
|
|
48614
|
+
let settled = false;
|
|
48615
|
+
const finish = (result) => {
|
|
48616
|
+
if (settled) {
|
|
48617
|
+
return;
|
|
48618
|
+
}
|
|
48619
|
+
settled = true;
|
|
48620
|
+
void rm2(configPath, { force: true });
|
|
48621
|
+
resolve2(result);
|
|
48622
|
+
};
|
|
48623
|
+
const child = spawn("claude", ["-p", prompt, "--mcp-config", configPath, "--strict-mcp-config", "--output-format", "text"], {
|
|
48624
|
+
cwd: tmpdir(),
|
|
48625
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
48626
|
+
});
|
|
48627
|
+
let out = "";
|
|
48628
|
+
let err = "";
|
|
48629
|
+
const timer = setTimeout(() => {
|
|
48630
|
+
child.kill("SIGKILL");
|
|
48631
|
+
finish({ ok: false, summary: "turn timed out after 180s" });
|
|
48632
|
+
}, 18e4);
|
|
48633
|
+
child.stdout.on("data", (data) => {
|
|
48634
|
+
out += data.toString("utf8");
|
|
48635
|
+
});
|
|
48636
|
+
child.stderr.on("data", (data) => {
|
|
48637
|
+
err += data.toString("utf8");
|
|
48638
|
+
});
|
|
48639
|
+
child.on("close", (code) => {
|
|
48640
|
+
clearTimeout(timer);
|
|
48641
|
+
finish({ ok: code === 0, summary: redactForLog((out || err || "completed").trim()).slice(0, 600) });
|
|
48642
|
+
});
|
|
48643
|
+
child.on("error", (error51) => {
|
|
48644
|
+
clearTimeout(timer);
|
|
48645
|
+
finish({ ok: false, summary: `spawn error: ${redactForLog(error51.message)}` });
|
|
48646
|
+
});
|
|
48647
|
+
});
|
|
48648
|
+
}
|
|
48649
|
+
function usage() {
|
|
48650
|
+
return "Usage: rost runner serve [--name <text>] [--state-file <path>] [--heartbeat-ms <n>] [--user-code <code>] [--once] [--execute]";
|
|
48651
|
+
}
|
|
48652
|
+
|
|
48067
48653
|
// src/index.ts
|
|
48068
48654
|
async function main(argv = process.argv.slice(2), options = {}) {
|
|
48069
48655
|
const io = options.io ?? {
|
|
@@ -48117,6 +48703,13 @@ async function main(argv = process.argv.slice(2), options = {}) {
|
|
|
48117
48703
|
}
|
|
48118
48704
|
return result.exitCode;
|
|
48119
48705
|
}
|
|
48706
|
+
if (command === "doctor") {
|
|
48707
|
+
return runDoctor({
|
|
48708
|
+
io,
|
|
48709
|
+
env: process.env,
|
|
48710
|
+
...options.store ? { store: options.store } : {}
|
|
48711
|
+
});
|
|
48712
|
+
}
|
|
48120
48713
|
if (command === "onboard" && args[0] === "run") {
|
|
48121
48714
|
io.stdout.write(`${renderOnboardRunPrompt()}
|
|
48122
48715
|
`);
|
|
@@ -48172,12 +48765,35 @@ async function main(argv = process.argv.slice(2), options = {}) {
|
|
|
48172
48765
|
`);
|
|
48173
48766
|
justLoggedIn = true;
|
|
48174
48767
|
}
|
|
48768
|
+
const config2 = loadConfig();
|
|
48769
|
+
if (command === "runner" && args[0] === "serve") {
|
|
48770
|
+
let runnerClient = null;
|
|
48771
|
+
if (session) {
|
|
48772
|
+
try {
|
|
48773
|
+
const refreshed2 = await refreshSession(config2, session);
|
|
48774
|
+
if (refreshed2 !== session) {
|
|
48775
|
+
session = refreshed2;
|
|
48776
|
+
await store.write(session);
|
|
48777
|
+
}
|
|
48778
|
+
runnerClient = new CommandClient({ appUrl: config2.appUrl, token: session.accessToken });
|
|
48779
|
+
} catch (error51) {
|
|
48780
|
+
io.stderr.write(`CLI session unavailable; trying paired runner state only: ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
48781
|
+
`);
|
|
48782
|
+
}
|
|
48783
|
+
}
|
|
48784
|
+
return runRunnerServe({
|
|
48785
|
+
io,
|
|
48786
|
+
client: runnerClient,
|
|
48787
|
+
appUrl: config2.appUrl,
|
|
48788
|
+
args: args.slice(1),
|
|
48789
|
+
env: process.env
|
|
48790
|
+
});
|
|
48791
|
+
}
|
|
48175
48792
|
if (!session) {
|
|
48176
48793
|
io.stderr.write(`Not logged in. Run ${cliBrand.binName} login first.
|
|
48177
48794
|
`);
|
|
48178
48795
|
return 1;
|
|
48179
48796
|
}
|
|
48180
|
-
const config2 = loadConfig();
|
|
48181
48797
|
let refreshed;
|
|
48182
48798
|
try {
|
|
48183
48799
|
refreshed = await refreshSession(config2, session);
|
|
@@ -48294,9 +48910,10 @@ async function executeDirectCommand(io, client, args) {
|
|
|
48294
48910
|
}
|
|
48295
48911
|
const commandId = first;
|
|
48296
48912
|
let seat;
|
|
48913
|
+
let autoConfirm = false;
|
|
48297
48914
|
let rest;
|
|
48298
48915
|
try {
|
|
48299
|
-
({ seat, rest } =
|
|
48916
|
+
({ seat, autoConfirm, rest } = extractCommandMetaFlags(args.slice(1)));
|
|
48300
48917
|
} catch (error51) {
|
|
48301
48918
|
io.stderr.write(`${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
48302
48919
|
`);
|
|
@@ -48317,11 +48934,15 @@ async function executeDirectCommand(io, client, args) {
|
|
|
48317
48934
|
`);
|
|
48318
48935
|
return 1;
|
|
48319
48936
|
}
|
|
48320
|
-
return printCommandOutput(io, client, commandId, body, void 0,
|
|
48937
|
+
return printCommandOutput(io, client, commandId, body, void 0, {
|
|
48938
|
+
...seat === void 0 ? {} : { targetSeatId: seat },
|
|
48939
|
+
autoConfirm
|
|
48940
|
+
});
|
|
48321
48941
|
}
|
|
48322
|
-
function
|
|
48942
|
+
function extractCommandMetaFlags(args) {
|
|
48323
48943
|
const rest = [];
|
|
48324
48944
|
let seat;
|
|
48945
|
+
let autoConfirm = false;
|
|
48325
48946
|
for (let index = 0; index < args.length; index += 1) {
|
|
48326
48947
|
const token = args[index];
|
|
48327
48948
|
if (token === "--seat") {
|
|
@@ -48333,11 +48954,15 @@ function extractSeatFlag(args) {
|
|
|
48333
48954
|
index += 1;
|
|
48334
48955
|
continue;
|
|
48335
48956
|
}
|
|
48957
|
+
if (token === "--yes" || token === "-y") {
|
|
48958
|
+
autoConfirm = true;
|
|
48959
|
+
continue;
|
|
48960
|
+
}
|
|
48336
48961
|
if (token !== void 0) {
|
|
48337
48962
|
rest.push(token);
|
|
48338
48963
|
}
|
|
48339
48964
|
}
|
|
48340
|
-
return { ...seat === void 0 ? {} : { seat }, rest };
|
|
48965
|
+
return { ...seat === void 0 ? {} : { seat }, autoConfirm, rest };
|
|
48341
48966
|
}
|
|
48342
48967
|
var SeatFlagError = class extends Error {
|
|
48343
48968
|
};
|
|
@@ -48352,7 +48977,9 @@ function formatCommandSchema(output) {
|
|
|
48352
48977
|
if (typeof help === "string" && help.length > 0) {
|
|
48353
48978
|
lines.push(`help: ${help}`);
|
|
48354
48979
|
}
|
|
48355
|
-
|
|
48980
|
+
const schemaSummary = formatInputSchemaSummary(record2.input_schema);
|
|
48981
|
+
lines.push("", "input:");
|
|
48982
|
+
lines.push(schemaSummary || " no input fields");
|
|
48356
48983
|
if (record2.example !== void 0) {
|
|
48357
48984
|
lines.push("", "example input:", JSON.stringify(record2.example, null, 2));
|
|
48358
48985
|
}
|
|
@@ -48366,6 +48993,23 @@ function formatCommandSchema(output) {
|
|
|
48366
48993
|
}
|
|
48367
48994
|
return lines.join("\n");
|
|
48368
48995
|
}
|
|
48996
|
+
function formatInputSchemaSummary(schema) {
|
|
48997
|
+
const root = asRecord3(schema);
|
|
48998
|
+
const properties = asRecord3(root.properties);
|
|
48999
|
+
const required2 = new Set(asStringArray(root.required));
|
|
49000
|
+
const entries = Object.entries(properties);
|
|
49001
|
+
if (entries.length === 0) {
|
|
49002
|
+
return "";
|
|
49003
|
+
}
|
|
49004
|
+
return entries.map(([key, value]) => {
|
|
49005
|
+
const prop = asRecord3(value);
|
|
49006
|
+
const type = Array.isArray(prop.type) ? prop.type.join("|") : field2(prop, "type");
|
|
49007
|
+
const enumValues = asStringArray(prop.enum);
|
|
49008
|
+
const description = typeof prop.description === "string" ? ` \u2014 ${prop.description}` : "";
|
|
49009
|
+
const enumText = enumValues.length > 0 ? ` enum=${enumValues.join("|")}` : "";
|
|
49010
|
+
return ` ${key}${required2.has(key) ? " (required)" : " (optional)"}: ${type}${enumText}${description}`;
|
|
49011
|
+
}).join("\n");
|
|
49012
|
+
}
|
|
48369
49013
|
function formatCommandList(output) {
|
|
48370
49014
|
const commands = Array.isArray(asRecord3(output).commands) ? asRecord3(output).commands : [];
|
|
48371
49015
|
if (commands.length === 0) {
|
|
@@ -48492,10 +49136,12 @@ async function printCommandOutput(io, client, commandId, body = {}, format, opti
|
|
|
48492
49136
|
`);
|
|
48493
49137
|
return 0;
|
|
48494
49138
|
} catch (error51) {
|
|
48495
|
-
|
|
49139
|
+
const envAutoConfirm = process.env[`${cliBrand.envPrefix}_CLI_AUTO_CONFIRM`] === "1";
|
|
49140
|
+
if (io.interactive === true || options.autoConfirm === true || envAutoConfirm) {
|
|
48496
49141
|
const pending = pendingConfirmationFromError2(error51);
|
|
48497
49142
|
if (pending && pending.commandId === commandId) {
|
|
48498
|
-
|
|
49143
|
+
const reason = io.interactive === true ? "interactive CLI user" : options.autoConfirm === true ? "explicit CLI auto-confirm" : `${cliBrand.envPrefix}_CLI_AUTO_CONFIRM environment auto-confirm`;
|
|
49144
|
+
io.stderr.write(`Approving ${pending.commandId} confirmation ${pending.confirmationId} as the ${reason}.
|
|
48499
49145
|
`);
|
|
48500
49146
|
try {
|
|
48501
49147
|
const approved = await client.execute("confirmation.approve", { confirmation_id: pending.confirmationId });
|
|
@@ -48540,6 +49186,14 @@ function printCommandError2(io, error51) {
|
|
|
48540
49186
|
io.stderr.write(`\u2192 try: ${redactForLog(help)}
|
|
48541
49187
|
`);
|
|
48542
49188
|
}
|
|
49189
|
+
if (error51.response.error.code === "COMMAND_CONFIRMATION_REQUIRED") {
|
|
49190
|
+
const details = asRecord3(error51.response.error.details);
|
|
49191
|
+
const expiresAt = details.expiresAt;
|
|
49192
|
+
if (typeof expiresAt === "string" && expiresAt.length > 0) {
|
|
49193
|
+
io.stderr.write(`confirmation expires at: ${redactForLog(expiresAt)}
|
|
49194
|
+
`);
|
|
49195
|
+
}
|
|
49196
|
+
}
|
|
48543
49197
|
if (error51.status === 409) {
|
|
48544
49198
|
return 3;
|
|
48545
49199
|
}
|
|
@@ -48561,7 +49215,7 @@ function parseJsonBody(args) {
|
|
|
48561
49215
|
return JSON.parse(body);
|
|
48562
49216
|
}
|
|
48563
49217
|
function isCommand(value) {
|
|
48564
|
-
return value === "login" || value === "logout" || value === "signup" || value === "whoami" || value === "tenants" || value === "use" || value === "command" || value === "onboard" || value === "mcp" || value === "skills" || value === "init" || value === "docs" || value === "reference" || value === "help";
|
|
49218
|
+
return value === "login" || value === "logout" || value === "signup" || value === "whoami" || value === "tenants" || value === "use" || value === "command" || value === "onboard" || value === "mcp" || value === "skills" || value === "init" || value === "docs" || value === "reference" || value === "doctor" || value === "help";
|
|
48565
49219
|
}
|
|
48566
49220
|
function printUsage(io) {
|
|
48567
49221
|
io.stdout.write([
|
|
@@ -48575,6 +49229,7 @@ function printUsage(io) {
|
|
|
48575
49229
|
`${cliBrand.binName} command <id> [--seat <seat-id>] --json [json-body]`,
|
|
48576
49230
|
`${cliBrand.binName} command schema <id> [--json]`,
|
|
48577
49231
|
`${cliBrand.binName} command list [--json]`,
|
|
49232
|
+
`${cliBrand.binName} doctor`,
|
|
48578
49233
|
...operationUsageLines(cliBrand.binName),
|
|
48579
49234
|
`${cliBrand.binName} onboard status`,
|
|
48580
49235
|
`${cliBrand.binName} onboard run`,
|