@flydocs/cli 0.5.0-beta.1 → 0.5.0-beta.10
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/dist/cli.js +537 -290
- package/package.json +2 -1
- package/template/.claude/CLAUDE.md +71 -36
- package/template/.claude/agents/implementation-agent.md +1 -1
- package/template/.claude/agents/research-agent.md +1 -1
- package/template/.claude/commands/flydocs-setup.md +39 -4
- package/template/.claude/commands/flydocs-update.md +3 -4
- package/template/.claude/settings.json +0 -10
- package/template/.claude/skills/README.md +36 -41
- package/template/.claude/skills/flydocs-context7/SKILL.md +105 -0
- package/template/.claude/skills/flydocs-context7/cursor-rule.mdc +49 -0
- package/template/.claude/skills/flydocs-context7/scripts/context7.py +293 -0
- package/template/.cursor/hooks.json +0 -5
- package/template/.env.example +11 -2
- package/template/.flydocs/config.json +3 -8
- package/template/.flydocs/hooks/auto-approve.py +2 -2
- package/template/.flydocs/hooks/post-edit.py +13 -0
- package/template/.flydocs/templates/instructions.md +17 -69
- package/template/.flydocs/version +1 -1
- package/template/AGENTS.md +44 -27
- package/template/CHANGELOG.md +99 -0
- package/template/flydocs/README.md +36 -55
- package/template/flydocs/design-system/README.md +21 -13
- package/template/manifest.json +7 -18
- package/template/.cursor/mcp.json +0 -16
- package/template/.flydocs/hooks/prefer-scripts.py +0 -89
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ var CLI_VERSION, CLI_NAME, PACKAGE_NAME;
|
|
|
15
15
|
var init_constants = __esm({
|
|
16
16
|
"src/lib/constants.ts"() {
|
|
17
17
|
"use strict";
|
|
18
|
-
CLI_VERSION = "0.5.0-beta.
|
|
18
|
+
CLI_VERSION = "0.5.0-beta.10";
|
|
19
19
|
CLI_NAME = "flydocs";
|
|
20
20
|
PACKAGE_NAME = "@flydocs/cli";
|
|
21
21
|
}
|
|
@@ -136,6 +136,9 @@ var init_template = __esm({
|
|
|
136
136
|
|
|
137
137
|
// src/lib/ui.ts
|
|
138
138
|
import pc2 from "picocolors";
|
|
139
|
+
function hyperlink(text3, url) {
|
|
140
|
+
return `\x1B]8;;${url}\x1B\\${text3}\x1B]8;;\x1B\\`;
|
|
141
|
+
}
|
|
139
142
|
function printStatus(message) {
|
|
140
143
|
console.log(`${pc2.green("\u2714")} ${message}`);
|
|
141
144
|
}
|
|
@@ -148,25 +151,27 @@ function printError(message) {
|
|
|
148
151
|
function printInfo(message) {
|
|
149
152
|
console.log(`${pc2.cyan("\u2139")} ${message}`);
|
|
150
153
|
}
|
|
151
|
-
function printStub(command) {
|
|
152
|
-
printWarning(`${pc2.bold(command)} is not yet implemented in the Node CLI.`);
|
|
153
|
-
console.log(` Use ${pc2.cyan("bash install.sh")} for now.`);
|
|
154
|
-
}
|
|
155
154
|
function printBanner(version) {
|
|
156
|
-
const pink = pc2.magenta;
|
|
157
|
-
const purple = (t) => pc2.cyan(t);
|
|
155
|
+
const pink = (t) => pc2.bold(pc2.magenta(t));
|
|
156
|
+
const purple = (t) => pc2.bold(pc2.cyan(t));
|
|
158
157
|
const dim = pc2.dim;
|
|
159
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");
|
|
160
163
|
console.log();
|
|
161
|
-
console.log(` ${
|
|
164
|
+
console.log(` ${pinkBlock12}`);
|
|
165
|
+
console.log(` ${pinkBlock12}`);
|
|
166
|
+
console.log(` ${pinkBlock4}`);
|
|
162
167
|
console.log(
|
|
163
|
-
` ${
|
|
168
|
+
` ${pinkBlock4} ${purpleBlock12} ${bold("FlyDocs")} ${dim("(Beta)")}`
|
|
164
169
|
);
|
|
165
170
|
console.log(
|
|
166
|
-
` ${
|
|
171
|
+
` ${purpleBlock12} ${dim("Spec-Driven Context That Helps Engineers Fly")}`
|
|
167
172
|
);
|
|
168
|
-
console.log(` ${
|
|
169
|
-
console.log(` ${
|
|
173
|
+
console.log(` ${purpleBlock4}`);
|
|
174
|
+
console.log(` ${purpleBlock4} ${dim(`v${version}`)}`);
|
|
170
175
|
console.log();
|
|
171
176
|
}
|
|
172
177
|
function printCompletionBox(title, lines) {
|
|
@@ -187,17 +192,16 @@ function printCompletionBox(title, lines) {
|
|
|
187
192
|
}
|
|
188
193
|
function printBetaCta() {
|
|
189
194
|
const dim = pc2.dim;
|
|
195
|
+
const url = "https://www.flydocs.ai?utm_source=cli&utm_medium=install&utm_campaign=beta";
|
|
190
196
|
console.log(
|
|
191
197
|
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")
|
|
192
198
|
);
|
|
193
199
|
console.log();
|
|
194
200
|
console.log(` ${pc2.bold("Join the FlyDocs Closed Beta")}`);
|
|
195
201
|
console.log(
|
|
196
|
-
` ${dim("Early access to cloud features,
|
|
197
|
-
);
|
|
198
|
-
console.log(
|
|
199
|
-
` ${pc2.cyan("https://www.flydocs.ai?utm_source=cli&utm_medium=install&utm_campaign=beta")}`
|
|
202
|
+
` ${dim("Early access to cloud features, web portal, and more.")}`
|
|
200
203
|
);
|
|
204
|
+
console.log(` ${pc2.cyan(hyperlink("flydocs.ai", url))}`);
|
|
201
205
|
console.log();
|
|
202
206
|
}
|
|
203
207
|
var init_ui = __esm({
|
|
@@ -237,7 +241,6 @@ function extractPreservedValues(config) {
|
|
|
237
241
|
issueLabels: config.issueLabels ?? {},
|
|
238
242
|
statusMapping: config.statusMapping ?? {},
|
|
239
243
|
detectedStack: config.detectedStack ?? {},
|
|
240
|
-
mcp: config.mcp ?? {},
|
|
241
244
|
skills: config.skills ?? {},
|
|
242
245
|
designSystem: config.designSystem ?? null,
|
|
243
246
|
aiLabor: config.aiLabor ?? {}
|
|
@@ -270,9 +273,6 @@ async function mergeConfig(templateDir, version, tierFlag, preserved) {
|
|
|
270
273
|
if (Object.keys(preserved.detectedStack).length > 0) {
|
|
271
274
|
config.detectedStack = preserved.detectedStack;
|
|
272
275
|
}
|
|
273
|
-
if (Object.keys(preserved.mcp).length > 0) {
|
|
274
|
-
config.mcp = preserved.mcp;
|
|
275
|
-
}
|
|
276
276
|
if (Object.keys(preserved.skills).length > 0) {
|
|
277
277
|
config.skills = preserved.skills;
|
|
278
278
|
}
|
|
@@ -317,12 +317,6 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
|
|
|
317
317
|
await replaceDirectory(src, join4(skillsDir, skill));
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
|
-
for (const skill of SUPPORTING_SKILLS) {
|
|
321
|
-
const src = join4(templateSkillsDir, skill);
|
|
322
|
-
if (await pathExists(src)) {
|
|
323
|
-
await replaceDirectory(src, join4(skillsDir, skill));
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
320
|
const readmeSrc = join4(templateSkillsDir, "README.md");
|
|
327
321
|
if (await pathExists(readmeSrc)) {
|
|
328
322
|
await copyFile(readmeSrc, join4(skillsDir, "README.md"));
|
|
@@ -331,7 +325,7 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
|
|
|
331
325
|
async function replaceOwnedSkills(templateDir, targetDir, tier) {
|
|
332
326
|
const skillsDir = join4(targetDir, ".claude", "skills");
|
|
333
327
|
const templateSkillsDir = join4(templateDir, ".claude", "skills");
|
|
334
|
-
for (const skill of
|
|
328
|
+
for (const skill of OWNED_SKILLS) {
|
|
335
329
|
const src = join4(templateSkillsDir, skill);
|
|
336
330
|
if (await pathExists(src)) {
|
|
337
331
|
await replaceDirectory(src, join4(skillsDir, skill));
|
|
@@ -379,20 +373,18 @@ async function copyCursorRules(targetDir) {
|
|
|
379
373
|
await copyFile(mechRule, join4(rulesDir, "flydocs-mechanism.mdc"));
|
|
380
374
|
}
|
|
381
375
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
await copyFile(skillRule, join4(rulesDir, `${skill}.mdc`));
|
|
392
|
-
}
|
|
376
|
+
const context7Rule = join4(
|
|
377
|
+
targetDir,
|
|
378
|
+
".claude",
|
|
379
|
+
"skills",
|
|
380
|
+
"flydocs-context7",
|
|
381
|
+
"cursor-rule.mdc"
|
|
382
|
+
);
|
|
383
|
+
if (await pathExists(context7Rule)) {
|
|
384
|
+
await copyFile(context7Rule, join4(rulesDir, "flydocs-context7.mdc"));
|
|
393
385
|
}
|
|
394
386
|
}
|
|
395
|
-
var OWNED_SKILLS,
|
|
387
|
+
var OWNED_SKILLS, MECHANISM_SKILLS;
|
|
396
388
|
var init_skills = __esm({
|
|
397
389
|
"src/lib/skills.ts"() {
|
|
398
390
|
"use strict";
|
|
@@ -401,24 +393,64 @@ var init_skills = __esm({
|
|
|
401
393
|
"flydocs-workflow",
|
|
402
394
|
"flydocs-figma",
|
|
403
395
|
"flydocs-estimates",
|
|
404
|
-
"flydocs-context-graph"
|
|
405
|
-
|
|
406
|
-
SUPPORTING_SKILLS = [
|
|
407
|
-
"implementation-flow",
|
|
408
|
-
"review-workflow",
|
|
409
|
-
"spec-templates"
|
|
396
|
+
"flydocs-context-graph",
|
|
397
|
+
"flydocs-context7"
|
|
410
398
|
];
|
|
411
399
|
MECHANISM_SKILLS = {
|
|
412
400
|
local: "flydocs-local",
|
|
413
401
|
cloud: "flydocs-cloud"
|
|
414
402
|
};
|
|
415
|
-
PREMIUM_CURSOR_RULES = ["flydocs-figma", "flydocs-estimates"];
|
|
416
403
|
}
|
|
417
404
|
});
|
|
418
405
|
|
|
419
406
|
// src/lib/stack.ts
|
|
420
407
|
import { readFile as readFile3 } from "fs/promises";
|
|
421
408
|
import { join as join5 } from "path";
|
|
409
|
+
async function parseProjectMdStack(targetDir) {
|
|
410
|
+
const detected = /* @__PURE__ */ new Set();
|
|
411
|
+
const projectMdPath = join5(targetDir, "flydocs", "context", "project.md");
|
|
412
|
+
try {
|
|
413
|
+
const content = await readFile3(projectMdPath, "utf-8");
|
|
414
|
+
const stackMatch = content.match(/## Stack\n([\s\S]*?)(?=\n## |\n---|\z)/);
|
|
415
|
+
if (!stackMatch) return detected;
|
|
416
|
+
const stackSection = stackMatch[1].toLowerCase();
|
|
417
|
+
const keywordMap = {
|
|
418
|
+
"next.js": ["nextjs", "react"],
|
|
419
|
+
nextjs: ["nextjs", "react"],
|
|
420
|
+
react: ["react"],
|
|
421
|
+
vue: ["vue"],
|
|
422
|
+
nuxt: ["nuxt", "vue"],
|
|
423
|
+
angular: ["angular"],
|
|
424
|
+
svelte: ["svelte"],
|
|
425
|
+
sveltekit: ["svelte"],
|
|
426
|
+
expo: ["expo", "react"],
|
|
427
|
+
typescript: ["typescript"],
|
|
428
|
+
tailwind: ["tailwind"],
|
|
429
|
+
convex: ["convex"],
|
|
430
|
+
prisma: ["prisma"],
|
|
431
|
+
postgresql: ["prisma"],
|
|
432
|
+
clerk: ["clerk"],
|
|
433
|
+
python: ["python"],
|
|
434
|
+
django: ["python"],
|
|
435
|
+
flask: ["python"],
|
|
436
|
+
fastapi: ["python"],
|
|
437
|
+
golang: ["go"],
|
|
438
|
+
" go ": ["go"],
|
|
439
|
+
rust: ["rust"],
|
|
440
|
+
vitest: ["vitest"],
|
|
441
|
+
jest: ["jest"]
|
|
442
|
+
};
|
|
443
|
+
for (const [keyword, triggers] of Object.entries(keywordMap)) {
|
|
444
|
+
if (stackSection.includes(keyword)) {
|
|
445
|
+
for (const trigger of triggers) {
|
|
446
|
+
detected.add(trigger);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
} catch {
|
|
451
|
+
}
|
|
452
|
+
return detected;
|
|
453
|
+
}
|
|
422
454
|
async function detectStack(targetDir) {
|
|
423
455
|
const detected = /* @__PURE__ */ new Set();
|
|
424
456
|
const pkgPath = join5(targetDir, "package.json");
|
|
@@ -433,6 +465,12 @@ async function detectStack(targetDir) {
|
|
|
433
465
|
if ("next" in allDeps) detected.add("nextjs");
|
|
434
466
|
if ("expo" in allDeps) detected.add("expo");
|
|
435
467
|
if ("react" in allDeps) detected.add("react");
|
|
468
|
+
if ("vue" in allDeps) detected.add("vue");
|
|
469
|
+
if ("nuxt" in allDeps) detected.add("nuxt");
|
|
470
|
+
if (Object.keys(allDeps).some((k) => k.startsWith("@angular/")))
|
|
471
|
+
detected.add("angular");
|
|
472
|
+
if ("svelte" in allDeps || "@sveltejs/kit" in allDeps)
|
|
473
|
+
detected.add("svelte");
|
|
436
474
|
if ("convex" in allDeps) detected.add("convex");
|
|
437
475
|
if ("prisma" in allDeps) detected.add("prisma");
|
|
438
476
|
if (Object.keys(allDeps).some((k) => k.startsWith("@clerk")))
|
|
@@ -462,14 +500,43 @@ async function detectStack(targetDir) {
|
|
|
462
500
|
if (await pathExists(join5(targetDir, "tsconfig.json"))) {
|
|
463
501
|
detected.add("typescript");
|
|
464
502
|
}
|
|
503
|
+
if (await pathExists(join5(targetDir, "nuxt.config.ts")) || await pathExists(join5(targetDir, "nuxt.config.js"))) {
|
|
504
|
+
detected.add("nuxt");
|
|
505
|
+
detected.add("vue");
|
|
506
|
+
}
|
|
507
|
+
if (await pathExists(join5(targetDir, "angular.json"))) {
|
|
508
|
+
detected.add("angular");
|
|
509
|
+
}
|
|
510
|
+
if (await pathExists(join5(targetDir, "svelte.config.js")) || await pathExists(join5(targetDir, "svelte.config.ts"))) {
|
|
511
|
+
detected.add("svelte");
|
|
512
|
+
}
|
|
513
|
+
if (await pathExists(join5(targetDir, "pyproject.toml")) || await pathExists(join5(targetDir, "requirements.txt")) || await pathExists(join5(targetDir, "setup.py"))) {
|
|
514
|
+
detected.add("python");
|
|
515
|
+
}
|
|
516
|
+
if (await pathExists(join5(targetDir, "go.mod"))) {
|
|
517
|
+
detected.add("go");
|
|
518
|
+
}
|
|
519
|
+
if (await pathExists(join5(targetDir, "Cargo.toml"))) {
|
|
520
|
+
detected.add("rust");
|
|
521
|
+
}
|
|
522
|
+
const projectMdStack = await parseProjectMdStack(targetDir);
|
|
523
|
+
for (const item of projectMdStack) {
|
|
524
|
+
detected.add(item);
|
|
525
|
+
}
|
|
465
526
|
const raw = Array.from(detected);
|
|
466
527
|
return {
|
|
467
528
|
raw,
|
|
468
|
-
frameworks: raw.filter(
|
|
529
|
+
frameworks: raw.filter(
|
|
530
|
+
(s) => ["nextjs", "react", "expo", "vue", "nuxt", "angular", "svelte"].includes(
|
|
531
|
+
s
|
|
532
|
+
)
|
|
533
|
+
),
|
|
469
534
|
database: raw.filter((s) => ["convex", "prisma"].includes(s)),
|
|
470
535
|
auth: raw.filter((s) => ["clerk", "workos"].includes(s)),
|
|
471
536
|
styling: raw.filter((s) => ["tailwind"].includes(s)),
|
|
472
|
-
language: raw.filter(
|
|
537
|
+
language: raw.filter(
|
|
538
|
+
(s) => ["typescript", "python", "go", "rust"].includes(s)
|
|
539
|
+
),
|
|
473
540
|
testing: raw.filter(
|
|
474
541
|
(s) => ["vitest", "jest", "testing-library"].includes(s)
|
|
475
542
|
)
|
|
@@ -494,7 +561,7 @@ var init_stack = __esm({
|
|
|
494
561
|
});
|
|
495
562
|
|
|
496
563
|
// src/lib/post-install.ts
|
|
497
|
-
import {
|
|
564
|
+
import { execFileSync } from "child_process";
|
|
498
565
|
import { join as join6 } from "path";
|
|
499
566
|
async function runManifestGeneration(targetDir) {
|
|
500
567
|
const scriptPath = join6(
|
|
@@ -505,7 +572,7 @@ async function runManifestGeneration(targetDir) {
|
|
|
505
572
|
);
|
|
506
573
|
if (!await pathExists(scriptPath)) return;
|
|
507
574
|
try {
|
|
508
|
-
|
|
575
|
+
execFileSync("python3", [scriptPath], {
|
|
509
576
|
cwd: targetDir,
|
|
510
577
|
stdio: "pipe"
|
|
511
578
|
});
|
|
@@ -525,7 +592,7 @@ async function runContextGraphBuild(targetDir) {
|
|
|
525
592
|
);
|
|
526
593
|
if (!await pathExists(scriptPath)) return;
|
|
527
594
|
try {
|
|
528
|
-
|
|
595
|
+
execFileSync("python3", [scriptPath], {
|
|
529
596
|
cwd: targetDir,
|
|
530
597
|
stdio: "pipe"
|
|
531
598
|
});
|
|
@@ -908,6 +975,7 @@ var init_skill_manager = __esm({
|
|
|
908
975
|
});
|
|
909
976
|
|
|
910
977
|
// src/lib/community-skills.ts
|
|
978
|
+
import { join as join8 } from "path";
|
|
911
979
|
import { multiselect, isCancel, cancel } from "@clack/prompts";
|
|
912
980
|
import pc4 from "picocolors";
|
|
913
981
|
function suggestSkills(stack) {
|
|
@@ -926,7 +994,14 @@ function suggestSkills(stack) {
|
|
|
926
994
|
}
|
|
927
995
|
async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
928
996
|
const suggestions = suggestSkills(stack);
|
|
929
|
-
|
|
997
|
+
const skillsDir = join8(targetDir, ".claude", "skills");
|
|
998
|
+
const filtered = [];
|
|
999
|
+
for (const skill of suggestions) {
|
|
1000
|
+
if (!await pathExists(join8(skillsDir, skill.name))) {
|
|
1001
|
+
filtered.push(skill);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
if (filtered.length === 0) {
|
|
930
1005
|
printInfo("No community skills suggested for detected stack.");
|
|
931
1006
|
console.log(` Browse more at: ${pc4.cyan("https://skills.sh/")}`);
|
|
932
1007
|
return;
|
|
@@ -941,18 +1016,20 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
|
|
|
941
1016
|
console.log();
|
|
942
1017
|
let selected;
|
|
943
1018
|
if (autoYes) {
|
|
944
|
-
selected =
|
|
1019
|
+
selected = filtered;
|
|
945
1020
|
console.log(" Auto-accepting all (--yes)");
|
|
946
1021
|
} else {
|
|
947
|
-
const options =
|
|
1022
|
+
const options = filtered.map((s) => ({
|
|
948
1023
|
value: s,
|
|
949
1024
|
label: s.name,
|
|
950
|
-
hint: s.description
|
|
1025
|
+
hint: s.description,
|
|
1026
|
+
initialValue: true
|
|
951
1027
|
}));
|
|
952
1028
|
const result = await multiselect({
|
|
953
|
-
message: "Select community skills to install",
|
|
1029
|
+
message: "Select community skills to install (space to toggle, enter to confirm)",
|
|
954
1030
|
options,
|
|
955
|
-
required: false
|
|
1031
|
+
required: false,
|
|
1032
|
+
initialValues: filtered
|
|
956
1033
|
});
|
|
957
1034
|
if (isCancel(result)) {
|
|
958
1035
|
cancel("Skipped community skills");
|
|
@@ -988,9 +1065,11 @@ var COMMUNITY_SKILLS_MAP;
|
|
|
988
1065
|
var init_community_skills = __esm({
|
|
989
1066
|
"src/lib/community-skills.ts"() {
|
|
990
1067
|
"use strict";
|
|
1068
|
+
init_fs_ops();
|
|
991
1069
|
init_ui();
|
|
992
1070
|
init_skill_manager();
|
|
993
1071
|
COMMUNITY_SKILLS_MAP = [
|
|
1072
|
+
// React / Next.js (Vercel official)
|
|
994
1073
|
{
|
|
995
1074
|
stackTrigger: "nextjs",
|
|
996
1075
|
repo: "vercel-labs/agent-skills",
|
|
@@ -1009,6 +1088,34 @@ var init_community_skills = __esm({
|
|
|
1009
1088
|
name: "react-best-practices",
|
|
1010
1089
|
description: "React performance optimization (40+ rules from Vercel)"
|
|
1011
1090
|
},
|
|
1091
|
+
// Vue / Nuxt
|
|
1092
|
+
{
|
|
1093
|
+
stackTrigger: "nuxt",
|
|
1094
|
+
repo: "onmax/nuxt-skills",
|
|
1095
|
+
name: "nuxt",
|
|
1096
|
+
description: "Nuxt framework patterns and best practices"
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
stackTrigger: "vue",
|
|
1100
|
+
repo: "onmax/nuxt-skills",
|
|
1101
|
+
name: "vue",
|
|
1102
|
+
description: "Vue.js composition API and component patterns"
|
|
1103
|
+
},
|
|
1104
|
+
// Angular
|
|
1105
|
+
{
|
|
1106
|
+
stackTrigger: "angular",
|
|
1107
|
+
repo: "Jeffallan/claude-skills",
|
|
1108
|
+
name: "angular-architect",
|
|
1109
|
+
description: "Angular architecture, modules, and component patterns"
|
|
1110
|
+
},
|
|
1111
|
+
// Svelte / SvelteKit
|
|
1112
|
+
{
|
|
1113
|
+
stackTrigger: "svelte",
|
|
1114
|
+
repo: "spences10/svelte-skills-kit",
|
|
1115
|
+
name: "svelte-skills",
|
|
1116
|
+
description: "Svelte 5 runes, SvelteKit routing, and component patterns"
|
|
1117
|
+
},
|
|
1118
|
+
// Convex
|
|
1012
1119
|
{
|
|
1013
1120
|
stackTrigger: "convex",
|
|
1014
1121
|
repo: "waynesutton/convexskills",
|
|
@@ -1021,17 +1128,26 @@ var init_community_skills = __esm({
|
|
|
1021
1128
|
name: "convex-functions",
|
|
1022
1129
|
description: "Convex query/mutation/action patterns"
|
|
1023
1130
|
},
|
|
1131
|
+
// Python
|
|
1024
1132
|
{
|
|
1025
|
-
stackTrigger: "
|
|
1026
|
-
repo: "
|
|
1027
|
-
name: "
|
|
1028
|
-
description: "
|
|
1133
|
+
stackTrigger: "python",
|
|
1134
|
+
repo: "wdm0006/python-skills",
|
|
1135
|
+
name: "python-skills",
|
|
1136
|
+
description: "Python library quality, packaging, and testing patterns"
|
|
1029
1137
|
},
|
|
1138
|
+
// Go
|
|
1030
1139
|
{
|
|
1031
|
-
stackTrigger: "
|
|
1032
|
-
repo: "
|
|
1033
|
-
name: "
|
|
1034
|
-
description: "
|
|
1140
|
+
stackTrigger: "go",
|
|
1141
|
+
repo: "saisudhir14/golang-agent-skill",
|
|
1142
|
+
name: "golang",
|
|
1143
|
+
description: "Go concurrency, error handling, and testing patterns"
|
|
1144
|
+
},
|
|
1145
|
+
// Rust
|
|
1146
|
+
{
|
|
1147
|
+
stackTrigger: "rust",
|
|
1148
|
+
repo: "leonardomso/rust-skills",
|
|
1149
|
+
name: "rust-skills",
|
|
1150
|
+
description: "Rust ownership, concurrency, and safety patterns (179 rules)"
|
|
1035
1151
|
}
|
|
1036
1152
|
];
|
|
1037
1153
|
}
|
|
@@ -1039,47 +1155,47 @@ var init_community_skills = __esm({
|
|
|
1039
1155
|
|
|
1040
1156
|
// src/lib/deprecated.ts
|
|
1041
1157
|
import { readdir as readdir2, mkdir as mkdir3, rename, rm as rm3 } from "fs/promises";
|
|
1042
|
-
import { join as
|
|
1158
|
+
import { join as join9 } from "path";
|
|
1043
1159
|
import { confirm, isCancel as isCancel2 } from "@clack/prompts";
|
|
1044
1160
|
async function scanDeprecated(targetDir) {
|
|
1045
1161
|
const found = [];
|
|
1046
1162
|
for (const item of [...DEPRECATED_DIRS, ...DEPRECATED_FILES]) {
|
|
1047
|
-
if (await pathExists(
|
|
1163
|
+
if (await pathExists(join9(targetDir, item))) {
|
|
1048
1164
|
found.push(item);
|
|
1049
1165
|
}
|
|
1050
1166
|
}
|
|
1051
1167
|
for (const skill of DEPRECATED_SKILLS) {
|
|
1052
|
-
const p =
|
|
1168
|
+
const p = join9(targetDir, ".claude", "skills", skill);
|
|
1053
1169
|
if (await pathExists(p)) {
|
|
1054
1170
|
found.push(`.claude/skills/${skill}`);
|
|
1055
1171
|
}
|
|
1056
1172
|
}
|
|
1057
1173
|
for (const dir of DEPRECATED_RULES_DIR) {
|
|
1058
|
-
if (await pathExists(
|
|
1174
|
+
if (await pathExists(join9(targetDir, dir))) {
|
|
1059
1175
|
found.push(dir);
|
|
1060
1176
|
}
|
|
1061
1177
|
}
|
|
1062
1178
|
for (const hook of DEPRECATED_HOOKS) {
|
|
1063
|
-
const p =
|
|
1179
|
+
const p = join9(targetDir, ".flydocs", "hooks", hook);
|
|
1064
1180
|
if (await pathExists(p)) {
|
|
1065
1181
|
found.push(`.flydocs/hooks/${hook}`);
|
|
1066
1182
|
}
|
|
1067
1183
|
}
|
|
1068
1184
|
for (const rule of DEPRECATED_CURSOR_RULES) {
|
|
1069
|
-
const p =
|
|
1185
|
+
const p = join9(targetDir, ".cursor", "rules", rule);
|
|
1070
1186
|
if (await pathExists(p)) {
|
|
1071
1187
|
found.push(`.cursor/rules/${rule}`);
|
|
1072
1188
|
}
|
|
1073
1189
|
}
|
|
1074
1190
|
for (const dir of DEPRECATED_CURSOR_RULE_DIRS) {
|
|
1075
|
-
const p =
|
|
1191
|
+
const p = join9(targetDir, ".cursor", "rules", dir);
|
|
1076
1192
|
if (await pathExists(p)) {
|
|
1077
1193
|
found.push(`.cursor/rules/${dir}`);
|
|
1078
1194
|
}
|
|
1079
1195
|
}
|
|
1080
1196
|
for (const cmd of DEPRECATED_COMMANDS) {
|
|
1081
1197
|
for (const prefix of [".cursor/commands", ".claude/commands"]) {
|
|
1082
|
-
const p =
|
|
1198
|
+
const p = join9(targetDir, prefix, cmd);
|
|
1083
1199
|
if (await pathExists(p)) {
|
|
1084
1200
|
found.push(`${prefix}/${cmd}`);
|
|
1085
1201
|
}
|
|
@@ -1088,12 +1204,12 @@ async function scanDeprecated(targetDir) {
|
|
|
1088
1204
|
return found;
|
|
1089
1205
|
}
|
|
1090
1206
|
async function handleLegacyContext(targetDir) {
|
|
1091
|
-
const contextDir =
|
|
1092
|
-
const legacyDir =
|
|
1207
|
+
const contextDir = join9(targetDir, "flydocs", "context");
|
|
1208
|
+
const legacyDir = join9(contextDir, "legacy");
|
|
1093
1209
|
const oldFiles = ["overview.md", "stack.md", "standards.md"];
|
|
1094
1210
|
let hasOld = false;
|
|
1095
1211
|
for (const f of oldFiles) {
|
|
1096
|
-
if (await pathExists(
|
|
1212
|
+
if (await pathExists(join9(contextDir, f))) {
|
|
1097
1213
|
hasOld = true;
|
|
1098
1214
|
break;
|
|
1099
1215
|
}
|
|
@@ -1101,9 +1217,9 @@ async function handleLegacyContext(targetDir) {
|
|
|
1101
1217
|
if (hasOld) {
|
|
1102
1218
|
await mkdir3(legacyDir, { recursive: true });
|
|
1103
1219
|
for (const f of oldFiles) {
|
|
1104
|
-
const src =
|
|
1220
|
+
const src = join9(contextDir, f);
|
|
1105
1221
|
if (await pathExists(src)) {
|
|
1106
|
-
await rename(src,
|
|
1222
|
+
await rename(src, join9(legacyDir, f));
|
|
1107
1223
|
printStatus(`Moved flydocs/context/${f} \u2192 legacy/`);
|
|
1108
1224
|
}
|
|
1109
1225
|
}
|
|
@@ -1113,7 +1229,7 @@ async function handleLegacyContext(targetDir) {
|
|
|
1113
1229
|
}
|
|
1114
1230
|
}
|
|
1115
1231
|
async function checkLegacyFolder(targetDir) {
|
|
1116
|
-
const legacyDir =
|
|
1232
|
+
const legacyDir = join9(targetDir, "flydocs", "context", "legacy");
|
|
1117
1233
|
if (!await pathExists(legacyDir)) return null;
|
|
1118
1234
|
try {
|
|
1119
1235
|
const entries = await readdir2(legacyDir);
|
|
@@ -1143,7 +1259,7 @@ async function promptCleanup(targetDir, paths) {
|
|
|
1143
1259
|
return;
|
|
1144
1260
|
}
|
|
1145
1261
|
for (const p of paths) {
|
|
1146
|
-
await rm3(
|
|
1262
|
+
await rm3(join9(targetDir, p), { recursive: true, force: true });
|
|
1147
1263
|
printStatus(`Deleted: ${p}`);
|
|
1148
1264
|
}
|
|
1149
1265
|
}
|
|
@@ -1154,19 +1270,20 @@ var init_deprecated = __esm({
|
|
|
1154
1270
|
init_fs_ops();
|
|
1155
1271
|
init_ui();
|
|
1156
1272
|
DEPRECATED_DIRS = [".docflow", "docflow"];
|
|
1157
|
-
DEPRECATED_FILES = ["AGENTS.md.bak"];
|
|
1273
|
+
DEPRECATED_FILES = ["AGENTS.md.bak", ".cursor/mcp.json"];
|
|
1158
1274
|
DEPRECATED_SKILLS = [
|
|
1159
1275
|
"linear-workflow",
|
|
1160
1276
|
"session-workflow",
|
|
1161
1277
|
"ai-labor-estimate",
|
|
1162
1278
|
"component-workflow",
|
|
1163
|
-
"figma-mcp"
|
|
1164
|
-
"implementation-flow",
|
|
1165
|
-
"review-workflow",
|
|
1166
|
-
"spec-templates"
|
|
1279
|
+
"figma-mcp"
|
|
1167
1280
|
];
|
|
1168
1281
|
DEPRECATED_RULES_DIR = [".flydocs/rules"];
|
|
1169
|
-
DEPRECATED_HOOKS = [
|
|
1282
|
+
DEPRECATED_HOOKS = [
|
|
1283
|
+
"linear-auto-approve.py",
|
|
1284
|
+
"session-end.py",
|
|
1285
|
+
"prefer-scripts.py"
|
|
1286
|
+
];
|
|
1170
1287
|
DEPRECATED_CURSOR_RULES = [
|
|
1171
1288
|
"designer-agent.mdc",
|
|
1172
1289
|
"docflow-core.mdc",
|
|
@@ -1194,9 +1311,9 @@ var init_deprecated = __esm({
|
|
|
1194
1311
|
|
|
1195
1312
|
// src/lib/gitignore.ts
|
|
1196
1313
|
import { readFile as readFile5, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
1197
|
-
import { join as
|
|
1314
|
+
import { join as join10 } from "path";
|
|
1198
1315
|
async function ensureGitignore(targetDir) {
|
|
1199
|
-
const gitignorePath =
|
|
1316
|
+
const gitignorePath = join10(targetDir, ".gitignore");
|
|
1200
1317
|
if (await pathExists(gitignorePath)) {
|
|
1201
1318
|
const content = await readFile5(gitignorePath, "utf-8");
|
|
1202
1319
|
if (!content.includes("# FlyDocs")) {
|
|
@@ -1210,7 +1327,7 @@ async function ensureGitignore(targetDir) {
|
|
|
1210
1327
|
}
|
|
1211
1328
|
}
|
|
1212
1329
|
async function migrateGitignore(targetDir) {
|
|
1213
|
-
const gitignorePath =
|
|
1330
|
+
const gitignorePath = join10(targetDir, ".gitignore");
|
|
1214
1331
|
if (!await pathExists(gitignorePath)) return;
|
|
1215
1332
|
const content = await readFile5(gitignorePath, "utf-8");
|
|
1216
1333
|
if (!content.includes("flydocs/context/graph.json")) {
|
|
@@ -1294,8 +1411,10 @@ __pycache__/
|
|
|
1294
1411
|
// src/lib/version.ts
|
|
1295
1412
|
import { readFile as readFile6 } from "fs/promises";
|
|
1296
1413
|
function compareVersions(v1, v2) {
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1414
|
+
const [core1, pre1] = v1.split("-", 2);
|
|
1415
|
+
const [core2, pre2] = v2.split("-", 2);
|
|
1416
|
+
const parts1 = core1.split(".").map(Number);
|
|
1417
|
+
const parts2 = core2.split(".").map(Number);
|
|
1299
1418
|
const len = Math.max(parts1.length, parts2.length);
|
|
1300
1419
|
for (let i = 0; i < len; i++) {
|
|
1301
1420
|
const a = parts1[i] ?? 0;
|
|
@@ -1303,6 +1422,27 @@ function compareVersions(v1, v2) {
|
|
|
1303
1422
|
if (a < b) return "older";
|
|
1304
1423
|
if (a > b) return "newer";
|
|
1305
1424
|
}
|
|
1425
|
+
if (!pre1 && pre2) return "newer";
|
|
1426
|
+
if (pre1 && !pre2) return "older";
|
|
1427
|
+
if (!pre1 && !pre2) return "equal";
|
|
1428
|
+
const preParts1 = pre1.split(".");
|
|
1429
|
+
const preParts2 = pre2.split(".");
|
|
1430
|
+
const preLen = Math.max(preParts1.length, preParts2.length);
|
|
1431
|
+
for (let i = 0; i < preLen; i++) {
|
|
1432
|
+
const a = preParts1[i];
|
|
1433
|
+
const b = preParts2[i];
|
|
1434
|
+
if (a === void 0) return "older";
|
|
1435
|
+
if (b === void 0) return "newer";
|
|
1436
|
+
const numA = Number(a);
|
|
1437
|
+
const numB = Number(b);
|
|
1438
|
+
if (!Number.isNaN(numA) && !Number.isNaN(numB)) {
|
|
1439
|
+
if (numA < numB) return "older";
|
|
1440
|
+
if (numA > numB) return "newer";
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
if (a < b) return "older";
|
|
1444
|
+
if (a > b) return "newer";
|
|
1445
|
+
}
|
|
1306
1446
|
return "equal";
|
|
1307
1447
|
}
|
|
1308
1448
|
async function getWhatsNew(changelogPath, fromVersion, toVersion) {
|
|
@@ -1315,7 +1455,7 @@ async function getWhatsNew(changelogPath, fromVersion, toVersion) {
|
|
|
1315
1455
|
const sections = content.split(/^## \[/m);
|
|
1316
1456
|
const relevant = [];
|
|
1317
1457
|
for (const section of sections.slice(1)) {
|
|
1318
|
-
const match = section.match(/^([\d.]+)\]/);
|
|
1458
|
+
const match = section.match(/^([\d.]+(?:-[\w.]+)?)\]/);
|
|
1319
1459
|
if (!match) continue;
|
|
1320
1460
|
const ver = match[1];
|
|
1321
1461
|
if (compareVersions(ver, fromVersion) !== "older" && compareVersions(ver, fromVersion) !== "equal" && (compareVersions(ver, toVersion) === "older" || compareVersions(ver, toVersion) === "equal")) {
|
|
@@ -1338,7 +1478,7 @@ var init_version = __esm({
|
|
|
1338
1478
|
|
|
1339
1479
|
// src/lib/update-check.ts
|
|
1340
1480
|
import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
1341
|
-
import { join as
|
|
1481
|
+
import { join as join11 } from "path";
|
|
1342
1482
|
import { homedir } from "os";
|
|
1343
1483
|
import pc5 from "picocolors";
|
|
1344
1484
|
async function readCache() {
|
|
@@ -1355,7 +1495,7 @@ async function readCache() {
|
|
|
1355
1495
|
}
|
|
1356
1496
|
async function writeCache(cache) {
|
|
1357
1497
|
try {
|
|
1358
|
-
await mkdir4(
|
|
1498
|
+
await mkdir4(join11(homedir(), ".flydocs"), { recursive: true });
|
|
1359
1499
|
await writeFile4(CACHE_FILE, JSON.stringify(cache), "utf-8");
|
|
1360
1500
|
} catch {
|
|
1361
1501
|
}
|
|
@@ -1414,7 +1554,7 @@ function printUpdateNotice(result) {
|
|
|
1414
1554
|
` ${pc5.dim("Update available:")} ${pc5.cyan(result.currentVersion)} ${pc5.dim("->")} ${pc5.cyan(result.latestVersion)}`
|
|
1415
1555
|
);
|
|
1416
1556
|
console.log(
|
|
1417
|
-
` ${pc5.dim("Run:")} ${pc5.yellow(`npm
|
|
1557
|
+
` ${pc5.dim("Run:")} ${pc5.yellow(`npm install -g ${PACKAGE_NAME}@beta`)}`
|
|
1418
1558
|
);
|
|
1419
1559
|
console.log();
|
|
1420
1560
|
}
|
|
@@ -1424,7 +1564,7 @@ var init_update_check = __esm({
|
|
|
1424
1564
|
"use strict";
|
|
1425
1565
|
init_constants();
|
|
1426
1566
|
init_version();
|
|
1427
|
-
CACHE_FILE =
|
|
1567
|
+
CACHE_FILE = join11(homedir(), ".flydocs", "update-check.json");
|
|
1428
1568
|
CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1429
1569
|
FETCH_TIMEOUT_MS = 5e3;
|
|
1430
1570
|
}
|
|
@@ -1437,8 +1577,8 @@ __export(install_exports, {
|
|
|
1437
1577
|
});
|
|
1438
1578
|
import { defineCommand } from "citty";
|
|
1439
1579
|
import { resolve as resolve2 } from "path";
|
|
1440
|
-
import { join as
|
|
1441
|
-
import { select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1580
|
+
import { join as join12 } from "path";
|
|
1581
|
+
import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
|
|
1442
1582
|
var install_default;
|
|
1443
1583
|
var init_install = __esm({
|
|
1444
1584
|
"src/commands/install.ts"() {
|
|
@@ -1515,7 +1655,7 @@ var init_install = __esm({
|
|
|
1515
1655
|
}
|
|
1516
1656
|
tier = args.tier;
|
|
1517
1657
|
printInfo(`Tier set via flag: ${tier}`);
|
|
1518
|
-
} else if (await pathExists(
|
|
1658
|
+
} else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
|
|
1519
1659
|
try {
|
|
1520
1660
|
const existing = await readConfig(targetDir);
|
|
1521
1661
|
if (existing.tier) {
|
|
@@ -1526,62 +1666,48 @@ var init_install = __esm({
|
|
|
1526
1666
|
}
|
|
1527
1667
|
}
|
|
1528
1668
|
if (!tier) {
|
|
1529
|
-
const
|
|
1530
|
-
message:
|
|
1531
|
-
|
|
1532
|
-
{
|
|
1533
|
-
value: "local",
|
|
1534
|
-
label: "local",
|
|
1535
|
-
hint: "File-based issues. No accounts, no API keys, works offline."
|
|
1536
|
-
},
|
|
1537
|
-
{
|
|
1538
|
-
value: "cloud",
|
|
1539
|
-
label: "cloud",
|
|
1540
|
-
hint: "Linear integration. Real-time sync with your team."
|
|
1541
|
-
}
|
|
1542
|
-
]
|
|
1669
|
+
const shouldInstall = await confirm2({
|
|
1670
|
+
message: `Install FlyDocs here? (local tier)
|
|
1671
|
+
Directory: ${targetDir}`
|
|
1543
1672
|
});
|
|
1544
|
-
if (isCancel3(
|
|
1673
|
+
if (isCancel3(shouldInstall) || !shouldInstall) {
|
|
1545
1674
|
cancel2("Installation cancelled.");
|
|
1546
1675
|
process.exit(0);
|
|
1547
1676
|
}
|
|
1548
|
-
tier =
|
|
1677
|
+
tier = "local";
|
|
1549
1678
|
console.log();
|
|
1550
1679
|
}
|
|
1551
|
-
if (!await pathExists(
|
|
1552
|
-
|
|
1553
|
-
"Not in a git repository. Please run from the root of your project."
|
|
1554
|
-
);
|
|
1555
|
-
process.exit(1);
|
|
1680
|
+
if (!await pathExists(join12(targetDir, ".git"))) {
|
|
1681
|
+
printWarning("No git repository detected. Run git init when ready.");
|
|
1556
1682
|
}
|
|
1557
1683
|
await ensureDirectories(targetDir, tier);
|
|
1558
1684
|
console.log("Installing framework files...");
|
|
1559
1685
|
await replaceDirectory(
|
|
1560
|
-
|
|
1561
|
-
|
|
1686
|
+
join12(templateDir, ".flydocs", "templates"),
|
|
1687
|
+
join12(targetDir, ".flydocs", "templates")
|
|
1562
1688
|
);
|
|
1563
1689
|
await replaceDirectory(
|
|
1564
|
-
|
|
1565
|
-
|
|
1690
|
+
join12(templateDir, ".flydocs", "hooks"),
|
|
1691
|
+
join12(targetDir, ".flydocs", "hooks")
|
|
1566
1692
|
);
|
|
1567
1693
|
await replaceDirectory(
|
|
1568
|
-
|
|
1569
|
-
|
|
1694
|
+
join12(templateDir, ".flydocs", "scripts"),
|
|
1695
|
+
join12(targetDir, ".flydocs", "scripts")
|
|
1570
1696
|
);
|
|
1571
1697
|
await copyFile(
|
|
1572
|
-
|
|
1573
|
-
|
|
1698
|
+
join12(templateDir, ".flydocs", "version"),
|
|
1699
|
+
join12(targetDir, ".flydocs", "version")
|
|
1574
1700
|
);
|
|
1575
|
-
const manifestSrc =
|
|
1701
|
+
const manifestSrc = join12(templateDir, "manifest.json");
|
|
1576
1702
|
if (await pathExists(manifestSrc)) {
|
|
1577
|
-
await copyFile(manifestSrc,
|
|
1703
|
+
await copyFile(manifestSrc, join12(targetDir, ".flydocs", "manifest.json"));
|
|
1578
1704
|
}
|
|
1579
|
-
const changelogSrc =
|
|
1705
|
+
const changelogSrc = join12(templateDir, "CHANGELOG.md");
|
|
1580
1706
|
if (await pathExists(changelogSrc)) {
|
|
1581
|
-
await copyFile(changelogSrc,
|
|
1707
|
+
await copyFile(changelogSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
1582
1708
|
}
|
|
1583
1709
|
printStatus(".flydocs/templates, hooks, version, manifest, changelog");
|
|
1584
|
-
const configPath =
|
|
1710
|
+
const configPath = join12(targetDir, ".flydocs", "config.json");
|
|
1585
1711
|
if (!await pathExists(configPath)) {
|
|
1586
1712
|
const config = await createFreshConfig(templateDir, version, tier);
|
|
1587
1713
|
await writeConfig(targetDir, config);
|
|
@@ -1607,56 +1733,47 @@ var init_install = __esm({
|
|
|
1607
1733
|
printStatus(`Skills installed (tier: ${tier})`);
|
|
1608
1734
|
console.log();
|
|
1609
1735
|
console.log("Installing agents and commands...");
|
|
1610
|
-
const claudeAgentsSrc =
|
|
1736
|
+
const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
|
|
1611
1737
|
if (await pathExists(claudeAgentsSrc)) {
|
|
1612
1738
|
await copyDirectoryContents(
|
|
1613
1739
|
claudeAgentsSrc,
|
|
1614
|
-
|
|
1740
|
+
join12(targetDir, ".claude", "agents")
|
|
1615
1741
|
);
|
|
1616
1742
|
}
|
|
1617
1743
|
await copyDirectoryContents(
|
|
1618
|
-
|
|
1619
|
-
|
|
1744
|
+
join12(templateDir, ".claude", "commands"),
|
|
1745
|
+
join12(targetDir, ".claude", "commands")
|
|
1620
1746
|
);
|
|
1621
1747
|
await copyFile(
|
|
1622
|
-
|
|
1623
|
-
|
|
1748
|
+
join12(templateDir, ".claude", "CLAUDE.md"),
|
|
1749
|
+
join12(targetDir, ".claude", "CLAUDE.md")
|
|
1624
1750
|
);
|
|
1625
1751
|
await copyFile(
|
|
1626
|
-
|
|
1627
|
-
|
|
1752
|
+
join12(templateDir, ".claude", "settings.json"),
|
|
1753
|
+
join12(targetDir, ".claude", "settings.json")
|
|
1628
1754
|
);
|
|
1629
1755
|
printStatus(".claude/ (agents, commands, CLAUDE.md, settings)");
|
|
1630
|
-
const cursorAgentsSrc =
|
|
1756
|
+
const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
|
|
1631
1757
|
if (await pathExists(cursorAgentsSrc)) {
|
|
1632
1758
|
await copyDirectoryContents(
|
|
1633
1759
|
cursorAgentsSrc,
|
|
1634
|
-
|
|
1760
|
+
join12(targetDir, ".cursor", "agents")
|
|
1635
1761
|
);
|
|
1636
1762
|
}
|
|
1637
1763
|
await copyDirectoryContents(
|
|
1638
|
-
|
|
1639
|
-
|
|
1764
|
+
join12(templateDir, ".claude", "commands"),
|
|
1765
|
+
join12(targetDir, ".cursor", "commands")
|
|
1640
1766
|
);
|
|
1641
1767
|
await copyFile(
|
|
1642
|
-
|
|
1643
|
-
|
|
1768
|
+
join12(templateDir, ".cursor", "hooks.json"),
|
|
1769
|
+
join12(targetDir, ".cursor", "hooks.json")
|
|
1644
1770
|
);
|
|
1645
1771
|
printStatus(".cursor/ (agents, commands, hooks)");
|
|
1646
1772
|
await copyCursorRules(targetDir);
|
|
1647
1773
|
printStatus(".cursor/rules/");
|
|
1648
|
-
const mcpResult = await copyFileIfNotExists(
|
|
1649
|
-
join11(templateDir, ".cursor", "mcp.json"),
|
|
1650
|
-
join11(targetDir, ".cursor", "mcp.json")
|
|
1651
|
-
);
|
|
1652
|
-
if (mcpResult === "created") {
|
|
1653
|
-
printStatus(".cursor/mcp.json (new)");
|
|
1654
|
-
} else {
|
|
1655
|
-
printWarning(".cursor/mcp.json exists, preserving");
|
|
1656
|
-
}
|
|
1657
1774
|
await copyFile(
|
|
1658
|
-
|
|
1659
|
-
|
|
1775
|
+
join12(templateDir, "AGENTS.md"),
|
|
1776
|
+
join12(targetDir, "AGENTS.md")
|
|
1660
1777
|
);
|
|
1661
1778
|
printStatus("AGENTS.md");
|
|
1662
1779
|
await runManifestGeneration(targetDir);
|
|
@@ -1665,40 +1782,40 @@ var init_install = __esm({
|
|
|
1665
1782
|
console.log("Installing project templates...");
|
|
1666
1783
|
const userFiles = [
|
|
1667
1784
|
{
|
|
1668
|
-
src:
|
|
1669
|
-
dest:
|
|
1785
|
+
src: join12(templateDir, "flydocs", "context", "project.md"),
|
|
1786
|
+
dest: join12(targetDir, "flydocs", "context", "project.md"),
|
|
1670
1787
|
label: "flydocs/context/project.md"
|
|
1671
1788
|
},
|
|
1672
1789
|
{
|
|
1673
|
-
src:
|
|
1674
|
-
dest:
|
|
1790
|
+
src: join12(templateDir, "flydocs", "knowledge", "INDEX.md"),
|
|
1791
|
+
dest: join12(targetDir, "flydocs", "knowledge", "INDEX.md"),
|
|
1675
1792
|
label: "flydocs/knowledge/INDEX.md"
|
|
1676
1793
|
},
|
|
1677
1794
|
{
|
|
1678
|
-
src:
|
|
1679
|
-
dest:
|
|
1795
|
+
src: join12(templateDir, "flydocs", "knowledge", "README.md"),
|
|
1796
|
+
dest: join12(targetDir, "flydocs", "knowledge", "README.md"),
|
|
1680
1797
|
label: "flydocs/knowledge/README.md"
|
|
1681
1798
|
},
|
|
1682
1799
|
{
|
|
1683
|
-
src:
|
|
1800
|
+
src: join12(
|
|
1684
1801
|
templateDir,
|
|
1685
1802
|
"flydocs",
|
|
1686
1803
|
"knowledge",
|
|
1687
1804
|
"product",
|
|
1688
1805
|
"personas.md"
|
|
1689
1806
|
),
|
|
1690
|
-
dest:
|
|
1807
|
+
dest: join12(targetDir, "flydocs", "knowledge", "product", "personas.md"),
|
|
1691
1808
|
label: "flydocs/knowledge/product/personas.md"
|
|
1692
1809
|
},
|
|
1693
1810
|
{
|
|
1694
|
-
src:
|
|
1811
|
+
src: join12(
|
|
1695
1812
|
templateDir,
|
|
1696
1813
|
"flydocs",
|
|
1697
1814
|
"knowledge",
|
|
1698
1815
|
"product",
|
|
1699
1816
|
"user-flows.md"
|
|
1700
1817
|
),
|
|
1701
|
-
dest:
|
|
1818
|
+
dest: join12(
|
|
1702
1819
|
targetDir,
|
|
1703
1820
|
"flydocs",
|
|
1704
1821
|
"knowledge",
|
|
@@ -1708,18 +1825,18 @@ var init_install = __esm({
|
|
|
1708
1825
|
label: "flydocs/knowledge/product/user-flows.md"
|
|
1709
1826
|
},
|
|
1710
1827
|
{
|
|
1711
|
-
src:
|
|
1712
|
-
dest:
|
|
1828
|
+
src: join12(templateDir, "flydocs", "design-system", "README.md"),
|
|
1829
|
+
dest: join12(targetDir, "flydocs", "design-system", "README.md"),
|
|
1713
1830
|
label: "flydocs/design-system/README.md"
|
|
1714
1831
|
},
|
|
1715
1832
|
{
|
|
1716
|
-
src:
|
|
1833
|
+
src: join12(
|
|
1717
1834
|
templateDir,
|
|
1718
1835
|
"flydocs",
|
|
1719
1836
|
"design-system",
|
|
1720
1837
|
"component-patterns.md"
|
|
1721
1838
|
),
|
|
1722
|
-
dest:
|
|
1839
|
+
dest: join12(
|
|
1723
1840
|
targetDir,
|
|
1724
1841
|
"flydocs",
|
|
1725
1842
|
"design-system",
|
|
@@ -1728,13 +1845,13 @@ var init_install = __esm({
|
|
|
1728
1845
|
label: "flydocs/design-system/component-patterns.md"
|
|
1729
1846
|
},
|
|
1730
1847
|
{
|
|
1731
|
-
src:
|
|
1732
|
-
dest:
|
|
1848
|
+
src: join12(templateDir, "flydocs", "design-system", "token-mapping.md"),
|
|
1849
|
+
dest: join12(targetDir, "flydocs", "design-system", "token-mapping.md"),
|
|
1733
1850
|
label: "flydocs/design-system/token-mapping.md"
|
|
1734
1851
|
},
|
|
1735
1852
|
{
|
|
1736
|
-
src:
|
|
1737
|
-
dest:
|
|
1853
|
+
src: join12(templateDir, "flydocs", "README.md"),
|
|
1854
|
+
dest: join12(targetDir, "flydocs", "README.md"),
|
|
1738
1855
|
label: "flydocs/README.md"
|
|
1739
1856
|
}
|
|
1740
1857
|
];
|
|
@@ -1748,14 +1865,10 @@ var init_install = __esm({
|
|
|
1748
1865
|
}
|
|
1749
1866
|
}
|
|
1750
1867
|
}
|
|
1751
|
-
const envExampleSrc =
|
|
1868
|
+
const envExampleSrc = join12(templateDir, ".env.example");
|
|
1752
1869
|
if (await pathExists(envExampleSrc)) {
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
if (!hasEnv && !hasEnvExample) {
|
|
1756
|
-
await copyFile(envExampleSrc, join11(targetDir, ".env.example"));
|
|
1757
|
-
printStatus(".env.example (new)");
|
|
1758
|
-
}
|
|
1870
|
+
await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
|
|
1871
|
+
printStatus(".env.example");
|
|
1759
1872
|
}
|
|
1760
1873
|
await ensureGitignore(targetDir);
|
|
1761
1874
|
console.log();
|
|
@@ -1797,8 +1910,116 @@ var init_install = __esm({
|
|
|
1797
1910
|
"",
|
|
1798
1911
|
"Documentation: flydocs/README.md"
|
|
1799
1912
|
];
|
|
1913
|
+
let copiedToClipboard = false;
|
|
1914
|
+
try {
|
|
1915
|
+
const clipboard = await import("clipboardy");
|
|
1916
|
+
await clipboard.default.write("/flydocs-setup");
|
|
1917
|
+
copiedToClipboard = true;
|
|
1918
|
+
} catch {
|
|
1919
|
+
}
|
|
1920
|
+
if (copiedToClipboard) {
|
|
1921
|
+
const localSteps = nextSteps.findIndex(
|
|
1922
|
+
(l) => l.includes("/flydocs-setup")
|
|
1923
|
+
);
|
|
1924
|
+
if (localSteps !== -1) {
|
|
1925
|
+
nextSteps[localSteps] = nextSteps[localSteps] + " (copied to clipboard)";
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1800
1928
|
printCompletionBox("Installation Complete!", nextSteps);
|
|
1801
1929
|
printBetaCta();
|
|
1930
|
+
try {
|
|
1931
|
+
const { execSync: execSync2, spawn } = await import("child_process");
|
|
1932
|
+
const isInstalled = (cmd) => {
|
|
1933
|
+
try {
|
|
1934
|
+
execSync2(`which ${cmd}`, { stdio: "pipe" });
|
|
1935
|
+
return true;
|
|
1936
|
+
} catch {
|
|
1937
|
+
return false;
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
const ideOptions = [];
|
|
1941
|
+
if (isInstalled("claude")) {
|
|
1942
|
+
ideOptions.push({
|
|
1943
|
+
cmd: "claude",
|
|
1944
|
+
label: "Claude Code",
|
|
1945
|
+
hint: "Opens and runs /flydocs-setup automatically",
|
|
1946
|
+
passCommand: true
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
if (isInstalled("cursor")) {
|
|
1950
|
+
ideOptions.push({
|
|
1951
|
+
cmd: "cursor",
|
|
1952
|
+
label: "Cursor",
|
|
1953
|
+
hint: copiedToClipboard ? "Opens project \u2014 paste /flydocs-setup from clipboard" : "Opens project \u2014 run /flydocs-setup in chat",
|
|
1954
|
+
passCommand: false
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
if (isInstalled("code")) {
|
|
1958
|
+
ideOptions.push({
|
|
1959
|
+
cmd: "code",
|
|
1960
|
+
label: "VS Code",
|
|
1961
|
+
hint: copiedToClipboard ? "Opens project \u2014 paste /flydocs-setup from clipboard" : "Opens project \u2014 run /flydocs-setup in chat",
|
|
1962
|
+
passCommand: false
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
if (ideOptions.length === 1) {
|
|
1966
|
+
const ide = ideOptions[0];
|
|
1967
|
+
const launchConfirm = await confirm2({
|
|
1968
|
+
message: ide.passCommand ? `Open ${ide.label} and run /flydocs-setup now?` : `Open ${ide.label}?`
|
|
1969
|
+
});
|
|
1970
|
+
if (!isCancel3(launchConfirm) && launchConfirm) {
|
|
1971
|
+
if (ide.passCommand) {
|
|
1972
|
+
spawn(ide.cmd, ["/flydocs-setup"], {
|
|
1973
|
+
cwd: targetDir,
|
|
1974
|
+
stdio: "inherit"
|
|
1975
|
+
});
|
|
1976
|
+
return;
|
|
1977
|
+
} else {
|
|
1978
|
+
spawn(ide.cmd, [targetDir], {
|
|
1979
|
+
stdio: "ignore",
|
|
1980
|
+
detached: true
|
|
1981
|
+
}).unref();
|
|
1982
|
+
printInfo(
|
|
1983
|
+
`${ide.label} opening \u2014 paste /flydocs-setup in the chat panel`
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
} else if (ideOptions.length > 1) {
|
|
1988
|
+
const options = [
|
|
1989
|
+
...ideOptions.map((ide) => ({
|
|
1990
|
+
value: ide.cmd,
|
|
1991
|
+
label: ide.label,
|
|
1992
|
+
hint: ide.hint
|
|
1993
|
+
})),
|
|
1994
|
+
{ value: "skip", label: "Skip", hint: "I'll open my IDE manually" }
|
|
1995
|
+
];
|
|
1996
|
+
const choice = await select({
|
|
1997
|
+
message: "Open an IDE to run /flydocs-setup?",
|
|
1998
|
+
options
|
|
1999
|
+
});
|
|
2000
|
+
if (!isCancel3(choice) && choice !== "skip") {
|
|
2001
|
+
const ide = ideOptions.find((o) => o.cmd === choice);
|
|
2002
|
+
if (ide) {
|
|
2003
|
+
if (ide.passCommand) {
|
|
2004
|
+
spawn(ide.cmd, ["/flydocs-setup"], {
|
|
2005
|
+
cwd: targetDir,
|
|
2006
|
+
stdio: "inherit"
|
|
2007
|
+
});
|
|
2008
|
+
return;
|
|
2009
|
+
} else {
|
|
2010
|
+
spawn(ide.cmd, [targetDir], {
|
|
2011
|
+
stdio: "ignore",
|
|
2012
|
+
detached: true
|
|
2013
|
+
}).unref();
|
|
2014
|
+
printInfo(
|
|
2015
|
+
`${ide.label} opening \u2014 paste /flydocs-setup in the chat panel`
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
} catch {
|
|
2022
|
+
}
|
|
1802
2023
|
try {
|
|
1803
2024
|
const updateResult = await checkForUpdate();
|
|
1804
2025
|
if (updateResult) {
|
|
@@ -1817,9 +2038,9 @@ __export(update_exports, {
|
|
|
1817
2038
|
default: () => update_default
|
|
1818
2039
|
});
|
|
1819
2040
|
import { defineCommand as defineCommand2 } from "citty";
|
|
1820
|
-
import { resolve as resolve3, join as
|
|
2041
|
+
import { resolve as resolve3, join as join13 } from "path";
|
|
1821
2042
|
import { mkdir as mkdir5, cp as cp2, readFile as readFile8, readdir as readdir3, rm as rm4 } from "fs/promises";
|
|
1822
|
-
import { select as select2, text, confirm as
|
|
2043
|
+
import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
|
|
1823
2044
|
import pc6 from "picocolors";
|
|
1824
2045
|
var update_default;
|
|
1825
2046
|
var init_update = __esm({
|
|
@@ -1923,9 +2144,9 @@ var init_update = __esm({
|
|
|
1923
2144
|
}
|
|
1924
2145
|
targetDir = resolve3(targetDir);
|
|
1925
2146
|
process.chdir(targetDir);
|
|
1926
|
-
const hasVersion = await pathExists(
|
|
2147
|
+
const hasVersion = await pathExists(join13(targetDir, ".flydocs", "version"));
|
|
1927
2148
|
const hasConfig = await pathExists(
|
|
1928
|
-
|
|
2149
|
+
join13(targetDir, ".flydocs", "config.json")
|
|
1929
2150
|
);
|
|
1930
2151
|
if (!hasVersion && !hasConfig) {
|
|
1931
2152
|
printError(`Not a FlyDocs project: ${targetDir}`);
|
|
@@ -1937,7 +2158,7 @@ var init_update = __esm({
|
|
|
1937
2158
|
let currentVersion = "0.1.0";
|
|
1938
2159
|
if (hasVersion) {
|
|
1939
2160
|
const vContent = await readFile8(
|
|
1940
|
-
|
|
2161
|
+
join13(targetDir, ".flydocs", "version"),
|
|
1941
2162
|
"utf-8"
|
|
1942
2163
|
);
|
|
1943
2164
|
currentVersion = vContent.trim();
|
|
@@ -1956,7 +2177,7 @@ var init_update = __esm({
|
|
|
1956
2177
|
printWarning(
|
|
1957
2178
|
`Project version (${currentVersion}) is newer than installer (${version})`
|
|
1958
2179
|
);
|
|
1959
|
-
const shouldContinue = await
|
|
2180
|
+
const shouldContinue = await confirm3({
|
|
1960
2181
|
message: "Continue anyway?"
|
|
1961
2182
|
});
|
|
1962
2183
|
if (isCancel4(shouldContinue) || !shouldContinue) {
|
|
@@ -1965,7 +2186,7 @@ var init_update = __esm({
|
|
|
1965
2186
|
}
|
|
1966
2187
|
console.log(`Updating: v${currentVersion} \u2192 v${version}`);
|
|
1967
2188
|
console.log();
|
|
1968
|
-
const changelogPath =
|
|
2189
|
+
const changelogPath = join13(templateDir, "CHANGELOG.md");
|
|
1969
2190
|
const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
|
|
1970
2191
|
if (whatsNew.length > 0) {
|
|
1971
2192
|
console.log(pc6.cyan("What's new:"));
|
|
@@ -1977,23 +2198,23 @@ var init_update = __esm({
|
|
|
1977
2198
|
}
|
|
1978
2199
|
const now = /* @__PURE__ */ new Date();
|
|
1979
2200
|
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")}`;
|
|
1980
|
-
const backupDir =
|
|
2201
|
+
const backupDir = join13(targetDir, ".flydocs", `backup-${ts}`);
|
|
1981
2202
|
await mkdir5(backupDir, { recursive: true });
|
|
1982
2203
|
if (hasConfig) {
|
|
1983
2204
|
await cp2(
|
|
1984
|
-
|
|
1985
|
-
|
|
2205
|
+
join13(targetDir, ".flydocs", "config.json"),
|
|
2206
|
+
join13(backupDir, "config.json")
|
|
1986
2207
|
);
|
|
1987
2208
|
printStatus(`Config backed up to .flydocs/backup-${ts}/`);
|
|
1988
2209
|
}
|
|
1989
2210
|
try {
|
|
1990
|
-
const flydocsDir =
|
|
2211
|
+
const flydocsDir = join13(targetDir, ".flydocs");
|
|
1991
2212
|
const entries = await readdir3(flydocsDir);
|
|
1992
2213
|
const backups = entries.filter((e) => e.startsWith("backup-")).sort();
|
|
1993
2214
|
if (backups.length > 3) {
|
|
1994
2215
|
const toRemove = backups.slice(0, backups.length - 3);
|
|
1995
2216
|
for (const old of toRemove) {
|
|
1996
|
-
await rm4(
|
|
2217
|
+
await rm4(join13(flydocsDir, old), { recursive: true, force: true });
|
|
1997
2218
|
}
|
|
1998
2219
|
}
|
|
1999
2220
|
} catch {
|
|
@@ -2006,7 +2227,6 @@ var init_update = __esm({
|
|
|
2006
2227
|
issueLabels: {},
|
|
2007
2228
|
statusMapping: {},
|
|
2008
2229
|
detectedStack: {},
|
|
2009
|
-
mcp: {},
|
|
2010
2230
|
skills: {},
|
|
2011
2231
|
designSystem: null,
|
|
2012
2232
|
aiLabor: {}
|
|
@@ -2031,74 +2251,79 @@ var init_update = __esm({
|
|
|
2031
2251
|
}
|
|
2032
2252
|
console.log("Replacing framework directories...");
|
|
2033
2253
|
await replaceDirectory(
|
|
2034
|
-
|
|
2035
|
-
|
|
2254
|
+
join13(templateDir, ".flydocs", "templates"),
|
|
2255
|
+
join13(targetDir, ".flydocs", "templates")
|
|
2036
2256
|
);
|
|
2037
2257
|
await replaceDirectory(
|
|
2038
|
-
|
|
2039
|
-
|
|
2258
|
+
join13(templateDir, ".flydocs", "hooks"),
|
|
2259
|
+
join13(targetDir, ".flydocs", "hooks")
|
|
2040
2260
|
);
|
|
2041
2261
|
await replaceDirectory(
|
|
2042
|
-
|
|
2043
|
-
|
|
2262
|
+
join13(templateDir, ".flydocs", "scripts"),
|
|
2263
|
+
join13(targetDir, ".flydocs", "scripts")
|
|
2044
2264
|
);
|
|
2045
2265
|
printStatus(".flydocs/templates, hooks, scripts");
|
|
2046
|
-
const claudeAgentsSrc =
|
|
2266
|
+
const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
|
|
2047
2267
|
if (await pathExists(claudeAgentsSrc)) {
|
|
2048
2268
|
await copyDirectoryContents(
|
|
2049
2269
|
claudeAgentsSrc,
|
|
2050
|
-
|
|
2270
|
+
join13(targetDir, ".claude", "agents")
|
|
2051
2271
|
);
|
|
2052
2272
|
}
|
|
2053
2273
|
printStatus(".claude/agents");
|
|
2054
2274
|
await replaceOwnedSkills(templateDir, targetDir, effectiveTier);
|
|
2055
2275
|
printStatus(`.claude/skills (tier: ${effectiveTier})`);
|
|
2056
|
-
const cursorAgentsSrc =
|
|
2276
|
+
const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
|
|
2057
2277
|
if (await pathExists(cursorAgentsSrc)) {
|
|
2058
2278
|
await copyDirectoryContents(
|
|
2059
2279
|
cursorAgentsSrc,
|
|
2060
|
-
|
|
2280
|
+
join13(targetDir, ".cursor", "agents")
|
|
2061
2281
|
);
|
|
2062
2282
|
}
|
|
2063
2283
|
printStatus(".cursor/agents");
|
|
2064
2284
|
console.log();
|
|
2065
2285
|
console.log("Replacing framework files...");
|
|
2066
2286
|
await copyFile(
|
|
2067
|
-
|
|
2068
|
-
|
|
2287
|
+
join13(templateDir, ".claude", "CLAUDE.md"),
|
|
2288
|
+
join13(targetDir, ".claude", "CLAUDE.md")
|
|
2069
2289
|
);
|
|
2070
2290
|
await copyFile(
|
|
2071
|
-
|
|
2072
|
-
|
|
2291
|
+
join13(templateDir, ".claude", "settings.json"),
|
|
2292
|
+
join13(targetDir, ".claude", "settings.json")
|
|
2073
2293
|
);
|
|
2074
2294
|
printStatus(".claude/CLAUDE.md, settings.json");
|
|
2075
2295
|
await copyDirectoryContents(
|
|
2076
|
-
|
|
2077
|
-
|
|
2296
|
+
join13(templateDir, ".claude", "commands"),
|
|
2297
|
+
join13(targetDir, ".claude", "commands")
|
|
2078
2298
|
);
|
|
2079
2299
|
await copyDirectoryContents(
|
|
2080
|
-
|
|
2081
|
-
|
|
2300
|
+
join13(templateDir, ".claude", "commands"),
|
|
2301
|
+
join13(targetDir, ".cursor", "commands")
|
|
2082
2302
|
);
|
|
2083
2303
|
printStatus(".claude/commands, .cursor/commands");
|
|
2084
|
-
const skillsReadmeSrc =
|
|
2304
|
+
const skillsReadmeSrc = join13(templateDir, ".claude", "skills", "README.md");
|
|
2085
2305
|
if (await pathExists(skillsReadmeSrc)) {
|
|
2086
2306
|
await copyFile(
|
|
2087
2307
|
skillsReadmeSrc,
|
|
2088
|
-
|
|
2308
|
+
join13(targetDir, ".claude", "skills", "README.md")
|
|
2089
2309
|
);
|
|
2090
2310
|
}
|
|
2091
2311
|
printStatus(".claude/skills/README.md");
|
|
2092
2312
|
await copyFile(
|
|
2093
|
-
|
|
2094
|
-
|
|
2313
|
+
join13(templateDir, ".cursor", "hooks.json"),
|
|
2314
|
+
join13(targetDir, ".cursor", "hooks.json")
|
|
2095
2315
|
);
|
|
2096
2316
|
printStatus(".cursor/hooks.json");
|
|
2097
2317
|
await copyFile(
|
|
2098
|
-
|
|
2099
|
-
|
|
2318
|
+
join13(templateDir, "AGENTS.md"),
|
|
2319
|
+
join13(targetDir, "AGENTS.md")
|
|
2100
2320
|
);
|
|
2101
2321
|
printStatus("AGENTS.md");
|
|
2322
|
+
const envExampleSrc = join13(templateDir, ".env.example");
|
|
2323
|
+
if (await pathExists(envExampleSrc)) {
|
|
2324
|
+
await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
|
|
2325
|
+
printStatus(".env.example");
|
|
2326
|
+
}
|
|
2102
2327
|
await runManifestGeneration(targetDir);
|
|
2103
2328
|
await runContextGraphBuild(targetDir);
|
|
2104
2329
|
console.log();
|
|
@@ -2121,18 +2346,18 @@ var init_update = __esm({
|
|
|
2121
2346
|
printWarning("Config merge failed \u2014 config.json preserved as-is");
|
|
2122
2347
|
}
|
|
2123
2348
|
await copyFile(
|
|
2124
|
-
|
|
2125
|
-
|
|
2349
|
+
join13(templateDir, ".flydocs", "version"),
|
|
2350
|
+
join13(targetDir, ".flydocs", "version")
|
|
2126
2351
|
);
|
|
2127
2352
|
printStatus(`.flydocs/version \u2192 ${version}`);
|
|
2128
|
-
const clSrc =
|
|
2353
|
+
const clSrc = join13(templateDir, "CHANGELOG.md");
|
|
2129
2354
|
if (await pathExists(clSrc)) {
|
|
2130
|
-
await copyFile(clSrc,
|
|
2355
|
+
await copyFile(clSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
|
|
2131
2356
|
printStatus(".flydocs/CHANGELOG.md");
|
|
2132
2357
|
}
|
|
2133
|
-
const mfSrc =
|
|
2358
|
+
const mfSrc = join13(templateDir, "manifest.json");
|
|
2134
2359
|
if (await pathExists(mfSrc)) {
|
|
2135
|
-
await copyFile(mfSrc,
|
|
2360
|
+
await copyFile(mfSrc, join13(targetDir, ".flydocs", "manifest.json"));
|
|
2136
2361
|
printStatus(".flydocs/manifest.json");
|
|
2137
2362
|
}
|
|
2138
2363
|
console.log();
|
|
@@ -2186,18 +2411,32 @@ __export(setup_exports, {
|
|
|
2186
2411
|
default: () => setup_default
|
|
2187
2412
|
});
|
|
2188
2413
|
import { defineCommand as defineCommand3 } from "citty";
|
|
2414
|
+
import pc7 from "picocolors";
|
|
2189
2415
|
var setup_default;
|
|
2190
2416
|
var init_setup = __esm({
|
|
2191
2417
|
"src/commands/setup.ts"() {
|
|
2192
2418
|
"use strict";
|
|
2193
|
-
init_ui();
|
|
2194
2419
|
setup_default = defineCommand3({
|
|
2195
2420
|
meta: {
|
|
2196
2421
|
name: "setup",
|
|
2197
2422
|
description: "Configure FlyDocs settings for this project"
|
|
2198
2423
|
},
|
|
2199
2424
|
run() {
|
|
2200
|
-
|
|
2425
|
+
console.log();
|
|
2426
|
+
console.log(` ${pc7.bold("FlyDocs Setup")}`);
|
|
2427
|
+
console.log();
|
|
2428
|
+
console.log(` Setup runs inside your IDE as an interactive AI command.`);
|
|
2429
|
+
console.log();
|
|
2430
|
+
console.log(
|
|
2431
|
+
` ${pc7.cyan("Claude Code:")} Type ${pc7.bold("/flydocs-setup")} in chat`
|
|
2432
|
+
);
|
|
2433
|
+
console.log(
|
|
2434
|
+
` ${pc7.cyan("Cursor:")} Type ${pc7.bold("/flydocs-setup")} in chat`
|
|
2435
|
+
);
|
|
2436
|
+
console.log();
|
|
2437
|
+
console.log(` This configures your project context, detects your stack,`);
|
|
2438
|
+
console.log(` and installs community skills tailored to your codebase.`);
|
|
2439
|
+
console.log();
|
|
2201
2440
|
}
|
|
2202
2441
|
});
|
|
2203
2442
|
}
|
|
@@ -2209,7 +2448,7 @@ __export(skills_exports, {
|
|
|
2209
2448
|
default: () => skills_default
|
|
2210
2449
|
});
|
|
2211
2450
|
import { defineCommand as defineCommand4 } from "citty";
|
|
2212
|
-
import
|
|
2451
|
+
import pc8 from "picocolors";
|
|
2213
2452
|
var list, search, add, remove, skills_default;
|
|
2214
2453
|
var init_skills2 = __esm({
|
|
2215
2454
|
"src/commands/skills.ts"() {
|
|
@@ -2231,19 +2470,19 @@ var init_skills2 = __esm({
|
|
|
2231
2470
|
console.log(`${total} skill(s) installed:`);
|
|
2232
2471
|
if (result.platform.length > 0) {
|
|
2233
2472
|
console.log();
|
|
2234
|
-
console.log(
|
|
2473
|
+
console.log(pc8.bold("Platform"));
|
|
2235
2474
|
for (const skill of result.platform) {
|
|
2236
2475
|
console.log(
|
|
2237
|
-
` ${skill.name} ${
|
|
2476
|
+
` ${skill.name} ${pc8.dim(`(${skill.triggers} triggers)`)}`
|
|
2238
2477
|
);
|
|
2239
2478
|
}
|
|
2240
2479
|
}
|
|
2241
2480
|
if (result.community.length > 0) {
|
|
2242
2481
|
console.log();
|
|
2243
|
-
console.log(
|
|
2482
|
+
console.log(pc8.bold("Community"));
|
|
2244
2483
|
for (const skill of result.community) {
|
|
2245
2484
|
console.log(
|
|
2246
|
-
` ${skill.name} ${
|
|
2485
|
+
` ${skill.name} ${pc8.dim(`(${skill.triggers} triggers)`)}`
|
|
2247
2486
|
);
|
|
2248
2487
|
}
|
|
2249
2488
|
}
|
|
@@ -2266,18 +2505,18 @@ var init_skills2 = __esm({
|
|
|
2266
2505
|
const results = await searchCatalog(args.keyword);
|
|
2267
2506
|
if (results.length === 0) {
|
|
2268
2507
|
console.log(`No skills found for "${args.keyword}".`);
|
|
2269
|
-
console.log(` Browse the catalog at: ${
|
|
2508
|
+
console.log(` Browse the catalog at: ${pc8.cyan("https://skills.sh/")}`);
|
|
2270
2509
|
return;
|
|
2271
2510
|
}
|
|
2272
2511
|
console.log();
|
|
2273
2512
|
console.log(`${results.length} skill(s) matching "${args.keyword}":`);
|
|
2274
2513
|
console.log();
|
|
2275
2514
|
for (const skill of results) {
|
|
2276
|
-
console.log(` ${
|
|
2515
|
+
console.log(` ${pc8.bold(skill.name)}`);
|
|
2277
2516
|
console.log(` ${skill.description}`);
|
|
2278
|
-
console.log(` ${
|
|
2517
|
+
console.log(` ${pc8.dim(skill.repo)}`);
|
|
2279
2518
|
if (skill.tags.length > 0) {
|
|
2280
|
-
console.log(` ${
|
|
2519
|
+
console.log(` ${pc8.dim(skill.tags.join(", "))}`);
|
|
2281
2520
|
}
|
|
2282
2521
|
console.log();
|
|
2283
2522
|
}
|
|
@@ -2336,11 +2575,10 @@ __export(connect_exports, {
|
|
|
2336
2575
|
default: () => connect_default
|
|
2337
2576
|
});
|
|
2338
2577
|
import { defineCommand as defineCommand5 } from "citty";
|
|
2339
|
-
import { text as text2, confirm as
|
|
2340
|
-
import
|
|
2578
|
+
import { text as text2, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
|
|
2579
|
+
import pc9 from "picocolors";
|
|
2341
2580
|
import { readFile as readFile9, writeFile as writeFile5, appendFile as appendFile2 } from "fs/promises";
|
|
2342
|
-
import { join as
|
|
2343
|
-
import { execSync as execSync2 } from "child_process";
|
|
2581
|
+
import { join as join14 } from "path";
|
|
2344
2582
|
var connect_default;
|
|
2345
2583
|
var init_connect = __esm({
|
|
2346
2584
|
"src/commands/connect.ts"() {
|
|
@@ -2374,11 +2612,11 @@ var init_connect = __esm({
|
|
|
2374
2612
|
},
|
|
2375
2613
|
async run({ args }) {
|
|
2376
2614
|
const targetDir = args.path ?? process.cwd();
|
|
2377
|
-
const configPath =
|
|
2615
|
+
const configPath = join14(targetDir, ".flydocs", "config.json");
|
|
2378
2616
|
if (!await pathExists(configPath)) {
|
|
2379
2617
|
printError("Not a FlyDocs project (.flydocs/config.json not found).");
|
|
2380
2618
|
console.log(
|
|
2381
|
-
` Run ${
|
|
2619
|
+
` Run ${pc9.cyan("flydocs")} first to install FlyDocs in this project.`
|
|
2382
2620
|
);
|
|
2383
2621
|
process.exit(1);
|
|
2384
2622
|
}
|
|
@@ -2386,7 +2624,7 @@ var init_connect = __esm({
|
|
|
2386
2624
|
if (config.tier === "cloud") {
|
|
2387
2625
|
printInfo("This project is already connected to the cloud tier.");
|
|
2388
2626
|
console.log();
|
|
2389
|
-
const reconnect = await
|
|
2627
|
+
const reconnect = await confirm4({
|
|
2390
2628
|
message: "Want to update your API key?"
|
|
2391
2629
|
});
|
|
2392
2630
|
if (isCancel5(reconnect) || !reconnect) {
|
|
@@ -2395,10 +2633,10 @@ var init_connect = __esm({
|
|
|
2395
2633
|
}
|
|
2396
2634
|
}
|
|
2397
2635
|
console.log();
|
|
2398
|
-
console.log(` ${
|
|
2636
|
+
console.log(` ${pc9.bold("Connect to Linear")}`);
|
|
2399
2637
|
console.log();
|
|
2400
2638
|
console.log(
|
|
2401
|
-
` ${
|
|
2639
|
+
` ${pc9.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
|
|
2402
2640
|
);
|
|
2403
2641
|
console.log();
|
|
2404
2642
|
let apiKey = args.key ?? "";
|
|
@@ -2421,27 +2659,31 @@ var init_connect = __esm({
|
|
|
2421
2659
|
}
|
|
2422
2660
|
printInfo("Validating API key...");
|
|
2423
2661
|
try {
|
|
2424
|
-
const
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
const
|
|
2437
|
-
|
|
2662
|
+
const response = await fetch("https://api.linear.app/graphql", {
|
|
2663
|
+
method: "POST",
|
|
2664
|
+
headers: {
|
|
2665
|
+
Authorization: apiKey,
|
|
2666
|
+
"Content-Type": "application/json"
|
|
2667
|
+
},
|
|
2668
|
+
body: JSON.stringify({ query: "{ viewer { id name email } }" }),
|
|
2669
|
+
signal: AbortSignal.timeout(15e3)
|
|
2670
|
+
});
|
|
2671
|
+
if (!response.ok) {
|
|
2672
|
+
throw new Error(`HTTP ${response.status}`);
|
|
2673
|
+
}
|
|
2674
|
+
const data = await response.json();
|
|
2675
|
+
if (!data.data?.viewer) {
|
|
2676
|
+
throw new Error("Invalid response");
|
|
2677
|
+
}
|
|
2678
|
+
const viewer = data.data.viewer;
|
|
2679
|
+
printStatus(`Authenticated as ${pc9.bold(viewer.name)} (${viewer.email})`);
|
|
2438
2680
|
} catch {
|
|
2439
2681
|
printError("Invalid API key or network error.");
|
|
2440
2682
|
console.log(` Check your key and try again.`);
|
|
2441
2683
|
process.exit(1);
|
|
2442
2684
|
}
|
|
2443
|
-
const envPath =
|
|
2444
|
-
const envLocalPath =
|
|
2685
|
+
const envPath = join14(targetDir, ".env");
|
|
2686
|
+
const envLocalPath = join14(targetDir, ".env.local");
|
|
2445
2687
|
const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
|
|
2446
2688
|
if (await pathExists(targetEnvPath)) {
|
|
2447
2689
|
const envContent = await readFile9(targetEnvPath, "utf-8");
|
|
@@ -2461,7 +2703,7 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2461
2703
|
`, "utf-8");
|
|
2462
2704
|
}
|
|
2463
2705
|
printStatus(
|
|
2464
|
-
`API key stored in ${
|
|
2706
|
+
`API key stored in ${pc9.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
|
|
2465
2707
|
);
|
|
2466
2708
|
const wasLocal = config.tier === "local";
|
|
2467
2709
|
config.tier = "cloud";
|
|
@@ -2474,14 +2716,14 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2474
2716
|
const templateDir = await resolveTemplatePath(
|
|
2475
2717
|
args["local-source"] || void 0
|
|
2476
2718
|
);
|
|
2477
|
-
const templateSkillsDir =
|
|
2478
|
-
const skillsDir =
|
|
2719
|
+
const templateSkillsDir = join14(templateDir, ".claude", "skills");
|
|
2720
|
+
const skillsDir = join14(targetDir, ".claude", "skills");
|
|
2479
2721
|
await replaceDirectory(
|
|
2480
|
-
|
|
2481
|
-
|
|
2722
|
+
join14(templateSkillsDir, "flydocs-cloud"),
|
|
2723
|
+
join14(skillsDir, "flydocs-cloud")
|
|
2482
2724
|
);
|
|
2483
2725
|
const { rm: rm5 } = await import("fs/promises");
|
|
2484
|
-
const localSkillDir =
|
|
2726
|
+
const localSkillDir = join14(skillsDir, "flydocs-local");
|
|
2485
2727
|
if (await pathExists(localSkillDir)) {
|
|
2486
2728
|
await rm5(localSkillDir, { recursive: true, force: true });
|
|
2487
2729
|
}
|
|
@@ -2494,14 +2736,14 @@ LINEAR_API_KEY=${apiKey}
|
|
|
2494
2736
|
}
|
|
2495
2737
|
console.log();
|
|
2496
2738
|
console.log(
|
|
2497
|
-
` ${
|
|
2739
|
+
` ${pc9.bold("Connected!")} Your project now syncs with Linear.`
|
|
2498
2740
|
);
|
|
2499
2741
|
console.log();
|
|
2500
2742
|
console.log(` Next steps:`);
|
|
2501
2743
|
console.log(
|
|
2502
|
-
` 1. Run ${
|
|
2744
|
+
` 1. Run ${pc9.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
|
|
2503
2745
|
);
|
|
2504
|
-
console.log(` 2. Run ${
|
|
2746
|
+
console.log(` 2. Run ${pc9.cyan("/start-session")} to begin working`);
|
|
2505
2747
|
console.log();
|
|
2506
2748
|
}
|
|
2507
2749
|
});
|
|
@@ -2514,7 +2756,7 @@ __export(upgrade_exports, {
|
|
|
2514
2756
|
default: () => upgrade_default
|
|
2515
2757
|
});
|
|
2516
2758
|
import { defineCommand as defineCommand6 } from "citty";
|
|
2517
|
-
import
|
|
2759
|
+
import pc10 from "picocolors";
|
|
2518
2760
|
var upgrade_default;
|
|
2519
2761
|
var init_upgrade = __esm({
|
|
2520
2762
|
"src/commands/upgrade.ts"() {
|
|
@@ -2550,37 +2792,37 @@ var init_upgrade = __esm({
|
|
|
2550
2792
|
console.log();
|
|
2551
2793
|
if (currentTier === "cloud") {
|
|
2552
2794
|
console.log(
|
|
2553
|
-
` ${
|
|
2795
|
+
` ${pc10.green("\u2713")} You're already on the ${pc10.bold("cloud")} tier.`
|
|
2554
2796
|
);
|
|
2555
2797
|
console.log();
|
|
2556
2798
|
console.log(
|
|
2557
2799
|
` Your issues sync with Linear via the cloud mechanism skill.`
|
|
2558
2800
|
);
|
|
2559
2801
|
console.log(
|
|
2560
|
-
` Run ${
|
|
2802
|
+
` Run ${pc10.cyan("flydocs connect")} to update your connection settings.`
|
|
2561
2803
|
);
|
|
2562
2804
|
console.log();
|
|
2563
2805
|
return;
|
|
2564
2806
|
}
|
|
2565
|
-
console.log(` ${
|
|
2807
|
+
console.log(` ${pc10.bold("FlyDocs Cloud Tier")}`);
|
|
2566
2808
|
console.log();
|
|
2567
|
-
console.log(` You're currently on the ${
|
|
2809
|
+
console.log(` You're currently on the ${pc10.yellow("local")} tier.`);
|
|
2568
2810
|
console.log(` Upgrade to cloud for:`);
|
|
2569
2811
|
console.log();
|
|
2570
2812
|
console.log(
|
|
2571
|
-
` ${
|
|
2813
|
+
` ${pc10.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
|
|
2572
2814
|
);
|
|
2573
|
-
console.log(` ${
|
|
2574
|
-
console.log(` ${
|
|
2575
|
-
console.log(` ${
|
|
2576
|
-
console.log(` ${
|
|
2815
|
+
console.log(` ${pc10.cyan("\u2192")} Project milestones and cycle management`);
|
|
2816
|
+
console.log(` ${pc10.cyan("\u2192")} Team assignment and priority tracking`);
|
|
2817
|
+
console.log(` ${pc10.cyan("\u2192")} Project health updates and dashboards`);
|
|
2818
|
+
console.log(` ${pc10.cyan("\u2192")} Cross-project issue linking`);
|
|
2577
2819
|
console.log();
|
|
2578
|
-
console.log(` ${
|
|
2820
|
+
console.log(` ${pc10.bold("How to upgrade:")}`);
|
|
2579
2821
|
console.log();
|
|
2580
|
-
console.log(` 1. Sign up at ${
|
|
2822
|
+
console.log(` 1. Sign up at ${pc10.cyan("https://www.flydocs.ai")}`);
|
|
2581
2823
|
console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
|
|
2582
2824
|
console.log(
|
|
2583
|
-
` 3. Run ${
|
|
2825
|
+
` 3. Run ${pc10.cyan("flydocs connect")} to connect your project`
|
|
2584
2826
|
);
|
|
2585
2827
|
console.log();
|
|
2586
2828
|
}
|
|
@@ -2594,8 +2836,8 @@ __export(self_update_exports, {
|
|
|
2594
2836
|
default: () => self_update_default
|
|
2595
2837
|
});
|
|
2596
2838
|
import { defineCommand as defineCommand7 } from "citty";
|
|
2597
|
-
import { execSync
|
|
2598
|
-
import
|
|
2839
|
+
import { execSync } from "child_process";
|
|
2840
|
+
import pc11 from "picocolors";
|
|
2599
2841
|
var self_update_default;
|
|
2600
2842
|
var init_self_update = __esm({
|
|
2601
2843
|
"src/commands/self-update.ts"() {
|
|
@@ -2609,17 +2851,19 @@ var init_self_update = __esm({
|
|
|
2609
2851
|
},
|
|
2610
2852
|
async run() {
|
|
2611
2853
|
console.log();
|
|
2612
|
-
console.log(` Updating ${
|
|
2854
|
+
console.log(` Updating ${pc11.cyan(PACKAGE_NAME)}...`);
|
|
2613
2855
|
console.log();
|
|
2614
2856
|
try {
|
|
2615
|
-
|
|
2857
|
+
execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
|
|
2616
2858
|
stdio: "inherit",
|
|
2617
2859
|
timeout: 6e4
|
|
2618
2860
|
});
|
|
2619
2861
|
console.log();
|
|
2620
2862
|
printStatus("FlyDocs CLI updated successfully");
|
|
2621
2863
|
} catch {
|
|
2622
|
-
printError(
|
|
2864
|
+
printError(
|
|
2865
|
+
`Update failed. Try manually: npm install -g ${PACKAGE_NAME}@beta`
|
|
2866
|
+
);
|
|
2623
2867
|
process.exit(1);
|
|
2624
2868
|
}
|
|
2625
2869
|
}
|
|
@@ -2640,8 +2884,11 @@ var SUB_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
2640
2884
|
"self-update"
|
|
2641
2885
|
]);
|
|
2642
2886
|
var userArgs = process.argv.slice(2);
|
|
2887
|
+
var hasMetaFlag = userArgs.some(
|
|
2888
|
+
(a) => a === "--version" || a === "--help" || a === "-h"
|
|
2889
|
+
);
|
|
2643
2890
|
var firstPositional = userArgs.find((a) => !a.startsWith("-"));
|
|
2644
|
-
if (!firstPositional || !SUB_COMMANDS.has(firstPositional)) {
|
|
2891
|
+
if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
|
|
2645
2892
|
process.argv.splice(2, 0, "install");
|
|
2646
2893
|
}
|
|
2647
2894
|
var main = defineCommand8({
|