@flydocs/cli 0.6.0-alpha.1 → 0.6.0-alpha.3

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, POSTHOG_API_KEY;
15
15
  var init_constants = __esm({
16
16
  "src/lib/constants.ts"() {
17
17
  "use strict";
18
- CLI_VERSION = "0.6.0-alpha.1";
18
+ CLI_VERSION = "0.6.0-alpha.3";
19
19
  CLI_NAME = "flydocs";
20
20
  PACKAGE_NAME = "@flydocs/cli";
21
21
  POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
@@ -135,8 +135,8 @@ var init_template = __esm({
135
135
 
136
136
  // src/lib/ui.ts
137
137
  import pc2 from "picocolors";
138
- function shadow(text3) {
139
- return `\x1B[38;2;55;45;70m${text3}\x1B[0m`;
138
+ function shadow(text4) {
139
+ return `\x1B[38;2;55;45;70m${text4}\x1B[0m`;
140
140
  }
141
141
  function renderBannerBlock() {
142
142
  const height = BANNER_ROWS.length;
@@ -485,6 +485,18 @@ import {
485
485
  writeFile as writeFile2
486
486
  } from "fs/promises";
487
487
  import { join as join5, dirname as dirname2 } from "path";
488
+ async function detectExistingConfigs(targetDir) {
489
+ const existing = [];
490
+ const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
491
+ for (const relativePath of RESTORABLE_FILES) {
492
+ const filePath = join5(targetDir, relativePath);
493
+ const backupPath = join5(backupDir, relativePath);
494
+ if (await pathExists(filePath) && !await pathExists(backupPath)) {
495
+ existing.push(relativePath);
496
+ }
497
+ }
498
+ return existing;
499
+ }
488
500
  async function backupOriginals(targetDir, files = RESTORABLE_FILES) {
489
501
  const backedUp = [];
490
502
  const backupDir = join5(targetDir, BACKUP_ORIGINALS_DIR);
@@ -760,8 +772,8 @@ function flushFrontmatterValue(mode, lines) {
760
772
  return lines.join("\n").trim();
761
773
  }
762
774
  }
763
- function parseFrontmatter(text3) {
764
- const match = text3.match(/^---\s*\n([\s\S]*?)\n---/);
775
+ function parseFrontmatter(text4) {
776
+ const match = text4.match(/^---\s*\n([\s\S]*?)\n---/);
765
777
  if (!match) return null;
766
778
  const block = match[1];
767
779
  const result = {};
@@ -947,7 +959,8 @@ function searchCatalog(keyword) {
947
959
  return searchable.includes(lower);
948
960
  });
949
961
  }
950
- async function addSkill(targetDir, source) {
962
+ async function addSkill(targetDir, source, options) {
963
+ const quiet = options?.quiet ?? false;
951
964
  if (isPlatformSkill(source)) {
952
965
  printError(`Cannot install platform skill '${source}'.`);
953
966
  console.log(" Platform skills (flydocs-*) are managed by the installer.");
@@ -965,11 +978,13 @@ async function addSkill(targetDir, source) {
965
978
  console.log(` Remove first: flydocs skills remove ${skillName}`);
966
979
  return;
967
980
  }
968
- console.log();
969
- console.log(
970
- `${pc3.blue("->")} Installing ${pc3.cyan(skillName)} from ${repo}...`
971
- );
972
- console.log();
981
+ if (!quiet) {
982
+ console.log();
983
+ console.log(
984
+ `${pc3.blue("->")} Installing ${pc3.cyan(skillName)} from ${repo}...`
985
+ );
986
+ console.log();
987
+ }
973
988
  let success;
974
989
  try {
975
990
  success = await downloadSkillTree(repo, skillName, skillsDir);
@@ -1003,19 +1018,23 @@ async function addSkill(targetDir, source) {
1003
1018
  );
1004
1019
  return;
1005
1020
  }
1006
- if (!fm["triggers"]) {
1021
+ if (!fm["triggers"] && !quiet) {
1007
1022
  printWarning(
1008
1023
  "SKILL.md has no triggers -- skill won't appear in manifest index."
1009
1024
  );
1010
1025
  }
1011
- printStatus("Downloaded skill files");
1026
+ if (!quiet) {
1027
+ printStatus("Downloaded skill files");
1028
+ }
1012
1029
  const cursorRuleSrc = join8(skillsDir, "cursor-rule.mdc");
1013
1030
  if (await pathExists(cursorRuleSrc)) {
1014
1031
  const cursorRulesDir = join8(targetDir, ".cursor", "rules");
1015
1032
  await mkdir3(cursorRulesDir, { recursive: true });
1016
1033
  const cursorRuleDest = join8(cursorRulesDir, `${skillName}.mdc`);
1017
1034
  await copyFile(cursorRuleSrc, cursorRuleDest);
1018
- printStatus("Installed cursor rule");
1035
+ if (!quiet) {
1036
+ printStatus("Installed cursor rule");
1037
+ }
1019
1038
  }
1020
1039
  const config = await readConfig(targetDir);
1021
1040
  const installed = config.skills?.installed ?? [];
@@ -1027,12 +1046,16 @@ async function addSkill(targetDir, source) {
1027
1046
  }
1028
1047
  config.skills.installed = installed;
1029
1048
  await writeConfig(targetDir, config);
1030
- printStatus("Updated config.json");
1049
+ if (!quiet) {
1050
+ printStatus("Updated config.json");
1051
+ }
1031
1052
  }
1032
1053
  await runManifestGeneration(targetDir);
1033
- console.log();
1034
- printStatus(`Installed ${pc3.cyan(skillName)}`);
1035
- console.log();
1054
+ if (!quiet) {
1055
+ console.log();
1056
+ printStatus(`Installed ${pc3.cyan(skillName)}`);
1057
+ console.log();
1058
+ }
1036
1059
  }
1037
1060
  async function removeSkill(targetDir, name) {
1038
1061
  if (isPlatformSkill(name)) {
@@ -1187,7 +1210,8 @@ async function promptCommunitySkills(targetDir, stack, autoYes) {
1187
1210
  let successCount = 0;
1188
1211
  for (const skill of selected) {
1189
1212
  try {
1190
- await addSkill(targetDir, `${skill.repo}:${skill.name}`);
1213
+ await addSkill(targetDir, `${skill.repo}:${skill.name}`, { quiet: true });
1214
+ printStatus(`Installed ${pc4.cyan(skill.name)}`);
1191
1215
  successCount++;
1192
1216
  } catch {
1193
1217
  printError(`${skill.name} (failed)`);
@@ -1840,6 +1864,76 @@ var init_telemetry = __esm({
1840
1864
  }
1841
1865
  });
1842
1866
 
1867
+ // src/lib/api-key.ts
1868
+ import { readFile as readFile10, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
1869
+ import { join as join14 } from "path";
1870
+ function detectKeyType(key) {
1871
+ if (key.startsWith("fdk_")) return "relay";
1872
+ if (key.startsWith("lin_api_")) return "direct";
1873
+ return "unknown";
1874
+ }
1875
+ async function validateRelayKey(apiKey) {
1876
+ const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
1877
+ const response = await fetch(`${baseUrl}/auth/validate`, {
1878
+ method: "POST",
1879
+ headers: {
1880
+ Authorization: `Bearer ${apiKey}`,
1881
+ "Content-Type": "application/json"
1882
+ },
1883
+ signal: AbortSignal.timeout(15e3)
1884
+ });
1885
+ if (!response.ok) return { valid: false };
1886
+ const data = await response.json();
1887
+ if (!data.valid) return { valid: false };
1888
+ return { valid: true, org: data.org ?? "your organization" };
1889
+ }
1890
+ async function validateLinearKey(apiKey) {
1891
+ const response = await fetch("https://api.linear.app/graphql", {
1892
+ method: "POST",
1893
+ headers: {
1894
+ Authorization: apiKey,
1895
+ "Content-Type": "application/json"
1896
+ },
1897
+ body: JSON.stringify({ query: "{ viewer { id name email } }" }),
1898
+ signal: AbortSignal.timeout(15e3)
1899
+ });
1900
+ if (!response.ok) return { valid: false };
1901
+ const data = await response.json();
1902
+ if (!data.data?.viewer) return { valid: false };
1903
+ return {
1904
+ valid: true,
1905
+ name: data.data.viewer.name,
1906
+ email: data.data.viewer.email
1907
+ };
1908
+ }
1909
+ async function storeEnvKey(targetDir, envVarName, value) {
1910
+ const envPath = join14(targetDir, ".env");
1911
+ const envLocalPath = join14(targetDir, ".env.local");
1912
+ const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
1913
+ const pattern = new RegExp(`${envVarName}=.*`);
1914
+ if (await pathExists(targetEnvPath)) {
1915
+ const envContent = await readFile10(targetEnvPath, "utf-8");
1916
+ if (pattern.test(envContent)) {
1917
+ const updated = envContent.replace(pattern, `${envVarName}=${value}`);
1918
+ await writeFile7(targetEnvPath, updated, "utf-8");
1919
+ } else {
1920
+ await appendFile2(targetEnvPath, `
1921
+ ${envVarName}=${value}
1922
+ `);
1923
+ }
1924
+ } else {
1925
+ await writeFile7(targetEnvPath, `${envVarName}=${value}
1926
+ `, "utf-8");
1927
+ }
1928
+ return targetEnvPath === envLocalPath ? ".env.local" : ".env";
1929
+ }
1930
+ var init_api_key = __esm({
1931
+ "src/lib/api-key.ts"() {
1932
+ "use strict";
1933
+ init_fs_ops();
1934
+ }
1935
+ });
1936
+
1843
1937
  // src/commands/install.ts
1844
1938
  var install_exports = {};
1845
1939
  __export(install_exports, {
@@ -1847,9 +1941,9 @@ __export(install_exports, {
1847
1941
  });
1848
1942
  import { defineCommand } from "citty";
1849
1943
  import { resolve as resolve2 } from "path";
1850
- import { join as join14 } from "path";
1944
+ import { join as join15 } from "path";
1851
1945
  import { mkdir as mkdir7 } from "fs/promises";
1852
- import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1946
+ import { confirm as confirm2, select, text, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1853
1947
  import pc6 from "picocolors";
1854
1948
  var install_default;
1855
1949
  var init_install = __esm({
@@ -1868,6 +1962,7 @@ var init_install = __esm({
1868
1962
  init_post_install();
1869
1963
  init_update_check();
1870
1964
  init_telemetry();
1965
+ init_api_key();
1871
1966
  install_default = defineCommand({
1872
1967
  meta: {
1873
1968
  name: "install",
@@ -1929,7 +2024,7 @@ var init_install = __esm({
1929
2024
  process.exit(1);
1930
2025
  }
1931
2026
  tier = args.tier;
1932
- } else if (await pathExists(join14(targetDir, ".flydocs", "config.json"))) {
2027
+ } else if (await pathExists(join15(targetDir, ".flydocs", "config.json"))) {
1933
2028
  try {
1934
2029
  const existing = await readConfig(targetDir);
1935
2030
  if (existing.tier) {
@@ -1978,46 +2073,126 @@ var init_install = __esm({
1978
2073
  }
1979
2074
  printInfo(`Tier: ${tier}`);
1980
2075
  await capture("install_tier_selected", { tier });
1981
- if (!await pathExists(join14(targetDir, ".git"))) {
2076
+ if (tier === "cloud") {
2077
+ console.log();
2078
+ console.log(` ${pc6.bold("Connect to FlyDocs Cloud")}`);
2079
+ console.log();
2080
+ console.log(
2081
+ ` ${pc6.dim("Get your API key from your FlyDocs dashboard (fdk_...)")}`
2082
+ );
2083
+ console.log();
2084
+ const keyInput = await text({
2085
+ message: "Enter your FlyDocs API key",
2086
+ placeholder: "fdk_...",
2087
+ validate(value) {
2088
+ if (!value.trim()) return "API key is required";
2089
+ const type = detectKeyType(value.trim());
2090
+ if (type !== "relay")
2091
+ return "Cloud tier requires a FlyDocs API key (fdk_...)";
2092
+ return void 0;
2093
+ }
2094
+ });
2095
+ if (isCancel3(keyInput)) {
2096
+ cancel2("Installation cancelled.");
2097
+ process.exit(0);
2098
+ }
2099
+ const apiKey = keyInput.trim();
2100
+ printInfo("Validating API key...");
2101
+ try {
2102
+ const result = await validateRelayKey(apiKey);
2103
+ if (!result.valid) {
2104
+ printError("Invalid API key or relay API unreachable.");
2105
+ console.log(` Check your key and try again.`);
2106
+ process.exit(1);
2107
+ }
2108
+ printStatus(`Connected to ${pc6.bold(result.org)}`);
2109
+ } catch {
2110
+ printError(
2111
+ "Could not reach relay API. Check your network and try again."
2112
+ );
2113
+ process.exit(1);
2114
+ }
2115
+ const envFile = await storeEnvKey(targetDir, "FLYDOCS_API_KEY", apiKey);
2116
+ printStatus(`API key stored in ${pc6.dim(envFile)}`);
2117
+ }
2118
+ let skipConfigOverwrite = false;
2119
+ if (!await pathExists(join15(targetDir, ".git"))) {
1982
2120
  printWarning("No git repository detected. Run git init when ready.");
1983
2121
  }
1984
2122
  await ensureDirectories(targetDir, tier);
1985
- const backedUp = await backupOriginals(targetDir);
1986
- if (backedUp.length > 0) {
1987
- printStatus(
1988
- `Backed up ${backedUp.length} existing config file(s) to .flydocs/backup-originals/`
2123
+ const existingFiles = await detectExistingConfigs(targetDir);
2124
+ if (existingFiles.length > 0) {
2125
+ console.log();
2126
+ printWarning(
2127
+ `Found ${existingFiles.length} existing config file(s) that FlyDocs will overwrite:`
1989
2128
  );
1990
- for (const f of backedUp) {
1991
- printInfo(` ${f}`);
2129
+ for (const f of existingFiles) {
2130
+ console.log(` ${pc6.dim(f)}`);
2131
+ }
2132
+ console.log();
2133
+ if (!args.yes) {
2134
+ const overwriteChoice = await select({
2135
+ message: "How should FlyDocs handle these files?",
2136
+ options: [
2137
+ {
2138
+ value: "backup",
2139
+ label: "Overwrite (backed up)",
2140
+ hint: "Files are saved to .flydocs/backup-originals/ and restored on uninstall"
2141
+ },
2142
+ {
2143
+ value: "skip",
2144
+ label: "Skip overwriting",
2145
+ hint: "Keep your existing files \u2014 FlyDocs config may be incomplete"
2146
+ }
2147
+ ]
2148
+ });
2149
+ if (isCancel3(overwriteChoice)) {
2150
+ cancel2("Installation cancelled.");
2151
+ process.exit(0);
2152
+ }
2153
+ if (overwriteChoice === "skip") {
2154
+ printInfo(
2155
+ "Keeping existing files. Run /flydocs-setup to merge your config manually."
2156
+ );
2157
+ skipConfigOverwrite = true;
2158
+ }
2159
+ }
2160
+ if (!skipConfigOverwrite) {
2161
+ const backedUp = await backupOriginals(targetDir);
2162
+ if (backedUp.length > 0) {
2163
+ printStatus(
2164
+ `Backed up ${backedUp.length} file(s) to .flydocs/backup-originals/`
2165
+ );
2166
+ }
1992
2167
  }
1993
2168
  }
1994
2169
  console.log("Installing framework files...");
1995
2170
  await replaceDirectory(
1996
- join14(templateDir, ".flydocs", "templates"),
1997
- join14(targetDir, ".flydocs", "templates")
2171
+ join15(templateDir, ".flydocs", "templates"),
2172
+ join15(targetDir, ".flydocs", "templates")
1998
2173
  );
1999
2174
  await replaceDirectory(
2000
- join14(templateDir, ".flydocs", "hooks"),
2001
- join14(targetDir, ".flydocs", "hooks")
2175
+ join15(templateDir, ".flydocs", "hooks"),
2176
+ join15(targetDir, ".flydocs", "hooks")
2002
2177
  );
2003
2178
  await replaceDirectory(
2004
- join14(templateDir, ".flydocs", "scripts"),
2005
- join14(targetDir, ".flydocs", "scripts")
2179
+ join15(templateDir, ".flydocs", "scripts"),
2180
+ join15(targetDir, ".flydocs", "scripts")
2006
2181
  );
2007
2182
  await copyFile(
2008
- join14(templateDir, ".flydocs", "version"),
2009
- join14(targetDir, ".flydocs", "version")
2183
+ join15(templateDir, ".flydocs", "version"),
2184
+ join15(targetDir, ".flydocs", "version")
2010
2185
  );
2011
- const manifestSrc = join14(templateDir, "manifest.json");
2186
+ const manifestSrc = join15(templateDir, "manifest.json");
2012
2187
  if (await pathExists(manifestSrc)) {
2013
- await copyFile(manifestSrc, join14(targetDir, ".flydocs", "manifest.json"));
2188
+ await copyFile(manifestSrc, join15(targetDir, ".flydocs", "manifest.json"));
2014
2189
  }
2015
- const changelogSrc = join14(templateDir, "CHANGELOG.md");
2190
+ const changelogSrc = join15(templateDir, "CHANGELOG.md");
2016
2191
  if (await pathExists(changelogSrc)) {
2017
- await copyFile(changelogSrc, join14(targetDir, ".flydocs", "CHANGELOG.md"));
2192
+ await copyFile(changelogSrc, join15(targetDir, ".flydocs", "CHANGELOG.md"));
2018
2193
  }
2019
2194
  printStatus(".flydocs/templates, hooks, version, manifest, changelog");
2020
- const configPath = join14(targetDir, ".flydocs", "config.json");
2195
+ const configPath = join15(targetDir, ".flydocs", "config.json");
2021
2196
  if (!await pathExists(configPath)) {
2022
2197
  const config = await createFreshConfig(templateDir, version, tier);
2023
2198
  await writeConfig(targetDir, config);
@@ -2071,20 +2246,20 @@ var init_install = __esm({
2071
2246
  }
2072
2247
  await capture("install_agents_chosen", { install_agents: installAgents });
2073
2248
  if (installAgents) {
2074
- const claudeAgentsSrc = join14(templateDir, ".claude", "agents");
2249
+ const claudeAgentsSrc = join15(templateDir, ".claude", "agents");
2075
2250
  if (await pathExists(claudeAgentsSrc)) {
2076
- await mkdir7(join14(targetDir, ".claude", "agents"), { recursive: true });
2251
+ await mkdir7(join15(targetDir, ".claude", "agents"), { recursive: true });
2077
2252
  await copyDirectoryContents(
2078
2253
  claudeAgentsSrc,
2079
- join14(targetDir, ".claude", "agents")
2254
+ join15(targetDir, ".claude", "agents")
2080
2255
  );
2081
2256
  }
2082
- const cursorAgentsSrc = join14(templateDir, ".cursor", "agents");
2257
+ const cursorAgentsSrc = join15(templateDir, ".cursor", "agents");
2083
2258
  if (await pathExists(cursorAgentsSrc)) {
2084
- await mkdir7(join14(targetDir, ".cursor", "agents"), { recursive: true });
2259
+ await mkdir7(join15(targetDir, ".cursor", "agents"), { recursive: true });
2085
2260
  await copyDirectoryContents(
2086
2261
  cursorAgentsSrc,
2087
- join14(targetDir, ".cursor", "agents")
2262
+ join15(targetDir, ".cursor", "agents")
2088
2263
  );
2089
2264
  }
2090
2265
  printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
@@ -2094,74 +2269,86 @@ var init_install = __esm({
2094
2269
  console.log();
2095
2270
  console.log("Installing commands and settings...");
2096
2271
  await copyDirectoryContents(
2097
- join14(templateDir, ".claude", "commands"),
2098
- join14(targetDir, ".claude", "commands")
2099
- );
2100
- await copyFile(
2101
- join14(templateDir, ".claude", "CLAUDE.md"),
2102
- join14(targetDir, ".claude", "CLAUDE.md")
2103
- );
2104
- await copyFile(
2105
- join14(templateDir, ".claude", "settings.json"),
2106
- join14(targetDir, ".claude", "settings.json")
2272
+ join15(templateDir, ".claude", "commands"),
2273
+ join15(targetDir, ".claude", "commands")
2107
2274
  );
2108
- printStatus(".claude/ (commands, CLAUDE.md, settings)");
2275
+ if (!skipConfigOverwrite) {
2276
+ await copyFile(
2277
+ join15(templateDir, ".claude", "CLAUDE.md"),
2278
+ join15(targetDir, ".claude", "CLAUDE.md")
2279
+ );
2280
+ await copyFile(
2281
+ join15(templateDir, ".claude", "settings.json"),
2282
+ join15(targetDir, ".claude", "settings.json")
2283
+ );
2284
+ printStatus(".claude/ (commands, CLAUDE.md, settings)");
2285
+ } else {
2286
+ printStatus(".claude/ (commands only \u2014 existing config preserved)");
2287
+ }
2109
2288
  await copyDirectoryContents(
2110
- join14(templateDir, ".claude", "commands"),
2111
- join14(targetDir, ".cursor", "commands")
2112
- );
2113
- await copyFile(
2114
- join14(templateDir, ".cursor", "hooks.json"),
2115
- join14(targetDir, ".cursor", "hooks.json")
2289
+ join15(templateDir, ".claude", "commands"),
2290
+ join15(targetDir, ".cursor", "commands")
2116
2291
  );
2117
- printStatus(".cursor/ (commands, hooks)");
2292
+ if (!skipConfigOverwrite) {
2293
+ await copyFile(
2294
+ join15(templateDir, ".cursor", "hooks.json"),
2295
+ join15(targetDir, ".cursor", "hooks.json")
2296
+ );
2297
+ printStatus(".cursor/ (commands, hooks)");
2298
+ } else {
2299
+ printStatus(".cursor/ (commands only \u2014 existing hooks preserved)");
2300
+ }
2118
2301
  await copyCursorRules(targetDir);
2119
2302
  printStatus(".cursor/rules/");
2120
- await copyFile(
2121
- join14(templateDir, "AGENTS.md"),
2122
- join14(targetDir, "AGENTS.md")
2123
- );
2124
- printStatus("AGENTS.md");
2303
+ if (!skipConfigOverwrite) {
2304
+ await copyFile(
2305
+ join15(templateDir, "AGENTS.md"),
2306
+ join15(targetDir, "AGENTS.md")
2307
+ );
2308
+ printStatus("AGENTS.md");
2309
+ } else {
2310
+ printInfo("AGENTS.md preserved (existing)");
2311
+ }
2125
2312
  await runManifestGeneration(targetDir);
2126
2313
  await runContextGraphBuild(targetDir);
2127
2314
  console.log();
2128
2315
  console.log("Installing project templates...");
2129
2316
  const userFiles = [
2130
2317
  {
2131
- src: join14(templateDir, "flydocs", "context", "project.md"),
2132
- dest: join14(targetDir, "flydocs", "context", "project.md"),
2318
+ src: join15(templateDir, "flydocs", "context", "project.md"),
2319
+ dest: join15(targetDir, "flydocs", "context", "project.md"),
2133
2320
  label: "flydocs/context/project.md"
2134
2321
  },
2135
2322
  {
2136
- src: join14(templateDir, "flydocs", "knowledge", "INDEX.md"),
2137
- dest: join14(targetDir, "flydocs", "knowledge", "INDEX.md"),
2323
+ src: join15(templateDir, "flydocs", "knowledge", "INDEX.md"),
2324
+ dest: join15(targetDir, "flydocs", "knowledge", "INDEX.md"),
2138
2325
  label: "flydocs/knowledge/INDEX.md"
2139
2326
  },
2140
2327
  {
2141
- src: join14(templateDir, "flydocs", "knowledge", "README.md"),
2142
- dest: join14(targetDir, "flydocs", "knowledge", "README.md"),
2328
+ src: join15(templateDir, "flydocs", "knowledge", "README.md"),
2329
+ dest: join15(targetDir, "flydocs", "knowledge", "README.md"),
2143
2330
  label: "flydocs/knowledge/README.md"
2144
2331
  },
2145
2332
  {
2146
- src: join14(
2333
+ src: join15(
2147
2334
  templateDir,
2148
2335
  "flydocs",
2149
2336
  "knowledge",
2150
2337
  "product",
2151
2338
  "personas.md"
2152
2339
  ),
2153
- dest: join14(targetDir, "flydocs", "knowledge", "product", "personas.md"),
2340
+ dest: join15(targetDir, "flydocs", "knowledge", "product", "personas.md"),
2154
2341
  label: "flydocs/knowledge/product/personas.md"
2155
2342
  },
2156
2343
  {
2157
- src: join14(
2344
+ src: join15(
2158
2345
  templateDir,
2159
2346
  "flydocs",
2160
2347
  "knowledge",
2161
2348
  "product",
2162
2349
  "user-flows.md"
2163
2350
  ),
2164
- dest: join14(
2351
+ dest: join15(
2165
2352
  targetDir,
2166
2353
  "flydocs",
2167
2354
  "knowledge",
@@ -2171,18 +2358,18 @@ var init_install = __esm({
2171
2358
  label: "flydocs/knowledge/product/user-flows.md"
2172
2359
  },
2173
2360
  {
2174
- src: join14(templateDir, "flydocs", "design-system", "README.md"),
2175
- dest: join14(targetDir, "flydocs", "design-system", "README.md"),
2361
+ src: join15(templateDir, "flydocs", "design-system", "README.md"),
2362
+ dest: join15(targetDir, "flydocs", "design-system", "README.md"),
2176
2363
  label: "flydocs/design-system/README.md"
2177
2364
  },
2178
2365
  {
2179
- src: join14(
2366
+ src: join15(
2180
2367
  templateDir,
2181
2368
  "flydocs",
2182
2369
  "design-system",
2183
2370
  "component-patterns.md"
2184
2371
  ),
2185
- dest: join14(
2372
+ dest: join15(
2186
2373
  targetDir,
2187
2374
  "flydocs",
2188
2375
  "design-system",
@@ -2191,13 +2378,13 @@ var init_install = __esm({
2191
2378
  label: "flydocs/design-system/component-patterns.md"
2192
2379
  },
2193
2380
  {
2194
- src: join14(templateDir, "flydocs", "design-system", "token-mapping.md"),
2195
- dest: join14(targetDir, "flydocs", "design-system", "token-mapping.md"),
2381
+ src: join15(templateDir, "flydocs", "design-system", "token-mapping.md"),
2382
+ dest: join15(targetDir, "flydocs", "design-system", "token-mapping.md"),
2196
2383
  label: "flydocs/design-system/token-mapping.md"
2197
2384
  },
2198
2385
  {
2199
- src: join14(templateDir, "flydocs", "README.md"),
2200
- dest: join14(targetDir, "flydocs", "README.md"),
2386
+ src: join15(templateDir, "flydocs", "README.md"),
2387
+ dest: join15(targetDir, "flydocs", "README.md"),
2201
2388
  label: "flydocs/README.md"
2202
2389
  }
2203
2390
  ];
@@ -2211,9 +2398,9 @@ var init_install = __esm({
2211
2398
  }
2212
2399
  }
2213
2400
  }
2214
- const envExampleSrc = join14(templateDir, ".env.example");
2401
+ const envExampleSrc = join15(templateDir, ".env.example");
2215
2402
  if (await pathExists(envExampleSrc)) {
2216
- await copyFile(envExampleSrc, join14(targetDir, ".env.example"));
2403
+ await copyFile(envExampleSrc, join15(targetDir, ".env.example"));
2217
2404
  printStatus(".env.example");
2218
2405
  }
2219
2406
  await ensureGitignore(targetDir);
@@ -2253,9 +2440,8 @@ var init_install = __esm({
2253
2440
  `Version: ${version}`,
2254
2441
  "",
2255
2442
  "Next steps:",
2256
- " 1. Run flydocs connect to set up your API key",
2257
- " 2. Run /flydocs-setup to configure your workspace",
2258
- " 3. Start working with /start-session",
2443
+ " 1. Run /flydocs-setup to configure your workspace",
2444
+ " 2. Start working with /start-session",
2259
2445
  "",
2260
2446
  "Docs: https://www.flydocs.ai/docs"
2261
2447
  ];
@@ -2392,9 +2578,9 @@ __export(update_exports, {
2392
2578
  default: () => update_default
2393
2579
  });
2394
2580
  import { defineCommand as defineCommand2 } from "citty";
2395
- import { resolve as resolve3, join as join15 } from "path";
2396
- import { mkdir as mkdir8, cp as cp2, readFile as readFile10, readdir as readdir3, rm as rm4 } from "fs/promises";
2397
- import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
2581
+ import { resolve as resolve3, join as join16 } from "path";
2582
+ import { mkdir as mkdir8, cp as cp2, readFile as readFile11, readdir as readdir3, rm as rm4 } from "fs/promises";
2583
+ import { select as select2, text as text2, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
2398
2584
  import pc7 from "picocolors";
2399
2585
  var update_default;
2400
2586
  var init_update = __esm({
@@ -2482,7 +2668,7 @@ var init_update = __esm({
2482
2668
  if (choice === "cwd") {
2483
2669
  targetDir = process.cwd();
2484
2670
  } else {
2485
- const enteredPath = await text({
2671
+ const enteredPath = await text2({
2486
2672
  message: "Enter project path:"
2487
2673
  });
2488
2674
  if (isCancel4(enteredPath)) {
@@ -2500,9 +2686,9 @@ var init_update = __esm({
2500
2686
  }
2501
2687
  targetDir = resolve3(targetDir);
2502
2688
  process.chdir(targetDir);
2503
- const hasVersion = await pathExists(join15(targetDir, ".flydocs", "version"));
2689
+ const hasVersion = await pathExists(join16(targetDir, ".flydocs", "version"));
2504
2690
  const hasConfig = await pathExists(
2505
- join15(targetDir, ".flydocs", "config.json")
2691
+ join16(targetDir, ".flydocs", "config.json")
2506
2692
  );
2507
2693
  if (!hasVersion && !hasConfig) {
2508
2694
  printError(`Not a FlyDocs project: ${targetDir}`);
@@ -2513,8 +2699,8 @@ var init_update = __esm({
2513
2699
  console.log();
2514
2700
  let currentVersion = "0.1.0";
2515
2701
  if (hasVersion) {
2516
- const vContent = await readFile10(
2517
- join15(targetDir, ".flydocs", "version"),
2702
+ const vContent = await readFile11(
2703
+ join16(targetDir, ".flydocs", "version"),
2518
2704
  "utf-8"
2519
2705
  );
2520
2706
  currentVersion = vContent.trim();
@@ -2548,7 +2734,7 @@ var init_update = __esm({
2548
2734
  });
2549
2735
  console.log(`Updating: v${currentVersion} \u2192 v${version}`);
2550
2736
  console.log();
2551
- const changelogPath = join15(templateDir, "CHANGELOG.md");
2737
+ const changelogPath = join16(templateDir, "CHANGELOG.md");
2552
2738
  const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
2553
2739
  if (whatsNew.length > 0) {
2554
2740
  console.log(pc7.cyan("What's new:"));
@@ -2560,23 +2746,23 @@ var init_update = __esm({
2560
2746
  }
2561
2747
  const now = /* @__PURE__ */ new Date();
2562
2748
  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")}`;
2563
- const backupDir = join15(targetDir, ".flydocs", `backup-${ts}`);
2749
+ const backupDir = join16(targetDir, ".flydocs", `backup-${ts}`);
2564
2750
  await mkdir8(backupDir, { recursive: true });
2565
2751
  if (hasConfig) {
2566
2752
  await cp2(
2567
- join15(targetDir, ".flydocs", "config.json"),
2568
- join15(backupDir, "config.json")
2753
+ join16(targetDir, ".flydocs", "config.json"),
2754
+ join16(backupDir, "config.json")
2569
2755
  );
2570
2756
  printStatus(`Config backed up to .flydocs/backup-${ts}/`);
2571
2757
  }
2572
2758
  try {
2573
- const flydocsDir = join15(targetDir, ".flydocs");
2759
+ const flydocsDir = join16(targetDir, ".flydocs");
2574
2760
  const entries = await readdir3(flydocsDir);
2575
2761
  const backups = entries.filter((e) => e.startsWith("backup-")).sort();
2576
2762
  if (backups.length > 3) {
2577
2763
  const toRemove = backups.slice(0, backups.length - 3);
2578
2764
  for (const old of toRemove) {
2579
- await rm4(join15(flydocsDir, old), { recursive: true, force: true });
2765
+ await rm4(join16(flydocsDir, old), { recursive: true, force: true });
2580
2766
  }
2581
2767
  }
2582
2768
  } catch {
@@ -2613,20 +2799,20 @@ var init_update = __esm({
2613
2799
  }
2614
2800
  console.log("Replacing framework directories...");
2615
2801
  await replaceDirectory(
2616
- join15(templateDir, ".flydocs", "templates"),
2617
- join15(targetDir, ".flydocs", "templates")
2802
+ join16(templateDir, ".flydocs", "templates"),
2803
+ join16(targetDir, ".flydocs", "templates")
2618
2804
  );
2619
2805
  await replaceDirectory(
2620
- join15(templateDir, ".flydocs", "hooks"),
2621
- join15(targetDir, ".flydocs", "hooks")
2806
+ join16(templateDir, ".flydocs", "hooks"),
2807
+ join16(targetDir, ".flydocs", "hooks")
2622
2808
  );
2623
2809
  await replaceDirectory(
2624
- join15(templateDir, ".flydocs", "scripts"),
2625
- join15(targetDir, ".flydocs", "scripts")
2810
+ join16(templateDir, ".flydocs", "scripts"),
2811
+ join16(targetDir, ".flydocs", "scripts")
2626
2812
  );
2627
2813
  printStatus(".flydocs/templates, hooks, scripts");
2628
2814
  const hasExistingAgents = await pathExists(
2629
- join15(targetDir, ".claude", "agents")
2815
+ join16(targetDir, ".claude", "agents")
2630
2816
  );
2631
2817
  let installAgents;
2632
2818
  if (args.yes) {
@@ -2658,20 +2844,20 @@ var init_update = __esm({
2658
2844
  }
2659
2845
  }
2660
2846
  if (installAgents) {
2661
- const claudeAgentsSrc = join15(templateDir, ".claude", "agents");
2847
+ const claudeAgentsSrc = join16(templateDir, ".claude", "agents");
2662
2848
  if (await pathExists(claudeAgentsSrc)) {
2663
- await mkdir8(join15(targetDir, ".claude", "agents"), { recursive: true });
2849
+ await mkdir8(join16(targetDir, ".claude", "agents"), { recursive: true });
2664
2850
  await copyDirectoryContents(
2665
2851
  claudeAgentsSrc,
2666
- join15(targetDir, ".claude", "agents")
2852
+ join16(targetDir, ".claude", "agents")
2667
2853
  );
2668
2854
  }
2669
- const cursorAgentsSrc = join15(templateDir, ".cursor", "agents");
2855
+ const cursorAgentsSrc = join16(templateDir, ".cursor", "agents");
2670
2856
  if (await pathExists(cursorAgentsSrc)) {
2671
- await mkdir8(join15(targetDir, ".cursor", "agents"), { recursive: true });
2857
+ await mkdir8(join16(targetDir, ".cursor", "agents"), { recursive: true });
2672
2858
  await copyDirectoryContents(
2673
2859
  cursorAgentsSrc,
2674
- join15(targetDir, ".cursor", "agents")
2860
+ join16(targetDir, ".cursor", "agents")
2675
2861
  );
2676
2862
  }
2677
2863
  printStatus(
@@ -2685,44 +2871,44 @@ var init_update = __esm({
2685
2871
  console.log();
2686
2872
  console.log("Replacing framework files...");
2687
2873
  await copyFile(
2688
- join15(templateDir, ".claude", "CLAUDE.md"),
2689
- join15(targetDir, ".claude", "CLAUDE.md")
2874
+ join16(templateDir, ".claude", "CLAUDE.md"),
2875
+ join16(targetDir, ".claude", "CLAUDE.md")
2690
2876
  );
2691
2877
  await copyFile(
2692
- join15(templateDir, ".claude", "settings.json"),
2693
- join15(targetDir, ".claude", "settings.json")
2878
+ join16(templateDir, ".claude", "settings.json"),
2879
+ join16(targetDir, ".claude", "settings.json")
2694
2880
  );
2695
2881
  printStatus(".claude/CLAUDE.md, settings.json");
2696
2882
  await copyDirectoryContents(
2697
- join15(templateDir, ".claude", "commands"),
2698
- join15(targetDir, ".claude", "commands")
2883
+ join16(templateDir, ".claude", "commands"),
2884
+ join16(targetDir, ".claude", "commands")
2699
2885
  );
2700
2886
  await copyDirectoryContents(
2701
- join15(templateDir, ".claude", "commands"),
2702
- join15(targetDir, ".cursor", "commands")
2887
+ join16(templateDir, ".claude", "commands"),
2888
+ join16(targetDir, ".cursor", "commands")
2703
2889
  );
2704
2890
  printStatus(".claude/commands, .cursor/commands");
2705
- const skillsReadmeSrc = join15(templateDir, ".claude", "skills", "README.md");
2891
+ const skillsReadmeSrc = join16(templateDir, ".claude", "skills", "README.md");
2706
2892
  if (await pathExists(skillsReadmeSrc)) {
2707
2893
  await copyFile(
2708
2894
  skillsReadmeSrc,
2709
- join15(targetDir, ".claude", "skills", "README.md")
2895
+ join16(targetDir, ".claude", "skills", "README.md")
2710
2896
  );
2711
2897
  }
2712
2898
  printStatus(".claude/skills/README.md");
2713
2899
  await copyFile(
2714
- join15(templateDir, ".cursor", "hooks.json"),
2715
- join15(targetDir, ".cursor", "hooks.json")
2900
+ join16(templateDir, ".cursor", "hooks.json"),
2901
+ join16(targetDir, ".cursor", "hooks.json")
2716
2902
  );
2717
2903
  printStatus(".cursor/hooks.json");
2718
2904
  await copyFile(
2719
- join15(templateDir, "AGENTS.md"),
2720
- join15(targetDir, "AGENTS.md")
2905
+ join16(templateDir, "AGENTS.md"),
2906
+ join16(targetDir, "AGENTS.md")
2721
2907
  );
2722
2908
  printStatus("AGENTS.md");
2723
- const envExampleSrc = join15(templateDir, ".env.example");
2909
+ const envExampleSrc = join16(templateDir, ".env.example");
2724
2910
  if (await pathExists(envExampleSrc)) {
2725
- await copyFile(envExampleSrc, join15(targetDir, ".env.example"));
2911
+ await copyFile(envExampleSrc, join16(targetDir, ".env.example"));
2726
2912
  printStatus(".env.example");
2727
2913
  }
2728
2914
  await runManifestGeneration(targetDir);
@@ -2747,18 +2933,18 @@ var init_update = __esm({
2747
2933
  printWarning("Config merge failed \u2014 config.json preserved as-is");
2748
2934
  }
2749
2935
  await copyFile(
2750
- join15(templateDir, ".flydocs", "version"),
2751
- join15(targetDir, ".flydocs", "version")
2936
+ join16(templateDir, ".flydocs", "version"),
2937
+ join16(targetDir, ".flydocs", "version")
2752
2938
  );
2753
2939
  printStatus(`.flydocs/version \u2192 ${version}`);
2754
- const clSrc = join15(templateDir, "CHANGELOG.md");
2940
+ const clSrc = join16(templateDir, "CHANGELOG.md");
2755
2941
  if (await pathExists(clSrc)) {
2756
- await copyFile(clSrc, join15(targetDir, ".flydocs", "CHANGELOG.md"));
2942
+ await copyFile(clSrc, join16(targetDir, ".flydocs", "CHANGELOG.md"));
2757
2943
  printStatus(".flydocs/CHANGELOG.md");
2758
2944
  }
2759
- const mfSrc = join15(templateDir, "manifest.json");
2945
+ const mfSrc = join16(templateDir, "manifest.json");
2760
2946
  if (await pathExists(mfSrc)) {
2761
- await copyFile(mfSrc, join15(targetDir, ".flydocs", "manifest.json"));
2947
+ await copyFile(mfSrc, join16(targetDir, ".flydocs", "manifest.json"));
2762
2948
  printStatus(".flydocs/manifest.json");
2763
2949
  }
2764
2950
  console.log();
@@ -2818,12 +3004,12 @@ __export(uninstall_exports, {
2818
3004
  default: () => uninstall_default
2819
3005
  });
2820
3006
  import { defineCommand as defineCommand3 } from "citty";
2821
- import { resolve as resolve4, join as join16 } from "path";
3007
+ import { resolve as resolve4, join as join17 } from "path";
2822
3008
  import { readdir as readdir4, rm as rm5, rename as rename2 } from "fs/promises";
2823
3009
  import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2824
3010
  import pc8 from "picocolors";
2825
3011
  async function removeOwnedSkills(targetDir) {
2826
- const skillsDir = join16(targetDir, ".claude", "skills");
3012
+ const skillsDir = join17(targetDir, ".claude", "skills");
2827
3013
  const removed = [];
2828
3014
  if (!await pathExists(skillsDir)) {
2829
3015
  return removed;
@@ -2832,7 +3018,7 @@ async function removeOwnedSkills(targetDir) {
2832
3018
  const entries = await readdir4(skillsDir);
2833
3019
  for (const entry of entries) {
2834
3020
  if (entry.startsWith(OWNED_SKILL_PREFIX)) {
2835
- await rm5(join16(skillsDir, entry), { recursive: true, force: true });
3021
+ await rm5(join17(skillsDir, entry), { recursive: true, force: true });
2836
3022
  removed.push(`.claude/skills/${entry}`);
2837
3023
  }
2838
3024
  }
@@ -2841,7 +3027,7 @@ async function removeOwnedSkills(targetDir) {
2841
3027
  return removed;
2842
3028
  }
2843
3029
  async function removeOwnedCursorRules(targetDir) {
2844
- const rulesDir = join16(targetDir, ".cursor", "rules");
3030
+ const rulesDir = join17(targetDir, ".cursor", "rules");
2845
3031
  const removed = [];
2846
3032
  if (!await pathExists(rulesDir)) {
2847
3033
  return removed;
@@ -2850,7 +3036,7 @@ async function removeOwnedCursorRules(targetDir) {
2850
3036
  const entries = await readdir4(rulesDir);
2851
3037
  for (const entry of entries) {
2852
3038
  if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
2853
- await rm5(join16(rulesDir, entry), { force: true });
3039
+ await rm5(join17(rulesDir, entry), { force: true });
2854
3040
  removed.push(`.cursor/rules/${entry}`);
2855
3041
  }
2856
3042
  }
@@ -2869,7 +3055,7 @@ async function isEmptyDir(dirPath) {
2869
3055
  async function cleanupEmptyParents(targetDir, dirs) {
2870
3056
  const cleaned = [];
2871
3057
  for (const dir of dirs) {
2872
- const fullPath = join16(targetDir, dir);
3058
+ const fullPath = join17(targetDir, dir);
2873
3059
  if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
2874
3060
  await rm5(fullPath, { recursive: true, force: true });
2875
3061
  cleaned.push(dir);
@@ -2946,8 +3132,8 @@ var init_uninstall = __esm({
2946
3132
  process.exit(1);
2947
3133
  }
2948
3134
  targetDir = resolve4(targetDir);
2949
- const hasFlydocs = await pathExists(join16(targetDir, ".flydocs"));
2950
- const hasAgentsMd = await pathExists(join16(targetDir, "AGENTS.md"));
3135
+ const hasFlydocs = await pathExists(join17(targetDir, ".flydocs"));
3136
+ const hasAgentsMd = await pathExists(join17(targetDir, "AGENTS.md"));
2951
3137
  if (!hasFlydocs && !hasAgentsMd) {
2952
3138
  printError(`Not a FlyDocs project: ${targetDir}`);
2953
3139
  printInfo("No .flydocs/ directory or AGENTS.md found.");
@@ -2959,7 +3145,7 @@ var init_uninstall = __esm({
2959
3145
  const removeAll = forceAll || args.all;
2960
3146
  const skipPrompts = forceAll || args.yes;
2961
3147
  let contentAction = "preserve";
2962
- const hasUserContent = await pathExists(join16(targetDir, "flydocs"));
3148
+ const hasUserContent = await pathExists(join17(targetDir, "flydocs"));
2963
3149
  if (hasUserContent) {
2964
3150
  if (removeAll) {
2965
3151
  contentAction = "remove";
@@ -3042,7 +3228,7 @@ var init_uninstall = __esm({
3042
3228
  const removedRules = await removeOwnedCursorRules(targetDir);
3043
3229
  result.removed.push(...removedRules);
3044
3230
  for (const [relativePath, type] of ALWAYS_REMOVED) {
3045
- const fullPath = join16(targetDir, relativePath);
3231
+ const fullPath = join17(targetDir, relativePath);
3046
3232
  if (!await pathExists(fullPath)) {
3047
3233
  result.skipped.push(relativePath);
3048
3234
  continue;
@@ -3060,9 +3246,9 @@ var init_uninstall = __esm({
3060
3246
  }
3061
3247
  }
3062
3248
  if (hasUserContent) {
3063
- const flydocsPath = join16(targetDir, "flydocs");
3249
+ const flydocsPath = join17(targetDir, "flydocs");
3064
3250
  if (contentAction === "archive") {
3065
- const archivePath = join16(targetDir, "flydocs-archive");
3251
+ const archivePath = join17(targetDir, "flydocs-archive");
3066
3252
  if (await pathExists(archivePath)) {
3067
3253
  await rm5(archivePath, { recursive: true, force: true });
3068
3254
  }
@@ -3301,70 +3487,9 @@ __export(connect_exports, {
3301
3487
  default: () => connect_default
3302
3488
  });
3303
3489
  import { defineCommand as defineCommand6 } from "citty";
3304
- import { text as text2, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
3490
+ import { text as text3, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
3305
3491
  import pc11 from "picocolors";
3306
- import { readFile as readFile11, writeFile as writeFile7, appendFile as appendFile2 } from "fs/promises";
3307
- import { join as join17 } from "path";
3308
- function detectKeyType(key) {
3309
- if (key.startsWith("fdk_")) return "relay";
3310
- if (key.startsWith("lin_api_")) return "direct";
3311
- return "unknown";
3312
- }
3313
- async function validateRelayKey(apiKey) {
3314
- const baseUrl = process.env.FLYDOCS_RELAY_URL?.replace(/\/$/, "") ?? "https://app.flydocs.ai/api/relay";
3315
- const response = await fetch(`${baseUrl}/auth/validate`, {
3316
- method: "POST",
3317
- headers: {
3318
- Authorization: `Bearer ${apiKey}`,
3319
- "Content-Type": "application/json"
3320
- },
3321
- signal: AbortSignal.timeout(15e3)
3322
- });
3323
- if (!response.ok) return { valid: false };
3324
- const data = await response.json();
3325
- if (!data.valid) return { valid: false };
3326
- return { valid: true, org: data.org ?? "your organization" };
3327
- }
3328
- async function validateLinearKey(apiKey) {
3329
- const response = await fetch("https://api.linear.app/graphql", {
3330
- method: "POST",
3331
- headers: {
3332
- Authorization: apiKey,
3333
- "Content-Type": "application/json"
3334
- },
3335
- body: JSON.stringify({ query: "{ viewer { id name email } }" }),
3336
- signal: AbortSignal.timeout(15e3)
3337
- });
3338
- if (!response.ok) return { valid: false };
3339
- const data = await response.json();
3340
- if (!data.data?.viewer) return { valid: false };
3341
- return {
3342
- valid: true,
3343
- name: data.data.viewer.name,
3344
- email: data.data.viewer.email
3345
- };
3346
- }
3347
- async function storeEnvKey(targetDir, envVarName, value) {
3348
- const envPath = join17(targetDir, ".env");
3349
- const envLocalPath = join17(targetDir, ".env.local");
3350
- const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
3351
- const pattern = new RegExp(`${envVarName}=.*`);
3352
- if (await pathExists(targetEnvPath)) {
3353
- const envContent = await readFile11(targetEnvPath, "utf-8");
3354
- if (pattern.test(envContent)) {
3355
- const updated = envContent.replace(pattern, `${envVarName}=${value}`);
3356
- await writeFile7(targetEnvPath, updated, "utf-8");
3357
- } else {
3358
- await appendFile2(targetEnvPath, `
3359
- ${envVarName}=${value}
3360
- `);
3361
- }
3362
- } else {
3363
- await writeFile7(targetEnvPath, `${envVarName}=${value}
3364
- `, "utf-8");
3365
- }
3366
- return targetEnvPath === envLocalPath ? ".env.local" : ".env";
3367
- }
3492
+ import { join as join18 } from "path";
3368
3493
  var connect_default;
3369
3494
  var init_connect = __esm({
3370
3495
  "src/commands/connect.ts"() {
@@ -3373,6 +3498,7 @@ var init_connect = __esm({
3373
3498
  init_fs_ops();
3374
3499
  init_template();
3375
3500
  init_ui();
3501
+ init_api_key();
3376
3502
  connect_default = defineCommand6({
3377
3503
  meta: {
3378
3504
  name: "connect",
@@ -3398,7 +3524,7 @@ var init_connect = __esm({
3398
3524
  },
3399
3525
  async run({ args }) {
3400
3526
  const targetDir = args.path ?? process.cwd();
3401
- const configPath = join17(targetDir, ".flydocs", "config.json");
3527
+ const configPath = join18(targetDir, ".flydocs", "config.json");
3402
3528
  if (!await pathExists(configPath)) {
3403
3529
  printError("Not a FlyDocs project (.flydocs/config.json not found).");
3404
3530
  console.log(
@@ -3430,7 +3556,7 @@ var init_connect = __esm({
3430
3556
  console.log();
3431
3557
  let apiKey = args.key ?? "";
3432
3558
  if (!apiKey) {
3433
- const keyInput = await text2({
3559
+ const keyInput = await text3({
3434
3560
  message: "Enter your API key",
3435
3561
  placeholder: "fdk_... or lin_api_...",
3436
3562
  validate(value) {
@@ -3500,14 +3626,14 @@ var init_connect = __esm({
3500
3626
  const templateDir = await resolveTemplatePath(
3501
3627
  args["local-source"] || void 0
3502
3628
  );
3503
- const templateSkillsDir = join17(templateDir, ".claude", "skills");
3504
- const skillsDir = join17(targetDir, ".claude", "skills");
3629
+ const templateSkillsDir = join18(templateDir, ".claude", "skills");
3630
+ const skillsDir = join18(targetDir, ".claude", "skills");
3505
3631
  await replaceDirectory(
3506
- join17(templateSkillsDir, "flydocs-cloud"),
3507
- join17(skillsDir, "flydocs-cloud")
3632
+ join18(templateSkillsDir, "flydocs-cloud"),
3633
+ join18(skillsDir, "flydocs-cloud")
3508
3634
  );
3509
3635
  const { rm: rm6 } = await import("fs/promises");
3510
- const localSkillDir = join17(skillsDir, "flydocs-local");
3636
+ const localSkillDir = join18(skillsDir, "flydocs-local");
3511
3637
  if (await pathExists(localSkillDir)) {
3512
3638
  await rm6(localSkillDir, { recursive: true, force: true });
3513
3639
  }