gnosys 5.9.2 → 5.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/cli.js +311 -147
  2. package/dist/cli.js.map +1 -1
  3. package/dist/lib/chat/index.d.ts.map +1 -1
  4. package/dist/lib/chat/index.js +5 -0
  5. package/dist/lib/chat/index.js.map +1 -1
  6. package/dist/lib/cleanup.d.ts +52 -0
  7. package/dist/lib/cleanup.d.ts.map +1 -0
  8. package/dist/lib/cleanup.js +168 -0
  9. package/dist/lib/cleanup.js.map +1 -0
  10. package/dist/lib/config.d.ts +7 -0
  11. package/dist/lib/config.d.ts.map +1 -1
  12. package/dist/lib/config.js +7 -1
  13. package/dist/lib/config.js.map +1 -1
  14. package/dist/lib/paths.d.ts +8 -0
  15. package/dist/lib/paths.d.ts.map +1 -1
  16. package/dist/lib/paths.js +15 -0
  17. package/dist/lib/paths.js.map +1 -1
  18. package/dist/lib/remoteWizard.d.ts.map +1 -1
  19. package/dist/lib/remoteWizard.js +112 -52
  20. package/dist/lib/remoteWizard.js.map +1 -1
  21. package/dist/lib/setup/coldStart.d.ts +71 -0
  22. package/dist/lib/setup/coldStart.d.ts.map +1 -0
  23. package/dist/lib/setup/coldStart.js +122 -0
  24. package/dist/lib/setup/coldStart.js.map +1 -0
  25. package/dist/lib/setup/configSetRender.d.ts +26 -0
  26. package/dist/lib/setup/configSetRender.d.ts.map +1 -0
  27. package/dist/lib/setup/configSetRender.js +103 -0
  28. package/dist/lib/setup/configSetRender.js.map +1 -0
  29. package/dist/lib/setup/dreamRender.d.ts +44 -0
  30. package/dist/lib/setup/dreamRender.d.ts.map +1 -0
  31. package/dist/lib/setup/dreamRender.js +55 -0
  32. package/dist/lib/setup/dreamRender.js.map +1 -0
  33. package/dist/lib/setup/modelsRender.d.ts +25 -0
  34. package/dist/lib/setup/modelsRender.d.ts.map +1 -0
  35. package/dist/lib/setup/modelsRender.js +33 -0
  36. package/dist/lib/setup/modelsRender.js.map +1 -0
  37. package/dist/lib/setup/remoteRender.d.ts +43 -0
  38. package/dist/lib/setup/remoteRender.d.ts.map +1 -0
  39. package/dist/lib/setup/remoteRender.js +65 -0
  40. package/dist/lib/setup/remoteRender.js.map +1 -0
  41. package/dist/lib/setup/routingRender.d.ts +44 -0
  42. package/dist/lib/setup/routingRender.d.ts.map +1 -0
  43. package/dist/lib/setup/routingRender.js +97 -0
  44. package/dist/lib/setup/routingRender.js.map +1 -0
  45. package/dist/lib/setup/sections/ides.d.ts +8 -0
  46. package/dist/lib/setup/sections/ides.d.ts.map +1 -1
  47. package/dist/lib/setup/sections/ides.js +49 -27
  48. package/dist/lib/setup/sections/ides.js.map +1 -1
  49. package/dist/lib/setup/sections/preferences.d.ts +8 -0
  50. package/dist/lib/setup/sections/preferences.d.ts.map +1 -1
  51. package/dist/lib/setup/sections/preferences.js +40 -19
  52. package/dist/lib/setup/sections/preferences.js.map +1 -1
  53. package/dist/lib/setup/sections/routing.d.ts +0 -1
  54. package/dist/lib/setup/sections/routing.d.ts.map +1 -1
  55. package/dist/lib/setup/sections/routing.js +49 -29
  56. package/dist/lib/setup/sections/routing.js.map +1 -1
  57. package/dist/lib/setup/summary.d.ts +33 -19
  58. package/dist/lib/setup/summary.d.ts.map +1 -1
  59. package/dist/lib/setup/summary.js +135 -105
  60. package/dist/lib/setup/summary.js.map +1 -1
  61. package/dist/lib/setup/syncProjectsRender.d.ts +56 -0
  62. package/dist/lib/setup/syncProjectsRender.d.ts.map +1 -0
  63. package/dist/lib/setup/syncProjectsRender.js +168 -0
  64. package/dist/lib/setup/syncProjectsRender.js.map +1 -0
  65. package/dist/lib/setup/ui/diff.d.ts +19 -0
  66. package/dist/lib/setup/ui/diff.d.ts.map +1 -0
  67. package/dist/lib/setup/ui/diff.js +34 -0
  68. package/dist/lib/setup/ui/diff.js.map +1 -0
  69. package/dist/lib/setup/ui/footer.d.ts +11 -0
  70. package/dist/lib/setup/ui/footer.d.ts.map +1 -0
  71. package/dist/lib/setup/ui/footer.js +21 -0
  72. package/dist/lib/setup/ui/footer.js.map +1 -0
  73. package/dist/lib/setup/ui/header.d.ts +24 -0
  74. package/dist/lib/setup/ui/header.d.ts.map +1 -0
  75. package/dist/lib/setup/ui/header.js +49 -0
  76. package/dist/lib/setup/ui/header.js.map +1 -0
  77. package/dist/lib/setup/ui/index.d.ts +26 -0
  78. package/dist/lib/setup/ui/index.d.ts.map +1 -0
  79. package/dist/lib/setup/ui/index.js +18 -0
  80. package/dist/lib/setup/ui/index.js.map +1 -0
  81. package/dist/lib/setup/ui/menu.d.ts +27 -0
  82. package/dist/lib/setup/ui/menu.d.ts.map +1 -0
  83. package/dist/lib/setup/ui/menu.js +75 -0
  84. package/dist/lib/setup/ui/menu.js.map +1 -0
  85. package/dist/lib/setup/ui/panel.d.ts +23 -0
  86. package/dist/lib/setup/ui/panel.d.ts.map +1 -0
  87. package/dist/lib/setup/ui/panel.js +53 -0
  88. package/dist/lib/setup/ui/panel.js.map +1 -0
  89. package/dist/lib/setup/ui/prompt.d.ts +27 -0
  90. package/dist/lib/setup/ui/prompt.d.ts.map +1 -0
  91. package/dist/lib/setup/ui/prompt.js +38 -0
  92. package/dist/lib/setup/ui/prompt.js.map +1 -0
  93. package/dist/lib/setup/ui/safePrompt.d.ts +24 -0
  94. package/dist/lib/setup/ui/safePrompt.d.ts.map +1 -0
  95. package/dist/lib/setup/ui/safePrompt.js +71 -0
  96. package/dist/lib/setup/ui/safePrompt.js.map +1 -0
  97. package/dist/lib/setup/ui/spinner.d.ts +28 -0
  98. package/dist/lib/setup/ui/spinner.d.ts.map +1 -0
  99. package/dist/lib/setup/ui/spinner.js +87 -0
  100. package/dist/lib/setup/ui/spinner.js.map +1 -0
  101. package/dist/lib/setup/ui/status.d.ts +21 -0
  102. package/dist/lib/setup/ui/status.d.ts.map +1 -0
  103. package/dist/lib/setup/ui/status.js +49 -0
  104. package/dist/lib/setup/ui/status.js.map +1 -0
  105. package/dist/lib/setup/ui/title.d.ts +14 -0
  106. package/dist/lib/setup/ui/title.d.ts.map +1 -0
  107. package/dist/lib/setup/ui/title.js +24 -0
  108. package/dist/lib/setup/ui/title.js.map +1 -0
  109. package/dist/lib/setup/ui/tokens.d.ts +66 -0
  110. package/dist/lib/setup/ui/tokens.d.ts.map +1 -0
  111. package/dist/lib/setup/ui/tokens.js +87 -0
  112. package/dist/lib/setup/ui/tokens.js.map +1 -0
  113. package/dist/lib/setup.d.ts +7 -0
  114. package/dist/lib/setup.d.ts.map +1 -1
  115. package/dist/lib/setup.js +204 -230
  116. package/dist/lib/setup.js.map +1 -1
  117. package/package.json +1 -1
