@flydocs/cli 0.5.0-beta.16 → 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.16";
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,10 +361,10 @@ 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
369
  for (const skill of CORE_SKILLS) {
369
370
  if (skill === "flydocs-workflow") continue;
@@ -388,7 +389,7 @@ async function installOwnedSkills(templateDir, targetDir, tier) {
388
389
  async function replaceOwnedSkills(templateDir, targetDir, tier) {
389
390
  const skillsDir = join4(targetDir, ".claude", "skills");
390
391
  const templateSkillsDir = join4(templateDir, ".claude", "skills");
391
- const { rm: rm5 } = await import("fs/promises");
392
+ const { rm: rm6 } = await import("fs/promises");
392
393
  for (const skill of CORE_SKILLS) {
393
394
  const src = join4(templateSkillsDir, skill);
394
395
  if (await pathExists(src)) {
@@ -403,14 +404,14 @@ async function replaceOwnedSkills(templateDir, targetDir, tier) {
403
404
  await replaceDirectory(src, dest);
404
405
  }
405
406
  } else if (await pathExists(dest)) {
406
- await rm5(dest, { recursive: true, force: true });
407
+ await rm6(dest, { recursive: true, force: true });
407
408
  }
408
409
  }
409
410
  const activeMech = MECHANISM_SKILLS[tier];
410
411
  const inactiveMech = tier === "local" ? MECHANISM_SKILLS.cloud : MECHANISM_SKILLS.local;
411
412
  const inactivePath = join4(skillsDir, inactiveMech);
412
413
  if (await pathExists(inactivePath)) {
413
- await rm5(inactivePath, { recursive: true, force: true });
414
+ await rm6(inactivePath, { recursive: true, force: true });
414
415
  }
415
416
  await replaceDirectory(
416
417
  join4(templateSkillsDir, activeMech),
@@ -422,9 +423,9 @@ async function replaceOwnedSkills(templateDir, targetDir, tier) {
422
423
  }
423
424
  }
424
425
  async function copyCursorRules(targetDir) {
425
- const { mkdir: mkdir7 } = await import("fs/promises");
426
+ const { mkdir: mkdir8 } = await import("fs/promises");
426
427
  const rulesDir = join4(targetDir, ".cursor", "rules");
427
- await mkdir7(rulesDir, { recursive: true });
428
+ await mkdir8(rulesDir, { recursive: true });
428
429
  const workflowRule = join4(
429
430
  targetDir,
430
431
  ".claude",
@@ -1643,6 +1644,143 @@ var init_update_check = __esm({
1643
1644
  }
1644
1645
  });
1645
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
+
1646
1784
  // src/commands/install.ts
1647
1785
  var install_exports = {};
1648
1786
  __export(install_exports, {
@@ -1650,8 +1788,8 @@ __export(install_exports, {
1650
1788
  });
1651
1789
  import { defineCommand } from "citty";
1652
1790
  import { resolve as resolve2 } from "path";
1653
- import { join as join12 } from "path";
1654
- import { mkdir as mkdir5 } from "fs/promises";
1791
+ import { join as join13 } from "path";
1792
+ import { mkdir as mkdir6 } from "fs/promises";
1655
1793
  import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1656
1794
  import pc6 from "picocolors";
1657
1795
  var install_default;
@@ -1669,6 +1807,7 @@ var init_install = __esm({
1669
1807
  init_gitignore();
1670
1808
  init_post_install();
1671
1809
  init_update_check();
1810
+ init_telemetry();
1672
1811
  install_default = defineCommand({
1673
1812
  meta: {
1674
1813
  name: "install",
@@ -1704,6 +1843,7 @@ var init_install = __esm({
1704
1843
  const templateDir = await resolveTemplatePath(args["local-source"]);
1705
1844
  const version = await readTemplateVersion(templateDir);
1706
1845
  printBanner(version);
1846
+ await capture("install_started", { template_version: version });
1707
1847
  let targetDir;
1708
1848
  if (args.path) {
1709
1849
  targetDir = resolve2(args.path.replace(/^~/, process.env.HOME ?? "~"));
@@ -1730,7 +1870,7 @@ var init_install = __esm({
1730
1870
  }
1731
1871
  tier = args.tier;
1732
1872
  printInfo(`Tier set via flag: ${tier}`);
1733
- } else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
1873
+ } else if (await pathExists(join13(targetDir, ".flydocs", "config.json"))) {
1734
1874
  try {
1735
1875
  const existing = await readConfig(targetDir);
1736
1876
  if (existing.tier) {
@@ -1752,37 +1892,38 @@ var init_install = __esm({
1752
1892
  tier = "local";
1753
1893
  console.log();
1754
1894
  }
1755
- if (!await pathExists(join12(targetDir, ".git"))) {
1895
+ await capture("install_tier_selected", { tier });
1896
+ if (!await pathExists(join13(targetDir, ".git"))) {
1756
1897
  printWarning("No git repository detected. Run git init when ready.");
1757
1898
  }
1758
1899
  await ensureDirectories(targetDir, tier);
1759
1900
  console.log("Installing framework files...");
1760
1901
  await replaceDirectory(
1761
- join12(templateDir, ".flydocs", "templates"),
1762
- join12(targetDir, ".flydocs", "templates")
1902
+ join13(templateDir, ".flydocs", "templates"),
1903
+ join13(targetDir, ".flydocs", "templates")
1763
1904
  );
1764
1905
  await replaceDirectory(
1765
- join12(templateDir, ".flydocs", "hooks"),
1766
- join12(targetDir, ".flydocs", "hooks")
1906
+ join13(templateDir, ".flydocs", "hooks"),
1907
+ join13(targetDir, ".flydocs", "hooks")
1767
1908
  );
1768
1909
  await replaceDirectory(
1769
- join12(templateDir, ".flydocs", "scripts"),
1770
- join12(targetDir, ".flydocs", "scripts")
1910
+ join13(templateDir, ".flydocs", "scripts"),
1911
+ join13(targetDir, ".flydocs", "scripts")
1771
1912
  );
1772
1913
  await copyFile(
1773
- join12(templateDir, ".flydocs", "version"),
1774
- join12(targetDir, ".flydocs", "version")
1914
+ join13(templateDir, ".flydocs", "version"),
1915
+ join13(targetDir, ".flydocs", "version")
1775
1916
  );
1776
- const manifestSrc = join12(templateDir, "manifest.json");
1917
+ const manifestSrc = join13(templateDir, "manifest.json");
1777
1918
  if (await pathExists(manifestSrc)) {
1778
- await copyFile(manifestSrc, join12(targetDir, ".flydocs", "manifest.json"));
1919
+ await copyFile(manifestSrc, join13(targetDir, ".flydocs", "manifest.json"));
1779
1920
  }
1780
- const changelogSrc = join12(templateDir, "CHANGELOG.md");
1921
+ const changelogSrc = join13(templateDir, "CHANGELOG.md");
1781
1922
  if (await pathExists(changelogSrc)) {
1782
- await copyFile(changelogSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
1923
+ await copyFile(changelogSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
1783
1924
  }
1784
1925
  printStatus(".flydocs/templates, hooks, version, manifest, changelog");
1785
- const configPath = join12(targetDir, ".flydocs", "config.json");
1926
+ const configPath = join13(targetDir, ".flydocs", "config.json");
1786
1927
  if (!await pathExists(configPath)) {
1787
1928
  const config = await createFreshConfig(templateDir, version, tier);
1788
1929
  await writeConfig(targetDir, config);
@@ -1834,21 +1975,22 @@ var init_install = __esm({
1834
1975
  installAgents = agentConfirm;
1835
1976
  }
1836
1977
  }
1978
+ await capture("install_agents_chosen", { install_agents: installAgents });
1837
1979
  if (installAgents) {
1838
- const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
1980
+ const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
1839
1981
  if (await pathExists(claudeAgentsSrc)) {
1840
- await mkdir5(join12(targetDir, ".claude", "agents"), { recursive: true });
1982
+ await mkdir6(join13(targetDir, ".claude", "agents"), { recursive: true });
1841
1983
  await copyDirectoryContents(
1842
1984
  claudeAgentsSrc,
1843
- join12(targetDir, ".claude", "agents")
1985
+ join13(targetDir, ".claude", "agents")
1844
1986
  );
1845
1987
  }
1846
- const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
1988
+ const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
1847
1989
  if (await pathExists(cursorAgentsSrc)) {
1848
- await mkdir5(join12(targetDir, ".cursor", "agents"), { recursive: true });
1990
+ await mkdir6(join13(targetDir, ".cursor", "agents"), { recursive: true });
1849
1991
  await copyDirectoryContents(
1850
1992
  cursorAgentsSrc,
1851
- join12(targetDir, ".cursor", "agents")
1993
+ join13(targetDir, ".cursor", "agents")
1852
1994
  );
1853
1995
  }
1854
1996
  printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
@@ -1858,32 +2000,32 @@ var init_install = __esm({
1858
2000
  console.log();
1859
2001
  console.log("Installing commands and settings...");
1860
2002
  await copyDirectoryContents(
1861
- join12(templateDir, ".claude", "commands"),
1862
- join12(targetDir, ".claude", "commands")
2003
+ join13(templateDir, ".claude", "commands"),
2004
+ join13(targetDir, ".claude", "commands")
1863
2005
  );
1864
2006
  await copyFile(
1865
- join12(templateDir, ".claude", "CLAUDE.md"),
1866
- join12(targetDir, ".claude", "CLAUDE.md")
2007
+ join13(templateDir, ".claude", "CLAUDE.md"),
2008
+ join13(targetDir, ".claude", "CLAUDE.md")
1867
2009
  );
1868
2010
  await copyFile(
1869
- join12(templateDir, ".claude", "settings.json"),
1870
- join12(targetDir, ".claude", "settings.json")
2011
+ join13(templateDir, ".claude", "settings.json"),
2012
+ join13(targetDir, ".claude", "settings.json")
1871
2013
  );
1872
2014
  printStatus(".claude/ (commands, CLAUDE.md, settings)");
1873
2015
  await copyDirectoryContents(
1874
- join12(templateDir, ".claude", "commands"),
1875
- join12(targetDir, ".cursor", "commands")
2016
+ join13(templateDir, ".claude", "commands"),
2017
+ join13(targetDir, ".cursor", "commands")
1876
2018
  );
1877
2019
  await copyFile(
1878
- join12(templateDir, ".cursor", "hooks.json"),
1879
- join12(targetDir, ".cursor", "hooks.json")
2020
+ join13(templateDir, ".cursor", "hooks.json"),
2021
+ join13(targetDir, ".cursor", "hooks.json")
1880
2022
  );
1881
2023
  printStatus(".cursor/ (commands, hooks)");
1882
2024
  await copyCursorRules(targetDir);
1883
2025
  printStatus(".cursor/rules/");
1884
2026
  await copyFile(
1885
- join12(templateDir, "AGENTS.md"),
1886
- join12(targetDir, "AGENTS.md")
2027
+ join13(templateDir, "AGENTS.md"),
2028
+ join13(targetDir, "AGENTS.md")
1887
2029
  );
1888
2030
  printStatus("AGENTS.md");
1889
2031
  await runManifestGeneration(targetDir);
@@ -1892,40 +2034,40 @@ var init_install = __esm({
1892
2034
  console.log("Installing project templates...");
1893
2035
  const userFiles = [
1894
2036
  {
1895
- src: join12(templateDir, "flydocs", "context", "project.md"),
1896
- dest: join12(targetDir, "flydocs", "context", "project.md"),
2037
+ src: join13(templateDir, "flydocs", "context", "project.md"),
2038
+ dest: join13(targetDir, "flydocs", "context", "project.md"),
1897
2039
  label: "flydocs/context/project.md"
1898
2040
  },
1899
2041
  {
1900
- src: join12(templateDir, "flydocs", "knowledge", "INDEX.md"),
1901
- dest: join12(targetDir, "flydocs", "knowledge", "INDEX.md"),
2042
+ src: join13(templateDir, "flydocs", "knowledge", "INDEX.md"),
2043
+ dest: join13(targetDir, "flydocs", "knowledge", "INDEX.md"),
1902
2044
  label: "flydocs/knowledge/INDEX.md"
1903
2045
  },
1904
2046
  {
1905
- src: join12(templateDir, "flydocs", "knowledge", "README.md"),
1906
- dest: join12(targetDir, "flydocs", "knowledge", "README.md"),
2047
+ src: join13(templateDir, "flydocs", "knowledge", "README.md"),
2048
+ dest: join13(targetDir, "flydocs", "knowledge", "README.md"),
1907
2049
  label: "flydocs/knowledge/README.md"
1908
2050
  },
1909
2051
  {
1910
- src: join12(
2052
+ src: join13(
1911
2053
  templateDir,
1912
2054
  "flydocs",
1913
2055
  "knowledge",
1914
2056
  "product",
1915
2057
  "personas.md"
1916
2058
  ),
1917
- dest: join12(targetDir, "flydocs", "knowledge", "product", "personas.md"),
2059
+ dest: join13(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1918
2060
  label: "flydocs/knowledge/product/personas.md"
1919
2061
  },
1920
2062
  {
1921
- src: join12(
2063
+ src: join13(
1922
2064
  templateDir,
1923
2065
  "flydocs",
1924
2066
  "knowledge",
1925
2067
  "product",
1926
2068
  "user-flows.md"
1927
2069
  ),
1928
- dest: join12(
2070
+ dest: join13(
1929
2071
  targetDir,
1930
2072
  "flydocs",
1931
2073
  "knowledge",
@@ -1935,18 +2077,18 @@ var init_install = __esm({
1935
2077
  label: "flydocs/knowledge/product/user-flows.md"
1936
2078
  },
1937
2079
  {
1938
- src: join12(templateDir, "flydocs", "design-system", "README.md"),
1939
- 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"),
1940
2082
  label: "flydocs/design-system/README.md"
1941
2083
  },
1942
2084
  {
1943
- src: join12(
2085
+ src: join13(
1944
2086
  templateDir,
1945
2087
  "flydocs",
1946
2088
  "design-system",
1947
2089
  "component-patterns.md"
1948
2090
  ),
1949
- dest: join12(
2091
+ dest: join13(
1950
2092
  targetDir,
1951
2093
  "flydocs",
1952
2094
  "design-system",
@@ -1955,13 +2097,13 @@ var init_install = __esm({
1955
2097
  label: "flydocs/design-system/component-patterns.md"
1956
2098
  },
1957
2099
  {
1958
- src: join12(templateDir, "flydocs", "design-system", "token-mapping.md"),
1959
- 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"),
1960
2102
  label: "flydocs/design-system/token-mapping.md"
1961
2103
  },
1962
2104
  {
1963
- src: join12(templateDir, "flydocs", "README.md"),
1964
- dest: join12(targetDir, "flydocs", "README.md"),
2105
+ src: join13(templateDir, "flydocs", "README.md"),
2106
+ dest: join13(targetDir, "flydocs", "README.md"),
1965
2107
  label: "flydocs/README.md"
1966
2108
  }
1967
2109
  ];
@@ -1975,9 +2117,9 @@ var init_install = __esm({
1975
2117
  }
1976
2118
  }
1977
2119
  }
1978
- const envExampleSrc = join12(templateDir, ".env.example");
2120
+ const envExampleSrc = join13(templateDir, ".env.example");
1979
2121
  if (await pathExists(envExampleSrc)) {
1980
- await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
2122
+ await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
1981
2123
  printStatus(".env.example");
1982
2124
  }
1983
2125
  await ensureGitignore(targetDir);
@@ -1996,6 +2138,9 @@ var init_install = __esm({
1996
2138
  } else {
1997
2139
  printInfo("No framework detected in package.json");
1998
2140
  }
2141
+ await capture("install_skills_chosen", {
2142
+ stack_detected: stack.raw
2143
+ });
1999
2144
  console.log();
2000
2145
  console.log("Checking for deprecated files...");
2001
2146
  const deprecated = await scanDeprecated(targetDir);
@@ -2037,6 +2182,7 @@ var init_install = __esm({
2037
2182
  }
2038
2183
  printCompletionBox("Installation Complete!", nextSteps);
2039
2184
  printBetaCta();
2185
+ const detectedIdes = [];
2040
2186
  try {
2041
2187
  const { execSync: execSync2, spawn } = await import("child_process");
2042
2188
  const isInstalled = (cmd) => {
@@ -2072,6 +2218,7 @@ var init_install = __esm({
2072
2218
  passCommand: false
2073
2219
  });
2074
2220
  }
2221
+ detectedIdes.push(...ideOptions.map((o) => o.cmd));
2075
2222
  if (ideOptions.length === 1) {
2076
2223
  const ide = ideOptions[0];
2077
2224
  const launchConfirm = await confirm2({
@@ -2130,6 +2277,9 @@ var init_install = __esm({
2130
2277
  }
2131
2278
  } catch {
2132
2279
  }
2280
+ await capture("install_ide_detected", { ides: detectedIdes });
2281
+ await capture("install_completed", { tier, version });
2282
+ await flush();
2133
2283
  try {
2134
2284
  const updateResult = await checkForUpdate();
2135
2285
  if (updateResult) {
@@ -2148,8 +2298,8 @@ __export(update_exports, {
2148
2298
  default: () => update_default
2149
2299
  });
2150
2300
  import { defineCommand as defineCommand2 } from "citty";
2151
- import { resolve as resolve3, join as join13 } from "path";
2152
- 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";
2153
2303
  import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
2154
2304
  import pc7 from "picocolors";
2155
2305
  var update_default;
@@ -2168,6 +2318,7 @@ var init_update = __esm({
2168
2318
  init_gitignore();
2169
2319
  init_post_install();
2170
2320
  init_update_check();
2321
+ init_telemetry();
2171
2322
  update_default = defineCommand2({
2172
2323
  meta: {
2173
2324
  name: "update",
@@ -2210,6 +2361,7 @@ var init_update = __esm({
2210
2361
  printBanner(version);
2211
2362
  printInfo("Running in update mode \u2014 framework files will be refreshed");
2212
2363
  console.log();
2364
+ await capture("update_started", { template_version: version });
2213
2365
  let targetDir;
2214
2366
  if (args.path) {
2215
2367
  targetDir = resolve3(args.path.replace(/^~/, process.env.HOME ?? "~"));
@@ -2254,9 +2406,9 @@ var init_update = __esm({
2254
2406
  }
2255
2407
  targetDir = resolve3(targetDir);
2256
2408
  process.chdir(targetDir);
2257
- const hasVersion = await pathExists(join13(targetDir, ".flydocs", "version"));
2409
+ const hasVersion = await pathExists(join14(targetDir, ".flydocs", "version"));
2258
2410
  const hasConfig = await pathExists(
2259
- join13(targetDir, ".flydocs", "config.json")
2411
+ join14(targetDir, ".flydocs", "config.json")
2260
2412
  );
2261
2413
  if (!hasVersion && !hasConfig) {
2262
2414
  printError(`Not a FlyDocs project: ${targetDir}`);
@@ -2267,8 +2419,8 @@ var init_update = __esm({
2267
2419
  console.log();
2268
2420
  let currentVersion = "0.1.0";
2269
2421
  if (hasVersion) {
2270
- const vContent = await readFile8(
2271
- join13(targetDir, ".flydocs", "version"),
2422
+ const vContent = await readFile9(
2423
+ join14(targetDir, ".flydocs", "version"),
2272
2424
  "utf-8"
2273
2425
  );
2274
2426
  currentVersion = vContent.trim();
@@ -2294,9 +2446,15 @@ var init_update = __esm({
2294
2446
  process.exit(0);
2295
2447
  }
2296
2448
  }
2449
+ await capture("update_version_compared", {
2450
+ current_version: currentVersion,
2451
+ target_version: version,
2452
+ version_status: versionStatus,
2453
+ force: args.force
2454
+ });
2297
2455
  console.log(`Updating: v${currentVersion} \u2192 v${version}`);
2298
2456
  console.log();
2299
- const changelogPath = join13(templateDir, "CHANGELOG.md");
2457
+ const changelogPath = join14(templateDir, "CHANGELOG.md");
2300
2458
  const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
2301
2459
  if (whatsNew.length > 0) {
2302
2460
  console.log(pc7.cyan("What's new:"));
@@ -2308,23 +2466,23 @@ var init_update = __esm({
2308
2466
  }
2309
2467
  const now = /* @__PURE__ */ new Date();
2310
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")}`;
2311
- const backupDir = join13(targetDir, ".flydocs", `backup-${ts}`);
2312
- await mkdir6(backupDir, { recursive: true });
2469
+ const backupDir = join14(targetDir, ".flydocs", `backup-${ts}`);
2470
+ await mkdir7(backupDir, { recursive: true });
2313
2471
  if (hasConfig) {
2314
2472
  await cp2(
2315
- join13(targetDir, ".flydocs", "config.json"),
2316
- join13(backupDir, "config.json")
2473
+ join14(targetDir, ".flydocs", "config.json"),
2474
+ join14(backupDir, "config.json")
2317
2475
  );
2318
2476
  printStatus(`Config backed up to .flydocs/backup-${ts}/`);
2319
2477
  }
2320
2478
  try {
2321
- const flydocsDir = join13(targetDir, ".flydocs");
2479
+ const flydocsDir = join14(targetDir, ".flydocs");
2322
2480
  const entries = await readdir3(flydocsDir);
2323
2481
  const backups = entries.filter((e) => e.startsWith("backup-")).sort();
2324
2482
  if (backups.length > 3) {
2325
2483
  const toRemove = backups.slice(0, backups.length - 3);
2326
2484
  for (const old of toRemove) {
2327
- await rm4(join13(flydocsDir, old), { recursive: true, force: true });
2485
+ await rm4(join14(flydocsDir, old), { recursive: true, force: true });
2328
2486
  }
2329
2487
  }
2330
2488
  } catch {
@@ -2361,20 +2519,20 @@ var init_update = __esm({
2361
2519
  }
2362
2520
  console.log("Replacing framework directories...");
2363
2521
  await replaceDirectory(
2364
- join13(templateDir, ".flydocs", "templates"),
2365
- join13(targetDir, ".flydocs", "templates")
2522
+ join14(templateDir, ".flydocs", "templates"),
2523
+ join14(targetDir, ".flydocs", "templates")
2366
2524
  );
2367
2525
  await replaceDirectory(
2368
- join13(templateDir, ".flydocs", "hooks"),
2369
- join13(targetDir, ".flydocs", "hooks")
2526
+ join14(templateDir, ".flydocs", "hooks"),
2527
+ join14(targetDir, ".flydocs", "hooks")
2370
2528
  );
2371
2529
  await replaceDirectory(
2372
- join13(templateDir, ".flydocs", "scripts"),
2373
- join13(targetDir, ".flydocs", "scripts")
2530
+ join14(templateDir, ".flydocs", "scripts"),
2531
+ join14(targetDir, ".flydocs", "scripts")
2374
2532
  );
2375
2533
  printStatus(".flydocs/templates, hooks, scripts");
2376
2534
  const hasExistingAgents = await pathExists(
2377
- join13(targetDir, ".claude", "agents")
2535
+ join14(targetDir, ".claude", "agents")
2378
2536
  );
2379
2537
  let installAgents;
2380
2538
  if (args.yes) {
@@ -2406,20 +2564,20 @@ var init_update = __esm({
2406
2564
  }
2407
2565
  }
2408
2566
  if (installAgents) {
2409
- const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
2567
+ const claudeAgentsSrc = join14(templateDir, ".claude", "agents");
2410
2568
  if (await pathExists(claudeAgentsSrc)) {
2411
- await mkdir6(join13(targetDir, ".claude", "agents"), { recursive: true });
2569
+ await mkdir7(join14(targetDir, ".claude", "agents"), { recursive: true });
2412
2570
  await copyDirectoryContents(
2413
2571
  claudeAgentsSrc,
2414
- join13(targetDir, ".claude", "agents")
2572
+ join14(targetDir, ".claude", "agents")
2415
2573
  );
2416
2574
  }
2417
- const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
2575
+ const cursorAgentsSrc = join14(templateDir, ".cursor", "agents");
2418
2576
  if (await pathExists(cursorAgentsSrc)) {
2419
- await mkdir6(join13(targetDir, ".cursor", "agents"), { recursive: true });
2577
+ await mkdir7(join14(targetDir, ".cursor", "agents"), { recursive: true });
2420
2578
  await copyDirectoryContents(
2421
2579
  cursorAgentsSrc,
2422
- join13(targetDir, ".cursor", "agents")
2580
+ join14(targetDir, ".cursor", "agents")
2423
2581
  );
2424
2582
  }
2425
2583
  printStatus(
@@ -2433,44 +2591,44 @@ var init_update = __esm({
2433
2591
  console.log();
2434
2592
  console.log("Replacing framework files...");
2435
2593
  await copyFile(
2436
- join13(templateDir, ".claude", "CLAUDE.md"),
2437
- join13(targetDir, ".claude", "CLAUDE.md")
2594
+ join14(templateDir, ".claude", "CLAUDE.md"),
2595
+ join14(targetDir, ".claude", "CLAUDE.md")
2438
2596
  );
2439
2597
  await copyFile(
2440
- join13(templateDir, ".claude", "settings.json"),
2441
- join13(targetDir, ".claude", "settings.json")
2598
+ join14(templateDir, ".claude", "settings.json"),
2599
+ join14(targetDir, ".claude", "settings.json")
2442
2600
  );
2443
2601
  printStatus(".claude/CLAUDE.md, settings.json");
2444
2602
  await copyDirectoryContents(
2445
- join13(templateDir, ".claude", "commands"),
2446
- join13(targetDir, ".claude", "commands")
2603
+ join14(templateDir, ".claude", "commands"),
2604
+ join14(targetDir, ".claude", "commands")
2447
2605
  );
2448
2606
  await copyDirectoryContents(
2449
- join13(templateDir, ".claude", "commands"),
2450
- join13(targetDir, ".cursor", "commands")
2607
+ join14(templateDir, ".claude", "commands"),
2608
+ join14(targetDir, ".cursor", "commands")
2451
2609
  );
2452
2610
  printStatus(".claude/commands, .cursor/commands");
2453
- const skillsReadmeSrc = join13(templateDir, ".claude", "skills", "README.md");
2611
+ const skillsReadmeSrc = join14(templateDir, ".claude", "skills", "README.md");
2454
2612
  if (await pathExists(skillsReadmeSrc)) {
2455
2613
  await copyFile(
2456
2614
  skillsReadmeSrc,
2457
- join13(targetDir, ".claude", "skills", "README.md")
2615
+ join14(targetDir, ".claude", "skills", "README.md")
2458
2616
  );
2459
2617
  }
2460
2618
  printStatus(".claude/skills/README.md");
2461
2619
  await copyFile(
2462
- join13(templateDir, ".cursor", "hooks.json"),
2463
- join13(targetDir, ".cursor", "hooks.json")
2620
+ join14(templateDir, ".cursor", "hooks.json"),
2621
+ join14(targetDir, ".cursor", "hooks.json")
2464
2622
  );
2465
2623
  printStatus(".cursor/hooks.json");
2466
2624
  await copyFile(
2467
- join13(templateDir, "AGENTS.md"),
2468
- join13(targetDir, "AGENTS.md")
2625
+ join14(templateDir, "AGENTS.md"),
2626
+ join14(targetDir, "AGENTS.md")
2469
2627
  );
2470
2628
  printStatus("AGENTS.md");
2471
- const envExampleSrc = join13(templateDir, ".env.example");
2629
+ const envExampleSrc = join14(templateDir, ".env.example");
2472
2630
  if (await pathExists(envExampleSrc)) {
2473
- await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
2631
+ await copyFile(envExampleSrc, join14(targetDir, ".env.example"));
2474
2632
  printStatus(".env.example");
2475
2633
  }
2476
2634
  await runManifestGeneration(targetDir);
@@ -2495,18 +2653,18 @@ var init_update = __esm({
2495
2653
  printWarning("Config merge failed \u2014 config.json preserved as-is");
2496
2654
  }
2497
2655
  await copyFile(
2498
- join13(templateDir, ".flydocs", "version"),
2499
- join13(targetDir, ".flydocs", "version")
2656
+ join14(templateDir, ".flydocs", "version"),
2657
+ join14(targetDir, ".flydocs", "version")
2500
2658
  );
2501
2659
  printStatus(`.flydocs/version \u2192 ${version}`);
2502
- const clSrc = join13(templateDir, "CHANGELOG.md");
2660
+ const clSrc = join14(templateDir, "CHANGELOG.md");
2503
2661
  if (await pathExists(clSrc)) {
2504
- await copyFile(clSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
2662
+ await copyFile(clSrc, join14(targetDir, ".flydocs", "CHANGELOG.md"));
2505
2663
  printStatus(".flydocs/CHANGELOG.md");
2506
2664
  }
2507
- const mfSrc = join13(templateDir, "manifest.json");
2665
+ const mfSrc = join14(templateDir, "manifest.json");
2508
2666
  if (await pathExists(mfSrc)) {
2509
- await copyFile(mfSrc, join13(targetDir, ".flydocs", "manifest.json"));
2667
+ await copyFile(mfSrc, join14(targetDir, ".flydocs", "manifest.json"));
2510
2668
  printStatus(".flydocs/manifest.json");
2511
2669
  }
2512
2670
  console.log();
@@ -2542,6 +2700,12 @@ var init_update = __esm({
2542
2700
  `Backup: .flydocs/backup-${ts}/`
2543
2701
  ]);
2544
2702
  printBetaCta();
2703
+ await capture("update_completed", {
2704
+ current_version: currentVersion,
2705
+ version,
2706
+ tier: effectiveTier
2707
+ });
2708
+ await flush();
2545
2709
  try {
2546
2710
  const updateResult = await checkForUpdate();
2547
2711
  if (updateResult) {
@@ -2554,33 +2718,336 @@ var init_update = __esm({
2554
2718
  }
2555
2719
  });
2556
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
+
2557
3024
  // src/commands/setup.ts
2558
3025
  var setup_exports = {};
2559
3026
  __export(setup_exports, {
2560
3027
  default: () => setup_default
2561
3028
  });
2562
- import { defineCommand as defineCommand3 } from "citty";
2563
- import pc8 from "picocolors";
3029
+ import { defineCommand as defineCommand4 } from "citty";
3030
+ import pc9 from "picocolors";
2564
3031
  var setup_default;
2565
3032
  var init_setup = __esm({
2566
3033
  "src/commands/setup.ts"() {
2567
3034
  "use strict";
2568
- setup_default = defineCommand3({
3035
+ setup_default = defineCommand4({
2569
3036
  meta: {
2570
3037
  name: "setup",
2571
3038
  description: "Configure FlyDocs settings for this project"
2572
3039
  },
2573
3040
  run() {
2574
3041
  console.log();
2575
- console.log(` ${pc8.bold("FlyDocs Setup")}`);
3042
+ console.log(` ${pc9.bold("FlyDocs Setup")}`);
2576
3043
  console.log();
2577
3044
  console.log(` Setup runs inside your IDE as an interactive AI command.`);
2578
3045
  console.log();
2579
3046
  console.log(
2580
- ` ${pc8.cyan("Claude Code:")} Type ${pc8.bold("/flydocs-setup")} in chat`
3047
+ ` ${pc9.cyan("Claude Code:")} Type ${pc9.bold("/flydocs-setup")} in chat`
2581
3048
  );
2582
3049
  console.log(
2583
- ` ${pc8.cyan("Cursor:")} Type ${pc8.bold("/flydocs-setup")} in chat`
3050
+ ` ${pc9.cyan("Cursor:")} Type ${pc9.bold("/flydocs-setup")} in chat`
2584
3051
  );
2585
3052
  console.log();
2586
3053
  console.log(` This configures your project context, detects your stack,`);
@@ -2596,14 +3063,14 @@ var skills_exports = {};
2596
3063
  __export(skills_exports, {
2597
3064
  default: () => skills_default
2598
3065
  });
2599
- import { defineCommand as defineCommand4 } from "citty";
2600
- import pc9 from "picocolors";
3066
+ import { defineCommand as defineCommand5 } from "citty";
3067
+ import pc10 from "picocolors";
2601
3068
  var list, search, add, remove, skills_default;
2602
3069
  var init_skills2 = __esm({
2603
3070
  "src/commands/skills.ts"() {
2604
3071
  "use strict";
2605
3072
  init_skill_manager();
2606
- list = defineCommand4({
3073
+ list = defineCommand5({
2607
3074
  meta: {
2608
3075
  name: "list",
2609
3076
  description: "List installed skills"
@@ -2619,26 +3086,26 @@ var init_skills2 = __esm({
2619
3086
  console.log(`${total} skill(s) installed:`);
2620
3087
  if (result.platform.length > 0) {
2621
3088
  console.log();
2622
- console.log(pc9.bold("Platform"));
3089
+ console.log(pc10.bold("Platform"));
2623
3090
  for (const skill of result.platform) {
2624
3091
  console.log(
2625
- ` ${skill.name} ${pc9.dim(`(${skill.triggers} triggers)`)}`
3092
+ ` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
2626
3093
  );
2627
3094
  }
2628
3095
  }
2629
3096
  if (result.community.length > 0) {
2630
3097
  console.log();
2631
- console.log(pc9.bold("Community"));
3098
+ console.log(pc10.bold("Community"));
2632
3099
  for (const skill of result.community) {
2633
3100
  console.log(
2634
- ` ${skill.name} ${pc9.dim(`(${skill.triggers} triggers)`)}`
3101
+ ` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
2635
3102
  );
2636
3103
  }
2637
3104
  }
2638
3105
  console.log();
2639
3106
  }
2640
3107
  });
2641
- search = defineCommand4({
3108
+ search = defineCommand5({
2642
3109
  meta: {
2643
3110
  name: "search",
2644
3111
  description: "Search community skills"
@@ -2654,24 +3121,24 @@ var init_skills2 = __esm({
2654
3121
  const results = await searchCatalog(args.keyword);
2655
3122
  if (results.length === 0) {
2656
3123
  console.log(`No skills found for "${args.keyword}".`);
2657
- console.log(` Browse the catalog at: ${pc9.cyan("https://skills.sh/")}`);
3124
+ console.log(` Browse the catalog at: ${pc10.cyan("https://skills.sh/")}`);
2658
3125
  return;
2659
3126
  }
2660
3127
  console.log();
2661
3128
  console.log(`${results.length} skill(s) matching "${args.keyword}":`);
2662
3129
  console.log();
2663
3130
  for (const skill of results) {
2664
- console.log(` ${pc9.bold(skill.name)}`);
3131
+ console.log(` ${pc10.bold(skill.name)}`);
2665
3132
  console.log(` ${skill.description}`);
2666
- console.log(` ${pc9.dim(skill.repo)}`);
3133
+ console.log(` ${pc10.dim(skill.repo)}`);
2667
3134
  if (skill.tags.length > 0) {
2668
- console.log(` ${pc9.dim(skill.tags.join(", "))}`);
3135
+ console.log(` ${pc10.dim(skill.tags.join(", "))}`);
2669
3136
  }
2670
3137
  console.log();
2671
3138
  }
2672
3139
  }
2673
3140
  });
2674
- add = defineCommand4({
3141
+ add = defineCommand5({
2675
3142
  meta: {
2676
3143
  name: "add",
2677
3144
  description: "Install a community skill"
@@ -2687,7 +3154,7 @@ var init_skills2 = __esm({
2687
3154
  await addSkill(process.cwd(), args.source);
2688
3155
  }
2689
3156
  });
2690
- remove = defineCommand4({
3157
+ remove = defineCommand5({
2691
3158
  meta: {
2692
3159
  name: "remove",
2693
3160
  description: "Remove an installed community skill"
@@ -2703,7 +3170,7 @@ var init_skills2 = __esm({
2703
3170
  await removeSkill(process.cwd(), args.name);
2704
3171
  }
2705
3172
  });
2706
- skills_default = defineCommand4({
3173
+ skills_default = defineCommand5({
2707
3174
  meta: {
2708
3175
  name: "skills",
2709
3176
  description: "Manage FlyDocs skills (list, search, add, remove)"
@@ -2723,11 +3190,11 @@ var connect_exports = {};
2723
3190
  __export(connect_exports, {
2724
3191
  default: () => connect_default
2725
3192
  });
2726
- import { defineCommand as defineCommand5 } from "citty";
2727
- import { text as text2, confirm as confirm4, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2728
- import pc10 from "picocolors";
2729
- import { readFile as readFile9, writeFile as writeFile5, appendFile as appendFile2 } from "fs/promises";
2730
- 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";
2731
3198
  var connect_default;
2732
3199
  var init_connect = __esm({
2733
3200
  "src/commands/connect.ts"() {
@@ -2736,7 +3203,7 @@ var init_connect = __esm({
2736
3203
  init_fs_ops();
2737
3204
  init_template();
2738
3205
  init_ui();
2739
- connect_default = defineCommand5({
3206
+ connect_default = defineCommand6({
2740
3207
  meta: {
2741
3208
  name: "connect",
2742
3209
  description: "Connect FlyDocs to a cloud provider (Linear)"
@@ -2761,11 +3228,11 @@ var init_connect = __esm({
2761
3228
  },
2762
3229
  async run({ args }) {
2763
3230
  const targetDir = args.path ?? process.cwd();
2764
- const configPath = join14(targetDir, ".flydocs", "config.json");
3231
+ const configPath = join16(targetDir, ".flydocs", "config.json");
2765
3232
  if (!await pathExists(configPath)) {
2766
3233
  printError("Not a FlyDocs project (.flydocs/config.json not found).");
2767
3234
  console.log(
2768
- ` Run ${pc10.cyan("flydocs")} first to install FlyDocs in this project.`
3235
+ ` Run ${pc11.cyan("flydocs")} first to install FlyDocs in this project.`
2769
3236
  );
2770
3237
  process.exit(1);
2771
3238
  }
@@ -2773,19 +3240,19 @@ var init_connect = __esm({
2773
3240
  if (config.tier === "cloud") {
2774
3241
  printInfo("This project is already connected to the cloud tier.");
2775
3242
  console.log();
2776
- const reconnect = await confirm4({
3243
+ const reconnect = await confirm5({
2777
3244
  message: "Want to update your API key?"
2778
3245
  });
2779
- if (isCancel5(reconnect) || !reconnect) {
3246
+ if (isCancel6(reconnect) || !reconnect) {
2780
3247
  console.log(` No changes made.`);
2781
3248
  return;
2782
3249
  }
2783
3250
  }
2784
3251
  console.log();
2785
- console.log(` ${pc10.bold("Connect to Linear")}`);
3252
+ console.log(` ${pc11.bold("Connect to Linear")}`);
2786
3253
  console.log();
2787
3254
  console.log(
2788
- ` ${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")}`
2789
3256
  );
2790
3257
  console.log();
2791
3258
  let apiKey = args.key ?? "";
@@ -2800,8 +3267,8 @@ var init_connect = __esm({
2800
3267
  return void 0;
2801
3268
  }
2802
3269
  });
2803
- if (isCancel5(keyInput)) {
2804
- cancel4("Connection cancelled.");
3270
+ if (isCancel6(keyInput)) {
3271
+ cancel5("Connection cancelled.");
2805
3272
  process.exit(0);
2806
3273
  }
2807
3274
  apiKey = keyInput;
@@ -2825,34 +3292,34 @@ var init_connect = __esm({
2825
3292
  throw new Error("Invalid response");
2826
3293
  }
2827
3294
  const viewer = data.data.viewer;
2828
- printStatus(`Authenticated as ${pc10.bold(viewer.name)} (${viewer.email})`);
3295
+ printStatus(`Authenticated as ${pc11.bold(viewer.name)} (${viewer.email})`);
2829
3296
  } catch {
2830
3297
  printError("Invalid API key or network error.");
2831
3298
  console.log(` Check your key and try again.`);
2832
3299
  process.exit(1);
2833
3300
  }
2834
- const envPath = join14(targetDir, ".env");
2835
- const envLocalPath = join14(targetDir, ".env.local");
3301
+ const envPath = join16(targetDir, ".env");
3302
+ const envLocalPath = join16(targetDir, ".env.local");
2836
3303
  const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
2837
3304
  if (await pathExists(targetEnvPath)) {
2838
- const envContent = await readFile9(targetEnvPath, "utf-8");
3305
+ const envContent = await readFile10(targetEnvPath, "utf-8");
2839
3306
  if (envContent.includes("LINEAR_API_KEY=")) {
2840
3307
  const updated = envContent.replace(
2841
3308
  /LINEAR_API_KEY=.*/,
2842
3309
  `LINEAR_API_KEY=${apiKey}`
2843
3310
  );
2844
- await writeFile5(targetEnvPath, updated, "utf-8");
3311
+ await writeFile6(targetEnvPath, updated, "utf-8");
2845
3312
  } else {
2846
3313
  await appendFile2(targetEnvPath, `
2847
3314
  LINEAR_API_KEY=${apiKey}
2848
3315
  `);
2849
3316
  }
2850
3317
  } else {
2851
- await writeFile5(targetEnvPath, `LINEAR_API_KEY=${apiKey}
3318
+ await writeFile6(targetEnvPath, `LINEAR_API_KEY=${apiKey}
2852
3319
  `, "utf-8");
2853
3320
  }
2854
3321
  printStatus(
2855
- `API key stored in ${pc10.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
3322
+ `API key stored in ${pc11.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
2856
3323
  );
2857
3324
  const wasLocal = config.tier === "local";
2858
3325
  config.tier = "cloud";
@@ -2865,16 +3332,16 @@ LINEAR_API_KEY=${apiKey}
2865
3332
  const templateDir = await resolveTemplatePath(
2866
3333
  args["local-source"] || void 0
2867
3334
  );
2868
- const templateSkillsDir = join14(templateDir, ".claude", "skills");
2869
- const skillsDir = join14(targetDir, ".claude", "skills");
3335
+ const templateSkillsDir = join16(templateDir, ".claude", "skills");
3336
+ const skillsDir = join16(targetDir, ".claude", "skills");
2870
3337
  await replaceDirectory(
2871
- join14(templateSkillsDir, "flydocs-cloud"),
2872
- join14(skillsDir, "flydocs-cloud")
3338
+ join16(templateSkillsDir, "flydocs-cloud"),
3339
+ join16(skillsDir, "flydocs-cloud")
2873
3340
  );
2874
- const { rm: rm5 } = await import("fs/promises");
2875
- const localSkillDir = join14(skillsDir, "flydocs-local");
3341
+ const { rm: rm6 } = await import("fs/promises");
3342
+ const localSkillDir = join16(skillsDir, "flydocs-local");
2876
3343
  if (await pathExists(localSkillDir)) {
2877
- await rm5(localSkillDir, { recursive: true, force: true });
3344
+ await rm6(localSkillDir, { recursive: true, force: true });
2878
3345
  }
2879
3346
  printStatus("Cloud mechanism skill installed");
2880
3347
  } catch {
@@ -2885,14 +3352,14 @@ LINEAR_API_KEY=${apiKey}
2885
3352
  }
2886
3353
  console.log();
2887
3354
  console.log(
2888
- ` ${pc10.bold("Connected!")} Your project now syncs with Linear.`
3355
+ ` ${pc11.bold("Connected!")} Your project now syncs with Linear.`
2889
3356
  );
2890
3357
  console.log();
2891
3358
  console.log(` Next steps:`);
2892
3359
  console.log(
2893
- ` 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`
2894
3361
  );
2895
- console.log(` 2. Run ${pc10.cyan("/start-session")} to begin working`);
3362
+ console.log(` 2. Run ${pc11.cyan("/start-session")} to begin working`);
2896
3363
  console.log();
2897
3364
  }
2898
3365
  });
@@ -2904,15 +3371,15 @@ var upgrade_exports = {};
2904
3371
  __export(upgrade_exports, {
2905
3372
  default: () => upgrade_default
2906
3373
  });
2907
- import { defineCommand as defineCommand6 } from "citty";
2908
- import pc11 from "picocolors";
3374
+ import { defineCommand as defineCommand7 } from "citty";
3375
+ import pc12 from "picocolors";
2909
3376
  var upgrade_default;
2910
3377
  var init_upgrade = __esm({
2911
3378
  "src/commands/upgrade.ts"() {
2912
3379
  "use strict";
2913
3380
  init_config();
2914
3381
  init_fs_ops();
2915
- upgrade_default = defineCommand6({
3382
+ upgrade_default = defineCommand7({
2916
3383
  meta: {
2917
3384
  name: "upgrade",
2918
3385
  description: "Learn about FlyDocs Cloud tier and upgrade from local"
@@ -2941,37 +3408,37 @@ var init_upgrade = __esm({
2941
3408
  console.log();
2942
3409
  if (currentTier === "cloud") {
2943
3410
  console.log(
2944
- ` ${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.`
2945
3412
  );
2946
3413
  console.log();
2947
3414
  console.log(
2948
3415
  ` Your issues sync with Linear via the cloud mechanism skill.`
2949
3416
  );
2950
3417
  console.log(
2951
- ` Run ${pc11.cyan("flydocs connect")} to update your connection settings.`
3418
+ ` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
2952
3419
  );
2953
3420
  console.log();
2954
3421
  return;
2955
3422
  }
2956
- console.log(` ${pc11.bold("FlyDocs Cloud Tier")}`);
3423
+ console.log(` ${pc12.bold("FlyDocs Cloud Tier")}`);
2957
3424
  console.log();
2958
- console.log(` You're currently on the ${pc11.yellow("local")} tier.`);
3425
+ console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
2959
3426
  console.log(` Upgrade to cloud for:`);
2960
3427
  console.log();
2961
3428
  console.log(
2962
- ` ${pc11.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
3429
+ ` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2963
3430
  );
2964
- console.log(` ${pc11.cyan("\u2192")} Project milestones and cycle management`);
2965
- console.log(` ${pc11.cyan("\u2192")} Team assignment and priority tracking`);
2966
- console.log(` ${pc11.cyan("\u2192")} Project health updates and dashboards`);
2967
- 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`);
2968
3435
  console.log();
2969
- console.log(` ${pc11.bold("How to upgrade:")}`);
3436
+ console.log(` ${pc12.bold("How to upgrade:")}`);
2970
3437
  console.log();
2971
- 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")}`);
2972
3439
  console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
2973
3440
  console.log(
2974
- ` 3. Run ${pc11.cyan("flydocs connect")} to connect your project`
3441
+ ` 3. Run ${pc12.cyan("flydocs connect")} to connect your project`
2975
3442
  );
2976
3443
  console.log();
2977
3444
  }
@@ -2984,23 +3451,23 @@ var self_update_exports = {};
2984
3451
  __export(self_update_exports, {
2985
3452
  default: () => self_update_default
2986
3453
  });
2987
- import { defineCommand as defineCommand7 } from "citty";
3454
+ import { defineCommand as defineCommand8 } from "citty";
2988
3455
  import { execSync } from "child_process";
2989
- import pc12 from "picocolors";
3456
+ import pc13 from "picocolors";
2990
3457
  var self_update_default;
2991
3458
  var init_self_update = __esm({
2992
3459
  "src/commands/self-update.ts"() {
2993
3460
  "use strict";
2994
3461
  init_constants();
2995
3462
  init_ui();
2996
- self_update_default = defineCommand7({
3463
+ self_update_default = defineCommand8({
2997
3464
  meta: {
2998
3465
  name: "self-update",
2999
3466
  description: "Update FlyDocs CLI to the latest version"
3000
3467
  },
3001
3468
  async run() {
3002
3469
  console.log();
3003
- console.log(` Updating ${pc12.cyan(PACKAGE_NAME)}...`);
3470
+ console.log(` Updating ${pc13.cyan(PACKAGE_NAME)}...`);
3004
3471
  console.log();
3005
3472
  try {
3006
3473
  execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
@@ -3020,17 +3487,117 @@ var init_self_update = __esm({
3020
3487
  }
3021
3488
  });
3022
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
+
3023
3588
  // src/cli.ts
3024
3589
  init_constants();
3025
- import { defineCommand as defineCommand8, runMain } from "citty";
3590
+ import { defineCommand as defineCommand10, runMain } from "citty";
3026
3591
  var SUB_COMMANDS = /* @__PURE__ */ new Set([
3027
3592
  "install",
3028
3593
  "update",
3594
+ "uninstall",
3029
3595
  "setup",
3030
3596
  "skills",
3031
3597
  "connect",
3032
3598
  "upgrade",
3033
- "self-update"
3599
+ "self-update",
3600
+ "telemetry"
3034
3601
  ]);
3035
3602
  var userArgs = process.argv.slice(2);
3036
3603
  var hasMetaFlag = userArgs.some(
@@ -3040,7 +3607,7 @@ var firstPositional = userArgs.find((a) => !a.startsWith("-"));
3040
3607
  if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
3041
3608
  process.argv.splice(2, 0, "install");
3042
3609
  }
3043
- var main = defineCommand8({
3610
+ var main = defineCommand10({
3044
3611
  meta: {
3045
3612
  name: CLI_NAME,
3046
3613
  version: CLI_VERSION,
@@ -3049,11 +3616,13 @@ var main = defineCommand8({
3049
3616
  subCommands: {
3050
3617
  install: () => Promise.resolve().then(() => (init_install(), install_exports)).then((m) => m.default),
3051
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),
3052
3620
  setup: () => Promise.resolve().then(() => (init_setup(), setup_exports)).then((m) => m.default),
3053
3621
  skills: () => Promise.resolve().then(() => (init_skills2(), skills_exports)).then((m) => m.default),
3054
3622
  connect: () => Promise.resolve().then(() => (init_connect(), connect_exports)).then((m) => m.default),
3055
3623
  upgrade: () => Promise.resolve().then(() => (init_upgrade(), upgrade_exports)).then((m) => m.default),
3056
- "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)
3057
3626
  }
3058
3627
  });
3059
3628
  runMain(main);