gnosys 5.9.3 → 5.9.5

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 (57) hide show
  1. package/dist/lib/config.d.ts.map +1 -1
  2. package/dist/lib/config.js +34 -1
  3. package/dist/lib/config.js.map +1 -1
  4. package/dist/lib/dream.d.ts.map +1 -1
  5. package/dist/lib/dream.js +14 -3
  6. package/dist/lib/dream.js.map +1 -1
  7. package/dist/lib/ingest.js +1 -1
  8. package/dist/lib/ingest.js.map +1 -1
  9. package/dist/lib/remote.d.ts +16 -0
  10. package/dist/lib/remote.d.ts.map +1 -1
  11. package/dist/lib/remote.js +47 -6
  12. package/dist/lib/remote.js.map +1 -1
  13. package/dist/lib/setup/dreamState.d.ts +50 -0
  14. package/dist/lib/setup/dreamState.d.ts.map +1 -0
  15. package/dist/lib/setup/dreamState.js +68 -0
  16. package/dist/lib/setup/dreamState.js.map +1 -0
  17. package/dist/lib/setup/routingRender.d.ts +4 -0
  18. package/dist/lib/setup/routingRender.d.ts.map +1 -1
  19. package/dist/lib/setup/routingRender.js +40 -23
  20. package/dist/lib/setup/routingRender.js.map +1 -1
  21. package/dist/lib/setup/sections/ides.d.ts.map +1 -1
  22. package/dist/lib/setup/sections/ides.js +56 -23
  23. package/dist/lib/setup/sections/ides.js.map +1 -1
  24. package/dist/lib/setup/sections/preferences.d.ts.map +1 -1
  25. package/dist/lib/setup/sections/preferences.js +25 -12
  26. package/dist/lib/setup/sections/preferences.js.map +1 -1
  27. package/dist/lib/setup/sections/routing.d.ts.map +1 -1
  28. package/dist/lib/setup/sections/routing.js +31 -9
  29. package/dist/lib/setup/sections/routing.js.map +1 -1
  30. package/dist/lib/setup/storePath.d.ts +30 -0
  31. package/dist/lib/setup/storePath.d.ts.map +1 -0
  32. package/dist/lib/setup/storePath.js +47 -0
  33. package/dist/lib/setup/storePath.js.map +1 -0
  34. package/dist/lib/setup/summary.d.ts +1 -1
  35. package/dist/lib/setup/summary.d.ts.map +1 -1
  36. package/dist/lib/setup/summary.js +27 -22
  37. package/dist/lib/setup/summary.js.map +1 -1
  38. package/dist/lib/setup/syncProjectsRender.d.ts +2 -1
  39. package/dist/lib/setup/syncProjectsRender.d.ts.map +1 -1
  40. package/dist/lib/setup/syncProjectsRender.js +54 -38
  41. package/dist/lib/setup/syncProjectsRender.js.map +1 -1
  42. package/dist/lib/setup/ui/index.d.ts +2 -0
  43. package/dist/lib/setup/ui/index.d.ts.map +1 -1
  44. package/dist/lib/setup/ui/index.js +1 -0
  45. package/dist/lib/setup/ui/index.js.map +1 -1
  46. package/dist/lib/setup/ui/panel.d.ts.map +1 -1
  47. package/dist/lib/setup/ui/panel.js +10 -3
  48. package/dist/lib/setup/ui/panel.js.map +1 -1
  49. package/dist/lib/setup/ui/table.d.ts +37 -0
  50. package/dist/lib/setup/ui/table.d.ts.map +1 -0
  51. package/dist/lib/setup/ui/table.js +82 -0
  52. package/dist/lib/setup/ui/table.js.map +1 -0
  53. package/dist/lib/setup.d.ts +31 -0
  54. package/dist/lib/setup.d.ts.map +1 -1
  55. package/dist/lib/setup.js +237 -79
  56. package/dist/lib/setup.js.map +1 -1
  57. package/package.json +1 -1
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Table atom — generic tabular layout for the v5.9.4 CLI vocabulary.
3
+ *
4
+ * Per `arch-004`: every tabular CLI screen reaches for `Table` first instead
5
+ * of hand-rolling `padEnd` columns. Header row + thin divider + auto-fit
6
+ * or fixed-width columns + optional per-row marker formatter (e.g. `▶` for
7
+ * changed routing rows).
8
+ *
9
+ * The renderer measures printable width with ANSI stripped so coloured
10
+ * cell contents don't break alignment. Cell `render(row)` returns the
11
+ * RAW string; `color` is applied per-column for the cell value (header
12
+ * is always `text-dim` per design §4).
13
+ */
14
+ import { c, color, glyph } from "./tokens.js";
15
+ import { stripAnsi } from "./header.js";
16
+ /**
17
+ * Render a table. Returns one string per line (header + divider + rows),
18
+ * never trailing newline. Returns `[]` for an empty `rows` array unless
19
+ * `showHeader` is true (in which case header + divider are still emitted).
20
+ */
21
+ export function renderTable(rows, columns, opts = {}) {
22
+ if (columns.length === 0)
23
+ return [];
24
+ const showHeader = opts.showHeader !== false;
25
+ const drawDivider = opts.dividerAfterHeader !== false;
26
+ const indent = " ".repeat(opts.indent ?? 1);
27
+ const gap = " ".repeat(opts.gap ?? 2);
28
+ // Pre-compute raw cell values + per-column widths.
29
+ const rawCells = rows.map((row) => columns.map((col) => col.render(row)));
30
+ const widths = columns.map((col, idx) => {
31
+ if (typeof col.width === "number")
32
+ return col.width;
33
+ const headerLen = col.header.length;
34
+ const maxCell = rawCells.reduce((max, cells) => {
35
+ const len = stripAnsi(cells[idx] ?? "").length;
36
+ return len > max ? len : max;
37
+ }, 0);
38
+ return Math.max(headerLen, maxCell);
39
+ });
40
+ const lines = [];
41
+ if (showHeader) {
42
+ const headerCells = columns.map((col, idx) => color(c.textDim, padCell(col.header, widths[idx], col.align ?? "left")));
43
+ lines.push(`${indent}${headerCells.join(gap)}`);
44
+ if (drawDivider) {
45
+ const ruleWidth = widths.reduce((sum, w) => sum + w, 0) + gap.length * (columns.length - 1);
46
+ lines.push(`${indent}${color(c.textGhost, glyph.ruleLight.repeat(Math.max(1, ruleWidth)))}`);
47
+ }
48
+ }
49
+ rows.forEach((row, rowIdx) => {
50
+ const cells = columns.map((col, colIdx) => {
51
+ const raw = rawCells[rowIdx][colIdx];
52
+ // Last left-aligned column doesn't need trailing pad — saves a row of
53
+ // ghost whitespace per snapshot and matches the v5.9.3 hand-rolled output.
54
+ const isLastCol = colIdx === columns.length - 1;
55
+ const align = col.align ?? "left";
56
+ const padded = isLastCol && align === "left"
57
+ ? raw
58
+ : padCell(raw, widths[colIdx], align);
59
+ // Empty string opts out of column-level colouring — useful when the
60
+ // cell's `render()` already emits its own ANSI (e.g. cost tiers).
61
+ const cellColor = col.color === "" ? null : col.color ?? c.text;
62
+ return cellColor ? color(cellColor, padded) : padded;
63
+ });
64
+ const line = `${indent}${cells.join(gap)}`;
65
+ lines.push(opts.rowFormatter ? opts.rowFormatter(row, line) : line);
66
+ });
67
+ return lines;
68
+ }
69
+ /** Convenience: render + print + trailing newline. */
70
+ export function printTable(rows, columns, opts = {}) {
71
+ const lines = renderTable(rows, columns, opts);
72
+ if (lines.length > 0)
73
+ process.stdout.write(`${lines.join("\n")}\n`);
74
+ }
75
+ /** Pad a cell value (which may contain ANSI) to a target printable width. */
76
+ function padCell(value, width, align) {
77
+ const bareLen = stripAnsi(value).length;
78
+ const padLen = Math.max(0, width - bareLen);
79
+ const pad = " ".repeat(padLen);
80
+ return align === "right" ? `${pad}${value}` : `${value}${pad}`;
81
+ }
82
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../../../src/lib/setup/ui/table.ts"],"names":[],"mappings":"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"}
@@ -70,6 +70,23 @@ export declare function writeApiKeyToKeychain(envVar: string, key: string): bool
70
70
  * Returns an array like ["claude", "cursor", "codex"].
