@flydocs/cli 0.5.0-beta.1 → 0.5.0-beta.11

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.1";
18
+ CLI_VERSION = "0.5.0-beta.11";
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}\x07${text3}\x1B]8;;\x07`;
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(` ${bold(pink("\u2588\u2588\u2588\u2588\u2588\u2588"))}`);
164
+ console.log(` ${pinkBlock12}`);
165
+ console.log(` ${pinkBlock12}`);
166
+ console.log(` ${pinkBlock4}`);
162
167
  console.log(
163
- ` ${bold(pink("\u2588\u2588"))} ${bold(purple("\u2588\u2588\u2588\u2588\u2588\u2588"))} ${bold(pink("Fly"))}${bold(purple("Docs"))} ${bold(pink("Core"))}`
168
+ ` ${pinkBlock4} ${purpleBlock12} ${bold("FlyDocs")} ${dim("(Beta)")}`
164
169
  );
165
170
  console.log(
166
- ` ${bold(purple("\u2588\u2588\u2588\u2588\u2588\u2588"))} ${dim("Context-as-a-Service Platform Built for Engineering at Altitude")}`
171
+ ` ${purpleBlock12} ${dim("Spec-Driven Context That Helps Engineers Fly")}`
167
172
  );
168
- console.log(` ${bold(purple("\u2588\u2588"))}`);
169
- console.log(` ${bold(purple("\u2588\u2588"))} ${dim(`v${version}`)}`);
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, priority support, and more.")}`
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(` ${hyperlink(pc2.cyan("https://www.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 [...OWNED_SKILLS, ...SUPPORTING_SKILLS]) {
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
- for (const skill of PREMIUM_CURSOR_RULES) {
383
- const skillRule = join4(
384
- targetDir,
385
- ".claude",
386
- "skills",
387
- skill,
388
- "cursor-rule.mdc"
389
- );
390
- if (await pathExists(skillRule)) {
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, SUPPORTING_SKILLS, MECHANISM_SKILLS, PREMIUM_CURSOR_RULES;
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((s) => ["nextjs", "react", "expo"].includes(s)),
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((s) => ["typescript"].includes(s)),
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 { execSync } from "child_process";
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
- execSync(`python3 "${scriptPath}"`, {
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
- execSync(`python3 "${scriptPath}"`, {
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
- if (suggestions.length === 0) {
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 = suggestions;
1019
+ selected = filtered;
945
1020
  console.log(" Auto-accepting all (--yes)");
946
1021
  } else {
947
- const options = suggestions.map((s) => ({
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: "tailwind",
1026
- repo: "blencorp/claude-code-kit",
1027
- name: "tailwind-v4",
1028
- description: "Tailwind CSS v4 patterns and configuration"
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: "clerk",
1032
- repo: "blencorp/claude-code-kit",
1033
- name: "clerk-auth",
1034
- description: "Clerk authentication patterns"
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 join8 } from "path";
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(join8(targetDir, item))) {
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 = join8(targetDir, ".claude", "skills", skill);
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(join8(targetDir, dir))) {
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 = join8(targetDir, ".flydocs", "hooks", hook);
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 = join8(targetDir, ".cursor", "rules", rule);
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 = join8(targetDir, ".cursor", "rules", dir);
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 = join8(targetDir, prefix, cmd);
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 = join8(targetDir, "flydocs", "context");
1092
- const legacyDir = join8(contextDir, "legacy");
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(join8(contextDir, f))) {
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 = join8(contextDir, f);
1220
+ const src = join9(contextDir, f);
1105
1221
  if (await pathExists(src)) {
1106
- await rename(src, join8(legacyDir, f));
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 = join8(targetDir, "flydocs", "context", "legacy");
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(join8(targetDir, p), { recursive: true, force: true });
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 = ["linear-auto-approve.py", "session-end.py"];
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 join9 } from "path";
1314
+ import { join as join10 } from "path";
1198
1315
  async function ensureGitignore(targetDir) {
1199
- const gitignorePath = join9(targetDir, ".gitignore");
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 = join9(targetDir, ".gitignore");
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 parts1 = v1.split(".").map(Number);
1298
- const parts2 = v2.split(".").map(Number);
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 join10 } from "path";
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(join10(homedir(), ".flydocs"), { recursive: true });
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 update -g ${PACKAGE_NAME}`)}`
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 = join10(homedir(), ".flydocs", "update-check.json");
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 join11 } from "path";
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(join11(targetDir, ".flydocs", "config.json"))) {
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 tierChoice = await select({
1530
- message: "Select your tier",
1531
- options: [
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(tierChoice)) {
1673
+ if (isCancel3(shouldInstall) || !shouldInstall) {
1545
1674
  cancel2("Installation cancelled.");
1546
1675
  process.exit(0);
1547
1676
  }
1548
- tier = tierChoice;
1677
+ tier = "local";
1549
1678
  console.log();
1550
1679
  }
1551
- if (!await pathExists(join11(targetDir, ".git"))) {
1552
- printError(
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
- join11(templateDir, ".flydocs", "templates"),
1561
- join11(targetDir, ".flydocs", "templates")
1686
+ join12(templateDir, ".flydocs", "templates"),
1687
+ join12(targetDir, ".flydocs", "templates")
1562
1688
  );
1563
1689
  await replaceDirectory(
1564
- join11(templateDir, ".flydocs", "hooks"),
1565
- join11(targetDir, ".flydocs", "hooks")
1690
+ join12(templateDir, ".flydocs", "hooks"),
1691
+ join12(targetDir, ".flydocs", "hooks")
1566
1692
  );
1567
1693
  await replaceDirectory(
1568
- join11(templateDir, ".flydocs", "scripts"),
1569
- join11(targetDir, ".flydocs", "scripts")
1694
+ join12(templateDir, ".flydocs", "scripts"),
1695
+ join12(targetDir, ".flydocs", "scripts")
1570
1696
  );
1571
1697
  await copyFile(
1572
- join11(templateDir, ".flydocs", "version"),
1573
- join11(targetDir, ".flydocs", "version")
1698
+ join12(templateDir, ".flydocs", "version"),
1699
+ join12(targetDir, ".flydocs", "version")
1574
1700
  );
1575
- const manifestSrc = join11(templateDir, "manifest.json");
1701
+ const manifestSrc = join12(templateDir, "manifest.json");
1576
1702
  if (await pathExists(manifestSrc)) {
1577
- await copyFile(manifestSrc, join11(targetDir, ".flydocs", "manifest.json"));
1703
+ await copyFile(manifestSrc, join12(targetDir, ".flydocs", "manifest.json"));
1578
1704
  }
1579
- const changelogSrc = join11(templateDir, "CHANGELOG.md");
1705
+ const changelogSrc = join12(templateDir, "CHANGELOG.md");
1580
1706
  if (await pathExists(changelogSrc)) {
1581
- await copyFile(changelogSrc, join11(targetDir, ".flydocs", "CHANGELOG.md"));
1707
+ await copyFile(changelogSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
1582
1708
  }
1583
1709
  printStatus(".flydocs/templates, hooks, version, manifest, changelog");
1584
- const configPath = join11(targetDir, ".flydocs", "config.json");
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 = join11(templateDir, ".claude", "agents");
1736
+ const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
1611
1737
  if (await pathExists(claudeAgentsSrc)) {
1612
1738
  await copyDirectoryContents(
1613
1739
  claudeAgentsSrc,
1614
- join11(targetDir, ".claude", "agents")
1740
+ join12(targetDir, ".claude", "agents")
1615
1741
  );
1616
1742
  }
1617
1743
  await copyDirectoryContents(
1618
- join11(templateDir, ".claude", "commands"),
1619
- join11(targetDir, ".claude", "commands")
1744
+ join12(templateDir, ".claude", "commands"),
1745
+ join12(targetDir, ".claude", "commands")
1620
1746
  );
1621
1747
  await copyFile(
1622
- join11(templateDir, ".claude", "CLAUDE.md"),
1623
- join11(targetDir, ".claude", "CLAUDE.md")
1748
+ join12(templateDir, ".claude", "CLAUDE.md"),
1749
+ join12(targetDir, ".claude", "CLAUDE.md")
1624
1750
  );
1625
1751
  await copyFile(
1626
- join11(templateDir, ".claude", "settings.json"),
1627
- join11(targetDir, ".claude", "settings.json")
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 = join11(templateDir, ".cursor", "agents");
1756
+ const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
1631
1757
  if (await pathExists(cursorAgentsSrc)) {
1632
1758
  await copyDirectoryContents(
1633
1759
  cursorAgentsSrc,
1634
- join11(targetDir, ".cursor", "agents")
1760
+ join12(targetDir, ".cursor", "agents")
1635
1761
  );
1636
1762
  }
1637
1763
  await copyDirectoryContents(
1638
- join11(templateDir, ".claude", "commands"),
1639
- join11(targetDir, ".cursor", "commands")
1764
+ join12(templateDir, ".claude", "commands"),
1765
+ join12(targetDir, ".cursor", "commands")
1640
1766
  );
1641
1767
  await copyFile(
1642
- join11(templateDir, ".cursor", "hooks.json"),
1643
- join11(targetDir, ".cursor", "hooks.json")
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
- join11(templateDir, "AGENTS.md"),
1659
- join11(targetDir, "AGENTS.md")
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: join11(templateDir, "flydocs", "context", "project.md"),
1669
- dest: join11(targetDir, "flydocs", "context", "project.md"),
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: join11(templateDir, "flydocs", "knowledge", "INDEX.md"),
1674
- dest: join11(targetDir, "flydocs", "knowledge", "INDEX.md"),
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: join11(templateDir, "flydocs", "knowledge", "README.md"),
1679
- dest: join11(targetDir, "flydocs", "knowledge", "README.md"),
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: join11(
1800
+ src: join12(
1684
1801
  templateDir,
1685
1802
  "flydocs",
1686
1803
  "knowledge",
1687
1804
  "product",
1688
1805
  "personas.md"
1689
1806
  ),
1690
- dest: join11(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1807
+ dest: join12(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1691
1808
  label: "flydocs/knowledge/product/personas.md"
1692
1809
  },
1693
1810
  {
1694
- src: join11(
1811
+ src: join12(
1695
1812
  templateDir,
1696
1813
  "flydocs",
1697
1814
  "knowledge",
1698
1815
  "product",
1699
1816
  "user-flows.md"
1700
1817
  ),
1701
- dest: join11(
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: join11(templateDir, "flydocs", "design-system", "README.md"),
1712
- dest: join11(targetDir, "flydocs", "design-system", "README.md"),
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: join11(
1833
+ src: join12(
1717
1834
  templateDir,
1718
1835
  "flydocs",
1719
1836
  "design-system",
1720
1837
  "component-patterns.md"
1721
1838
  ),
1722
- dest: join11(
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: join11(templateDir, "flydocs", "design-system", "token-mapping.md"),
1732
- dest: join11(targetDir, "flydocs", "design-system", "token-mapping.md"),
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: join11(templateDir, "flydocs", "README.md"),
1737
- dest: join11(targetDir, "flydocs", "README.md"),
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 = join11(templateDir, ".env.example");
1868
+ const envExampleSrc = join12(templateDir, ".env.example");
1752
1869
  if (await pathExists(envExampleSrc)) {
1753
- const hasEnv = await pathExists(join11(targetDir, ".env"));
1754
- const hasEnvExample = await pathExists(join11(targetDir, ".env.example"));
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 join12 } from "path";
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 confirm2, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
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(join12(targetDir, ".flydocs", "version"));
2147
+ const hasVersion = await pathExists(join13(targetDir, ".flydocs", "version"));
1927
2148
  const hasConfig = await pathExists(
1928
- join12(targetDir, ".flydocs", "config.json")
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
- join12(targetDir, ".flydocs", "version"),
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 confirm2({
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 = join12(templateDir, "CHANGELOG.md");
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 = join12(targetDir, ".flydocs", `backup-${ts}`);
2201
+ const backupDir = join13(targetDir, ".flydocs", `backup-${ts}`);
1981
2202
  await mkdir5(backupDir, { recursive: true });
1982
2203
  if (hasConfig) {
1983
2204
  await cp2(
1984
- join12(targetDir, ".flydocs", "config.json"),
1985
- join12(backupDir, "config.json")
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 = join12(targetDir, ".flydocs");
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(join12(flydocsDir, old), { recursive: true, force: true });
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
- join12(templateDir, ".flydocs", "templates"),
2035
- join12(targetDir, ".flydocs", "templates")
2254
+ join13(templateDir, ".flydocs", "templates"),
2255
+ join13(targetDir, ".flydocs", "templates")
2036
2256
  );
2037
2257
  await replaceDirectory(
2038
- join12(templateDir, ".flydocs", "hooks"),
2039
- join12(targetDir, ".flydocs", "hooks")
2258
+ join13(templateDir, ".flydocs", "hooks"),
2259
+ join13(targetDir, ".flydocs", "hooks")
2040
2260
  );
2041
2261
  await replaceDirectory(
2042
- join12(templateDir, ".flydocs", "scripts"),
2043
- join12(targetDir, ".flydocs", "scripts")
2262
+ join13(templateDir, ".flydocs", "scripts"),
2263
+ join13(targetDir, ".flydocs", "scripts")
2044
2264
  );
2045
2265
  printStatus(".flydocs/templates, hooks, scripts");
2046
- const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
2266
+ const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
2047
2267
  if (await pathExists(claudeAgentsSrc)) {
2048
2268
  await copyDirectoryContents(
2049
2269
  claudeAgentsSrc,
2050
- join12(targetDir, ".claude", "agents")
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 = join12(templateDir, ".cursor", "agents");
2276
+ const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
2057
2277
  if (await pathExists(cursorAgentsSrc)) {
2058
2278
  await copyDirectoryContents(
2059
2279
  cursorAgentsSrc,
2060
- join12(targetDir, ".cursor", "agents")
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
- join12(templateDir, ".claude", "CLAUDE.md"),
2068
- join12(targetDir, ".claude", "CLAUDE.md")
2287
+ join13(templateDir, ".claude", "CLAUDE.md"),
2288
+ join13(targetDir, ".claude", "CLAUDE.md")
2069
2289
  );
2070
2290
  await copyFile(
2071
- join12(templateDir, ".claude", "settings.json"),
2072
- join12(targetDir, ".claude", "settings.json")
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
- join12(templateDir, ".claude", "commands"),
2077
- join12(targetDir, ".claude", "commands")
2296
+ join13(templateDir, ".claude", "commands"),
2297
+ join13(targetDir, ".claude", "commands")
2078
2298
  );
2079
2299
  await copyDirectoryContents(
2080
- join12(templateDir, ".claude", "commands"),
2081
- join12(targetDir, ".cursor", "commands")
2300
+ join13(templateDir, ".claude", "commands"),
2301
+ join13(targetDir, ".cursor", "commands")
2082
2302
  );
2083
2303
  printStatus(".claude/commands, .cursor/commands");
2084
- const skillsReadmeSrc = join12(templateDir, ".claude", "skills", "README.md");
2304
+ const skillsReadmeSrc = join13(templateDir, ".claude", "skills", "README.md");
2085
2305
  if (await pathExists(skillsReadmeSrc)) {
2086
2306
  await copyFile(
2087
2307
  skillsReadmeSrc,
2088
- join12(targetDir, ".claude", "skills", "README.md")
2308
+ join13(targetDir, ".claude", "skills", "README.md")
2089
2309
  );
2090
2310
  }
2091
2311
  printStatus(".claude/skills/README.md");
2092
2312
  await copyFile(
2093
- join12(templateDir, ".cursor", "hooks.json"),
2094
- join12(targetDir, ".cursor", "hooks.json")
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
- join12(templateDir, "AGENTS.md"),
2099
- join12(targetDir, "AGENTS.md")
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
- join12(templateDir, ".flydocs", "version"),
2125
- join12(targetDir, ".flydocs", "version")
2349
+ join13(templateDir, ".flydocs", "version"),
2350
+ join13(targetDir, ".flydocs", "version")
2126
2351
  );
2127
2352
  printStatus(`.flydocs/version \u2192 ${version}`);
2128
- const clSrc = join12(templateDir, "CHANGELOG.md");
2353
+ const clSrc = join13(templateDir, "CHANGELOG.md");
2129
2354
  if (await pathExists(clSrc)) {
2130
- await copyFile(clSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
2355
+ await copyFile(clSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
2131
2356
  printStatus(".flydocs/CHANGELOG.md");
2132
2357
  }
2133
- const mfSrc = join12(templateDir, "manifest.json");
2358
+ const mfSrc = join13(templateDir, "manifest.json");
2134
2359
  if (await pathExists(mfSrc)) {
2135
- await copyFile(mfSrc, join12(targetDir, ".flydocs", "manifest.json"));
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
- printStub("flydocs setup");
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 pc7 from "picocolors";
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(pc7.bold("Platform"));
2473
+ console.log(pc8.bold("Platform"));
2235
2474
  for (const skill of result.platform) {
2236
2475
  console.log(
2237
- ` ${skill.name} ${pc7.dim(`(${skill.triggers} triggers)`)}`
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(pc7.bold("Community"));
2482
+ console.log(pc8.bold("Community"));
2244
2483
  for (const skill of result.community) {
2245
2484
  console.log(
2246
- ` ${skill.name} ${pc7.dim(`(${skill.triggers} triggers)`)}`
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: ${pc7.cyan("https://skills.sh/")}`);
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(` ${pc7.bold(skill.name)}`);
2515
+ console.log(` ${pc8.bold(skill.name)}`);
2277
2516
  console.log(` ${skill.description}`);
