@skhema/cli 0.5.1 → 0.6.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Skhema
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,10 @@
1
+ > [!IMPORTANT]
2
+ > **Generated mirror of a private source repo — do not open PRs here.**
3
+ > This repository is an automatically generated, read-only mirror of a package
4
+ > built from Skhema's private monorepo. Pull requests are disabled and any change
5
+ > pushed here is overwritten on the next release. Questions and bug reports:
6
+ > support@skhema.com. Security: see [SECURITY.md](./SECURITY.md).
7
+
1
8
  # @skhema/cli
2
9
 
3
10
  The Skhema command-line interface (`skhema`). Authenticate as a human or an
package/dist/cli.js CHANGED
@@ -1,8 +1,9 @@
1
+ import { CommanderError } from 'commander';
1
2
  import { createRequire } from 'module';
2
3
  import { isApprovedContributor } from './lib/auth/entitlements.js';
3
4
  import { getStoredCredentials } from './lib/auth/token-store.js';
4
5
  import { outputError } from './lib/output.js';
5
- import { buildProgram } from './program.js';
6
+ import { buildProgram, resolveCommanderExitCode } from './program.js';
6
7
  const require = createRequire(import.meta.url);
7
8
  const pkg = require('../package.json');
8
9
  const program = buildProgram(pkg.version);
@@ -35,6 +36,17 @@ async function main() {
35
36
  }
36
37
  }
37
38
  }
38
- await program.parseAsync();
39
+ try {
40
+ await program.parseAsync();
41
+ }
42
+ catch (err) {
43
+ // With exitOverride set, commander throws instead of exiting for every
44
+ // parser-level outcome (usage error, --help, --version). Map those onto the
45
+ // ExitCode contract; anything else is a real failure and should propagate.
46
+ if (err instanceof CommanderError) {
47
+ process.exit(resolveCommanderExitCode(err));
48
+ }
49
+ throw err;
50
+ }
39
51
  }
40
52
  main();
@@ -1,7 +1,8 @@
1
1
  import { Command } from 'commander';
2
2
  /**
3
- * Element commands — the strategic building blocks in a workspace. All are
4
- * workspace-scoped via `--workspace` (falling back to the default workspace).
3
+ * Element commands — the strategic building blocks in a workspace. Most are
4
+ * workspace-scoped via `--workspace` (falling back to the default workspace);
5
+ * `types` is a local, network-free lookup of the method vocabulary.
5
6
  */
6
7
  export declare function registerElementCommands(program: Command): void;
7
8
  //# sourceMappingURL=element.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../../src/commands/element.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAkBnC;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8S9D"}
1
+ {"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../../src/commands/element.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA2EnC;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2T9D"}
@@ -1,3 +1,4 @@
1
+ import { getElementDefinition, getElementsForComponent, SKHEMA_MAPPING, } from '@skhema/method';
1
2
  import chalk from 'chalk';
2
3
  import { resolveClient } from '../lib/api/client.js';
3
4
  import { asRecord, buildBody, coerceList, readPayloadFile, resolveWorkspaceId, } from '../lib/api/command-helpers.js';
@@ -8,9 +9,47 @@ function summarize(content) {
8
9
  const text = typeof content === 'string' ? content : '';
9
10
  return text.length > 48 ? `${text.slice(0, 47)}…` : text || '—';
10
11
  }
