gnosys 5.9.2 → 5.9.4
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 +311 -147
- package/dist/cli.js.map +1 -1
- package/dist/lib/chat/index.d.ts.map +1 -1
- package/dist/lib/chat/index.js +5 -0
- package/dist/lib/chat/index.js.map +1 -1
- package/dist/lib/cleanup.d.ts +52 -0
- package/dist/lib/cleanup.d.ts.map +1 -0
- package/dist/lib/cleanup.js +168 -0
- package/dist/lib/cleanup.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +41 -2
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/dream.d.ts.map +1 -1
- package/dist/lib/dream.js +13 -2
- package/dist/lib/dream.js.map +1 -1
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/lib/paths.js +15 -0
- package/dist/lib/paths.js.map +1 -1
- package/dist/lib/remote.d.ts +11 -0
- package/dist/lib/remote.d.ts.map +1 -1
- package/dist/lib/remote.js +26 -2
- package/dist/lib/remote.js.map +1 -1
- package/dist/lib/remoteWizard.d.ts.map +1 -1
- package/dist/lib/remoteWizard.js +112 -52
- package/dist/lib/remoteWizard.js.map +1 -1
- package/dist/lib/setup/coldStart.d.ts +71 -0
- package/dist/lib/setup/coldStart.d.ts.map +1 -0
- package/dist/lib/setup/coldStart.js +122 -0
- package/dist/lib/setup/coldStart.js.map +1 -0
- package/dist/lib/setup/configSetRender.d.ts +26 -0
- package/dist/lib/setup/configSetRender.d.ts.map +1 -0
- package/dist/lib/setup/configSetRender.js +103 -0
- package/dist/lib/setup/configSetRender.js.map +1 -0
- package/dist/lib/setup/dreamRender.d.ts +44 -0
- package/dist/lib/setup/dreamRender.d.ts.map +1 -0
- package/dist/lib/setup/dreamRender.js +55 -0
- package/dist/lib/setup/dreamRender.js.map +1 -0
- package/dist/lib/setup/dreamState.d.ts +50 -0
- package/dist/lib/setup/dreamState.d.ts.map +1 -0
- package/dist/lib/setup/dreamState.js +68 -0
- package/dist/lib/setup/dreamState.js.map +1 -0
- package/dist/lib/setup/modelsRender.d.ts +25 -0
- package/dist/lib/setup/modelsRender.d.ts.map +1 -0
- package/dist/lib/setup/modelsRender.js +33 -0
- package/dist/lib/setup/modelsRender.js.map +1 -0
- package/dist/lib/setup/remoteRender.d.ts +43 -0
- package/dist/lib/setup/remoteRender.d.ts.map +1 -0
- package/dist/lib/setup/remoteRender.js +65 -0
- package/dist/lib/setup/remoteRender.js.map +1 -0
- package/dist/lib/setup/routingRender.d.ts +48 -0
- package/dist/lib/setup/routingRender.d.ts.map +1 -0
- package/dist/lib/setup/routingRender.js +114 -0
- package/dist/lib/setup/routingRender.js.map +1 -0
- package/dist/lib/setup/sections/ides.d.ts +8 -0
- package/dist/lib/setup/sections/ides.d.ts.map +1 -1
- package/dist/lib/setup/sections/ides.js +88 -33
- package/dist/lib/setup/sections/ides.js.map +1 -1
- package/dist/lib/setup/sections/preferences.d.ts +8 -0
- package/dist/lib/setup/sections/preferences.d.ts.map +1 -1
- package/dist/lib/setup/sections/preferences.js +54 -20
- package/dist/lib/setup/sections/preferences.js.map +1 -1
- package/dist/lib/setup/sections/routing.d.ts +0 -1
- package/dist/lib/setup/sections/routing.d.ts.map +1 -1
- package/dist/lib/setup/sections/routing.js +80 -38
- package/dist/lib/setup/sections/routing.js.map +1 -1
- package/dist/lib/setup/storePath.d.ts +30 -0
- package/dist/lib/setup/storePath.d.ts.map +1 -0
- package/dist/lib/setup/storePath.js +47 -0
- package/dist/lib/setup/storePath.js.map +1 -0
- package/dist/lib/setup/summary.d.ts +33 -19
- package/dist/lib/setup/summary.d.ts.map +1 -1
- package/dist/lib/setup/summary.js +148 -113
- package/dist/lib/setup/summary.js.map +1 -1
- package/dist/lib/setup/syncProjectsRender.d.ts +57 -0
- package/dist/lib/setup/syncProjectsRender.d.ts.map +1 -0
- package/dist/lib/setup/syncProjectsRender.js +184 -0
- package/dist/lib/setup/syncProjectsRender.js.map +1 -0
- package/dist/lib/setup/ui/diff.d.ts +19 -0
- package/dist/lib/setup/ui/diff.d.ts.map +1 -0
- package/dist/lib/setup/ui/diff.js +34 -0
- package/dist/lib/setup/ui/diff.js.map +1 -0
- package/dist/lib/setup/ui/footer.d.ts +11 -0
- package/dist/lib/setup/ui/footer.d.ts.map +1 -0
- package/dist/lib/setup/ui/footer.js +21 -0
- package/dist/lib/setup/ui/footer.js.map +1 -0
- package/dist/lib/setup/ui/header.d.ts +24 -0
- package/dist/lib/setup/ui/header.d.ts.map +1 -0
- package/dist/lib/setup/ui/header.js +49 -0
- package/dist/lib/setup/ui/header.js.map +1 -0
- package/dist/lib/setup/ui/index.d.ts +28 -0
- package/dist/lib/setup/ui/index.d.ts.map +1 -0
- package/dist/lib/setup/ui/index.js +19 -0
- package/dist/lib/setup/ui/index.js.map +1 -0
- package/dist/lib/setup/ui/menu.d.ts +27 -0
- package/dist/lib/setup/ui/menu.d.ts.map +1 -0
- package/dist/lib/setup/ui/menu.js +75 -0
- package/dist/lib/setup/ui/menu.js.map +1 -0
- package/dist/lib/setup/ui/panel.d.ts +23 -0
- package/dist/lib/setup/ui/panel.d.ts.map +1 -0
- package/dist/lib/setup/ui/panel.js +60 -0
- package/dist/lib/setup/ui/panel.js.map +1 -0
- package/dist/lib/setup/ui/prompt.d.ts +27 -0
- package/dist/lib/setup/ui/prompt.d.ts.map +1 -0
- package/dist/lib/setup/ui/prompt.js +38 -0
- package/dist/lib/setup/ui/prompt.js.map +1 -0
- package/dist/lib/setup/ui/safePrompt.d.ts +24 -0
- package/dist/lib/setup/ui/safePrompt.d.ts.map +1 -0
- package/dist/lib/setup/ui/safePrompt.js +71 -0
- package/dist/lib/setup/ui/safePrompt.js.map +1 -0
- package/dist/lib/setup/ui/spinner.d.ts +28 -0
- package/dist/lib/setup/ui/spinner.d.ts.map +1 -0
- package/dist/lib/setup/ui/spinner.js +87 -0
- package/dist/lib/setup/ui/spinner.js.map +1 -0
- package/dist/lib/setup/ui/status.d.ts +21 -0
- package/dist/lib/setup/ui/status.d.ts.map +1 -0
- package/dist/lib/setup/ui/status.js +49 -0
- package/dist/lib/setup/ui/status.js.map +1 -0
- package/dist/lib/setup/ui/table.d.ts +37 -0
- package/dist/lib/setup/ui/table.d.ts.map +1 -0
- package/dist/lib/setup/ui/table.js +82 -0
- package/dist/lib/setup/ui/table.js.map +1 -0
- package/dist/lib/setup/ui/title.d.ts +14 -0
- package/dist/lib/setup/ui/title.d.ts.map +1 -0
- package/dist/lib/setup/ui/title.js +24 -0
- package/dist/lib/setup/ui/title.js.map +1 -0
- package/dist/lib/setup/ui/tokens.d.ts +66 -0
- package/dist/lib/setup/ui/tokens.d.ts.map +1 -0
- package/dist/lib/setup/ui/tokens.js +87 -0
- package/dist/lib/setup/ui/tokens.js.map +1 -0
- package/dist/lib/setup.d.ts +38 -0
- package/dist/lib/setup.d.ts.map +1 -1
- package/dist/lib/setup.js +440 -308
- package/dist/lib/setup.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/setup.js
CHANGED
|
@@ -16,7 +16,8 @@ import os from "os";
|
|
|
16
16
|
import { execSync } from "child_process";
|
|
17
17
|
import { loadConfig, updateConfig, getProviderModel, } from "./config.js";
|
|
18
18
|
import { validateModel } from "./modelValidation.js";
|
|
19
|
-
import {
|
|
19
|
+
import { resolveActiveStorePath, ensureActiveStorePath } from "./setup/storePath.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";
|
|
@@ -138,6 +139,12 @@ export async function fetchDynamicModels() {
|
|
|
138
139
|
})
|
|
139
140
|
.filter((m) => m.input > 0 && !m.isFree && !m.isVariant && !m.isGuard)
|
|
140
141
|
.filter((m) => !/audio|search|embed|tts|vision|image|code-/i.test(m.modelId)) // skip specialized models
|
|
142
|
+
// v5.9.4 Bug 3 — xAI: OpenRouter returns weird names like
|
|
143
|
+
// `grok-build-0.1` and `grok-4.20-multi-agent`. Keep only canonical
|
|
144
|
+
// numbered Grok flagship/preview models (e.g. `grok-3`, `grok-4.0`,
|
|
145
|
+
// `grok-4.3`). When nothing matches we fall through to the static
|
|
146
|
+
// tiers a few lines down.
|
|
147
|
+
.filter((m) => ourProvider !== "xai" || /^grok-[0-9]/.test(m.modelId))
|
|
141
148
|
.sort((a, b) => b.created - a.created); // newest first
|
|
142
149
|
if (models.length === 0)
|
|
143
150
|
continue;
|
|
@@ -226,6 +233,19 @@ export async function fetchDynamicModels() {
|
|
|
226
233
|
if (!tiers.some((t) => t.recommended) && tiers.length > 0) {
|
|
227
234
|
tiers[0].recommended = true;
|
|
228
235
|
}
|
|
236
|
+
// v5.9.4 Bug 3 — UNION OpenRouter tiers with static PROVIDER_TIERS.xai
|
|
237
|
+
// so the static catalog (e.g. grok-4.3) always shows up even when
|
|
238
|
+
// OpenRouter omits it. Dedup by model id; static entries win the tie
|
|
239
|
+
// (their pricing matches the launch price more reliably).
|
|
240
|
+
if (ourProvider === "xai") {
|
|
241
|
+
const seen = new Set(tiers.map((t) => t.model));
|
|
242
|
+
for (const staticTier of PROVIDER_TIERS.xai ?? []) {
|
|
243
|
+
if (!seen.has(staticTier.model)) {
|
|
244
|
+
tiers.push(staticTier);
|
|
245
|
+
seen.add(staticTier.model);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
229
249
|
result[ourProvider] = tiers;
|
|
230
250
|
}
|
|
231
251
|
// Cache the result
|
|
@@ -532,6 +552,16 @@ export async function detectIDEs(projectDir) {
|
|
|
532
552
|
// Not installed
|
|
533
553
|
}
|
|
534
554
|
}
|
|
555
|
+
// v5.9.4 Bug 12 — Grok Build (xAI's coding agent) stores MCP config at
|
|
556
|
+
// ~/.grok/config.toml. The directory's presence is the detection signal.
|
|
557
|
+
try {
|
|
558
|
+
const stat = await fs.stat(path.join(home, ".grok"));
|
|
559
|
+
if (stat.isDirectory())
|
|
560
|
+
detected.push("grok-build");
|
|
561
|
+
}
|
|
562
|
+
catch {
|
|
563
|
+
// Not installed
|
|
564
|
+
}
|
|
535
565
|
return detected;
|
|
536
566
|
}
|
|
537
567
|
/**
|
|
@@ -551,6 +581,68 @@ function claudeDesktopConfigPath() {
|
|
|
551
581
|
}
|
|
552
582
|
return path.join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
553
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* Replace (or append) a `[mcp.<name>]` block inside the TOML text for
|
|
586
|
+
* Grok Build's config file. Preserves every line outside that block —
|
|
587
|
+
* deci-046 read-then-merge rule. We can't pull in a TOML dependency
|
|
588
|
+
* without adding to package.json, so we ship a minimal hand-rolled
|
|
589
|
+
* updater scoped exactly to the `[mcp.gnosys]` use case.
|
|
590
|
+
*
|
|
591
|
+
* Spec assumption: TOML headers we touch are simple `[a.b]` lines with
|
|
592
|
+
* no inline tables or nested arrays. Any other content is left alone.
|
|
593
|
+
*
|
|
594
|
+
* Exported for tests.
|
|
595
|
+
*/
|
|
596
|
+
export function upsertGrokMcpBlock(existing, name, entry) {
|
|
597
|
+
const sectionHeader = `[mcp.${name}]`;
|
|
598
|
+
const lines = existing.split("\n");
|
|
599
|
+
const headerIdx = lines.findIndex((line) => line.trim() === sectionHeader);
|
|
600
|
+
const blockBody = renderGrokMcpBlock(entry);
|
|
601
|
+
if (headerIdx === -1) {
|
|
602
|
+
// Append a fresh block, separated by a blank line if the file has content.
|
|
603
|
+
const prefix = existing.length === 0 || existing.endsWith("\n\n")
|
|
604
|
+
? existing
|
|
605
|
+
: existing.endsWith("\n") ? `${existing}\n` : `${existing}\n\n`;
|
|
606
|
+
return `${prefix}${sectionHeader}\n${blockBody}`;
|
|
607
|
+
}
|
|
608
|
+
// Replace the existing block — everything from sectionHeader up to the
|
|
609
|
+
// next `[` header (or EOF). Count blank lines immediately after the block
|
|
610
|
+
// so we can preserve the original spacing before the next section.
|
|
611
|
+
let endIdx = lines.length;
|
|
612
|
+
for (let i = headerIdx + 1; i < lines.length; i++) {
|
|
613
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
614
|
+
endIdx = i;
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
let trailingBlankBeforeNext = 0;
|
|
619
|
+
while (endIdx > headerIdx + 1 && lines[endIdx - 1].trim() === "") {
|
|
620
|
+
trailingBlankBeforeNext++;
|
|
621
|
+
endIdx--;
|
|
622
|
+
}
|
|
623
|
+
const afterLines = lines.slice(endIdx);
|
|
624
|
+
const hasFollowingSection = afterLines.some((l) => /^\s*\[/.test(l));
|
|
625
|
+
const beforeBlock = lines.slice(0, headerIdx).join("\n");
|
|
626
|
+
const head = beforeBlock.length > 0 ? `${beforeBlock}\n` : "";
|
|
627
|
+
if (!hasFollowingSection) {
|
|
628
|
+
// No following section — drop trailing blank lines and end with a single \n.
|
|
629
|
+
return `${head}${sectionHeader}\n${blockBody}`;
|
|
630
|
+
}
|
|
631
|
+
const gap = "\n".repeat(Math.max(1, trailingBlankBeforeNext));
|
|
632
|
+
const afterBlock = afterLines.join("\n");
|
|
633
|
+
return `${head}${sectionHeader}\n${blockBody}${gap}${afterBlock}`;
|
|
634
|
+
}
|
|
635
|
+
function renderGrokMcpBlock(entry) {
|
|
636
|
+
const argsStr = `[${entry.args.map((a) => JSON.stringify(a)).join(", ")}]`;
|
|
637
|
+
const lines = [
|
|
638
|
+
`command = ${JSON.stringify(entry.command)}`,
|
|
639
|
+
`args = ${argsStr}`,
|
|
640
|
+
];
|
|
641
|
+
if (typeof entry.startup_timeout_sec === "number") {
|
|
642
|
+
lines.push(`startup_timeout_sec = ${entry.startup_timeout_sec}`);
|
|
643
|
+
}
|
|
644
|
+
return `${lines.join("\n")}\n`;
|
|
645
|
+
}
|
|
554
646
|
/**
|
|
555
647
|
* Set up Gnosys MCP integration for a specific IDE.
|
|
556
648
|
*/
|
|
@@ -716,6 +808,29 @@ export async function setupIDE(ide, projectDir) {
|
|
|
716
808
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
717
809
|
return { success: true, message: "Antigravity MCP config updated (~/.gemini/antigravity/mcp_config.json)" };
|
|
718
810
|
}
|
|
811
|
+
case "grok-build": {
|
|
812
|
+
// v5.9.4 Bug 12 — Grok Build reads its MCP servers from a
|
|
813
|
+
// `[mcp.<name>]` block in ~/.grok/config.toml. We never clobber
|
|
814
|
+
// unrelated TOML content (per deci-046 read-then-merge rule); the
|
|
815
|
+
// helper preserves every line outside the `[mcp.gnosys]` block.
|
|
816
|
+
const grokDir = path.join(os.homedir(), ".grok");
|
|
817
|
+
const configPath = path.join(grokDir, "config.toml");
|
|
818
|
+
await fs.mkdir(grokDir, { recursive: true });
|
|
819
|
+
let existing = "";
|
|
820
|
+
try {
|
|
821
|
+
existing = await fs.readFile(configPath, "utf-8");
|
|
822
|
+
}
|
|
823
|
+
catch {
|
|
824
|
+
// File doesn't exist yet — start fresh
|
|
825
|
+
}
|
|
826
|
+
const updated = upsertGrokMcpBlock(existing, "gnosys", {
|
|
827
|
+
command: "gnosys",
|
|
828
|
+
args: ["serve"],
|
|
829
|
+
startup_timeout_sec: 90,
|
|
830
|
+
});
|
|
831
|
+
await fs.writeFile(configPath, updated, "utf-8");
|
|
832
|
+
return { success: true, message: "Grok Build MCP config updated (~/.grok/config.toml)" };
|
|
833
|
+
}
|
|
719
834
|
case "claude-desktop": {
|
|
720
835
|
// Claude Desktop reads MCP servers from claude_desktop_config.json
|
|
721
836
|
// in a platform-specific app data directory. Distinct from Claude
|
|
@@ -769,7 +884,7 @@ async function askChoice(rl, question, options) {
|
|
|
769
884
|
}
|
|
770
885
|
console.log();
|
|
771
886
|
while (true) {
|
|
772
|
-
const answer = await rl
|
|
887
|
+
const answer = await safeQuestion(rl, `${DIM}>${RESET} `);
|
|
773
888
|
const num = parseInt(answer.trim(), 10);
|
|
774
889
|
if (num >= 1 && num <= options.length) {
|
|
775
890
|
return num - 1;
|
|
@@ -782,7 +897,7 @@ async function askChoice(rl, question, options) {
|
|
|
782
897
|
*/
|
|
783
898
|
async function askInput(rl, prompt, opts) {
|
|
784
899
|
const suffix = opts?.default ? ` ${DIM}(${opts.default})${RESET}` : "";
|
|
785
|
-
const answer = await rl
|
|
900
|
+
const answer = await safeQuestion(rl, `${prompt}${suffix}: `);
|
|
786
901
|
const trimmed = answer.trim();
|
|
787
902
|
return trimmed || opts?.default || "";
|
|
788
903
|
}
|
|
@@ -791,7 +906,7 @@ async function askInput(rl, prompt, opts) {
|
|
|
791
906
|
*/
|
|
792
907
|
async function askYesNo(rl, question, defaultYes = true) {
|
|
793
908
|
const hint = defaultYes ? "Y/n" : "y/N";
|
|
794
|
-
const answer = await rl
|
|
909
|
+
const answer = await safeQuestion(rl, `${question} [${hint}] `);
|
|
795
910
|
const trimmed = answer.trim().toLowerCase();
|
|
796
911
|
if (trimmed === "")
|
|
797
912
|
return defaultYes;
|
|
@@ -866,31 +981,21 @@ async function getRegisteredProjects() {
|
|
|
866
981
|
}
|
|
867
982
|
/**
|
|
868
983
|
* Try to load existing gnosys.json config for displaying current values.
|
|
869
|
-
*
|
|
870
|
-
*
|
|
984
|
+
* Resolves the active store via the shared `resolveActiveStorePath` helper
|
|
985
|
+
* (v5.9.4 Bug 10 — was reading from a different store than the summary
|
|
986
|
+
* panel, producing stale-display bugs in `gnosys setup models`).
|
|
987
|
+
* Returns null if no config exists in either project or global stores.
|
|
871
988
|
*/
|
|
872
989
|
async function loadExistingConfig(projectDir) {
|
|
873
|
-
|
|
990
|
+
const storePath = resolveActiveStorePath(projectDir);
|
|
874
991
|
try {
|
|
875
|
-
const
|
|
876
|
-
const stat = await fs.stat(path.join(projectStore, "gnosys.json"));
|
|
992
|
+
const stat = await fs.stat(path.join(storePath, "gnosys.json"));
|
|
877
993
|
if (stat.isFile()) {
|
|
878
|
-
return await loadConfig(
|
|
994
|
+
return await loadConfig(storePath);
|
|
879
995
|
}
|
|
880
996
|
}
|
|
881
997
|
catch {
|
|
882
|
-
// No
|
|
883
|
-
}
|
|
884
|
-
// Try global config at ~/.gnosys
|
|
885
|
-
try {
|
|
886
|
-
const globalStore = getGnosysHome();
|
|
887
|
-
const stat = await fs.stat(path.join(globalStore, "gnosys.json"));
|
|
888
|
-
if (stat.isFile()) {
|
|
889
|
-
return await loadConfig(globalStore);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
catch {
|
|
893
|
-
// No global config
|
|
998
|
+
// No config in the resolved store
|
|
894
999
|
}
|
|
895
1000
|
return null;
|
|
896
1001
|
}
|
|
@@ -983,16 +1088,10 @@ export async function runSetup(opts) {
|
|
|
983
1088
|
let upgraded = false;
|
|
984
1089
|
try {
|
|
985
1090
|
// ─── Banner ───────────────────────────────────────────────────────
|
|
986
|
-
|
|
987
|
-
const
|
|
988
|
-
const bannerContentWidth = Math.max(versionStr.length, tagline.length);
|
|
989
|
-
const bannerInner = bannerContentWidth + 4;
|
|
990
|
-
const bannerBorder = "\u2500".repeat(bannerInner);
|
|
1091
|
+
// v5.9.3 redesign: atom-based splash replaces the old ASCII box banner.
|
|
1092
|
+
const { renderColdStartSplash } = await import("./setup/coldStart.js");
|
|
991
1093
|
console.log();
|
|
992
|
-
console.log(
|
|
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`);
|
|
1094
|
+
console.log(renderColdStartSplash(version));
|
|
996
1095
|
console.log();
|
|
997
1096
|
// ─── Load existing config for defaults ───────────────────────────
|
|
998
1097
|
const existingConfig = await loadExistingConfig(projectDir);
|
|
@@ -1076,7 +1175,12 @@ export async function runSetup(opts) {
|
|
|
1076
1175
|
const currentProviderHint = currentProvider
|
|
1077
1176
|
? ` ${DIM}(current: ${currentProvider})${RESET}`
|
|
1078
1177
|
: "";
|
|
1079
|
-
|
|
1178
|
+
// v5.9.3 Screen 1.1 chrome \u2014 Header + Title + step counter wrap.
|
|
1179
|
+
const { renderProviderStepHeader, renderModelStepHeader, renderKeyStepHeader } = await import("./setup/coldStart.js");
|
|
1180
|
+
console.log();
|
|
1181
|
+
console.log(renderProviderStepHeader(version));
|
|
1182
|
+
console.log();
|
|
1183
|
+
const providerIndex = await askChoice(rl, `Choose your LLM provider${currentProviderHint}`, providerOptions);
|
|
1080
1184
|
const isSkip = providerIndex === PROVIDER_ORDER.length; // last option
|
|
1081
1185
|
const provider = isSkip ? "skip" : PROVIDER_ORDER[providerIndex];
|
|
1082
1186
|
// ─── Step 2/5 — Model tier ────────────────────────────────────────
|
|
@@ -1096,7 +1200,11 @@ export async function runSetup(opts) {
|
|
|
1096
1200
|
return `${t.name} (${t.model}) ${DIM}${formatPrice(t.input, t.output)}${RESET}${rec}`;
|
|
1097
1201
|
});
|
|
1098
1202
|
tierOptions.push(`Custom ${DIM}(enter model name)${RESET}`);
|
|
1099
|
-
|
|
1203
|
+
// v5.9.3 Screen 1.2 chrome \u2014 Header + Title + step counter wrap.
|
|
1204
|
+
console.log();
|
|
1205
|
+
console.log(renderModelStepHeader(provider, version));
|
|
1206
|
+
console.log();
|
|
1207
|
+
const tierIndex = await askChoice(rl, `Choose model tier${currentModelHint}`, tierOptions);
|
|
1100
1208
|
if (tierIndex === tiers.length) {
|
|
1101
1209
|
model = await askInput(rl, "Enter model name");
|
|
1102
1210
|
}
|
|
@@ -1169,8 +1277,9 @@ export async function runSetup(opts) {
|
|
|
1169
1277
|
};
|
|
1170
1278
|
const legacyEnvVar = legacyEnvVars[provider] ?? "";
|
|
1171
1279
|
if (needsKey) {
|
|
1280
|
+
// v5.9.3 Screen 1.3 chrome \u2014 Header + Title + step counter wrap.
|
|
1172
1281
|
console.log();
|
|
1173
|
-
console.log(
|
|
1282
|
+
console.log(renderKeyStepHeader(provider, version));
|
|
1174
1283
|
console.log();
|
|
1175
1284
|
// Check where the key currently lives
|
|
1176
1285
|
const existingKeySource = detectKeySource(envVarName, legacyEnvVar);
|
|
@@ -1503,12 +1612,14 @@ export async function runSetup(opts) {
|
|
|
1503
1612
|
codex: "Codex",
|
|
1504
1613
|
"gemini-cli": "Gemini CLI",
|
|
1505
1614
|
antigravity: "Antigravity",
|
|
1615
|
+
// v5.9.4 Bug 12 — Grok Build (~/.grok/config.toml).
|
|
1616
|
+
"grok-build": "Grok Build",
|
|
1506
1617
|
};
|
|
1507
1618
|
// IDEs whose MCP config lives at the user level (~/...) rather than per-project.
|
|
1508
1619
|
// We don't try to create a project-level directory for these.
|
|
1509
|
-
const userLevelIdes = new Set(["claude", "claude-desktop", "gemini-cli", "antigravity"]);
|
|
1620
|
+
const userLevelIdes = new Set(["claude", "claude-desktop", "gemini-cli", "antigravity", "grok-build"]);
|
|
1510
1621
|
// Build IDE options: show detected ones and offer to create missing ones
|
|
1511
|
-
const allIdeKeys = ["claude", "claude-desktop", "cursor", "codex", "gemini-cli", "antigravity"];
|
|
1622
|
+
const allIdeKeys = ["claude", "claude-desktop", "cursor", "codex", "gemini-cli", "antigravity", "grok-build"];
|
|
1512
1623
|
const ideOptions = [];
|
|
1513
1624
|
const ideKeyForOption = []; // parallel array mapping option index to IDE key
|
|
1514
1625
|
for (const ide of allIdeKeys) {
|
|
@@ -1590,21 +1701,8 @@ export async function runSetup(opts) {
|
|
|
1590
1701
|
const structuringModel = isSkip ? "" : (taskOverrides.structuring?.model ?? getStructuringModel(provider, model));
|
|
1591
1702
|
// ─── Write config to gnosys.json ─────────────────────────────────
|
|
1592
1703
|
if (!isSkip) {
|
|
1593
|
-
//
|
|
1594
|
-
|
|
1595
|
-
const projectStore = path.join(projectDir, ".gnosys");
|
|
1596
|
-
const globalStore = getGnosysHome();
|
|
1597
|
-
if (fsSync.existsSync(path.join(projectStore, "gnosys.json"))) {
|
|
1598
|
-
storePath = projectStore;
|
|
1599
|
-
}
|
|
1600
|
-
else if (fsSync.existsSync(path.join(globalStore, "gnosys.json"))) {
|
|
1601
|
-
storePath = globalStore;
|
|
1602
|
-
}
|
|
1603
|
-
else {
|
|
1604
|
-
// Default to global store — create directory if needed
|
|
1605
|
-
await fs.mkdir(globalStore, { recursive: true });
|
|
1606
|
-
storePath = globalStore;
|
|
1607
|
-
}
|
|
1704
|
+
// v5.9.4 Bug 10 — unified store resolution.
|
|
1705
|
+
const storePath = ensureActiveStorePath(projectDir);
|
|
1608
1706
|
// Build the config updates
|
|
1609
1707
|
// Build LLM config update, preserving existing provider-specific settings
|
|
1610
1708
|
const existingLlm = existingConfig?.llm;
|
|
@@ -1716,7 +1814,7 @@ export async function runSetup(opts) {
|
|
|
1716
1814
|
console.log("Share your gnosys.db across machines via NAS or shared drive.");
|
|
1717
1815
|
console.log(`Your local DB stays fast, the remote is the source of truth.`);
|
|
1718
1816
|
console.log();
|
|
1719
|
-
const setUpRemote = (await rl
|
|
1817
|
+
const setUpRemote = (await safeQuestion(rl, `Configure remote sync now? [y/N] `)).trim().toLowerCase();
|
|
1720
1818
|
if (setUpRemote === "y" || setUpRemote === "yes") {
|
|
1721
1819
|
console.log();
|
|
1722
1820
|
try {
|
|
@@ -1767,6 +1865,60 @@ export async function runSetup(opts) {
|
|
|
1767
1865
|
throw err;
|
|
1768
1866
|
}
|
|
1769
1867
|
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Update ONLY `llm.defaultProvider` in gnosys.json. Used by the summary
|
|
1870
|
+
* panel row 1 ("provider") so it stops dragging the user into the full
|
|
1871
|
+
* model picker — that's row 2's job.
|
|
1872
|
+
*
|
|
1873
|
+
* v5.9.4 Bug 4 — before this split, both summary rows routed through
|
|
1874
|
+
* `runModelsSetup`, leaving no way to swap provider without also choosing
|
|
1875
|
+
* a new model. Now row 1 picks a provider, row 2 picks a model.
|
|
1876
|
+
*/
|
|
1877
|
+
export async function runProviderOnlySetup(opts = {}) {
|
|
1878
|
+
const projectDir = opts.directory ? path.resolve(opts.directory) : process.cwd();
|
|
1879
|
+
const ownsRl = !opts.rl;
|
|
1880
|
+
const rl = opts.rl ?? createInterface({ input: stdin, output: stdout });
|
|
1881
|
+
try {
|
|
1882
|
+
const { Header } = await import("./setup/ui/header.js");
|
|
1883
|
+
const { Title } = await import("./setup/ui/title.js");
|
|
1884
|
+
const { Spinner } = await import("./setup/ui/spinner.js");
|
|
1885
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
1886
|
+
console.log();
|
|
1887
|
+
console.log(Header(["gnosys", "setup", "provider"]));
|
|
1888
|
+
console.log();
|
|
1889
|
+
console.log(Title("Default provider", "pick the LLM provider — model stays as configured"));
|
|
1890
|
+
console.log();
|
|
1891
|
+
const existingConfig = await loadExistingConfig(projectDir);
|
|
1892
|
+
const currentProvider = existingConfig?.llm.defaultProvider;
|
|
1893
|
+
const pricingSpin = Spinner("fetching latest pricing from openrouter…");
|
|
1894
|
+
const fetchStart = Date.now();
|
|
1895
|
+
const dynamicModels = await fetchDynamicModels();
|
|
1896
|
+
const fetchMs = Date.now() - fetchStart;
|
|
1897
|
+
if (Object.keys(dynamicModels).length > 0) {
|
|
1898
|
+
pricingSpin.ok("pricing loaded", `${fetchMs} ms`);
|
|
1899
|
+
}
|
|
1900
|
+
else {
|
|
1901
|
+
pricingSpin.fail("pricing fetch failed", "using bundled tiers");
|
|
1902
|
+
}
|
|
1903
|
+
console.log();
|
|
1904
|
+
const provider = await pickProvider(rl, dynamicModels, "Choose your LLM provider", currentProvider);
|
|
1905
|
+
if (!provider || provider === currentProvider) {
|
|
1906
|
+
printStatus("warn", "no change · provider unchanged");
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
const storePath = ensureActiveStorePath(projectDir);
|
|
1910
|
+
const existingLlm = existingConfig?.llm ?? {};
|
|
1911
|
+
await updateConfig(storePath, {
|
|
1912
|
+
llm: { ...existingLlm, defaultProvider: provider },
|
|
1913
|
+
});
|
|
1914
|
+
printStatus("ok", `default provider · ${provider}`, `${storePath}/gnosys.json`);
|
|
1915
|
+
printStatus("progress", "model unchanged", "use row 2 to swap the model");
|
|
1916
|
+
}
|
|
1917
|
+
finally {
|
|
1918
|
+
if (ownsRl)
|
|
1919
|
+
rl.close();
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1770
1922
|
/**
|
|
1771
1923
|
* Models-only configuration — prompts for provider, model, and key (or accepts
|
|
1772
1924
|
* them via options for non-interactive use). Validates the model against the
|
|
@@ -1777,30 +1929,47 @@ export async function runModelsSetup(opts = {}) {
|
|
|
1777
1929
|
const ownsRl = !opts.rl;
|
|
1778
1930
|
const rl = opts.rl ?? createInterface({ input: stdin, output: stdout });
|
|
1779
1931
|
try {
|
|
1932
|
+
// v5.9.3 Screen 3 — Header + Title at the top.
|
|
1933
|
+
const { Header } = await import("./setup/ui/header.js");
|
|
1934
|
+
const { Title } = await import("./setup/ui/title.js");
|
|
1935
|
+
const { Spinner } = await import("./setup/ui/spinner.js");
|
|
1936
|
+
const { printDiff } = await import("./setup/ui/diff.js");
|
|
1937
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
1780
1938
|
console.log();
|
|
1781
|
-
console.log(
|
|
1939
|
+
console.log(Header(["gnosys", "setup", "models"]));
|
|
1940
|
+
console.log();
|
|
1941
|
+
console.log(Title("Model configuration", "pick a provider and model — we'll validate it before saving"));
|
|
1782
1942
|
console.log();
|
|
1783
1943
|
const existingConfig = await loadExistingConfig(projectDir);
|
|
1784
1944
|
const currentProvider = existingConfig?.llm.defaultProvider;
|
|
1785
1945
|
const currentModel = existingConfig
|
|
1786
1946
|
? getProviderModel(existingConfig, existingConfig.llm.defaultProvider)
|
|
1787
1947
|
: undefined;
|
|
1788
|
-
// Step 1: provider (or use --provider flag)
|
|
1789
|
-
|
|
1948
|
+
// Step 1: provider (or use --provider flag). v5.9.3: animate the
|
|
1949
|
+
// OpenRouter pricing fetch under a Spinner so the user gets feedback
|
|
1950
|
+
// on what would otherwise feel like a hang.
|
|
1951
|
+
const pricingSpin = Spinner("fetching latest pricing from openrouter…");
|
|
1952
|
+
const fetchStart = Date.now();
|
|
1790
1953
|
const dynamicModels = await fetchDynamicModels();
|
|
1954
|
+
const fetchMs = Date.now() - fetchStart;
|
|
1955
|
+
const modelCount = Object.values(dynamicModels).reduce((n, tiers) => n + tiers.length, 0);
|
|
1791
1956
|
if (Object.keys(dynamicModels).length > 0) {
|
|
1792
|
-
|
|
1957
|
+
pricingSpin.ok(`pricing loaded · ${modelCount} models cached`, `${fetchMs} ms`);
|
|
1958
|
+
}
|
|
1959
|
+
else {
|
|
1960
|
+
// No-op fallback (cache miss + network fail) — keep the hardcoded
|
|
1961
|
+
// tiers but signal that we're running offline.
|
|
1962
|
+
pricingSpin.fail("pricing fetch failed", "using bundled tiers");
|
|
1793
1963
|
}
|
|
1794
1964
|
console.log();
|
|
1795
1965
|
let provider;
|
|
1796
1966
|
if (opts.provider) {
|
|
1797
1967
|
if (!PROVIDER_ORDER.includes(opts.provider)) {
|
|
1798
|
-
|
|
1799
|
-
console.log(` Valid: ${PROVIDER_ORDER.join(", ")}`);
|
|
1968
|
+
printStatus("fail", `unknown provider \`${opts.provider}\``, `valid: ${PROVIDER_ORDER.join(", ")}`);
|
|
1800
1969
|
return;
|
|
1801
1970
|
}
|
|
1802
1971
|
provider = opts.provider;
|
|
1803
|
-
|
|
1972
|
+
printStatus("ok", "provider", provider);
|
|
1804
1973
|
}
|
|
1805
1974
|
else {
|
|
1806
1975
|
provider = await pickProvider(rl, dynamicModels, "Choose your LLM provider", currentProvider);
|
|
@@ -1809,7 +1978,7 @@ export async function runModelsSetup(opts = {}) {
|
|
|
1809
1978
|
let model;
|
|
1810
1979
|
if (opts.model) {
|
|
1811
1980
|
model = opts.model;
|
|
1812
|
-
|
|
1981
|
+
printStatus("ok", "model", model);
|
|
1813
1982
|
}
|
|
1814
1983
|
else {
|
|
1815
1984
|
const tiers = dynamicModels[provider] ?? PROVIDER_TIERS[provider];
|
|
@@ -1822,7 +1991,7 @@ export async function runModelsSetup(opts = {}) {
|
|
|
1822
1991
|
}
|
|
1823
1992
|
}
|
|
1824
1993
|
if (!model) {
|
|
1825
|
-
|
|
1994
|
+
printStatus("fail", "no model selected · aborting");
|
|
1826
1995
|
return;
|
|
1827
1996
|
}
|
|
1828
1997
|
// Step 3: load API key from existing storage (if available)
|
|
@@ -1849,42 +2018,31 @@ export async function runModelsSetup(opts = {}) {
|
|
|
1849
2018
|
console.log(`${WARN} No API key found for ${provider}. Run 'gnosys setup' to configure one.`);
|
|
1850
2019
|
// Continue anyway — user might just want to update the model in config
|
|
1851
2020
|
}
|
|
1852
|
-
// Step 4: validate (default: true)
|
|
2021
|
+
// Step 4: validate (default: true) — v5.9.3 Screen 3: animated
|
|
2022
|
+
// Spinner with latency reported on success.
|
|
1853
2023
|
const shouldValidate = opts.validate !== false;
|
|
1854
2024
|
const isLocalProvider = provider === "ollama" || provider === "lmstudio";
|
|
1855
2025
|
if (shouldValidate && (apiKey || isLocalProvider)) {
|
|
1856
2026
|
console.log();
|
|
1857
|
-
|
|
2027
|
+
const validateSpin = Spinner(`validating ${provider} / ${model}…`);
|
|
1858
2028
|
const customBaseUrl = provider === "custom"
|
|
1859
2029
|
? process.env.GNOSYS_LLM_BASE_URL
|
|
1860
2030
|
: undefined;
|
|
1861
2031
|
const result = await validateModel(provider, model, apiKey, { customBaseUrl });
|
|
1862
2032
|
if (result.ok) {
|
|
1863
|
-
|
|
2033
|
+
validateSpin.ok("model validated", `${result.latencyMs} ms · ${provider} / ${model}`);
|
|
1864
2034
|
}
|
|
1865
2035
|
else {
|
|
1866
|
-
|
|
1867
|
-
const proceed = await askYesNo(rl, "
|
|
2036
|
+
validateSpin.fail("model test failed", result.error);
|
|
2037
|
+
const proceed = await askYesNo(rl, "Save config anyway?", false);
|
|
1868
2038
|
if (!proceed) {
|
|
1869
|
-
|
|
2039
|
+
printStatus("warn", "cancelled · no changes written");
|
|
1870
2040
|
return;
|
|
1871
2041
|
}
|
|
1872
2042
|
}
|
|
1873
2043
|
}
|
|
1874
|
-
// Step 5: write config
|
|
1875
|
-
const
|
|
1876
|
-
const globalStore = getGnosysHome();
|
|
1877
|
-
let storePath;
|
|
1878
|
-
if (fsSync.existsSync(path.join(projectStore, "gnosys.json"))) {
|
|
1879
|
-
storePath = projectStore;
|
|
1880
|
-
}
|
|
1881
|
-
else if (fsSync.existsSync(path.join(globalStore, "gnosys.json"))) {
|
|
1882
|
-
storePath = globalStore;
|
|
1883
|
-
}
|
|
1884
|
-
else {
|
|
1885
|
-
await fs.mkdir(globalStore, { recursive: true });
|
|
1886
|
-
storePath = globalStore;
|
|
1887
|
-
}
|
|
2044
|
+
// Step 5: write config (v5.9.4 Bug 10 — unified store resolution).
|
|
2045
|
+
const storePath = ensureActiveStorePath(projectDir);
|
|
1888
2046
|
const existingLlm = existingConfig?.llm;
|
|
1889
2047
|
const existingProviderConfig = existingLlm
|
|
1890
2048
|
? existingLlm[provider]
|
|
@@ -1902,10 +2060,12 @@ export async function runModelsSetup(opts = {}) {
|
|
|
1902
2060
|
},
|
|
1903
2061
|
},
|
|
1904
2062
|
});
|
|
2063
|
+
// v5.9.3 Screen 3 — Diff() before the saved confirmation. Shows what
|
|
2064
|
+
// landed in gnosys.json.
|
|
2065
|
+
const { buildModelsDiffRows } = await import("./setup/modelsRender.js");
|
|
1905
2066
|
console.log();
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
console.log(` ${DIM}Model: ${model}${RESET}`);
|
|
2067
|
+
printDiff(buildModelsDiffRows(currentProvider, currentModel, provider, model));
|
|
2068
|
+
printStatus("ok", `saved · ${storePath}/gnosys.json`);
|
|
1909
2069
|
}
|
|
1910
2070
|
finally {
|
|
1911
2071
|
if (ownsRl)
|
|
@@ -1960,11 +2120,8 @@ export async function runModelsCommand(opts = {}) {
|
|
|
1960
2120
|
console.log(`${WARN} No provider configured. Run 'gnosys setup' first.`);
|
|
1961
2121
|
return;
|
|
1962
2122
|
}
|
|
1963
|
-
|
|
1964
|
-
const
|
|
1965
|
-
const storePath = fsSync.existsSync(path.join(projectStore, "gnosys.json"))
|
|
1966
|
-
? projectStore
|
|
1967
|
-
: globalStore;
|
|
2123
|
+
// v5.9.4 Bug 10 — unified store resolution.
|
|
2124
|
+
const storePath = ensureActiveStorePath(projectDir);
|
|
1968
2125
|
const existingProviderConfig = existingConfig?.llm?.[currentProvider];
|
|
1969
2126
|
const providerConfigBase = (typeof existingProviderConfig === "object" && existingProviderConfig !== null)
|
|
1970
2127
|
? existingProviderConfig
|
|
@@ -2009,81 +2166,105 @@ export async function runDreamSetup(opts = {}) {
|
|
|
2009
2166
|
const ownsRl = !opts.rl;
|
|
2010
2167
|
const rl = opts.rl ?? createInterface({ input: stdin, output: stdout });
|
|
2011
2168
|
try {
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2169
|
+
// v5.9.3 Screen 7 — three grouped sub-screens (7.0 enable, 7.1
|
|
2170
|
+
// machine+model, 7.2 thresholds+sub-tasks). Each sub-screen renders
|
|
2171
|
+
// its own Header with `step N of 3` so the progress is always visible.
|
|
2172
|
+
const { Header } = await import("./setup/ui/header.js");
|
|
2173
|
+
const { Title } = await import("./setup/ui/title.js");
|
|
2174
|
+
const { Spinner } = await import("./setup/ui/spinner.js");
|
|
2175
|
+
const { printDiff } = await import("./setup/ui/diff.js");
|
|
2176
|
+
const { printStatus } = await import("./setup/ui/status.js");
|
|
2015
2177
|
const existingConfig = await loadExistingConfig(projectDir);
|
|
2016
2178
|
const existingDream = existingConfig?.dream;
|
|
2017
2179
|
// Show current state via central DB
|
|
2018
2180
|
const { GnosysDB } = await import("./db.js");
|
|
2181
|
+
const { getMachineId } = await import("./remote.js");
|
|
2019
2182
|
const localDb = GnosysDB.openLocal();
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2183
|
+
// v5.9.4 Bugs 7+8 — also peek at the remote DB (if configured) so re-entry
|
|
2184
|
+
// sees a designation made on a different machine. Open remote read-only;
|
|
2185
|
+
// we'll mirror writes below.
|
|
2186
|
+
const remoteDb = await openRemoteDbIfConfigured(localDb);
|
|
2187
|
+
const designatedMachine = localDb.getDreamMachineId() ?? remoteDb?.getDreamMachineId() ?? null;
|
|
2188
|
+
// v5.9.4 Bug 9 — share the canonical machine-id resolver (os.hostname()
|
|
2189
|
+
// fallback included) instead of re-rolling HOSTNAME/COMPUTERNAME logic.
|
|
2190
|
+
const localMachine = getMachineId(localDb);
|
|
2191
|
+
// Mirror dream_machine_id writes to both DBs (Bug 8).
|
|
2192
|
+
const setDreamMachineEverywhere = (id) => {
|
|
2193
|
+
localDb.setDreamMachineId(id);
|
|
2194
|
+
try {
|
|
2195
|
+
remoteDb?.setDreamMachineId(id);
|
|
2027
2196
|
}
|
|
2028
|
-
|
|
2029
|
-
}
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2197
|
+
catch { /* remote may be transiently unavailable */ }
|
|
2198
|
+
};
|
|
2199
|
+
const clearDreamMachineEverywhere = () => {
|
|
2200
|
+
localDb.clearDreamMachineId();
|
|
2201
|
+
try {
|
|
2202
|
+
remoteDb?.clearDreamMachineId();
|
|
2203
|
+
}
|
|
2204
|
+
catch { /* remote may be transiently unavailable */ }
|
|
2205
|
+
};
|
|
2206
|
+
// ─── 7.0 Overview & enable ────────────────────────────────────────
|
|
2207
|
+
console.log();
|
|
2208
|
+
console.log(Header(["gnosys", "setup", "dream"], { version: "step 1 of 3" }));
|
|
2209
|
+
console.log();
|
|
2210
|
+
console.log(Title("Dream Mode", "gnosys runs background consolidation while you're idle — merging related memories, generating summaries, surfacing relationships."));
|
|
2211
|
+
console.log();
|
|
2212
|
+
const currentStateLine = existingDream?.enabled
|
|
2213
|
+
? `enabled · ${designatedMachine ? designatedMachine === localMachine ? `${localMachine} (this machine)` : designatedMachine : "no designated machine"}`
|
|
2214
|
+
: "disabled · no designated machine";
|
|
2215
|
+
printStatus("progress", "current", currentStateLine);
|
|
2047
2216
|
console.log();
|
|
2048
|
-
|
|
2049
|
-
const enabled = await askYesNo(rl, "Enable dream mode?", existingDream?.enabled ?? true);
|
|
2217
|
+
const enabled = await askYesNo(rl, "enable Dream Mode?", existingDream?.enabled ?? true);
|
|
2050
2218
|
if (!enabled) {
|
|
2051
2219
|
// Persist disabled state and clear designation
|
|
2052
|
-
const storePath =
|
|
2220
|
+
const storePath = ensureActiveStorePath(projectDir);
|
|
2053
2221
|
await updateConfig(storePath, {
|
|
2054
2222
|
dream: { ...(existingDream ?? {}), enabled: false },
|
|
2055
2223
|
});
|
|
2056
|
-
|
|
2057
|
-
console.log(
|
|
2224
|
+
clearDreamMachineEverywhere();
|
|
2225
|
+
console.log();
|
|
2226
|
+
printStatus("ok", "dream mode disabled · designation cleared");
|
|
2058
2227
|
localDb.close();
|
|
2228
|
+
remoteDb?.close();
|
|
2059
2229
|
return;
|
|
2060
2230
|
}
|
|
2061
|
-
//
|
|
2231
|
+
// ─── 7.1 Designated machine + model ───────────────────────────────
|
|
2232
|
+
console.log();
|
|
2233
|
+
console.log(Header(["gnosys", "setup", "dream", "machine"], { version: "step 2 of 3" }));
|
|
2234
|
+
console.log();
|
|
2235
|
+
console.log(Title("Only one machine dreams at a time — we'll designate one now."));
|
|
2236
|
+
console.log();
|
|
2237
|
+
printStatus("progress", "this machine", localMachine);
|
|
2238
|
+
console.log();
|
|
2062
2239
|
const designate = await askYesNo(rl, designatedMachine === localMachine
|
|
2063
|
-
? "
|
|
2064
|
-
: `
|
|
2240
|
+
? "this machine is currently the dreamer — keep it?"
|
|
2241
|
+
: `designate THIS machine (${localMachine}) as the dreamer?`, true);
|
|
2065
2242
|
if (designate) {
|
|
2066
|
-
|
|
2067
|
-
|
|
2243
|
+
setDreamMachineEverywhere(localMachine);
|
|
2244
|
+
printStatus("ok", `${localMachine} is the dreamer`);
|
|
2068
2245
|
}
|
|
2069
2246
|
else if (designatedMachine === localMachine) {
|
|
2070
|
-
|
|
2071
|
-
|
|
2247
|
+
clearDreamMachineEverywhere();
|
|
2248
|
+
printStatus("warn", "designation cleared", "no machine will dream until you re-run on another");
|
|
2072
2249
|
}
|
|
2073
2250
|
else {
|
|
2074
|
-
|
|
2251
|
+
printStatus("progress", "keeping current designation", designatedMachine || "none");
|
|
2075
2252
|
}
|
|
2076
|
-
//
|
|
2253
|
+
// Pricing fetch — animated Spinner.
|
|
2077
2254
|
console.log();
|
|
2078
|
-
|
|
2255
|
+
const pricingSpin = Spinner("fetching latest pricing from openrouter…");
|
|
2256
|
+
const fetchStart = Date.now();
|
|
2079
2257
|
const dynamicModels = await fetchDynamicModels();
|
|
2258
|
+
const fetchMs = Date.now() - fetchStart;
|
|
2080
2259
|
if (Object.keys(dynamicModels).length > 0) {
|
|
2081
|
-
|
|
2260
|
+
pricingSpin.ok("pricing loaded", `${fetchMs} ms`);
|
|
2261
|
+
}
|
|
2262
|
+
else {
|
|
2263
|
+
pricingSpin.fail("pricing fetch failed", "using bundled tiers");
|
|
2082
2264
|
}
|
|
2083
2265
|
console.log();
|
|
2084
2266
|
const defaultProvider = existingDream?.provider || existingConfig?.llm.defaultProvider || "ollama";
|
|
2085
|
-
const dreamProvider = await pickProvider(rl, dynamicModels,
|
|
2086
|
-
// Step 4: Model
|
|
2267
|
+
const dreamProvider = await pickProvider(rl, dynamicModels, "Choose dream LLM provider — local is recommended (dream runs a lot)", defaultProvider);
|
|
2087
2268
|
let dreamModel = "";
|
|
2088
2269
|
if (dreamProvider === "custom" || dreamProvider === "skip") {
|
|
2089
2270
|
dreamModel = await askInput(rl, "Enter model name");
|
|
@@ -2094,63 +2275,83 @@ export async function runDreamSetup(opts = {}) {
|
|
|
2094
2275
|
dreamModel = await askInput(rl, "Enter model name");
|
|
2095
2276
|
}
|
|
2096
2277
|
else {
|
|
2097
|
-
dreamModel = await pickModel(rl, dreamProvider, dynamicModels,
|
|
2278
|
+
dreamModel = await pickModel(rl, dreamProvider, dynamicModels, "Choose dream model", existingDream?.model);
|
|
2098
2279
|
}
|
|
2099
2280
|
}
|
|
2100
|
-
//
|
|
2281
|
+
// Validate — animated Spinner with the model latency reported.
|
|
2101
2282
|
if (dreamProvider !== "skip") {
|
|
2102
2283
|
const apiKey = await getApiKeyForProvider(dreamProvider);
|
|
2103
|
-
|
|
2284
|
+
const isLocalProvider = dreamProvider === "ollama" || dreamProvider === "lmstudio";
|
|
2285
|
+
if (apiKey || isLocalProvider) {
|
|
2104
2286
|
console.log();
|
|
2105
|
-
|
|
2287
|
+
const validateSpin = Spinner(`validating ${dreamProvider} / ${dreamModel}…`);
|
|
2106
2288
|
try {
|
|
2107
2289
|
const customBaseUrl = dreamProvider === "custom" ? process.env.GNOSYS_LLM_BASE_URL : undefined;
|
|
2108
2290
|
const result = await validateModel(dreamProvider, dreamModel, apiKey, { customBaseUrl });
|
|
2109
2291
|
if (result.ok) {
|
|
2110
|
-
|
|
2292
|
+
validateSpin.ok("model validated", `${result.latencyMs} ms · ${dreamProvider} / ${dreamModel}`);
|
|
2111
2293
|
}
|
|
2112
2294
|
else {
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
const proceed = await askYesNo(rl, " Continue saving config anyway?", true);
|
|
2295
|
+
validateSpin.fail("could not reach model", result.error);
|
|
2296
|
+
const proceed = await askYesNo(rl, "save config anyway?", true);
|
|
2116
2297
|
if (!proceed) {
|
|
2117
|
-
|
|
2298
|
+
printStatus("warn", "setup cancelled · no changes written");
|
|
2118
2299
|
localDb.close();
|
|
2300
|
+
remoteDb?.close();
|
|
2119
2301
|
return;
|
|
2120
2302
|
}
|
|
2121
2303
|
}
|
|
2122
2304
|
}
|
|
2123
2305
|
catch (err) {
|
|
2124
|
-
|
|
2306
|
+
printStatus("warn", "validation skipped", err instanceof Error ? err.message : String(err));
|
|
2125
2307
|
}
|
|
2126
2308
|
}
|
|
2127
2309
|
else {
|
|
2128
|
-
|
|
2310
|
+
printStatus("warn", `no API key for ${dreamProvider}`, "set one via `gnosys setup models`");
|
|
2129
2311
|
}
|
|
2130
2312
|
}
|
|
2131
|
-
//
|
|
2313
|
+
// ─── 7.2 Thresholds + sub-tasks ───────────────────────────────────
|
|
2132
2314
|
console.log();
|
|
2133
|
-
console.log(
|
|
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
|
|
2315
|
+
console.log(Header(["gnosys", "setup", "dream", "when & what"], { version: "step 3 of 3" }));
|
|
2147
2316
|
console.log();
|
|
2148
|
-
console.log(
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
const
|
|
2317
|
+
console.log(Title("Thresholds & sub-tasks", "press enter to accept defaults, or `e` to edit"));
|
|
2318
|
+
console.log();
|
|
2319
|
+
// Defaults pulled from the existing config (or the global defaults).
|
|
2320
|
+
const dIdle = existingDream?.idleMinutes ?? 10;
|
|
2321
|
+
const dRuntime = existingDream?.maxRuntimeMinutes ?? 30;
|
|
2322
|
+
const dMinMem = existingDream?.minMemories ?? 10;
|
|
2323
|
+
const dSelfCritique = existingDream?.selfCritique ?? true;
|
|
2324
|
+
const dGenSummaries = existingDream?.generateSummaries ?? true;
|
|
2325
|
+
const dDiscover = existingDream?.discoverRelationships ?? true;
|
|
2326
|
+
const { renderThresholdsBlock } = await import("./setup/dreamRender.js");
|
|
2327
|
+
for (const line of renderThresholdsBlock(dIdle, dRuntime, dMinMem, {
|
|
2328
|
+
selfCritique: dSelfCritique,
|
|
2329
|
+
generateSummaries: dGenSummaries,
|
|
2330
|
+
discoverRelationships: dDiscover,
|
|
2331
|
+
})) {
|
|
2332
|
+
console.log(line);
|
|
2333
|
+
}
|
|
2334
|
+
console.log();
|
|
2335
|
+
const editChoice = (await askInput(rl, "press enter to accept defaults, or e to edit")).trim().toLowerCase();
|
|
2336
|
+
let idleMinutes = dIdle;
|
|
2337
|
+
let maxRuntimeMinutes = dRuntime;
|
|
2338
|
+
let minMemories = dMinMem;
|
|
2339
|
+
let selfCritique = dSelfCritique;
|
|
2340
|
+
let generateSummaries = dGenSummaries;
|
|
2341
|
+
let discoverRelationships = dDiscover;
|
|
2342
|
+
if (editChoice === "e") {
|
|
2343
|
+
const idleAns = await askInput(rl, "idle minutes before triggering", { default: String(dIdle) });
|
|
2344
|
+
idleMinutes = Math.max(1, parseInt(idleAns) || dIdle);
|
|
2345
|
+
const runtimeAns = await askInput(rl, "max runtime minutes", { default: String(dRuntime) });
|
|
2346
|
+
maxRuntimeMinutes = Math.max(1, parseInt(runtimeAns) || dRuntime);
|
|
2347
|
+
const minMemAns = await askInput(rl, "minimum memories before activating", { default: String(dMinMem) });
|
|
2348
|
+
minMemories = Math.max(1, parseInt(minMemAns) || dMinMem);
|
|
2349
|
+
selfCritique = await askYesNo(rl, "self-critique (rule + LLM-based review flagging)", dSelfCritique);
|
|
2350
|
+
generateSummaries = await askYesNo(rl, "generate summaries (LLM)", dGenSummaries);
|
|
2351
|
+
discoverRelationships = await askYesNo(rl, "discover relationships (LLM)", dDiscover);
|
|
2352
|
+
}
|
|
2152
2353
|
// Save
|
|
2153
|
-
const storePath =
|
|
2354
|
+
const storePath = ensureActiveStorePath(projectDir);
|
|
2154
2355
|
await updateConfig(storePath, {
|
|
2155
2356
|
dream: {
|
|
2156
2357
|
enabled: true,
|
|
@@ -2168,159 +2369,90 @@ export async function runDreamSetup(opts = {}) {
|
|
|
2168
2369
|
// doesn't fire immediately based on stale history.
|
|
2169
2370
|
localDb.resetDreamConsecutiveFailures();
|
|
2170
2371
|
localDb.close();
|
|
2372
|
+
remoteDb?.close();
|
|
2373
|
+
// Final Diff block per the design — provider/machine + the two
|
|
2374
|
+
// threshold fields most users actually care about.
|
|
2171
2375
|
console.log();
|
|
2172
|
-
|
|
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}`);
|
|
2376
|
+
printStatus("ok", "dream mode enabled");
|
|
2176
2377
|
console.log();
|
|
2177
|
-
|
|
2378
|
+
const { buildDreamDiffRows } = await import("./setup/dreamRender.js");
|
|
2379
|
+
printDiff(buildDreamDiffRows(existingDream
|
|
2380
|
+
? {
|
|
2381
|
+
provider: existingDream.provider,
|
|
2382
|
+
model: existingDream.model,
|
|
2383
|
+
machine: designatedMachine ?? "—",
|
|
2384
|
+
idleMinutes: existingDream.idleMinutes,
|
|
2385
|
+
maxRuntimeMinutes: existingDream.maxRuntimeMinutes,
|
|
2386
|
+
}
|
|
2387
|
+
: null, {
|
|
2388
|
+
provider: dreamProvider,
|
|
2389
|
+
model: dreamModel || undefined,
|
|
2390
|
+
machine: designate ? localMachine : (designatedMachine ?? "none"),
|
|
2391
|
+
idleMinutes,
|
|
2392
|
+
maxRuntimeMinutes,
|
|
2393
|
+
selfCritique,
|
|
2394
|
+
generateSummaries,
|
|
2395
|
+
discoverRelationships,
|
|
2396
|
+
}));
|
|
2397
|
+
const dreamerName = designate ? localMachine : (designatedMachine ?? "the designated machine");
|
|
2398
|
+
printStatus("progress", `first cycle runs after ${dreamerName} is idle for ${idleMinutes} min`);
|
|
2399
|
+
printStatus("progress", "check status anytime with", "gnosys dashboard");
|
|
2178
2400
|
}
|
|
2179
2401
|
finally {
|
|
2180
2402
|
if (ownsRl)
|
|
2181
2403
|
rl.close();
|
|
2182
2404
|
}
|
|
2183
2405
|
}
|
|
2406
|
+
/**
|
|
2407
|
+
* v5.9.3 (deci-050): `gnosys setup chat` is deprecated. Chat config
|
|
2408
|
+
* moves into the chat TUI's own settings panel in v6.0 (road-014). This
|
|
2409
|
+
* stub renders a deprecation notice and exits. The function signature
|
|
2410
|
+
* is preserved so existing callers (cli.ts subcommand registration)
|
|
2411
|
+
* continue to compile.
|
|
2412
|
+
*/
|
|
2184
2413
|
export async function runChatSetup(opts = {}) {
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
const
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
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
|
-
}
|
|
2414
|
+
void opts; // signature preserved; opts unused in deprecation notice
|
|
2415
|
+
// Use atom-based render so the notice matches the rest of v5.9.3.
|
|
2416
|
+
const { Header } = await import("./setup/ui/header.js");
|
|
2417
|
+
const { Status } = await import("./setup/ui/status.js");
|
|
2418
|
+
const { Footer } = await import("./setup/ui/footer.js");
|
|
2419
|
+
const { c, color } = await import("./setup/ui/tokens.js");
|
|
2420
|
+
const v = `v${getVersion()}`;
|
|
2421
|
+
console.log();
|
|
2422
|
+
console.log(Header(["gnosys", "setup", "chat"], { version: v }));
|
|
2423
|
+
console.log();
|
|
2424
|
+
console.log(Status("warn", "chat settings have moved"));
|
|
2425
|
+
console.log();
|
|
2426
|
+
console.log(` ${color(c.text, "chat is now configured from inside the TUI itself.")}`);
|
|
2427
|
+
console.log(` ${color(c.textDim, "open it with")} ${color(c.text, "gnosys chat")}`);
|
|
2428
|
+
console.log(` ${color(c.textDim, "then press")} ${color(c.text, "⌃, (settings)")}`);
|
|
2429
|
+
console.log();
|
|
2430
|
+
console.log(Footer("v6.0 will retire this command entirely"));
|
|
2312
2431
|
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2432
|
+
// ─── runChatSetup body removed in v5.9.3 (deci-050) ─────────────────
|
|
2433
|
+
// Provider/model override + recall tuning + tools fence + auto-summarize
|
|
2434
|
+
// + system prompt prefix all move to the v6.0 chat TUI's settings panel
|
|
2435
|
+
// (road-014). The exported stub above renders a deprecation notice.
|
|
2436
|
+
/**
|
|
2437
|
+
* Open the remote central DB ONLY when sync is configured AND the share
|
|
2438
|
+
* is reachable. Returns null otherwise. Used by the dream wizard so it
|
|
2439
|
+
* can mirror `dream_machine_id` writes to both DB meta tables (Bug 8).
|
|
2440
|
+
*/
|
|
2441
|
+
async function openRemoteDbIfConfigured(localDb) {
|
|
2442
|
+
try {
|
|
2443
|
+
if (!localDb.isAvailable())
|
|
2444
|
+
return null;
|
|
2445
|
+
const remotePath = localDb.getMeta("remote_path");
|
|
2446
|
+
if (!remotePath)
|
|
2447
|
+
return null;
|
|
2448
|
+
if (!fsSync.existsSync(path.join(remotePath, "gnosys.db")))
|
|
2449
|
+
return null;
|
|
2450
|
+
const { GnosysDB } = await import("./db.js");
|
|
2451
|
+
return new GnosysDB(remotePath);
|
|
2319
2452
|
}
|
|
2320
|
-
|
|
2321
|
-
|
|
2453
|
+
catch {
|
|
2454
|
+
return null;
|
|
2322
2455
|
}
|
|
2323
|
-
return globalStore;
|
|
2324
2456
|
}
|
|
2325
2457
|
/**
|
|
2326
2458
|
* Best-effort lookup of the API key for a provider. Used by the dream setup
|