@flydocs/cli 0.5.0-beta.9 → 0.6.0-alpha.2
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 +1259 -370
- 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 +109 -26
- package/template/.claude/commands/flydocs-upgrade.md +330 -0
- package/template/.claude/skills/flydocs-cloud/SKILL.md +53 -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/create_team.py +39 -0
- 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 +144 -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.2";
|
|
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,8 +135,58 @@ var init_template = __esm({
|
|
|
136
135
|
|
|
137
136
|
// src/lib/ui.ts
|
|
138
137
|
import pc2 from "picocolors";
|
|
139
|
-
function
|
|
140
|
-
return `\x1B
|
|
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
|
+
}
|
|
141
190
|
}
|
|
142
191
|
function printStatus(message) {
|
|
143
192
|
console.log(`${pc2.green("\u2714")} ${message}`);
|
|
@@ -152,26 +201,13 @@ function printInfo(message) {
|
|
|
152
201
|
console.log(`${pc2.cyan("\u2139")} ${message}`);
|
|
153
202
|
}
|
|
154
203
|
function printBanner(version) {
|
|
155
|
-
const pink = (t) => pc2.bold(pc2.magenta(t));
|
|
156
|
-
const purple = (t) => pc2.bold(pc2.cyan(t));
|
|
157
|
-
const dim = pc2.dim;
|
|
158
|
-
const bold = pc2.bold;
|
|
159
|
-
const pinkBlock12 = pink("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
160
|
-
const pinkBlock4 = pink("\u2588\u2588\u2588\u2588");
|
|
161
|
-
const purpleBlock12 = purple("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588");
|
|
162
|
-
const purpleBlock4 = purple("\u2588\u2588\u2588\u2588");
|
|
163
204
|
console.log();
|
|
164
|
-
|
|
165
|
-
console.log(
|
|
166
|
-
console.log(` ${pinkBlock4}`);
|
|
167
|
-
console.log(
|
|
168
|
-
` ${pinkBlock4} ${purpleBlock12} ${bold("FlyDocs")} ${dim("(Beta)")}`
|
|
169
|
-
);
|
|
205
|
+
renderBannerBlock();
|
|
206
|
+
console.log();
|
|
170
207
|
console.log(
|
|
171
|
-
`
|
|
208
|
+
` ${pc2.bold(pc2.white("Structured context for AI coding tools"))} ${pc2.dim("(Beta)")}`
|
|
172
209
|
);
|
|
173
|
-
console.log(`
|
|
174
|
-
console.log(` ${purpleBlock4} ${dim(`v${version}`)}`);
|
|
210
|
+
console.log(` ${pc2.dim(`Version: ${version}`)}`);
|
|
175
211
|
console.log();
|
|
176
212
|
}
|
|
177
213
|
function printCompletionBox(title, lines) {
|
|
@@ -192,22 +228,42 @@ function printCompletionBox(title, lines) {
|
|
|
192
228
|
}
|
|
193
229
|
function printBetaCta() {
|
|
194
230
|
const dim = pc2.dim;
|
|
195
|
-
const
|
|
231
|
+
const discordUrl = "https://discord.com/invite/YAkjePmZTQ";
|
|
232
|
+
const siteUrl = "https://www.flydocs.ai?utm_source=cli&utm_medium=install&utm_campaign=beta";
|
|
196
233
|
console.log(
|
|
197
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")
|
|
198
235
|
);
|
|
199
236
|
console.log();
|
|
200
|
-
console.log(` ${pc2.bold("Join the FlyDocs Closed Beta")}`);
|
|
201
237
|
console.log(
|
|
202
|
-
` ${
|
|
238
|
+
` ${pc2.bold(pc2.cyan("Join the Discord"))} for upcoming features, support, and early access to what's next.`
|
|
239
|
+
);
|
|
240
|
+
console.log(` ${dim("Invite link:")}`);
|
|
241
|
+
console.log(` ${pc2.cyan(discordUrl)}`);
|
|
242
|
+
console.log();
|
|
243
|
+
console.log(
|
|
244
|
+
` ${dim("Docs and updates:")} ${pc2.cyan("https://www.flydocs.ai")}`
|
|
203
245
|
);
|
|
204
|
-
console.log(` ${pc2.cyan(hyperlink("flydocs.ai", url))}`);
|
|
205
246
|
console.log();
|
|
206
247
|
}
|
|
248
|
+
var GRADIENT, BANNER_ROWS;
|
|
207
249
|
var init_ui = __esm({
|
|
208
250
|
"src/lib/ui.ts"() {
|
|
209
251
|
"use strict";
|
|
210
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
|
+
];
|
|
211
267
|
}
|
|
212
268
|
});
|
|
213
269
|
|
|
@@ -305,18 +361,26 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
|
|
|
305
361
|
join4(templateSkillsDir, activeMech),
|
|
306
362
|
join4(skillsDir, activeMech)
|
|
307
363
|
);
|
|
308
|
-
const { rm:
|
|
364
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
309
365
|
const inactivePath = join4(skillsDir, inactiveMech);
|
|
310
366
|
if (await pathExists(inactivePath)) {
|
|
311
|
-
await
|
|
367
|
+
await rm6(inactivePath, { recursive: true, force: true });
|
|
312
368
|
}
|
|
313
|
-
for (const skill of
|
|
369
|
+
for (const skill of CORE_SKILLS) {
|
|
314
370
|
if (skill === "flydocs-workflow") continue;
|
|
315
371
|
const src = join4(templateSkillsDir, skill);
|
|
316
372
|
if (await pathExists(src)) {
|
|
317
373
|
await replaceDirectory(src, join4(skillsDir, skill));
|
|
318
374
|
}
|
|
319
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
|
+
}
|
|
320
384
|
const readmeSrc = join4(templateSkillsDir, "README.md");
|
|
321
385
|
if (await pathExists(readmeSrc)) {
|
|
322
386
|
await copyFile(readmeSrc, join4(skillsDir, "README.md"));
|
|
@@ -325,18 +389,29 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
|
|
|
325
389
|
async function replaceOwnedSkills(templateDir, targetDir, tier) {
|
|
326
390
|
const skillsDir = join4(targetDir, ".claude", "skills");
|
|
327
391
|
const templateSkillsDir = join4(templateDir, ".claude", "skills");
|
|
328
|
-
|
|
392
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
393
|
+
for (const skill of CORE_SKILLS) {
|
|
329
394
|
const src = join4(templateSkillsDir, skill);
|
|
330
395
|
if (await pathExists(src)) {
|
|
331
396
|
await replaceDirectory(src, join4(skillsDir, skill));
|
|
332
397
|
}
|
|
333
398
|
}
|
|
334
|
-
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
|
+
}
|
|
335
410
|
const activeMech = MECHANISM_SKILLS[tier];
|
|
336
411
|
const inactiveMech = tier === "local" ? MECHANISM_SKILLS.cloud : MECHANISM_SKILLS.local;
|
|
337
412
|
const inactivePath = join4(skillsDir, inactiveMech);
|
|
338
413
|
if (await pathExists(inactivePath)) {
|
|
339
|
-
await
|
|
414
|
+
await rm6(inactivePath, { recursive: true, force: true });
|
|
340
415
|
}
|
|
341
416
|
await replaceDirectory(
|
|
342
417
|
join4(templateSkillsDir, activeMech),
|
|
@@ -348,9 +423,9 @@ async function replaceOwnedSkills(templateDir, targetDir, tier) {
|
|
|
348
423
|
}
|
|
349
424
|
}
|
|
350
425
|
async function copyCursorRules(targetDir) {
|
|
351
|
-
const { mkdir:
|
|
426
|
+
const { mkdir: mkdir9 } = await import("fs/promises");
|
|
352
427
|
const rulesDir = join4(targetDir, ".cursor", "rules");
|
|
353
|
-
await
|
|
428
|
+
await mkdir9(rulesDir, { recursive: true });
|
|
354
429
|
const workflowRule = join4(
|
|
355
430
|
targetDir,
|
|
356
431
|
".claude",
|
|
@@ -384,18 +459,17 @@ async function copyCursorRules(targetDir) {
|
|
|
384
459
|
await copyFile(context7Rule, join4(rulesDir, "flydocs-context7.mdc"));
|
|
385
460
|
}
|
|
386
461
|
}
|
|
387
|
-
var
|
|
462
|
+
var CORE_SKILLS, CLOUD_ONLY_SKILLS, MECHANISM_SKILLS;
|
|
388
463
|
var init_skills = __esm({
|
|
389
464
|
"src/lib/skills.ts"() {
|
|
390
465
|
"use strict";
|
|
391
466
|
init_fs_ops();
|
|
392
|
-
|
|
467
|
+
CORE_SKILLS = [
|
|
393
468
|
"flydocs-workflow",
|
|
394
|
-
"flydocs-figma",
|
|
395
|
-
"flydocs-estimates",
|
|
396
469
|
"flydocs-context-graph",
|
|
397
470
|
"flydocs-context7"
|
|
398
471
|
];
|
|
472
|
+
CLOUD_ONLY_SKILLS = ["flydocs-figma", "flydocs-estimates"];
|
|
399
473
|
MECHANISM_SKILLS = {
|
|
400
474
|
local: "flydocs-local",
|
|
401
475
|
cloud: "flydocs-cloud"
|
|
@@ -403,14 +477,77 @@ var init_skills = __esm({
|
|
|
403
477
|
}
|
|
404
478
|
});
|
|
405
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
|
+
|
|
406
543
|
// src/lib/stack.ts
|
|
407
|
-
import { readFile as
|
|
408
|
-
import { join as
|
|
544
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
545
|
+
import { join as join6 } from "path";
|
|
409
546
|
async function parseProjectMdStack(targetDir) {
|
|
410
547
|
const detected = /* @__PURE__ */ new Set();
|
|
411
|
-
const projectMdPath =
|
|
548
|
+
const projectMdPath = join6(targetDir, "flydocs", "context", "project.md");
|
|
412
549
|
try {
|
|
413
|
-
const content = await
|
|
550
|
+
const content = await readFile4(projectMdPath, "utf-8");
|
|
414
551
|
const stackMatch = content.match(/## Stack\n([\s\S]*?)(?=\n## |\n---|\z)/);
|
|
415
552
|
if (!stackMatch) return detected;
|
|
416
553
|
const stackSection = stackMatch[1].toLowerCase();
|
|
@@ -453,10 +590,10 @@ async function parseProjectMdStack(targetDir) {
|
|
|
453
590
|
}
|
|
454
591
|
async function detectStack(targetDir) {
|
|
455
592
|
const detected = /* @__PURE__ */ new Set();
|
|
456
|
-
const pkgPath =
|
|
593
|
+
const pkgPath = join6(targetDir, "package.json");
|
|
457
594
|
let pkg;
|
|
458
595
|
try {
|
|
459
|
-
const content = await
|
|
596
|
+
const content = await readFile4(pkgPath, "utf-8");
|
|
460
597
|
pkg = JSON.parse(content);
|
|
461
598
|
} catch {
|
|
462
599
|
}
|
|
@@ -484,39 +621,39 @@ async function detectStack(targetDir) {
|
|
|
484
621
|
detected.add("testing-library");
|
|
485
622
|
}
|
|
486
623
|
for (const f of ["convex/schema.ts", "convex/schema.js"]) {
|
|
487
|
-
if (await pathExists(
|
|
624
|
+
if (await pathExists(join6(targetDir, f))) detected.add("convex");
|
|
488
625
|
}
|
|
489
626
|
for (const f of ["next.config.ts", "next.config.js", "next.config.mjs"]) {
|
|
490
|
-
if (await pathExists(
|
|
627
|
+
if (await pathExists(join6(targetDir, f))) detected.add("nextjs");
|
|
491
628
|
}
|
|
492
|
-
const appJsonPath =
|
|
629
|
+
const appJsonPath = join6(targetDir, "app.json");
|
|
493
630
|
if (await pathExists(appJsonPath)) {
|
|
494
631
|
try {
|
|
495
|
-
const appContent = await
|
|
632
|
+
const appContent = await readFile4(appJsonPath, "utf-8");
|
|
496
633
|
if (appContent.includes('"expo"')) detected.add("expo");
|
|
497
634
|
} catch {
|
|
498
635
|
}
|
|
499
636
|
}
|
|
500
|
-
if (await pathExists(
|
|
637
|
+
if (await pathExists(join6(targetDir, "tsconfig.json"))) {
|
|
501
638
|
detected.add("typescript");
|
|
502
639
|
}
|
|
503
|
-
if (await pathExists(
|
|
640
|
+
if (await pathExists(join6(targetDir, "nuxt.config.ts")) || await pathExists(join6(targetDir, "nuxt.config.js"))) {
|
|
504
641
|
detected.add("nuxt");
|
|
505
642
|
detected.add("vue");
|
|
506
643
|
}
|
|
507
|
-
if (await pathExists(
|
|
644
|
+
if (await pathExists(join6(targetDir, "angular.json"))) {
|
|
508
645
|
detected.add("angular");
|
|
509
646
|
}
|
|
510
|
-
if (await pathExists(
|
|
647
|
+
if (await pathExists(join6(targetDir, "svelte.config.js")) || await pathExists(join6(targetDir, "svelte.config.ts"))) {
|
|
511
648
|
detected.add("svelte");
|
|
512
649
|
}
|
|
513
|
-
if (await pathExists(
|
|
650
|
+
if (await pathExists(join6(targetDir, "pyproject.toml")) || await pathExists(join6(targetDir, "requirements.txt")) || await pathExists(join6(targetDir, "setup.py"))) {
|
|
514
651
|
detected.add("python");
|
|
515
652
|
}
|
|
516
|
-
if (await pathExists(
|
|
653
|
+
if (await pathExists(join6(targetDir, "go.mod"))) {
|
|
517
654
|
detected.add("go");
|
|
518
655
|
}
|
|
519
|
-
if (await pathExists(
|
|
656
|
+
if (await pathExists(join6(targetDir, "Cargo.toml"))) {
|
|
520
657
|
detected.add("rust");
|
|
521
658
|
}
|
|
522
659
|
const projectMdStack = await parseProjectMdStack(targetDir);
|
|
@@ -562,9 +699,9 @@ var init_stack = __esm({
|
|
|
562
699
|
|
|
563
700
|
// src/lib/post-install.ts
|
|
564
701
|
import { execFileSync } from "child_process";
|
|
565
|
-
import { join as
|
|
702
|
+
import { join as join7 } from "path";
|
|
566
703
|
async function runManifestGeneration(targetDir) {
|
|
567
|
-
const scriptPath =
|
|
704
|
+
const scriptPath = join7(
|
|
568
705
|
targetDir,
|
|
569
706
|
".flydocs",
|
|
570
707
|
"scripts",
|
|
@@ -582,7 +719,7 @@ async function runManifestGeneration(targetDir) {
|
|
|
582
719
|
}
|
|
583
720
|
}
|
|
584
721
|
async function runContextGraphBuild(targetDir) {
|
|
585
|
-
const scriptPath =
|
|
722
|
+
const scriptPath = join7(
|
|
586
723
|
targetDir,
|
|
587
724
|
".claude",
|
|
588
725
|
"skills",
|
|
@@ -610,8 +747,8 @@ var init_post_install = __esm({
|
|
|
610
747
|
});
|
|
611
748
|
|
|
612
749
|
// src/lib/skill-manager.ts
|
|
613
|
-
import { readFile as
|
|
614
|
-
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";
|
|
615
752
|
import pc3 from "picocolors";
|
|
616
753
|
function flushFrontmatterValue(mode, lines) {
|
|
617
754
|
switch (mode) {
|
|
@@ -738,13 +875,13 @@ async function downloadFileContent(downloadUrl) {
|
|
|
738
875
|
async function downloadRecursive(url, destDir) {
|
|
739
876
|
const items = await fetchGitHubJson(url);
|
|
740
877
|
if (items === null) return false;
|
|
741
|
-
await
|
|
878
|
+
await mkdir3(destDir, { recursive: true });
|
|
742
879
|
for (const item of items) {
|
|
743
|
-
const destPath =
|
|
880
|
+
const destPath = join8(destDir, item.name);
|
|
744
881
|
if (item.type === "file") {
|
|
745
882
|
if (item.download_url) {
|
|
746
883
|
const content = await downloadFileContent(item.download_url);
|
|
747
|
-
await
|
|
884
|
+
await writeFile3(destPath, content);
|
|
748
885
|
}
|
|
749
886
|
} else if (item.type === "dir") {
|
|
750
887
|
await downloadRecursive(item.url, destPath);
|
|
@@ -757,7 +894,7 @@ async function downloadSkillTree(repo, skillName, targetDir) {
|
|
|
757
894
|
return downloadRecursive(apiUrl, targetDir);
|
|
758
895
|
}
|
|
759
896
|
async function listSkills(targetDir) {
|
|
760
|
-
const skillsDir =
|
|
897
|
+
const skillsDir = join8(targetDir, ".claude", "skills");
|
|
761
898
|
const platform = [];
|
|
762
899
|
const community = [];
|
|
763
900
|
if (!await pathExists(skillsDir)) {
|
|
@@ -770,11 +907,11 @@ async function listSkills(targetDir) {
|
|
|
770
907
|
return { platform, community };
|
|
771
908
|
}
|
|
772
909
|
for (const entry of entries.sort()) {
|
|
773
|
-
const skillFile =
|
|
910
|
+
const skillFile = join8(skillsDir, entry, "SKILL.md");
|
|
774
911
|
if (!await pathExists(skillFile)) continue;
|
|
775
912
|
let content;
|
|
776
913
|
try {
|
|
777
|
-
content = await
|
|
914
|
+
content = await readFile5(skillFile, "utf-8");
|
|
778
915
|
} catch {
|
|
779
916
|
continue;
|
|
780
917
|
}
|
|
@@ -822,7 +959,7 @@ async function addSkill(targetDir, source) {
|
|
|
822
959
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
823
960
|
return;
|
|
824
961
|
}
|
|
825
|
-
const skillsDir =
|
|
962
|
+
const skillsDir = join8(targetDir, ".claude", "skills", skillName);
|
|
826
963
|
if (await pathExists(skillsDir)) {
|
|
827
964
|
printWarning(`Skill '${skillName}' is already installed.`);
|
|
828
965
|
console.log(` Remove first: flydocs skills remove ${skillName}`);
|
|
@@ -851,13 +988,13 @@ async function addSkill(targetDir, source) {
|
|
|
851
988
|
printError(`Skill not found at ${repo}/skills/${skillName}`);
|
|
852
989
|
return;
|
|
853
990
|
}
|
|
854
|
-
const skillMdPath =
|
|
991
|
+
const skillMdPath = join8(skillsDir, "SKILL.md");
|
|
855
992
|
if (!await pathExists(skillMdPath)) {
|
|
856
993
|
await rm2(skillsDir, { recursive: true, force: true });
|
|
857
994
|
printError("Invalid skill: SKILL.md not found.");
|
|
858
995
|
return;
|
|
859
996
|
}
|
|
860
|
-
const skillMdContent = await
|
|
997
|
+
const skillMdContent = await readFile5(skillMdPath, "utf-8");
|
|
861
998
|
const fm = parseFrontmatter(skillMdContent);
|
|
862
999
|
if (fm === null || !fm["name"] || !fm["description"]) {
|
|
863
1000
|
await rm2(skillsDir, { recursive: true, force: true });
|
|
@@ -872,11 +1009,11 @@ async function addSkill(targetDir, source) {
|
|
|
872
1009
|
);
|
|
873
1010
|
}
|
|
874
1011
|
printStatus("Downloaded skill files");
|
|
875
|
-
const cursorRuleSrc =
|
|
1012
|
+
const cursorRuleSrc = join8(skillsDir, "cursor-rule.mdc");
|
|
876
1013
|
if (await pathExists(cursorRuleSrc)) {
|
|
877
|
-
const cursorRulesDir =
|
|
878
|
-
await
|
|
879
|
-
const cursorRuleDest =
|
|
1014
|
+
const cursorRulesDir = join8(targetDir, ".cursor", "rules");
|
|
1015
|
+
await mkdir3(cursorRulesDir, { recursive: true });
|
|
1016
|
+
const cursorRuleDest = join8(cursorRulesDir, `${skillName}.mdc`);
|
|
880
1017
|
await copyFile(cursorRuleSrc, cursorRuleDest);
|
|
881
1018
|
printStatus("Installed cursor rule");
|
|
882
1019
|
}
|
|
@@ -903,14 +1040,14 @@ async function removeSkill(targetDir, name) {
|
|
|
903
1040
|
console.log(" Platform skills (flydocs-*) are managed by the installer.");
|
|
904
1041
|
return;
|
|
905
1042
|
}
|
|
906
|
-
const skillDir =
|
|
1043
|
+
const skillDir = join8(targetDir, ".claude", "skills", name);
|
|
907
1044
|
if (!await pathExists(skillDir)) {
|
|
908
1045
|
printError(`Skill '${name}' is not installed.`);
|
|
909
1046
|
return;
|
|
910
1047
|
}
|
|
911
1048
|
await rm2(skillDir, { recursive: true, force: true });
|
|
912
1049
|
printStatus("Removed skill directory");
|
|
913
|
-
const cursorRule =
|
|
1050
|
+
const cursorRule = join8(targetDir, ".cursor", "rules", `${name}.mdc`);
|
|
914
1051
|
if (await pathExists(cursorRule)) {
|
|
915
1052
|
await rm2(cursorRule, { force: true });
|
|
916
1053
|
printStatus("Removed cursor rule");
|
|
@@ -975,7 +1112,7 @@ var init_skill_manager = __esm({
|
|
|
975
1112
|
});
|
|
976
1113
|
|
|
977
1114
|
// src/lib/community-skills.ts
|
|
978
|
-
import { join as
|
|
1115
|
+
import { join as join9 } from "path";
|
|
979
1116
|
import { multiselect, isCancel, cancel } from "@clack/prompts";
|
|
980
1117
|
import pc4 from "picocolors";
|
|
981
1118
|
function suggestSkills(stack) {
|
|
@@ -994,10 +1131,10 @@ function suggestSkills(stack) {
|
|
|
994
1131
|
}
|
|
995
1132
|
async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
996
1133
|
const suggestions = suggestSkills(stack);
|
|
997
|
-
const skillsDir =
|
|
1134
|
+
const skillsDir = join9(targetDir, ".claude", "skills");
|
|
998
1135
|
const filtered = [];
|
|
999
1136
|
for (const skill of suggestions) {
|
|
1000
|
-
if (!await pathExists(
|
|
1137
|
+
if (!await pathExists(join9(skillsDir, skill.name))) {
|
|
1001
1138
|
filtered.push(skill);
|
|
1002
1139
|
}
|
|
1003
1140
|
}
|
|
@@ -1154,48 +1291,48 @@ var init_community_skills = __esm({
|
|
|
1154
1291
|
});
|
|
1155
1292
|
|
|
1156
1293
|
// src/lib/deprecated.ts
|
|
1157
|
-
import { readdir as readdir2, mkdir as
|
|
1158
|
-
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";
|
|
1159
1296
|
import { confirm, isCancel as isCancel2 } from "@clack/prompts";
|
|
1160
1297
|
async function scanDeprecated(targetDir) {
|
|
1161
1298
|
const found = [];
|
|
1162
1299
|
for (const item of [...DEPRECATED_DIRS, ...DEPRECATED_FILES]) {
|
|
1163
|
-
if (await pathExists(
|
|
1300
|
+
if (await pathExists(join10(targetDir, item))) {
|
|
1164
1301
|
found.push(item);
|
|
1165
1302
|
}
|
|
1166
1303
|
}
|
|
1167
1304
|
for (const skill of DEPRECATED_SKILLS) {
|
|
1168
|
-
const p =
|
|
1305
|
+
const p = join10(targetDir, ".claude", "skills", skill);
|
|
1169
1306
|
if (await pathExists(p)) {
|
|
1170
1307
|
found.push(`.claude/skills/${skill}`);
|
|
1171
1308
|
}
|
|
1172
1309
|
}
|
|
1173
1310
|
for (const dir of DEPRECATED_RULES_DIR) {
|
|
1174
|
-
if (await pathExists(
|
|
1311
|
+
if (await pathExists(join10(targetDir, dir))) {
|
|
1175
1312
|
found.push(dir);
|
|
1176
1313
|
}
|
|
1177
1314
|
}
|
|
1178
1315
|
for (const hook of DEPRECATED_HOOKS) {
|
|
1179
|
-
const p =
|
|
1316
|
+
const p = join10(targetDir, ".flydocs", "hooks", hook);
|
|
1180
1317
|
if (await pathExists(p)) {
|
|
1181
1318
|
found.push(`.flydocs/hooks/${hook}`);
|
|
1182
1319
|
}
|
|
1183
1320
|
}
|
|
1184
1321
|
for (const rule of DEPRECATED_CURSOR_RULES) {
|
|
1185
|
-
const p =
|
|
1322
|
+
const p = join10(targetDir, ".cursor", "rules", rule);
|
|
1186
1323
|
if (await pathExists(p)) {
|
|
1187
1324
|
found.push(`.cursor/rules/${rule}`);
|
|
1188
1325
|
}
|
|
1189
1326
|
}
|
|
1190
1327
|
for (const dir of DEPRECATED_CURSOR_RULE_DIRS) {
|
|
1191
|
-
const p =
|
|
1328
|
+
const p = join10(targetDir, ".cursor", "rules", dir);
|
|
1192
1329
|
if (await pathExists(p)) {
|
|
1193
1330
|
found.push(`.cursor/rules/${dir}`);
|
|
1194
1331
|
}
|
|
1195
1332
|
}
|
|
1196
1333
|
for (const cmd of DEPRECATED_COMMANDS) {
|
|
1197
1334
|
for (const prefix of [".cursor/commands", ".claude/commands"]) {
|
|
1198
|
-
const p =
|
|
1335
|
+
const p = join10(targetDir, prefix, cmd);
|
|
1199
1336
|
if (await pathExists(p)) {
|
|
1200
1337
|
found.push(`${prefix}/${cmd}`);
|
|
1201
1338
|
}
|
|
@@ -1204,22 +1341,22 @@ async function scanDeprecated(targetDir) {
|
|
|
1204
1341
|
return found;
|
|
1205
1342
|
}
|
|
1206
1343
|
async function handleLegacyContext(targetDir) {
|
|
1207
|
-
const contextDir =
|
|
1208
|
-
const legacyDir =
|
|
1344
|
+
const contextDir = join10(targetDir, "flydocs", "context");
|
|
1345
|
+
const legacyDir = join10(contextDir, "legacy");
|
|
1209
1346
|
const oldFiles = ["overview.md", "stack.md", "standards.md"];
|
|
1210
1347
|
let hasOld = false;
|
|
1211
1348
|
for (const f of oldFiles) {
|
|
1212
|
-
if (await pathExists(
|
|
1349
|
+
if (await pathExists(join10(contextDir, f))) {
|
|
1213
1350
|
hasOld = true;
|
|
1214
1351
|
break;
|
|
1215
1352
|
}
|
|
1216
1353
|
}
|
|
1217
1354
|
if (hasOld) {
|
|
1218
|
-
await
|
|
1355
|
+
await mkdir4(legacyDir, { recursive: true });
|
|
1219
1356
|
for (const f of oldFiles) {
|
|
1220
|
-
const src =
|
|
1357
|
+
const src = join10(contextDir, f);
|
|
1221
1358
|
if (await pathExists(src)) {
|
|
1222
|
-
await rename(src,
|
|
1359
|
+
await rename(src, join10(legacyDir, f));
|
|
1223
1360
|
printStatus(`Moved flydocs/context/${f} \u2192 legacy/`);
|
|
1224
1361
|
}
|
|
1225
1362
|
}
|
|
@@ -1229,7 +1366,7 @@ async function handleLegacyContext(targetDir) {
|
|
|
1229
1366
|
}
|
|
1230
1367
|
}
|
|
1231
1368
|
async function checkLegacyFolder(targetDir) {
|
|
1232
|
-
const legacyDir =
|
|
1369
|
+
const legacyDir = join10(targetDir, "flydocs", "context", "legacy");
|
|
1233
1370
|
if (!await pathExists(legacyDir)) return null;
|
|
1234
1371
|
try {
|
|
1235
1372
|
const entries = await readdir2(legacyDir);
|
|
@@ -1259,7 +1396,7 @@ async function promptCleanup(targetDir, paths) {
|
|
|
1259
1396
|
return;
|
|
1260
1397
|
}
|
|
1261
1398
|
for (const p of paths) {
|
|
1262
|
-
await rm3(
|
|
1399
|
+
await rm3(join10(targetDir, p), { recursive: true, force: true });
|
|
1263
1400
|
printStatus(`Deleted: ${p}`);
|
|
1264
1401
|
}
|
|
1265
1402
|
}
|
|
@@ -1310,26 +1447,26 @@ var init_deprecated = __esm({
|
|
|
1310
1447
|
});
|
|
1311
1448
|
|
|
1312
1449
|
// src/lib/gitignore.ts
|
|
1313
|
-
import { readFile as
|
|
1314
|
-
import { join as
|
|
1450
|
+
import { readFile as readFile6, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
1451
|
+
import { join as join11 } from "path";
|
|
1315
1452
|
async function ensureGitignore(targetDir) {
|
|
1316
|
-
const gitignorePath =
|
|
1453
|
+
const gitignorePath = join11(targetDir, ".gitignore");
|
|
1317
1454
|
if (await pathExists(gitignorePath)) {
|
|
1318
|
-
const content = await
|
|
1455
|
+
const content = await readFile6(gitignorePath, "utf-8");
|
|
1319
1456
|
if (!content.includes("# FlyDocs")) {
|
|
1320
1457
|
const section = "\n# FlyDocs\n" + FLYDOCS_GITIGNORE_ENTRIES.join("\n") + "\n";
|
|
1321
1458
|
await appendFile(gitignorePath, section, "utf-8");
|
|
1322
1459
|
printStatus("Added FlyDocs entries to .gitignore");
|
|
1323
1460
|
}
|
|
1324
1461
|
} else {
|
|
1325
|
-
await
|
|
1462
|
+
await writeFile4(gitignorePath, FULL_GITIGNORE_TEMPLATE, "utf-8");
|
|
1326
1463
|
printStatus(".gitignore (new)");
|
|
1327
1464
|
}
|
|
1328
1465
|
}
|
|
1329
1466
|
async function migrateGitignore(targetDir) {
|
|
1330
|
-
const gitignorePath =
|
|
1467
|
+
const gitignorePath = join11(targetDir, ".gitignore");
|
|
1331
1468
|
if (!await pathExists(gitignorePath)) return;
|
|
1332
|
-
const content = await
|
|
1469
|
+
const content = await readFile6(gitignorePath, "utf-8");
|
|
1333
1470
|
if (!content.includes("flydocs/context/graph.json")) {
|
|
1334
1471
|
if (content.includes("# FlyDocs")) {
|
|
1335
1472
|
const lines = content.split("\n");
|
|
@@ -1340,7 +1477,7 @@ async function migrateGitignore(targetDir) {
|
|
|
1340
1477
|
insertIdx++;
|
|
1341
1478
|
}
|
|
1342
1479
|
lines.splice(insertIdx, 0, "flydocs/context/graph.json");
|
|
1343
|
-
await
|
|
1480
|
+
await writeFile4(gitignorePath, lines.join("\n"), "utf-8");
|
|
1344
1481
|
} else {
|
|
1345
1482
|
await appendFile(
|
|
1346
1483
|
gitignorePath,
|
|
@@ -1409,7 +1546,7 @@ __pycache__/
|
|
|
1409
1546
|
});
|
|
1410
1547
|
|
|
1411
1548
|
// src/lib/version.ts
|
|
1412
|
-
import { readFile as
|
|
1549
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
1413
1550
|
function compareVersions(v1, v2) {
|
|
1414
1551
|
const [core1, pre1] = v1.split("-", 2);
|
|
1415
1552
|
const [core2, pre2] = v2.split("-", 2);
|
|
@@ -1448,7 +1585,7 @@ function compareVersions(v1, v2) {
|
|
|
1448
1585
|
async function getWhatsNew(changelogPath, fromVersion, toVersion) {
|
|
1449
1586
|
let content;
|
|
1450
1587
|
try {
|
|
1451
|
-
content = await
|
|
1588
|
+
content = await readFile7(changelogPath, "utf-8");
|
|
1452
1589
|
} catch {
|
|
1453
1590
|
return [];
|
|
1454
1591
|
}
|
|
@@ -1477,13 +1614,13 @@ var init_version = __esm({
|
|
|
1477
1614
|
});
|
|
1478
1615
|
|
|
1479
1616
|
// src/lib/update-check.ts
|
|
1480
|
-
import { readFile as
|
|
1481
|
-
import { join as
|
|
1617
|
+
import { readFile as readFile8, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
1618
|
+
import { join as join12 } from "path";
|
|
1482
1619
|
import { homedir } from "os";
|
|
1483
1620
|
import pc5 from "picocolors";
|
|
1484
1621
|
async function readCache() {
|
|
1485
1622
|
try {
|
|
1486
|
-
const raw = await
|
|
1623
|
+
const raw = await readFile8(CACHE_FILE, "utf-8");
|
|
1487
1624
|
const parsed = JSON.parse(raw);
|
|
1488
1625
|
if (typeof parsed === "object" && parsed !== null && "checkedAt" in parsed && "latestVersion" in parsed && typeof parsed.checkedAt === "number" && typeof parsed.latestVersion === "string") {
|
|
1489
1626
|
return parsed;
|
|
@@ -1495,8 +1632,8 @@ async function readCache() {
|
|
|
1495
1632
|
}
|
|
1496
1633
|
async function writeCache(cache) {
|
|
1497
1634
|
try {
|
|
1498
|
-
await
|
|
1499
|
-
await
|
|
1635
|
+
await mkdir5(join12(homedir(), ".flydocs"), { recursive: true });
|
|
1636
|
+
await writeFile5(CACHE_FILE, JSON.stringify(cache), "utf-8");
|
|
1500
1637
|
} catch {
|
|
1501
1638
|
}
|
|
1502
1639
|
}
|
|
@@ -1564,12 +1701,145 @@ var init_update_check = __esm({
|
|
|
1564
1701
|
"use strict";
|
|
1565
1702
|
init_constants();
|
|
1566
1703
|
init_version();
|
|
1567
|
-
CACHE_FILE =
|
|
1704
|
+
CACHE_FILE = join12(homedir(), ".flydocs", "update-check.json");
|
|
1568
1705
|
CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1569
1706
|
FETCH_TIMEOUT_MS = 5e3;
|
|
1570
1707
|
}
|
|
1571
1708
|
});
|
|
1572
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
|
+
|
|
1573
1843
|
// src/commands/install.ts
|
|
1574
1844
|
var install_exports = {};
|
|
1575
1845
|
__export(install_exports, {
|
|
@@ -1577,8 +1847,10 @@ __export(install_exports, {
|
|
|
1577
1847
|
});
|
|
1578
1848
|
import { defineCommand } from "citty";
|
|
1579
1849
|
import { resolve as resolve2 } from "path";
|
|
1580
|
-
import { join as
|
|
1850
|
+
import { join as join14 } from "path";
|
|
1851
|
+
import { mkdir as mkdir7 } from "fs/promises";
|
|
1581
1852
|
import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1853
|
+
import pc6 from "picocolors";
|
|
1582
1854
|
var install_default;
|
|
1583
1855
|
var init_install = __esm({
|
|
1584
1856
|
"src/commands/install.ts"() {
|
|
@@ -1588,12 +1860,14 @@ var init_install = __esm({
|
|
|
1588
1860
|
init_ui();
|
|
1589
1861
|
init_config();
|
|
1590
1862
|
init_skills();
|
|
1863
|
+
init_user_content();
|
|
1591
1864
|
init_stack();
|
|
1592
1865
|
init_community_skills();
|
|
1593
1866
|
init_deprecated();
|
|
1594
1867
|
init_gitignore();
|
|
1595
1868
|
init_post_install();
|
|
1596
1869
|
init_update_check();
|
|
1870
|
+
init_telemetry();
|
|
1597
1871
|
install_default = defineCommand({
|
|
1598
1872
|
meta: {
|
|
1599
1873
|
name: "install",
|
|
@@ -1602,7 +1876,7 @@ var init_install = __esm({
|
|
|
1602
1876
|
args: {
|
|
1603
1877
|
tier: {
|
|
1604
1878
|
type: "string",
|
|
1605
|
-
description: "Set tier: 'local' (free) or 'cloud' (
|
|
1879
|
+
description: "Set tier: 'local' (free) or 'cloud' (managed)"
|
|
1606
1880
|
},
|
|
1607
1881
|
path: {
|
|
1608
1882
|
type: "string",
|
|
@@ -1629,6 +1903,7 @@ var init_install = __esm({
|
|
|
1629
1903
|
const templateDir = await resolveTemplatePath(args["local-source"]);
|
|
1630
1904
|
const version = await readTemplateVersion(templateDir);
|
|
1631
1905
|
printBanner(version);
|
|
1906
|
+
await capture("install_started", { template_version: version });
|
|
1632
1907
|
let targetDir;
|
|
1633
1908
|
if (args.path) {
|
|
1634
1909
|
targetDir = resolve2(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
@@ -1654,60 +1929,95 @@ var init_install = __esm({
|
|
|
1654
1929
|
process.exit(1);
|
|
1655
1930
|
}
|
|
1656
1931
|
tier = args.tier;
|
|
1657
|
-
|
|
1658
|
-
} else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
|
|
1932
|
+
} else if (await pathExists(join14(targetDir, ".flydocs", "config.json"))) {
|
|
1659
1933
|
try {
|
|
1660
1934
|
const existing = await readConfig(targetDir);
|
|
1661
1935
|
if (existing.tier) {
|
|
1662
1936
|
tier = existing.tier;
|
|
1663
|
-
printInfo(`Tier from config: ${tier}`);
|
|
1664
1937
|
}
|
|
1665
1938
|
} catch {
|
|
1666
1939
|
}
|
|
1667
1940
|
}
|
|
1668
|
-
if (!tier) {
|
|
1669
|
-
|
|
1670
|
-
|
|
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)
|
|
1671
1967
|
Directory: ${targetDir}`
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1968
|
+
});
|
|
1969
|
+
if (isCancel3(shouldInstall) || !shouldInstall) {
|
|
1970
|
+
cancel2("Installation cancelled.");
|
|
1971
|
+
process.exit(0);
|
|
1972
|
+
}
|
|
1973
|
+
console.log();
|
|
1676
1974
|
}
|
|
1975
|
+
}
|
|
1976
|
+
if (!tier) {
|
|
1677
1977
|
tier = "local";
|
|
1678
|
-
console.log();
|
|
1679
1978
|
}
|
|
1680
|
-
|
|
1979
|
+
printInfo(`Tier: ${tier}`);
|
|
1980
|
+
await capture("install_tier_selected", { tier });
|
|
1981
|
+
if (!await pathExists(join14(targetDir, ".git"))) {
|
|
1681
1982
|
printWarning("No git repository detected. Run git init when ready.");
|
|
1682
1983
|
}
|
|
1683
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
|
+
}
|
|
1684
1994
|
console.log("Installing framework files...");
|
|
1685
1995
|
await replaceDirectory(
|
|
1686
|
-
|
|
1687
|
-
|
|
1996
|
+
join14(templateDir, ".flydocs", "templates"),
|
|
1997
|
+
join14(targetDir, ".flydocs", "templates")
|
|
1688
1998
|
);
|
|
1689
1999
|
await replaceDirectory(
|
|
1690
|
-
|
|
1691
|
-
|
|
2000
|
+
join14(templateDir, ".flydocs", "hooks"),
|
|
2001
|
+
join14(targetDir, ".flydocs", "hooks")
|
|
1692
2002
|
);
|
|
1693
2003
|
await replaceDirectory(
|
|
1694
|
-
|
|
1695
|
-
|
|
2004
|
+
join14(templateDir, ".flydocs", "scripts"),
|
|
2005
|
+
join14(targetDir, ".flydocs", "scripts")
|
|
1696
2006
|
);
|
|
1697
2007
|
await copyFile(
|
|
1698
|
-
|
|
1699
|
-
|
|
2008
|
+
join14(templateDir, ".flydocs", "version"),
|
|
2009
|
+
join14(targetDir, ".flydocs", "version")
|
|
1700
2010
|
);
|
|
1701
|
-
const manifestSrc =
|
|
2011
|
+
const manifestSrc = join14(templateDir, "manifest.json");
|
|
1702
2012
|
if (await pathExists(manifestSrc)) {
|
|
1703
|
-
await copyFile(manifestSrc,
|
|
2013
|
+
await copyFile(manifestSrc, join14(targetDir, ".flydocs", "manifest.json"));
|
|
1704
2014
|
}
|
|
1705
|
-
const changelogSrc =
|
|
2015
|
+
const changelogSrc = join14(templateDir, "CHANGELOG.md");
|
|
1706
2016
|
if (await pathExists(changelogSrc)) {
|
|
1707
|
-
await copyFile(changelogSrc,
|
|
2017
|
+
await copyFile(changelogSrc, join14(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
1708
2018
|
}
|
|
1709
2019
|
printStatus(".flydocs/templates, hooks, version, manifest, changelog");
|
|
1710
|
-
const configPath =
|
|
2020
|
+
const configPath = join14(targetDir, ".flydocs", "config.json");
|
|
1711
2021
|
if (!await pathExists(configPath)) {
|
|
1712
2022
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
1713
2023
|
await writeConfig(targetDir, config);
|
|
@@ -1732,48 +2042,84 @@ var init_install = __esm({
|
|
|
1732
2042
|
await installOwnedSkills(templateDir, targetDir, tier);
|
|
1733
2043
|
printStatus(`Skills installed (tier: ${tier})`);
|
|
1734
2044
|
console.log();
|
|
1735
|
-
console.log("
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
)
|
|
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
|
+
}
|
|
1742
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...");
|
|
1743
2096
|
await copyDirectoryContents(
|
|
1744
|
-
|
|
1745
|
-
|
|
2097
|
+
join14(templateDir, ".claude", "commands"),
|
|
2098
|
+
join14(targetDir, ".claude", "commands")
|
|
1746
2099
|
);
|
|
1747
2100
|
await copyFile(
|
|
1748
|
-
|
|
1749
|
-
|
|
2101
|
+
join14(templateDir, ".claude", "CLAUDE.md"),
|
|
2102
|
+
join14(targetDir, ".claude", "CLAUDE.md")
|
|
1750
2103
|
);
|
|
1751
2104
|
await copyFile(
|
|
1752
|
-
|
|
1753
|
-
|
|
2105
|
+
join14(templateDir, ".claude", "settings.json"),
|
|
2106
|
+
join14(targetDir, ".claude", "settings.json")
|
|
1754
2107
|
);
|
|
1755
|
-
printStatus(".claude/ (
|
|
1756
|
-
const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
|
|
1757
|
-
if (await pathExists(cursorAgentsSrc)) {
|
|
1758
|
-
await copyDirectoryContents(
|
|
1759
|
-
cursorAgentsSrc,
|
|
1760
|
-
join12(targetDir, ".cursor", "agents")
|
|
1761
|
-
);
|
|
1762
|
-
}
|
|
2108
|
+
printStatus(".claude/ (commands, CLAUDE.md, settings)");
|
|
1763
2109
|
await copyDirectoryContents(
|
|
1764
|
-
|
|
1765
|
-
|
|
2110
|
+
join14(templateDir, ".claude", "commands"),
|
|
2111
|
+
join14(targetDir, ".cursor", "commands")
|
|
1766
2112
|
);
|
|
1767
2113
|
await copyFile(
|
|
1768
|
-
|
|
1769
|
-
|
|
2114
|
+
join14(templateDir, ".cursor", "hooks.json"),
|
|
2115
|
+
join14(targetDir, ".cursor", "hooks.json")
|
|
1770
2116
|
);
|
|
1771
|
-
printStatus(".cursor/ (
|
|
2117
|
+
printStatus(".cursor/ (commands, hooks)");
|
|
1772
2118
|
await copyCursorRules(targetDir);
|
|
1773
2119
|
printStatus(".cursor/rules/");
|
|
1774
2120
|
await copyFile(
|
|
1775
|
-
|
|
1776
|
-
|
|
2121
|
+
join14(templateDir, "AGENTS.md"),
|
|
2122
|
+
join14(targetDir, "AGENTS.md")
|
|
1777
2123
|
);
|
|
1778
2124
|
printStatus("AGENTS.md");
|
|
1779
2125
|
await runManifestGeneration(targetDir);
|
|
@@ -1782,40 +2128,40 @@ var init_install = __esm({
|
|
|
1782
2128
|
console.log("Installing project templates...");
|
|
1783
2129
|
const userFiles = [
|
|
1784
2130
|
{
|
|
1785
|
-
src:
|
|
1786
|
-
dest:
|
|
2131
|
+
src: join14(templateDir, "flydocs", "context", "project.md"),
|
|
2132
|
+
dest: join14(targetDir, "flydocs", "context", "project.md"),
|
|
1787
2133
|
label: "flydocs/context/project.md"
|
|
1788
2134
|
},
|
|
1789
2135
|
{
|
|
1790
|
-
src:
|
|
1791
|
-
dest:
|
|
2136
|
+
src: join14(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
2137
|
+
dest: join14(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
1792
2138
|
label: "flydocs/knowledge/INDEX.md"
|
|
1793
2139
|
},
|
|
1794
2140
|
{
|
|
1795
|
-
src:
|
|
1796
|
-
dest:
|
|
2141
|
+
src: join14(templateDir, "flydocs", "knowledge", "README.md"),
|
|
2142
|
+
dest: join14(targetDir, "flydocs", "knowledge", "README.md"),
|
|
1797
2143
|
label: "flydocs/knowledge/README.md"
|
|
1798
2144
|
},
|
|
1799
2145
|
{
|
|
1800
|
-
src:
|
|
2146
|
+
src: join14(
|
|
1801
2147
|
templateDir,
|
|
1802
2148
|
"flydocs",
|
|
1803
2149
|
"knowledge",
|
|
1804
2150
|
"product",
|
|
1805
2151
|
"personas.md"
|
|
1806
2152
|
),
|
|
1807
|
-
dest:
|
|
2153
|
+
dest: join14(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
1808
2154
|
label: "flydocs/knowledge/product/personas.md"
|
|
1809
2155
|
},
|
|
1810
2156
|
{
|
|
1811
|
-
src:
|
|
2157
|
+
src: join14(
|
|
1812
2158
|
templateDir,
|
|
1813
2159
|
"flydocs",
|
|
1814
2160
|
"knowledge",
|
|
1815
2161
|
"product",
|
|
1816
2162
|
"user-flows.md"
|
|
1817
2163
|
),
|
|
1818
|
-
dest:
|
|
2164
|
+
dest: join14(
|
|
1819
2165
|
targetDir,
|
|
1820
2166
|
"flydocs",
|
|
1821
2167
|
"knowledge",
|
|
@@ -1825,18 +2171,18 @@ var init_install = __esm({
|
|
|
1825
2171
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
1826
2172
|
},
|
|
1827
2173
|
{
|
|
1828
|
-
src:
|
|
1829
|
-
dest:
|
|
2174
|
+
src: join14(templateDir, "flydocs", "design-system", "README.md"),
|
|
2175
|
+
dest: join14(targetDir, "flydocs", "design-system", "README.md"),
|
|
1830
2176
|
label: "flydocs/design-system/README.md"
|
|
1831
2177
|
},
|
|
1832
2178
|
{
|
|
1833
|
-
src:
|
|
2179
|
+
src: join14(
|
|
1834
2180
|
templateDir,
|
|
1835
2181
|
"flydocs",
|
|
1836
2182
|
"design-system",
|
|
1837
2183
|
"component-patterns.md"
|
|
1838
2184
|
),
|
|
1839
|
-
dest:
|
|
2185
|
+
dest: join14(
|
|
1840
2186
|
targetDir,
|
|
1841
2187
|
"flydocs",
|
|
1842
2188
|
"design-system",
|
|
@@ -1845,13 +2191,13 @@ var init_install = __esm({
|
|
|
1845
2191
|
label: "flydocs/design-system/component-patterns.md"
|
|
1846
2192
|
},
|
|
1847
2193
|
{
|
|
1848
|
-
src:
|
|
1849
|
-
dest:
|
|
2194
|
+
src: join14(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
2195
|
+
dest: join14(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
1850
2196
|
label: "flydocs/design-system/token-mapping.md"
|
|
1851
2197
|
},
|
|
1852
2198
|
{
|
|
1853
|
-
src:
|
|
1854
|
-
dest:
|
|
2199
|
+
src: join14(templateDir, "flydocs", "README.md"),
|
|
2200
|
+
dest: join14(targetDir, "flydocs", "README.md"),
|
|
1855
2201
|
label: "flydocs/README.md"
|
|
1856
2202
|
}
|
|
1857
2203
|
];
|
|
@@ -1865,14 +2211,10 @@ var init_install = __esm({
|
|
|
1865
2211
|
}
|
|
1866
2212
|
}
|
|
1867
2213
|
}
|
|
1868
|
-
const envExampleSrc =
|
|
2214
|
+
const envExampleSrc = join14(templateDir, ".env.example");
|
|
1869
2215
|
if (await pathExists(envExampleSrc)) {
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
if (!hasEnv && !hasEnvExample) {
|
|
1873
|
-
await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
|
|
1874
|
-
printStatus(".env.example (new)");
|
|
1875
|
-
}
|
|
2216
|
+
await copyFile(envExampleSrc, join14(targetDir, ".env.example"));
|
|
2217
|
+
printStatus(".env.example");
|
|
1876
2218
|
}
|
|
1877
2219
|
await ensureGitignore(targetDir);
|
|
1878
2220
|
console.log();
|
|
@@ -1890,6 +2232,9 @@ var init_install = __esm({
|
|
|
1890
2232
|
} else {
|
|
1891
2233
|
printInfo("No framework detected in package.json");
|
|
1892
2234
|
}
|
|
2235
|
+
await capture("install_skills_chosen", {
|
|
2236
|
+
stack_detected: stack.raw
|
|
2237
|
+
});
|
|
1893
2238
|
console.log();
|
|
1894
2239
|
console.log("Checking for deprecated files...");
|
|
1895
2240
|
const deprecated = await scanDeprecated(targetDir);
|
|
@@ -1902,17 +2247,17 @@ var init_install = __esm({
|
|
|
1902
2247
|
" 1. Run /flydocs-setup to configure your project",
|
|
1903
2248
|
" 2. Start working with /start-session",
|
|
1904
2249
|
"",
|
|
1905
|
-
"
|
|
2250
|
+
"Docs: https://www.flydocs.ai/docs"
|
|
1906
2251
|
] : [
|
|
1907
2252
|
`Tier: ${tier}`,
|
|
1908
2253
|
`Version: ${version}`,
|
|
1909
2254
|
"",
|
|
1910
2255
|
"Next steps:",
|
|
1911
|
-
" 1.
|
|
1912
|
-
" 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",
|
|
1913
2258
|
" 3. Start working with /start-session",
|
|
1914
2259
|
"",
|
|
1915
|
-
"
|
|
2260
|
+
"Docs: https://www.flydocs.ai/docs"
|
|
1916
2261
|
];
|
|
1917
2262
|
let copiedToClipboard = false;
|
|
1918
2263
|
try {
|
|
@@ -1931,6 +2276,7 @@ var init_install = __esm({
|
|
|
1931
2276
|
}
|
|
1932
2277
|
printCompletionBox("Installation Complete!", nextSteps);
|
|
1933
2278
|
printBetaCta();
|
|
2279
|
+
const detectedIdes = [];
|
|
1934
2280
|
try {
|
|
1935
2281
|
const { execSync: execSync2, spawn } = await import("child_process");
|
|
1936
2282
|
const isInstalled = (cmd) => {
|
|
@@ -1966,6 +2312,7 @@ var init_install = __esm({
|
|
|
1966
2312
|
passCommand: false
|
|
1967
2313
|
});
|
|
1968
2314
|
}
|
|
2315
|
+
detectedIdes.push(...ideOptions.map((o) => o.cmd));
|
|
1969
2316
|
if (ideOptions.length === 1) {
|
|
1970
2317
|
const ide = ideOptions[0];
|
|
1971
2318
|
const launchConfirm = await confirm2({
|
|
@@ -2024,6 +2371,9 @@ var init_install = __esm({
|
|
|
2024
2371
|
}
|
|
2025
2372
|
} catch {
|
|
2026
2373
|
}
|
|
2374
|
+
await capture("install_ide_detected", { ides: detectedIdes });
|
|
2375
|
+
await capture("install_completed", { tier, version });
|
|
2376
|
+
await flush();
|
|
2027
2377
|
try {
|
|
2028
2378
|
const updateResult = await checkForUpdate();
|
|
2029
2379
|
if (updateResult) {
|
|
@@ -2042,10 +2392,10 @@ __export(update_exports, {
|
|
|
2042
2392
|
default: () => update_default
|
|
2043
2393
|
});
|
|
2044
2394
|
import { defineCommand as defineCommand2 } from "citty";
|
|
2045
|
-
import { resolve as resolve3, join as
|
|
2046
|
-
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";
|
|
2047
2397
|
import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
2048
|
-
import
|
|
2398
|
+
import pc7 from "picocolors";
|
|
2049
2399
|
var update_default;
|
|
2050
2400
|
var init_update = __esm({
|
|
2051
2401
|
"src/commands/update.ts"() {
|
|
@@ -2062,6 +2412,7 @@ var init_update = __esm({
|
|
|
2062
2412
|
init_gitignore();
|
|
2063
2413
|
init_post_install();
|
|
2064
2414
|
init_update_check();
|
|
2415
|
+
init_telemetry();
|
|
2065
2416
|
update_default = defineCommand2({
|
|
2066
2417
|
meta: {
|
|
2067
2418
|
name: "update",
|
|
@@ -2079,7 +2430,7 @@ var init_update = __esm({
|
|
|
2079
2430
|
},
|
|
2080
2431
|
tier: {
|
|
2081
2432
|
type: "string",
|
|
2082
|
-
description: "Change tier: 'local' (free) or 'cloud' (
|
|
2433
|
+
description: "Change tier: 'local' (free) or 'cloud' (managed)"
|
|
2083
2434
|
},
|
|
2084
2435
|
force: {
|
|
2085
2436
|
type: "boolean",
|
|
@@ -2104,6 +2455,7 @@ var init_update = __esm({
|
|
|
2104
2455
|
printBanner(version);
|
|
2105
2456
|
printInfo("Running in update mode \u2014 framework files will be refreshed");
|
|
2106
2457
|
console.log();
|
|
2458
|
+
await capture("update_started", { template_version: version });
|
|
2107
2459
|
let targetDir;
|
|
2108
2460
|
if (args.path) {
|
|
2109
2461
|
targetDir = resolve3(args.path.replace(/^~/, process.env.HOME ?? "~"));
|
|
@@ -2148,9 +2500,9 @@ var init_update = __esm({
|
|
|
2148
2500
|
}
|
|
2149
2501
|
targetDir = resolve3(targetDir);
|
|
2150
2502
|
process.chdir(targetDir);
|
|
2151
|
-
const hasVersion = await pathExists(
|
|
2503
|
+
const hasVersion = await pathExists(join15(targetDir, ".flydocs", "version"));
|
|
2152
2504
|
const hasConfig = await pathExists(
|
|
2153
|
-
|
|
2505
|
+
join15(targetDir, ".flydocs", "config.json")
|
|
2154
2506
|
);
|
|
2155
2507
|
if (!hasVersion && !hasConfig) {
|
|
2156
2508
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -2161,8 +2513,8 @@ var init_update = __esm({
|
|
|
2161
2513
|
console.log();
|
|
2162
2514
|
let currentVersion = "0.1.0";
|
|
2163
2515
|
if (hasVersion) {
|
|
2164
|
-
const vContent = await
|
|
2165
|
-
|
|
2516
|
+
const vContent = await readFile10(
|
|
2517
|
+
join15(targetDir, ".flydocs", "version"),
|
|
2166
2518
|
"utf-8"
|
|
2167
2519
|
);
|
|
2168
2520
|
currentVersion = vContent.trim();
|
|
@@ -2188,12 +2540,18 @@ var init_update = __esm({
|
|
|
2188
2540
|
process.exit(0);
|
|
2189
2541
|
}
|
|
2190
2542
|
}
|
|
2543
|
+
await capture("update_version_compared", {
|
|
2544
|
+
current_version: currentVersion,
|
|
2545
|
+
target_version: version,
|
|
2546
|
+
version_status: versionStatus,
|
|
2547
|
+
force: args.force
|
|
2548
|
+
});
|
|
2191
2549
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
2192
2550
|
console.log();
|
|
2193
|
-
const changelogPath =
|
|
2551
|
+
const changelogPath = join15(templateDir, "CHANGELOG.md");
|
|
2194
2552
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
2195
2553
|
if (whatsNew.length > 0) {
|
|
2196
|
-
console.log(
|
|
2554
|
+
console.log(pc7.cyan("What's new:"));
|
|
2197
2555
|
console.log();
|
|
2198
2556
|
for (const entry of whatsNew) {
|
|
2199
2557
|
console.log(` ${entry}`);
|
|
@@ -2202,23 +2560,23 @@ var init_update = __esm({
|
|
|
2202
2560
|
}
|
|
2203
2561
|
const now = /* @__PURE__ */ new Date();
|
|
2204
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")}`;
|
|
2205
|
-
const backupDir =
|
|
2206
|
-
await
|
|
2563
|
+
const backupDir = join15(targetDir, ".flydocs", `backup-${ts}`);
|
|
2564
|
+
await mkdir8(backupDir, { recursive: true });
|
|
2207
2565
|
if (hasConfig) {
|
|
2208
2566
|
await cp2(
|
|
2209
|
-
|
|
2210
|
-
|
|
2567
|
+
join15(targetDir, ".flydocs", "config.json"),
|
|
2568
|
+
join15(backupDir, "config.json")
|
|
2211
2569
|
);
|
|
2212
2570
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
2213
2571
|
}
|
|
2214
2572
|
try {
|
|
2215
|
-
const flydocsDir =
|
|
2573
|
+
const flydocsDir = join15(targetDir, ".flydocs");
|
|
2216
2574
|
const entries = await readdir3(flydocsDir);
|
|
2217
2575
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
2218
2576
|
if (backups.length > 3) {
|
|
2219
2577
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
2220
2578
|
for (const old of toRemove) {
|
|
2221
|
-
await rm4(
|
|
2579
|
+
await rm4(join15(flydocsDir, old), { recursive: true, force: true });
|
|
2222
2580
|
}
|
|
2223
2581
|
}
|
|
2224
2582
|
} catch {
|
|
@@ -2255,74 +2613,118 @@ var init_update = __esm({
|
|
|
2255
2613
|
}
|
|
2256
2614
|
console.log("Replacing framework directories...");
|
|
2257
2615
|
await replaceDirectory(
|
|
2258
|
-
|
|
2259
|
-
|
|
2616
|
+
join15(templateDir, ".flydocs", "templates"),
|
|
2617
|
+
join15(targetDir, ".flydocs", "templates")
|
|
2260
2618
|
);
|
|
2261
2619
|
await replaceDirectory(
|
|
2262
|
-
|
|
2263
|
-
|
|
2620
|
+
join15(templateDir, ".flydocs", "hooks"),
|
|
2621
|
+
join15(targetDir, ".flydocs", "hooks")
|
|
2264
2622
|
);
|
|
2265
2623
|
await replaceDirectory(
|
|
2266
|
-
|
|
2267
|
-
|
|
2624
|
+
join15(templateDir, ".flydocs", "scripts"),
|
|
2625
|
+
join15(targetDir, ".flydocs", "scripts")
|
|
2268
2626
|
);
|
|
2269
2627
|
printStatus(".flydocs/templates, hooks, scripts");
|
|
2270
|
-
const
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
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"
|
|
2275
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
|
+
}
|
|
2276
2659
|
}
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
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)"
|
|
2285
2679
|
);
|
|
2680
|
+
} else {
|
|
2681
|
+
printInfo("Skipped sub-agents");
|
|
2286
2682
|
}
|
|
2287
|
-
|
|
2683
|
+
await replaceOwnedSkills(templateDir, targetDir, effectiveTier);
|
|
2684
|
+
printStatus(`.claude/skills (tier: ${effectiveTier})`);
|
|
2288
2685
|
console.log();
|
|
2289
2686
|
console.log("Replacing framework files...");
|
|
2290
2687
|
await copyFile(
|
|
2291
|
-
|
|
2292
|
-
|
|
2688
|
+
join15(templateDir, ".claude", "CLAUDE.md"),
|
|
2689
|
+
join15(targetDir, ".claude", "CLAUDE.md")
|
|
2293
2690
|
);
|
|
2294
2691
|
await copyFile(
|
|
2295
|
-
|
|
2296
|
-
|
|
2692
|
+
join15(templateDir, ".claude", "settings.json"),
|
|
2693
|
+
join15(targetDir, ".claude", "settings.json")
|
|
2297
2694
|
);
|
|
2298
2695
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2299
2696
|
await copyDirectoryContents(
|
|
2300
|
-
|
|
2301
|
-
|
|
2697
|
+
join15(templateDir, ".claude", "commands"),
|
|
2698
|
+
join15(targetDir, ".claude", "commands")
|
|
2302
2699
|
);
|
|
2303
2700
|
await copyDirectoryContents(
|
|
2304
|
-
|
|
2305
|
-
|
|
2701
|
+
join15(templateDir, ".claude", "commands"),
|
|
2702
|
+
join15(targetDir, ".cursor", "commands")
|
|
2306
2703
|
);
|
|
2307
2704
|
printStatus(".claude/commands, .cursor/commands");
|
|
2308
|
-
const skillsReadmeSrc =
|
|
2705
|
+
const skillsReadmeSrc = join15(templateDir, ".claude", "skills", "README.md");
|
|
2309
2706
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2310
2707
|
await copyFile(
|
|
2311
2708
|
skillsReadmeSrc,
|
|
2312
|
-
|
|
2709
|
+
join15(targetDir, ".claude", "skills", "README.md")
|
|
2313
2710
|
);
|
|
2314
2711
|
}
|
|
2315
2712
|
printStatus(".claude/skills/README.md");
|
|
2316
2713
|
await copyFile(
|
|
2317
|
-
|
|
2318
|
-
|
|
2714
|
+
join15(templateDir, ".cursor", "hooks.json"),
|
|
2715
|
+
join15(targetDir, ".cursor", "hooks.json")
|
|
2319
2716
|
);
|
|
2320
2717
|
printStatus(".cursor/hooks.json");
|
|
2321
2718
|
await copyFile(
|
|
2322
|
-
|
|
2323
|
-
|
|
2719
|
+
join15(templateDir, "AGENTS.md"),
|
|
2720
|
+
join15(targetDir, "AGENTS.md")
|
|
2324
2721
|
);
|
|
2325
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
|
+
}
|
|
2326
2728
|
await runManifestGeneration(targetDir);
|
|
2327
2729
|
await runContextGraphBuild(targetDir);
|
|
2328
2730
|
console.log();
|
|
@@ -2345,18 +2747,18 @@ var init_update = __esm({
|
|
|
2345
2747
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2346
2748
|
}
|
|
2347
2749
|
await copyFile(
|
|
2348
|
-
|
|
2349
|
-
|
|
2750
|
+
join15(templateDir, ".flydocs", "version"),
|
|
2751
|
+
join15(targetDir, ".flydocs", "version")
|
|
2350
2752
|
);
|
|
2351
2753
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2352
|
-
const clSrc =
|
|
2754
|
+
const clSrc = join15(templateDir, "CHANGELOG.md");
|
|
2353
2755
|
if (await pathExists(clSrc)) {
|
|
2354
|
-
await copyFile(clSrc,
|
|
2756
|
+
await copyFile(clSrc, join15(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2355
2757
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2356
2758
|
}
|
|
2357
|
-
const mfSrc =
|
|
2759
|
+
const mfSrc = join15(templateDir, "manifest.json");
|
|
2358
2760
|
if (await pathExists(mfSrc)) {
|
|
2359
|
-
await copyFile(mfSrc,
|
|
2761
|
+
await copyFile(mfSrc, join15(targetDir, ".flydocs", "manifest.json"));
|
|
2360
2762
|
printStatus(".flydocs/manifest.json");
|
|
2361
2763
|
}
|
|
2362
2764
|
console.log();
|
|
@@ -2392,6 +2794,12 @@ var init_update = __esm({
|
|
|
2392
2794
|
`Backup: .flydocs/backup-${ts}/`
|
|
2393
2795
|
]);
|
|
2394
2796
|
printBetaCta();
|
|
2797
|
+
await capture("update_completed", {
|
|
2798
|
+
current_version: currentVersion,
|
|
2799
|
+
version,
|
|
2800
|
+
tier: effectiveTier
|
|
2801
|
+
});
|
|
2802
|
+
await flush();
|
|
2395
2803
|
try {
|
|
2396
2804
|
const updateResult = await checkForUpdate();
|
|
2397
2805
|
if (updateResult) {
|
|
@@ -2404,33 +2812,352 @@ var init_update = __esm({
|
|
|
2404
2812
|
}
|
|
2405
2813
|
});
|
|
2406
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
|
+
|
|
2407
3134
|
// src/commands/setup.ts
|
|
2408
3135
|
var setup_exports = {};
|
|
2409
3136
|
__export(setup_exports, {
|
|
2410
3137
|
default: () => setup_default
|
|
2411
3138
|
});
|
|
2412
|
-
import { defineCommand as
|
|
2413
|
-
import
|
|
3139
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
3140
|
+
import pc9 from "picocolors";
|
|
2414
3141
|
var setup_default;
|
|
2415
3142
|
var init_setup = __esm({
|
|
2416
3143
|
"src/commands/setup.ts"() {
|
|
2417
3144
|
"use strict";
|
|
2418
|
-
setup_default =
|
|
3145
|
+
setup_default = defineCommand4({
|
|
2419
3146
|
meta: {
|
|
2420
3147
|
name: "setup",
|
|
2421
3148
|
description: "Configure FlyDocs settings for this project"
|
|
2422
3149
|
},
|
|
2423
3150
|
run() {
|
|
2424
3151
|
console.log();
|
|
2425
|
-
console.log(` ${
|
|
3152
|
+
console.log(` ${pc9.bold("FlyDocs Setup")}`);
|
|
2426
3153
|
console.log();
|
|
2427
3154
|
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
2428
3155
|
console.log();
|
|
2429
3156
|
console.log(
|
|
2430
|
-
` ${
|
|
3157
|
+
` ${pc9.cyan("Claude Code:")} Type ${pc9.bold("/flydocs-setup")} in chat`
|
|
2431
3158
|
);
|
|
2432
3159
|
console.log(
|
|
2433
|
-
` ${
|
|
3160
|
+
` ${pc9.cyan("Cursor:")} Type ${pc9.bold("/flydocs-setup")} in chat`
|
|
2434
3161
|
);
|
|
2435
3162
|
console.log();
|
|
2436
3163
|
console.log(` This configures your project context, detects your stack,`);
|
|
@@ -2446,14 +3173,14 @@ var skills_exports = {};
|
|
|
2446
3173
|
__export(skills_exports, {
|
|
2447
3174
|
default: () => skills_default
|
|
2448
3175
|
});
|
|
2449
|
-
import { defineCommand as
|
|
2450
|
-
import
|
|
3176
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
3177
|
+
import pc10 from "picocolors";
|
|
2451
3178
|
var list, search, add, remove, skills_default;
|
|
2452
3179
|
var init_skills2 = __esm({
|
|
2453
3180
|
"src/commands/skills.ts"() {
|
|
2454
3181
|
"use strict";
|
|
2455
3182
|
init_skill_manager();
|
|
2456
|
-
list =
|
|
3183
|
+
list = defineCommand5({
|
|
2457
3184
|
meta: {
|
|
2458
3185
|
name: "list",
|
|
2459
3186
|
description: "List installed skills"
|
|
@@ -2469,26 +3196,26 @@ var init_skills2 = __esm({
|
|
|
2469
3196
|
console.log(`${total} skill(s) installed:`);
|
|
2470
3197
|
if (result.platform.length > 0) {
|
|
2471
3198
|
console.log();
|
|
2472
|
-
console.log(
|
|
3199
|
+
console.log(pc10.bold("Platform"));
|
|
2473
3200
|
for (const skill of result.platform) {
|
|
2474
3201
|
console.log(
|
|
2475
|
-
` ${skill.name} ${
|
|
3202
|
+
` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
|
|
2476
3203
|
);
|
|
2477
3204
|
}
|
|
2478
3205
|
}
|
|
2479
3206
|
if (result.community.length > 0) {
|
|
2480
3207
|
console.log();
|
|
2481
|
-
console.log(
|
|
3208
|
+
console.log(pc10.bold("Community"));
|
|
2482
3209
|
for (const skill of result.community) {
|
|
2483
3210
|
console.log(
|
|
2484
|
-
` ${skill.name} ${
|
|
3211
|
+
` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
|
|
2485
3212
|
);
|
|
2486
3213
|
}
|
|
2487
3214
|
}
|
|
2488
3215
|
console.log();
|
|
2489
3216
|
}
|
|
2490
3217
|
});
|
|
2491
|
-
search =
|
|
3218
|
+
search = defineCommand5({
|
|
2492
3219
|
meta: {
|
|
2493
3220
|
name: "search",
|
|
2494
3221
|
description: "Search community skills"
|
|
@@ -2504,24 +3231,24 @@ var init_skills2 = __esm({
|
|
|
2504
3231
|
const results = await searchCatalog(args.keyword);
|
|
2505
3232
|
if (results.length === 0) {
|
|
2506
3233
|
console.log(`No skills found for "${args.keyword}".`);
|
|
2507
|
-
console.log(` Browse the catalog at: ${
|
|
3234
|
+
console.log(` Browse the catalog at: ${pc10.cyan("https://skills.sh/")}`);
|
|
2508
3235
|
return;
|
|
2509
3236
|
}
|
|
2510
3237
|
console.log();
|
|
2511
3238
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
2512
3239
|
console.log();
|
|
2513
3240
|
for (const skill of results) {
|
|
2514
|
-
console.log(` ${
|
|
3241
|
+
console.log(` ${pc10.bold(skill.name)}`);
|
|
2515
3242
|
console.log(` ${skill.description}`);
|
|
2516
|
-
console.log(` ${
|
|
3243
|
+
console.log(` ${pc10.dim(skill.repo)}`);
|
|
2517
3244
|
if (skill.tags.length > 0) {
|
|
2518
|
-
console.log(` ${
|
|
3245
|
+
console.log(` ${pc10.dim(skill.tags.join(", "))}`);
|
|
2519
3246
|
}
|
|
2520
3247
|
console.log();
|
|
2521
3248
|
}
|
|
2522
3249
|
}
|
|
2523
3250
|
});
|
|
2524
|
-
add =
|
|
3251
|
+
add = defineCommand5({
|
|
2525
3252
|
meta: {
|
|
2526
3253
|
name: "add",
|
|
2527
3254
|
description: "Install a community skill"
|
|
@@ -2537,7 +3264,7 @@ var init_skills2 = __esm({
|
|
|
2537
3264
|
await addSkill(process.cwd(), args.source);
|
|
2538
3265
|
}
|
|
2539
3266
|
});
|
|
2540
|
-
remove =
|
|
3267
|
+
remove = defineCommand5({
|
|
2541
3268
|
meta: {
|
|
2542
3269
|
name: "remove",
|
|
2543
3270
|
description: "Remove an installed community skill"
|
|
@@ -2553,7 +3280,7 @@ var init_skills2 = __esm({
|
|
|
2553
3280
|
await removeSkill(process.cwd(), args.name);
|
|
2554
3281
|
}
|
|
2555
3282
|
});
|
|
2556
|
-
skills_default =
|
|
3283
|
+
skills_default = defineCommand5({
|
|
2557
3284
|
meta: {
|
|
2558
3285
|
name: "skills",
|
|
2559
3286
|
description: "Manage FlyDocs skills (list, search, add, remove)"
|
|
@@ -2573,11 +3300,71 @@ var connect_exports = {};
|
|
|
2573
3300
|
__export(connect_exports, {
|
|
2574
3301
|
default: () => connect_default
|
|
2575
3302
|
});
|
|
2576
|
-
import { defineCommand as
|
|
2577
|
-
import { text as text2, confirm as
|
|
2578
|
-
import
|
|
2579
|
-
import { readFile as
|
|
2580
|
-
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
|
+
}
|
|
2581
3368
|
var connect_default;
|
|
2582
3369
|
var init_connect = __esm({
|
|
2583
3370
|
"src/commands/connect.ts"() {
|
|
@@ -2586,10 +3373,10 @@ var init_connect = __esm({
|
|
|
2586
3373
|
init_fs_ops();
|
|
2587
3374
|
init_template();
|
|
2588
3375
|
init_ui();
|
|
2589
|
-
connect_default =
|
|
3376
|
+
connect_default = defineCommand6({
|
|
2590
3377
|
meta: {
|
|
2591
3378
|
name: "connect",
|
|
2592
|
-
description: "Connect FlyDocs to a cloud provider
|
|
3379
|
+
description: "Connect FlyDocs to a cloud provider"
|
|
2593
3380
|
},
|
|
2594
3381
|
args: {
|
|
2595
3382
|
path: {
|
|
@@ -2606,16 +3393,16 @@ var init_connect = __esm({
|
|
|
2606
3393
|
},
|
|
2607
3394
|
key: {
|
|
2608
3395
|
type: "string",
|
|
2609
|
-
description: "
|
|
3396
|
+
description: "API key (fdk_ for relay, lin_api_ for direct Linear)"
|
|
2610
3397
|
}
|
|
2611
3398
|
},
|
|
2612
3399
|
async run({ args }) {
|
|
2613
3400
|
const targetDir = args.path ?? process.cwd();
|
|
2614
|
-
const configPath =
|
|
3401
|
+
const configPath = join17(targetDir, ".flydocs", "config.json");
|
|
2615
3402
|
if (!await pathExists(configPath)) {
|
|
2616
3403
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
2617
3404
|
console.log(
|
|
2618
|
-
` Run ${
|
|
3405
|
+
` Run ${pc11.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
2619
3406
|
);
|
|
2620
3407
|
process.exit(1);
|
|
2621
3408
|
}
|
|
@@ -2623,87 +3410,85 @@ var init_connect = __esm({
|
|
|
2623
3410
|
if (config.tier === "cloud") {
|
|
2624
3411
|
printInfo("This project is already connected to the cloud tier.");
|
|
2625
3412
|
console.log();
|
|
2626
|
-
const reconnect = await
|
|
3413
|
+
const reconnect = await confirm5({
|
|
2627
3414
|
message: "Want to update your API key?"
|
|
2628
3415
|
});
|
|
2629
|
-
if (
|
|
3416
|
+
if (isCancel6(reconnect) || !reconnect) {
|
|
2630
3417
|
console.log(` No changes made.`);
|
|
2631
3418
|
return;
|
|
2632
3419
|
}
|
|
2633
3420
|
}
|
|
2634
3421
|
console.log();
|
|
2635
|
-
console.log(` ${
|
|
3422
|
+
console.log(` ${pc11.bold("Connect to FlyDocs Cloud")}`);
|
|
2636
3423
|
console.log();
|
|
2637
3424
|
console.log(
|
|
2638
|
-
` ${
|
|
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")}`
|
|
2639
3429
|
);
|
|
2640
3430
|
console.log();
|
|
2641
3431
|
let apiKey = args.key ?? "";
|
|
2642
3432
|
if (!apiKey) {
|
|
2643
3433
|
const keyInput = await text2({
|
|
2644
|
-
message: "Enter your
|
|
2645
|
-
placeholder: "lin_api_...",
|
|
3434
|
+
message: "Enter your API key",
|
|
3435
|
+
placeholder: "fdk_... or lin_api_...",
|
|
2646
3436
|
validate(value) {
|
|
2647
3437
|
if (!value.trim()) return "API key is required";
|
|
2648
|
-
|
|
2649
|
-
|
|
3438
|
+
const type = detectKeyType(value.trim());
|
|
3439
|
+
if (type === "unknown")
|
|
3440
|
+
return "Key must start with fdk_ (FlyDocs) or lin_api_ (Linear)";
|
|
2650
3441
|
return void 0;
|
|
2651
3442
|
}
|
|
2652
3443
|
});
|
|
2653
|
-
if (
|
|
2654
|
-
|
|
3444
|
+
if (isCancel6(keyInput)) {
|
|
3445
|
+
cancel5("Connection cancelled.");
|
|
2655
3446
|
process.exit(0);
|
|
2656
3447
|
}
|
|
2657
|
-
apiKey = keyInput;
|
|
3448
|
+
apiKey = keyInput.trim();
|
|
2658
3449
|
}
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
method: "POST",
|
|
2663
|
-
headers: {
|
|
2664
|
-
Authorization: apiKey,
|
|
2665
|
-
"Content-Type": "application/json"
|
|
2666
|
-
},
|
|
2667
|
-
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
2668
|
-
signal: AbortSignal.timeout(15e3)
|
|
2669
|
-
});
|
|
2670
|
-
if (!response.ok) {
|
|
2671
|
-
throw new Error(`HTTP ${response.status}`);
|
|
2672
|
-
}
|
|
2673
|
-
const data = await response.json();
|
|
2674
|
-
if (!data.data?.viewer) {
|
|
2675
|
-
throw new Error("Invalid response");
|
|
2676
|
-
}
|
|
2677
|
-
const viewer = data.data.viewer;
|
|
2678
|
-
printStatus(`Authenticated as ${pc9.bold(viewer.name)} (${viewer.email})`);
|
|
2679
|
-
} catch {
|
|
2680
|
-
printError("Invalid API key or network error.");
|
|
2681
|
-
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.");
|
|
2682
3453
|
process.exit(1);
|
|
2683
3454
|
}
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
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."
|
|
2693
3468
|
);
|
|
2694
|
-
|
|
2695
|
-
} else {
|
|
2696
|
-
await appendFile2(targetEnvPath, `
|
|
2697
|
-
LINEAR_API_KEY=${apiKey}
|
|
2698
|
-
`);
|
|
3469
|
+
process.exit(1);
|
|
2699
3470
|
}
|
|
3471
|
+
const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
|
|
3472
|
+
printStatus(`API key stored in ${pc11.dim(envFile)}`);
|
|
2700
3473
|
} else {
|
|
2701
|
-
|
|
2702
|
-
|
|
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)}`);
|
|
2703
3491
|
}
|
|
2704
|
-
printStatus(
|
|
2705
|
-
`API key stored in ${pc9.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
|
|
2706
|
-
);
|
|
2707
3492
|
const wasLocal = config.tier === "local";
|
|
2708
3493
|
config.tier = "cloud";
|
|
2709
3494
|
config.provider = config.provider ?? { type: "linear", teamId: null };
|
|
@@ -2715,16 +3500,16 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2715
3500
|
const templateDir = await resolveTemplatePath(
|
|
2716
3501
|
args["local-source"] || void 0
|
|
2717
3502
|
);
|
|
2718
|
-
const templateSkillsDir =
|
|
2719
|
-
const skillsDir =
|
|
3503
|
+
const templateSkillsDir = join17(templateDir, ".claude", "skills");
|
|
3504
|
+
const skillsDir = join17(targetDir, ".claude", "skills");
|
|
2720
3505
|
await replaceDirectory(
|
|
2721
|
-
|
|
2722
|
-
|
|
3506
|
+
join17(templateSkillsDir, "flydocs-cloud"),
|
|
3507
|
+
join17(skillsDir, "flydocs-cloud")
|
|
2723
3508
|
);
|
|
2724
|
-
const { rm:
|
|
2725
|
-
const localSkillDir =
|
|
3509
|
+
const { rm: rm6 } = await import("fs/promises");
|
|
3510
|
+
const localSkillDir = join17(skillsDir, "flydocs-local");
|
|
2726
3511
|
if (await pathExists(localSkillDir)) {
|
|
2727
|
-
await
|
|
3512
|
+
await rm6(localSkillDir, { recursive: true, force: true });
|
|
2728
3513
|
}
|
|
2729
3514
|
printStatus("Cloud mechanism skill installed");
|
|
2730
3515
|
} catch {
|
|
@@ -2735,14 +3520,14 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2735
3520
|
}
|
|
2736
3521
|
console.log();
|
|
2737
3522
|
console.log(
|
|
2738
|
-
` ${
|
|
3523
|
+
` ${pc11.bold("Connected!")} Your project is now on the cloud tier.`
|
|
2739
3524
|
);
|
|
2740
3525
|
console.log();
|
|
2741
3526
|
console.log(` Next steps:`);
|
|
2742
3527
|
console.log(
|
|
2743
|
-
` 1. Run ${
|
|
3528
|
+
` 1. Run ${pc11.cyan("/flydocs-setup")} in your IDE to configure your project`
|
|
2744
3529
|
);
|
|
2745
|
-
console.log(` 2. Run ${
|
|
3530
|
+
console.log(` 2. Run ${pc11.cyan("/start-session")} to begin working`);
|
|
2746
3531
|
console.log();
|
|
2747
3532
|
}
|
|
2748
3533
|
});
|
|
@@ -2754,15 +3539,15 @@ var upgrade_exports = {};
|
|
|
2754
3539
|
__export(upgrade_exports, {
|
|
2755
3540
|
default: () => upgrade_default
|
|
2756
3541
|
});
|
|
2757
|
-
import { defineCommand as
|
|
2758
|
-
import
|
|
3542
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
3543
|
+
import pc12 from "picocolors";
|
|
2759
3544
|
var upgrade_default;
|
|
2760
3545
|
var init_upgrade = __esm({
|
|
2761
3546
|
"src/commands/upgrade.ts"() {
|
|
2762
3547
|
"use strict";
|
|
2763
3548
|
init_config();
|
|
2764
3549
|
init_fs_ops();
|
|
2765
|
-
upgrade_default =
|
|
3550
|
+
upgrade_default = defineCommand7({
|
|
2766
3551
|
meta: {
|
|
2767
3552
|
name: "upgrade",
|
|
2768
3553
|
description: "Learn about FlyDocs Cloud tier and upgrade from local"
|
|
@@ -2791,38 +3576,40 @@ var init_upgrade = __esm({
|
|
|
2791
3576
|
console.log();
|
|
2792
3577
|
if (currentTier === "cloud") {
|
|
2793
3578
|
console.log(
|
|
2794
|
-
` ${
|
|
3579
|
+
` ${pc12.green("\u2713")} You're already on the ${pc12.bold("cloud")} tier.`
|
|
2795
3580
|
);
|
|
2796
3581
|
console.log();
|
|
2797
3582
|
console.log(
|
|
2798
3583
|
` Your issues sync with Linear via the cloud mechanism skill.`
|
|
2799
3584
|
);
|
|
2800
3585
|
console.log(
|
|
2801
|
-
` Run ${
|
|
3586
|
+
` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
|
|
2802
3587
|
);
|
|
2803
3588
|
console.log();
|
|
2804
3589
|
return;
|
|
2805
3590
|
}
|
|
2806
|
-
console.log(` ${
|
|
3591
|
+
console.log(` ${pc12.bold("FlyDocs Cloud Tier")}`);
|
|
2807
3592
|
console.log();
|
|
2808
|
-
console.log(` You're currently on the ${
|
|
3593
|
+
console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
|
|
2809
3594
|
console.log(` Upgrade to cloud for:`);
|
|
2810
3595
|
console.log();
|
|
2811
3596
|
console.log(
|
|
2812
|
-
` ${
|
|
3597
|
+
` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
|
|
2813
3598
|
);
|
|
2814
|
-
console.log(` ${
|
|
2815
|
-
console.log(` ${
|
|
2816
|
-
console.log(` ${
|
|
2817
|
-
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:")}`);
|
|
2818
3605
|
console.log();
|
|
2819
|
-
console.log(`
|
|
3606
|
+
console.log(` Option 1: Run ${pc12.cyan("/flydocs-upgrade")} in your IDE`);
|
|
3607
|
+
console.log(` Guided migration with issue transfer`);
|
|
2820
3608
|
console.log();
|
|
2821
|
-
console.log(` 1. Sign up at ${pc10.cyan("https://www.flydocs.ai")}`);
|
|
2822
|
-
console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
|
|
2823
3609
|
console.log(
|
|
2824
|
-
`
|
|
3610
|
+
` Option 2: Run ${pc12.cyan("flydocs connect")} from terminal`
|
|
2825
3611
|
);
|
|
3612
|
+
console.log(` Quick tier swap (no issue migration)`);
|
|
2826
3613
|
console.log();
|
|
2827
3614
|
}
|
|
2828
3615
|
});
|
|
@@ -2834,23 +3621,23 @@ var self_update_exports = {};
|
|
|
2834
3621
|
__export(self_update_exports, {
|
|
2835
3622
|
default: () => self_update_default
|
|
2836
3623
|
});
|
|
2837
|
-
import { defineCommand as
|
|
3624
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2838
3625
|
import { execSync } from "child_process";
|
|
2839
|
-
import
|
|
3626
|
+
import pc13 from "picocolors";
|
|
2840
3627
|
var self_update_default;
|
|
2841
3628
|
var init_self_update = __esm({
|
|
2842
3629
|
"src/commands/self-update.ts"() {
|
|
2843
3630
|
"use strict";
|
|
2844
3631
|
init_constants();
|
|
2845
3632
|
init_ui();
|
|
2846
|
-
self_update_default =
|
|
3633
|
+
self_update_default = defineCommand8({
|
|
2847
3634
|
meta: {
|
|
2848
3635
|
name: "self-update",
|
|
2849
3636
|
description: "Update FlyDocs CLI to the latest version"
|
|
2850
3637
|
},
|
|
2851
3638
|
async run() {
|
|
2852
3639
|
console.log();
|
|
2853
|
-
console.log(` Updating ${
|
|
3640
|
+
console.log(` Updating ${pc13.cyan(PACKAGE_NAME)}...`);
|
|
2854
3641
|
console.log();
|
|
2855
3642
|
try {
|
|
2856
3643
|
execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
|
|
@@ -2870,17 +3657,117 @@ var init_self_update = __esm({
|
|
|
2870
3657
|
}
|
|
2871
3658
|
});
|
|
2872
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
|
+
|
|
2873
3758
|
// src/cli.ts
|
|
2874
3759
|
init_constants();
|
|
2875
|
-
import { defineCommand as
|
|
3760
|
+
import { defineCommand as defineCommand10, runMain } from "citty";
|
|
2876
3761
|
var SUB_COMMANDS = /* @__PURE__ */ new Set([
|
|
2877
3762
|
"install",
|
|
2878
3763
|
"update",
|
|
3764
|
+
"uninstall",
|
|
2879
3765
|
"setup",
|
|
2880
3766
|
"skills",
|
|
2881
3767
|
"connect",
|
|
2882
3768
|
"upgrade",
|
|
2883
|
-
"self-update"
|
|
3769
|
+
"self-update",
|
|
3770
|
+
"telemetry"
|
|
2884
3771
|
]);
|
|
2885
3772
|
var userArgs = process.argv.slice(2);
|
|
2886
3773
|
var hasMetaFlag = userArgs.some(
|
|
@@ -2890,7 +3777,7 @@ var firstPositional = userArgs.find((a) => !a.startsWith("-"));
|
|
|
2890
3777
|
if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
|
|
2891
3778
|
process.argv.splice(2, 0, "install");
|
|
2892
3779
|
}
|
|
2893
|
-
var main =
|
|
3780
|
+
var main = defineCommand10({
|
|
2894
3781
|
meta: {
|
|
2895
3782
|
name: CLI_NAME,
|
|
2896
3783
|
version: CLI_VERSION,
|
|
@@ -2899,11 +3786,13 @@ var main = defineCommand8({
|
|
|
2899
3786
|
subCommands: {
|
|
2900
3787
|
install: () => Promise.resolve().then(() => (init_install(), install_exports)).then((m) => m.default),
|
|
2901
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),
|
|
2902
3790
|
setup: () => Promise.resolve().then(() => (init_setup(), setup_exports)).then((m) => m.default),
|
|
2903
3791
|
skills: () => Promise.resolve().then(() => (init_skills2(), skills_exports)).then((m) => m.default),
|
|
2904
3792
|
connect: () => Promise.resolve().then(() => (init_connect(), connect_exports)).then((m) => m.default),
|
|
2905
3793
|
upgrade: () => Promise.resolve().then(() => (init_upgrade(), upgrade_exports)).then((m) => m.default),
|
|
2906
|
-
"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)
|
|
2907
3796
|
}
|
|
2908
3797
|
});
|
|
2909
3798
|
runMain(main);
|