repowisestage 0.0.53 → 0.0.55

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 (2) hide show
  1. package/dist/bin/repowise.js +691 -331
  2. package/package.json +1 -1
@@ -2019,6 +2019,7 @@ var init_toolchain_installer = __esm({
2019
2019
  import { promises as fs4 } from "fs";
2020
2020
  import { join as join17, dirname as dirname6 } from "path";
2021
2021
  import { spawn as spawn7 } from "child_process";
2022
+ import lockfile3 from "proper-lockfile";
2022
2023
  function getLspInstallDir() {
2023
2024
  return join17(getConfigDir(), "lsp-servers");
2024
2025
  }
@@ -2035,18 +2036,42 @@ async function ensureNpmLspInstalled(config2) {
2035
2036
  }
2036
2037
  try {
2037
2038
  await fs4.mkdir(installDir, { recursive: true });
2038
- const pkgJsonPath = join17(installDir, "package.json");
2039
- if (!await pathExists4(pkgJsonPath)) {
2040
- await fs4.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
2039
+ let release = null;
2040
+ try {
2041
+ release = await lockfile3.lock(installDir, {
2042
+ stale: 18e4,
2043
+ retries: { retries: 20, factor: 1.5, minTimeout: 500, maxTimeout: 5e3 },
2044
+ realpath: false
2045
+ });
2046
+ } catch {
2047
+ if (await pathExists4(binPath)) {
2048
+ return { installed: false, skipped: "already-present" };
2049
+ }
2041
2050
  }
2042
- await runNpmInstall(installDir, config2.npmPackage);
2043
- if (!await pathExists4(binPath)) {
2044
- return {
2045
- installed: false,
2046
- error: `npm install completed but ${config2.command} still not at ${binPath}`
2047
- };
2051
+ try {
2052
+ if (await pathExists4(binPath)) {
2053
+ return { installed: false, skipped: "already-present" };
2054
+ }
2055
+ const pkgJsonPath = join17(installDir, "package.json");
2056
+ if (!await pathExists4(pkgJsonPath)) {
2057
+ await fs4.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
2058
+ }
2059
+ await runNpmInstall(installDir, config2.npmPackage);
2060
+ if (!await pathExists4(binPath)) {
2061
+ return {
2062
+ installed: false,
2063
+ error: `npm install completed but ${config2.command} still not at ${binPath}`
2064
+ };
2065
+ }
2066
+ return { installed: true };
2067
+ } finally {
2068
+ if (release) {
2069
+ try {
2070
+ await release();
2071
+ } catch {
2072
+ }
2073
+ }
2048
2074
  }
2049
- return { installed: true };
2050
2075
  } catch (err) {
2051
2076
  return {
2052
2077
  installed: false,
@@ -2526,7 +2551,9 @@ __export(lsp_tools_exports, {
2526
2551
  lspImplementation: () => lspImplementation,
2527
2552
  lspReferences: () => lspReferences,
2528
2553
  lspTypeHierarchy: () => lspTypeHierarchy,
2529
- lspWorkspaceSymbol: () => lspWorkspaceSymbol
2554
+ lspWorkspaceSymbol: () => lspWorkspaceSymbol,
2555
+ pickAvailableConfig: () => pickAvailableConfig,
2556
+ probeBinary: () => probeBinary
2530
2557
  });
2531
2558
  import { fileURLToPath as fileURLToPath2 } from "url";
2532
2559
  import { relative as pathRelative, resolve as pathResolve3, join as pathJoin } from "path";
@@ -2973,15 +3000,15 @@ var init_telemetry = __esm({
2973
3000
  // bin/repowise.ts
2974
3001
  import { readFileSync as readFileSync3 } from "fs";
2975
3002
  import { fileURLToPath as fileURLToPath4 } from "url";
2976
- import { dirname as dirname19, join as join51 } from "path";
3003
+ import { dirname as dirname19, join as join52 } from "path";
2977
3004
  import { Command } from "commander";
2978
3005
 
2979
3006
  // ../listener/dist/main.js
2980
3007
  init_config_dir();
2981
3008
  import { readFile as readFile12, writeFile as writeFile14, mkdir as mkdir14, stat as fsStat } from "fs/promises";
2982
- import { join as join31, dirname as dirname14 } from "path";
3009
+ import { join as join32, dirname as dirname14 } from "path";
2983
3010
  import { fileURLToPath as fileURLToPath3 } from "url";
2984
- import lockfile3 from "proper-lockfile";
3011
+ import lockfile4 from "proper-lockfile";
2985
3012
 
2986
3013
  // ../../packages/shared/dist/lib/ai-tools.js
2987
3014
  import { readFile, writeFile, mkdir, readdir, stat, unlink } from "fs/promises";
@@ -3389,10 +3416,19 @@ async function getListenerConfig() {
3389
3416
  repos: validRepos,
3390
3417
  autoDiscoverRepos: raw.autoDiscoverRepos ?? false,
3391
3418
  noAutoUpdate: raw.noAutoUpdate ?? false,
3419
+ lspEnabled: raw.lspEnabled ?? true,
3420
+ lspAutoWarm: raw.lspAutoWarm ?? true,
3392
3421
  ...lspOverrides ? { lspOverrides } : {}
3393
3422
  };
3394
3423
  } catch {
3395
- return { defaultApiUrl: apiUrl, repos: [], autoDiscoverRepos: false, noAutoUpdate: false };
3424
+ return {
3425
+ defaultApiUrl: apiUrl,
3426
+ repos: [],
3427
+ autoDiscoverRepos: false,
3428
+ noAutoUpdate: false,
3429
+ lspEnabled: true,
3430
+ lspAutoWarm: true
3431
+ };
3396
3432
  }
3397
3433
  }
3398
3434
  async function saveListenerConfig(config2) {
@@ -3416,6 +3452,12 @@ async function saveListenerConfig(config2) {
3416
3452
  ...raw,
3417
3453
  apiUrl: config2.defaultApiUrl,
3418
3454
  repos: config2.repos,
3455
+ // Persist the LSP flags explicitly (not "only when non-default") so a
3456
+ // listener-driven reconcile save can never silently drop a user's
3457
+ // `repowise lsp off`. The CLI writes these via mergeAndSaveConfig;
3458
+ // the listener round-trips them here unchanged.
3459
+ lspEnabled: config2.lspEnabled,
3460
+ lspAutoWarm: config2.lspAutoWarm,
3419
3461
  ...config2.lspOverrides ? { lspOverrides: config2.lspOverrides } : {}
3420
3462
  };
3421
3463
  const tmpPath = configPath + ".tmp";
@@ -6738,41 +6780,83 @@ function handleRequest(req, res, options, sessions, secretCtx) {
6738
6780
  return {
6739
6781
  "/mcp/tools/lsp_definition": async (body, root) => {
6740
6782
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6741
- return mod.lspDefinition({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6783
+ return mod.lspDefinition({
6784
+ workspaces: ws,
6785
+ repoRoot: root,
6786
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6787
+ }, body);
6742
6788
  },
6743
6789
  "/mcp/tools/lsp_references": async (body, root) => {
6744
6790
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6745
- return mod.lspReferences({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6791
+ return mod.lspReferences({
6792
+ workspaces: ws,
6793
+ repoRoot: root,
6794
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6795
+ }, body);
6746
6796
  },
6747
6797
  "/mcp/tools/lsp_hover": async (body, root) => {
6748
6798
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6749
- return mod.lspHover({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6799
+ return mod.lspHover({
6800
+ workspaces: ws,
6801
+ repoRoot: root,
6802
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6803
+ }, body);
6750
6804
  },
6751
6805
  "/mcp/tools/lsp_workspace_symbol": async (body, root) => {
6752
6806
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6753
- return mod.lspWorkspaceSymbol({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6807
+ return mod.lspWorkspaceSymbol({
6808
+ workspaces: ws,
6809
+ repoRoot: root,
6810
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6811
+ }, body);
6754
6812
  },
6755
6813
  "/mcp/tools/lsp_document_symbol": async (body, root) => {
6756
6814
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6757
- return mod.lspDocumentSymbol({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6815
+ return mod.lspDocumentSymbol({
6816
+ workspaces: ws,
6817
+ repoRoot: root,
6818
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6819
+ }, body);
6758
6820
  },
6759
6821
  "/mcp/tools/lsp_call_hierarchy": async (body, root) => {
6760
6822
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6761
- return mod.lspCallHierarchy({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6823
+ return mod.lspCallHierarchy({
6824
+ workspaces: ws,
6825
+ repoRoot: root,
6826
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6827
+ }, body);
6762
6828
  },
6763
6829
  "/mcp/tools/lsp_implementation": async (body, root) => {
6764
6830
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6765
- return mod.lspImplementation({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6831
+ return mod.lspImplementation({
6832
+ workspaces: ws,
6833
+ repoRoot: root,
6834
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6835
+ }, body);
6766
6836
  },
6767
6837
  "/mcp/tools/lsp_type_hierarchy": async (body, root) => {
6768
6838
  const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
6769
- return mod.lspTypeHierarchy({ workspaces: ws, repoRoot: root, ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {} }, body);
6839
+ return mod.lspTypeHierarchy({
6840
+ workspaces: ws,
6841
+ repoRoot: root,
6842
+ ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
6843
+ }, body);
6770
6844
  }
6771
6845
  };
6772
6846
  })();
6773
6847
  if (method === "POST" && lspDispatch[url]) {
6774
6848
  const lspHandler = lspDispatch[url];
6775
6849
  dispatchSessionTool(req, res, url, sessions, options.mcpLogger, async (session, body) => {
6850
+ if (options.getLspEnabled && options.getLspEnabled() === false) {
6851
+ return {
6852
+ ok: true,
6853
+ value: {
6854
+ error: "lsp_disabled",
6855
+ hint: "LSP is turned off for this listener (run `repowise lsp on` to re-enable). Use graph-only tools (find_symbol, find_callers, find_references, get_call_graph) instead.",
6856
+ isError: true
6857
+ }
6858
+ };
6859
+ }
6776
6860
  const root = getRepoIdToRoot().get(session.repoId) ?? fallbackRoot;
6777
6861
  if (!root) {
6778
6862
  return {
@@ -7074,6 +7158,7 @@ async function startMcp(options) {
7074
7158
  ...firstRepoLocal ? { defaultRepoRoot: firstRepoLocal } : {},
7075
7159
  repoIdToRoot: () => repoIdToRoot,
7076
7160
  ...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {},
7161
+ ...options.getLspEnabled ? { getLspEnabled: options.getLspEnabled } : {},
7077
7162
  mcpLogger
7078
7163
  });
7079
7164
  const reapInterval = lspWorkspaces ? setInterval(() => {
@@ -7239,10 +7324,10 @@ async function ensureServerConsent(opts) {
7239
7324
  });
7240
7325
  if (!res.ok)
7241
7326
  return;
7242
- const fs24 = await import("fs/promises");
7327
+ const fs25 = await import("fs/promises");
7243
7328
  const path = await import("path");
7244
- await fs24.mkdir(path.dirname(opts.markerPath), { recursive: true });
7245
- await fs24.writeFile(opts.markerPath, (/* @__PURE__ */ new Date()).toISOString() + "\n", {
7329
+ await fs25.mkdir(path.dirname(opts.markerPath), { recursive: true });
7330
+ await fs25.writeFile(opts.markerPath, (/* @__PURE__ */ new Date()).toISOString() + "\n", {
7246
7331
  encoding: "utf-8",
7247
7332
  mode: 384
7248
7333
  });
@@ -7658,12 +7743,100 @@ async function runAutoConfig(opts) {
7658
7743
  // ../listener/dist/main.js
7659
7744
  init_installer();
7660
7745
 
7746
+ // ../listener/dist/lsp/warm.js
7747
+ init_registry();
7748
+ init_lsp_tools();
7749
+ import { promises as fs14 } from "fs";
7750
+ import { join as join30 } from "path";
7751
+ async function collectRepresentativeFiles(repoRoot) {
7752
+ const reps = /* @__PURE__ */ new Map();
7753
+ let inspected = 0;
7754
+ const MAX_INSPECT = 200;
7755
+ async function inspect(dir, relDir) {
7756
+ if (inspected >= MAX_INSPECT)
7757
+ return;
7758
+ let entries;
7759
+ try {
7760
+ entries = await fs14.readdir(dir);
7761
+ } catch {
7762
+ return;
7763
+ }
7764
+ for (const name of entries) {
7765
+ if (inspected >= MAX_INSPECT)
7766
+ return;
7767
+ if (name.startsWith("."))
7768
+ continue;
7769
+ if (name === "node_modules" || name === "dist" || name === "build")
7770
+ continue;
7771
+ const lang = detectLanguage(name);
7772
+ if (lang) {
7773
+ inspected += 1;
7774
+ if (!reps.has(lang))
7775
+ reps.set(lang, relDir ? `${relDir}/${name}` : name);
7776
+ }
7777
+ }
7778
+ }
7779
+ await inspect(repoRoot, "");
7780
+ let topEntries = [];
7781
+ try {
7782
+ topEntries = await fs14.readdir(repoRoot);
7783
+ } catch {
7784
+ return reps;
7785
+ }
7786
+ for (const name of topEntries) {
7787
+ if (name.startsWith("."))
7788
+ continue;
7789
+ if (name === "node_modules" || name === "dist" || name === "build")
7790
+ continue;
7791
+ const sub = join30(repoRoot, name);
7792
+ try {
7793
+ const stat7 = await fs14.stat(sub);
7794
+ if (stat7.isDirectory())
7795
+ await inspect(sub, name);
7796
+ } catch {
7797
+ }
7798
+ }
7799
+ return reps;
7800
+ }
7801
+ async function warmReposLsp(repos, workspaces, lspOverrides, isAvailable) {
7802
+ for (const repo of repos) {
7803
+ const repoRoot = repo.localPath;
7804
+ if (!repoRoot)
7805
+ continue;
7806
+ try {
7807
+ const stat7 = await fs14.stat(repoRoot);
7808
+ if (!stat7.isDirectory())
7809
+ continue;
7810
+ } catch {
7811
+ continue;
7812
+ }
7813
+ let reps;
7814
+ try {
7815
+ reps = await collectRepresentativeFiles(repoRoot);
7816
+ } catch {
7817
+ continue;
7818
+ }
7819
+ for (const [language, relFile] of reps) {
7820
+ try {
7821
+ const configs = getEffectiveConfigList(language, process.env, lspOverrides);
7822
+ const config2 = pickAvailableConfig(configs, isAvailable);
7823
+ if (!config2)
7824
+ continue;
7825
+ const session = await workspaces.getOrOpen({ repoRoot, language, config: config2 });
7826
+ await workspaces.ensureOpen(session, relFile);
7827
+ } catch (err) {
7828
+ console.warn(`[lsp-warm] ${language} warm failed for ${repoRoot}: ${err instanceof Error ? err.message : String(err)}`);
7829
+ }
7830
+ }
7831
+ }
7832
+ }
7833
+
7661
7834
  // ../listener/dist/lib/workspace-prep.js
7662
7835
  init_config_dir();
7663
- import { promises as fs14 } from "fs";
7836
+ import { promises as fs15 } from "fs";
7664
7837
  import { spawn as spawn9, execFile as execFile4 } from "child_process";
7665
7838
  import { createWriteStream as createWriteStream2 } from "fs";
7666
- import { join as join30 } from "path";
7839
+ import { join as join31 } from "path";
7667
7840
  import { promisify as promisify3 } from "util";
7668
7841
  var execFileAsync3 = promisify3(execFile4);
7669
7842
  async function isCommandOnPath2(cmd) {
@@ -7717,7 +7890,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
7717
7890
  return;
7718
7891
  let ents;
7719
7892
  try {
7720
- ents = await fs14.readdir(dir, { withFileTypes: true });
7893
+ ents = await fs15.readdir(dir, { withFileTypes: true });
7721
7894
  } catch {
7722
7895
  return;
7723
7896
  }
@@ -7727,7 +7900,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
7727
7900
  if (e.isDirectory()) {
7728
7901
  if (skip.has(e.name) || e.name.startsWith("."))
7729
7902
  continue;
7730
- await rec(join30(dir, e.name));
7903
+ await rec(join31(dir, e.name));
7731
7904
  continue;
7732
7905
  }
7733
7906
  const dot = e.name.lastIndexOf(".");
@@ -7736,7 +7909,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
7736
7909
  const ext = e.name.slice(dot);
7737
7910
  if (!C_EXTS.has(ext) && !CPP_EXTS.has(ext))
7738
7911
  continue;
7739
- sources.push({ path: join30(dir, e.name), ext });
7912
+ sources.push({ path: join31(dir, e.name), ext });
7740
7913
  }
7741
7914
  }
7742
7915
  await rec(repoRoot);
@@ -7752,10 +7925,10 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
7752
7925
  command: `${driver} ${std} -I. -I./include -c "${src}"`
7753
7926
  };
7754
7927
  });
7755
- const outDir = join30(repoRoot, ".repowise");
7756
- await fs14.mkdir(outDir, { recursive: true });
7757
- const outPath = join30(outDir, "compile_commands.json");
7758
- await fs14.writeFile(outPath, JSON.stringify(entries, null, 2));
7928
+ const outDir = join31(repoRoot, ".repowise");
7929
+ await fs15.mkdir(outDir, { recursive: true });
7930
+ const outPath = join31(outDir, "compile_commands.json");
7931
+ await fs15.writeFile(outPath, JSON.stringify(entries, null, 2));
7759
7932
  const capHit = sources.length >= MAX_STUB_SOURCES;
7760
7933
  console.log(`[workspace-prep] ${repoId}: wrote ${entries.length.toString()}-entry compile_commands stub to .repowise/${capHit ? " (cap reached \u2014 additional sources truncated)" : ""}`);
7761
7934
  return true;
@@ -7763,7 +7936,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
7763
7936
  var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
7764
7937
  async function fileExists10(repoRoot, name) {
7765
7938
  try {
7766
- await fs14.access(join30(repoRoot, name));
7939
+ await fs15.access(join31(repoRoot, name));
7767
7940
  return true;
7768
7941
  } catch {
7769
7942
  return false;
@@ -7774,7 +7947,7 @@ async function detectWorkspaceDeps(repoRoot) {
7774
7947
  if (await fileExists10(repoRoot, "package.json")) {
7775
7948
  let pkgRaw = "";
7776
7949
  try {
7777
- pkgRaw = await fs14.readFile(join30(repoRoot, "package.json"), "utf8");
7950
+ pkgRaw = await fs15.readFile(join31(repoRoot, "package.json"), "utf8");
7778
7951
  } catch {
7779
7952
  }
7780
7953
  if (pkgRaw) {
@@ -7877,8 +8050,8 @@ async function runWorkspacePreps(opts) {
7877
8050
  if (opts.missing.length === 0)
7878
8051
  return [];
7879
8052
  const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
7880
- const logPath2 = join30(getConfigDir(), `install-log.${safeRepoId}.txt`);
7881
- await fs14.mkdir(getConfigDir(), { recursive: true });
8053
+ const logPath2 = join31(getConfigDir(), `install-log.${safeRepoId}.txt`);
8054
+ await fs15.mkdir(getConfigDir(), { recursive: true });
7882
8055
  const stream = opts.logStream ?? createWriteStream2(logPath2, { flags: "a" });
7883
8056
  stream.on("error", () => {
7884
8057
  });
@@ -8765,7 +8938,7 @@ var CRASH_LOOP_WINDOW_MS = 3e4;
8765
8938
  var CRASH_LOOP_THRESHOLD = 3;
8766
8939
  async function readRawToolConfig() {
8767
8940
  try {
8768
- const configPath = join31(getConfigDir(), "config.json");
8941
+ const configPath = join32(getConfigDir(), "config.json");
8769
8942
  const data = await readFile12(configPath, "utf-8");
8770
8943
  const raw = JSON.parse(data);
8771
8944
  return {
@@ -8828,8 +9001,8 @@ function resolveAuditRoots() {
8828
9001
  const out = /* @__PURE__ */ new Set();
8829
9002
  let dir = dirname14(process.execPath);
8830
9003
  for (let i = 0; i < 8; i += 1) {
8831
- out.add(join31(dir, "node_modules"));
8832
- out.add(join31(dir, "lib", "node_modules"));
9004
+ out.add(join32(dir, "node_modules"));
9005
+ out.add(join32(dir, "lib", "node_modules"));
8833
9006
  const parent = dirname14(dir);
8834
9007
  if (parent === dir)
8835
9008
  break;
@@ -9049,7 +9222,7 @@ async function checkStaleContext(repos, state, groups) {
9049
9222
  if (group?.offline.isOffline)
9050
9223
  continue;
9051
9224
  const { statSync: statSync2, readdirSync: readdirSync2 } = await import("fs");
9052
- const contextPath = join31(repo.localPath, "repowise-context");
9225
+ const contextPath = join32(repo.localPath, "repowise-context");
9053
9226
  let isMissingOrEmpty = false;
9054
9227
  try {
9055
9228
  const s = statSync2(contextPath);
@@ -9107,7 +9280,7 @@ async function reconcileMcpConfigs(repos, packageName) {
9107
9280
  }
9108
9281
  async function reconcileAgentInstructions(repos) {
9109
9282
  for (const repo of repos) {
9110
- const path = join31(repo.localPath, "repowise-context", "project-overview.md");
9283
+ const path = join32(repo.localPath, "repowise-context", "project-overview.md");
9111
9284
  let content;
9112
9285
  try {
9113
9286
  content = await readFile12(path, "utf-8");
@@ -9169,11 +9342,11 @@ async function startListener() {
9169
9342
  }
9170
9343
  const configDir = getConfigDir();
9171
9344
  await mkdir14(configDir, { recursive: true });
9172
- const lockPath = join31(configDir, "listener.lock");
9345
+ const lockPath = join32(configDir, "listener.lock");
9173
9346
  await writeFile14(lockPath, "", { flag: "a" });
9174
9347
  let lockIsHeld = false;
9175
9348
  try {
9176
- lockIsHeld = await lockfile3.check(lockPath, { stale: 3e4, realpath: false });
9349
+ lockIsHeld = await lockfile4.check(lockPath, { stale: 3e4, realpath: false });
9177
9350
  } catch {
9178
9351
  }
9179
9352
  if (!lockIsHeld) {
@@ -9187,7 +9360,7 @@ async function startListener() {
9187
9360
  }
9188
9361
  }
9189
9362
  try {
9190
- releaseLock = await lockfile3.lock(lockPath, { stale: 3e4, realpath: false });
9363
+ releaseLock = await lockfile4.lock(lockPath, { stale: 3e4, realpath: false });
9191
9364
  } catch {
9192
9365
  console.error(`Listener already running. Stop it first with \`${true ? "repowisestage" : "repowise"} stop\`.`);
9193
9366
  process.exitCode = 1;
@@ -9212,7 +9385,7 @@ async function startListener() {
9212
9385
  return;
9213
9386
  }
9214
9387
  if (config2.repos.length === 0 && !config2.autoDiscoverRepos) {
9215
- console.error(`No repos configured. Add repos to ${join31(configDir, "config.json")}`);
9388
+ console.error(`No repos configured. Add repos to ${join32(configDir, "config.json")}`);
9216
9389
  await releaseLockAndExit();
9217
9390
  process.exitCode = 1;
9218
9391
  return;
@@ -9280,7 +9453,7 @@ async function startListener() {
9280
9453
  let currentVersion = "";
9281
9454
  try {
9282
9455
  const selfDir = dirname14(fileURLToPath3(import.meta.url));
9283
- const pkgJsonPath = join31(selfDir, "..", "..", "package.json");
9456
+ const pkgJsonPath = join32(selfDir, "..", "..", "package.json");
9284
9457
  const pkgJson = JSON.parse(await readFile12(pkgJsonPath, "utf-8"));
9285
9458
  currentVersion = pkgJson.version;
9286
9459
  } catch (err) {
@@ -9324,7 +9497,14 @@ async function startListener() {
9324
9497
  // Read at each lsp_* dispatch from the live (reconcile-refreshed)
9325
9498
  // config so `repowise lsp enable intelephense` takes effect within
9326
9499
  // the 5-min reconcile window without a listener restart.
9327
- getLspOverrides: () => config2.lspOverrides
9500
+ getLspOverrides: () => config2.lspOverrides,
9501
+ // Boot gate: when LSP is off at startup, don't construct the
9502
+ // WorkspaceManager at all (same effect as REPOWISE_LSP_DISABLED).
9503
+ lspDisabled: config2.lspEnabled === false,
9504
+ // Live dispatch gate: `repowise lsp off` mid-session takes effect at
9505
+ // the next reconcile (~5 min) without a restart. Closure over the
9506
+ // in-memory config the reconcile loop refreshes from disk.
9507
+ getLspEnabled: () => config2.lspEnabled !== false
9328
9508
  });
9329
9509
  if (mcpRuntime.server) {
9330
9510
  console.log(`[mcp] Listening at ${mcpRuntime.server.endpoint}`);
@@ -9345,6 +9525,10 @@ async function startListener() {
9345
9525
  }
9346
9526
  })();
9347
9527
  void (async () => {
9528
+ if (config2.lspEnabled === false) {
9529
+ console.log("[lsp] disabled via config (repowise lsp off) \u2014 skipping install + warm");
9530
+ return;
9531
+ }
9348
9532
  try {
9349
9533
  const lspResults = await prepareLspServersForRepos(config2.repos, {
9350
9534
  ...config2.lspOverrides ? { lspOverrides: config2.lspOverrides } : {}
@@ -9379,6 +9563,14 @@ async function startListener() {
9379
9563
  }
9380
9564
  }
9381
9565
  }
9566
+ if (config2.lspAutoWarm !== false && mcpRuntime?.lspWorkspaces) {
9567
+ try {
9568
+ await warmReposLsp(config2.repos, mcpRuntime.lspWorkspaces, config2.lspOverrides);
9569
+ console.log("[lsp] warmed language servers for watched repos");
9570
+ } catch (warmErr) {
9571
+ console.warn("[lsp] auto-warm failed:", warmErr instanceof Error ? warmErr.message : String(warmErr));
9572
+ }
9573
+ }
9382
9574
  } catch (err) {
9383
9575
  console.warn("[lsp-install] Pre-install scan failed:", err instanceof Error ? err.message : String(err));
9384
9576
  }
@@ -9516,6 +9708,27 @@ async function startListener() {
9516
9708
  console.warn(`[self-heal] Context download failed for ${addedRepo.repoId}:`, fetchErr instanceof Error ? fetchErr.message : String(fetchErr));
9517
9709
  }
9518
9710
  }
9711
+ if (config2.lspEnabled !== false) {
9712
+ void (async () => {
9713
+ try {
9714
+ const lspResults = await prepareLspServersForRepos(result.addedRepos, {
9715
+ ...config2.lspOverrides ? { lspOverrides: config2.lspOverrides } : {}
9716
+ });
9717
+ for (const r of lspResults) {
9718
+ if (r.installed) {
9719
+ console.log(`[lsp-install] (reconcile) Installed ${r.language} LSP server`);
9720
+ } else if (r.error) {
9721
+ console.warn(`[lsp-install] (reconcile) ${r.language} install failed: ${r.error}`);
9722
+ }
9723
+ }
9724
+ if (config2.lspAutoWarm !== false && mcpRuntime?.lspWorkspaces) {
9725
+ await warmReposLsp(result.addedRepos, mcpRuntime.lspWorkspaces, config2.lspOverrides);
9726
+ }
9727
+ } catch (lspErr) {
9728
+ console.warn("[lsp-install] (reconcile) install/warm failed:", lspErr instanceof Error ? lspErr.message : String(lspErr));
9729
+ }
9730
+ })();
9731
+ }
9519
9732
  }
9520
9733
  }
9521
9734
  } catch (reconcileErr) {
@@ -9663,12 +9876,12 @@ async function startListener() {
9663
9876
  } catch {
9664
9877
  }
9665
9878
  }
9666
- const credentialsPath = join31(getConfigDir(), "credentials.json");
9879
+ const credentialsPath = join32(getConfigDir(), "credentials.json");
9667
9880
  let credentialsChanged = false;
9668
9881
  let watcher = null;
9669
9882
  try {
9670
- const fs24 = await import("fs");
9671
- watcher = fs24.watch(credentialsPath, () => {
9883
+ const fs25 = await import("fs");
9884
+ watcher = fs25.watch(credentialsPath, () => {
9672
9885
  credentialsChanged = true;
9673
9886
  });
9674
9887
  } catch {
@@ -9709,7 +9922,7 @@ if (isDirectRun) {
9709
9922
 
9710
9923
  // src/lib/env.ts
9711
9924
  import { homedir as homedir6 } from "os";
9712
- import { join as join32 } from "path";
9925
+ import { join as join33 } from "path";
9713
9926
  var IS_STAGING2 = true ? true : false;
9714
9927
  var PRODUCTION = {
9715
9928
  apiUrl: "https://api.repowise.ai",
@@ -9729,7 +9942,7 @@ function getEnvConfig() {
9729
9942
  return IS_STAGING2 ? STAGING : PRODUCTION;
9730
9943
  }
9731
9944
  function getConfigDir2() {
9732
- return join32(homedir6(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
9945
+ return join33(homedir6(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
9733
9946
  }
9734
9947
  function getPackageName() {
9735
9948
  return true ? "repowisestage" : "repowise";
@@ -9740,11 +9953,11 @@ import chalk from "chalk";
9740
9953
 
9741
9954
  // src/lib/config.ts
9742
9955
  import { readFile as readFile13, writeFile as writeFile15, mkdir as mkdir15, rename as rename4, unlink as unlink9 } from "fs/promises";
9743
- import { join as join33 } from "path";
9744
- import lockfile4 from "proper-lockfile";
9956
+ import { join as join34 } from "path";
9957
+ import lockfile5 from "proper-lockfile";
9745
9958
  async function getConfig() {
9746
9959
  try {
9747
- const data = await readFile13(join33(getConfigDir2(), "config.json"), "utf-8");
9960
+ const data = await readFile13(join34(getConfigDir2(), "config.json"), "utf-8");
9748
9961
  return JSON.parse(data);
9749
9962
  } catch {
9750
9963
  return {};
@@ -9752,7 +9965,7 @@ async function getConfig() {
9752
9965
  }
9753
9966
  async function saveConfig(config2) {
9754
9967
  const dir = getConfigDir2();
9755
- const path = join33(dir, "config.json");
9968
+ const path = join34(dir, "config.json");
9756
9969
  await mkdir15(dir, { recursive: true });
9757
9970
  const tmpPath = path + ".tmp";
9758
9971
  try {
@@ -9768,7 +9981,7 @@ async function saveConfig(config2) {
9768
9981
  }
9769
9982
  async function mergeAndSaveConfig(updates) {
9770
9983
  const dir = getConfigDir2();
9771
- const path = join33(dir, "config.json");
9984
+ const path = join34(dir, "config.json");
9772
9985
  await mkdir15(dir, { recursive: true });
9773
9986
  try {
9774
9987
  await writeFile15(path, "", { flag: "a" });
@@ -9776,7 +9989,7 @@ async function mergeAndSaveConfig(updates) {
9776
9989
  }
9777
9990
  let release = null;
9778
9991
  try {
9779
- release = await lockfile4.lock(path, { stale: 1e4, retries: 3, realpath: false });
9992
+ release = await lockfile5.lock(path, { stale: 1e4, retries: 3, realpath: false });
9780
9993
  let raw = {};
9781
9994
  try {
9782
9995
  raw = JSON.parse(await readFile13(path, "utf-8"));
@@ -9839,16 +10052,16 @@ async function showWelcome(currentVersion) {
9839
10052
 
9840
10053
  // src/commands/create.ts
9841
10054
  import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
9842
- import { dirname as dirname15, join as join39 } from "path";
10055
+ import { dirname as dirname15, join as join40 } from "path";
9843
10056
  init_src();
9844
- import chalk7 from "chalk";
10057
+ import chalk8 from "chalk";
9845
10058
  import ora from "ora";
9846
10059
 
9847
10060
  // src/lib/auth.ts
9848
10061
  import { createHash as createHash4, randomBytes as randomBytes3 } from "crypto";
9849
10062
  import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir16, chmod as chmod4, unlink as unlink10 } from "fs/promises";
9850
10063
  import http from "http";
9851
- import { join as join34 } from "path";
10064
+ import { join as join35 } from "path";
9852
10065
  var CLI_CALLBACK_PORT = 19876;
9853
10066
  var CALLBACK_TIMEOUT_MS = 12e4;
9854
10067
  function getCognitoConfigForStorage() {
@@ -10014,7 +10227,7 @@ async function refreshTokens2(refreshToken) {
10014
10227
  }
10015
10228
  async function getStoredCredentials2() {
10016
10229
  try {
10017
- const credPath = join34(getConfigDir2(), "credentials.json");
10230
+ const credPath = join35(getConfigDir2(), "credentials.json");
10018
10231
  const data = await readFile14(credPath, "utf-8");
10019
10232
  return JSON.parse(data);
10020
10233
  } catch (err) {
@@ -10026,14 +10239,14 @@ async function getStoredCredentials2() {
10026
10239
  }
10027
10240
  async function storeCredentials2(credentials) {
10028
10241
  const dir = getConfigDir2();
10029
- const credPath = join34(dir, "credentials.json");
10242
+ const credPath = join35(dir, "credentials.json");
10030
10243
  await mkdir16(dir, { recursive: true, mode: 448 });
10031
10244
  await writeFile16(credPath, JSON.stringify(credentials, null, 2));
10032
10245
  await chmod4(credPath, 384);
10033
10246
  }
10034
10247
  async function clearCredentials() {
10035
10248
  try {
10036
- await unlink10(join34(getConfigDir2(), "credentials.json"));
10249
+ await unlink10(join35(getConfigDir2(), "credentials.json"));
10037
10250
  } catch (err) {
10038
10251
  if (err.code !== "ENOENT") throw err;
10039
10252
  }
@@ -10240,10 +10453,10 @@ async function selectAiTools() {
10240
10453
 
10241
10454
  // src/lib/ai-tools.ts
10242
10455
  import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir17 } from "fs/promises";
10243
- import { join as join35 } from "path";
10456
+ import { join as join36 } from "path";
10244
10457
  var REPOWISE_HOOK_MARKER = "repowise-context";
10245
10458
  async function writeClaudeSubagentHook(repoRoot, contextFolder) {
10246
- const settingsPath = join35(repoRoot, ".claude", "settings.json");
10459
+ const settingsPath = join36(repoRoot, ".claude", "settings.json");
10247
10460
  let settings = {};
10248
10461
  try {
10249
10462
  const raw = await readFile15(settingsPath, "utf-8");
@@ -10278,15 +10491,15 @@ async function writeClaudeSubagentHook(repoRoot, contextFolder) {
10278
10491
  }
10279
10492
  hooks["SubagentStart"] = subagentStart;
10280
10493
  settings["hooks"] = hooks;
10281
- await mkdir17(join35(repoRoot, ".claude"), { recursive: true });
10494
+ await mkdir17(join36(repoRoot, ".claude"), { recursive: true });
10282
10495
  await writeFile17(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
10283
10496
  }
10284
10497
 
10285
10498
  // src/lib/gitignore.ts
10286
10499
  import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
10287
- import { join as join36 } from "path";
10500
+ import { join as join37 } from "path";
10288
10501
  function ensureGitignore(repoRoot, entry) {
10289
- const gitignorePath = join36(repoRoot, ".gitignore");
10502
+ const gitignorePath = join37(repoRoot, ".gitignore");
10290
10503
  if (existsSync2(gitignorePath)) {
10291
10504
  const content = readFileSync2(gitignorePath, "utf-8");
10292
10505
  const lines = content.split("\n").map((l) => l.trim());
@@ -10852,8 +11065,8 @@ async function promptDepInstallConsent(missing, opts) {
10852
11065
  import chalk6 from "chalk";
10853
11066
 
10854
11067
  // src/lib/dep-installer.ts
10855
- import { promises as fs15 } from "fs";
10856
- import { join as join37 } from "path";
11068
+ import { promises as fs16 } from "fs";
11069
+ import { join as join38 } from "path";
10857
11070
  var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
10858
11071
  "typescript",
10859
11072
  "javascript",
@@ -10863,14 +11076,14 @@ var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
10863
11076
  ]);
10864
11077
  var exists = async (p) => {
10865
11078
  try {
10866
- await fs15.access(p);
11079
+ await fs16.access(p);
10867
11080
  return true;
10868
11081
  } catch {
10869
11082
  return false;
10870
11083
  }
10871
11084
  };
10872
11085
  async function fileExists11(repoRoot, name) {
10873
- return exists(join37(repoRoot, name));
11086
+ return exists(join38(repoRoot, name));
10874
11087
  }
10875
11088
  async function detectNodePackageManager(repoRoot) {
10876
11089
  if (await fileExists11(repoRoot, "pnpm-lock.yaml")) {
@@ -10947,13 +11160,13 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
10947
11160
  // src/lib/dep-installer-runner.ts
10948
11161
  import { spawn as spawn10 } from "child_process";
10949
11162
  import { createWriteStream as createWriteStream3 } from "fs";
10950
- import { promises as fs16 } from "fs";
10951
- import { join as join38 } from "path";
11163
+ import { promises as fs17 } from "fs";
11164
+ import { join as join39 } from "path";
10952
11165
  var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
10953
11166
  async function runMissingDepInstalls(opts) {
10954
11167
  const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
10955
- const logPath2 = join38(getConfigDir2(), `install-log.${safeRepoId}.txt`);
10956
- await fs16.mkdir(getConfigDir2(), { recursive: true });
11168
+ const logPath2 = join39(getConfigDir2(), `install-log.${safeRepoId}.txt`);
11169
+ await fs17.mkdir(getConfigDir2(), { recursive: true });
10957
11170
  const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
10958
11171
  stream.on("error", () => {
10959
11172
  });
@@ -10999,7 +11212,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
10999
11212
  }
11000
11213
  async function runPipFlow(repoRoot, stream, timeoutMs) {
11001
11214
  await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
11002
- const venvPip = process.platform === "win32" ? join38(".venv", "Scripts", "pip.exe") : join38(".venv", "bin", "pip");
11215
+ const venvPip = process.platform === "win32" ? join39(".venv", "Scripts", "pip.exe") : join39(".venv", "bin", "pip");
11003
11216
  await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
11004
11217
  }
11005
11218
  function runSimple(cmd, repoRoot, stream, timeoutMs) {
@@ -11110,6 +11323,51 @@ function reportInstallOutcomes(repoId, outcomes) {
11110
11323
  );
11111
11324
  }
11112
11325
 
11326
+ // src/lib/lsp-installer-orchestrator.ts
11327
+ init_installer();
11328
+ import chalk7 from "chalk";
11329
+ async function maybeInstallLspServers(args) {
11330
+ if (!args.repoRoot) return { installPromise: Promise.resolve([]) };
11331
+ let overrides = args.lspOverrides;
11332
+ try {
11333
+ const config2 = await getConfig();
11334
+ if (config2.lspEnabled === false) return { installPromise: Promise.resolve([]) };
11335
+ overrides = overrides ?? config2.lspOverrides;
11336
+ } catch {
11337
+ }
11338
+ const repoRoot = args.repoRoot;
11339
+ return {
11340
+ installPromise: prepareLspServersForRepos(
11341
+ [{ localPath: repoRoot }],
11342
+ overrides ? { lspOverrides: overrides } : {}
11343
+ )
11344
+ };
11345
+ }
11346
+ function reportLspInstallOutcomes(results) {
11347
+ if (results.length === 0) return;
11348
+ const installed = results.filter((r) => r.installed);
11349
+ const failed = results.filter((r) => r.error);
11350
+ const hints = results.filter((r) => !r.installed && !r.error && r.hint);
11351
+ if (installed.length > 0) {
11352
+ console.log(
11353
+ chalk7.dim(` Language servers installed: ${installed.map((r) => r.language).join(", ")}`)
11354
+ );
11355
+ }
11356
+ for (const h of hints) {
11357
+ console.log(chalk7.dim(` ${h.language}: ${h.hint ?? ""}`));
11358
+ }
11359
+ if (failed.length > 0) {
11360
+ console.log(
11361
+ chalk7.yellow(
11362
+ ` \u26A0 ${failed.length.toString()} language server(s) could not be installed (LSP features limited until resolved):`
11363
+ )
11364
+ );
11365
+ for (const f of failed) {
11366
+ console.log(chalk7.yellow(` ${f.language}: ${f.error ?? "unknown error"}`));
11367
+ }
11368
+ }
11369
+ }
11370
+
11113
11371
  // src/commands/create.ts
11114
11372
  function formatElapsed(ms) {
11115
11373
  const totalSeconds = Math.round(ms / 1e3);
@@ -11127,10 +11385,10 @@ async function create() {
11127
11385
  try {
11128
11386
  let credentials = await getValidCredentials2();
11129
11387
  if (!credentials) {
11130
- spinner.info(chalk7.yellow("Not logged in. Opening browser to authenticate..."));
11388
+ spinner.info(chalk8.yellow("Not logged in. Opening browser to authenticate..."));
11131
11389
  credentials = await performLogin();
11132
11390
  const { email } = decodeIdToken(credentials.idToken);
11133
- spinner.succeed(chalk7.green(`Authenticated as ${chalk7.bold(email)}`));
11391
+ spinner.succeed(chalk8.green(`Authenticated as ${chalk8.bold(email)}`));
11134
11392
  } else {
11135
11393
  spinner.succeed("Authenticated");
11136
11394
  }
@@ -11146,7 +11404,7 @@ async function create() {
11146
11404
  if (pending?.repoId) {
11147
11405
  repoId = pending.repoId;
11148
11406
  repoName = pending.repoName;
11149
- spinner.succeed(`Found pending repository: ${chalk7.bold(repoName)}`);
11407
+ spinner.succeed(`Found pending repository: ${chalk8.bold(repoName)}`);
11150
11408
  apiRequest("/v1/onboarding/pending", { method: "DELETE" }).catch(() => {
11151
11409
  });
11152
11410
  }
@@ -11157,10 +11415,10 @@ async function create() {
11157
11415
  try {
11158
11416
  repoRoot = detectRepoRoot();
11159
11417
  repoName = detectRepoName(repoRoot);
11160
- spinner.succeed(`Repository: ${chalk7.bold(repoName)}`);
11418
+ spinner.succeed(`Repository: ${chalk8.bold(repoName)}`);
11161
11419
  } catch {
11162
11420
  spinner.fail(
11163
- chalk7.red(
11421
+ chalk8.red(
11164
11422
  "Not in a git repository. Run this command from your repo directory, or select a repo on the dashboard first."
11165
11423
  )
11166
11424
  );
@@ -11186,10 +11444,10 @@ async function create() {
11186
11444
  }
11187
11445
  if (!repoId) {
11188
11446
  if (repoLookupError) {
11189
- spinner.fail(chalk7.red(`Failed to look up repositories: ${repoLookupError}`));
11447
+ spinner.fail(chalk8.red(`Failed to look up repositories: ${repoLookupError}`));
11190
11448
  } else {
11191
11449
  spinner.fail(
11192
- chalk7.red(
11450
+ chalk8.red(
11193
11451
  "Could not find this repository in your RepoWise account. Connect it on the dashboard first."
11194
11452
  )
11195
11453
  );
@@ -11207,11 +11465,11 @@ async function create() {
11207
11465
  const role = resolveRole(groups ?? []);
11208
11466
  const canRescan = hasPermission(role, "connectRepos");
11209
11467
  if (!canRescan) {
11210
- spinner.fail(chalk7.red("This repository already has context generated."));
11468
+ spinner.fail(chalk8.red("This repository already has context generated."));
11211
11469
  console.log(
11212
- chalk7.cyan(
11470
+ chalk8.cyan(
11213
11471
  `
11214
- As a team member, run: ${chalk7.bold("repowise member")}
11472
+ As a team member, run: ${chalk8.bold("repowise member")}
11215
11473
  This will download context and configure your AI tools.
11216
11474
  `
11217
11475
  )
@@ -11220,20 +11478,20 @@ async function create() {
11220
11478
  return;
11221
11479
  }
11222
11480
  if (pricing.allowed && pricing.isFree) {
11223
- spinner.succeed(chalk7.cyan("Free rescan available. Will trigger a full rescan."));
11481
+ spinner.succeed(chalk8.cyan("Free rescan available. Will trigger a full rescan."));
11224
11482
  useFreeRescan = true;
11225
11483
  } else if (pricing.allowed) {
11226
11484
  spinner.stop();
11227
11485
  const costText = pricing.estimatedCost && pricing.estimatedCost > 0 ? `$${pricing.estimatedCost.toFixed(2)}` : "pay-as-you-go (based on actual processing cost)";
11228
11486
  console.log(
11229
- chalk7.yellow(
11487
+ chalk8.yellow(
11230
11488
  `
11231
11489
  This repository already has context generated.
11232
- A full rescan will cost: ${chalk7.bold(costText)}`
11490
+ A full rescan will cost: ${chalk8.bold(costText)}`
11233
11491
  )
11234
11492
  );
11235
11493
  if (pricing.costWarning) {
11236
- console.log(chalk7.dim(` ${pricing.costWarning}`));
11494
+ console.log(chalk8.dim(` ${pricing.costWarning}`));
11237
11495
  }
11238
11496
  const { confirm: confirm3 } = await import("@inquirer/prompts");
11239
11497
  const proceed = await confirm3({
@@ -11241,13 +11499,13 @@ async function create() {
11241
11499
  default: false
11242
11500
  });
11243
11501
  if (!proceed) {
11244
- console.log(chalk7.dim("\n To sync recent changes, use: repowise sync\n"));
11502
+ console.log(chalk8.dim("\n To sync recent changes, use: repowise sync\n"));
11245
11503
  process.exitCode = 0;
11246
11504
  return;
11247
11505
  }
11248
11506
  useFreeRescan = true;
11249
11507
  } else {
11250
- spinner.fail(chalk7.red(pricing.reason ?? "Cannot rescan at this time."));
11508
+ spinner.fail(chalk8.red(pricing.reason ?? "Cannot rescan at this time."));
11251
11509
  process.exitCode = 1;
11252
11510
  return;
11253
11511
  }
@@ -11257,14 +11515,14 @@ async function create() {
11257
11515
  const { tools, hasOther } = await selectAiTools();
11258
11516
  if (hasOther) {
11259
11517
  console.log(
11260
- chalk7.cyan(
11518
+ chalk8.cyan(
11261
11519
  "\nFor AI tools not listed, context files still work with any tool that reads the filesystem.\nTo request full support for a new AI tool, email support@repowise.ai"
11262
11520
  )
11263
11521
  );
11264
11522
  }
11265
11523
  if (tools.length === 0 && !hasOther) {
11266
11524
  console.log(
11267
- chalk7.yellow(
11525
+ chalk8.yellow(
11268
11526
  "\nNo AI tools selected. You can configure them later with `repowise config`."
11269
11527
  )
11270
11528
  );
@@ -11301,13 +11559,19 @@ async function create() {
11301
11559
  syncId = retryResult.syncId;
11302
11560
  } else {
11303
11561
  syncId = active.syncId;
11304
- spinner.info(chalk7.cyan("Resuming existing pipeline..."));
11562
+ spinner.info(chalk8.cyan("Resuming existing pipeline..."));
11305
11563
  spinner.start();
11306
11564
  }
11307
11565
  }
11308
11566
  if (!syncId) {
11309
11567
  throw new Error("Free rescan retry did not return a syncId");
11310
11568
  }
11569
+ let graphOnly = false;
11570
+ try {
11571
+ const usage = await apiRequest("/v1/account/usage");
11572
+ graphOnly = usage.plan === "free";
11573
+ } catch {
11574
+ }
11311
11575
  let pollAttempts = 0;
11312
11576
  let pollErrors = 0;
11313
11577
  const MAX_POLL_ERRORS = 5;
@@ -11315,9 +11579,14 @@ async function create() {
11315
11579
  let depInstallShown = false;
11316
11580
  let seenAwaitingInput = false;
11317
11581
  let depInstallPromise = null;
11582
+ let lspInstallPromise = null;
11583
+ if (repoRoot) {
11584
+ const lspResult = await maybeInstallLspServers({ repoRoot, spinner });
11585
+ lspInstallPromise = lspResult.installPromise;
11586
+ }
11318
11587
  while (true) {
11319
11588
  if (++pollAttempts > MAX_POLL_ATTEMPTS) {
11320
- spinner.fail(chalk7.red("Pipeline timed out. Check dashboard for status."));
11589
+ spinner.fail(chalk8.red("Pipeline timed out. Check dashboard for status."));
11321
11590
  process.exitCode = 1;
11322
11591
  return;
11323
11592
  }
@@ -11376,10 +11645,12 @@ async function create() {
11376
11645
  spinner.succeed(
11377
11646
  `Context generation complete \u2014 ${coreCount} core + ${tailoredCount} tailored files`
11378
11647
  );
11648
+ } else if (graphOnly) {
11649
+ spinner.succeed("Knowledge graph built \u2014 MCP ready (Free plan).");
11379
11650
  } else {
11380
- spinner.warn(chalk7.yellow("Pipeline completed but no context files were generated."));
11651
+ spinner.warn(chalk8.yellow("Pipeline completed but no context files were generated."));
11381
11652
  console.log(
11382
- chalk7.yellow(
11653
+ chalk8.yellow(
11383
11654
  " This may be due to AI throttling or a parsing issue. Try running `repowise create` again."
11384
11655
  )
11385
11656
  );
@@ -11388,18 +11659,18 @@ async function create() {
11388
11659
  }
11389
11660
  if (syncResult.status === "failed") {
11390
11661
  progressRenderer.finalize();
11391
- spinner.fail(chalk7.red(`Pipeline failed: ${syncResult.error ?? "Unknown error"}`));
11662
+ spinner.fail(chalk8.red(`Pipeline failed: ${syncResult.error ?? "Unknown error"}`));
11392
11663
  process.exitCode = 1;
11393
11664
  return;
11394
11665
  }
11395
11666
  }
11396
- if (repoRoot) {
11667
+ if (repoRoot && !graphOnly) {
11397
11668
  spinner.start("Downloading context files from server...");
11398
11669
  try {
11399
11670
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
11400
11671
  const files = listResult.data?.files ?? listResult.files ?? [];
11401
11672
  if (files.length > 0) {
11402
- const contextDir = join39(repoRoot, DEFAULT_CONTEXT_FOLDER);
11673
+ const contextDir = join40(repoRoot, DEFAULT_CONTEXT_FOLDER);
11403
11674
  mkdirSync(contextDir, { recursive: true });
11404
11675
  let downloadedCount = 0;
11405
11676
  let failedCount = 0;
@@ -11413,7 +11684,7 @@ async function create() {
11413
11684
  const response = await fetch(presignedUrl);
11414
11685
  if (response.ok) {
11415
11686
  const content = await response.text();
11416
- const filePath = join39(contextDir, file.fileName);
11687
+ const filePath = join40(contextDir, file.fileName);
11417
11688
  mkdirSync(dirname15(filePath), { recursive: true });
11418
11689
  writeFileSync2(filePath, content, "utf-8");
11419
11690
  downloadedCount++;
@@ -11438,7 +11709,7 @@ async function create() {
11438
11709
  } catch (err) {
11439
11710
  const msg = err instanceof Error ? err.message : "Unknown error";
11440
11711
  spinner.warn(
11441
- chalk7.yellow(
11712
+ chalk8.yellow(
11442
11713
  `Cannot reach RepoWise servers to download context: ${msg}
11443
11714
  Files are stored on our servers (not in git). Retry when online.`
11444
11715
  )
@@ -11446,30 +11717,16 @@ Files are stored on our servers (not in git). Retry when online.`
11446
11717
  }
11447
11718
  }
11448
11719
  const contextFolder = DEFAULT_CONTEXT_FOLDER;
11449
- let graphOnly = false;
11450
- try {
11451
- const usage = await apiRequest("/v1/account/usage");
11452
- graphOnly = usage.plan === "free";
11453
- } catch {
11454
- }
11455
11720
  let contextFiles = [];
11456
11721
  if (repoRoot) {
11457
11722
  contextFiles = await scanLocalContextFiles(repoRoot, contextFolder);
11458
11723
  }
11459
- if (contextFiles.length === 0) {
11460
- if (graphOnly) {
11461
- console.log(
11462
- chalk7.cyan(
11463
- ` Knowledge graph + MCP ready (Free plan). Upgrade to Pro for AI-generated context docs.`
11464
- )
11465
- );
11466
- } else {
11467
- console.log(
11468
- chalk7.yellow(
11469
- ` No context files found in ${contextFolder}/. Try re-running \`repowise create\`.`
11470
- )
11471
- );
11472
- }
11724
+ if (contextFiles.length === 0 && !graphOnly) {
11725
+ console.log(
11726
+ chalk8.yellow(
11727
+ ` No context files found in ${contextFolder}/. Try re-running \`repowise create\`.`
11728
+ )
11729
+ );
11473
11730
  }
11474
11731
  if (repoRoot) {
11475
11732
  spinner.start("Configuring AI tools...");
@@ -11507,7 +11764,7 @@ Files are stored on our servers (not in git). Retry when online.`
11507
11764
  results.push(" Configured .claude/settings.json (SubagentStart hook)");
11508
11765
  }
11509
11766
  spinner.succeed("AI tools configured");
11510
- console.log(chalk7.dim(results.join("\n")));
11767
+ console.log(chalk8.dim(results.join("\n")));
11511
11768
  }
11512
11769
  const priorAutoInstall = await getPriorConsent(repoId);
11513
11770
  const updatedRepos = [];
@@ -11533,11 +11790,11 @@ Files are stored on our servers (not in git). Retry when online.`
11533
11790
  }
11534
11791
  if (!listenerRunning) {
11535
11792
  console.log(
11536
- chalk7.yellow(
11793
+ chalk8.yellow(
11537
11794
  "Warning: Could not start listener automatically. Run the following to enable it:"
11538
11795
  )
11539
11796
  );
11540
- console.log(chalk7.yellow(` $ repowise listen --install`));
11797
+ console.log(chalk8.yellow(` $ repowise listen --install`));
11541
11798
  }
11542
11799
  if (depInstallPromise) {
11543
11800
  const installSpinner = ora("Finalizing dependency installs...").start();
@@ -11554,47 +11811,84 @@ Files are stored on our servers (not in git). Retry when online.`
11554
11811
  );
11555
11812
  }
11556
11813
  }
11814
+ if (lspInstallPromise) {
11815
+ const LSP_INSTALL_SOFT_TIMEOUT_MS = 18e4;
11816
+ const lspSpinner = ora("Finalizing language-server setup...").start();
11817
+ let lspTimer;
11818
+ const timeoutResults = new Promise((resolve5) => {
11819
+ lspTimer = setTimeout(() => resolve5(null), LSP_INSTALL_SOFT_TIMEOUT_MS);
11820
+ });
11821
+ const lspResults = await Promise.race([lspInstallPromise, timeoutResults]);
11822
+ clearTimeout(lspTimer);
11823
+ if (lspResults === null) {
11824
+ lspSpinner.info("Language servers are finishing in the background.");
11825
+ } else {
11826
+ const installed = lspResults.filter((r) => r.installed).length;
11827
+ const failed = lspResults.filter((r) => r.error).length;
11828
+ if (failed > 0) {
11829
+ lspSpinner.warn(`${failed.toString()} language server(s) could not be installed`);
11830
+ } else {
11831
+ lspSpinner.succeed(
11832
+ installed > 0 ? `Language servers ready (${installed.toString()} installed)` : "Language servers ready"
11833
+ );
11834
+ }
11835
+ reportLspInstallOutcomes(lspResults);
11836
+ }
11837
+ }
11557
11838
  const elapsed = formatElapsed(Date.now() - startTime);
11558
11839
  console.log("");
11559
- console.log(chalk7.green.bold(` \u2728 Setup complete \u2014 ${repoName} is ready.`));
11840
+ console.log(chalk8.green.bold(` \u2728 Setup complete \u2014 ${repoName} is ready.`));
11560
11841
  if (listenerRunning) {
11561
11842
  console.log("");
11562
- console.log(chalk7.cyan(" What\u2019s running now"));
11843
+ console.log(chalk8.cyan(" What\u2019s running now"));
11563
11844
  console.log(
11564
- ` ${chalk7.green("\u2022")} The RepoWise Listener is Live \u2014 context auto-updates on every push.`
11845
+ ` ${chalk8.green("\u2022")} The RepoWise Listener is Live \u2014 context auto-updates on every push.`
11565
11846
  );
11566
11847
  console.log(
11567
- ` ${chalk7.green("\u2022")} The RepoWise MCP is Live \u2014 your AI tools can query the knowledge graph directly.`
11848
+ ` ${chalk8.green("\u2022")} The RepoWise MCP is Live \u2014 your AI tools can query the knowledge graph directly.`
11568
11849
  );
11850
+ let lspOn2 = true;
11851
+ let lspWarm2 = true;
11852
+ try {
11853
+ const cfg = await getConfig();
11854
+ lspOn2 = cfg.lspEnabled !== false;
11855
+ lspWarm2 = cfg.lspAutoWarm !== false;
11856
+ } catch {
11857
+ }
11858
+ if (lspOn2 && lspWarm2) {
11859
+ console.log(
11860
+ ` ${chalk8.green("\u2022")} Language servers are warming for instant code-intelligence answers (idle after 5 min). Turn off anytime: ${chalk8.bold("repowise lsp off")}`
11861
+ );
11862
+ }
11569
11863
  }
11570
11864
  if (graphOnly) {
11571
11865
  console.log("");
11572
- console.log(chalk7.cyan(" You\u2019re on the Free plan \u2014 knowledge graph + MCP only."));
11866
+ console.log(chalk8.cyan(" You\u2019re on the Free plan \u2014 knowledge graph + MCP only."));
11573
11867
  console.log(
11574
- chalk7.dim(" Upgrade to Pro for AI-generated context docs and auto-sync on merge.")
11868
+ chalk8.dim(" Upgrade to Pro for AI-generated context docs and auto-sync on merge.")
11575
11869
  );
11576
11870
  }
11577
11871
  console.log("");
11578
- console.log(chalk7.cyan(" Next steps"));
11872
+ console.log(chalk8.cyan(" Next steps"));
11579
11873
  console.log(
11580
- ` ${chalk7.cyan("\u2022")} Open Claude Code / Cursor and ask: "What does this repo do?"`
11874
+ ` ${chalk8.cyan("\u2022")} Open Claude Code / Cursor and ask: "What does this repo do?"`
11581
11875
  );
11582
11876
  console.log(
11583
- ` ${chalk7.cyan("\u2022")} Head to the dashboard \u2192 "Complete Onboarding" to explore quality scores and gaps.`
11877
+ ` ${chalk8.cyan("\u2022")} Head to the dashboard \u2192 "Complete Onboarding" to explore quality scores and gaps.`
11584
11878
  );
11585
- console.log(chalk7.dim(`
11879
+ console.log(chalk8.dim(`
11586
11880
  Total time: ${elapsed}`));
11587
11881
  } catch (err) {
11588
11882
  const message = err instanceof Error ? err.message : "Create failed";
11589
- spinner.fail(chalk7.red(message));
11883
+ spinner.fail(chalk8.red(message));
11590
11884
  process.exitCode = 1;
11591
11885
  }
11592
11886
  }
11593
11887
 
11594
11888
  // src/commands/member.ts
11595
11889
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
11596
- import { dirname as dirname16, join as join40, resolve, sep } from "path";
11597
- import chalk8 from "chalk";
11890
+ import { dirname as dirname16, join as join41, resolve, sep } from "path";
11891
+ import chalk9 from "chalk";
11598
11892
  import ora2 from "ora";
11599
11893
  var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
11600
11894
  function formatElapsed2(ms) {
@@ -11625,10 +11919,10 @@ async function member() {
11625
11919
  try {
11626
11920
  let credentials = await getValidCredentials2();
11627
11921
  if (!credentials) {
11628
- spinner.info(chalk8.yellow("Not logged in. Opening browser to authenticate..."));
11922
+ spinner.info(chalk9.yellow("Not logged in. Opening browser to authenticate..."));
11629
11923
  credentials = await performLogin();
11630
11924
  const { email } = decodeIdToken(credentials.idToken);
11631
- spinner.succeed(chalk8.green(`Authenticated as ${chalk8.bold(email)}`));
11925
+ spinner.succeed(chalk9.green(`Authenticated as ${chalk9.bold(email)}`));
11632
11926
  } else {
11633
11927
  spinner.succeed("Authenticated");
11634
11928
  }
@@ -11636,12 +11930,12 @@ async function member() {
11636
11930
  const usage = await apiRequest("/v1/account/usage");
11637
11931
  if (usage.plan && usage.plan !== "team") {
11638
11932
  spinner.fail(
11639
- chalk8.yellow(
11933
+ chalk9.yellow(
11640
11934
  `'repowise member' is a Team-plan feature (your account is on the ${usage.plan} plan).`
11641
11935
  )
11642
11936
  );
11643
11937
  console.log(
11644
- chalk8.dim(" The account owner sets up the repository with `repowise create`.")
11938
+ chalk9.dim(" The account owner sets up the repository with `repowise create`.")
11645
11939
  );
11646
11940
  return;
11647
11941
  }
@@ -11658,7 +11952,7 @@ async function member() {
11658
11952
  if (pending?.repoId) {
11659
11953
  repoId = pending.repoId;
11660
11954
  repoName = pending.repoName;
11661
- spinner.succeed(`Found pending repository: ${chalk8.bold(repoName)}`);
11955
+ spinner.succeed(`Found pending repository: ${chalk9.bold(repoName)}`);
11662
11956
  apiRequest("/v1/onboarding/pending", { method: "DELETE" }).catch(() => {
11663
11957
  });
11664
11958
  }
@@ -11669,10 +11963,10 @@ async function member() {
11669
11963
  try {
11670
11964
  repoRoot = detectRepoRoot();
11671
11965
  repoName = detectRepoName(repoRoot);
11672
- spinner.succeed(`Repository: ${chalk8.bold(repoName)}`);
11966
+ spinner.succeed(`Repository: ${chalk9.bold(repoName)}`);
11673
11967
  } catch {
11674
11968
  spinner.fail(
11675
- chalk8.red("Not in a git repository. Run this command from your project directory.")
11969
+ chalk9.red("Not in a git repository. Run this command from your project directory.")
11676
11970
  );
11677
11971
  process.exitCode = 1;
11678
11972
  return;
@@ -11683,15 +11977,15 @@ async function member() {
11683
11977
  const localRepoName = detectRepoName(repoRoot);
11684
11978
  if (repoName && localRepoName !== repoName && !repoName.endsWith(`/${localRepoName}`)) {
11685
11979
  spinner.warn(
11686
- chalk8.yellow(
11687
- `Pending repo is ${chalk8.bold(repoName)} but you're in ${chalk8.bold(localRepoName)}.
11980
+ chalk9.yellow(
11981
+ `Pending repo is ${chalk9.bold(repoName)} but you're in ${chalk9.bold(localRepoName)}.
11688
11982
  Make sure you're in the right project directory, or the context files will be saved here.`
11689
11983
  )
11690
11984
  );
11691
11985
  }
11692
11986
  } catch {
11693
11987
  spinner.fail(
11694
- chalk8.red(
11988
+ chalk9.red(
11695
11989
  "Please navigate to your project directory first, then run `repowise member` again."
11696
11990
  )
11697
11991
  );
@@ -11711,14 +12005,14 @@ async function member() {
11711
12005
  repoPlatform = match.platform;
11712
12006
  repoExternalId = match.externalId;
11713
12007
  if (!repoName) repoName = match.fullName;
11714
- spinner.succeed(`Repository: ${chalk8.bold(match.fullName)}`);
12008
+ spinner.succeed(`Repository: ${chalk9.bold(match.fullName)}`);
11715
12009
  }
11716
12010
  } catch {
11717
12011
  }
11718
12012
  }
11719
12013
  if (!repoId) {
11720
12014
  spinner.fail(
11721
- chalk8.red(
12015
+ chalk9.red(
11722
12016
  "This repository is not connected to your team. Ask your team admin to add it on the dashboard."
11723
12017
  )
11724
12018
  );
@@ -11731,23 +12025,23 @@ async function member() {
11731
12025
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
11732
12026
  files = listResult.data?.files ?? listResult.files ?? [];
11733
12027
  } catch {
11734
- spinner.fail(chalk8.red("Failed to check context files on server."));
12028
+ spinner.fail(chalk9.red("Failed to check context files on server."));
11735
12029
  process.exitCode = 1;
11736
12030
  return;
11737
12031
  }
11738
12032
  if (files.length === 0) {
11739
12033
  spinner.fail(
11740
- chalk8.red(
12034
+ chalk9.red(
11741
12035
  "No context files found for this repository. Your team admin needs to run the initial scan first."
11742
12036
  )
11743
12037
  );
11744
12038
  process.exitCode = 1;
11745
12039
  return;
11746
12040
  }
11747
- spinner.succeed(`Found ${chalk8.bold(files.length)} context files on server`);
12041
+ spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
11748
12042
  const { tools } = await selectAiTools();
11749
12043
  spinner.start("Downloading context files...");
11750
- const contextDir = join40(repoRoot, DEFAULT_CONTEXT_FOLDER2);
12044
+ const contextDir = join41(repoRoot, DEFAULT_CONTEXT_FOLDER2);
11751
12045
  mkdirSync2(contextDir, { recursive: true });
11752
12046
  let downloadedCount = 0;
11753
12047
  let failedCount = 0;
@@ -11823,7 +12117,7 @@ async function member() {
11823
12117
  }
11824
12118
  spinner.succeed("AI tools configured");
11825
12119
  for (const msg of configured) {
11826
- console.log(chalk8.dim(` ${msg}`));
12120
+ console.log(chalk9.dim(` ${msg}`));
11827
12121
  }
11828
12122
  }
11829
12123
  let depInstallPromise = null;
@@ -11837,6 +12131,7 @@ async function member() {
11837
12131
  });
11838
12132
  depInstallPromise = result.installPromise;
11839
12133
  }
12134
+ const lspInstallPromise = (await maybeInstallLspServers({ repoRoot, spinner })).installPromise;
11840
12135
  spinner.start("Saving configuration...");
11841
12136
  const priorAutoInstall = await getPriorConsent(repoId);
11842
12137
  const repoEntry = {
@@ -11881,54 +12176,78 @@ async function member() {
11881
12176
  );
11882
12177
  }
11883
12178
  }
12179
+ {
12180
+ const LSP_INSTALL_SOFT_TIMEOUT_MS = 18e4;
12181
+ const lspSpinner = ora2("Finalizing language-server setup...").start();
12182
+ let lspTimer;
12183
+ const timeoutResults = new Promise((resolve5) => {
12184
+ lspTimer = setTimeout(() => resolve5(null), LSP_INSTALL_SOFT_TIMEOUT_MS);
12185
+ });
12186
+ const lspResults = await Promise.race([lspInstallPromise, timeoutResults]);
12187
+ clearTimeout(lspTimer);
12188
+ if (lspResults === null) {
12189
+ lspSpinner.info("Language servers are finishing in the background.");
12190
+ } else {
12191
+ const installed = lspResults.filter((r) => r.installed).length;
12192
+ const failed = lspResults.filter((r) => r.error).length;
12193
+ if (failed > 0) {
12194
+ lspSpinner.warn(`${failed.toString()} language server(s) could not be installed`);
12195
+ } else {
12196
+ lspSpinner.succeed(
12197
+ installed > 0 ? `Language servers ready (${installed.toString()} installed)` : "Language servers ready"
12198
+ );
12199
+ }
12200
+ reportLspInstallOutcomes(lspResults);
12201
+ }
12202
+ }
11884
12203
  const elapsed = formatElapsed2(Date.now() - startTime);
11885
12204
  console.log("");
11886
- console.log(chalk8.green.bold("All done! Context downloaded and configured."));
12205
+ console.log(chalk9.green.bold("All done! Context downloaded and configured."));
11887
12206
  console.log("");
11888
- console.log(`Your AI tools now have access to project context for ${chalk8.bold(repoName)}.`);
12207
+ console.log(`Your AI tools now have access to project context for ${chalk9.bold(repoName)}.`);
11889
12208
  console.log(
11890
- `Downloaded ${chalk8.bold(downloadedCount)} context files to ./${DEFAULT_CONTEXT_FOLDER2}/`
12209
+ `Downloaded ${chalk9.bold(downloadedCount)} context files to ./${DEFAULT_CONTEXT_FOLDER2}/`
11891
12210
  );
11892
12211
  console.log("");
11893
12212
  if (listenerRunning) {
11894
12213
  console.log(
11895
- chalk8.dim(
12214
+ chalk9.dim(
11896
12215
  "The RepoWise listener is running in the background \u2014\nyour context will stay in sync automatically."
11897
12216
  )
11898
12217
  );
11899
12218
  } else {
11900
12219
  console.log(
11901
- chalk8.yellow(
12220
+ chalk9.yellow(
11902
12221
  "Could not start listener automatically. Run `repowise listen --install` to enable auto-sync."
11903
12222
  )
11904
12223
  );
11905
12224
  }
11906
12225
  console.log("");
11907
12226
  console.log(
11908
- chalk8.dim(`Head back to the dashboard and click "Complete Onboarding" to finish setup.`)
12227
+ chalk9.dim(`Head back to the dashboard and click "Complete Onboarding" to finish setup.`)
11909
12228
  );
11910
- console.log(chalk8.dim(`Total time: ${elapsed}`));
12229
+ console.log(chalk9.dim(`Total time: ${elapsed}`));
11911
12230
  } catch (err) {
11912
12231
  const message = err instanceof Error ? err.message : "Unknown error";
11913
- spinner.fail(chalk8.red(`Setup failed: ${message}`));
12232
+ spinner.fail(chalk9.red(`Setup failed: ${message}`));
11914
12233
  process.exitCode = 1;
11915
12234
  }
11916
12235
  }
11917
12236
 
11918
12237
  // src/commands/login.ts
11919
- import chalk9 from "chalk";
12238
+ import chalk10 from "chalk";
11920
12239
  import ora3 from "ora";
11921
12240
 
11922
12241
  // src/lib/tenant-graph-purge.ts
11923
- import { promises as fs17 } from "fs";
12242
+ import { promises as fs18 } from "fs";
11924
12243
  import { homedir as homedir7 } from "os";
11925
- import { join as join41 } from "path";
12244
+ import { join as join42 } from "path";
11926
12245
  async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
11927
- const graphsDir = join41(home, ".repowise", "graphs");
12246
+ const graphsDir = join42(home, ".repowise", "graphs");
11928
12247
  const result = { kept: [], removed: [] };
11929
12248
  let entries;
11930
12249
  try {
11931
- entries = await fs17.readdir(graphsDir);
12250
+ entries = await fs18.readdir(graphsDir);
11932
12251
  } catch (err) {
11933
12252
  if (err.code === "ENOENT") return result;
11934
12253
  throw err;
@@ -11942,15 +12261,15 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
11942
12261
  result.kept.push(entry);
11943
12262
  continue;
11944
12263
  }
11945
- const path = join41(graphsDir, entry);
12264
+ const path = join42(graphsDir, entry);
11946
12265
  try {
11947
- const stat7 = await fs17.lstat(path);
12266
+ const stat7 = await fs18.lstat(path);
11948
12267
  if (stat7.isSymbolicLink()) {
11949
- await fs17.unlink(path);
12268
+ await fs18.unlink(path);
11950
12269
  result.removed.push(entry);
11951
12270
  continue;
11952
12271
  }
11953
- await fs17.rm(path, { recursive: true, force: true });
12272
+ await fs18.rm(path, { recursive: true, force: true });
11954
12273
  result.removed.push(entry);
11955
12274
  } catch {
11956
12275
  }
@@ -11972,7 +12291,7 @@ async function login(options = {}) {
11972
12291
  console.log(`
11973
12292
  Open this URL in your browser to authenticate:
11974
12293
  `);
11975
- console.log(chalk9.cyan(authorizeUrl));
12294
+ console.log(chalk10.cyan(authorizeUrl));
11976
12295
  console.log(`
11977
12296
  Waiting for authentication...`);
11978
12297
  } else {
@@ -11986,7 +12305,7 @@ Waiting for authentication...`);
11986
12305
  console.log(`
11987
12306
  Could not open browser automatically. Open this URL:
11988
12307
  `);
11989
- console.log(chalk9.cyan(authorizeUrl));
12308
+ console.log(chalk10.cyan(authorizeUrl));
11990
12309
  console.log(`
11991
12310
  Waiting for authentication...`);
11992
12311
  }
@@ -12000,14 +12319,14 @@ Waiting for authentication...`);
12000
12319
  credentials.cognito = getCognitoConfigForStorage();
12001
12320
  await storeCredentials2(credentials);
12002
12321
  const { email } = decodeIdToken(credentials.idToken);
12003
- spinner.succeed(chalk9.green(`Logged in as ${chalk9.bold(email)}`));
12322
+ spinner.succeed(chalk10.green(`Logged in as ${chalk10.bold(email)}`));
12004
12323
  try {
12005
12324
  const repos = await apiRequest("/v1/repos");
12006
12325
  const validRepoIds = new Set(repos.map((r) => r.repoId));
12007
12326
  const result = await purgeForeignGraphs(validRepoIds);
12008
12327
  if (result.removed.length > 0) {
12009
12328
  console.log(
12010
- chalk9.dim(
12329
+ chalk10.dim(
12011
12330
  ` Cleaned ${result.removed.length.toString()} graph artifact(s) from a prior tenant.`
12012
12331
  )
12013
12332
  );
@@ -12016,30 +12335,30 @@ Waiting for authentication...`);
12016
12335
  }
12017
12336
  } catch (err) {
12018
12337
  const message = err instanceof Error ? err.message : "Login failed";
12019
- spinner.fail(chalk9.red(message));
12338
+ spinner.fail(chalk10.red(message));
12020
12339
  process.exitCode = 1;
12021
12340
  }
12022
12341
  }
12023
12342
 
12024
12343
  // src/commands/logout.ts
12025
- import chalk10 from "chalk";
12344
+ import chalk11 from "chalk";
12026
12345
  async function logout() {
12027
12346
  const creds = await getStoredCredentials2();
12028
12347
  if (!creds) {
12029
- console.log(chalk10.yellow("Not logged in."));
12348
+ console.log(chalk11.yellow("Not logged in."));
12030
12349
  return;
12031
12350
  }
12032
12351
  await clearCredentials();
12033
- console.log(chalk10.green("Logged out successfully."));
12352
+ console.log(chalk11.green("Logged out successfully."));
12034
12353
  }
12035
12354
 
12036
12355
  // src/commands/status.ts
12037
12356
  import { readFile as readFile16 } from "fs/promises";
12038
- import { basename as basename3, join as join42 } from "path";
12357
+ import { basename as basename3, join as join43 } from "path";
12039
12358
  async function status() {
12040
12359
  const configDir = getConfigDir2();
12041
- const STATE_PATH = join42(configDir, "listener-state.json");
12042
- const CONFIG_PATH = join42(configDir, "config.json");
12360
+ const STATE_PATH = join43(configDir, "listener-state.json");
12361
+ const CONFIG_PATH = join43(configDir, "config.json");
12043
12362
  let state = null;
12044
12363
  try {
12045
12364
  const data = await readFile16(STATE_PATH, "utf-8");
@@ -12087,8 +12406,8 @@ async function status() {
12087
12406
 
12088
12407
  // src/commands/sync.ts
12089
12408
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
12090
- import { dirname as dirname17, join as join43 } from "path";
12091
- import chalk11 from "chalk";
12409
+ import { dirname as dirname17, join as join44 } from "path";
12410
+ import chalk12 from "chalk";
12092
12411
  import ora4 from "ora";
12093
12412
  var POLL_INTERVAL_MS2 = 3e3;
12094
12413
  var MAX_POLL_ATTEMPTS2 = 7200;
@@ -12106,10 +12425,10 @@ async function sync() {
12106
12425
  try {
12107
12426
  let credentials = await getValidCredentials2();
12108
12427
  if (!credentials) {
12109
- spinner.info(chalk11.yellow("Not logged in. Opening browser to authenticate..."));
12428
+ spinner.info(chalk12.yellow("Not logged in. Opening browser to authenticate..."));
12110
12429
  credentials = await performLogin();
12111
12430
  const { email } = decodeIdToken(credentials.idToken);
12112
- spinner.succeed(chalk11.green(`Authenticated as ${chalk11.bold(email)}`));
12431
+ spinner.succeed(chalk12.green(`Authenticated as ${chalk12.bold(email)}`));
12113
12432
  } else {
12114
12433
  spinner.succeed("Authenticated");
12115
12434
  }
@@ -12119,10 +12438,10 @@ async function sync() {
12119
12438
  try {
12120
12439
  repoRoot = detectRepoRoot();
12121
12440
  repoName = detectRepoName(repoRoot);
12122
- spinner.succeed(`Repository: ${chalk11.bold(repoName)}`);
12441
+ spinner.succeed(`Repository: ${chalk12.bold(repoName)}`);
12123
12442
  } catch {
12124
12443
  spinner.fail(
12125
- chalk11.red("Not in a git repository. Run this command from your repo directory.")
12444
+ chalk12.red("Not in a git repository. Run this command from your repo directory.")
12126
12445
  );
12127
12446
  process.exitCode = 1;
12128
12447
  return;
@@ -12145,10 +12464,10 @@ async function sync() {
12145
12464
  }
12146
12465
  if (!repoId) {
12147
12466
  if (repoLookupError) {
12148
- spinner.fail(chalk11.red(`Failed to look up repositories: ${repoLookupError}`));
12467
+ spinner.fail(chalk12.red(`Failed to look up repositories: ${repoLookupError}`));
12149
12468
  } else {
12150
12469
  spinner.fail(
12151
- chalk11.red(
12470
+ chalk12.red(
12152
12471
  "Could not find this repository in your RepoWise account. Run `repowise create` first."
12153
12472
  )
12154
12473
  );
@@ -12186,7 +12505,7 @@ async function sync() {
12186
12505
  syncId = retryResult.syncId;
12187
12506
  } else {
12188
12507
  syncId = active.syncId;
12189
- spinner.info(chalk11.cyan("Resuming existing sync..."));
12508
+ spinner.info(chalk12.cyan("Resuming existing sync..."));
12190
12509
  spinner.start();
12191
12510
  }
12192
12511
  }
@@ -12194,7 +12513,7 @@ async function sync() {
12194
12513
  const progressRenderer = new ProgressRenderer();
12195
12514
  while (true) {
12196
12515
  if (++pollAttempts > MAX_POLL_ATTEMPTS2) {
12197
- spinner.fail(chalk11.red("Sync timed out. Check dashboard for status."));
12516
+ spinner.fail(chalk12.red("Sync timed out. Check dashboard for status."));
12198
12517
  process.exitCode = 1;
12199
12518
  return;
12200
12519
  }
@@ -12218,15 +12537,15 @@ async function sync() {
12218
12537
  const generatedFiles = syncResult.filesGenerated ?? [];
12219
12538
  const fileCount = generatedFiles.length;
12220
12539
  if (fileCount > 0) {
12221
- spinner.succeed(chalk11.green(`Incremental update complete \u2014 ${fileCount} files updated`));
12540
+ spinner.succeed(chalk12.green(`Incremental update complete \u2014 ${fileCount} files updated`));
12222
12541
  } else {
12223
- spinner.succeed(chalk11.green("Incremental sync complete \u2014 no files needed updating"));
12542
+ spinner.succeed(chalk12.green("Incremental sync complete \u2014 no files needed updating"));
12224
12543
  }
12225
12544
  break;
12226
12545
  }
12227
12546
  if (syncResult.status === "failed") {
12228
12547
  progressRenderer.finalize();
12229
- spinner.fail(chalk11.red(`Sync failed: ${syncResult.error ?? "Unknown error"}`));
12548
+ spinner.fail(chalk12.red(`Sync failed: ${syncResult.error ?? "Unknown error"}`));
12230
12549
  process.exitCode = 1;
12231
12550
  return;
12232
12551
  }
@@ -12236,7 +12555,7 @@ async function sync() {
12236
12555
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
12237
12556
  const files = listResult.data?.files ?? listResult.files ?? [];
12238
12557
  if (files.length > 0) {
12239
- const contextDir = join43(repoRoot, DEFAULT_CONTEXT_FOLDER3);
12558
+ const contextDir = join44(repoRoot, DEFAULT_CONTEXT_FOLDER3);
12240
12559
  mkdirSync3(contextDir, { recursive: true });
12241
12560
  let downloadedCount = 0;
12242
12561
  let failedCount = 0;
@@ -12250,7 +12569,7 @@ async function sync() {
12250
12569
  const response = await fetch(presignedUrl);
12251
12570
  if (response.ok) {
12252
12571
  const content = await response.text();
12253
- const filePath = join43(contextDir, file.fileName);
12572
+ const filePath = join44(contextDir, file.fileName);
12254
12573
  mkdirSync3(dirname17(filePath), { recursive: true });
12255
12574
  writeFileSync4(filePath, content, "utf-8");
12256
12575
  downloadedCount++;
@@ -12306,7 +12625,7 @@ async function sync() {
12306
12625
  }
12307
12626
  } catch (err) {
12308
12627
  const msg = err instanceof Error ? err.message : "Unknown error";
12309
- spinner.warn(chalk11.yellow(`Could not download context files: ${msg}
12628
+ spinner.warn(chalk12.yellow(`Could not download context files: ${msg}
12310
12629
  Retry when online.`));
12311
12630
  }
12312
12631
  if (repoRoot && repoId) {
@@ -12327,11 +12646,11 @@ Retry when online.`));
12327
12646
  }
12328
12647
  }
12329
12648
  const elapsed = formatElapsed3(Date.now() - startTime);
12330
- console.log(chalk11.dim(`
12649
+ console.log(chalk12.dim(`
12331
12650
  Total time: ${elapsed}`));
12332
12651
  } catch (err) {
12333
12652
  const message = err instanceof Error ? err.message : "Sync failed";
12334
- spinner.fail(chalk11.red(message));
12653
+ spinner.fail(chalk12.red(message));
12335
12654
  process.exitCode = 1;
12336
12655
  }
12337
12656
  }
@@ -12414,7 +12733,7 @@ async function stop2() {
12414
12733
  }
12415
12734
 
12416
12735
  // src/commands/config.ts
12417
- import chalk12 from "chalk";
12736
+ import chalk13 from "chalk";
12418
12737
  import ora5 from "ora";
12419
12738
  import { select } from "@inquirer/prompts";
12420
12739
  async function config() {
@@ -12422,10 +12741,10 @@ async function config() {
12422
12741
  try {
12423
12742
  let credentials = await getValidCredentials2();
12424
12743
  if (!credentials) {
12425
- spinner.info(chalk12.yellow("Not logged in. Opening browser to authenticate..."));
12744
+ spinner.info(chalk13.yellow("Not logged in. Opening browser to authenticate..."));
12426
12745
  credentials = await performLogin();
12427
12746
  const { email } = decodeIdToken(credentials.idToken);
12428
- spinner.succeed(chalk12.green(`Authenticated as ${chalk12.bold(email)}`));
12747
+ spinner.succeed(chalk13.green(`Authenticated as ${chalk13.bold(email)}`));
12429
12748
  } else {
12430
12749
  spinner.succeed("Authenticated");
12431
12750
  }
@@ -12433,7 +12752,7 @@ async function config() {
12433
12752
  const repos = await apiRequest("/v1/repos");
12434
12753
  spinner.stop();
12435
12754
  if (repos.length === 0) {
12436
- console.log(chalk12.yellow("No repositories connected. Run `repowise create` first."));
12755
+ console.log(chalk13.yellow("No repositories connected. Run `repowise create` first."));
12437
12756
  return;
12438
12757
  }
12439
12758
  const repoId = await select({
@@ -12447,10 +12766,10 @@ async function config() {
12447
12766
  const currentDelivery = repo.deliveryMode ?? "direct";
12448
12767
  const currentBranch = repo.monitoredBranch ?? repo.defaultBranch;
12449
12768
  console.log("");
12450
- console.log(chalk12.bold(`Settings for ${repo.fullName}`));
12451
- console.log(chalk12.dim(` Context storage: RepoWise servers`));
12452
- console.log(chalk12.dim(` Delivery mode: ${currentDelivery}`));
12453
- console.log(chalk12.dim(` Monitored branch: ${currentBranch}`));
12769
+ console.log(chalk13.bold(`Settings for ${repo.fullName}`));
12770
+ console.log(chalk13.dim(` Context storage: RepoWise servers`));
12771
+ console.log(chalk13.dim(` Delivery mode: ${currentDelivery}`));
12772
+ console.log(chalk13.dim(` Monitored branch: ${currentBranch}`));
12454
12773
  console.log("");
12455
12774
  const setting = await select({
12456
12775
  message: "What would you like to change?",
@@ -12470,7 +12789,7 @@ async function config() {
12470
12789
  default: currentDelivery
12471
12790
  });
12472
12791
  if (newMode === currentDelivery) {
12473
- console.log(chalk12.dim("No change."));
12792
+ console.log(chalk13.dim("No change."));
12474
12793
  return;
12475
12794
  }
12476
12795
  patch.deliveryMode = newMode;
@@ -12481,7 +12800,7 @@ async function config() {
12481
12800
  default: currentBranch
12482
12801
  });
12483
12802
  if (newBranch === currentBranch) {
12484
- console.log(chalk12.dim("No change."));
12803
+ console.log(chalk13.dim("No change."));
12485
12804
  return;
12486
12805
  }
12487
12806
  patch.monitoredBranch = newBranch;
@@ -12491,11 +12810,11 @@ async function config() {
12491
12810
  method: "PATCH",
12492
12811
  body: JSON.stringify(patch)
12493
12812
  });
12494
- spinner.succeed(chalk12.green("Setting updated"));
12813
+ spinner.succeed(chalk13.green("Setting updated"));
12495
12814
  } catch (err) {
12496
12815
  spinner.stop();
12497
12816
  const message = err instanceof Error ? err.message : "Config failed";
12498
- console.error(chalk12.red(message));
12817
+ console.error(chalk13.red(message));
12499
12818
  process.exitCode = 1;
12500
12819
  }
12501
12820
  }
@@ -12503,7 +12822,7 @@ async function config() {
12503
12822
  // src/commands/mcp-log.ts
12504
12823
  import { createDecipheriv as createDecipheriv2 } from "crypto";
12505
12824
  import { mkdir as mkdir18, readFile as readFile17, stat as stat6, writeFile as writeFile18 } from "fs/promises";
12506
- import { dirname as dirname18, join as join44 } from "path";
12825
+ import { dirname as dirname18, join as join45 } from "path";
12507
12826
  var FLAG_FILE = "mcp-log.flag";
12508
12827
  var LOG_FILE = "mcp-log.jsonl.enc";
12509
12828
  var KEY_FILE = "mcp-log.key";
@@ -12511,10 +12830,10 @@ var ENDPOINT_FILE = "listener.endpoint";
12511
12830
  var IV_BYTES2 = 12;
12512
12831
  var TAG_BYTES2 = 16;
12513
12832
  function flagPath() {
12514
- return join44(getConfigDir2(), FLAG_FILE);
12833
+ return join45(getConfigDir2(), FLAG_FILE);
12515
12834
  }
12516
12835
  function logPath() {
12517
- return join44(getConfigDir2(), LOG_FILE);
12836
+ return join45(getConfigDir2(), LOG_FILE);
12518
12837
  }
12519
12838
  async function writeFlag(flag) {
12520
12839
  const path = flagPath();
@@ -12555,14 +12874,14 @@ async function trySendConsentToServer() {
12555
12874
  let apiUrl = null;
12556
12875
  let token = null;
12557
12876
  try {
12558
- const body = await readFile17(join44(getConfigDir2(), "config.json"), "utf-8");
12877
+ const body = await readFile17(join45(getConfigDir2(), "config.json"), "utf-8");
12559
12878
  const parsed = JSON.parse(body);
12560
12879
  apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
12561
12880
  } catch {
12562
12881
  return false;
12563
12882
  }
12564
12883
  try {
12565
- const body = await readFile17(join44(getConfigDir2(), "credentials.json"), "utf-8");
12884
+ const body = await readFile17(join45(getConfigDir2(), "credentials.json"), "utf-8");
12566
12885
  const parsed = JSON.parse(body);
12567
12886
  token = parsed.idToken ?? null;
12568
12887
  } catch {
@@ -12632,7 +12951,7 @@ async function mcpLogStatus() {
12632
12951
  process.stderr.write("Log size: no file yet\n");
12633
12952
  }
12634
12953
  try {
12635
- const endpointBody = await readFile17(join44(getConfigDir2(), ENDPOINT_FILE), "utf-8");
12954
+ const endpointBody = await readFile17(join45(getConfigDir2(), ENDPOINT_FILE), "utf-8");
12636
12955
  const match = /endpoint=([^\n]+)/.exec(endpointBody);
12637
12956
  process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
12638
12957
  `);
@@ -12663,7 +12982,7 @@ async function mcpLogViewingFlags(flags = {}) {
12663
12982
  const key = await readKey();
12664
12983
  if (!key) {
12665
12984
  process.stderr.write(
12666
- `No encryption key at ${join44(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
12985
+ `No encryption key at ${join45(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
12667
12986
  `
12668
12987
  );
12669
12988
  return;
@@ -12739,7 +13058,7 @@ async function mcpLogViewingFlags(flags = {}) {
12739
13058
  }
12740
13059
  async function readKey() {
12741
13060
  try {
12742
- const body = await readFile17(join44(getConfigDir2(), KEY_FILE), "utf-8");
13061
+ const body = await readFile17(join45(getConfigDir2(), KEY_FILE), "utf-8");
12743
13062
  const parsed = Buffer.from(body.trim(), "base64");
12744
13063
  if (parsed.length !== 32) return null;
12745
13064
  return parsed;
@@ -12779,11 +13098,11 @@ async function mcpLog(subcommand, flags = {}) {
12779
13098
  }
12780
13099
 
12781
13100
  // src/commands/query/_shared.ts
12782
- import chalk13 from "chalk";
13101
+ import chalk14 from "chalk";
12783
13102
 
12784
13103
  // src/lib/graph-loader.ts
12785
- import { promises as fs18 } from "fs";
12786
- import { join as join45, resolve as resolve2 } from "path";
13104
+ import { promises as fs19 } from "fs";
13105
+ import { join as join46, resolve as resolve2 } from "path";
12787
13106
  import { gunzipSync } from "zlib";
12788
13107
  var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
12789
13108
  var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
@@ -12800,8 +13119,8 @@ var GraphNotFoundError = class extends Error {
12800
13119
  var cache = /* @__PURE__ */ new Map();
12801
13120
  async function loadGraph(repoRoot = process.cwd()) {
12802
13121
  const root = resolve2(repoRoot);
12803
- const gzPath = join45(root, GZIPPED_GRAPH_PATH);
12804
- const plainPath = join45(root, RELATIVE_GRAPH_PATH);
13122
+ const gzPath = join46(root, GZIPPED_GRAPH_PATH);
13123
+ const plainPath = join46(root, RELATIVE_GRAPH_PATH);
12805
13124
  const cached = cache.get(root);
12806
13125
  if (cached) {
12807
13126
  return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
@@ -12809,14 +13128,14 @@ async function loadGraph(repoRoot = process.cwd()) {
12809
13128
  let graphPath = null;
12810
13129
  let raw = null;
12811
13130
  try {
12812
- raw = await fs18.readFile(gzPath);
13131
+ raw = await fs19.readFile(gzPath);
12813
13132
  graphPath = gzPath;
12814
13133
  } catch (err) {
12815
13134
  if (err.code !== "ENOENT") throw err;
12816
13135
  }
12817
13136
  if (!raw) {
12818
13137
  try {
12819
- raw = await fs18.readFile(plainPath);
13138
+ raw = await fs19.readFile(plainPath);
12820
13139
  graphPath = plainPath;
12821
13140
  } catch (err) {
12822
13141
  if (err.code === "ENOENT") {
@@ -13019,7 +13338,7 @@ async function loadService() {
13019
13338
  return createGraphQueryService(graph);
13020
13339
  } catch (err) {
13021
13340
  if (err instanceof GraphNotFoundError) {
13022
- process.stderr.write(chalk13.red(`\u2717 ${err.message}
13341
+ process.stderr.write(chalk14.red(`\u2717 ${err.message}
13023
13342
  `));
13024
13343
  process.exit(err.exitCode);
13025
13344
  }
@@ -13215,14 +13534,14 @@ function registerQueryCommand(program2) {
13215
13534
  }
13216
13535
 
13217
13536
  // src/commands/uninstall.ts
13218
- import { promises as fs22 } from "fs";
13537
+ import { promises as fs23 } from "fs";
13219
13538
  import { homedir as homedir9 } from "os";
13220
- import { join as join49 } from "path";
13221
- import chalk14 from "chalk";
13539
+ import { join as join50 } from "path";
13540
+ import chalk15 from "chalk";
13222
13541
 
13223
13542
  // src/lib/cleanup/marker-blocks.ts
13224
- import { promises as fs19 } from "fs";
13225
- import { join as join46 } from "path";
13543
+ import { promises as fs20 } from "fs";
13544
+ import { join as join47 } from "path";
13226
13545
  var MARKER_START = "<!-- repowise-start -->";
13227
13546
  var MARKER_END = "<!-- repowise-end -->";
13228
13547
  var CONTEXT_FILES = [
@@ -13238,7 +13557,7 @@ var CONTEXT_FILES = [
13238
13557
  async function stripMarkerBlock(filePath) {
13239
13558
  let raw;
13240
13559
  try {
13241
- raw = await fs19.readFile(filePath, "utf-8");
13560
+ raw = await fs20.readFile(filePath, "utf-8");
13242
13561
  } catch (err) {
13243
13562
  if (err.code === "ENOENT")
13244
13563
  return { path: filePath, status: "missing" };
@@ -13253,16 +13572,16 @@ async function stripMarkerBlock(filePath) {
13253
13572
  const after = raw.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
13254
13573
  const stripped = (before + (before && after ? "\n\n" : "") + after).trim();
13255
13574
  if (stripped.length === 0) {
13256
- await fs19.unlink(filePath);
13575
+ await fs20.unlink(filePath);
13257
13576
  return { path: filePath, status: "deleted" };
13258
13577
  }
13259
- await fs19.writeFile(filePath, stripped + "\n", "utf-8");
13578
+ await fs20.writeFile(filePath, stripped + "\n", "utf-8");
13260
13579
  return { path: filePath, status: "stripped" };
13261
13580
  }
13262
13581
  async function stripAllMarkerBlocks(repoRoot) {
13263
13582
  const out = [];
13264
13583
  for (const relative of CONTEXT_FILES) {
13265
- const full = join46(repoRoot, relative);
13584
+ const full = join47(repoRoot, relative);
13266
13585
  const result = await stripMarkerBlock(full).catch((err) => ({
13267
13586
  path: full,
13268
13587
  status: "untouched",
@@ -13274,25 +13593,25 @@ async function stripAllMarkerBlocks(repoRoot) {
13274
13593
  }
13275
13594
 
13276
13595
  // src/lib/cleanup/mcp-configs.ts
13277
- import { promises as fs20 } from "fs";
13278
- import { join as join47 } from "path";
13596
+ import { promises as fs21 } from "fs";
13597
+ import { join as join48 } from "path";
13279
13598
  function mcpConfigPaths(repoRoot, home) {
13280
13599
  return [
13281
- join47(repoRoot, ".mcp.json"),
13282
- join47(repoRoot, ".cursor", "mcp.json"),
13283
- join47(repoRoot, ".vscode", "mcp.json"),
13284
- join47(repoRoot, ".roo", "mcp.json"),
13285
- join47(home, ".cline", "mcp.json"),
13286
- join47(home, ".codeium", "windsurf", "mcp_config.json"),
13287
- join47(home, ".gemini", "settings.json"),
13288
- join47(home, ".codex", "mcp.json"),
13289
- join47(home, ".roo", "mcp.json")
13600
+ join48(repoRoot, ".mcp.json"),
13601
+ join48(repoRoot, ".cursor", "mcp.json"),
13602
+ join48(repoRoot, ".vscode", "mcp.json"),
13603
+ join48(repoRoot, ".roo", "mcp.json"),
13604
+ join48(home, ".cline", "mcp.json"),
13605
+ join48(home, ".codeium", "windsurf", "mcp_config.json"),
13606
+ join48(home, ".gemini", "settings.json"),
13607
+ join48(home, ".codex", "mcp.json"),
13608
+ join48(home, ".roo", "mcp.json")
13290
13609
  ];
13291
13610
  }
13292
13611
  async function removeRepowiseFromConfig(path, serverName) {
13293
13612
  let raw;
13294
13613
  try {
13295
- raw = await fs20.readFile(path, "utf-8");
13614
+ raw = await fs21.readFile(path, "utf-8");
13296
13615
  } catch (err) {
13297
13616
  if (err.code === "ENOENT") return { path, status: "not-found" };
13298
13617
  return { path, status: "error", error: err.message };
@@ -13312,7 +13631,7 @@ async function removeRepowiseFromConfig(path, serverName) {
13312
13631
  } else {
13313
13632
  next.mcpServers = servers;
13314
13633
  }
13315
- await fs20.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
13634
+ await fs21.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
13316
13635
  return { path, status: "removed" };
13317
13636
  }
13318
13637
  async function removeAllMcpEntries(repoRoot, home, repoId) {
@@ -13325,17 +13644,17 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
13325
13644
  }
13326
13645
 
13327
13646
  // src/lib/cleanup/local-state.ts
13328
- import { promises as fs21 } from "fs";
13647
+ import { promises as fs22 } from "fs";
13329
13648
  import { homedir as homedir8 } from "os";
13330
- import { join as join48, resolve as resolve3 } from "path";
13649
+ import { join as join49, resolve as resolve3 } from "path";
13331
13650
  async function clearLocalState(homeOverride) {
13332
13651
  const home = homeOverride ?? homedir8();
13333
- const target = resolve3(join48(home, ".repowise"));
13652
+ const target = resolve3(join49(home, ".repowise"));
13334
13653
  if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
13335
13654
  return { path: target, status: "error", error: "refused: not under home" };
13336
13655
  }
13337
13656
  try {
13338
- await fs21.rm(target, { recursive: true, force: false });
13657
+ await fs22.rm(target, { recursive: true, force: false });
13339
13658
  return { path: target, status: "removed" };
13340
13659
  } catch (err) {
13341
13660
  if (err.code === "ENOENT")
@@ -13374,7 +13693,7 @@ async function uninstall2(opts = {}) {
13374
13693
  else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
13375
13694
  if (tier === "stop") return report;
13376
13695
  try {
13377
- await fs22.unlink(join49(home, ".repowise", "credentials.json"));
13696
+ await fs23.unlink(join50(home, ".repowise", "credentials.json"));
13378
13697
  report.removed.push("credentials");
13379
13698
  } catch (err) {
13380
13699
  if (err.code !== "ENOENT") {
@@ -13401,7 +13720,7 @@ async function uninstall2(opts = {}) {
13401
13720
  const allPaths = mcpConfigPaths(repoRoot, home);
13402
13721
  for (const p of allPaths) {
13403
13722
  try {
13404
- await fs22.access(p);
13723
+ await fs23.access(p);
13405
13724
  } catch {
13406
13725
  }
13407
13726
  }
@@ -13413,7 +13732,7 @@ async function uninstall2(opts = {}) {
13413
13732
  }
13414
13733
  async function defaultLoadRepoIds(home) {
13415
13734
  try {
13416
- const raw = await fs22.readFile(join49(home, ".repowise", "config.json"), "utf-8");
13735
+ const raw = await fs23.readFile(join50(home, ".repowise", "config.json"), "utf-8");
13417
13736
  const parsed = JSON.parse(raw);
13418
13737
  return (parsed.repos ?? []).map((r) => r.repoId);
13419
13738
  } catch {
@@ -13430,29 +13749,29 @@ async function uninstallCommand(opts = {}) {
13430
13749
  default: false
13431
13750
  });
13432
13751
  if (!proceed) {
13433
- process.stderr.write(chalk14.yellow("Uninstall cancelled.\n"));
13752
+ process.stderr.write(chalk15.yellow("Uninstall cancelled.\n"));
13434
13753
  process.exitCode = 1;
13435
13754
  return;
13436
13755
  }
13437
13756
  }
13438
13757
  }
13439
- process.stderr.write(chalk14.bold(`RepoWise ${tier}
13758
+ process.stderr.write(chalk15.bold(`RepoWise ${tier}
13440
13759
  `));
13441
13760
  const report = await uninstall2({ ...opts, tier });
13442
13761
  for (const p of report.removed) {
13443
- process.stderr.write(chalk14.green(` \u2713 removed: ${p}
13762
+ process.stderr.write(chalk15.green(` \u2713 removed: ${p}
13444
13763
  `));
13445
13764
  }
13446
13765
  for (const p of report.preserved) {
13447
- process.stderr.write(chalk14.gray(` \xB7 preserved: ${p}
13766
+ process.stderr.write(chalk15.gray(` \xB7 preserved: ${p}
13448
13767
  `));
13449
13768
  }
13450
13769
  for (const s of report.skipped) {
13451
- process.stderr.write(chalk14.yellow(` ! skipped: ${s.path} (${s.reason})
13770
+ process.stderr.write(chalk15.yellow(` ! skipped: ${s.path} (${s.reason})
13452
13771
  `));
13453
13772
  }
13454
13773
  process.stderr.write(
13455
- chalk14.bold(`
13774
+ chalk15.bold(`
13456
13775
  Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
13457
13776
  `)
13458
13777
  );
@@ -13460,12 +13779,12 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
13460
13779
 
13461
13780
  // src/commands/mcp-shim.ts
13462
13781
  init_config_dir();
13463
- import { promises as fs23 } from "fs";
13782
+ import { promises as fs24 } from "fs";
13464
13783
  import { createInterface as createInterface2 } from "readline";
13465
- import { join as join50 } from "path";
13784
+ import { join as join51 } from "path";
13466
13785
  var DEFAULT_MAX = 200 * 1024;
13467
13786
  async function mcpShim(opts) {
13468
- const endpointPath = opts.endpointFile ?? join50(getConfigDir(), "listener.endpoint");
13787
+ const endpointPath = opts.endpointFile ?? join51(getConfigDir(), "listener.endpoint");
13469
13788
  const stdin = opts.stdin ?? process.stdin;
13470
13789
  const stdout = opts.stdout ?? process.stdout;
13471
13790
  const stderr = opts.stderr ?? process.stderr;
@@ -13538,7 +13857,7 @@ async function mcpShim(opts) {
13538
13857
  }
13539
13858
  async function readEndpoint(path) {
13540
13859
  try {
13541
- const raw = (await fs23.readFile(path, "utf-8")).trim();
13860
+ const raw = (await fs24.readFile(path, "utf-8")).trim();
13542
13861
  if (!raw) return null;
13543
13862
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
13544
13863
  return { endpoint: raw.split("\n")[0].trim(), secret: null };
@@ -13780,7 +14099,7 @@ init_coursier_installer();
13780
14099
  init_toolchain_installer();
13781
14100
  import { spawn as spawn11 } from "child_process";
13782
14101
  import { resolve as resolve4 } from "path";
13783
- import chalk15 from "chalk";
14102
+ import chalk16 from "chalk";
13784
14103
  async function isOnPath(command) {
13785
14104
  if (/[^\w./+-]/.test(command)) return false;
13786
14105
  const isWin = process.platform === "win32";
@@ -13798,14 +14117,14 @@ async function isOnPath(command) {
13798
14117
  async function lspDoctor() {
13799
14118
  const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
13800
14119
  if (noColor) {
13801
- chalk15.level = 0;
14120
+ chalk16.level = 0;
13802
14121
  }
13803
- const okGlyph = noColor ? "[OK]" : chalk15.green("\u2713");
13804
- const missingGlyph = noColor ? "[MISSING]" : chalk15.yellow("\u2717");
13805
- console.log(chalk15.bold("RepoWise LSP doctor"));
13806
- console.log(chalk15.dim("Probing PATH for language servers used by the listener."));
14122
+ const okGlyph = noColor ? "[OK]" : chalk16.green("\u2713");
14123
+ const missingGlyph = noColor ? "[MISSING]" : chalk16.yellow("\u2717");
14124
+ console.log(chalk16.bold("RepoWise LSP doctor"));
14125
+ console.log(chalk16.dim("Probing PATH for language servers used by the listener."));
13807
14126
  console.log(
13808
- chalk15.dim(
14127
+ chalk16.dim(
13809
14128
  "Type-aware resolution covers 9 languages: Go, Python, Rust, Java, Ruby, Dart, Kotlin, PHP, Scala (Phase 7L + 7L++ + 7L+)."
13810
14129
  )
13811
14130
  );
@@ -13837,21 +14156,21 @@ async function lspDoctor() {
13837
14156
  const missing = reports.filter((r) => r.status === "missing").length;
13838
14157
  for (const r of reports) {
13839
14158
  const head = r.status === "found" ? okGlyph : missingGlyph;
13840
- const cmd = r.command ? chalk15.cyan(r.command) : chalk15.dim(r.candidates.join(" / "));
14159
+ const cmd = r.command ? chalk16.cyan(r.command) : chalk16.dim(r.candidates.join(" / "));
13841
14160
  const effectiveConfigs = getEffectiveConfigList(r.language, process.env, lspOverrides);
13842
14161
  const method = describeInstallMethod(effectiveConfigs);
13843
- console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${chalk15.dim(`[${method}]`)}`);
14162
+ console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${chalk16.dim(`[${method}]`)}`);
13844
14163
  if (r.status === "missing" && r.hint) {
13845
- console.log(` ${chalk15.dim("install:")} ${r.hint}`);
14164
+ console.log(` ${chalk16.dim("install:")} ${r.hint}`);
13846
14165
  }
13847
14166
  }
13848
14167
  console.log();
13849
14168
  console.log(
13850
- `${chalk15.green(found.toString())} found, ${chalk15.yellow(missing.toString())} missing of ${reports.length.toString()} languages.`
14169
+ `${chalk16.green(found.toString())} found, ${chalk16.yellow(missing.toString())} missing of ${reports.length.toString()} languages.`
13851
14170
  );
13852
14171
  if (missing > 0) {
13853
14172
  console.log(
13854
- chalk15.dim(
14173
+ chalk16.dim(
13855
14174
  "Missing servers degrade LSP-backed MCP tools to AST-only fallback. Run `repowise lsp install` to auto-install."
13856
14175
  )
13857
14176
  );
@@ -13868,15 +14187,15 @@ function describeInstallMethod(configs) {
13868
14187
  }
13869
14188
  async function lspInstall(language) {
13870
14189
  const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
13871
- if (noColor) chalk15.level = 0;
13872
- console.log(chalk15.bold("RepoWise LSP install"));
14190
+ if (noColor) chalk16.level = 0;
14191
+ console.log(chalk16.bold("RepoWise LSP install"));
13873
14192
  const cliConfig = await getConfig();
13874
14193
  const lspOverrides = cliConfig.lspOverrides;
13875
14194
  const targets = language ? [language] : Object.keys(LSP_REGISTRY);
13876
14195
  for (const lang of targets) {
13877
14196
  const configs = getEffectiveConfigList(lang, process.env, lspOverrides);
13878
14197
  if (!configs || configs.length === 0) {
13879
- console.log(` ${chalk15.red("\u2717")} ${lang} ${chalk15.dim("(unknown language)")}`);
14198
+ console.log(` ${chalk16.red("\u2717")} ${lang} ${chalk16.dim("(unknown language)")}`);
13880
14199
  continue;
13881
14200
  }
13882
14201
  const result = await installOneLanguage(configs);
@@ -13944,11 +14263,11 @@ async function installOneLanguage(configs) {
13944
14263
  };
13945
14264
  }
13946
14265
  function formatInstallLine(lang, outcome) {
13947
- const glyph = outcome.ok ? chalk15.green("\u2713") : chalk15.yellow("\u2717");
13948
- const tag = chalk15.dim(`[${outcome.method}]`);
14266
+ const glyph = outcome.ok ? chalk16.green("\u2713") : chalk16.yellow("\u2717");
14267
+ const tag = chalk16.dim(`[${outcome.method}]`);
13949
14268
  console.log(` ${glyph} ${lang.padEnd(12)} ${tag} ${outcome.detail}`);
13950
14269
  if (!outcome.ok && outcome.hint) {
13951
- console.log(` ${chalk15.dim("install:")} ${outcome.hint}`);
14270
+ console.log(` ${chalk16.dim("install:")} ${outcome.hint}`);
13952
14271
  }
13953
14272
  }
13954
14273
  var MAX_KEEP_WARM_MINUTES = 240;
@@ -13986,42 +14305,42 @@ async function autoDetectLanguages(cwd) {
13986
14305
  async function lspWarm(opts = {}) {
13987
14306
  const cwd = resolve4(opts.cwd ?? process.cwd());
13988
14307
  const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
13989
- if (noColor) chalk15.level = 0;
14308
+ if (noColor) chalk16.level = 0;
13990
14309
  let languages;
13991
14310
  if (opts.lang && opts.lang.length > 0) {
13992
14311
  const valid = Object.keys(LSP_REGISTRY);
13993
14312
  languages = opts.lang.filter((l) => valid.includes(l));
13994
14313
  const invalid = opts.lang.filter((l) => !valid.includes(l));
13995
14314
  if (invalid.length > 0) {
13996
- console.log(chalk15.yellow(`[lsp warm] unknown languages skipped: ${invalid.join(", ")}`));
14315
+ console.log(chalk16.yellow(`[lsp warm] unknown languages skipped: ${invalid.join(", ")}`));
13997
14316
  }
13998
14317
  } else {
13999
14318
  languages = await autoDetectLanguages(cwd);
14000
14319
  if (languages.length === 0) {
14001
14320
  console.log(
14002
- chalk15.yellow(
14321
+ chalk16.yellow(
14003
14322
  "[lsp warm] no recognised source files in this repo \u2014 pass --lang <id> to force a server."
14004
14323
  )
14005
14324
  );
14006
14325
  return;
14007
14326
  }
14008
- console.log(chalk15.dim(`[lsp warm] auto-detected languages: ${languages.join(", ")}`));
14327
+ console.log(chalk16.dim(`[lsp warm] auto-detected languages: ${languages.join(", ")}`));
14009
14328
  }
14010
14329
  let keepWarmMinutes = 0;
14011
14330
  if (typeof opts.keepWarm === "number" && opts.keepWarm > 0) {
14012
14331
  keepWarmMinutes = Math.min(opts.keepWarm, MAX_KEEP_WARM_MINUTES);
14013
14332
  if (opts.keepWarm > MAX_KEEP_WARM_MINUTES) {
14014
14333
  console.log(
14015
- chalk15.yellow(
14334
+ chalk16.yellow(
14016
14335
  `[lsp warm] --keep-warm clipped to ${MAX_KEEP_WARM_MINUTES.toString()} minutes (hard cap per Phase 7L plan).`
14017
14336
  )
14018
14337
  );
14019
14338
  }
14020
14339
  }
14021
- console.log(chalk15.bold("RepoWise LSP warm \u2014 preview"));
14022
- console.log(chalk15.dim(`Workspace: ${cwd}`));
14340
+ console.log(chalk16.bold("RepoWise LSP warm \u2014 preview"));
14341
+ console.log(chalk16.dim(`Workspace: ${cwd}`));
14023
14342
  console.log(
14024
- chalk15.dim(
14343
+ chalk16.dim(
14025
14344
  "LSP sessions live inside the listener (lazy-by-default, idle-evict after 5 min). The CLI cannot currently trigger a remote spawn \u2014 this preview shows which servers would be used."
14026
14345
  )
14027
14346
  );
@@ -14037,23 +14356,23 @@ async function lspWarm(opts = {}) {
14037
14356
  if (onPath) {
14038
14357
  foundCount += 1;
14039
14358
  console.log(
14040
- chalk15.green(` \u2713 ${lang.padEnd(12)} ${config2.displayName} (${config2.command}) on PATH`)
14359
+ chalk16.green(` \u2713 ${lang.padEnd(12)} ${config2.displayName} (${config2.command}) on PATH`)
14041
14360
  );
14042
14361
  } else {
14043
14362
  missingCount += 1;
14044
- console.log(chalk15.yellow(` \u2717 ${lang.padEnd(12)} ${config2.displayName} not on PATH`));
14363
+ console.log(chalk16.yellow(` \u2717 ${lang.padEnd(12)} ${config2.displayName} not on PATH`));
14045
14364
  if (config2.installHint) {
14046
- console.log(chalk15.dim(` install: ${config2.installHint}`));
14365
+ console.log(chalk16.dim(` install: ${config2.installHint}`));
14047
14366
  }
14048
14367
  }
14049
14368
  }
14050
14369
  console.log();
14051
14370
  console.log(
14052
- `${chalk15.green(foundCount.toString())} ready, ${chalk15.yellow(missingCount.toString())} missing.`
14371
+ `${chalk16.green(foundCount.toString())} ready, ${chalk16.yellow(missingCount.toString())} missing.`
14053
14372
  );
14054
14373
  if (keepWarmMinutes > 0) {
14055
14374
  console.log(
14056
- chalk15.dim(
14375
+ chalk16.dim(
14057
14376
  `Holding for ${keepWarmMinutes.toString()} minute(s) so the listener has time to spawn on its next sync.completed; Ctrl-C to exit early.`
14058
14377
  )
14059
14378
  );
@@ -14070,20 +14389,20 @@ async function lspWarm(opts = {}) {
14070
14389
  }
14071
14390
  function lspStatus() {
14072
14391
  const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
14073
- if (noColor) chalk15.level = 0;
14074
- console.log(chalk15.bold("RepoWise LSP status"));
14392
+ if (noColor) chalk16.level = 0;
14393
+ console.log(chalk16.bold("RepoWise LSP status"));
14075
14394
  console.log(
14076
- chalk15.dim(
14395
+ chalk16.dim(
14077
14396
  "Active LSP sessions live inside the listener (not the CLI). Sessions are lazy-by-default: spawn on first MCP tool / receiver query, idle-evict after 5 minutes. Scala sessions also evict their paired Bloop daemon (Phase 7L+)."
14078
14397
  )
14079
14398
  );
14080
14399
  console.log();
14081
- console.log(chalk15.dim("See `repowise lsp doctor` for PATH probe + install hints."));
14400
+ console.log(chalk16.dim("See `repowise lsp doctor` for PATH probe + install hints."));
14082
14401
  }
14083
14402
  function lspStop() {
14084
- console.log(chalk15.bold("RepoWise LSP stop \u2014 preview"));
14403
+ console.log(chalk16.bold("RepoWise LSP stop \u2014 preview"));
14085
14404
  console.log(
14086
- chalk15.dim(
14405
+ chalk16.dim(
14087
14406
  "No CLI-owned warm sessions exist. Listener-owned LSP sessions evict automatically after 5 minutes of idle (Phase 7L) and under the RSS soft-cap LRU when memory pressure rises. Explicit listener-side stop IPC is a future follow-up."
14088
14407
  )
14089
14408
  );
@@ -14106,29 +14425,29 @@ var ENABLE_TARGETS = {
14106
14425
  };
14107
14426
  async function lspEnable(target) {
14108
14427
  const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
14109
- if (noColor) chalk15.level = 0;
14428
+ if (noColor) chalk16.level = 0;
14110
14429
  if (!target) {
14111
- console.error(chalk15.red("Usage: repowise lsp enable <target>"));
14112
- console.error(chalk15.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14430
+ console.error(chalk16.red("Usage: repowise lsp enable <target>"));
14431
+ console.error(chalk16.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14113
14432
  process.exitCode = 1;
14114
14433
  return;
14115
14434
  }
14116
14435
  const spec = ENABLE_TARGETS[target];
14117
14436
  if (!spec) {
14118
- console.error(chalk15.red(`\u2716 Unknown LSP override target: ${target}`));
14119
- console.error(chalk15.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14437
+ console.error(chalk16.red(`\u2716 Unknown LSP override target: ${target}`));
14438
+ console.error(chalk16.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14120
14439
  process.exitCode = 1;
14121
14440
  return;
14122
14441
  }
14123
14442
  const config2 = await getConfig();
14124
14443
  const existing = config2.lspOverrides?.[spec.language];
14125
14444
  if (existing === spec.name) {
14126
- console.log(chalk15.green(`\u2714 ${spec.displayName} is already enabled.`));
14127
- console.log(chalk15.dim(` ${spec.postAcceptTip}`));
14445
+ console.log(chalk16.green(`\u2714 ${spec.displayName} is already enabled.`));
14446
+ console.log(chalk16.dim(` ${spec.postAcceptTip}`));
14128
14447
  return;
14129
14448
  }
14130
14449
  console.log();
14131
- console.log(chalk15.cyan.bold(` \u2500\u2500 Enable ${spec.displayName} \u2500\u2500`));
14450
+ console.log(chalk16.cyan.bold(` \u2500\u2500 Enable ${spec.displayName} \u2500\u2500`));
14132
14451
  for (const line of spec.consentLines) {
14133
14452
  console.log(` ${line}`);
14134
14453
  }
@@ -14139,47 +14458,82 @@ async function lspEnable(target) {
14139
14458
  default: false
14140
14459
  });
14141
14460
  if (!proceed) {
14142
- console.log(chalk15.dim(` Cancelled. ${spec.language.toUpperCase()} will continue using ${spec.revertDisplay}.`));
14461
+ console.log(
14462
+ chalk16.dim(
14463
+ ` Cancelled. ${spec.language.toUpperCase()} will continue using ${spec.revertDisplay}.`
14464
+ )
14465
+ );
14143
14466
  return;
14144
14467
  }
14145
14468
  const nextOverrides = { ...config2.lspOverrides ?? {}, [spec.language]: spec.name };
14146
14469
  await mergeAndSaveConfig({ lspOverrides: nextOverrides });
14147
- console.log(chalk15.green(` \u2714 ${spec.displayName} enabled \u2014 listener will use it within ~5 min (reconcile cycle) or on next session restart.`));
14148
- console.log(chalk15.dim(` \u2139 ${spec.postAcceptTip}`));
14470
+ console.log(
14471
+ chalk16.green(
14472
+ ` \u2714 ${spec.displayName} enabled \u2014 listener will use it within ~5 min (reconcile cycle) or on next session restart.`
14473
+ )
14474
+ );
14475
+ console.log(chalk16.dim(` \u2139 ${spec.postAcceptTip}`));
14149
14476
  }
14150
14477
  async function lspDisable(target) {
14151
14478
  const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
14152
- if (noColor) chalk15.level = 0;
14479
+ if (noColor) chalk16.level = 0;
14153
14480
  if (!target) {
14154
- console.error(chalk15.red("Usage: repowise lsp disable <target>"));
14155
- console.error(chalk15.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14481
+ console.error(chalk16.red("Usage: repowise lsp disable <target>"));
14482
+ console.error(chalk16.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14156
14483
  process.exitCode = 1;
14157
14484
  return;
14158
14485
  }
14159
14486
  const spec = ENABLE_TARGETS[target];
14160
14487
  if (!spec) {
14161
- console.error(chalk15.red(`\u2716 Unknown LSP override target: ${target}`));
14162
- console.error(chalk15.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14488
+ console.error(chalk16.red(`\u2716 Unknown LSP override target: ${target}`));
14489
+ console.error(chalk16.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
14163
14490
  process.exitCode = 1;
14164
14491
  return;
14165
14492
  }
14166
14493
  const config2 = await getConfig();
14167
14494
  const current = config2.lspOverrides?.[spec.language];
14168
14495
  if (current !== spec.name) {
14169
- console.log(chalk15.dim(` ${spec.displayName} is not enabled \u2014 nothing to do.`));
14496
+ console.log(chalk16.dim(` ${spec.displayName} is not enabled \u2014 nothing to do.`));
14170
14497
  return;
14171
14498
  }
14172
14499
  const { [spec.language]: _removed, ...rest } = config2.lspOverrides ?? {};
14173
14500
  void _removed;
14174
14501
  const nextOverrides = Object.keys(rest).length > 0 ? rest : void 0;
14175
- await mergeAndSaveConfig({ ...nextOverrides ? { lspOverrides: nextOverrides } : { lspOverrides: void 0 } });
14176
- console.log(chalk15.green(` \u2714 ${spec.displayName} disabled \u2014 listener will revert to ${spec.revertDisplay} within ~5 min or on next session restart.`));
14502
+ await mergeAndSaveConfig({
14503
+ ...nextOverrides ? { lspOverrides: nextOverrides } : { lspOverrides: void 0 }
14504
+ });
14505
+ console.log(
14506
+ chalk16.green(
14507
+ ` \u2714 ${spec.displayName} disabled \u2014 listener will revert to ${spec.revertDisplay} within ~5 min or on next session restart.`
14508
+ )
14509
+ );
14510
+ }
14511
+ async function lspOff() {
14512
+ const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
14513
+ if (noColor) chalk16.level = 0;
14514
+ await mergeAndSaveConfig({ lspEnabled: false });
14515
+ console.log(
14516
+ chalk16.green(
14517
+ " \u2714 LSP subsystem disabled. The listener will stop spawning language servers and `lsp_*` tools will report disabled within ~5 min (reconcile) or on next restart."
14518
+ )
14519
+ );
14520
+ console.log(chalk16.dim(" Re-enable with: repowise lsp on"));
14521
+ }
14522
+ async function lspOn() {
14523
+ const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
14524
+ if (noColor) chalk16.level = 0;
14525
+ await mergeAndSaveConfig({ lspEnabled: true });
14526
+ console.log(
14527
+ chalk16.green(
14528
+ " \u2714 LSP subsystem enabled. The listener will install + warm language servers for your repos within ~5 min (reconcile) or on next restart."
14529
+ )
14530
+ );
14177
14531
  }
14178
14532
 
14179
14533
  // bin/repowise.ts
14180
14534
  var __filename = fileURLToPath4(import.meta.url);
14181
14535
  var __dirname = dirname19(__filename);
14182
- var pkg = JSON.parse(readFileSync3(join51(__dirname, "..", "..", "package.json"), "utf-8"));
14536
+ var pkg = JSON.parse(readFileSync3(join52(__dirname, "..", "..", "package.json"), "utf-8"));
14183
14537
  var program = new Command();
14184
14538
  program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
14185
14539
  await showWelcome(pkg.version);
@@ -14249,6 +14603,12 @@ lspCommand.command("enable <target>").description("Opt into a non-default LSP (e
14249
14603
  lspCommand.command("disable <target>").description("Revert an LSP override and fall back to the registry default").action(async (target) => {
14250
14604
  await lspDisable(target);
14251
14605
  });
14606
+ lspCommand.command("off").description("Disable the LSP subsystem entirely (kill-switch)").action(async () => {
14607
+ await lspOff();
14608
+ });
14609
+ lspCommand.command("on").description("Re-enable the LSP subsystem after `lsp off`").action(async () => {
14610
+ await lspOn();
14611
+ });
14252
14612
  program.command("uninstall").description("Remove RepoWise from this machine (3 tiers: stop | logout | uninstall)").option("--tier <tier>", "Cleanup tier: stop | logout | uninstall", "uninstall").option("--yes", "Skip confirm prompt", false).action(async (options) => {
14253
14613
  const tier = options.tier ?? "uninstall";
14254
14614
  await uninstallCommand({ tier, yes: options.yes });