@flydocs/cli 0.5.0-beta.16 → 0.5.0-beta.18

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.18";
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,139 @@ 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: false,
1678
+ anonymousId: randomUUID()
1679
+ };
1680
+ await writeConfig2(config);
1681
+ return config;
1682
+ }
1683
+ async function isEnabled() {
1684
+ try {
1685
+ if (process.env.FLYDOCS_TELEMETRY === "0") {
1686
+ return false;
1687
+ }
1688
+ const config = await readConfig2();
1689
+ if (config) {
1690
+ return config.enabled;
1691
+ }
1692
+ return false;
1693
+ } catch {
1694
+ return false;
1695
+ }
1696
+ }
1697
+ function baseProperties() {
1698
+ return {
1699
+ cli_version: CLI_VERSION,
1700
+ os: process.platform,
1701
+ os_arch: process.arch,
1702
+ node_version: process.version,
1703
+ is_ci: Boolean(
1704
+ process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.BUILD_NUMBER
1705
+ ),
1706
+ $ip: null,
1707
+ $process_person_profile: false
1708
+ };
1709
+ }
1710
+ async function capture(event, properties = {}) {
1711
+ try {
1712
+ if (!await isEnabled()) {
1713
+ return;
1714
+ }
1715
+ const config = await ensureConfig();
1716
+ eventQueue.push({
1717
+ event,
1718
+ properties: {
1719
+ distinct_id: config.anonymousId,
1720
+ ...baseProperties(),
1721
+ ...properties
1722
+ },
1723
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1724
+ });
1725
+ } catch {
1726
+ }
1727
+ }
1728
+ async function flush() {
1729
+ try {
1730
+ if (eventQueue.length === 0) {
1731
+ return;
1732
+ }
1733
+ if (!await isEnabled()) {
1734
+ eventQueue.length = 0;
1735
+ return;
1736
+ }
1737
+ const batch = eventQueue.splice(0, eventQueue.length);
1738
+ const controller = new AbortController();
1739
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
1740
+ await fetch(POSTHOG_BATCH_URL, {
1741
+ method: "POST",
1742
+ headers: { "Content-Type": "application/json" },
1743
+ body: JSON.stringify({
1744
+ api_key: POSTHOG_API_KEY,
1745
+ batch
1746
+ }),
1747
+ signal: controller.signal
1748
+ });
1749
+ clearTimeout(timeout);
1750
+ } catch {
1751
+ }
1752
+ }
1753
+ async function setEnabled(enabled) {
1754
+ const config = await ensureConfig();
1755
+ config.enabled = enabled;
1756
+ await writeConfig2(config);
1757
+ }
1758
+ async function getStatus() {
1759
+ const envOverride = process.env.FLYDOCS_TELEMETRY === "0";
1760
+ const config = await readConfig2();
1761
+ return {
1762
+ enabled: config?.enabled ?? false,
1763
+ envOverride,
1764
+ anonymousId: config?.anonymousId ?? null
1765
+ };
1766
+ }
1767
+ var CONFIG_DIR, CONFIG_FILE, POSTHOG_BATCH_URL, FETCH_TIMEOUT_MS2, eventQueue;
1768
+ var init_telemetry = __esm({
1769
+ "src/lib/telemetry.ts"() {
1770
+ "use strict";
1771
+ init_constants();
1772
+ CONFIG_DIR = join12(homedir2(), ".flydocs");
1773
+ CONFIG_FILE = join12(CONFIG_DIR, "telemetry.json");
1774
+ POSTHOG_BATCH_URL = "https://us.i.posthog.com/batch/";
1775
+ FETCH_TIMEOUT_MS2 = 5e3;
1776
+ eventQueue = [];
1777
+ }
1778
+ });
1779
+
1646
1780
  // src/commands/install.ts
1647
1781
  var install_exports = {};
