@soku-ai/cli 0.1.0-alpha.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.
Files changed (85) hide show
  1. package/README.md +91 -0
  2. package/dist/auth/device.d.ts +36 -0
  3. package/dist/auth/device.d.ts.map +1 -0
  4. package/dist/auth/device.js +66 -0
  5. package/dist/auth/device.js.map +1 -0
  6. package/dist/auth/store.d.ts +11 -0
  7. package/dist/auth/store.d.ts.map +1 -0
  8. package/dist/auth/store.js +89 -0
  9. package/dist/auth/store.js.map +1 -0
  10. package/dist/commands/auth.d.ts +4 -0
  11. package/dist/commands/auth.d.ts.map +1 -0
  12. package/dist/commands/auth.js +99 -0
  13. package/dist/commands/auth.js.map +1 -0
  14. package/dist/commands/brand.d.ts +4 -0
  15. package/dist/commands/brand.d.ts.map +1 -0
  16. package/dist/commands/brand.js +53 -0
  17. package/dist/commands/brand.js.map +1 -0
  18. package/dist/commands/call.d.ts +4 -0
  19. package/dist/commands/call.d.ts.map +1 -0
  20. package/dist/commands/call.js +48 -0
  21. package/dist/commands/call.js.map +1 -0
  22. package/dist/commands/egress.d.ts +24 -0
  23. package/dist/commands/egress.d.ts.map +1 -0
  24. package/dist/commands/egress.js +197 -0
  25. package/dist/commands/egress.js.map +1 -0
  26. package/dist/commands/generated.d.ts +41 -0
  27. package/dist/commands/generated.d.ts.map +1 -0
  28. package/dist/commands/generated.js +106 -0
  29. package/dist/commands/generated.js.map +1 -0
  30. package/dist/commands/org.d.ts +4 -0
  31. package/dist/commands/org.d.ts.map +1 -0
  32. package/dist/commands/org.js +49 -0
  33. package/dist/commands/org.js.map +1 -0
  34. package/dist/commands/resources.d.ts +4 -0
  35. package/dist/commands/resources.d.ts.map +1 -0
  36. package/dist/commands/resources.js +22 -0
  37. package/dist/commands/resources.js.map +1 -0
  38. package/dist/commands/review.d.ts +8 -0
  39. package/dist/commands/review.d.ts.map +1 -0
  40. package/dist/commands/review.js +74 -0
  41. package/dist/commands/review.js.map +1 -0
  42. package/dist/commands/skill.d.ts +19 -0
  43. package/dist/commands/skill.d.ts.map +1 -0
  44. package/dist/commands/skill.js +313 -0
  45. package/dist/commands/skill.js.map +1 -0
  46. package/dist/config.d.ts +17 -0
  47. package/dist/config.d.ts.map +1 -0
  48. package/dist/config.js +45 -0
  49. package/dist/config.js.map +1 -0
  50. package/dist/generated/capabilities.json +770 -0
  51. package/dist/http/client.d.ts +12 -0
  52. package/dist/http/client.d.ts.map +1 -0
  53. package/dist/http/client.js +91 -0
  54. package/dist/http/client.js.map +1 -0
  55. package/dist/index.d.ts +4 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +39 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/output/envelope.d.ts +45 -0
  60. package/dist/output/envelope.d.ts.map +1 -0
  61. package/dist/output/envelope.js +86 -0
  62. package/dist/output/envelope.js.map +1 -0
  63. package/dist/output/unwrap.d.ts +11 -0
  64. package/dist/output/unwrap.d.ts.map +1 -0
  65. package/dist/output/unwrap.js +33 -0
  66. package/dist/output/unwrap.js.map +1 -0
  67. package/dist/resolve.d.ts +24 -0
  68. package/dist/resolve.d.ts.map +1 -0
  69. package/dist/resolve.js +24 -0
  70. package/dist/resolve.js.map +1 -0
  71. package/dist/skills/unzip.d.ts +14 -0
  72. package/dist/skills/unzip.d.ts.map +1 -0
  73. package/dist/skills/unzip.js +86 -0
  74. package/dist/skills/unzip.js.map +1 -0
  75. package/dist/update-check.d.ts +24 -0
  76. package/dist/update-check.d.ts.map +1 -0
  77. package/dist/update-check.js +204 -0
  78. package/dist/update-check.js.map +1 -0
  79. package/dist/version.d.ts +3 -0
  80. package/dist/version.d.ts.map +1 -0
  81. package/dist/version.js +3 -0
  82. package/dist/version.js.map +1 -0
  83. package/package.json +61 -0
  84. package/skills/soku/SKILL.md +225 -0
  85. package/skills/soku/references/capability-flow.md +71 -0
