@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,204 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { configDir } from './config.js';
4
+ import { cyan, dim, emitError, emitSuccess, ExitCode } from './output/envelope.js';
5
+ import { CLI_PACKAGE_NAME, CLI_VERSION } from './version.js';
6
+ const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org';
7
+ const INSTALL_COMMAND = `npm i -g ${CLI_PACKAGE_NAME}`;
8
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
9
+ const REQUEST_TIMEOUT_MS = 2500;
10
+ function cachePath() {
11
+ return join(configDir(), 'update-check.json');
12
+ }
13
+ function readCache(now) {
14
+ try {
15
+ const cache = JSON.parse(readFileSync(cachePath(), 'utf8'));
16
+ const checkedAt = new Date(cache.checked_at).getTime();
17
+ if (!Number.isFinite(checkedAt))
18
+ return null;
19
+ if (now.getTime() - checkedAt > CACHE_TTL_MS)
20
+ return null;
21
+ return cache;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ function writeCache(cache) {
28
+ const path = cachePath();
29
+ mkdirSync(dirname(path), { recursive: true });
30
+ writeFileSync(path, `${JSON.stringify(cache, null, 2)}\n`, { mode: 0o600 });
31
+ }
32
+ function parseVersionParts(version) {
33
+ const core = version.split('-', 1)[0] ?? '';
34
+ return core.split('.').map((part) => {
35
+ const n = Number(part);
36
+ return Number.isFinite(n) ? n : 0;
37
+ });
38
+ }
39
+ function prereleaseParts(version) {
40
+ const idx = version.indexOf('-');
41
+ if (idx === -1)
42
+ return [];
43
+ return version.slice(idx + 1).split(/[.+]/).filter(Boolean);
44
+ }
45
+ function comparePrerelease(a, b) {
46
+ const aa = prereleaseParts(a);
47
+ const bb = prereleaseParts(b);
48
+ if (aa.length === 0 && bb.length === 0)
49
+ return 0;
50
+ if (aa.length === 0)
51
+ return 1;
52
+ if (bb.length === 0)
53
+ return -1;
54
+ for (let i = 0; i < Math.max(aa.length, bb.length); i++) {
55
+ const left = aa[i];
56
+ const right = bb[i];
57
+ if (left === undefined)
58
+ return -1;
59
+ if (right === undefined)
60
+ return 1;
61
+ const leftNum = /^\d+$/.test(left) ? Number(left) : null;
62
+ const rightNum = /^\d+$/.test(right) ? Number(right) : null;
63
+ if (leftNum !== null && rightNum !== null) {
64
+ const diff = leftNum - rightNum;
65
+ if (diff !== 0)
66
+ return diff;
67
+ continue;
68
+ }
69
+ if (leftNum !== null)
70
+ return -1;
71
+ if (rightNum !== null)
72
+ return 1;
73
+ const diff = left.localeCompare(right);
74
+ if (diff !== 0)
75
+ return diff;
76
+ }
77
+ return 0;
78
+ }
79
+ export function compareSemverish(a, b) {
80
+ const aa = parseVersionParts(a);
81
+ const bb = parseVersionParts(b);
82
+ for (let i = 0; i < Math.max(aa.length, bb.length); i++) {
83
+ const diff = (aa[i] ?? 0) - (bb[i] ?? 0);
84
+ if (diff !== 0)
85
+ return diff;
86
+ }
87
+ return comparePrerelease(a, b);
88
+ }
89
+ async function fetchLatestVersion(registryUrl, fetchImpl) {
90
+ const controller = new AbortController();
91
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
92
+ try {
93
+ const res = await fetchImpl(`${registryUrl.replace(/\/$/, '')}/@soku%2fcli/latest`, {
94
+ signal: controller.signal,
95
+ headers: { Accept: 'application/json' },
96
+ });
97
+ if (res.status === 404)
98
+ return null;
99
+ if (!res.ok) {
100
+ throw new Error(`npm registry returned HTTP ${res.status}`);
101
+ }
102
+ const data = (await res.json());
103
+ if (typeof data.version !== 'string' || data.version.length === 0) {
104
+ throw new Error('npm registry response did not include a version');
105
+ }
106
+ return data.version;
107
+ }
108
+ finally {
109
+ clearTimeout(timeout);
110
+ }
111
+ }
112
+ export async function checkForUpdate(opts = {}) {
113
+ const currentVersion = opts.currentVersion ?? CLI_VERSION;
114
+ const registryUrl = (opts.registryUrl ?? DEFAULT_REGISTRY_URL).replace(/\/$/, '');
115
+ const now = opts.now ?? new Date();
116
+ if (opts.useCache !== false) {
117
+ const cache = readCache(now);
118
+ if (cache) {
119
+ const latestVersion = cache.latest_version;
120
+ return {
121
+ packageName: CLI_PACKAGE_NAME,
122
+ currentVersion,
123
+ latestVersion,
124
+ published: !cache.package_unpublished,
125
+ updateAvailable: latestVersion !== null && compareSemverish(latestVersion, currentVersion) > 0,
126
+ installCommand: INSTALL_COMMAND,
127
+ checkedAt: cache.checked_at,
128
+ registryUrl,
129
+ };
130
+ }
131
+ }
132
+ const latestVersion = await fetchLatestVersion(registryUrl, opts.fetchImpl ?? fetch);
133
+ const checkedAt = now.toISOString();
134
+ writeCache({
135
+ checked_at: checkedAt,
136
+ latest_version: latestVersion,
137
+ ...(latestVersion === null ? { package_unpublished: true } : {}),
138
+ });
139
+ return {
140
+ packageName: CLI_PACKAGE_NAME,
141
+ currentVersion,
142
+ latestVersion,
143
+ published: latestVersion !== null,
144
+ updateAvailable: latestVersion !== null && compareSemverish(latestVersion, currentVersion) > 0,
145
+ installCommand: INSTALL_COMMAND,
146
+ checkedAt,
147
+ registryUrl,
148
+ };
149
+ }
150
+ function shouldSkipNotice() {
151
+ if (!process.stderr.isTTY)
152
+ return true;
153
+ if (process.env.CI)
154
+ return true;
155
+ if (process.env.SOKU_NO_UPDATE_CHECK === '1')
156
+ return true;
157
+ return false;
158
+ }
159
+ export async function maybeNotifyUpdate() {
160
+ if (shouldSkipNotice())
161
+ return;
162
+ try {
163
+ const result = await checkForUpdate();
164
+ if (!result.updateAvailable || !result.latestVersion)
165
+ return;
166
+ process.stderr.write(`${dim('Update available:')} ${CLI_PACKAGE_NAME} ${result.currentVersion} -> ${result.latestVersion}\n` +
167
+ `${dim('Run')} ${cyan(result.installCommand)}\n`);
168
+ }
169
+ catch {
170
+ // Update checks are advisory. Never fail the user command because npm is
171
+ // unreachable, private, or temporarily returning a malformed response.
172
+ }
173
+ }
174
+ export function registerUpdateCheckCommand(program) {
175
+ program
176
+ .command('update-check')
177
+ .description('Check whether a newer Soku CLI is available on npm')
178
+ .option('--registry-url <url>', 'Override the npm registry URL')
179
+ .action(async (opts) => {
180
+ try {
181
+ const result = await checkForUpdate({
182
+ registryUrl: opts.registryUrl,
183
+ useCache: false,
184
+ });
185
+ emitSuccess(result, (d) => {
186
+ if (!d.published) {
187
+ return `${CLI_PACKAGE_NAME} is not published on npm yet.\n${dim('Use a local linked build for development.')}`;
188
+ }
189
+ if (!d.latestVersion)
190
+ return `${CLI_PACKAGE_NAME}: no published version found.`;
191
+ if (!d.updateAvailable)
192
+ return `${CLI_PACKAGE_NAME} is up to date (${d.currentVersion}).`;
193
+ return [
194
+ `${CLI_PACKAGE_NAME} ${d.currentVersion} -> ${d.latestVersion}`,
195
+ `${dim('Run')} ${cyan(d.installCommand)}`,
196
+ ].join('\n');
197
+ });
198
+ }
199
+ catch (err) {
200
+ emitError('update_check_failed', err instanceof Error ? err.message : String(err), ExitCode.RUNTIME, 'Set SOKU_NO_UPDATE_CHECK=1 to disable background checks.');
201
+ }
202
+ });
203
+ }
204
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAIzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAClF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE5D,MAAM,oBAAoB,GAAG,4BAA4B,CAAA;AACzD,MAAM,eAAe,GAAG,YAAY,gBAAgB,EAAE,CAAA;AACtD,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AACxC,MAAM,kBAAkB,GAAG,IAAI,CAAA;AA2B/B,SAAS,SAAS;IAChB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,mBAAmB,CAAC,CAAA;AAC/C,CAAC;AAED,SAAS,SAAS,CAAC,GAAS;IAC1B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,EAAE,MAAM,CAAC,CAAgB,CAAA;QAC1E,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAA;QACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,OAAO,IAAI,CAAA;QAC5C,IAAI,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,GAAG,YAAY;YAAE,OAAO,IAAI,CAAA;QACzD,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAkB;IACpC,MAAM,IAAI,GAAG,SAAS,EAAE,CAAA;IACxB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QACtB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IACzB,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAS,EAAE,CAAS;IAC7C,MAAM,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;IAC7B,MAAM,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;IAC7B,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IAChD,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IAC7B,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,CAAA;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QAClB,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC,CAAA;QACjC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,CAAA;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAC3D,IAAI,OAAO,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,OAAO,GAAG,QAAQ,CAAA;YAC/B,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAA;YAC3B,SAAQ;QACV,CAAC;QACD,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,CAAC,CAAC,CAAA;QAC/B,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,CAAC,CAAA;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;QACtC,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;IAC7B,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAS,EAAE,CAAS;IACnD,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAA;IAC/B,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAA;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QACxC,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;IAC7B,CAAC;IACD,OAAO,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAChC,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,WAAmB,EAAE,SAAuB;IAC5E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,kBAAkB,CAAC,CAAA;IACxE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,EAAE;YAClF,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SACxC,CAAC,CAAA;QACF,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QACnC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;QAC7D,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0B,CAAA;QACxD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAqB,EAAE;IAC1D,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,WAAW,CAAA;IACzD,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,oBAAoB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAA;IAElC,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;QAC5B,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAA;YAC1C,OAAO;gBACL,WAAW,EAAE,gBAAgB;gBAC7B,cAAc;gBACd,aAAa;gBACb,SAAS,EAAE,CAAC,KAAK,CAAC,mBAAmB;gBACrC,eAAe,EAAE,aAAa,KAAK,IAAI,IAAI,gBAAgB,CAAC,aAAa,EAAE,cAAc,CAAC,GAAG,CAAC;gBAC9F,cAAc,EAAE,eAAe;gBAC/B,SAAS,EAAE,KAAK,CAAC,UAAU;gBAC3B,WAAW;aACZ,CAAA;QACH,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,CAAA;IACpF,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,EAAE,CAAA;IACnC,UAAU,CAAC;QACT,UAAU,EAAE,SAAS;QACrB,cAAc,EAAE,aAAa;QAC7B,GAAG,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC,CAAA;IAEF,OAAO;QACL,WAAW,EAAE,gBAAgB;QAC7B,cAAc;QACd,aAAa;QACb,SAAS,EAAE,aAAa,KAAK,IAAI;QACjC,eAAe,EAAE,aAAa,KAAK,IAAI,IAAI,gBAAgB,CAAC,aAAa,EAAE,cAAc,CAAC,GAAG,CAAC;QAC9F,cAAc,EAAE,eAAe;QAC/B,SAAS;QACT,WAAW;KACZ,CAAA;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACtC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG;QAAE,OAAO,IAAI,CAAA;IACzD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,gBAAgB,EAAE;QAAE,OAAM;IAC9B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAA;QACrC,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,aAAa;YAAE,OAAM;QAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,GAAG,CAAC,mBAAmB,CAAC,IAAI,gBAAgB,IAAI,MAAM,CAAC,cAAc,OAAO,MAAM,CAAC,aAAa,IAAI;YACrG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CACnD,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,uEAAuE;IACzE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAgB;IACzD,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,oDAAoD,CAAC;SACjE,MAAM,CAAC,sBAAsB,EAAE,+BAA+B,CAAC;SAC/D,MAAM,CAAC,KAAK,EAAE,IAA8B,EAAE,EAAE;QAC/C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;gBAClC,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAA;YACF,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;gBACxB,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;oBACjB,OAAO,GAAG,gBAAgB,kCAAkC,GAAG,CAAC,2CAA2C,CAAC,EAAE,CAAA;gBAChH,CAAC;gBACD,IAAI,CAAC,CAAC,CAAC,aAAa;oBAAE,OAAO,GAAG,gBAAgB,+BAA+B,CAAA;gBAC/E,IAAI,CAAC,CAAC,CAAC,eAAe;oBAAE,OAAO,GAAG,gBAAgB,mBAAmB,CAAC,CAAC,cAAc,IAAI,CAAA;gBACzF,OAAO;oBACL,GAAG,gBAAgB,IAAI,CAAC,CAAC,cAAc,OAAO,CAAC,CAAC,aAAa,EAAE;oBAC/D,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE;iBAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACd,CAAC,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,CACP,qBAAqB,EACrB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAChD,QAAQ,CAAC,OAAO,EAChB,0DAA0D,CAC3D,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const CLI_PACKAGE_NAME = "@soku-ai/cli";
2
+ export declare const CLI_VERSION = "0.1.0-alpha.0";
3
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,iBAAiB,CAAA;AAC9C,eAAO,MAAM,WAAW,kBAAkB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const CLI_PACKAGE_NAME = '@soku-ai/cli';
2
+ export const CLI_VERSION = '0.1.0-alpha.0';
3
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAA;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAA"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@soku-ai/cli",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Soku CLI — call Soku ads/GA4 data capabilities from any AI agent or shell.",
5
+ "license": "Proprietary",
6
+ "author": "Soku",
7
+ "homepage": "https://soku.ai/cli",
8
+ "bugs": {
9
+ "url": "https://github.com/About-Intelligence/nex-studio/issues"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/About-Intelligence/nex-studio.git",
14
+ "directory": "apps/cli"
15
+ },
16
+ "keywords": [
17
+ "soku",
18
+ "cli",
19
+ "ai-agent",
20
+ "marketing-analytics",
21
+ "google-ads",
22
+ "ga4"
23
+ ],
24
+ "type": "module",
25
+ "bin": {
26
+ "soku": "dist/index.js"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "skills"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public",
37
+ "registry": "https://registry.npmjs.org/"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc && mkdir -p dist/generated && cp src/generated/capabilities.json dist/generated/capabilities.json",
41
+ "typecheck": "tsc --noEmit",
42
+ "test": "tsc -p tsconfig.test.json && node --test \".test-build/**/*.test.js\"",
43
+ "gen:capabilities": "pnpm run build && node scripts/gen-capabilities.ts",
44
+ "clean": "rm -rf dist .test-build",
45
+ "prepublishOnly": "pnpm run clean && pnpm run build"
46
+ },
47
+ "dependencies": {
48
+ "commander": "^12.1.0",
49
+ "fflate": "^0.8.2",
50
+ "open": "^10.1.0",
51
+ "qrcode-terminal": "^0.12.0"
52
+ },
53
+ "optionalDependencies": {
54
+ "keytar": "^7.9.0"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^22.0.0",
58
+ "@types/qrcode-terminal": "^0.12.2",
59
+ "typescript": "^5.7.0"
60
+ }
61
+ }
@@ -0,0 +1,225 @@
1
+ ---
2
+ name: soku
3
+ description: >-
4
+ Use when calling Soku ads/GA4 marketing-data capabilities from the shell —
5
+ running `soku auth login`, switching org/brand with `soku org use` /
6
+ `soku brand use`, discovering capabilities, calling a data action, routing a
7
+ third-party API call (Ahrefs/DataForSEO/Firecrawl/Gemini/…) through
8
+ `soku egress`, handling 401/403 errors, or installing/updating the Soku CLI.
9
+ license: Proprietary
10
+ metadata:
11
+ author: nex-ad
12
+ version: "0.1"
13
+ ---
14
+
15
+ # Soku CLI
16
+
17
+ The `soku` CLI calls Soku's ads + GA4 data capabilities over HTTP. It is the
18
+ preferred way for an agent to use Soku data — it works in any shell, with no MCP
19
+ host required. Output is JSON on stdout; errors are a JSON envelope on stderr
20
+ with a semantic exit code.
21
+
22
+ ## Output & exit codes
23
+
24
+ Every command prints JSON. When piped (non-TTY) success is
25
+ `{"ok": true, "data": ...}`; errors are `{"ok": false, "error": {"type", "message", "hint"}}`.
26
+
27
+ | Exit | Meaning | What to do |
28
+ |------|---------|------------|
29
+ | 0 | Success | Parse `data`. |
30
+ | 1 | Usage / no workspace selected | Fix arguments, or run `soku org use` / `soku brand use`. |
31
+ | 2 | Auth — not signed in or token expired/revoked | Run `soku auth login` (or set `SOKU_TOKEN`). |
32
+ | 4 | Not found (unknown capability) | Re-check via `soku --help` / `soku <ns> --help`. |
33
+ | 5 | Runtime / network | Retry; if behind a proxy set `ALL_PROXY`. |
34
+
35
+ ## Authentication
36
+
37
+ `soku` authenticates once per machine with a long-lived, **org-agnostic** session
38
+ token. The org and brand are chosen at runtime (see Workspace), not at login.
39
+
40
+ ### Agent path (recommended): non-blocking split-flow
41
+
42
+ Do NOT block a turn waiting for a human at a browser. Start login with
43
+ `--no-wait`, surface the URL, end your turn, then resume:
44
+
45
+ ```bash
46
+ soku auth login --no-wait
47
+ ```
48
+
49
+ This returns immediately, e.g.:
50
+
51
+ ```json
52
+ {"ok":true,"data":{"user_code":"MWVP-ZTSZ","verification_uri":"https://studio.nex.ad/device","verification_uri_complete":"https://studio.nex.ad/device?user_code=MWVP-ZTSZ","device_code":"...","next":"soku auth login --device-code ..."}}
53
+ ```
54
+
55
+ Surface `verification_uri` and `user_code` to the user as your turn's final
56
+ message (treat the URL as an opaque string — do not edit, re-encode, or
57
+ re-assemble it). After the user says they approved, resume polling:
58
+
59
+ ```bash
60
+ soku auth login --device-code <device_code>
61
+ ```
62
+
63
+ ### Human path
64
+
65
+ `soku auth login` opens the browser and polls until the user approves. Add
66
+ `--qr` to render the verification URL as a QR code.
67
+
68
+ ### CI / non-interactive
69
+
70
+ Set `SOKU_TOKEN` to a pre-issued token; it overrides stored credentials and
71
+ skips all interactive auth. This is the right path for CI and headless agents —
72
+ it also avoids the OS keychain, which may be unavailable in containers.
73
+
74
+ ### Session state
75
+
76
+ - `soku auth status` — show the current identity.
77
+ - `soku auth logout` — delete the stored token.
78
+ - On exit code 2 with `expired` / `key_revoked`, the stored token is dropped
79
+ automatically; re-run `soku auth login`.
80
+
81
+ ## Workspace (org + brand)
82
+
83
+ The session token carries no org/brand. Pick a workspace before calling data
84
+ actions; the selection is saved to `~/.soku/config.json` and sent as
85
+ `X-Soku-Org` / `X-Soku-Brand` headers.
86
+
87
+ ```bash
88
+ soku org list # organizations you belong to
89
+ soku org use <slug|id> # set active org (id, slug, or name; clears a now-mismatched brand)
90
+ soku brand list # brands in the active org
91
+ soku brand use <slug|id> # id, slug, or name
92
+ ```
93
+
94
+ Env overrides for one-off invocations: `SOKU_ORG_ID`, `SOKU_BRAND_ID`.
95
+
96
+ ## Calling capabilities (discover with --help, then run)
97
+
98
+ Each data capability is a typed sub-command under its namespace. Discover and
99
+ inspect them with `--help` — never guess action names or flags.
100
+
101
+ ```bash
102
+ soku resources list # what's granted (e.g. data-infra)
103
+ soku --help # namespaces: ads, ga4, …
104
+ soku ads --help # actions in the ads namespace
105
+ soku ads query-single-dimension --help # flags, types, and usage for one action
106
+
107
+ soku ads list-ad-accounts --platform google
108
+ soku ads query-single-dimension --account-id 123 --dimension campaign \
109
+ --date-start 2026-05-01 --date-end 2026-05-18
110
+ ```
111
+
112
+ `<command> --help` is authoritative for valid flags, required vs optional, types,
113
+ and usage. Read it before invoking an unfamiliar action. Object/list flags take a
114
+ JSON string, e.g. `--filters '{"campaign_id":["123"]}'`.
115
+
116
+ ### Raw escape hatch
117
+
118
+ `soku call <namespace> <action>` runs any action by its raw (snake_case) name
119
+ with a JSON payload. Use it only when a typed sub-command isn't available — e.g.
120
+ a newer action than this CLI version ships:
121
+
122
+ ```bash
123
+ soku call ads list_ad_accounts -p platform=google
124
+ soku call ads query_single_dimension --payload '{"account_id":"123","dimension":"campaign"}'
125
+ ```
126
+
127
+ ## Write actions (human approval required)
128
+
129
+ Some actions mutate state (e.g. conversion-group writes) and are **review-gated**.
130
+ They are NOT in the typed command tree — call them with `soku call` and a
131
+ required `--summary` describing the change. The call does NOT execute; it returns
132
+ a pending review that a human approves.
133
+
134
+ ```bash
135
+ soku call ads create_conversion_group --summary "create group: qualified leads" -p name="Qualified leads"
136
+ # → {"ok":true,"data":{"status":"pending_review","pending_review_id":"<id>","summary":"..."}}
137
+
138
+ soku review list # see pending reviews
139
+ soku review show <id> # full payload + (after approval) result
140
+ soku review approve <id> # a human approves → the action executes now
141
+ soku review deny <id> --feedback "wrong account"
142
+ ```
143
+
144
+ - The write resource must be granted to the session (request it at login:
145
+ `soku auth login --resource data-infra,conversion-groups-write`). Without it,
146
+ `soku call` returns 403.
147
+ - Approval is **single-use**: one review = one execution. Approving an already
148
+ decided review is a no-op that returns the existing result.
149
+ - Do NOT loop `soku review approve` expecting retries; a failed approval is
150
+ terminal — create a fresh `soku call` to try again.
151
+ - As an agent: surface the `pending_review_id` + summary to the user and let
152
+ THEM run `soku review approve`. Do not approve on the user's behalf.
153
+
154
+ ## Third-party APIs (egress)
155
+
156
+ Skills that call third-party providers (Ahrefs, DataForSEO, Firecrawl, Gemini, …)
157
+ must route the call through `soku egress`. The credential is injected
158
+ server-side, so **no third-party API key lives on this machine**.
159
+
160
+ Prefix the skill's `curl` with `soku egress --`:
161
+
162
+ ```bash
163
+ soku egress -- curl -H "Authorization: Bearer $AHREFS_API_KEY" "https://api.ahrefs.com/v3/..."
164
+ ```
165
+
166
+ `$AHREFS_API_KEY` is not set here, and that is expected — `soku egress` strips the
167
+ empty auth header, Soku injects the real key, and the upstream response is
168
+ returned verbatim on stdout.
169
+
170
+ - Do NOT pre-flight check whether an API key env var is set, and do NOT abort a
171
+ skill because a key looks missing (no `[ -z "$X_API_KEY" ]` guards, no
172
+ `if not os.environ.get(...)` early-exits). Assume the credential is available;
173
+ just make the call through `soku egress`.
174
+ - A skill's own `SKILL.md` shows the raw `curl -H "Authorization: Bearer $X"`
175
+ form for reference. Ignore whether the key is set — prefix the whole command
176
+ with `soku egress --`.
177
+ - `soku egress providers` lists the covered hosts. For a host NOT listed, the
178
+ proxy does not inject a credential — follow that skill's own auth instead.
179
+
180
+ ## Installing / updating the skill
181
+
182
+ ```bash
183
+ soku update-check # check whether the CLI itself needs updating
184
+ soku skill install # this meta-skill into .claude / .codex / .cursor (project)
185
+ soku skill install --global # into ~/.claude, ~/.codex, ~/.cursor
186
+ soku skill install --agent claude --global
187
+ ```
188
+
189
+ If `soku update-check` reports an available CLI update, ask the user before
190
+ running:
191
+
192
+ ```bash
193
+ npm i -g @soku-ai/cli
194
+ ```
195
+
196
+ ## Installing business skills (account audits, Google Ads, reports, …)
197
+
198
+ Beyond this meta-skill, Soku publishes a catalog of domain skills (e.g.
199
+ `account-audit`, `google-ads`, `ads-report`) that already know which `soku call`
200
+ actions and `soku egress` providers to use — install one and your agent gains
201
+ that playbook.
202
+
203
+ ```bash
204
+ soku skill list # browse the catalog
205
+ soku skill install account-audit # install one (into soku-account-audit/)
206
+ soku skill install ads-report google-ads
207
+ soku skill install --all # install everything
208
+ soku skill installed # what's installed locally
209
+ soku skill remove account-audit
210
+ ```
211
+
212
+ Each installed skill carries a "Running this skill with the Soku CLI" section
213
+ (its data actions mapped to `soku call`, its third-party APIs to `soku egress`),
214
+ so it runs through this same CLI — no in-sandbox tools, no local API keys.
215
+
216
+ ## Security rules
217
+
218
+ - Never print the access token (it grants account access). Prefer `SOKU_TOKEN`
219
+ for CI rather than echoing it.
220
+ - Reads (`data-infra`) run directly. Writes are review-gated: `soku call`
221
+ creates a pending review and only `soku review approve` (a human action)
222
+ executes it. Don't approve on the user's behalf, and don't assume a
223
+ `--yes`-style bypass exists — there isn't one.
224
+ - Pass user-provided values as separate argv elements (the `-p key=value` form),
225
+ never by string-concatenating them into a shell command.
@@ -0,0 +1,71 @@
1
+ # Capability discovery flow
2
+
3
+ A worked example of the discover → inspect → run loop the agent should follow.
4
+ Each data capability is a typed sub-command under its namespace; `--help` is the
5
+ discovery and inspection surface.
6
+
7
+ ## 1. Confirm what's granted
8
+
9
+ ```bash
10
+ soku resources list
11
+ ```
12
+
13
+ ```json
14
+ {"ok":true,"data":{"resources":[{"id":"data-infra","label":"Data Infra","description":"Read-only Soku synchronized data actions for ads and GA4.","enabled":true}],"count":1}}
15
+ ```
16
+
17
+ ## 2. Discover namespaces and actions with --help
18
+
19
+ ```bash
20
+ soku --help # top level: namespaces (ads, ga4, …) plus auth/org/brand
21
+ soku ads --help # actions in the ads namespace
22
+ soku ga4 --help # actions in the ga4 namespace
23
+ ```
24
+
25
+ Common ads actions:
26
+
27
+ - `soku ads list-ad-accounts` — discover account_id values (run first when you have none)
28
+ - `soku ads list-dimensions` — discover queryable dimensions/metrics/filters
29
+ - `soku ads query-single-dimension`, `soku ads query-multi-dimension` — metric queries
30
+ - `soku ads gaql-search` — raw Google Ads GAQL
31
+ - `soku ga4 list-properties`, `soku ga4 get-property-overview`, `soku ga4 list-top-pages`, …
32
+
33
+ ## 3. Inspect a command's flags before running
34
+
35
+ ```bash
36
+ soku ads query-single-dimension --help
37
+ ```
38
+
39
+ The help is authoritative for flag names, required vs optional, types, and the
40
+ appended usage notes. Never guess flags — read `--help` first. Object/list flags
41
+ take a JSON string (e.g. `--filters '{"campaign_id":["123"]}'`).
42
+
43
+ ## 4. Run
44
+
45
+ ```bash
46
+ soku ads list-ad-accounts --platform google
47
+ soku ads query-single-dimension \
48
+ --account-id 1234567890 \
49
+ --dimension campaign \
50
+ --date-start 2026-05-01 \
51
+ --date-end 2026-05-07
52
+ ```
53
+
54
+ ## Raw escape hatch
55
+
56
+ When no typed sub-command exists for an action (e.g. a newer action than this
57
+ CLI version ships), call it by its raw snake_case name:
58
+
59
+ ```bash
60
+ soku call ads query_single_dimension --payload '{"account_id":"1234567890","dimension":"campaign","date_start":"2026-05-01","date_end":"2026-05-07"}'
61
+ ```
62
+
63
+ ## Typical chaining
64
+
65
+ 1. `soku ads list-ad-accounts` → pick an `account_id`.
66
+ 2. `soku ads list-dimensions` → learn valid dimension/metric slugs for that account.
67
+ 3. `soku ads query-single-dimension` / `query-multi-dimension` with the chosen
68
+ `--account-id` + slugs.
69
+
70
+ Each command's `--help` lists related actions (`see_also`) so you can jump
71
+ between them without re-scanning everything.