71
71
  */
72
72
  export declare function detectIDEs(projectDir: string): Promise<string[]>;
73
+ /**
74
+ * Replace (or append) a `[mcp.<name>]` block inside the TOML text for
75
+ * Grok Build's config file. Preserves every line outside that block —
76
+ * deci-046 read-then-merge rule. We can't pull in a TOML dependency
77
+ * without adding to package.json, so we ship a minimal hand-rolled
78
+ * updater scoped exactly to the `[mcp.gnosys]` use case.
79
+ *
80
+ * Spec assumption: TOML headers we touch are simple `[a.b]` lines with
81
+ * no inline tables or nested arrays. Any other content is left alone.
82
+ *
83
+ * Exported for tests.
84
+ */
85
+ export declare function upsertGrokMcpBlock(existing: string, name: string, entry: {
86
+ command: string;
87
+ args: string[];
88
+ startup_timeout_sec?: number;
89
+ }): string;
73
90
  /**
74
91
  * Set up Gnosys MCP integration for a specific IDE.
75
92
  */
@@ -81,6 +98,20 @@ export declare function runSetup(opts: {
81
98
  directory?: string;
82
99
  nonInteractive?: boolean;
83
100
  }): Promise<SetupResult>;
101
+ export interface ProviderOnlySetupOpts {
102
+ directory?: string;
103
+ rl?: ReadlineInterface;
104
+ }
105
+ /**
106
+ * Update ONLY `llm.defaultProvider` in gnosys.json. Used by the summary
107
+ * panel row 1 ("provider") so it stops dragging the user into the full
108
+ * model picker — that's row 2's job.
109
+ *
110
+ * v5.9.4 Bug 4 — before this split, both summary rows routed through
111
+ * `runModelsSetup`, leaving no way to swap provider without also choosing
112
+ * a new model. Now row 1 picks a provider, row 2 picks a model.
113
+ */
114
+ export declare function runProviderOnlySetup(opts?: ProviderOnlySetupOpts): Promise<void>;
84
115
  export interface ModelsSetupOpts {
85
116
  provider?: string;
86
117
  model?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/lib/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/lib/setup.ts"],"names":[],"mappings":"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"}
package/dist/lib/setup.js CHANGED
@@ -16,7 +16,7 @@ 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 { getGnosysHome } from "./paths.js";
19
+ import { resolveActiveStorePath, ensureActiveStorePath } from "./setup/storePath.js";
20
20
  import { safeQuestion } from "./setup/ui/safePrompt.js";
21
21
  // ─── ANSI Colors ────────────────────────────────────────────────────────────
22
22
  const BOLD = "\x1b[1m";
@@ -139,6 +139,12 @@ export async function fetchDynamicModels() {
139
139
  })