1648
1782
  __export(install_exports, {
@@ -1650,8 +1784,8 @@ __export(install_exports, {
1650
1784
  });
1651
1785
  import { defineCommand } from "citty";
1652
1786
  import { resolve as resolve2 } from "path";
1653
- import { join as join12 } from "path";
1654
- import { mkdir as mkdir5 } from "fs/promises";
1787
+ import { join as join13 } from "path";
1788
+ import { mkdir as mkdir6 } from "fs/promises";
1655
1789
  import { confirm as confirm2, select, isCancel as isCancel3, cancel as cancel2 } from "@clack/prompts";
1656
1790
  import pc6 from "picocolors";
1657
1791
  var install_default;
@@ -1669,6 +1803,7 @@ var init_install = __esm({
1669
1803
  init_gitignore();
1670
1804
  init_post_install();
1671
1805
  init_update_check();
1806
+ init_telemetry();
1672
1807
  install_default = defineCommand({
1673
1808
  meta: {
1674
1809
  name: "install",
@@ -1704,6 +1839,7 @@ var init_install = __esm({
1704
1839
  const templateDir = await resolveTemplatePath(args["local-source"]);
1705
1840
  const version = await readTemplateVersion(templateDir);
1706
1841
  printBanner(version);
1842
+ await capture("install_started", { template_version: version });
1707
1843
  let targetDir;
1708
1844
  if (args.path) {
1709
1845
  targetDir = resolve2(args.path.replace(/^~/, process.env.HOME ?? "~"));
@@ -1730,7 +1866,7 @@ var init_install = __esm({
1730
1866
  }
1731
1867
  tier = args.tier;
1732
1868
  printInfo(`Tier set via flag: ${tier}`);
1733
- } else if (await pathExists(join12(targetDir, ".flydocs", "config.json"))) {
1869
+ } else if (await pathExists(join13(targetDir, ".flydocs", "config.json"))) {
1734
1870
  try {
1735
1871
  const existing = await readConfig(targetDir);
1736
1872
  if (existing.tier) {
@@ -1752,37 +1888,38 @@ var init_install = __esm({
1752
1888
  tier = "local";
1753
1889
  console.log();
1754
1890
  }
1755
- if (!await pathExists(join12(targetDir, ".git"))) {
1891
+ await capture("install_tier_selected", { tier });
1892
+ if (!await pathExists(join13(targetDir, ".git"))) {
1756
1893
  printWarning("No git repository detected. Run git init when ready.");
1757
1894
  }
1758
1895
  await ensureDirectories(targetDir, tier);
1759
1896
  console.log("Installing framework files...");
1760
1897
  await replaceDirectory(
1761
- join12(templateDir, ".flydocs", "templates"),
1762
- join12(targetDir, ".flydocs", "templates")
1898
+ join13(templateDir, ".flydocs", "templates"),
1899
+ join13(targetDir, ".flydocs", "templates")
1763
1900
  );
1764
1901
  await replaceDirectory(
1765
- join12(templateDir, ".flydocs", "hooks"),
1766
- join12(targetDir, ".flydocs", "hooks")
1902
+ join13(templateDir, ".flydocs", "hooks"),
1903
+ join13(targetDir, ".flydocs", "hooks")
1767
1904
  );
1768
1905
  await replaceDirectory(
1769
- join12(templateDir, ".flydocs", "scripts"),
1770
- join12(targetDir, ".flydocs", "scripts")
1906
+ join13(templateDir, ".flydocs", "scripts"),
1907
+ join13(targetDir, ".flydocs", "scripts")
1771
1908
  );
1772
1909
  await copyFile(
1773
- join12(templateDir, ".flydocs", "version"),
1774
- join12(targetDir, ".flydocs", "version")
1910
+ join13(templateDir, ".flydocs", "version"),
1911
+ join13(targetDir, ".flydocs", "version")
1775
1912
  );
1776
- const manifestSrc = join12(templateDir, "manifest.json");
1913
+ const manifestSrc = join13(templateDir, "manifest.json");
1777
1914
  if (await pathExists(manifestSrc)) {
1778
- await copyFile(manifestSrc, join12(targetDir, ".flydocs", "manifest.json"));
1915
+ await copyFile(manifestSrc, join13(targetDir, ".flydocs", "manifest.json"));
1779
1916
  }
1780
- const changelogSrc = join12(templateDir, "CHANGELOG.md");
1917
+ const changelogSrc = join13(templateDir, "CHANGELOG.md");
1781
1918
  if (await pathExists(changelogSrc)) {
1782
- await copyFile(changelogSrc, join12(targetDir, ".flydocs", "CHANGELOG.md"));
1919
+ await copyFile(changelogSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
1783
1920
  }
1784
1921
  printStatus(".flydocs/templates, hooks, version, manifest, changelog");
1785
- const configPath = join12(targetDir, ".flydocs", "config.json");
1922
+ const configPath = join13(targetDir, ".flydocs", "config.json");
1786
1923
  if (!await pathExists(configPath)) {
1787
1924
  const config = await createFreshConfig(templateDir, version, tier);
1788
1925
  await writeConfig(targetDir, config);
@@ -1834,21 +1971,22 @@ var init_install = __esm({
1834
1971
  installAgents = agentConfirm;
1835
1972
  }
1836
1973
  }
1974
+ await capture("install_agents_chosen", { install_agents: installAgents });
1837
1975
  if (installAgents) {
1838
- const claudeAgentsSrc = join12(templateDir, ".claude", "agents");
1976
+ const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
1839
1977
  if (await pathExists(claudeAgentsSrc)) {
1840
- await mkdir5(join12(targetDir, ".claude", "agents"), { recursive: true });
1978
+ await mkdir6(join13(targetDir, ".claude", "agents"), { recursive: true });
1841
1979
  await copyDirectoryContents(
1842
1980
  claudeAgentsSrc,
1843
- join12(targetDir, ".claude", "agents")
1981
+ join13(targetDir, ".claude", "agents")
1844
1982
  );
1845
1983
  }
1846
- const cursorAgentsSrc = join12(templateDir, ".cursor", "agents");
1984
+ const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
1847
1985
  if (await pathExists(cursorAgentsSrc)) {
1848
- await mkdir5(join12(targetDir, ".cursor", "agents"), { recursive: true });
1986
+ await mkdir6(join13(targetDir, ".cursor", "agents"), { recursive: true });
1849
1987
  await copyDirectoryContents(
1850
1988
  cursorAgentsSrc,
1851
- join12(targetDir, ".cursor", "agents")
1989
+ join13(targetDir, ".cursor", "agents")
1852
1990
  );
1853
1991
  }
1854
1992
  printStatus("Sub-agents installed (.claude/agents, .cursor/agents)");
@@ -1858,32 +1996,32 @@ var init_install = __esm({
1858
1996
  console.log();
1859
1997
  console.log("Installing commands and settings...");
1860
1998
  await copyDirectoryContents(
1861
- join12(templateDir, ".claude", "commands"),
1862
- join12(targetDir, ".claude", "commands")
1999
+ join13(templateDir, ".claude", "commands"),
2000
+ join13(targetDir, ".claude", "commands")
1863
2001
  );
1864
2002
  await copyFile(
1865
- join12(templateDir, ".claude", "CLAUDE.md"),
1866
- join12(targetDir, ".claude", "CLAUDE.md")
2003
+ join13(templateDir, ".claude", "CLAUDE.md"),
2004
+ join13(targetDir, ".claude", "CLAUDE.md")
1867
2005
  );
1868
2006
  await copyFile(
1869
- join12(templateDir, ".claude", "settings.json"),
1870
- join12(targetDir, ".claude", "settings.json")
2007
+ join13(templateDir, ".claude", "settings.json"),
2008
+ join13(targetDir, ".claude", "settings.json")
1871
2009
  );
1872
2010
  printStatus(".claude/ (commands, CLAUDE.md, settings)");
1873
2011
  await copyDirectoryContents(
1874
- join12(templateDir, ".claude", "commands"),
1875
- join12(targetDir, ".cursor", "commands")
2012
+ join13(templateDir, ".claude", "commands"),
2013
+ join13(targetDir, ".cursor", "commands")
1876
2014
  );
1877
2015
  await copyFile(
1878
- join12(templateDir, ".cursor", "hooks.json"),
1879
- join12(targetDir, ".cursor", "hooks.json")
2016
+ join13(templateDir, ".cursor", "hooks.json"),
2017
+ join13(targetDir, ".cursor", "hooks.json")
1880
2018
  );
1881
2019
  printStatus(".cursor/ (commands, hooks)");
1882
2020
  await copyCursorRules(targetDir);
1883
2021
  printStatus(".cursor/rules/");
1884
2022
  await copyFile(
1885
- join12(templateDir, "AGENTS.md"),
1886
- join12(targetDir, "AGENTS.md")
2023
+ join13(templateDir, "AGENTS.md"),
2024
+ join13(targetDir, "AGENTS.md")
1887
2025
  );
1888
2026
  printStatus("AGENTS.md");
1889
2027
  await runManifestGeneration(targetDir);
@@ -1892,40 +2030,40 @@ var init_install = __esm({
1892
2030
  console.log("Installing project templates...");
1893
2031
  const userFiles = [
1894
2032
  {
1895
- src: join12(templateDir, "flydocs", "context", "project.md"),
1896
- dest: join12(targetDir, "flydocs", "context", "project.md"),
2033
+ src: join13(templateDir, "flydocs", "context", "project.md"),
2034
+ dest: join13(targetDir, "flydocs", "context", "project.md"),
1897
2035
  label: "flydocs/context/project.md"
1898
2036
  },
1899
2037
  {
1900
- src: join12(templateDir, "flydocs", "knowledge", "INDEX.md"),
1901
- dest: join12(targetDir, "flydocs", "knowledge", "INDEX.md"),
2038
+ src: join13(templateDir, "flydocs", "knowledge", "INDEX.md"),
2039
+ dest: join13(targetDir, "flydocs", "knowledge", "INDEX.md"),
1902
2040
  label: "flydocs/knowledge/INDEX.md"
1903
2041
  },
1904
2042
  {
1905
- src: join12(templateDir, "flydocs", "knowledge", "README.md"),
1906
- dest: join12(targetDir, "flydocs", "knowledge", "README.md"),
2043
+ src: join13(templateDir, "flydocs", "knowledge", "README.md"),
2044
+ dest: join13(targetDir, "flydocs", "knowledge", "README.md"),
1907
2045
  label: "flydocs/knowledge/README.md"
1908
2046
  },
1909
2047
  {
1910
- src: join12(
2048
+ src: join13(
1911
2049
  templateDir,
1912
2050
  "flydocs",
1913
2051
  "knowledge",
1914
2052
  "product",
1915
2053
  "personas.md"
1916
2054
  ),
1917
- dest: join12(targetDir, "flydocs", "knowledge", "product", "personas.md"),
2055
+ dest: join13(targetDir, "flydocs", "knowledge", "product", "personas.md"),
1918
2056
  label: "flydocs/knowledge/product/personas.md"
1919
2057
  },
1920
2058
  {
1921
- src: join12(
2059
+ src: join13(
1922
2060
  templateDir,
1923
2061
  "flydocs",
1924
2062
  "knowledge",
1925
2063
  "product",
1926
2064
  "user-flows.md"
1927
2065
  ),
1928
- dest: join12(
2066
+ dest: join13(
1929
2067
  targetDir,
1930
2068
  "flydocs",
1931
2069
  "knowledge",
@@ -1935,18 +2073,18 @@ var init_install = __esm({
1935
2073
  label: "flydocs/knowledge/product/user-flows.md"
1936
2074
  },
1937
2075
  {
1938
- src: join12(templateDir, "flydocs", "design-system", "README.md"),
1939
- dest: join12(targetDir, "flydocs", "design-system", "README.md"),
2076
+ src: join13(templateDir, "flydocs", "design-system", "README.md"),
2077
+ dest: join13(targetDir, "flydocs", "design-system", "README.md"),
1940
2078
  label: "flydocs/design-system/README.md"
1941
2079
  },
1942
2080
  {
1943
- src: join12(
2081
+ src: join13(
1944
2082
  templateDir,
1945
2083
  "flydocs",
1946
2084
  "design-system",
1947
2085
  "component-patterns.md"
1948
2086
  ),
1949
- dest: join12(
2087
+ dest: join13(
1950
2088
  targetDir,
1951
2089
  "flydocs",
1952
2090
  "design-system",
@@ -1955,13 +2093,13 @@ var init_install = __esm({
1955
2093
  label: "flydocs/design-system/component-patterns.md"
1956
2094
  },
1957
2095
  {
1958
- src: join12(templateDir, "flydocs", "design-system", "token-mapping.md"),
1959
- dest: join12(targetDir, "flydocs", "design-system", "token-mapping.md"),
2096
+ src: join13(templateDir, "flydocs", "design-system", "token-mapping.md"),
2097
+ dest: join13(targetDir, "flydocs", "design-system", "token-mapping.md"),
1960
2098
  label: "flydocs/design-system/token-mapping.md"
1961
2099
  },
1962
2100
  {
1963
- src: join12(templateDir, "flydocs", "README.md"),
1964
- dest: join12(targetDir, "flydocs", "README.md"),
2101
+ src: join13(templateDir, "flydocs", "README.md"),
2102
+ dest: join13(targetDir, "flydocs", "README.md"),
1965
2103
  label: "flydocs/README.md"
1966
2104
  }
1967
2105
  ];
@@ -1975,9 +2113,9 @@ var init_install = __esm({
1975
2113
  }
1976
2114
  }
1977
2115
  }
1978
- const envExampleSrc = join12(templateDir, ".env.example");
2116
+ const envExampleSrc = join13(templateDir, ".env.example");
1979
2117
  if (await pathExists(envExampleSrc)) {
1980
- await copyFile(envExampleSrc, join12(targetDir, ".env.example"));
2118
+ await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
1981
2119
  printStatus(".env.example");
1982
2120
  }
1983
2121
  await ensureGitignore(targetDir);
@@ -1996,6 +2134,9 @@ var init_install = __esm({
1996
2134
  } else {
1997
2135
  printInfo("No framework detected in package.json");
1998
2136
  }
2137
+ await capture("install_skills_chosen", {
2138
+ stack_detected: stack.raw
2139
+ });
1999
2140
  console.log();
2000
2141
  console.log("Checking for deprecated files...");
2001
2142
  const deprecated = await scanDeprecated(targetDir);
@@ -2037,6 +2178,7 @@ var init_install = __esm({
2037
2178
  }
2038
2179
  printCompletionBox("Installation Complete!", nextSteps);
2039
2180
  printBetaCta();
2181
+ const detectedIdes = [];
2040
2182
  try {
2041
2183
  const { execSync: execSync2, spawn } = await import("child_process");
2042
2184
  const isInstalled = (cmd) => {
@@ -2072,6 +2214,7 @@ var init_install = __esm({
2072
2214
  passCommand: false
2073
2215
  });
2074
2216
  }
2217
+ detectedIdes.push(...ideOptions.map((o) => o.cmd));
2075
2218
  if (ideOptions.length === 1) {
2076
2219
  const ide = ideOptions[0];
2077
2220
  const launchConfirm = await confirm2({
@@ -2130,6 +2273,9 @@ var init_install = __esm({
2130
2273
  }
2131
2274
  } catch {
2132
2275
  }
2276
+ await capture("install_ide_detected", { ides: detectedIdes });
2277
+ await capture("install_completed", { tier, version });
2278
+ await flush();
2133
2279
  try {
2134
2280
  const updateResult = await checkForUpdate();
2135
2281
  if (updateResult) {
@@ -2148,8 +2294,8 @@ __export(update_exports, {
2148
2294
  default: () => update_default
2149
2295
  });
2150
2296
  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";
2297
+ import { resolve as resolve3, join as join14 } from "path";
2298
+ import { mkdir as mkdir7, cp as cp2, readFile as readFile9, readdir as readdir3, rm as rm4 } from "fs/promises";
2153
2299
  import { select as select2, text, confirm as confirm3, isCancel as isCancel4, cancel as cancel3 } from "@clack/prompts";
2154
2300
  import pc7 from "picocolors";
2155
2301
  var update_default;
@@ -2168,6 +2314,7 @@ var init_update = __esm({
2168
2314
  init_gitignore();
2169
2315
  init_post_install();
2170
2316
  init_update_check();
2317
+ init_telemetry();
2171
2318
  update_default = defineCommand2({
2172
2319
  meta: {
2173
2320
  name: "update",
@@ -2210,6 +2357,7 @@ var init_update = __esm({
2210
2357
  printBanner(version);
2211
2358
  printInfo("Running in update mode \u2014 framework files will be refreshed");
2212
2359
  console.log();
2360
+ await capture("update_started", { template_version: version });
2213
2361
  let targetDir;
2214
2362
  if (args.path) {
2215
2363
  targetDir = resolve3(args.path.replace(/^~/, process.env.HOME ?? "~"));
@@ -2254,9 +2402,9 @@ var init_update = __esm({
2254
2402
  }
2255
2403
  targetDir = resolve3(targetDir);
2256
2404
  process.chdir(targetDir);
2257
- const hasVersion = await pathExists(join13(targetDir, ".flydocs", "version"));
2405
+ const hasVersion = await pathExists(join14(targetDir, ".flydocs", "version"));
2258
2406
  const hasConfig = await pathExists(
2259
- join13(targetDir, ".flydocs", "config.json")
2407
+ join14(targetDir, ".flydocs", "config.json")
2260
2408
  );
2261
2409
  if (!hasVersion && !hasConfig) {
2262
2410
  printError(`Not a FlyDocs project: ${targetDir}`);
@@ -2267,8 +2415,8 @@ var init_update = __esm({
2267
2415
  console.log();
2268
2416
  let currentVersion = "0.1.0";
2269
2417
  if (hasVersion) {
2270
- const vContent = await readFile8(
2271
- join13(targetDir, ".flydocs", "version"),
2418
+ const vContent = await readFile9(
2419
+ join14(targetDir, ".flydocs", "version"),
2272
2420
  "utf-8"
2273
2421
  );
2274
2422
  currentVersion = vContent.trim();
@@ -2294,9 +2442,15 @@ var init_update = __esm({
2294
2442
  process.exit(0);
2295
2443
  }
2296
2444
  }
2445
+ await capture("update_version_compared", {
2446
+ current_version: currentVersion,
2447
+ target_version: version,
2448
+ version_status: versionStatus,
2449
+ force: args.force
2450
+ });
2297
2451
  console.log(`Updating: v${currentVersion} \u2192 v${version}`);
2298
2452
  console.log();
2299
- const changelogPath = join13(templateDir, "CHANGELOG.md");
2453
+ const changelogPath = join14(templateDir, "CHANGELOG.md");
2300
2454
  const whatsNew = await getWhatsNew(changelogPath, currentVersion, version);
2301
2455
  if (whatsNew.length > 0) {
2302
2456
  console.log(pc7.cyan("What's new:"));
@@ -2308,23 +2462,23 @@ var init_update = __esm({
2308
2462
  }
2309
2463
  const now = /* @__PURE__ */ new Date();
2310
2464
  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 });
2465
+ const backupDir = join14(targetDir, ".flydocs", `backup-${ts}`);
2466
+ await mkdir7(backupDir, { recursive: true });
2313
2467
  if (hasConfig) {
2314
2468
  await cp2(
2315
- join13(targetDir, ".flydocs", "config.json"),
2316
- join13(backupDir, "config.json")
2469
+ join14(targetDir, ".flydocs", "config.json"),
2470
+ join14(backupDir, "config.json")
2317
2471
  );
2318
2472
  printStatus(`Config backed up to .flydocs/backup-${ts}/`);
2319
2473
  }
2320
2474
  try {
2321
- const flydocsDir = join13(targetDir, ".flydocs");
2475
+ const flydocsDir = join14(targetDir, ".flydocs");
2322
2476
  const entries = await readdir3(flydocsDir);
2323
2477
  const backups = entries.filter((e) => e.startsWith("backup-")).sort();
2324
2478
  if (backups.length > 3) {
2325
2479
  const toRemove = backups.slice(0, backups.length - 3);
2326
2480
  for (const old of toRemove) {
2327
- await rm4(join13(flydocsDir, old), { recursive: true, force: true });
2481
+ await rm4(join14(flydocsDir, old), { recursive: true, force: true });
2328
2482
  }
2329
2483
  }
2330
2484
  } catch {
@@ -2361,20 +2515,20 @@ var init_update = __esm({
2361
2515
  }
2362
2516
  console.log("Replacing framework directories...");
2363
2517
  await replaceDirectory(
2364
- join13(templateDir, ".flydocs", "templates"),
2365
- join13(targetDir, ".flydocs", "templates")
2518
+ join14(templateDir, ".flydocs", "templates"),
2519
+ join14(targetDir, ".flydocs", "templates")
2366
2520
  );
2367
2521
  await replaceDirectory(
2368
- join13(templateDir, ".flydocs", "hooks"),
2369
- join13(targetDir, ".flydocs", "hooks")
2522
+ join14(templateDir, ".flydocs", "hooks"),
2523
+ join14(targetDir, ".flydocs", "hooks")
2370
2524
  );
2371
2525
  await replaceDirectory(
2372
- join13(templateDir, ".flydocs", "scripts"),
2373
- join13(targetDir, ".flydocs", "scripts")
2526
+ join14(templateDir, ".flydocs", "scripts"),
2527
+ join14(targetDir, ".flydocs", "scripts")
2374
2528
  );
2375
2529
  printStatus(".flydocs/templates, hooks, scripts");
2376
2530
  const hasExistingAgents = await pathExists(
2377
- join13(targetDir, ".claude", "agents")
2531
+ join14(targetDir, ".claude", "agents")
2378
2532
  );
2379
2533
  let installAgents;
2380
2534
  if (args.yes) {
@@ -2406,20 +2560,20 @@ var init_update = __esm({
2406
2560
  }
2407
2561
  }
2408
2562
  if (installAgents) {
2409
- const claudeAgentsSrc = join13(templateDir, ".claude", "agents");
2563
+ const claudeAgentsSrc = join14(templateDir, ".claude", "agents");
2410
2564
  if (await pathExists(claudeAgentsSrc)) {
2411
- await mkdir6(join13(targetDir, ".claude", "agents"), { recursive: true });
2565
+ await mkdir7(join14(targetDir, ".claude", "agents"), { recursive: true });
2412
2566
  await copyDirectoryContents(
2413
2567
  claudeAgentsSrc,
2414
- join13(targetDir, ".claude", "agents")
2568
+ join14(targetDir, ".claude", "agents")
2415
2569
  );
2416
2570
  }
2417
- const cursorAgentsSrc = join13(templateDir, ".cursor", "agents");
2571
+ const cursorAgentsSrc = join14(templateDir, ".cursor", "agents");
2418
2572
  if (await pathExists(cursorAgentsSrc)) {
2419
- await mkdir6(join13(targetDir, ".cursor", "agents"), { recursive: true });
2573
+ await mkdir7(join14(targetDir, ".cursor", "agents"), { recursive: true });
2420
2574
  await copyDirectoryContents(
2421
2575
  cursorAgentsSrc,
2422
- join13(targetDir, ".cursor", "agents")
2576
+ join14(targetDir, ".cursor", "agents")
2423
2577
  );
2424
2578
  }
2425
2579
  printStatus(
@@ -2433,44 +2587,44 @@ var init_update = __esm({
2433
2587
  console.log();
2434
2588
  console.log("Replacing framework files...");
2435
2589
  await copyFile(
2436
- join13(templateDir, ".claude", "CLAUDE.md"),
2437
- join13(targetDir, ".claude", "CLAUDE.md")
2590
+ join14(templateDir, ".claude", "CLAUDE.md"),
2591
+ join14(targetDir, ".claude", "CLAUDE.md")
2438
2592
  );
2439
2593
  await copyFile(
2440
- join13(templateDir, ".claude", "settings.json"),
2441
- join13(targetDir, ".claude", "settings.json")
2594
+ join14(templateDir, ".claude", "settings.json"),
2595
+ join14(targetDir, ".claude", "settings.json")
2442
2596
  );
2443
2597
  printStatus(".claude/CLAUDE.md, settings.json");
2444
2598
  await copyDirectoryContents(
2445
- join13(templateDir, ".claude", "commands"),
2446
- join13(targetDir, ".claude", "commands")
2599
+ join14(templateDir, ".claude", "commands"),
2600
+ join14(targetDir, ".claude", "commands")
2447
2601
  );
2448
2602
  await copyDirectoryContents(
2449
- join13(templateDir, ".claude", "commands"),
2450
- join13(targetDir, ".cursor", "commands")
2603
+ join14(templateDir, ".claude", "commands"),
2604
+ join14(targetDir, ".cursor", "commands")
2451
2605
  );
2452
2606
  printStatus(".claude/commands, .cursor/commands");
2453
- const skillsReadmeSrc = join13(templateDir, ".claude", "skills", "README.md");
2607
+ const skillsReadmeSrc = join14(templateDir, ".claude", "skills", "README.md");
2454
2608
  if (await pathExists(skillsReadmeSrc)) {
2455
2609
  await copyFile(
2456
2610
  skillsReadmeSrc,
2457
- join13(targetDir, ".claude", "skills", "README.md")
2611
+ join14(targetDir, ".claude", "skills", "README.md")
2458
2612
  );
2459
2613
  }
2460
2614
  printStatus(".claude/skills/README.md");
2461
2615
  await copyFile(
2462
- join13(templateDir, ".cursor", "hooks.json"),
2463
- join13(targetDir, ".cursor", "hooks.json")
2616
+ join14(templateDir, ".cursor", "hooks.json"),
2617
+ join14(targetDir, ".cursor", "hooks.json")
2464
2618
  );
2465
2619
  printStatus(".cursor/hooks.json");
2466
2620
  await copyFile(
2467
- join13(templateDir, "AGENTS.md"),
2468
- join13(targetDir, "AGENTS.md")
2621
+ join14(templateDir, "AGENTS.md"),
2622
+ join14(targetDir, "AGENTS.md")
2469
2623
  );
2470
2624
  printStatus("AGENTS.md");
2471
- const envExampleSrc = join13(templateDir, ".env.example");
2625
+ const envExampleSrc = join14(templateDir, ".env.example");
2472
2626
  if (await pathExists(envExampleSrc)) {
2473
- await copyFile(envExampleSrc, join13(targetDir, ".env.example"));
2627
+ await copyFile(envExampleSrc, join14(targetDir, ".env.example"));
2474
2628
  printStatus(".env.example");
2475
2629
  }
2476
2630
  await runManifestGeneration(targetDir);
@@ -2495,18 +2649,18 @@ var init_update = __esm({
2495
2649
  printWarning("Config merge failed \u2014 config.json preserved as-is");
2496
2650
  }
2497
2651
  await copyFile(
2498
- join13(templateDir, ".flydocs", "version"),
2499
- join13(targetDir, ".flydocs", "version")
2652
+ join14(templateDir, ".flydocs", "version"),
2653
+ join14(targetDir, ".flydocs", "version")
2500
2654
  );
2501
2655
  printStatus(`.flydocs/version \u2192 ${version}`);
2502
- const clSrc = join13(templateDir, "CHANGELOG.md");
2656
+ const clSrc = join14(templateDir, "CHANGELOG.md");
2503
2657
  if (await pathExists(clSrc)) {
2504
- await copyFile(clSrc, join13(targetDir, ".flydocs", "CHANGELOG.md"));
2658
+ await copyFile(clSrc, join14(targetDir, ".flydocs", "CHANGELOG.md"));
2505
2659
  printStatus(".flydocs/CHANGELOG.md");
2506
2660
  }
2507
- const mfSrc = join13(templateDir, "manifest.json");
2661
+ const mfSrc = join14(templateDir, "manifest.json");
2508
2662
  if (await pathExists(mfSrc)) {
2509
- await copyFile(mfSrc, join13(targetDir, ".flydocs", "manifest.json"));
2663
+ await copyFile(mfSrc, join14(targetDir, ".flydocs", "manifest.json"));
2510
2664
  printStatus(".flydocs/manifest.json");
2511
2665
  }
2512
2666
  console.log();
@@ -2542,6 +2696,12 @@ var init_update = __esm({
2542
2696
  `Backup: .flydocs/backup-${ts}/`
2543
2697
  ]);
2544
2698
  printBetaCta();
2699
+ await capture("update_completed", {
2700
+ current_version: currentVersion,
2701
+ version,
2702
+ tier: effectiveTier
2703
+ });
2704
+ await flush();
2545
2705
  try {
2546
2706
  const updateResult = await checkForUpdate();
2547
2707
  if (updateResult) {
@@ -2554,33 +2714,336 @@ var init_update = __esm({
2554
2714
  }
2555
2715
  });
2556
2716
 
2717
+ // src/commands/uninstall.ts
2718
+ var uninstall_exports = {};
2719
+ __export(uninstall_exports, {
2720
+ default: () => uninstall_default
2721
+ });
2722
+ import { defineCommand as defineCommand3 } from "citty";
2723
+ import { resolve as resolve4, join as join15 } from "path";
2724
+ import { readdir as readdir4, rm as rm5, rename as rename2 } from "fs/promises";
2725
+ import { confirm as confirm4, select as select3, isCancel as isCancel5, cancel as cancel4 } from "@clack/prompts";
2726
+ import pc8 from "picocolors";
2727
+ async function removeOwnedSkills(targetDir) {
2728
+ const skillsDir = join15(targetDir, ".claude", "skills");
2729
+ const removed = [];
2730
+ if (!await pathExists(skillsDir)) {
2731
+ return removed;
2732
+ }
2733
+ try {
2734
+ const entries = await readdir4(skillsDir);
2735
+ for (const entry of entries) {
2736
+ if (entry.startsWith(OWNED_SKILL_PREFIX)) {
2737
+ await rm5(join15(skillsDir, entry), { recursive: true, force: true });
2738
+ removed.push(`.claude/skills/${entry}`);
2739
+ }
2740
+ }
2741
+ } catch {
2742
+ }
2743
+ return removed;
2744
+ }
2745
+ async function removeOwnedCursorRules(targetDir) {
2746
+ const rulesDir = join15(targetDir, ".cursor", "rules");
2747
+ const removed = [];
2748
+ if (!await pathExists(rulesDir)) {
2749
+ return removed;
2750
+ }
2751
+ try {
2752
+ const entries = await readdir4(rulesDir);
2753
+ for (const entry of entries) {
2754
+ if (entry.startsWith(OWNED_RULE_PREFIX) && entry.endsWith(".mdc")) {
2755
+ await rm5(join15(rulesDir, entry), { force: true });
2756
+ removed.push(`.cursor/rules/${entry}`);
2757
+ }
2758
+ }
2759
+ } catch {
2760
+ }
2761
+ return removed;
2762
+ }
2763
+ async function isEmptyDir(dirPath) {
2764
+ try {
2765
+ const entries = await readdir4(dirPath);
2766
+ return entries.length === 0;
2767
+ } catch {
2768
+ return false;
2769
+ }
2770
+ }
2771
+ async function cleanupEmptyParents(targetDir, dirs) {
2772
+ const cleaned = [];
2773
+ for (const dir of dirs) {
2774
+ const fullPath = join15(targetDir, dir);
2775
+ if (await pathExists(fullPath) && await isEmptyDir(fullPath)) {
2776
+ await rm5(fullPath, { recursive: true, force: true });
2777
+ cleaned.push(dir);
2778
+ }
2779
+ }
2780
+ return cleaned;
2781
+ }
2782
+ var ALWAYS_REMOVED, OWNED_SKILL_PREFIX, OWNED_RULE_PREFIX, uninstall_default;
2783
+ var init_uninstall = __esm({
2784
+ "src/commands/uninstall.ts"() {
2785
+ "use strict";
2786
+ init_fs_ops();
2787
+ init_ui();
2788
+ init_constants();
2789
+ ALWAYS_REMOVED = [
2790
+ [".claude/CLAUDE.md", "file"],
2791
+ [".claude/settings.json", "file"],
2792
+ [".claude/agents", "dir"],
2793
+ [".claude/commands", "dir"],
2794
+ [".claude/skills/README.md", "file"],
2795
+ [".cursor/hooks.json", "file"],
2796
+ [".cursor/agents", "dir"],
2797
+ [".flydocs", "dir"],
2798
+ ["AGENTS.md", "file"],
2799
+ [".env.example", "file"]
2800
+ ];
2801
+ OWNED_SKILL_PREFIX = "flydocs-";
2802
+ OWNED_RULE_PREFIX = "flydocs-";
2803
+ uninstall_default = defineCommand3({
2804
+ meta: {
2805
+ name: "uninstall",
2806
+ description: "Remove FlyDocs from a project directory"
2807
+ },
2808
+ args: {
2809
+ path: {
2810
+ type: "string",
2811
+ description: "Uninstall from the specified directory"
2812
+ },
2813
+ here: {
2814
+ type: "boolean",
2815
+ description: "Uninstall from the current directory",
2816
+ default: false
2817
+ },
2818
+ all: {
2819
+ type: "boolean",
2820
+ description: "Remove everything including flydocs/ user content",
2821
+ default: false
2822
+ },
2823
+ yes: {
2824
+ type: "boolean",
2825
+ alias: ["y"],
2826
+ description: "Skip confirmation prompts",
2827
+ default: false
2828
+ },
2829
+ force: {
2830
+ type: "boolean",
2831
+ description: "Alias for --all --yes (complete removal, no prompts)",
2832
+ default: false
2833
+ }
2834
+ },
2835
+ async run({ args }) {
2836
+ printBanner(CLI_VERSION);
2837
+ let targetDir;
2838
+ if (args.path) {
2839
+ targetDir = resolve4(args.path.replace(/^~/, process.env.HOME ?? "~"));
2840
+ } else if (args.here) {
2841
+ targetDir = process.cwd();
2842
+ } else {
2843
+ targetDir = process.cwd();
2844
+ }
2845
+ if (!await pathExists(targetDir)) {
2846
+ printError(`Directory does not exist: ${targetDir}`);
2847
+ process.exit(1);
2848
+ }
2849
+ targetDir = resolve4(targetDir);
2850
+ const hasFlydocs = await pathExists(join15(targetDir, ".flydocs"));
2851
+ const hasAgentsMd = await pathExists(join15(targetDir, "AGENTS.md"));
2852
+ if (!hasFlydocs && !hasAgentsMd) {
2853
+ printError(`Not a FlyDocs project: ${targetDir}`);
2854
+ printInfo("No .flydocs/ directory or AGENTS.md found.");
2855
+ process.exit(1);
2856
+ }
2857
+ printInfo(`Project: ${targetDir}`);
2858
+ console.log();
2859
+ const forceAll = args.force;
2860
+ const removeAll = forceAll || args.all;
2861
+ const skipPrompts = forceAll || args.yes;
2862
+ let contentAction = "preserve";
2863
+ const hasUserContent = await pathExists(join15(targetDir, "flydocs"));
2864
+ if (hasUserContent) {
2865
+ if (removeAll) {
2866
+ contentAction = "remove";
2867
+ } else if (!skipPrompts) {
2868
+ const choice = await select3({
2869
+ message: "What should happen to your flydocs/ content (project docs, knowledge base)?",
2870
+ options: [
2871
+ {
2872
+ value: "archive",
2873
+ label: "Archive",
2874
+ hint: "Rename to flydocs-archive/ (safe, reversible)"
2875
+ },
2876
+ {
2877
+ value: "remove",
2878
+ label: "Remove completely",
2879
+ hint: "Permanently delete flydocs/ and all contents"
2880
+ },
2881
+ {
2882
+ value: "preserve",
2883
+ label: "Keep as-is",
2884
+ hint: "Leave flydocs/ untouched"
2885
+ }
2886
+ ]
2887
+ });
2888
+ if (isCancel5(choice)) {
2889
+ cancel4("Uninstall cancelled.");
2890
+ process.exit(0);
2891
+ }
2892
+ contentAction = choice;
2893
+ }
2894
+ }
2895
+ if (!skipPrompts) {
2896
+ console.log();
2897
+ console.log(pc8.bold("The following will be removed:"));
2898
+ console.log();
2899
+ console.log(" Framework files:");
2900
+ for (const [path] of ALWAYS_REMOVED) {
2901
+ console.log(` ${pc8.dim(path)}`);
2902
+ }
2903
+ console.log(` ${pc8.dim(".claude/skills/flydocs-*")}`);
2904
+ console.log(` ${pc8.dim(".cursor/rules/flydocs-*.mdc")}`);
2905
+ if (hasUserContent) {
2906
+ if (contentAction === "archive") {
2907
+ console.log();
2908
+ console.log(
2909
+ ` User content: ${pc8.yellow("flydocs/ -> flydocs-archive/")}`
2910
+ );
2911
+ } else if (contentAction === "remove") {
2912
+ console.log();
2913
+ console.log(` User content: ${pc8.red("flydocs/ (deleted)")}`);
2914
+ } else {
2915
+ console.log();
2916
+ console.log(` User content: ${pc8.green("flydocs/ (preserved)")}`);
2917
+ }
2918
+ }
2919
+ console.log();
2920
+ console.log(pc8.bold("Preserved:"));
2921
+ console.log(
2922
+ ` ${pc8.dim(".claude/skills/ (non-flydocs community skills)")}`
2923
+ );
2924
+ console.log(` ${pc8.dim(".env, .env.local")}`);
2925
+ console.log();
2926
+ const shouldContinue = await confirm4({
2927
+ message: "Proceed with uninstall?"
2928
+ });
2929
+ if (isCancel5(shouldContinue) || !shouldContinue) {
2930
+ cancel4("Uninstall cancelled.");
2931
+ process.exit(0);
2932
+ }
2933
+ }
2934
+ const result = {
2935
+ removed: [],
2936
+ skipped: [],
2937
+ archived: []
2938
+ };
2939
+ const removedSkills = await removeOwnedSkills(targetDir);
2940
+ result.removed.push(...removedSkills);
2941
+ const removedRules = await removeOwnedCursorRules(targetDir);
2942
+ result.removed.push(...removedRules);
2943
+ for (const [relativePath, type] of ALWAYS_REMOVED) {
2944
+ const fullPath = join15(targetDir, relativePath);
2945
+ if (!await pathExists(fullPath)) {
2946
+ result.skipped.push(relativePath);
2947
+ continue;
2948
+ }
2949
+ try {
2950
+ if (type === "dir") {
2951
+ await rm5(fullPath, { recursive: true, force: true });
2952
+ } else {
2953
+ await rm5(fullPath, { force: true });
2954
+ }
2955
+ result.removed.push(relativePath);
2956
+ } catch {
2957
+ printWarning(`Could not remove: ${relativePath}`);
2958
+ result.skipped.push(relativePath);
2959
+ }
2960
+ }
2961
+ if (hasUserContent) {
2962
+ const flydocsPath = join15(targetDir, "flydocs");
2963
+ if (contentAction === "archive") {
2964
+ const archivePath = join15(targetDir, "flydocs-archive");
2965
+ if (await pathExists(archivePath)) {
2966
+ await rm5(archivePath, { recursive: true, force: true });
2967
+ }
2968
+ await rename2(flydocsPath, archivePath);
2969
+ result.archived.push("flydocs/ -> flydocs-archive/");
2970
+ } else if (contentAction === "remove") {
2971
+ await rm5(flydocsPath, { recursive: true, force: true });
2972
+ result.removed.push("flydocs/");
2973
+ }
2974
+ }
2975
+ const emptyCandidates = [
2976
+ ".claude/skills",
2977
+ ".claude",
2978
+ ".cursor/rules",
2979
+ ".cursor"
2980
+ ];
2981
+ const cleaned = await cleanupEmptyParents(targetDir, emptyCandidates);
2982
+ for (const dir of cleaned) {
2983
+ result.removed.push(`${dir}/ (empty, cleaned up)`);
2984
+ }
2985
+ console.log();
2986
+ console.log(pc8.bold("Uninstall Summary"));
2987
+ console.log();
2988
+ if (result.removed.length > 0) {
2989
+ console.log(` ${pc8.green("Removed")} (${result.removed.length}):`);
2990
+ for (const item of result.removed) {
2991
+ printStatus(item);
2992
+ }
2993
+ }
2994
+ if (result.archived.length > 0) {
2995
+ console.log();
2996
+ console.log(` ${pc8.yellow("Archived")} (${result.archived.length}):`);
2997
+ for (const item of result.archived) {
2998
+ printInfo(item);
2999
+ }
3000
+ }
3001
+ if (result.skipped.length > 0) {
3002
+ console.log();
3003
+ console.log(
3004
+ ` ${pc8.dim("Skipped")} (${result.skipped.length} \u2014 not found):`
3005
+ );
3006
+ for (const item of result.skipped) {
3007
+ console.log(` ${pc8.dim(item)}`);
3008
+ }
3009
+ }
3010
+ console.log();
3011
+ printStatus("FlyDocs has been removed from this project.");
3012
+ console.log();
3013
+ printInfo(`To reinstall: ${pc8.cyan("npx @flydocs/cli install --here")}`);
3014
+ console.log();
3015
+ }
3016
+ });
3017
+ }
3018
+ });
3019
+
2557
3020
  // src/commands/setup.ts
2558
3021
  var setup_exports = {};
2559
3022
  __export(setup_exports, {
2560
3023
  default: () => setup_default
2561
3024
  });
2562
- import { defineCommand as defineCommand3 } from "citty";
2563
- import pc8 from "picocolors";
3025
+ import { defineCommand as defineCommand4 } from "citty";
3026
+ import pc9 from "picocolors";
2564
3027
  var setup_default;
2565
3028
  var init_setup = __esm({
2566
3029
  "src/commands/setup.ts"() {
2567
3030
  "use strict";
2568
- setup_default = defineCommand3({
3031
+ setup_default = defineCommand4({
2569
3032
  meta: {
2570
3033
  name: "setup",
2571
3034
  description: "Configure FlyDocs settings for this project"
2572
3035
  },
2573
3036
  run() {
2574
3037
  console.log();
2575
- console.log(` ${pc8.bold("FlyDocs Setup")}`);
3038
+ console.log(` ${pc9.bold("FlyDocs Setup")}`);
2576
3039
  console.log();
2577
3040
  console.log(` Setup runs inside your IDE as an interactive AI command.`);
2578
3041
  console.log();
2579
3042
  console.log(
2580
- ` ${pc8.cyan("Claude Code:")} Type ${pc8.bold("/flydocs-setup")} in chat`
3043
+ ` ${pc9.cyan("Claude Code:")} Type ${pc9.bold("/flydocs-setup")} in chat`
2581
3044
  );
2582
3045
  console.log(
2583
- ` ${pc8.cyan("Cursor:")} Type ${pc8.bold("/flydocs-setup")} in chat`
3046
+ ` ${pc9.cyan("Cursor:")} Type ${pc9.bold("/flydocs-setup")} in chat`
2584
3047
  );
2585
3048
  console.log();
2586
3049
  console.log(` This configures your project context, detects your stack,`);
@@ -2596,14 +3059,14 @@ var skills_exports = {};
2596
3059
  __export(skills_exports, {
2597
3060
  default: () => skills_default
2598
3061
  });
2599
- import { defineCommand as defineCommand4 } from "citty";
2600
- import pc9 from "picocolors";
3062
+ import { defineCommand as defineCommand5 } from "citty";
3063
+ import pc10 from "picocolors";
2601
3064
  var list, search, add, remove, skills_default;
2602
3065
  var init_skills2 = __esm({
2603
3066
  "src/commands/skills.ts"() {
2604
3067
  "use strict";
2605
3068
  init_skill_manager();
2606
- list = defineCommand4({
3069
+ list = defineCommand5({
2607
3070
  meta: {
2608
3071
  name: "list",
2609
3072
  description: "List installed skills"
@@ -2619,26 +3082,26 @@ var init_skills2 = __esm({
2619
3082
  console.log(`${total} skill(s) installed:`);
2620
3083
  if (result.platform.length > 0) {
2621
3084
  console.log();
2622
- console.log(pc9.bold("Platform"));
3085
+ console.log(pc10.bold("Platform"));
2623
3086
  for (const skill of result.platform) {
2624
3087
  console.log(
2625
- ` ${skill.name} ${pc9.dim(`(${skill.triggers} triggers)`)}`
3088
+ ` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
2626
3089
  );
2627
3090
  }
2628
3091
  }
2629
3092
  if (result.community.length > 0) {
2630
3093
  console.log();
2631
- console.log(pc9.bold("Community"));
3094
+ console.log(pc10.bold("Community"));
2632
3095
  for (const skill of result.community) {
2633
3096
  console.log(
2634
- ` ${skill.name} ${pc9.dim(`(${skill.triggers} triggers)`)}`
3097
+ ` ${skill.name} ${pc10.dim(`(${skill.triggers} triggers)`)}`
2635
3098
  );
2636
3099
  }
2637
3100
  }
2638
3101
  console.log();
2639
3102
  }
2640
3103
  });
2641
- search = defineCommand4({
3104
+ search = defineCommand5({
2642
3105
  meta: {
2643
3106
  name: "search",
2644
3107
  description: "Search community skills"
@@ -2654,24 +3117,24 @@ var init_skills2 = __esm({
2654
3117
  const results = await searchCatalog(args.keyword);
2655
3118
  if (results.length === 0) {
2656
3119
  console.log(`No skills found for "${args.keyword}".`);
2657
- console.log(` Browse the catalog at: ${pc9.cyan("https://skills.sh/")}`);
3120
+ console.log(` Browse the catalog at: ${pc10.cyan("https://skills.sh/")}`);
2658
3121
  return;
2659
3122
  }
2660
3123
  console.log();
2661
3124
  console.log(`${results.length} skill(s) matching "${args.keyword}":`);
2662
3125
  console.log();
2663
3126
  for (const skill of results) {
2664
- console.log(` ${pc9.bold(skill.name)}`);
3127
+ console.log(` ${pc10.bold(skill.name)}`);
2665
3128
  console.log(` ${skill.description}`);
2666
- console.log(` ${pc9.dim(skill.repo)}`);
3129
+ console.log(` ${pc10.dim(skill.repo)}`);
2667
3130
  if (skill.tags.length > 0) {
2668
- console.log(` ${pc9.dim(skill.tags.join(", "))}`);
3131
+ console.log(` ${pc10.dim(skill.tags.join(", "))}`);
2669
3132
  }
2670
3133
  console.log();
2671
3134
  }
2672
3135
  }
2673
3136
  });
2674
- add = defineCommand4({
3137
+ add = defineCommand5({
2675
3138
  meta: {
2676
3139
  name: "add",
2677
3140
  description: "Install a community skill"
@@ -2687,7 +3150,7 @@ var init_skills2 = __esm({
2687
3150
  await addSkill(process.cwd(), args.source);
2688
3151
  }
2689
3152
  });
2690
- remove = defineCommand4({
3153
+ remove = defineCommand5({
2691
3154
  meta: {
2692
3155
  name: "remove",
2693
3156
  description: "Remove an installed community skill"
@@ -2703,7 +3166,7 @@ var init_skills2 = __esm({
2703
3166
  await removeSkill(process.cwd(), args.name);
2704
3167
  }
2705
3168
  });
2706
- skills_default = defineCommand4({
3169
+ skills_default = defineCommand5({
2707
3170
  meta: {
2708
3171
  name: "skills",
2709
3172
  description: "Manage FlyDocs skills (list, search, add, remove)"
@@ -2723,11 +3186,11 @@ var connect_exports = {};
2723
3186
  __export(connect_exports, {
2724
3187
  default: () => connect_default
2725
3188
  });
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";
3189
+ import { defineCommand as defineCommand6 } from "citty";
3190
+ import { text as text2, confirm as confirm5, isCancel as isCancel6, cancel as cancel5 } from "@clack/prompts";
3191
+ import pc11 from "picocolors";
3192
+ import { readFile as readFile10, writeFile as writeFile6, appendFile as appendFile2 } from "fs/promises";
3193
+ import { join as join16 } from "path";
2731
3194
  var connect_default;
2732
3195
  var init_connect = __esm({
2733
3196
  "src/commands/connect.ts"() {
@@ -2736,7 +3199,7 @@ var init_connect = __esm({
2736
3199
  init_fs_ops();
2737
3200
  init_template();
2738
3201
  init_ui();
2739
- connect_default = defineCommand5({
3202
+ connect_default = defineCommand6({
2740
3203
  meta: {
2741
3204
  name: "connect",
2742
3205
  description: "Connect FlyDocs to a cloud provider (Linear)"
@@ -2761,11 +3224,11 @@ var init_connect = __esm({
2761
3224
  },
2762
3225
  async run({ args }) {
2763
3226
  const targetDir = args.path ?? process.cwd();
2764
- const configPath = join14(targetDir, ".flydocs", "config.json");
3227
+ const configPath = join16(targetDir, ".flydocs", "config.json");
2765
3228
  if (!await pathExists(configPath)) {
2766
3229
  printError("Not a FlyDocs project (.flydocs/config.json not found).");
2767
3230
  console.log(
2768
- ` Run ${pc10.cyan("flydocs")} first to install FlyDocs in this project.`
3231
+ ` Run ${pc11.cyan("flydocs")} first to install FlyDocs in this project.`
2769
3232
  );
2770
3233
  process.exit(1);
2771
3234
  }
@@ -2773,19 +3236,19 @@ var init_connect = __esm({
2773
3236
  if (config.tier === "cloud") {
2774
3237
  printInfo("This project is already connected to the cloud tier.");
2775
3238
  console.log();
2776
- const reconnect = await confirm4({
3239
+ const reconnect = await confirm5({
2777
3240
  message: "Want to update your API key?"
2778
3241
  });
2779
- if (isCancel5(reconnect) || !reconnect) {
3242
+ if (isCancel6(reconnect) || !reconnect) {
2780
3243
  console.log(` No changes made.`);
2781
3244
  return;
2782
3245
  }
2783
3246
  }
2784
3247
  console.log();
2785
- console.log(` ${pc10.bold("Connect to Linear")}`);
3248
+ console.log(` ${pc11.bold("Connect to Linear")}`);
2786
3249
  console.log();
2787
3250
  console.log(
2788
- ` ${pc10.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
3251
+ ` ${pc11.dim("Get your API key from: Linear \u2192 Settings \u2192 API \u2192 Personal API keys")}`
2789
3252
  );
2790
3253
  console.log();
2791
3254
  let apiKey = args.key ?? "";
@@ -2800,8 +3263,8 @@ var init_connect = __esm({
2800
3263
  return void 0;
2801
3264
  }
2802
3265
  });
2803
- if (isCancel5(keyInput)) {
2804
- cancel4("Connection cancelled.");
3266
+ if (isCancel6(keyInput)) {
3267
+ cancel5("Connection cancelled.");
2805
3268
  process.exit(0);
2806
3269
  }
2807
3270
  apiKey = keyInput;
@@ -2825,34 +3288,34 @@ var init_connect = __esm({
2825
3288
  throw new Error("Invalid response");
2826
3289
  }
2827
3290
  const viewer = data.data.viewer;
2828
- printStatus(`Authenticated as ${pc10.bold(viewer.name)} (${viewer.email})`);
3291
+ printStatus(`Authenticated as ${pc11.bold(viewer.name)} (${viewer.email})`);
2829
3292
  } catch {
2830
3293
  printError("Invalid API key or network error.");
2831
3294
  console.log(` Check your key and try again.`);
2832
3295
  process.exit(1);
2833
3296
  }
2834
- const envPath = join14(targetDir, ".env");
2835
- const envLocalPath = join14(targetDir, ".env.local");
3297
+ const envPath = join16(targetDir, ".env");
3298
+ const envLocalPath = join16(targetDir, ".env.local");
2836
3299
  const targetEnvPath = await pathExists(envLocalPath) ? envLocalPath : envPath;
2837
3300
  if (await pathExists(targetEnvPath)) {
2838
- const envContent = await readFile9(targetEnvPath, "utf-8");
3301
+ const envContent = await readFile10(targetEnvPath, "utf-8");
2839
3302
  if (envContent.includes("LINEAR_API_KEY=")) {
2840
3303
  const updated = envContent.replace(
2841
3304
  /LINEAR_API_KEY=.*/,
2842
3305
  `LINEAR_API_KEY=${apiKey}`
2843
3306
  );
2844
- await writeFile5(targetEnvPath, updated, "utf-8");
3307
+ await writeFile6(targetEnvPath, updated, "utf-8");
2845
3308
  } else {
2846
3309
  await appendFile2(targetEnvPath, `
2847
3310
  LINEAR_API_KEY=${apiKey}
2848
3311
  `);
2849
3312
  }
2850
3313
  } else {
2851
- await writeFile5(targetEnvPath, `LINEAR_API_KEY=${apiKey}
3314
+ await writeFile6(targetEnvPath, `LINEAR_API_KEY=${apiKey}
2852
3315
  `, "utf-8");
2853
3316
  }
2854
3317
  printStatus(
2855
- `API key stored in ${pc10.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
3318
+ `API key stored in ${pc11.dim(targetEnvPath === envLocalPath ? ".env.local" : ".env")}`
2856
3319
  );
2857
3320
  const wasLocal = config.tier === "local";
2858
3321
  config.tier = "cloud";
@@ -2865,16 +3328,16 @@ LINEAR_API_KEY=${apiKey}
2865
3328
  const templateDir = await resolveTemplatePath(
2866
3329
  args["local-source"] || void 0
2867
3330
  );
2868
- const templateSkillsDir = join14(templateDir, ".claude", "skills");
2869
- const skillsDir = join14(targetDir, ".claude", "skills");
3331
+ const templateSkillsDir = join16(templateDir, ".claude", "skills");
3332
+ const skillsDir = join16(targetDir, ".claude", "skills");
2870
3333
  await replaceDirectory(
2871
- join14(templateSkillsDir, "flydocs-cloud"),
2872
- join14(skillsDir, "flydocs-cloud")
3334
+ join16(templateSkillsDir, "flydocs-cloud"),
3335
+ join16(skillsDir, "flydocs-cloud")
2873
3336
  );
2874
- const { rm: rm5 } = await import("fs/promises");
2875
- const localSkillDir = join14(skillsDir, "flydocs-local");
3337
+ const { rm: rm6 } = await import("fs/promises");
3338
+ const localSkillDir = join16(skillsDir, "flydocs-local");
2876
3339
  if (await pathExists(localSkillDir)) {
2877
- await rm5(localSkillDir, { recursive: true, force: true });
3340
+ await rm6(localSkillDir, { recursive: true, force: true });
2878
3341
  }
2879
3342
  printStatus("Cloud mechanism skill installed");
2880
3343
  } catch {
@@ -2885,14 +3348,14 @@ LINEAR_API_KEY=${apiKey}
2885
3348
  }
2886
3349
  console.log();
2887
3350
  console.log(
2888
- ` ${pc10.bold("Connected!")} Your project now syncs with Linear.`
3351
+ ` ${pc11.bold("Connected!")} Your project now syncs with Linear.`
2889
3352
  );
2890
3353
  console.log();
2891
3354
  console.log(` Next steps:`);
2892
3355
  console.log(
2893
- ` 1. Run ${pc10.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
3356
+ ` 1. Run ${pc11.cyan("/flydocs-setup")} in your IDE to configure your Linear project`
2894
3357
  );
2895
- console.log(` 2. Run ${pc10.cyan("/start-session")} to begin working`);
3358
+ console.log(` 2. Run ${pc11.cyan("/start-session")} to begin working`);
2896
3359
  console.log();
2897
3360
  }
2898
3361
  });
@@ -2904,15 +3367,15 @@ var upgrade_exports = {};
2904
3367
  __export(upgrade_exports, {
2905
3368
  default: () => upgrade_default
2906
3369
  });
2907
- import { defineCommand as defineCommand6 } from "citty";
2908
- import pc11 from "picocolors";
3370
+ import { defineCommand as defineCommand7 } from "citty";
3371
+ import pc12 from "picocolors";
2909
3372
  var upgrade_default;
2910
3373
  var init_upgrade = __esm({
2911
3374
  "src/commands/upgrade.ts"() {
2912
3375
  "use strict";
2913
3376
  init_config();
2914
3377
  init_fs_ops();
2915
- upgrade_default = defineCommand6({
3378
+ upgrade_default = defineCommand7({
2916
3379
  meta: {
2917
3380
  name: "upgrade",
2918
3381
  description: "Learn about FlyDocs Cloud tier and upgrade from local"
@@ -2941,37 +3404,37 @@ var init_upgrade = __esm({
2941
3404
  console.log();
2942
3405
  if (currentTier === "cloud") {
2943
3406
  console.log(
2944
- ` ${pc11.green("\u2713")} You're already on the ${pc11.bold("cloud")} tier.`
3407
+ ` ${pc12.green("\u2713")} You're already on the ${pc12.bold("cloud")} tier.`
2945
3408
  );
2946
3409
  console.log();
2947
3410
  console.log(
2948
3411
  ` Your issues sync with Linear via the cloud mechanism skill.`
2949
3412
  );
2950
3413
  console.log(
2951
- ` Run ${pc11.cyan("flydocs connect")} to update your connection settings.`
3414
+ ` Run ${pc12.cyan("flydocs connect")} to update your connection settings.`
2952
3415
  );
2953
3416
  console.log();
2954
3417
  return;
2955
3418
  }
2956
- console.log(` ${pc11.bold("FlyDocs Cloud Tier")}`);
3419
+ console.log(` ${pc12.bold("FlyDocs Cloud Tier")}`);
2957
3420
  console.log();
2958
- console.log(` You're currently on the ${pc11.yellow("local")} tier.`);
3421
+ console.log(` You're currently on the ${pc12.yellow("local")} tier.`);
2959
3422
  console.log(` Upgrade to cloud for:`);
2960
3423
  console.log();
2961
3424
  console.log(
2962
- ` ${pc11.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
3425
+ ` ${pc12.cyan("\u2192")} Issue sync with Linear (Jira coming soon)`
2963
3426
  );
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`);
3427
+ console.log(` ${pc12.cyan("\u2192")} Project milestones and cycle management`);
3428
+ console.log(` ${pc12.cyan("\u2192")} Team assignment and priority tracking`);
3429
+ console.log(` ${pc12.cyan("\u2192")} Project health updates and dashboards`);
3430
+ console.log(` ${pc12.cyan("\u2192")} Cross-project issue linking`);
2968
3431
  console.log();
2969
- console.log(` ${pc11.bold("How to upgrade:")}`);
3432
+ console.log(` ${pc12.bold("How to upgrade:")}`);
2970
3433
  console.log();
2971
- console.log(` 1. Sign up at ${pc11.cyan("https://www.flydocs.ai")}`);
3434
+ console.log(` 1. Sign up at ${pc12.cyan("https://www.flydocs.ai")}`);
2972
3435
  console.log(` 2. Get your Linear API key from Linear \u2192 Settings \u2192 API`);
2973
3436
  console.log(
2974
- ` 3. Run ${pc11.cyan("flydocs connect")} to connect your project`
3437
+ ` 3. Run ${pc12.cyan("flydocs connect")} to connect your project`
2975
3438
  );
2976
3439
  console.log();
2977
3440
  }
@@ -2984,23 +3447,23 @@ var self_update_exports = {};
2984
3447
  __export(self_update_exports, {
2985
3448
  default: () => self_update_default
2986
3449
  });
2987
- import { defineCommand as defineCommand7 } from "citty";
3450
+ import { defineCommand as defineCommand8 } from "citty";
2988
3451
  import { execSync } from "child_process";
2989
- import pc12 from "picocolors";
3452
+ import pc13 from "picocolors";
2990
3453
  var self_update_default;
2991
3454
  var init_self_update = __esm({
2992
3455
  "src/commands/self-update.ts"() {
2993
3456
  "use strict";
2994
3457
  init_constants();
2995
3458
  init_ui();
2996
- self_update_default = defineCommand7({
3459
+ self_update_default = defineCommand8({
2997
3460
  meta: {
2998
3461
  name: "self-update",
2999
3462
  description: "Update FlyDocs CLI to the latest version"
3000
3463
  },
3001
3464
  async run() {
3002
3465
  console.log();
3003
- console.log(` Updating ${pc12.cyan(PACKAGE_NAME)}...`);
3466
+ console.log(` Updating ${pc13.cyan(PACKAGE_NAME)}...`);
3004
3467
  console.log();
3005
3468
  try {
3006
3469
  execSync(`npm install -g ${PACKAGE_NAME}@beta`, {
@@ -3020,17 +3483,117 @@ var init_self_update = __esm({
3020
3483
  }
3021
3484
  });
3022
3485
 
3486
+ // src/commands/telemetry.ts
3487
+ var telemetry_exports = {};
3488
+ __export(telemetry_exports, {
3489
+ default: () => telemetry_default
3490
+ });
3491
+ import { defineCommand as defineCommand9 } from "citty";
3492
+ import pc14 from "picocolors";
3493
+ var enable, disable, status, telemetry_default;
3494
+ var init_telemetry2 = __esm({
3495
+ "src/commands/telemetry.ts"() {
3496
+ "use strict";
3497
+ init_telemetry();
3498
+ init_ui();
3499
+ enable = defineCommand9({
3500
+ meta: {
3501
+ name: "enable",
3502
+ description: "Enable anonymous usage analytics"
3503
+ },
3504
+ async run() {
3505
+ try {
3506
+ await setEnabled(true);
3507
+ printStatus("Telemetry enabled");
3508
+ } catch {
3509
+ printError("Failed to update telemetry settings");
3510
+ process.exit(1);
3511
+ }
3512
+ }
3513
+ });
3514
+ disable = defineCommand9({
3515
+ meta: {
3516
+ name: "disable",
3517
+ description: "Disable anonymous usage analytics"
3518
+ },
3519
+ async run() {
3520
+ try {
3521
+ await setEnabled(false);
3522
+ printStatus("Telemetry disabled");
3523
+ printInfo(
3524
+ "You can also set FLYDOCS_TELEMETRY=0 in your shell environment."
3525
+ );
3526
+ } catch {
3527
+ printError("Failed to update telemetry settings");
3528
+ process.exit(1);
3529
+ }
3530
+ }
3531
+ });
3532
+ status = defineCommand9({
3533
+ meta: {
3534
+ name: "status",
3535
+ description: "Show current telemetry status"
3536
+ },
3537
+ async run() {
3538
+ const info = await getStatus();
3539
+ console.log();
3540
+ console.log(pc14.bold("Telemetry Status"));
3541
+ console.log();
3542
+ const effectivelyEnabled = info.enabled && !info.envOverride;
3543
+ console.log(
3544
+ ` Enabled: ${effectivelyEnabled ? pc14.green("yes") : pc14.yellow("no")}`
3545
+ );
3546
+ if (info.envOverride) {
3547
+ console.log(
3548
+ ` Env override: ${pc14.yellow("FLYDOCS_TELEMETRY=0 (disabled via env)")}`
3549
+ );
3550
+ }
3551
+ if (info.anonymousId) {
3552
+ console.log(` Anonymous ID: ${pc14.dim(info.anonymousId)}`);
3553
+ } else {
3554
+ console.log(
3555
+ ` Anonymous ID: ${pc14.dim("(not yet created \u2014 generated on first run)")}`
3556
+ );
3557
+ }
3558
+ console.log();
3559
+ console.log(
3560
+ pc14.dim(
3561
+ " FlyDocs collects anonymous usage analytics to improve the CLI."
3562
+ )
3563
+ );
3564
+ console.log(
3565
+ pc14.dim(" No personal data, file contents, or code is ever collected.")
3566
+ );
3567
+ console.log();
3568
+ }
3569
+ });
3570
+ telemetry_default = defineCommand9({
3571
+ meta: {
3572
+ name: "telemetry",
3573
+ description: "Manage anonymous usage analytics (enable, disable, status)"
3574
+ },
3575
+ subCommands: {
3576
+ enable,
3577
+ disable,
3578
+ status
3579
+ }
3580
+ });
3581
+ }
3582
+ });
3583
+
3023
3584
  // src/cli.ts
3024
3585
  init_constants();
3025
- import { defineCommand as defineCommand8, runMain } from "citty";
3586
+ import { defineCommand as defineCommand10, runMain } from "citty";
3026
3587
  var SUB_COMMANDS = /* @__PURE__ */ new Set([
3027
3588
  "install",
3028
3589
  "update",
3590
+ "uninstall",
3029
3591
  "setup",
3030
3592
  "skills",
3031
3593
  "connect",
3032
3594
  "upgrade",
3033
- "self-update"
3595
+ "self-update",
3596
+ "telemetry"
3034
3597
  ]);
3035
3598
  var userArgs = process.argv.slice(2);
3036
3599
  var hasMetaFlag = userArgs.some(
@@ -3040,7 +3603,7 @@ var firstPositional = userArgs.find((a) => !a.startsWith("-"));
3040
3603
  if (!hasMetaFlag && (!firstPositional || !SUB_COMMANDS.has(firstPositional))) {
3041
3604
  process.argv.splice(2, 0, "install");
3042
3605
  }
3043
- var main = defineCommand8({
3606
+ var main = defineCommand10({
3044
3607
  meta: {
3045
3608
  name: CLI_NAME,
3046
3609
  version: CLI_VERSION,
@@ -3049,11 +3612,13 @@ var main = defineCommand8({
3049
3612
  subCommands: {
3050
3613
  install: () => Promise.resolve().then(() => (init_install(), install_exports)).then((m) => m.default),
3051
3614
  update: () => Promise.resolve().then(() => (init_update(), update_exports)).then((m) => m.default),
3615
+ uninstall: () => Promise.resolve().then(() => (init_uninstall(), uninstall_exports)).then((m) => m.default),
3052
3616
  setup: () => Promise.resolve().then(() => (init_setup(), setup_exports)).then((m) => m.default),
3053
3617
  skills: () => Promise.resolve().then(() => (init_skills2(), skills_exports)).then((m) => m.default),
3054
3618
  connect: () => Promise.resolve().then(() => (init_connect(), connect_exports)).then((m) => m.default),
3055
3619
  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)
3620
+ "self-update": () => Promise.resolve().then(() => (init_self_update(), self_update_exports)).then((m) => m.default),
3621
+ telemetry: () => Promise.resolve().then(() => (init_telemetry2(), telemetry_exports)).then((m) => m.default)
3057
3622
  }
3058
3623
  });
3059
3624
  runMain(main);