callkaro-cli-unofficial 0.1.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 (42) hide show
  1. package/README.md +196 -0
  2. package/dist/commands/accounts.js +275 -0
  3. package/dist/commands/agentPhone.js +50 -0
  4. package/dist/commands/agentVersions.js +228 -0
  5. package/dist/commands/agents.js +455 -0
  6. package/dist/commands/analytics.js +77 -0
  7. package/dist/commands/analyzers.js +130 -0
  8. package/dist/commands/auditStrategies.js +178 -0
  9. package/dist/commands/batches.js +189 -0
  10. package/dist/commands/calls.js +193 -0
  11. package/dist/commands/chatAgents.js +251 -0
  12. package/dist/commands/jsonInput.js +56 -0
  13. package/dist/commands/kpi.js +681 -0
  14. package/dist/commands/models.js +99 -0
  15. package/dist/commands/numbers.js +154 -0
  16. package/dist/commands/ongoing.js +39 -0
  17. package/dist/commands/secrets.js +124 -0
  18. package/dist/commands/setJson.js +42 -0
  19. package/dist/commands/simulations.js +139 -0
  20. package/dist/commands/skills.js +318 -0
  21. package/dist/commands/transcribers.js +95 -0
  22. package/dist/commands/update.js +86 -0
  23. package/dist/commands/voices.js +211 -0
  24. package/dist/data/catalog.json +1978 -0
  25. package/dist/endpoints.json +8 -0
  26. package/dist/index.js +684 -0
  27. package/dist/lib/agentImport.js +60 -0
  28. package/dist/lib/agentUpdate.js +262 -0
  29. package/dist/lib/api.js +287 -0
  30. package/dist/lib/browserAuth.js +93 -0
  31. package/dist/lib/catalog.js +136 -0
  32. package/dist/lib/config.js +354 -0
  33. package/dist/lib/dashboardApi.js +197 -0
  34. package/dist/lib/dashboardAuth.js +339 -0
  35. package/dist/lib/dbFields.js +30 -0
  36. package/dist/lib/logQuery.js +140 -0
  37. package/dist/lib/looseJson.js +198 -0
  38. package/dist/lib/session.js +17 -0
  39. package/dist/lib/types.js +15 -0
  40. package/dist/lib/ui.js +91 -0
  41. package/dist/lib/versions.js +19 -0
  42. package/package.json +52 -0
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchSkills = fetchSkills;
4
+ exports.readManifest = readManifest;
5
+ exports.syncSkills = syncSkills;
6
+ exports.skillsInstallCommand = skillsInstallCommand;
7
+ exports.skillsUpdateCommand = skillsUpdateCommand;
8
+ exports.skillsDirCommand = skillsDirCommand;
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ const os_1 = require("os");
12
+ const child_process_1 = require("child_process");
13
+ const ui_1 = require("../lib/ui");
14
+ const config_1 = require("../lib/config");
15
+ /**
16
+ * Skills live in their own public repo (Mail-Daddy-AI/callkaro-skills), NOT in
17
+ * this package — so a skills update never requires a CLI release. Install and
18
+ * update both mean: download the repo tarball, extract `skills/callkaro`, copy
19
+ * it into place.
20
+ */
21
+ const CODEX_MARK_START = '<!-- callkaro-skills:start -->';
22
+ const CODEX_MARK_END = '<!-- callkaro-skills:end -->';
23
+ const PROVIDERS = {
24
+ copilot: { label: 'GitHub Copilot', global: ['.copilot'], project: ['.github'] },
25
+ gemini: { label: 'Gemini CLI', global: ['.gemini'], project: ['.gemini'] },
26
+ cursor: { label: 'Cursor', global: ['.cursor'], project: ['.cursor'] },
27
+ windsurf: { label: 'Windsurf', global: ['.codeium', 'windsurf'], project: ['.windsurf'] },
28
+ roo: { label: 'Roo Code', global: ['.roo'], project: ['.roo'] },
29
+ opencode: { label: 'OpenCode', global: ['.config', 'opencode'], project: ['.opencode'] },
30
+ cline: { label: 'Cline', global: ['.cline'], project: ['.cline'] },
31
+ claude: { label: 'Claude Code', global: ['.claude'], project: ['.claude'] },
32
+ codex: { label: 'OpenAI Codex', global: ['.codex'], project: ['.codex'] },
33
+ };
34
+ const providerNames = Object.keys(PROVIDERS);
35
+ /**
36
+ * Where a provider's skills live, e.g. ~/.claude/skills/ for Claude Code at
37
+ * user scope, or <cwd>/.claude/skills/ with --project. The skills root, not a
38
+ * single skill — each skill is a subdirectory beneath it.
39
+ */
40
+ function providerTarget(provider, project) {
41
+ const root = project ? process.cwd() : (0, os_1.homedir)();
42
+ const segments = project ? PROVIDERS[provider].project : PROVIDERS[provider].global;
43
+ return (0, path_1.join)(root, ...segments, 'skills');
44
+ }
45
+ function selectedProviders(opts) {
46
+ if (opts.all)
47
+ return providerNames;
48
+ const selected = providerNames.filter((p) => opts[p]);
49
+ return selected.length > 0 ? selected : ['claude'];
50
+ }
51
+ function hasProviderSelection(opts) {
52
+ return Boolean(opts.all) || providerNames.some((p) => opts[p]);
53
+ }
54
+ /**
55
+ * Fetch the skills repo and return the local path to its skills root.
56
+ * Uses the GitHub codeload tarball + system `tar` (present on macOS, Linux and
57
+ * Windows 10+), so no git and no npm dependency is required.
58
+ *
59
+ * Returns every directory under `skills/`, not just `skills/callkaro`. The
60
+ * upstream pack is a single `callkaro` skill; this fork's pack is a set of
61
+ * `callkaro-*` skills. Installing the whole directory works for both layouts
62
+ * and keeps a new skill flowing through without a CLI change.
63
+ */
64
+ async function fetchSkills(official) {
65
+ const repo = (0, config_1.skillsRepoFor)(official);
66
+ const branch = (0, config_1.skillsBranch)();
67
+ const url = `https://codeload.github.com/${repo}/tar.gz/refs/heads/${branch}`;
68
+ const work = (0, path_1.join)((0, os_1.tmpdir)(), `cku-skills-${Date.now()}`);
69
+ const cleanup = () => {
70
+ try {
71
+ (0, fs_1.rmSync)(work, { recursive: true, force: true });
72
+ }
73
+ catch { /* best effort */ }
74
+ };
75
+ (0, fs_1.mkdirSync)(work, { recursive: true });
76
+ (0, ui_1.info)(`Fetching skills from ${repo}@${branch}…`);
77
+ let res;
78
+ try {
79
+ res = await fetch(url);
80
+ }
81
+ catch (e) {
82
+ cleanup();
83
+ throw new Error(`Could not reach GitHub (${e.message}). Check your connection and retry.`);
84
+ }
85
+ if (!res.ok) {
86
+ cleanup();
87
+ throw new Error(`Download failed (${res.status}) from ${url}`);
88
+ }
89
+ const tgz = (0, path_1.join)(work, 'skills.tar.gz');
90
+ (0, fs_1.writeFileSync)(tgz, Buffer.from(await res.arrayBuffer()));
91
+ try {
92
+ // Run tar with `work` as the working directory and pass only *relative*
93
+ // names. An absolute path is not an option on Windows: GNU tar reads
94
+ // "C:/Users/..." as a <host>:<path> remote spec and tries to connect to a
95
+ // machine named "C" ("Cannot connect to C: resolve failed"). Backslashes
96
+ // fail differently — tar treats them as escapes. Relative names sidestep
97
+ // both, and are exactly what upstream does not do, which is why
98
+ // `ck skills install` is broken on Windows.
99
+ (0, child_process_1.execFileSync)('tar', ['-xzf', 'skills.tar.gz', '--strip-components=1'], {
100
+ cwd: work,
101
+ stdio: 'ignore',
102
+ });
103
+ }
104
+ catch {
105
+ cleanup();
106
+ throw new Error('Could not extract the download — is `tar` available on your PATH?');
107
+ }
108
+ const skillsRoot = (0, path_1.join)(work, 'skills');
109
+ if (!(0, fs_1.existsSync)(skillsRoot)) {
110
+ cleanup();
111
+ throw new Error(`The repo ${repo} has no skills/ directory — check the branch (${branch}).`);
112
+ }
113
+ // A skill is a directory containing SKILL.md; anything else is not one.
114
+ const names = (0, fs_1.readdirSync)(skillsRoot, { withFileTypes: true })
115
+ .filter((e) => e.isDirectory() && (0, fs_1.existsSync)((0, path_1.join)(skillsRoot, e.name, 'SKILL.md')))
116
+ .map((e) => e.name);
117
+ if (!names.length) {
118
+ cleanup();
119
+ throw new Error(`No skills found in ${repo}@${branch} — expected directories under skills/ each containing SKILL.md.`);
120
+ }
121
+ return { dir: skillsRoot, names, cleanup };
122
+ }
123
+ /** Copy the pack into a target dir, replacing whatever is there. */
124
+ function place(src, dest) {
125
+ try {
126
+ (0, fs_1.rmSync)(dest, { recursive: true, force: true }); // drop files deleted upstream
127
+ }
128
+ catch (e) {
129
+ // Almost always: a previous `sudo cku ...` left root-owned files behind.
130
+ throw new Error(`Cannot replace ${dest} (${e.code || e.message}).\n` +
131
+ `It likely contains files owned by another user — created by running the CLI with sudo.\n` +
132
+ `Fix it with:\n sudo rm -rf ${dest}\nthen re-run this command WITHOUT sudo.`);
133
+ }
134
+ (0, fs_1.mkdirSync)(dest, { recursive: true });
135
+ (0, fs_1.cpSync)(src, dest, { recursive: true });
136
+ restoreOwnershipIfSudo(dest);
137
+ }
138
+ /**
139
+ * When invoked through sudo, files land owned by root inside the user's home —
140
+ * which then blocks every later non-sudo `skills update`. Hand them back to the
141
+ * invoking user so the next run works normally.
142
+ */
143
+ function restoreOwnershipIfSudo(dest) {
144
+ if (process.platform === 'win32')
145
+ return;
146
+ const uid = process.env.SUDO_UID;
147
+ const gid = process.env.SUDO_GID;
148
+ if (!uid || typeof process.getuid !== 'function' || process.getuid() !== 0)
149
+ return;
150
+ try {
151
+ (0, child_process_1.execFileSync)('chown', ['-R', `${uid}:${gid || uid}`, dest], { stdio: 'ignore' });
152
+ }
153
+ catch {
154
+ (0, ui_1.info)(`Note: could not hand ${dest} back to your user — if a later update fails, run: sudo chown -R $USER ${dest}`);
155
+ }
156
+ }
157
+ /** Codex has no skills system — wire a pointer block into ~/.codex/AGENTS.md. */
158
+ function wireCodexPointer() {
159
+ const codexHome = (0, path_1.join)((0, os_1.homedir)(), '.codex');
160
+ const block = `${CODEX_MARK_START}
161
+ ## CallKaro voice agents
162
+ For ANY task involving CallKaro (voice agents, calls, batch campaigns,
163
+ simulations, phone numbers, analytics): FIRST read
164
+ ~/.codex/skills/callkaro/SKILL.md and follow the files it routes to
165
+ (INSTRUCTIONS.md for how to operate; authoring-pipeline/ when building agents).
166
+ All operations run through the \`cku\` CLI (this fork) — it must be logged in (\`cku login\`).
167
+ If you have the official CLI instead, substitute \`ck\` for \`cku\` throughout.
168
+ Prefer \`--json\` output and never invent ids — list first.
169
+ ${CODEX_MARK_END}`;
170
+ const agentsMd = (0, path_1.join)(codexHome, 'AGENTS.md');
171
+ let content = (0, fs_1.existsSync)(agentsMd) ? (0, fs_1.readFileSync)(agentsMd, 'utf8') : '';
172
+ if (content.includes(CODEX_MARK_START)) {
173
+ content = content.replace(new RegExp(`${CODEX_MARK_START}[\\s\\S]*?${CODEX_MARK_END}`), block);
174
+ }
175
+ else {
176
+ content = content ? `${content.replace(/\n*$/, '\n\n')}${block}\n` : `${block}\n`;
177
+ }
178
+ (0, fs_1.mkdirSync)(codexHome, { recursive: true });
179
+ (0, fs_1.writeFileSync)(agentsMd, content);
180
+ return agentsMd;
181
+ }
182
+ /**
183
+ * Install and update are the same operation: pull the latest pack and place it.
184
+ * Each skill goes into its own subdirectory under the provider's skills root,
185
+ * so adding a skill to the repo flows through with no CLI change.
186
+ *
187
+ * `pack` lets a caller that already fetched (bare `update`) avoid a second download.
188
+ */
189
+ async function installOrUpdate(opts, verb, pack) {
190
+ const { dir, names, cleanup } = pack || (await fetchSkills(Boolean(opts.official)));
191
+ const repo = (0, config_1.skillsRepoFor)(Boolean(opts.official));
192
+ try {
193
+ const providers = selectedProviders(opts);
194
+ for (const provider of providers) {
195
+ const root = providerTarget(provider, Boolean(opts.project));
196
+ syncSkills(root, dir, names, repo);
197
+ if (provider === 'codex' && !opts.project) {
198
+ const agentsMd = wireCodexPointer();
199
+ (0, ui_1.success)(`${verb} for ${PROVIDERS[provider].label}:\n skills: ${root}\n wired into: ${agentsMd}`);
200
+ }
201
+ else {
202
+ (0, ui_1.success)(`${verb} for ${PROVIDERS[provider].label}:\n ${root}\n ${names.length} skill(s): ${names.join(', ')}`);
203
+ }
204
+ }
205
+ (0, ui_1.info)(opts.project
206
+ ? 'Scope: this project. Commit the skill folder(s) to share them with your team.'
207
+ : 'Scope: your user account — available across projects.');
208
+ const which = opts.official ? `official (${config_1.OFFICIAL_SKILLS_REPO})` : `fork (${(0, config_1.skillsRepo)()})`;
209
+ (0, ui_1.info)(`\nPack: ${which}`);
210
+ (0, ui_1.info)('Open a new agent session and ask it anything about CallKaro.');
211
+ (0, ui_1.info)('Requires the `cku` CLI to be logged in (`cku login`) — the skill pack documents that CLI.');
212
+ }
213
+ finally {
214
+ cleanup();
215
+ }
216
+ }
217
+ /**
218
+ * Which skills `cku` itself put in a skills root, per source repo. Lives beside
219
+ * them as `.cku-skills.json`.
220
+ *
221
+ * Pruning and bare `update` both go by this record, never by the `callkaro*`
222
+ * name prefix. The official `ck` installs its own `callkaro` skill into the same
223
+ * roots, and a prefix match would delete it (or update a root `cku` never
224
+ * installed into). A skill not listed here is not ours to touch.
225
+ */
226
+ const MANIFEST = '.cku-skills.json';
227
+ function readManifest(root) {
228
+ try {
229
+ const m = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(root, MANIFEST), 'utf8'));
230
+ return m && typeof m === 'object' && !Array.isArray(m) ? m : {};
231
+ }
232
+ catch {
233
+ return {};
234
+ }
235
+ }
236
+ /**
237
+ * Place a pack's skills into `root`, remove skills this repo installed earlier
238
+ * that the pack no longer has, and record what is now installed.
239
+ *
240
+ * Keyed by repo, so updating the fork pack never prunes skills placed from the
241
+ * upstream pack beside it, and vice versa.
242
+ */
243
+ function syncSkills(root, srcDir, names, repo) {
244
+ (0, fs_1.mkdirSync)(root, { recursive: true });
245
+ const manifest = readManifest(root);
246
+ for (const name of names)
247
+ place((0, path_1.join)(srcDir, name), (0, path_1.join)(root, name));
248
+ for (const name of manifest[repo] || []) {
249
+ if (names.includes(name))
250
+ continue;
251
+ try {
252
+ (0, fs_1.rmSync)((0, path_1.join)(root, name), { recursive: true, force: true });
253
+ (0, ui_1.info)(` removed stale skill: ${name}`);
254
+ }
255
+ catch {
256
+ /* leave it; the next update can retry */
257
+ }
258
+ }
259
+ manifest[repo] = [...names];
260
+ const path = (0, path_1.join)(root, MANIFEST);
261
+ (0, fs_1.writeFileSync)(path, JSON.stringify(manifest, null, 2) + '\n');
262
+ restoreOwnershipIfSudo(path);
263
+ }
264
+ async function skillsInstallCommand(opts) {
265
+ try {
266
+ await installOrUpdate(opts, 'Installed');
267
+ }
268
+ catch (err) {
269
+ (0, ui_1.handleError)(err);
270
+ }
271
+ }
272
+ async function skillsUpdateCommand(opts) {
273
+ try {
274
+ // With no flags, refresh every location that already has this pack, so a
275
+ // bare `cku skills update` does the obvious thing for every provider.
276
+ if (!opts.project && !hasProviderSelection(opts)) {
277
+ const pack = await fetchSkills(Boolean(opts.official));
278
+ const repo = (0, config_1.skillsRepoFor)(Boolean(opts.official));
279
+ // "Has this pack" = cku recorded installing it there, or (for installs made
280
+ // before the record existed) one of the pack's own skill names is present.
281
+ // Not any `callkaro*` directory: ~/.claude/skills/callkaro is usually the
282
+ // official `ck` skill, and updating that root would install this pack beside it.
283
+ const holdsPack = (root) => Boolean(readManifest(root)[repo]) ||
284
+ pack.names.some((n) => (0, fs_1.existsSync)((0, path_1.join)(root, n, 'SKILL.md')));
285
+ const targets = providerNames
286
+ .flatMap((provider) => [
287
+ { opts: { ...opts, [provider]: true }, path: providerTarget(provider, false) },
288
+ { opts: { ...opts, [provider]: true, project: true }, path: providerTarget(provider, true) },
289
+ ])
290
+ .filter((target) => holdsPack(target.path));
291
+ if (targets.length === 0) {
292
+ pack.cleanup();
293
+ (0, ui_1.fail)('The skill pack is not installed yet — run `cku skills install` first.');
294
+ process.exitCode = 1;
295
+ return;
296
+ }
297
+ // One download serves every target; cleanup runs after the last.
298
+ const shared = { ...pack, cleanup: () => { } };
299
+ try {
300
+ for (const t of targets)
301
+ await installOrUpdate(t.opts, 'Updated', shared);
302
+ }
303
+ finally {
304
+ pack.cleanup();
305
+ }
306
+ return;
307
+ }
308
+ await installOrUpdate(opts, 'Updated');
309
+ }
310
+ catch (err) {
311
+ (0, ui_1.handleError)(err);
312
+ }
313
+ }
314
+ function skillsDirCommand(opts) {
315
+ for (const provider of selectedProviders(opts)) {
316
+ console.log(providerTarget(provider, Boolean(opts.project)));
317
+ }
318
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transcribersCommand = transcribersCommand;
4
+ const ui_1 = require("../lib/ui");
5
+ const dashboardAuth_1 = require("../lib/dashboardAuth");
6
+ const catalog_1 = require("../lib/catalog");
7
+ function rowsFor(p) {
8
+ if (!p.models.length) {
9
+ return [{
10
+ provider: p.name,
11
+ model: '(none)',
12
+ languageKind: p.languageKind || '—',
13
+ languages: p.languages.join(' '),
14
+ }];
15
+ }
16
+ return p.models.map((m) => ({
17
+ provider: p.name,
18
+ model: m.name,
19
+ languageKind: p.languageKind || '—',
20
+ languages: m.languages.join(' '),
21
+ }));
22
+ }
23
+ /** `--provider X --fields` — the exact keys a provider's `transcriber` object takes. */
24
+ function showFields(p, json) {
25
+ if (json) {
26
+ return void console.log(JSON.stringify({ provider: p.name, fields: p.fields, models: p.models, languageKind: p.languageKind, languages: p.languages, gate: p.gate, notes: p.notes }, null, 2));
27
+ }
28
+ (0, ui_1.keyValue)({
29
+ provider: p.name,
30
+ 'transcriber keys': p.fields.join(', '),
31
+ models: p.models.length ? p.models.map((m) => m.name).join(', ') : '(no transcriber_model key)',
32
+ transcriber_language: p.languageKind === 'array' ? 'array of locales' : 'single string',
33
+ languages: p.languages.join(' '),
34
+ access: p.gate === 'admin' ? 'master admin only' : 'all accounts',
35
+ });
36
+ if (p.notes)
37
+ (0, ui_1.info)(`\n${p.notes}`);
38
+ (0, ui_1.info)("\nCopy transcriber_language verbatim — never reformat [\"en-IN\"] to \"en\", and never wrap a string provider's value in an array.");
39
+ }
40
+ function unknownProvider(name) {
41
+ (0, ui_1.info)(`Unknown transcriber provider "${name}". Known: ${catalog_1.TRANSCRIBER_PROVIDERS.map((p) => p.name).join(', ')}.`);
42
+ process.exitCode = 1;
43
+ }
44
+ async function transcribersCommand(opts) {
45
+ try {
46
+ // Prefer the server's own model list; the built-in copy has drifted from it
47
+ // (Groq is listed here but not served, and Smallest's model id has changed).
48
+ await (0, dashboardAuth_1.refreshModelCatalog)();
49
+ const providers = (0, catalog_1.visibleTranscriberProviders)({ all: opts.all });
50
+ const stale = providers.filter((p) => p.servedBy === false);
51
+ if (opts.fields) {
52
+ if (!opts.provider) {
53
+ (0, ui_1.info)('--fields needs a provider, e.g. `cku transcribers --provider sarvam --fields`.');
54
+ process.exitCode = 1;
55
+ return;
56
+ }
57
+ const p = (0, catalog_1.findTranscriberProvider)(opts.provider);
58
+ if (!p)
59
+ return unknownProvider(opts.provider);
60
+ return showFields(p, opts.json);
61
+ }
62
+ let scoped = providers;
63
+ if (opts.provider) {
64
+ const p = (0, catalog_1.findTranscriberProvider)(opts.provider);
65
+ if (!p)
66
+ return unknownProvider(opts.provider);
67
+ scoped = providers.filter((x) => x.name === p.name);
68
+ // A gated provider asked for by name should still show, not be silently empty.
69
+ if (!scoped.length)
70
+ scoped = [p];
71
+ }
72
+ let rows = scoped.flatMap(rowsFor);
73
+ if (opts.language) {
74
+ rows = rows.filter((r) => r.languages.split(' ').some((l) => (0, catalog_1.langMatches)(l, [opts.language])));
75
+ }
76
+ if (opts.json)
77
+ return void console.log(JSON.stringify(rows, null, 2));
78
+ if (!rows.length)
79
+ return void (0, ui_1.info)('No transcribers matched. Try fewer filters.');
80
+ (0, ui_1.table)(['PROVIDER', 'MODEL', 'LANGUAGE FIELD', 'LANGUAGES'], rows.map((r) => [r.provider, r.model, r.languageKind, r.languages]));
81
+ (0, ui_1.info)(`\n${rows.length} provider/model combination(s).`);
82
+ (0, ui_1.info)('Use `cku transcribers --provider <name> --fields` for the exact keys a provider takes.');
83
+ if (!opts.all && catalog_1.TRANSCRIBER_PROVIDERS.some((p) => p.gate === 'admin')) {
84
+ (0, ui_1.info)('Admin-gated providers are hidden — add --all to include them.');
85
+ }
86
+ if (stale.length) {
87
+ (0, ui_1.info)('');
88
+ (0, ui_1.info)(`Not currently served by the backend, kept from the built-in list: ${stale.map((p) => p.name).join(', ')}`);
89
+ (0, ui_1.info)(' Their models are stale. Re-run `npm run catalog:sync` to drop them.');
90
+ }
91
+ }
92
+ catch (err) {
93
+ (0, ui_1.handleError)(err);
94
+ }
95
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.updateCommand = updateCommand;
37
+ const child_process_1 = require("child_process");
38
+ const ui_1 = require("../lib/ui");
39
+ /**
40
+ * `cku update` — upgrade the CLI itself from npm, then refresh the skill pack
41
+ * (which lives in its own repo, so it may have moved on even if the CLI hasn't).
42
+ */
43
+ async function updateCommand(opts) {
44
+ try {
45
+ (0, ui_1.info)('Installing globally via npm …');
46
+ try {
47
+ let legacyInstalled = false;
48
+ try {
49
+ (0, child_process_1.execFileSync)('npm', ['list', '--global', '@callkaro/cli', '--depth=0'], { stdio: 'ignore' });
50
+ legacyInstalled = true;
51
+ }
52
+ catch {
53
+ /* legacy package is not installed */
54
+ }
55
+ if (legacyInstalled) {
56
+ (0, ui_1.info)('Removing legacy @callkaro/cli installation …');
57
+ (0, child_process_1.execFileSync)('npm', ['uninstall', '--global', '@callkaro/cli'], { stdio: 'ignore' });
58
+ }
59
+ (0, child_process_1.execFileSync)('npm', ['install', '--global', 'callkaro-cli-unofficial'], { stdio: 'ignore' });
60
+ }
61
+ catch {
62
+ (0, ui_1.fail)('npm could not write to the global folder (it needs elevated permissions).');
63
+ (0, ui_1.info)('Re-run as:\n sudo cku update');
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+ let version = '';
68
+ try {
69
+ version = (0, child_process_1.execFileSync)('cku', ['--version'], { encoding: 'utf8' }).trim();
70
+ }
71
+ catch {
72
+ /* not on PATH yet in this shell */
73
+ }
74
+ (0, ui_1.success)(`CLI updated${version ? ` to v${version}` : ''}.`);
75
+ if (opts.skipSkills) {
76
+ (0, ui_1.info)('Skipped the skill pack (--skip-skills). Refresh it with `cku skills update`.');
77
+ return;
78
+ }
79
+ (0, ui_1.info)('\nRefreshing the skill pack…');
80
+ const { skillsUpdateCommand } = await Promise.resolve().then(() => __importStar(require('./skills')));
81
+ await skillsUpdateCommand({});
82
+ }
83
+ catch (err) {
84
+ (0, ui_1.handleError)(err);
85
+ }
86
+ }