140
140
  .filter((m) => m.input > 0 && !m.isFree && !m.isVariant && !m.isGuard)
141
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))
142
148
  .sort((a, b) => b.created - a.created); // newest first
143
149
  if (models.length === 0)
144
150
  continue;
@@ -227,6 +233,19 @@ export async function fetchDynamicModels() {
227
233
  if (!tiers.some((t) => t.recommended) && tiers.length > 0) {
228
234
  tiers[0].recommended = true;
229
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
+ }
230
249
  result[ourProvider] = tiers;
231
250
  }
232
251
  // Cache the result
@@ -533,6 +552,16 @@ export async function detectIDEs(projectDir) {
533
552
  // Not installed
534
553
  }
535
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
+ }
536
565
  return detected;
537
566
  }
538
567
  /**
@@ -552,6 +581,68 @@ function claudeDesktopConfigPath() {
552
581
  }
553
582
  return path.join(home, ".config", "Claude", "claude_desktop_config.json");
554
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
+ }
555
646
  /**
556
647
  * Set up Gnosys MCP integration for a specific IDE.
557
648
  */
@@ -717,6 +808,29 @@ export async function setupIDE(ide, projectDir) {
717
808
  await fs.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
718
809
  return { success: true, message: "Antigravity MCP config updated (~/.gemini/antigravity/mcp_config.json)" };
719
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
+ }
720
834
  case "claude-desktop": {
721
835
  // Claude Desktop reads MCP servers from claude_desktop_config.json
722
836
  // in a platform-specific app data directory. Distinct from Claude
@@ -867,31 +981,21 @@ async function getRegisteredProjects() {
867
981
  }
868
982
  /**
869
983
  * Try to load existing gnosys.json config for displaying current values.
870
- * Checks the project .gnosys dir first, then the global ~/.gnosys dir.
871
- * Returns null if no config found.
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.
872
988
  */
873
989
  async function loadExistingConfig(projectDir) {
874
- // Try project-level config first
875
- try {
876
- const projectStore = path.join(projectDir, ".gnosys");
877
- const stat = await fs.stat(path.join(projectStore, "gnosys.json"));
878
- if (stat.isFile()) {
879
- return await loadConfig(projectStore);
880
- }
881
- }
882
- catch {
883
- // No project config
884
- }
885
- // Try global config at ~/.gnosys
990
+ const storePath = resolveActiveStorePath(projectDir);
886
991
  try {
887
- const globalStore = getGnosysHome();
888
- const stat = await fs.stat(path.join(globalStore, "gnosys.json"));
992
+ const stat = await fs.stat(path.join(storePath, "gnosys.json"));
889
993
  if (stat.isFile()) {
890
- return await loadConfig(globalStore);
994
+ return await loadConfig(storePath);
891
995
  }
892
996
  }
893
997
  catch {
894
- // No global config
998
+ // No config in the resolved store
895
999
  }
896
1000
  return null;
897
1001
  }
@@ -1508,12 +1612,14 @@ export async function runSetup(opts) {
1508
1612
  codex: "Codex",
1509
1613
  "gemini-cli": "Gemini CLI",
1510
1614
  antigravity: "Antigravity",
1615
+ // v5.9.4 Bug 12 — Grok Build (~/.grok/config.toml).
1616
+ "grok-build": "Grok Build",
1511
1617
  };
1512
1618
  // IDEs whose MCP config lives at the user level (~/...) rather than per-project.
1513
1619
  // We don't try to create a project-level directory for these.
1514
- const userLevelIdes = new Set(["claude", "claude-desktop", "gemini-cli", "antigravity"]);
1620
+ const userLevelIdes = new Set(["claude", "claude-desktop", "gemini-cli", "antigravity", "grok-build"]);
1515
1621
  // Build IDE options: show detected ones and offer to create missing ones
1516
- const allIdeKeys = ["claude", "claude-desktop", "cursor", "codex", "gemini-cli", "antigravity"];
1622
+ const allIdeKeys = ["claude", "claude-desktop", "cursor", "codex", "gemini-cli", "antigravity", "grok-build"];
1517
1623
  const ideOptions = [];
1518
1624
  const ideKeyForOption = []; // parallel array mapping option index to IDE key
1519
1625
  for (const ide of allIdeKeys) {
@@ -1595,21 +1701,8 @@ export async function runSetup(opts) {
1595
1701
  const structuringModel = isSkip ? "" : (taskOverrides.structuring?.model ?? getStructuringModel(provider, model));
1596
1702
  // ─── Write config to gnosys.json ─────────────────────────────────
1597
1703
  if (!isSkip) {
1598
- // Determine which store path to write to prefer project, fall back to global
1599
- let storePath;
1600
- const projectStore = path.join(projectDir, ".gnosys");
1601
- const globalStore = getGnosysHome();
1602
- if (fsSync.existsSync(path.join(projectStore, "gnosys.json"))) {
1603
- storePath = projectStore;
1604
- }
1605
- else if (fsSync.existsSync(path.join(globalStore, "gnosys.json"))) {
1606
- storePath = globalStore;
1607
- }
1608
- else {
1609
- // Default to global store — create directory if needed
1610
- await fs.mkdir(globalStore, { recursive: true });
1611
- storePath = globalStore;
1612
- }
1704
+ // v5.9.4 Bug 10unified store resolution.
1705
+ const storePath = ensureActiveStorePath(projectDir);
1613
1706
  // Build the config updates
1614
1707
  // Build LLM config update, preserving existing provider-specific settings
1615
1708
  const existingLlm = existingConfig?.llm;
@@ -1772,6 +1865,60 @@ export async function runSetup(opts) {
1772
1865
  throw err;
1773
1866
  }
1774
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
+ }
1775
1922
  /**
1776
1923
  * Models-only configuration — prompts for provider, model, and key (or accepts
1777
1924
  * them via options for non-interactive use). Validates the model against the
@@ -1894,20 +2041,8 @@ export async function runModelsSetup(opts = {}) {
1894
2041
  }
1895
2042
  }
1896
2043
  }
1897
- // Step 5: write config
1898
- const projectStore = path.join(projectDir, ".gnosys");
1899
- const globalStore = getGnosysHome();
1900
- let storePath;
1901
- if (fsSync.existsSync(path.join(projectStore, "gnosys.json"))) {
1902
- storePath = projectStore;
1903
- }
1904
- else if (fsSync.existsSync(path.join(globalStore, "gnosys.json"))) {
1905
- storePath = globalStore;
1906
- }
1907
- else {
1908
- await fs.mkdir(globalStore, { recursive: true });
1909
- storePath = globalStore;
1910
- }
2044
+ // Step 5: write config (v5.9.4 Bug 10 — unified store resolution).
2045
+ const storePath = ensureActiveStorePath(projectDir);
1911
2046
  const existingLlm = existingConfig?.llm;
1912
2047
  const existingProviderConfig = existingLlm
1913
2048
  ? existingLlm[provider]
@@ -1985,11 +2120,8 @@ export async function runModelsCommand(opts = {}) {
1985
2120
  console.log(`${WARN} No provider configured. Run 'gnosys setup' first.`);
1986
2121
  return;
1987
2122
  }
1988
- const projectStore = path.join(projectDir, ".gnosys");
1989
- const globalStore = getGnosysHome();
1990
- const storePath = fsSync.existsSync(path.join(projectStore, "gnosys.json"))
1991
- ? projectStore
1992
- : globalStore;
2123
+ // v5.9.4 Bug 10 — unified store resolution.
2124
+ const storePath = ensureActiveStorePath(projectDir);
1993
2125
  const existingProviderConfig = existingConfig?.llm?.[currentProvider];
1994
2126
  const providerConfigBase = (typeof existingProviderConfig === "object" && existingProviderConfig !== null)
1995
2127
  ? existingProviderConfig
@@ -2046,17 +2178,31 @@ export async function runDreamSetup(opts = {}) {
2046
2178
  const existingDream = existingConfig?.dream;
2047
2179
  // Show current state via central DB
2048
2180
  const { GnosysDB } = await import("./db.js");
2181
+ const { getMachineId } = await import("./remote.js");
2049
2182
  const localDb = GnosysDB.openLocal();
2050
- const designatedMachine = localDb.getDreamMachineId();
2051
- const localMachine = (() => {
2052
- let id = localDb.getMeta("machine_id");
2053
- if (!id) {
2054
- const hostname = process.env.HOSTNAME || process.env.COMPUTERNAME || "unknown";
2055
- id = `${hostname}-${Date.now().toString(36)}`;
2056
- localDb.setMeta("machine_id", id);
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);
2196
+ }
2197
+ catch { /* remote may be transiently unavailable */ }
2198
+ };
2199
+ const clearDreamMachineEverywhere = () => {
2200
+ localDb.clearDreamMachineId();
2201
+ try {
2202
+ remoteDb?.clearDreamMachineId();
2057
2203
  }
2058
- return id;
2059
- })();
2204
+ catch { /* remote may be transiently unavailable */ }
2205
+ };
2060
2206
  // ─── 7.0 Overview & enable ────────────────────────────────────────
