@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 +23 -13
- package/dist/index.js +209 -124
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
163
|
-
const s =
|
|
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
|
-
|
|
206
|
+
p2.log.error(err instanceof Error ? err.message : String(err));
|
|
207
|
+
outroError("error");
|
|
172
208
|
process.exit(1);
|
|
173
209
|
}
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
231
|
+
outro2(lime("done"));
|
|
196
232
|
return;
|
|
197
233
|
}
|
|
198
234
|
if (result.status === "expired") {
|
|
199
235
|
s.stop("Session expired");
|
|
200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
{
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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: ".
|
|
241
|
-
{ path: ".
|
|
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
|
|
420
|
-
const
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
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
|
-
|
|
433
|
-
|
|
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 [
|
|
448
|
-
const
|
|
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:
|
|
528
|
+
type: first.type,
|
|
451
529
|
name: dir,
|
|
452
|
-
|
|
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
|
-
|
|
546
|
+
intro2("collect");
|
|
466
547
|
const token = getToken();
|
|
467
548
|
if (!token) {
|
|
468
|
-
|
|
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 =
|
|
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
|
-
|
|
481
|
-
|
|
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
|
-
|
|
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
|
|
574
|
+
const name = await p3.text({
|
|
491
575
|
message: "Project name:",
|
|
492
576
|
defaultValue: defaultName,
|
|
493
577
|
placeholder: defaultName
|
|
494
578
|
});
|
|
495
|
-
if (
|
|
496
|
-
|
|
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
|
-
|
|
590
|
+
p3.log.info(
|
|
507
591
|
`${lime(String(selectedFiles.length))} included${excluded.length > 0 ? ` \xB7 ${dim(String(excluded.length) + " excluded")}` : ""}`
|
|
508
592
|
);
|
|
509
|
-
let
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
528
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
575
|
-
|
|
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
|
|
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 (
|
|
589
|
-
|
|
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
|
-
|
|
677
|
+
allResources = classify(selectedFiles);
|
|
596
678
|
if (selectedFiles.length === 0) {
|
|
597
|
-
|
|
598
|
-
|
|
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
|
-
|
|
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
|
-
|
|
615
|
-
|
|
696
|
+
p3.log.success(dim(result.url));
|
|
697
|
+
outro2(lime("done"));
|
|
616
698
|
} catch (err) {
|
|
617
699
|
s.stop("Upload failed");
|
|
618
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
695
|
-
const s =
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
732
|
-
|
|
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
|
-
|
|
757
|
-
|
|
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
|
|
846
|
+
const confirm2 = await p4.confirm({
|
|
762
847
|
message: `Write ${lime(String(toWrite.length))} new files? ${dim(`(${skipped.length} skipped)`)}`
|
|
763
848
|
});
|
|
764
|
-
if (
|
|
765
|
-
|
|
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
|
-
|
|
859
|
+
p4.log.success(
|
|
775
860
|
`${lime(String(toWrite.length))} written, ${dim(String(skipped.length) + " skipped")}`
|
|
776
861
|
);
|
|
777
|
-
|
|
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":"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","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.
|
|
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": {
|
|
13
|
+
"bin": {
|
|
14
|
+
"aistack": "dist/index.js"
|
|
15
|
+
},
|
|
14
16
|
"files": ["dist", "README.md"],
|
|
15
|
-
"publishConfig": {
|
|
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": {
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
}
|
|
35
41
|
}
|