@skhema/cli 0.3.1 → 0.4.0

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/cli.js CHANGED
@@ -24,7 +24,7 @@ const pkg = require('../package.json');
24
24
  const program = new Command();
25
25
  program
26
26
  .name('skhema')
27
- .description('Skhema CLI — authentication and AI skills management')
27
+ .description('Skhema CLI — drive the Skhema Public API from your terminal, CI, or agent')
28
28
  .version(pkg.version)
29
29
  .option('--json', 'Output structured JSON')
30
30
  .option('--verbose', 'Verbose output')
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuBnC,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AACD,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;CACzD;AASD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,WAAW,GAChB,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB1D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkF1D"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuBnC,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AACD,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;CACzD;AASD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,WAAW,GAChB,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB1D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsF1D"}
@@ -63,7 +63,9 @@ export function registerApiCommands(program) {
63
63
  readFile: (p) => readFile(p, 'utf-8'),
64
64
  readStdin,
65
65
  });
66
- const { client } = await resolveClient();
66
+ // Meta endpoints (health, openapi) work with no credential; the SDK
67
+ // still throws (exit 3) for any authed path resolved anonymously.
68
+ const { client } = await resolveClient({ allowAnonymous: true });
67
69
  const data = await client.request(httpMethod, path, {
68
70
  body,
69
71
  query,
@@ -81,7 +83,9 @@ export function registerApiCommands(program) {
81
83
  .description('List every live gateway route from /v1/openapi.json')
82
84
  .action(async () => {
83
85
  await runCommand('api routes', async () => {
84
- const { client } = await resolveClient();
86
+ // Route discovery hits only GET /v1/openapi.json (unauthenticated), so
87
+ // it works anonymously — part of the first-touch agent experience.
88
+ const { client } = await resolveClient({ allowAnonymous: true });
85
89
  const spec = await client.meta.openapi();
86
90
  if (getGlobalOptions().json) {
87
91
  // Under --json the raw spec is the payload (the envelope wraps it).
@@ -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,CA+P9D"}
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,CAwS9D"}
@@ -39,6 +39,40 @@ export function registerElementCommands(program) {
39
39
  return data;
40
40
  });
41
41
  });
42
+ withWorkspace(element
43
+ .command('search <query>')
44
+ .description('Full-text search over the workspace elements')
45
+ .option('--limit <n>', 'Maximum results')).action(async (query, options) => {
46
+ await runCommand('element search', async () => {
47
+ const workspaceId = resolveWorkspaceId(options.workspace);
48
+ if (options.limit !== undefined && !/^\d+$/.test(options.limit)) {
49
+ throw new UsageError('--limit must be a positive integer');
50
+ }
51
+ const { client } = await resolveClient();
52
+ const data = await client.elements.search(workspaceId, query, {
53
+ ...(options.limit !== undefined && {
54
+ limit: Number(options.limit),
55
+ }),
56
+ });
57
+ const rows = coerceList(data, 'elements');
58
+ if (!getGlobalOptions().json) {
59
+ logHeader(`Search results (${rows.length})`);
60
+ if (rows.length === 0)
61
+ log(chalk.dim(' No matching elements.'));
62
+ else
63
+ logTable(['Id', 'Component', 'Type', 'Content'], rows.map((r) => {
64
+ const e = asRecord(r);
65
+ return [
66
+ String(e.id ?? '—'),
67
+ String(e.componentType ?? '—'),
68
+ String(e.elementType ?? '—'),
69
+ summarize(e.content),
70
+ ];
71
+ }));
72
+ }
73
+ return data;
74
+ });
75
+ });
42
76
  // No `GET /v1/.../elements/:id` route exists on the gateway, so `element get`
43
77
  // fetches the workspace's element list and filters it client-side by id.
44
78
  withWorkspace(element.command('get <element-id>').description('Get an element by id')).action(async (elementId, options) => {
@@ -1,10 +1,13 @@
1
1
  import { SkhemaClient } from '@skhema/sdk';
2
2
  /** Which credential source, in precedence order, is backing the client. */
3
- export type CredentialLane = 'flag' | 'env' | 'stored-key' | 'oauth';
3
+ export type CredentialLane = 'flag' | 'env' | 'stored-key' | 'oauth' | 'anonymous';
4
4
  export interface CredentialDescriptor {
5
5
  lane: CredentialLane;
6
- /** `api-key` for the three key lanes; `oauth` for the stored session. */
7
- kind: 'api-key' | 'oauth';
6
+ /**
7
+ * `api-key` for the three key lanes; `oauth` for the stored session;
8
+ * `anonymous` for a credential-less client (meta endpoints only).
9
+ */
10
+ kind: 'api-key' | 'oauth' | 'anonymous';
8
11
  /** Masked key (`sk_live_...last4`), present for api-key lanes only. */
9
12
  maskedKey?: string;
10
13
  /** Organization id, when known without a network round-trip (OAuth lane). */
@@ -18,10 +21,22 @@ export interface ResolvedClient {
18
21
  }
19
22
  /** Mask a raw key to `sk_live_...abcd` — the only safe form to ever print. */
20
23
  export declare function maskApiKey(rawKey: string): string;
24
+ /** Options controlling {@link resolveClient}'s behaviour when no credential exists. */
25
+ export interface ResolveClientOptions {
26
+ /**
27
+ * When no credential is found, return an anonymous client (meta endpoints
28
+ * only) instead of throwing {@link AuthRequiredError}. For commands that touch
29
+ * only the unauthenticated meta endpoints (`api routes`, `api GET /health`).
30
+ * The SDK still enforces the per-route gate: an anonymous non-meta call throws
31
+ * {@link AuthError} (exit 3), so authed routes remain protected.
32
+ */
33
+ allowAnonymous?: boolean;
34
+ }
21
35
  /**
22
36
  * Resolve the active credential using the fixed precedence (spec §3.1):
23
37
  * `--api-key` flag → `SKHEMA_API_KEY` env → stored key → stored OAuth session.
24
- * Throws {@link AuthRequiredError} (exit 3) when none is available.
38
+ * Throws {@link AuthRequiredError} (exit 3) when none is available, unless
39
+ * `allowAnonymous` is set — then it falls back to a credential-less client.
25
40
  */
26
- export declare function resolveClient(): Promise<ResolvedClient>;
41
+ export declare function resolveClient(options?: ResolveClientOptions): Promise<ResolvedClient>;
27
42
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/lib/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,MAAM,aAAa,CAAA;AAO9D,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,YAAY,GAAG,OAAO,CAAA;AAEpE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAA;IACpB,yEAAyE;IACzE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAA;IACzB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,YAAY,CAAA;IACpB,UAAU,EAAE,oBAAoB,CAAA;CACjC;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjD;AASD;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC,CA4D7D"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/lib/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,MAAM,aAAa,CAAA;AAO9D,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,KAAK,GACL,YAAY,GACZ,OAAO,GACP,WAAW,CAAA;AAEf,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAA;IACpB;;;OAGG;IACH,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,CAAA;IACvC,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,YAAY,CAAA;IACpB,UAAU,EAAE,oBAAoB,CAAA;CACjC;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjD;AASD,uFAAuF;AACvF,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,CAAC,CA0EzB"}
@@ -15,9 +15,10 @@ function apiKeyClient(rawKey) {
15
15
  /**
16
16
  * Resolve the active credential using the fixed precedence (spec §3.1):
17
17
  * `--api-key` flag → `SKHEMA_API_KEY` env → stored key → stored OAuth session.
18
- * Throws {@link AuthRequiredError} (exit 3) when none is available.
18
+ * Throws {@link AuthRequiredError} (exit 3) when none is available, unless
19
+ * `allowAnonymous` is set — then it falls back to a credential-less client.
19
20
  */
20
- export async function resolveClient() {
21
+ export async function resolveClient(options = {}) {
21
22
  const flagKey = getApiKeyFlag();
22
23
  if (flagKey) {
23
24
  return {
@@ -66,6 +67,19 @@ export async function resolveClient() {
66
67
  },
67
68
  };
68
69
  }
70
+ if (options.allowAnonymous) {
71
+ return {
72
+ client: createSkhemaClient(undefined, {
73
+ baseUrl: API_BASE_URL,
74
+ authBaseUrl: AUTH_BASE_URL,
75
+ }),
76
+ credential: {
77
+ lane: 'anonymous',
78
+ kind: 'anonymous',
79
+ source: 'anonymous (meta endpoints only)',
80
+ },
81
+ };
82
+ }
69
83
  throw new AuthRequiredError('No credentials found. Run `skhema auth login` for interactive use, or set ' +
70
84
  `${API_KEY_ENV_VAR}=sk_live_… (or run \`skhema auth key use <key>\`) for headless/CI use.`);
71
85
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skhema/cli",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Skhema CLI - Authentication and AI skills management for agent platforms",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -44,7 +44,7 @@
44
44
  "commander": "^12.0.0",
45
45
  "ora": "^8.0.0",
46
46
  "@skhema/agent-sdk": "0.1.4",
47
- "@skhema/sdk": "0.1.2"
47
+ "@skhema/sdk": "0.2.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@skhema/linter": "2.2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "syncedAt": "2026-07-09T00:22:20.025Z",
2
+ "syncedAt": "2026-07-09T00:27:14.921Z",
3
3
  "source": "/Users/michaellovell/Desktop/GitHub/skhema-skills",
4
4
  "sourceSha": "77561c7dbde8602ca799e5224c65ea18675ee37b",
5
5
  "skills": [