@aiorg/cli 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aiorg.dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # @aiorg/cli
2
+
3
+ Official CLI for downloading and managing [aiorg](https://aiorg.dev) kits - Claude Code starter kits for founders.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Global install
9
+ npm install -g @aiorg/cli
10
+
11
+ # Or use npx (no install needed)
12
+ npx @aiorg/cli <command>
13
+ ```
14
+
15
+ ## Commands
16
+
17
+ ### `aiorg login`
18
+
19
+ Save your license key for future use.
20
+
21
+ ```bash
22
+ aiorg login
23
+ # → Enter your license key: ak_live_xxxxx
24
+ # → ✓ Logged in as user@email.com
25
+ ```
26
+
27
+ ### `aiorg init <kit> [path]`
28
+
29
+ Download and extract a kit to a folder. Free kits work without login.
30
+
31
+ ```bash
32
+ # Free kit - no login needed
33
+ aiorg init claude-starter ~/Projects/my-project
34
+
35
+ # Paid kit - requires login
36
+ aiorg init marketing-os ~/Projects/my-marketing
37
+ ```
38
+
39
+ Options:
40
+ - `--force` - Overwrite existing folder
41
+
42
+ ### `aiorg upgrade`
43
+
44
+ Upgrade a kit in the current directory to the latest version.
45
+
46
+ ```bash
47
+ cd ~/Projects/my-marketing
48
+ aiorg upgrade
49
+ # → Update available: v1.5.0 → v1.6.0
50
+ # → ✓ Applied 15 files (your data preserved)
51
+ ```
52
+
53
+ Options:
54
+ - `--yes, -y` - Skip confirmation prompts
55
+ - `--backup` - Always create git backup commit before upgrade
56
+
57
+ ### `aiorg version`
58
+
59
+ Show CLI and kit versions.
60
+
61
+ ```bash
62
+ aiorg version
63
+ # → CLI: v1.0.0
64
+ # → Marketing OS: v1.5.0 (latest: v1.6.0)
65
+ ```
66
+
67
+ ### `aiorg logout`
68
+
69
+ Remove saved credentials.
70
+
71
+ ```bash
72
+ aiorg logout
73
+ # → ✓ Logged out
74
+ ```
75
+
76
+ ## Environment Variables
77
+
78
+ - `AIORG_LICENSE_KEY` - Your license key (alternative to `aiorg login`)
79
+ - `AIORG_API_URL` - Custom API URL (default: https://aiorg.dev)
80
+
81
+ ## Config Storage
82
+
83
+ Configuration is stored in `~/.aiorg/config.json`:
84
+
85
+ ```json
86
+ {
87
+ "licenseKey": "ak_live_xxxxx",
88
+ "email": "user@email.com",
89
+ "kits": {
90
+ "marketing-os": {
91
+ "tier": "paid",
92
+ "purchasedAt": "2026-01-01"
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## How Upgrades Work
99
+
100
+ When you run `aiorg upgrade`, the CLI:
101
+
102
+ 1. Checks for new versions via the API
103
+ 2. Downloads the new version ZIP
104
+ 3. Applies updates based on `fileCategories` in the kit's `version.json`:
105
+ - `alwaysReplace`: Files that get overwritten (CLI code, commands)
106
+ - `neverTouch`: Files that are preserved (your config, data, content)
107
+ 4. Creates a git backup commit (optional)
108
+
109
+ Your customizations and data are preserved during upgrades.
110
+
111
+ ## Available Kits
112
+
113
+ | Kit | Type | Description |
114
+ |-----|------|-------------|
115
+ | `claude-starter` | Free | Best practices template for Claude Code |
116
+ | `marketing-os` | Paid | AI-powered marketing automation |
117
+ | `nextjs-supabase-saas` | Paid | Full-stack SaaS template |
118
+ | `landing-page` | Paid | High-converting landing page |
119
+
120
+ Visit [aiorg.dev](https://aiorg.dev) to purchase paid kits.
121
+
122
+ ## Requirements
123
+
124
+ - Node.js 18+
125
+ - npm, pnpm, or yarn
126
+
127
+ ## License
128
+
129
+ MIT
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,972 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import cac from "cac";
5
+
6
+ // src/commands/login.ts
7
+ import * as p from "@clack/prompts";
8
+ import pc2 from "picocolors";
9
+
10
+ // src/lib/api.ts
11
+ import { z } from "zod";
12
+ var API_BASE_URL = process.env.AIORG_API_URL?.trim() || "https://aiorg.dev";
13
+ var API_TIMEOUT_MS = 3e4;
14
+ async function fetchWithTimeout(url, options = {}, timeoutMs = API_TIMEOUT_MS) {
15
+ const controller = new AbortController();
16
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
17
+ try {
18
+ const response = await fetch(url, {
19
+ ...options,
20
+ signal: controller.signal
21
+ });
22
+ return response;
23
+ } finally {
24
+ clearTimeout(timeout);
25
+ }
26
+ }
27
+ var LatestVersionSchema = z.object({
28
+ version: z.string(),
29
+ releasedAt: z.string(),
30
+ packageName: z.string(),
31
+ packageDisplayName: z.string(),
32
+ changelog: z.record(z.string(), z.any()).optional(),
33
+ tier: z.enum(["free", "paid"]).optional(),
34
+ type: z.enum(["template", "companion", "inject"]).optional()
35
+ });
36
+ var DownloadResponseSchema = z.object({
37
+ downloadUrl: z.string(),
38
+ version: z.string(),
39
+ filename: z.string()
40
+ });
41
+ var VerifyLicenseResponseSchema = z.object({
42
+ valid: z.boolean(),
43
+ email: z.string().optional(),
44
+ kits: z.array(
45
+ z.object({
46
+ name: z.string(),
47
+ tier: z.enum(["free", "paid"]),
48
+ purchasedAt: z.string()
49
+ })
50
+ ).optional(),
51
+ error: z.string().optional()
52
+ });
53
+ var APIError = class extends Error {
54
+ constructor(message, statusCode) {
55
+ super(message);
56
+ this.statusCode = statusCode;
57
+ this.name = "APIError";
58
+ }
59
+ };
60
+ async function fetchLatestVersion(kitName) {
61
+ const url = `${API_BASE_URL}/api/kits/${kitName}/latest`;
62
+ try {
63
+ const response = await fetchWithTimeout(url);
64
+ if (!response.ok) {
65
+ if (response.status === 404) {
66
+ throw new APIError(`Kit not found: "${kitName}"`, 404);
67
+ }
68
+ throw new APIError(`Failed to fetch version info`, response.status);
69
+ }
70
+ const data = await response.json();
71
+ return LatestVersionSchema.parse(data);
72
+ } catch (error2) {
73
+ if (error2 instanceof APIError) throw error2;
74
+ if (error2 instanceof Error && error2.name === "AbortError") {
75
+ throw new APIError("Request timed out");
76
+ }
77
+ throw new APIError(
78
+ `Network error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
79
+ );
80
+ }
81
+ }
82
+ async function getDownloadUrl(kitName, licenseKey) {
83
+ const url = `${API_BASE_URL}/api/kits/${kitName}/download`;
84
+ const headers = {};
85
+ if (licenseKey) {
86
+ headers.Authorization = `Bearer ${licenseKey}`;
87
+ }
88
+ try {
89
+ const response = await fetchWithTimeout(url, { headers });
90
+ if (!response.ok) {
91
+ if (response.status === 401) {
92
+ throw new APIError("Invalid or expired license key", 401);
93
+ }
94
+ if (response.status === 403) {
95
+ throw new APIError(
96
+ "License key does not have access to this kit",
97
+ 403
98
+ );
99
+ }
100
+ if (response.status === 404) {
101
+ throw new APIError(`Kit not found: "${kitName}"`, 404);
102
+ }
103
+ throw new APIError(`Failed to get download URL`, response.status);
104
+ }
105
+ const data = await response.json();
106
+ return DownloadResponseSchema.parse(data);
107
+ } catch (error2) {
108
+ if (error2 instanceof APIError) throw error2;
109
+ if (error2 instanceof Error && error2.name === "AbortError") {
110
+ throw new APIError("Request timed out");
111
+ }
112
+ throw new APIError(
113
+ `Network error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
114
+ );
115
+ }
116
+ }
117
+ async function verifyLicense(licenseKey, kitName) {
118
+ const url = `${API_BASE_URL}/api/licenses/verify`;
119
+ try {
120
+ const response = await fetchWithTimeout(url, {
121
+ method: "POST",
122
+ headers: {
123
+ "Content-Type": "application/json"
124
+ },
125
+ body: JSON.stringify({
126
+ key: licenseKey,
127
+ kit: kitName
128
+ })
129
+ });
130
+ if (!response.ok) {
131
+ const data2 = await response.json().catch(() => ({}));
132
+ throw new APIError(
133
+ data2.error || "License verification failed",
134
+ response.status
135
+ );
136
+ }
137
+ const data = await response.json();
138
+ return VerifyLicenseResponseSchema.parse(data);
139
+ } catch (error2) {
140
+ if (error2 instanceof APIError) throw error2;
141
+ if (error2 instanceof Error && error2.name === "AbortError") {
142
+ throw new APIError("Request timed out");
143
+ }
144
+ throw new APIError(
145
+ `Network error: ${error2 instanceof Error ? error2.message : "Unknown error"}`
146
+ );
147
+ }
148
+ }
149
+ async function downloadFile(url) {
150
+ const DOWNLOAD_TIMEOUT_MS = 12e4;
151
+ try {
152
+ const response = await fetchWithTimeout(url, {}, DOWNLOAD_TIMEOUT_MS);
153
+ if (!response.ok) {
154
+ throw new APIError(`Download failed`, response.status);
155
+ }
156
+ return await response.arrayBuffer();
157
+ } catch (error2) {
158
+ if (error2 instanceof APIError) throw error2;
159
+ if (error2 instanceof Error && error2.name === "AbortError") {
160
+ throw new APIError("Download timed out");
161
+ }
162
+ throw new APIError(
163
+ `Download failed: ${error2 instanceof Error ? error2.message : "Unknown error"}`
164
+ );
165
+ }
166
+ }
167
+
168
+ // src/lib/auth.ts
169
+ import fs from "fs-extra";
170
+ import path from "path";
171
+ import os from "os";
172
+ import { z as z2 } from "zod";
173
+ var CONFIG_DIR = path.join(os.homedir(), ".aiorg");
174
+ var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
175
+ var KitLicenseSchema = z2.object({
176
+ tier: z2.enum(["free", "paid"]),
177
+ purchasedAt: z2.string()
178
+ });
179
+ var ConfigSchema = z2.object({
180
+ licenseKey: z2.string(),
181
+ email: z2.string().optional(),
182
+ kits: z2.record(z2.string(), KitLicenseSchema).optional()
183
+ });
184
+ async function ensureConfigDir() {
185
+ await fs.ensureDir(CONFIG_DIR);
186
+ }
187
+ async function isLoggedIn() {
188
+ try {
189
+ const config = await loadConfig();
190
+ return !!config?.licenseKey;
191
+ } catch {
192
+ return false;
193
+ }
194
+ }
195
+ async function loadConfig() {
196
+ try {
197
+ if (!await fs.pathExists(CONFIG_FILE)) {
198
+ return null;
199
+ }
200
+ const raw = await fs.readJson(CONFIG_FILE);
201
+ return ConfigSchema.parse(raw);
202
+ } catch {
203
+ return null;
204
+ }
205
+ }
206
+ async function saveConfig(config) {
207
+ await ensureConfigDir();
208
+ await fs.writeJson(CONFIG_FILE, config, { spaces: 2 });
209
+ }
210
+ async function getLicenseKey() {
211
+ const envKey = process.env.AIORG_LICENSE_KEY;
212
+ if (envKey) {
213
+ return envKey;
214
+ }
215
+ const config = await loadConfig();
216
+ return config?.licenseKey ?? null;
217
+ }
218
+ async function saveLicenseKey(licenseKey, email, kits) {
219
+ const existing = await loadConfig();
220
+ await saveConfig({
221
+ ...existing || {},
222
+ licenseKey,
223
+ email: email ?? existing?.email,
224
+ kits: kits ?? existing?.kits
225
+ });
226
+ }
227
+ async function clearConfig() {
228
+ try {
229
+ await fs.remove(CONFIG_FILE);
230
+ } catch {
231
+ }
232
+ }
233
+
234
+ // src/utils/logger.ts
235
+ import pc from "picocolors";
236
+ function success(message) {
237
+ console.log(pc.green("\u2713"), message);
238
+ }
239
+ function error(message) {
240
+ console.log(pc.red("\u2717"), message);
241
+ }
242
+ function warn(message) {
243
+ console.log(pc.yellow("!"), message);
244
+ }
245
+ function info(message) {
246
+ console.log(pc.blue("\u2139"), message);
247
+ }
248
+ function log(message) {
249
+ console.log(message);
250
+ }
251
+ function blank() {
252
+ console.log();
253
+ }
254
+ function header(title) {
255
+ console.log();
256
+ console.log(pc.bold(title));
257
+ console.log(pc.dim("\u2500".repeat(40)));
258
+ }
259
+ function keyValue(key, value) {
260
+ console.log(`${pc.dim(key + ":")} ${value}`);
261
+ }
262
+ function listItem(item, indent = 0) {
263
+ const prefix = " ".repeat(indent);
264
+ console.log(`${prefix}${pc.dim("\u2022")} ${item}`);
265
+ }
266
+
267
+ // src/commands/login.ts
268
+ async function login() {
269
+ p.intro(pc2.cyan("aiorg login"));
270
+ if (await isLoggedIn()) {
271
+ const config = await loadConfig();
272
+ const shouldContinue = await p.confirm({
273
+ message: `Already logged in${config?.email ? ` as ${pc2.cyan(config.email)}` : ""}. Replace license key?`,
274
+ initialValue: false
275
+ });
276
+ if (p.isCancel(shouldContinue) || !shouldContinue) {
277
+ p.outro("Login cancelled");
278
+ return;
279
+ }
280
+ }
281
+ const licenseKey = await p.text({
282
+ message: "Enter your license key",
283
+ placeholder: "ak_live_xxxxx",
284
+ validate: (value) => {
285
+ if (!value) return "License key is required";
286
+ if (!value.startsWith("ak_")) return 'License key should start with "ak_"';
287
+ return void 0;
288
+ }
289
+ });
290
+ if (p.isCancel(licenseKey)) {
291
+ p.cancel("Login cancelled");
292
+ process.exit(0);
293
+ }
294
+ const spinner4 = p.spinner();
295
+ spinner4.start("Verifying license...");
296
+ try {
297
+ const result = await verifyLicense(licenseKey);
298
+ if (!result.valid) {
299
+ spinner4.stop("License verification failed");
300
+ error(result.error || "Invalid license key");
301
+ process.exit(1);
302
+ }
303
+ const kitsRecord = {};
304
+ if (result.kits) {
305
+ for (const kit of result.kits) {
306
+ kitsRecord[kit.name] = {
307
+ tier: kit.tier,
308
+ purchasedAt: kit.purchasedAt
309
+ };
310
+ }
311
+ }
312
+ await saveLicenseKey(licenseKey, result.email, kitsRecord);
313
+ spinner4.stop("License verified");
314
+ blank();
315
+ success(`Logged in${result.email ? ` as ${pc2.cyan(result.email)}` : ""}`);
316
+ if (result.kits && result.kits.length > 0) {
317
+ blank();
318
+ log("Licensed kits:");
319
+ for (const kit of result.kits) {
320
+ listItem(`${kit.name} (${kit.tier})`);
321
+ }
322
+ }
323
+ p.outro("Ready to use aiorg kits!");
324
+ } catch (error2) {
325
+ spinner4.stop("License verification failed");
326
+ throw error2;
327
+ }
328
+ }
329
+
330
+ // src/commands/logout.ts
331
+ import * as p2 from "@clack/prompts";
332
+ import pc3 from "picocolors";
333
+ async function logout() {
334
+ p2.intro(pc3.cyan("aiorg logout"));
335
+ if (!await isLoggedIn()) {
336
+ info("Not currently logged in");
337
+ p2.outro("");
338
+ return;
339
+ }
340
+ const config = await loadConfig();
341
+ const email = config?.email;
342
+ const shouldLogout = await p2.confirm({
343
+ message: `Log out${email ? ` from ${pc3.cyan(email)}` : ""}?`,
344
+ initialValue: true
345
+ });
346
+ if (p2.isCancel(shouldLogout) || !shouldLogout) {
347
+ p2.cancel("Logout cancelled");
348
+ return;
349
+ }
350
+ await clearConfig();
351
+ success("Logged out");
352
+ p2.outro("");
353
+ }
354
+
355
+ // src/commands/init.ts
356
+ import * as p3 from "@clack/prompts";
357
+ import pc4 from "picocolors";
358
+ import path3 from "path";
359
+ import os3 from "os";
360
+
361
+ // src/lib/extract.ts
362
+ import extractZip from "extract-zip";
363
+ import fs2 from "fs-extra";
364
+ import path2 from "path";
365
+ import os2 from "os";
366
+ async function createTempDir(prefix = "aiorg-") {
367
+ const tempDir = path2.join(os2.tmpdir(), `${prefix}${Date.now()}`);
368
+ await fs2.ensureDir(tempDir);
369
+ return tempDir;
370
+ }
371
+ async function saveToFile(data, filePath) {
372
+ await fs2.ensureDir(path2.dirname(filePath));
373
+ await fs2.writeFile(filePath, Buffer.from(data));
374
+ }
375
+ async function extractZipToDir(zipPath, destPath) {
376
+ await fs2.ensureDir(destPath);
377
+ await extractZip(zipPath, { dir: destPath });
378
+ }
379
+ async function cleanupTempDir(tempDir) {
380
+ try {
381
+ await fs2.remove(tempDir);
382
+ } catch {
383
+ }
384
+ }
385
+ async function dirExistsAndNotEmpty(dirPath) {
386
+ try {
387
+ const exists = await fs2.pathExists(dirPath);
388
+ if (!exists) return false;
389
+ const files = await fs2.readdir(dirPath);
390
+ return files.length > 0;
391
+ } catch {
392
+ return false;
393
+ }
394
+ }
395
+ async function getFileSizeKB(filePath) {
396
+ const stats = await fs2.stat(filePath);
397
+ return Math.round(stats.size / 1024);
398
+ }
399
+
400
+ // src/commands/init.ts
401
+ async function init(kitName, targetPath, options) {
402
+ p3.intro(pc4.cyan(`aiorg init ${kitName}`));
403
+ const resolvedPath = targetPath ? path3.resolve(targetPath.replace(/^~/, os3.homedir())) : path3.resolve(process.cwd(), kitName);
404
+ if (!options.force && await dirExistsAndNotEmpty(resolvedPath)) {
405
+ error(`Folder already exists: ${pc4.yellow(resolvedPath)}`);
406
+ log(pc4.dim("Use --force to overwrite"));
407
+ process.exit(1);
408
+ }
409
+ const spinner4 = p3.spinner();
410
+ spinner4.start("Fetching version info...");
411
+ let versionInfo;
412
+ try {
413
+ versionInfo = await fetchLatestVersion(kitName);
414
+ spinner4.stop(`Found ${pc4.cyan(versionInfo.packageDisplayName)} v${versionInfo.version}`);
415
+ } catch (error2) {
416
+ spinner4.stop("Failed to fetch version info");
417
+ throw error2;
418
+ }
419
+ const isFreeKit = versionInfo.tier === "free";
420
+ let licenseKey = null;
421
+ if (!isFreeKit) {
422
+ if (!await isLoggedIn()) {
423
+ info("Not logged in. Please log in first.");
424
+ blank();
425
+ await login();
426
+ blank();
427
+ }
428
+ licenseKey = await getLicenseKey();
429
+ if (!licenseKey) {
430
+ error('No license key found. Run "aiorg login" first.');
431
+ process.exit(1);
432
+ }
433
+ }
434
+ if (isFreeKit) {
435
+ spinner4.start("Getting download URL...");
436
+ } else {
437
+ spinner4.start("Verifying license...");
438
+ }
439
+ let downloadInfo;
440
+ try {
441
+ downloadInfo = await getDownloadUrl(kitName, licenseKey);
442
+ spinner4.stop(isFreeKit ? "Ready to download" : "License verified");
443
+ } catch (error2) {
444
+ spinner4.stop(isFreeKit ? "Failed to get download URL" : "License verification failed");
445
+ throw error2;
446
+ }
447
+ spinner4.start(`Downloading ${kitName} v${versionInfo.version}...`);
448
+ let tempDir = null;
449
+ try {
450
+ tempDir = await createTempDir("aiorg-init-");
451
+ const zipPath = path3.join(tempDir, "kit.zip");
452
+ const zipData = await downloadFile(downloadInfo.downloadUrl);
453
+ await saveToFile(zipData, zipPath);
454
+ const sizeKB = await getFileSizeKB(zipPath);
455
+ spinner4.stop(`Downloaded ${kitName} v${versionInfo.version} (${sizeKB} KB)`);
456
+ spinner4.start(`Extracting to ${resolvedPath}...`);
457
+ await extractZipToDir(zipPath, resolvedPath);
458
+ spinner4.stop(`Extracted to ${pc4.yellow(resolvedPath)}`);
459
+ await cleanupTempDir(tempDir);
460
+ } catch (error2) {
461
+ if (tempDir) {
462
+ await cleanupTempDir(tempDir);
463
+ }
464
+ throw error2;
465
+ }
466
+ blank();
467
+ success(`${versionInfo.packageDisplayName} v${versionInfo.version} installed!`);
468
+ blank();
469
+ log("Next steps:");
470
+ listItem(`cd ${resolvedPath}`);
471
+ listItem("claude");
472
+ listItem("/setup");
473
+ p3.outro(pc4.green("Happy building!"));
474
+ }
475
+
476
+ // src/commands/upgrade.ts
477
+ import * as p4 from "@clack/prompts";
478
+ import pc5 from "picocolors";
479
+ import path6 from "path";
480
+ import semver from "semver";
481
+
482
+ // src/lib/detect.ts
483
+ import fs3 from "fs-extra";
484
+ import path4 from "path";
485
+ import { z as z3 } from "zod";
486
+ var VersionJsonSchema = z3.object({
487
+ version: z3.string(),
488
+ packageName: z3.string(),
489
+ packageDisplayName: z3.string().optional(),
490
+ releasedAt: z3.string().optional(),
491
+ minUpgradeFrom: z3.string().optional(),
492
+ fileCategories: z3.object({
493
+ alwaysReplace: z3.array(z3.string()).optional(),
494
+ neverTouch: z3.array(z3.string()).optional(),
495
+ mergeIfChanged: z3.array(z3.string()).optional(),
496
+ addOnly: z3.array(z3.string()).optional()
497
+ }).optional(),
498
+ changelog: z3.record(z3.string(), z3.any()).optional()
499
+ });
500
+ var KitJsonSchema = z3.object({
501
+ name: z3.string(),
502
+ displayName: z3.string().optional(),
503
+ type: z3.enum(["bootstrap", "inject"]).optional()
504
+ });
505
+ async function detectKit(dirPath) {
506
+ const versionJsonPath = path4.join(dirPath, ".claude", "version.json");
507
+ const kitJsonPath = path4.join(dirPath, ".claude", "kit.json");
508
+ if (!await fs3.pathExists(versionJsonPath)) {
509
+ return null;
510
+ }
511
+ try {
512
+ const versionRaw = await fs3.readJson(versionJsonPath);
513
+ const versionJson = VersionJsonSchema.parse(versionRaw);
514
+ let kitJson;
515
+ if (await fs3.pathExists(kitJsonPath)) {
516
+ try {
517
+ const kitRaw = await fs3.readJson(kitJsonPath);
518
+ kitJson = KitJsonSchema.parse(kitRaw);
519
+ } catch {
520
+ }
521
+ }
522
+ return {
523
+ name: kitJson?.name ?? versionJson.packageName,
524
+ displayName: kitJson?.displayName ?? versionJson.packageDisplayName ?? versionJson.packageName,
525
+ version: versionJson.version,
526
+ versionJson,
527
+ kitJson,
528
+ rootPath: dirPath
529
+ };
530
+ } catch {
531
+ return null;
532
+ }
533
+ }
534
+ async function detectKitInCwd() {
535
+ return detectKit(process.cwd());
536
+ }
537
+
538
+ // src/lib/apply.ts
539
+ import fs4 from "fs-extra";
540
+ import path5 from "path";
541
+ import { glob } from "glob";
542
+ import { minimatch } from "minimatch";
543
+ import { merge } from "lodash-es";
544
+ function getErrorMessage(err) {
545
+ if (err instanceof Error) return err.message;
546
+ return String(err);
547
+ }
548
+ async function applyFileCategories(sourceDir, destDir, versionJson) {
549
+ const result = {
550
+ replaced: [],
551
+ merged: [],
552
+ added: [],
553
+ skipped: [],
554
+ errors: []
555
+ };
556
+ const alwaysReplace = versionJson.fileCategories?.alwaysReplace ?? [];
557
+ const neverTouch = versionJson.fileCategories?.neverTouch ?? [];
558
+ const mergeIfChanged = versionJson.fileCategories?.mergeIfChanged ?? [];
559
+ const addOnly = versionJson.fileCategories?.addOnly ?? [];
560
+ const processedFiles = /* @__PURE__ */ new Set();
561
+ for (const pattern of alwaysReplace) {
562
+ try {
563
+ const files = await glob(pattern, {
564
+ cwd: sourceDir,
565
+ dot: true,
566
+ nodir: true
567
+ });
568
+ for (const file of files) {
569
+ if (processedFiles.has(file)) continue;
570
+ const shouldSkip = neverTouch.some((ntPattern) => {
571
+ return matchesPattern(file, ntPattern);
572
+ });
573
+ if (shouldSkip) {
574
+ result.skipped.push(file);
575
+ processedFiles.add(file);
576
+ continue;
577
+ }
578
+ const srcPath = path5.join(sourceDir, file);
579
+ const destPath = path5.join(destDir, file);
580
+ try {
581
+ await fs4.ensureDir(path5.dirname(destPath));
582
+ await fs4.copy(srcPath, destPath, { overwrite: true });
583
+ result.replaced.push(file);
584
+ processedFiles.add(file);
585
+ } catch (err) {
586
+ result.errors.push(`Failed to copy ${file}: ${getErrorMessage(err)}`);
587
+ }
588
+ }
589
+ } catch (err) {
590
+ result.errors.push(`Failed to process pattern ${pattern}: ${getErrorMessage(err)}`);
591
+ }
592
+ }
593
+ for (const pattern of mergeIfChanged) {
594
+ try {
595
+ const files = await glob(pattern, {
596
+ cwd: sourceDir,
597
+ dot: true,
598
+ nodir: true
599
+ });
600
+ for (const file of files) {
601
+ if (processedFiles.has(file)) continue;
602
+ const shouldSkip = neverTouch.some((ntPattern) => {
603
+ return matchesPattern(file, ntPattern);
604
+ });
605
+ if (shouldSkip) {
606
+ result.skipped.push(file);
607
+ processedFiles.add(file);
608
+ continue;
609
+ }
610
+ const srcPath = path5.join(sourceDir, file);
611
+ const destPath = path5.join(destDir, file);
612
+ try {
613
+ const destExists = await fs4.pathExists(destPath);
614
+ if (destExists && file.endsWith(".json")) {
615
+ const incoming = await fs4.readJson(srcPath);
616
+ const existing = await fs4.readJson(destPath);
617
+ const merged = merge({}, incoming, existing);
618
+ await fs4.writeJson(destPath, merged, { spaces: 2 });
619
+ result.merged.push(file);
620
+ } else if (destExists) {
621
+ result.skipped.push(file);
622
+ } else {
623
+ await fs4.ensureDir(path5.dirname(destPath));
624
+ await fs4.copy(srcPath, destPath);
625
+ result.replaced.push(file);
626
+ }
627
+ processedFiles.add(file);
628
+ } catch (err) {
629
+ result.errors.push(`Failed to merge ${file}: ${getErrorMessage(err)}`);
630
+ }
631
+ }
632
+ } catch (err) {
633
+ result.errors.push(`Failed to process merge pattern ${pattern}: ${getErrorMessage(err)}`);
634
+ }
635
+ }
636
+ for (const pattern of addOnly) {
637
+ try {
638
+ const files = await glob(pattern, {
639
+ cwd: sourceDir,
640
+ dot: true,
641
+ nodir: true
642
+ });
643
+ for (const file of files) {
644
+ if (processedFiles.has(file)) continue;
645
+ const shouldSkip = neverTouch.some((ntPattern) => {
646
+ return matchesPattern(file, ntPattern);
647
+ });
648
+ if (shouldSkip) {
649
+ result.skipped.push(file);
650
+ processedFiles.add(file);
651
+ continue;
652
+ }
653
+ const srcPath = path5.join(sourceDir, file);
654
+ const destPath = path5.join(destDir, file);
655
+ try {
656
+ const destExists = await fs4.pathExists(destPath);
657
+ if (!destExists) {
658
+ await fs4.ensureDir(path5.dirname(destPath));
659
+ await fs4.copy(srcPath, destPath);
660
+ result.added.push(file);
661
+ } else {
662
+ result.skipped.push(file);
663
+ }
664
+ processedFiles.add(file);
665
+ } catch (err) {
666
+ result.errors.push(`Failed to add ${file}: ${getErrorMessage(err)}`);
667
+ }
668
+ }
669
+ } catch (err) {
670
+ result.errors.push(`Failed to process addOnly pattern ${pattern}: ${getErrorMessage(err)}`);
671
+ }
672
+ }
673
+ return result;
674
+ }
675
+ function matchesPattern(filePath, pattern) {
676
+ return minimatch(filePath, pattern, { dot: true });
677
+ }
678
+ async function isGitRepo(dirPath) {
679
+ try {
680
+ const gitDir = path5.join(dirPath, ".git");
681
+ return await fs4.pathExists(gitDir);
682
+ } catch {
683
+ return false;
684
+ }
685
+ }
686
+ async function createGitBackup(dirPath, message) {
687
+ try {
688
+ const { spawnSync } = await import("child_process");
689
+ spawnSync("git", ["add", "-A"], { cwd: dirPath, stdio: "pipe" });
690
+ const diffResult = spawnSync("git", ["diff", "--cached", "--quiet"], {
691
+ cwd: dirPath,
692
+ stdio: "pipe"
693
+ });
694
+ if (diffResult.status === 0) {
695
+ return false;
696
+ }
697
+ const commitResult = spawnSync("git", ["commit", "-m", message], {
698
+ cwd: dirPath,
699
+ stdio: "pipe"
700
+ });
701
+ return commitResult.status === 0;
702
+ } catch {
703
+ return false;
704
+ }
705
+ }
706
+
707
+ // src/commands/upgrade.ts
708
+ async function upgrade(options) {
709
+ p4.intro(pc5.cyan("aiorg upgrade"));
710
+ const kit = await detectKitInCwd();
711
+ if (!kit) {
712
+ error("Not in a kit directory");
713
+ log(pc5.dim("Run this command from a folder with .claude/version.json"));
714
+ process.exit(1);
715
+ }
716
+ keyValue("Kit", pc5.magenta(kit.displayName));
717
+ keyValue("Current version", pc5.cyan(`v${kit.version}`));
718
+ const spinner4 = p4.spinner();
719
+ spinner4.start("Checking for updates...");
720
+ let latest;
721
+ try {
722
+ latest = await fetchLatestVersion(kit.name);
723
+ spinner4.stop("Version info fetched");
724
+ } catch (error2) {
725
+ spinner4.stop("Failed to check for updates");
726
+ throw error2;
727
+ }
728
+ if (!semver.gt(latest.version, kit.version)) {
729
+ blank();
730
+ success(`Already on latest version (${pc5.cyan(`v${kit.version}`)})`);
731
+ p4.outro("");
732
+ return;
733
+ }
734
+ blank();
735
+ log(
736
+ `Update available: ${pc5.cyan(`v${kit.version}`)} \u2192 ${pc5.green(`v${latest.version}`)}`
737
+ );
738
+ if (latest.changelog && latest.changelog[latest.version]) {
739
+ const entry = latest.changelog[latest.version];
740
+ blank();
741
+ header(`What's new in v${latest.version}`);
742
+ if (entry.highlights && entry.highlights.length > 0) {
743
+ for (const highlight of entry.highlights) {
744
+ listItem(highlight);
745
+ }
746
+ }
747
+ if (entry.added && entry.added.length > 0) {
748
+ blank();
749
+ log(pc5.green("Added:"));
750
+ for (const item of entry.added.slice(0, 5)) {
751
+ listItem(item);
752
+ }
753
+ if (entry.added.length > 5) {
754
+ log(pc5.dim(` ... and ${entry.added.length - 5} more`));
755
+ }
756
+ }
757
+ if (entry.changed && entry.changed.length > 0) {
758
+ blank();
759
+ log(pc5.yellow("Changed:"));
760
+ for (const item of entry.changed.slice(0, 3)) {
761
+ listItem(item);
762
+ }
763
+ }
764
+ if (entry.upgradeNotes) {
765
+ blank();
766
+ log(pc5.dim("Note: " + entry.upgradeNotes));
767
+ }
768
+ }
769
+ blank();
770
+ log("Your data will be preserved:");
771
+ const neverTouch = kit.versionJson.fileCategories?.neverTouch ?? [];
772
+ for (const pattern of neverTouch.slice(0, 5)) {
773
+ listItem(pc5.dim(pattern));
774
+ }
775
+ if (neverTouch.length > 5) {
776
+ log(pc5.dim(` ... and ${neverTouch.length - 5} more patterns`));
777
+ }
778
+ if (!options.yes) {
779
+ blank();
780
+ const shouldUpgrade = await p4.confirm({
781
+ message: "Proceed with upgrade?",
782
+ initialValue: true
783
+ });
784
+ if (p4.isCancel(shouldUpgrade) || !shouldUpgrade) {
785
+ p4.cancel("Upgrade cancelled");
786
+ return;
787
+ }
788
+ }
789
+ const isFreeKit = latest.tier === "free";
790
+ let licenseKey = null;
791
+ if (!isFreeKit) {
792
+ if (!await isLoggedIn()) {
793
+ blank();
794
+ info("Login required for download");
795
+ await login();
796
+ blank();
797
+ }
798
+ licenseKey = await getLicenseKey();
799
+ if (!licenseKey) {
800
+ error("No license key found");
801
+ process.exit(1);
802
+ }
803
+ }
804
+ const inGitRepo = await isGitRepo(kit.rootPath);
805
+ if (inGitRepo) {
806
+ if (options.backup) {
807
+ spinner4.start("Creating git backup...");
808
+ const created = await createGitBackup(
809
+ kit.rootPath,
810
+ `chore: backup before upgrade to v${latest.version}`
811
+ );
812
+ spinner4.stop(created ? "Git backup created" : "No changes to backup");
813
+ } else if (!options.yes) {
814
+ const shouldBackup = await p4.confirm({
815
+ message: "Create git backup commit first?",
816
+ initialValue: true
817
+ });
818
+ if (shouldBackup === true) {
819
+ spinner4.start("Creating git backup...");
820
+ const created = await createGitBackup(
821
+ kit.rootPath,
822
+ `chore: backup before upgrade to v${latest.version}`
823
+ );
824
+ spinner4.stop(created ? "Git backup created" : "No changes to backup");
825
+ }
826
+ }
827
+ }
828
+ if (isFreeKit) {
829
+ spinner4.start("Getting download URL...");
830
+ } else {
831
+ spinner4.start("Verifying license...");
832
+ }
833
+ let downloadInfo;
834
+ try {
835
+ downloadInfo = await getDownloadUrl(kit.name, licenseKey);
836
+ spinner4.stop(isFreeKit ? "Ready to download" : "License verified");
837
+ } catch (error2) {
838
+ spinner4.stop(isFreeKit ? "Failed to get download URL" : "License verification failed");
839
+ throw error2;
840
+ }
841
+ spinner4.start(`Downloading v${latest.version}...`);
842
+ let tempDir = null;
843
+ try {
844
+ tempDir = await createTempDir("aiorg-upgrade-");
845
+ const zipPath = path6.join(tempDir, "kit.zip");
846
+ const extractPath = path6.join(tempDir, "extracted");
847
+ const zipData = await downloadFile(downloadInfo.downloadUrl);
848
+ await saveToFile(zipData, zipPath);
849
+ const sizeKB = await getFileSizeKB(zipPath);
850
+ spinner4.stop(`Downloaded v${latest.version} (${sizeKB} KB)`);
851
+ spinner4.start("Extracting...");
852
+ await extractZipToDir(zipPath, extractPath);
853
+ spinner4.stop("Extracted");
854
+ spinner4.start("Applying updates...");
855
+ const result = await applyFileCategories(
856
+ extractPath,
857
+ kit.rootPath,
858
+ kit.versionJson
859
+ );
860
+ spinner4.stop("Updates applied");
861
+ blank();
862
+ success(
863
+ `Upgraded ${kit.displayName}: ${pc5.cyan(`v${kit.version}`)} \u2192 ${pc5.green(`v${latest.version}`)}`
864
+ );
865
+ blank();
866
+ keyValue("Files updated", String(result.replaced.length));
867
+ if (result.merged.length > 0) {
868
+ keyValue("Files merged", String(result.merged.length));
869
+ }
870
+ if (result.added.length > 0) {
871
+ keyValue("Files added", String(result.added.length));
872
+ }
873
+ keyValue("Files preserved", String(result.skipped.length));
874
+ if (result.errors.length > 0) {
875
+ blank();
876
+ warn(`${result.errors.length} errors occurred:`);
877
+ for (const err of result.errors) {
878
+ listItem(pc5.dim(err));
879
+ }
880
+ }
881
+ await cleanupTempDir(tempDir);
882
+ } catch (error2) {
883
+ if (tempDir) {
884
+ await cleanupTempDir(tempDir);
885
+ }
886
+ throw error2;
887
+ }
888
+ blank();
889
+ log(pc5.yellow("\u26A0\uFE0F Restart Claude Code to use new commands"));
890
+ log(pc5.dim(' Type "exit" then start a new session'));
891
+ p4.outro(pc5.green("Upgrade complete!"));
892
+ }
893
+
894
+ // src/commands/version.ts
895
+ import pc6 from "picocolors";
896
+ import semver2 from "semver";
897
+ var CLI_VERSION = "1.0.0";
898
+ async function version() {
899
+ header("aiorg version");
900
+ keyValue("CLI", pc6.cyan(`v${CLI_VERSION}`));
901
+ const kit = await detectKitInCwd();
902
+ if (!kit) {
903
+ blank();
904
+ info("No kit detected in current directory");
905
+ log(pc6.dim("Run this command from a folder containing a kit"));
906
+ return;
907
+ }
908
+ keyValue(kit.displayName, pc6.cyan(`v${kit.version}`));
909
+ try {
910
+ const latest = await fetchLatestVersion(kit.name);
911
+ if (semver2.gt(latest.version, kit.version)) {
912
+ blank();
913
+ warn(
914
+ `Update available: ${pc6.cyan(`v${kit.version}`)} \u2192 ${pc6.green(`v${latest.version}`)}`
915
+ );
916
+ log(pc6.dim("Run 'aiorg upgrade' to update"));
917
+ } else {
918
+ blank();
919
+ success("You are on the latest version");
920
+ }
921
+ } catch {
922
+ blank();
923
+ log(pc6.dim("Could not check for updates"));
924
+ }
925
+ }
926
+
927
+ // src/index.ts
928
+ var cli = cac("aiorg");
929
+ cli.command("login", "Save your license key").action(async () => {
930
+ try {
931
+ await login();
932
+ } catch (error2) {
933
+ error(error2 instanceof Error ? error2.message : "Login failed");
934
+ process.exit(1);
935
+ }
936
+ });
937
+ cli.command("logout", "Remove saved license key").action(async () => {
938
+ try {
939
+ await logout();
940
+ } catch (error2) {
941
+ error(error2 instanceof Error ? error2.message : "Logout failed");
942
+ process.exit(1);
943
+ }
944
+ });
945
+ cli.command("init <kit> [path]", "Download and extract a kit").option("--force", "Overwrite existing folder").action(async (kit, path7, options) => {
946
+ try {
947
+ await init(kit, path7, options);
948
+ } catch (error2) {
949
+ error(error2 instanceof Error ? error2.message : "Init failed");
950
+ process.exit(1);
951
+ }
952
+ });
953
+ cli.command("upgrade", "Upgrade kit in current directory").option("--yes, -y", "Skip confirmation").option("--backup", "Always create git backup").action(async (options) => {
954
+ try {
955
+ await upgrade(options);
956
+ } catch (error2) {
957
+ error(error2 instanceof Error ? error2.message : "Upgrade failed");
958
+ process.exit(1);
959
+ }
960
+ });
961
+ cli.command("version", "Show CLI and kit versions").action(async () => {
962
+ try {
963
+ await version();
964
+ } catch (error2) {
965
+ error(error2 instanceof Error ? error2.message : "Version check failed");
966
+ process.exit(1);
967
+ }
968
+ });
969
+ cli.help();
970
+ cli.version("1.0.0");
971
+ cli.parse();
972
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/api.ts","../src/lib/auth.ts","../src/utils/logger.ts","../src/commands/logout.ts","../src/commands/init.ts","../src/lib/extract.ts","../src/commands/upgrade.ts","../src/lib/detect.ts","../src/lib/apply.ts","../src/commands/version.ts"],"sourcesContent":["import cac from 'cac'\nimport { login } from './commands/login.js'\nimport { logout } from './commands/logout.js'\nimport { init } from './commands/init.js'\nimport { upgrade } from './commands/upgrade.js'\nimport { version } from './commands/version.js'\nimport * as logger from './utils/logger.js'\n\nconst cli = cac('aiorg')\n\n// Login command\ncli\n .command('login', 'Save your license key')\n .action(async () => {\n try {\n await login()\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Login failed')\n process.exit(1)\n }\n })\n\n// Logout command\ncli\n .command('logout', 'Remove saved license key')\n .action(async () => {\n try {\n await logout()\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Logout failed')\n process.exit(1)\n }\n })\n\n// Init command\ncli\n .command('init <kit> [path]', 'Download and extract a kit')\n .option('--force', 'Overwrite existing folder')\n .action(async (kit: string, path: string | undefined, options: { force?: boolean }) => {\n try {\n await init(kit, path, options)\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Init failed')\n process.exit(1)\n }\n })\n\n// Upgrade command\ncli\n .command('upgrade', 'Upgrade kit in current directory')\n .option('--yes, -y', 'Skip confirmation')\n .option('--backup', 'Always create git backup')\n .action(async (options: { yes?: boolean; backup?: boolean }) => {\n try {\n await upgrade(options)\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Upgrade failed')\n process.exit(1)\n }\n })\n\n// Version command\ncli\n .command('version', 'Show CLI and kit versions')\n .action(async () => {\n try {\n await version()\n } catch (error) {\n logger.error(error instanceof Error ? error.message : 'Version check failed')\n process.exit(1)\n }\n })\n\n// Global options\ncli.help()\ncli.version('1.0.0')\n\n// Parse and run\ncli.parse()\n","import * as p from '@clack/prompts'\nimport pc from 'picocolors'\nimport { verifyLicense } from '../lib/api.js'\nimport { saveLicenseKey, isLoggedIn, loadConfig } from '../lib/auth.js'\nimport * as logger from '../utils/logger.js'\n\nexport async function login(): Promise<void> {\n p.intro(pc.cyan('aiorg login'))\n\n // Check if already logged in\n if (await isLoggedIn()) {\n const config = await loadConfig()\n const shouldContinue = await p.confirm({\n message: `Already logged in${config?.email ? ` as ${pc.cyan(config.email)}` : ''}. Replace license key?`,\n initialValue: false,\n })\n\n if (p.isCancel(shouldContinue) || !shouldContinue) {\n p.outro('Login cancelled')\n return\n }\n }\n\n // Get license key\n const licenseKey = await p.text({\n message: 'Enter your license key',\n placeholder: 'ak_live_xxxxx',\n validate: (value) => {\n if (!value) return 'License key is required'\n if (!value.startsWith('ak_')) return 'License key should start with \"ak_\"'\n return undefined\n },\n })\n\n if (p.isCancel(licenseKey)) {\n p.cancel('Login cancelled')\n process.exit(0)\n }\n\n // Verify with API\n const spinner = p.spinner()\n spinner.start('Verifying license...')\n\n try {\n const result = await verifyLicense(licenseKey)\n\n if (!result.valid) {\n spinner.stop('License verification failed')\n logger.error(result.error || 'Invalid license key')\n process.exit(1)\n }\n\n // Save to config\n const kitsRecord: Record<string, { tier: 'free' | 'paid'; purchasedAt: string }> = {}\n if (result.kits) {\n for (const kit of result.kits) {\n kitsRecord[kit.name] = {\n tier: kit.tier,\n purchasedAt: kit.purchasedAt,\n }\n }\n }\n\n await saveLicenseKey(licenseKey, result.email, kitsRecord)\n spinner.stop('License verified')\n\n // Show success\n logger.blank()\n logger.success(`Logged in${result.email ? ` as ${pc.cyan(result.email)}` : ''}`)\n\n if (result.kits && result.kits.length > 0) {\n logger.blank()\n logger.log('Licensed kits:')\n for (const kit of result.kits) {\n logger.listItem(`${kit.name} (${kit.tier})`)\n }\n }\n\n p.outro('Ready to use aiorg kits!')\n } catch (error) {\n spinner.stop('License verification failed')\n throw error\n }\n}\n","import { z } from 'zod'\n\nconst API_BASE_URL = process.env.AIORG_API_URL?.trim() || 'https://aiorg.dev'\nconst API_TIMEOUT_MS = 30000 // 30 seconds\n\n/**\n * Fetch with timeout support\n */\nasync function fetchWithTimeout(\n url: string,\n options: RequestInit = {},\n timeoutMs: number = API_TIMEOUT_MS\n): Promise<Response> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), timeoutMs)\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n })\n return response\n } finally {\n clearTimeout(timeout)\n }\n}\n\n// Response schemas\nconst LatestVersionSchema = z.object({\n version: z.string(),\n releasedAt: z.string(),\n packageName: z.string(),\n packageDisplayName: z.string(),\n changelog: z.record(z.string(), z.any()).optional(),\n tier: z.enum(['free', 'paid']).optional(),\n type: z.enum(['template', 'companion', 'inject']).optional(),\n})\n\nconst DownloadResponseSchema = z.object({\n downloadUrl: z.string(),\n version: z.string(),\n filename: z.string(),\n})\n\nconst VerifyLicenseResponseSchema = z.object({\n valid: z.boolean(),\n email: z.string().optional(),\n kits: z\n .array(\n z.object({\n name: z.string(),\n tier: z.enum(['free', 'paid']),\n purchasedAt: z.string(),\n })\n )\n .optional(),\n error: z.string().optional(),\n})\n\nexport type LatestVersion = z.infer<typeof LatestVersionSchema>\nexport type DownloadResponse = z.infer<typeof DownloadResponseSchema>\nexport type VerifyLicenseResponse = z.infer<typeof VerifyLicenseResponseSchema>\n\nclass APIError extends Error {\n constructor(\n message: string,\n public statusCode?: number\n ) {\n super(message)\n this.name = 'APIError'\n }\n}\n\n/**\n * Fetch latest version info for a kit\n */\nexport async function fetchLatestVersion(\n kitName: string\n): Promise<LatestVersion> {\n const url = `${API_BASE_URL}/api/kits/${kitName}/latest`\n\n try {\n const response = await fetchWithTimeout(url)\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new APIError(`Kit not found: \"${kitName}\"`, 404)\n }\n throw new APIError(`Failed to fetch version info`, response.status)\n }\n\n const data = await response.json()\n return LatestVersionSchema.parse(data)\n } catch (error) {\n if (error instanceof APIError) throw error\n if (error instanceof Error && error.name === 'AbortError') {\n throw new APIError('Request timed out')\n }\n throw new APIError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n}\n\n/**\n * Get download URL for a kit (license key optional for free kits)\n */\nexport async function getDownloadUrl(\n kitName: string,\n licenseKey: string | null\n): Promise<DownloadResponse> {\n const url = `${API_BASE_URL}/api/kits/${kitName}/download`\n\n const headers: Record<string, string> = {}\n if (licenseKey) {\n headers.Authorization = `Bearer ${licenseKey}`\n }\n\n try {\n const response = await fetchWithTimeout(url, { headers })\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new APIError('Invalid or expired license key', 401)\n }\n if (response.status === 403) {\n throw new APIError(\n 'License key does not have access to this kit',\n 403\n )\n }\n if (response.status === 404) {\n throw new APIError(`Kit not found: \"${kitName}\"`, 404)\n }\n throw new APIError(`Failed to get download URL`, response.status)\n }\n\n const data = await response.json()\n return DownloadResponseSchema.parse(data)\n } catch (error) {\n if (error instanceof APIError) throw error\n if (error instanceof Error && error.name === 'AbortError') {\n throw new APIError('Request timed out')\n }\n throw new APIError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n}\n\n/**\n * Verify a license key with the API\n */\nexport async function verifyLicense(\n licenseKey: string,\n kitName?: string\n): Promise<VerifyLicenseResponse> {\n const url = `${API_BASE_URL}/api/licenses/verify`\n\n try {\n const response = await fetchWithTimeout(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key: licenseKey,\n kit: kitName,\n }),\n })\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({})) as { error?: string }\n throw new APIError(\n data.error || 'License verification failed',\n response.status\n )\n }\n\n const data = await response.json()\n return VerifyLicenseResponseSchema.parse(data)\n } catch (error) {\n if (error instanceof APIError) throw error\n if (error instanceof Error && error.name === 'AbortError') {\n throw new APIError('Request timed out')\n }\n throw new APIError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n}\n\n/**\n * Download a file from a URL\n */\nexport async function downloadFile(url: string): Promise<ArrayBuffer> {\n const DOWNLOAD_TIMEOUT_MS = 120000 // 2 minutes for file downloads\n\n try {\n const response = await fetchWithTimeout(url, {}, DOWNLOAD_TIMEOUT_MS)\n\n if (!response.ok) {\n throw new APIError(`Download failed`, response.status)\n }\n\n return await response.arrayBuffer()\n } catch (error) {\n if (error instanceof APIError) throw error\n if (error instanceof Error && error.name === 'AbortError') {\n throw new APIError('Download timed out')\n }\n throw new APIError(\n `Download failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n}\n","import fs from 'fs-extra'\nimport path from 'path'\nimport os from 'os'\nimport { z } from 'zod'\n\nconst CONFIG_DIR = path.join(os.homedir(), '.aiorg')\nconst CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')\n\nconst KitLicenseSchema = z.object({\n tier: z.enum(['free', 'paid']),\n purchasedAt: z.string(),\n})\n\nconst ConfigSchema = z.object({\n licenseKey: z.string(),\n email: z.string().optional(),\n kits: z.record(z.string(), KitLicenseSchema).optional(),\n})\n\nexport type Config = z.infer<typeof ConfigSchema>\nexport type KitLicense = z.infer<typeof KitLicenseSchema>\n\n/**\n * Get the config directory path\n */\nexport function getConfigDir(): string {\n return CONFIG_DIR\n}\n\n/**\n * Get the config file path\n */\nexport function getConfigFile(): string {\n return CONFIG_FILE\n}\n\n/**\n * Ensure config directory exists\n */\nexport async function ensureConfigDir(): Promise<void> {\n await fs.ensureDir(CONFIG_DIR)\n}\n\n/**\n * Check if user is logged in (has config file with license key)\n */\nexport async function isLoggedIn(): Promise<boolean> {\n try {\n const config = await loadConfig()\n return !!config?.licenseKey\n } catch {\n return false\n }\n}\n\n/**\n * Load config from disk\n */\nexport async function loadConfig(): Promise<Config | null> {\n try {\n if (!(await fs.pathExists(CONFIG_FILE))) {\n return null\n }\n const raw = await fs.readJson(CONFIG_FILE)\n return ConfigSchema.parse(raw)\n } catch {\n return null\n }\n}\n\n/**\n * Save config to disk\n */\nexport async function saveConfig(config: Config): Promise<void> {\n await ensureConfigDir()\n await fs.writeJson(CONFIG_FILE, config, { spaces: 2 })\n}\n\n/**\n * Get license key from config or environment\n */\nexport async function getLicenseKey(): Promise<string | null> {\n // Check environment first\n const envKey = process.env.AIORG_LICENSE_KEY\n if (envKey) {\n return envKey\n }\n\n // Check config file\n const config = await loadConfig()\n return config?.licenseKey ?? null\n}\n\n/**\n * Save license key to config\n */\nexport async function saveLicenseKey(\n licenseKey: string,\n email?: string,\n kits?: Record<string, KitLicense>\n): Promise<void> {\n const existing = await loadConfig()\n await saveConfig({\n ...(existing || {}),\n licenseKey,\n email: email ?? existing?.email,\n kits: kits ?? existing?.kits,\n })\n}\n\n/**\n * Clear config (logout)\n */\nexport async function clearConfig(): Promise<void> {\n try {\n await fs.remove(CONFIG_FILE)\n } catch {\n // Ignore errors\n }\n}\n\n/**\n * Add kit to user's licensed kits\n */\nexport async function addLicensedKit(\n kitName: string,\n tier: 'free' | 'paid' = 'paid'\n): Promise<void> {\n const config = await loadConfig()\n if (!config) {\n throw new Error('Not logged in')\n }\n\n const kits = config.kits ?? {}\n kits[kitName] = {\n tier,\n purchasedAt: new Date().toISOString().split('T')[0],\n }\n\n await saveConfig({ ...config, kits })\n}\n","import pc from 'picocolors'\n\n/**\n * Log a success message\n */\nexport function success(message: string): void {\n console.log(pc.green('✓'), message)\n}\n\n/**\n * Log an error message\n */\nexport function error(message: string): void {\n console.log(pc.red('✗'), message)\n}\n\n/**\n * Log a warning message\n */\nexport function warn(message: string): void {\n console.log(pc.yellow('!'), message)\n}\n\n/**\n * Log an info message\n */\nexport function info(message: string): void {\n console.log(pc.blue('ℹ'), message)\n}\n\n/**\n * Log a plain message\n */\nexport function log(message: string): void {\n console.log(message)\n}\n\n/**\n * Log a blank line\n */\nexport function blank(): void {\n console.log()\n}\n\n/**\n * Log a header\n */\nexport function header(title: string): void {\n console.log()\n console.log(pc.bold(title))\n console.log(pc.dim('─'.repeat(40)))\n}\n\n/**\n * Log a key-value pair\n */\nexport function keyValue(key: string, value: string): void {\n console.log(`${pc.dim(key + ':')} ${value}`)\n}\n\n/**\n * Log a list item\n */\nexport function listItem(item: string, indent: number = 0): void {\n const prefix = ' '.repeat(indent)\n console.log(`${prefix}${pc.dim('•')} ${item}`)\n}\n\n/**\n * Format a version for display\n */\nexport function formatVersion(version: string): string {\n return pc.cyan(`v${version}`)\n}\n\n/**\n * Format a kit name for display\n */\nexport function formatKit(name: string): string {\n return pc.magenta(name)\n}\n\n/**\n * Format a path for display\n */\nexport function formatPath(path: string): string {\n return pc.yellow(path)\n}\n\n/**\n * Format a command for display\n */\nexport function formatCommand(cmd: string): string {\n return pc.cyan(cmd)\n}\n","import * as p from '@clack/prompts'\nimport pc from 'picocolors'\nimport { clearConfig, isLoggedIn, loadConfig } from '../lib/auth.js'\nimport * as logger from '../utils/logger.js'\n\nexport async function logout(): Promise<void> {\n p.intro(pc.cyan('aiorg logout'))\n\n // Check if logged in\n if (!(await isLoggedIn())) {\n logger.info('Not currently logged in')\n p.outro('')\n return\n }\n\n const config = await loadConfig()\n const email = config?.email\n\n // Confirm\n const shouldLogout = await p.confirm({\n message: `Log out${email ? ` from ${pc.cyan(email)}` : ''}?`,\n initialValue: true,\n })\n\n if (p.isCancel(shouldLogout) || !shouldLogout) {\n p.cancel('Logout cancelled')\n return\n }\n\n // Clear config\n await clearConfig()\n\n logger.success('Logged out')\n p.outro('')\n}\n","import * as p from '@clack/prompts'\nimport pc from 'picocolors'\nimport path from 'path'\nimport os from 'os'\nimport { getLicenseKey, isLoggedIn } from '../lib/auth.js'\nimport { fetchLatestVersion, getDownloadUrl, downloadFile } from '../lib/api.js'\nimport {\n createTempDir,\n saveToFile,\n extractZipToDir,\n cleanupTempDir,\n dirExistsAndNotEmpty,\n getFileSizeKB,\n} from '../lib/extract.js'\nimport * as logger from '../utils/logger.js'\nimport { login } from './login.js'\n\ninterface InitOptions {\n force?: boolean\n}\n\nexport async function init(\n kitName: string,\n targetPath: string | undefined,\n options: InitOptions\n): Promise<void> {\n p.intro(pc.cyan(`aiorg init ${kitName}`))\n\n // Resolve target path\n const resolvedPath = targetPath\n ? path.resolve(targetPath.replace(/^~/, os.homedir()))\n : path.resolve(process.cwd(), kitName)\n\n // Check if target exists\n if (!options.force && (await dirExistsAndNotEmpty(resolvedPath))) {\n logger.error(`Folder already exists: ${pc.yellow(resolvedPath)}`)\n logger.log(pc.dim('Use --force to overwrite'))\n process.exit(1)\n }\n\n // Fetch latest version info first (to check tier)\n const spinner = p.spinner()\n spinner.start('Fetching version info...')\n\n let versionInfo\n try {\n versionInfo = await fetchLatestVersion(kitName)\n spinner.stop(`Found ${pc.cyan(versionInfo.packageDisplayName)} v${versionInfo.version}`)\n } catch (error) {\n spinner.stop('Failed to fetch version info')\n throw error\n }\n\n const isFreeKit = versionInfo.tier === 'free'\n let licenseKey: string | null = null\n\n // Only require login for paid kits\n if (!isFreeKit) {\n if (!(await isLoggedIn())) {\n logger.info('Not logged in. Please log in first.')\n logger.blank()\n await login()\n logger.blank()\n }\n\n licenseKey = await getLicenseKey()\n if (!licenseKey) {\n logger.error('No license key found. Run \"aiorg login\" first.')\n process.exit(1)\n }\n }\n\n // Get download URL\n if (isFreeKit) {\n spinner.start('Getting download URL...')\n } else {\n spinner.start('Verifying license...')\n }\n\n let downloadInfo\n try {\n downloadInfo = await getDownloadUrl(kitName, licenseKey)\n spinner.stop(isFreeKit ? 'Ready to download' : 'License verified')\n } catch (error) {\n spinner.stop(isFreeKit ? 'Failed to get download URL' : 'License verification failed')\n throw error\n }\n\n // Download ZIP\n spinner.start(`Downloading ${kitName} v${versionInfo.version}...`)\n\n let tempDir: string | null = null\n try {\n tempDir = await createTempDir('aiorg-init-')\n const zipPath = path.join(tempDir, 'kit.zip')\n\n const zipData = await downloadFile(downloadInfo.downloadUrl)\n await saveToFile(zipData, zipPath)\n\n const sizeKB = await getFileSizeKB(zipPath)\n spinner.stop(`Downloaded ${kitName} v${versionInfo.version} (${sizeKB} KB)`)\n\n // Extract to target\n spinner.start(`Extracting to ${resolvedPath}...`)\n await extractZipToDir(zipPath, resolvedPath)\n spinner.stop(`Extracted to ${pc.yellow(resolvedPath)}`)\n\n // Cleanup\n await cleanupTempDir(tempDir)\n } catch (error) {\n if (tempDir) {\n await cleanupTempDir(tempDir)\n }\n throw error\n }\n\n // Success message\n logger.blank()\n logger.success(`${versionInfo.packageDisplayName} v${versionInfo.version} installed!`)\n logger.blank()\n logger.log('Next steps:')\n logger.listItem(`cd ${resolvedPath}`)\n logger.listItem('claude')\n logger.listItem('/setup')\n\n p.outro(pc.green('Happy building!'))\n}\n","import extractZip from 'extract-zip'\nimport fs from 'fs-extra'\nimport path from 'path'\nimport os from 'os'\n\n/**\n * Create a temporary directory for downloads\n */\nexport async function createTempDir(prefix: string = 'aiorg-'): Promise<string> {\n const tempDir = path.join(os.tmpdir(), `${prefix}${Date.now()}`)\n await fs.ensureDir(tempDir)\n return tempDir\n}\n\n/**\n * Save buffer to a file\n */\nexport async function saveToFile(\n data: ArrayBuffer,\n filePath: string\n): Promise<void> {\n await fs.ensureDir(path.dirname(filePath))\n await fs.writeFile(filePath, Buffer.from(data))\n}\n\n/**\n * Extract ZIP file to a directory\n */\nexport async function extractZipToDir(\n zipPath: string,\n destPath: string\n): Promise<void> {\n await fs.ensureDir(destPath)\n await extractZip(zipPath, { dir: destPath })\n}\n\n/**\n * Clean up temporary directory\n */\nexport async function cleanupTempDir(tempDir: string): Promise<void> {\n try {\n await fs.remove(tempDir)\n } catch {\n // Ignore cleanup errors\n }\n}\n\n/**\n * Check if a directory exists and is not empty\n */\nexport async function dirExistsAndNotEmpty(dirPath: string): Promise<boolean> {\n try {\n const exists = await fs.pathExists(dirPath)\n if (!exists) return false\n\n const files = await fs.readdir(dirPath)\n return files.length > 0\n } catch {\n return false\n }\n}\n\n/**\n * Get the size of a file in KB\n */\nexport async function getFileSizeKB(filePath: string): Promise<number> {\n const stats = await fs.stat(filePath)\n return Math.round(stats.size / 1024)\n}\n","import * as p from '@clack/prompts'\nimport pc from 'picocolors'\nimport path from 'path'\nimport semver from 'semver'\nimport { detectKitInCwd } from '../lib/detect.js'\nimport { getLicenseKey, isLoggedIn } from '../lib/auth.js'\nimport { fetchLatestVersion, getDownloadUrl, downloadFile } from '../lib/api.js'\nimport {\n createTempDir,\n saveToFile,\n extractZipToDir,\n cleanupTempDir,\n getFileSizeKB,\n} from '../lib/extract.js'\nimport { applyFileCategories, isGitRepo, createGitBackup } from '../lib/apply.js'\nimport * as logger from '../utils/logger.js'\nimport { login } from './login.js'\n\ninterface UpgradeOptions {\n yes?: boolean\n backup?: boolean\n}\n\nexport async function upgrade(options: UpgradeOptions): Promise<void> {\n p.intro(pc.cyan('aiorg upgrade'))\n\n // Detect kit in current directory\n const kit = await detectKitInCwd()\n\n if (!kit) {\n logger.error('Not in a kit directory')\n logger.log(pc.dim('Run this command from a folder with .claude/version.json'))\n process.exit(1)\n }\n\n logger.keyValue('Kit', pc.magenta(kit.displayName))\n logger.keyValue('Current version', pc.cyan(`v${kit.version}`))\n\n // Check for updates\n const spinner = p.spinner()\n spinner.start('Checking for updates...')\n\n let latest\n try {\n latest = await fetchLatestVersion(kit.name)\n spinner.stop('Version info fetched')\n } catch (error) {\n spinner.stop('Failed to check for updates')\n throw error\n }\n\n // Compare versions\n if (!semver.gt(latest.version, kit.version)) {\n logger.blank()\n logger.success(`Already on latest version (${pc.cyan(`v${kit.version}`)})`)\n p.outro('')\n return\n }\n\n // Show update available\n logger.blank()\n logger.log(\n `Update available: ${pc.cyan(`v${kit.version}`)} → ${pc.green(`v${latest.version}`)}`\n )\n\n // Show changelog\n if (latest.changelog && latest.changelog[latest.version]) {\n const entry = latest.changelog[latest.version]\n logger.blank()\n logger.header(`What's new in v${latest.version}`)\n\n if (entry.highlights && entry.highlights.length > 0) {\n for (const highlight of entry.highlights) {\n logger.listItem(highlight)\n }\n }\n\n if (entry.added && entry.added.length > 0) {\n logger.blank()\n logger.log(pc.green('Added:'))\n for (const item of entry.added.slice(0, 5)) {\n logger.listItem(item)\n }\n if (entry.added.length > 5) {\n logger.log(pc.dim(` ... and ${entry.added.length - 5} more`))\n }\n }\n\n if (entry.changed && entry.changed.length > 0) {\n logger.blank()\n logger.log(pc.yellow('Changed:'))\n for (const item of entry.changed.slice(0, 3)) {\n logger.listItem(item)\n }\n }\n\n if (entry.upgradeNotes) {\n logger.blank()\n logger.log(pc.dim('Note: ' + entry.upgradeNotes))\n }\n }\n\n // Show what will be preserved\n logger.blank()\n logger.log('Your data will be preserved:')\n const neverTouch = kit.versionJson.fileCategories?.neverTouch ?? []\n for (const pattern of neverTouch.slice(0, 5)) {\n logger.listItem(pc.dim(pattern))\n }\n if (neverTouch.length > 5) {\n logger.log(pc.dim(` ... and ${neverTouch.length - 5} more patterns`))\n }\n\n // Confirm upgrade\n if (!options.yes) {\n logger.blank()\n const shouldUpgrade = await p.confirm({\n message: 'Proceed with upgrade?',\n initialValue: true,\n })\n\n if (p.isCancel(shouldUpgrade) || !shouldUpgrade) {\n p.cancel('Upgrade cancelled')\n return\n }\n }\n\n // Check if kit is free (no license required)\n const isFreeKit = latest.tier === 'free'\n let licenseKey: string | null = null\n\n // Only require login for paid kits\n if (!isFreeKit) {\n if (!(await isLoggedIn())) {\n logger.blank()\n logger.info('Login required for download')\n await login()\n logger.blank()\n }\n\n licenseKey = await getLicenseKey()\n if (!licenseKey) {\n logger.error('No license key found')\n process.exit(1)\n }\n }\n\n // Git backup\n const inGitRepo = await isGitRepo(kit.rootPath)\n if (inGitRepo) {\n if (options.backup) {\n spinner.start('Creating git backup...')\n const created = await createGitBackup(\n kit.rootPath,\n `chore: backup before upgrade to v${latest.version}`\n )\n spinner.stop(created ? 'Git backup created' : 'No changes to backup')\n } else if (!options.yes) {\n const shouldBackup = await p.confirm({\n message: 'Create git backup commit first?',\n initialValue: true,\n })\n\n if (shouldBackup === true) {\n spinner.start('Creating git backup...')\n const created = await createGitBackup(\n kit.rootPath,\n `chore: backup before upgrade to v${latest.version}`\n )\n spinner.stop(created ? 'Git backup created' : 'No changes to backup')\n }\n }\n }\n\n // Get download URL\n if (isFreeKit) {\n spinner.start('Getting download URL...')\n } else {\n spinner.start('Verifying license...')\n }\n\n let downloadInfo\n try {\n downloadInfo = await getDownloadUrl(kit.name, licenseKey)\n spinner.stop(isFreeKit ? 'Ready to download' : 'License verified')\n } catch (error) {\n spinner.stop(isFreeKit ? 'Failed to get download URL' : 'License verification failed')\n throw error\n }\n\n // Download\n spinner.start(`Downloading v${latest.version}...`)\n\n let tempDir: string | null = null\n try {\n tempDir = await createTempDir('aiorg-upgrade-')\n const zipPath = path.join(tempDir, 'kit.zip')\n const extractPath = path.join(tempDir, 'extracted')\n\n const zipData = await downloadFile(downloadInfo.downloadUrl)\n await saveToFile(zipData, zipPath)\n\n const sizeKB = await getFileSizeKB(zipPath)\n spinner.stop(`Downloaded v${latest.version} (${sizeKB} KB)`)\n\n // Extract to temp\n spinner.start('Extracting...')\n await extractZipToDir(zipPath, extractPath)\n spinner.stop('Extracted')\n\n // Apply fileCategories\n spinner.start('Applying updates...')\n const result = await applyFileCategories(\n extractPath,\n kit.rootPath,\n kit.versionJson\n )\n spinner.stop('Updates applied')\n\n // Show summary\n logger.blank()\n logger.success(\n `Upgraded ${kit.displayName}: ${pc.cyan(`v${kit.version}`)} → ${pc.green(`v${latest.version}`)}`\n )\n logger.blank()\n logger.keyValue('Files updated', String(result.replaced.length))\n if (result.merged.length > 0) {\n logger.keyValue('Files merged', String(result.merged.length))\n }\n if (result.added.length > 0) {\n logger.keyValue('Files added', String(result.added.length))\n }\n logger.keyValue('Files preserved', String(result.skipped.length))\n\n if (result.errors.length > 0) {\n logger.blank()\n logger.warn(`${result.errors.length} errors occurred:`)\n for (const err of result.errors) {\n logger.listItem(pc.dim(err))\n }\n }\n\n // Cleanup\n await cleanupTempDir(tempDir)\n } catch (error) {\n if (tempDir) {\n await cleanupTempDir(tempDir)\n }\n throw error\n }\n\n // Post-upgrade note\n logger.blank()\n logger.log(pc.yellow('⚠️ Restart Claude Code to use new commands'))\n logger.log(pc.dim(' Type \"exit\" then start a new session'))\n\n p.outro(pc.green('Upgrade complete!'))\n}\n","import fs from 'fs-extra'\nimport path from 'path'\nimport { z } from 'zod'\n\nconst VersionJsonSchema = z.object({\n version: z.string(),\n packageName: z.string(),\n packageDisplayName: z.string().optional(),\n releasedAt: z.string().optional(),\n minUpgradeFrom: z.string().optional(),\n fileCategories: z\n .object({\n alwaysReplace: z.array(z.string()).optional(),\n neverTouch: z.array(z.string()).optional(),\n mergeIfChanged: z.array(z.string()).optional(),\n addOnly: z.array(z.string()).optional(),\n })\n .optional(),\n changelog: z.record(z.string(), z.any()).optional(),\n})\n\nconst KitJsonSchema = z.object({\n name: z.string(),\n displayName: z.string().optional(),\n type: z.enum(['bootstrap', 'inject']).optional(),\n})\n\nexport type VersionJson = z.infer<typeof VersionJsonSchema>\nexport type KitJson = z.infer<typeof KitJsonSchema>\n\nexport interface DetectedKit {\n name: string\n displayName: string\n version: string\n versionJson: VersionJson\n kitJson?: KitJson\n rootPath: string\n}\n\n/**\n * Detect kit in a directory by looking for .claude/version.json or .claude/kit.json\n */\nexport async function detectKit(dirPath: string): Promise<DetectedKit | null> {\n const versionJsonPath = path.join(dirPath, '.claude', 'version.json')\n const kitJsonPath = path.join(dirPath, '.claude', 'kit.json')\n\n // Check for version.json (required)\n if (!(await fs.pathExists(versionJsonPath))) {\n return null\n }\n\n try {\n const versionRaw = await fs.readJson(versionJsonPath)\n const versionJson = VersionJsonSchema.parse(versionRaw)\n\n // Optionally load kit.json\n let kitJson: KitJson | undefined\n if (await fs.pathExists(kitJsonPath)) {\n try {\n const kitRaw = await fs.readJson(kitJsonPath)\n kitJson = KitJsonSchema.parse(kitRaw)\n } catch {\n // Ignore kit.json parse errors\n }\n }\n\n return {\n name: kitJson?.name ?? versionJson.packageName,\n displayName:\n kitJson?.displayName ??\n versionJson.packageDisplayName ??\n versionJson.packageName,\n version: versionJson.version,\n versionJson,\n kitJson,\n rootPath: dirPath,\n }\n } catch {\n return null\n }\n}\n\n/**\n * Detect kit in current working directory\n */\nexport async function detectKitInCwd(): Promise<DetectedKit | null> {\n return detectKit(process.cwd())\n}\n\n/**\n * Get file categories from version.json\n */\nexport function getFileCategories(versionJson: VersionJson): {\n alwaysReplace: string[]\n neverTouch: string[]\n mergeIfChanged: string[]\n addOnly: string[]\n} {\n return {\n alwaysReplace: versionJson.fileCategories?.alwaysReplace ?? [],\n neverTouch: versionJson.fileCategories?.neverTouch ?? [],\n mergeIfChanged: versionJson.fileCategories?.mergeIfChanged ?? [],\n addOnly: versionJson.fileCategories?.addOnly ?? [],\n }\n}\n","import fs from 'fs-extra'\nimport path from 'path'\nimport { glob } from 'glob'\nimport { minimatch } from 'minimatch'\nimport { merge } from 'lodash-es'\nimport type { VersionJson } from './detect.js'\n\n/**\n * Safely extract error message from unknown error\n */\nfunction getErrorMessage(err: unknown): string {\n if (err instanceof Error) return err.message\n return String(err)\n}\n\nexport interface ApplyResult {\n replaced: string[]\n merged: string[]\n added: string[]\n skipped: string[]\n errors: string[]\n}\n\n/**\n * Apply fileCategories from source to destination\n * - alwaysReplace: copy/overwrite from source\n * - neverTouch: skip entirely\n * - mergeIfChanged: deep merge JSON files (user values win)\n * - addOnly: add only if file doesn't exist\n */\nexport async function applyFileCategories(\n sourceDir: string,\n destDir: string,\n versionJson: VersionJson\n): Promise<ApplyResult> {\n const result: ApplyResult = {\n replaced: [],\n merged: [],\n added: [],\n skipped: [],\n errors: [],\n }\n\n const alwaysReplace = versionJson.fileCategories?.alwaysReplace ?? []\n const neverTouch = versionJson.fileCategories?.neverTouch ?? []\n const mergeIfChanged = versionJson.fileCategories?.mergeIfChanged ?? []\n const addOnly = versionJson.fileCategories?.addOnly ?? []\n\n // Track processed files to avoid duplicates\n const processedFiles = new Set<string>()\n\n // 1. Process alwaysReplace patterns\n for (const pattern of alwaysReplace) {\n try {\n const files = await glob(pattern, {\n cwd: sourceDir,\n dot: true,\n nodir: true,\n })\n\n for (const file of files) {\n if (processedFiles.has(file)) continue\n\n // Check if file matches any neverTouch pattern\n const shouldSkip = neverTouch.some((ntPattern) => {\n return matchesPattern(file, ntPattern)\n })\n\n if (shouldSkip) {\n result.skipped.push(file)\n processedFiles.add(file)\n continue\n }\n\n const srcPath = path.join(sourceDir, file)\n const destPath = path.join(destDir, file)\n\n try {\n await fs.ensureDir(path.dirname(destPath))\n await fs.copy(srcPath, destPath, { overwrite: true })\n result.replaced.push(file)\n processedFiles.add(file)\n } catch (err) {\n result.errors.push(`Failed to copy ${file}: ${getErrorMessage(err)}`)\n }\n }\n } catch (err) {\n result.errors.push(`Failed to process pattern ${pattern}: ${getErrorMessage(err)}`)\n }\n }\n\n // 2. Process mergeIfChanged patterns (JSON deep merge)\n for (const pattern of mergeIfChanged) {\n try {\n const files = await glob(pattern, {\n cwd: sourceDir,\n dot: true,\n nodir: true,\n })\n\n for (const file of files) {\n if (processedFiles.has(file)) continue\n\n // Check if file matches any neverTouch pattern\n const shouldSkip = neverTouch.some((ntPattern) => {\n return matchesPattern(file, ntPattern)\n })\n\n if (shouldSkip) {\n result.skipped.push(file)\n processedFiles.add(file)\n continue\n }\n\n const srcPath = path.join(sourceDir, file)\n const destPath = path.join(destDir, file)\n\n try {\n const destExists = await fs.pathExists(destPath)\n\n if (destExists && file.endsWith('.json')) {\n // Merge JSON files - user's values win (existing overwrites incoming)\n const incoming = await fs.readJson(srcPath)\n const existing = await fs.readJson(destPath)\n\n // Deep merge: start with incoming, overlay existing (user's changes win)\n const merged = merge({}, incoming, existing)\n\n await fs.writeJson(destPath, merged, { spaces: 2 })\n result.merged.push(file)\n } else if (destExists) {\n // Non-JSON file exists - skip (preserve user's version)\n result.skipped.push(file)\n } else {\n // File doesn't exist - copy it\n await fs.ensureDir(path.dirname(destPath))\n await fs.copy(srcPath, destPath)\n result.replaced.push(file)\n }\n processedFiles.add(file)\n } catch (err) {\n result.errors.push(`Failed to merge ${file}: ${getErrorMessage(err)}`)\n }\n }\n } catch (err) {\n result.errors.push(`Failed to process merge pattern ${pattern}: ${getErrorMessage(err)}`)\n }\n }\n\n // 3. Process addOnly patterns (add if missing)\n for (const pattern of addOnly) {\n try {\n const files = await glob(pattern, {\n cwd: sourceDir,\n dot: true,\n nodir: true,\n })\n\n for (const file of files) {\n if (processedFiles.has(file)) continue\n\n // Check if file matches any neverTouch pattern\n const shouldSkip = neverTouch.some((ntPattern) => {\n return matchesPattern(file, ntPattern)\n })\n\n if (shouldSkip) {\n result.skipped.push(file)\n processedFiles.add(file)\n continue\n }\n\n const srcPath = path.join(sourceDir, file)\n const destPath = path.join(destDir, file)\n\n try {\n const destExists = await fs.pathExists(destPath)\n\n if (!destExists) {\n // Only add if file doesn't exist\n await fs.ensureDir(path.dirname(destPath))\n await fs.copy(srcPath, destPath)\n result.added.push(file)\n } else {\n // File exists - skip\n result.skipped.push(file)\n }\n processedFiles.add(file)\n } catch (err) {\n result.errors.push(`Failed to add ${file}: ${getErrorMessage(err)}`)\n }\n }\n } catch (err) {\n result.errors.push(`Failed to process addOnly pattern ${pattern}: ${getErrorMessage(err)}`)\n }\n }\n\n return result\n}\n\n/**\n * Pattern matching using minimatch (supports *, **, etc.)\n */\nfunction matchesPattern(filePath: string, pattern: string): boolean {\n return minimatch(filePath, pattern, { dot: true })\n}\n\n/**\n * Check if git is available and directory is a git repo\n */\nexport async function isGitRepo(dirPath: string): Promise<boolean> {\n try {\n const gitDir = path.join(dirPath, '.git')\n return await fs.pathExists(gitDir)\n } catch {\n return false\n }\n}\n\n/**\n * Create a git backup commit\n */\nexport async function createGitBackup(\n dirPath: string,\n message: string\n): Promise<boolean> {\n try {\n const { spawnSync } = await import('child_process')\n\n // Stage all changes\n spawnSync('git', ['add', '-A'], { cwd: dirPath, stdio: 'pipe' })\n\n // Check if there are changes to commit\n const diffResult = spawnSync('git', ['diff', '--cached', '--quiet'], {\n cwd: dirPath,\n stdio: 'pipe',\n })\n\n if (diffResult.status === 0) {\n // No changes\n return false\n }\n\n // Has changes, commit them (using spawnSync to avoid shell injection)\n const commitResult = spawnSync('git', ['commit', '-m', message], {\n cwd: dirPath,\n stdio: 'pipe',\n })\n\n return commitResult.status === 0\n } catch {\n return false\n }\n}\n","import pc from 'picocolors'\nimport semver from 'semver'\nimport { detectKitInCwd } from '../lib/detect.js'\nimport { fetchLatestVersion } from '../lib/api.js'\nimport * as logger from '../utils/logger.js'\n\nconst CLI_VERSION = '1.0.0'\n\nexport async function version(): Promise<void> {\n logger.header('aiorg version')\n\n // CLI version\n logger.keyValue('CLI', pc.cyan(`v${CLI_VERSION}`))\n\n // Detect kit in current directory\n const kit = await detectKitInCwd()\n\n if (!kit) {\n logger.blank()\n logger.info('No kit detected in current directory')\n logger.log(pc.dim('Run this command from a folder containing a kit'))\n return\n }\n\n // Show current kit version\n logger.keyValue(kit.displayName, pc.cyan(`v${kit.version}`))\n\n // Check for updates\n try {\n const latest = await fetchLatestVersion(kit.name)\n\n if (semver.gt(latest.version, kit.version)) {\n logger.blank()\n logger.warn(\n `Update available: ${pc.cyan(`v${kit.version}`)} → ${pc.green(`v${latest.version}`)}`\n )\n logger.log(pc.dim(\"Run 'aiorg upgrade' to update\"))\n } else {\n logger.blank()\n logger.success('You are on the latest version')\n }\n } catch {\n // Silently ignore API errors for version check\n logger.blank()\n logger.log(pc.dim('Could not check for updates'))\n }\n}\n"],"mappings":"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","names":["pc","error","data","z","pc","spinner","error","p","pc","pc","p","pc","path","os","fs","path","os","pc","path","os","spinner","error","p","pc","path","fs","path","z","fs","path","pc","spinner","error","path","pc","semver","pc","semver","error","path"]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@aiorg/cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI for downloading and upgrading aiorg kits",
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "bin": {
10
+ "aiorg": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsup --watch",
18
+ "typecheck": "tsc --noEmit",
19
+ "prepublishOnly": "pnpm build"
20
+ },
21
+ "keywords": [
22
+ "aiorg",
23
+ "cli",
24
+ "claude",
25
+ "starter-kit"
26
+ ],
27
+ "author": "aiorg.dev",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/aiorgdev/cli"
32
+ },
33
+ "engines": {
34
+ "node": ">=18"
35
+ },
36
+ "dependencies": {
37
+ "cac": "^6.7.14",
38
+ "@clack/prompts": "^0.8.2",
39
+ "picocolors": "^1.1.1",
40
+ "ora": "^8.1.1",
41
+ "extract-zip": "^2.0.1",
42
+ "fs-extra": "^11.2.0",
43
+ "glob": "^11.0.0",
44
+ "lodash-es": "^4.17.21",
45
+ "minimatch": "^10.0.1",
46
+ "zod": "^3.24.1",
47
+ "semver": "^7.6.3"
48
+ },
49
+ "devDependencies": {
50
+ "@types/fs-extra": "^11.0.4",
51
+ "@types/lodash-es": "^4.17.12",
52
+ "@types/node": "^22.10.5",
53
+ "@types/semver": "^7.5.8",
54
+ "tsup": "^8.3.5",
55
+ "typescript": "^5.7.2"
56
+ }
57
+ }