@flydocs/cli 0.5.0-beta.5 → 0.5.0-beta.7

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 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.5";
18
+ CLI_VERSION = "0.5.0-beta.7";
19
19
  CLI_NAME = "flydocs";
20
20
  PACKAGE_NAME = "@flydocs/cli";
21
21
  }
@@ -148,9 +148,6 @@ function printError(message) {
148
148
  function printInfo(message) {
149
149
  console.log(`${pc2.cyan("\u2139")} ${message}`);
150
150
  }
151
- function printStub(command) {
152
- printWarning(`${pc2.bold(command)} is not yet implemented.`);
153
- }
154
151
  function printBanner(version) {
155
152
  const pink = (t) => pc2.bold(pc2.magenta(t));
156
153
  const purple = (t) => pc2.bold(pc2.cyan(t));
@@ -242,7 +239,6 @@ function extractPreservedValues(config) {
242
239
  issueLabels: config.issueLabels ?? {},
243
240
  statusMapping: config.statusMapping ?? {},
244
241
  detectedStack: config.detectedStack ?? {},
245
- mcp: config.mcp ?? {},
246
242
  skills: config.skills ?? {},
247
243
  designSystem: config.designSystem ?? null,
248
244
  aiLabor: config.aiLabor ?? {}
@@ -275,9 +271,6 @@ async function mergeConfig(templateDir, version, tierFlag, preserved) {
275
271
  if (Object.keys(preserved.detectedStack).length > 0) {
276
272
  config.detectedStack = preserved.detectedStack;
277
273
  }
278
- if (Object.keys(preserved.mcp).length > 0) {
279
- config.mcp = preserved.mcp;
280
- }
281
274
  if (Object.keys(preserved.skills).length > 0) {
282
275
  config.skills = preserved.skills;
283
276
  }
@@ -322,12 +315,6 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
322
315
  await replaceDirectory(src, join4(skillsDir, skill));
323
316
  }
324
317
  }
325
- for (const skill of SUPPORTING_SKILLS) {
326
- const src = join4(templateSkillsDir, skill);
327
- if (await pathExists(src)) {
328
- await replaceDirectory(src, join4(skillsDir, skill));
329
- }
330
- }
331
318
  const readmeSrc = join4(templateSkillsDir, "README.md");
332
319
  if (await pathExists(readmeSrc)) {
333
320
  await copyFile(readmeSrc, join4(skillsDir, "README.md"));
@@ -336,7 +323,7 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
336
323
  async function replaceOwnedSkills(templateDir, targetDir, tier) {
337
324
  const skillsDir = join4(targetDir, ".claude", "skills");
338
325
  const templateSkillsDir = join4(templateDir, ".claude", "skills");
339
- for (const skill of [...OWNED_SKILLS, ...SUPPORTING_SKILLS]) {
326
+ for (const skill of OWNED_SKILLS) {
340
327
  const src = join4(templateSkillsDir, skill);
341
328
  if (await pathExists(src)) {
342
329
  await replaceDirectory(src, join4(skillsDir, skill));
@@ -384,20 +371,8 @@ async function copyCursorRules(targetDir) {
384
371
  await copyFile(mechRule, join4(rulesDir, "flydocs-mechanism.mdc"));
385
372
  }
386
373
  }
387
- for (const skill of PREMIUM_CURSOR_RULES) {
388
- const skillRule = join4(
389
- targetDir,
390
- ".claude",
391
- "skills",
392
- skill,
393
- "cursor-rule.mdc"
394
- );
395
- if (await pathExists(skillRule)) {
396
- await copyFile(skillRule, join4(rulesDir, `${skill}.mdc`));
397
- }
398
- }
399
374
  }
400
- var OWNED_SKILLS, SUPPORTING_SKILLS, MECHANISM_SKILLS, PREMIUM_CURSOR_RULES;
375
+ var OWNED_SKILLS, MECHANISM_SKILLS;
401
376
  var init_skills = __esm({
402
377
  "src/lib/skills.ts"() {
403
378
  "use strict";
@@ -408,22 +383,61 @@ var init_skills = __esm({
408
383
  "flydocs-estimates",
409
384
  "flydocs-context-graph"
410
385
  ];
411
- SUPPORTING_SKILLS = [
412
- "implementation-flow",
413
- "review-workflow",
414
- "spec-templates"
415
- ];
416
386
  MECHANISM_SKILLS = {
417
387
  local: "flydocs-local",
418
388
  cloud: "flydocs-cloud"
419
389
  };
420
- PREMIUM_CURSOR_RULES = ["flydocs-figma", "flydocs-estimates"];
421
390
  }
422
391
  });
423
392
 
424
393
  // src/lib/stack.ts
425
394
  import { readFile as readFile3 } from "fs/promises";
426
395
  import { join as join5 } from "path";
396
+ async function parseProjectMdStack(targetDir) {
397
+ const detected = /* @__PURE__ */ new Set();
398
+ const projectMdPath = join5(targetDir, "flydocs", "context", "project.md");
399
+ try {
400
+ const content = await readFile3(projectMdPath, "utf-8");
401
+ const stackMatch = content.match(/## Stack\n([\s\S]*?)(?=\n## |\n---|\z)/);
402
+ if (!stackMatch) return detected;
403
+ const stackSection = stackMatch[1].toLowerCase();
404
+ const keywordMap = {
405
+ "next.js": ["nextjs", "react"],
406
+ nextjs: ["nextjs", "react"],
407
+ react: ["react"],
408
+ vue: ["vue"],
409
+ nuxt: ["nuxt", "vue"],
410
+ angular: ["angular"],
411
+ svelte: ["svelte"],
412
+ sveltekit: ["svelte"],
413
+ expo: ["expo", "react"],
414
+ typescript: ["typescript"],
415
+ tailwind: ["tailwind"],
416
+ convex: ["convex"],
417
+ prisma: ["prisma"],
418
+ postgresql: ["prisma"],
419
+ clerk: ["clerk"],
420
+ python: ["python"],
421
+ django: ["python"],
422
+ flask: ["python"],
423
+ fastapi: ["python"],
424
+ golang: ["go"],
425
+ " go ": ["go"],
426
+ rust: ["rust"],
427
+ vitest: ["vitest"],
428
+ jest: ["jest"]
429
+ };
430
+ for (const [keyword, triggers] of Object.entries(keywordMap)) {
431
+ if (stackSection.includes(keyword)) {
432
+ for (const trigger of triggers) {
433
+ detected.add(trigger);
434
+ }
435
+ }
436
+ }
437
+ } catch {
438
+ }
439
+ return detected;
440
+ }
427
441
  async function detectStack(targetDir) {
428
442
  const detected = /* @__PURE__ */ new Set();
429
443
  const pkgPath = join5(targetDir, "package.json");
@@ -492,6 +506,10 @@ async function detectStack(targetDir) {
492
506
  if (await pathExists(join5(targetDir, "Cargo.toml"))) {
493
507
  detected.add("rust");
494
508
  }
509
+ const projectMdStack = await parseProjectMdStack(targetDir);
510
+ for (const item of projectMdStack) {
511
+ detected.add(item);
512
+ }
495
513
  const raw = Array.from(detected);
496
514
  return {
497
515
  raw,
@@ -530,7 +548,7 @@ var init_stack = __esm({
530
548
  });
531
549
 
532
550
  // src/lib/post-install.ts
533
- import { execSync } from "child_process";
551
+ import { execFileSync } from "child_process";
534
552
  import { join as join6 } from "path";
535
553
  async function runManifestGeneration(targetDir) {
536
554
  const scriptPath = join6(
@@ -541,7 +559,7 @@ async function runManifestGeneration(targetDir) {
541
559
  );
542
560
  if (!await pathExists(scriptPath)) return;
543
561
  try {
544
- execSync(`python3 "${scriptPath}"`, {
562
+ execFileSync("python3", [scriptPath], {
545
563
  cwd: targetDir,
546
564
  stdio: "pipe"
547
565
  });
@@ -561,7 +579,7 @@ async function runContextGraphBuild(targetDir) {
561
579
  );
562
580
  if (!await pathExists(scriptPath)) return;
563
581
  try {
564
- execSync(`python3 "${scriptPath}"`, {
582
+ execFileSync("python3", [scriptPath], {
565
583
  cwd: targetDir,
566
584
  stdio: "pipe"
567
585
  });
@@ -944,6 +962,7 @@ var init_skill_manager = __esm({
944
962
  });
945
963
 
946
964
  // src/lib/community-skills.ts
965
+ import { join as join8 } from "path";
947
966
  import { multiselect, isCancel, cancel } from "@clack/prompts";
948
967
  import pc4 from "picocolors";
949
968
  function suggestSkills(stack) {
@@ -962,7 +981,14 @@ function suggestSkills(stack) {
962
981
  }
963
982
  async function promptCommunitySkills(targetDir, stack, autoYes) {
964
983
  const suggestions = suggestSkills(stack);
965
- if (suggestions.length === 0) {
984
+ const skillsDir = join8(targetDir, ".claude", "skills");
985
+ const filtered = [];
986
+ for (const skill of suggestions) {
987
+ if (!await pathExists(join8(skillsDir, skill.name))) {
988
+ filtered.push(skill);
989
+ }
990
+ }
991
+ if (filtered.length === 0) {
966
992
  printInfo("No community skills suggested for detected stack.");
967
993
  console.log(` Browse more at: ${pc4.cyan("https://skills.sh/")}`);
968
994
  return;
@@ -977,10 +1003,10 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
977
1003
  console.log();
978
1004
  let selected;
979
1005
  if (autoYes) {
980
- selected = suggestions;
1006
+ selected = filtered;
981
1007
  console.log(" Auto-accepting all (--yes)");
982
1008
  } else {
983
- const options = suggestions.map((s) => ({
1009
+ const options = filtered.map((s) => ({
984
1010
  value: s,
985
1011
  label: s.name,
986
1012
  hint: s.description,
@@ -990,7 +1016,7 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
990
1016
  message: "Select community skills to install (space to toggle, enter to confirm)",
991
1017
  options,
992
1018
  required: false,
993
- initialValues: suggestions
1019
+ initialValues: filtered
994
1020
  });
995
1021
  if (isCancel(result)) {
996
1022
  cancel("Skipped community skills");
@@ -1026,6 +1052,7 @@ var COMMUNITY_SKILLS_MAP;
1026
1052
  var init_community_skills = __esm({
1027
1053
  "src/lib/community-skills.ts"() {
1028
1054
  "use strict";
1055
+ init_fs_ops();
1029
1056
  init_ui();
1030
1057
  init_skill_manager();
1031
1058
  COMMUNITY_SKILLS_MAP = [
@@ -1115,47 +1142,47 @@ var init_community_skills = __esm({
1115
1142
 
1116
1143
  // src/lib/deprecated.ts
1117
1144
  import { readdir as readdir2, mkdir as mkdir3, rename, rm as rm3 } from "fs/promises";
1118
- import { join as join8 } from "path";
1145
+ import { join as join9 } from "path";
1119
1146
  import { confirm, isCancel as isCancel2 } from "@clack/prompts";
1120
1147
  async function scanDeprecated(targetDir) {
1121
1148
  const found = [];
1122
1149
  for (const item of [...DEPRECATED_DIRS, ...DEPRECATED_FILES]) {
1123
- if (await pathExists(join8(targetDir, item))) {
1150
+ if (await pathExists(join9(targetDir, item))) {
1124
1151
  found.push(item);
1125
1152
  }
1126
1153
  }
1127
1154
  for (const skill of DEPRECATED_SKILLS) {
1128
- const p = join8(targetDir, ".claude", "skills", skill);
1155
+ const p = join9(targetDir, ".claude", "skills", skill);
1129
1156
  if (await pathExists(p)) {
1130
1157
  found.push(`.claude/skills/${skill}`);
1131
1158
  }
1132
1159
  }
1133
1160
  for (const dir of DEPRECATED_RULES_DIR) {
1134
- if (await pathExists(join8(targetDir, dir))) {
1161
+ if (await pathExists(join9(targetDir, dir))) {
1135
1162
  found.push(dir);
1136
1163
  }
1137
1164
  }
1138
1165
  for (const hook of DEPRECATED_HOOKS) {
1139
- const p = join8(targetDir, ".flydocs", "hooks", hook);
1166
+ const p = join9(targetDir, ".flydocs", "hooks", hook);
1140
1167
  if (await pathExists(p)) {
1141
1168
  found.push(`.flydocs/hooks/${hook}`);
1142
1169
  }
1143
1170
  }
1144
1171
  for (const rule of DEPRECATED_CURSOR_RULES) {
1145
- const p = join8(targetDir, ".cursor", "rules", rule);
1172
+ const p = join9(targetDir, ".cursor", "rules", rule);
1146
1173
  if (await pathExists(p)) {
1147
1174
  found.push(`.cursor/rules/${rule}`);
1148
1175
  }
1149
1176
  }
1150
1177
  for (const dir of DEPRECATED_CURSOR_RULE_DIRS) {
1151
- const p = join8(targetDir, ".cursor", "rules", dir);
1178
+ const p = join9(targetDir, ".cursor", "rules", dir);
1152
1179
  if (await pathExists(p)) {
1153
1180
  found.push(`.cursor/rules/${dir}`);
1154
1181
  }
1155
1182
  }
1156
1183
  for (const cmd of DEPRECATED_COMMANDS) {
1157
1184
  for (const prefix of [".cursor/commands", ".claude/commands"]) {
1158
- const p = join8(targetDir, prefix, cmd);
1185
+ const p = join9(targetDir, prefix, cmd);
1159
1186
  if (await pathExists(p)) {
1160
1187
  found.push(`${prefix}/${cmd}`);
1161
1188
  }
@@ -1164,12 +1191,12 @@ async function scanDeprecated(targetDir) {
1164
1191
  return found;
1165
1192
  }
1166
1193
  async function handleLegacyContext(targetDir) {
1167
- const contextDir = join8(targetDir, "flydocs", "context");
1168
- const legacyDir = join8(contextDir, "legacy");
1194
+ const contextDir = join9(targetDir, "flydocs", "context");
1195
+ const legacyDir = join9(contextDir, "legacy");
1169
1196
  const oldFiles = ["overview.md", "stack.md", "standards.md"];
1170
1197
  let hasOld = false;
1171
1198
  for (const f of oldFiles) {
1172
- if (await pathExists(join8(contextDir, f))) {
1199
+ if (await pathExists(join9(contextDir, f))) {
1173
1200
  hasOld = true;
1174
1201
  break;
1175
1202
  }
@@ -1177,9 +1204,9 @@ async function handleLegacyContext(targetDir) {
1177
1204
  if (hasOld) {
1178
1205
  await mkdir3(legacyDir, { recursive: true });
1179
1206
  for (const f of oldFiles) {
1180
- const src = join8(contextDir, f);
1207
+ const src = join9(contextDir, f);
1181
1208
  if (await pathExists(src)) {
1182
- await rename(src, join8(legacyDir, f));
1209
+ await rename(src, join9(legacyDir, f));
1183
1210
  printStatus(`Moved flydocs/context/${f} \u2192 legacy/`);
1184
1211
  }
1185
1212
  }
@@ -1189,7 +1216,7 @@ async function handleLegacyContext(targetDir) {
1189
1216
  }
1190
1217
  }
1191
1218
  async function checkLegacyFolder(targetDir) {
1192
- const legacyDir = join8(targetDir, "flydocs", "context", "legacy");
1219
+ const legacyDir = join9(targetDir, "flydocs", "context", "legacy");
1193
1220
  if (!await pathExists(legacyDir)) return null;
1194
1221
  try {
1195
1222
  const entries = await readdir2(legacyDir);
@@ -1219,7 +1246,7 @@ async function promptCleanup(targetDir, paths) {
1219
1246
  return;
1220
1247
  }
1221
1248
  for (const p of paths) {
1222
- await rm3(join8(targetDir, p), { recursive: true, force: true });
1249
+ await rm3(join9(targetDir, p), { recursive: true, force: true });
1223
1250
  printStatus(`Deleted: ${p}`);
1224
1251
  }
1225
1252
  }
@@ -1230,19 +1257,20 @@ var init_deprecated = __esm({
1230
1257
  init_fs_ops();
1231
1258
  init_ui();
1232
1259
  DEPRECATED_DIRS = [".docflow", "docflow"];
1233
- DEPRECATED_FILES = ["AGENTS.md.bak"];
1260
+ DEPRECATED_FILES = ["AGENTS.md.bak", ".cursor/mcp.json"];
1234
1261
  DEPRECATED_SKILLS = [
1235
1262
  "linear-workflow",
1236
1263
  "session-workflow",
1237
1264
  "ai-labor-estimate",
1238
1265
  "component-workflow",
1239
- "figma-mcp",
1240
- "implementation-flow",
1241
- "review-workflow",
1242
- "spec-templates"
1266
+ "figma-mcp"
1243
1267
  ];
1244
1268
  DEPRECATED_RULES_DIR = [".flydocs/rules"];
1245
- DEPRECATED_HOOKS = ["linear-auto-approve.py", "session-end.py"];
1269
+ DEPRECATED_HOOKS = [
1270
+ "linear-auto-approve.py",
1271
+ "session-end.py",
1272
+ "prefer-scripts.py"
1273
+ ];
1246
1274
  DEPRECATED_CURSOR_RULES = [
1247
1275
  "designer-agent.mdc",
1248
1276
  "docflow-core.mdc",
@@ -1270,9 +1298,9 @@ var init_deprecated = __esm({
1270
1298
 
1271
1299
  // src/lib/gitignore.ts
1272
1300
  import { readFile as readFile5, writeFile as writeFile3, appendFile } from "fs/promises";
1273
- import { join as join9 } from "path";
1301
+ import { join as join10 } from "path";
1274
1302
  async function ensureGitignore(targetDir) {
1275
- const gitignorePath = join9(targetDir, ".gitignore");
1303
+ const gitignorePath = join10(targetDir, ".gitignore");
1276
1304
  if (await pathExists(gitignorePath)) {
1277
1305
  const content = await readFile5(gitignorePath, "utf-8");
1278
1306
  if (!content.includes("# FlyDocs")) {
@@ -1286,7 +1314,7 @@ async function ensureGitignore(targetDir) {
1286
1314
  }
1287
1315
  }
1288
1316
  async function migrateGitignore(targetDir) {
1289
- const gitignorePath = join9(targetDir, ".gitignore");
1317
+ const gitignorePath = join10(targetDir, ".gitignore");
1290
1318
  if (!await pathExists(gitignorePath)) return;
1291
1319
  const content = await readFile5(gitignorePath, "utf-8");
1292
1320
  if (!content.includes("flydocs/context/graph.json")) {
@@ -1370,8 +1398,10 @@ __pycache__/
1370
1398
  // src/lib/version.ts
1371
1399
  import { readFile as readFile6 } from "fs/promises";
1372
1400
  function compareVersions(v1, v2) {
1373
- const parts1 = v1.split(".").map(Number);
1374
- const parts2 = v2.split(".").map(Number);
1401
+ const [core1, pre1] = v1.split("-", 2);
1402
+ const [core2, pre2] = v2.split("-", 2);
1403
+ const parts1 = core1.split(".").map(Number);
1404
+ const parts2 = core2.split(".").map(Number);
1375
1405
  const len = Math.max(parts1.length, parts2.length);
1376
1406
  for (let i = 0; i < len; i++) {
1377
1407
  const a = parts1[i] ?? 0;
@@ -1379,6 +1409,27 @@ function compareVersions(v1, v2) {
1379
1409
  if (a < b) return "older";
1380
1410
  if (a > b) return "newer";
1381
1411
  }
1412
+ if (!pre1 && pre2) return "newer";
1413
+ if (pre1 && !pre2) return "older";
1414
+ if (!pre1 && !pre2) return "equal";
1415
+ const preParts1 = pre1.split(".");
1416
+ const preParts2 = pre2.split(".");
1417
+ const preLen = Math.max(preParts1.length, preParts2.length);
1418
+ for (let i = 0; i < preLen; i++) {
1419
+ const a = preParts1[i];
1420
+ const b = preParts2[i];
1421
+ if (a === void 0) return "older";
1422
+ if (b === void 0) return "newer";
1423
+ const numA = Number(a);
1424
+ const numB = Number(b);
1425
+ if (!Number.isNaN(numA) && !Number.isNaN(numB)) {
1426
+ if (numA < numB) return "older";
1427
+ if (numA > numB) return "newer";
1428
+ continue;
1429
+ }
1430
+ if (a < b) return "older";
1431
+ if (a > b) return "newer";
1432
+ }
1382
1433
  return "equal";
1383
1434
  }
1384
1435
  async function getWhatsNew(changelogPath, fromVersion, toVersion) {
@@ -1391,7 +1442,7 @@ async function getWhatsNew(changelogPath, fromVersion, toVersion) {
1391
1442
  const sections = content.split(/^## \[/m);
1392
1443
  const relevant = [];
1393
1444
  for (const section of sections.slice(1)) {
1394
- const match = section.match(/^([\d.]+)\]/);
1445
+ const match = section.match(/^([\d.]+(?:-[\w.]+)?)\]/);
1395
1446
  if (!match) continue;
1396
1447
  const ver = match[1];
1397
1448
  if (compareVersions(ver, fromVersion) !== "older" && compareVersions(ver, fromVersion) !== "equal" && (compareVersions(ver, toVersion) === "older" || compareVersions(ver, toVersion) === "equal")) {
@@ -1414,7 +1465,7 @@ var init_version = __esm({
1414
1465
 
1415
1466
  // src/lib/update-check.ts
1416
1467
  import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
1417
- import { join as join10 } from "path";
1468
+ import { join as join11 } from "path";
1418
1469
  import { homedir } from "os";
1419
1470
  import pc5 from "picocolors";
1420
1471
  async function readCache() {
@@ -1431,7 +1482,7 @@ async function readCache() {
1431
1482
  }
1432
1483
  async function writeCache(cache) {
1433
1484
  try {
1434
- await mkdir4(join10(homedir(), ".flydocs"), { recursive: true });
1485
+ await mkdir4(join11(homedir(), ".flydocs"), { recursive: true });
1435
1486
  await writeFile4(CACHE_FILE, JSON.stringify(cache), "utf-8");
1436
1487
  } catch {
1437
1488
  }
@@ -1500,7 +1551,7 @@ var init_update_check = __esm({
1500
1551
  "use strict";
1501
1552
  init_constants();
1502
1553
  init_version();
1503
- CACHE_FILE = join10(homedir(), ".flydocs", "update-check.json");
1554
+ CACHE_FILE = join11(homedir(), ".flydocs", "update-check.json");
1504
1555
  CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
1505
1556
  FETCH_TIMEOUT_MS = 5e3;
1506
1557
  }
@@ -1513,8 +1564,8 @@ __export(install_exports, {
1513
1564
  });
1514
1565
  import { defineCommand } from "citty";
1515
1566
  import { resolve as resolve2 } from "path";
1516
- import { join as join11 } from "path";
1517
- import { confirm as confirm2, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1567
+ import { join as join12 } from "path";
1568
+ import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1518
1569
  var install_default;
1519
1570
  var init_install = __esm({
1520
1571
  "src/commands/install.ts"() {
@@ -1591,7 +1642,7 @@ var init_install = __esm({
1591
1642
  }
1592
1643
  tier = args.tier;
1593
1644
  printInfo(`Tier set via flag: ${tier}`);
1594
- } else if (await pathExists(join11(targetDir, ".flydocs", "config.json"))) {
1645
+ } else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
1595
1646
  try {
1596
1647
  const existing = await readConfig(targetDir);
1597
1648
  if (existing.tier) {
@@ -1613,37 +1664,37 @@ var init_install = __esm({
1613
1664
  tier = "local";
1614
1665
  console.log();
1615
1666
  }
1616
- if (!await pathExists(join11(targetDir, ".git"))) {
1667
+ if (!await pathExists(join12(targetDir, ".git"))) {
1617
1668
  printWarning("No git repository detected. Run git init when ready.");
1618
1669
  }
1619
1670
  await ensureDirectories(targetDir, tier);
1620
1671
  console.log("Installing framework files...");
1621
1672
  await replaceDirectory(
1622
- join11(templateDir, ".flydocs", "templates"),
1623
- join11(targetDir, ".flydocs", "templates")
1673
+ join12(templateDir, ".flydocs", "templates"),
1674
+ join12(targetDir, ".flydocs", "templates")
1624
1675
  );
1625
1676
  await replaceDirectory(
1626
- join11(templateDir, ".flydocs", "hooks"),
1627
- join11(targetDir, ".flydocs", "hooks")
1677
+ join12(templateDir, ".flydocs", "hooks"),
1678
+ join12(targetDir, ".flydocs", "hooks")
1628
1679
  );
1629
1680
  await replaceDirectory(
1630
- join11(templateDir, ".flydocs", "scripts"),
1631
- join11(targetDir, ".flydocs", "scripts")
1681
+ join12(templateDir, ".flydocs", "scripts"),
1682
+ join12(targetDir, ".flydocs", "scripts")
1632
1683
  );
1633
1684
  await copyFile(
1634
- join11(templateDir, ".flydocs", "version"),
1635
- join11(targetDir, ".flydocs", "version")
1685
+ join12(templateDir, ".flydocs", "version"),
1686
+ join12(targetDir, ".flydocs", "version")
1636
1687
  );
1637
- const manifestSrc = join11(templateDir, "manifest.json");
1688
+ const manifestSrc = join12(templateDir, "manifest.json");
1638
1689
  if (await pathExists(manifestSrc)) {
1639
- await copyFile(manifestSrc, join11(targetDir, ".flydocs", "manifest.json"));
1690
+ await copyFile(manifestSrc, join12(targetDir, ".flydocs", "manifest.json"));
1640
1691
  }
1641
- const changelogSrc = join11(templateDir, "CHANGELOG.md");
1692
+ const changelogSrc = join12(templateDir, "CHANGELOG.md");
1642
1693
  if (await pathExists(changelogSrc)) {
1643
- await copyFile(changelogSrc, join11(targetDir, ".flydocs", "CHANGELOG.md"));
1694
+ await copyFile(changelogSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
1644
1695
  }
1645
1696
  printStatus(".flydocs/templates, hooks, version, manifest, changelog");
1646
- const configPath = join11(targetDir, ".flydocs", "config.json");
1697
+ const configPath = join12(targetDir, ".flydocs", "config.json");
1647
1698
  if (!await pathExists(configPath)) {
1648
1699
  const config = await createFreshConfig(templateDir, version, tier);
1649
1700
  await writeConfig(targetDir, config);
@@ -1669,56 +1720,47 @@ var init_install = __esm({
1669
1720
  printStatus(`Skills installed (tier: ${tier})`);
1670
1721
  console.log();
1671
1722
  console.log("Installing agents and commands...");
1672
- const claudeAgentsSrc = join11(templateDir, ".claude", "agents");
1723
+ const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
1673
1724
  if (await pathExists(claudeAgentsSrc)) {
1674
1725
  await copyDirectoryContents(
1675
1726
  claudeAgentsSrc,
1676
- join11(targetDir, ".claude", "agents")
1727
+ join12(targetDir, ".claude", "agents")
1677
1728
  );
1678
1729
  }
1679
1730
  await copyDirectoryContents(
1680
- join11(templateDir, ".claude", "commands"),
1681
- join11(targetDir, ".claude", "commands")
1731
+ join12(templateDir, ".claude", "commands"),
1732
+ join12(targetDir, ".claude", "commands")
1682
1733
  );
1683
1734
  await copyFile(
1684
- join11(templateDir, ".claude", "CLAUDE.md"),
1685
- join11(targetDir, ".claude", "CLAUDE.md")
1735
+ join12(templateDir, ".claude", "CLAUDE.md"),
1736
+ join12(targetDir, ".claude", "CLAUDE.md")
1686
1737
  );
1687
1738
  await copyFile(
1688
- join11(templateDir, ".claude", "settings.json"),
1689
- join11(targetDir, ".claude", "settings.json")
1739
+ join12(templateDir, ".claude", "settings.json"),
1740
+ join12(targetDir, ".claude", "settings.json")
1690
1741
  );
1691
1742
  printStatus(".claude/ (agents, commands, CLAUDE.md, settings)");
1692
- const cursorAgentsSrc = join11(templateDir, ".cursor", "agents");
1743
+ const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
1693
1744
  if (await pathExists(cursorAgentsSrc)) {
1694
1745
  await copyDirectoryContents(
1695
1746
  cursorAgentsSrc,
1696
- join11(targetDir, ".cursor", "agents")
1747
+ join12(targetDir, ".cursor", "agents")
1697
1748
  );
1698
1749
  }
1699
1750
  await copyDirectoryContents(
1700
- join11(templateDir, ".claude", "commands"),
1701
- join11(targetDir, ".cursor", "commands")
1751
+ join12(templateDir, ".claude", "commands"),
1752
+ join12(targetDir, ".cursor", "commands")
1702
1753
  );
1703
1754
  await copyFile(
1704
- join11(templateDir, ".cursor", "hooks.json"),
1705
- join11(targetDir, ".cursor", "hooks.json")
1755
+ join12(templateDir, ".cursor", "hooks.json"),
1756
+ join12(targetDir, ".cursor", "hooks.json")
1706
1757
  );
1707
1758
  printStatus(".cursor/ (agents, commands, hooks)");
1708
1759
  await copyCursorRules(targetDir);
1709
1760
  printStatus(".cursor/rules/");
1710
- const mcpResult = await copyFileIfNotExists(
1711
- join11(templateDir, ".cursor", "mcp.json"),
1712
- join11(targetDir, ".cursor", "mcp.json")
1713
- );
1714
- if (mcpResult === "created") {
1715
- printStatus(".cursor/mcp.json (new)");
1716
- } else {
1717
- printWarning(".cursor/mcp.json exists, preserving");
1718
- }
1719
1761
  await copyFile(
1720
- join11(templateDir, "AGENTS.md"),
1721
- join11(targetDir, "AGENTS.md")
1762
+ join12(templateDir, "AGENTS.md"),
1763
+ join12(targetDir, "AGENTS.md")
1722
1764
  );
1723
1765
  printStatus("AGENTS.md");
1724
1766
  await runManifestGeneration(targetDir);
@@ -1727,40 +1769,40 @@ var init_install = __esm({
1727
1769
  console.log("Installing project templates...");
1728
1770
  const userFiles = [
1729
1771
  {
1730
- src: join11(templateDir, "flydocs", "context", "project.md"),
1731
- dest: join11(targetDir, "flydocs", "context", "project.md"),
1772
+ src: join12(templateDir, "flydocs", "context", "project.md"),
1773
+ dest: join12(targetDir, "flydocs", "context", "project.md"),
1732
1774
  label: "flydocs/context/project.md"
1733
1775
  },
1734
1776
  {
1735
- src: join11(templateDir, "flydocs", "knowledge", "INDEX.md"),
1736
- dest: join11(targetDir, "flydocs", "knowledge", "INDEX.md"),
1777
+ src: join12(templateDir, "flydocs", "knowledge", "INDEX.md"),
1778
+ dest: join12(targetDir, "flydocs", "knowledge", "INDEX.md"),
1737
1779
  label: "flydocs/knowledge/INDEX.md"
1738
1780
  },
1739
1781
  {
1740
- src: join11(templateDir, "flydocs", "knowledge", "README.md"),
1741
- dest: join11(targetDir, "flydocs", "knowledge", "README.md"),
1782
+ src: join12(templateDir, "flydocs", "knowledge", "README.md"),
1783
+ dest: join12(targetDir, "flydocs", "knowledge", "README.md"),
1742
1784
  label: "flydocs/knowledge/README.md"
1743
1785
  },
1744
1786
  {
1745
- src: join11(
1787
+ src: join12(
1746
1788
  templateDir,
1747
1789
  "flydocs",
1748
1790
  "knowledge",
1749
1791
  "product",
1750
1792
  "personas.md"
1751
1793
  ),
1752
- dest: join11(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1794
+ dest: join12(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1753
1795
  label: "flydocs/knowledge/product/personas.md"
1754
1796
  },
1755
1797
  {
1756
- src: join11(
1798
+ src: join12(
1757
1799
  templateDir,
1758
1800
  "flydocs",
1759
1801
  "knowledge",
1760
1802
  "product",
1761
1803
  "user-flows.md"
1762
1804
  ),
1763
- dest: join11(
1805
+ dest: join12(
1764
1806
  targetDir,
1765
1807
  "flydocs",
1766
1808
  "knowledge",
@@ -1770,18 +1812,18 @@ var init_install = __esm({
1770
1812
  label: "flydocs/knowledge/product/user-flows.md"
1771
1813
  },
1772
1814
  {
1773
- src: join11(templateDir, "flydocs", "design-system", "README.md"),
1774
- dest: join11(targetDir, "flydocs", "design-system", "README.md"),
1815
+ src: join12(templateDir, "flydocs", "design-system", "README.md"),
1816
+ dest: join12(targetDir, "flydocs", "design-system", "README.md"),
1775
1817
  label: "flydocs/design-system/README.md"
1776
1818
  },
1777
1819
  {
1778
- src: join11(
1820
+ src: join12(
1779
1821
  templateDir,
1780
1822
  "flydocs",
1781
1823
  "design-system",
1782
1824
  "component-patterns.md"
1783
1825
  ),
1784
- dest: join11(
1826
+ dest: join12(
1785
1827
  targetDir,
1786
1828
  "flydocs",
1787
1829
  "design-system",
@@ -1790,13 +1832,13 @@ var init_install = __esm({
1790
1832
  label: "flydocs/design-system/component-patterns.md"
1791
1833
  },
1792
1834
  {
1793
- src: join11(templateDir, "flydocs", "design-system", "token-mapping.md"),
1794
- dest: join11(targetDir, "flydocs", "design-system", "token-mapping.md"),
1835
+ src: join12(templateDir, "flydocs", "design-system", "token-mapping.md"),
1836
+ dest: join12(targetDir, "flydocs", "design-system", "token-mapping.md"),
1795
1837
  label: "flydocs/design-system/token-mapping.md"
1796
1838
  },
1797
1839
  {
1798
- src: join11(templateDir, "flydocs", "README.md"),
1799
- dest: join11(targetDir, "flydocs", "README.md"),
1840
+ src: join12(templateDir, "flydocs", "README.md"),
1841
+ dest: join12(targetDir, "flydocs", "README.md"),
1800
1842
  label: "flydocs/README.md"
1801
1843
  }
1802
1844
  ];
@@ -1810,12 +1852,12 @@ var init_install = __esm({
1810
1852
  }
1811
1853
  }
1812
1854
  }
1813
- const envExampleSrc = join11(templateDir, ".env.example");
1855
+ const envExampleSrc = join12(templateDir, ".env.example");
1814
1856
  if (await pathExists(envExampleSrc)) {
1815
- const hasEnv = await pathExists(join11(targetDir, ".env"));
1816
- const hasEnvExample = await pathExists(join11(targetDir, ".env.example"));
1857
+ const hasEnv = await pathExists(join12(targetDir, ".env"));
1858
+ const hasEnvExample = await pathExists(join12(targetDir, ".env.example"));
1817
1859
  if (!hasEnv && !hasEnvExample) {
1818
- await copyFile(envExampleSrc, join11(targetDir, ".env.example"));
1860
+ await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
1819
1861
  printStatus(".env.example (new)");
1820
1862
  }
1821
1863
  }
@@ -1877,50 +1919,94 @@ var init_install = __esm({
1877
1919
  printCompletionBox("Installation Complete!", nextSteps);
1878
1920
  printBetaCta();
1879
1921
  try {
1880
- const { execSync: execSync4, spawn } = await import("child_process");
1922
+ const { execSync: execSync2, spawn } = await import("child_process");
1881
1923
  const isInstalled = (cmd) => {
1882
1924
  try {
1883
- execSync4(`which ${cmd}`, { stdio: "pipe" });
1925
+ execSync2(`which ${cmd}`, { stdio: "pipe" });
1884
1926
  return true;
1885
1927
  } catch {
1886
1928
  return false;
1887
1929
  }
1888
1930
  };
1889
- const hasClaude = isInstalled("claude");
1890
- const hasCursor = isInstalled("cursor");
1891
- const hasCode = isInstalled("code");
1892
- if (hasClaude) {
1893
- const launchClaude = await confirm2({
1894
- message: "Open Claude Code and run /flydocs-setup now?"
1931
+ const ideOptions = [];
1932
+ if (isInstalled("claude")) {
1933
+ ideOptions.push({
1934
+ cmd: "claude",
1935
+ label: "Claude Code",
1936
+ hint: "Opens and runs /flydocs-setup automatically",
1937
+ passCommand: true
1895
1938
  });
1896
- if (!isCancel3(launchClaude) && launchClaude) {
1897
- spawn("claude", ["/flydocs-setup"], {
1898
- cwd: targetDir,
1899
- stdio: "inherit"
1900
- });
1901
- return;
1902
- }
1903
- } else if (hasCursor) {
1904
- const launchCursor = await confirm2({
1905
- message: copiedToClipboard ? "Open Cursor? (paste /flydocs-setup from clipboard)" : "Open Cursor?"
1939
+ }
1940
+ if (isInstalled("cursor")) {
1941
+ ideOptions.push({
1942
+ cmd: "cursor",
1943
+ label: "Cursor",
1944
+ hint: copiedToClipboard ? "Opens project \u2014 paste /flydocs-setup from clipboard" : "Opens project \u2014 run /flydocs-setup in chat",
1945
+ passCommand: false
1946
+ });
1947
+ }
1948
+ if (isInstalled("code")) {
1949
+ ideOptions.push({
1950
+ cmd: "code",
1951
+ label: "VS Code",
1952
+ hint: copiedToClipboard ? "Opens project \u2014 paste /flydocs-setup from clipboard" : "Opens project \u2014 run /flydocs-setup in chat",
1953
+ passCommand: false
1906
1954
  });
1907
- if (!isCancel3(launchCursor) && launchCursor) {
1908
- spawn("cursor", [targetDir], {
1909
- stdio: "ignore",
1910
- detached: true
1911
- }).unref();
1912
- printInfo("Cursor opening \u2014 paste /flydocs-setup in the chat panel");
1955
+ }
1956
+ if (ideOptions.length === 1) {
1957
+ const ide = ideOptions[0];
1958
+ const launchConfirm = await confirm2({
1959
+ message: ide.passCommand ? `Open ${ide.label} and run /flydocs-setup now?` : `Open ${ide.label}?`
1960
+ });
1961
+ if (!isCancel3(launchConfirm) && launchConfirm) {
1962
+ if (ide.passCommand) {
1963
+ spawn(ide.cmd, ["/flydocs-setup"], {
1964
+ cwd: targetDir,
1965
+ stdio: "inherit"
1966
+ });
1967
+ return;
1968
+ } else {
1969
+ spawn(ide.cmd, [targetDir], {
1970
+ stdio: "ignore",
1971
+ detached: true
1972
+ }).unref();
1973
+ printInfo(
1974
+ `${ide.label} opening \u2014 paste /flydocs-setup in the chat panel`
1975
+ );
1976
+ }
1913
1977
  }
1914
- } else if (hasCode) {
1915
- const launchCode = await confirm2({
1916
- message: copiedToClipboard ? "Open VS Code? (paste /flydocs-setup from clipboard)" : "Open VS Code?"
1978
+ } else if (ideOptions.length > 1) {
1979
+ const options = [
1980
+ ...ideOptions.map((ide) => ({
1981
+ value: ide.cmd,
1982
+ label: ide.label,
1983
+ hint: ide.hint
1984
+ })),
1985
+ { value: "skip", label: "Skip", hint: "I'll open my IDE manually" }
1986
+ ];
1987
+ const choice = await select({
1988
+ message: "Open an IDE to run /flydocs-setup?",
1989
+ options
1917
1990
  });
1918
- if (!isCancel3(launchCode) && launchCode) {
1919
- spawn("code", [targetDir], {
1920
- stdio: "ignore",
1921
- detached: true
1922
- }).unref();
1923
- printInfo("VS Code opening \u2014 paste /flydocs-setup in the chat panel");
1991
+ if (!isCancel3(choice) && choice !== "skip") {
1992
+ const ide = ideOptions.find((o) => o.cmd === choice);
1993
+ if (ide) {
1994
+ if (ide.passCommand) {
1995
+ spawn(ide.cmd, ["/flydocs-setup"], {
1996
+ cwd: targetDir,
1997
+ stdio: "inherit"
1998
+ });
1999
+ return;
2000
+ } else {
2001
+ spawn(ide.cmd, [targetDir], {
2002
+ stdio: "ignore",
2003
+ detached: true
2004
+ }).unref();
2005
+ printInfo(
2006
+ `${ide.label} opening \u2014 paste /flydocs-setup in the chat panel`
2007
+ );
2008
+ }
2009
+ }
1924
2010
  }
1925
2011
  }
1926
2012
  } catch {
@@ -1943,9 +2029,9 @@ __export(update_exports, {
1943
2029
  default: () => update_default
1944
2030
  });
1945
2031
  import { defineCommand as defineCommand2 } from "citty";
1946
- import { resolve as resolve3, join as join12 } from "path";
2032
+ import { resolve as resolve3, join as join13 } from "path";
1947
2033
  import { mkdir as mkdir5, cp as cp2, readFile as readFile8, readdir as readdir3, rm as rm4 } from "fs/promises";
1948
- import { select, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
2034
+ import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
1949
2035
  import pc6 from "picocolors";
1950
2036
  var update_default;
1951
2037
  var init_update = __esm({
@@ -2011,7 +2097,7 @@ var init_update = __esm({
2011
2097
  } else if (args.here) {
2012
2098
  targetDir = process.cwd();
2013
2099
  } else {
2014
- const choice = await select({
2100
+ const choice = await select2({
2015
2101
  message: "Which project would you like to update?",
2016
2102
  options: [
2017
2103
  {
@@ -2049,9 +2135,9 @@ var init_update = __esm({
2049
2135
  }
2050
2136
  targetDir = resolve3(targetDir);
2051
2137
  process.chdir(targetDir);
2052
- const hasVersion = await pathExists(join12(targetDir, ".flydocs", "version"));
2138
+ const hasVersion = await pathExists(join13(targetDir, ".flydocs", "version"));
2053
2139
  const hasConfig = await pathExists(
2054
- join12(targetDir, ".flydocs", "config.json")
2140
+ join13(targetDir, ".flydocs", "config.json")
2055
2141
  );
2056
2142
  if (!hasVersion && !hasConfig) {
2057
2143
  printError(`Not a FlyDocs project: ${targetDir}`);
@@ -2063,7 +2149,7 @@ var init_update = __esm({
2063
2149
  let currentVersion = "0.1.0";
2064
2150
  if (hasVersion) {
2065
2151
  const vContent = await readFile8(
2066
- join12(targetDir, ".flydocs", "version"),
2152
+ join13(targetDir, ".flydocs", "version"),
2067
2153
  "utf-8"
2068
2154
  );
2069
2155
  currentVersion = vContent.trim();
@@ -2091,7 +2177,7 @@ var init_update = __esm({
2091
2177
  }
2092
2178
  console.log(`Updating: v${currentVersion} \u2192 v${version}`);
2093
2179
  console.log();
2094
- const changelogPath = join12(templateDir, "CHANGELOG.md");
2180
+ const changelogPath = join13(templateDir, "CHANGELOG.md");
2095
2181
  const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
2096
2182
  if (whatsNew.length > 0) {
2097
2183
  console.log(pc6.cyan("What's new:"));
@@ -2103,23 +2189,23 @@ var init_update = __esm({
2103
2189
  }
2104
2190
  const now = /* @__PURE__ */ new Date();
2105
2191
  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")}`;
2106
- const backupDir = join12(targetDir, ".flydocs", `backup-${ts}`);
2192
+ const backupDir = join13(targetDir, ".flydocs", `backup-${ts}`);
2107
2193
  await mkdir5(backupDir, { recursive: true });
2108
2194
  if (hasConfig) {
2109
2195
  await cp2(
2110
- join12(targetDir, ".flydocs", "config.json"),
2111
- join12(backupDir, "config.json")
2196
+ join13(targetDir, ".flydocs", "config.json"),
2197
+ join13(backupDir, "config.json")
2112
2198
  );
2113
2199
  printStatus(`Config backed up to .flydocs/backup-${ts}/`);
2114
2200
  }
2115
2201
  try {
2116
- const flydocsDir = join12(targetDir, ".flydocs");
2202
+ const flydocsDir = join13(targetDir, ".flydocs");
2117
2203
  const entries = await readdir3(flydocsDir);
2118
2204
  const backups = entries.filter((e) => e.startsWith("backup-")).sort();
2119
2205
  if (backups.length > 3) {
2120
2206
  const toRemove = backups.slice(0, backups.length - 3);
2121
2207
  for (const old of toRemove) {
2122
- await rm4(join12(flydocsDir, old), { recursive: true, force: true });
2208
+ await rm4(join13(flydocsDir, old), { recursive: true, force: true });
2123
2209
  }
2124
2210
  }
2125
2211
  } catch {
@@ -2132,7 +2218,6 @@ var init_update = __esm({
2132
2218
  issueLabels: {},
2133
2219
  statusMapping: {},
2134
2220
  detectedStack: {},
2135
- mcp: {},
2136
2221
  skills: {},
2137
2222
  designSystem: null,
2138
2223
  aiLabor: {}
@@ -2157,72 +2242,72 @@ var init_update = __esm({
2157
2242
  }
2158
2243
  console.log("Replacing framework directories...");
2159
2244
  await replaceDirectory(
2160
- join12(templateDir, ".flydocs", "templates"),
2161
- join12(targetDir, ".flydocs", "templates")
2245
+ join13(templateDir, ".flydocs", "templates"),
2246
+ join13(targetDir, ".flydocs", "templates")
2162
2247
  );
2163
2248
  await replaceDirectory(
2164
- join12(templateDir, ".flydocs", "hooks"),
2165
- join12(targetDir, ".flydocs", "hooks")
2249
+ join13(templateDir, ".flydocs", "hooks"),
2250
+ join13(targetDir, ".flydocs", "hooks")
2166
2251
  );
2167
2252
  await replaceDirectory(
2168
- join12(templateDir, ".flydocs", "scripts"),
2169
- join12(targetDir, ".flydocs", "scripts")
2253
+ join13(templateDir, ".flydocs", "scripts"),
2254
+ join13(targetDir, ".flydocs", "scripts")
2170
2255
  );
2171
2256
  printStatus(".flydocs/templates, hooks, scripts");
2172
- const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
2257
+ const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
2173
2258
  if (await pathExists(claudeAgentsSrc)) {
2174
2259
  await copyDirectoryContents(
2175
2260
  claudeAgentsSrc,
2176
- join12(targetDir, ".claude", "agents")
2261
+ join13(targetDir, ".claude", "agents")
2177
2262
  );
2178
2263
  }
2179
2264
  printStatus(".claude/agents");
2180
2265
  await replaceOwnedSkills(templateDir, targetDir, effectiveTier);
2181
2266
  printStatus(`.claude/skills (tier: ${effectiveTier})`);
2182
- const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
2267
+ const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
2183
2268
  if (await pathExists(cursorAgentsSrc)) {
2184
2269
  await copyDirectoryContents(
2185
2270
  cursorAgentsSrc,
2186
- join12(targetDir, ".cursor", "agents")
2271
+ join13(targetDir, ".cursor", "agents")
2187
2272
  );
2188
2273
  }
2189
2274
  printStatus(".cursor/agents");
2190
2275
  console.log();
2191
2276
  console.log("Replacing framework files...");
2192
2277
  await copyFile(
2193
- join12(templateDir, ".claude", "CLAUDE.md"),
2194
- join12(targetDir, ".claude", "CLAUDE.md")
2278
+ join13(templateDir, ".claude", "CLAUDE.md"),
2279
+ join13(targetDir, ".claude", "CLAUDE.md")
2195
2280
  );
2196
2281
  await copyFile(
2197
- join12(templateDir, ".claude", "settings.json"),
2198
- join12(targetDir, ".claude", "settings.json")
2282
+ join13(templateDir, ".claude", "settings.json"),
2283
+ join13(targetDir, ".claude", "settings.json")
2199
2284
  );
2200
2285
  printStatus(".claude/CLAUDE.md, settings.json");
2201
2286
  await copyDirectoryContents(
2202
- join12(templateDir, ".claude", "commands"),
2203
- join12(targetDir, ".claude", "commands")
2287
+ join13(templateDir, ".claude", "commands"),
2288
+ join13(targetDir, ".claude", "commands")
2204
2289
  );
2205
2290
  await copyDirectoryContents(
2206
- join12(templateDir, ".claude", "commands"),
2207
- join12(targetDir, ".cursor", "commands")
2291
+ join13(templateDir, ".claude", "commands"),
2292
+ join13(targetDir, ".cursor", "commands")
2208
2293
  );
2209
2294
  printStatus(".claude/commands, .cursor/commands");
2210
- const skillsReadmeSrc = join12(templateDir, ".claude", "skills", "README.md");
2295
+ const skillsReadmeSrc = join13(templateDir, ".claude", "skills", "README.md");
2211
2296
  if (await pathExists(skillsReadmeSrc)) {
2212
2297
  await copyFile(
2213
2298
  skillsReadmeSrc,
2214
- join12(targetDir, ".claude", "skills", "README.md")
2299
+ join13(targetDir, ".claude", "skills", "README.md")
2215
2300
  );
2216
2301
  }
2217
2302
  printStatus(".claude/skills/README.md");
2218
2303
  await copyFile(
2219
- join12(templateDir, ".cursor", "hooks.json"),
2220
- join12(targetDir, ".cursor", "hooks.json")
2304
+ join13(templateDir, ".cursor", "hooks.json"),
2305
+ join13(targetDir, ".cursor", "hooks.json")
2221
2306
  );
2222
2307
  printStatus(".cursor/hooks.json");
2223
2308
  await copyFile(
2224
- join12(templateDir, "AGENTS.md"),
2225
- join12(targetDir, "AGENTS.md")
2309
+ join13(templateDir, "AGENTS.md"),
2310
+ join13(targetDir, "AGENTS.md")
2226
2311
  );
2227
2312
  printStatus("AGENTS.md");
2228
2313
  await runManifestGeneration(targetDir);
@@ -2247,18 +2332,18 @@ var init_update = __esm({
2247
2332
  printWarning("Config merge failed \u2014 config.json preserved as-is");
2248
2333
  }
2249
2334
  await copyFile(
2250
- join12(templateDir, ".flydocs", "version"),
2251
- join12(targetDir, ".flydocs", "version")
2335
+ join13(templateDir, ".flydocs", "version"),
2336
+ join13(targetDir, ".flydocs", "version")
2252
2337
  );
2253
2338
  printStatus(`.flydocs/version \u2192 ${version}`);
2254
- const clSrc = join12(templateDir, "CHANGELOG.md");
2339
+ const clSrc = join13(templateDir, "CHANGELOG.md");
2255
2340
  if (await pathExists(clSrc)) {
2256
- await copyFile(clSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
2341
+ await copyFile(clSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
2257
2342
  printStatus(".flydocs/CHANGELOG.md");
2258
2343
  }
2259
- const mfSrc = join12(templateDir, "manifest.json");
2344
+ const mfSrc = join13(templateDir, "manifest.json");
2260
2345
  if (await pathExists(mfSrc)) {
2261
- await copyFile(mfSrc, join12(targetDir, ".flydocs", "manifest.json"));
2346
+ await copyFile(mfSrc, join13(targetDir, ".flydocs", "manifest.json"));
2262
2347
  printStatus(".flydocs/manifest.json");
2263
2348
  }
2264
2349
  console.log();
@@ -2312,18 +2397,32 @@ __export(setup_exports, {
2312
2397
  default: () => setup_default
2313
2398
  });
2314
2399
  import { defineCommand as defineCommand3 } from "citty";
2400
+ import pc7 from "picocolors";
2315
2401
  var setup_default;
2316
2402
  var init_setup = __esm({
2317
2403
  "src/commands/setup.ts"() {
2318
2404
  "use strict";
2319
- init_ui();
2320
2405
  setup_default = defineCommand3({
2321
2406
  meta: {
2322
2407
  name: "setup",
2323
2408
  description: "Configure FlyDocs settings for this project"
2324
2409
  },
2325
2410
  run() {
2326
- printStub("flydocs setup");
2411
+ console.log();
2412
+ console.log(` ${pc7.bold("FlyDocs Setup")}`);
2413
+ console.log();
2414
+ console.log(` Setup runs inside your IDE as an interactive AI command.`);
2415
+ console.log();
2416
+ console.log(
2417
+ ` ${pc7.cyan("Claude Code:")} Type ${pc7.bold("/flydocs-setup")} in chat`
2418
+ );
2419
+ console.log(
2420
+ ` ${pc7.cyan("Cursor:")} Type ${pc7.bold("/flydocs-setup")} in chat`
2421
+ );
2422
+ console.log();
2423
+ console.log(` This configures your project context, detects your stack,`);
2424
+ console.log(` and installs community skills tailored to your codebase.`);
2425
+ console.log();
2327
2426
  }
2328
2427
  });
2329
2428
  }
@@ -2335,7 +2434,7 @@ __export(skills_exports, {
2335
2434
  default: () => skills_default
2336
2435
  });
2337
2436
  import { defineCommand as defineCommand4 } from "citty";
2338
- import pc7 from "picocolors";
2437
+ import pc8 from "picocolors";
2339
2438
  var list, search, add, remove, skills_default;
2340
2439
  var init_skills2 = __esm({
2341
2440
  "src/commands/skills.ts"() {
@@ -2357,19 +2456,19 @@ var init_skills2 = __esm({
2357
2456
  console.log(`${total} skill(s) installed:`);
2358
2457
  if (result.platform.length > 0) {
2359
2458
  console.log();
2360
- console.log(pc7.bold("Platform"));
2459
+ console.log(pc8.bold("Platform"));
2361
2460
  for (const skill of result.platform) {
2362
2461
  console.log(
2363
- ` ${skill.name} ${pc7.dim(`(${skill.triggers} triggers)`)}`
2462
+ ` ${skill.name} ${pc8.dim(`(${skill.triggers} triggers)`)}`
2364
2463
  );
2365
2464
  }
2366
2465
  }
2367
2466
  if (result.community.length > 0) {
2368
2467
  console.log();
2369
- console.log(pc7.bold("Community"));
2468
+ console.log(pc8.bold("Community"));
2370
2469
  for (const skill of result.community) {
2371
2470
  console.log(
2372
- ` ${skill.name} ${pc7.dim(`(${skill.triggers} triggers)`)}`
2471
+ ` ${skill.name} ${pc8.dim(`(${skill.triggers} triggers)`)}`
2373
2472
  );
2374
2473
  }
2375
2474
  }
@@ -2392,18 +2491,18 @@ var init_skills2 = __esm({
2392
2491
  const results = await searchCatalog(args.keyword);
2393
2492
  if (results.length === 0) {
2394
2493
  console.log(`No skills found for "${args.keyword}".`);
2395
- console.log(` Browse the catalog at: ${pc7.cyan("https://skills.sh/")}`);
2494
+ console.log(` Browse the catalog at: ${pc8.cyan("https://skills.sh/")}`);
2396
2495
  return;
2397
2496
  }
2398
2497
  console.log();
2399
2498
  console.log(`${results.length} skill(s) matching "${args.keyword}":`);
2400
2499
  console.log();
2401
2500
  for (const skill of results) {
2402
- console.log(` ${pc7.bold(skill.name)}`);
2501
+ console.log(` ${pc8.bold(skill.name)}`);
2403
2502
  console.log(` ${skill.description}`);
2404
- console.log(` ${pc7.dim(skill.repo)}`);
2503
+ console.log(` ${pc8.dim(skill.repo)}`);
2405
2504
  if (skill.tags.length > 0) {
2406
- console.log(` ${pc7.dim(skill.tags.join(", "))}`);
2505
+ console.log(` ${pc8.dim(skill.tags.join(", "))}`);
2407
2506
  }
2408
2507
  console.log();
2409
2508
  }
@@ -2463,10 +2562,9 @@ __export(connect_exports, {
2463
2562
  });
2464
2563
  import { defineCommand as defineCommand5 } from "citty";
2465
2564
  import { text as text2, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2466
- import pc8 from "picocolors";
2565
+ import pc9 from "picocolors";
2467
2566
  import { readFile as readFile9, writeFile as writeFile5, appendFile as appendFile2 } from "fs/promises";
2468
- import { join as join13 } from "path";
2469
- import { execSync as execSync2 } from "child_process";
2567
+ import { join as join14 } from "path";
2470
2568
  var connect_default;
2471
2569
  var init_connect = __esm({
2472
2570
  "src/commands/connect.ts"() {
@@ -2500,11 +2598,11 @@ var init_connect = __esm({
2500
2598
  },
2501
2599
  async run({ args }) {
2502
2600
  const targetDir = args.path ?? process.cwd();
2503
- const configPath = join13(targetDir, ".flydocs", "config.json");
2601
+ const configPath = join14(targetDir, ".flydocs", "config.json");
2504
2602
  if (!await pathExists(configPath)) {
2505
2603
  printError("Not a FlyDocs project (.flydocs/config.json not found).");
2506
2604
  console.log(
2507
- ` Run ${pc8.cyan("flydocs")} first to install FlyDocs in this project.`
2605
+ ` Run ${pc9.cyan("flydocs")} first to install FlyDocs in this project.`
2508
2606
  );
2509
2607
  process.exit(1);
2510
2608
  }
@@ -2521,10 +2619,10 @@ var init_connect = __esm({
2521
2619
  }
2522
2620
  }
2523
2621
  console.log();
2524
- console.log(` ${pc8.bold("Connect to Linear")}`);
2622
+ console.log(` ${pc9.bold("Connect to Linear")}`);
2525
2623
  console.log();
2526
2624
  console.log(
2527
- ` ${pc8.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
2625
+ ` ${pc9.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
2528
2626
  );
2529
2627
  console.log();
2530
2628
  let apiKey = args.key ?? "";
@@ -2547,27 +2645,31 @@ var init_connect = __esm({
2547
2645
  }
2548
2646
  printInfo("Validating API key...");
2549
2647
  try {
2550
- const result = execSync2(
2551
- `python3 -c "
2552
- import urllib.request, json
2553
- req = urllib.request.Request('https://api.linear.app/graphql',
2554
- data=json.dumps({'query': '{ viewer { id name email } }'}).encode(),
2555
- headers={'Authorization': '${apiKey}', 'Content-Type': 'application/json'})
2556
- res = urllib.request.urlopen(req)
2557
- data = json.loads(res.read())
2558
- print(json.dumps(data['data']['viewer']))
2559
- "`,
2560
- { encoding: "utf-8", timeout: 15e3 }
2561
- );
2562
- const viewer = JSON.parse(result.trim());
2563
- printStatus(`Authenticated as ${pc8.bold(viewer.name)} (${viewer.email})`);
2648
+ const response = await fetch("https://api.linear.app/graphql", {
2649
+ method: "POST",
2650
+ headers: {
2651
+ Authorization: apiKey,
2652
+ "Content-Type": "application/json"
2653
+ },
2654
+ body: JSON.stringify({ query: "{ viewer { id name email } }" }),
2655
+ signal: AbortSignal.timeout(15e3)
2656
+ });
2657
+ if (!response.ok) {
2658
+ throw new Error(`HTTP ${response.status}`);
2659
+ }
2660
+ const data = await response.json();
2661
+ if (!data.data?.viewer) {
2662
+ throw new Error("Invalid response");
2663
+ }
2664
+ const viewer = data.data.viewer;
2665
+ printStatus(`Authenticated as ${pc9.bold(viewer.name)} (${viewer.email})`);
2564
2666
  } catch {
2565
2667
  printError("Invalid API key or network error.");
2566
2668
  console.log(` Check your key and try again.`);
2567
2669
  process.exit(1);
2568
2670
  }
2569
- const envPath = join13(targetDir, ".env");
2570
- const envLocalPath = join13(targetDir, ".env.local");
2671
+ const envPath = join14(targetDir, ".env");
2672
+ const envLocalPath = join14(targetDir, ".env.local");
2571
2673
  const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
2572
2674
  if (await pathExists(targetEnvPath)) {
2573
2675
  const envContent = await readFile9(targetEnvPath, "utf-8");
@@ -2587,7 +2689,7 @@ LINEAR_API_KEY=${apiKey}
2587
2689
  `, "utf-8");
2588
2690
  }
2589
2691
  printStatus(
2590
- `API key stored in ${pc8.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
2692
+ `API key stored in ${pc9.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
2591
2693
  );
2592
2694
  const wasLocal = config.tier === "local";
2593
2695
  config.tier = "cloud";
@@ -2600,14 +2702,14 @@ LINEAR_API_KEY=${apiKey}
2600
2702
  const templateDir = await resolveTemplatePath(
2601
2703
  args["local-source"] || void 0
2602
2704
  );
2603
- const templateSkillsDir = join13(templateDir, ".claude", "skills");
2604
- const skillsDir = join13(targetDir, ".claude", "skills");
2705
+ const templateSkillsDir = join14(templateDir, ".claude", "skills");
2706
+ const skillsDir = join14(targetDir, ".claude", "skills");
2605
2707
  await replaceDirectory(
2606
- join13(templateSkillsDir, "flydocs-cloud"),
2607
- join13(skillsDir, "flydocs-cloud")
2708
+ join14(templateSkillsDir, "flydocs-cloud"),
2709
+ join14(skillsDir, "flydocs-cloud")
2608
2710
  );
2609
2711
  const { rm: rm5 } = await import("fs/promises");
2610
- const localSkillDir = join13(skillsDir, "flydocs-local");
2712
+ const localSkillDir = join14(skillsDir, "flydocs-local");
2611
2713
  if (await pathExists(localSkillDir)) {
2612
2714
  await rm5(localSkillDir, { recursive: true, force: true });
2613
2715
  }
@@ -2620,14 +2722,14 @@ LINEAR_API_KEY=${apiKey}
2620
2722
  }
2621
2723
  console.log();
2622
2724
  console.log(
2623
- ` ${pc8.bold("Connected!")} Your project now syncs with Linear.`
2725
+ ` ${pc9.bold("Connected!")} Your project now syncs with Linear.`
2624
2726
  );
2625
2727
  console.log();
2626
2728
  console.log(` Next steps:`);
2627
2729
  console.log(
2628
- ` 1. Run ${pc8.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
2730
+ ` 1. Run ${pc9.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
2629
2731
  );
2630
- console.log(` 2. Run ${pc8.cyan("/start-session")} to begin working`);
2732
+ console.log(` 2. Run ${pc9.cyan("/start-session")} to begin working`);
2631
2733
  console.log();
2632
2734
  }
2633
2735
  });
@@ -2640,7 +2742,7 @@ __export(upgrade_exports, {
2640
2742
  default: () => upgrade_default
2641
2743
  });
2642
2744
  import { defineCommand as defineCommand6 } from "citty";
2643
- import pc9 from "picocolors";
2745
+ import pc10 from "picocolors";
2644
2746
  var upgrade_default;
2645
2747
  var init_upgrade = __esm({
2646
2748
  "src/commands/upgrade.ts"() {
@@ -2676,37 +2778,37 @@ var init_upgrade = __esm({
2676
2778
  console.log();
2677
2779
  if (currentTier === "cloud") {
2678
2780
  console.log(
2679
- ` ${pc9.green("\u2713")} You're already on the ${pc9.bold("cloud")} tier.`
2781
+ ` ${pc10.green("\u2713")} You're already on the ${pc10.bold("cloud")} tier.`
2680
2782
  );
2681
2783
  console.log();
2682
2784
  console.log(
2683
2785
  ` Your issues sync with Linear via the cloud mechanism skill.`
2684
2786
  );
2685
2787
  console.log(
2686
- ` Run ${pc9.cyan("flydocs connect")} to update your connection settings.`
2788
+ ` Run ${pc10.cyan("flydocs connect")} to update your connection settings.`
2687
2789
  );
2688
2790
  console.log();
2689
2791
  return;
2690
2792
  }
2691
- console.log(` ${pc9.bold("FlyDocs Cloud Tier")}`);
2793
+ console.log(` ${pc10.bold("FlyDocs Cloud Tier")}`);
2692
2794
  console.log();
2693
- console.log(` You're currently on the ${pc9.yellow("local")} tier.`);
2795
+ console.log(` You're currently on the ${pc10.yellow("local")} tier.`);
2694
2796
  console.log(` Upgrade to cloud for:`);
2695
2797
  console.log();
2696
2798
  console.log(
2697
- ` ${pc9.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2799
+ ` ${pc10.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2698
2800
  );
2699
- console.log(` ${pc9.cyan("\u2192")} Project milestones and cycle management`);
2700
- console.log(` ${pc9.cyan("\u2192")} Team assignment and priority tracking`);
2701
- console.log(` ${pc9.cyan("\u2192")} Project health updates and dashboards`);
2702
- console.log(` ${pc9.cyan("\u2192")} Cross-project issue linking`);
2801
+ console.log(` ${pc10.cyan("\u2192")} Project milestones and cycle management`);
2802
+ console.log(` ${pc10.cyan("\u2192")} Team assignment and priority tracking`);
2803
+ console.log(` ${pc10.cyan("\u2192")} Project health updates and dashboards`);
2804
+ console.log(` ${pc10.cyan("\u2192")} Cross-project issue linking`);
2703
2805
  console.log();
2704
- console.log(` ${pc9.bold("How to upgrade:")}`);
2806
+ console.log(` ${pc10.bold("How to upgrade:")}`);
2705
2807
  console.log();
2706
- console.log(` 1. Sign up at ${pc9.cyan("https://www.flydocs.ai")}`);
2808
+ console.log(` 1. Sign up at ${pc10.cyan("https://www.flydocs.ai")}`);
2707
2809
  console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
2708
2810
  console.log(
2709
- ` 3. Run ${pc9.cyan("flydocs connect")} to connect your project`
2811
+ ` 3. Run ${pc10.cyan("flydocs connect")} to connect your project`
2710
2812
  );
2711
2813
  console.log();
2712
2814
  }
@@ -2720,8 +2822,8 @@ __export(self_update_exports, {
2720
2822
  default: () => self_update_default
2721
2823
  });
2722
2824
  import { defineCommand as defineCommand7 } from "citty";
2723
- import { execSync as execSync3 } from "child_process";
2724
- import pc10 from "picocolors";
2825
+ import { execSync } from "child_process";
2826
+ import pc11 from "picocolors";
2725
2827
  var self_update_default;
2726
2828
  var init_self_update = __esm({
2727
2829
  "src/commands/self-update.ts"() {
@@ -2735,10 +2837,10 @@ var init_self_update = __esm({
2735
2837
  },
2736
2838
  async run() {
2737
2839
  console.log();
2738
- console.log(` Updating ${pc10.cyan(PACKAGE_NAME)}...`);
2840
+ console.log(` Updating ${pc11.cyan(PACKAGE_NAME)}...`);
2739
2841
  console.log();
2740
2842
  try {
2741
- execSync3(`npm install -g ${PACKAGE_NAME}@beta`, {
2843
+ execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
2742
2844
  stdio: "inherit",
2743
2845
  timeout: 6e4
2744
2846
  });