@flydocs/cli 0.5.0-beta.15 → 0.5.0-beta.17

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
@@ -11,13 +11,14 @@ var __export = (target, all) => {
11
11
 
12
12
  // src/lib/constants.ts
13
13
  import pc from "picocolors";
14
- var CLI_VERSION, CLI_NAME, PACKAGE_NAME;
14
+ var CLI_VERSION, CLI_NAME, PACKAGE_NAME, POSTHOG_API_KEY;
15
15
  var init_constants = __esm({
16
16
  "src/lib/constants.ts"() {
17
17
  "use strict";
18
- CLI_VERSION = "0.5.0-beta.15";
18
+ CLI_VERSION = "0.5.0-beta.17";
19
19
  CLI_NAME = "flydocs";
20
20
  PACKAGE_NAME = "@flydocs/cli";
21
+ POSTHOG_API_KEY = "phc_v1MSJTQDFkMS90CBh3mxIz3v8bYCCnKU6v1ir6bz0Xn";
21
22
  }
22
23
  });
23
24
 
@@ -360,18 +361,26 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
360
361
  join4(templateSkillsDir, activeMech),
361
362
  join4(skillsDir, activeMech)
362
363
  );
363
- const { rm: rm5 } = await import("fs/promises");
364
+ const { rm: rm6 } = await import("fs/promises");
364
365
  const inactivePath = join4(skillsDir, inactiveMech);
365
366
  if (await pathExists(inactivePath)) {
366
- await rm5(inactivePath, { recursive: true, force: true });
367
+ await rm6(inactivePath, { recursive: true, force: true });
367
368
  }