@@ -0,0 +1,197 @@
1
+ /** `soku egress -- <curl…>` — proxy a third-party API call through Soku so the
2
+ * credential is injected server-side (no API key on this machine), and
3
+ * `soku egress providers` — list the covered hosts.
4
+ *
5
+ * The agent prefixes its existing skill `curl` with `soku egress --`; we parse
6
+ * the curl, strip any placeholder auth header, and forward the request to
7
+ * `/api/cli/egress`. The upstream response is streamed back to stdout verbatim,
8
+ * so the skill sees exactly what a direct call would return. Only Soku-level
9
+ * failures (auth, allowlist, billing) become a CLI error envelope.
10
+ */
11
+ import { randomUUID } from 'node:crypto';
12
+ import { readFileSync } from 'node:fs';
13
+ import { Readable } from 'node:stream';
14
+ import { pipeline } from 'node:stream/promises';
15
+ import { clearToken, loadToken } from '../auth/store.js';
16
+ import { loadConfig, resolveApiBaseUrl } from '../config.js';
17
+ import { apiRequest } from '../http/client.js';
18
+ import { cyan, dim, emitError, emitSuccess, ExitCode, table } from '../output/envelope.js';
19
+ // A header value carrying only an auth scheme word (or nothing) — the result of
20
+ // `-H "Authorization: Bearer $X"` when `$X` is unset. Not a real credential.
21
+ const PLACEHOLDER_AUTH = /^\s*(bearer|token|key|basic)?\s*$/i;
22
+ function readData(value) {
23
+ if (value.startsWith('@'))
24
+ return readFileSync(value.slice(1));
25
+ return Buffer.from(value);
26
+ }
27
+ /** Extract method / url / headers / body from a curl-style token list. Pure. */
28
+ export function parseCurl(tokens) {
29
+ const headers = {};
30
+ let method;
31
+ let url;
32
+ let body;
33
+ let getMode = false;
34
+ let i = tokens[0] === 'curl' ? 1 : 0;
35
+ for (; i < tokens.length; i++) {
36
+ const t = tokens[i];
37
+ switch (t) {
38
+ case '-X':
39
+ case '--request':
40
+ method = tokens[++i]?.toUpperCase();
41
+ break;
42
+ case '-H':
43
+ case '--header': {
44
+ const h = tokens[++i];
45
+ if (h) {
46
+ const idx = h.indexOf(':');
47
+ if (idx > 0)
48
+ headers[h.slice(0, idx).trim().toLowerCase()] = h.slice(idx + 1).trim();
49
+ }
50
+ break;
51
+ }
52
+ case '-d':
53
+ case '--data':
54
+ case '--data-raw':
55
+ case '--data-ascii':
56
+ case '--data-binary': {
57
+ const d = tokens[++i];
58
+ if (d !== undefined)
59
+ body = readData(d);
60
+ break;
61
+ }
62
+ case '-G':
63
+ case '--get':
64
+ getMode = true;
65
+ break;
66
+ case '--url':
67
+ url = tokens[++i];
68
+ break;
69
+ default:
70
+ if (/^https?:\/\//i.test(t))
71
+ url = t;
72
+ // Unknown flags are skipped; we do not consume their value, so a few
73
+ // exotic curl flags may leak a token — the documented subset is
74
+ // -X/-H/-d/--data*/-G/--url + the URL.
75
+ break;
76
+ }
77
+ }
78
+ if (!method)
79
+ method = body ? 'POST' : 'GET';
80
+ if (getMode && body && url) {
81
+ const u = new URL(url);
82
+ for (const [k, v] of new URLSearchParams(body.toString()))
83
+ u.searchParams.append(k, v);
84
+ url = u.toString();
85
+ body = undefined;
86
+ method = 'GET';
87
+ }
88
+ return { method, url, headers, body };
89
+ }
90
+ /** Drop empty / bare-scheme auth headers so the server injects the real key
91
+ * (an empty `Authorization: Bearer ` would otherwise be treated as BYO). */
92
+ export function stripPlaceholderAuth(headers) {
93
+ const out = {};
94
+ for (const [k, v] of Object.entries(headers)) {
95
+ if (PLACEHOLDER_AUTH.test(v))
96
+ continue;
97
+ out[k] = v;
98
+ }
99
+ return out;
100
+ }
101
+ function workspace() {
102
+ const cfg = loadConfig();
103
+ const orgId = process.env.SOKU_ORG_ID || cfg.activeOrgId;
104
+ const brandId = process.env.SOKU_BRAND_ID || cfg.activeBrandId;
105
+ if (!orgId || !brandId) {
106
+ emitError('no_workspace', 'No active workspace selected.', ExitCode.USAGE, 'Run `soku org use <id>` then `soku brand use <id>`.');
107
+ }
108
+ return { orgId, brandId };
109
+ }
110
+ function egressErrorExit(status, type, message) {
111
+ const code = status === 401 || status === 403
112
+ ? ExitCode.AUTH
113
+ : status === 402 || status === 400
114
+ ? ExitCode.USAGE
115
+ : status === 404
116
+ ? ExitCode.NOT_FOUND
117
+ : ExitCode.RUNTIME;
118
+ return emitError(type, message, code);
119
+ }
120
+ async function runEgress(parsed) {
121
+ if (!parsed.url) {
122
+ emitError('usage', 'No URL found in the egress request.', ExitCode.USAGE, 'Usage: soku egress -- curl <url>');
123
+ }
124
+ const token = await loadToken();
125
+ if (!token) {
126
+ emitError('not_authenticated', 'No Soku session found.', ExitCode.AUTH, 'Run `soku auth login`.');
127
+ }
128
+ const { orgId, brandId } = workspace();
129
+ const headers = stripPlaceholderAuth(parsed.headers);
130
+ const spec = { method: parsed.method, url: parsed.url, headers, id: randomUUID() };
131
+ const specHeader = Buffer.from(JSON.stringify(spec)).toString('base64');
132
+ const base = resolveApiBaseUrl();
133
+ let res;
134
+ try {
135
+ res = await fetch(`${base}/api/cli/egress`, {
136
+ method: 'POST',
137
+ headers: {
138
+ Authorization: `Bearer ${token}`,
139
+ 'X-Soku-Org': orgId,
140
+ 'X-Soku-Brand': brandId,
141
+ 'X-Soku-Egress-Spec': specHeader,
142
+ ...(parsed.body ? { 'Content-Type': 'application/octet-stream' } : {}),
143
+ },
144
+ body: parsed.body,
145
+ });
146
+ }
147
+ catch (err) {
148
+ return emitError('network_error', `Could not reach ${base}: ${err.message}`, ExitCode.RUNTIME, 'Behind a proxy? Set ALL_PROXY.');
149
+ }
150
+ // Success always carries the upstream marker; anything else is a Soku-level
151
+ // failure (auth/workspace dependency error, or an _egress_error envelope).
152
+ if (res.headers.get('x-soku-egress') !== 'upstream') {
153
+ if (res.status === 401)
154
+ await clearToken();
155
+ const parsedBody = (await res.json().catch(() => null));
156
+ const errObj = parsedBody?.error ??
157
+ parsedBody?.detail ??
158
+ {};
159
+ const type = String(errObj.type ?? errObj.error ?? 'egress_error');
160
+ const message = String(errObj.message ?? `Egress failed (HTTP ${res.status}).`);
161
+ egressErrorExit(res.status, type, message);
162
+ }
163
+ // Passthrough: stream the upstream body to stdout verbatim.
164
+ if (res.body) {
165
+ await pipeline(Readable.fromWeb(res.body), process.stdout);
166
+ }
167
+ process.exit(ExitCode.OK);
168
+ }
169
+ export function registerEgressCommands(program) {
170
+ const egress = program
171
+ .command('egress')
172
+ .description('Proxy a third-party API call with a server-injected credential')
173
+ .argument('[request...]', 'the third-party request, e.g. `-- curl -H "..." https://host/path`')
174
+ .allowUnknownOption()
175
+ .action(async (request) => {
176
+ await runEgress(parseCurl(request));
177
+ });
178
+ egress
179
+ .command('providers')
180
+ .description('List third-party hosts the egress proxy injects credentials for')
181
+ .action(async () => {
182
+ const data = await apiRequest('/api/cli/egress/providers', { workspace: true });
183
+ emitSuccess(data, (d) => {
184
+ const t = table(d.providers.map((p) => ({
185
+ id: p.id,
186
+ hosts: p.hostnames.join(', '),
187
+ auth: `${p.auth.location}:${p.auth.name}`,
188
+ })), [
189
+ { key: 'id', header: 'PROVIDER' },
190
+ { key: 'hosts', header: 'HOSTS' },
191
+ { key: 'auth', header: 'AUTH' },
192
+ ]);
193
+ return `${t}\n${dim(`${d.count} covered · call via: `)}${cyan('soku egress -- curl <url>')}`;
194
+ });
195
+ });
196
+ }
197
+ //# sourceMappingURL=egress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress.js","sourceRoot":"","sources":["../../src/commands/egress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /** Typed data-action sub-commands, generated from the capability manifest.
2
+ *
3
+ * The manifest (`src/generated/capabilities.json`, produced by
4
+ * `scripts/gen-capabilities.ts`) is a snapshot of the backend ActionSpec
5
+ * registry's read-only data-infra surface. Each action becomes a sub-command
6
+ * under its namespace (e.g. `soku ads query-single-dimension`), with one flag
7
+ * per input param. `--help` on any command is the shell-native equivalent of
8
+ * the old `capabilities describe`. The raw `soku call` command remains as a
9
+ * forward-compat escape hatch for actions not yet in a published manifest.
10
+ */
11
+ import { Command } from 'commander';
12
+ export interface ManifestParam {
13
+ name: string;
14
+ type: string;
15
+ required: boolean;
16
+ description: string;
17
+ example?: unknown;
18
+ }
19
+ export interface ManifestAction {
20
+ id: string;
21
+ namespace: string;
22
+ action: string;
23
+ description: string;
24
+ long_description: string | null;
25
+ capability_mode: string;
26
+ priority: string;
27
+ requires_review: boolean;
28
+ freshness_kind: string;
29
+ input_params: ManifestParam[];
30
+ output_shape: string | null;
31
+ see_also: string[];
32
+ }
33
+ export interface CapabilityManifest {
34
+ actions: ManifestAction[];
35
+ }
36
+ /** Load the committed manifest shipped alongside the compiled CLI. */
37
+ export declare function loadManifest(): CapabilityManifest;
38
+ /** Register one namespace group + typed sub-command per manifest action. */
39
+ export declare function buildGeneratedCommands(program: Command, manifest: CapabilityManifest): void;
40
+ export declare function registerGeneratedCommands(program: Command): void;
41
+ //# sourceMappingURL=generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generated.d.ts","sourceRoot":"","sources":["../../src/commands/generated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,aAAa,EAAE,CAAA;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,cAAc,EAAE,CAAA;CAC1B;AAmCD,sEAAsE;AACtE,wBAAgB,YAAY,IAAI,kBAAkB,CAGjD;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAmD3F;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEhE"}
@@ -0,0 +1,106 @@
1
+ /** Typed data-action sub-commands, generated from the capability manifest.
2
+ *
3
+ * The manifest (`src/generated/capabilities.json`, produced by
4
+ * `scripts/gen-capabilities.ts`) is a snapshot of the backend ActionSpec
5
+ * registry's read-only data-infra surface. Each action becomes a sub-command
6
+ * under its namespace (e.g. `soku ads query-single-dimension`), with one flag
7
+ * per input param. `--help` on any command is the shell-native equivalent of
8
+ * the old `capabilities describe`. The raw `soku call` command remains as a
9
+ * forward-compat escape hatch for actions not yet in a published manifest.
10
+ */
11
+ import { readFileSync } from 'node:fs';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { apiRequest } from '../http/client.js';
14
+ import { emitError, emitSuccess, ExitCode } from '../output/envelope.js';
15
+ import { unwrapDispatch } from '../output/unwrap.js';
16
+ function toKebab(name) {
17
+ return name.replace(/_/g, '-');
18
+ }
19
+ function toCamel(name) {
20
+ return name.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
21
+ }
22
+ function isJsonType(type) {
23
+ // object / list, plus unions that include either (e.g. "string|list").
24
+ return /\b(object|list)\b/.test(type);
25
+ }
26
+ function isNumberType(type) {
27
+ return type === 'integer' || type === 'number';
28
+ }
29
+ function parseJsonFlag(param, raw) {
30
+ try {
31
+ return JSON.parse(raw);
32
+ }
33
+ catch {
34
+ return emitError('usage', `--${toKebab(param)} must be valid JSON.`, ExitCode.USAGE);
35
+ }
36
+ }
37
+ function parseNumberFlag(param, raw) {
38
+ const n = Number(raw);
39
+ if (Number.isNaN(n)) {
40
+ return emitError('usage', `--${toKebab(param)} must be a number.`, ExitCode.USAGE);
41
+ }
42
+ return n;
43
+ }
44
+ /** Load the committed manifest shipped alongside the compiled CLI. */
45
+ export function loadManifest() {
46
+ const path = fileURLToPath(new URL('../generated/capabilities.json', import.meta.url));
47
+ return JSON.parse(readFileSync(path, 'utf8'));
48
+ }
49
+ /** Register one namespace group + typed sub-command per manifest action. */
50
+ export function buildGeneratedCommands(program, manifest) {
51
+ const groups = new Map();
52
+ const groupFor = (namespace) => {
53
+ let group = groups.get(namespace);
54
+ if (!group) {
55
+ group = program.command(namespace).description(`${namespace} data capabilities`);
56
+ groups.set(namespace, group);
57
+ }
58
+ return group;
59
+ };
60
+ for (const spec of manifest.actions) {
61
+ const cmd = groupFor(spec.namespace).command(toKebab(spec.action));
62
+ cmd.description(spec.description);
63
+ if (spec.long_description)
64
+ cmd.addHelpText('after', `\n${spec.long_description}`);
65
+ for (const param of spec.input_params) {
66
+ const flag = `--${toKebab(param.name)}`;
67
+ const desc = param.description || param.name;
68
+ if (param.type === 'boolean') {
69
+ cmd.option(flag, desc);
70
+ continue;
71
+ }
72
+ const valueFlag = `${flag} <value>`;
73
+ const coerce = isJsonType(param.type)
74
+ ? (v) => parseJsonFlag(param.name, v)
75
+ : isNumberType(param.type)
76
+ ? (v) => parseNumberFlag(param.name, v)
77
+ : undefined;
78
+ if (param.required) {
79
+ if (coerce)
80
+ cmd.requiredOption(valueFlag, desc, coerce);
81
+ else
82
+ cmd.requiredOption(valueFlag, desc);
83
+ }
84
+ else {
85
+ if (coerce)
86
+ cmd.option(valueFlag, desc, coerce);
87
+ else
88
+ cmd.option(valueFlag, desc);
89
+ }
90
+ }
91
+ cmd.action(async (opts) => {
92
+ const payload = {};
93
+ for (const param of spec.input_params) {
94
+ const value = opts[toCamel(param.name)];
95
+ if (value !== undefined)
96
+ payload[param.name] = value;
97
+ }
98
+ const result = await apiRequest(`/api/cli/call/${encodeURIComponent(spec.namespace)}/${encodeURIComponent(spec.action)}`, { method: 'POST', body: payload, workspace: true });
99
+ emitSuccess(unwrapDispatch(result));
100
+ });
101
+ }
102
+ }
103
+ export function registerGeneratedCommands(program) {
104
+ buildGeneratedCommands(program, loadManifest());
105
+ }
106
+ //# sourceMappingURL=generated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generated.js","sourceRoot":"","sources":["../../src/commands/generated.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** `soku org list | use <id>` */
2
+ import { Command } from 'commander';
3
+ export declare function registerOrgCommands(program: Command): void;
4
+ //# sourceMappingURL=org.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org.d.ts","sourceRoot":"","sources":["../../src/commands/org.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAanC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+D1D"}
@@ -0,0 +1,49 @@
1
+ /** `soku org list | use <id>` */
2
+ import { loadConfig, updateConfig } from '../config.js';
3
+ import { apiRequest } from '../http/client.js';
4
+ import { cyan, dim, emitError, emitSuccess, ExitCode, green, table } from '../output/envelope.js';
5
+ import { matchRef } from '../resolve.js';
6
+ export function registerOrgCommands(program) {
7
+ const org = program.command('org').description('Manage the active organization');
8
+ org
9
+ .command('list')
10
+ .description('List organizations you belong to')
11
+ .action(async () => {
12
+ const data = await apiRequest('/api/cli/orgs');
13
+ const activeOrgId = loadConfig().activeOrgId;
14
+ emitSuccess(data, (d) => table(d.orgs.map((o) => ({
15
+ active: o.id === activeOrgId ? green('●') : ' ',
16
+ name: o.name,
17
+ slug: o.slug ?? '',
18
+ id: o.id,
19
+ })), [
20
+ { key: 'active', header: ' ' },
21
+ { key: 'name', header: 'NAME' },
22
+ { key: 'slug', header: 'SLUG' },
23
+ { key: 'id', header: 'ID' },
24
+ ]));
25
+ });
26
+ org
27
+ .command('use <org>')
28
+ .description('Set the active organization (accepts id, slug, or name)')
29
+ .action(async (ref) => {
30
+ const { orgs } = await apiRequest('/api/cli/orgs');
31
+ const res = matchRef(orgs, ref);
32
+ if (res.kind === 'none') {
33
+ emitError('not_found', `No organization matching "${ref}".`, ExitCode.NOT_FOUND, 'Run `soku org list` to see available orgs.');
34
+ }
35
+ if (res.kind === 'ambiguous') {
36
+ const candidates = res.matches.map((o) => `${o.slug ?? o.id} (${o.id})`).join(', ');
37
+ emitError('ambiguous', `"${ref}" matches ${res.matches.length} organizations.`, ExitCode.USAGE, `Use a slug or id: ${candidates}`);
38
+ }
39
+ const match = res.item;
40
+ // Switching org clears the brand — it may not belong to the new org.
41
+ const prev = loadConfig();
42
+ updateConfig({
43
+ activeOrgId: match.id,
44
+ activeBrandId: prev.activeOrgId === match.id ? prev.activeBrandId : undefined,
45
+ });
46
+ emitSuccess({ active_org_id: match.id, name: match.name, slug: match.slug }, (d) => `${green('✓')} Active org: ${cyan(d.name ?? d.active_org_id)} ${dim(`(${d.active_org_id})`)}\n ${dim('Next: soku brand use <slug|id>')}`);
47
+ });
48
+ }
49
+ //# sourceMappingURL=org.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org.js","sourceRoot":"","sources":["../../src/commands/org.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** `soku resources list` — show the external resources granted to this session. */
2
+ import { Command } from 'commander';
3
+ export declare function registerResourceCommands(program: Command): void;
4
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../src/commands/resources.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAYnC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0B/D"}
@@ -0,0 +1,22 @@
1
+ /** `soku resources list` — show the external resources granted to this session. */
2
+ import { Command } from 'commander';
3
+ import { apiRequest } from '../http/client.js';
4
+ import { emitSuccess, table } from '../output/envelope.js';
5
+ export function registerResourceCommands(program) {
6
+ program
7
+ .command('resources')
8
+ .description('List external resources granted to this session')
9
+ .addCommand(new Command('list').action(async () => {
10
+ const data = await apiRequest('/api/cli/resources', { workspace: true });
11
+ emitSuccess(data, (d) => table(d.resources.map((r) => ({
12
+ id: r.id,
13
+ label: r.label ?? '',
14
+ description: r.description ?? '',
15
+ })), [
16
+ { key: 'id', header: 'RESOURCE' },
17
+ { key: 'label', header: 'LABEL' },
18
+ { key: 'description', header: 'DESCRIPTION' },
19
+ ]));
20
+ }));
21
+ }
22
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/commands/resources.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAS1D,MAAM,UAAU,wBAAwB,CAAC,OAAgB;IACvD,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,iDAAiD,CAAC;SAC9D,UAAU,CACT,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QACpC,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,oBAAoB,EACpB,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAA;QACD,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CACtB,KAAK,CACH,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;YACpB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;SACjC,CAAC,CAAC,EACH;YACE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE;YACjC,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;YACjC,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE;SAC9C,CACF,CACF,CAAA;IACH,CAAC,CAAC,CACH,CAAA;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** `soku review list | show <id> | approve <id> | deny <id>`
2
+ *
3
+ * HITL for review-gated write actions: a `soku call` of a write action returns
4
+ * a pending review id; the user approves it here, which executes the action.
5
+ */
6
+ import { Command } from 'commander';
7
+ export declare function registerReviewCommands(program: Command): void;
8
+ //# sourceMappingURL=review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA4BnC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqE7D"}
@@ -0,0 +1,74 @@
1
+ /** `soku review list | show <id> | approve <id> | deny <id>`
2
+ *
3
+ * HITL for review-gated write actions: a `soku call` of a write action returns
4
+ * a pending review id; the user approves it here, which executes the action.
5
+ */
6
+ import { apiRequest } from '../http/client.js';
7
+ import { cyan, dim, emitSuccess, green, red, table } from '../output/envelope.js';
8
+ function statusMark(status) {
9
+ if (status === 'approved')
10
+ return green('approved');
11
+ if (status === 'failed' || status === 'rejected')
12
+ return red(status);
13
+ return dim(status);
14
+ }
15
+ function truncate(text, max) {
16
+ const one = (text ?? '').replace(/\s+/g, ' ').trim();
17
+ return one.length > max ? `${one.slice(0, max - 1)}…` : one;
18
+ }
19
+ export function registerReviewCommands(program) {
20
+ const review = program
21
+ .command('review')
22
+ .description('Approve or inspect review-gated write actions');
23
+ review
24
+ .command('list')
25
+ .description('List your review-gated actions (pending and decided)')
26
+ .option('--status <status>', 'Filter: pending | executing | approved | failed | rejected')
27
+ .action(async (opts) => {
28
+ const q = opts.status ? `?status=${encodeURIComponent(opts.status)}` : '';
29
+ const data = await apiRequest(`/api/cli/reviews${q}`, {
30
+ workspace: true,
31
+ });
32
+ emitSuccess(data, (d) => table(d.reviews.map((r) => ({
33
+ id: r.id,
34
+ action: `${r.namespace}/${r.action}`,
35
+ status: statusMark(r.status),
36
+ summary: truncate(r.summary, 48),
37
+ })), [
38
+ { key: 'id', header: 'ID' },
39
+ { key: 'action', header: 'ACTION' },
40
+ { key: 'status', header: 'STATUS' },
41
+ { key: 'summary', header: 'SUMMARY' },
42
+ ]));
43
+ });
44
+ review
45
+ .command('show <id>')
46
+ .description('Show one review (full payload, executed payload, result)')
47
+ .action(async (id) => {
48
+ emitSuccess(await apiRequest(`/api/cli/reviews/${encodeURIComponent(id)}`, { workspace: true }));
49
+ });
50
+ review
51
+ .command('approve <id>')
52
+ .description('Approve a review — this executes the write action')
53
+ .action(async (id) => {
54
+ const r = await apiRequest(`/api/cli/reviews/${encodeURIComponent(id)}/respond`, {
55
+ method: 'POST',
56
+ body: { decision: 'approve' },
57
+ workspace: true,
58
+ });
59
+ emitSuccess(r, (d) => `${d.status === 'approved' ? green('✓') : red('✖')} ${statusMark(d.status)}: ${cyan(`${d.namespace}/${d.action}`)}`);
60
+ });
61
+ review
62
+ .command('deny <id>')
63
+ .description('Reject a review — the action is not executed')
64
+ .option('--feedback <text>', 'Reason for rejecting')
65
+ .action(async (id, opts) => {
66
+ const r = await apiRequest(`/api/cli/reviews/${encodeURIComponent(id)}/respond`, {
67
+ method: 'POST',
68
+ body: { decision: 'reject', feedback: opts.feedback },
69
+ workspace: true,
70
+ });
71
+ emitSuccess(r, (d) => `${red('✖')} rejected: ${cyan(`${d.namespace}/${d.action}`)}`);
72
+ });
73
+ }
74
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /** `soku skill` — discover and install Soku skills into an AI client.
2
+ *
3
+ * - `soku skill list` browse the public skill catalog (CDN)
4
+ * - `soku skill install <slug...>` download + install business skills
5
+ * - `soku skill install --all` install the whole catalog
6
+ * - `soku skill install` (no slug) install just the bundled `soku` meta-skill
7
+ * - `soku skill installed` / `remove` manage what's installed locally
8
+ *
9
+ * Business skills are fetched as per-skill zips from a public CDN
10
+ * (`cdn.soku.ai/skills/`), already translated to CLI-native at pack time. We
11
+ * verify the sha256 from index.json, unzip safely, and drop each business skill
12
+ * into `<skillsDir>/soku/<slug>/` with a top-level symlink
13
+ * `<skillsDir>/soku-<slug> -> soku/<slug>`. The bundled `soku` meta-skill (how
14
+ * to drive the CLI) ships in the npm package and is installed as a prerequisite. */
15
+ import { Command } from 'commander';
16
+ /** A slug is safe to use as a path segment (no traversal/separators). Exported for tests. */
17
+ export declare function isSafeSlug(slug: string): boolean;
18
+ export declare function registerSkillCommand(program: Command): void;
19
+ //# sourceMappingURL=skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;oFAaoF;AAQpF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiFnC,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAuKD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8H3D"}