@rosthq/cli 0.5.18 → 0.5.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +555 -87
- package/dist/index.js.map +4 -4
- package/dist/skills.d.ts +19 -0
- package/dist/skills.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(path3, preserveJsx) {
|
|
476
|
+
if (typeof path3 === "string" && /^\.\.?\//.test(path3)) {
|
|
477
|
+
return path3.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 path3;
|
|
482
482
|
}
|
|
483
483
|
var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
|
|
484
484
|
var init_tslib_es6 = __esm({
|
|
@@ -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, path3) {
|
|
14030
|
+
if (!path3)
|
|
14031
14031
|
return obj;
|
|
14032
|
-
return
|
|
14032
|
+
return path3.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(path3, 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(path3);
|
|
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, path3 = []) => {
|
|
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 }, [...path3, ...issue2.path]));
|
|
14596
14596
|
} else if (issue2.code === "invalid_key") {
|
|
14597
|
-
processError({ issues: issue2.issues }, [...
|
|
14597
|
+
processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
|
|
14598
14598
|
} else if (issue2.code === "invalid_element") {
|
|
14599
|
-
processError({ issues: issue2.issues }, [...
|
|
14599
|
+
processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
|
|
14600
14600
|
} else {
|
|
14601
|
-
const fullpath = [...
|
|
14601
|
+
const fullpath = [...path3, ...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, path3 = []) => {
|
|
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 }, [...path3, ...issue2.path]));
|
|
14633
14633
|
} else if (issue2.code === "invalid_key") {
|
|
14634
|
-
processError({ issues: issue2.issues }, [...
|
|
14634
|
+
processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
|
|
14635
14635
|
} else if (issue2.code === "invalid_element") {
|
|
14636
|
-
processError({ issues: issue2.issues }, [...
|
|
14636
|
+
processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
|
|
14637
14637
|
} else {
|
|
14638
|
-
const fullpath = [...
|
|
14638
|
+
const fullpath = [...path3, ...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 path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
14671
|
+
for (const seg of path3) {
|
|
14672
14672
|
if (typeof seg === "number")
|
|
14673
14673
|
segs.push(`[${seg}]`);
|
|
14674
14674
|
else if (typeof seg === "symbol")
|
|
@@ -27360,13 +27360,13 @@ function resolveRef(ref, ctx) {
|
|
|
27360
27360
|
if (!ref.startsWith("#")) {
|
|
27361
27361
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
27362
27362
|
}
|
|
27363
|
-
const
|
|
27364
|
-
if (
|
|
27363
|
+
const path3 = ref.slice(1).split("/").filter(Boolean);
|
|
27364
|
+
if (path3.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 (path3[0] === defsKey) {
|
|
27369
|
+
const key = path3[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 path3 = `/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}${path3}`, {
|
|
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 ${path3}` + (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, path3, query) {
|
|
33060
|
+
const url2 = new URL(path3, 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: path3,
|
|
33091
33091
|
query,
|
|
33092
33092
|
body,
|
|
33093
33093
|
headers
|
|
33094
33094
|
}) {
|
|
33095
|
-
const url2 = buildUrl(options.baseUrl,
|
|
33095
|
+
const url2 = buildUrl(options.baseUrl, path3, 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, path3, 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(path3);
|
|
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(path3, fileBody, fileOptions) {
|
|
34059
|
+
return this.uploadOrUpdate("POST", path3, 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(path3, token, fileBody, fileOptions) {
|
|
34100
34100
|
var _this3 = this;
|
|
34101
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
34101
|
+
const cleanPath = _this3._removeEmptyFolders(path3);
|
|
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(path3, options) {
|
|
34171
34171
|
var _this4 = this;
|
|
34172
34172
|
return _this4.handleOperation(async () => {
|
|
34173
|
-
let _path = _this4._getFinalPath(
|
|
34173
|
+
let _path = _this4._getFinalPath(path3);
|
|
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: path3,
|
|
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(path3, fileBody, fileOptions) {
|
|
34243
|
+
return this.uploadOrUpdate("PUT", path3, 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(path3, expiresIn, options) {
|
|
34395
34395
|
var _this8 = this;
|
|
34396
34396
|
return _this8.handleOperation(async () => {
|
|
34397
|
-
let _path = _this8._getFinalPath(
|
|
34397
|
+
let _path = _this8._getFinalPath(path3);
|
|
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(path3, 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(path3);
|
|
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(path3) {
|
|
34571
34571
|
var _this10 = this;
|
|
34572
|
-
const _path = _this10._getFinalPath(
|
|
34572
|
+
const _path = _this10._getFinalPath(path3);
|
|
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(path3) {
|
|
34594
34594
|
var _this11 = this;
|
|
34595
|
-
const _path = _this11._getFinalPath(
|
|
34595
|
+
const _path = _this11._getFinalPath(path3);
|
|
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(path3, options) {
|
|
34675
|
+
const _path = this._getFinalPath(path3);
|
|
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(path3, 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: path3 || "" });
|
|
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(path3) {
|
|
34883
|
+
return `${this.bucketId}/${path3.replace(/^\/+/, "")}`;
|
|
34884
34884
|
}
|
|
34885
|
-
_removeEmptyFolders(
|
|
34886
|
-
return
|
|
34885
|
+
_removeEmptyFolders(path3) {
|
|
34886
|
+
return path3.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
34887
34887
|
}
|
|
34888
34888
|
/** Modifies the `query`, appending values the from `transform` */
|
|
34889
34889
|
applyTransformOptsToQuery(query, transform2) {
|
|
@@ -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: path3, errorMaps, issueData } = params;
|
|
37924
|
+
const fullPath = [...path3, ...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, path3, key) {
|
|
38041
38041
|
this._cachedPath = [];
|
|
38042
38042
|
this.parent = parent;
|
|
38043
38043
|
this.data = value;
|
|
38044
|
-
this._path =
|
|
38044
|
+
this._path = path3;
|
|
38045
38045
|
this._key = key;
|
|
38046
38046
|
}
|
|
38047
38047
|
get path() {
|
|
@@ -41830,7 +41830,7 @@ Drafting can be assisted by agents. Activation is a human decision. When authori
|
|
|
41830
41830
|
order: 40,
|
|
41831
41831
|
title: "Agent staffing playbook",
|
|
41832
41832
|
summary: "How to decide whether a seat should be human, agent, or hybrid, and how to go live safely.",
|
|
41833
|
-
version: "2026-06-
|
|
41833
|
+
version: "2026-06-21.2",
|
|
41834
41834
|
public: true,
|
|
41835
41835
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
41836
41836
|
stages: ["staffing"],
|
|
@@ -41889,7 +41889,7 @@ Two creation paths, both draft-first. Read the stock-agents guide for templates
|
|
|
41889
41889
|
- Custom: \`agent_setup.start\` / \`rost_start_agent_setup\` (returns a \`setup_id\`), iterate with \`agent_setup.get\` and \`agent_setup.update\`, then \`agent.create_custom\` / \`rost_create_custom_agent\`. Stage tools with \`agent.configure_tools\` (vault refs only) and sandbox with \`agent.run_dry_run\`.
|
|
41890
41890
|
- Inspect runtime: \`agent.status\` / \`rost_get_agent_status\` with \`{"seat_id":"<seat-id>"}\` returns lane, live state, steward chain, dry-run result, and Runner availability.
|
|
41891
41891
|
- Run on demand: \`{{cli}} agent run-now --seat-id <seat-id>\` / \`agent.run_now\` / \`rost_run_agent_now\` queues an immediate live run without changing the saved schedule. Cloud agents dispatch to the Inngest executor; runner agents queue work for the paired runner. The command is ungated but still requires a live staffed agent and the normal server-side tool guard.
|
|
41892
|
-
- Audit what an agent did (Trust Card): \`{{cli}} command agent.list_runs --json '{"seat_id":"<seat-id>"}'\` / \`rost_list_agent_runs\` returns the seat's run history with per-run tool-call and guard-held counts; \`{{cli}} agent get-run --seat-id <seat-id> --run-id <run-id>\` / \`agent.get_run\` / \`rost_get_agent_run_diagnostics\` reads one run's transcript reference, token/cost usage, outcome,
|
|
41892
|
+
- Audit what an agent did (Trust Card): \`{{cli}} command agent.list_runs --json '{"seat_id":"<seat-id>"}'\` / \`rost_list_agent_runs\` returns the seat's run history with per-run Skill activation counts plus tool-call and guard-held counts; \`{{cli}} agent get-run --seat-id <seat-id> --run-id <run-id>\` / \`agent.get_run\` / \`rost_get_agent_run_diagnostics\` reads one run's transcript reference, token/cost usage, outcome, product-visible run errors, and any Skill versions/files loaded for that run. Loaded Skill file hashes and sizes identify the immutable source package; the runtime may still bound or truncate prompt text before sending it to the model. \`{{cli}} command agent.list_tool_calls --json '{"seat_id":"<seat-id>"}'\` / \`rost_list_agent_tool_calls\` returns the tool-call ledger with each call's guard result. Both list commands include a \`denied_tool_call_count\` rollup \u2014 the actions held because they exceeded the charter. Pass \`{"seat_id":"<seat-id>","held_only":true}\` to \`agent.list_tool_calls\` for only the held calls. The web seat page shows the same facts as a Trust Card.
|
|
41893
41893
|
|
|
41894
41894
|
## Review readiness before go-live
|
|
41895
41895
|
|
|
@@ -41910,7 +41910,7 @@ No orphan agents. No raw secrets in prompts, logs, or tool arguments. No durable
|
|
|
41910
41910
|
order: 41,
|
|
41911
41911
|
title: "Add agents to your Responsibility Graph",
|
|
41912
41912
|
summary: "The visual journey for adding an agent seat: where to start, choosing a mode, placing the seat, naming a Steward, setup, the safety gates, and go-live.",
|
|
41913
|
-
version: "2026-06-
|
|
41913
|
+
version: "2026-06-21.1",
|
|
41914
41914
|
public: true,
|
|
41915
41915
|
audiences: ["human", "in_app_agent"],
|
|
41916
41916
|
stages: ["staffing"],
|
|
@@ -41959,10 +41959,11 @@ The wizard builds a teammate, not a prompt:
|
|
|
41959
41959
|
|
|
41960
41960
|
1. **Responsibilities and authority** \u2014 what the seat owns, what it may do alone, what needs approval, and what must escalate. Every clause is editable before sign-off.
|
|
41961
41961
|
2. **Signals** \u2014 the measurables the seat is judged on.
|
|
41962
|
-
3. **
|
|
41963
|
-
4. **
|
|
41962
|
+
3. **Skills** \u2014 pin published, immutable Skill versions that the agent should carry. Skills are procedures, not authority: selecting one creates a proposed assignment and surfaces required/optional tool dependencies before sign-off.
|
|
41963
|
+
4. **Tools** \u2014 connect or decline each proposed tool. Declining a tool updates the permission manifest and the dry-run task so the agent stays safe. Credentials go in through write-only credential ingress and are stored as vault references, never shown again. Missing required Skill tools block sign-off, dry-run, and go-live until resolved; missing optional Skill tools warn without blocking.
|
|
41964
|
+
5. **Schedule and lane** \u2014 when the agent runs and on which lane. These stay advanced unless the mode needs them.
|
|
41964
41965
|
|
|
41965
|
-
You can save and resume a draft setup at any point. Returning to the flow restores the parent, Steward, mode, answers, tool decisions, and dry-run result.
|
|
41966
|
+
You can save and resume a draft setup at any point. Returning to the flow restores the parent, Steward, mode, answers, Skill selections, tool decisions, and dry-run result.
|
|
41966
41967
|
|
|
41967
41968
|
## The safety gates
|
|
41968
41969
|
|
|
@@ -42139,7 +42140,7 @@ Decisions should be recorded as human decisions. Handoffs should attach to seats
|
|
|
42139
42140
|
order: 45,
|
|
42140
42141
|
title: "How agents work",
|
|
42141
42142
|
summary: "How {{brand}} agents operate inside seats, use Charters, report work, and escalate beyond authority.",
|
|
42142
|
-
version: "2026-06-
|
|
42143
|
+
version: "2026-06-21.1",
|
|
42143
42144
|
public: true,
|
|
42144
42145
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
42145
42146
|
stages: ["staffing", "operating_rhythm"],
|
|
@@ -42231,7 +42232,7 @@ Before an agent goes live, the sandbox dry run rehearses this against fake data
|
|
|
42231
42232
|
|
|
42232
42233
|
## What humans should review
|
|
42233
42234
|
|
|
42234
|
-
The Agents page shows fleet health first: live state, recent runs, failed runs, open held actions, last activity, cost, and the next operator action. It also shows configuration completeness for each staffed agent seat: Steward chain, lane or runtime substrate, vaulted credentials, granted tools, model config, sandbox dry run, and go-live state, each with a remediation link when incomplete. A seat's Trust Card drills into the same facts: run history, one-run detail, tool-call outcomes, product-visible errors, transcript references, and held confirmations or escalations. Open confirmations stay visible until they are decided or expire, even when they are older than the default activity window. Approving or rejecting a held confirmation from the seat page is scoped to that seat; rejection can include a short reason.
|
|
42235
|
+
The Agents page shows fleet health first: live state, recent runs, failed runs, open held actions, last activity, cost, and the next operator action. It also shows configuration completeness for each staffed agent seat: Steward chain, lane or runtime substrate, vaulted credentials, granted tools, model config, sandbox dry run, and go-live state, each with a remediation link when incomplete. A seat's Trust Card drills into the same facts: run history, one-run detail, tool-call outcomes, product-visible errors, transcript references, loaded Skill versions, and held confirmations or escalations. Open confirmations stay visible until they are decided or expire, even when they are older than the default activity window. Approving or rejecting a held confirmation from the seat page is scoped to that seat; rejection can include a short reason.
|
|
42235
42236
|
|
|
42236
42237
|
Review the first dry runs, fleet overview, tool-call audit rows, escalations, deliverables, and Signal impact. A seat's completed-work area combines explicit deliverables, work-log evidence, and successful run summaries into one operator-facing trail with safe links labelled as internal, Linear, GitHub, or external. The fleet view at \`/agents\` shows every staffed agent seat at a glance; the agent-native equivalents are \`{{cli}} command agent.list_fleet --json '{}'\` / \`rost_list_agent_fleet\` for the compact overview, and \`{{cli}} agent fleet-digest --json\` / \`agent.fleet_digest\` / \`rost_get_dogfood_fleet_health_digest\` for the daily dogfood evidence bundle. The digest returns live/idle state, 24h/7d turns, 7d/30d spend, recent failed runs, unresolved product errors, failed notifications, and a next action per seat. Fleet real-turn counts use the same seat-run association as \`agent.list_runs\`, filtered to real runs. Scheduled agents are checked in rounded five-minute buckets, so a minute-level cron inside the bucket queues one work order for that bucket rather than one order per minute. Sandbox dry runs do not count as real turns. If the agent is repeatedly blocked, revise the Charter or split the seat. If the agent is taking too much judgment, narrow its autonomous scope.`
|
|
42237
42238
|
},
|
|
@@ -42378,7 +42379,7 @@ External connectors are being rolled out provider by provider, conservatively (r
|
|
|
42378
42379
|
order: 48,
|
|
42379
42380
|
title: "CLI and MCP installation guide",
|
|
42380
42381
|
summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
|
|
42381
|
-
version: "2026-06-
|
|
42382
|
+
version: "2026-06-21.5",
|
|
42382
42383
|
public: true,
|
|
42383
42384
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
42384
42385
|
stages: ["company_setup", "staffing"],
|
|
@@ -42784,6 +42785,8 @@ Ergonomic subcommands for everyday operation. Each wrapper is sugar over the sam
|
|
|
42784
42785
|
|
|
42785
42786
|
These ergonomic wrappers (including the \`{{cli}} agent\` group) require **{{cli}} 0.2.0 or newer** \u2014 run \`npx {{cliPackage}}@latest \u2026\` to get them. Older versions can still reach every command through the \`{{cli}} command <id> --json\` floor, since command execution is server-side.
|
|
42786
42787
|
|
|
42788
|
+
The signed-in app exposes the same Skill command surface under **Skills** in the left sidebar. Use \`/skills\` to filter the tenant library, \`/skills/new\` to build canonical \`SKILL.md\` frontmatter with \`tool.catalog\` dependencies, \`/skills/import\` for bounded GitHub or upload imports, and each Skill detail page to review validation, publish, check Seat dependencies, and assign a published version. During \`/agents/new\`, \`agent_setup.get\` can return \`next_action: "choose_skills"\`; selected Skills are proposed immutable-version assignments and required Skill tools block sign-off/go-live until tool configuration is ready.
|
|
42789
|
+
|
|
42787
42790
|
| Command | Command ids | Purpose | Scope | Safe example |
|
|
42788
42791
|
|---|---|---|---|---|
|
|
42789
42792
|
| \`{{cli}} task list|accept|decline|complete|create\` | \`task.list\`, \`task.accept\`, \`task.decline\`, \`task.complete\`, \`task.create\` | Operate a seat's task queue. | Seat | \`{{cli}} task list --json\` |
|
|
@@ -42801,11 +42804,29 @@ These ergonomic wrappers (including the \`{{cli}} agent\` group) require **{{cli
|
|
|
42801
42804
|
| \`{{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. 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\` |
|
|
42802
42805
|
| \`{{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\` |
|
|
42803
42806
|
| \`{{cli}} skills list|get|file|assigned|check-dependencies\` | \`skill.list\`, \`skill.get\`, \`skill.file.get\`, \`skill.assigned.list\`, \`skill.check_dependencies\` | Discover reusable Skills, read descriptors and stored package files, list approved Seat assignments, and compare required/optional tool dependencies with a Seat's signed Charter manifest. Skills are instructions, not authority. | Tenant and seat | \`{{cli}} skills list --json\`; \`{{cli}} skills file --slug invoice-review --path SKILL.md\` |
|
|
42807
|
+
| \`{{cli}} skills catalog|enable|install|sync\` | \`skill.catalog\`, \`skill.enable_catalog\`, \`skill.install_local\`, \`skill.sync_local\` | Discover entitled ROST catalog Skills, enable a catalog Skill into the company library with human confirmation, and install or sync approved Skill files locally from ROST APIs. Private catalog source URLs and GitHub tokens never go to local agents. | Tenant and seat | \`{{cli}} skills sync --seat-id <id> --client codex\`; \`{{cli}} skills install rost/ap-review --seat-id <id> --client codex\` |
|
|
42804
42808
|
| \`{{cli}} skills create|update-draft|import|publish|assign|revoke\` | \`skill.create\`, \`skill.update_draft\`, \`skill.import_github\`, \`skill.import_upload\`, \`skill.publish\`, \`skill.assign_to_seat\`, \`skill.revoke_from_seat\` | Create or import bounded text Skill packages, publish reviewed immutable versions, propose or approve Seat assignments, and revoke future use without deleting historical activations. Publish, revoke, and approved assignment stop at human confirmation; blocked required tools cannot be approved. | Tenant and seat | \`{{cli}} skills import github --url https://github.com/acme/skills/tree/main/ap --json\`; \`{{cli}} skills assign --seat-id <id> --slug invoice-review --json\` |
|
|
42805
42809
|
| \`{{cli}} model list\` | \`model.catalog\` | List guided model tiers with recommendations, token prices, cost bands, best-fit work, and model ids for \`--model\`. | Tenant | \`{{cli}} model list --json\` |
|
|
42806
42810
|
| \`{{cli}} compass show\` | \`compass.show_markdown\` | Render the current Compass as a clean markdown card for review. | Tenant | \`{{cli}} compass show --markdown\` |
|
|
42807
42811
|
| \`{{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\` |
|
|
42808
42812
|
|
|
42813
|
+
Skills wrapper help:
|
|
42814
|
+
|
|
42815
|
+
\`\`\`text
|
|
42816
|
+
{{cli}} skills list [--json]
|
|
42817
|
+
{{cli}} skills catalog [--json]
|
|
42818
|
+
{{cli}} skills get --slug <slug> [--json]
|
|
42819
|
+
{{cli}} skills file --slug <slug> --path SKILL.md
|
|
42820
|
+
{{cli}} skills enable rost/<slug> [--json]
|
|
42821
|
+
{{cli}} skills install <slug-or-rost/slug> [--seat-id <id>] [--client claude-code|codex|cursor] [--version <n>] [--local-only] [--json]
|
|
42822
|
+
{{cli}} skills sync --seat-id <id> [--client claude-code|codex|cursor] [--json]
|
|
42823
|
+
{{cli}} skills assign --seat-id <id> (--skill <slug>|--slug <slug>|--skill-version-id <id>) [--approve] [--allow-blocked-proposal] [--json]
|
|
42824
|
+
{{cli}} skills revoke (--assignment-id <id>|--seat-id <id> --skill <slug>) [--json]
|
|
42825
|
+
{{cli}} skills publish (--slug <slug>|--skill-version-id <id>) [--allow-warnings] [--json]
|
|
42826
|
+
\`\`\`
|
|
42827
|
+
|
|
42828
|
+
\`{{cli}} skills install\` writes into the client Skills directory and records \`.rost-skill.json\` with \`skill_version_id\`, \`content_sha256\`, source, client, and \`installed_from: "rost_api"\`. Set \`ROST_SKILL_INSTALL_ROOT\` to override the local root in CI or a sandbox. Use \`install\` for one Skill and \`sync\` as the default local-agent command because it installs every approved Skill assigned to the Seat and skips unchanged local copies by hash. Entitlement failures mean the tenant cannot access that ROST catalog tier yet; stale local copies are fixed by rerunning \`sync\`; private catalog access is always served by ROST APIs, not by giving the agent a private GitHub credential.
|
|
42829
|
+
|
|
42809
42830
|
### MCP registration
|
|
42810
42831
|
|
|
42811
42832
|
| Command | Purpose | Scope | Safe example |
|
|
@@ -42902,8 +42923,8 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
42902
42923
|
| \`rost_list_agent_fleet\` | \`agent.list_fleet\` | Read every staffed agent seat at once: lane, live state, last real turn, 24h/7d real turns, measurable status, escalations, and 7-day spend. | Tenant | Call with \`{}\`; counts use the same seat-run association as \`agent.list_runs\`, with sandbox dry runs excluded from real turns. |
|
|
42903
42924
|
| \`rost_get_dogfood_fleet_health_digest\` | \`agent.fleet_digest\` | Capture the daily dogfood fleet-health digest: live/idle state, 24h/7d turns, spend, recent failed runs, unresolved errors, failed notifications, and next actions. | Tenant | Call with \`{}\`; optional \`window_hours\` bounds recent failed-run evidence, while \`error_limit\` caps linked evidence per seat. |
|
|
42904
42925
|
| \`rost_run_agent_now\` | \`agent.run_now\` | Queue an immediate run for a live staffed agent without changing its saved schedule; cloud lane dispatches to the executor and runner lane queues for the paired runner. | Tenant | Call with \`{"seat_id":"<seat-id>"}\`. |
|
|
42905
|
-
| \`rost_list_agent_runs\` | \`agent.list_runs\` | Read a seat's agent run history (status, lane, model, cost, per-run tool-call and guard-held counts) plus the seat's run/tool-call rollup including held-action count. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`; pass \`limit\` for a deeper window. |
|
|
42906
|
-
| \`rost_get_agent_run_diagnostics\` | \`agent.get_run\` | Read one run's diagnostic record: transcript reference, token/cost usage, outcome,
|
|
42926
|
+
| \`rost_list_agent_runs\` | \`agent.list_runs\` | Read a seat's agent run history (status, lane, model, cost, per-run Skill activation, tool-call, and guard-held counts) plus the seat's run/tool-call rollup including held-action count. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`; pass \`limit\` for a deeper window. |
|
|
42927
|
+
| \`rost_get_agent_run_diagnostics\` | \`agent.get_run\` | Read one run's diagnostic record: transcript reference, token/cost usage, outcome, linked product-visible run errors, and loaded Skill activation file metadata. File hashes/sizes identify the immutable source package, while model prompt text may be bounded or truncated. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>","run_id":"<run-id>"}\`. |
|
|
42907
42928
|
| \`rost_list_agent_tool_calls\` | \`agent.list_tool_calls\` | Read a seat's tool-call ledger (tool name, guard result, manifest clause, outcome) with the held-action count as the hero metric. Never returns argument summaries or secret material. | Seat or tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`; pass \`held_only: true\` for only guard-held calls. |
|
|
42908
42929
|
| \`rost_list_agent_templates\` | \`agent_template.list\` | List stock agent templates and metadata. | Tenant | Call with \`{}\`. |
|
|
42909
42930
|
| \`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. |
|
|
@@ -42968,6 +42989,10 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
42968
42989
|
| \`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>"}\`. |
|
|
42969
42990
|
| \`rost_list_tool_catalog\` | \`tool.catalog\` | List the discoverable tool catalog the agent builder reads \u2014 id, prescriptive description, scope tiers, credential requirement, access policy, and execution-boundary guidance. | Tenant | Call with \`{}\` or \`{"provider":"google"}\`. |
|
|
42970
42991
|
| \`rost_list_skills\` | \`skill.list\` | List tenant Skills with application descriptors, dependency metadata, source status, latest version, and assigned Seat count. Seat-scoped reads are available through \`rost://skills\`. | Tenant-admin | Call with \`{}\` or \`{"query":"invoice"}\`. |
|
|
42992
|
+
| \`rost_list_rost_skill_catalog\` | \`skill.catalog\` | List entitled ROST catalog Skills. Private catalog source URLs and credentials stay server-side. | Tenant-admin | Call with \`{}\`; use \`{"include_unentitled":true}\` only to inspect tier availability. |
|
|
42993
|
+
| \`rost_enable_rost_catalog_skill\` | \`skill.enable_catalog\` | Enable an entitled ROST catalog Skill into the company library with human confirmation. | Tenant-admin | Call with \`{"slug":"rost/ap-review"}\`; non-interactive callers receive a confirmation handoff. |
|
|
42994
|
+
| \`rost_install_skill_locally\` | \`skill.install_local\` | Resolve company or entitled ROST catalog Skill files from ROST APIs for a local client install. It returns package files and metadata, not private GitHub URLs. | Tenant-admin | Call with \`{"slug":"invoice-review","client":"codex"}\`; \`rost/<slug>\` enablement may require confirmation. |
|
|
42995
|
+
| \`rost_sync_assigned_skills_locally\` | \`skill.sync_local\` | Resolve every approved Skill assigned to a Seat plus revoked local-copy markers for a local client sync. | Tenant-admin | Call with \`{"seat_id":"<seat-id>","client":"codex"}\`; local clients remove revoked copies. |
|
|
42971
42996
|
| \`rost_get_skill\` | \`skill.get\` | Read one Skill descriptor and latest stored version metadata. Seat-scoped reads are available through \`rost://skills/{slug}\`. | Tenant-admin | Call with \`{"slug":"invoice-review"}\`. |
|
|
42972
42997
|
| \`rost_get_skill_file\` | \`skill.file.get\` | Read stored Skill package file content by slug and package path; paths resolve only inside the stored package payload. Seat-scoped reads are available through \`rost://skills/{slug}/files/{path}\`. | Tenant-admin | Call with \`{"slug":"invoice-review","path":"SKILL.md"}\`. |
|
|
42973
42998
|
| \`rost_list_assigned_skills\` | \`skill.assigned.list\` | List approved Skill assignments for a Seat, including immutable version, dependency status, rationale, and approval time. Seat-scoped reads are available through \`rost://seat/{id}/skills\`. | Tenant-admin | Call with \`{"seat_id":"<seat-id>"}\`. |
|
|
@@ -46626,6 +46651,431 @@ function ensureTrailingSlash2(value) {
|
|
|
46626
46651
|
return value.endsWith("/") ? value : `${value}/`;
|
|
46627
46652
|
}
|
|
46628
46653
|
|
|
46654
|
+
// src/skills.ts
|
|
46655
|
+
import { existsSync, mkdirSync, readFileSync as readFileSync3, rmSync, writeFileSync } from "node:fs";
|
|
46656
|
+
import os from "node:os";
|
|
46657
|
+
import path2 from "node:path";
|
|
46658
|
+
var UsageError2 = class extends Error {
|
|
46659
|
+
};
|
|
46660
|
+
var CLIENTS = /* @__PURE__ */ new Set(["claude-code", "codex", "cursor"]);
|
|
46661
|
+
function skillsUsage2(binName = cliBrand.binName) {
|
|
46662
|
+
return [
|
|
46663
|
+
`${binName} skills list [--json]`,
|
|
46664
|
+
`${binName} skills catalog [--json]`,
|
|
46665
|
+
`${binName} skills get --slug <slug> [--json]`,
|
|
46666
|
+
`${binName} skills file --slug <slug> --path SKILL.md`,
|
|
46667
|
+
`${binName} skills enable rost/<slug> [--json]`,
|
|
46668
|
+
`${binName} skills install <slug-or-rost/slug> [--seat-id <id>] [--client claude-code|codex|cursor] [--version <n>] [--local-only] [--json]`,
|
|
46669
|
+
`${binName} skills sync --seat-id <id> [--client claude-code|codex|cursor] [--json]`,
|
|
46670
|
+
`${binName} skills assign --seat-id <id> (--skill <slug>|--slug <slug>|--skill-version-id <id>) [--approve] [--allow-blocked-proposal] [--json]`,
|
|
46671
|
+
`${binName} skills revoke (--assignment-id <id>|--seat-id <id> --skill <slug>) [--json]`,
|
|
46672
|
+
`${binName} skills publish (--slug <slug>|--skill-version-id <id>) [--allow-warnings] [--json]`
|
|
46673
|
+
].join("\n");
|
|
46674
|
+
}
|
|
46675
|
+
async function runSkills(context, args, env = process.env) {
|
|
46676
|
+
try {
|
|
46677
|
+
const [action, ...rest] = args;
|
|
46678
|
+
if (action === "help" || action === "--help" || action === "-h" || action === void 0) {
|
|
46679
|
+
context.io.stdout.write(`${skillsUsage2(context.binName)}
|
|
46680
|
+
`);
|
|
46681
|
+
return action === void 0 ? 1 : 0;
|
|
46682
|
+
}
|
|
46683
|
+
if (action === "list") {
|
|
46684
|
+
return context.run(context.client, "skill.list", {}, void 0);
|
|
46685
|
+
}
|
|
46686
|
+
if (action === "catalog") {
|
|
46687
|
+
const parsed = parseFlags2(rest, /* @__PURE__ */ new Set(["include-unentitled"]));
|
|
46688
|
+
return context.run(context.client, "skill.catalog", {
|
|
46689
|
+
...parsed.flags.has("include-unentitled") ? { include_unentitled: true } : {}
|
|
46690
|
+
}, parsed.json ? void 0 : formatCatalog);
|
|
46691
|
+
}
|
|
46692
|
+
if (action === "get") {
|
|
46693
|
+
const parsed = parseFlags2(rest);
|
|
46694
|
+
return context.run(context.client, "skill.get", { slug: requireValue3(parsed, "slug") }, parsed.json ? void 0 : formatSkillDetail2);
|
|
46695
|
+
}
|
|
46696
|
+
if (action === "file") {
|
|
46697
|
+
const parsed = parseFlags2(rest);
|
|
46698
|
+
return context.run(context.client, "skill.file.get", {
|
|
46699
|
+
slug: requireValue3(parsed, "slug"),
|
|
46700
|
+
path: requireValue3(parsed, "path")
|
|
46701
|
+
}, (output) => {
|
|
46702
|
+
const content = asRecord2(output).content;
|
|
46703
|
+
return typeof content === "string" ? content : JSON.stringify(output, null, 2);
|
|
46704
|
+
});
|
|
46705
|
+
}
|
|
46706
|
+
if (action === "enable") {
|
|
46707
|
+
const slug2 = rest[0];
|
|
46708
|
+
if (!slug2 || slug2.startsWith("--")) {
|
|
46709
|
+
throw new UsageError2(`Usage: ${context.binName} skills enable rost/<slug> [--json]`);
|
|
46710
|
+
}
|
|
46711
|
+
const parsed = parseFlags2(rest.slice(1));
|
|
46712
|
+
return context.run(context.client, "skill.enable_catalog", { slug: slug2 }, parsed.json ? void 0 : formatEnable);
|
|
46713
|
+
}
|
|
46714
|
+
if (action === "install") {
|
|
46715
|
+
return installOne(context, rest, env);
|
|
46716
|
+
}
|
|
46717
|
+
if (action === "sync") {
|
|
46718
|
+
return syncAssigned(context, rest, env);
|
|
46719
|
+
}
|
|
46720
|
+
if (action === "assign") {
|
|
46721
|
+
const parsed = parseFlags2(rest, /* @__PURE__ */ new Set(["approve", "allow-blocked-proposal"]));
|
|
46722
|
+
const body = withDefined({
|
|
46723
|
+
seat_id: requireValue3(parsed, "seat-id"),
|
|
46724
|
+
status: parsed.flags.has("approve") ? "approved" : "proposed",
|
|
46725
|
+
rationale: optionalValue2(parsed, "rationale") ?? "Skill selected for this Seat.",
|
|
46726
|
+
allow_blocked_proposal: parsed.flags.has("allow-blocked-proposal")
|
|
46727
|
+
}, {
|
|
46728
|
+
slug: optionalValue2(parsed, "skill") ?? optionalValue2(parsed, "slug"),
|
|
46729
|
+
skill_version_id: optionalValue2(parsed, "skill-version-id")
|
|
46730
|
+
});
|
|
46731
|
+
return context.run(context.client, "skill.assign_to_seat", body, parsed.json ? void 0 : formatAssignment2, { targetSeatId: body.seat_id });
|
|
46732
|
+
}
|
|
46733
|
+
if (action === "revoke") {
|
|
46734
|
+
const parsed = parseFlags2(rest);
|
|
46735
|
+
const seatId = optionalValue2(parsed, "seat-id");
|
|
46736
|
+
const body = withDefined({}, {
|
|
46737
|
+
assignment_id: optionalValue2(parsed, "assignment-id"),
|
|
46738
|
+
seat_id: seatId,
|
|
46739
|
+
slug: optionalValue2(parsed, "skill") ?? optionalValue2(parsed, "slug"),
|
|
46740
|
+
skill_version_id: optionalValue2(parsed, "skill-version-id"),
|
|
46741
|
+
rationale: optionalValue2(parsed, "rationale")
|
|
46742
|
+
});
|
|
46743
|
+
return context.run(context.client, "skill.revoke_from_seat", body, parsed.json ? void 0 : formatRevoke, seatId ? { targetSeatId: seatId } : {});
|
|
46744
|
+
}
|
|
46745
|
+
if (action === "publish") {
|
|
46746
|
+
const parsed = parseFlags2(rest, /* @__PURE__ */ new Set(["allow-warnings"]));
|
|
46747
|
+
const body = withDefined({
|
|
46748
|
+
allow_warnings: parsed.flags.has("allow-warnings")
|
|
46749
|
+
}, {
|
|
46750
|
+
slug: optionalValue2(parsed, "slug"),
|
|
46751
|
+
skill_version_id: optionalValue2(parsed, "skill-version-id")
|
|
46752
|
+
});
|
|
46753
|
+
return context.run(context.client, "skill.publish", body, parsed.json ? void 0 : formatPublish);
|
|
46754
|
+
}
|
|
46755
|
+
throw new UsageError2(`Unknown skills action: ${action}`);
|
|
46756
|
+
} catch (error51) {
|
|
46757
|
+
if (error51 instanceof UsageError2) {
|
|
46758
|
+
context.io.stderr.write(`${error51.message}
|
|
46759
|
+
`);
|
|
46760
|
+
return 1;
|
|
46761
|
+
}
|
|
46762
|
+
if (error51 instanceof CommandClientError) {
|
|
46763
|
+
return printCommandError(context.io, error51);
|
|
46764
|
+
}
|
|
46765
|
+
throw error51;
|
|
46766
|
+
}
|
|
46767
|
+
}
|
|
46768
|
+
async function installOne(context, args, env) {
|
|
46769
|
+
const slug2 = args[0];
|
|
46770
|
+
if (!slug2 || slug2.startsWith("--")) {
|
|
46771
|
+
throw new UsageError2(`Usage: ${context.binName} skills install <slug-or-rost/slug> [--seat-id <id>] [--client claude-code|codex|cursor] [--version <n>] [--local-only] [--json]`);
|
|
46772
|
+
}
|
|
46773
|
+
const parsed = parseFlags2(args.slice(1), /* @__PURE__ */ new Set(["local-only"]));
|
|
46774
|
+
const client = parseClient2(optionalValue2(parsed, "client") ?? "codex");
|
|
46775
|
+
const seatId = optionalValue2(parsed, "seat-id");
|
|
46776
|
+
const body = withDefined({
|
|
46777
|
+
slug: slug2,
|
|
46778
|
+
client,
|
|
46779
|
+
local_only: parsed.flags.has("local-only")
|
|
46780
|
+
}, {
|
|
46781
|
+
seat_id: seatId,
|
|
46782
|
+
version: optionalNumber2(parsed, "version")
|
|
46783
|
+
});
|
|
46784
|
+
const options = seatId ? { targetSeatId: seatId } : {};
|
|
46785
|
+
const output = await executeInstallCommand(context, body, options);
|
|
46786
|
+
const summary = applyLocalSkillChanges(output, client, env, { removeRevoked: false });
|
|
46787
|
+
const outputRecord = asRecord2(output);
|
|
46788
|
+
context.io.stdout.write(parsed.json ? `${JSON.stringify({ ...outputRecord, local: summary }, null, 2)}
|
|
46789
|
+
` : `${formatLocalSummary(summary)}
|
|
46790
|
+
`);
|
|
46791
|
+
return 0;
|
|
46792
|
+
}
|
|
46793
|
+
async function syncAssigned(context, args, env) {
|
|
46794
|
+
const parsed = parseFlags2(args);
|
|
46795
|
+
const seatId = requireValue3(parsed, "seat-id");
|
|
46796
|
+
const client = parseClient2(optionalValue2(parsed, "client") ?? "codex");
|
|
46797
|
+
const output = await executeSkillCommand(context, "skill.sync_local", {
|
|
46798
|
+
seat_id: seatId,
|
|
46799
|
+
client
|
|
46800
|
+
}, { targetSeatId: seatId });
|
|
46801
|
+
const summary = applyLocalSkillChanges(output, client, env, { removeRevoked: true });
|
|
46802
|
+
const outputRecord = asRecord2(output);
|
|
46803
|
+
context.io.stdout.write(parsed.json ? `${JSON.stringify({ ...outputRecord, local: summary }, null, 2)}
|
|
46804
|
+
` : `${formatLocalSummary(summary)}
|
|
46805
|
+
`);
|
|
46806
|
+
return 0;
|
|
46807
|
+
}
|
|
46808
|
+
async function executeInstallCommand(context, body, options) {
|
|
46809
|
+
const slug2 = typeof body.slug === "string" ? body.slug : "";
|
|
46810
|
+
if (slug2.startsWith("rost/") && body.local_only !== true) {
|
|
46811
|
+
try {
|
|
46812
|
+
return await executeSkillCommand(context, "skill.install_local", { ...body, local_only: true }, options);
|
|
46813
|
+
} catch (error51) {
|
|
46814
|
+
if (!isCommandConflict(error51)) {
|
|
46815
|
+
throw error51;
|
|
46816
|
+
}
|
|
46817
|
+
}
|
|
46818
|
+
}
|
|
46819
|
+
return executeSkillCommand(context, "skill.install_local", body, options);
|
|
46820
|
+
}
|
|
46821
|
+
async function executeSkillCommand(context, commandId, body, options = {}) {
|
|
46822
|
+
try {
|
|
46823
|
+
const output = await context.client.execute(commandId, body, options);
|
|
46824
|
+
return output.output;
|
|
46825
|
+
} catch (error51) {
|
|
46826
|
+
const pending = context.io.interactive === true ? pendingConfirmationFromError(error51) : null;
|
|
46827
|
+
if (pending && pending.commandId === commandId) {
|
|
46828
|
+
context.io.stderr.write(`Approving ${pending.commandId} confirmation ${pending.confirmationId} as the interactive CLI user.
|
|
46829
|
+
`);
|
|
46830
|
+
const approved = await context.client.execute("confirmation.approve", { confirmation_id: pending.confirmationId });
|
|
46831
|
+
return asRecord2(approved.output).output ?? approved.output;
|
|
46832
|
+
}
|
|
46833
|
+
throw error51;
|
|
46834
|
+
}
|
|
46835
|
+
}
|
|
46836
|
+
function applyLocalSkillChanges(output, client, env, options) {
|
|
46837
|
+
const root = installRoot(client, env);
|
|
46838
|
+
const changes = writeInstalls(output, root);
|
|
46839
|
+
if (options.removeRevoked) {
|
|
46840
|
+
changes.push(...removeRevokedInstalls(output, root));
|
|
46841
|
+
}
|
|
46842
|
+
return changes;
|
|
46843
|
+
}
|
|
46844
|
+
function writeInstalls(output, root) {
|
|
46845
|
+
const installs = asArray2(asRecord2(output).installs);
|
|
46846
|
+
return installs.map((entry) => {
|
|
46847
|
+
const install = asRecord2(entry);
|
|
46848
|
+
const slug2 = safeLocalSlug(String(install.slug ?? ""));
|
|
46849
|
+
const metadata = asRecord2(install.metadata);
|
|
46850
|
+
const files = asArray2(install.files).map(asRecord2);
|
|
46851
|
+
const dir = path2.join(root, slug2);
|
|
46852
|
+
const metadataPath = path2.join(dir, ".rost-skill.json");
|
|
46853
|
+
const expectedHash = String(metadata.content_sha256 ?? "");
|
|
46854
|
+
if (existingHash(metadataPath) === expectedHash) {
|
|
46855
|
+
return { slug: slug2, dir, status: "unchanged", files: files.length };
|
|
46856
|
+
}
|
|
46857
|
+
rmSync(dir, { recursive: true, force: true });
|
|
46858
|
+
mkdirSync(dir, { recursive: true });
|
|
46859
|
+
for (const file2 of files) {
|
|
46860
|
+
const relativePath = safeRelativePath(String(file2.path ?? ""));
|
|
46861
|
+
const content = String(file2.content ?? "");
|
|
46862
|
+
const target = path2.join(dir, relativePath);
|
|
46863
|
+
mkdirSync(path2.dirname(target), { recursive: true });
|
|
46864
|
+
writeFileSync(target, content, "utf8");
|
|
46865
|
+
}
|
|
46866
|
+
writeFileSync(metadataPath, `${JSON.stringify(metadata, null, 2)}
|
|
46867
|
+
`, "utf8");
|
|
46868
|
+
return { slug: slug2, dir, status: "installed", files: files.length };
|
|
46869
|
+
});
|
|
46870
|
+
}
|
|
46871
|
+
function removeRevokedInstalls(output, root) {
|
|
46872
|
+
const installs = new Set(asArray2(asRecord2(output).installs).map((entry) => {
|
|
46873
|
+
const slug2 = asRecord2(entry).slug;
|
|
46874
|
+
return typeof slug2 === "string" ? slug2 : "";
|
|
46875
|
+
}));
|
|
46876
|
+
const revoked = asArray2(asRecord2(output).revoked);
|
|
46877
|
+
const changes = [];
|
|
46878
|
+
for (const entry of revoked) {
|
|
46879
|
+
const slug2 = safeLocalSlug(String(asRecord2(entry).slug ?? ""));
|
|
46880
|
+
if (installs.has(slug2)) {
|
|
46881
|
+
continue;
|
|
46882
|
+
}
|
|
46883
|
+
const dir = path2.join(root, slug2);
|
|
46884
|
+
if (!existsSync(dir)) {
|
|
46885
|
+
continue;
|
|
46886
|
+
}
|
|
46887
|
+
rmSync(dir, { recursive: true, force: true });
|
|
46888
|
+
changes.push({ slug: slug2, dir, status: "removed", files: 0 });
|
|
46889
|
+
}
|
|
46890
|
+
return changes;
|
|
46891
|
+
}
|
|
46892
|
+
function installRoot(client, env) {
|
|
46893
|
+
const override = env.ROST_SKILL_INSTALL_ROOT;
|
|
46894
|
+
if (override && override.length > 0) {
|
|
46895
|
+
return path2.resolve(override, client);
|
|
46896
|
+
}
|
|
46897
|
+
if (client === "codex") {
|
|
46898
|
+
return path2.join(env.CODEX_HOME ?? path2.join(os.homedir(), ".codex"), "skills", "rost");
|
|
46899
|
+
}
|
|
46900
|
+
if (client === "claude-code") {
|
|
46901
|
+
return path2.join(env.CLAUDE_HOME ?? path2.join(os.homedir(), ".claude"), "skills", "rost");
|
|
46902
|
+
}
|
|
46903
|
+
return path2.join(os.homedir(), ".cursor", "skills", "rost");
|
|
46904
|
+
}
|
|
46905
|
+
function safeRelativePath(value) {
|
|
46906
|
+
const normalized = value.trim().replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
46907
|
+
if (!normalized || normalized.startsWith("/") || normalized.includes("//") || normalized.split("/").includes("..")) {
|
|
46908
|
+
throw new UsageError2("Server returned an invalid skill file path.");
|
|
46909
|
+
}
|
|
46910
|
+
return normalized;
|
|
46911
|
+
}
|
|
46912
|
+
function safeLocalSlug(value) {
|
|
46913
|
+
if (!/^[a-z0-9][a-z0-9-]{1,80}$/.test(value)) {
|
|
46914
|
+
throw new UsageError2("Server returned an invalid skill slug.");
|
|
46915
|
+
}
|
|
46916
|
+
return value;
|
|
46917
|
+
}
|
|
46918
|
+
function existingHash(metadataPath) {
|
|
46919
|
+
if (!existsSync(metadataPath)) {
|
|
46920
|
+
return null;
|
|
46921
|
+
}
|
|
46922
|
+
try {
|
|
46923
|
+
const parsed = JSON.parse(readFileSync3(metadataPath, "utf8"));
|
|
46924
|
+
const hash2 = asRecord2(parsed).content_sha256;
|
|
46925
|
+
return typeof hash2 === "string" ? hash2 : null;
|
|
46926
|
+
} catch {
|
|
46927
|
+
return null;
|
|
46928
|
+
}
|
|
46929
|
+
}
|
|
46930
|
+
function parseFlags2(args, booleanFlags = /* @__PURE__ */ new Set()) {
|
|
46931
|
+
const values = /* @__PURE__ */ new Map();
|
|
46932
|
+
const flags = /* @__PURE__ */ new Set();
|
|
46933
|
+
let json2 = false;
|
|
46934
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
46935
|
+
const token = args[index];
|
|
46936
|
+
if (token === void 0) {
|
|
46937
|
+
continue;
|
|
46938
|
+
}
|
|
46939
|
+
if (!token.startsWith("--")) {
|
|
46940
|
+
throw new UsageError2(`Unexpected argument: ${token}`);
|
|
46941
|
+
}
|
|
46942
|
+
const key = token.slice(2);
|
|
46943
|
+
if (key === "json") {
|
|
46944
|
+
json2 = true;
|
|
46945
|
+
continue;
|
|
46946
|
+
}
|
|
46947
|
+
if (booleanFlags.has(key)) {
|
|
46948
|
+
flags.add(key);
|
|
46949
|
+
continue;
|
|
46950
|
+
}
|
|
46951
|
+
const value = args[index + 1];
|
|
46952
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
46953
|
+
flags.add(key);
|
|
46954
|
+
continue;
|
|
46955
|
+
}
|
|
46956
|
+
values.set(key, value);
|
|
46957
|
+
index += 1;
|
|
46958
|
+
}
|
|
46959
|
+
return { json: json2, values, flags };
|
|
46960
|
+
}
|
|
46961
|
+
function requireValue3(parsed, key) {
|
|
46962
|
+
const value = optionalValue2(parsed, key);
|
|
46963
|
+
if (value === void 0) {
|
|
46964
|
+
throw new UsageError2(`Missing required --${key} value.`);
|
|
46965
|
+
}
|
|
46966
|
+
return value;
|
|
46967
|
+
}
|
|
46968
|
+
function optionalValue2(parsed, key) {
|
|
46969
|
+
const value = parsed.values.get(key);
|
|
46970
|
+
return value && value.length > 0 ? value : void 0;
|
|
46971
|
+
}
|
|
46972
|
+
function optionalNumber2(parsed, key) {
|
|
46973
|
+
const value = optionalValue2(parsed, key);
|
|
46974
|
+
if (value === void 0) {
|
|
46975
|
+
return void 0;
|
|
46976
|
+
}
|
|
46977
|
+
const parsedNumber = Number(value);
|
|
46978
|
+
if (!Number.isSafeInteger(parsedNumber) || parsedNumber <= 0) {
|
|
46979
|
+
throw new UsageError2(`--${key} must be a positive integer.`);
|
|
46980
|
+
}
|
|
46981
|
+
return parsedNumber;
|
|
46982
|
+
}
|
|
46983
|
+
function parseClient2(value) {
|
|
46984
|
+
if (!CLIENTS.has(value)) {
|
|
46985
|
+
throw new UsageError2("--client must be claude-code, codex, or cursor.");
|
|
46986
|
+
}
|
|
46987
|
+
return value;
|
|
46988
|
+
}
|
|
46989
|
+
function isCommandConflict(error51) {
|
|
46990
|
+
return error51 instanceof CommandClientError && error51.status === 409;
|
|
46991
|
+
}
|
|
46992
|
+
function withDefined(base, extra) {
|
|
46993
|
+
const next = { ...base };
|
|
46994
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
46995
|
+
if (value !== void 0) {
|
|
46996
|
+
next[key] = value;
|
|
46997
|
+
}
|
|
46998
|
+
}
|
|
46999
|
+
return next;
|
|
47000
|
+
}
|
|
47001
|
+
function asRecord2(value) {
|
|
47002
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
47003
|
+
}
|
|
47004
|
+
function asArray2(value) {
|
|
47005
|
+
return Array.isArray(value) ? value : [];
|
|
47006
|
+
}
|
|
47007
|
+
function formatCatalog(output) {
|
|
47008
|
+
const entries = asArray2(asRecord2(output).catalog);
|
|
47009
|
+
if (entries.length === 0) {
|
|
47010
|
+
return "No ROST catalog skills are available for this tenant.";
|
|
47011
|
+
}
|
|
47012
|
+
return entries.map((entry) => {
|
|
47013
|
+
const record2 = asRecord2(entry);
|
|
47014
|
+
return `${record2.catalog_slug} [${record2.tier}/${record2.entitlement_status}] ${record2.name}`;
|
|
47015
|
+
}).join("\n");
|
|
47016
|
+
}
|
|
47017
|
+
function formatSkillDetail2(output) {
|
|
47018
|
+
const skill = asRecord2(asRecord2(output).skill);
|
|
47019
|
+
return `${skill.slug} v${skill.latest_version ?? "\u2014"} [${skill.status}] ${skill.name}
|
|
47020
|
+
${skill.description}`;
|
|
47021
|
+
}
|
|
47022
|
+
function formatEnable(output) {
|
|
47023
|
+
const skill = asRecord2(asRecord2(output).skill);
|
|
47024
|
+
const catalog = asRecord2(asRecord2(output).catalog);
|
|
47025
|
+
return `Enabled ${catalog.catalog_slug} as ${skill.slug} v${skill.version} (${skill.skill_version_id})`;
|
|
47026
|
+
}
|
|
47027
|
+
function formatAssignment2(output) {
|
|
47028
|
+
const assignment = asRecord2(asRecord2(output).assignment);
|
|
47029
|
+
return `${assignment.status} ${assignment.slug} for seat ${assignment.seat_id}; sync: ${String(asRecord2(output).local_sync_next_step)}`;
|
|
47030
|
+
}
|
|
47031
|
+
function formatRevoke(output) {
|
|
47032
|
+
const record2 = asRecord2(output);
|
|
47033
|
+
return `Revoked ${record2.slug} for seat ${record2.seat_id}; sync: ${record2.local_sync_next_step}`;
|
|
47034
|
+
}
|
|
47035
|
+
function formatPublish(output) {
|
|
47036
|
+
const skill = asRecord2(asRecord2(output).skill);
|
|
47037
|
+
return `Published ${skill.slug} v${skill.version} (${skill.skill_version_id})`;
|
|
47038
|
+
}
|
|
47039
|
+
function formatLocalSummary(summary) {
|
|
47040
|
+
if (summary.length === 0) {
|
|
47041
|
+
return "No skills to install.";
|
|
47042
|
+
}
|
|
47043
|
+
return summary.map((entry) => `${entry.status} ${entry.slug} -> ${entry.dir} (${entry.files} files)`).join("\n");
|
|
47044
|
+
}
|
|
47045
|
+
function printCommandError(io, error51) {
|
|
47046
|
+
if (error51.response && !error51.response.ok) {
|
|
47047
|
+
const payload = {
|
|
47048
|
+
code: error51.response.error.code,
|
|
47049
|
+
message: error51.response.error.message,
|
|
47050
|
+
...error51.response.error.details === void 0 ? {} : { details: error51.response.error.details },
|
|
47051
|
+
...error51.response.error.help === void 0 ? {} : { help: error51.response.error.help },
|
|
47052
|
+
...error51.response.requestId === void 0 ? {} : { requestId: error51.response.requestId }
|
|
47053
|
+
};
|
|
47054
|
+
io.stderr.write(`${redactForLog(payload)}
|
|
47055
|
+
`);
|
|
47056
|
+
if (error51.response.error.help !== void 0) {
|
|
47057
|
+
io.stderr.write(`\u2192 try: ${redactForLog(error51.response.error.help)}
|
|
47058
|
+
`);
|
|
47059
|
+
}
|
|
47060
|
+
return error51.status === 409 ? 3 : error51.status >= 400 && error51.status < 500 ? 1 : 2;
|
|
47061
|
+
}
|
|
47062
|
+
io.stderr.write(`${redactForLog(error51.message)}
|
|
47063
|
+
`);
|
|
47064
|
+
return error51.status >= 400 && error51.status < 500 ? 1 : 2;
|
|
47065
|
+
}
|
|
47066
|
+
function pendingConfirmationFromError(error51) {
|
|
47067
|
+
if (!(error51 instanceof CommandClientError) || !error51.response || error51.response.ok || error51.response.error.code !== "COMMAND_CONFIRMATION_REQUIRED") {
|
|
47068
|
+
return null;
|
|
47069
|
+
}
|
|
47070
|
+
const details = asRecord2(error51.response.error.details);
|
|
47071
|
+
const confirmationId = details.confirmationId;
|
|
47072
|
+
const commandId = details.commandId;
|
|
47073
|
+
if (typeof confirmationId !== "string" || confirmationId.length === 0 || typeof commandId !== "string" || commandId.length === 0) {
|
|
47074
|
+
return null;
|
|
47075
|
+
}
|
|
47076
|
+
return { confirmationId, commandId };
|
|
47077
|
+
}
|
|
47078
|
+
|
|
46629
47079
|
// src/index.ts
|
|
46630
47080
|
async function main(argv = process.argv.slice(2), options = {}) {
|
|
46631
47081
|
const io = options.io ?? {
|
|
@@ -46788,6 +47238,23 @@ Run ${cliBrand.binName} login --device again if the next command asks you to aut
|
|
|
46788
47238
|
if (command === "mcp") {
|
|
46789
47239
|
return executeMcp(io, client, config2.appUrl, args);
|
|
46790
47240
|
}
|
|
47241
|
+
if (command === "skills") {
|
|
47242
|
+
const skillsAction = args[0];
|
|
47243
|
+
if (skillsAction !== "catalog" && skillsAction !== "enable" && skillsAction !== "install" && skillsAction !== "sync") {
|
|
47244
|
+
return runOperation(command, args, {
|
|
47245
|
+
io,
|
|
47246
|
+
client,
|
|
47247
|
+
binName: cliBrand.binName,
|
|
47248
|
+
run: (wrapperClient, commandId, body, format, options2) => printCommandOutput(io, wrapperClient, commandId, body, format, options2)
|
|
47249
|
+
});
|
|
47250
|
+
}
|
|
47251
|
+
return runSkills({
|
|
47252
|
+
io,
|
|
47253
|
+
client,
|
|
47254
|
+
binName: cliBrand.binName,
|
|
47255
|
+
run: (wrapperClient, commandId, body, format, options2) => printCommandOutput(io, wrapperClient, commandId, body, format, options2)
|
|
47256
|
+
}, args);
|
|
47257
|
+
}
|
|
46791
47258
|
if (command === "init") {
|
|
46792
47259
|
return executeInit(io, client, config2.appUrl, args);
|
|
46793
47260
|
}
|
|
@@ -46887,7 +47354,7 @@ function extractSeatFlag(args) {
|
|
|
46887
47354
|
var SeatFlagError = class extends Error {
|
|
46888
47355
|
};
|
|
46889
47356
|
function formatCommandSchema(output) {
|
|
46890
|
-
const record2 =
|
|
47357
|
+
const record2 = asRecord3(output);
|
|
46891
47358
|
const lines = [
|
|
46892
47359
|
`${field2(record2, "id")} \u2014 ${field2(record2, "title")}`,
|
|
46893
47360
|
field2(record2, "description"),
|
|
@@ -46912,16 +47379,16 @@ function formatCommandSchema(output) {
|
|
|
46912
47379
|
return lines.join("\n");
|
|
46913
47380
|
}
|
|
46914
47381
|
function formatCommandList(output) {
|
|
46915
|
-
const commands = Array.isArray(
|
|
47382
|
+
const commands = Array.isArray(asRecord3(output).commands) ? asRecord3(output).commands : [];
|
|
46916
47383
|
if (commands.length === 0) {
|
|
46917
47384
|
return "No commands registered.";
|
|
46918
47385
|
}
|
|
46919
47386
|
return commands.map((entry) => {
|
|
46920
|
-
const record2 =
|
|
47387
|
+
const record2 = asRecord3(entry);
|
|
46921
47388
|
return `${field2(record2, "id")} [${field2(record2, "required_scope")}/${field2(record2, "confirmation")}] ${field2(record2, "title")}`;
|
|
46922
47389
|
}).join("\n");
|
|
46923
47390
|
}
|
|
46924
|
-
function
|
|
47391
|
+
function asRecord3(value) {
|
|
46925
47392
|
return typeof value === "object" && value !== null ? value : {};
|
|
46926
47393
|
}
|
|
46927
47394
|
function asStringArray(value) {
|
|
@@ -46982,7 +47449,7 @@ async function executeMcp(io, client, appUrl2, args, env = process.env) {
|
|
|
46982
47449
|
return 1;
|
|
46983
47450
|
}
|
|
46984
47451
|
if (error51 instanceof CommandClientError) {
|
|
46985
|
-
return
|
|
47452
|
+
return printCommandError2(io, error51);
|
|
46986
47453
|
}
|
|
46987
47454
|
io.stderr.write(`${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
46988
47455
|
`);
|
|
@@ -47038,30 +47505,30 @@ async function printCommandOutput(io, client, commandId, body = {}, format, opti
|
|
|
47038
47505
|
return 0;
|
|
47039
47506
|
} catch (error51) {
|
|
47040
47507
|
if (io.interactive === true) {
|
|
47041
|
-
const pending =
|
|
47508
|
+
const pending = pendingConfirmationFromError2(error51);
|
|
47042
47509
|
if (pending && pending.commandId === commandId) {
|
|
47043
47510
|
io.stderr.write(`Approving ${pending.commandId} confirmation ${pending.confirmationId} as the interactive CLI user.
|
|
47044
47511
|
`);
|
|
47045
47512
|
try {
|
|
47046
47513
|
const approved = await client.execute("confirmation.approve", { confirmation_id: pending.confirmationId });
|
|
47047
|
-
const approvedOutput =
|
|
47514
|
+
const approvedOutput = asRecord3(approved.output).output ?? approved.output;
|
|
47048
47515
|
const rendered = format ? format(approvedOutput) : JSON.stringify(approvedOutput, null, 2);
|
|
47049
47516
|
io.stdout.write(`${rendered}
|
|
47050
47517
|
`);
|
|
47051
47518
|
return 0;
|
|
47052
47519
|
} catch (approvalError) {
|
|
47053
|
-
return
|
|
47520
|
+
return printCommandError2(io, approvalError);
|
|
47054
47521
|
}
|
|
47055
47522
|
}
|
|
47056
47523
|
}
|
|
47057
|
-
return
|
|
47524
|
+
return printCommandError2(io, error51);
|
|
47058
47525
|
}
|
|
47059
47526
|
}
|
|
47060
|
-
function
|
|
47527
|
+
function pendingConfirmationFromError2(error51) {
|
|
47061
47528
|
if (!(error51 instanceof CommandClientError) || !error51.response || error51.response.ok || error51.response.error.code !== "COMMAND_CONFIRMATION_REQUIRED") {
|
|
47062
47529
|
return null;
|
|
47063
47530
|
}
|
|
47064
|
-
const details =
|
|
47531
|
+
const details = asRecord3(error51.response.error.details);
|
|
47065
47532
|
const confirmationId = details.confirmationId;
|
|
47066
47533
|
const commandId = details.commandId;
|
|
47067
47534
|
if (typeof confirmationId !== "string" || confirmationId.length === 0 || typeof commandId !== "string" || commandId.length === 0) {
|
|
@@ -47069,7 +47536,7 @@ function pendingConfirmationFromError(error51) {
|
|
|
47069
47536
|
}
|
|
47070
47537
|
return { confirmationId, commandId };
|
|
47071
47538
|
}
|
|
47072
|
-
function
|
|
47539
|
+
function printCommandError2(io, error51) {
|
|
47073
47540
|
if (error51 instanceof CommandClientError && error51.response && !error51.response.ok) {
|
|
47074
47541
|
const help = error51.response.error.help;
|
|
47075
47542
|
const requestId = error51.response.requestId;
|
|
@@ -47106,7 +47573,7 @@ function parseJsonBody(args) {
|
|
|
47106
47573
|
return JSON.parse(body);
|
|
47107
47574
|
}
|
|
47108
47575
|
function isCommand(value) {
|
|
47109
|
-
return value === "login" || value === "logout" || value === "signup" || value === "whoami" || value === "tenants" || value === "use" || value === "command" || value === "onboard" || value === "mcp" || value === "init" || value === "docs" || value === "reference" || value === "help";
|
|
47576
|
+
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";
|
|
47110
47577
|
}
|
|
47111
47578
|
function printUsage(io) {
|
|
47112
47579
|
io.stdout.write([
|
|
@@ -47126,6 +47593,7 @@ function printUsage(io) {
|
|
|
47126
47593
|
`${cliBrand.binName} mcp install --client claude-code|codex|cursor --scope tenant-admin|seat [--seat-id <id>] [--expires-in <days>|--no-expiry] [--skip-permissions]`,
|
|
47127
47594
|
`${cliBrand.binName} mcp install --client claude-code|codex|cursor --rotate <old-token-id> (inherits the old token's scope; no --scope)`,
|
|
47128
47595
|
`${cliBrand.binName} mcp install ... --skip-permissions (or ${cliBrand.envPrefix}_CLI_SKIP_PERMISSIONS=1 \u2014 auto-approves the token-mint confirmation in a non-interactive session)`,
|
|
47596
|
+
skillsUsage2(cliBrand.binName),
|
|
47129
47597
|
`${cliBrand.binName} init [--client claude-code|codex|cursor] (defaults --scope tenant-admin)`,
|
|
47130
47598
|
`${cliBrand.binName} docs`,
|
|
47131
47599
|
`${cliBrand.binName} reference <list|search|get> [options]`,
|