@rosthq/cli 0.7.142 → 0.7.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +69 -45
- package/dist/index.js.map +3 -3
- package/dist/skill-install.d.ts +17 -0
- package/dist/skill-install.d.ts.map +1 -1
- package/dist/skill-trust.d.ts +6 -1
- package/dist/skill-trust.d.ts.map +1 -1
- package/dist/skills.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -53729,7 +53729,7 @@ External connectors are being rolled out provider by provider, conservatively (r
|
|
|
53729
53729
|
order: 48,
|
|
53730
53730
|
title: "CLI and MCP installation guide",
|
|
53731
53731
|
summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
|
|
53732
|
-
version: "2026-07-31.
|
|
53732
|
+
version: "2026-07-31.3",
|
|
53733
53733
|
public: true,
|
|
53734
53734
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
53735
53735
|
stages: ["company_setup", "staffing"],
|
|
@@ -54369,7 +54369,7 @@ Skills wrapper help:
|
|
|
54369
54369
|
{{cli}} skills publish (--slug <slug>|--skill-version-id <id>) [--allow-warnings] [--json]
|
|
54370
54370
|
\`\`\`
|
|
54371
54371
|
|
|
54372
|
-
\`{{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
|
|
54372
|
+
\`{{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 a local copy only when its recorded hash matches and the installed file's own sha256 and byte size verify against the package the server returned; an edited or truncated local file is reinstalled instead of being reported unchanged. For \`--client claude-code\` the root is \`$CLAUDE_CONFIG_DIR/skills\` \u2014 \`CLAUDE_CONFIG_DIR\` is the variable Claude Code itself reads \u2014 otherwise \`~/.claude/skills\`; \`CLAUDE_HOME\` set on its own is a usage error with a migration instruction, and \`CLAUDE_HOME\` set alongside a different \`CLAUDE_CONFIG_DIR\` prints a notice that \`CLAUDE_HOME\` is ignored. For \`--client codex\` the root is \`$CODEX_HOME/skills\`, otherwise \`~/.codex/skills\`. For \`--client cursor\` the root is \`~/.cursor/skills\`. Catalog Skills land under \`<skills root>/rost/<slug>\`, except under \`ROST_SKILL_INSTALL_ROOT\`, where they land under \`<override root>/<client>/<slug>\`. A whitespace-only value for any of these variables is rejected rather than resolving somewhere unintended; an empty value means unset (the shell's \`FOO= cmd\` idiom for turning an inherited variable off) and falls back to the default root above. Entitlement failures mean the tenant cannot access that {{brand}} catalog tier yet; stale local copies are fixed by rerunning \`sync\`; private catalog access is always served by {{brand}} APIs, not by giving the agent a private GitHub credential.
|
|
54373
54373
|
|
|
54374
54374
|
{{brand}}-maintained catalog entries are seeded from first-party Skill packages with stable content hashes, application descriptors, and declared required or optional tool dependencies. Catalog seed validation is fail-closed: a package with parser warnings is not published. Enabling a catalog Skill copies the current immutable version into the company library; later catalog refreshes update the global catalog row but do not silently rewrite already-enabled tenant Skill versions.
|
|
54375
54375
|
|
|
@@ -61954,7 +61954,6 @@ function ensureTrailingSlash2(value) {
|
|
|
61954
61954
|
|
|
61955
61955
|
// src/skills.ts
|
|
61956
61956
|
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
61957
|
-
import os2 from "node:os";
|
|
61958
61957
|
import path5 from "node:path";
|
|
61959
61958
|
|
|
61960
61959
|
// src/skill-install.ts
|
|
@@ -62473,7 +62472,7 @@ async function runInstallImplementation(context, args) {
|
|
|
62473
62472
|
parsed = parseFlags2(args);
|
|
62474
62473
|
client = parseClient2(optionalValue2(parsed, "client") ?? "codex");
|
|
62475
62474
|
tag = optionalValue2(parsed, "tag") ?? DEFAULT_RELEASE_TAG;
|
|
62476
|
-
|
|
62475
|
+
resolveSkillInstallRoot(client, context.env);
|
|
62477
62476
|
} catch (error51) {
|
|
62478
62477
|
if (error51 instanceof UsageError2) {
|
|
62479
62478
|
writeErrorLine(context.io, error51.message);
|
|
@@ -62640,7 +62639,7 @@ async function installRelease(context, plan, testOverrides = {}) {
|
|
|
62640
62639
|
let legacyNotice;
|
|
62641
62640
|
let viaOverride;
|
|
62642
62641
|
try {
|
|
62643
|
-
({ root, legacyNotice, viaOverride } =
|
|
62642
|
+
({ root, legacyNotice, viaOverride } = resolveSkillInstallRoot(plan.client, context.env));
|
|
62644
62643
|
} catch (error51) {
|
|
62645
62644
|
if (error51 instanceof UsageError2) {
|
|
62646
62645
|
writeErrorLine(context.io, error51.message);
|
|
@@ -62771,7 +62770,7 @@ function writeMarker(dir, input) {
|
|
|
62771
62770
|
writeFileSync(path4.join(dir, SKILL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
62772
62771
|
`, "utf8");
|
|
62773
62772
|
}
|
|
62774
|
-
function listInstalledFiles(dir) {
|
|
62773
|
+
function listInstalledFiles(dir, markerFile) {
|
|
62775
62774
|
const files = [];
|
|
62776
62775
|
const walk = (current, prefix) => {
|
|
62777
62776
|
for (const name of readdirSync(current)) {
|
|
@@ -62785,7 +62784,7 @@ function listInstalledFiles(dir) {
|
|
|
62785
62784
|
walk(absolute, relative);
|
|
62786
62785
|
continue;
|
|
62787
62786
|
}
|
|
62788
|
-
if (relative ===
|
|
62787
|
+
if (relative === markerFile) {
|
|
62789
62788
|
continue;
|
|
62790
62789
|
}
|
|
62791
62790
|
files.push({ path: relative, absolute, dev: stats.dev, ino: stats.ino });
|
|
@@ -62794,26 +62793,32 @@ function listInstalledFiles(dir) {
|
|
|
62794
62793
|
walk(dir, "");
|
|
62795
62794
|
return files;
|
|
62796
62795
|
}
|
|
62797
|
-
function verifyInstalledTree(dir, manifest) {
|
|
62796
|
+
function verifyInstalledTree(dir, manifest, options = {}) {
|
|
62797
|
+
const markerFile = options.markerFile ?? SKILL_MARKER_FILE;
|
|
62798
62798
|
let present;
|
|
62799
62799
|
try {
|
|
62800
|
-
present = listInstalledFiles(dir);
|
|
62800
|
+
present = listInstalledFiles(dir, markerFile);
|
|
62801
62801
|
} catch (error51) {
|
|
62802
62802
|
return { ok: false, reason: error51 instanceof Error ? error51.message : "install directory is unreadable" };
|
|
62803
62803
|
}
|
|
62804
|
-
const
|
|
62805
|
-
const unexpected = present.find((file2) => !
|
|
62804
|
+
const manifestByPath = new Map(manifest.files.map((file2) => [file2.path, file2]));
|
|
62805
|
+
const unexpected = present.find((file2) => !manifestByPath.has(file2.path));
|
|
62806
62806
|
if (unexpected !== void 0) {
|
|
62807
|
-
return { ok: false, reason: "an installed file is not listed in the
|
|
62807
|
+
return { ok: false, reason: "an installed file is not listed in the package" };
|
|
62808
62808
|
}
|
|
62809
|
-
if (present.length !==
|
|
62810
|
-
return { ok: false, reason: "the installed tree is missing files listed in the
|
|
62809
|
+
if (present.length !== manifestByPath.size) {
|
|
62810
|
+
return { ok: false, reason: "the installed tree is missing files listed in the package" };
|
|
62811
62811
|
}
|
|
62812
62812
|
for (const file2 of present) {
|
|
62813
62813
|
try {
|
|
62814
|
-
|
|
62814
|
+
const size = statSync(file2.absolute).size;
|
|
62815
|
+
if (size > MAX_RESPONSE_BYTES) {
|
|
62815
62816
|
return { ok: false, reason: `an installed file exceeds the ${MAX_RESPONSE_BYTES}-byte verification cap: ${file2.path}` };
|
|
62816
62817
|
}
|
|
62818
|
+
const declaredSize = manifestByPath.get(file2.path)?.sizeBytes;
|
|
62819
|
+
if (declaredSize !== void 0 && size !== declaredSize) {
|
|
62820
|
+
return { ok: false, reason: `an installed file's size does not match the declared size: ${file2.path}` };
|
|
62821
|
+
}
|
|
62817
62822
|
} catch (error51) {
|
|
62818
62823
|
return { ok: false, reason: error51 instanceof Error ? error51.message : "an installed file is unreadable" };
|
|
62819
62824
|
}
|
|
@@ -62911,7 +62916,7 @@ function resolveCodexSkillsRoot(env) {
|
|
|
62911
62916
|
const codexHome = requireNonBlank("CODEX_HOME", env.CODEX_HOME);
|
|
62912
62917
|
return path4.resolve(path4.join(codexHome ?? path4.join(resolveHome(env), ".codex"), "skills"));
|
|
62913
62918
|
}
|
|
62914
|
-
function
|
|
62919
|
+
function resolveSkillInstallRoot(client, env) {
|
|
62915
62920
|
const override = requireNonBlank("ROST_SKILL_INSTALL_ROOT", env.ROST_SKILL_INSTALL_ROOT);
|
|
62916
62921
|
if (override !== null) {
|
|
62917
62922
|
return { root: path4.resolve(override, client), legacyNotice: null, viaOverride: true };
|
|
@@ -62966,6 +62971,7 @@ function parseClient2(value) {
|
|
|
62966
62971
|
}
|
|
62967
62972
|
|
|
62968
62973
|
// src/skills.ts
|
|
62974
|
+
var CATALOG_SKILL_MARKER_FILE = ".rost-skill.json";
|
|
62969
62975
|
var UsageError3 = class extends Error {
|
|
62970
62976
|
};
|
|
62971
62977
|
var CLIENTS2 = /* @__PURE__ */ new Set(["claude-code", "codex", "cursor"]);
|
|
@@ -63095,7 +63101,7 @@ async function installOne(context, args, env) {
|
|
|
63095
63101
|
});
|
|
63096
63102
|
const options = seatId ? { targetSeatId: seatId } : {};
|
|
63097
63103
|
const output = await executeInstallCommand(context, body, options);
|
|
63098
|
-
const summary = applyLocalSkillChanges(output, client, env, { removeRevoked: false });
|
|
63104
|
+
const summary = applyLocalSkillChanges(context.io, output, client, env, { removeRevoked: false });
|
|
63099
63105
|
const outputRecord = asRecord4(output);
|
|
63100
63106
|
context.io.stdout.write(parsed.json ? `${JSON.stringify({ ...outputRecord, local: summary }, null, 2)}
|
|
63101
63107
|
` : `${formatLocalSummary(summary)}
|
|
@@ -63110,7 +63116,7 @@ async function syncAssigned(context, args, env) {
|
|
|
63110
63116
|
seat_id: seatId,
|
|
63111
63117
|
client
|
|
63112
63118
|
}, { targetSeatId: seatId });
|
|
63113
|
-
const summary = applyLocalSkillChanges(output, client, env, { removeRevoked: true });
|
|
63119
|
+
const summary = applyLocalSkillChanges(context.io, output, client, env, { removeRevoked: true });
|
|
63114
63120
|
const outputRecord = asRecord4(output);
|
|
63115
63121
|
context.io.stdout.write(parsed.json ? `${JSON.stringify({ ...outputRecord, local: summary }, null, 2)}
|
|
63116
63122
|
` : `${formatLocalSummary(summary)}
|
|
@@ -63146,15 +63152,19 @@ async function executeSkillCommand(context, commandId, body, options = {}) {
|
|
|
63146
63152
|
throw error51;
|
|
63147
63153
|
}
|
|
63148
63154
|
}
|
|
63149
|
-
function applyLocalSkillChanges(output, client, env, options) {
|
|
63150
|
-
const root =
|
|
63151
|
-
|
|
63155
|
+
function applyLocalSkillChanges(io, output, client, env, options) {
|
|
63156
|
+
const { root, legacyNotice } = installRoot(client, env);
|
|
63157
|
+
if (legacyNotice !== null) {
|
|
63158
|
+
io.stderr.write(`${legacyNotice}
|
|
63159
|
+
`);
|
|
63160
|
+
}
|
|
63161
|
+
const changes = writeInstalls(io, output, root);
|
|
63152
63162
|
if (options.removeRevoked) {
|
|
63153
63163
|
changes.push(...removeRevokedInstalls(output, root));
|
|
63154
63164
|
}
|
|
63155
63165
|
return changes;
|
|
63156
63166
|
}
|
|
63157
|
-
function writeInstalls(output, root) {
|
|
63167
|
+
function writeInstalls(io, output, root) {
|
|
63158
63168
|
const installs = asArray2(asRecord4(output).installs);
|
|
63159
63169
|
return installs.map((entry) => {
|
|
63160
63170
|
const install = asRecord4(entry);
|
|
@@ -63162,10 +63172,27 @@ function writeInstalls(output, root) {
|
|
|
63162
63172
|
const metadata = asRecord4(install.metadata);
|
|
63163
63173
|
const files = asArray2(install.files).map(asRecord4);
|
|
63164
63174
|
const dir = path5.join(root, slug2);
|
|
63165
|
-
const metadataPath = path5.join(dir,
|
|
63175
|
+
const metadataPath = path5.join(dir, CATALOG_SKILL_MARKER_FILE);
|
|
63166
63176
|
const expectedHash = String(metadata.content_sha256 ?? "");
|
|
63167
63177
|
if (existingHash(metadataPath) === expectedHash) {
|
|
63168
|
-
|
|
63178
|
+
const expected = files.map((file2) => {
|
|
63179
|
+
const declaredHash = file2.content_sha256;
|
|
63180
|
+
const sha256 = typeof declaredHash === "string" ? declaredHash : "";
|
|
63181
|
+
const sizeBytes = typeof file2.size_bytes === "number" ? file2.size_bytes : void 0;
|
|
63182
|
+
return {
|
|
63183
|
+
path: safeRelativePath2(String(file2.path ?? "")),
|
|
63184
|
+
sha256,
|
|
63185
|
+
...sizeBytes === void 0 ? {} : { sizeBytes }
|
|
63186
|
+
};
|
|
63187
|
+
});
|
|
63188
|
+
const verified = verifyInstalledTree(dir, { files: expected }, { markerFile: CATALOG_SKILL_MARKER_FILE });
|
|
63189
|
+
if (verified.ok) {
|
|
63190
|
+
return { slug: slug2, dir, status: "unchanged", files: files.length };
|
|
63191
|
+
}
|
|
63192
|
+
io.stderr.write(
|
|
63193
|
+
`NOTICE: the installed Skill ${slug2} does not match the server package (${verified.reason}); reinstalling.
|
|
63194
|
+
`
|
|
63195
|
+
);
|
|
63169
63196
|
}
|
|
63170
63197
|
rmSync2(dir, { recursive: true, force: true });
|
|
63171
63198
|
mkdirSync2(dir, { recursive: true });
|
|
@@ -63202,32 +63229,29 @@ function removeRevokedInstalls(output, root) {
|
|
|
63202
63229
|
}
|
|
63203
63230
|
return changes;
|
|
63204
63231
|
}
|
|
63205
|
-
function
|
|
63206
|
-
|
|
63207
|
-
|
|
63208
|
-
|
|
63209
|
-
}
|
|
63210
|
-
|
|
63211
|
-
|
|
63212
|
-
return path5.join(resolveCodexSkillsRoot(env), "rost");
|
|
63213
|
-
} catch (error51) {
|
|
63214
|
-
if (error51 instanceof UsageError2) {
|
|
63215
|
-
throw new UsageError3(error51.message);
|
|
63216
|
-
}
|
|
63217
|
-
throw error51;
|
|
63232
|
+
function installRoot(client, env) {
|
|
63233
|
+
let resolved;
|
|
63234
|
+
try {
|
|
63235
|
+
resolved = resolveSkillInstallRoot(client, env);
|
|
63236
|
+
} catch (error51) {
|
|
63237
|
+
if (error51 instanceof UsageError2) {
|
|
63238
|
+
throw new UsageError3(error51.message);
|
|
63218
63239
|
}
|
|
63240
|
+
throw error51;
|
|
63219
63241
|
}
|
|
63220
|
-
|
|
63221
|
-
|
|
63222
|
-
}
|
|
63223
|
-
return path5.join(os2.homedir(), ".cursor", "skills", "rost");
|
|
63242
|
+
const root = resolved.viaOverride ? resolved.root : path5.join(resolved.root, "rost");
|
|
63243
|
+
return { root, legacyNotice: resolved.legacyNotice };
|
|
63224
63244
|
}
|
|
63225
63245
|
function safeRelativePath2(value) {
|
|
63226
63246
|
const normalized = value.trim().replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
63227
63247
|
if (!normalized || normalized.startsWith("/") || normalized.includes("//") || normalized.split("/").includes("..")) {
|
|
63228
63248
|
throw new UsageError3("Server returned an invalid skill file path.");
|
|
63229
63249
|
}
|
|
63230
|
-
|
|
63250
|
+
const collapsed = normalized.split("/").filter((segment) => segment !== ".").join("/");
|
|
63251
|
+
if (!collapsed) {
|
|
63252
|
+
throw new UsageError3("Server returned an invalid skill file path.");
|
|
63253
|
+
}
|
|
63254
|
+
return collapsed;
|
|
63231
63255
|
}
|
|
63232
63256
|
function safeLocalSlug(value) {
|
|
63233
63257
|
if (!/^[a-z0-9][a-z0-9-]{1,80}$/.test(value)) {
|
|
@@ -64661,7 +64685,7 @@ import { execFile as execFileCallback4 } from "node:child_process";
|
|
|
64661
64685
|
import { createHash as createHash3, randomBytes } from "node:crypto";
|
|
64662
64686
|
import { constants as fsConstants3 } from "node:fs";
|
|
64663
64687
|
import { chmod, link, lstat, mkdir as mkdir5, mkdtemp, open, readdir as readdir3, readFile as readFile8, realpath, rename, rm as rm5, stat as stat4, writeFile as writeFile5 } from "node:fs/promises";
|
|
64664
|
-
import
|
|
64688
|
+
import os2 from "node:os";
|
|
64665
64689
|
import path8 from "node:path";
|
|
64666
64690
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
64667
64691
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -64764,7 +64788,7 @@ function resolveSourceClaudeConfigDir(base) {
|
|
|
64764
64788
|
return explicit;
|
|
64765
64789
|
}
|
|
64766
64790
|
const home = base.HOME;
|
|
64767
|
-
const homeDir = typeof home === "string" && home.length > 0 ? home :
|
|
64791
|
+
const homeDir = typeof home === "string" && home.length > 0 ? home : os2.homedir();
|
|
64768
64792
|
return path8.join(homeDir, ".claude");
|
|
64769
64793
|
}
|
|
64770
64794
|
async function provisionIsolatedClaudeConfigDir(base, configDir, onRepair) {
|
|
@@ -64787,7 +64811,7 @@ function resolveSourceCodexHomeDir(base) {
|
|
|
64787
64811
|
return explicit;
|
|
64788
64812
|
}
|
|
64789
64813
|
const home = base.HOME;
|
|
64790
|
-
const homeDir = typeof home === "string" && home.length > 0 ? home :
|
|
64814
|
+
const homeDir = typeof home === "string" && home.length > 0 ? home : os2.homedir();
|
|
64791
64815
|
return path8.join(homeDir, ".codex");
|
|
64792
64816
|
}
|
|
64793
64817
|
var CODEX_HOME_TMP_PREFIX = ".rost-tmp-";
|