12
+ /** Human-friendly rendering of an expected mood (e.g. `noun_phrase` → `noun phrase`). */
13
+ function formatMood(mood) {
14
+ return mood ? mood.replace(/_/g, ' ') : '—';
15
+ }
16
+ /**
17
+ * The component → allowed-element-type mapping, read straight from
18
+ * `@skhema/method` (SKHEMA_MAPPING) in canonical component-flow order. This is
19
+ * the same vocabulary the backend enforces, so agents can discover the
20
+ * allow-list locally instead of probing it via `bad_request` errors.
21
+ */
22
+ function buildElementTypeMapping() {
23
+ return SKHEMA_MAPPING.componentFlow.map((component) => ({
24
+ component: component.value,
25
+ label: component.label,
26
+ acronym: component.acronym,
27
+ elementTypes: getElementsForComponent(component.value).map((element) => ({
28
+ type: element.value,
29
+ label: element.label,
30
+ acronym: element.acronym,
31
+ mood: getElementDefinition(element.value)?.expectedMood ?? null,
32
+ })),
33
+ }));
34
+ }
35
+ /** Render the mapping as a per-component section with an element-type table. */
36
+ function renderElementTypeMapping(mapping) {
37
+ logHeader('Element types by component');
38
+ for (const component of mapping) {
39
+ log('');
40
+ log(chalk.bold(`${component.label} ${chalk.dim(`(${component.acronym})`)}`));
41
+ logTable(['acronym', 'type', 'label', 'mood'], component.elementTypes.map((element) => [
42
+ element.acronym,
43
+ element.type,
44
+ element.label,
45
+ formatMood(element.mood),
46
+ ]));
47
+ }
48
+ }
11
49
  /**
12
- * Element commands — the strategic building blocks in a workspace. All are
13
- * workspace-scoped via `--workspace` (falling back to the default workspace).
50
+ * Element commands — the strategic building blocks in a workspace. Most are
51
+ * workspace-scoped via `--workspace` (falling back to the default workspace);
52
+ * `types` is a local, network-free lookup of the method vocabulary.
14
53
  */
15
54
  export function registerElementCommands(program) {
16
55
  const element = program.command('element').description('Element commands');
@@ -200,4 +239,15 @@ export function registerElementCommands(program) {
200
239
  return data;
201
240
  });
202
241
  });
242
+ element
243
+ .command('types')
244
+ .description('List element types allowed in each component (method vocabulary, no network)')
245
+ .action(async () => {
246
+ await runCommand('element types', async () => {
247
+ const mapping = buildElementTypeMapping();
248
+ if (!getGlobalOptions().json)
249
+ renderElementTypeMapping(mapping);
250
+ return { components: mapping };
251
+ });
252
+ });
203
253
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAenC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgO7D"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAwCnC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6U7D"}
@@ -1,10 +1,28 @@
1
+ import readline from 'readline';
1
2
  import chalk from 'chalk';
2
3
  import ora from 'ora';
3
4
  import { getGlobalOptions, log, logHeader, logTable, outputError, outputSuccess, } from '../lib/output.js';
4
5
  import { listBundledSkills, readBundledSkill } from '../lib/skills/bundled.js';
5
- import { installSkills, updateSkills } from '../lib/skills/installer.js';
6
+ import { installSkills, pruneSkills, updateSkills, } from '../lib/skills/installer.js';
6
7
  import { readLock } from '../lib/skills/lock.js';
7
8
  import { detectPlatforms } from '../lib/skills/platform-detect.js';
9
+ function interactiveTerminal() {
10
+ return (Boolean(process.stdin.isTTY && process.stdout.isTTY) &&
11
+ !getGlobalOptions().json);
12
+ }
13
+ async function confirm(question) {
14
+ const rl = readline.createInterface({
15
+ input: process.stdin,
16
+ output: process.stdout,
17
+ });
18
+ const answer = await new Promise((resolve) => {
19
+ rl.question(`${question} [y/N]: `, (value) => {
20
+ rl.close();
21
+ resolve(value.trim().toLowerCase());
22
+ });
23
+ });
24
+ return answer === 'y' || answer === 'yes';
25
+ }
8
26
  export function registerSkillsCommands(program) {
9
27
  const skills = program.command('skills').description('AI skills management');
10
28
  skills
@@ -171,4 +189,83 @@ export function registerSkillsCommands(program) {
171
189
  process.exit(1);
172
190
  }
173
191
  });