2061
2207
  console.log();
2062
2208
  console.log(Header(["gnosys", "setup", "dream"], { version: "step 1 of 3" }));
@@ -2071,14 +2217,15 @@ export async function runDreamSetup(opts = {}) {
2071
2217
  const enabled = await askYesNo(rl, "enable Dream Mode?", existingDream?.enabled ?? true);
2072
2218
  if (!enabled) {
2073
2219
  // Persist disabled state and clear designation
2074
- const storePath = pickStorePath(projectDir);
2220
+ const storePath = ensureActiveStorePath(projectDir);
2075
2221
  await updateConfig(storePath, {
2076
2222
  dream: { ...(existingDream ?? {}), enabled: false },
2077
2223
  });
2078
- localDb.clearDreamMachineId();
2224
+ clearDreamMachineEverywhere();
2079
2225
  console.log();
2080
2226
  printStatus("ok", "dream mode disabled · designation cleared");
2081
2227
  localDb.close();
2228
+ remoteDb?.close();
2082
2229
  return;
2083
2230
  }
2084
2231
  // ─── 7.1 Designated machine + model ───────────────────────────────
@@ -2093,11 +2240,11 @@ export async function runDreamSetup(opts = {}) {
2093
2240
  ? "this machine is currently the dreamer — keep it?"
2094
2241
  : `designate THIS machine (${localMachine}) as the dreamer?`, true);
2095
2242
  if (designate) {
2096
- localDb.setDreamMachineId(localMachine);
2243
+ setDreamMachineEverywhere(localMachine);
2097
2244
  printStatus("ok", `${localMachine} is the dreamer`);
2098
2245
  }
2099
2246
  else if (designatedMachine === localMachine) {
2100
- localDb.clearDreamMachineId();
2247
+ clearDreamMachineEverywhere();
2101
2248
  printStatus("warn", "designation cleared", "no machine will dream until you re-run on another");
2102
2249
  }
2103
2250
  else {
@@ -2150,6 +2297,7 @@ export async function runDreamSetup(opts = {}) {
2150
2297
  if (!proceed) {
2151
2298
  printStatus("warn", "setup cancelled · no changes written");
2152
2299
  localDb.close();
2300
+ remoteDb?.close();
2153
2301
  return;
2154
2302
  }
2155
2303
  }
@@ -2203,7 +2351,7 @@ export async function runDreamSetup(opts = {}) {
2203
2351
  discoverRelationships = await askYesNo(rl, "discover relationships (LLM)", dDiscover);
2204
2352
  }
2205
2353
  // Save
2206
- const storePath = pickStorePath(projectDir);
2354
+ const storePath = ensureActiveStorePath(projectDir);
2207
2355
  await updateConfig(storePath, {
2208
2356
  dream: {
2209
2357
  enabled: true,
@@ -2221,6 +2369,7 @@ export async function runDreamSetup(opts = {}) {
2221
2369
  // doesn't fire immediately based on stale history.
2222
2370
  localDb.resetDreamConsecutiveFailures();
2223
2371
  localDb.close();
2372
+ remoteDb?.close();
2224
2373
  // Final Diff block per the design — provider/machine + the two
2225
2374
  // threshold fields most users actually care about.
2226
2375
  console.log();
@@ -2247,7 +2396,7 @@ export async function runDreamSetup(opts = {}) {
2247
2396
  }));
2248
2397
  const dreamerName = designate ? localMachine : (designatedMachine ?? "the designated machine");
2249
2398
  printStatus("progress", `first cycle runs after ${dreamerName} is idle for ${idleMinutes} min`);
2250
- printStatus("progress", "check status anytime with", "gnosys dashboard");
2399
+ printStatus("progress", "check status anytime with `gnosys status --system`");
2251
2400
  }
2252
2401
  finally {
2253
2402
  if (ownsRl)
@@ -2284,17 +2433,26 @@ export async function runChatSetup(opts = {}) {
2284
2433
  // Provider/model override + recall tuning + tools fence + auto-summarize
2285
2434
  // + system prompt prefix all move to the v6.0 chat TUI's settings panel
2286
2435
  // (road-014). The exported stub above renders a deprecation notice.
2287
- /** Resolve where to write gnosys.json — project store if exists, else global store. */
2288
- function pickStorePath(projectDir) {
2289
- const projectStore = path.join(projectDir, ".gnosys");
2290
- const globalStore = getGnosysHome();
2291
- if (fsSync.existsSync(path.join(projectStore, "gnosys.json"))) {
2292
- return projectStore;
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);
2293
2452
  }
2294
- if (!fsSync.existsSync(globalStore)) {
2295
- fsSync.mkdirSync(globalStore, { recursive: true });
2453
+ catch {
2454
+ return null;
2296
2455
  }
2297
- return globalStore;
2298
2456
  }
2299
2457
  /**
2300
2458
  * Best-effort lookup of the API key for a provider. Used by the dream setup