package/dist/lib/setup.js CHANGED
@@ -17,6 +17,7 @@ import { execSync } from "child_process";
17
17
  import { loadConfig, updateConfig, getProviderModel, } from "./config.js";
18
18
  import { validateModel } from "./modelValidation.js";
19
19
  import { getGnosysHome } from "./paths.js";
20
+ import { safeQuestion } from "./setup/ui/safePrompt.js";
20
21
  // ─── ANSI Colors ────────────────────────────────────────────────────────────
21
22
  const BOLD = "\x1b[1m";
22
23
  const DIM = "\x1b[2m";
@@ -769,7 +770,7 @@ async function askChoice(rl, question, options) {
769
770
  }
770
771
  console.log();
771
772
  while (true) {
772
- const answer = await rl.question(`${DIM}>${RESET} `);
773
+ const answer = await safeQuestion(rl, `${DIM}>${RESET} `);
773
774
  const num = parseInt(answer.trim(), 10);
774
775
  if (num >= 1 && num <= options.length) {
775
776
  return num - 1;
@@ -782,7 +783,7 @@ async function askChoice(rl, question, options) {
782
783
  */
783
784
  async function askInput(rl, prompt, opts) {
784
785
  const suffix = opts?.default ? ` ${DIM}(${opts.default})${RESET}` : "";
785
- const answer = await rl.question(`${prompt}${suffix}: `);
786
+ const answer = await safeQuestion(rl, `${prompt}${suffix}: `);
786
787
  const trimmed = answer.trim();
787
788
  return trimmed || opts?.default || "";
788
789
  }
@@ -791,7 +792,7 @@ async function askInput(rl, prompt, opts) {
791
792
  */
792
793
  async function askYesNo(rl, question, defaultYes = true) {
793
794
  const hint = defaultYes ? "Y/n" : "y/N";
794
- const answer = await rl.question(`${question} [${hint}] `);
795
+ const answer = await safeQuestion(rl, `${question} [${hint}] `);
795
796
  const trimmed = answer.trim().toLowerCase();
796
797
  if (trimmed === "")
797
798
  return defaultYes;
@@ -983,16 +984,10 @@ export async function runSetup(opts) {
983
984
  let upgraded = false;
984
985
  try {
985
986
  // ─── Banner ───────────────────────────────────────────────────────
986
- const tagline = "Persistent Memory for AI Agents";
987
- const versionStr = `Gnosys v${version}`;
988
- const bannerContentWidth = Math.max(versionStr.length, tagline.length);
989
- const bannerInner = bannerContentWidth + 4;
990
- const bannerBorder = "\u2500".repeat(bannerInner);
987
+ // v5.9.3 redesign: atom-based splash replaces the old ASCII box banner.
988
+ const { renderColdStartSplash } = await import("./setup/coldStart.js");
991
989
  console.log();
992
- console.log(`\u250C${bannerBorder}\u2510`);
993
- console.log(`\u2502 ${BOLD}${CYAN}Gnosys${RESET} v${version}${" ".repeat(bannerInner - versionStr.length - 2)}\u2502`);
994
- console.log(`\u2502 ${DIM}${tagline}${RESET}${" ".repeat(bannerInner - tagline.length - 2)}\u2502`);
995
- console.log(`\u2514${bannerBorder}\u2518`);
990
+ console.log(renderColdStartSplash(version));
996
991
  console.log();
997
992
  // ─── Load existing config for defaults ───────────────────────────
998
993
  const existingConfig = await loadExistingConfig(projectDir);
@@ -1076,7 +1071,12 @@ export async function runSetup(opts) {
1076
1071
  const currentProviderHint = currentProvider
1077
1072
  ? ` ${DIM}(current: ${currentProvider})${RESET}`
1078
1073
  : "";
1079
- const providerIndex = await askChoice(rl, `${BOLD}Step 1/5${RESET} ${DIM}\u2014${RESET} Choose your LLM provider${currentProviderHint}`, providerOptions);
1074
+ // v5.9.3 Screen 1.1 chrome \u2014 Header + Title + step counter wrap.
1075
+ const { renderProviderStepHeader, renderModelStepHeader, renderKeyStepHeader } = await import("./setup/coldStart.js");
1076
+ console.log();
1077
+ console.log(renderProviderStepHeader(version));
1078
+ console.log();
1079
+ const providerIndex = await askChoice(rl, `Choose your LLM provider${currentProviderHint}`, providerOptions);
1080
1080
  const isSkip = providerIndex === PROVIDER_ORDER.length; // last option
1081
1081
  const provider = isSkip ? "skip" : PROVIDER_ORDER[providerIndex];
1082
1082
  // ─── Step 2/5 — Model tier ────────────────────────────────────────
@@ -1096,7 +1096,11 @@ export async function runSetup(opts) {
1096
1096
  return `${t.name} (${t.model}) ${DIM}${formatPrice(t.input, t.output)}${RESET}${rec}`;
1097
1097
  });
1098
1098
  tierOptions.push(`Custom ${DIM}(enter model name)${RESET}`);
1099
- const tierIndex = await askChoice(rl, `${BOLD}Step 2/5${RESET} ${DIM}\u2014${RESET} Choose model tier${currentModelHint}`, tierOptions);
1099
+ // v5.9.3 Screen 1.2 chrome \u2014 Header + Title + step counter wrap.
1100
+ console.log();
1101
+ console.log(renderModelStepHeader(provider, version));
1102
+ console.log();
1103
+ const tierIndex = await askChoice(rl, `Choose model tier${currentModelHint}`, tierOptions);
1100
1104
  if (tierIndex === tiers.length) {
1101
1105
  model = await askInput(rl, "Enter model name");
1102
1106
  }
@@ -1169,8 +1173,9 @@ export async function runSetup(opts) {
1169
1173
  };
1170
1174
  const legacyEnvVar = legacyEnvVars[provider] ?? "";
1171
1175
  if (needsKey) {
1176
+ // v5.9.3 Screen 1.3 chrome \u2014 Header + Title + step counter wrap.
1172
1177
  console.log();
1173
- console.log(`${BOLD}Step 3/5${RESET} ${DIM}\u2014${RESET} API Key`);
1178
+ console.log(renderKeyStepHeader(provider, version));
1174
1179
  console.log();
1175
1180
  // Check where the key currently lives
1176
1181
  const existingKeySource = detectKeySource(envVarName, legacyEnvVar);
@@ -1716,7 +1721,7 @@ export async function runSetup(opts) {
1716
1721
  console.log("Share your gnosys.db across machines via NAS or shared drive.");
1717
1722
  console.log(`Your local DB stays fast, the remote is the source of truth.`);
1718
1723
  console.log();
1719
- const setUpRemote = (await rl.question(`Configure remote sync now? [y/N] `)).trim().toLowerCase();
1724
+ const setUpRemote = (await safeQuestion(rl, `Configure remote sync now? [y/N] `)).trim().toLowerCase();
1720
1725
  if (setUpRemote === "y" || setUpRemote === "yes") {
1721
1726
  console.log();
1722
1727
  try {
@@ -1777,30 +1782,47 @@ export async function runModelsSetup(opts = {}) {
1777
1782
  const ownsRl = !opts.rl;
1778
1783
  const rl = opts.rl ?? createInterface({ input: stdin, output: stdout });
1779
1784
  try {
1785
+ // v5.9.3 Screen 3 — Header + Title at the top.
1786
+ const { Header } = await import("./setup/ui/header.js");
1787
+ const { Title } = await import("./setup/ui/title.js");
1788
+ const { Spinner } = await import("./setup/ui/spinner.js");
1789
+ const { printDiff } = await import("./setup/ui/diff.js");
1790
+ const { printStatus } = await import("./setup/ui/status.js");
1791
+ console.log();
1792
+ console.log(Header(["gnosys", "setup", "models"]));
1780
1793
  console.log();
1781
- console.log(`${BOLD}${CYAN}Gnosys${RESET} ${DIM}Model Configuration${RESET}`);
1794
+ console.log(Title("Model configuration", "pick a provider and model we'll validate it before saving"));
1782
1795
  console.log();
1783
1796
  const existingConfig = await loadExistingConfig(projectDir);
1784
1797
  const currentProvider = existingConfig?.llm.defaultProvider;
1785
1798
  const currentModel = existingConfig
1786
1799
  ? getProviderModel(existingConfig, existingConfig.llm.defaultProvider)
1787
1800
  : undefined;
1788
- // Step 1: provider (or use --provider flag)
1789
- console.log(`${DIM}Fetching latest model pricing...${RESET}`);
1801
+ // Step 1: provider (or use --provider flag). v5.9.3: animate the
1802
+ // OpenRouter pricing fetch under a Spinner so the user gets feedback
1803
+ // on what would otherwise feel like a hang.
1804
+ const pricingSpin = Spinner("fetching latest pricing from openrouter…");
1805
+ const fetchStart = Date.now();
1790
1806
  const dynamicModels = await fetchDynamicModels();
1807
+ const fetchMs = Date.now() - fetchStart;
1808
+ const modelCount = Object.values(dynamicModels).reduce((n, tiers) => n + tiers.length, 0);
1791
1809
  if (Object.keys(dynamicModels).length > 0) {
1792
- console.log(`${DIM}${CHECK} Live pricing loaded from OpenRouter${RESET}`);
1810
+ pricingSpin.ok(`pricing loaded · ${modelCount} models cached`, `${fetchMs} ms`);
1811
+ }
1812
+ else {
1813
+ // No-op fallback (cache miss + network fail) — keep the hardcoded
1814
+ // tiers but signal that we're running offline.
1815
+ pricingSpin.fail("pricing fetch failed", "using bundled tiers");
1793
1816
  }
1794
1817
  console.log();
1795
1818
  let provider;
1796
1819
  if (opts.provider) {
1797
1820
  if (!PROVIDER_ORDER.includes(opts.provider)) {
1798
- console.log(`${CROSS} Unknown provider: ${opts.provider}`);
1799
- console.log(` Valid: ${PROVIDER_ORDER.join(", ")}`);
1821
+ printStatus("fail", `unknown provider \`${opts.provider}\``, `valid: ${PROVIDER_ORDER.join(", ")}`);
1800
1822
  return;
1801
1823
  }
1802
1824
  provider = opts.provider;
1803
- console.log(`Provider: ${GREEN}${provider}${RESET}`);
1825
+ printStatus("ok", "provider", provider);
1804
1826
  }
1805
1827
  else {
1806
1828
  provider = await pickProvider(rl, dynamicModels, "Choose your LLM provider", currentProvider);
@@ -1809,7 +1831,7 @@ export async function runModelsSetup(opts = {}) {
1809
1831
  let model;
1810
1832
  if (opts.model) {
1811
1833
  model = opts.model;
1812
- console.log(`Model: ${GREEN}${model}${RESET}`);
1834
+ printStatus("ok", "model", model);
1813
1835
  }
1814
1836
  else {
1815
1837
  const tiers = dynamicModels[provider] ?? PROVIDER_TIERS[provider];
@@ -1822,7 +1844,7 @@ export async function runModelsSetup(opts = {}) {
1822
1844
  }
1823
1845
  }
1824
1846
  if (!model) {
1825
- console.log(`${CROSS} No model selected. Aborting.`);
1847
+ printStatus("fail", "no model selected · aborting");
1826
1848
  return;
1827
1849
  }
1828
1850
  // Step 3: load API key from existing storage (if available)
@@ -1849,24 +1871,25 @@ export async function runModelsSetup(opts = {}) {
1849
1871
  console.log(`${WARN} No API key found for ${provider}. Run 'gnosys setup' to configure one.`);
1850
1872
  // Continue anyway — user might just want to update the model in config
1851
1873
  }
1852
- // Step 4: validate (default: true)
1874
+ // Step 4: validate (default: true) — v5.9.3 Screen 3: animated
1875
+ // Spinner with latency reported on success.
1853
1876
  const shouldValidate = opts.validate !== false;
1854
1877
  const isLocalProvider = provider === "ollama" || provider === "lmstudio";
1855
1878
  if (shouldValidate && (apiKey || isLocalProvider)) {
1856
1879
  console.log();
1857
- console.log(`${DIM}Testing ${provider}/${model}...${RESET}`);
1880
+ const validateSpin = Spinner(`validating ${provider} / ${model}…`);
1858
1881
  const customBaseUrl = provider === "custom"
1859
1882
  ? process.env.GNOSYS_LLM_BASE_URL
1860
1883
  : undefined;
1861
1884
  const result = await validateModel(provider, model, apiKey, { customBaseUrl });
1862
1885
  if (result.ok) {
1863
- console.log(` ${CHECK} Model validated (${result.latencyMs}ms)`);
1886
+ validateSpin.ok("model validated", `${result.latencyMs} ms · ${provider} / ${model}`);
1864
1887
  }
1865
1888
  else {
1866
- console.log(` ${WARN} Model test failed: ${result.error}`);
1867
- const proceed = await askYesNo(rl, " Save config anyway?", false);
1889
+ validateSpin.fail("model test failed", result.error);
1890
+ const proceed = await askYesNo(rl, "Save config anyway?", false);
1868
1891
  if (!proceed) {
1869
- console.log(` ${DIM}Cancelled.${RESET}`);
1892
+ printStatus("warn", "cancelled · no changes written");
1870
1893
  return;
1871
1894
  }
1872
1895
  }
@@ -1902,10 +1925,12 @@ export async function runModelsSetup(opts = {}) {
1902
1925
  },
1903
1926
  },
1904
1927
  });
1928
+ // v5.9.3 Screen 3 — Diff() before the saved confirmation. Shows what
1929
+ // landed in gnosys.json.
1930
+ const { buildModelsDiffRows } = await import("./setup/modelsRender.js");
1905
1931
  console.log();
1906
- console.log(` ${CHECK} Config saved: ${storePath}/gnosys.json`);
1907
- console.log(` ${DIM}Provider: ${provider}${RESET}`);
1908
- console.log(` ${DIM}Model: ${model}${RESET}`);
1932
+ printDiff(buildModelsDiffRows(currentProvider, currentModel, provider, model));
1933
+ printStatus("ok", `saved · ${storePath}/gnosys.json`);
1909
1934
  }
1910
1935
  finally {
1911
1936
  if (ownsRl)
@@ -2009,9 +2034,14 @@ export async function runDreamSetup(opts = {}) {
2009
2034
  const ownsRl = !opts.rl;
2010
2035
  const rl = opts.rl ?? createInterface({ input: stdin, output: stdout });
2011
2036
  try {
2012
- console.log();
2013
- console.log(`${BOLD}${CYAN}Gnosys${RESET} ${DIM}— Dream Mode Setup${RESET}`);
2014
- console.log();
2037
+ // v5.9.3 Screen 7 — three grouped sub-screens (7.0 enable, 7.1
2038
+ // machine+model, 7.2 thresholds+sub-tasks). Each sub-screen renders
2039
+ // its own Header with `step N of 3` so the progress is always visible.
2040
+ const { Header } = await import("./setup/ui/header.js");
2041
+ const { Title } = await import("./setup/ui/title.js");
2042
+ const { Spinner } = await import("./setup/ui/spinner.js");
2043
+ const { printDiff } = await import("./setup/ui/diff.js");
2044
+ const { printStatus } = await import("./setup/ui/status.js");
2015
2045
  const existingConfig = await loadExistingConfig(projectDir);
2016
2046
  const existingDream = existingConfig?.dream;
2017
2047
  // Show current state via central DB
@@ -2027,26 +2057,18 @@ export async function runDreamSetup(opts = {}) {
2027
2057
  }
2028
2058
  return id;
2029
2059
  })();
2030
- const recentRuns = localDb.getRecentDreamRuns(1);
2031
- const lastRun = recentRuns[0];
2032
- console.log(`${DIM}Current state${RESET}`);
2033
- console.log(` Enabled: ${existingDream?.enabled ? GREEN + "yes" + RESET : DIM + "no" + RESET}`);
2034
- console.log(` Designated: ${designatedMachine ? designatedMachine + (designatedMachine === localMachine ? ` ${GREEN}(this machine)${RESET}` : ` ${DIM}(other machine)${RESET}`) : DIM + "none" + RESET}`);
2035
- console.log(` This machine ID: ${DIM}${localMachine}${RESET}`);
2036
- if (existingDream) {
2037
- console.log(` Provider: ${existingDream.provider}${existingDream.model ? "/" + existingDream.model : ""}`);
2038
- console.log(` Idle threshold: ${existingDream.idleMinutes} min`);
2039
- console.log(` Max runtime: ${existingDream.maxRuntimeMinutes} min`);
2040
- }
2041
- if (lastRun) {
2042
- console.log(` Last run: ${DIM}${lastRun.completed}${RESET}`);
2043
- }
2044
- else {
2045
- console.log(` Last run: ${DIM}never${RESET}`);
2046
- }
2060
+ // ─── 7.0 Overview & enable ────────────────────────────────────────
2061
+ console.log();
2062
+ console.log(Header(["gnosys", "setup", "dream"], { version: "step 1 of 3" }));
2063
+ console.log();
2064
+ console.log(Title("Dream Mode", "gnosys runs background consolidation while you're idle merging related memories, generating summaries, surfacing relationships."));
2065
+ console.log();
2066
+ const currentStateLine = existingDream?.enabled
2067
+ ? `enabled · ${designatedMachine ? designatedMachine === localMachine ? `${localMachine} (this machine)` : designatedMachine : "no designated machine"}`
2068
+ : "disabled · no designated machine";
2069
+ printStatus("progress", "current", currentStateLine);
2047
2070
  console.log();
2048
- // Step 1: Enable
2049
- const enabled = await askYesNo(rl, "Enable dream mode?", existingDream?.enabled ?? true);
2071
+ const enabled = await askYesNo(rl, "enable Dream Mode?", existingDream?.enabled ?? true);
2050
2072
  if (!enabled) {
2051
2073
  // Persist disabled state and clear designation
2052
2074
  const storePath = pickStorePath(projectDir);
@@ -2054,36 +2076,48 @@ export async function runDreamSetup(opts = {}) {
2054
2076
  dream: { ...(existingDream ?? {}), enabled: false },
2055
2077
  });
2056
2078
  localDb.clearDreamMachineId();
2057
- console.log(`${CHECK} Dream mode disabled. Designation cleared.`);
2079
+ console.log();
2080
+ printStatus("ok", "dream mode disabled · designation cleared");
2058
2081
  localDb.close();
2059
2082
  return;
2060
2083
  }
2061
- // Step 2: Designate this machine
2084
+ // ─── 7.1 Designated machine + model ───────────────────────────────
2085
+ console.log();
2086
+ console.log(Header(["gnosys", "setup", "dream", "machine"], { version: "step 2 of 3" }));
2087
+ console.log();
2088
+ console.log(Title("Only one machine dreams at a time — we'll designate one now."));
2089
+ console.log();
2090
+ printStatus("progress", "this machine", localMachine);
2091
+ console.log();
2062
2092
  const designate = await askYesNo(rl, designatedMachine === localMachine
2063
- ? "This machine is currently the dream node. Keep it that way?"
2064
- : `Designate THIS machine (${localMachine}) to run dream cycles?`, true);
2093
+ ? "this machine is currently the dreamer keep it?"
2094
+ : `designate THIS machine (${localMachine}) as the dreamer?`, true);
2065
2095
  if (designate) {
2066
2096
  localDb.setDreamMachineId(localMachine);
2067
- console.log(` ${CHECK} ${localMachine} is now the dream node.`);
2097
+ printStatus("ok", `${localMachine} is the dreamer`);
2068
2098
  }
2069
2099
  else if (designatedMachine === localMachine) {
2070
2100
  localDb.clearDreamMachineId();
2071
- console.log(` ${WARN} Designation cleared. No machine will dream until you re-run this on another machine.`);
2101
+ printStatus("warn", "designation cleared", "no machine will dream until you re-run on another");
2072
2102
  }
2073
2103
  else {
2074
- console.log(` ${DIM}Keeping current designation: ${designatedMachine || "none"}${RESET}`);
2104
+ printStatus("progress", "keeping current designation", designatedMachine || "none");
2075
2105
  }
2076
- // Step 3: Provider
2106
+ // Pricing fetch — animated Spinner.
2077
2107
  console.log();
2078
- console.log(`${DIM}Fetching latest model pricing...${RESET}`);
2108
+ const pricingSpin = Spinner("fetching latest pricing from openrouter…");
2109
+ const fetchStart = Date.now();
2079
2110
  const dynamicModels = await fetchDynamicModels();
2111
+ const fetchMs = Date.now() - fetchStart;
2080
2112
  if (Object.keys(dynamicModels).length > 0) {
2081
- console.log(`${DIM}${CHECK} Live pricing loaded from OpenRouter${RESET}`);
2113
+ pricingSpin.ok("pricing loaded", `${fetchMs} ms`);
2114
+ }
2115
+ else {
2116
+ pricingSpin.fail("pricing fetch failed", "using bundled tiers");
2082
2117
  }
2083
2118
  console.log();
2084
2119
  const defaultProvider = existingDream?.provider || existingConfig?.llm.defaultProvider || "ollama";
2085
- const dreamProvider = await pickProvider(rl, dynamicModels, `${BOLD}Step 3${RESET} ${DIM}—${RESET} Choose dream LLM provider`, defaultProvider);
2086
- // Step 4: Model
2120
+ const dreamProvider = await pickProvider(rl, dynamicModels, "Choose dream LLM provider — local is recommended (dream runs a lot)", defaultProvider);
2087
2121
  let dreamModel = "";
2088
2122
  if (dreamProvider === "custom" || dreamProvider === "skip") {
2089
2123
  dreamModel = await askInput(rl, "Enter model name");
@@ -2094,61 +2128,80 @@ export async function runDreamSetup(opts = {}) {
2094
2128
  dreamModel = await askInput(rl, "Enter model name");
2095
2129
  }
2096
2130
  else {
2097
- dreamModel = await pickModel(rl, dreamProvider, dynamicModels, `${BOLD}Step 4${RESET} ${DIM}—${RESET} Choose dream model`, existingDream?.model);
2131
+ dreamModel = await pickModel(rl, dreamProvider, dynamicModels, "Choose dream model", existingDream?.model);
2098
2132
  }
2099
2133
  }
2100
- // Step 5: Validate (Layer 1 alert)
2134
+ // Validate animated Spinner with the model latency reported.
2101
2135
  if (dreamProvider !== "skip") {
2102
2136
  const apiKey = await getApiKeyForProvider(dreamProvider);
2103
- if (apiKey || dreamProvider === "ollama" || dreamProvider === "lmstudio") {
2137
+ const isLocalProvider = dreamProvider === "ollama" || dreamProvider === "lmstudio";
2138
+ if (apiKey || isLocalProvider) {
2104
2139
  console.log();
2105
- console.log(`${DIM}Testing ${dreamProvider}/${dreamModel}...${RESET}`);
2140
+ const validateSpin = Spinner(`validating ${dreamProvider} / ${dreamModel}…`);
2106
2141
  try {
2107
2142
  const customBaseUrl = dreamProvider === "custom" ? process.env.GNOSYS_LLM_BASE_URL : undefined;
2108
2143
  const result = await validateModel(dreamProvider, dreamModel, apiKey, { customBaseUrl });
2109
2144
  if (result.ok) {
2110
- console.log(` ${CHECK} Validated (${result.latencyMs}ms)`);
2145
+ validateSpin.ok("model validated", `${result.latencyMs} ms · ${dreamProvider} / ${dreamModel}`);
2111
2146
  }
2112
2147
  else {
2113
- console.log(` ${WARN} Could not reach ${dreamProvider}/${dreamModel}: ${result.error}`);
2114
- console.log(` ${DIM}Dream is configured but won't run useful work until this is fixed.${RESET}`);
2115
- const proceed = await askYesNo(rl, " Continue saving config anyway?", true);
2148
+ validateSpin.fail("could not reach model", result.error);
2149
+ const proceed = await askYesNo(rl, "save config anyway?", true);
2116
2150
  if (!proceed) {
2117
- console.log(` ${DIM}Setup cancelled. No changes saved.${RESET}`);
2151
+ printStatus("warn", "setup cancelled · no changes written");
2118
2152
  localDb.close();
2119
2153
  return;
2120
2154
  }
2121
2155
  }
2122
2156
  }
2123
2157
  catch (err) {
2124
- console.log(` ${DIM}Validation skipped: ${err instanceof Error ? err.message : err}${RESET}`);
2158
+ printStatus("warn", "validation skipped", err instanceof Error ? err.message : String(err));
2125
2159
  }
2126
2160
  }
2127
2161
  else {
2128
- console.log(` ${WARN} No API key configured for ${dreamProvider}. Set one via 'gnosys setup models'.`);
2162
+ printStatus("warn", `no API key for ${dreamProvider}`, "set one via `gnosys setup models`");
2129
2163
  }
2130
2164
  }
2131
- // Step 6-8: schedule
2165
+ // ─── 7.2 Thresholds + sub-tasks ───────────────────────────────────
2132
2166
  console.log();
2133
- console.log(`${BOLD}Step 6${RESET} ${DIM}—${RESET} Schedule`);
2134
- const idleAns = await askInput(rl, `Idle minutes before triggering`, {
2135
- default: String(existingDream?.idleMinutes ?? 10),
2136
- });
2137
- const idleMinutes = Math.max(1, parseInt(idleAns) || 10);
2138
- const runtimeAns = await askInput(rl, `Max runtime minutes`, {
2139
- default: String(existingDream?.maxRuntimeMinutes ?? 30),
2140
- });
2141
- const maxRuntimeMinutes = Math.max(1, parseInt(runtimeAns) || 30);
2142
- const minMemAns = await askInput(rl, `Minimum memories before activating`, {
2143
- default: String(existingDream?.minMemories ?? 10),
2144
- });
2145
- const minMemories = Math.max(1, parseInt(minMemAns) || 10);
2146
- // Step 9: sub-tasks
2167
+ console.log(Header(["gnosys", "setup", "dream", "when & what"], { version: "step 3 of 3" }));
2168
+ console.log();
2169
+ console.log(Title("Thresholds & sub-tasks", "press enter to accept defaults, or `e` to edit"));
2170
+ console.log();
2171
+ // Defaults pulled from the existing config (or the global defaults).
2172
+ const dIdle = existingDream?.idleMinutes ?? 10;
2173
+ const dRuntime = existingDream?.maxRuntimeMinutes ?? 30;
2174
+ const dMinMem = existingDream?.minMemories ?? 10;
2175
+ const dSelfCritique = existingDream?.selfCritique ?? true;
2176
+ const dGenSummaries = existingDream?.generateSummaries ?? true;
2177
+ const dDiscover = existingDream?.discoverRelationships ?? true;
2178
+ const { renderThresholdsBlock } = await import("./setup/dreamRender.js");
2179
+ for (const line of renderThresholdsBlock(dIdle, dRuntime, dMinMem, {
2180
+ selfCritique: dSelfCritique,
2181
+ generateSummaries: dGenSummaries,
2182
+ discoverRelationships: dDiscover,
2183
+ })) {
2184
+ console.log(line);
2185
+ }
2147
2186
  console.log();
2148
- console.log(`${BOLD}Step 9${RESET} ${DIM}—${RESET} Dream sub-tasks`);
2149
- const selfCritique = await askYesNo(rl, "Self-critique (rule + LLM-based review flagging)", existingDream?.selfCritique ?? true);
2150
- const generateSummaries = await askYesNo(rl, "Generate summaries (LLM)", existingDream?.generateSummaries ?? true);
2151
- const discoverRelationships = await askYesNo(rl, "Discover relationships (LLM)", existingDream?.discoverRelationships ?? true);
2187
+ const editChoice = (await askInput(rl, "press enter to accept defaults, or e to edit")).trim().toLowerCase();
2188
+ let idleMinutes = dIdle;
2189
+ let maxRuntimeMinutes = dRuntime;
2190
+ let minMemories = dMinMem;
2191
+ let selfCritique = dSelfCritique;
2192
+ let generateSummaries = dGenSummaries;
2193
+ let discoverRelationships = dDiscover;
2194
+ if (editChoice === "e") {
2195
+ const idleAns = await askInput(rl, "idle minutes before triggering", { default: String(dIdle) });
2196
+ idleMinutes = Math.max(1, parseInt(idleAns) || dIdle);
2197
+ const runtimeAns = await askInput(rl, "max runtime minutes", { default: String(dRuntime) });
2198
+ maxRuntimeMinutes = Math.max(1, parseInt(runtimeAns) || dRuntime);
2199
+ const minMemAns = await askInput(rl, "minimum memories before activating", { default: String(dMinMem) });
2200
+ minMemories = Math.max(1, parseInt(minMemAns) || dMinMem);
2201
+ selfCritique = await askYesNo(rl, "self-critique (rule + LLM-based review flagging)", dSelfCritique);
2202
+ generateSummaries = await askYesNo(rl, "generate summaries (LLM)", dGenSummaries);
2203
+ discoverRelationships = await askYesNo(rl, "discover relationships (LLM)", dDiscover);
2204
+ }
2152
2205
  // Save
2153
2206
  const storePath = pickStorePath(projectDir);
2154
2207
  await updateConfig(storePath, {
@@ -2168,148 +2221,69 @@ export async function runDreamSetup(opts = {}) {
2168
2221
  // doesn't fire immediately based on stale history.
2169
2222
  localDb.resetDreamConsecutiveFailures();
2170
2223
  localDb.close();
2224
+ // Final Diff block per the design — provider/machine + the two
2225
+ // threshold fields most users actually care about.
2171
2226
  console.log();
2172
- console.log(` ${CHECK} Dream config saved: ${storePath}/gnosys.json`);
2173
- console.log(` ${DIM}Provider: ${dreamProvider}${dreamModel ? "/" + dreamModel : ""}${RESET}`);
2174
- console.log(` ${DIM}Schedule: idle ${idleMinutes}m / max ${maxRuntimeMinutes}m / min ${minMemories} memories${RESET}`);
2175
- console.log(` ${DIM}Designated: ${designate ? localMachine + " (this machine)" : (designatedMachine || "none")}${RESET}`);
2227
+ printStatus("ok", "dream mode enabled");
2176
2228
  console.log();
2177
- console.log(`${DIM}Tip: 'gnosys dream log' shows recent runs once dream starts cycling.${RESET}`);
2229
+ const { buildDreamDiffRows } = await import("./setup/dreamRender.js");
2230
+ printDiff(buildDreamDiffRows(existingDream
2231
+ ? {
2232
+ provider: existingDream.provider,
2233
+ model: existingDream.model,
2234
+ machine: designatedMachine ?? "—",
2235
+ idleMinutes: existingDream.idleMinutes,
2236
+ maxRuntimeMinutes: existingDream.maxRuntimeMinutes,
2237
+ }
2238
+ : null, {
2239
+ provider: dreamProvider,
2240
+ model: dreamModel || undefined,
2241
+ machine: designate ? localMachine : (designatedMachine ?? "none"),
2242
+ idleMinutes,
2243
+ maxRuntimeMinutes,
2244
+ selfCritique,
2245
+ generateSummaries,
2246
+ discoverRelationships,
2247
+ }));
2248
+ const dreamerName = designate ? localMachine : (designatedMachine ?? "the designated machine");
2249
+ printStatus("progress", `first cycle runs after ${dreamerName} is idle for ${idleMinutes} min`);
2250
+ printStatus("progress", "check status anytime with", "gnosys dashboard");
2178
2251
  }
2179
2252
  finally {
2180
2253
  if (ownsRl)
2181
2254
  rl.close();
2182
2255
  }
2183
2256
  }
2257
+ /**
2258
+ * v5.9.3 (deci-050): `gnosys setup chat` is deprecated. Chat config
2259
+ * moves into the chat TUI's own settings panel in v6.0 (road-014). This
2260
+ * stub renders a deprecation notice and exits. The function signature
2261
+ * is preserved so existing callers (cli.ts subcommand registration)
2262
+ * continue to compile.
2263
+ */
2184
2264
  export async function runChatSetup(opts = {}) {
2185
- const projectDir = opts.directory ? path.resolve(opts.directory) : process.cwd();
2186
- const ownsRl = !opts.rl;
2187
- const rl = opts.rl ?? createInterface({ input: stdin, output: stdout });
2188
- try {
2189
- console.log();
2190
- console.log(`${BOLD}${CYAN}Gnosys${RESET} ${DIM} Chat Setup${RESET}`);
2191
- console.log();
2192
- const existingConfig = await loadExistingConfig(projectDir);
2193
- const existingChat = existingConfig?.chat;
2194
- const existingRecall = existingConfig?.recall;
2195
- const existingChatTask = existingConfig?.taskModels?.chat;
2196
- const defaultLLMProvider = existingConfig?.llm.defaultProvider || "anthropic";
2197
- // ── Current state ────────────────────────────────────────────────
2198
- console.log(`${DIM}Current state${RESET}`);
2199
- const currentProvider = existingChatTask?.provider || defaultLLMProvider;
2200
- const currentModel = existingChatTask?.model || "(default for provider)";
2201
- console.log(` Provider: ${currentProvider}${existingChatTask ? "" : ` ${DIM}(inherited from default)${RESET}`}`);
2202
- console.log(` Model: ${currentModel}`);
2203
- console.log(` Recall mode: ${existingRecall?.aggressive ? "aggressive" : "filtered"} (max ${existingRecall?.maxMemories ?? 8}, threshold ${existingRecall?.minRelevance ?? 0.4})`);
2204
- console.log(` Tools fence: ${existingChat?.toolsEnabled !== false ? GREEN + "on" + RESET : DIM + "off" + RESET}`);
2205
- console.log(` Auto-summarize: ${existingChat?.autoSummarizeAfterTurns && existingChat.autoSummarizeAfterTurns > 0 ? `after ${existingChat.autoSummarizeAfterTurns} turns` : DIM + "off" + RESET}`);
2206
- console.log(` System prefix: ${existingChat?.systemPromptPrefix ? `${DIM}"${existingChat.systemPromptPrefix.slice(0, 50)}${existingChat.systemPromptPrefix.length > 50 ? "…" : ""}"${RESET}` : DIM + "none" + RESET}`);
2207
- console.log();
2208
- // ── Step 1: provider/model override ──────────────────────────────
2209
- const overrideProvider = await askYesNo(rl, existingChatTask
2210
- ? `Currently routing chat to ${currentProvider}. Change it?`
2211
- : `Chat currently uses the default provider (${defaultLLMProvider}). Route chat to a different LLM?`, false);
2212
- let chatProvider;
2213
- let chatModel;
2214
- if (overrideProvider) {
2215
- console.log();
2216
- console.log(`${DIM}Fetching latest model pricing...${RESET}`);
2217
- const dynamicModels = await fetchDynamicModels();
2218
- console.log();
2219
- chatProvider = await pickProvider(rl, dynamicModels, `${BOLD}Step 1${RESET} ${DIM}—${RESET} Choose chat LLM provider`, currentProvider);
2220
- if (chatProvider === "custom" || chatProvider === "skip") {
2221
- chatModel = await askInput(rl, "Enter model name");
2222
- }
2223
- else {
2224
- const tiers = dynamicModels[chatProvider] ?? PROVIDER_TIERS[chatProvider] ?? [];
2225
- if (tiers.length === 0) {
2226
- chatModel = await askInput(rl, "Enter model name");
2227
- }
2228
- else {
2229
- chatModel = await pickModel(rl, chatProvider, dynamicModels, `${BOLD}Step 2${RESET} ${DIM}—${RESET} Choose chat model`, existingChatTask?.model);
2230
- }
2231
- }
2232
- // Validate
2233
- const apiKey = await getApiKeyForProvider(chatProvider);
2234
- if (apiKey || chatProvider === "ollama" || chatProvider === "lmstudio") {
2235
- console.log();
2236
- console.log(`${DIM}Testing ${chatProvider}/${chatModel}...${RESET}`);
2237
- try {
2238
- const customBaseUrl = chatProvider === "custom" ? process.env.GNOSYS_LLM_BASE_URL : undefined;
2239
- const result = await validateModel(chatProvider, chatModel, apiKey, { customBaseUrl });
2240
- if (result.ok) {
2241
- console.log(` ${CHECK} Validated (${result.latencyMs}ms)`);
2242
- }
2243
- else {
2244
- console.log(` ${WARN} Could not reach ${chatProvider}/${chatModel}: ${result.error}`);
2245
- const proceed = await askYesNo(rl, " Continue saving config anyway?", true);
2246
- if (!proceed) {
2247
- console.log(` ${DIM}Setup cancelled. No changes saved.${RESET}`);
2248
- return;
2249
- }
2250
- }
2251
- }
2252
- catch (err) {
2253
- console.log(` ${DIM}Validation skipped: ${err instanceof Error ? err.message : err}${RESET}`);
2254
- }
2255
- }
2256
- else {
2257
- console.log(` ${WARN} No API key configured for ${chatProvider}. Set one via 'gnosys setup models'.`);
2258
- }
2259
- }
2260
- // ── Step 2: recall tuning ─────────────────────────────────────────
2261
- console.log();
2262
- console.log(`${BOLD}Recall${RESET} ${DIM}—${RESET} how aggressively to inject memories into chat`);
2263
- const recallAggressive = await askYesNo(rl, "Aggressive (more memories, lower threshold) vs filtered (fewer, higher quality)?", existingRecall?.aggressive ?? true);
2264
- const maxMemAns = await askInput(rl, "Max memories per chat turn", {
2265
- default: String(existingRecall?.maxMemories ?? 8),
2266
- });
2267
- const maxMemories = Math.max(1, Math.min(20, parseInt(maxMemAns) || 8));
2268
- const thresholdAns = await askInput(rl, "Min relevance score (0.0-1.0, lower returns more)", {
2269
- default: String(existingRecall?.minRelevance ?? 0.4),
2270
- });
2271
- const minRelevance = Math.max(0, Math.min(1, parseFloat(thresholdAns) || 0.4));
2272
- // ── Step 3: chat-only knobs ───────────────────────────────────────
2273
- console.log();
2274
- console.log(`${BOLD}Chat options${RESET}`);
2275
- const toolsEnabled = await askYesNo(rl, "Allow LLM to call gnosys tools via gnosys-tool fences?", existingChat?.toolsEnabled ?? true);
2276
- const autoSumAns = await askInput(rl, "Auto-summarize nudge after N turns (0 to disable)", { default: String(existingChat?.autoSummarizeAfterTurns ?? 0) });
2277
- const autoSummarizeAfterTurns = Math.max(0, parseInt(autoSumAns) || 0);
2278
- const prefixDefault = existingChat?.systemPromptPrefix ?? "";
2279
- const systemPromptPrefix = await askInput(rl, `System prompt prefix (persona/style/domain — Enter for ${prefixDefault ? "current" : "none"})`, { default: prefixDefault });
2280
- // ── Save ──────────────────────────────────────────────────────────
2281
- const storePath = pickStorePath(projectDir);
2282
- const updates = {
2283
- recall: { aggressive: recallAggressive, maxMemories, minRelevance },
2284
- chat: { toolsEnabled, autoSummarizeAfterTurns, systemPromptPrefix },
2285
- };
2286
- if (overrideProvider && chatProvider && chatProvider !== "skip" && chatModel) {
2287
- const existingTaskModels = existingConfig?.taskModels || {};
2288
- updates.taskModels = {
2289
- ...existingTaskModels,
2290
- chat: { provider: chatProvider, model: chatModel },
2291
- };
2292
- }
2293
- await updateConfig(storePath, updates);
2294
- console.log();
2295
- console.log(` ${CHECK} Chat config saved: ${storePath}/gnosys.json`);
2296
- if (overrideProvider && chatProvider && chatModel) {
2297
- console.log(` ${DIM}Provider: ${chatProvider}/${chatModel}${RESET}`);
2298
- }
2299
- else {
2300
- console.log(` ${DIM}Provider: (inherits default → ${defaultLLMProvider})${RESET}`);
2301
- }
2302
- console.log(` ${DIM}Recall: ${recallAggressive ? "aggressive" : "filtered"} (max ${maxMemories}, threshold ${minRelevance})${RESET}`);
2303
- console.log(` ${DIM}Tools: ${toolsEnabled ? "on" : "off"}${RESET}`);
2304
- console.log(` ${DIM}Auto-summarize: ${autoSummarizeAfterTurns > 0 ? `after ${autoSummarizeAfterTurns} turns` : "off"}${RESET}`);
2305
- console.log();
2306
- console.log(`${DIM}Tip: run 'gnosys chat' to start a session.${RESET}`);
2307
- }
2308
- finally {
2309
- if (ownsRl)
2310
- rl.close();
2311
- }
2265
+ void opts; // signature preserved; opts unused in deprecation notice
2266
+ // Use atom-based render so the notice matches the rest of v5.9.3.
2267
+ const { Header } = await import("./setup/ui/header.js");
2268
+ const { Status } = await import("./setup/ui/status.js");
2269
+ const { Footer } = await import("./setup/ui/footer.js");
2270
+ const { c, color } = await import("./setup/ui/tokens.js");
2271
+ const v = `v${getVersion()}`;
2272
+ console.log();
2273
+ console.log(Header(["gnosys", "setup", "chat"], { version: v }));
2274
+ console.log();
2275
+ console.log(Status("warn", "chat settings have moved"));
2276
+ console.log();
2277
+ console.log(` ${color(c.text, "chat is now configured from inside the TUI itself.")}`);
2278
+ console.log(` ${color(c.textDim, "open it with")} ${color(c.text, "gnosys chat")}`);
2279
+ console.log(` ${color(c.textDim, "then press")} ${color(c.text, "⌃, (settings)")}`);
2280
+ console.log();
2281
+ console.log(Footer("v6.0 will retire this command entirely"));
2312
2282
  }
2283
+ // ─── runChatSetup body removed in v5.9.3 (deci-050) ─────────────────
2284
+ // Provider/model override + recall tuning + tools fence + auto-summarize
2285
+ // + system prompt prefix all move to the v6.0 chat TUI's settings panel
2286
+ // (road-014). The exported stub above renders a deprecation notice.
2313
2287
  /** Resolve where to write gnosys.json — project store if exists, else global store. */
2314
2288
  function pickStorePath(projectDir) {
2315
2289
  const projectStore = path.join(projectDir, ".gnosys");