192
+ skills
193
+ .command('prune')
194
+ .description('Remove installed skills that are no longer bundled with this CLI (retired or renamed)')
195
+ .option('--platform <id>', 'Prune a specific platform only')
196
+ .option('--yes', 'Actually remove; without it, only preview what would go')
197
+ .action(async (options) => {
198
+ const opts = getGlobalOptions();
199
+ const spinner = opts.json || opts.quiet
200
+ ? null
201
+ : ora('Detecting agent platforms...').start();
202
+ try {
203
+ const platforms = detectPlatforms().filter((p) => p.detected);
204
+ const targets = options.platform
205
+ ? platforms.filter((p) => p.id === options.platform)
206
+ : platforms;
207
+ if (targets.length === 0) {
208
+ spinner?.warn(options.platform
209
+ ? `Platform "${options.platform}" not detected.`
210
+ : 'No agent platforms detected.');
211
+ if (opts.json)
212
+ outputSuccess([], 'skills prune');
213
+ return;
214
+ }
215
+ // Preview first — this never writes.
216
+ const preview = await pruneSkills(targets, { apply: false });
217
+ if (preview.length === 0) {
218
+ spinner?.succeed('No retired skills to prune. Everything is current.');
219
+ if (opts.json)
220
+ outputSuccess([], 'skills prune');
221
+ return;
222
+ }
223
+ spinner?.info(`Found ${preview.length} retired skill install(s) across ${new Set(preview.map((r) => r.platform.id)).size} platform(s).`);
224
+ // Mutate only with --yes, or after an interactive confirmation.
225
+ let apply = Boolean(options.yes);
226
+ if (!apply) {
227
+ if (interactiveTerminal()) {
228
+ logHeader('Would remove');
229
+ logTable(['Platform', 'Skill', 'Path'], preview.map((r) => [
230
+ r.platform.name,
231
+ r.skill,
232
+ chalk.dim(r.targetPath),
233
+ ]));
234
+ apply = await confirm('Remove these skills?');
235
+ }
236
+ }
237
+ if (!apply) {
238
+ const results = preview;
239
+ if (opts.json) {
240
+ outputSuccess(results, 'skills prune');
241
+ return;
242
+ }
243
+ logHeader('Prune Preview (dry run — pass --yes to remove)');
244
+ logTable(['Platform', 'Skill', 'Path'], results.map((r) => [
245
+ r.platform.name,
246
+ r.skill,
247
+ chalk.dim(r.targetPath),
248
+ ]));
249
+ log('');
250
+ log(chalk.dim('Re-run with --yes to remove these skills.'));
251
+ return;
252
+ }
253
+ const results = await pruneSkills(targets, { apply: true });
254
+ if (opts.json) {
255
+ outputSuccess(results, 'skills prune');
256
+ return;
257
+ }
258
+ logHeader('Prune Results');
259
+ logTable(['Platform', 'Skill', 'Status'], results.map((r) => [
260
+ r.platform.name,
261
+ r.skill,
262
+ chalk.red(r.action),
263
+ ]));
264
+ }
265
+ catch (error) {
266
+ spinner?.fail('Prune failed');
267
+ outputError(error instanceof Error ? error.message : 'Unknown error', 'skills prune');
268
+ process.exit(1);
269
+ }
270
+ });
174
271
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-key-admin.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/api-key-admin.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,YAAY,CAAA;AAC9D,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,CAAA;AAExC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,WAAW,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,EAAE,CAAA;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC;AAsDD,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,WAAW,CAAA;CACnB,GACA,OAAO,CAAC,aAAa,CAAC,CAKxB;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAK5B;AAED,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAK9C"}
1
+ {"version":3,"file":"api-key-admin.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/api-key-admin.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,YAAY,CAAA;AAC9D,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,CAAA;AAExC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,WAAW,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,EAAE,CAAA;IACrB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACtC;AAsDD,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,WAAW,CAAA;CACnB,GACA,OAAO,CAAC,aAAa,CAAC,CAKxB;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAK5B;AAED,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAK9C"}
@@ -1,11 +1,10 @@
1
1
  import { SkhemaApiError } from '@skhema/sdk';
2
2
  import { SUPABASE_PUBLISHABLE_KEY, SUPABASE_URL } from '../config.js';
