@use-aistack/cli 0.1.0 → 0.3.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/README.md CHANGED
@@ -2,45 +2,55 @@
2
2
 
3
3
  Share and clone AI development configurations (prompts, rules, skills, MCP setups).
4
4
 
5
- ## Install
5
+ Run on-demand with `npx` — no install required:
6
6
 
7
7
  ```sh
8
8
  npx @use-aistack/cli <command>
9
9
  ```
10
10
 
11
- Or install globally:
12
-
13
- ```sh
14
- npm i -g @use-aistack/cli
15
- ```
16
-
17
11
  ## Commands
18
12
 
19
- ### `aistack login`
13
+ ### `npx @use-aistack/cli login`
20
14
 
21
15
  Authenticate with your AI Stack account via browser.
22
16
 
23
17
  ```sh
24
- aistack login
18
+ npx @use-aistack/cli login
25
19
  ```
26
20
 
27
- ### `aistack collect`
21
+ ### `npx @use-aistack/cli collect`
28
22
 
29
23
  Scan your project for AI config files and upload them.
30
24
 
31
25
  ```sh
32
26
  cd your-project
33
- aistack collect
27
+ npx @use-aistack/cli collect
34
28
  ```
35
29
 
36
30
  Detects: `.cursorrules`, `CLAUDE.md`, `AGENTS.md`, `.cursor/rules/`, `mcp.json`, skill directories, prompts, and global configs (`~/.claude/`, `~/.cursor/`, etc).
37
31
 
38
- ### `aistack create <slug>`
32
+ ### `npx @use-aistack/cli create <slug>`
39
33
 
40
34
  Clone a shared project's AI config files into your current directory.
41
35
 
42
36
  ```sh
43
- aistack create my-project-abc123
37
+ npx @use-aistack/cli create my-project-abc123
38
+ ```
39
+
40
+ ## Install globally (optional)
41
+
42
+ If you'd rather type `aistack` instead of `npx @use-aistack/cli` every time, install it globally:
43
+
44
+ ```sh
45
+ npm i -g @use-aistack/cli
46
+ ```
47
+
48
+ Then the same commands become:
49
+
50
+ ```sh
51
+ aistack login
52
+ aistack collect
53
+ aistack create <slug>
44
54
  ```
45
55
 
46
56
  ## Development
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/login.ts
7
- import * as p from "@clack/prompts";
7
+ import * as p2 from "@clack/prompts";
8
8
  import open from "open";
9
9
 
10
10
  // src/api.ts
@@ -41,7 +41,9 @@ async function projectsCheck(token, name) {
41
41
  }
42
42
  );
43
43
  if (res.status === 401)
44
- throw new Error("Authentication expired. Run `aistack login` again.");
44
+ throw new Error(
45
+ "Authentication expired. Run `npx @use-aistack/cli login` again."
46
+ );
45
47
  if (!res.ok) throw new Error(`Project check failed: ${res.status}`);
46
48
  return res.json();
47
49
  }
@@ -52,15 +54,27 @@ async function projectsCollect(token, data) {
52
54
  body: JSON.stringify(data)
53
55
  });
54
56
  if (res.status === 401)
55
- throw new Error("Authentication expired. Run `aistack login` again.");
56
- if (!res.ok) {
57
- const body = await res.json().catch(() => ({}));
58
57
  throw new Error(
59
- body.error || `Collect failed: ${res.status}`
58
+ "Authentication expired. Run `npx @use-aistack/cli login` again."
60
59
  );
60
+ if (!res.ok) {
61
+ throw new Error(await formatHttpError(res, "Collect failed"));
61
62
  }
62
63
  return res.json();
63
64
  }
65
+ async function formatHttpError(res, label) {
66
+ const prefix = `${label}: ${res.status} ${res.statusText || ""}`.trim();
67
+ const text2 = await res.text().catch(() => "");
68
+ if (!text2) return prefix;
69
+ try {
70
+ const body = JSON.parse(text2);
71
+ const detail = body.error || body.message;
72
+ if (detail) return `${prefix} \u2014 ${detail}`;
73
+ } catch {
74
+ }
75
+ const snippet = text2.trim().slice(0, 500);
76
+ return snippet ? `${prefix} \u2014 ${snippet}` : prefix;
77
+ }
64
78
  async function projectGet(shortId) {
65
79
  const res = await request(`/api/cli/projects/${encodeURIComponent(shortId)}`);
66
80
  if (res.status === 404) return null;
@@ -127,6 +141,7 @@ function saveProjectSettings(directory, name, excluded) {
127
141
  }
128
142
 
129
143
  // src/theme.ts
144
+ import * as p from "@clack/prompts";
130
145
  var esc = (code) => `\x1B[${code}m`;
131
146
  var reset = esc("0");
132
147
  var LIME = "163;230;53";
@@ -156,11 +171,31 @@ function section(label, count) {
156
171
  function divider() {
157
172
  console.log(`${BAR} ${dim("\u2500".repeat(40))}`);
158
173
  }
174
+ function intro2(cmd) {
175
+ console.log();
176
+ p.intro(banner(cmd));
177
+ }
178
+ function outro2(msg) {
179
+ p.outro(msg);
180
+ console.log();
181
+ }
182
+ function outroError(msg) {
183
+ p.outro(red(msg));
184
+ console.log();
185
+ }
186
+ function outroCancel(msg = "cancelled") {
187
+ p.cancel(dim(msg));
188
+ console.log();
189
+ }
190
+ function outroSkipped(msg) {
191
+ p.outro(dim(msg));
192
+ console.log();
193
+ }
159
194
 
160
195
  // src/commands/login.ts
161
196
  async function loginCommand() {
162
- p.intro(banner("login"));
163
- const s = p.spinner();
197
+ intro2("login");
198
+ const s = p2.spinner();
164
199
  s.start("Starting authentication...");
165
200
  let session;
166
201
  try {
@@ -168,15 +203,16 @@ async function loginCommand() {
168
203
  s.stop("Session created");
169
204
  } catch (err) {
170
205
  s.stop("Failed to start authentication");
171
- p.log.error(err instanceof Error ? err.message : String(err));
206
+ p2.log.error(err instanceof Error ? err.message : String(err));
207
+ outroError("error");
172
208
  process.exit(1);
173
209
  }
174
- p.log.info(`${dim("CODE")} ${limeBold(session.userCode)}`);
175
- p.log.info(`${dim("OPEN")} ${dim(session.authUrl)}`);
210
+ p2.log.info(`${dim("CODE")} ${limeBold(session.userCode)}`);
211
+ p2.log.info(`${dim("OPEN")} ${dim(session.authUrl)}`);
176
212
  try {
177
213
  await open(session.authUrl);
178
214
  } catch {
179
- p.log.warn(
215
+ p2.log.warn(
180
216
  "Could not open browser automatically. Please visit the URL above."
181
217
  );
182
218
  }
@@ -189,30 +225,33 @@ async function loginCommand() {
189
225
  if (result.status === "approved" && result.token) {
190
226
  s.stop(lime("Authenticated"));
191
227
  saveToken(result.token, result.userId);
192
- p.log.success(
193
- `Token saved. Run ${limeBold("aistack collect")} to get started.`
228
+ p2.log.success(
229
+ `Token saved. Run ${limeBold("npx @use-aistack/cli collect")} to get started.`
194
230
  );
195
- p.outro(lime("done"));
231
+ outro2(lime("done"));
196
232
  return;
197
233
  }
198
234
  if (result.status === "expired") {
199
235
  s.stop("Session expired");
200
- p.log.error("Authentication session expired. Please try again.");
236
+ p2.log.error("Authentication session expired. Please try again.");
237
+ outroError("expired");
201
238
  process.exit(1);
202
239
  }
203
240
  } catch (err) {
204
241
  s.stop("Error polling");
205
- p.log.error(err instanceof Error ? err.message : String(err));
242
+ p2.log.error(err instanceof Error ? err.message : String(err));
243
+ outroError("error");
206
244
  process.exit(1);
207
245
  }
208
246
  }
209
247
  s.stop("Timed out");
210
- p.log.error("Authentication timed out after 3 minutes. Please try again.");
248
+ p2.log.error("Authentication timed out after 3 minutes. Please try again.");
249
+ outroError("timed out");
211
250
  process.exit(1);
212
251
  }
213
252
 
214
253
  // src/commands/collect.ts
215
- import * as p2 from "@clack/prompts";
254
+ import * as p3 from "@clack/prompts";
216
255
  import { basename as basename2 } from "path";
217
256
 
218
257
  // src/scanner.ts
@@ -223,32 +262,39 @@ import ignore from "ignore";
223
262
  var MAX_FILE_SIZE = 100 * 1024;
224
263
  var LOCAL_PATTERNS = [
225
264
  // Rules
226
- { path: "CLAUDE.md", type: "rule" },
227
- { path: "AGENTS.md", type: "rule" },
228
- { path: ".cursorrules", type: "rule" },
229
- { path: ".windsurfrules", type: "rule" },
230
- { path: ".clinerules", type: "rule" },
231
- { path: ".github/copilot-instructions.md", type: "rule" },
265
+ { path: "CLAUDE.md", type: "rule", group: "claude-code" },
266
+ { path: "AGENTS.md", type: "rule", group: "claude-code" },
267
+ { path: ".cursorrules", type: "rule", group: "cursor" },
268
+ { path: ".windsurfrules", type: "rule", group: "windsurf" },
269
+ { path: ".clinerules", type: "rule", group: "cline" },
270
+ { path: ".github/copilot-instructions.md", type: "rule", group: "copilot" },
232
271
  // MCP
233
- { path: "mcp.json", type: "mcp" },
234
- { path: ".cursor/mcp.json", type: "mcp" },
235
- { path: "claude_desktop_config.json", type: "mcp" },
236
- // Config
237
- { path: ".aider.conf.yml", type: "config" },
238
- { path: ".continue/config.json", type: "config" },
272
+ { path: "mcp.json", type: "mcp", group: "generic" },
273
+ { path: ".cursor/mcp.json", type: "mcp", group: "cursor" },
274
+ {
275
+ path: "claude_desktop_config.json",
276
+ type: "mcp",
277
+ group: "claude-desktop"
278
+ },
239
279
  // Config
240
- { path: ".claude/settings.json", type: "config" },
241
- { path: ".claude/settings.local.json", type: "config" },
280
+ { path: ".aider.conf.yml", type: "config", group: "aider" },
281
+ { path: ".continue/config.json", type: "config", group: "continue" },
282
+ { path: ".claude/settings.json", type: "config", group: "claude-code" },
283
+ {
284
+ path: ".claude/settings.local.json",
285
+ type: "config",
286
+ group: "claude-code"
287
+ },
242
288
  // Prompts
243
- { path: "system-prompt.md", type: "prompt" }
289
+ { path: "system-prompt.md", type: "prompt", group: "generic" }
244
290
  ];
245
291
  var LOCAL_DIR_PATTERNS = [
246
- { dir: ".cursor/rules", type: "rule" },
247
- { dir: ".claude/commands", type: "command" },
248
- { dir: ".claude/agents", type: "subagent" },
249
- { dir: ".claude/hooks", type: "hook" },
250
- { dir: "prompts", type: "prompt" },
251
- { dir: ".ai", type: "custom" }
292
+ { dir: ".cursor/rules", type: "rule", group: "cursor" },
293
+ { dir: ".claude/commands", type: "command", group: "claude-code" },
294
+ { dir: ".claude/agents", type: "subagent", group: "claude-code" },
295
+ { dir: ".claude/hooks", type: "hook", group: "claude-code" },
296
+ { dir: "prompts", type: "prompt", group: "generic" },
297
+ { dir: ".ai", type: "custom", group: "generic" }
252
298
  ];
253
299
  function loadGitignore(cwd) {
254
300
  const ig = ignore();
@@ -298,12 +344,13 @@ function scanLocal(cwd) {
298
344
  relativePath: rel,
299
345
  content,
300
346
  type: pattern.type,
301
- source: "local"
347
+ source: "local",
348
+ group: pattern.group
302
349
  });
303
350
  }
304
351
  }
305
352
  }
306
- for (const { dir, type } of LOCAL_DIR_PATTERNS) {
353
+ for (const { dir, type, group } of LOCAL_DIR_PATTERNS) {
307
354
  const dirPath = join2(cwd, dir);
308
355
  const files = walkDir(dirPath);
309
356
  for (const filePath of files) {
@@ -316,7 +363,8 @@ function scanLocal(cwd) {
316
363
  relativePath: rel,
317
364
  content,
318
365
  type,
319
- source: "local"
366
+ source: "local",
367
+ group
320
368
  });
321
369
  }
322
370
  }
@@ -347,7 +395,8 @@ function scanSkillDirs(dir, cwd, ig, results, depth) {
347
395
  relativePath: rel,
348
396
  content,
349
397
  type: "skill",
350
- source: "local"
398
+ source: "local",
399
+ group: "generic"
351
400
  });
352
401
  }
353
402
  }
@@ -369,11 +418,11 @@ function scanGlobal() {
369
418
  const home = homedir2();
370
419
  const results = [];
371
420
  const globalPatterns = [
372
- { path: ".claude/CLAUDE.md", type: "rule" },
373
- { path: ".claude/settings.json", type: "config" },
374
- { path: ".cursor/mcp.json", type: "mcp" },
375
- { path: ".continue/config.json", type: "config" },
376
- { path: ".aider.conf.yml", type: "config" }
421
+ { path: ".claude/CLAUDE.md", type: "rule", group: "claude-code" },
422
+ { path: ".claude/settings.json", type: "config", group: "claude-code" },
423
+ { path: ".cursor/mcp.json", type: "mcp", group: "cursor" },
424
+ { path: ".continue/config.json", type: "config", group: "continue" },
425
+ { path: ".aider.conf.yml", type: "config", group: "aider" }
377
426
  ];
378
427
  for (const pattern of globalPatterns) {
379
428
  const filePath = join2(home, pattern.path);
@@ -384,17 +433,18 @@ function scanGlobal() {
384
433
  relativePath: `~/${pattern.path}`,
385
434
  content,
386
435
  type: pattern.type,
387
- source: "global"
436
+ source: "global",
437
+ group: pattern.group
388
438
  });
389
439
  }
390
440
  }
391
441
  const globalDirs = [
392
- { dir: ".claude/commands", type: "command" },
393
- { dir: ".claude/agents", type: "subagent" },
394
- { dir: ".claude/hooks", type: "hook" },
395
- { dir: ".cursor/rules", type: "rule" }
442
+ { dir: ".claude/commands", type: "command", group: "claude-code" },
443
+ { dir: ".claude/agents", type: "subagent", group: "claude-code" },
444
+ { dir: ".claude/hooks", type: "hook", group: "claude-code" },
445
+ { dir: ".cursor/rules", type: "rule", group: "cursor" }
396
446
  ];
397
- for (const { dir, type } of globalDirs) {
447
+ for (const { dir, type, group } of globalDirs) {
398
448
  const dirPath = join2(home, dir);
399
449
  const files = walkDir(dirPath, 2);
400
450
  for (const filePath of files) {
@@ -405,7 +455,8 @@ function scanGlobal() {
405
455
  relativePath: `~/${relative(home, filePath)}`,
406
456
  content,
407
457
  type,
408
- source: "global"
458
+ source: "global",
459
+ group
409
460
  });
410
461
  }
411
462
  }