368
- for (const skill of OWNED_SKILLS) {
369
+ for (const skill of CORE_SKILLS) {
369
370
  if (skill === "flydocs-workflow") continue;
370
371
  const src = join4(templateSkillsDir, skill);
371
372
  if (await pathExists(src)) {
372
373
  await replaceDirectory(src, join4(skillsDir, skill));
373
374
  }
374
375
  }
376
+ if (tier === "cloud") {
377
+ for (const skill of CLOUD_ONLY_SKILLS) {
378
+ const src = join4(templateSkillsDir, skill);
379
+ if (await pathExists(src)) {
380
+ await replaceDirectory(src, join4(skillsDir, skill));
381
+ }
382
+ }
383
+ }
375
384
  const readmeSrc = join4(templateSkillsDir, "README.md");
376
385
  if (await pathExists(readmeSrc)) {
377
386
  await copyFile(readmeSrc, join4(skillsDir, "README.md"));
@@ -380,18 +389,29 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
380
389
  async function replaceOwnedSkills(templateDir, targetDir, tier) {
381
390
  const skillsDir = join4(targetDir, ".claude", "skills");
382
391
  const templateSkillsDir = join4(templateDir, ".claude", "skills");
383
- for (const skill of OWNED_SKILLS) {
392
+ const { rm: rm6 } = await import("fs/promises");
393
+ for (const skill of CORE_SKILLS) {
384
394
  const src = join4(templateSkillsDir, skill);
385
395
  if (await pathExists(src)) {
386
396
  await replaceDirectory(src, join4(skillsDir, skill));
387
397
  }
388
398
  }
389
- const { rm: rm5 } = await import("fs/promises");
399
+ for (const skill of CLOUD_ONLY_SKILLS) {
400
+ const dest = join4(skillsDir, skill);
401
+ if (tier === "cloud") {
402
+ const src = join4(templateSkillsDir, skill);
403
+ if (await pathExists(src)) {
404
+ await replaceDirectory(src, dest);
405
+ }
406
+ } else if (await pathExists(dest)) {
407
+ await rm6(dest, { recursive: true, force: true });
408
+ }
409
+ }
390
410
  const activeMech = MECHANISM_SKILLS[tier];
391
411
  const inactiveMech = tier === "local" ? MECHANISM_SKILLS.cloud : MECHANISM_SKILLS.local;
392
412
  const inactivePath = join4(skillsDir, inactiveMech);
393
413
  if (await pathExists(inactivePath)) {
394
- await rm5(inactivePath, { recursive: true, force: true });
414
+ await rm6(inactivePath, { recursive: true, force: true });
395
415
  }
396
416
  await replaceDirectory(
397
417
  join4(templateSkillsDir, activeMech),
@@ -403,9 +423,9 @@ async function replaceOwnedSkills(templateDir, targetDir, tier) {
403
423
  }
404
424
  }
405
425
  async function copyCursorRules(targetDir) {
406
- const { mkdir: mkdir7 } = await import("fs/promises");
426
+ const { mkdir: mkdir8 } = await import("fs/promises");
407
427
  const rulesDir = join4(targetDir, ".cursor", "rules");
408
- await mkdir7(rulesDir, { recursive: true });
428
+ await mkdir8(rulesDir, { recursive: true });
409
429
  const workflowRule = join4(
410
430
  targetDir,
411
431
  ".claude",
@@ -439,18 +459,17 @@ async function copyCursorRules(targetDir) {
439
459
  await copyFile(context7Rule, join4(rulesDir, "flydocs-context7.mdc"));
440
460
  }
441
461
  }
442
- var OWNED_SKILLS, MECHANISM_SKILLS;
462
+ var CORE_SKILLS, CLOUD_ONLY_SKILLS, MECHANISM_SKILLS;
443
463
  var init_skills = __esm({
444
464
  "src/lib/skills.ts"() {
445
465
  "use strict";
446
466
  init_fs_ops();
447
- OWNED_SKILLS = [
467
+ CORE_SKILLS = [
448
468
  "flydocs-workflow",
449
- "flydocs-figma",
450
- "flydocs-estimates",
451
469
  "flydocs-context-graph",
452
470
  "flydocs-context7"
453
471
  ];
472
+ CLOUD_ONLY_SKILLS = ["flydocs-figma", "flydocs-estimates"];
454
473
  MECHANISM_SKILLS = {
455
474
  local: "flydocs-local",
456
475
  cloud: "flydocs-cloud"
@@ -1625,6 +1644,143 @@ var init_update_check = __esm({
1625
1644
  }
1626
1645
  });
1627
1646
 
1647
+ // src/lib/telemetry.ts
1648
+ import { readFile as readFile8, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
1649
+ import { randomUUID } from "crypto";
1650
+ import { join as join12 } from "path";
1651
+ import { homedir as homedir2 } from "os";
1652
+ async function readConfig2() {
1653
+ try {
1654
+ const raw = await readFile8(CONFIG_FILE, "utf-8");
1655
+ const parsed = JSON.parse(raw);
1656
+ if (typeof parsed === "object" && parsed !== null && "enabled" in parsed && "anonymousId" in parsed && typeof parsed.enabled === "boolean" && typeof parsed.anonymousId === "string") {
1657
+ return parsed;
1658
+ }
1659
+ return null;
1660
+ } catch {
1661
+ return null;
1662
+ }
1663
+ }
1664
+ async function writeConfig2(config) {
1665
+ try {
1666
+ await mkdir5(CONFIG_DIR, { recursive: true });
1667
+ await writeFile5(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
1668
+ } catch {
1669
+ }
1670
+ }
1671
+ async function ensureConfig() {
1672
+ const existing = await readConfig2();
1673
+ if (existing) {
1674
+ return existing;
1675
+ }
1676
+ const config = {
1677
+ enabled: true,
1678
+ anonymousId: randomUUID()
1679
+ };
1680
+ await writeConfig2(config);
1681
+ printInfo(
1682
+ "Anonymous usage analytics enabled. Run `flydocs telemetry disable` to opt out."
1683
+ );
1684
+ return config;
1685
+ }
1686
+ async function isEnabled() {
1687
+ try {
1688
+ if (process.env.FLYDOCS_TELEMETRY === "0") {
1689
+ return false;
1690
+ }
1691
+ const config = await readConfig2();
1692
+ if (config) {
1693
+ return config.enabled;
1694
+ }
1695
+ return true;
1696
+ } catch {
1697
+ return false;
1698
+ }
1699
+ }
1700
+ function baseProperties() {
1701
+ return {
1702
+ cli_version: CLI_VERSION,
1703
+ os: process.platform,
1704
+ os_arch: process.arch,
1705
+ node_version: process.version,
1706
+ is_ci: Boolean(
1707
+ process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.BUILD_NUMBER
1708
+ ),
1709
+ $ip: null,
1710
+ $process_person_profile: false
1711
+ };
1712
+ }
1713
+ async function capture(event, properties = {}) {
1714
+ try {
1715
+ if (!await isEnabled()) {
1716
+ return;
1717
+ }
1718
+ const config = await ensureConfig();
1719
+ eventQueue.push({
1720
+ event,
1721
+ properties: {
1722
+ distinct_id: config.anonymousId,
1723
+ ...baseProperties(),
1724
+ ...properties
1725
+ },
1726
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1727
+ });
1728
+ } catch {
1729
+ }
1730
+ }
1731
+ async function flush() {
1732
+ try {
1733
+ if (eventQueue.length === 0) {
1734
+ return;
1735
+ }
1736
+ if (!await isEnabled()) {
1737
+ eventQueue.length = 0;
1738
+ return;
1739
+ }
1740
+ const batch = eventQueue.splice(0, eventQueue.length);
1741
+ const controller = new AbortController();
1742
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
1743
+ await fetch(POSTHOG_BATCH_URL, {
1744
+ method: "POST",
1745
+ headers: { "Content-Type": "application/json" },
1746
+ body: JSON.stringify({
1747
+ api_key: POSTHOG_API_KEY,
1748
+ batch
1749
+ }),
1750
+ signal: controller.signal
1751
+ });
1752
+ clearTimeout(timeout);
1753
+ } catch {
1754
+ }
1755
+ }
1756
+ async function setEnabled(enabled) {
1757
+ const config = await ensureConfig();
1758
+ config.enabled = enabled;
1759
+ await writeConfig2(config);
1760
+ }
1761
+ async function getStatus() {
1762
+ const envOverride = process.env.FLYDOCS_TELEMETRY === "0";
1763
+ const config = await readConfig2();
1764
+ return {
1765
+ enabled: config?.enabled ?? true,
1766
+ envOverride,
1767
+ anonymousId: config?.anonymousId ?? null
1768
+ };
1769
+ }
1770
+ var CONFIG_DIR, CONFIG_FILE, POSTHOG_BATCH_URL, FETCH_TIMEOUT_MS2, eventQueue;
1771
+ var init_telemetry = __esm({
1772
+ "src/lib/telemetry.ts"() {
1773
+ "use strict";
1774
+ init_constants();
1775
+ init_ui();
1776
+ CONFIG_DIR = join12(homedir2(), ".flydocs");
1777
+ CONFIG_FILE = join12(CONFIG_DIR, "telemetry.json");
1778
+ POSTHOG_BATCH_URL = "https://us.i.posthog.com/batch/";
1779
+ FETCH_TIMEOUT_MS2 = 5e3;
1780
+ eventQueue = [];
1781
+ }
1782
+ });
1783
+
1628
1784
  // src/commands/install.ts
1629
1785
  var install_exports = {};
1630
1786
  __export(install_exports, {
@@ -1632,8 +1788,8 @@ __export(install_exports, {
1632
1788
  });
1633
1789
  import { defineCommand } from "citty";
1634
1790
  import { resolve as resolve2 } from "path";
1635
- import { join as join12 } from "path";
1636
- import { mkdir as mkdir5 } from "fs/promises";
1791
+ import { join as join13 } from "path";
1792
+ import { mkdir as mkdir6 } from "fs/promises";
1637
1793
  import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1638
1794
  import pc6 from "picocolors";
1639
1795
  var install_default;
@@ -1651,6 +1807,7 @@ var init_install = __esm({
1651
1807
  init_gitignore();
1652
1808
  init_post_install();
1653
1809
  init_update_check();
1810
+ init_telemetry();
1654
1811
  install_default = defineCommand({
1655
1812
  meta: {
1656
1813
  name: "install",
@@ -1686,6 +1843,7 @@ var init_install = __esm({
1686
1843
  const templateDir = await resolveTemplatePath(args["local-source"]);
1687
1844
  const version = await readTemplateVersion(templateDir);
1688
1845
  printBanner(version);
1846
+ await capture("install_started", { template_version: version });
1689
1847
  let targetDir;
1690
1848
  if (args.path) {
1691
1849
  targetDir = resolve2(args.path.replace(/^~/, process.env.HOME ?? "~"));
@@ -1712,7 +1870,7 @@ var init_install = __esm({
1712
1870
  }
1713
1871
  tier = args.tier;
1714
1872
  printInfo(`Tier set via flag: ${tier}`);
1715
- } else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
1873
+ } else if (await pathExists(join13(targetDir, ".flydocs", "config.json"))) {
1716
1874
  try {
1717
1875
  const existing = await readConfig(targetDir);
1718
1876
  if (existing.tier) {
@@ -1734,37 +1892,38 @@ var init_install = __esm({
1734
1892
  tier = "local";
1735
1893
  console.log();
1736
1894
  }
1737
- if (!await pathExists(join12(targetDir, ".git"))) {
1895
+ await capture("install_tier_selected", { tier });
1896
+ if (!await pathExists(join13(targetDir, ".git"))) {
1738
1897
  printWarning("No git repository detected. Run git init when ready.");
1739
1898
  }
1740
1899
  await ensureDirectories(targetDir, tier);
1741
1900
  console.log("Installing framework files...");
1742
1901
  await replaceDirectory(
1743
- join12(templateDir, ".flydocs", "templates"),
1744
- join12(targetDir, ".flydocs", "templates")
1902
+ join13(templateDir, ".flydocs", "templates"),
1903
+ join13(targetDir, ".flydocs", "templates")
1745
1904
  );
1746
1905
  await replaceDirectory(
1747
- join12(templateDir, ".flydocs", "hooks"),
1748
- join12(targetDir, ".flydocs", "hooks")
1906
+ join13(templateDir, ".flydocs", "hooks"),
1907
+ join13(targetDir, ".flydocs", "hooks")
1749
1908
  );
1750
1909
  await replaceDirectory(
1751
- join12(templateDir, ".flydocs", "scripts"),
1752
- join12(targetDir, ".flydocs", "scripts")
1910
+ join13(templateDir, ".flydocs", "scripts"),
1911
+ join13(targetDir, ".flydocs", "scripts")
1753
1912
  );
1754
1913
  await copyFile(
1755
- join12(templateDir, ".flydocs", "version"),
1756
- join12(targetDir, ".flydocs", "version")
1914
+ join13(templateDir, ".flydocs", "version"),
1915
+ join13(targetDir, ".flydocs", "version")
1757
1916
  );
1758
- const manifestSrc = join12(templateDir, "manifest.json");
1917
+ const manifestSrc = join13(templateDir, "manifest.json");
1759
1918
  if (await pathExists(manifestSrc)) {
1760
- await copyFile(manifestSrc, join12(targetDir, ".flydocs", "manifest.json"));
1919
+ await copyFile(manifestSrc, join13(targetDir, ".flydocs", "manifest.json"));
1761
1920
  }
1762
- const changelogSrc = join12(templateDir, "CHANGELOG.md");
1921
+ const changelogSrc = join13(templateDir, "CHANGELOG.md");
1763
1922
  if (await pathExists(changelogSrc)) {
1764
- await copyFile(changelogSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
1923
+ await copyFile(changelogSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
1765
1924
  }
1766
1925
  printStatus(".flydocs/templates, hooks, version, manifest, changelog");
1767
- const configPath = join12(targetDir, ".flydocs", "config.json");
1926
+ const configPath = join13(targetDir, ".flydocs", "config.json");
1768
1927
  if (!await pathExists(configPath)) {
1769
1928
  const config = await createFreshConfig(templateDir, version, tier);
1770
1929
  await writeConfig(targetDir, config);
@@ -1816,21 +1975,22 @@ var init_install = __esm({
1816
1975
  installAgents = agentConfirm;
1817
1976
  }
1818
1977
  }
1978
+ await capture("install_agents_chosen", { install_agents: installAgents });
1819
1979
  if (installAgents) {
1820
- const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
1980
+ const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
1821
1981
  if (await pathExists(claudeAgentsSrc)) {
1822
- await mkdir5(join12(targetDir, ".claude", "agents"), { recursive: true });
1982
+ await mkdir6(join13(targetDir, ".claude", "agents"), { recursive: true });
1823
1983
  await copyDirectoryContents(
1824
1984
  claudeAgentsSrc,
1825
- join12(targetDir, ".claude", "agents")
1985
+ join13(targetDir, ".claude", "agents")
1826
1986
  );
1827
1987
  }
1828
- const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
1988
+ const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
1829
1989
  if (await pathExists(cursorAgentsSrc)) {
1830
- await mkdir5(join12(targetDir, ".cursor", "agents"), { recursive: true });
1990
+ await mkdir6(join13(targetDir, ".cursor", "agents"), { recursive: true });
1831
1991
  await copyDirectoryContents(
1832
1992
  cursorAgentsSrc,
1833
- join12(targetDir, ".cursor", "agents")
1993
+ join13(targetDir, ".cursor", "agents")
1834
1994
  );
1835
1995
  }
1836
1996
  printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
@@ -1840,32 +2000,32 @@ var init_install = __esm({
1840
2000
  console.log();
1841
2001
  console.log("Installing commands and settings...");
1842
2002
  await copyDirectoryContents(
1843
- join12(templateDir, ".claude", "commands"),
1844
- join12(targetDir, ".claude", "commands")
2003
+ join13(templateDir, ".claude", "commands"),
2004
+ join13(targetDir, ".claude", "commands")
1845
2005
  );
1846
2006
  await copyFile(
1847
- join12(templateDir, ".claude", "CLAUDE.md"),
1848
- join12(targetDir, ".claude", "CLAUDE.md")
2007
+ join13(templateDir, ".claude", "CLAUDE.md"),
2008
+ join13(targetDir, ".claude", "CLAUDE.md")
1849
2009
  );
1850
2010
  await copyFile(
1851
- join12(templateDir, ".claude", "settings.json"),
1852
- join12(targetDir, ".claude", "settings.json")
2011
+ join13(templateDir, ".claude", "settings.json"),
2012
+ join13(targetDir, ".claude", "settings.json")
1853
2013
  );
1854
2014
  printStatus(".claude/ (commands, CLAUDE.md, settings)");
1855
2015
  await copyDirectoryContents(
1856
- join12(templateDir, ".claude", "commands"),
1857
- join12(targetDir, ".cursor", "commands")
2016
+ join13(templateDir, ".claude", "commands"),
2017
+ join13(targetDir, ".cursor", "commands")
1858
2018
  );
1859
2019
  await copyFile(
1860
- join12(templateDir, ".cursor", "hooks.json"),
1861
- join12(targetDir, ".cursor", "hooks.json")
2020
+ join13(templateDir, ".cursor", "hooks.json"),
2021
+ join13(targetDir, ".cursor", "hooks.json")
1862
2022
  );
1863
2023
  printStatus(".cursor/ (commands, hooks)");
1864
2024
  await copyCursorRules(targetDir);
1865
2025
  printStatus(".cursor/rules/");
1866
2026
  await copyFile(
1867
- join12(templateDir, "AGENTS.md"),
1868
- join12(targetDir, "AGENTS.md")
2027
+ join13(templateDir, "AGENTS.md"),
2028
+ join13(targetDir, "AGENTS.md")
1869
2029
  );
1870
2030
  printStatus("AGENTS.md");
1871
2031
  await runManifestGeneration(targetDir);
@@ -1874,40 +2034,40 @@ var init_install = __esm({
1874
2034
  console.log("Installing project templates...");
1875
2035
  const userFiles = [
1876
2036
  {
1877
- src: join12(templateDir, "flydocs", "context", "project.md"),
1878
- dest: join12(targetDir, "flydocs", "context", "project.md"),
2037
+ src: join13(templateDir, "flydocs", "context", "project.md"),
2038
+ dest: join13(targetDir, "flydocs", "context", "project.md"),
1879
2039
  label: "flydocs/context/project.md"
1880
2040
  },
1881
2041
  {
1882
- src: join12(templateDir, "flydocs", "knowledge", "INDEX.md"),
1883
- dest: join12(targetDir, "flydocs", "knowledge", "INDEX.md"),
2042
+ src: join13(templateDir, "flydocs", "knowledge", "INDEX.md"),
2043
+ dest: join13(targetDir, "flydocs", "knowledge", "INDEX.md"),
1884
2044
  label: "flydocs/knowledge/INDEX.md"
1885
2045
  },
1886
2046
  {
1887
- src: join12(templateDir, "flydocs", "knowledge", "README.md"),
1888
- dest: join12(targetDir, "flydocs", "knowledge", "README.md"),
2047
+ src: join13(templateDir, "flydocs", "knowledge", "README.md"),
2048
+ dest: join13(targetDir, "flydocs", "knowledge", "README.md"),
1889
2049
  label: "flydocs/knowledge/README.md"
1890
2050
  },
1891
2051
  {
1892
- src: join12(
2052
+ src: join13(
1893
2053
  templateDir,
1894
2054
  "flydocs",
1895
2055
  "knowledge",
1896
2056
  "product",
1897
2057
  "personas.md"
1898
2058
  ),
1899
- dest: join12(targetDir, "flydocs", "knowledge", "product", "personas.md"),
2059
+ dest: join13(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1900
2060
  label: "flydocs/knowledge/product/personas.md"
1901
2061
  },
1902
2062
  {
1903
- src: join12(
2063
+ src: join13(
1904
2064
  templateDir,
1905
2065
  "flydocs",
1906
2066
  "knowledge",
1907
2067
  "product",
1908
2068
  "user-flows.md"
1909
2069
  ),
1910
- dest: join12(
2070
+ dest: join13(
1911
2071
  targetDir,
1912
2072
  "flydocs",
1913
2073
  "knowledge",
@@ -1917,18 +2077,18 @@ var init_install = __esm({
1917
2077
  label: "flydocs/knowledge/product/user-flows.md"
1918
2078
  },
1919
2079
  {
1920
- src: join12(templateDir, "flydocs", "design-system", "README.md"),
1921
- dest: join12(targetDir, "flydocs", "design-system", "README.md"),
2080
+ src: join13(templateDir, "flydocs", "design-system", "README.md"),
2081
+ dest: join13(targetDir, "flydocs", "design-system", "README.md"),
1922
2082
  label: "flydocs/design-system/README.md"
1923
2083
  },
1924
2084
  {
1925
- src: join12(
2085
+ src: join13(
1926
2086
  templateDir,
1927
2087
  "flydocs",
1928
2088
  "design-system",
1929
2089
  "component-patterns.md"
1930
2090
  ),
1931
- dest: join12(
2091
+ dest: join13(
1932
2092
  targetDir,
1933
2093
  "flydocs",
1934
2094
  "design-system",
@@ -1937,13 +2097,13 @@ var init_install = __esm({
1937
2097
  label: "flydocs/design-system/component-patterns.md"
1938
2098
  },
1939
2099
  {
1940
- src: join12(templateDir, "flydocs", "design-system", "token-mapping.md"),
1941
- dest: join12(targetDir, "flydocs", "design-system", "token-mapping.md"),
2100
+ src: join13(templateDir, "flydocs", "design-system", "token-mapping.md"),
2101
+ dest: join13(targetDir, "flydocs", "design-system", "token-mapping.md"),
1942
2102
  label: "flydocs/design-system/token-mapping.md"
1943
2103
  },
1944
2104
  {
1945
- src: join12(templateDir, "flydocs", "README.md"),
1946
- dest: join12(targetDir, "flydocs", "README.md"),
2105
+ src: join13(templateDir, "flydocs", "README.md"),
2106
+ dest: join13(targetDir, "flydocs", "README.md"),
1947
2107
  label: "flydocs/README.md"
1948
2108
  }
1949
2109
  ];
@@ -1957,9 +2117,9 @@ var init_install = __esm({
1957
2117
  }
1958
2118
  }
1959
2119
  }
1960
- const envExampleSrc = join12(templateDir, ".env.example");
2120
+ const envExampleSrc = join13(templateDir, ".env.example");
1961
2121
  if (await pathExists(envExampleSrc)) {
1962
- await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
2122
+ await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
1963
2123
  printStatus(".env.example");
1964
2124
  }
1965
2125
  await ensureGitignore(targetDir);
@@ -1978,6 +2138,9 @@ var init_install = __esm({
1978
2138
  } else {
1979
2139
  printInfo("No framework detected in package.json");
1980
2140
  }
2141
+ await capture("install_skills_chosen", {
2142
+ stack_detected: stack.raw
2143
+ });
1981
2144
  console.log();
1982
2145
  console.log("Checking for deprecated files...");
1983
2146
  const deprecated = await scanDeprecated(targetDir);
@@ -2019,6 +2182,7 @@ var init_install = __esm({
2019
2182
  }
2020
2183
  printCompletionBox("Installation Complete!", nextSteps);
2021
2184
  printBetaCta();
2185
+ const detectedIdes = [];
2022
2186
  try {
2023
2187
  const { execSync: execSync2, spawn } = await import("child_process");
2024
2188
  const isInstalled = (cmd) => {
@@ -2054,6 +2218,7 @@ var init_install = __esm({
2054
2218
  passCommand: false
2055
2219
  });
2056
2220
  }
2221
+ detectedIdes.push(...ideOptions.map((o) => o.cmd));
2057
2222
  if (ideOptions.length === 1) {
2058
2223
  const ide = ideOptions[0];
2059
2224
  const launchConfirm = await confirm2({
@@ -2112,6 +2277,9 @@ var init_install = __esm({
2112
2277
  }
2113
2278
  } catch {
2114
2279
  }
2280
+ await capture("install_ide_detected", { ides: detectedIdes });
2281
+ await capture("install_completed", { tier, version });
2282
+ await flush();
2115
2283
  try {
2116
2284
  const updateResult = await checkForUpdate();
2117
2285
  if (updateResult) {
@@ -2130,8 +2298,8 @@ __export(update_exports, {
2130
2298
  default: () => update_default
2131
2299
  });
2132
2300
  import { defineCommand as defineCommand2 } from "citty";
2133
- import { resolve as resolve3, join as join13 } from "path";
2134
- import { mkdir as mkdir6, cp as cp2, readFile as readFile8, readdir as readdir3, rm as rm4 } from "fs/promises";
2301
+ import { resolve as resolve3, join as join14 } from "path";
2302
+ import { mkdir as mkdir7, cp as cp2, readFile as readFile9, readdir as readdir3, rm as rm4 } from "fs/promises";
2135
2303
  import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
2136
2304
  import pc7 from "picocolors";
2137
2305
  var update_default;
@@ -2150,6 +2318,7 @@ var init_update = __esm({
2150
2318
  init_gitignore();
2151
2319
  init_post_install();
2152
2320
  init_update_check();
2321
+ init_telemetry();
2153
2322
  update_default = defineCommand2({
2154
2323
  meta: {
2155
2324
  name: "update",
@@ -2192,6 +2361,7 @@ var init_update = __esm({
2192
2361
  printBanner(version);
2193
2362
  printInfo("Running in update mode \u2014 framework files will be refreshed");
2194
2363
  console.log();
2364
+ await capture("update_started", { template_version: version });
2195
2365
  let targetDir;
2196
2366
  if (args.path) {
2197
2367
  targetDir = resolve3(args.path.replace(/^~/, process.env.HOME ?? "~"));
@@ -2236,9 +2406,9 @@ var init_update = __esm({
2236
2406
  }
2237
2407
  targetDir = resolve3(targetDir);
2238
2408
  process.chdir(targetDir);
2239
- const hasVersion = await pathExists(join13(targetDir, ".flydocs", "version"));
2409
+ const hasVersion = await pathExists(join14(targetDir, ".flydocs", "version"));
2240
2410
  const hasConfig = await pathExists(
2241
- join13(targetDir, ".flydocs", "config.json")
2411
+ join14(targetDir, ".flydocs", "config.json")
2242
2412
  );
2243
2413
  if (!hasVersion && !hasConfig) {
2244
2414
  printError(`Not a FlyDocs project: ${targetDir}`);
@@ -2249,8 +2419,8 @@ var init_update = __esm({
2249
2419
  console.log();
2250
2420
  let currentVersion = "0.1.0";
2251
2421
  if (hasVersion) {
2252
- const vContent = await readFile8(
2253
- join13(targetDir, ".flydocs", "version"),
2422
+ const vContent = await readFile9(
2423
+ join14(targetDir, ".flydocs", "version"),
2254
2424
  "utf-8"
2255
2425
  );
2256
2426
  currentVersion = vContent.trim();
@@ -2276,9 +2446,15 @@ var init_update = __esm({
2276
2446
  process.exit(0);
2277
2447
  }
2278
2448
  }
2449
+ await capture("update_version_compared", {
2450
+ current_version: currentVersion,
2451
+ target_version: version,
2452
+ version_status: versionStatus,
2453
+ force: args.force
2454
+ });
2279
2455
  console.log(`Updating: v${currentVersion} \u2192 v${version}`);
2280
2456
  console.log();
2281
- const changelogPath = join13(templateDir, "CHANGELOG.md");
2457
+ const changelogPath = join14(templateDir, "CHANGELOG.md");
2282
2458
  const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
2283
2459
  if (whatsNew.length > 0) {
2284
2460
  console.log(pc7.cyan("What's new:"));
@@ -2290,23 +2466,23 @@ var init_update = __esm({
2290
2466
  }
2291
2467
  const now = /* @__PURE__ */ new Date();
2292
2468
  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")}`;
2293
- const backupDir = join13(targetDir, ".flydocs", `backup-${ts}`);
2294
- await mkdir6(backupDir, { recursive: true });
2469
+ const backupDir = join14(targetDir, ".flydocs", `backup-${ts}`);
2470
+ await mkdir7(backupDir, { recursive: true });
2295
2471
  if (hasConfig) {
2296
2472
  await cp2(
2297
- join13(targetDir, ".flydocs", "config.json"),
2298
- join13(backupDir, "config.json")
2473
+ join14(targetDir, ".flydocs", "config.json"),
2474
+ join14(backupDir, "config.json")
2299
2475
  );
2300
2476
  printStatus(`Config backed up to .flydocs/backup-${ts}/`);
2301
2477
  }
2302
2478
  try {
2303
- const flydocsDir = join13(targetDir, ".flydocs");
2479
+ const flydocsDir = join14(targetDir, ".flydocs");
2304
2480
  const entries = await readdir3(flydocsDir);
2305
2481
  const backups = entries.filter((e) => e.startsWith("backup-")).sort();
2306
2482
  if (backups.length > 3) {
2307
2483
  const toRemove = backups.slice(0, backups.length - 3);
2308
2484
  for (const old of toRemove) {
2309
- await rm4(join13(flydocsDir, old), { recursive: true, force: true });
2485
+ await rm4(join14(flydocsDir, old), { recursive: true, force: true });
2310
2486
  }
2311
2487
  }
2312
2488
  } catch {
@@ -2343,20 +2519,20 @@ var init_update = __esm({
2343
2519
  }
2344
2520
  console.log("Replacing framework directories...");
2345
2521
  await replaceDirectory(
2346
- join13(templateDir, ".flydocs", "templates"),
2347
- join13(targetDir, ".flydocs", "templates")
2522
+ join14(templateDir, ".flydocs", "templates"),
2523
+ join14(targetDir, ".flydocs", "templates")
2348
2524
  );
2349
2525
  await replaceDirectory(
2350
- join13(templateDir, ".flydocs", "hooks"),
2351
- join13(targetDir, ".flydocs", "hooks")
2526
+ join14(templateDir, ".flydocs", "hooks"),
2527
+ join14(targetDir, ".flydocs", "hooks")
2352
2528
  );
2353
2529
  await replaceDirectory(
2354
- join13(templateDir, ".flydocs", "scripts"),
2355
- join13(targetDir, ".flydocs", "scripts")
2530
+ join14(templateDir, ".flydocs", "scripts"),
2531
+ join14(targetDir, ".flydocs", "scripts")
2356
2532
  );
2357
2533
  printStatus(".flydocs/templates, hooks, scripts");
2358
2534
  const hasExistingAgents = await pathExists(
2359
- join13(targetDir, ".claude", "agents")
2535
+ join14(targetDir, ".claude", "agents")
2360
2536
  );
2361
2537
  let installAgents;
2362
2538
  if (args.yes) {
@@ -2388,20 +2564,20 @@ var init_update = __esm({
2388
2564
  }
2389
2565
  }
2390
2566
  if (installAgents) {
2391
- const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
2567
+ const claudeAgentsSrc = join14(templateDir, ".claude", "agents");
2392
2568
  if (await pathExists(claudeAgentsSrc)) {
2393
- await mkdir6(join13(targetDir, ".claude", "agents"), { recursive: true });
2569
+ await mkdir7(join14(targetDir, ".claude", "agents"), { recursive: true });
2394
2570
  await copyDirectoryContents(
2395
2571
  claudeAgentsSrc,
2396
- join13(targetDir, ".claude", "agents")
2572
+ join14(targetDir, ".claude", "agents")
2397
2573
  );
2398
2574
  }
2399
- const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
2575
+ const cursorAgentsSrc = join14(templateDir, ".cursor", "agents");
2400
2576
  if (await pathExists(cursorAgentsSrc)) {
2401
- await mkdir6(join13(targetDir, ".cursor", "agents"), { recursive: true });
2577
+ await mkdir7(join14(targetDir, ".cursor", "agents"), { recursive: true });
2402
2578
  await copyDirectoryContents(
2403
2579
  cursorAgentsSrc,
2404
- join13(targetDir, ".cursor", "agents")
2580
+ join14(targetDir, ".cursor", "agents")
2405
2581
  );
2406
2582
  }
2407
2583
  printStatus(
@@ -2415,44 +2591,44 @@ var init_update = __esm({
2415
2591
  console.log();
2416
2592
  console.log("Replacing framework files...");
2417
2593
  await copyFile(
2418
- join13(templateDir, ".claude", "CLAUDE.md"),
2419
- join13(targetDir, ".claude", "CLAUDE.md")
2594
+ join14(templateDir, ".claude", "CLAUDE.md"),
2595
+ join14(targetDir, ".claude", "CLAUDE.md")
2420
2596
  );
2421
2597
  await copyFile(
2422
- join13(templateDir, ".claude", "settings.json"),
2423
- join13(targetDir, ".claude", "settings.json")
2598
+ join14(templateDir, ".claude", "settings.json"),
2599
+ join14(targetDir, ".claude", "settings.json")
2424
2600
  );
2425
2601
  printStatus(".claude/CLAUDE.md, settings.json");
2426
2602
  await copyDirectoryContents(
2427
- join13(templateDir, ".claude", "commands"),
2428
- join13(targetDir, ".claude", "commands")
2603
+ join14(templateDir, ".claude", "commands"),
2604
+ join14(targetDir, ".claude", "commands")
2429
2605
  );
2430
2606
  await copyDirectoryContents(
2431
- join13(templateDir, ".claude", "commands"),
2432
- join13(targetDir, ".cursor", "commands")
2607
+ join14(templateDir, ".claude", "commands"),
2608
+ join14(targetDir, ".cursor", "commands")
2433
2609
  );
2434
2610
  printStatus(".claude/commands, .cursor/commands");
2435
- const skillsReadmeSrc = join13(templateDir, ".claude", "skills", "README.md");
2611
+ const skillsReadmeSrc = join14(templateDir, ".claude", "skills", "README.md");
2436
2612
  if (await pathExists(skillsReadmeSrc)) {
2437
2613
  await copyFile(
2438
2614
  skillsReadmeSrc,
2439
- join13(targetDir, ".claude", "skills", "README.md")
2615
+ join14(targetDir, ".claude", "skills", "README.md")
2440
2616
  );
2441
2617
  }
2442
2618
  printStatus(".claude/skills/README.md");
2443
2619
  await copyFile(
2444
- join13(templateDir, ".cursor", "hooks.json"),
2445
- join13(targetDir, ".cursor", "hooks.json")
2620
+ join14(templateDir, ".cursor", "hooks.json"),
2621
+ join14(targetDir, ".cursor", "hooks.json")
2446
2622
  );
2447
2623
  printStatus(".cursor/hooks.json");
2448
2624
  await copyFile(
2449
- join13(templateDir, "AGENTS.md"),
2450
- join13(targetDir, "AGENTS.md")
2625
+ join14(templateDir, "AGENTS.md"),
2626
+ join14(targetDir, "AGENTS.md")
2451
2627
  );
2452
2628
  printStatus("AGENTS.md");
2453
- const envExampleSrc = join13(templateDir, ".env.example");
2629
+ const envExampleSrc = join14(templateDir, ".env.example");
2454
2630
  if (await pathExists(envExampleSrc)) {
2455
- await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
2631
+ await copyFile(envExampleSrc, join14(targetDir, ".env.example"));
2456
2632
  printStatus(".env.example");
2457
2633
  }
2458
2634
  await runManifestGeneration(targetDir);
@@ -2477,18 +2653,18 @@ var init_update = __esm({
2477
2653
  printWarning("Config merge failed \u2014 config.json preserved as-is");
2478
2654
  }
2479
2655
  await copyFile(
2480
- join13(templateDir, ".flydocs", "version"),
2481
- join13(targetDir, ".flydocs", "version")
2656
+ join14(templateDir, ".flydocs", "version"),
2657
+ join14(targetDir, ".flydocs", "version")
2482
2658
  );
2483
2659
  printStatus(`.flydocs/version \u2192 ${version}`);
2484
- const clSrc = join13(templateDir, "CHANGELOG.md");
2660
+ const clSrc = join14(templateDir, "CHANGELOG.md");
2485
2661
  if (await pathExists(clSrc)) {
2486
- await copyFile(clSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
2662
+ await copyFile(clSrc, join14(targetDir, ".flydocs", "CHANGELOG.md"));
2487
2663
  printStatus(".flydocs/CHANGELOG.md");
2488
2664
  }
2489
- const mfSrc = join13(templateDir, "manifest.json");
2665
+ const mfSrc = join14(templateDir, "manifest.json");
2490
2666
  if (await pathExists(mfSrc)) {
2491
- await copyFile(mfSrc, join13(targetDir, ".flydocs", "manifest.json"));
2667
+ await copyFile(mfSrc, join14(targetDir, ".flydocs", "manifest.json"));
2492
2668
  printStatus(".flydocs/manifest.json");
2493
2669
  }
2494
2670
  console.log();
@@ -2524,6 +2700,12 @@ var init_update = __esm({
2524
2700
  `Backup: .flydocs/backup-${ts}/`
2525
2701
  ]);
2526
2702
  printBetaCta();
2703
+ await capture("update_completed", {
2704
+ current_version: currentVersion,
2705
+ version,
2706
+ tier: effectiveTier
2707
+ });
2708
+ await flush();
2527
2709
  try {
2528
2710
  const updateResult = await checkForUpdate();
2529
2711
  if (updateResult) {
@@ -2536,33 +2718,336 @@ var init_update = __esm({
2536
2718
  }
2537
2719
  });
2538
2720
 
2721
+ // src/commands/uninstall.ts
2722
+ var uninstall_exports = {};
2723
+ __export(uninstall_exports, {
2724
+ default: () => uninstall_default
2725
+ });
2726
+ import { defineCommand as defineCommand3 } from "citty";
2727
+ import { resolve as resolve4, join as join15 } from "path";
2728
+ import { readdir as readdir4, rm as rm5, rename as rename2 } from "fs/promises";
2729
+ import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2730
+ import pc8 from "picocolors";
2731
+ async function removeOwnedSkills(targetDir) {
2732
+ const skillsDir = join15(targetDir, ".claude", "skills");
2733
+ const removed = [];
2734
+ if (!await pathExists(skillsDir)) {
2735
+ return removed;
2736
+ }
2737
+ try {
2738
+ const entries = await readdir4(skillsDir);
2739
+ for (const entry of entries) {
2740
+ if (entry.startsWith(OWNED_SKILL_PREFIX)) {
2741
+ await rm5(join15(skillsDir, entry), { recursive: true, force: true });
2742
+ removed.push(`.claude/skills/${entry}`);
2743
+ }
2744
+ }
2745
+ } catch {
2746
+ }
2747
+ return removed;
2748
+ }
2749
+ async function removeOwnedCursorRules(targetDir) {
2750
+ const rulesDir = join15(targetDir, ".cursor", "rules");
2751
+ const removed = [];
2752
+ if (!await pathExists(rulesDir)) {
2753
+ return removed;
2754
+ }
2755
+ try {
2756
+ const entries = await readdir4(rulesDir);
2757
+ for (const entry of entries) {
2758
+ if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
2759
+ await rm5(join15(rulesDir, entry), { force: true });
2760
+ removed.push(`.cursor/rules/${entry}`);
2761
+ }
2762
+ }
2763
+ } catch {
2764
+ }
2765
+ return removed;
2766
+ }
2767
+ async function isEmptyDir(dirPath) {
2768
+ try {
2769
+ const entries = await readdir4(dirPath);
2770
+ return entries.length === 0;
2771
+ } catch {
2772
+ return false;
2773
+ }
2774
+ }
2775
+ async function cleanupEmptyParents(targetDir, dirs) {
2776
+ const cleaned = [];
2777
+ for (const dir of dirs) {
2778
+ const fullPath = join15(targetDir, dir);
2779
+ if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
2780
+ await rm5(fullPath, { recursive: true, force: true });
2781
+ cleaned.push(dir);
2782
+ }
2783
+ }
2784
+ return cleaned;
2785
+ }
2786
+ var ALWAYS_REMOVED, OWNED_SKILL_PREFIX, OWNED_RULE_PREFIX, uninstall_default;
2787
+ var init_uninstall = __esm({
2788
+ "src/commands/uninstall.ts"() {
2789
+ "use strict";
2790
+ init_fs_ops();
2791
+ init_ui();
2792
+ init_constants();
2793
+ ALWAYS_REMOVED = [
2794
+ [".claude/CLAUDE.md", "file"],
2795
+ [".claude/settings.json", "file"],
2796
+ [".claude/agents", "dir"],
2797
+ [".claude/commands", "dir"],
2798
+ [".claude/skills/README.md", "file"],
2799
+ [".cursor/hooks.json", "file"],
2800
+ [".cursor/agents", "dir"],
2801
+ [".flydocs", "dir"],
2802
+ ["AGENTS.md", "file"],
2803
+ [".env.example", "file"]
2804
+ ];
2805
+ OWNED_SKILL_PREFIX = "flydocs-";
2806
+ OWNED_RULE_PREFIX = "flydocs-";
2807
+ uninstall_default = defineCommand3({
2808
+ meta: {
2809
+ name: "uninstall",
2810
+ description: "Remove FlyDocs from a project directory"
2811
+ },
2812
+ args: {
2813
+ path: {
2814
+ type: "string",
2815
+ description: "Uninstall from the specified directory"
2816
+ },
2817
+ here: {
2818
+ type: "boolean",
2819
+ description: "Uninstall from the current directory",
2820
+ default: false
2821
+ },
2822
+ all: {
2823
+ type: "boolean",
2824
+ description: "Remove everything including flydocs/ user content",
2825
+ default: false
2826
+ },
2827
+ yes: {
2828
+ type: "boolean",
2829
+ alias: ["y"],
2830
+ description: "Skip confirmation prompts",
2831
+ default: false
2832
+ },
2833
+ force: {
2834
+ type: "boolean",
2835
+ description: "Alias for --all --yes (complete removal, no prompts)",
2836
+ default: false
2837
+ }
2838
+ },
2839
+ async run({ args }) {
2840
+ printBanner(CLI_VERSION);
2841
+ let targetDir;
2842
+ if (args.path) {
2843
+ targetDir = resolve4(args.path.replace(/^~/, process.env.HOME ?? "~"));
2844
+ } else if (args.here) {
2845
+ targetDir = process.cwd();
2846
+ } else {
2847
+ targetDir = process.cwd();
2848
+ }
2849
+ if (!await pathExists(targetDir)) {
2850
+ printError(`Directory does not exist: ${targetDir}`);
2851
+ process.exit(1);
2852
+ }
2853
+ targetDir = resolve4(targetDir);
2854
+ const hasFlydocs = await pathExists(join15(targetDir, ".flydocs"));
2855
+ const hasAgentsMd = await pathExists(join15(targetDir, "AGENTS.md"));
2856
+ if (!hasFlydocs && !hasAgentsMd) {
2857
+ printError(`Not a FlyDocs project: ${targetDir}`);
2858
+ printInfo("No .flydocs/ directory or AGENTS.md found.");
2859
+ process.exit(1);
2860
+ }
2861
+ printInfo(`Project: ${targetDir}`);
2862
+ console.log();
2863
+ const forceAll = args.force;
2864
+ const removeAll = forceAll || args.all;
2865
+ const skipPrompts = forceAll || args.yes;
2866
+ let contentAction = "preserve";
2867
+ const hasUserContent = await pathExists(join15(targetDir, "flydocs"));
2868
+ if (hasUserContent) {
2869
+ if (removeAll) {
2870
+ contentAction = "remove";
2871
+ } else if (!skipPrompts) {
2872
+ const choice = await select3({
2873
+ message: "What should happen to your flydocs/ content (project docs, knowledge base)?",
2874
+ options: [
2875
+ {
2876
+ value: "archive",
2877
+ label: "Archive",
2878
+ hint: "Rename to flydocs-archive/ (safe, reversible)"
2879
+ },
2880
+ {
2881
+ value: "remove",
2882
+ label: "Remove completely",
2883
+ hint: "Permanently delete flydocs/ and all contents"
2884
+ },
2885
+ {
2886
+ value: "preserve",
2887
+ label: "Keep as-is",
2888
+ hint: "Leave flydocs/ untouched"
2889
+ }
2890
+ ]
2891
+ });
2892
+ if (isCancel5(choice)) {
2893
+ cancel4("Uninstall cancelled.");
2894
+ process.exit(0);
2895
+ }
2896
+ contentAction = choice;
2897
+ }
2898
+ }
2899
+ if (!skipPrompts) {
2900
+ console.log();
2901
+ console.log(pc8.bold("The following will be removed:"));
2902
+ console.log();
2903
+ console.log(" Framework files:");
2904
+ for (const [path] of ALWAYS_REMOVED) {
2905
+ console.log(` ${pc8.dim(path)}`);
2906
+ }
2907
+ console.log(` ${pc8.dim(".claude/skills/flydocs-*")}`);
2908
+ console.log(` ${pc8.dim(".cursor/rules/flydocs-*.mdc")}`);
2909
+ if (hasUserContent) {
2910
+ if (contentAction === "archive") {
2911
+ console.log();
2912
+ console.log(
2913
+ ` User content: ${pc8.yellow("flydocs/ -> flydocs-archive/")}`
2914
+ );
2915
+ } else if (contentAction === "remove") {
2916
+ console.log();
2917
+ console.log(` User content: ${pc8.red("flydocs/ (deleted)")}`);
2918
+ } else {
2919
+ console.log();
2920
+ console.log(` User content: ${pc8.green("flydocs/ (preserved)")}`);
2921
+ }
2922
+ }
2923
+ console.log();
2924
+ console.log(pc8.bold("Preserved:"));
2925
+ console.log(
2926
+ ` ${pc8.dim(".claude/skills/ (non-flydocs community skills)")}`
2927
+ );
2928
+ console.log(` ${pc8.dim(".env, .env.local")}`);
2929
+ console.log();
2930
+ const shouldContinue = await confirm4({
2931
+ message: "Proceed with uninstall?"
2932
+ });
2933
+ if (isCancel5(shouldContinue) || !shouldContinue) {
2934
+ cancel4("Uninstall cancelled.");
2935
+ process.exit(0);
2936
+ }
2937
+ }
2938
+ const result = {
2939
+ removed: [],
2940
+ skipped: [],
2941
+ archived: []
2942
+ };
2943
+ const removedSkills = await removeOwnedSkills(targetDir);
2944
+ result.removed.push(...removedSkills);
2945
+ const removedRules = await removeOwnedCursorRules(targetDir);
2946
+ result.removed.push(...removedRules);
2947
+ for (const [relativePath, type] of ALWAYS_REMOVED) {
2948
+ const fullPath = join15(targetDir, relativePath);
2949
+ if (!await pathExists(fullPath)) {
2950
+ result.skipped.push(relativePath);
2951
+ continue;
2952
+ }
2953
+ try {
2954
+ if (type === "dir") {
2955
+ await rm5(fullPath, { recursive: true, force: true });
2956
+ } else {
2957
+ await rm5(fullPath, { force: true });
2958
+ }
2959
+ result.removed.push(relativePath);
2960
+ } catch {
2961
+ printWarning(`Could not remove: ${relativePath}`);
2962
+ result.skipped.push(relativePath);
2963
+ }
2964
+ }
2965
+ if (hasUserContent) {
2966
+ const flydocsPath = join15(targetDir, "flydocs");
2967
+ if (contentAction === "archive") {
2968
+ const archivePath = join15(targetDir, "flydocs-archive");
2969
+ if (await pathExists(archivePath)) {
2970
+ await rm5(archivePath, { recursive: true, force: true });
2971
+ }
2972
+ await rename2(flydocsPath, archivePath);
2973
+ result.archived.push("flydocs/ -> flydocs-archive/");
2974
+ } else if (contentAction === "remove") {
2975
+ await rm5(flydocsPath, { recursive: true, force: true });
2976
+ result.removed.push("flydocs/");
2977
+ }
2978
+ }
2979
+ const emptyCandidates = [
2980
+ ".claude/skills",
2981
+ ".claude",
2982
+ ".cursor/rules",
2983
+ ".cursor"
2984
+ ];
2985
+ const cleaned = await cleanupEmptyParents(targetDir, emptyCandidates);
2986
+ for (const dir of cleaned) {
2987
+ result.removed.push(`${dir}/ (empty, cleaned up)`);
2988
+ }
2989
+ console.log();
2990
+ console.log(pc8.bold("Uninstall Summary"));
2991
+ console.log();
2992
+ if (result.removed.length > 0) {
2993
+ console.log(` ${pc8.green("Removed")} (${result.removed.length}):`);
2994
+ for (const item of result.removed) {
2995
+ printStatus(item);
2996
+ }
2997
+ }
2998
+ if (result.archived.length > 0) {
2999
+ console.log();
3000
+ console.log(` ${pc8.yellow("Archived")} (${result.archived.length}):`);
3001
+ for (const item of result.archived) {
3002
+ printInfo(item);
3003
+ }
3004
+ }
3005
+ if (result.skipped.length > 0) {
3006
+ console.log();
3007
+ console.log(
3008
+ ` ${pc8.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
3009
+ );
3010
+ for (const item of result.skipped) {
3011
+ console.log(` ${pc8.dim(item)}`);
3012
+ }
3013
+ }
3014
+ console.log();
3015
+ printStatus("FlyDocs has been removed from this project.");
3016
+ console.log();
3017
+ printInfo(`To reinstall: ${pc8.cyan("npx @flydocs/cli install --here")}`);
3018
+ console.log();
3019
+ }
3020
+ });
3021
+ }
3022
+ });
3023
+
2539
3024
  // src/commands/setup.ts
2540
3025
  var setup_exports = {};
2541
3026
  __export(setup_exports, {
2542
3027
  default: () => setup_default
2543
3028
  });
2544
- import { defineCommand as defineCommand3 } from "citty";
2545
- import pc8 from "picocolors";
3029
+ import { defineCommand as defineCommand4 } from "citty";
3030
+ import pc9 from "picocolors";
2546
3031
  var setup_default;
2547
3032
  var init_setup = __esm({
2548
3033
  "src/commands/setup.ts"() {
2549
3034
  "use strict";
2550
- setup_default = defineCommand3({
3035
+ setup_default = defineCommand4({
2551
3036
  meta: {
2552
3037
  name: "setup",
2553
3038
  description: "Configure FlyDocs settings for this project"
2554
3039
  },
2555
3040
  run() {
2556
3041
  console.log();
2557
- console.log(` ${pc8.bold("FlyDocs Setup")}`);
3042
+ console.log(` ${pc9.bold("FlyDocs Setup")}`);
2558
3043
  console.log();
2559
3044
  console.log(` Setup runs inside your IDE as an interactive AI command.`);
2560
3045
  console.log();
2561
3046
  console.log(
2562
- ` ${pc8.cyan("Claude Code:")} Type ${pc8.bold("/flydocs-setup")} in chat`
3047
+ ` ${pc9.cyan("Claude Code:")} Type ${pc9.bold("/flydocs-setup")} in chat`
2563
3048
  );
2564
3049
  console.log(
2565
- ` ${pc8.cyan("Cursor:")} Type ${pc8.bold("/flydocs-setup")} in chat`
3050
+ ` ${pc9.cyan("Cursor:")} Type ${pc9.bold("/flydocs-setup")} in chat`
2566
3051
  );
2567
3052
  console.log();
2568
3053
  console.log(` This configures your project context, detects your stack,`);
@@ -2578,14 +3063,14 @@ var skills_exports = {};
2578
3063
  __export(skills_exports, {
2579
3064
  default: () => skills_default
2580
3065
  });
2581
- import { defineCommand as defineCommand4 } from "citty";
2582
- import pc9 from "picocolors";
3066
+ import { defineCommand as defineCommand5 } from "citty";
3067
+ import pc10 from "picocolors";
2583
3068
  var list, search, add, remove, skills_default;
2584
3069
  var init_skills2 = __esm({
2585
3070
  "src/commands/skills.ts"() {
2586
3071
  "use strict";
2587
3072
  init_skill_manager();
2588
- list = defineCommand4({
3073
+ list = defineCommand5({
2589
3074
  meta: {
2590
3075
  name: "list",
2591
3076
  description: "List installed skills"
@@ -2601,26 +3086,26 @@ var init_skills2 = __esm({
2601
3086
  console.log(`${total} skill(s) installed:`);
2602
3087
  if (result.platform.length > 0) {
2603
3088
  console.log();
2604
- console.log(pc9.bold("Platform"));
3089
+ console.log(pc10.bold("Platform"));
2605
3090
  for (const skill of result.platform) {
2606
3091
  console.log(
2607
- ` ${skill.name} ${pc9.dim(`(${skill.triggers} triggers)`)}`
3092
+ ` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
2608
3093
  );
2609
3094
  }
2610
3095
  }
2611
3096
  if (result.community.length > 0) {
2612
3097
  console.log();
2613
- console.log(pc9.bold("Community"));
3098
+ console.log(pc10.bold("Community"));
2614
3099
  for (const skill of result.community) {
2615
3100
  console.log(
2616
- ` ${skill.name} ${pc9.dim(`(${skill.triggers} triggers)`)}`
3101
+ ` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
2617
3102
  );
2618
3103
  }
2619
3104
  }
2620
3105
  console.log();
2621
3106
  }
2622
3107
  });
2623
- search = defineCommand4({
3108
+ search = defineCommand5({
2624
3109
  meta: {
2625
3110
  name: "search",
2626
3111
  description: "Search community skills"
@@ -2636,24 +3121,24 @@ var init_skills2 = __esm({
2636
3121
  const results = await searchCatalog(args.keyword);
2637
3122
  if (results.length === 0) {
2638
3123
  console.log(`No skills found for "${args.keyword}".`);
2639
- console.log(` Browse the catalog at: ${pc9.cyan("https://skills.sh/")}`);
3124
+ console.log(` Browse the catalog at: ${pc10.cyan("https://skills.sh/")}`);
2640
3125
  return;
2641
3126
  }
2642
3127
  console.log();
2643
3128
  console.log(`${results.length} skill(s) matching "${args.keyword}":`);
2644
3129
  console.log();
2645
3130
  for (const skill of results) {
2646
- console.log(` ${pc9.bold(skill.name)}`);
3131
+ console.log(` ${pc10.bold(skill.name)}`);
2647
3132
  console.log(` ${skill.description}`);
2648
- console.log(` ${pc9.dim(skill.repo)}`);
3133
+ console.log(` ${pc10.dim(skill.repo)}`);
2649
3134
  if (skill.tags.length > 0) {
2650
- console.log(` ${pc9.dim(skill.tags.join(", "))}`);
3135
+ console.log(` ${pc10.dim(skill.tags.join(", "))}`);
2651
3136
  }
2652
3137
  console.log();
2653
3138
  }
2654
3139
  }
2655
3140
  });
2656
- add = defineCommand4({
3141
+ add = defineCommand5({
2657
3142
  meta: {
2658
3143
  name: "add",
2659
3144
  description: "Install a community skill"
@@ -2669,7 +3154,7 @@ var init_skills2 = __esm({
2669
3154
  await addSkill(process.cwd(), args.source);
2670
3155
  }
2671
3156
  });
2672
- remove = defineCommand4({
3157
+ remove = defineCommand5({
2673
3158
  meta: {
2674
3159
  name: "remove",
2675
3160
  description: "Remove an installed community skill"
@@ -2685,7 +3170,7 @@ var init_skills2 = __esm({
2685
3170
  await removeSkill(process.cwd(), args.name);
2686
3171
  }
2687
3172
  });
2688
- skills_default = defineCommand4({
3173
+ skills_default = defineCommand5({
2689
3174
  meta: {
2690
3175
  name: "skills",
2691
3176
  description: "Manage FlyDocs skills (list, search, add, remove)"
@@ -2705,11 +3190,11 @@ var connect_exports = {};
2705
3190
  __export(connect_exports, {
2706
3191
  default: () => connect_default
2707
3192
  });
2708
- import { defineCommand as defineCommand5 } from "citty";
2709
- import { text as text2, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2710
- import pc10 from "picocolors";
2711
- import { readFile as readFile9, writeFile as writeFile5, appendFile as appendFile2 } from "fs/promises";
2712
- import { join as join14 } from "path";
3193
+ import { defineCommand as defineCommand6 } from "citty";
3194
+ import { text as text2, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
3195
+ import pc11 from "picocolors";
3196
+ import { readFile as readFile10, writeFile as writeFile6, appendFile as appendFile2 } from "fs/promises";
3197
+ import { join as join16 } from "path";
2713
3198
  var connect_default;
2714
3199
  var init_connect = __esm({
2715
3200
  "src/commands/connect.ts"() {
@@ -2718,7 +3203,7 @@ var init_connect = __esm({
2718
3203
  init_fs_ops();
2719
3204
  init_template();
2720
3205
  init_ui();
2721
- connect_default = defineCommand5({
3206
+ connect_default = defineCommand6({
2722
3207
  meta: {
2723
3208
  name: "connect",
2724
3209
  description: "Connect FlyDocs to a cloud provider (Linear)"
@@ -2743,11 +3228,11 @@ var init_connect = __esm({
2743
3228
  },
2744
3229
  async run({ args }) {
2745
3230
  const targetDir = args.path ?? process.cwd();
2746
- const configPath = join14(targetDir, ".flydocs", "config.json");
3231
+ const configPath = join16(targetDir, ".flydocs", "config.json");
2747
3232
  if (!await pathExists(configPath)) {
2748
3233
  printError("Not a FlyDocs project (.flydocs/config.json not found).");
2749
3234
  console.log(
2750
- ` Run ${pc10.cyan("flydocs")} first to install FlyDocs in this project.`
3235
+ ` Run ${pc11.cyan("flydocs")} first to install FlyDocs in this project.`
2751
3236
  );
2752
3237
  process.exit(1);
2753
3238
  }
@@ -2755,19 +3240,19 @@ var init_connect = __esm({
2755
3240
  if (config.tier === "cloud") {
2756
3241
  printInfo("This project is already connected to the cloud tier.");
2757
3242
  console.log();
2758
- const reconnect = await confirm4({
3243
+ const reconnect = await confirm5({
2759
3244
  message: "Want to update your API key?"
2760
3245
  });
2761
- if (isCancel5(reconnect) || !reconnect) {
3246
+ if (isCancel6(reconnect) || !reconnect) {
2762
3247
  console.log(` No changes made.`);
2763
3248
  return;
2764
3249
  }
2765
3250
  }
2766
3251
  console.log();
2767
- console.log(` ${pc10.bold("Connect to Linear")}`);
3252
+ console.log(` ${pc11.bold("Connect to Linear")}`);
2768
3253
  console.log();
2769
3254
  console.log(
2770
- ` ${pc10.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
3255
+ ` ${pc11.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
2771
3256
  );
2772
3257
  console.log();
2773
3258
  let apiKey = args.key ?? "";
@@ -2782,8 +3267,8 @@ var init_connect = __esm({
2782
3267
  return void 0;
2783
3268
  }
2784
3269
  });
2785
- if (isCancel5(keyInput)) {
2786
- cancel4("Connection cancelled.");
3270
+ if (isCancel6(keyInput)) {
3271
+ cancel5("Connection cancelled.");
2787
3272
  process.exit(0);
2788
3273
  }
2789
3274
  apiKey = keyInput;
@@ -2807,34 +3292,34 @@ var init_connect = __esm({
2807
3292
  throw new Error("Invalid response");
2808
3293
  }
2809
3294
  const viewer = data.data.viewer;
2810
- printStatus(`Authenticated as ${pc10.bold(viewer.name)} (${viewer.email})`);
3295
+ printStatus(`Authenticated as ${pc11.bold(viewer.name)} (${viewer.email})`);
2811
3296
  } catch {
2812
3297
  printError("Invalid API key or network error.");
2813
3298
  console.log(` Check your key and try again.`);
2814
3299
  process.exit(1);
2815
3300
  }
2816
- const envPath = join14(targetDir, ".env");
2817
- const envLocalPath = join14(targetDir, ".env.local");
3301
+ const envPath = join16(targetDir, ".env");
3302
+ const envLocalPath = join16(targetDir, ".env.local");
2818
3303
  const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
2819
3304
  if (await pathExists(targetEnvPath)) {
2820
- const envContent = await readFile9(targetEnvPath, "utf-8");
3305
+ const envContent = await readFile10(targetEnvPath, "utf-8");
2821
3306
  if (envContent.includes("LINEAR_API_KEY=")) {
2822
3307
  const updated = envContent.replace(
2823
3308
  /LINEAR_API_KEY=.*/,
2824
3309
  `LINEAR_API_KEY=${apiKey}`
2825
3310
  );
2826
- await writeFile5(targetEnvPath, updated, "utf-8");
3311
+ await writeFile6(targetEnvPath, updated, "utf-8");
2827
3312
  } else {
2828
3313
  await appendFile2(targetEnvPath, `
2829
3314
  LINEAR_API_KEY=${apiKey}
2830
3315
  `);
2831
3316
  }
2832
3317
  } else {
2833
- await writeFile5(targetEnvPath, `LINEAR_API_KEY=${apiKey}
3318
+ await writeFile6(targetEnvPath, `LINEAR_API_KEY=${apiKey}
2834
3319
  `, "utf-8");
2835
3320
  }
2836
3321
  printStatus(
2837
- `API key stored in ${pc10.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
3322
+ `API key stored in ${pc11.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
2838
3323
  );
2839
3324
  const wasLocal = config.tier === "local";
2840
3325
  config.tier = "cloud";
@@ -2847,16 +3332,16 @@ LINEAR_API_KEY=${apiKey}
2847
3332
  const templateDir = await resolveTemplatePath(
2848
3333
  args["local-source"] || void 0
2849
3334
  );
2850
- const templateSkillsDir = join14(templateDir, ".claude", "skills");
2851
- const skillsDir = join14(targetDir, ".claude", "skills");
3335
+ const templateSkillsDir = join16(templateDir, ".claude", "skills");
3336
+ const skillsDir = join16(targetDir, ".claude", "skills");
2852
3337
  await replaceDirectory(
2853
- join14(templateSkillsDir, "flydocs-cloud"),
2854
- join14(skillsDir, "flydocs-cloud")
3338
+ join16(templateSkillsDir, "flydocs-cloud"),
3339
+ join16(skillsDir, "flydocs-cloud")
2855
3340
  );
2856
- const { rm: rm5 } = await import("fs/promises");
2857
- const localSkillDir = join14(skillsDir, "flydocs-local");
3341
+ const { rm: rm6 } = await import("fs/promises");
3342
+ const localSkillDir = join16(skillsDir, "flydocs-local");
2858
3343
  if (await pathExists(localSkillDir)) {
2859
- await rm5(localSkillDir, { recursive: true, force: true });
3344
+ await rm6(localSkillDir, { recursive: true, force: true });
2860
3345
  }
2861
3346
  printStatus("Cloud mechanism skill installed");
2862
3347
  } catch {
@@ -2867,14 +3352,14 @@ LINEAR_API_KEY=${apiKey}
2867
3352
  }
2868
3353
  console.log();
2869
3354
  console.log(
2870
- ` ${pc10.bold("Connected!")} Your project now syncs with Linear.`
3355
+ ` ${pc11.bold("Connected!")} Your project now syncs with Linear.`
2871
3356
  );
2872
3357
  console.log();
2873
3358
  console.log(` Next steps:`);
2874
3359
  console.log(
2875
- ` 1. Run ${pc10.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
3360
+ ` 1. Run ${pc11.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
2876
3361
  );
2877
- console.log(` 2. Run ${pc10.cyan("/start-session")} to begin working`);
3362
+ console.log(` 2. Run ${pc11.cyan("/start-session")} to begin working`);
2878
3363
  console.log();
2879
3364
  }
2880
3365
  });
@@ -2886,15 +3371,15 @@ var upgrade_exports = {};
2886
3371
  __export(upgrade_exports, {
2887
3372
  default: () => upgrade_default
2888
3373
  });
2889
- import { defineCommand as defineCommand6 } from "citty";
2890
- import pc11 from "picocolors";
3374
+ import { defineCommand as defineCommand7 } from "citty";
3375
+ import pc12 from "picocolors";
2891
3376
  var upgrade_default;
2892
3377
  var init_upgrade = __esm({
2893
3378
  "src/commands/upgrade.ts"() {
2894
3379
  "use strict";
2895
3380
  init_config();
2896
3381
  init_fs_ops();
2897
- upgrade_default = defineCommand6({
3382
+ upgrade_default = defineCommand7({
2898
3383
  meta: {
2899
3384
  name: "upgrade",
2900
3385
  description: "Learn about FlyDocs Cloud tier and upgrade from local"
@@ -2923,37 +3408,37 @@ var init_upgrade = __esm({
2923
3408
  console.log();
2924
3409
  if (currentTier === "cloud") {
2925
3410
  console.log(
2926
- ` ${pc11.green("\u2713")} You're already on the ${pc11.bold("cloud")} tier.`
3411
+ ` ${pc12.green("\u2713")} You're already on the ${pc12.bold("cloud")} tier.`
2927
3412
  );
2928
3413
  console.log();
2929
3414
  console.log(
2930
3415
  ` Your issues sync with Linear via the cloud mechanism skill.`
2931
3416
  );
2932
3417
  console.log(
2933
- ` Run ${pc11.cyan("flydocs connect")} to update your connection settings.`
3418
+ ` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
2934
3419
  );
2935
3420
  console.log();
2936
3421
  return;
2937
3422
  }
2938
- console.log(` ${pc11.bold("FlyDocs Cloud Tier")}`);
3423
+ console.log(` ${pc12.bold("FlyDocs Cloud Tier")}`);
2939
3424
  console.log();
2940
- console.log(` You're currently on the ${pc11.yellow("local")} tier.`);
3425
+ console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
2941
3426
  console.log(` Upgrade to cloud for:`);
2942
3427
  console.log();
2943
3428
  console.log(
2944
- ` ${pc11.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
3429
+ ` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2945
3430
  );
2946
- console.log(` ${pc11.cyan("\u2192")} Project milestones and cycle management`);
2947
- console.log(` ${pc11.cyan("\u2192")} Team assignment and priority tracking`);
2948
- console.log(` ${pc11.cyan("\u2192")} Project health updates and dashboards`);
2949
- console.log(` ${pc11.cyan("\u2192")} Cross-project issue linking`);
3431
+ console.log(` ${pc12.cyan("\u2192")} Project milestones and cycle management`);
3432
+ console.log(` ${pc12.cyan("\u2192")} Team assignment and priority tracking`);
3433
+ console.log(` ${pc12.cyan("\u2192")} Project health updates and dashboards`);
3434
+ console.log(` ${pc12.cyan("\u2192")} Cross-project issue linking`);
2950
3435
  console.log();
2951
- console.log(` ${pc11.bold("How to upgrade:")}`);
3436
+ console.log(` ${pc12.bold("How to upgrade:")}`);
2952
3437
  console.log();
2953
- console.log(` 1. Sign up at ${pc11.cyan("https://www.flydocs.ai")}`);
3438
+ console.log(` 1. Sign up at ${pc12.cyan("https://www.flydocs.ai")}`);
2954
3439
  console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
2955
3440
  console.log(
2956
- ` 3. Run ${pc11.cyan("flydocs connect")} to connect your project`
3441
+ ` 3. Run ${pc12.cyan("flydocs connect")} to connect your project`
2957
3442
  );
2958
3443
  console.log();
2959
3444
  }
@@ -2966,23 +3451,23 @@ var self_update_exports = {};
2966
3451
  __export(self_update_exports, {
2967
3452
  default: () => self_update_default
2968
3453
  });
2969
- import { defineCommand as defineCommand7 } from "citty";
3454
+ import { defineCommand as defineCommand8 } from "citty";
2970
3455
  import { execSync } from "child_process";
2971
- import pc12 from "picocolors";
3456
+ import pc13 from "picocolors";
2972
3457
  var self_update_default;
2973
3458
  var init_self_update = __esm({
2974
3459
  "src/commands/self-update.ts"() {
2975
3460
  "use strict";
2976
3461
  init_constants();
2977
3462
  init_ui();
2978
- self_update_default = defineCommand7({
3463
+ self_update_default = defineCommand8({
2979
3464
  meta: {
2980
3465
  name: "self-update",
2981
3466
  description: "Update FlyDocs CLI to the latest version"
2982
3467
  },
2983
3468
  async run() {
2984
3469
  console.log();
2985
- console.log(` Updating ${pc12.cyan(PACKAGE_NAME)}...`);
3470
+ console.log(` Updating ${pc13.cyan(PACKAGE_NAME)}...`);
2986
3471
  console.log();
2987
3472
  try {
2988
3473
  execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
@@ -3002,17 +3487,117 @@ var init_self_update = __esm({
3002
3487
  }
3003
3488
  });
3004
3489
 
3490
+ // src/commands/telemetry.ts
3491
+ var telemetry_exports = {};
3492
+ __export(telemetry_exports, {
3493
+ default: () => telemetry_default
3494
+ });
3495
+ import { defineCommand as defineCommand9 } from "citty";
3496
+ import pc14 from "picocolors";
3497
+ var enable, disable, status, telemetry_default;
3498
+ var init_telemetry2 = __esm({
3499
+ "src/commands/telemetry.ts"() {
3500
+ "use strict";
3501
+ init_telemetry();
3502
+ init_ui();
3503
+ enable = defineCommand9({
3504
+ meta: {
3505
+ name: "enable",
3506
+ description: "Enable anonymous usage analytics"
3507
+ },
3508
+ async run() {
3509
+ try {
3510
+ await setEnabled(true);
3511
+ printStatus("Telemetry enabled");
3512
+ } catch {
3513
+ printError("Failed to update telemetry settings");
3514
+ process.exit(1);
3515
+ }
3516
+ }
3517
+ });
3518
+ disable = defineCommand9({
3519
+ meta: {
3520
+ name: "disable",
3521
+ description: "Disable anonymous usage analytics"
3522
+ },
3523
+ async run() {
3524
+ try {
3525
+ await setEnabled(false);
3526
+ printStatus("Telemetry disabled");
3527
+ printInfo(
3528
+ "You can also set FLYDOCS_TELEMETRY=0 in your shell environment."
3529
+ );
3530
+ } catch {
3531
+ printError("Failed to update telemetry settings");
3532
+ process.exit(1);
3533
+ }
3534
+ }
3535
+ });
3536
+ status = defineCommand9({
3537
+ meta: {
3538
+ name: "status",
3539
+ description: "Show current telemetry status"
3540
+ },
3541
+ async run() {
3542
+ const info = await getStatus();
3543
+ console.log();
3544
+ console.log(pc14.bold("Telemetry Status"));
3545
+ console.log();
3546
+ const effectivelyEnabled = info.enabled && !info.envOverride;
3547
+ console.log(
3548
+ ` Enabled: ${effectivelyEnabled ? pc14.green("yes") : pc14.yellow("no")}`
3549
+ );
3550
+ if (info.envOverride) {
3551
+ console.log(
3552
+ ` Env override: ${pc14.yellow("FLYDOCS_TELEMETRY=0 (disabled via env)")}`
3553
+ );
3554
+ }
3555
+ if (info.anonymousId) {
3556
+ console.log(` Anonymous ID: ${pc14.dim(info.anonymousId)}`);
3557
+ } else {
3558
+ console.log(
3559
+ ` Anonymous ID: ${pc14.dim("(not yet created \u2014 generated on first run)")}`
3560
+ );
3561
+ }
3562
+ console.log();
3563
+ console.log(
3564
+ pc14.dim(
3565
+ " FlyDocs collects anonymous usage analytics to improve the CLI."
3566
+ )
3567
+ );
3568
+ console.log(
3569
+ pc14.dim(" No personal data, file contents, or code is ever collected.")
3570
+ );
3571
+ console.log();
3572
+ }
3573
+ });
3574
+ telemetry_default = defineCommand9({
3575
+ meta: {
3576
+ name: "telemetry",
3577
+ description: "Manage anonymous usage analytics (enable, disable, status)"
3578
+ },
3579
+ subCommands: {
3580
+ enable,
3581
+ disable,
3582
+ status
3583
+ }
3584
+ });
3585
+ }
3586
+ });
3587
+
3005
3588
  // src/cli.ts
3006
3589
  init_constants();
3007
- import { defineCommand as defineCommand8, runMain } from "citty";
3590
+ import { defineCommand as defineCommand10, runMain } from "citty";
3008
3591
  var SUB_COMMANDS = /* @__PURE__ */ new Set([
3009
3592
  "install",
3010
3593
  "update",
3594
+ "uninstall",
3011
3595
  "setup",
3012
3596
  "skills",
3013
3597
  "connect",
3014
3598
  "upgrade",
3015
- "self-update"
3599
+ "self-update",
3600
+ "telemetry"
3016
3601
  ]);
3017
3602
  var userArgs = process.argv.slice(2);
3018
3603
  var hasMetaFlag = userArgs.some(
@@ -3022,7 +3607,7 @@ var firstPositional = userArgs.find((a) => !a.startsWith("-"));
3022
3607
  if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
3023
3608
  process.argv.splice(2, 0, "install");
3024
3609
  }
3025
- var main = defineCommand8({
3610
+ var main = defineCommand10({
3026
3611
  meta: {
3027
3612
  name: CLI_NAME,
3028
3613
  version: CLI_VERSION,
@@ -3031,11 +3616,13 @@ var main = defineCommand8({
3031
3616
  subCommands: {
3032
3617
  install: () => Promise.resolve().then(() => (init_install(), install_exports)).then((m) => m.default),
3033
3618
  update: () => Promise.resolve().then(() => (init_update(), update_exports)).then((m) => m.default),
3619
+ uninstall: () => Promise.resolve().then(() => (init_uninstall(), uninstall_exports)).then((m) => m.default),
3034
3620
  setup: () => Promise.resolve().then(() => (init_setup(), setup_exports)).then((m) => m.default),
3035
3621
  skills: () => Promise.resolve().then(() => (init_skills2(), skills_exports)).then((m) => m.default),
3036
3622
  connect: () => Promise.resolve().then(() => (init_connect(), connect_exports)).then((m) => m.default),
3037
3623
  upgrade: () => Promise.resolve().then(() => (init_upgrade(), upgrade_exports)).then((m) => m.default),
3038
- "self-update": () => Promise.resolve().then(() => (init_self_update(), self_update_exports)).then((m) => m.default)
3624
+ "self-update": () => Promise.resolve().then(() => (init_self_update(), self_update_exports)).then((m) => m.default),
3625
+ telemetry: () => Promise.resolve().then(() => (init_telemetry2(), telemetry_exports)).then((m) => m.default)
3039
3626
  }
3040
3627
  });
3041
3628
  runMain(main);