3
3
  /**
4
- * Client for the `api-key-manage` edge function the same function the web
5
- * dashboard uses to create/list/revoke API keys. It authenticates with the
6
- * caller's OAuth bearer (`verifyAuth` + `requireUser`), so issuance authorization
7
- * (org owner/admin, plan limits, one-time key display, security emails) is
8
- * enforced server-side and unchanged. This is NOT the public gateway.
4
+ * Client for creating, listing, and revoking the caller's Skhema API keys.
5
+ * Authenticates with the user's OAuth bearer; key-issuance authorization
6
+ * (org role, plan limits, one-time key display, security notifications) is
7
+ * enforced by the server, not the CLI.
9
8
  */
10
9
  const API_KEY_MANAGE_URL = `${SUPABASE_URL}/functions/v1/api-key-manage`;
11
10
  async function callApiKeyManage(accessToken, body) {
@@ -25,10 +25,10 @@ export const API_KEY_ENV_VAR = 'SKHEMA_API_KEY';
25
25
  // never injects a credential here.
26
26
  // Override via env for staging/preview environments.
27
27
  export const MCP_SERVER_URL = process.env.SKHEMA_MCP_URL ?? 'https://mcp.skhema.com/mcp';
28
- // Supabase project configuration.
29
- // Publishable keys are safe to embed in client-side code (they are the new
30
- // replacement for the legacy anon key and rely on RLS + server-side auth
31
- // checks for security). Override via env for staging/preview environments.
28
+ // Backend project configuration for the CLI's authenticated data calls.
29
+ // The publishable key is safe to embed in client-side code it carries no
30
+ // privileged access and relies on server-side authorization. Override via env
31
+ // for staging/preview environments.
32
32
  export const SUPABASE_URL = process.env.SKHEMA_SUPABASE_URL ?? 'https://uiybgpcjjrdqmdbarqlx.supabase.co';
33
33
  export const SUPABASE_PUBLISHABLE_KEY = process.env.SKHEMA_SUPABASE_PUBLISHABLE_KEY ??
34
34
  'sb_publishable_G9uXii5AYDLK6vUpyaqy3A_-NmdwQF1';
@@ -1,7 +1,7 @@
1
- /** Supabase edge functions the contributor commands talk to. */
1
+ /** Backend actions the contributor commands invoke. */
2
2
  export type ContributeEdgeFunction = 'contributor-manage' | 'embed-manage' | 'contributor-payout';
3
3
  /**
4
- * POST a JSON action to a Supabase edge function with the stored OAuth session.
4
+ * POST a JSON action to the contributor backend with the stored OAuth session.
5
5
  * Shared by every authenticated `contribute` subcommand so the auth headers,
6
6
  * base URL, and error mapping live in exactly one place.
7
7
  *
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/api.ts"],"names":[],"mappings":"AAGA,gEAAgE;AAChE,MAAM,MAAM,sBAAsB,GAC9B,oBAAoB,GACpB,cAAc,GACd,oBAAoB,CAAA;AAExB;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,EAAE,EAAE,sBAAsB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC,CA+BZ"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/api.ts"],"names":[],"mappings":"AAGA,uDAAuD;AACvD,MAAM,MAAM,sBAAsB,GAC9B,oBAAoB,GACpB,cAAc,GACd,oBAAoB,CAAA;AAExB;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,EAAE,EAAE,sBAAsB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC,CA+BZ"}
@@ -1,7 +1,7 @@
1
1
  import { getStoredCredentials } from '../auth/token-store.js';
2
2
  import { SUPABASE_PUBLISHABLE_KEY, SUPABASE_URL } from '../config.js';
3
3
  /**
4
- * POST a JSON action to a Supabase edge function with the stored OAuth session.
4
+ * POST a JSON action to the contributor backend with the stored OAuth session.
5
5
  * Shared by every authenticated `contribute` subcommand so the auth headers,
6
6
  * base URL, and error mapping live in exactly one place.
7
7
  *
@@ -25,8 +25,8 @@ export async function postContributeFunction(fn, body) {
25
25
  body: JSON.stringify(body),
26
26
  });
27
27
  if (!response.ok) {
28
- // Supabase edge functions and the gateway return `{ message }`, while some
29
- // handlers return `{ error }` — accept either before the generic fallback.
28
+ // The backend returns `{ message }`, while some handlers return
29
+ // `{ error }` — accept either before the generic fallback.
30
30
  const detail = (await response.json().catch(() => ({})));
31
31
  throw new Error(detail.error ||
32
32
  detail.message ||
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/contribute/types.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,8 @@ import { ExitCode } from '../api/run-command.js';
7
7
  * options, or exit codes change — never on a plain version bump.
8
8
  *
9
9
  * The committed copy lives at docs/cli-reference.mdx and is drift-tested
10
- * (src/__tests__/cli-reference-drift.test.ts). The deployed copy is
11
- * skhema-web content/docs/api/cli.mdx — sync it when this file changes.
10
+ * (src/__tests__/cli-reference-drift.test.ts). A copy is also published to the
11
+ * public docs site regenerate and sync both when this file changes.
12
12
  */
13
13
  /** Human meanings for the stable exit-code contract (run-command.ts). */
14
14
  const EXIT_CODE_MEANINGS = {
@@ -137,7 +137,7 @@ export function generateCliReference() {
137
137
  lines.push('---');
138
138
  lines.push('');
139
139
  lines.push('{/* AUTO-GENERATED from the @skhema/cli command tree — do not edit by hand.');
140
- lines.push(' Regenerate with `npm run generate:cli-reference` in skhema-packages/skhema-cli. */}');
140
+ lines.push(' Regenerate with `npm run generate:cli-reference`. */}');
141
141
  lines.push('');
142
142
  lines.push('This page is generated from the CLI itself, so it always matches the installed command surface. For a guided tour, start with [Using the CLI](/docs/guides/using-the-cli).');
143
143
  lines.push('');
@@ -1,4 +1,17 @@
1
- import type { DetectedPlatform, InstallResult } from './types.js';
1
+ import type { DetectedPlatform, InstallResult, PruneResult } from './types.js';
2
2
  export declare function installSkills(platforms: DetectedPlatform[]): Promise<InstallResult[]>;
3
3
  export declare function updateSkills(platforms: DetectedPlatform[]): Promise<InstallResult[]>;
4
+ /**
5
+ * Find skills we previously installed that are no longer bundled with this CLI
6
+ * (retired or renamed) and remove them from each platform.
7
+ *
8
+ * Attribution is anchored on the per-platform lock file: only skills recorded
9
+ * there by our own installer are candidates, so a skill authored by the user or
10
+ * another tool that happens to share the skills directory is never touched. With
11
+ * `apply: false` (the default), nothing is written — the returned list is a
12
+ * preview of what removal would do.
13
+ */
14
+ export declare function pruneSkills(platforms: DetectedPlatform[], options?: {
15
+ apply: boolean;
16
+ }): Promise<PruneResult[]>;
4
17
  //# sourceMappingURL=installer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/installer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AA+DjE,wBAAsB,aAAa,CACjC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC,CA0C1B;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC,CAG1B"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/installer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA+D9E,wBAAsB,aAAa,CACjC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC,CA0C1B;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC,CAG1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,GAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAqB,GAC7C,OAAO,CAAC,WAAW,EAAE,CAAC,CAmCxB"}
@@ -83,3 +83,43 @@ export async function updateSkills(platforms) {
83
83
  // Update uses the same logic as install — content comparison handles skip/update
84
84
  return installSkills(platforms);
85
85
  }
86
+ /**
87
+ * Find skills we previously installed that are no longer bundled with this CLI
88
+ * (retired or renamed) and remove them from each platform.
89
+ *
90
+ * Attribution is anchored on the per-platform lock file: only skills recorded
91
+ * there by our own installer are candidates, so a skill authored by the user or
92
+ * another tool that happens to share the skills directory is never touched. With
93
+ * `apply: false` (the default), nothing is written — the returned list is a
94
+ * preview of what removal would do.
95
+ */
96
+ export async function pruneSkills(platforms, options = { apply: false }) {
97
+ const bundledNames = new Set(getBundledSkills().map((skill) => skill.name));
98
+ const results = [];
99
+ for (const platform of platforms) {
100
+ const lock = readLock(platform);
101
+ const retired = Object.keys(lock.skills)
102
+ .filter((name) => !bundledNames.has(name))
103
+ .sort((a, b) => a.localeCompare(b));
104
+ for (const name of retired) {
105
+ const targetPath = path.join(platform.skillsDir, name);
106
+ if (options.apply) {
107
+ // Remove only the directory our lock attributes to this skill.
108
+ if (fs.existsSync(targetPath)) {
109
+ fs.rmSync(targetPath, { recursive: true, force: true });
110
+ }
111
+ delete lock.skills[name];
112
+ }
113
+ results.push({
114
+ platform,
115
+ skill: name,
116
+ action: options.apply ? 'removed' : 'would-remove',
117
+ targetPath,
118
+ });
119
+ }
120
+ if (options.apply && retired.length > 0) {
121
+ writeLock(platform, lock);
122
+ }
123
+ }
124
+ return results;
125
+ }
@@ -17,6 +17,12 @@ export interface InstallResult {
17
17
  action: 'installed' | 'updated' | 'skipped';
18
18
  targetPath: string;
19
19
  }
20
+ export interface PruneResult {
21
+ platform: DetectedPlatform;
22
+ skill: string;
23
+ action: 'removed' | 'would-remove';
24
+ targetPath: string;
25
+ }
20
26
  export interface SkillLock {
21
27
  version: string;
22
28
  installedAt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;IAC3C,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CACZ,MAAM,EACN;QACE,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,WAAW,EAAE,MAAM,CAAA;KACpB,CACF,CAAA;CACF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/skills/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;IAC3C,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,GAAG,cAAc,CAAA;IAClC,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CACZ,MAAM,EACN;QACE,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,WAAW,EAAE,MAAM,CAAA;KACpB,CACF,CAAA;CACF"}
package/dist/program.d.ts CHANGED
@@ -1,4 +1,16 @@
1
- import { Command } from 'commander';
1
+ import { Command, CommanderError } from 'commander';
2
+ /**
3
+ * Resolve the process exit code for a parser-level {@link CommanderError}.
4
+ *
5
+ * Commander's own defaults are inconsistent (unknown option → 1, unknown
6
+ * command silently swallowed → 0, missing subcommand → 1). We collapse them
7
+ * onto the CLI's stable {@link ExitCode} contract: printing help or the version
8
+ * is an informational success (`0`), and every other parser failure — unknown
9
+ * option, unknown/missing command, missing or excess argument — is a usage
10
+ * error ({@link ExitCode.Usage}). Commander tags the informational cases with
11
+ * `exitCode === 0`, which is the only discriminator we need.
12
+ */
13
+ export declare function resolveCommanderExitCode(err: CommanderError): number;
2
14
  /**
3
15
  * Assemble the full skhema CLI program. The runtime entry (cli.ts) and the
4
16
  * docs reference generator both build from here, so every registered command
@@ -1 +1 @@
1
- {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAqBnC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiDrD"}
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAsBnD;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAqErD"}
package/dist/program.js CHANGED
@@ -16,8 +16,23 @@ import { registerStrategyCommands } from './commands/strategy.js';
16
16
  import { registerWebhookCommands } from './commands/webhook.js';
17
17
  import { registerWorkspaceCommands } from './commands/workspace.js';
18
18
  import { setApiKeyFlag } from './lib/api/credential-context.js';
19
+ import { ExitCode } from './lib/api/run-command.js';
19
20
  import { showBanner } from './lib/banner.js';
20
21
  import { setGlobalOptions } from './lib/output.js';
22
+ /**
23
+ * Resolve the process exit code for a parser-level {@link CommanderError}.
24
+ *
25
+ * Commander's own defaults are inconsistent (unknown option → 1, unknown
26
+ * command silently swallowed → 0, missing subcommand → 1). We collapse them
27
+ * onto the CLI's stable {@link ExitCode} contract: printing help or the version
28
+ * is an informational success (`0`), and every other parser failure — unknown
29
+ * option, unknown/missing command, missing or excess argument — is a usage
30
+ * error ({@link ExitCode.Usage}). Commander tags the informational cases with
31
+ * `exitCode === 0`, which is the only discriminator we need.
32
+ */
33
+ export function resolveCommanderExitCode(err) {
34
+ return err.exitCode === 0 ? ExitCode.Ok : ExitCode.Usage;
35
+ }
21
36
  /**
22
37
  * Assemble the full skhema CLI program. The runtime entry (cli.ts) and the
23
38
  * docs reference generator both build from here, so every registered command
@@ -25,6 +40,15 @@ import { setGlobalOptions } from './lib/output.js';
25
40
  */
26
41
  export function buildProgram(version) {
27
42
  const program = new Command();
43
+ // Throw a CommanderError instead of calling process.exit directly, so the
44
+ // entry point can map every parser-level failure onto the ExitCode taxonomy.
45
+ // Set before registering subcommands: commander copies the exit callback into
46
+ // each child at `.command()` time, so this one call covers the whole tree.
47
+ program.exitOverride();
48
+ // The default `.action()` below (banner on bare invocation) otherwise
49
+ // suppresses commander's implicit `help` command, so `skhema help [command]`
50
+ // would fall through to the unknown-command guard. Re-enable it explicitly.
51
+ program.helpCommand(true);
28
52
  program
29
53
  .name('skhema')
30
54
  .description('Skhema CLI — drive the Skhema Public API from your terminal, CI, or agent')
@@ -43,7 +67,16 @@ export function buildProgram(version) {
43
67
  setApiKeyFlag(opts.apiKey);
44
68
  })
45
69
  .action(() => {
46
- // Show banner when run with no subcommand
70
+ // A bare `skhema` invocation shows the banner. Any leftover operand means
71
+ // an unknown command was given: commander routes it here (the default
72
+ // action) instead of erroring, so we must reject it ourselves — otherwise
73
+ // the banner prints and the process exits 0, hiding the mistake.
74
+ if (program.args.length > 0) {
75
+ program.error(`unknown command '${program.args[0]}'`, {
76
+ code: 'commander.unknownCommand',
77
+ exitCode: ExitCode.Usage,
78
+ });
79
+ }
47
80
  showBanner(version);
48
81
  program.help();
49
82
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skhema/cli",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "Skhema CLI - Authentication and AI skills management for agent platforms",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,29 +20,12 @@
20
20
  "skills"
21
21
  ],
22
22
  "scripts": {
23
- "dev": "tsc --watch",
24
23
  "build": "tsc",
25
- "lint": "eslint .",
26
- "lint:fix": "eslint . --fix",
27
- "format": "prettier --write .",
28
- "format:check": "prettier --check .",
29
- "typecheck": "tsc --noEmit",
30
- "test": "vitest run",
31
- "test:watch": "vitest",
32
- "clean": "rm -rf dist node_modules skills",
33
- "clean:dist": "rm -rf dist",
34
- "sync-skills": "tsx scripts/sync-skills.ts",
35
- "prebuild": "npm run clean:dist && npm run sync-skills",
36
- "prepack": "npm run sync-skills",
37
- "check": "npm run typecheck && npm run lint && npm run format:check",
38
- "check:fix": "npm run format && npm run lint:fix",
39
- "prepublishOnly": "npm run build",
40
- "postinstall": "node dist/postinstall.js || true",
41
- "generate:cli-reference": "tsx scripts/generate-cli-reference.ts"
24
+ "prebuild": "rm -rf dist"
42
25
  },
43
26
  "dependencies": {
44
27
  "@skhema/agent-sdk": "0.1.4",
45
- "@skhema/method": "0.3.0",
28
+ "@skhema/method": "0.4.1",
46
29
  "@skhema/sdk": "0.2.4",
47
30
  "chalk": "^5.3.0",
48
31
  "commander": "^12.0.0",
@@ -50,8 +33,6 @@
50
33
  },
51
34
  "devDependencies": {
52
35
  "@mdx-js/mdx": "3.1.1",
53
- "@skhema/linter": "2.3.0",
54
- "@skhema/prettier-config": "1.0.0",
55
36
  "@types/node": "^22.0.0",
56
37
  "eslint": "^9.0.0",
57
38
  "prettier": "^3.0.0",
@@ -67,5 +48,12 @@
67
48
  "publishConfig": {
68
49
  "access": "public"
69
50
  },
70
- "homepage": "https://skhema.com/docs/api"
51
+ "homepage": "https://skhema.com/docs/cli",
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/skhema/cli.git"
55
+ },
56
+ "bugs": {
57
+ "url": "https://github.com/skhema/cli/issues"
58
+ }
71
59
  }
@@ -38,8 +38,9 @@ to *write* the element — indicative for a judgment, imperative for a command,
38
38
  a noun phrase for a thing. It is a check on the sentence. **Placement** tells
39
39
  you *where the element is allowed to live*, and the platform enforces a strict
40
40
  type→component allow-list that does NOT follow mood. Put a type in the wrong
41
- component and `element create` rejects it. There is no discovery command for
42
- this; the allow-list is:
41
+ component and `element create` rejects it. Discover it locally (no network)
42
+ with `skhema element types` (add `--json` for machine-readable output); the
43
+ allow-list is:
43
44
 
44
45
  | Component | Element types it accepts |
45
46
  |---|---|
@@ -83,13 +83,18 @@ thing we've decided is true" and "a thing we've decided to do about a danger" is
83
83
  the whole discipline — an assumption you never test and a risk you never watch
84
84
  are the same landmine wearing two hats.
85
85
 
86
- **Encoding this in Skhema.** There is no `risk` element type in the taxonomy, so
87
- both halves land as `assumption_hypothesis`. A belief is the bet stated as a
88
- claim. A risk is *also* an `assumption_hypothesis` the bet that the danger
89
- stays away paired with a linked `experiment` or `action` that carries the
90
- tripwire: the signal you'll watch and what you'll do when it fires. The tripwire
91
- condition itself goes in the element's `reasoning` field until the taxonomy
92
- grows a better home for it. Don't reach for a `risk` type; it doesn't exist.
86
+ **Encoding this in Skhema.** There is no `risk` element type in the taxonomy
87
+ a deliberate decision (2026-07-20), not a gap. Encode both halves with the
88
+ types that exist. A belief is the bet stated as a claim: an
89
+ `assumption_hypothesis`. A risk is *also* an `assumption_hypothesis` the bet
90
+ that the danger stays away paired with a linked `experiment` or `action` that
91
+ carries the tripwire: the signal you'll watch and what you'll do when it fires.
92
+ The tripwire condition goes in the element's `reasoning` field. One refinement:
93
+ when the risk is really "this quantity must hold for the solution to stay
94
+ valid" — a threshold, a rate, a level — encode it as a `performance_variable`
95
+ (in Measures) instead; that is exactly what the type means, and it gives the
96
+ tripwire a measurable home. Don't reach for a `risk` type; it doesn't exist,
97
+ and won't unless a feature ever needs to query risks as first-class objects.
93
98
 
94
99
  ```
95
100
  CAUSE 1 → ASSUMPTION: Sales team can sell upmarket.
@@ -1,13 +0,0 @@
1
- {
2
- "syncedAt": "2026-07-09T17:15:20.908Z",
3
- "source": "/Users/michaellovell/Desktop/GitHub/skhema-skills",
4
- "sourceSha": "2a3abbb24f2fb2539608102eabc90de10fc9984b",
5
- "skills": [
6
- "skhema-frame",
7
- "skhema-compose",
8
- "skhema-calibrate",
9
- "skhema-pressure-test",
10
- "skhema-communicate",
11
- "skhema-operate"
12
- ]
13
- }