2278
- console.log(` ${pc7.dim(skill.repo)}`);
2517
+ console.log(` ${pc8.dim(skill.repo)}`);
2279
2518
  if (skill.tags.length > 0) {
2280
- console.log(` ${pc7.dim(skill.tags.join(", "))}`);
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 confirm3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2340
- import pc8 from "picocolors";
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 join13 } from "path";
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 = join13(targetDir, ".flydocs", "config.json");
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 ${pc8.cyan("flydocs")} first to install FlyDocs in this project.`
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 confirm3({
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(` ${pc8.bold("Connect to Linear")}`);
2636
+ console.log(` ${pc9.bold("Connect to Linear")}`);
2399
2637
  console.log();
2400
2638
  console.log(
2401
- ` ${pc8.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
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 result = execSync2(
2425
- `python3 -c "
2426
- import urllib.request, json
2427
- req = urllib.request.Request('https://api.linear.app/graphql',
2428
- data=json.dumps({'query': '{ viewer { id name email } }'}).encode(),
2429
- headers={'Authorization': '${apiKey}', 'Content-Type': 'application/json'})
2430
- res = urllib.request.urlopen(req)
2431
- data = json.loads(res.read())
2432
- print(json.dumps(data['data']['viewer']))
2433
- "`,
2434
- { encoding: "utf-8", timeout: 15e3 }
2435
- );
2436
- const viewer = JSON.parse(result.trim());
2437
- printStatus(`Authenticated as ${pc8.bold(viewer.name)} (${viewer.email})`);
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 = join13(targetDir, ".env");
2444
- const envLocalPath = join13(targetDir, ".env.local");
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 ${pc8.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
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 = join13(templateDir, ".claude", "skills");
2478
- const skillsDir = join13(targetDir, ".claude", "skills");
2719
+ const templateSkillsDir = join14(templateDir, ".claude", "skills");
2720
+ const skillsDir = join14(targetDir, ".claude", "skills");
2479
2721
  await replaceDirectory(
2480
- join13(templateSkillsDir, "flydocs-cloud"),
2481
- join13(skillsDir, "flydocs-cloud")
2722
+ join14(templateSkillsDir, "flydocs-cloud"),
2723
+ join14(skillsDir, "flydocs-cloud")
2482
2724
  );
2483
2725
  const { rm: rm5 } = await import("fs/promises");
2484
- const localSkillDir = join13(skillsDir, "flydocs-local");
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
- ` ${pc8.bold("Connected!")} Your project now syncs with Linear.`
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 ${pc8.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
2744
+ ` 1. Run ${pc9.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
2503
2745
  );
2504
- console.log(` 2. Run ${pc8.cyan("/start-session")} to begin working`);
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 pc9 from "picocolors";
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
- ` ${pc9.green("\u2713")} You're already on the ${pc9.bold("cloud")} tier.`
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 ${pc9.cyan("flydocs connect")} to update your connection settings.`
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(` ${pc9.bold("FlyDocs Cloud Tier")}`);
2807
+ console.log(` ${pc10.bold("FlyDocs Cloud Tier")}`);
2566
2808
  console.log();
2567
- console.log(` You're currently on the ${pc9.yellow("local")} tier.`);
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
- ` ${pc9.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2813
+ ` ${pc10.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2572
2814
  );
2573
- console.log(` ${pc9.cyan("\u2192")} Project milestones and cycle management`);
2574
- console.log(` ${pc9.cyan("\u2192")} Team assignment and priority tracking`);
2575
- console.log(` ${pc9.cyan("\u2192")} Project health updates and dashboards`);
2576
- console.log(` ${pc9.cyan("\u2192")} Cross-project issue linking`);
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(` ${pc9.bold("How to upgrade:")}`);
2820
+ console.log(` ${pc10.bold("How to upgrade:")}`);
2579
2821
  console.log();
2580
- console.log(` 1. Sign up at ${pc9.cyan("https://www.flydocs.ai")}`);
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 ${pc9.cyan("flydocs connect")} to connect your project`
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 as execSync3 } from "child_process";
2598
- import pc10 from "picocolors";
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 ${pc10.cyan(PACKAGE_NAME)}...`);
2854
+ console.log(` Updating ${pc11.cyan(PACKAGE_NAME)}...`);
2613
2855
  console.log();
2614
2856
  try {
2615
- execSync3(`npm update -g ${PACKAGE_NAME}`, {
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(`Update failed. Try manually: npm update -g ${PACKAGE_NAME}`);
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({