@flydocs/cli 0.5.0-beta.8 → 0.6.0-alpha.1
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 +6 -0
- package/dist/cli.js +1258 -367
- package/package.json +1 -1
- package/template/.claude/agents/implementation-agent.md +0 -1
- package/template/.claude/agents/pm-agent.md +0 -1
- package/template/.claude/agents/research-agent.md +0 -1
- package/template/.claude/agents/review-agent.md +0 -1
- package/template/.claude/commands/flydocs-setup.md +96 -26
- package/template/.claude/commands/flydocs-upgrade.md +330 -0
- package/template/.claude/skills/flydocs-cloud/SKILL.md +52 -38
- package/template/.claude/skills/flydocs-cloud/cursor-rule.mdc +5 -5
- package/template/.claude/skills/flydocs-cloud/scripts/assign.py +8 -24
- package/template/.claude/skills/flydocs-cloud/scripts/assign_cycle.py +14 -30
- package/template/.claude/skills/flydocs-cloud/scripts/assign_milestone.py +10 -32
- package/template/.claude/skills/flydocs-cloud/scripts/comment.py +15 -25
- package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +21 -58
- package/template/.claude/skills/flydocs-cloud/scripts/create_milestone.py +26 -37
- package/template/.claude/skills/flydocs-cloud/scripts/create_project.py +24 -31
- package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +10 -19
- package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +103 -170
- package/template/.claude/skills/flydocs-cloud/scripts/get_issue.py +6 -59
- package/template/.claude/skills/flydocs-cloud/scripts/link.py +16 -35
- package/template/.claude/skills/flydocs-cloud/scripts/list_cycles.py +21 -28
- package/template/.claude/skills/flydocs-cloud/scripts/list_issues.py +16 -77
- package/template/.claude/skills/flydocs-cloud/scripts/list_labels.py +19 -0
- package/template/.claude/skills/flydocs-cloud/scripts/list_milestones.py +21 -33
- package/template/.claude/skills/flydocs-cloud/scripts/list_projects.py +24 -38
- package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +19 -0
- package/template/.claude/skills/flydocs-cloud/scripts/priority.py +10 -19
- package/template/.claude/skills/flydocs-cloud/scripts/project_update.py +36 -50
- package/template/.claude/skills/flydocs-cloud/scripts/set_labels.py +68 -0
- package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +41 -0
- package/template/.claude/skills/flydocs-cloud/scripts/transition.py +11 -52
- package/template/.claude/skills/flydocs-cloud/scripts/update_description.py +16 -27
- package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +23 -52
- package/template/.env.example +16 -7
- package/template/.flydocs/config.json +1 -1
- package/template/.flydocs/version +1 -1
- package/template/CHANGELOG.md +155 -0
- package/template/manifest.json +5 -3
package/dist/cli.js
CHANGED
|
@@ -11,13 +11,14 @@ var __export = (target, all) => {
|
|
|
11
11
|
|
|
12
12
|
// src/lib/constants.ts
|
|
13
13
|
import pc from "picocolors";
|
|
14
|
-
var CLI_VERSION, CLI_NAME, PACKAGE_NAME;
|
|
14
|
+
var CLI_VERSION, CLI_NAME, PACKAGE_NAME, POSTHOG_API_KEY;
|
|
15
15
|
var init_constants = __esm({
|
|
16
16
|
"src/lib/constants.ts"() {
|
|
17
17
|
"use strict";
|
|
18
|
-
CLI_VERSION = "0.
|
|
18
|
+
CLI_VERSION = "0.6.0-alpha.1";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
|
+
POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
|
|
21
22
|
}
|
|
22
23
|
});
|
|
23
24
|
|
|
@@ -42,9 +43,7 @@ async function ensureDirectories(targetDir, tier) {
|
|
|
42
43
|
const dirs = [
|
|
43
44
|
".flydocs",
|
|
44
45
|
".claude/skills",
|
|
45
|
-
".claude/agents",
|
|
46
46
|
".claude/commands",
|
|
47
|
-
".cursor/agents",
|
|
48
47
|
".cursor/commands",
|
|
49
48
|
".cursor/rules",
|
|
50
49
|
"flydocs/context",
|
|
@@ -136,6 +135,59 @@ var init_template = __esm({
|
|
|
136
135
|
|
|
137
136
|
// src/lib/ui.ts
|
|
138
137
|
import pc2 from "picocolors";
|
|
138
|
+
function shadow(text3) {
|
|
139
|
+
return `\x1B[38;2;55;45;70m${text3}\x1B[0m`;
|
|
140
|
+
}
|
|
141
|
+
function renderBannerBlock() {
|
|
142
|
+
const height = BANNER_ROWS.length;
|
|
143
|
+
const width = BANNER_ROWS[0].length;
|
|
144
|
+
const padded = BANNER_ROWS.map((r) => r.padEnd(width));
|
|
145
|
+
console.log(` ${GRADIENT[0](padded[0])}`);
|
|
146
|
+
for (let i = 1; i < height; i++) {
|
|
147
|
+
let line = "";
|
|
148
|
+
const shadowSrc2 = padded[i - 1];
|
|
149
|
+
const textSrc = padded[i];
|
|
150
|
+
for (let c = 0; c < width; c++) {
|
|
151
|
+
const textChar = textSrc[c];
|
|
152
|
+
const shadowChar = c > 0 ? shadowSrc2[c - 1] : " ";
|
|
153
|
+
if (textChar === "\u2588") {
|
|
154
|
+
line += "\u2588";
|
|
155
|
+
} else if (shadowChar === "\u2588") {
|
|
156
|
+
line += "\u2593";
|
|
157
|
+
} else {
|
|
158
|
+
line += " ";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
let colored = " ";
|
|
162
|
+
let j = 0;
|
|
163
|
+
while (j < line.length) {
|
|
164
|
+
const ch = line[j];
|
|
165
|
+
let run = "";
|
|
166
|
+
while (j < line.length && line[j] === ch) {
|
|
167
|
+
run += line[j];
|
|
168
|
+
j++;
|
|
169
|
+
}
|
|
170
|
+
if (ch === "\u2588") {
|
|
171
|
+
colored += GRADIENT[i](run);
|
|
172
|
+
} else if (ch === "\u2593") {
|
|
173
|
+
colored += shadow(run);
|
|
174
|
+
} else {
|
|
175
|
+
colored += run;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
console.log(colored);
|
|
179
|
+
}
|
|
180
|
+
const shadowSrc = padded[height - 1];
|
|
181
|
+
let bottomShadow = "";
|
|
182
|
+
for (let c = 0; c < width + 1; c++) {
|
|
183
|
+
const shadowChar = c > 0 ? shadowSrc[c - 1] : " ";
|
|
184
|
+
bottomShadow += shadowChar === "\u2588" ? "\u2593" : " ";
|
|
185
|
+
}
|
|
186
|
+
bottomShadow = bottomShadow.replace(/\s+$/, "");
|
|
187
|
+
if (bottomShadow.trim()) {
|
|
188
|
+
console.log(` ${shadow(" " + bottomShadow)}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
139
191
|
function printStatus(message) {
|
|
140
192
|
console.log(`${pc2.green("\u2714")} ${message}`);
|
|
141
193
|
}
|
|
@@ -149,26 +201,13 @@ function printInfo(message) {
|
|
|
149
201
|
console.log(`${pc2.cyan("\u2139")} ${message}`);
|
|
150
202
|
}
|
|
151
203
|
function printBanner(version) {
|
|
152
|
-
const pink = (t) => pc2.bold(pc2.magenta(t));
|
|
153
|
-
const purple = (t) => pc2.bold(pc2.cyan(t));
|
|
154
|
-
const dim = pc2.dim;
|
|
155
|
-
const bold = pc2.bold;
|
|
156
|
-
const pinkBlock12 = pink("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
157
|
-
const pinkBlock4 = pink("\u2588\u2588\u2588\u2588");
|
|
158
|
-
const purpleBlock12 = purple("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
159
|
-
const purpleBlock4 = purple("\u2588\u2588\u2588\u2588");
|
|
160
204
|
console.log();
|
|
161
|
-
|
|
162
|
-
console.log(
|
|
163
|
-
console.log(` ${pinkBlock4}`);
|
|
164
|
-
console.log(
|
|
165
|
-
` ${pinkBlock4} ${purpleBlock12} ${bold("Fly")}${bold("Docs")} ${bold("Core")}`
|
|
166
|
-
);
|
|
205
|
+
renderBannerBlock();
|
|
206
|
+
console.log();
|
|
167
207
|
console.log(
|
|
168
|
-
`
|
|
208
|
+
` ${pc2.bold(pc2.white("Structured context for AI coding tools"))} ${pc2.dim("(Beta)")}`
|
|
169
209
|
);
|
|
170
|
-
console.log(`
|
|
171
|
-
console.log(` ${purpleBlock4} ${dim(`v${version}`)}`);
|
|
210
|
+
console.log(` ${pc2.dim(`Version: ${version}`)}`);
|
|
172
211
|
console.log();
|
|
173
212
|
}
|
|
174
213
|
function printCompletionBox(title, lines) {
|
|
@@ -189,23 +228,42 @@ function printCompletionBox(title, lines) {
|
|
|
189
228
|
}
|
|
190
229
|
function printBetaCta() {
|
|
191
230
|
const dim = pc2.dim;
|
|
231
|
+
const discordUrl = "https://discord.com/invite/YAkjePmZTQ";
|
|
232
|
+
const siteUrl = "https://www.flydocs.ai?utm_source=cli&utm_medium=install&utm_campaign=beta";
|
|
192
233
|
console.log(
|
|
193
234
|
dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")
|
|
194
235
|
);
|
|
195
236
|
console.log();
|
|
196
|
-
console.log(` ${pc2.bold("Join the FlyDocs Closed Beta")}`);
|
|
197
237
|
console.log(
|
|
198
|
-
` ${
|
|
238
|
+
` ${pc2.bold(pc2.cyan("Join the Discord"))} for upcoming features, support, and early access to what's next.`
|
|
199
239
|
);
|
|
240
|
+
console.log(` ${dim("Invite link:")}`);
|
|
241
|
+
console.log(` ${pc2.cyan(discordUrl)}`);
|
|
242
|
+
console.log();
|
|
200
243
|
console.log(
|
|
201
|
-
` ${pc2.cyan("https://www.flydocs.ai
|
|
244
|
+
` ${dim("Docs and updates:")} ${pc2.cyan("https://www.flydocs.ai")}`
|
|
202
245
|
);
|
|
203
246
|
console.log();
|
|
204
247
|
}
|
|
248
|
+
var GRADIENT, BANNER_ROWS;
|
|
205
249
|
var init_ui = __esm({
|
|
206
250
|
"src/lib/ui.ts"() {
|
|
207
251
|
"use strict";
|
|
208
252
|
init_constants();
|
|
253
|
+
GRADIENT = [
|
|
254
|
+
(t) => `\x1B[1;38;2;255;0;128m${t}\x1B[0m`,
|
|
255
|
+
(t) => `\x1B[1;38;2;225;15;158m${t}\x1B[0m`,
|
|
256
|
+
(t) => `\x1B[1;38;2;190;30;190m${t}\x1B[0m`,
|
|
257
|
+
(t) => `\x1B[1;38;2;158;44;214m${t}\x1B[0m`,
|
|
258
|
+
(t) => `\x1B[1;38;2;124;58;237m${t}\x1B[0m`
|
|
259
|
+
];
|
|
260
|
+
BANNER_ROWS = [
|
|
261
|
+
"\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588",
|
|
262
|
+
"\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ",
|
|
263
|
+
"\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 ",
|
|
264
|
+
"\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588",
|
|
265
|
+
"\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588"
|
|
266
|
+
];
|
|
209
267
|
}
|
|
210
268
|
});
|
|
211
269
|
|
|
@@ -303,18 +361,26 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
|
|
|
303
361
|
join4(templateSkillsDir, activeMech),
|
|
304
362
|
join4(skillsDir, activeMech)
|
|
305
363
|
);
|
|
306
|
-
const { rm:
|
|
364
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
307
365
|
const inactivePath = join4(skillsDir, inactiveMech);
|
|
308
366
|
if (await pathExists(inactivePath)) {
|
|
309
|
-
await
|
|
367
|
+
await rm6(inactivePath, { recursive: true, force: true });
|
|
310
368
|
}
|
|
311
|
-
for (const skill of
|
|
369
|
+
for (const skill of CORE_SKILLS) {
|
|
312
370
|
if (skill === "flydocs-workflow") continue;
|
|
313
371
|
const src = join4(templateSkillsDir, skill);
|
|
314
372
|
if (await pathExists(src)) {
|
|
315
373
|
await replaceDirectory(src, join4(skillsDir, skill));
|
|
316
374
|
}
|
|
317
375
|
}
|
|
376
|
+
if (tier === "cloud") {
|
|
377
|
+
for (const skill of CLOUD_ONLY_SKILLS) {
|
|
378
|
+
const src = join4(templateSkillsDir, skill);
|
|
379
|
+
if (await pathExists(src)) {
|
|
380
|
+
await replaceDirectory(src, join4(skillsDir, skill));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
318
384
|
const readmeSrc = join4(templateSkillsDir, "README.md");
|
|
319
385
|
if (await pathExists(readmeSrc)) {
|
|
320
386
|
await copyFile(readmeSrc, join4(skillsDir, "README.md"));
|
|
@@ -323,18 +389,29 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
|
|
|
323
389
|
async function replaceOwnedSkills(templateDir, targetDir, tier) {
|
|
324
390
|
const skillsDir = join4(targetDir, ".claude", "skills");
|
|
325
391
|
const templateSkillsDir = join4(templateDir, ".claude", "skills");
|
|
326
|
-
|
|
392
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
393
|
+
for (const skill of CORE_SKILLS) {
|
|
327
394
|
const src = join4(templateSkillsDir, skill);
|
|
328
395
|
if (await pathExists(src)) {
|
|
329
396
|
await replaceDirectory(src, join4(skillsDir, skill));
|
|
330
397
|
}
|
|
331
398
|
}
|
|
332
|
-
const
|
|
399
|
+
for (const skill of CLOUD_ONLY_SKILLS) {
|
|
400
|
+
const dest = join4(skillsDir, skill);
|
|
401
|
+
if (tier === "cloud") {
|
|
402
|
+
const src = join4(templateSkillsDir, skill);
|
|
403
|
+
if (await pathExists(src)) {
|
|
404
|
+
await replaceDirectory(src, dest);
|
|
405
|
+
}
|
|
406
|
+
} else if (await pathExists(dest)) {
|
|
407
|
+
await rm6(dest, { recursive: true, force: true });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
333
410
|
const activeMech = MECHANISM_SKILLS[tier];
|
|
334
411
|
const inactiveMech = tier === "local" ? MECHANISM_SKILLS.cloud : MECHANISM_SKILLS.local;
|
|
335
412
|
const inactivePath = join4(skillsDir, inactiveMech);
|
|
336
413
|
if (await pathExists(inactivePath)) {
|
|
337
|
-
await
|
|
414
|
+
await rm6(inactivePath, { recursive: true, force: true });
|
|
338
415
|
}
|
|
339
416
|
await replaceDirectory(
|
|
340
417
|
join4(templateSkillsDir, activeMech),
|
|
@@ -346,9 +423,9 @@ async function replaceOwnedSkills(templateDir, targetDir, tier) {
|
|
|
346
423
|
}
|
|
347
424
|
}
|
|
348
425
|
async function copyCursorRules(targetDir) {
|
|
349
|
-
const { mkdir:
|
|
426
|
+
const { mkdir: mkdir9 } = await import("fs/promises");
|
|
350
427
|
const rulesDir = join4(targetDir, ".cursor", "rules");
|
|
351
|
-
await
|
|
428
|
+
await mkdir9(rulesDir, { recursive: true });
|
|
352
429
|
const workflowRule = join4(
|
|
353
430
|
targetDir,
|
|
354
431
|
".claude",
|
|
@@ -382,18 +459,17 @@ async function copyCursorRules(targetDir) {
|
|
|
382
459
|
await copyFile(context7Rule, join4(rulesDir, "flydocs-context7.mdc"));
|
|
383
460
|
}
|
|
384
461
|
}
|
|
385
|
-
var
|
|
462
|
+
var CORE_SKILLS, CLOUD_ONLY_SKILLS, MECHANISM_SKILLS;
|
|
386
463
|
var init_skills = __esm({
|
|
387
464
|
"src/lib/skills.ts"() {
|
|
388
465
|
"use strict";
|
|
389
466
|
init_fs_ops();
|
|
390
|
-
|
|
467
|
+
CORE_SKILLS = [
|
|
391
468
|
"flydocs-workflow",
|
|
392
|
-
"flydocs-figma",
|
|
393
|
-
"flydocs-estimates",
|
|
394
469
|
"flydocs-context-graph",
|
|
395
470
|
"flydocs-context7"
|
|
396
471
|
];
|
|
472
|
+
CLOUD_ONLY_SKILLS = ["flydocs-figma", "flydocs-estimates"];
|
|
397
473
|
MECHANISM_SKILLS = {
|
|
398
474
|
local: "flydocs-local",
|
|
399
475
|
cloud: "flydocs-cloud"
|
|
@@ -401,14 +477,77 @@ var init_skills = __esm({
|
|
|
401
477
|
}
|
|
402
478
|
});
|
|
403
479
|
|
|
480
|
+
// src/lib/user-content.ts
|
|
481
|
+
import {
|
|
482
|
+
copyFile as fsCopyFile2,
|
|
483
|
+
mkdir as mkdir2,
|
|
484
|
+
readFile as readFile3,
|
|
485
|
+
writeFile as writeFile2
|
|
486
|
+
} from "fs/promises";
|
|
487
|
+
import { join as join5, dirname as dirname2 } from "path";
|
|
488
|
+
async function backupOriginals(targetDir, files = RESTORABLE_FILES) {
|
|
489
|
+
const backedUp = [];
|
|
490
|
+
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
491
|
+
for (const relativePath of files) {
|
|
492
|
+
const srcPath = join5(targetDir, relativePath);
|
|
493
|
+
const destPath = join5(backupDir, relativePath);
|
|
494
|
+
if (!await pathExists(srcPath)) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (await pathExists(destPath)) {
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
await mkdir2(dirname2(destPath), { recursive: true });
|
|
501
|
+
await fsCopyFile2(srcPath, destPath);
|
|
502
|
+
backedUp.push(relativePath);
|
|
503
|
+
}
|
|
504
|
+
return backedUp;
|
|
505
|
+
}
|
|
506
|
+
async function readBackupOriginals(targetDir) {
|
|
507
|
+
const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
|
|
508
|
+
if (!await pathExists(backupDir)) {
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
const files = [];
|
|
512
|
+
for (const relativePath of RESTORABLE_FILES) {
|
|
513
|
+
const backupPath = join5(backupDir, relativePath);
|
|
514
|
+
if (await pathExists(backupPath)) {
|
|
515
|
+
const content = await readFile3(backupPath);
|
|
516
|
+
files.push({ relativePath, content });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return files;
|
|
520
|
+
}
|
|
521
|
+
async function writeRestoredFiles(targetDir, files) {
|
|
522
|
+
for (const { relativePath, content } of files) {
|
|
523
|
+
const destPath = join5(targetDir, relativePath);
|
|
524
|
+
await mkdir2(dirname2(destPath), { recursive: true });
|
|
525
|
+
await writeFile2(destPath, content);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
var BACKUP_ORIGINALS_DIR, RESTORABLE_FILES;
|
|
529
|
+
var init_user_content = __esm({
|
|
530
|
+
"src/lib/user-content.ts"() {
|
|
531
|
+
"use strict";
|
|
532
|
+
init_fs_ops();
|
|
533
|
+
BACKUP_ORIGINALS_DIR = ".flydocs/backup-originals";
|
|
534
|
+
RESTORABLE_FILES = [
|
|
535
|
+
".claude/CLAUDE.md",
|
|
536
|
+
".claude/settings.json",
|
|
537
|
+
".cursor/hooks.json",
|
|
538
|
+
"AGENTS.md"
|
|
539
|
+
];
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
404
543
|
// src/lib/stack.ts
|
|
405
|
-
import { readFile as
|
|
406
|
-
import { join as
|
|
544
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
545
|
+
import { join as join6 } from "path";
|
|
407
546
|
async function parseProjectMdStack(targetDir) {
|
|
408
547
|
const detected = /* @__PURE__ */ new Set();
|
|
409
|
-
const projectMdPath =
|
|
548
|
+
const projectMdPath = join6(targetDir, "flydocs", "context", "project.md");
|
|
410
549
|
try {
|
|
411
|
-
const content = await
|
|
550
|
+
const content = await readFile4(projectMdPath, "utf-8");
|
|
412
551
|
const stackMatch = content.match(/## Stack\n([\s\S]*?)(?=\n## |\n---|\z)/);
|
|
413
552
|
if (!stackMatch) return detected;
|
|
414
553
|
const stackSection = stackMatch[1].toLowerCase();
|
|
@@ -451,10 +590,10 @@ async function parseProjectMdStack(targetDir) {
|
|
|
451
590
|
}
|
|
452
591
|
async function detectStack(targetDir) {
|
|
453
592
|
const detected = /* @__PURE__ */ new Set();
|
|
454
|
-
const pkgPath =
|
|
593
|
+
const pkgPath = join6(targetDir, "package.json");
|
|
455
594
|
let pkg;
|
|
456
595
|
try {
|
|
457
|
-
const content = await
|
|
596
|
+
const content = await readFile4(pkgPath, "utf-8");
|
|
458
597
|
pkg = JSON.parse(content);
|
|
459
598
|
} catch {
|
|
460
599
|
}
|
|
@@ -482,39 +621,39 @@ async function detectStack(targetDir) {
|
|
|
482
621
|
detected.add("testing-library");
|
|
483
622
|
}
|
|
484
623
|
for (const f of ["convex/schema.ts", "convex/schema.js"]) {
|
|
485
|
-
if (await pathExists(
|
|
624
|
+
if (await pathExists(join6(targetDir, f))) detected.add("convex");
|
|
486
625
|
}
|
|
487
626
|
for (const f of ["next.config.ts", "next.config.js", "next.config.mjs"]) {
|
|
488
|
-
if (await pathExists(
|
|
627
|
+
if (await pathExists(join6(targetDir, f))) detected.add("nextjs");
|
|
489
628
|
}
|
|
490
|
-
const appJsonPath =
|
|
629
|
+
const appJsonPath = join6(targetDir, "app.json");
|
|
491
630
|
if (await pathExists(appJsonPath)) {
|
|
492
631
|
try {
|
|
493
|
-
const appContent = await
|
|
632
|
+
const appContent = await readFile4(appJsonPath, "utf-8");
|
|
494
633
|
if (appContent.includes('"expo"')) detected.add("expo");
|
|
495
634
|
} catch {
|
|
496
635
|
}
|
|
497
636
|
}
|
|
498
|
-
if (await pathExists(
|
|
637
|
+
if (await pathExists(join6(targetDir, "tsconfig.json"))) {
|
|
499
638
|
detected.add("typescript");
|
|
500
639
|
}
|
|
501
|
-
if (await pathExists(
|
|
640
|
+
if (await pathExists(join6(targetDir, "nuxt.config.ts")) || await pathExists(join6(targetDir, "nuxt.config.js"))) {
|
|
502
641
|
detected.add("nuxt");
|
|
503
642
|
detected.add("vue");
|
|
504
643
|
}
|
|
505
|
-
if (await pathExists(
|
|
644
|
+
if (await pathExists(join6(targetDir, "angular.json"))) {
|
|
506
645
|
detected.add("angular");
|
|
507
646
|
}
|
|
508
|
-
if (await pathExists(
|
|
647
|
+
if (await pathExists(join6(targetDir, "svelte.config.js")) || await pathExists(join6(targetDir, "svelte.config.ts"))) {
|
|
509
648
|
detected.add("svelte");
|
|
510
649
|
}
|
|
511
|
-
if (await pathExists(
|
|
650
|
+
if (await pathExists(join6(targetDir, "pyproject.toml")) || await pathExists(join6(targetDir, "requirements.txt")) || await pathExists(join6(targetDir, "setup.py"))) {
|
|
512
651
|
detected.add("python");
|
|
513
652
|
}
|
|
514
|
-
if (await pathExists(
|
|
653
|
+
if (await pathExists(join6(targetDir, "go.mod"))) {
|
|
515
654
|
detected.add("go");
|
|
516
655
|
}
|
|
517
|
-
if (await pathExists(
|
|
656
|
+
if (await pathExists(join6(targetDir, "Cargo.toml"))) {
|
|
518
657
|
detected.add("rust");
|
|
519
658
|
}
|
|
520
659
|
const projectMdStack = await parseProjectMdStack(targetDir);
|
|
@@ -560,9 +699,9 @@ var init_stack = __esm({
|
|
|
560
699
|
|
|
561
700
|
// src/lib/post-install.ts
|
|
562
701
|
import { execFileSync } from "child_process";
|
|
563
|
-
import { join as
|
|
702
|
+
import { join as join7 } from "path";
|
|
564
703
|
async function runManifestGeneration(targetDir) {
|
|
565
|
-
const scriptPath =
|
|
704
|
+
const scriptPath = join7(
|
|
566
705
|
targetDir,
|
|
567
706
|
".flydocs",
|
|
568
707
|
"scripts",
|
|
@@ -580,7 +719,7 @@ async function runManifestGeneration(targetDir) {
|
|
|
580
719
|
}
|
|
581
720
|
}
|
|
582
721
|
async function runContextGraphBuild(targetDir) {
|
|
583
|
-
const scriptPath =
|
|
722
|
+
const scriptPath = join7(
|
|
584
723
|
targetDir,
|
|
585
724
|
".claude",
|
|
586
725
|
"skills",
|
|
@@ -608,8 +747,8 @@ var init_post_install = __esm({
|
|
|
608
747
|
});
|
|
609
748
|
|
|
610
749
|
// src/lib/skill-manager.ts
|
|
611
|
-
import { readFile as
|
|
612
|
-
import { join as
|
|
750
|
+
import { readFile as readFile5, readdir, rm as rm2, mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
751
|
+
import { join as join8 } from "path";
|
|
613
752
|
import pc3 from "picocolors";
|
|
614
753
|
function flushFrontmatterValue(mode, lines) {
|
|
615
754
|
switch (mode) {
|
|
@@ -736,13 +875,13 @@ async function downloadFileContent(downloadUrl) {
|
|
|
736
875
|
async function downloadRecursive(url, destDir) {
|
|
737
876
|
const items = await fetchGitHubJson(url);
|
|
738
877
|
if (items === null) return false;
|
|
739
|
-
await
|
|
878
|
+
await mkdir3(destDir, { recursive: true });
|
|
740
879
|
for (const item of items) {
|
|
741
|
-
const destPath =
|
|
880
|
+
const destPath = join8(destDir, item.name);
|
|
742
881
|
if (item.type === "file") {
|
|
743
882
|
if (item.download_url) {
|
|
744
883
|
const content = await downloadFileContent(item.download_url);
|
|
745
|
-
await
|
|
884
|
+
await writeFile3(destPath, content);
|
|
746
885
|
}
|
|
747
886
|
} else if (item.type === "dir") {
|
|
748
887
|
await downloadRecursive(item.url, destPath);
|
|
@@ -755,7 +894,7 @@ async function downloadSkillTree(repo, skillName, targetDir) {
|
|
|
755
894
|
return downloadRecursive(apiUrl, targetDir);
|
|
756
895
|
}
|
|
757
896
|
async function listSkills(targetDir) {
|
|
758
|
-
const skillsDir =
|
|
897
|
+
const skillsDir = join8(targetDir, ".claude", "skills");
|
|
759
898
|
const platform = [];
|
|
760
899
|
const community = [];
|
|
761
900
|
if (!await pathExists(skillsDir)) {
|
|
@@ -768,11 +907,11 @@ async function listSkills(targetDir) {
|
|
|
768
907
|
return { platform, community };
|
|
769
908
|
}
|
|
770
909
|
for (const entry of entries.sort()) {
|
|
771
|
-
const skillFile =
|
|
910
|
+
const skillFile = join8(skillsDir, entry, "SKILL.md");
|
|
772
911
|
if (!await pathExists(skillFile)) continue;
|
|
773
912
|
let content;
|
|
774
913
|
try {
|
|
775
|
-
content = await
|
|
914
|
+
content = await readFile5(skillFile, "utf-8");
|
|
776
915
|
} catch {
|
|
777
916
|
continue;
|
|
778
917
|
}
|
|
@@ -820,7 +959,7 @@ async function addSkill(targetDir, source) {
|
|
|
820
959
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
821
960
|
return;
|
|
822
961
|
}
|
|
823
|
-
const skillsDir =
|
|
962
|
+
const skillsDir = join8(targetDir, ".claude", "skills", skillName);
|
|
824
963
|
if (await pathExists(skillsDir)) {
|
|
825
964
|
printWarning(`Skill '${skillName}' is already installed.`);
|
|
826
965
|
console.log(` Remove first: flydocs skills remove ${skillName}`);
|
|
@@ -849,13 +988,13 @@ async function addSkill(targetDir, source) {
|
|
|
849
988
|
printError(`Skill not found at ${repo}/skills/${skillName}`);
|
|
850
989
|
return;
|
|
851
990
|
}
|
|
852
|
-
const skillMdPath =
|
|
991
|
+
const skillMdPath = join8(skillsDir, "SKILL.md");
|
|
853
992
|
if (!await pathExists(skillMdPath)) {
|
|
854
993
|
await rm2(skillsDir, { recursive: true, force: true });
|
|
855
994
|
printError("Invalid skill: SKILL.md not found.");
|
|
856
995
|
return;
|
|
857
996
|
}
|
|
858
|
-
const skillMdContent = await
|
|
997
|
+
const skillMdContent = await readFile5(skillMdPath, "utf-8");
|
|
859
998
|
const fm = parseFrontmatter(skillMdContent);
|
|
860
999
|
if (fm === null || !fm["name"] || !fm["description"]) {
|
|
861
1000
|
await rm2(skillsDir, { recursive: true, force: true });
|
|
@@ -870,11 +1009,11 @@ async function addSkill(targetDir, source) {
|
|
|
870
1009
|
);
|
|
871
1010
|
}
|
|
872
1011
|
printStatus("Downloaded skill files");
|
|
873
|
-
const cursorRuleSrc =
|
|
1012
|
+
const cursorRuleSrc = join8(skillsDir, "cursor-rule.mdc");
|
|
874
1013
|
if (await pathExists(cursorRuleSrc)) {
|
|
875
|
-
const cursorRulesDir =
|
|
876
|
-
await
|
|
877
|
-
const cursorRuleDest =
|
|
1014
|
+
const cursorRulesDir = join8(targetDir, ".cursor", "rules");
|
|
1015
|
+
await mkdir3(cursorRulesDir, { recursive: true });
|
|
1016
|
+
const cursorRuleDest = join8(cursorRulesDir, `${skillName}.mdc`);
|
|
878
1017
|
await copyFile(cursorRuleSrc, cursorRuleDest);
|
|
879
1018
|
printStatus("Installed cursor rule");
|
|
880
1019
|
}
|
|
@@ -901,14 +1040,14 @@ async function removeSkill(targetDir, name) {
|
|
|
901
1040
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
902
1041
|
return;
|
|
903
1042
|
}
|
|
904
|
-
const skillDir =
|
|
1043
|
+
const skillDir = join8(targetDir, ".claude", "skills", name);
|
|
905
1044
|
if (!await pathExists(skillDir)) {
|
|
906
1045
|
printError(`Skill '${name}' is not installed.`);
|
|
907
1046
|
return;
|
|
908
1047
|
}
|
|
909
1048
|
await rm2(skillDir, { recursive: true, force: true });
|
|
910
1049
|
printStatus("Removed skill directory");
|
|
911
|
-
const cursorRule =
|
|
1050
|
+
const cursorRule = join8(targetDir, ".cursor", "rules", `${name}.mdc`);
|
|
912
1051
|
if (await pathExists(cursorRule)) {
|
|
913
1052
|
await rm2(cursorRule, { force: true });
|
|
914
1053
|
printStatus("Removed cursor rule");
|
|
@@ -973,7 +1112,7 @@ var init_skill_manager = __esm({
|
|
|
973
1112
|
});
|
|
974
1113
|
|
|
975
1114
|
// src/lib/community-skills.ts
|
|
976
|
-
import { join as
|
|
1115
|
+
import { join as join9 } from "path";
|
|
977
1116
|
import { multiselect, isCancel, cancel } from "@clack/prompts";
|
|
978
1117
|
import pc4 from "picocolors";
|
|
979
1118
|
function suggestSkills(stack) {
|
|
@@ -992,10 +1131,10 @@ function suggestSkills(stack) {
|
|
|
992
1131
|
}
|
|
993
1132
|
async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
994
1133
|
const suggestions = suggestSkills(stack);
|
|
995
|
-
const skillsDir =
|
|
1134
|
+
const skillsDir = join9(targetDir, ".claude", "skills");
|
|
996
1135
|
const filtered = [];
|
|
997
1136
|
for (const skill of suggestions) {
|
|
998
|
-
if (!await pathExists(
|
|
1137
|
+
if (!await pathExists(join9(skillsDir, skill.name))) {
|
|
999
1138
|
filtered.push(skill);
|
|
1000
1139
|
}
|
|
1001
1140
|
}
|
|
@@ -1152,48 +1291,48 @@ var init_community_skills = __esm({
|
|
|
1152
1291
|
});
|
|
1153
1292
|
|
|
1154
1293
|
// src/lib/deprecated.ts
|
|
1155
|
-
import { readdir as readdir2, mkdir as
|
|
1156
|
-
import { join as
|
|
1294
|
+
import { readdir as readdir2, mkdir as mkdir4, rename, rm as rm3 } from "fs/promises";
|
|
1295
|
+
import { join as join10 } from "path";
|
|
1157
1296
|
import { confirm, isCancel as isCancel2 } from "@clack/prompts";
|
|
1158
1297
|
async function scanDeprecated(targetDir) {
|
|
1159
1298
|
const found = [];
|
|
1160
1299
|
for (const item of [...DEPRECATED_DIRS, ...DEPRECATED_FILES]) {
|
|
1161
|
-
if (await pathExists(
|
|
1300
|
+
if (await pathExists(join10(targetDir, item))) {
|
|
1162
1301
|
found.push(item);
|
|
1163
1302
|
}
|
|
1164
1303
|
}
|
|
1165
1304
|
for (const skill of DEPRECATED_SKILLS) {
|
|
1166
|
-
const p =
|
|
1305
|
+
const p = join10(targetDir, ".claude", "skills", skill);
|
|
1167
1306
|
if (await pathExists(p)) {
|
|
1168
1307
|
found.push(`.claude/skills/${skill}`);
|
|
1169
1308
|
}
|
|
1170
1309
|
}
|
|
1171
1310
|
for (const dir of DEPRECATED_RULES_DIR) {
|
|
1172
|
-
if (await pathExists(
|
|
1311
|
+
if (await pathExists(join10(targetDir, dir))) {
|
|
1173
1312
|
found.push(dir);
|
|
1174
1313
|
}
|
|
1175
1314
|
}
|
|
1176
1315
|
for (const hook of DEPRECATED_HOOKS) {
|
|
1177
|
-
const p =
|
|
1316
|
+
const p = join10(targetDir, ".flydocs", "hooks", hook);
|
|
1178
1317
|
if (await pathExists(p)) {
|
|
1179
1318
|
found.push(`.flydocs/hooks/${hook}`);
|
|
1180
1319
|
}
|
|
1181
1320
|
}
|
|
1182
1321
|
for (const rule of DEPRECATED_CURSOR_RULES) {
|
|
1183
|
-
const p =
|
|
1322
|
+
const p = join10(targetDir, ".cursor", "rules", rule);
|
|
1184
1323
|
if (await pathExists(p)) {
|
|
1185
1324
|
found.push(`.cursor/rules/${rule}`);
|
|
1186
1325
|
}
|
|
1187
1326
|
}
|
|
1188
1327
|
for (const dir of DEPRECATED_CURSOR_RULE_DIRS) {
|
|
1189
|
-
const p =
|
|
1328
|
+
const p = join10(targetDir, ".cursor", "rules", dir);
|
|
1190
1329
|
if (await pathExists(p)) {
|
|
1191
1330
|
found.push(`.cursor/rules/${dir}`);
|
|
1192
1331
|
}
|
|
1193
1332
|
}
|
|
1194
1333
|
for (const cmd of DEPRECATED_COMMANDS) {
|
|
1195
1334
|
for (const prefix of [".cursor/commands", ".claude/commands"]) {
|
|
1196
|
-
const p =
|
|
1335
|
+
const p = join10(targetDir, prefix, cmd);
|
|
1197
1336
|
if (await pathExists(p)) {
|
|
1198
1337
|
found.push(`${prefix}/${cmd}`);
|
|
1199
1338
|
}
|
|
@@ -1202,22 +1341,22 @@ async function scanDeprecated(targetDir) {
|
|
|
1202
1341
|
return found;
|
|
1203
1342
|
}
|
|
1204
1343
|
async function handleLegacyContext(targetDir) {
|
|
1205
|
-
const contextDir =
|
|
1206
|
-
const legacyDir =
|
|
1344
|
+
const contextDir = join10(targetDir, "flydocs", "context");
|
|
1345
|
+
const legacyDir = join10(contextDir, "legacy");
|
|
1207
1346
|
const oldFiles = ["overview.md", "stack.md", "standards.md"];
|
|
1208
1347
|
let hasOld = false;
|
|
1209
1348
|
for (const f of oldFiles) {
|
|
1210
|
-
if (await pathExists(
|
|
1349
|
+
if (await pathExists(join10(contextDir, f))) {
|
|
1211
1350
|
hasOld = true;
|
|
1212
1351
|
break;
|
|
1213
1352
|
}
|
|
1214
1353
|
}
|
|
1215
1354
|
if (hasOld) {
|
|
1216
|
-
await
|
|
1355
|
+
await mkdir4(legacyDir, { recursive: true });
|
|
1217
1356
|
for (const f of oldFiles) {
|
|
1218
|
-
const src =
|
|
1357
|
+
const src = join10(contextDir, f);
|
|
1219
1358
|
if (await pathExists(src)) {
|
|
1220
|
-
await rename(src,
|
|
1359
|
+
await rename(src, join10(legacyDir, f));
|
|
1221
1360
|
printStatus(`Moved flydocs/context/${f} \u2192 legacy/`);
|
|
1222
1361
|
}
|
|
1223
1362
|
}
|
|
@@ -1227,7 +1366,7 @@ async function handleLegacyContext(targetDir) {
|
|
|
1227
1366
|
}
|
|
1228
1367
|
}
|
|
1229
1368
|
async function checkLegacyFolder(targetDir) {
|
|
1230
|
-
const legacyDir =
|
|
1369
|
+
const legacyDir = join10(targetDir, "flydocs", "context", "legacy");
|
|
1231
1370
|
if (!await pathExists(legacyDir)) return null;
|
|
1232
1371
|
try {
|
|
1233
1372
|
const entries = await readdir2(legacyDir);
|
|
@@ -1257,7 +1396,7 @@ async function promptCleanup(targetDir, paths) {
|
|
|
1257
1396
|
return;
|
|
1258
1397
|
}
|
|
1259
1398
|
for (const p of paths) {
|
|
1260
|
-
await rm3(
|
|
1399
|
+
await rm3(join10(targetDir, p), { recursive: true, force: true });
|
|
1261
1400
|
printStatus(`Deleted: ${p}`);
|
|
1262
1401
|
}
|
|
1263
1402
|
}
|
|
@@ -1308,26 +1447,26 @@ var init_deprecated = __esm({
|
|
|
1308
1447
|
});
|
|
1309
1448
|
|
|
1310
1449
|
// src/lib/gitignore.ts
|
|
1311
|
-
import { readFile as
|
|
1312
|
-
import { join as
|
|
1450
|
+
import { readFile as readFile6, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
1451
|
+
import { join as join11 } from "path";
|
|
1313
1452
|
async function ensureGitignore(targetDir) {
|
|
1314
|
-
const gitignorePath =
|
|
1453
|
+
const gitignorePath = join11(targetDir, ".gitignore");
|
|
1315
1454
|
if (await pathExists(gitignorePath)) {
|
|
1316
|
-
const content = await
|
|
1455
|
+
const content = await readFile6(gitignorePath, "utf-8");
|
|
1317
1456
|
if (!content.includes("# FlyDocs")) {
|
|
1318
1457
|
const section = "\n# FlyDocs\n" + FLYDOCS_GITIGNORE_ENTRIES.join("\n") + "\n";
|
|
1319
1458
|
await appendFile(gitignorePath, section, "utf-8");
|
|
1320
1459
|
printStatus("Added FlyDocs entries to .gitignore");
|
|
1321
1460
|
}
|
|
1322
1461
|
} else {
|
|
1323
|
-
await
|
|
1462
|
+
await writeFile4(gitignorePath, FULL_GITIGNORE_TEMPLATE, "utf-8");
|
|
1324
1463
|
printStatus(".gitignore (new)");
|
|
1325
1464
|
}
|
|
1326
1465
|
}
|
|
1327
1466
|
async function migrateGitignore(targetDir) {
|
|
1328
|
-
const gitignorePath =
|
|
1467
|
+
const gitignorePath = join11(targetDir, ".gitignore");
|
|
1329
1468
|
if (!await pathExists(gitignorePath)) return;
|
|
1330
|
-
const content = await
|
|
1469
|
+
const content = await readFile6(gitignorePath, "utf-8");
|
|
1331
1470
|
if (!content.includes("flydocs/context/graph.json")) {
|
|
1332
1471
|
if (content.includes("# FlyDocs")) {
|
|
1333
1472
|
const lines = content.split("\n");
|
|
@@ -1338,7 +1477,7 @@ async function migrateGitignore(targetDir) {
|
|
|
1338
1477
|
insertIdx++;
|
|
1339
1478
|
}
|
|
1340
1479
|
lines.splice(insertIdx, 0, "flydocs/context/graph.json");
|
|
1341
|
-
await
|
|
1480
|
+
await writeFile4(gitignorePath, lines.join("\n"), "utf-8");
|
|
1342
1481
|
} else {
|
|
1343
1482
|
await appendFile(
|
|
1344
1483
|
gitignorePath,
|
|
@@ -1407,7 +1546,7 @@ __pycache__/
|
|
|
1407
1546
|
});
|
|
1408
1547
|
|
|
1409
1548
|
// src/lib/version.ts
|
|
1410
|
-
import { readFile as
|
|
1549
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
1411
1550
|
function compareVersions(v1, v2) {
|
|
1412
1551
|
const [core1, pre1] = v1.split("-", 2);
|
|
1413
1552
|
const [core2, pre2] = v2.split("-", 2);
|
|
@@ -1446,7 +1585,7 @@ function compareVersions(v1, v2) {
|
|
|
1446
1585
|
async function getWhatsNew(changelogPath, fromVersion, toVersion) {
|
|
1447
1586
|
let content;
|
|
1448
1587
|
try {
|
|
1449
|
-
content = await
|
|
1588
|
+
content = await readFile7(changelogPath, "utf-8");
|
|
1450
1589
|
} catch {
|
|
1451
1590
|
return [];
|
|
1452
1591
|
}
|
|
@@ -1475,13 +1614,13 @@ var init_version = __esm({
|
|
|
1475
1614
|
});
|
|
1476
1615
|
|
|
1477
1616
|
// src/lib/update-check.ts
|
|
1478
|
-
import { readFile as
|
|
1479
|
-
import { join as
|
|
1617
|
+
import { readFile as readFile8, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
1618
|
+
import { join as join12 } from "path";
|
|
1480
1619
|
import { homedir } from "os";
|
|
1481
1620
|
import pc5 from "picocolors";
|
|
1482
1621
|
async function readCache() {
|
|
1483
1622
|
try {
|
|
1484
|
-
const raw = await
|
|
1623
|
+
const raw = await readFile8(CACHE_FILE, "utf-8");
|
|
1485
1624
|
const parsed = JSON.parse(raw);
|
|
1486
1625
|
if (typeof parsed === "object" && parsed !== null && "checkedAt" in parsed && "latestVersion" in parsed && typeof parsed.checkedAt === "number" && typeof parsed.latestVersion === "string") {
|
|
1487
1626
|
return parsed;
|
|
@@ -1493,8 +1632,8 @@ async function readCache() {
|
|
|
1493
1632
|
}
|
|
1494
1633
|
async function writeCache(cache) {
|
|
1495
1634
|
try {
|
|
1496
|
-
await
|
|
1497
|
-
await
|
|
1635
|
+
await mkdir5(join12(homedir(), ".flydocs"), { recursive: true });
|
|
1636
|
+
await writeFile5(CACHE_FILE, JSON.stringify(cache), "utf-8");
|
|
1498
1637
|
} catch {
|
|
1499
1638
|
}
|
|
1500
1639
|
}
|
|
@@ -1562,12 +1701,145 @@ var init_update_check = __esm({
|
|
|
1562
1701
|
"use strict";
|
|
1563
1702
|
init_constants();
|
|
1564
1703
|
init_version();
|
|
1565
|
-
CACHE_FILE =
|
|
1704
|
+
CACHE_FILE = join12(homedir(), ".flydocs", "update-check.json");
|
|
1566
1705
|
CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1567
1706
|
FETCH_TIMEOUT_MS = 5e3;
|
|
1568
1707
|
}
|
|
1569
1708
|
});
|
|
1570
1709
|
|
|
1710
|
+
// src/lib/telemetry.ts
|
|
1711
|
+
import { readFile as readFile9, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
|
|
1712
|
+
import { randomUUID } from "crypto";
|
|
1713
|
+
import { join as join13 } from "path";
|
|
1714
|
+
import { homedir as homedir2 } from "os";
|
|
1715
|
+
async function readConfig2() {
|
|
1716
|
+
try {
|
|
1717
|
+
const raw = await readFile9(CONFIG_FILE, "utf-8");
|
|
1718
|
+
const parsed = JSON.parse(raw);
|
|
1719
|
+
if (typeof parsed === "object" && parsed !== null && "enabled" in parsed && "anonymousId" in parsed && typeof parsed.enabled === "boolean" && typeof parsed.anonymousId === "string") {
|
|
1720
|
+
return parsed;
|
|
1721
|
+
}
|
|
1722
|
+
return null;
|
|
1723
|
+
} catch {
|
|
1724
|
+
return null;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
async function writeConfig2(config) {
|
|
1728
|
+
try {
|
|
1729
|
+
await mkdir6(CONFIG_DIR, { recursive: true });
|
|
1730
|
+
await writeFile6(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
1731
|
+
} catch {
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
async function ensureConfig() {
|
|
1735
|
+
const existing = await readConfig2();
|
|
1736
|
+
if (existing) {
|
|
1737
|
+
return existing;
|
|
1738
|
+
}
|
|
1739
|
+
const config = {
|
|
1740
|
+
enabled: false,
|
|
1741
|
+
anonymousId: randomUUID()
|
|
1742
|
+
};
|
|
1743
|
+
await writeConfig2(config);
|
|
1744
|
+
return config;
|
|
1745
|
+
}
|
|
1746
|
+
async function isEnabled() {
|
|
1747
|
+
try {
|
|
1748
|
+
if (process.env.FLYDOCS_TELEMETRY === "0") {
|
|
1749
|
+
return false;
|
|
1750
|
+
}
|
|
1751
|
+
const config = await readConfig2();
|
|
1752
|
+
if (config) {
|
|
1753
|
+
return config.enabled;
|
|
1754
|
+
}
|
|
1755
|
+
return false;
|
|
1756
|
+
} catch {
|
|
1757
|
+
return false;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
function baseProperties() {
|
|
1761
|
+
return {
|
|
1762
|
+
cli_version: CLI_VERSION,
|
|
1763
|
+
os: process.platform,
|
|
1764
|
+
os_arch: process.arch,
|
|
1765
|
+
node_version: process.version,
|
|
1766
|
+
is_ci: Boolean(
|
|
1767
|
+
process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.BUILD_NUMBER
|
|
1768
|
+
),
|
|
1769
|
+
$ip: null,
|
|
1770
|
+
$process_person_profile: false
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
async function capture(event, properties = {}) {
|
|
1774
|
+
try {
|
|
1775
|
+
if (!await isEnabled()) {
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
const config = await ensureConfig();
|
|
1779
|
+
eventQueue.push({
|
|
1780
|
+
event,
|
|
1781
|
+
properties: {
|
|
1782
|
+
distinct_id: config.anonymousId,
|
|
1783
|
+
...baseProperties(),
|
|
1784
|
+
...properties
|
|
1785
|
+
},
|
|
1786
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1787
|
+
});
|
|
1788
|
+
} catch {
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
async function flush() {
|
|
1792
|
+
try {
|
|
1793
|
+
if (eventQueue.length === 0) {
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
if (!await isEnabled()) {
|
|
1797
|
+
eventQueue.length = 0;
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
const batch = eventQueue.splice(0, eventQueue.length);
|
|
1801
|
+
const controller = new AbortController();
|
|
1802
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
|
|
1803
|
+
await fetch(POSTHOG_BATCH_URL, {
|
|
1804
|
+
method: "POST",
|
|
1805
|
+
headers: { "Content-Type": "application/json" },
|
|
1806
|
+
body: JSON.stringify({
|
|
1807
|
+
api_key: POSTHOG_API_KEY,
|
|
1808
|
+
batch
|
|
1809
|
+
}),
|
|
1810
|
+
signal: controller.signal
|
|
1811
|
+
});
|
|
1812
|
+
clearTimeout(timeout);
|
|
1813
|
+
} catch {
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
async function setEnabled(enabled) {
|
|
1817
|
+
const config = await ensureConfig();
|
|
1818
|
+
config.enabled = enabled;
|
|
1819
|
+
await writeConfig2(config);
|
|
1820
|
+
}
|
|
1821
|
+
async function getStatus() {
|
|
1822
|
+
const envOverride = process.env.FLYDOCS_TELEMETRY === "0";
|
|
1823
|
+
const config = await readConfig2();
|
|
1824
|
+
return {
|
|
1825
|
+
enabled: config?.enabled ?? false,
|
|
1826
|
+
envOverride,
|
|
1827
|
+
anonymousId: config?.anonymousId ?? null
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
var CONFIG_DIR, CONFIG_FILE, POSTHOG_BATCH_URL, FETCH_TIMEOUT_MS2, eventQueue;
|
|
1831
|
+
var init_telemetry = __esm({
|
|
1832
|
+
"src/lib/telemetry.ts"() {
|
|
1833
|
+
"use strict";
|
|
1834
|
+
init_constants();
|
|
1835
|
+
CONFIG_DIR = join13(homedir2(), ".flydocs");
|
|
1836
|
+
CONFIG_FILE = join13(CONFIG_DIR, "telemetry.json");
|
|
1837
|
+
POSTHOG_BATCH_URL = "https://us.i.posthog.com/batch/";
|
|
1838
|
+
FETCH_TIMEOUT_MS2 = 5e3;
|
|
1839
|
+
eventQueue = [];
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
|
|
1571
1843
|
// src/commands/install.ts
|
|
1572
1844
|
var install_exports = {};
|
|
1573
1845
|
__export(install_exports, {
|
|
@@ -1575,8 +1847,10 @@ __export(install_exports, {
|
|
|
1575
1847
|
});
|
|
1576
1848
|
import { defineCommand } from "citty";
|
|
1577
1849
|
import { resolve as resolve2 } from "path";
|
|
1578
|
-
import { join as
|
|
1850
|
+
import { join as join14 } from "path";
|
|
1851
|
+
import { mkdir as mkdir7 } from "fs/promises";
|
|
1579
1852
|
import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1853
|
+
import pc6 from "picocolors";
|
|
1580
1854
|
var install_default;
|
|
1581
1855
|
var init_install = __esm({
|
|
1582
1856
|
"src/commands/install.ts"() {
|
|
@@ -1586,12 +1860,14 @@ var init_install = __esm({
|
|
|
1586
1860
|
init_ui();
|
|
1587
1861
|
init_config();
|
|
1588
1862
|
init_skills();
|
|
1863
|
+
init_user_content();
|
|
1589
1864
|
init_stack();
|
|
1590
1865
|
init_community_skills();
|
|
1591
1866
|
init_deprecated();
|
|
1592
1867
|
init_gitignore();
|
|
1593
1868
|
init_post_install();
|
|
1594
1869
|
init_update_check();
|
|
1870
|
+
init_telemetry();
|
|
1595
1871
|
install_default = defineCommand({
|
|
1596
1872
|
meta: {
|
|
1597
1873
|
name: "install",
|
|
@@ -1600,7 +1876,7 @@ var init_install = __esm({
|
|
|
1600
1876
|
args: {
|
|
1601
1877
|
tier: {
|
|
1602
1878
|
type: "string",
|
|
1603
|
-
description: "Set tier: 'local' (free) or 'cloud' (
|
|
1879
|
+
description: "Set tier: 'local' (free) or 'cloud' (managed)"
|
|
1604
1880
|
},
|
|
1605
1881
|
path: {
|
|
1606
1882
|
type: "string",
|
|
@@ -1627,6 +1903,7 @@ var init_install = __esm({
|
|
|
1627
1903
|
const templateDir = await resolveTemplatePath(args["local-source"]);
|
|
1628
1904
|
const version = await readTemplateVersion(templateDir);
|
|
1629
1905
|
printBanner(version);
|
|
1906
|
+
await capture("install_started", { template_version: version });
|
|
1630
1907
|
let targetDir;
|
|
1631
1908
|
if (args.path) {
|
|
1632
1909
|
targetDir = resolve2(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
@@ -1652,60 +1929,95 @@ var init_install = __esm({
|
|
|
1652
1929
|
process.exit(1);
|
|
1653
1930
|
}
|
|
1654
1931
|
tier = args.tier;
|
|
1655
|
-
|
|
1656
|
-
} else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
|
|
1932
|
+
} else if (await pathExists(join14(targetDir, ".flydocs", "config.json"))) {
|
|
1657
1933
|
try {
|
|
1658
1934
|
const existing = await readConfig(targetDir);
|
|
1659
1935
|
if (existing.tier) {
|
|
1660
1936
|
tier = existing.tier;
|
|
1661
|
-
printInfo(`Tier from config: ${tier}`);
|
|
1662
1937
|
}
|
|
1663
1938
|
} catch {
|
|
1664
1939
|
}
|
|
1665
1940
|
}
|
|
1666
|
-
if (!tier) {
|
|
1667
|
-
|
|
1668
|
-
|
|
1941
|
+
if (!args.tier) {
|
|
1942
|
+
if (!tier) {
|
|
1943
|
+
const tierChoice = await select({
|
|
1944
|
+
message: `Install FlyDocs in: ${targetDir}`,
|
|
1945
|
+
options: [
|
|
1946
|
+
{
|
|
1947
|
+
value: "local",
|
|
1948
|
+
label: "Local (free)",
|
|
1949
|
+
hint: "File-based issues, no account needed"
|
|
1950
|
+
},
|
|
1951
|
+
{
|
|
1952
|
+
value: "cloud",
|
|
1953
|
+
label: "Cloud (managed)",
|
|
1954
|
+
hint: "Sync with Linear \u2014 run flydocs connect after install"
|
|
1955
|
+
}
|
|
1956
|
+
]
|
|
1957
|
+
});
|
|
1958
|
+
if (isCancel3(tierChoice)) {
|
|
1959
|
+
cancel2("Installation cancelled.");
|
|
1960
|
+
process.exit(0);
|
|
1961
|
+
}
|
|
1962
|
+
tier = tierChoice;
|
|
1963
|
+
console.log();
|
|
1964
|
+
} else {
|
|
1965
|
+
const shouldInstall = await confirm2({
|
|
1966
|
+
message: `Install FlyDocs here? (${tier} tier)
|
|
1669
1967
|
Directory: ${targetDir}`
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1968
|
+
});
|
|
1969
|
+
if (isCancel3(shouldInstall) || !shouldInstall) {
|
|
1970
|
+
cancel2("Installation cancelled.");
|
|
1971
|
+
process.exit(0);
|
|
1972
|
+
}
|
|
1973
|
+
console.log();
|
|
1674
1974
|
}
|
|
1975
|
+
}
|
|
1976
|
+
if (!tier) {
|
|
1675
1977
|
tier = "local";
|
|
1676
|
-
console.log();
|
|
1677
1978
|
}
|
|
1678
|
-
|
|
1979
|
+
printInfo(`Tier: ${tier}`);
|
|
1980
|
+
await capture("install_tier_selected", { tier });
|
|
1981
|
+
if (!await pathExists(join14(targetDir, ".git"))) {
|
|
1679
1982
|
printWarning("No git repository detected. Run git init when ready.");
|
|
1680
1983
|
}
|
|
1681
1984
|
await ensureDirectories(targetDir, tier);
|
|
1985
|
+
const backedUp = await backupOriginals(targetDir);
|
|
1986
|
+
if (backedUp.length > 0) {
|
|
1987
|
+
printStatus(
|
|
1988
|
+
`Backed up ${backedUp.length} existing config file(s) to .flydocs/backup-originals/`
|
|
1989
|
+
);
|
|
1990
|
+
for (const f of backedUp) {
|
|
1991
|
+
printInfo(` ${f}`);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1682
1994
|
console.log("Installing framework files...");
|
|
1683
1995
|
await replaceDirectory(
|
|
1684
|
-
|
|
1685
|
-
|
|
1996
|
+
join14(templateDir, ".flydocs", "templates"),
|
|
1997
|
+
join14(targetDir, ".flydocs", "templates")
|
|
1686
1998
|
);
|
|
1687
1999
|
await replaceDirectory(
|
|
1688
|
-
|
|
1689
|
-
|
|
2000
|
+
join14(templateDir, ".flydocs", "hooks"),
|
|
2001
|
+
join14(targetDir, ".flydocs", "hooks")
|
|
1690
2002
|
);
|
|
1691
2003
|
await replaceDirectory(
|
|
1692
|
-
|
|
1693
|
-
|
|
2004
|
+
join14(templateDir, ".flydocs", "scripts"),
|
|
2005
|
+
join14(targetDir, ".flydocs", "scripts")
|
|
1694
2006
|
);
|
|
1695
2007
|
await copyFile(
|
|
1696
|
-
|
|
1697
|
-
|
|
2008
|
+
join14(templateDir, ".flydocs", "version"),
|
|
2009
|
+
join14(targetDir, ".flydocs", "version")
|
|
1698
2010
|
);
|
|
1699
|
-
const manifestSrc =
|
|
2011
|
+
const manifestSrc = join14(templateDir, "manifest.json");
|
|
1700
2012
|
if (await pathExists(manifestSrc)) {
|
|
1701
|
-
await copyFile(manifestSrc,
|
|
2013
|
+
await copyFile(manifestSrc, join14(targetDir, ".flydocs", "manifest.json"));
|
|
1702
2014
|
}
|
|
1703
|
-
const changelogSrc =
|
|
2015
|
+
const changelogSrc = join14(templateDir, "CHANGELOG.md");
|
|
1704
2016
|
if (await pathExists(changelogSrc)) {
|
|
1705
|
-
await copyFile(changelogSrc,
|
|
2017
|
+
await copyFile(changelogSrc, join14(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
1706
2018
|
}
|
|
1707
2019
|
printStatus(".flydocs/templates, hooks, version, manifest, changelog");
|
|
1708
|
-
const configPath =
|
|
2020
|
+
const configPath = join14(targetDir, ".flydocs", "config.json");
|
|
1709
2021
|
if (!await pathExists(configPath)) {
|
|
1710
2022
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
1711
2023
|
await writeConfig(targetDir, config);
|
|
@@ -1730,48 +2042,84 @@ var init_install = __esm({
|
|
|
1730
2042
|
await installOwnedSkills(templateDir, targetDir, tier);
|
|
1731
2043
|
printStatus(`Skills installed (tier: ${tier})`);
|
|
1732
2044
|
console.log();
|
|
1733
|
-
console.log("
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
)
|
|
2045
|
+
console.log(` ${pc6.bold(pc6.yellow("Sub-Agents (Recommended)"))}`);
|
|
2046
|
+
console.log();
|
|
2047
|
+
console.log(
|
|
2048
|
+
" Sub-agents are specialized roles (PM, implementation, review,"
|
|
2049
|
+
);
|
|
2050
|
+
console.log(
|
|
2051
|
+
" research) that your AI tool can delegate tasks to. They help"
|
|
2052
|
+
);
|
|
2053
|
+
console.log(
|
|
2054
|
+
" structure work but are not required \u2014 everything works without them."
|
|
2055
|
+
);
|
|
2056
|
+
console.log();
|
|
2057
|
+
let installAgents;
|
|
2058
|
+
if (args.yes) {
|
|
2059
|
+
installAgents = true;
|
|
2060
|
+
console.log(" Auto-accepting (--yes)");
|
|
2061
|
+
} else {
|
|
2062
|
+
const agentConfirm = await confirm2({
|
|
2063
|
+
message: "Install sub-agents?",
|
|
2064
|
+
initialValue: true
|
|
2065
|
+
});
|
|
2066
|
+
if (isCancel3(agentConfirm)) {
|
|
2067
|
+
installAgents = false;
|
|
2068
|
+
} else {
|
|
2069
|
+
installAgents = agentConfirm;
|
|
2070
|
+
}
|
|
1740
2071
|
}
|
|
2072
|
+
await capture("install_agents_chosen", { install_agents: installAgents });
|
|
2073
|
+
if (installAgents) {
|
|
2074
|
+
const claudeAgentsSrc = join14(templateDir, ".claude", "agents");
|
|
2075
|
+
if (await pathExists(claudeAgentsSrc)) {
|
|
2076
|
+
await mkdir7(join14(targetDir, ".claude", "agents"), { recursive: true });
|
|
2077
|
+
await copyDirectoryContents(
|
|
2078
|
+
claudeAgentsSrc,
|
|
2079
|
+
join14(targetDir, ".claude", "agents")
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
const cursorAgentsSrc = join14(templateDir, ".cursor", "agents");
|
|
2083
|
+
if (await pathExists(cursorAgentsSrc)) {
|
|
2084
|
+
await mkdir7(join14(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2085
|
+
await copyDirectoryContents(
|
|
2086
|
+
cursorAgentsSrc,
|
|
2087
|
+
join14(targetDir, ".cursor", "agents")
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
|
|
2091
|
+
} else {
|
|
2092
|
+
printInfo("Skipped sub-agents");
|
|
2093
|
+
}
|
|
2094
|
+
console.log();
|
|
2095
|
+
console.log("Installing commands and settings...");
|
|
1741
2096
|
await copyDirectoryContents(
|
|
1742
|
-
|
|
1743
|
-
|
|
2097
|
+
join14(templateDir, ".claude", "commands"),
|
|
2098
|
+
join14(targetDir, ".claude", "commands")
|
|
1744
2099
|
);
|
|
1745
2100
|
await copyFile(
|
|
1746
|
-
|
|
1747
|
-
|
|
2101
|
+
join14(templateDir, ".claude", "CLAUDE.md"),
|
|
2102
|
+
join14(targetDir, ".claude", "CLAUDE.md")
|
|
1748
2103
|
);
|
|
1749
2104
|
await copyFile(
|
|
1750
|
-
|
|
1751
|
-
|
|
2105
|
+
join14(templateDir, ".claude", "settings.json"),
|
|
2106
|
+
join14(targetDir, ".claude", "settings.json")
|
|
1752
2107
|
);
|
|
1753
|
-
printStatus(".claude/ (
|
|
1754
|
-
const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
|
|
1755
|
-
if (await pathExists(cursorAgentsSrc)) {
|
|
1756
|
-
await copyDirectoryContents(
|
|
1757
|
-
cursorAgentsSrc,
|
|
1758
|
-
join12(targetDir, ".cursor", "agents")
|
|
1759
|
-
);
|
|
1760
|
-
}
|
|
2108
|
+
printStatus(".claude/ (commands, CLAUDE.md, settings)");
|
|
1761
2109
|
await copyDirectoryContents(
|
|
1762
|
-
|
|
1763
|
-
|
|
2110
|
+
join14(templateDir, ".claude", "commands"),
|
|
2111
|
+
join14(targetDir, ".cursor", "commands")
|
|
1764
2112
|
);
|
|
1765
2113
|
await copyFile(
|
|
1766
|
-
|
|
1767
|
-
|
|
2114
|
+
join14(templateDir, ".cursor", "hooks.json"),
|
|
2115
|
+
join14(targetDir, ".cursor", "hooks.json")
|
|
1768
2116
|
);
|
|
1769
|
-
printStatus(".cursor/ (
|
|
2117
|
+
printStatus(".cursor/ (commands, hooks)");
|
|
1770
2118
|
await copyCursorRules(targetDir);
|
|
1771
2119
|
printStatus(".cursor/rules/");
|
|
1772
2120
|
await copyFile(
|
|
1773
|
-
|
|
1774
|
-
|
|
2121
|
+
join14(templateDir, "AGENTS.md"),
|
|
2122
|
+
join14(targetDir, "AGENTS.md")
|
|
1775
2123
|
);
|
|
1776
2124
|
printStatus("AGENTS.md");
|
|
1777
2125
|
await runManifestGeneration(targetDir);
|
|
@@ -1780,40 +2128,40 @@ var init_install = __esm({
|
|
|
1780
2128
|
console.log("Installing project templates...");
|
|
1781
2129
|
const userFiles = [
|
|
1782
2130
|
{
|
|
1783
|
-
src:
|
|
1784
|
-
dest:
|
|
2131
|
+
src: join14(templateDir, "flydocs", "context", "project.md"),
|
|
2132
|
+
dest: join14(targetDir, "flydocs", "context", "project.md"),
|
|
1785
2133
|
label: "flydocs/context/project.md"
|
|
1786
2134
|
},
|
|
1787
2135
|
{
|
|
1788
|
-
src:
|
|
1789
|
-
dest:
|
|
2136
|
+
src: join14(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2137
|
+
dest: join14(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
1790
2138
|
label: "flydocs/knowledge/INDEX.md"
|
|
1791
2139
|
},
|
|
1792
2140
|
{
|
|
1793
|
-
src:
|
|
1794
|
-
dest:
|
|
2141
|
+
src: join14(templateDir, "flydocs", "knowledge", "README.md"),
|
|
2142
|
+
dest: join14(targetDir, "flydocs", "knowledge", "README.md"),
|
|
1795
2143
|
label: "flydocs/knowledge/README.md"
|
|
1796
2144
|
},
|
|
1797
2145
|
{
|
|
1798
|
-
src:
|
|
2146
|
+
src: join14(
|
|
1799
2147
|
templateDir,
|
|
1800
2148
|
"flydocs",
|
|
1801
2149
|
"knowledge",
|
|
1802
2150
|
"product",
|
|
1803
2151
|
"personas.md"
|
|
1804
2152
|
),
|
|
1805
|
-
dest:
|
|
2153
|
+
dest: join14(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
1806
2154
|
label: "flydocs/knowledge/product/personas.md"
|
|
1807
2155
|
},
|
|
1808
2156
|
{
|
|
1809
|
-
src:
|
|
2157
|
+
src: join14(
|
|
1810
2158
|
templateDir,
|
|
1811
2159
|
"flydocs",
|
|
1812
2160
|
"knowledge",
|
|
1813
2161
|
"product",
|
|
1814
2162
|
"user-flows.md"
|
|
1815
2163
|
),
|
|
1816
|
-
dest:
|
|
2164
|
+
dest: join14(
|
|
1817
2165
|
targetDir,
|
|
1818
2166
|
"flydocs",
|
|
1819
2167
|
"knowledge",
|
|
@@ -1823,18 +2171,18 @@ var init_install = __esm({
|
|
|
1823
2171
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
1824
2172
|
},
|
|
1825
2173
|
{
|
|
1826
|
-
src:
|
|
1827
|
-
dest:
|
|
2174
|
+
src: join14(templateDir, "flydocs", "design-system", "README.md"),
|
|
2175
|
+
dest: join14(targetDir, "flydocs", "design-system", "README.md"),
|
|
1828
2176
|
label: "flydocs/design-system/README.md"
|
|
1829
2177
|
},
|
|
1830
2178
|
{
|
|
1831
|
-
src:
|
|
2179
|
+
src: join14(
|
|
1832
2180
|
templateDir,
|
|
1833
2181
|
"flydocs",
|
|
1834
2182
|
"design-system",
|
|
1835
2183
|
"component-patterns.md"
|
|
1836
2184
|
),
|
|
1837
|
-
dest:
|
|
2185
|
+
dest: join14(
|
|
1838
2186
|
targetDir,
|
|
1839
2187
|
"flydocs",
|
|
1840
2188
|
"design-system",
|
|
@@ -1843,13 +2191,13 @@ var init_install = __esm({
|
|
|
1843
2191
|
label: "flydocs/design-system/component-patterns.md"
|
|
1844
2192
|
},
|
|
1845
2193
|
{
|
|
1846
|
-
src:
|
|
1847
|
-
dest:
|
|
2194
|
+
src: join14(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2195
|
+
dest: join14(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
1848
2196
|
label: "flydocs/design-system/token-mapping.md"
|
|
1849
2197
|
},
|
|
1850
2198
|
{
|
|
1851
|
-
src:
|
|
1852
|
-
dest:
|
|
2199
|
+
src: join14(templateDir, "flydocs", "README.md"),
|
|
2200
|
+
dest: join14(targetDir, "flydocs", "README.md"),
|
|
1853
2201
|
label: "flydocs/README.md"
|
|
1854
2202
|
}
|
|
1855
2203
|
];
|
|
@@ -1863,14 +2211,10 @@ var init_install = __esm({
|
|
|
1863
2211
|
}
|
|
1864
2212
|
}
|
|
1865
2213
|
}
|
|
1866
|
-
const envExampleSrc =
|
|
2214
|
+
const envExampleSrc = join14(templateDir, ".env.example");
|
|
1867
2215
|
if (await pathExists(envExampleSrc)) {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
if (!hasEnv && !hasEnvExample) {
|
|
1871
|
-
await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
|
|
1872
|
-
printStatus(".env.example (new)");
|
|
1873
|
-
}
|
|
2216
|
+
await copyFile(envExampleSrc, join14(targetDir, ".env.example"));
|
|
2217
|
+
printStatus(".env.example");
|
|
1874
2218
|
}
|
|
1875
2219
|
await ensureGitignore(targetDir);
|
|
1876
2220
|
console.log();
|
|
@@ -1888,6 +2232,9 @@ var init_install = __esm({
|
|
|
1888
2232
|
} else {
|
|
1889
2233
|
printInfo("No framework detected in package.json");
|
|
1890
2234
|
}
|
|
2235
|
+
await capture("install_skills_chosen", {
|
|
2236
|
+
stack_detected: stack.raw
|
|
2237
|
+
});
|
|
1891
2238
|
console.log();
|
|
1892
2239
|
console.log("Checking for deprecated files...");
|
|
1893
2240
|
const deprecated = await scanDeprecated(targetDir);
|
|
@@ -1900,17 +2247,17 @@ var init_install = __esm({
|
|
|
1900
2247
|
" 1. Run /flydocs-setup to configure your project",
|
|
1901
2248
|
" 2. Start working with /start-session",
|
|
1902
2249
|
"",
|
|
1903
|
-
"
|
|
2250
|
+
"Docs: https://www.flydocs.ai/docs"
|
|
1904
2251
|
] : [
|
|
1905
2252
|
`Tier: ${tier}`,
|
|
1906
2253
|
`Version: ${version}`,
|
|
1907
2254
|
"",
|
|
1908
2255
|
"Next steps:",
|
|
1909
|
-
" 1.
|
|
1910
|
-
" 2. Run /flydocs-setup to configure your
|
|
2256
|
+
" 1. Run flydocs connect to set up your API key",
|
|
2257
|
+
" 2. Run /flydocs-setup to configure your workspace",
|
|
1911
2258
|
" 3. Start working with /start-session",
|
|
1912
2259
|
"",
|
|
1913
|
-
"
|
|
2260
|
+
"Docs: https://www.flydocs.ai/docs"
|
|
1914
2261
|
];
|
|
1915
2262
|
let copiedToClipboard = false;
|
|
1916
2263
|
try {
|
|
@@ -1929,6 +2276,7 @@ var init_install = __esm({
|
|
|
1929
2276
|
}
|
|
1930
2277
|
printCompletionBox("Installation Complete!", nextSteps);
|
|
1931
2278
|
printBetaCta();
|
|
2279
|
+
const detectedIdes = [];
|
|
1932
2280
|
try {
|
|
1933
2281
|
const { execSync: execSync2, spawn } = await import("child_process");
|
|
1934
2282
|
const isInstalled = (cmd) => {
|
|
@@ -1964,6 +2312,7 @@ var init_install = __esm({
|
|
|
1964
2312
|
passCommand: false
|
|
1965
2313
|
});
|
|
1966
2314
|
}
|
|
2315
|
+
detectedIdes.push(...ideOptions.map((o) => o.cmd));
|
|
1967
2316
|
if (ideOptions.length === 1) {
|
|
1968
2317
|
const ide = ideOptions[0];
|
|
1969
2318
|
const launchConfirm = await confirm2({
|
|
@@ -2022,6 +2371,9 @@ var init_install = __esm({
|
|
|
2022
2371
|
}
|
|
2023
2372
|
} catch {
|
|
2024
2373
|
}
|
|
2374
|
+
await capture("install_ide_detected", { ides: detectedIdes });
|
|
2375
|
+
await capture("install_completed", { tier, version });
|
|
2376
|
+
await flush();
|
|
2025
2377
|
try {
|
|
2026
2378
|
const updateResult = await checkForUpdate();
|
|
2027
2379
|
if (updateResult) {
|
|
@@ -2040,10 +2392,10 @@ __export(update_exports, {
|
|
|
2040
2392
|
default: () => update_default
|
|
2041
2393
|
});
|
|
2042
2394
|
import { defineCommand as defineCommand2 } from "citty";
|
|
2043
|
-
import { resolve as resolve3, join as
|
|
2044
|
-
import { mkdir as
|
|
2395
|
+
import { resolve as resolve3, join as join15 } from "path";
|
|
2396
|
+
import { mkdir as mkdir8, cp as cp2, readFile as readFile10, readdir as readdir3, rm as rm4 } from "fs/promises";
|
|
2045
2397
|
import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2046
|
-
import
|
|
2398
|
+
import pc7 from "picocolors";
|
|
2047
2399
|
var update_default;
|
|
2048
2400
|
var init_update = __esm({
|
|
2049
2401
|
"src/commands/update.ts"() {
|
|
@@ -2060,6 +2412,7 @@ var init_update = __esm({
|
|
|
2060
2412
|
init_gitignore();
|
|
2061
2413
|
init_post_install();
|
|
2062
2414
|
init_update_check();
|
|
2415
|
+
init_telemetry();
|
|
2063
2416
|
update_default = defineCommand2({
|
|
2064
2417
|
meta: {
|
|
2065
2418
|
name: "update",
|
|
@@ -2077,7 +2430,7 @@ var init_update = __esm({
|
|
|
2077
2430
|
},
|
|
2078
2431
|
tier: {
|
|
2079
2432
|
type: "string",
|
|
2080
|
-
description: "Change tier: 'local' (free) or 'cloud' (
|
|
2433
|
+
description: "Change tier: 'local' (free) or 'cloud' (managed)"
|
|
2081
2434
|
},
|
|
2082
2435
|
force: {
|
|
2083
2436
|
type: "boolean",
|
|
@@ -2102,6 +2455,7 @@ var init_update = __esm({
|
|
|
2102
2455
|
printBanner(version);
|
|
2103
2456
|
printInfo("Running in update mode \u2014 framework files will be refreshed");
|
|
2104
2457
|
console.log();
|
|
2458
|
+
await capture("update_started", { template_version: version });
|
|
2105
2459
|
let targetDir;
|
|
2106
2460
|
if (args.path) {
|
|
2107
2461
|
targetDir = resolve3(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
@@ -2146,9 +2500,9 @@ var init_update = __esm({
|
|
|
2146
2500
|
}
|
|
2147
2501
|
targetDir = resolve3(targetDir);
|
|
2148
2502
|
process.chdir(targetDir);
|
|
2149
|
-
const hasVersion = await pathExists(
|
|
2503
|
+
const hasVersion = await pathExists(join15(targetDir, ".flydocs", "version"));
|
|
2150
2504
|
const hasConfig = await pathExists(
|
|
2151
|
-
|
|
2505
|
+
join15(targetDir, ".flydocs", "config.json")
|
|
2152
2506
|
);
|
|
2153
2507
|
if (!hasVersion && !hasConfig) {
|
|
2154
2508
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2159,8 +2513,8 @@ var init_update = __esm({
|
|
|
2159
2513
|
console.log();
|
|
2160
2514
|
let currentVersion = "0.1.0";
|
|
2161
2515
|
if (hasVersion) {
|
|
2162
|
-
const vContent = await
|
|
2163
|
-
|
|
2516
|
+
const vContent = await readFile10(
|
|
2517
|
+
join15(targetDir, ".flydocs", "version"),
|
|
2164
2518
|
"utf-8"
|
|
2165
2519
|
);
|
|
2166
2520
|
currentVersion = vContent.trim();
|
|
@@ -2186,12 +2540,18 @@ var init_update = __esm({
|
|
|
2186
2540
|
process.exit(0);
|
|
2187
2541
|
}
|
|
2188
2542
|
}
|
|
2543
|
+
await capture("update_version_compared", {
|
|
2544
|
+
current_version: currentVersion,
|
|
2545
|
+
target_version: version,
|
|
2546
|
+
version_status: versionStatus,
|
|
2547
|
+
force: args.force
|
|
2548
|
+
});
|
|
2189
2549
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2190
2550
|
console.log();
|
|
2191
|
-
const changelogPath =
|
|
2551
|
+
const changelogPath = join15(templateDir, "CHANGELOG.md");
|
|
2192
2552
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2193
2553
|
if (whatsNew.length > 0) {
|
|
2194
|
-
console.log(
|
|
2554
|
+
console.log(pc7.cyan("What's new:"));
|
|
2195
2555
|
console.log();
|
|
2196
2556
|
for (const entry of whatsNew) {
|
|
2197
2557
|
console.log(` ${entry}`);
|
|
@@ -2200,23 +2560,23 @@ var init_update = __esm({
|
|
|
2200
2560
|
}
|
|
2201
2561
|
const now = /* @__PURE__ */ new Date();
|
|
2202
2562
|
const ts = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}${String(now.getSeconds()).padStart(2, "0")}`;
|
|
2203
|
-
const backupDir =
|
|
2204
|
-
await
|
|
2563
|
+
const backupDir = join15(targetDir, ".flydocs", `backup-${ts}`);
|
|
2564
|
+
await mkdir8(backupDir, { recursive: true });
|
|
2205
2565
|
if (hasConfig) {
|
|
2206
2566
|
await cp2(
|
|
2207
|
-
|
|
2208
|
-
|
|
2567
|
+
join15(targetDir, ".flydocs", "config.json"),
|
|
2568
|
+
join15(backupDir, "config.json")
|
|
2209
2569
|
);
|
|
2210
2570
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2211
2571
|
}
|
|
2212
2572
|
try {
|
|
2213
|
-
const flydocsDir =
|
|
2573
|
+
const flydocsDir = join15(targetDir, ".flydocs");
|
|
2214
2574
|
const entries = await readdir3(flydocsDir);
|
|
2215
2575
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2216
2576
|
if (backups.length > 3) {
|
|
2217
2577
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2218
2578
|
for (const old of toRemove) {
|
|
2219
|
-
await rm4(
|
|
2579
|
+
await rm4(join15(flydocsDir, old), { recursive: true, force: true });
|
|
2220
2580
|
}
|
|
2221
2581
|
}
|
|
2222
2582
|
} catch {
|
|
@@ -2253,74 +2613,118 @@ var init_update = __esm({
|
|
|
2253
2613
|
}
|
|
2254
2614
|
console.log("Replacing framework directories...");
|
|
2255
2615
|
await replaceDirectory(
|
|
2256
|
-
|
|
2257
|
-
|
|
2616
|
+
join15(templateDir, ".flydocs", "templates"),
|
|
2617
|
+
join15(targetDir, ".flydocs", "templates")
|
|
2258
2618
|
);
|
|
2259
2619
|
await replaceDirectory(
|
|
2260
|
-
|
|
2261
|
-
|
|
2620
|
+
join15(templateDir, ".flydocs", "hooks"),
|
|
2621
|
+
join15(targetDir, ".flydocs", "hooks")
|
|
2262
2622
|
);
|
|
2263
2623
|
await replaceDirectory(
|
|
2264
|
-
|
|
2265
|
-
|
|
2624
|
+
join15(templateDir, ".flydocs", "scripts"),
|
|
2625
|
+
join15(targetDir, ".flydocs", "scripts")
|
|
2266
2626
|
);
|
|
2267
2627
|
printStatus(".flydocs/templates, hooks, scripts");
|
|
2268
|
-
const
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2628
|
+
const hasExistingAgents = await pathExists(
|
|
2629
|
+
join15(targetDir, ".claude", "agents")
|
|
2630
|
+
);
|
|
2631
|
+
let installAgents;
|
|
2632
|
+
if (args.yes) {
|
|
2633
|
+
installAgents = hasExistingAgents ? true : true;
|
|
2634
|
+
} else if (hasExistingAgents) {
|
|
2635
|
+
installAgents = true;
|
|
2636
|
+
} else {
|
|
2637
|
+
console.log();
|
|
2638
|
+
console.log(` ${pc7.bold(pc7.yellow("Sub-Agents (Recommended)"))}`);
|
|
2639
|
+
console.log();
|
|
2640
|
+
console.log(
|
|
2641
|
+
" Sub-agents are specialized roles (PM, implementation, review,"
|
|
2642
|
+
);
|
|
2643
|
+
console.log(
|
|
2644
|
+
" research) that your AI tool can delegate tasks to. They help"
|
|
2273
2645
|
);
|
|
2646
|
+
console.log(
|
|
2647
|
+
" structure work but are not required \u2014 everything works without them."
|
|
2648
|
+
);
|
|
2649
|
+
console.log();
|
|
2650
|
+
const agentConfirm = await confirm3({
|
|
2651
|
+
message: "Install sub-agents?",
|
|
2652
|
+
initialValue: true
|
|
2653
|
+
});
|
|
2654
|
+
if (isCancel4(agentConfirm)) {
|
|
2655
|
+
installAgents = false;
|
|
2656
|
+
} else {
|
|
2657
|
+
installAgents = agentConfirm;
|
|
2658
|
+
}
|
|
2274
2659
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2660
|
+
if (installAgents) {
|
|
2661
|
+
const claudeAgentsSrc = join15(templateDir, ".claude", "agents");
|
|
2662
|
+
if (await pathExists(claudeAgentsSrc)) {
|
|
2663
|
+
await mkdir8(join15(targetDir, ".claude", "agents"), { recursive: true });
|
|
2664
|
+
await copyDirectoryContents(
|
|
2665
|
+
claudeAgentsSrc,
|
|
2666
|
+
join15(targetDir, ".claude", "agents")
|
|
2667
|
+
);
|
|
2668
|
+
}
|
|
2669
|
+
const cursorAgentsSrc = join15(templateDir, ".cursor", "agents");
|
|
2670
|
+
if (await pathExists(cursorAgentsSrc)) {
|
|
2671
|
+
await mkdir8(join15(targetDir, ".cursor", "agents"), { recursive: true });
|
|
2672
|
+
await copyDirectoryContents(
|
|
2673
|
+
cursorAgentsSrc,
|
|
2674
|
+
join15(targetDir, ".cursor", "agents")
|
|
2675
|
+
);
|
|
2676
|
+
}
|
|
2677
|
+
printStatus(
|
|
2678
|
+
hasExistingAgents ? "Sub-agents updated (.claude/agents, .cursor/agents)" : "Sub-agents installed (.claude/agents, .cursor/agents)"
|
|
2283
2679
|
);
|
|
2680
|
+
} else {
|
|
2681
|
+
printInfo("Skipped sub-agents");
|
|
2284
2682
|
}
|
|
2285
|
-
|
|
2683
|
+
await replaceOwnedSkills(templateDir, targetDir, effectiveTier);
|
|
2684
|
+
printStatus(`.claude/skills (tier: ${effectiveTier})`);
|
|
2286
2685
|
console.log();
|
|
2287
2686
|
console.log("Replacing framework files...");
|
|
2288
2687
|
await copyFile(
|
|
2289
|
-
|
|
2290
|
-
|
|
2688
|
+
join15(templateDir, ".claude", "CLAUDE.md"),
|
|
2689
|
+
join15(targetDir, ".claude", "CLAUDE.md")
|
|
2291
2690
|
);
|
|
2292
2691
|
await copyFile(
|
|
2293
|
-
|
|
2294
|
-
|
|
2692
|
+
join15(templateDir, ".claude", "settings.json"),
|
|
2693
|
+
join15(targetDir, ".claude", "settings.json")
|
|
2295
2694
|
);
|
|
2296
2695
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2297
2696
|
await copyDirectoryContents(
|
|
2298
|
-
|
|
2299
|
-
|
|
2697
|
+
join15(templateDir, ".claude", "commands"),
|
|
2698
|
+
join15(targetDir, ".claude", "commands")
|
|
2300
2699
|
);
|
|
2301
2700
|
await copyDirectoryContents(
|
|
2302
|
-
|
|
2303
|
-
|
|
2701
|
+
join15(templateDir, ".claude", "commands"),
|
|
2702
|
+
join15(targetDir, ".cursor", "commands")
|
|
2304
2703
|
);
|
|
2305
2704
|
printStatus(".claude/commands, .cursor/commands");
|
|
2306
|
-
const skillsReadmeSrc =
|
|
2705
|
+
const skillsReadmeSrc = join15(templateDir, ".claude", "skills", "README.md");
|
|
2307
2706
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2308
2707
|
await copyFile(
|
|
2309
2708
|
skillsReadmeSrc,
|
|
2310
|
-
|
|
2709
|
+
join15(targetDir, ".claude", "skills", "README.md")
|
|
2311
2710
|
);
|
|
2312
2711
|
}
|
|
2313
2712
|
printStatus(".claude/skills/README.md");
|
|
2314
2713
|
await copyFile(
|
|
2315
|
-
|
|
2316
|
-
|
|
2714
|
+
join15(templateDir, ".cursor", "hooks.json"),
|
|
2715
|
+
join15(targetDir, ".cursor", "hooks.json")
|
|
2317
2716
|
);
|
|
2318
2717
|
printStatus(".cursor/hooks.json");
|
|
2319
2718
|
await copyFile(
|
|
2320
|
-
|
|
2321
|
-
|
|
2719
|
+
join15(templateDir, "AGENTS.md"),
|
|
2720
|
+
join15(targetDir, "AGENTS.md")
|
|
2322
2721
|
);
|
|
2323
2722
|
printStatus("AGENTS.md");
|
|
2723
|
+
const envExampleSrc = join15(templateDir, ".env.example");
|
|
2724
|
+
if (await pathExists(envExampleSrc)) {
|
|
2725
|
+
await copyFile(envExampleSrc, join15(targetDir, ".env.example"));
|
|
2726
|
+
printStatus(".env.example");
|
|
2727
|
+
}
|
|
2324
2728
|
await runManifestGeneration(targetDir);
|
|
2325
2729
|
await runContextGraphBuild(targetDir);
|
|
2326
2730
|
console.log();
|
|
@@ -2343,18 +2747,18 @@ var init_update = __esm({
|
|
|
2343
2747
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2344
2748
|
}
|
|
2345
2749
|
await copyFile(
|
|
2346
|
-
|
|
2347
|
-
|
|
2750
|
+
join15(templateDir, ".flydocs", "version"),
|
|
2751
|
+
join15(targetDir, ".flydocs", "version")
|
|
2348
2752
|
);
|
|
2349
2753
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2350
|
-
const clSrc =
|
|
2754
|
+
const clSrc = join15(templateDir, "CHANGELOG.md");
|
|
2351
2755
|
if (await pathExists(clSrc)) {
|
|
2352
|
-
await copyFile(clSrc,
|
|
2756
|
+
await copyFile(clSrc, join15(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2353
2757
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2354
2758
|
}
|
|
2355
|
-
const mfSrc =
|
|
2759
|
+
const mfSrc = join15(templateDir, "manifest.json");
|
|
2356
2760
|
if (await pathExists(mfSrc)) {
|
|
2357
|
-
await copyFile(mfSrc,
|
|
2761
|
+
await copyFile(mfSrc, join15(targetDir, ".flydocs", "manifest.json"));
|
|
2358
2762
|
printStatus(".flydocs/manifest.json");
|
|
2359
2763
|
}
|
|
2360
2764
|
console.log();
|
|
@@ -2390,6 +2794,12 @@ var init_update = __esm({
|
|
|
2390
2794
|
`Backup: .flydocs/backup-${ts}/`
|
|
2391
2795
|
]);
|
|
2392
2796
|
printBetaCta();
|
|
2797
|
+
await capture("update_completed", {
|
|
2798
|
+
current_version: currentVersion,
|
|
2799
|
+
version,
|
|
2800
|
+
tier: effectiveTier
|
|
2801
|
+
});
|
|
2802
|
+
await flush();
|
|
2393
2803
|
try {
|
|
2394
2804
|
const updateResult = await checkForUpdate();
|
|
2395
2805
|
if (updateResult) {
|
|
@@ -2402,33 +2812,352 @@ var init_update = __esm({
|
|
|
2402
2812
|
}
|
|
2403
2813
|
});
|
|
2404
2814
|
|
|
2815
|
+
// src/commands/uninstall.ts
|
|
2816
|
+
var uninstall_exports = {};
|
|
2817
|
+
__export(uninstall_exports, {
|
|
2818
|
+
default: () => uninstall_default
|
|
2819
|
+
});
|
|
2820
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
2821
|
+
import { resolve as resolve4, join as join16 } from "path";
|
|
2822
|
+
import { readdir as readdir4, rm as rm5, rename as rename2 } from "fs/promises";
|
|
2823
|
+
import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
2824
|
+
import pc8 from "picocolors";
|
|
2825
|
+
async function removeOwnedSkills(targetDir) {
|
|
2826
|
+
const skillsDir = join16(targetDir, ".claude", "skills");
|
|
2827
|
+
const removed = [];
|
|
2828
|
+
if (!await pathExists(skillsDir)) {
|
|
2829
|
+
return removed;
|
|
2830
|
+
}
|
|
2831
|
+
try {
|
|
2832
|
+
const entries = await readdir4(skillsDir);
|
|
2833
|
+
for (const entry of entries) {
|
|
2834
|
+
if (entry.startsWith(OWNED_SKILL_PREFIX)) {
|
|
2835
|
+
await rm5(join16(skillsDir, entry), { recursive: true, force: true });
|
|
2836
|
+
removed.push(`.claude/skills/${entry}`);
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
} catch {
|
|
2840
|
+
}
|
|
2841
|
+
return removed;
|
|
2842
|
+
}
|
|
2843
|
+
async function removeOwnedCursorRules(targetDir) {
|
|
2844
|
+
const rulesDir = join16(targetDir, ".cursor", "rules");
|
|
2845
|
+
const removed = [];
|
|
2846
|
+
if (!await pathExists(rulesDir)) {
|
|
2847
|
+
return removed;
|
|
2848
|
+
}
|
|
2849
|
+
try {
|
|
2850
|
+
const entries = await readdir4(rulesDir);
|
|
2851
|
+
for (const entry of entries) {
|
|
2852
|
+
if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
|
|
2853
|
+
await rm5(join16(rulesDir, entry), { force: true });
|
|
2854
|
+
removed.push(`.cursor/rules/${entry}`);
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
} catch {
|
|
2858
|
+
}
|
|
2859
|
+
return removed;
|
|
2860
|
+
}
|
|
2861
|
+
async function isEmptyDir(dirPath) {
|
|
2862
|
+
try {
|
|
2863
|
+
const entries = await readdir4(dirPath);
|
|
2864
|
+
return entries.length === 0;
|
|
2865
|
+
} catch {
|
|
2866
|
+
return false;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
async function cleanupEmptyParents(targetDir, dirs) {
|
|
2870
|
+
const cleaned = [];
|
|
2871
|
+
for (const dir of dirs) {
|
|
2872
|
+
const fullPath = join16(targetDir, dir);
|
|
2873
|
+
if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
|
|
2874
|
+
await rm5(fullPath, { recursive: true, force: true });
|
|
2875
|
+
cleaned.push(dir);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
return cleaned;
|
|
2879
|
+
}
|
|
2880
|
+
var ALWAYS_REMOVED, OWNED_SKILL_PREFIX, OWNED_RULE_PREFIX, uninstall_default;
|
|
2881
|
+
var init_uninstall = __esm({
|
|
2882
|
+
"src/commands/uninstall.ts"() {
|
|
2883
|
+
"use strict";
|
|
2884
|
+
init_fs_ops();
|
|
2885
|
+
init_user_content();
|
|
2886
|
+
init_ui();
|
|
2887
|
+
init_constants();
|
|
2888
|
+
ALWAYS_REMOVED = [
|
|
2889
|
+
[".claude/CLAUDE.md", "file"],
|
|
2890
|
+
[".claude/settings.json", "file"],
|
|
2891
|
+
[".claude/agents", "dir"],
|
|
2892
|
+
[".claude/commands", "dir"],
|
|
2893
|
+
[".claude/skills/README.md", "file"],
|
|
2894
|
+
[".cursor/hooks.json", "file"],
|
|
2895
|
+
[".cursor/agents", "dir"],
|
|
2896
|
+
[".flydocs", "dir"],
|
|
2897
|
+
["AGENTS.md", "file"],
|
|
2898
|
+
[".env.example", "file"]
|
|
2899
|
+
];
|
|
2900
|
+
OWNED_SKILL_PREFIX = "flydocs-";
|
|
2901
|
+
OWNED_RULE_PREFIX = "flydocs-";
|
|
2902
|
+
uninstall_default = defineCommand3({
|
|
2903
|
+
meta: {
|
|
2904
|
+
name: "uninstall",
|
|
2905
|
+
description: "Remove FlyDocs from a project directory"
|
|
2906
|
+
},
|
|
2907
|
+
args: {
|
|
2908
|
+
path: {
|
|
2909
|
+
type: "string",
|
|
2910
|
+
description: "Uninstall from the specified directory"
|
|
2911
|
+
},
|
|
2912
|
+
here: {
|
|
2913
|
+
type: "boolean",
|
|
2914
|
+
description: "Uninstall from the current directory",
|
|
2915
|
+
default: false
|
|
2916
|
+
},
|
|
2917
|
+
all: {
|
|
2918
|
+
type: "boolean",
|
|
2919
|
+
description: "Remove everything including flydocs/ user content",
|
|
2920
|
+
default: false
|
|
2921
|
+
},
|
|
2922
|
+
yes: {
|
|
2923
|
+
type: "boolean",
|
|
2924
|
+
alias: ["y"],
|
|
2925
|
+
description: "Skip confirmation prompts",
|
|
2926
|
+
default: false
|
|
2927
|
+
},
|
|
2928
|
+
force: {
|
|
2929
|
+
type: "boolean",
|
|
2930
|
+
description: "Alias for --all --yes (complete removal, no prompts)",
|
|
2931
|
+
default: false
|
|
2932
|
+
}
|
|
2933
|
+
},
|
|
2934
|
+
async run({ args }) {
|
|
2935
|
+
printBanner(CLI_VERSION);
|
|
2936
|
+
let targetDir;
|
|
2937
|
+
if (args.path) {
|
|
2938
|
+
targetDir = resolve4(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
2939
|
+
} else if (args.here) {
|
|
2940
|
+
targetDir = process.cwd();
|
|
2941
|
+
} else {
|
|
2942
|
+
targetDir = process.cwd();
|
|
2943
|
+
}
|
|
2944
|
+
if (!await pathExists(targetDir)) {
|
|
2945
|
+
printError(`Directory does not exist: ${targetDir}`);
|
|
2946
|
+
process.exit(1);
|
|
2947
|
+
}
|
|
2948
|
+
targetDir = resolve4(targetDir);
|
|
2949
|
+
const hasFlydocs = await pathExists(join16(targetDir, ".flydocs"));
|
|
2950
|
+
const hasAgentsMd = await pathExists(join16(targetDir, "AGENTS.md"));
|
|
2951
|
+
if (!hasFlydocs && !hasAgentsMd) {
|
|
2952
|
+
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
2953
|
+
printInfo("No .flydocs/ directory or AGENTS.md found.");
|
|
2954
|
+
process.exit(1);
|
|
2955
|
+
}
|
|
2956
|
+
printInfo(`Project: ${targetDir}`);
|
|
2957
|
+
console.log();
|
|
2958
|
+
const forceAll = args.force;
|
|
2959
|
+
const removeAll = forceAll || args.all;
|
|
2960
|
+
const skipPrompts = forceAll || args.yes;
|
|
2961
|
+
let contentAction = "preserve";
|
|
2962
|
+
const hasUserContent = await pathExists(join16(targetDir, "flydocs"));
|
|
2963
|
+
if (hasUserContent) {
|
|
2964
|
+
if (removeAll) {
|
|
2965
|
+
contentAction = "remove";
|
|
2966
|
+
} else if (!skipPrompts) {
|
|
2967
|
+
const choice = await select3({
|
|
2968
|
+
message: "What should happen to your flydocs/ content (project docs, knowledge base)?",
|
|
2969
|
+
options: [
|
|
2970
|
+
{
|
|
2971
|
+
value: "archive",
|
|
2972
|
+
label: "Archive",
|
|
2973
|
+
hint: "Rename to flydocs-archive/ (safe, reversible)"
|
|
2974
|
+
},
|
|
2975
|
+
{
|
|
2976
|
+
value: "remove",
|
|
2977
|
+
label: "Remove completely",
|
|
2978
|
+
hint: "Permanently delete flydocs/ and all contents"
|
|
2979
|
+
},
|
|
2980
|
+
{
|
|
2981
|
+
value: "preserve",
|
|
2982
|
+
label: "Keep as-is",
|
|
2983
|
+
hint: "Leave flydocs/ untouched"
|
|
2984
|
+
}
|
|
2985
|
+
]
|
|
2986
|
+
});
|
|
2987
|
+
if (isCancel5(choice)) {
|
|
2988
|
+
cancel4("Uninstall cancelled.");
|
|
2989
|
+
process.exit(0);
|
|
2990
|
+
}
|
|
2991
|
+
contentAction = choice;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
if (!skipPrompts) {
|
|
2995
|
+
console.log();
|
|
2996
|
+
console.log(pc8.bold("The following will be removed:"));
|
|
2997
|
+
console.log();
|
|
2998
|
+
console.log(" Framework files:");
|
|
2999
|
+
for (const [path] of ALWAYS_REMOVED) {
|
|
3000
|
+
console.log(` ${pc8.dim(path)}`);
|
|
3001
|
+
}
|
|
3002
|
+
console.log(` ${pc8.dim(".claude/skills/flydocs-*")}`);
|
|
3003
|
+
console.log(` ${pc8.dim(".cursor/rules/flydocs-*.mdc")}`);
|
|
3004
|
+
if (hasUserContent) {
|
|
3005
|
+
if (contentAction === "archive") {
|
|
3006
|
+
console.log();
|
|
3007
|
+
console.log(
|
|
3008
|
+
` User content: ${pc8.yellow("flydocs/ -> flydocs-archive/")}`
|
|
3009
|
+
);
|
|
3010
|
+
} else if (contentAction === "remove") {
|
|
3011
|
+
console.log();
|
|
3012
|
+
console.log(` User content: ${pc8.red("flydocs/ (deleted)")}`);
|
|
3013
|
+
} else {
|
|
3014
|
+
console.log();
|
|
3015
|
+
console.log(` User content: ${pc8.green("flydocs/ (preserved)")}`);
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
console.log();
|
|
3019
|
+
console.log(pc8.bold("Preserved:"));
|
|
3020
|
+
console.log(
|
|
3021
|
+
` ${pc8.dim(".claude/skills/ (non-flydocs community skills)")}`
|
|
3022
|
+
);
|
|
3023
|
+
console.log(` ${pc8.dim(".env, .env.local")}`);
|
|
3024
|
+
console.log();
|
|
3025
|
+
const shouldContinue = await confirm4({
|
|
3026
|
+
message: "Proceed with uninstall?"
|
|
3027
|
+
});
|
|
3028
|
+
if (isCancel5(shouldContinue) || !shouldContinue) {
|
|
3029
|
+
cancel4("Uninstall cancelled.");
|
|
3030
|
+
process.exit(0);
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
const originals = await readBackupOriginals(targetDir);
|
|
3034
|
+
const result = {
|
|
3035
|
+
removed: [],
|
|
3036
|
+
skipped: [],
|
|
3037
|
+
archived: [],
|
|
3038
|
+
restored: []
|
|
3039
|
+
};
|
|
3040
|
+
const removedSkills = await removeOwnedSkills(targetDir);
|
|
3041
|
+
result.removed.push(...removedSkills);
|
|
3042
|
+
const removedRules = await removeOwnedCursorRules(targetDir);
|
|
3043
|
+
result.removed.push(...removedRules);
|
|
3044
|
+
for (const [relativePath, type] of ALWAYS_REMOVED) {
|
|
3045
|
+
const fullPath = join16(targetDir, relativePath);
|
|
3046
|
+
if (!await pathExists(fullPath)) {
|
|
3047
|
+
result.skipped.push(relativePath);
|
|
3048
|
+
continue;
|
|
3049
|
+
}
|
|
3050
|
+
try {
|
|
3051
|
+
if (type === "dir") {
|
|
3052
|
+
await rm5(fullPath, { recursive: true, force: true });
|
|
3053
|
+
} else {
|
|
3054
|
+
await rm5(fullPath, { force: true });
|
|
3055
|
+
}
|
|
3056
|
+
result.removed.push(relativePath);
|
|
3057
|
+
} catch {
|
|
3058
|
+
printWarning(`Could not remove: ${relativePath}`);
|
|
3059
|
+
result.skipped.push(relativePath);
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
if (hasUserContent) {
|
|
3063
|
+
const flydocsPath = join16(targetDir, "flydocs");
|
|
3064
|
+
if (contentAction === "archive") {
|
|
3065
|
+
const archivePath = join16(targetDir, "flydocs-archive");
|
|
3066
|
+
if (await pathExists(archivePath)) {
|
|
3067
|
+
await rm5(archivePath, { recursive: true, force: true });
|
|
3068
|
+
}
|
|
3069
|
+
await rename2(flydocsPath, archivePath);
|
|
3070
|
+
result.archived.push("flydocs/ -> flydocs-archive/");
|
|
3071
|
+
} else if (contentAction === "remove") {
|
|
3072
|
+
await rm5(flydocsPath, { recursive: true, force: true });
|
|
3073
|
+
result.removed.push("flydocs/");
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
const emptyCandidates = [
|
|
3077
|
+
".claude/skills",
|
|
3078
|
+
".claude",
|
|
3079
|
+
".cursor/rules",
|
|
3080
|
+
".cursor"
|
|
3081
|
+
];
|
|
3082
|
+
const cleaned = await cleanupEmptyParents(targetDir, emptyCandidates);
|
|
3083
|
+
for (const dir of cleaned) {
|
|
3084
|
+
result.removed.push(`${dir}/ (empty, cleaned up)`);
|
|
3085
|
+
}
|
|
3086
|
+
if (originals.length > 0) {
|
|
3087
|
+
await writeRestoredFiles(targetDir, originals);
|
|
3088
|
+
result.restored = originals.map((f) => f.relativePath);
|
|
3089
|
+
}
|
|
3090
|
+
console.log();
|
|
3091
|
+
console.log(pc8.bold("Uninstall Summary"));
|
|
3092
|
+
console.log();
|
|
3093
|
+
if (result.removed.length > 0) {
|
|
3094
|
+
console.log(` ${pc8.green("Removed")} (${result.removed.length}):`);
|
|
3095
|
+
for (const item of result.removed) {
|
|
3096
|
+
printStatus(item);
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
if (result.archived.length > 0) {
|
|
3100
|
+
console.log();
|
|
3101
|
+
console.log(` ${pc8.yellow("Archived")} (${result.archived.length}):`);
|
|
3102
|
+
for (const item of result.archived) {
|
|
3103
|
+
printInfo(item);
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
if (result.restored.length > 0) {
|
|
3107
|
+
console.log();
|
|
3108
|
+
console.log(
|
|
3109
|
+
` ${pc8.green("Restored")} (${result.restored.length} pre-FlyDocs original(s)):`
|
|
3110
|
+
);
|
|
3111
|
+
for (const item of result.restored) {
|
|
3112
|
+
printInfo(item);
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
if (result.skipped.length > 0) {
|
|
3116
|
+
console.log();
|
|
3117
|
+
console.log(
|
|
3118
|
+
` ${pc8.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
|
|
3119
|
+
);
|
|
3120
|
+
for (const item of result.skipped) {
|
|
3121
|
+
console.log(` ${pc8.dim(item)}`);
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
console.log();
|
|
3125
|
+
printStatus("FlyDocs has been removed from this project.");
|
|
3126
|
+
console.log();
|
|
3127
|
+
printInfo(`To reinstall: ${pc8.cyan("npx @flydocs/cli install --here")}`);
|
|
3128
|
+
console.log();
|
|
3129
|
+
}
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
});
|
|
3133
|
+
|
|
2405
3134
|
// src/commands/setup.ts
|
|
2406
3135
|
var setup_exports = {};
|
|
2407
3136
|
__export(setup_exports, {
|
|
2408
3137
|
default: () => setup_default
|
|
2409
3138
|
});
|
|
2410
|
-
import { defineCommand as
|
|
2411
|
-
import
|
|
3139
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
3140
|
+
import pc9 from "picocolors";
|
|
2412
3141
|
var setup_default;
|
|
2413
3142
|
var init_setup = __esm({
|
|
2414
3143
|
"src/commands/setup.ts"() {
|
|
2415
3144
|
"use strict";
|
|
2416
|
-
setup_default =
|
|
3145
|
+
setup_default = defineCommand4({
|
|
2417
3146
|
meta: {
|
|
2418
3147
|
name: "setup",
|
|
2419
3148
|
description: "Configure FlyDocs settings for this project"
|
|
2420
3149
|
},
|
|
2421
3150
|
run() {
|
|
2422
3151
|
console.log();
|
|
2423
|
-
console.log(` ${
|
|
3152
|
+
console.log(` ${pc9.bold("FlyDocs Setup")}`);
|
|
2424
3153
|
console.log();
|
|
2425
3154
|
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
2426
3155
|
console.log();
|
|
2427
3156
|
console.log(
|
|
2428
|
-
` ${
|
|
3157
|
+
` ${pc9.cyan("Claude Code:")} Type ${pc9.bold("/flydocs-setup")} in chat`
|
|
2429
3158
|
);
|
|
2430
3159
|
console.log(
|
|
2431
|
-
` ${
|
|
3160
|
+
` ${pc9.cyan("Cursor:")} Type ${pc9.bold("/flydocs-setup")} in chat`
|
|
2432
3161
|
);
|
|
2433
3162
|
console.log();
|
|
2434
3163
|
console.log(` This configures your project context, detects your stack,`);
|
|
@@ -2444,14 +3173,14 @@ var skills_exports = {};
|
|
|
2444
3173
|
__export(skills_exports, {
|
|
2445
3174
|
default: () => skills_default
|
|
2446
3175
|
});
|
|
2447
|
-
import { defineCommand as
|
|
2448
|
-
import
|
|
3176
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
3177
|
+
import pc10 from "picocolors";
|
|
2449
3178
|
var list, search, add, remove, skills_default;
|
|
2450
3179
|
var init_skills2 = __esm({
|
|
2451
3180
|
"src/commands/skills.ts"() {
|
|
2452
3181
|
"use strict";
|
|
2453
3182
|
init_skill_manager();
|
|
2454
|
-
list =
|
|
3183
|
+
list = defineCommand5({
|
|
2455
3184
|
meta: {
|
|
2456
3185
|
name: "list",
|
|
2457
3186
|
description: "List installed skills"
|
|
@@ -2467,26 +3196,26 @@ var init_skills2 = __esm({
|
|
|
2467
3196
|
console.log(`${total} skill(s) installed:`);
|
|
2468
3197
|
if (result.platform.length > 0) {
|
|
2469
3198
|
console.log();
|
|
2470
|
-
console.log(
|
|
3199
|
+
console.log(pc10.bold("Platform"));
|
|
2471
3200
|
for (const skill of result.platform) {
|
|
2472
3201
|
console.log(
|
|
2473
|
-
` ${skill.name} ${
|
|
3202
|
+
` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
|
|
2474
3203
|
);
|
|
2475
3204
|
}
|
|
2476
3205
|
}
|
|
2477
3206
|
if (result.community.length > 0) {
|
|
2478
3207
|
console.log();
|
|
2479
|
-
console.log(
|
|
3208
|
+
console.log(pc10.bold("Community"));
|
|
2480
3209
|
for (const skill of result.community) {
|
|
2481
3210
|
console.log(
|
|
2482
|
-
` ${skill.name} ${
|
|
3211
|
+
` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
|
|
2483
3212
|
);
|
|
2484
3213
|
}
|
|
2485
3214
|
}
|
|
2486
3215
|
console.log();
|
|
2487
3216
|
}
|
|
2488
3217
|
});
|
|
2489
|
-
search =
|
|
3218
|
+
search = defineCommand5({
|
|
2490
3219
|
meta: {
|
|
2491
3220
|
name: "search",
|
|
2492
3221
|
description: "Search community skills"
|
|
@@ -2502,24 +3231,24 @@ var init_skills2 = __esm({
|
|
|
2502
3231
|
const results = await searchCatalog(args.keyword);
|
|
2503
3232
|
if (results.length === 0) {
|
|
2504
3233
|
console.log(`No skills found for "${args.keyword}".`);
|
|
2505
|
-
console.log(` Browse the catalog at: ${
|
|
3234
|
+
console.log(` Browse the catalog at: ${pc10.cyan("https://skills.sh/")}`);
|
|
2506
3235
|
return;
|
|
2507
3236
|
}
|
|
2508
3237
|
console.log();
|
|
2509
3238
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
2510
3239
|
console.log();
|
|
2511
3240
|
for (const skill of results) {
|
|
2512
|
-
console.log(` ${
|
|
3241
|
+
console.log(` ${pc10.bold(skill.name)}`);
|
|
2513
3242
|
console.log(` ${skill.description}`);
|
|
2514
|
-
console.log(` ${
|
|
3243
|
+
console.log(` ${pc10.dim(skill.repo)}`);
|
|
2515
3244
|
if (skill.tags.length > 0) {
|
|
2516
|
-
console.log(` ${
|
|
3245
|
+
console.log(` ${pc10.dim(skill.tags.join(", "))}`);
|
|
2517
3246
|
}
|
|
2518
3247
|
console.log();
|
|
2519
3248
|
}
|
|
2520
3249
|
}
|
|
2521
3250
|
});
|
|
2522
|
-
add =
|
|
3251
|
+
add = defineCommand5({
|
|
2523
3252
|
meta: {
|
|
2524
3253
|
name: "add",
|
|
2525
3254
|
description: "Install a community skill"
|
|
@@ -2535,7 +3264,7 @@ var init_skills2 = __esm({
|
|
|
2535
3264
|
await addSkill(process.cwd(), args.source);
|
|
2536
3265
|
}
|
|
2537
3266
|
});
|
|
2538
|
-
remove =
|
|
3267
|
+
remove = defineCommand5({
|
|
2539
3268
|
meta: {
|
|
2540
3269
|
name: "remove",
|
|
2541
3270
|
description: "Remove an installed community skill"
|
|
@@ -2551,7 +3280,7 @@ var init_skills2 = __esm({
|
|
|
2551
3280
|
await removeSkill(process.cwd(), args.name);
|
|
2552
3281
|
}
|
|
2553
3282
|
});
|
|
2554
|
-
skills_default =
|
|
3283
|
+
skills_default = defineCommand5({
|
|
2555
3284
|
meta: {
|
|
2556
3285
|
name: "skills",
|
|
2557
3286
|
description: "Manage FlyDocs skills (list, search, add, remove)"
|
|
@@ -2571,11 +3300,71 @@ var connect_exports = {};
|
|
|
2571
3300
|
__export(connect_exports, {
|
|
2572
3301
|
default: () => connect_default
|
|
2573
3302
|
});
|
|
2574
|
-
import { defineCommand as
|
|
2575
|
-
import { text as text2, confirm as
|
|
2576
|
-
import
|
|
2577
|
-
import { readFile as
|
|
2578
|
-
import { join as
|
|
3303
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
3304
|
+
import { text as text2, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
|
|
3305
|
+
import pc11 from "picocolors";
|
|
3306
|
+
import { readFile as readFile11, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
|
|
3307
|
+
import { join as join17 } from "path";
|
|
3308
|
+
function detectKeyType(key) {
|
|
3309
|
+
if (key.startsWith("fdk_")) return "relay";
|
|
3310
|
+
if (key.startsWith("lin_api_")) return "direct";
|
|
3311
|
+
return "unknown";
|
|
3312
|
+
}
|
|
3313
|
+
async function validateRelayKey(apiKey) {
|
|
3314
|
+
const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
|
|
3315
|
+
const response = await fetch(`${baseUrl}/auth/validate`, {
|
|
3316
|
+
method: "POST",
|
|
3317
|
+
headers: {
|
|
3318
|
+
Authorization: `Bearer ${apiKey}`,
|
|
3319
|
+
"Content-Type": "application/json"
|
|
3320
|
+
},
|
|
3321
|
+
signal: AbortSignal.timeout(15e3)
|
|
3322
|
+
});
|
|
3323
|
+
if (!response.ok) return { valid: false };
|
|
3324
|
+
const data = await response.json();
|
|
3325
|
+
if (!data.valid) return { valid: false };
|
|
3326
|
+
return { valid: true, org: data.org ?? "your organization" };
|
|
3327
|
+
}
|
|
3328
|
+
async function validateLinearKey(apiKey) {
|
|
3329
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
3330
|
+
method: "POST",
|
|
3331
|
+
headers: {
|
|
3332
|
+
Authorization: apiKey,
|
|
3333
|
+
"Content-Type": "application/json"
|
|
3334
|
+
},
|
|
3335
|
+
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
3336
|
+
signal: AbortSignal.timeout(15e3)
|
|
3337
|
+
});
|
|
3338
|
+
if (!response.ok) return { valid: false };
|
|
3339
|
+
const data = await response.json();
|
|
3340
|
+
if (!data.data?.viewer) return { valid: false };
|
|
3341
|
+
return {
|
|
3342
|
+
valid: true,
|
|
3343
|
+
name: data.data.viewer.name,
|
|
3344
|
+
email: data.data.viewer.email
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3347
|
+
async function storeEnvKey(targetDir, envVarName, value) {
|
|
3348
|
+
const envPath = join17(targetDir, ".env");
|
|
3349
|
+
const envLocalPath = join17(targetDir, ".env.local");
|
|
3350
|
+
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
3351
|
+
const pattern = new RegExp(`${envVarName}=.*`);
|
|
3352
|
+
if (await pathExists(targetEnvPath)) {
|
|
3353
|
+
const envContent = await readFile11(targetEnvPath, "utf-8");
|
|
3354
|
+
if (pattern.test(envContent)) {
|
|
3355
|
+
const updated = envContent.replace(pattern, `${envVarName}=${value}`);
|
|
3356
|
+
await writeFile7(targetEnvPath, updated, "utf-8");
|
|
3357
|
+
} else {
|
|
3358
|
+
await appendFile2(targetEnvPath, `
|
|
3359
|
+
${envVarName}=${value}
|
|
3360
|
+
`);
|
|
3361
|
+
}
|
|
3362
|
+
} else {
|
|
3363
|
+
await writeFile7(targetEnvPath, `${envVarName}=${value}
|
|
3364
|
+
`, "utf-8");
|
|
3365
|
+
}
|
|
3366
|
+
return targetEnvPath === envLocalPath ? ".env.local" : ".env";
|
|
3367
|
+
}
|
|
2579
3368
|
var connect_default;
|
|
2580
3369
|
var init_connect = __esm({
|
|
2581
3370
|
"src/commands/connect.ts"() {
|
|
@@ -2584,10 +3373,10 @@ var init_connect = __esm({
|
|
|
2584
3373
|
init_fs_ops();
|
|
2585
3374
|
init_template();
|
|
2586
3375
|
init_ui();
|
|
2587
|
-
connect_default =
|
|
3376
|
+
connect_default = defineCommand6({
|
|
2588
3377
|
meta: {
|
|
2589
3378
|
name: "connect",
|
|
2590
|
-
description: "Connect FlyDocs to a cloud provider
|
|
3379
|
+
description: "Connect FlyDocs to a cloud provider"
|
|
2591
3380
|
},
|
|
2592
3381
|
args: {
|
|
2593
3382
|
path: {
|
|
@@ -2604,16 +3393,16 @@ var init_connect = __esm({
|
|
|
2604
3393
|
},
|
|
2605
3394
|
key: {
|
|
2606
3395
|
type: "string",
|
|
2607
|
-
description: "
|
|
3396
|
+
description: "API key (fdk_ for relay, lin_api_ for direct Linear)"
|
|
2608
3397
|
}
|
|
2609
3398
|
},
|
|
2610
3399
|
async run({ args }) {
|
|
2611
3400
|
const targetDir = args.path ?? process.cwd();
|
|
2612
|
-
const configPath =
|
|
3401
|
+
const configPath = join17(targetDir, ".flydocs", "config.json");
|
|
2613
3402
|
if (!await pathExists(configPath)) {
|
|
2614
3403
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
2615
3404
|
console.log(
|
|
2616
|
-
` Run ${
|
|
3405
|
+
` Run ${pc11.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
2617
3406
|
);
|
|
2618
3407
|
process.exit(1);
|
|
2619
3408
|
}
|
|
@@ -2621,87 +3410,85 @@ var init_connect = __esm({
|
|
|
2621
3410
|
if (config.tier === "cloud") {
|
|
2622
3411
|
printInfo("This project is already connected to the cloud tier.");
|
|
2623
3412
|
console.log();
|
|
2624
|
-
const reconnect = await
|
|
3413
|
+
const reconnect = await confirm5({
|
|
2625
3414
|
message: "Want to update your API key?"
|
|
2626
3415
|
});
|
|
2627
|
-
if (
|
|
3416
|
+
if (isCancel6(reconnect) || !reconnect) {
|
|
2628
3417
|
console.log(` No changes made.`);
|
|
2629
3418
|
return;
|
|
2630
3419
|
}
|
|
2631
3420
|
}
|
|
2632
3421
|
console.log();
|
|
2633
|
-
console.log(` ${
|
|
3422
|
+
console.log(` ${pc11.bold("Connect to FlyDocs Cloud")}`);
|
|
2634
3423
|
console.log();
|
|
2635
3424
|
console.log(
|
|
2636
|
-
` ${
|
|
3425
|
+
` ${pc11.dim("FlyDocs API key (fdk_...): Get from your FlyDocs dashboard")}`
|
|
3426
|
+
);
|
|
3427
|
+
console.log(
|
|
3428
|
+
` ${pc11.dim("Linear API key (lin_api_...): Get from Linear \u2192 Settings \u2192 API")}`
|
|
2637
3429
|
);
|
|
2638
3430
|
console.log();
|
|
2639
3431
|
let apiKey = args.key ?? "";
|
|
2640
3432
|
if (!apiKey) {
|
|
2641
3433
|
const keyInput = await text2({
|
|
2642
|
-
message: "Enter your
|
|
2643
|
-
placeholder: "lin_api_...",
|
|
3434
|
+
message: "Enter your API key",
|
|
3435
|
+
placeholder: "fdk_... or lin_api_...",
|
|
2644
3436
|
validate(value) {
|
|
2645
3437
|
if (!value.trim()) return "API key is required";
|
|
2646
|
-
|
|
2647
|
-
|
|
3438
|
+
const type = detectKeyType(value.trim());
|
|
3439
|
+
if (type === "unknown")
|
|
3440
|
+
return "Key must start with fdk_ (FlyDocs) or lin_api_ (Linear)";
|
|
2648
3441
|
return void 0;
|
|
2649
3442
|
}
|
|
2650
3443
|
});
|
|
2651
|
-
if (
|
|
2652
|
-
|
|
3444
|
+
if (isCancel6(keyInput)) {
|
|
3445
|
+
cancel5("Connection cancelled.");
|
|
2653
3446
|
process.exit(0);
|
|
2654
3447
|
}
|
|
2655
|
-
apiKey = keyInput;
|
|
3448
|
+
apiKey = keyInput.trim();
|
|
2656
3449
|
}
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
method: "POST",
|
|
2661
|
-
headers: {
|
|
2662
|
-
Authorization: apiKey,
|
|
2663
|
-
"Content-Type": "application/json"
|
|
2664
|
-
},
|
|
2665
|
-
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
2666
|
-
signal: AbortSignal.timeout(15e3)
|
|
2667
|
-
});
|
|
2668
|
-
if (!response.ok) {
|
|
2669
|
-
throw new Error(`HTTP ${response.status}`);
|
|
2670
|
-
}
|
|
2671
|
-
const data = await response.json();
|
|
2672
|
-
if (!data.data?.viewer) {
|
|
2673
|
-
throw new Error("Invalid response");
|
|
2674
|
-
}
|
|
2675
|
-
const viewer = data.data.viewer;
|
|
2676
|
-
printStatus(`Authenticated as ${pc9.bold(viewer.name)} (${viewer.email})`);
|
|
2677
|
-
} catch {
|
|
2678
|
-
printError("Invalid API key or network error.");
|
|
2679
|
-
console.log(` Check your key and try again.`);
|
|
3450
|
+
const keyType = detectKeyType(apiKey);
|
|
3451
|
+
if (keyType === "unknown") {
|
|
3452
|
+
printError("Unrecognized key format. Expected fdk_ or lin_api_ prefix.");
|
|
2680
3453
|
process.exit(1);
|
|
2681
3454
|
}
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
3455
|
+
printInfo("Validating API key...");
|
|
3456
|
+
if (keyType === "relay") {
|
|
3457
|
+
try {
|
|
3458
|
+
const result = await validateRelayKey(apiKey);
|
|
3459
|
+
if (!result.valid) {
|
|
3460
|
+
printError("Invalid API key or relay API unreachable.");
|
|
3461
|
+
console.log(` Check your key and try again.`);
|
|
3462
|
+
process.exit(1);
|
|
3463
|
+
}
|
|
3464
|
+
printStatus(`Connected to ${pc11.bold(result.org)}`);
|
|
3465
|
+
} catch {
|
|
3466
|
+
printError(
|
|
3467
|
+
"Could not reach relay API. Check your network and try again."
|
|
2691
3468
|
);
|
|
2692
|
-
|
|
2693
|
-
} else {
|
|
2694
|
-
await appendFile2(targetEnvPath, `
|
|
2695
|
-
LINEAR_API_KEY=${apiKey}
|
|
2696
|
-
`);
|
|
3469
|
+
process.exit(1);
|
|
2697
3470
|
}
|
|
3471
|
+
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
3472
|
+
printStatus(`API key stored in ${pc11.dim(envFile)}`);
|
|
2698
3473
|
} else {
|
|
2699
|
-
|
|
2700
|
-
|
|
3474
|
+
try {
|
|
3475
|
+
const result = await validateLinearKey(apiKey);
|
|
3476
|
+
if (!result.valid) {
|
|
3477
|
+
printError("Invalid API key or network error.");
|
|
3478
|
+
console.log(` Check your key and try again.`);
|
|
3479
|
+
process.exit(1);
|
|
3480
|
+
}
|
|
3481
|
+
printStatus(
|
|
3482
|
+
`Authenticated as ${pc11.bold(result.name)} (${result.email})`
|
|
3483
|
+
);
|
|
3484
|
+
} catch {
|
|
3485
|
+
printError("Invalid API key or network error.");
|
|
3486
|
+
console.log(` Check your key and try again.`);
|
|
3487
|
+
process.exit(1);
|
|
3488
|
+
}
|
|
3489
|
+
const envFile = await storeEnvKey(targetDir, "LINEAR_API_KEY", apiKey);
|
|
3490
|
+
printStatus(`API key stored in ${pc11.dim(envFile)}`);
|
|
2701
3491
|
}
|
|
2702
|
-
printStatus(
|
|
2703
|
-
`API key stored in ${pc9.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
|
|
2704
|
-
);
|
|
2705
3492
|
const wasLocal = config.tier === "local";
|
|
2706
3493
|
config.tier = "cloud";
|
|
2707
3494
|
config.provider = config.provider ?? { type: "linear", teamId: null };
|
|
@@ -2713,16 +3500,16 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2713
3500
|
const templateDir = await resolveTemplatePath(
|
|
2714
3501
|
args["local-source"] || void 0
|
|
2715
3502
|
);
|
|
2716
|
-
const templateSkillsDir =
|
|
2717
|
-
const skillsDir =
|
|
3503
|
+
const templateSkillsDir = join17(templateDir, ".claude", "skills");
|
|
3504
|
+
const skillsDir = join17(targetDir, ".claude", "skills");
|
|
2718
3505
|
await replaceDirectory(
|
|
2719
|
-
|
|
2720
|
-
|
|
3506
|
+
join17(templateSkillsDir, "flydocs-cloud"),
|
|
3507
|
+
join17(skillsDir, "flydocs-cloud")
|
|
2721
3508
|
);
|
|
2722
|
-
const { rm:
|
|
2723
|
-
const localSkillDir =
|
|
3509
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
3510
|
+
const localSkillDir = join17(skillsDir, "flydocs-local");
|
|
2724
3511
|
if (await pathExists(localSkillDir)) {
|
|
2725
|
-
await
|
|
3512
|
+
await rm6(localSkillDir, { recursive: true, force: true });
|
|
2726
3513
|
}
|
|
2727
3514
|
printStatus("Cloud mechanism skill installed");
|
|
2728
3515
|
} catch {
|
|
@@ -2733,14 +3520,14 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2733
3520
|
}
|
|
2734
3521
|
console.log();
|
|
2735
3522
|
console.log(
|
|
2736
|
-
` ${
|
|
3523
|
+
` ${pc11.bold("Connected!")} Your project is now on the cloud tier.`
|
|
2737
3524
|
);
|
|
2738
3525
|
console.log();
|
|
2739
3526
|
console.log(` Next steps:`);
|
|
2740
3527
|
console.log(
|
|
2741
|
-
` 1. Run ${
|
|
3528
|
+
` 1. Run ${pc11.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
2742
3529
|
);
|
|
2743
|
-
console.log(` 2. Run ${
|
|
3530
|
+
console.log(` 2. Run ${pc11.cyan("/start-session")} to begin working`);
|
|
2744
3531
|
console.log();
|
|
2745
3532
|
}
|
|
2746
3533
|
});
|
|
@@ -2752,15 +3539,15 @@ var upgrade_exports = {};
|
|
|
2752
3539
|
__export(upgrade_exports, {
|
|
2753
3540
|
default: () => upgrade_default
|
|
2754
3541
|
});
|
|
2755
|
-
import { defineCommand as
|
|
2756
|
-
import
|
|
3542
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
3543
|
+
import pc12 from "picocolors";
|
|
2757
3544
|
var upgrade_default;
|
|
2758
3545
|
var init_upgrade = __esm({
|
|
2759
3546
|
"src/commands/upgrade.ts"() {
|
|
2760
3547
|
"use strict";
|
|
2761
3548
|
init_config();
|
|
2762
3549
|
init_fs_ops();
|
|
2763
|
-
upgrade_default =
|
|
3550
|
+
upgrade_default = defineCommand7({
|
|
2764
3551
|
meta: {
|
|
2765
3552
|
name: "upgrade",
|
|
2766
3553
|
description: "Learn about FlyDocs Cloud tier and upgrade from local"
|
|
@@ -2789,38 +3576,40 @@ var init_upgrade = __esm({
|
|
|
2789
3576
|
console.log();
|
|
2790
3577
|
if (currentTier === "cloud") {
|
|
2791
3578
|
console.log(
|
|
2792
|
-
` ${
|
|
3579
|
+
` ${pc12.green("\u2713")} You're already on the ${pc12.bold("cloud")} tier.`
|
|
2793
3580
|
);
|
|
2794
3581
|
console.log();
|
|
2795
3582
|
console.log(
|
|
2796
3583
|
` Your issues sync with Linear via the cloud mechanism skill.`
|
|
2797
3584
|
);
|
|
2798
3585
|
console.log(
|
|
2799
|
-
` Run ${
|
|
3586
|
+
` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
|
|
2800
3587
|
);
|
|
2801
3588
|
console.log();
|
|
2802
3589
|
return;
|
|
2803
3590
|
}
|
|
2804
|
-
console.log(` ${
|
|
3591
|
+
console.log(` ${pc12.bold("FlyDocs Cloud Tier")}`);
|
|
2805
3592
|
console.log();
|
|
2806
|
-
console.log(` You're currently on the ${
|
|
3593
|
+
console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
|
|
2807
3594
|
console.log(` Upgrade to cloud for:`);
|
|
2808
3595
|
console.log();
|
|
2809
3596
|
console.log(
|
|
2810
|
-
` ${
|
|
3597
|
+
` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
|
|
2811
3598
|
);
|
|
2812
|
-
console.log(` ${
|
|
2813
|
-
console.log(` ${
|
|
2814
|
-
console.log(` ${
|
|
2815
|
-
console.log(` ${
|
|
3599
|
+
console.log(` ${pc12.cyan("\u2192")} Project milestones and cycle management`);
|
|
3600
|
+
console.log(` ${pc12.cyan("\u2192")} Team assignment and priority tracking`);
|
|
3601
|
+
console.log(` ${pc12.cyan("\u2192")} Project health updates and dashboards`);
|
|
3602
|
+
console.log(` ${pc12.cyan("\u2192")} Cross-project issue linking`);
|
|
3603
|
+
console.log();
|
|
3604
|
+
console.log(` ${pc12.bold("How to upgrade:")}`);
|
|
2816
3605
|
console.log();
|
|
2817
|
-
console.log(`
|
|
3606
|
+
console.log(` Option 1: Run ${pc12.cyan("/flydocs-upgrade")} in your IDE`);
|
|
3607
|
+
console.log(` Guided migration with issue transfer`);
|
|
2818
3608
|
console.log();
|
|
2819
|
-
console.log(` 1. Sign up at ${pc10.cyan("https://www.flydocs.ai")}`);
|
|
2820
|
-
console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
|
|
2821
3609
|
console.log(
|
|
2822
|
-
`
|
|
3610
|
+
` Option 2: Run ${pc12.cyan("flydocs connect")} from terminal`
|
|
2823
3611
|
);
|
|
3612
|
+
console.log(` Quick tier swap (no issue migration)`);
|
|
2824
3613
|
console.log();
|
|
2825
3614
|
}
|
|
2826
3615
|
});
|
|
@@ -2832,23 +3621,23 @@ var self_update_exports = {};
|
|
|
2832
3621
|
__export(self_update_exports, {
|
|
2833
3622
|
default: () => self_update_default
|
|
2834
3623
|
});
|
|
2835
|
-
import { defineCommand as
|
|
3624
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2836
3625
|
import { execSync } from "child_process";
|
|
2837
|
-
import
|
|
3626
|
+
import pc13 from "picocolors";
|
|
2838
3627
|
var self_update_default;
|
|
2839
3628
|
var init_self_update = __esm({
|
|
2840
3629
|
"src/commands/self-update.ts"() {
|
|
2841
3630
|
"use strict";
|
|
2842
3631
|
init_constants();
|
|
2843
3632
|
init_ui();
|
|
2844
|
-
self_update_default =
|
|
3633
|
+
self_update_default = defineCommand8({
|
|
2845
3634
|
meta: {
|
|
2846
3635
|
name: "self-update",
|
|
2847
3636
|
description: "Update FlyDocs CLI to the latest version"
|
|
2848
3637
|
},
|
|
2849
3638
|
async run() {
|
|
2850
3639
|
console.log();
|
|
2851
|
-
console.log(` Updating ${
|
|
3640
|
+
console.log(` Updating ${pc13.cyan(PACKAGE_NAME)}...`);
|
|
2852
3641
|
console.log();
|
|
2853
3642
|
try {
|
|
2854
3643
|
execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
|
|
@@ -2868,17 +3657,117 @@ var init_self_update = __esm({
|
|
|
2868
3657
|
}
|
|
2869
3658
|
});
|
|
2870
3659
|
|
|
3660
|
+
// src/commands/telemetry.ts
|
|
3661
|
+
var telemetry_exports = {};
|
|
3662
|
+
__export(telemetry_exports, {
|
|
3663
|
+
default: () => telemetry_default
|
|
3664
|
+
});
|
|
3665
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
3666
|
+
import pc14 from "picocolors";
|
|
3667
|
+
var enable, disable, status, telemetry_default;
|
|
3668
|
+
var init_telemetry2 = __esm({
|
|
3669
|
+
"src/commands/telemetry.ts"() {
|
|
3670
|
+
"use strict";
|
|
3671
|
+
init_telemetry();
|
|
3672
|
+
init_ui();
|
|
3673
|
+
enable = defineCommand9({
|
|
3674
|
+
meta: {
|
|
3675
|
+
name: "enable",
|
|
3676
|
+
description: "Enable anonymous usage analytics"
|
|
3677
|
+
},
|
|
3678
|
+
async run() {
|
|
3679
|
+
try {
|
|
3680
|
+
await setEnabled(true);
|
|
3681
|
+
printStatus("Telemetry enabled");
|
|
3682
|
+
} catch {
|
|
3683
|
+
printError("Failed to update telemetry settings");
|
|
3684
|
+
process.exit(1);
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
});
|
|
3688
|
+
disable = defineCommand9({
|
|
3689
|
+
meta: {
|
|
3690
|
+
name: "disable",
|
|
3691
|
+
description: "Disable anonymous usage analytics"
|
|
3692
|
+
},
|
|
3693
|
+
async run() {
|
|
3694
|
+
try {
|
|
3695
|
+
await setEnabled(false);
|
|
3696
|
+
printStatus("Telemetry disabled");
|
|
3697
|
+
printInfo(
|
|
3698
|
+
"You can also set FLYDOCS_TELEMETRY=0 in your shell environment."
|
|
3699
|
+
);
|
|
3700
|
+
} catch {
|
|
3701
|
+
printError("Failed to update telemetry settings");
|
|
3702
|
+
process.exit(1);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
});
|
|
3706
|
+
status = defineCommand9({
|
|
3707
|
+
meta: {
|
|
3708
|
+
name: "status",
|
|
3709
|
+
description: "Show current telemetry status"
|
|
3710
|
+
},
|
|
3711
|
+
async run() {
|
|
3712
|
+
const info = await getStatus();
|
|
3713
|
+
console.log();
|
|
3714
|
+
console.log(pc14.bold("Telemetry Status"));
|
|
3715
|
+
console.log();
|
|
3716
|
+
const effectivelyEnabled = info.enabled && !info.envOverride;
|
|
3717
|
+
console.log(
|
|
3718
|
+
` Enabled: ${effectivelyEnabled ? pc14.green("yes") : pc14.yellow("no")}`
|
|
3719
|
+
);
|
|
3720
|
+
if (info.envOverride) {
|
|
3721
|
+
console.log(
|
|
3722
|
+
` Env override: ${pc14.yellow("FLYDOCS_TELEMETRY=0 (disabled via env)")}`
|
|
3723
|
+
);
|
|
3724
|
+
}
|
|
3725
|
+
if (info.anonymousId) {
|
|
3726
|
+
console.log(` Anonymous ID: ${pc14.dim(info.anonymousId)}`);
|
|
3727
|
+
} else {
|
|
3728
|
+
console.log(
|
|
3729
|
+
` Anonymous ID: ${pc14.dim("(not yet created \u2014 generated on first run)")}`
|
|
3730
|
+
);
|
|
3731
|
+
}
|
|
3732
|
+
console.log();
|
|
3733
|
+
console.log(
|
|
3734
|
+
pc14.dim(
|
|
3735
|
+
" FlyDocs collects anonymous usage analytics to improve the CLI."
|
|
3736
|
+
)
|
|
3737
|
+
);
|
|
3738
|
+
console.log(
|
|
3739
|
+
pc14.dim(" No personal data, file contents, or code is ever collected.")
|
|
3740
|
+
);
|
|
3741
|
+
console.log();
|
|
3742
|
+
}
|
|
3743
|
+
});
|
|
3744
|
+
telemetry_default = defineCommand9({
|
|
3745
|
+
meta: {
|
|
3746
|
+
name: "telemetry",
|
|
3747
|
+
description: "Manage anonymous usage analytics (enable, disable, status)"
|
|
3748
|
+
},
|
|
3749
|
+
subCommands: {
|
|
3750
|
+
enable,
|
|
3751
|
+
disable,
|
|
3752
|
+
status
|
|
3753
|
+
}
|
|
3754
|
+
});
|
|
3755
|
+
}
|
|
3756
|
+
});
|
|
3757
|
+
|
|
2871
3758
|
// src/cli.ts
|
|
2872
3759
|
init_constants();
|
|
2873
|
-
import { defineCommand as
|
|
3760
|
+
import { defineCommand as defineCommand10, runMain } from "citty";
|
|
2874
3761
|
var SUB_COMMANDS = /* @__PURE__ */ new Set([
|
|
2875
3762
|
"install",
|
|
2876
3763
|
"update",
|
|
3764
|
+
"uninstall",
|
|
2877
3765
|
"setup",
|
|
2878
3766
|
"skills",
|
|
2879
3767
|
"connect",
|
|
2880
3768
|
"upgrade",
|
|
2881
|
-
"self-update"
|
|
3769
|
+
"self-update",
|
|
3770
|
+
"telemetry"
|
|
2882
3771
|
]);
|
|
2883
3772
|
var userArgs = process.argv.slice(2);
|
|
2884
3773
|
var hasMetaFlag = userArgs.some(
|
|
@@ -2888,7 +3777,7 @@ var firstPositional = userArgs.find((a) => !a.startsWith("-"));
|
|
|
2888
3777
|
if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
|
|
2889
3778
|
process.argv.splice(2, 0, "install");
|
|
2890
3779
|
}
|
|
2891
|
-
var main =
|
|
3780
|
+
var main = defineCommand10({
|
|
2892
3781
|
meta: {
|
|
2893
3782
|
name: CLI_NAME,
|
|
2894
3783
|
version: CLI_VERSION,
|
|
@@ -2897,11 +3786,13 @@ var main = defineCommand8({
|
|
|
2897
3786
|
subCommands: {
|
|
2898
3787
|
install: () => Promise.resolve().then(() => (init_install(), install_exports)).then((m) => m.default),
|
|
2899
3788
|
update: () => Promise.resolve().then(() => (init_update(), update_exports)).then((m) => m.default),
|
|
3789
|
+
uninstall: () => Promise.resolve().then(() => (init_uninstall(), uninstall_exports)).then((m) => m.default),
|
|
2900
3790
|
setup: () => Promise.resolve().then(() => (init_setup(), setup_exports)).then((m) => m.default),
|
|
2901
3791
|
skills: () => Promise.resolve().then(() => (init_skills2(), skills_exports)).then((m) => m.default),
|
|
2902
3792
|
connect: () => Promise.resolve().then(() => (init_connect(), connect_exports)).then((m) => m.default),
|
|
2903
3793
|
upgrade: () => Promise.resolve().then(() => (init_upgrade(), upgrade_exports)).then((m) => m.default),
|
|
2904
|
-
"self-update": () => Promise.resolve().then(() => (init_self_update(), self_update_exports)).then((m) => m.default)
|
|
3794
|
+
"self-update": () => Promise.resolve().then(() => (init_self_update(), self_update_exports)).then((m) => m.default),
|
|
3795
|
+
telemetry: () => Promise.resolve().then(() => (init_telemetry2(), telemetry_exports)).then((m) => m.default)
|
|
2905
3796
|
}
|
|
2906
3797
|
});
|
|
2907
3798
|
runMain(main);
|