@@ -415,45 +466,75 @@ function scanGlobal() {
415
466
 
416
467
  // src/classifier.ts
417
468
  import { basename, dirname } from "path";
469
+
470
+ // src/stableKey.ts
471
+ function computeStableKey(group, type, relPath) {
472
+ return `${group}:${type}:${relPath}`;
473
+ }
474
+
475
+ // src/classifier.ts
418
476
  function classify(files) {
419
- const skillDirs = /* @__PURE__ */ new Map();
420
- const nonSkillFiles = [];
477
+ const groups = /* @__PURE__ */ new Map();
478
+ const singletons = [];
479
+ const singletonRoots = /* @__PURE__ */ new Set([
480
+ ".",
481
+ "~",
482
+ "~/.claude",
483
+ "~/.cursor",
484
+ "~/.continue",
485
+ ".claude",
486
+ ".cursor",
487
+ ".github"
488
+ ]);
421
489
  for (const file of files) {
422
- if (file.type === "skill") {
423
- const dir = dirname(file.relativePath);
424
- const existing = skillDirs.get(dir) ?? [];
425
- existing.push(file);
426
- skillDirs.set(dir, existing);
490
+ const dir = dirname(file.relativePath);
491
+ const isSingleton = singletonRoots.has(dir);
492
+ if (isSingleton) {
493
+ singletons.push(file);
427
494
  } else {
428
- nonSkillFiles.push(file);
495
+ const key = `${file.group}:${file.source}:${file.type}:${dir}`;
496
+ const existing = groups.get(key) ?? [];
497
+ existing.push(file);
498
+ groups.set(key, existing);
429
499
  }
430
500
  }
431
501
  const items = [];
432
- for (const file of nonSkillFiles) {
433
- const tags = file.source === "global" ? ["global"] : void 0;
502
+ const scope = (source) => source === "global" ? "global" : "project";
503
+ for (const file of singletons) {
504
+ const s = scope(file.source);
505
+ const relPath = file.relativePath.replace(/^~\/\.[^/]+\//, "").replace(/^\.[^/]+\//, "");
434
506
  items.push({
435
507
  type: file.type,
436
508
  name: file.relativePath,
509
+ group: file.group,
510
+ scope: s,
511
+ stableKey: computeStableKey(file.group, file.type, relPath),
437
512
  files: [
438
513
  {
439
514
  name: basename(file.relativePath),
440
515
  content: file.content,
441
- path: file.relativePath,
442
- tags
516
+ path: file.relativePath
443
517
  }
444
518
  ]
445
519
  });
446
520
  }
447
- for (const [dir, dirFiles] of skillDirs) {
448
- const isGlobal = dirFiles[0]?.source === "global";
521
+ for (const [, groupFiles] of groups) {
522
+ const first = groupFiles[0];
523
+ const dir = dirname(first.relativePath);
524
+ const s = scope(first.source);
525
+ const relPath = dir.replace(/^~\/\.claude\//, "").replace(/^\.claude\//, "").replace(/^~\/\.cursor\//, "").replace(/^\.cursor\//, "");
526
+ const typeLabel = first.type === "subagent" ? "subagents" : `${first.type}s`;
449
527
  items.push({
450
- type: "skill",
528
+ type: first.type,
451
529
  name: dir,
452
- files: dirFiles.map((f) => ({
530
+ description: `${groupFiles.length} ${typeLabel}`,
531
+ group: first.group,
532
+ scope: s,
533
+ stableKey: computeStableKey(first.group, first.type, relPath),
534
+ files: groupFiles.map((f) => ({
453
535
  name: basename(f.relativePath),
454
536
  content: f.content,
455
- path: f.relativePath,
456
- tags: isGlobal ? ["global"] : void 0
537
+ path: f.relativePath
457
538
  }))
458
539
  });
459
540
  }
@@ -462,38 +543,41 @@ function classify(files) {
462
543
 
463
544
  // src/commands/collect.ts
464
545
  async function collectCommand(options) {
465
- p2.intro(banner("collect"));
546
+ intro2("collect");
466
547
  const token = getToken();
467
548
  if (!token) {
468
- p2.log.error(`Not authenticated. Run ${limeBold("aistack login")} first.`);
549
+ p3.log.error(
550
+ `Not authenticated. Run ${limeBold("npx @use-aistack/cli login")} first.`
551
+ );
552
+ outroError("not authenticated");
469
553
  process.exit(1);
470
554
  }
471
555
  const cwd = process.cwd();
472
556
  const savedName = getProjectName(cwd);
473
557
  const savedExcluded = getExcludedPaths(cwd);
474
- const s = p2.spinner();
558
+ const s = p3.spinner();
475
559
  s.start("Scanning...");
476
560
  const localFiles = scanLocal(cwd);
477
561
  const globalFiles = options.global ? scanGlobal() : [];
478
562
  s.stop("Scan complete");
479
563
  if (localFiles.length === 0 && globalFiles.length === 0) {
480
- p2.log.warn("No AI configuration files found.");
481
- p2.outro(dim("nothing to collect"));
564
+ p3.log.warn("No AI configuration files found.");
565
+ outroSkipped("nothing to collect");
482
566
  return;
483
567
  }
484
568
  let projectName;
485
569
  if (savedName) {
486
- p2.log.info(`${dim("PROJECT")} ${limeBold(savedName)}`);
570
+ p3.log.info(`${dim("PROJECT")} ${limeBold(savedName)}`);
487
571
  projectName = savedName;
488
572
  } else {
489
573
  const defaultName = basename2(cwd);
490
- const name = await p2.text({
574
+ const name = await p3.text({
491
575
  message: "Project name:",
492
576
  defaultValue: defaultName,
493
577
  placeholder: defaultName
494
578
  });
495
- if (p2.isCancel(name)) {
496
- p2.cancel("Cancelled.");
579
+ if (p3.isCancel(name)) {
580
+ outroCancel();
497
581
  process.exit(0);
498
582
  }
499
583
  projectName = name || defaultName;
@@ -503,10 +587,10 @@ async function collectCommand(options) {
503
587
  (f) => !savedExcluded.includes(f.relativePath)
504
588
  );
505
589
  let excluded = allFiles.filter((f) => savedExcluded.includes(f.relativePath));
506
- p2.log.info(
590
+ p3.log.info(
507
591
  `${lime(String(selectedFiles.length))} included${excluded.length > 0 ? ` \xB7 ${dim(String(excluded.length) + " excluded")}` : ""}`
508
592
  );
509
- let allInstructions = classify(selectedFiles);
593
+ let allResources = classify(selectedFiles);
510
594
  let existingProject = null;
511
595
  try {
512
596
  const check = await projectsCheck(token, projectName);
@@ -515,17 +599,15 @@ async function collectCommand(options) {
515
599
  existingProject = await projectGet(shortId);
516
600
  }
517
601
  } catch (err) {
518
- p2.log.error(err instanceof Error ? err.message : String(err));
602
+ p3.log.error(err instanceof Error ? err.message : String(err));
603
+ outroError("error");
519
604
  process.exit(1);
520
605
  }
521
606
  if (existingProject) {
522
- const diff = diffInstructions(
523
- allInstructions,
524
- existingProject.instructions
525
- );
607
+ const diff = diffResources(allResources, existingProject.resources);
526
608
  if (diff.changed === 0 && diff.added === 0 && diff.removed === 0) {
527
- p2.log.info("No changes since last collect.");
528
- p2.outro(dim("nothing to upload"));
609
+ p3.log.info("No changes since last collect.");
610
+ outroSkipped("nothing to upload");
529
611
  return;
530
612
  }
531
613
  divider();
@@ -545,7 +627,7 @@ async function collectCommand(options) {
545
627
  const local = selectedFiles.filter((f) => f.source === "local");
546
628
  const global = selectedFiles.filter((f) => f.source === "global");
547
629
  if (local.length > 0) {
548
- p2.log.step(`${bold("LOCAL")} ${dim(String(local.length))}`);
630
+ p3.log.step(`${bold("LOCAL")} ${dim(String(local.length))}`);
549
631
  divider();
550
632
  for (const [type, files] of groupByType(local)) {
551
633
  lines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);
@@ -554,7 +636,7 @@ async function collectCommand(options) {
554
636
  divider();
555
637
  }
556
638
  if (global.length > 0) {
557
- p2.log.step(`${bold("GLOBAL")} ${dim(String(global.length))}`);
639
+ p3.log.step(`${bold("GLOBAL")} ${dim(String(global.length))}`);
558
640
  divider();
559
641
  for (const [type, files] of groupByType(global)) {
560
642
  lines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);
@@ -563,7 +645,7 @@ async function collectCommand(options) {
563
645
  divider();
564
646
  }
565
647
  }
566
- const action = await p2.select({
648
+ const action = await p3.select({
567
649
  message: existingProject ? "Upload changes?" : `Upload ${bold(String(selectedFiles.length))} files as ${limeBold(projectName)}?`,
568
650
  options: [
569
651
  { value: "upload", label: "Upload" },
@@ -571,12 +653,12 @@ async function collectCommand(options) {
571
653
  { value: "cancel", label: "Cancel" }
572
654
  ]
573
655
  });
574
- if (p2.isCancel(action) || action === "cancel") {
575
- p2.cancel("Cancelled.");
656
+ if (p3.isCancel(action) || action === "cancel") {
657
+ outroCancel();
576
658
  process.exit(0);
577
659
  }
578
660
  if (action === "customize") {
579
- const selected = await p2.multiselect({
661
+ const selected = await p3.multiselect({
580
662
  message: "Select files to include:",
581
663
  options: allFiles.map((f) => ({
582
664
  value: f.relativePath,
@@ -585,17 +667,17 @@ async function collectCommand(options) {
585
667
  })),
586
668
  initialValues: selectedFiles.map((f) => f.relativePath)
587
669
  });
588
- if (p2.isCancel(selected)) {
589
- p2.cancel("Cancelled.");
670
+ if (p3.isCancel(selected)) {
671
+ outroCancel();
590
672
  process.exit(0);
591
673
  }
592
674
  const selectedSet = new Set(selected);
593
675
  selectedFiles = allFiles.filter((f) => selectedSet.has(f.relativePath));
594
676
  excluded = allFiles.filter((f) => !selectedSet.has(f.relativePath));
595
- allInstructions = classify(selectedFiles);
677
+ allResources = classify(selectedFiles);
596
678
  if (selectedFiles.length === 0) {
597
- p2.log.warn("No files selected.");
598
- p2.outro(dim("nothing to collect"));
679
+ p3.log.warn("No files selected.");
680
+ outroSkipped("nothing to collect");
599
681
  process.exit(0);
600
682
  }
601
683
  }
@@ -603,7 +685,7 @@ async function collectCommand(options) {
603
685
  try {
604
686
  const result = await projectsCollect(token, {
605
687
  name: projectName,
606
- instructions: allInstructions
688
+ resources: allResources
607
689
  });
608
690
  s.stop(lime("Uploaded"));
609
691
  saveProjectSettings(
@@ -611,11 +693,12 @@ async function collectCommand(options) {
611
693
  projectName,
612
694
  excluded.map((f) => f.relativePath)
613
695
  );
614
- p2.log.success(dim(result.url));
615
- p2.outro(lime("done"));
696
+ p3.log.success(dim(result.url));
697
+ outro2(lime("done"));
616
698
  } catch (err) {
617
699
  s.stop("Upload failed");
618
- p2.log.error(err instanceof Error ? err.message : String(err));
700
+ p3.log.error(err instanceof Error ? err.message : String(err));
701
+ outroError("upload failed");
619
702
  process.exit(1);
620
703
  }
621
704
  }
@@ -647,7 +730,7 @@ function groupByType(files) {
647
730
  }
648
731
  return sorted;
649
732
  }
650
- function diffInstructions(current, existing) {
733
+ function diffResources(current, existing) {
651
734
  const existingMap = /* @__PURE__ */ new Map();
652
735
  for (const item of existing) {
653
736
  for (const file of item.files) {
@@ -687,12 +770,12 @@ function diffInstructions(current, existing) {
687
770
  }
688
771
 
689
772
  // src/commands/create.ts
690
- import * as p3 from "@clack/prompts";
773
+ import * as p4 from "@clack/prompts";
691
774
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
692
775
  import { dirname as dirname2, join as join3 } from "path";
693
776
  async function createCommand(slugOrShortId) {
694
- p3.intro(banner("create"));
695
- const s = p3.spinner();
777
+ intro2("create");
778
+ const s = p4.spinner();
696
779
  s.start("Fetching project...");
697
780
  const shortId = slugOrShortId.includes("-") ? slugOrShortId.slice(slugOrShortId.lastIndexOf("-") + 1) : slugOrShortId;
698
781
  let project;
@@ -700,21 +783,23 @@ async function createCommand(slugOrShortId) {
700
783
  project = await projectGet(shortId);
701
784
  if (!project) {
702
785
  s.stop("Not found");
703
- p3.log.error(`Project "${slugOrShortId}" not found.`);
786
+ p4.log.error(`Project "${slugOrShortId}" not found.`);
787
+ outroError("not found");
704
788
  process.exit(1);
705
789
  }
706
790
  s.stop(bold(project.name));
707
791
  } catch (err) {
708
792
  s.stop("Failed to fetch project");
709
- p3.log.error(err instanceof Error ? err.message : String(err));
793
+ p4.log.error(err instanceof Error ? err.message : String(err));
794
+ outroError("error");
710
795
  process.exit(1);
711
796
  }
712
797
  const localFiles = [];
713
798
  const globalFiles = [];
714
- for (const item of project.instructions) {
799
+ for (const item of project.resources) {
800
+ const isGlobal = item.scope === "global";
715
801
  for (const file of item.files) {
716
802
  const writePath = file.path ?? file.name;
717
- const isGlobal = file.tags?.includes("global");
718
803
  if (isGlobal) {
719
804
  globalFiles.push({ path: writePath, content: file.content });
720
805
  } else {
@@ -728,8 +813,8 @@ async function createCommand(slugOrShortId) {
728
813
  lines(globalFiles.map((f) => dim(f.path)));
729
814
  }
730
815
  if (localFiles.length === 0) {
731
- p3.log.warn("No local files to write.");
732
- p3.outro(dim("nothing to create"));
816
+ p4.log.warn("No local files to write.");
817
+ outroSkipped("nothing to create");
733
818
  return;
734
819
  }
735
820
  const cwd = process.cwd();
@@ -753,16 +838,16 @@ async function createCommand(slugOrShortId) {
753
838
  );
754
839
  if (toWrite.length === 0) {
755
840
  divider();
756
- p3.log.info("All local files already exist.");
757
- p3.outro(dim("nothing to write"));
841
+ p4.log.info("All local files already exist.");
842
+ outroSkipped("nothing to write");
758
843
  return;
759
844
  }
760
845
  divider();
761
- const confirm2 = await p3.confirm({
846
+ const confirm2 = await p4.confirm({
762
847
  message: `Write ${lime(String(toWrite.length))} new files? ${dim(`(${skipped.length} skipped)`)}`
763
848
  });
764
- if (p3.isCancel(confirm2) || !confirm2) {
765
- p3.cancel("Cancelled.");
849
+ if (p4.isCancel(confirm2) || !confirm2) {
850
+ outroCancel();
766
851
  process.exit(0);
767
852
  }
768
853
  for (const f of toWrite) {
@@ -771,10 +856,10 @@ async function createCommand(slugOrShortId) {
771
856
  mkdirSync2(dir, { recursive: true });
772
857
  writeFileSync2(fullPath, f.content);
773
858
  }
774
- p3.log.success(
859
+ p4.log.success(
775
860
  `${lime(String(toWrite.length))} written, ${dim(String(skipped.length) + " skipped")}`
776
861
  );
777
- p3.outro(lime("done"));
862
+ outro2(lime("done"));
778
863
  }
779
864
 
780
865
  // src/index.ts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/api.ts","../src/config.ts","../src/theme.ts","../src/commands/collect.ts","../src/scanner.ts","../src/classifier.ts","../src/commands/create.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { collectCommand } from \"./commands/collect.js\";\nimport { createCommand } from \"./commands/create.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"aistack\")\n\t.description(\"Share and clone AI development configurations\")\n\t.version(\"0.1.0\");\n\nprogram\n\t.command(\"login\")\n\t.description(\"Authenticate with AI Stack\")\n\t.action(loginCommand);\n\nprogram\n\t.command(\"collect\")\n\t.description(\"Scan and upload AI config files from your project\")\n\t.option(\"--no-global\", \"Exclude global config files (~/.claude, etc.)\")\n\t.action((options) => collectCommand({ global: options.global ?? true }));\n\nprogram\n\t.command(\"create\")\n\t.description(\"Download and write AI config files from a shared project\")\n\t.argument(\"<slug>\", \"Project slug or short ID\")\n\t.action(createCommand);\n\nprogram.parse();\n","import * as p from \"@clack/prompts\";\nimport open from \"open\";\nimport { authStart, authPoll } from \"../api.js\";\nimport { saveToken } from \"../config.js\";\nimport { banner, dim, lime, limeBold } from \"../theme.js\";\n\nexport async function loginCommand() {\n\tp.intro(banner(\"login\"));\n\n\tconst s = p.spinner();\n\ts.start(\"Starting authentication...\");\n\n\tlet session: Awaited<ReturnType<typeof authStart>>;\n\ttry {\n\t\tsession = await authStart();\n\t\ts.stop(\"Session created\");\n\t} catch (err) {\n\t\ts.stop(\"Failed to start authentication\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\tprocess.exit(1);\n\t}\n\n\tp.log.info(`${dim(\"CODE\")} ${limeBold(session.userCode)}`);\n\tp.log.info(`${dim(\"OPEN\")} ${dim(session.authUrl)}`);\n\n\ttry {\n\t\tawait open(session.authUrl);\n\t} catch {\n\t\tp.log.warn(\n\t\t\t\"Could not open browser automatically. Please visit the URL above.\",\n\t\t);\n\t}\n\n\ts.start(\"Waiting for approval...\");\n\n\tconst maxAttempts = 36;\n\tfor (let i = 0; i < maxAttempts; i++) {\n\t\tawait new Promise((resolve) => setTimeout(resolve, 5000));\n\n\t\ttry {\n\t\t\tconst result = await authPoll(session.secretId);\n\n\t\t\tif (result.status === \"approved\" && result.token) {\n\t\t\t\ts.stop(lime(\"Authenticated\"));\n\t\t\t\tsaveToken(result.token, result.userId);\n\t\t\t\tp.log.success(\n\t\t\t\t\t`Token saved. Run ${limeBold(\"aistack collect\")} to get started.`,\n\t\t\t\t);\n\t\t\t\tp.outro(lime(\"done\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (result.status === \"expired\") {\n\t\t\t\ts.stop(\"Session expired\");\n\t\t\t\tp.log.error(\"Authentication session expired. Please try again.\");\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\ts.stop(\"Error polling\");\n\t\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\ts.stop(\"Timed out\");\n\tp.log.error(\"Authentication timed out after 3 minutes. Please try again.\");\n\tprocess.exit(1);\n}\n","const BASE_URL = process.env.AISTACK_URL || \"https://aistack.to\";\n\nasync function request(\n\tpath: string,\n\toptions: RequestInit = {},\n): Promise<Response> {\n\treturn fetch(`${BASE_URL}${path}`, {\n\t\t...options,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t...options.headers,\n\t\t},\n\t});\n}\n\nfunction authHeaders(token: string): HeadersInit {\n\treturn { Authorization: `Bearer ${token}` };\n}\n\nexport async function authStart(): Promise<{\n\tsecretId: string;\n\tuserCode: string;\n\tauthUrl: string;\n}> {\n\tconst res = await request(\"/api/cli/auth/start\", { method: \"POST\" });\n\tif (!res.ok) throw new Error(`Auth start failed: ${res.status}`);\n\treturn res.json();\n}\n\nexport async function authPoll(\n\tsecretId: string,\n): Promise<{ status: string; token?: string; userId?: string }> {\n\tconst res = await request(\n\t\t`/api/cli/auth/poll?secretId=${encodeURIComponent(secretId)}`,\n\t);\n\tif (!res.ok) throw new Error(`Auth poll failed: ${res.status}`);\n\treturn res.json();\n}\n\nexport async function projectsCheck(\n\ttoken: string,\n\tname: string,\n): Promise<{ exists: boolean; slug?: string }> {\n\tconst res = await request(\n\t\t`/api/cli/projects/check?name=${encodeURIComponent(name)}`,\n\t\t{\n\t\t\theaders: authHeaders(token),\n\t\t},\n\t);\n\tif (res.status === 401)\n\t\tthrow new Error(\"Authentication expired. Run `aistack login` again.\");\n\tif (!res.ok) throw new Error(`Project check failed: ${res.status}`);\n\treturn res.json();\n}\n\nexport async function projectsCollect(\n\ttoken: string,\n\tdata: { name: string; instructions: InstructionItem[] },\n): Promise<{ slug: string; shortId: string; url: string }> {\n\tconst res = await request(\"/api/cli/projects/collect\", {\n\t\tmethod: \"POST\",\n\t\theaders: authHeaders(token),\n\t\tbody: JSON.stringify(data),\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\"Authentication expired. Run `aistack login` again.\");\n\tif (!res.ok) {\n\t\tconst body = await res.json().catch(() => ({}));\n\t\tthrow new Error(\n\t\t\t(body as { error?: string }).error || `Collect failed: ${res.status}`,\n\t\t);\n\t}\n\treturn res.json();\n}\n\nexport async function projectGet(shortId: string): Promise<ProjectData | null> {\n\tconst res = await request(`/api/cli/projects/${encodeURIComponent(shortId)}`);\n\tif (res.status === 404) return null;\n\tif (!res.ok) throw new Error(`Project fetch failed: ${res.status}`);\n\treturn res.json();\n}\n\n// Types used across the CLI\nexport interface InstructionFile {\n\tname: string;\n\tcontent: string;\n\tpath?: string;\n\ttags?: string[];\n}\n\nexport interface InstructionItem {\n\ttype: string;\n\tname: string;\n\tdescription?: string;\n\tfiles: InstructionFile[];\n}\n\nexport interface ProjectData {\n\tname: string;\n\tslug: string;\n\tshortId: string;\n\tinstructions: InstructionItem[];\n\tcreator?: { name: string };\n\tstack?: { name: string; slug: string };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst CONFIG_DIR = join(homedir(), \".config\", \"aistack\");\nconst CREDENTIALS_FILE = join(CONFIG_DIR, \"credentials.json\");\n\ninterface Credentials {\n\ttoken: string;\n\tuserId?: string;\n}\n\nexport function getToken(): string | null {\n\tif (!existsSync(CREDENTIALS_FILE)) return null;\n\ttry {\n\t\tconst data = JSON.parse(\n\t\t\treadFileSync(CREDENTIALS_FILE, \"utf-8\"),\n\t\t) as Credentials;\n\t\treturn data.token ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function saveToken(token: string, userId?: string): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(CREDENTIALS_FILE, JSON.stringify({ token, userId }, null, 2));\n}\n\nexport function clearToken(): void {\n\tif (existsSync(CREDENTIALS_FILE)) {\n\t\twriteFileSync(CREDENTIALS_FILE, \"{}\");\n\t}\n}\n\nconst PROJECTS_FILE = join(CONFIG_DIR, \"projects.json\");\n\ninterface ProjectEntry {\n\tname: string;\n\texcluded?: string[];\n}\n\ninterface ProjectsData {\n\t[directory: string]: ProjectEntry;\n}\n\nfunction readProjects(): ProjectsData {\n\tif (!existsSync(PROJECTS_FILE)) return {};\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(PROJECTS_FILE, \"utf-8\"));\n\t\t// Migrate old format (string values) to new format\n\t\tconst data: ProjectsData = {};\n\t\tfor (const [key, value] of Object.entries(raw)) {\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tdata[key] = { name: value };\n\t\t\t} else {\n\t\t\t\tdata[key] = value as ProjectEntry;\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeProjects(data: ProjectsData): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(PROJECTS_FILE, JSON.stringify(data, null, 2));\n}\n\nexport function getProjectName(directory: string): string | null {\n\treturn readProjects()[directory]?.name ?? null;\n}\n\nexport function getExcludedPaths(directory: string): string[] {\n\treturn readProjects()[directory]?.excluded ?? [];\n}\n\nexport function saveProjectSettings(\n\tdirectory: string,\n\tname: string,\n\texcluded: string[],\n): void {\n\tconst data = readProjects();\n\tdata[directory] = {\n\t\tname,\n\t\texcluded: excluded.length > 0 ? excluded : undefined,\n\t};\n\twriteProjects(data);\n}\n","const esc = (code: string) => `\\x1b[${code}m`;\nconst reset = esc(\"0\");\n\nconst LIME = \"163;230;53\";\nconst BLACK = \"0;0;0\";\nconst YELLOW = \"250;204;21\";\nconst RED = \"248;113;113\";\nconst MUTED = \"120;120;120\";\n\nexport const lime = (s: string) => `${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const limeBold = (s: string) =>\n\t`${esc(\"1\")}${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const bgLime = (s: string) =>\n\t`${esc(`48;2;${LIME}`)}${esc(`38;2;${BLACK}`)}${s}${reset}`;\nexport const yellow = (s: string) => `${esc(`38;2;${YELLOW}`)}${s}${reset}`;\nexport const red = (s: string) => `${esc(`38;2;${RED}`)}${s}${reset}`;\nexport const dim = (s: string) => `${esc(`38;2;${MUTED}`)}${s}${reset}`;\nexport const bold = (s: string) => `${esc(\"1\")}${s}${reset}`;\n\n// ■ logo square in lime + AISTACK in bold on lime bg\nexport const banner = (cmd: string) =>\n\t`${lime(\"■\")} ${bgLime(` AISTACK `)} ${bold(cmd.toUpperCase())}`;\n\n// Compact line with clack-style bar\nconst BAR = `${esc(`38;2;${MUTED}`)}│${reset}`;\n\nexport function lines(items: string[]) {\n\tfor (const item of items) {\n\t\tconsole.log(`${BAR} ${item}`);\n\t}\n}\n\nexport function section(label: string, count?: number) {\n\tconsole.log(`${BAR}`);\n\tconst countStr = count !== undefined ? ` ${dim(String(count))}` : \"\";\n\tconsole.log(`${BAR} ${bold(label.toUpperCase())}${countStr}`);\n}\n\nexport function divider() {\n\tconsole.log(`${BAR} ${dim(\"─\".repeat(40))}`);\n}\n","import * as p from \"@clack/prompts\";\nimport { basename } from \"node:path\";\nimport { scanLocal, scanGlobal, type ScannedFile } from \"../scanner.js\";\nimport { classify } from \"../classifier.js\";\nimport {\n\tprojectsCheck,\n\tprojectsCollect,\n\tprojectGet,\n\ttype InstructionItem,\n} from \"../api.js\";\nimport {\n\tgetToken,\n\tgetProjectName,\n\tgetExcludedPaths,\n\tsaveProjectSettings,\n} from \"../config.js\";\nimport {\n\tbanner,\n\tbold,\n\tdim,\n\tdivider,\n\tlime,\n\tlimeBold,\n\tlines,\n\tred,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\nexport async function collectCommand(options: { global: boolean }) {\n\tp.intro(banner(\"collect\"));\n\n\tconst token = getToken();\n\tif (!token) {\n\t\tp.log.error(`Not authenticated. Run ${limeBold(\"aistack login\")} first.`);\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst savedName = getProjectName(cwd);\n\tconst savedExcluded = getExcludedPaths(cwd);\n\n\tconst s = p.spinner();\n\ts.start(\"Scanning...\");\n\n\tconst localFiles = scanLocal(cwd);\n\tconst globalFiles = options.global ? scanGlobal() : [];\n\ts.stop(\"Scan complete\");\n\n\tif (localFiles.length === 0 && globalFiles.length === 0) {\n\t\tp.log.warn(\"No AI configuration files found.\");\n\t\tp.outro(dim(\"nothing to collect\"));\n\t\treturn;\n\t}\n\n\t// Project name\n\tlet projectName: string;\n\tif (savedName) {\n\t\tp.log.info(`${dim(\"PROJECT\")} ${limeBold(savedName)}`);\n\t\tprojectName = savedName;\n\t} else {\n\t\tconst defaultName = basename(cwd);\n\t\tconst name = await p.text({\n\t\t\tmessage: \"Project name:\",\n\t\t\tdefaultValue: defaultName,\n\t\t\tplaceholder: defaultName,\n\t\t});\n\t\tif (p.isCancel(name)) {\n\t\t\tp.cancel(\"Cancelled.\");\n\t\t\tprocess.exit(0);\n\t\t}\n\t\tprojectName = (name as string) || defaultName;\n\t}\n\n\t// Apply saved exclusions\n\tconst allFiles = [...localFiles, ...globalFiles];\n\tlet selectedFiles = allFiles.filter(\n\t\t(f) => !savedExcluded.includes(f.relativePath),\n\t);\n\tlet excluded = allFiles.filter((f) => savedExcluded.includes(f.relativePath));\n\n\t// Show file counts\n\tp.log.info(\n\t\t`${lime(String(selectedFiles.length))} included${excluded.length > 0 ? ` · ${dim(String(excluded.length) + \" excluded\")}` : \"\"}`,\n\t);\n\n\t// Classify selected files\n\tlet allInstructions = classify(selectedFiles);\n\n\t// Fetch existing project and diff\n\tlet existingProject: Awaited<ReturnType<typeof projectGet>> = null;\n\ttry {\n\t\tconst check = await projectsCheck(token, projectName);\n\t\tif (check.exists && check.slug) {\n\t\t\tconst shortId = check.slug.includes(\"-\")\n\t\t\t\t? check.slug.slice(check.slug.lastIndexOf(\"-\") + 1)\n\t\t\t\t: check.slug;\n\t\t\texistingProject = await projectGet(shortId);\n\t\t}\n\t} catch (err) {\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\tprocess.exit(1);\n\t}\n\n\t// Show file list or diff\n\tif (existingProject) {\n\t\tconst diff = diffInstructions(\n\t\t\tallInstructions,\n\t\t\texistingProject.instructions,\n\t\t);\n\n\t\tif (diff.changed === 0 && diff.added === 0 && diff.removed === 0) {\n\t\t\tp.log.info(\"No changes since last collect.\");\n\t\t\tp.outro(dim(\"nothing to upload\"));\n\t\t\treturn;\n\t\t}\n\n\t\tdivider();\n\t\tsection(\"changes\");\n\t\tlines(\n\t\t\tdiff.details.map((f) => {\n\t\t\t\tif (f.status === \"added\") return lime(`+ ${f.name}`);\n\t\t\t\tif (f.status === \"changed\") return yellow(`~ ${f.name}`);\n\t\t\t\treturn red(`- ${f.name}`);\n\t\t\t}),\n\t\t);\n\t\tif (diff.unchanged > 0) {\n\t\t\tlines([dim(`${diff.unchanged} unchanged`)]);\n\t\t}\n\t\tdivider();\n\t} else {\n\t\tconst local = selectedFiles.filter((f) => f.source === \"local\");\n\t\tconst global = selectedFiles.filter((f) => f.source === \"global\");\n\n\t\tif (local.length > 0) {\n\t\t\tp.log.step(`${bold(\"LOCAL\")} ${dim(String(local.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(local)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t\tif (global.length > 0) {\n\t\t\tp.log.step(`${bold(\"GLOBAL\")} ${dim(String(global.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(global)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t}\n\n\t// Action: upload, customize, or cancel\n\tconst action = await p.select({\n\t\tmessage: existingProject\n\t\t\t? \"Upload changes?\"\n\t\t\t: `Upload ${bold(String(selectedFiles.length))} files as ${limeBold(projectName)}?`,\n\t\toptions: [\n\t\t\t{ value: \"upload\", label: \"Upload\" },\n\t\t\t{ value: \"customize\", label: \"Select files\" },\n\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(action) || action === \"cancel\") {\n\t\tp.cancel(\"Cancelled.\");\n\t\tprocess.exit(0);\n\t}\n\n\tif (action === \"customize\") {\n\t\tconst selected = await p.multiselect({\n\t\t\tmessage: \"Select files to include:\",\n\t\t\toptions: allFiles.map((f) => ({\n\t\t\t\tvalue: f.relativePath,\n\t\t\t\tlabel: f.relativePath,\n\t\t\t\thint: `${f.type}${f.source === \"global\" ? \" · global\" : \"\"}`,\n\t\t\t})),\n\t\t\tinitialValues: selectedFiles.map((f) => f.relativePath),\n\t\t});\n\n\t\tif (p.isCancel(selected)) {\n\t\t\tp.cancel(\"Cancelled.\");\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\tconst selectedSet = new Set(selected as string[]);\n\t\tselectedFiles = allFiles.filter((f) => selectedSet.has(f.relativePath));\n\t\texcluded = allFiles.filter((f) => !selectedSet.has(f.relativePath));\n\t\tallInstructions = classify(selectedFiles);\n\n\t\tif (selectedFiles.length === 0) {\n\t\t\tp.log.warn(\"No files selected.\");\n\t\t\tp.outro(dim(\"nothing to collect\"));\n\t\t\tprocess.exit(0);\n\t\t}\n\t}\n\n\ts.start(\"Uploading...\");\n\ttry {\n\t\tconst result = await projectsCollect(token, {\n\t\t\tname: projectName,\n\t\t\tinstructions: allInstructions,\n\t\t});\n\t\ts.stop(lime(\"Uploaded\"));\n\t\tsaveProjectSettings(\n\t\t\tcwd,\n\t\t\tprojectName,\n\t\t\texcluded.map((f) => f.relativePath),\n\t\t);\n\t\tp.log.success(dim(result.url));\n\t\tp.outro(lime(\"done\"));\n\t} catch (err) {\n\t\ts.stop(\"Upload failed\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\tprocess.exit(1);\n\t}\n}\n\nconst TYPE_ORDER = [\n\t\"config\",\n\t\"prompt\",\n\t\"rule\",\n\t\"command\",\n\t\"skill\",\n\t\"subagent\",\n\t\"mcp\",\n\t\"hook\",\n\t\"custom\",\n];\n\nfunction groupByType(files: ScannedFile[]): Map<string, ScannedFile[]> {\n\tconst map = new Map<string, ScannedFile[]>();\n\tfor (const f of files) {\n\t\tconst existing = map.get(f.type) ?? [];\n\t\texisting.push(f);\n\t\tmap.set(f.type, existing);\n\t}\n\tconst sorted = new Map<string, ScannedFile[]>();\n\tfor (const type of TYPE_ORDER) {\n\t\tconst group = map.get(type);\n\t\tif (group) sorted.set(type, group);\n\t}\n\tfor (const [type, group] of map) {\n\t\tif (!sorted.has(type)) sorted.set(type, group);\n\t}\n\treturn sorted;\n}\n\ninterface DiffResult {\n\tadded: number;\n\tchanged: number;\n\tremoved: number;\n\tunchanged: number;\n\tdetails: Array<{ name: string; status: \"added\" | \"changed\" | \"removed\" }>;\n}\n\nfunction diffInstructions(\n\tcurrent: InstructionItem[],\n\texisting: InstructionItem[],\n): DiffResult {\n\tconst existingMap = new Map<string, string>();\n\tfor (const item of existing) {\n\t\tfor (const file of item.files) {\n\t\t\texistingMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst currentMap = new Map<string, string>();\n\tfor (const item of current) {\n\t\tfor (const file of item.files) {\n\t\t\tcurrentMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst details: DiffResult[\"details\"] = [];\n\tlet added = 0;\n\tlet changed = 0;\n\tlet unchanged = 0;\n\n\tfor (const [key, content] of currentMap) {\n\t\tconst prev = existingMap.get(key);\n\t\tif (prev === undefined) {\n\t\t\tadded++;\n\t\t\tdetails.push({ name: key, status: \"added\" });\n\t\t} else if (prev !== content) {\n\t\t\tchanged++;\n\t\t\tdetails.push({ name: key, status: \"changed\" });\n\t\t} else {\n\t\t\tunchanged++;\n\t\t}\n\t}\n\n\tlet removed = 0;\n\tfor (const key of existingMap.keys()) {\n\t\tif (!currentMap.has(key)) {\n\t\t\tremoved++;\n\t\t\tdetails.push({ name: key, status: \"removed\" });\n\t\t}\n\t}\n\n\treturn { added, changed, removed, unchanged, details };\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport ignore from \"ignore\";\n\nexport type FileType =\n\t| \"rule\"\n\t| \"mcp\"\n\t| \"skill\"\n\t| \"command\"\n\t| \"prompt\"\n\t| \"hook\"\n\t| \"subagent\"\n\t| \"config\"\n\t| \"custom\";\n\nexport interface ScannedFile {\n\tpath: string;\n\trelativePath: string;\n\tcontent: string;\n\ttype: FileType;\n\tsource: \"local\" | \"global\";\n}\n\nconst MAX_FILE_SIZE = 100 * 1024; // 100KB\n\ninterface FilePattern {\n\tpath: string;\n\ttype: FileType;\n}\n\nconst LOCAL_PATTERNS: FilePattern[] = [\n\t// Rules\n\t{ path: \"CLAUDE.md\", type: \"rule\" },\n\t{ path: \"AGENTS.md\", type: \"rule\" },\n\t{ path: \".cursorrules\", type: \"rule\" },\n\t{ path: \".windsurfrules\", type: \"rule\" },\n\t{ path: \".clinerules\", type: \"rule\" },\n\t{ path: \".github/copilot-instructions.md\", type: \"rule\" },\n\t// MCP\n\t{ path: \"mcp.json\", type: \"mcp\" },\n\t{ path: \".cursor/mcp.json\", type: \"mcp\" },\n\t{ path: \"claude_desktop_config.json\", type: \"mcp\" },\n\t// Config\n\t{ path: \".aider.conf.yml\", type: \"config\" },\n\t{ path: \".continue/config.json\", type: \"config\" },\n\t// Config\n\t{ path: \".claude/settings.json\", type: \"config\" },\n\t{ path: \".claude/settings.local.json\", type: \"config\" },\n\t// Prompts\n\t{ path: \"system-prompt.md\", type: \"prompt\" },\n];\n\nconst LOCAL_DIR_PATTERNS: { dir: string; type: FileType }[] = [\n\t{ dir: \".cursor/rules\", type: \"rule\" },\n\t{ dir: \".claude/commands\", type: \"command\" },\n\t{ dir: \".claude/agents\", type: \"subagent\" },\n\t{ dir: \".claude/hooks\", type: \"hook\" },\n\t{ dir: \"prompts\", type: \"prompt\" },\n\t{ dir: \".ai\", type: \"custom\" },\n];\n\nfunction loadGitignore(cwd: string): ReturnType<typeof ignore> {\n\tconst ig = ignore();\n\tconst gitignorePath = join(cwd, \".gitignore\");\n\tif (existsSync(gitignorePath)) {\n\t\tig.add(readFileSync(gitignorePath, \"utf-8\"));\n\t}\n\tig.add([\"node_modules\", \".git\", \"dist\", \"build\", \".next\", \".output\"]);\n\treturn ig;\n}\n\nfunction readFileSafe(filePath: string): string | null {\n\ttry {\n\t\tconst stat = statSync(filePath);\n\t\tif (stat.size > MAX_FILE_SIZE) return null;\n\t\treturn readFileSync(filePath, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction walkDir(dir: string, maxDepth = 3, currentDepth = 0): string[] {\n\tif (currentDepth >= maxDepth || !existsSync(dir)) return [];\n\tconst results: string[] = [];\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tif (entry.isFile()) {\n\t\t\t\tresults.push(fullPath);\n\t\t\t} else if (entry.isDirectory()) {\n\t\t\t\tresults.push(...walkDir(fullPath, maxDepth, currentDepth + 1));\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors, etc */\n\t}\n\treturn results;\n}\n\nexport function scanLocal(cwd: string): ScannedFile[] {\n\tconst ig = loadGitignore(cwd);\n\tconst results: ScannedFile[] = [];\n\n\tfor (const pattern of LOCAL_PATTERNS) {\n\t\tconst filePath = join(cwd, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (!ig.ignores(rel)) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: pattern.type,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const { dir, type } of LOCAL_DIR_PATTERNS) {\n\t\tconst dirPath = join(cwd, dir);\n\t\tconst files = walkDir(dirPath);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Scan for skill directories (dirs with SKILL.md, 3 levels deep)\n\ttry {\n\t\tfor (const entry of readdirSync(cwd, { withFileTypes: true }).filter((e) =>\n\t\t\te.isDirectory(),\n\t\t)) {\n\t\t\tif (ig.ignores(entry.name + \"/\")) continue;\n\t\t\tscanSkillDirs(join(cwd, entry.name), cwd, ig, results, 1);\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n\n\treturn results;\n}\n\nfunction scanSkillDirs(\n\tdir: string,\n\tcwd: string,\n\tig: ReturnType<typeof ignore>,\n\tresults: ScannedFile[],\n\tdepth: number,\n) {\n\tif (depth > 3) return;\n\tconst skillMd = join(dir, \"SKILL.md\");\n\tif (existsSync(skillMd)) {\n\t\tconst files = walkDir(dir, 1);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: \"skill\",\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tconst rel = relative(cwd, join(dir, entry.name));\n\t\t\t\tif (!ig.ignores(rel + \"/\")) {\n\t\t\t\t\tscanSkillDirs(join(dir, entry.name), cwd, ig, results, depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n}\n\nexport function scanGlobal(): ScannedFile[] {\n\tconst home = homedir();\n\tconst results: ScannedFile[] = [];\n\n\tconst globalPatterns: FilePattern[] = [\n\t\t{ path: \".claude/CLAUDE.md\", type: \"rule\" },\n\t\t{ path: \".claude/settings.json\", type: \"config\" },\n\t\t{ path: \".cursor/mcp.json\", type: \"mcp\" },\n\t\t{ path: \".continue/config.json\", type: \"config\" },\n\t\t{ path: \".aider.conf.yml\", type: \"config\" },\n\t];\n\n\tfor (const pattern of globalPatterns) {\n\t\tconst filePath = join(home, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tresults.push({\n\t\t\t\tpath: filePath,\n\t\t\t\trelativePath: `~/${pattern.path}`,\n\t\t\t\tcontent,\n\t\t\t\ttype: pattern.type,\n\t\t\t\tsource: \"global\",\n\t\t\t});\n\t\t}\n\t}\n\n\tconst globalDirs: { dir: string; type: FileType }[] = [\n\t\t{ dir: \".claude/commands\", type: \"command\" },\n\t\t{ dir: \".claude/agents\", type: \"subagent\" },\n\t\t{ dir: \".claude/hooks\", type: \"hook\" },\n\t\t{ dir: \".cursor/rules\", type: \"rule\" },\n\t];\n\n\tfor (const { dir, type } of globalDirs) {\n\t\tconst dirPath = join(home, dir);\n\t\tconst files = walkDir(dirPath, 2);\n\t\tfor (const filePath of files) {\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: `~/${relative(home, filePath)}`,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"global\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n","import type { ScannedFile } from \"./scanner.js\";\nimport type { InstructionItem } from \"./api.js\";\nimport { basename, dirname } from \"node:path\";\n\nexport function classify(files: ScannedFile[]): InstructionItem[] {\n\tconst skillDirs = new Map<string, ScannedFile[]>();\n\tconst nonSkillFiles: ScannedFile[] = [];\n\n\tfor (const file of files) {\n\t\tif (file.type === \"skill\") {\n\t\t\tconst dir = dirname(file.relativePath);\n\t\t\tconst existing = skillDirs.get(dir) ?? [];\n\t\t\texisting.push(file);\n\t\t\tskillDirs.set(dir, existing);\n\t\t} else {\n\t\t\tnonSkillFiles.push(file);\n\t\t}\n\t}\n\n\tconst items: InstructionItem[] = [];\n\n\tfor (const file of nonSkillFiles) {\n\t\tconst tags = file.source === \"global\" ? [\"global\"] : undefined;\n\t\titems.push({\n\t\t\ttype: file.type,\n\t\t\tname: file.relativePath,\n\t\t\tfiles: [\n\t\t\t\t{\n\t\t\t\t\tname: basename(file.relativePath),\n\t\t\t\t\tcontent: file.content,\n\t\t\t\t\tpath: file.relativePath,\n\t\t\t\t\ttags,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n\n\tfor (const [dir, dirFiles] of skillDirs) {\n\t\tconst isGlobal = dirFiles[0]?.source === \"global\";\n\t\titems.push({\n\t\t\ttype: \"skill\",\n\t\t\tname: dir,\n\t\t\tfiles: dirFiles.map((f) => ({\n\t\t\t\tname: basename(f.relativePath),\n\t\t\t\tcontent: f.content,\n\t\t\t\tpath: f.relativePath,\n\t\t\t\ttags: isGlobal ? [\"global\"] : undefined,\n\t\t\t})),\n\t\t});\n\t}\n\n\treturn items;\n}\n\nexport function isGlobalItem(item: InstructionItem): boolean {\n\treturn item.files.some((f) => f.tags?.includes(\"global\"));\n}\n","import * as p from \"@clack/prompts\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { projectGet } from \"../api.js\";\nimport {\n\tbanner,\n\tbold,\n\tdim,\n\tdivider,\n\tlime,\n\tlines,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\nexport async function createCommand(slugOrShortId: string) {\n\tp.intro(banner(\"create\"));\n\n\tconst s = p.spinner();\n\ts.start(\"Fetching project...\");\n\n\tconst shortId = slugOrShortId.includes(\"-\")\n\t\t? slugOrShortId.slice(slugOrShortId.lastIndexOf(\"-\") + 1)\n\t\t: slugOrShortId;\n\n\tlet project: Awaited<ReturnType<typeof projectGet>>;\n\ttry {\n\t\tproject = await projectGet(shortId);\n\t\tif (!project) {\n\t\t\ts.stop(\"Not found\");\n\t\t\tp.log.error(`Project \"${slugOrShortId}\" not found.`);\n\t\t\tprocess.exit(1);\n\t\t}\n\t\ts.stop(bold(project.name));\n\t} catch (err) {\n\t\ts.stop(\"Failed to fetch project\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\tprocess.exit(1);\n\t}\n\n\tconst localFiles: FileToWrite[] = [];\n\tconst globalFiles: FileToWrite[] = [];\n\n\tfor (const item of project.instructions) {\n\t\tfor (const file of item.files) {\n\t\t\tconst writePath = file.path ?? file.name;\n\t\t\tconst isGlobal = file.tags?.includes(\"global\");\n\t\t\tif (isGlobal) {\n\t\t\t\tglobalFiles.push({ path: writePath, content: file.content });\n\t\t\t} else {\n\t\t\t\tlocalFiles.push({ path: writePath, content: file.content });\n\t\t\t}\n\t\t}\n\t}\n\n\tif (globalFiles.length > 0) {\n\t\tsection(\"global config\", globalFiles.length);\n\t\tlines([dim(\"view only\")]);\n\t\tlines(globalFiles.map((f) => dim(f.path)));\n\t}\n\n\tif (localFiles.length === 0) {\n\t\tp.log.warn(\"No local files to write.\");\n\t\tp.outro(dim(\"nothing to create\"));\n\t\treturn;\n\t}\n\n\tconst cwd = process.cwd();\n\tconst toWrite: FileToWrite[] = [];\n\tconst skipped: { path: string; differs: boolean }[] = [];\n\n\tfor (const f of localFiles) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconst existing = readFileSync(fullPath, \"utf-8\");\n\t\t\tskipped.push({ path: f.path, differs: existing !== f.content });\n\t\t} else {\n\t\t\ttoWrite.push(f);\n\t\t}\n\t}\n\n\tsection(\"local files\", localFiles.length);\n\tlines(toWrite.map((f) => lime(`+ ${f.path}`)));\n\tlines(\n\t\tskipped.map((f) =>\n\t\t\tf.differs\n\t\t\t\t? `${yellow(`= ${f.path}`)} ${dim(\"(differs)\")}`\n\t\t\t\t: dim(`= ${f.path} (identical)`),\n\t\t),\n\t);\n\n\tif (toWrite.length === 0) {\n\t\tdivider();\n\t\tp.log.info(\"All local files already exist.\");\n\t\tp.outro(dim(\"nothing to write\"));\n\t\treturn;\n\t}\n\n\tdivider();\n\n\tconst confirm = await p.confirm({\n\t\tmessage: `Write ${lime(String(toWrite.length))} new files? ${dim(`(${skipped.length} skipped)`)}`,\n\t});\n\n\tif (p.isCancel(confirm) || !confirm) {\n\t\tp.cancel(\"Cancelled.\");\n\t\tprocess.exit(0);\n\t}\n\n\tfor (const f of toWrite) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tconst dir = dirname(fullPath);\n\t\tmkdirSync(dir, { recursive: true });\n\t\twriteFileSync(fullPath, f.content);\n\t}\n\n\tp.log.success(\n\t\t`${lime(String(toWrite.length))} written, ${dim(String(skipped.length) + \" skipped\")}`,\n\t);\n\tp.outro(lime(\"done\"));\n}\n\ninterface FileToWrite {\n\tpath: string;\n\tcontent: string;\n}\n"],"mappings":"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","names":["p","basename","existsSync","readFileSync","join","homedir","basename","p","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","join","existsSync","readFileSync","confirm","dirname","mkdirSync","writeFileSync"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/api.ts","../src/config.ts","../src/theme.ts","../src/commands/collect.ts","../src/scanner.ts","../src/classifier.ts","../src/stableKey.ts","../src/commands/create.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { collectCommand } from \"./commands/collect.js\";\nimport { createCommand } from \"./commands/create.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"aistack\")\n\t.description(\"Share and clone AI development configurations\")\n\t.version(\"0.1.0\");\n\nprogram\n\t.command(\"login\")\n\t.description(\"Authenticate with AI Stack\")\n\t.action(loginCommand);\n\nprogram\n\t.command(\"collect\")\n\t.description(\"Scan and upload AI config files from your project\")\n\t.option(\"--no-global\", \"Exclude global config files (~/.claude, etc.)\")\n\t.action((options) => collectCommand({ global: options.global ?? true }));\n\nprogram\n\t.command(\"create\")\n\t.description(\"Download and write AI config files from a shared project\")\n\t.argument(\"<slug>\", \"Project slug or short ID\")\n\t.action(createCommand);\n\nprogram.parse();\n","import * as p from \"@clack/prompts\";\nimport open from \"open\";\nimport { authStart, authPoll } from \"../api.js\";\nimport { saveToken } from \"../config.js\";\nimport { dim, intro, lime, limeBold, outro, outroError } from \"../theme.js\";\n\nexport async function loginCommand() {\n\tintro(\"login\");\n\n\tconst s = p.spinner();\n\ts.start(\"Starting authentication...\");\n\n\tlet session: Awaited<ReturnType<typeof authStart>>;\n\ttry {\n\t\tsession = await authStart();\n\t\ts.stop(\"Session created\");\n\t} catch (err) {\n\t\ts.stop(\"Failed to start authentication\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\tp.log.info(`${dim(\"CODE\")} ${limeBold(session.userCode)}`);\n\tp.log.info(`${dim(\"OPEN\")} ${dim(session.authUrl)}`);\n\n\ttry {\n\t\tawait open(session.authUrl);\n\t} catch {\n\t\tp.log.warn(\n\t\t\t\"Could not open browser automatically. Please visit the URL above.\",\n\t\t);\n\t}\n\n\ts.start(\"Waiting for approval...\");\n\n\tconst maxAttempts = 36;\n\tfor (let i = 0; i < maxAttempts; i++) {\n\t\tawait new Promise((resolve) => setTimeout(resolve, 5000));\n\n\t\ttry {\n\t\t\tconst result = await authPoll(session.secretId);\n\n\t\t\tif (result.status === \"approved\" && result.token) {\n\t\t\t\ts.stop(lime(\"Authenticated\"));\n\t\t\t\tsaveToken(result.token, result.userId);\n\t\t\t\tp.log.success(\n\t\t\t\t\t`Token saved. Run ${limeBold(\"npx @use-aistack/cli collect\")} to get started.`,\n\t\t\t\t);\n\t\t\t\toutro(lime(\"done\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (result.status === \"expired\") {\n\t\t\t\ts.stop(\"Session expired\");\n\t\t\t\tp.log.error(\"Authentication session expired. Please try again.\");\n\t\t\t\toutroError(\"expired\");\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\ts.stop(\"Error polling\");\n\t\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\t\toutroError(\"error\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\ts.stop(\"Timed out\");\n\tp.log.error(\"Authentication timed out after 3 minutes. Please try again.\");\n\toutroError(\"timed out\");\n\tprocess.exit(1);\n}\n","const BASE_URL = process.env.AISTACK_URL || \"https://aistack.to\";\n\nasync function request(\n\tpath: string,\n\toptions: RequestInit = {},\n): Promise<Response> {\n\treturn fetch(`${BASE_URL}${path}`, {\n\t\t...options,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t...options.headers,\n\t\t},\n\t});\n}\n\nfunction authHeaders(token: string): HeadersInit {\n\treturn { Authorization: `Bearer ${token}` };\n}\n\nexport async function authStart(): Promise<{\n\tsecretId: string;\n\tuserCode: string;\n\tauthUrl: string;\n}> {\n\tconst res = await request(\"/api/cli/auth/start\", { method: \"POST\" });\n\tif (!res.ok) throw new Error(`Auth start failed: ${res.status}`);\n\treturn res.json();\n}\n\nexport async function authPoll(\n\tsecretId: string,\n): Promise<{ status: string; token?: string; userId?: string }> {\n\tconst res = await request(\n\t\t`/api/cli/auth/poll?secretId=${encodeURIComponent(secretId)}`,\n\t);\n\tif (!res.ok) throw new Error(`Auth poll failed: ${res.status}`);\n\treturn res.json();\n}\n\nexport async function projectsCheck(\n\ttoken: string,\n\tname: string,\n): Promise<{ exists: boolean; slug?: string }> {\n\tconst res = await request(\n\t\t`/api/cli/projects/check?name=${encodeURIComponent(name)}`,\n\t\t{\n\t\t\theaders: authHeaders(token),\n\t\t},\n\t);\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (!res.ok) throw new Error(`Project check failed: ${res.status}`);\n\treturn res.json();\n}\n\nexport async function projectsCollect(\n\ttoken: string,\n\tdata: { name: string; resources: Resource[] },\n): Promise<{ slug: string; shortId: string; url: string }> {\n\tconst res = await request(\"/api/cli/projects/collect\", {\n\t\tmethod: \"POST\",\n\t\theaders: authHeaders(token),\n\t\tbody: JSON.stringify(data),\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (!res.ok) {\n\t\tthrow new Error(await formatHttpError(res, \"Collect failed\"));\n\t}\n\treturn res.json();\n}\n\nasync function formatHttpError(res: Response, label: string): Promise<string> {\n\tconst prefix = `${label}: ${res.status} ${res.statusText || \"\"}`.trim();\n\tconst text = await res.text().catch(() => \"\");\n\tif (!text) return prefix;\n\ttry {\n\t\tconst body = JSON.parse(text) as { error?: string; message?: string };\n\t\tconst detail = body.error || body.message;\n\t\tif (detail) return `${prefix} — ${detail}`;\n\t} catch {}\n\tconst snippet = text.trim().slice(0, 500);\n\treturn snippet ? `${prefix} — ${snippet}` : prefix;\n}\n\nexport async function projectGet(shortId: string): Promise<ProjectData | null> {\n\tconst res = await request(`/api/cli/projects/${encodeURIComponent(shortId)}`);\n\tif (res.status === 404) return null;\n\tif (!res.ok) throw new Error(`Project fetch failed: ${res.status}`);\n\treturn res.json();\n}\n\n// Types used across the CLI\nexport interface ResourceFile {\n\tname: string;\n\tcontent: string;\n\tpath?: string;\n\ttags?: string[];\n}\n\nexport interface Resource {\n\ttype: string;\n\tname: string;\n\tdescription?: string;\n\tgroup: string;\n\tscope?: \"global\" | \"project\";\n\tstableKey: string;\n\tfiles: ResourceFile[];\n\tsource?: \"authored\" | \"cli\" | \"github\";\n\tupstream?: {\n\t\trepoUrl: string;\n\t\tpath?: string;\n\t\tlicense?: string;\n\t\tstars?: number;\n\t\tlastCommitSha?: string;\n\t\tmirrorMode: \"link\" | \"preview\" | \"mirror\";\n\t\tlastSyncAt?: number;\n\t};\n}\n\nexport interface ProjectData {\n\tname: string;\n\tslug: string;\n\tshortId: string;\n\tresources: Resource[];\n\tcreator?: { name: string };\n\tstack?: { name: string; slug: string };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst CONFIG_DIR = join(homedir(), \".config\", \"aistack\");\nconst CREDENTIALS_FILE = join(CONFIG_DIR, \"credentials.json\");\n\ninterface Credentials {\n\ttoken: string;\n\tuserId?: string;\n}\n\nexport function getToken(): string | null {\n\tif (!existsSync(CREDENTIALS_FILE)) return null;\n\ttry {\n\t\tconst data = JSON.parse(\n\t\t\treadFileSync(CREDENTIALS_FILE, \"utf-8\"),\n\t\t) as Credentials;\n\t\treturn data.token ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function saveToken(token: string, userId?: string): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(CREDENTIALS_FILE, JSON.stringify({ token, userId }, null, 2));\n}\n\nexport function clearToken(): void {\n\tif (existsSync(CREDENTIALS_FILE)) {\n\t\twriteFileSync(CREDENTIALS_FILE, \"{}\");\n\t}\n}\n\nconst PROJECTS_FILE = join(CONFIG_DIR, \"projects.json\");\n\ninterface ProjectEntry {\n\tname: string;\n\texcluded?: string[];\n}\n\ninterface ProjectsData {\n\t[directory: string]: ProjectEntry;\n}\n\nfunction readProjects(): ProjectsData {\n\tif (!existsSync(PROJECTS_FILE)) return {};\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(PROJECTS_FILE, \"utf-8\"));\n\t\t// Migrate old format (string values) to new format\n\t\tconst data: ProjectsData = {};\n\t\tfor (const [key, value] of Object.entries(raw)) {\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tdata[key] = { name: value };\n\t\t\t} else {\n\t\t\t\tdata[key] = value as ProjectEntry;\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeProjects(data: ProjectsData): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(PROJECTS_FILE, JSON.stringify(data, null, 2));\n}\n\nexport function getProjectName(directory: string): string | null {\n\treturn readProjects()[directory]?.name ?? null;\n}\n\nexport function getExcludedPaths(directory: string): string[] {\n\treturn readProjects()[directory]?.excluded ?? [];\n}\n\nexport function saveProjectSettings(\n\tdirectory: string,\n\tname: string,\n\texcluded: string[],\n): void {\n\tconst data = readProjects();\n\tdata[directory] = {\n\t\tname,\n\t\texcluded: excluded.length > 0 ? excluded : undefined,\n\t};\n\twriteProjects(data);\n}\n","import * as p from \"@clack/prompts\";\n\nconst esc = (code: string) => `\\x1b[${code}m`;\nconst reset = esc(\"0\");\n\nconst LIME = \"163;230;53\";\nconst BLACK = \"0;0;0\";\nconst YELLOW = \"250;204;21\";\nconst RED = \"248;113;113\";\nconst MUTED = \"120;120;120\";\n\nexport const lime = (s: string) => `${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const limeBold = (s: string) =>\n\t`${esc(\"1\")}${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const bgLime = (s: string) =>\n\t`${esc(`48;2;${LIME}`)}${esc(`38;2;${BLACK}`)}${s}${reset}`;\nexport const yellow = (s: string) => `${esc(`38;2;${YELLOW}`)}${s}${reset}`;\nexport const red = (s: string) => `${esc(`38;2;${RED}`)}${s}${reset}`;\nexport const dim = (s: string) => `${esc(`38;2;${MUTED}`)}${s}${reset}`;\nexport const bold = (s: string) => `${esc(\"1\")}${s}${reset}`;\n\n// ■ logo square in lime + AISTACK in bold on lime bg\nexport const banner = (cmd: string) =>\n\t`${lime(\"■\")} ${bgLime(` AISTACK `)} ${bold(cmd.toUpperCase())}`;\n\n// Compact line with clack-style bar\nconst BAR = `${esc(`38;2;${MUTED}`)}│${reset}`;\n\nexport function lines(items: string[]) {\n\tfor (const item of items) {\n\t\tconsole.log(`${BAR} ${item}`);\n\t}\n}\n\nexport function section(label: string, count?: number) {\n\tconsole.log(`${BAR}`);\n\tconst countStr = count !== undefined ? ` ${dim(String(count))}` : \"\";\n\tconsole.log(`${BAR} ${bold(label.toUpperCase())}${countStr}`);\n}\n\nexport function divider() {\n\tconsole.log(`${BAR} ${dim(\"─\".repeat(40))}`);\n}\n\nexport function intro(cmd: string) {\n\tconsole.log();\n\tp.intro(banner(cmd));\n}\n\nexport function outro(msg: string) {\n\tp.outro(msg);\n\tconsole.log();\n}\n\nexport function outroError(msg: string) {\n\tp.outro(red(msg));\n\tconsole.log();\n}\n\nexport function outroCancel(msg = \"cancelled\") {\n\tp.cancel(dim(msg));\n\tconsole.log();\n}\n\nexport function outroSkipped(msg: string) {\n\tp.outro(dim(msg));\n\tconsole.log();\n}\n","import * as p from \"@clack/prompts\";\nimport { basename } from \"node:path\";\nimport { scanLocal, scanGlobal, type ScannedFile } from \"../scanner.js\";\nimport { classify } from \"../classifier.js\";\nimport {\n\tprojectsCheck,\n\tprojectsCollect,\n\tprojectGet,\n\ttype Resource,\n} from \"../api.js\";\nimport {\n\tgetToken,\n\tgetProjectName,\n\tgetExcludedPaths,\n\tsaveProjectSettings,\n} from \"../config.js\";\nimport {\n\tbold,\n\tdim,\n\tdivider,\n\tintro,\n\tlime,\n\tlimeBold,\n\tlines,\n\toutro,\n\toutroCancel,\n\toutroError,\n\toutroSkipped,\n\tred,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\nexport async function collectCommand(options: { global: boolean }) {\n\tintro(\"collect\");\n\n\tconst token = getToken();\n\tif (!token) {\n\t\tp.log.error(\n\t\t\t`Not authenticated. Run ${limeBold(\"npx @use-aistack/cli login\")} first.`,\n\t\t);\n\t\toutroError(\"not authenticated\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst savedName = getProjectName(cwd);\n\tconst savedExcluded = getExcludedPaths(cwd);\n\n\tconst s = p.spinner();\n\ts.start(\"Scanning...\");\n\n\tconst localFiles = scanLocal(cwd);\n\tconst globalFiles = options.global ? scanGlobal() : [];\n\ts.stop(\"Scan complete\");\n\n\tif (localFiles.length === 0 && globalFiles.length === 0) {\n\t\tp.log.warn(\"No AI configuration files found.\");\n\t\toutroSkipped(\"nothing to collect\");\n\t\treturn;\n\t}\n\n\t// Project name\n\tlet projectName: string;\n\tif (savedName) {\n\t\tp.log.info(`${dim(\"PROJECT\")} ${limeBold(savedName)}`);\n\t\tprojectName = savedName;\n\t} else {\n\t\tconst defaultName = basename(cwd);\n\t\tconst name = await p.text({\n\t\t\tmessage: \"Project name:\",\n\t\t\tdefaultValue: defaultName,\n\t\t\tplaceholder: defaultName,\n\t\t});\n\t\tif (p.isCancel(name)) {\n\t\t\toutroCancel();\n\t\t\tprocess.exit(0);\n\t\t}\n\t\tprojectName = (name as string) || defaultName;\n\t}\n\n\t// Apply saved exclusions\n\tconst allFiles = [...localFiles, ...globalFiles];\n\tlet selectedFiles = allFiles.filter(\n\t\t(f) => !savedExcluded.includes(f.relativePath),\n\t);\n\tlet excluded = allFiles.filter((f) => savedExcluded.includes(f.relativePath));\n\n\t// Show file counts\n\tp.log.info(\n\t\t`${lime(String(selectedFiles.length))} included${excluded.length > 0 ? ` · ${dim(String(excluded.length) + \" excluded\")}` : \"\"}`,\n\t);\n\n\t// Classify selected files\n\tlet allResources = classify(selectedFiles);\n\n\t// Fetch existing project and diff\n\tlet existingProject: Awaited<ReturnType<typeof projectGet>> = null;\n\ttry {\n\t\tconst check = await projectsCheck(token, projectName);\n\t\tif (check.exists && check.slug) {\n\t\t\tconst shortId = check.slug.includes(\"-\")\n\t\t\t\t? check.slug.slice(check.slug.lastIndexOf(\"-\") + 1)\n\t\t\t\t: check.slug;\n\t\t\texistingProject = await projectGet(shortId);\n\t\t}\n\t} catch (err) {\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Show file list or diff\n\tif (existingProject) {\n\t\tconst diff = diffResources(allResources, existingProject.resources);\n\n\t\tif (diff.changed === 0 && diff.added === 0 && diff.removed === 0) {\n\t\t\tp.log.info(\"No changes since last collect.\");\n\t\t\toutroSkipped(\"nothing to upload\");\n\t\t\treturn;\n\t\t}\n\n\t\tdivider();\n\t\tsection(\"changes\");\n\t\tlines(\n\t\t\tdiff.details.map((f) => {\n\t\t\t\tif (f.status === \"added\") return lime(`+ ${f.name}`);\n\t\t\t\tif (f.status === \"changed\") return yellow(`~ ${f.name}`);\n\t\t\t\treturn red(`- ${f.name}`);\n\t\t\t}),\n\t\t);\n\t\tif (diff.unchanged > 0) {\n\t\t\tlines([dim(`${diff.unchanged} unchanged`)]);\n\t\t}\n\t\tdivider();\n\t} else {\n\t\tconst local = selectedFiles.filter((f) => f.source === \"local\");\n\t\tconst global = selectedFiles.filter((f) => f.source === \"global\");\n\n\t\tif (local.length > 0) {\n\t\t\tp.log.step(`${bold(\"LOCAL\")} ${dim(String(local.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(local)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t\tif (global.length > 0) {\n\t\t\tp.log.step(`${bold(\"GLOBAL\")} ${dim(String(global.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(global)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t}\n\n\t// Action: upload, customize, or cancel\n\tconst action = await p.select({\n\t\tmessage: existingProject\n\t\t\t? \"Upload changes?\"\n\t\t\t: `Upload ${bold(String(selectedFiles.length))} files as ${limeBold(projectName)}?`,\n\t\toptions: [\n\t\t\t{ value: \"upload\", label: \"Upload\" },\n\t\t\t{ value: \"customize\", label: \"Select files\" },\n\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(action) || action === \"cancel\") {\n\t\toutroCancel();\n\t\tprocess.exit(0);\n\t}\n\n\tif (action === \"customize\") {\n\t\tconst selected = await p.multiselect({\n\t\t\tmessage: \"Select files to include:\",\n\t\t\toptions: allFiles.map((f) => ({\n\t\t\t\tvalue: f.relativePath,\n\t\t\t\tlabel: f.relativePath,\n\t\t\t\thint: `${f.type}${f.source === \"global\" ? \" · global\" : \"\"}`,\n\t\t\t})),\n\t\t\tinitialValues: selectedFiles.map((f) => f.relativePath),\n\t\t});\n\n\t\tif (p.isCancel(selected)) {\n\t\t\toutroCancel();\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\tconst selectedSet = new Set(selected as string[]);\n\t\tselectedFiles = allFiles.filter((f) => selectedSet.has(f.relativePath));\n\t\texcluded = allFiles.filter((f) => !selectedSet.has(f.relativePath));\n\t\tallResources = classify(selectedFiles);\n\n\t\tif (selectedFiles.length === 0) {\n\t\t\tp.log.warn(\"No files selected.\");\n\t\t\toutroSkipped(\"nothing to collect\");\n\t\t\tprocess.exit(0);\n\t\t}\n\t}\n\n\ts.start(\"Uploading...\");\n\ttry {\n\t\tconst result = await projectsCollect(token, {\n\t\t\tname: projectName,\n\t\t\tresources: allResources,\n\t\t});\n\t\ts.stop(lime(\"Uploaded\"));\n\t\tsaveProjectSettings(\n\t\t\tcwd,\n\t\t\tprojectName,\n\t\t\texcluded.map((f) => f.relativePath),\n\t\t);\n\t\tp.log.success(dim(result.url));\n\t\toutro(lime(\"done\"));\n\t} catch (err) {\n\t\ts.stop(\"Upload failed\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"upload failed\");\n\t\tprocess.exit(1);\n\t}\n}\n\nconst TYPE_ORDER = [\n\t\"config\",\n\t\"prompt\",\n\t\"rule\",\n\t\"command\",\n\t\"skill\",\n\t\"subagent\",\n\t\"mcp\",\n\t\"hook\",\n\t\"custom\",\n];\n\nfunction groupByType(files: ScannedFile[]): Map<string, ScannedFile[]> {\n\tconst map = new Map<string, ScannedFile[]>();\n\tfor (const f of files) {\n\t\tconst existing = map.get(f.type) ?? [];\n\t\texisting.push(f);\n\t\tmap.set(f.type, existing);\n\t}\n\tconst sorted = new Map<string, ScannedFile[]>();\n\tfor (const type of TYPE_ORDER) {\n\t\tconst group = map.get(type);\n\t\tif (group) sorted.set(type, group);\n\t}\n\tfor (const [type, group] of map) {\n\t\tif (!sorted.has(type)) sorted.set(type, group);\n\t}\n\treturn sorted;\n}\n\ninterface DiffResult {\n\tadded: number;\n\tchanged: number;\n\tremoved: number;\n\tunchanged: number;\n\tdetails: Array<{ name: string; status: \"added\" | \"changed\" | \"removed\" }>;\n}\n\nfunction diffResources(current: Resource[], existing: Resource[]): DiffResult {\n\tconst existingMap = new Map<string, string>();\n\tfor (const item of existing) {\n\t\tfor (const file of item.files) {\n\t\t\texistingMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst currentMap = new Map<string, string>();\n\tfor (const item of current) {\n\t\tfor (const file of item.files) {\n\t\t\tcurrentMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst details: DiffResult[\"details\"] = [];\n\tlet added = 0;\n\tlet changed = 0;\n\tlet unchanged = 0;\n\n\tfor (const [key, content] of currentMap) {\n\t\tconst prev = existingMap.get(key);\n\t\tif (prev === undefined) {\n\t\t\tadded++;\n\t\t\tdetails.push({ name: key, status: \"added\" });\n\t\t} else if (prev !== content) {\n\t\t\tchanged++;\n\t\t\tdetails.push({ name: key, status: \"changed\" });\n\t\t} else {\n\t\t\tunchanged++;\n\t\t}\n\t}\n\n\tlet removed = 0;\n\tfor (const key of existingMap.keys()) {\n\t\tif (!currentMap.has(key)) {\n\t\t\tremoved++;\n\t\t\tdetails.push({ name: key, status: \"removed\" });\n\t\t}\n\t}\n\n\treturn { added, changed, removed, unchanged, details };\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport ignore from \"ignore\";\n\nexport type FileType =\n\t| \"rule\"\n\t| \"mcp\"\n\t| \"skill\"\n\t| \"command\"\n\t| \"prompt\"\n\t| \"hook\"\n\t| \"subagent\"\n\t| \"config\"\n\t| \"custom\";\n\nexport interface ScannedFile {\n\tpath: string;\n\trelativePath: string;\n\tcontent: string;\n\ttype: FileType;\n\tsource: \"local\" | \"global\";\n\tgroup: string;\n}\n\nconst MAX_FILE_SIZE = 100 * 1024; // 100KB\n\ninterface FilePattern {\n\tpath: string;\n\ttype: FileType;\n\tgroup: string;\n}\n\nconst LOCAL_PATTERNS: FilePattern[] = [\n\t// Rules\n\t{ path: \"CLAUDE.md\", type: \"rule\", group: \"claude-code\" },\n\t{ path: \"AGENTS.md\", type: \"rule\", group: \"claude-code\" },\n\t{ path: \".cursorrules\", type: \"rule\", group: \"cursor\" },\n\t{ path: \".windsurfrules\", type: \"rule\", group: \"windsurf\" },\n\t{ path: \".clinerules\", type: \"rule\", group: \"cline\" },\n\t{ path: \".github/copilot-instructions.md\", type: \"rule\", group: \"copilot\" },\n\t// MCP\n\t{ path: \"mcp.json\", type: \"mcp\", group: \"generic\" },\n\t{ path: \".cursor/mcp.json\", type: \"mcp\", group: \"cursor\" },\n\t{\n\t\tpath: \"claude_desktop_config.json\",\n\t\ttype: \"mcp\",\n\t\tgroup: \"claude-desktop\",\n\t},\n\t// Config\n\t{ path: \".aider.conf.yml\", type: \"config\", group: \"aider\" },\n\t{ path: \".continue/config.json\", type: \"config\", group: \"continue\" },\n\t{ path: \".claude/settings.json\", type: \"config\", group: \"claude-code\" },\n\t{\n\t\tpath: \".claude/settings.local.json\",\n\t\ttype: \"config\",\n\t\tgroup: \"claude-code\",\n\t},\n\t// Prompts\n\t{ path: \"system-prompt.md\", type: \"prompt\", group: \"generic\" },\n];\n\nconst LOCAL_DIR_PATTERNS: { dir: string; type: FileType; group: string }[] = [\n\t{ dir: \".cursor/rules\", type: \"rule\", group: \"cursor\" },\n\t{ dir: \".claude/commands\", type: \"command\", group: \"claude-code\" },\n\t{ dir: \".claude/agents\", type: \"subagent\", group: \"claude-code\" },\n\t{ dir: \".claude/hooks\", type: \"hook\", group: \"claude-code\" },\n\t{ dir: \"prompts\", type: \"prompt\", group: \"generic\" },\n\t{ dir: \".ai\", type: \"custom\", group: \"generic\" },\n];\n\nfunction loadGitignore(cwd: string): ReturnType<typeof ignore> {\n\tconst ig = ignore();\n\tconst gitignorePath = join(cwd, \".gitignore\");\n\tif (existsSync(gitignorePath)) {\n\t\tig.add(readFileSync(gitignorePath, \"utf-8\"));\n\t}\n\tig.add([\"node_modules\", \".git\", \"dist\", \"build\", \".next\", \".output\"]);\n\treturn ig;\n}\n\nfunction readFileSafe(filePath: string): string | null {\n\ttry {\n\t\tconst stat = statSync(filePath);\n\t\tif (stat.size > MAX_FILE_SIZE) return null;\n\t\treturn readFileSync(filePath, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction walkDir(dir: string, maxDepth = 3, currentDepth = 0): string[] {\n\tif (currentDepth >= maxDepth || !existsSync(dir)) return [];\n\tconst results: string[] = [];\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tif (entry.isFile()) {\n\t\t\t\tresults.push(fullPath);\n\t\t\t} else if (entry.isDirectory()) {\n\t\t\t\tresults.push(...walkDir(fullPath, maxDepth, currentDepth + 1));\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors, etc */\n\t}\n\treturn results;\n}\n\nexport function scanLocal(cwd: string): ScannedFile[] {\n\tconst ig = loadGitignore(cwd);\n\tconst results: ScannedFile[] = [];\n\n\tfor (const pattern of LOCAL_PATTERNS) {\n\t\tconst filePath = join(cwd, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (!ig.ignores(rel)) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: pattern.type,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup: pattern.group,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const { dir, type, group } of LOCAL_DIR_PATTERNS) {\n\t\tconst dirPath = join(cwd, dir);\n\t\tconst files = walkDir(dirPath);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Scan for skill directories (dirs with SKILL.md, 3 levels deep)\n\ttry {\n\t\tfor (const entry of readdirSync(cwd, { withFileTypes: true }).filter((e) =>\n\t\t\te.isDirectory(),\n\t\t)) {\n\t\t\tif (ig.ignores(entry.name + \"/\")) continue;\n\t\t\tscanSkillDirs(join(cwd, entry.name), cwd, ig, results, 1);\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n\n\treturn results;\n}\n\nfunction scanSkillDirs(\n\tdir: string,\n\tcwd: string,\n\tig: ReturnType<typeof ignore>,\n\tresults: ScannedFile[],\n\tdepth: number,\n) {\n\tif (depth > 3) return;\n\tconst skillMd = join(dir, \"SKILL.md\");\n\tif (existsSync(skillMd)) {\n\t\tconst files = walkDir(dir, 1);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: \"skill\",\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup: \"generic\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tconst rel = relative(cwd, join(dir, entry.name));\n\t\t\t\tif (!ig.ignores(rel + \"/\")) {\n\t\t\t\t\tscanSkillDirs(join(dir, entry.name), cwd, ig, results, depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n}\n\nexport function scanGlobal(): ScannedFile[] {\n\tconst home = homedir();\n\tconst results: ScannedFile[] = [];\n\n\tconst globalPatterns: FilePattern[] = [\n\t\t{ path: \".claude/CLAUDE.md\", type: \"rule\", group: \"claude-code\" },\n\t\t{ path: \".claude/settings.json\", type: \"config\", group: \"claude-code\" },\n\t\t{ path: \".cursor/mcp.json\", type: \"mcp\", group: \"cursor\" },\n\t\t{ path: \".continue/config.json\", type: \"config\", group: \"continue\" },\n\t\t{ path: \".aider.conf.yml\", type: \"config\", group: \"aider\" },\n\t];\n\n\tfor (const pattern of globalPatterns) {\n\t\tconst filePath = join(home, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tresults.push({\n\t\t\t\tpath: filePath,\n\t\t\t\trelativePath: `~/${pattern.path}`,\n\t\t\t\tcontent,\n\t\t\t\ttype: pattern.type,\n\t\t\t\tsource: \"global\",\n\t\t\t\tgroup: pattern.group,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst globalDirs: { dir: string; type: FileType; group: string }[] = [\n\t\t{ dir: \".claude/commands\", type: \"command\", group: \"claude-code\" },\n\t\t{ dir: \".claude/agents\", type: \"subagent\", group: \"claude-code\" },\n\t\t{ dir: \".claude/hooks\", type: \"hook\", group: \"claude-code\" },\n\t\t{ dir: \".cursor/rules\", type: \"rule\", group: \"cursor\" },\n\t];\n\n\tfor (const { dir, type, group } of globalDirs) {\n\t\tconst dirPath = join(home, dir);\n\t\tconst files = walkDir(dirPath, 2);\n\t\tfor (const filePath of files) {\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: `~/${relative(home, filePath)}`,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"global\",\n\t\t\t\t\tgroup,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n","import type { ScannedFile } from \"./scanner.js\";\nimport type { Resource } from \"./api.js\";\nimport { basename, dirname } from \"node:path\";\nimport { computeStableKey } from \"./stableKey.js\";\n\nexport function classify(files: ScannedFile[]): Resource[] {\n\t// Group by {group, scope, type, containing directory}\n\tconst groups = new Map<string, ScannedFile[]>();\n\tconst singletons: ScannedFile[] = [];\n\n\tconst singletonRoots = new Set([\n\t\t\".\",\n\t\t\"~\",\n\t\t\"~/.claude\",\n\t\t\"~/.cursor\",\n\t\t\"~/.continue\",\n\t\t\".claude\",\n\t\t\".cursor\",\n\t\t\".github\",\n\t]);\n\n\tfor (const file of files) {\n\t\tconst dir = dirname(file.relativePath);\n\t\tconst isSingleton = singletonRoots.has(dir);\n\n\t\tif (isSingleton) {\n\t\t\tsingletons.push(file);\n\t\t} else {\n\t\t\tconst key = `${file.group}:${file.source}:${file.type}:${dir}`;\n\t\t\tconst existing = groups.get(key) ?? [];\n\t\t\texisting.push(file);\n\t\t\tgroups.set(key, existing);\n\t\t}\n\t}\n\n\tconst items: Resource[] = [];\n\tconst scope = (source: string) =>\n\t\tsource === \"global\" ? (\"global\" as const) : (\"project\" as const);\n\n\t// Singletons: one Resource per file\n\tfor (const file of singletons) {\n\t\tconst s = scope(file.source);\n\t\tconst relPath = file.relativePath\n\t\t\t.replace(/^~\\/\\.[^/]+\\//, \"\")\n\t\t\t.replace(/^\\.[^/]+\\//, \"\");\n\t\titems.push({\n\t\t\ttype: file.type,\n\t\t\tname: file.relativePath,\n\t\t\tgroup: file.group,\n\t\t\tscope: s,\n\t\t\tstableKey: computeStableKey(file.group, file.type, relPath),\n\t\t\tfiles: [\n\t\t\t\t{\n\t\t\t\t\tname: basename(file.relativePath),\n\t\t\t\t\tcontent: file.content,\n\t\t\t\t\tpath: file.relativePath,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n\n\t// Groups: one Resource per directory group\n\tfor (const [, groupFiles] of groups) {\n\t\tconst first = groupFiles[0];\n\t\tconst dir = dirname(first.relativePath);\n\t\tconst s = scope(first.source);\n\t\tconst relPath = dir\n\t\t\t.replace(/^~\\/\\.claude\\//, \"\")\n\t\t\t.replace(/^\\.claude\\//, \"\")\n\t\t\t.replace(/^~\\/\\.cursor\\//, \"\")\n\t\t\t.replace(/^\\.cursor\\//, \"\");\n\t\tconst typeLabel =\n\t\t\tfirst.type === \"subagent\" ? \"subagents\" : `${first.type}s`;\n\n\t\titems.push({\n\t\t\ttype: first.type,\n\t\t\tname: dir,\n\t\t\tdescription: `${groupFiles.length} ${typeLabel}`,\n\t\t\tgroup: first.group,\n\t\t\tscope: s,\n\t\t\tstableKey: computeStableKey(first.group, first.type, relPath),\n\t\t\tfiles: groupFiles.map((f) => ({\n\t\t\t\tname: basename(f.relativePath),\n\t\t\t\tcontent: f.content,\n\t\t\t\tpath: f.relativePath,\n\t\t\t})),\n\t\t});\n\t}\n\n\treturn items;\n}\n","export function computeStableKey(\n\tgroup: string,\n\ttype: string,\n\trelPath: string,\n): string {\n\treturn `${group}:${type}:${relPath}`;\n}\n","import * as p from \"@clack/prompts\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { projectGet } from \"../api.js\";\nimport {\n\tbold,\n\tdim,\n\tdivider,\n\tintro,\n\tlime,\n\tlines,\n\toutro,\n\toutroCancel,\n\toutroError,\n\toutroSkipped,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\nexport async function createCommand(slugOrShortId: string) {\n\tintro(\"create\");\n\n\tconst s = p.spinner();\n\ts.start(\"Fetching project...\");\n\n\tconst shortId = slugOrShortId.includes(\"-\")\n\t\t? slugOrShortId.slice(slugOrShortId.lastIndexOf(\"-\") + 1)\n\t\t: slugOrShortId;\n\n\tlet project: Awaited<ReturnType<typeof projectGet>>;\n\ttry {\n\t\tproject = await projectGet(shortId);\n\t\tif (!project) {\n\t\t\ts.stop(\"Not found\");\n\t\t\tp.log.error(`Project \"${slugOrShortId}\" not found.`);\n\t\t\toutroError(\"not found\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\ts.stop(bold(project.name));\n\t} catch (err) {\n\t\ts.stop(\"Failed to fetch project\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst localFiles: FileToWrite[] = [];\n\tconst globalFiles: FileToWrite[] = [];\n\n\tfor (const item of project.resources) {\n\t\tconst isGlobal = item.scope === \"global\";\n\t\tfor (const file of item.files) {\n\t\t\tconst writePath = file.path ?? file.name;\n\t\t\tif (isGlobal) {\n\t\t\t\tglobalFiles.push({ path: writePath, content: file.content });\n\t\t\t} else {\n\t\t\t\tlocalFiles.push({ path: writePath, content: file.content });\n\t\t\t}\n\t\t}\n\t}\n\n\tif (globalFiles.length > 0) {\n\t\tsection(\"global config\", globalFiles.length);\n\t\tlines([dim(\"view only\")]);\n\t\tlines(globalFiles.map((f) => dim(f.path)));\n\t}\n\n\tif (localFiles.length === 0) {\n\t\tp.log.warn(\"No local files to write.\");\n\t\toutroSkipped(\"nothing to create\");\n\t\treturn;\n\t}\n\n\tconst cwd = process.cwd();\n\tconst toWrite: FileToWrite[] = [];\n\tconst skipped: { path: string; differs: boolean }[] = [];\n\n\tfor (const f of localFiles) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconst existing = readFileSync(fullPath, \"utf-8\");\n\t\t\tskipped.push({ path: f.path, differs: existing !== f.content });\n\t\t} else {\n\t\t\ttoWrite.push(f);\n\t\t}\n\t}\n\n\tsection(\"local files\", localFiles.length);\n\tlines(toWrite.map((f) => lime(`+ ${f.path}`)));\n\tlines(\n\t\tskipped.map((f) =>\n\t\t\tf.differs\n\t\t\t\t? `${yellow(`= ${f.path}`)} ${dim(\"(differs)\")}`\n\t\t\t\t: dim(`= ${f.path} (identical)`),\n\t\t),\n\t);\n\n\tif (toWrite.length === 0) {\n\t\tdivider();\n\t\tp.log.info(\"All local files already exist.\");\n\t\toutroSkipped(\"nothing to write\");\n\t\treturn;\n\t}\n\n\tdivider();\n\n\tconst confirm = await p.confirm({\n\t\tmessage: `Write ${lime(String(toWrite.length))} new files? ${dim(`(${skipped.length} skipped)`)}`,\n\t});\n\n\tif (p.isCancel(confirm) || !confirm) {\n\t\toutroCancel();\n\t\tprocess.exit(0);\n\t}\n\n\tfor (const f of toWrite) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tconst dir = dirname(fullPath);\n\t\tmkdirSync(dir, { recursive: true });\n\t\twriteFileSync(fullPath, f.content);\n\t}\n\n\tp.log.success(\n\t\t`${lime(String(toWrite.length))} written, ${dim(String(skipped.length) + \" skipped\")}`,\n\t);\n\toutro(lime(\"done\"));\n}\n\ninterface FileToWrite {\n\tpath: string;\n\tcontent: string;\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;;;ACAxB,YAAYA,QAAO;AACnB,OAAO,UAAU;;;ACDjB,IAAM,WAAW,QAAQ,IAAI,eAAe;AAE5C,eAAe,QACd,MACA,UAAuB,CAAC,GACJ;AACpB,SAAO,MAAM,GAAG,QAAQ,GAAG,IAAI,IAAI;AAAA,IAClC,GAAG;AAAA,IACH,SAAS;AAAA,MACR,gBAAgB;AAAA,MAChB,GAAG,QAAQ;AAAA,IACZ;AAAA,EACD,CAAC;AACF;AAEA,SAAS,YAAY,OAA4B;AAChD,SAAO,EAAE,eAAe,UAAU,KAAK,GAAG;AAC3C;AAEA,eAAsB,YAInB;AACF,QAAM,MAAM,MAAM,QAAQ,uBAAuB,EAAE,QAAQ,OAAO,CAAC;AACnE,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,sBAAsB,IAAI,MAAM,EAAE;AAC/D,SAAO,IAAI,KAAK;AACjB;AAEA,eAAsB,SACrB,UAC+D;AAC/D,QAAM,MAAM,MAAM;AAAA,IACjB,+BAA+B,mBAAmB,QAAQ,CAAC;AAAA,EAC5D;AACA,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,qBAAqB,IAAI,MAAM,EAAE;AAC9D,SAAO,IAAI,KAAK;AACjB;AAEA,eAAsB,cACrB,OACA,MAC8C;AAC9C,QAAM,MAAM,MAAM;AAAA,IACjB,gCAAgC,mBAAmB,IAAI,CAAC;AAAA,IACxD;AAAA,MACC,SAAS,YAAY,KAAK;AAAA,IAC3B;AAAA,EACD;AACA,MAAI,IAAI,WAAW;AAClB,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,EAAE;AAClE,SAAO,IAAI,KAAK;AACjB;AAEA,eAAsB,gBACrB,OACA,MAC0D;AAC1D,QAAM,MAAM,MAAM,QAAQ,6BAA6B;AAAA,IACtD,QAAQ;AAAA,IACR,SAAS,YAAY,KAAK;AAAA,IAC1B,MAAM,KAAK,UAAU,IAAI;AAAA,EAC1B,CAAC;AACD,MAAI,IAAI,WAAW;AAClB,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AACD,MAAI,CAAC,IAAI,IAAI;AACZ,UAAM,IAAI,MAAM,MAAM,gBAAgB,KAAK,gBAAgB,CAAC;AAAA,EAC7D;AACA,SAAO,IAAI,KAAK;AACjB;AAEA,eAAe,gBAAgB,KAAe,OAAgC;AAC7E,QAAM,SAAS,GAAG,KAAK,KAAK,IAAI,MAAM,IAAI,IAAI,cAAc,EAAE,GAAG,KAAK;AACtE,QAAMC,QAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,MAAI,CAACA,MAAM,QAAO;AAClB,MAAI;AACH,UAAM,OAAO,KAAK,MAAMA,KAAI;AAC5B,UAAM,SAAS,KAAK,SAAS,KAAK;AAClC,QAAI,OAAQ,QAAO,GAAG,MAAM,WAAM,MAAM;AAAA,EACzC,QAAQ;AAAA,EAAC;AACT,QAAM,UAAUA,MAAK,KAAK,EAAE,MAAM,GAAG,GAAG;AACxC,SAAO,UAAU,GAAG,MAAM,WAAM,OAAO,KAAK;AAC7C;AAEA,eAAsB,WAAW,SAA8C;AAC9E,QAAM,MAAM,MAAM,QAAQ,qBAAqB,mBAAmB,OAAO,CAAC,EAAE;AAC5E,MAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,EAAE;AAClE,SAAO,IAAI,KAAK;AACjB;;;AC9FA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,eAAe;AACxB,SAAS,YAAY;AAErB,IAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,SAAS;AACvD,IAAM,mBAAmB,KAAK,YAAY,kBAAkB;AAOrD,SAAS,WAA0B;AACzC,MAAI,CAAC,WAAW,gBAAgB,EAAG,QAAO;AAC1C,MAAI;AACH,UAAM,OAAO,KAAK;AAAA,MACjB,aAAa,kBAAkB,OAAO;AAAA,IACvC;AACA,WAAO,KAAK,SAAS;AAAA,EACtB,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEO,SAAS,UAAU,OAAe,QAAuB;AAC/D,YAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,gBAAc,kBAAkB,KAAK,UAAU,EAAE,OAAO,OAAO,GAAG,MAAM,CAAC,CAAC;AAC3E;AAQA,IAAM,gBAAgB,KAAK,YAAY,eAAe;AAWtD,SAAS,eAA6B;AACrC,MAAI,CAAC,WAAW,aAAa,EAAG,QAAO,CAAC;AACxC,MAAI;AACH,UAAM,MAAM,KAAK,MAAM,aAAa,eAAe,OAAO,CAAC;AAE3D,UAAM,OAAqB,CAAC;AAC5B,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC/C,UAAI,OAAO,UAAU,UAAU;AAC9B,aAAK,GAAG,IAAI,EAAE,MAAM,MAAM;AAAA,MAC3B,OAAO;AACN,aAAK,GAAG,IAAI;AAAA,MACb;AAAA,IACD;AACA,WAAO;AAAA,EACR,QAAQ;AACP,WAAO,CAAC;AAAA,EACT;AACD;AAEA,SAAS,cAAc,MAA0B;AAChD,YAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,gBAAc,eAAe,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAC3D;AAEO,SAAS,eAAe,WAAkC;AAChE,SAAO,aAAa,EAAE,SAAS,GAAG,QAAQ;AAC3C;AAEO,SAAS,iBAAiB,WAA6B;AAC7D,SAAO,aAAa,EAAE,SAAS,GAAG,YAAY,CAAC;AAChD;AAEO,SAAS,oBACf,WACA,MACA,UACO;AACP,QAAM,OAAO,aAAa;AAC1B,OAAK,SAAS,IAAI;AAAA,IACjB;AAAA,IACA,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,EAC5C;AACA,gBAAc,IAAI;AACnB;;;ACzFA,YAAY,OAAO;AAEnB,IAAM,MAAM,CAAC,SAAiB,QAAQ,IAAI;AAC1C,IAAM,QAAQ,IAAI,GAAG;AAErB,IAAM,OAAO;AACb,IAAM,QAAQ;AACd,IAAM,SAAS;AACf,IAAM,MAAM;AACZ,IAAM,QAAQ;AAEP,IAAM,OAAO,CAAC,MAAc,GAAG,IAAI,QAAQ,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK;AAC9D,IAAM,WAAW,CAAC,MACxB,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,QAAQ,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK;AACvC,IAAM,SAAS,CAAC,MACtB,GAAG,IAAI,QAAQ,IAAI,EAAE,CAAC,GAAG,IAAI,QAAQ,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK;AACnD,IAAM,SAAS,CAAC,MAAc,GAAG,IAAI,QAAQ,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK;AAClE,IAAM,MAAM,CAAC,MAAc,GAAG,IAAI,QAAQ,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK;AAC5D,IAAM,MAAM,CAAC,MAAc,GAAG,IAAI,QAAQ,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK;AAC9D,IAAM,OAAO,CAAC,MAAc,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;AAGnD,IAAM,SAAS,CAAC,QACtB,GAAG,KAAK,QAAG,CAAC,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,IAAI,YAAY,CAAC,CAAC;AAG/D,IAAM,MAAM,GAAG,IAAI,QAAQ,KAAK,EAAE,CAAC,SAAI,KAAK;AAErC,SAAS,MAAM,OAAiB;AACtC,aAAW,QAAQ,OAAO;AACzB,YAAQ,IAAI,GAAG,GAAG,KAAK,IAAI,EAAE;AAAA,EAC9B;AACD;AAEO,SAAS,QAAQ,OAAe,OAAgB;AACtD,UAAQ,IAAI,GAAG,GAAG,EAAE;AACpB,QAAM,WAAW,UAAU,SAAY,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,KAAK;AAClE,UAAQ,IAAI,GAAG,GAAG,KAAK,KAAK,MAAM,YAAY,CAAC,CAAC,GAAG,QAAQ,EAAE;AAC9D;AAEO,SAAS,UAAU;AACzB,UAAQ,IAAI,GAAG,GAAG,KAAK,IAAI,SAAI,OAAO,EAAE,CAAC,CAAC,EAAE;AAC7C;AAEO,SAASC,OAAM,KAAa;AAClC,UAAQ,IAAI;AACZ,EAAE,QAAM,OAAO,GAAG,CAAC;AACpB;AAEO,SAASC,OAAM,KAAa;AAClC,EAAE,QAAM,GAAG;AACX,UAAQ,IAAI;AACb;AAEO,SAAS,WAAW,KAAa;AACvC,EAAE,QAAM,IAAI,GAAG,CAAC;AAChB,UAAQ,IAAI;AACb;AAEO,SAAS,YAAY,MAAM,aAAa;AAC9C,EAAE,SAAO,IAAI,GAAG,CAAC;AACjB,UAAQ,IAAI;AACb;AAEO,SAAS,aAAa,KAAa;AACzC,EAAE,QAAM,IAAI,GAAG,CAAC;AAChB,UAAQ,IAAI;AACb;;;AH7DA,eAAsB,eAAe;AACpC,EAAAC,OAAM,OAAO;AAEb,QAAM,IAAM,WAAQ;AACpB,IAAE,MAAM,4BAA4B;AAEpC,MAAI;AACJ,MAAI;AACH,cAAU,MAAM,UAAU;AAC1B,MAAE,KAAK,iBAAiB;AAAA,EACzB,SAAS,KAAK;AACb,MAAE,KAAK,gCAAgC;AACvC,IAAE,OAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5D,eAAW,OAAO;AAClB,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,EAAE,OAAI,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,SAAS,QAAQ,QAAQ,CAAC,EAAE;AACzD,EAAE,OAAI,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,IAAI,QAAQ,OAAO,CAAC,EAAE;AAEnD,MAAI;AACH,UAAM,KAAK,QAAQ,OAAO;AAAA,EAC3B,QAAQ;AACP,IAAE,OAAI;AAAA,MACL;AAAA,IACD;AAAA,EACD;AAEA,IAAE,MAAM,yBAAyB;AAEjC,QAAM,cAAc;AACpB,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAExD,QAAI;AACH,YAAM,SAAS,MAAM,SAAS,QAAQ,QAAQ;AAE9C,UAAI,OAAO,WAAW,cAAc,OAAO,OAAO;AACjD,UAAE,KAAK,KAAK,eAAe,CAAC;AAC5B,kBAAU,OAAO,OAAO,OAAO,MAAM;AACrC,QAAE,OAAI;AAAA,UACL,oBAAoB,SAAS,8BAA8B,CAAC;AAAA,QAC7D;AACA,QAAAC,OAAM,KAAK,MAAM,CAAC;AAClB;AAAA,MACD;AAEA,UAAI,OAAO,WAAW,WAAW;AAChC,UAAE,KAAK,iBAAiB;AACxB,QAAE,OAAI,MAAM,mDAAmD;AAC/D,mBAAW,SAAS;AACpB,gBAAQ,KAAK,CAAC;AAAA,MACf;AAAA,IACD,SAAS,KAAK;AACb,QAAE,KAAK,eAAe;AACtB,MAAE,OAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5D,iBAAW,OAAO;AAClB,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AAEA,IAAE,KAAK,WAAW;AAClB,EAAE,OAAI,MAAM,6DAA6D;AACzE,aAAW,WAAW;AACtB,UAAQ,KAAK,CAAC;AACf;;;AIvEA,YAAYC,QAAO;AACnB,SAAS,YAAAC,iBAAgB;;;ACDzB,SAAS,cAAAC,aAAY,aAAa,gBAAAC,eAAc,gBAAgB;AAChE,SAAS,QAAAC,OAAM,gBAAgB;AAC/B,SAAS,WAAAC,gBAAe;AACxB,OAAO,YAAY;AAsBnB,IAAM,gBAAgB,MAAM;AAQ5B,IAAM,iBAAgC;AAAA;AAAA,EAErC,EAAE,MAAM,aAAa,MAAM,QAAQ,OAAO,cAAc;AAAA,EACxD,EAAE,MAAM,aAAa,MAAM,QAAQ,OAAO,cAAc;AAAA,EACxD,EAAE,MAAM,gBAAgB,MAAM,QAAQ,OAAO,SAAS;AAAA,EACtD,EAAE,MAAM,kBAAkB,MAAM,QAAQ,OAAO,WAAW;AAAA,EAC1D,EAAE,MAAM,eAAe,MAAM,QAAQ,OAAO,QAAQ;AAAA,EACpD,EAAE,MAAM,mCAAmC,MAAM,QAAQ,OAAO,UAAU;AAAA;AAAA,EAE1E,EAAE,MAAM,YAAY,MAAM,OAAO,OAAO,UAAU;AAAA,EAClD,EAAE,MAAM,oBAAoB,MAAM,OAAO,OAAO,SAAS;AAAA,EACzD;AAAA,IACC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,EACR;AAAA;AAAA,EAEA,EAAE,MAAM,mBAAmB,MAAM,UAAU,OAAO,QAAQ;AAAA,EAC1D,EAAE,MAAM,yBAAyB,MAAM,UAAU,OAAO,WAAW;AAAA,EACnE,EAAE,MAAM,yBAAyB,MAAM,UAAU,OAAO,cAAc;AAAA,EACtE;AAAA,IACC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,EACR;AAAA;AAAA,EAEA,EAAE,MAAM,oBAAoB,MAAM,UAAU,OAAO,UAAU;AAC9D;AAEA,IAAM,qBAAuE;AAAA,EAC5E,EAAE,KAAK,iBAAiB,MAAM,QAAQ,OAAO,SAAS;AAAA,EACtD,EAAE,KAAK,oBAAoB,MAAM,WAAW,OAAO,cAAc;AAAA,EACjE,EAAE,KAAK,kBAAkB,MAAM,YAAY,OAAO,cAAc;AAAA,EAChE,EAAE,KAAK,iBAAiB,MAAM,QAAQ,OAAO,cAAc;AAAA,EAC3D,EAAE,KAAK,WAAW,MAAM,UAAU,OAAO,UAAU;AAAA,EACnD,EAAE,KAAK,OAAO,MAAM,UAAU,OAAO,UAAU;AAChD;AAEA,SAAS,cAAc,KAAwC;AAC9D,QAAM,KAAK,OAAO;AAClB,QAAM,gBAAgBD,MAAK,KAAK,YAAY;AAC5C,MAAIF,YAAW,aAAa,GAAG;AAC9B,OAAG,IAAIC,cAAa,eAAe,OAAO,CAAC;AAAA,EAC5C;AACA,KAAG,IAAI,CAAC,gBAAgB,QAAQ,QAAQ,SAAS,SAAS,SAAS,CAAC;AACpE,SAAO;AACR;AAEA,SAAS,aAAa,UAAiC;AACtD,MAAI;AACH,UAAM,OAAO,SAAS,QAAQ;AAC9B,QAAI,KAAK,OAAO,cAAe,QAAO;AACtC,WAAOA,cAAa,UAAU,OAAO;AAAA,EACtC,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,QAAQ,KAAa,WAAW,GAAG,eAAe,GAAa;AACvE,MAAI,gBAAgB,YAAY,CAACD,YAAW,GAAG,EAAG,QAAO,CAAC;AAC1D,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACH,eAAW,SAAS,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9D,YAAM,WAAWE,MAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,OAAO,GAAG;AACnB,gBAAQ,KAAK,QAAQ;AAAA,MACtB,WAAW,MAAM,YAAY,GAAG;AAC/B,gBAAQ,KAAK,GAAG,QAAQ,UAAU,UAAU,eAAe,CAAC,CAAC;AAAA,MAC9D;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AACA,SAAO;AACR;AAEO,SAAS,UAAU,KAA4B;AACrD,QAAM,KAAK,cAAc,GAAG;AAC5B,QAAM,UAAyB,CAAC;AAEhC,aAAW,WAAW,gBAAgB;AACrC,UAAM,WAAWA,MAAK,KAAK,QAAQ,IAAI;AACvC,UAAM,UAAU,aAAa,QAAQ;AACrC,QAAI,YAAY,MAAM;AACrB,YAAM,MAAM,SAAS,KAAK,QAAQ;AAClC,UAAI,CAAC,GAAG,QAAQ,GAAG,GAAG;AACrB,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,cAAc;AAAA,UACd;AAAA,UACA,MAAM,QAAQ;AAAA,UACd,QAAQ;AAAA,UACR,OAAO,QAAQ;AAAA,QAChB,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAEA,aAAW,EAAE,KAAK,MAAM,MAAM,KAAK,oBAAoB;AACtD,UAAM,UAAUA,MAAK,KAAK,GAAG;AAC7B,UAAM,QAAQ,QAAQ,OAAO;AAC7B,eAAW,YAAY,OAAO;AAC7B,YAAM,MAAM,SAAS,KAAK,QAAQ;AAClC,UAAI,GAAG,QAAQ,GAAG,EAAG;AACrB,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,YAAY,MAAM;AACrB,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,cAAc;AAAA,UACd;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAGA,MAAI;AACH,eAAW,SAAS,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,EAAE;AAAA,MAAO,CAAC,MACrE,EAAE,YAAY;AAAA,IACf,GAAG;AACF,UAAI,GAAG,QAAQ,MAAM,OAAO,GAAG,EAAG;AAClC,oBAAcA,MAAK,KAAK,MAAM,IAAI,GAAG,KAAK,IAAI,SAAS,CAAC;AAAA,IACzD;AAAA,EACD,QAAQ;AAAA,EAER;AAEA,SAAO;AACR;AAEA,SAAS,cACR,KACA,KACA,IACA,SACA,OACC;AACD,MAAI,QAAQ,EAAG;AACf,QAAM,UAAUA,MAAK,KAAK,UAAU;AACpC,MAAIF,YAAW,OAAO,GAAG;AACxB,UAAM,QAAQ,QAAQ,KAAK,CAAC;AAC5B,eAAW,YAAY,OAAO;AAC7B,YAAM,MAAM,SAAS,KAAK,QAAQ;AAClC,UAAI,GAAG,QAAQ,GAAG,EAAG;AACrB,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,YAAY,MAAM;AACrB,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,cAAc;AAAA,UACd;AAAA,UACA,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAO;AAAA,QACR,CAAC;AAAA,MACF;AAAA,IACD;AACA;AAAA,EACD;AACA,MAAI;AACH,eAAW,SAAS,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9D,UAAI,MAAM,YAAY,GAAG;AACxB,cAAM,MAAM,SAAS,KAAKE,MAAK,KAAK,MAAM,IAAI,CAAC;AAC/C,YAAI,CAAC,GAAG,QAAQ,MAAM,GAAG,GAAG;AAC3B,wBAAcA,MAAK,KAAK,MAAM,IAAI,GAAG,KAAK,IAAI,SAAS,QAAQ,CAAC;AAAA,QACjE;AAAA,MACD;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AACD;AAEO,SAAS,aAA4B;AAC3C,QAAM,OAAOC,SAAQ;AACrB,QAAM,UAAyB,CAAC;AAEhC,QAAM,iBAAgC;AAAA,IACrC,EAAE,MAAM,qBAAqB,MAAM,QAAQ,OAAO,cAAc;AAAA,IAChE,EAAE,MAAM,yBAAyB,MAAM,UAAU,OAAO,cAAc;AAAA,IACtE,EAAE,MAAM,oBAAoB,MAAM,OAAO,OAAO,SAAS;AAAA,IACzD,EAAE,MAAM,yBAAyB,MAAM,UAAU,OAAO,WAAW;AAAA,IACnE,EAAE,MAAM,mBAAmB,MAAM,UAAU,OAAO,QAAQ;AAAA,EAC3D;AAEA,aAAW,WAAW,gBAAgB;AACrC,UAAM,WAAWD,MAAK,MAAM,QAAQ,IAAI;AACxC,UAAM,UAAU,aAAa,QAAQ;AACrC,QAAI,YAAY,MAAM;AACrB,cAAQ,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,cAAc,KAAK,QAAQ,IAAI;AAAA,QAC/B;AAAA,QACA,MAAM,QAAQ;AAAA,QACd,QAAQ;AAAA,QACR,OAAO,QAAQ;AAAA,MAChB,CAAC;AAAA,IACF;AAAA,EACD;AAEA,QAAM,aAA+D;AAAA,IACpE,EAAE,KAAK,oBAAoB,MAAM,WAAW,OAAO,cAAc;AAAA,IACjE,EAAE,KAAK,kBAAkB,MAAM,YAAY,OAAO,cAAc;AAAA,IAChE,EAAE,KAAK,iBAAiB,MAAM,QAAQ,OAAO,cAAc;AAAA,IAC3D,EAAE,KAAK,iBAAiB,MAAM,QAAQ,OAAO,SAAS;AAAA,EACvD;AAEA,aAAW,EAAE,KAAK,MAAM,MAAM,KAAK,YAAY;AAC9C,UAAM,UAAUA,MAAK,MAAM,GAAG;AAC9B,UAAM,QAAQ,QAAQ,SAAS,CAAC;AAChC,eAAW,YAAY,OAAO;AAC7B,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,YAAY,MAAM;AACrB,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,cAAc,KAAK,SAAS,MAAM,QAAQ,CAAC;AAAA,UAC3C;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;;;ACnQA,SAAS,UAAU,eAAe;;;ACF3B,SAAS,iBACf,OACA,MACA,SACS;AACT,SAAO,GAAG,KAAK,IAAI,IAAI,IAAI,OAAO;AACnC;;;ADDO,SAAS,SAAS,OAAkC;AAE1D,QAAM,SAAS,oBAAI,IAA2B;AAC9C,QAAM,aAA4B,CAAC;AAEnC,QAAM,iBAAiB,oBAAI,IAAI;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AAED,aAAW,QAAQ,OAAO;AACzB,UAAM,MAAM,QAAQ,KAAK,YAAY;AACrC,UAAM,cAAc,eAAe,IAAI,GAAG;AAE1C,QAAI,aAAa;AAChB,iBAAW,KAAK,IAAI;AAAA,IACrB,OAAO;AACN,YAAM,MAAM,GAAG,KAAK,KAAK,IAAI,KAAK,MAAM,IAAI,KAAK,IAAI,IAAI,GAAG;AAC5D,YAAM,WAAW,OAAO,IAAI,GAAG,KAAK,CAAC;AACrC,eAAS,KAAK,IAAI;AAClB,aAAO,IAAI,KAAK,QAAQ;AAAA,IACzB;AAAA,EACD;AAEA,QAAM,QAAoB,CAAC;AAC3B,QAAM,QAAQ,CAAC,WACd,WAAW,WAAY,WAAsB;AAG9C,aAAW,QAAQ,YAAY;AAC9B,UAAM,IAAI,MAAM,KAAK,MAAM;AAC3B,UAAM,UAAU,KAAK,aACnB,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,cAAc,EAAE;AAC1B,UAAM,KAAK;AAAA,MACV,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,WAAW,iBAAiB,KAAK,OAAO,KAAK,MAAM,OAAO;AAAA,MAC1D,OAAO;AAAA,QACN;AAAA,UACC,MAAM,SAAS,KAAK,YAAY;AAAA,UAChC,SAAS,KAAK;AAAA,UACd,MAAM,KAAK;AAAA,QACZ;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAGA,aAAW,CAAC,EAAE,UAAU,KAAK,QAAQ;AACpC,UAAM,QAAQ,WAAW,CAAC;AAC1B,UAAM,MAAM,QAAQ,MAAM,YAAY;AACtC,UAAM,IAAI,MAAM,MAAM,MAAM;AAC5B,UAAM,UAAU,IACd,QAAQ,kBAAkB,EAAE,EAC5B,QAAQ,eAAe,EAAE,EACzB,QAAQ,kBAAkB,EAAE,EAC5B,QAAQ,eAAe,EAAE;AAC3B,UAAM,YACL,MAAM,SAAS,aAAa,cAAc,GAAG,MAAM,IAAI;AAExD,UAAM,KAAK;AAAA,MACV,MAAM,MAAM;AAAA,MACZ,MAAM;AAAA,MACN,aAAa,GAAG,WAAW,MAAM,IAAI,SAAS;AAAA,MAC9C,OAAO,MAAM;AAAA,MACb,OAAO;AAAA,MACP,WAAW,iBAAiB,MAAM,OAAO,MAAM,MAAM,OAAO;AAAA,MAC5D,OAAO,WAAW,IAAI,CAAC,OAAO;AAAA,QAC7B,MAAM,SAAS,EAAE,YAAY;AAAA,QAC7B,SAAS,EAAE;AAAA,QACX,MAAM,EAAE;AAAA,MACT,EAAE;AAAA,IACH,CAAC;AAAA,EACF;AAEA,SAAO;AACR;;;AFzDA,eAAsB,eAAe,SAA8B;AAClE,EAAAE,OAAM,SAAS;AAEf,QAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,OAAO;AACX,IAAE,OAAI;AAAA,MACL,0BAA0B,SAAS,4BAA4B,CAAC;AAAA,IACjE;AACA,eAAW,mBAAmB;AAC9B,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,YAAY,eAAe,GAAG;AACpC,QAAM,gBAAgB,iBAAiB,GAAG;AAE1C,QAAM,IAAM,WAAQ;AACpB,IAAE,MAAM,aAAa;AAErB,QAAM,aAAa,UAAU,GAAG;AAChC,QAAM,cAAc,QAAQ,SAAS,WAAW,IAAI,CAAC;AACrD,IAAE,KAAK,eAAe;AAEtB,MAAI,WAAW,WAAW,KAAK,YAAY,WAAW,GAAG;AACxD,IAAE,OAAI,KAAK,kCAAkC;AAC7C,iBAAa,oBAAoB;AACjC;AAAA,EACD;AAGA,MAAI;AACJ,MAAI,WAAW;AACd,IAAE,OAAI,KAAK,GAAG,IAAI,SAAS,CAAC,IAAI,SAAS,SAAS,CAAC,EAAE;AACrD,kBAAc;AAAA,EACf,OAAO;AACN,UAAM,cAAcC,UAAS,GAAG;AAChC,UAAM,OAAO,MAAQ,QAAK;AAAA,MACzB,SAAS;AAAA,MACT,cAAc;AAAA,MACd,aAAa;AAAA,IACd,CAAC;AACD,QAAM,YAAS,IAAI,GAAG;AACrB,kBAAY;AACZ,cAAQ,KAAK,CAAC;AAAA,IACf;AACA,kBAAe,QAAmB;AAAA,EACnC;AAGA,QAAM,WAAW,CAAC,GAAG,YAAY,GAAG,WAAW;AAC/C,MAAI,gBAAgB,SAAS;AAAA,IAC5B,CAAC,MAAM,CAAC,cAAc,SAAS,EAAE,YAAY;AAAA,EAC9C;AACA,MAAI,WAAW,SAAS,OAAO,CAAC,MAAM,cAAc,SAAS,EAAE,YAAY,CAAC;AAG5E,EAAE,OAAI;AAAA,IACL,GAAG,KAAK,OAAO,cAAc,MAAM,CAAC,CAAC,YAAY,SAAS,SAAS,IAAI,SAAM,IAAI,OAAO,SAAS,MAAM,IAAI,WAAW,CAAC,KAAK,EAAE;AAAA,EAC/H;AAGA,MAAI,eAAe,SAAS,aAAa;AAGzC,MAAI,kBAA0D;AAC9D,MAAI;AACH,UAAM,QAAQ,MAAM,cAAc,OAAO,WAAW;AACpD,QAAI,MAAM,UAAU,MAAM,MAAM;AAC/B,YAAM,UAAU,MAAM,KAAK,SAAS,GAAG,IACpC,MAAM,KAAK,MAAM,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC,IAChD,MAAM;AACT,wBAAkB,MAAM,WAAW,OAAO;AAAA,IAC3C;AAAA,EACD,SAAS,KAAK;AACb,IAAE,OAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5D,eAAW,OAAO;AAClB,YAAQ,KAAK,CAAC;AAAA,EACf;AAGA,MAAI,iBAAiB;AACpB,UAAM,OAAO,cAAc,cAAc,gBAAgB,SAAS;AAElE,QAAI,KAAK,YAAY,KAAK,KAAK,UAAU,KAAK,KAAK,YAAY,GAAG;AACjE,MAAE,OAAI,KAAK,gCAAgC;AAC3C,mBAAa,mBAAmB;AAChC;AAAA,IACD;AAEA,YAAQ;AACR,YAAQ,SAAS;AACjB;AAAA,MACC,KAAK,QAAQ,IAAI,CAAC,MAAM;AACvB,YAAI,EAAE,WAAW,QAAS,QAAO,KAAK,KAAK,EAAE,IAAI,EAAE;AACnD,YAAI,EAAE,WAAW,UAAW,QAAO,OAAO,KAAK,EAAE,IAAI,EAAE;AACvD,eAAO,IAAI,KAAK,EAAE,IAAI,EAAE;AAAA,MACzB,CAAC;AAAA,IACF;AACA,QAAI,KAAK,YAAY,GAAG;AACvB,YAAM,CAAC,IAAI,GAAG,KAAK,SAAS,YAAY,CAAC,CAAC;AAAA,IAC3C;AACA,YAAQ;AAAA,EACT,OAAO;AACN,UAAM,QAAQ,cAAc,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO;AAC9D,UAAM,SAAS,cAAc,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ;AAEhE,QAAI,MAAM,SAAS,GAAG;AACrB,MAAE,OAAI,KAAK,GAAG,KAAK,OAAO,CAAC,IAAI,IAAI,OAAO,MAAM,MAAM,CAAC,CAAC,EAAE;AAC1D,cAAQ;AACR,iBAAW,CAAC,MAAM,KAAK,KAAK,YAAY,KAAK,GAAG;AAC/C,cAAM,CAAC,GAAG,KAAK,KAAK,YAAY,CAAC,CAAC,IAAI,IAAI,GAAG,MAAM,MAAM,EAAE,CAAC,EAAE,CAAC;AAC/D,cAAM,MAAM,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;AAAA,MACnD;AACA,cAAQ;AAAA,IACT;AACA,QAAI,OAAO,SAAS,GAAG;AACtB,MAAE,OAAI,KAAK,GAAG,KAAK,QAAQ,CAAC,IAAI,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC,EAAE;AAC5D,cAAQ;AACR,iBAAW,CAAC,MAAM,KAAK,KAAK,YAAY,MAAM,GAAG;AAChD,cAAM,CAAC,GAAG,KAAK,KAAK,YAAY,CAAC,CAAC,IAAI,IAAI,GAAG,MAAM,MAAM,EAAE,CAAC,EAAE,CAAC;AAC/D,cAAM,MAAM,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;AAAA,MACnD;AACA,cAAQ;AAAA,IACT;AAAA,EACD;AAGA,QAAM,SAAS,MAAQ,UAAO;AAAA,IAC7B,SAAS,kBACN,oBACA,UAAU,KAAK,OAAO,cAAc,MAAM,CAAC,CAAC,aAAa,SAAS,WAAW,CAAC;AAAA,IACjF,SAAS;AAAA,MACR,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,MACnC,EAAE,OAAO,aAAa,OAAO,eAAe;AAAA,MAC5C,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,IACpC;AAAA,EACD,CAAC;AAED,MAAM,YAAS,MAAM,KAAK,WAAW,UAAU;AAC9C,gBAAY;AACZ,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,MAAI,WAAW,aAAa;AAC3B,UAAM,WAAW,MAAQ,eAAY;AAAA,MACpC,SAAS;AAAA,MACT,SAAS,SAAS,IAAI,CAAC,OAAO;AAAA,QAC7B,OAAO,EAAE;AAAA,QACT,OAAO,EAAE;AAAA,QACT,MAAM,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,WAAW,iBAAc,EAAE;AAAA,MAC3D,EAAE;AAAA,MACF,eAAe,cAAc,IAAI,CAAC,MAAM,EAAE,YAAY;AAAA,IACvD,CAAC;AAED,QAAM,YAAS,QAAQ,GAAG;AACzB,kBAAY;AACZ,cAAQ,KAAK,CAAC;AAAA,IACf;AAEA,UAAM,cAAc,IAAI,IAAI,QAAoB;AAChD,oBAAgB,SAAS,OAAO,CAAC,MAAM,YAAY,IAAI,EAAE,YAAY,CAAC;AACtE,eAAW,SAAS,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,YAAY,CAAC;AAClE,mBAAe,SAAS,aAAa;AAErC,QAAI,cAAc,WAAW,GAAG;AAC/B,MAAE,OAAI,KAAK,oBAAoB;AAC/B,mBAAa,oBAAoB;AACjC,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AAEA,IAAE,MAAM,cAAc;AACtB,MAAI;AACH,UAAM,SAAS,MAAM,gBAAgB,OAAO;AAAA,MAC3C,MAAM;AAAA,MACN,WAAW;AAAA,IACZ,CAAC;AACD,MAAE,KAAK,KAAK,UAAU,CAAC;AACvB;AAAA,MACC;AAAA,MACA;AAAA,MACA,SAAS,IAAI,CAAC,MAAM,EAAE,YAAY;AAAA,IACnC;AACA,IAAE,OAAI,QAAQ,IAAI,OAAO,GAAG,CAAC;AAC7B,IAAAC,OAAM,KAAK,MAAM,CAAC;AAAA,EACnB,SAAS,KAAK;AACb,MAAE,KAAK,eAAe;AACtB,IAAE,OAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5D,eAAW,eAAe;AAC1B,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;AAEA,IAAM,aAAa;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAEA,SAAS,YAAY,OAAkD;AACtE,QAAM,MAAM,oBAAI,IAA2B;AAC3C,aAAW,KAAK,OAAO;AACtB,UAAM,WAAW,IAAI,IAAI,EAAE,IAAI,KAAK,CAAC;AACrC,aAAS,KAAK,CAAC;AACf,QAAI,IAAI,EAAE,MAAM,QAAQ;AAAA,EACzB;AACA,QAAM,SAAS,oBAAI,IAA2B;AAC9C,aAAW,QAAQ,YAAY;AAC9B,UAAM,QAAQ,IAAI,IAAI,IAAI;AAC1B,QAAI,MAAO,QAAO,IAAI,MAAM,KAAK;AAAA,EAClC;AACA,aAAW,CAAC,MAAM,KAAK,KAAK,KAAK;AAChC,QAAI,CAAC,OAAO,IAAI,IAAI,EAAG,QAAO,IAAI,MAAM,KAAK;AAAA,EAC9C;AACA,SAAO;AACR;AAUA,SAAS,cAAc,SAAqB,UAAkC;AAC7E,QAAM,cAAc,oBAAI,IAAoB;AAC5C,aAAW,QAAQ,UAAU;AAC5B,eAAW,QAAQ,KAAK,OAAO;AAC9B,kBAAY,IAAI,KAAK,QAAQ,KAAK,MAAM,KAAK,OAAO;AAAA,IACrD;AAAA,EACD;AAEA,QAAM,aAAa,oBAAI,IAAoB;AAC3C,aAAW,QAAQ,SAAS;AAC3B,eAAW,QAAQ,KAAK,OAAO;AAC9B,iBAAW,IAAI,KAAK,QAAQ,KAAK,MAAM,KAAK,OAAO;AAAA,IACpD;AAAA,EACD;AAEA,QAAM,UAAiC,CAAC;AACxC,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,MAAI,YAAY;AAEhB,aAAW,CAAC,KAAK,OAAO,KAAK,YAAY;AACxC,UAAM,OAAO,YAAY,IAAI,GAAG;AAChC,QAAI,SAAS,QAAW;AACvB;AACA,cAAQ,KAAK,EAAE,MAAM,KAAK,QAAQ,QAAQ,CAAC;AAAA,IAC5C,WAAW,SAAS,SAAS;AAC5B;AACA,cAAQ,KAAK,EAAE,MAAM,KAAK,QAAQ,UAAU,CAAC;AAAA,IAC9C,OAAO;AACN;AAAA,IACD;AAAA,EACD;AAEA,MAAI,UAAU;AACd,aAAW,OAAO,YAAY,KAAK,GAAG;AACrC,QAAI,CAAC,WAAW,IAAI,GAAG,GAAG;AACzB;AACA,cAAQ,KAAK,EAAE,MAAM,KAAK,QAAQ,UAAU,CAAC;AAAA,IAC9C;AAAA,EACD;AAEA,SAAO,EAAE,OAAO,SAAS,SAAS,WAAW,QAAQ;AACtD;;;AIlTA,YAAYC,QAAO;AACnB,SAAS,cAAAC,aAAY,aAAAC,YAAW,gBAAAC,eAAc,iBAAAC,sBAAqB;AACnE,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAiB9B,eAAsB,cAAc,eAAuB;AAC1D,EAAAC,OAAM,QAAQ;AAEd,QAAM,IAAM,WAAQ;AACpB,IAAE,MAAM,qBAAqB;AAE7B,QAAM,UAAU,cAAc,SAAS,GAAG,IACvC,cAAc,MAAM,cAAc,YAAY,GAAG,IAAI,CAAC,IACtD;AAEH,MAAI;AACJ,MAAI;AACH,cAAU,MAAM,WAAW,OAAO;AAClC,QAAI,CAAC,SAAS;AACb,QAAE,KAAK,WAAW;AAClB,MAAE,OAAI,MAAM,YAAY,aAAa,cAAc;AACnD,iBAAW,WAAW;AACtB,cAAQ,KAAK,CAAC;AAAA,IACf;AACA,MAAE,KAAK,KAAK,QAAQ,IAAI,CAAC;AAAA,EAC1B,SAAS,KAAK;AACb,MAAE,KAAK,yBAAyB;AAChC,IAAE,OAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5D,eAAW,OAAO;AAClB,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,QAAM,aAA4B,CAAC;AACnC,QAAM,cAA6B,CAAC;AAEpC,aAAW,QAAQ,QAAQ,WAAW;AACrC,UAAM,WAAW,KAAK,UAAU;AAChC,eAAW,QAAQ,KAAK,OAAO;AAC9B,YAAM,YAAY,KAAK,QAAQ,KAAK;AACpC,UAAI,UAAU;AACb,oBAAY,KAAK,EAAE,MAAM,WAAW,SAAS,KAAK,QAAQ,CAAC;AAAA,MAC5D,OAAO;AACN,mBAAW,KAAK,EAAE,MAAM,WAAW,SAAS,KAAK,QAAQ,CAAC;AAAA,MAC3D;AAAA,IACD;AAAA,EACD;AAEA,MAAI,YAAY,SAAS,GAAG;AAC3B,YAAQ,iBAAiB,YAAY,MAAM;AAC3C,UAAM,CAAC,IAAI,WAAW,CAAC,CAAC;AACxB,UAAM,YAAY,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,CAAC;AAAA,EAC1C;AAEA,MAAI,WAAW,WAAW,GAAG;AAC5B,IAAE,OAAI,KAAK,0BAA0B;AACrC,iBAAa,mBAAmB;AAChC;AAAA,EACD;AAEA,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,UAAyB,CAAC;AAChC,QAAM,UAAgD,CAAC;AAEvD,aAAW,KAAK,YAAY;AAC3B,UAAM,WAAWC,MAAK,KAAK,EAAE,IAAI;AACjC,QAAIC,YAAW,QAAQ,GAAG;AACzB,YAAM,WAAWC,cAAa,UAAU,OAAO;AAC/C,cAAQ,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,aAAa,EAAE,QAAQ,CAAC;AAAA,IAC/D,OAAO;AACN,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AAEA,UAAQ,eAAe,WAAW,MAAM;AACxC,QAAM,QAAQ,IAAI,CAAC,MAAM,KAAK,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C;AAAA,IACC,QAAQ;AAAA,MAAI,CAAC,MACZ,EAAE,UACC,GAAG,OAAO,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,IAAI,WAAW,CAAC,KAC5C,IAAI,KAAK,EAAE,IAAI,cAAc;AAAA,IACjC;AAAA,EACD;AAEA,MAAI,QAAQ,WAAW,GAAG;AACzB,YAAQ;AACR,IAAE,OAAI,KAAK,gCAAgC;AAC3C,iBAAa,kBAAkB;AAC/B;AAAA,EACD;AAEA,UAAQ;AAER,QAAMC,WAAU,MAAQ,WAAQ;AAAA,IAC/B,SAAS,SAAS,KAAK,OAAO,QAAQ,MAAM,CAAC,CAAC,eAAe,IAAI,IAAI,QAAQ,MAAM,WAAW,CAAC;AAAA,EAChG,CAAC;AAED,MAAM,YAASA,QAAO,KAAK,CAACA,UAAS;AACpC,gBAAY;AACZ,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,aAAW,KAAK,SAAS;AACxB,UAAM,WAAWH,MAAK,KAAK,EAAE,IAAI;AACjC,UAAM,MAAMI,SAAQ,QAAQ;AAC5B,IAAAC,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,IAAAC,eAAc,UAAU,EAAE,OAAO;AAAA,EAClC;AAEA,EAAE,OAAI;AAAA,IACL,GAAG,KAAK,OAAO,QAAQ,MAAM,CAAC,CAAC,aAAa,IAAI,OAAO,QAAQ,MAAM,IAAI,UAAU,CAAC;AAAA,EACrF;AACA,EAAAC,OAAM,KAAK,MAAM,CAAC;AACnB;;;ATzHA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACE,KAAK,SAAS,EACd,YAAY,+CAA+C,EAC3D,QAAQ,OAAO;AAEjB,QACE,QAAQ,OAAO,EACf,YAAY,4BAA4B,EACxC,OAAO,YAAY;AAErB,QACE,QAAQ,SAAS,EACjB,YAAY,mDAAmD,EAC/D,OAAO,eAAe,+CAA+C,EACrE,OAAO,CAAC,YAAY,eAAe,EAAE,QAAQ,QAAQ,UAAU,KAAK,CAAC,CAAC;AAExE,QACE,QAAQ,QAAQ,EAChB,YAAY,0DAA0D,EACtE,SAAS,UAAU,0BAA0B,EAC7C,OAAO,aAAa;AAEtB,QAAQ,MAAM;","names":["p","text","intro","outro","intro","outro","p","basename","existsSync","readFileSync","join","homedir","intro","basename","outro","p","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","intro","join","existsSync","readFileSync","confirm","dirname","mkdirSync","writeFileSync","outro"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@use-aistack/cli",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Share and clone AI development configurations",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -10,9 +10,13 @@
10
10
  "directory": "packages/cli"
11
11
  },
12
12
  "homepage": "https://github.com/alp82/aistack#readme",
13
- "bin": { "aistack": "./dist/index.js" },
13
+ "bin": {
14
+ "aistack": "dist/index.js"
15
+ },
14
16
  "files": ["dist", "README.md"],
15
- "publishConfig": { "access": "public" },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
16
20
  "scripts": {
17
21
  "build": "tsup",
18
22
  "postbuild": "chmod +x dist/index.js",
@@ -31,5 +35,7 @@
31
35
  "typescript": "^5.7.2",
32
36
  "@types/node": "^22.10.2"
33
37
  },
34
- "engines": { "node": ">=18" }
38
+ "engines": {
39
+ "node": ">=18"
40
+ }
35
41
  }