repowisestage 0.0.53 → 0.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/repowise.js +689 -331
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -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
|
-
|
|
2039
|
-
|
|
2040
|
-
await
|
|
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
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
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
|
|
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
|
|
3009
|
+
import { join as join32, dirname as dirname14 } from "path";
|
|
2983
3010
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2984
|
-
import
|
|
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 {
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
|
7327
|
+
const fs25 = await import("fs/promises");
|
|
7243
7328
|
const path = await import("path");
|
|
7244
|
-
await
|
|
7245
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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:
|
|
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 =
|
|
7756
|
-
await
|
|
7757
|
-
const outPath =
|
|
7758
|
-
await
|
|
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
|
|
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
|
|
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 =
|
|
7881
|
-
await
|
|
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 =
|
|
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(
|
|
8832
|
-
out.add(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 ${
|
|
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 =
|
|
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 =
|
|
9879
|
+
const credentialsPath = join32(getConfigDir(), "credentials.json");
|
|
9667
9880
|
let credentialsChanged = false;
|
|
9668
9881
|
let watcher = null;
|
|
9669
9882
|
try {
|
|
9670
|
-
const
|
|
9671
|
-
watcher =
|
|
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
|
|
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
|
|
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
|
|
9744
|
-
import
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
10055
|
+
import { dirname as dirname15, join as join40 } from "path";
|
|
9843
10056
|
init_src();
|
|
9844
|
-
import
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
10500
|
+
import { join as join37 } from "path";
|
|
10288
10501
|
function ensureGitignore(repoRoot, entry) {
|
|
10289
|
-
const gitignorePath =
|
|
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
|
|
10856
|
-
import { join as
|
|
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
|
|
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(
|
|
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
|
|
10951
|
-
import { join as
|
|
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 =
|
|
10956
|
-
await
|
|
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" ?
|
|
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(
|
|
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(
|
|
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: ${
|
|
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: ${
|
|
11418
|
+
spinner.succeed(`Repository: ${chalk8.bold(repoName)}`);
|
|
11161
11419
|
} catch {
|
|
11162
11420
|
spinner.fail(
|
|
11163
|
-
|
|
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(
|
|
11447
|
+
spinner.fail(chalk8.red(`Failed to look up repositories: ${repoLookupError}`));
|
|
11190
11448
|
} else {
|
|
11191
11449
|
spinner.fail(
|
|
11192
|
-
|
|
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(
|
|
11468
|
+
spinner.fail(chalk8.red("This repository already has context generated."));
|
|
11211
11469
|
console.log(
|
|
11212
|
-
|
|
11470
|
+
chalk8.cyan(
|
|
11213
11471
|
`
|
|
11214
|
-
As a team member, run: ${
|
|
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(
|
|
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
|
-
|
|
11487
|
+
chalk8.yellow(
|
|
11230
11488
|
`
|
|
11231
11489
|
This repository already has context generated.
|
|
11232
|
-
A full rescan will cost: ${
|
|
11490
|
+
A full rescan will cost: ${chalk8.bold(costText)}`
|
|
11233
11491
|
)
|
|
11234
11492
|
);
|
|
11235
11493
|
if (pricing.costWarning) {
|
|
11236
|
-
console.log(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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,10 @@ async function create() {
|
|
|
11315
11579
|
let depInstallShown = false;
|
|
11316
11580
|
let seenAwaitingInput = false;
|
|
11317
11581
|
let depInstallPromise = null;
|
|
11582
|
+
let lspInstallPromise = null;
|
|
11318
11583
|
while (true) {
|
|
11319
11584
|
if (++pollAttempts > MAX_POLL_ATTEMPTS) {
|
|
11320
|
-
spinner.fail(
|
|
11585
|
+
spinner.fail(chalk8.red("Pipeline timed out. Check dashboard for status."));
|
|
11321
11586
|
process.exitCode = 1;
|
|
11322
11587
|
return;
|
|
11323
11588
|
}
|
|
@@ -11363,6 +11628,8 @@ async function create() {
|
|
|
11363
11628
|
resumeText: "Resuming pipeline..."
|
|
11364
11629
|
});
|
|
11365
11630
|
depInstallPromise = result.installPromise;
|
|
11631
|
+
const lspResult = await maybeInstallLspServers({ repoRoot, spinner });
|
|
11632
|
+
lspInstallPromise = lspResult.installPromise;
|
|
11366
11633
|
}
|
|
11367
11634
|
if (syncResult.status === "completed") {
|
|
11368
11635
|
progressRenderer.finalize();
|
|
@@ -11376,10 +11643,12 @@ async function create() {
|
|
|
11376
11643
|
spinner.succeed(
|
|
11377
11644
|
`Context generation complete \u2014 ${coreCount} core + ${tailoredCount} tailored files`
|
|
11378
11645
|
);
|
|
11646
|
+
} else if (graphOnly) {
|
|
11647
|
+
spinner.succeed("Knowledge graph built \u2014 MCP ready (Free plan).");
|
|
11379
11648
|
} else {
|
|
11380
|
-
spinner.warn(
|
|
11649
|
+
spinner.warn(chalk8.yellow("Pipeline completed but no context files were generated."));
|
|
11381
11650
|
console.log(
|
|
11382
|
-
|
|
11651
|
+
chalk8.yellow(
|
|
11383
11652
|
" This may be due to AI throttling or a parsing issue. Try running `repowise create` again."
|
|
11384
11653
|
)
|
|
11385
11654
|
);
|
|
@@ -11388,18 +11657,18 @@ async function create() {
|
|
|
11388
11657
|
}
|
|
11389
11658
|
if (syncResult.status === "failed") {
|
|
11390
11659
|
progressRenderer.finalize();
|
|
11391
|
-
spinner.fail(
|
|
11660
|
+
spinner.fail(chalk8.red(`Pipeline failed: ${syncResult.error ?? "Unknown error"}`));
|
|
11392
11661
|
process.exitCode = 1;
|
|
11393
11662
|
return;
|
|
11394
11663
|
}
|
|
11395
11664
|
}
|
|
11396
|
-
if (repoRoot) {
|
|
11665
|
+
if (repoRoot && !graphOnly) {
|
|
11397
11666
|
spinner.start("Downloading context files from server...");
|
|
11398
11667
|
try {
|
|
11399
11668
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
11400
11669
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
11401
11670
|
if (files.length > 0) {
|
|
11402
|
-
const contextDir =
|
|
11671
|
+
const contextDir = join40(repoRoot, DEFAULT_CONTEXT_FOLDER);
|
|
11403
11672
|
mkdirSync(contextDir, { recursive: true });
|
|
11404
11673
|
let downloadedCount = 0;
|
|
11405
11674
|
let failedCount = 0;
|
|
@@ -11413,7 +11682,7 @@ async function create() {
|
|
|
11413
11682
|
const response = await fetch(presignedUrl);
|
|
11414
11683
|
if (response.ok) {
|
|
11415
11684
|
const content = await response.text();
|
|
11416
|
-
const filePath =
|
|
11685
|
+
const filePath = join40(contextDir, file.fileName);
|
|
11417
11686
|
mkdirSync(dirname15(filePath), { recursive: true });
|
|
11418
11687
|
writeFileSync2(filePath, content, "utf-8");
|
|
11419
11688
|
downloadedCount++;
|
|
@@ -11438,7 +11707,7 @@ async function create() {
|
|
|
11438
11707
|
} catch (err) {
|
|
11439
11708
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
11440
11709
|
spinner.warn(
|
|
11441
|
-
|
|
11710
|
+
chalk8.yellow(
|
|
11442
11711
|
`Cannot reach RepoWise servers to download context: ${msg}
|
|
11443
11712
|
Files are stored on our servers (not in git). Retry when online.`
|
|
11444
11713
|
)
|
|
@@ -11446,30 +11715,16 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11446
11715
|
}
|
|
11447
11716
|
}
|
|
11448
11717
|
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
11718
|
let contextFiles = [];
|
|
11456
11719
|
if (repoRoot) {
|
|
11457
11720
|
contextFiles = await scanLocalContextFiles(repoRoot, contextFolder);
|
|
11458
11721
|
}
|
|
11459
|
-
if (contextFiles.length === 0) {
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
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
|
-
}
|
|
11722
|
+
if (contextFiles.length === 0 && !graphOnly) {
|
|
11723
|
+
console.log(
|
|
11724
|
+
chalk8.yellow(
|
|
11725
|
+
` No context files found in ${contextFolder}/. Try re-running \`repowise create\`.`
|
|
11726
|
+
)
|
|
11727
|
+
);
|
|
11473
11728
|
}
|
|
11474
11729
|
if (repoRoot) {
|
|
11475
11730
|
spinner.start("Configuring AI tools...");
|
|
@@ -11507,7 +11762,7 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11507
11762
|
results.push(" Configured .claude/settings.json (SubagentStart hook)");
|
|
11508
11763
|
}
|
|
11509
11764
|
spinner.succeed("AI tools configured");
|
|
11510
|
-
console.log(
|
|
11765
|
+
console.log(chalk8.dim(results.join("\n")));
|
|
11511
11766
|
}
|
|
11512
11767
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
11513
11768
|
const updatedRepos = [];
|
|
@@ -11533,11 +11788,11 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11533
11788
|
}
|
|
11534
11789
|
if (!listenerRunning) {
|
|
11535
11790
|
console.log(
|
|
11536
|
-
|
|
11791
|
+
chalk8.yellow(
|
|
11537
11792
|
"Warning: Could not start listener automatically. Run the following to enable it:"
|
|
11538
11793
|
)
|
|
11539
11794
|
);
|
|
11540
|
-
console.log(
|
|
11795
|
+
console.log(chalk8.yellow(` $ repowise listen --install`));
|
|
11541
11796
|
}
|
|
11542
11797
|
if (depInstallPromise) {
|
|
11543
11798
|
const installSpinner = ora("Finalizing dependency installs...").start();
|
|
@@ -11554,47 +11809,84 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11554
11809
|
);
|
|
11555
11810
|
}
|
|
11556
11811
|
}
|
|
11812
|
+
if (lspInstallPromise) {
|
|
11813
|
+
const LSP_INSTALL_SOFT_TIMEOUT_MS = 18e4;
|
|
11814
|
+
const lspSpinner = ora("Finalizing language-server setup...").start();
|
|
11815
|
+
let lspTimer;
|
|
11816
|
+
const timeoutResults = new Promise((resolve5) => {
|
|
11817
|
+
lspTimer = setTimeout(() => resolve5(null), LSP_INSTALL_SOFT_TIMEOUT_MS);
|
|
11818
|
+
});
|
|
11819
|
+
const lspResults = await Promise.race([lspInstallPromise, timeoutResults]);
|
|
11820
|
+
clearTimeout(lspTimer);
|
|
11821
|
+
if (lspResults === null) {
|
|
11822
|
+
lspSpinner.info("Language servers are finishing in the background.");
|
|
11823
|
+
} else {
|
|
11824
|
+
const installed = lspResults.filter((r) => r.installed).length;
|
|
11825
|
+
const failed = lspResults.filter((r) => r.error).length;
|
|
11826
|
+
if (failed > 0) {
|
|
11827
|
+
lspSpinner.warn(`${failed.toString()} language server(s) could not be installed`);
|
|
11828
|
+
} else {
|
|
11829
|
+
lspSpinner.succeed(
|
|
11830
|
+
installed > 0 ? `Language servers ready (${installed.toString()} installed)` : "Language servers ready"
|
|
11831
|
+
);
|
|
11832
|
+
}
|
|
11833
|
+
reportLspInstallOutcomes(lspResults);
|
|
11834
|
+
}
|
|
11835
|
+
}
|
|
11557
11836
|
const elapsed = formatElapsed(Date.now() - startTime);
|
|
11558
11837
|
console.log("");
|
|
11559
|
-
console.log(
|
|
11838
|
+
console.log(chalk8.green.bold(` \u2728 Setup complete \u2014 ${repoName} is ready.`));
|
|
11560
11839
|
if (listenerRunning) {
|
|
11561
11840
|
console.log("");
|
|
11562
|
-
console.log(
|
|
11841
|
+
console.log(chalk8.cyan(" What\u2019s running now"));
|
|
11563
11842
|
console.log(
|
|
11564
|
-
` ${
|
|
11843
|
+
` ${chalk8.green("\u2022")} The RepoWise Listener is Live \u2014 context auto-updates on every push.`
|
|
11565
11844
|
);
|
|
11566
11845
|
console.log(
|
|
11567
|
-
` ${
|
|
11846
|
+
` ${chalk8.green("\u2022")} The RepoWise MCP is Live \u2014 your AI tools can query the knowledge graph directly.`
|
|
11568
11847
|
);
|
|
11848
|
+
let lspOn2 = true;
|
|
11849
|
+
let lspWarm2 = true;
|
|
11850
|
+
try {
|
|
11851
|
+
const cfg = await getConfig();
|
|
11852
|
+
lspOn2 = cfg.lspEnabled !== false;
|
|
11853
|
+
lspWarm2 = cfg.lspAutoWarm !== false;
|
|
11854
|
+
} catch {
|
|
11855
|
+
}
|
|
11856
|
+
if (lspOn2 && lspWarm2) {
|
|
11857
|
+
console.log(
|
|
11858
|
+
` ${chalk8.green("\u2022")} Language servers are warming for instant code-intelligence answers (idle after 5 min). Turn off anytime: ${chalk8.bold("repowise lsp off")}`
|
|
11859
|
+
);
|
|
11860
|
+
}
|
|
11569
11861
|
}
|
|
11570
11862
|
if (graphOnly) {
|
|
11571
11863
|
console.log("");
|
|
11572
|
-
console.log(
|
|
11864
|
+
console.log(chalk8.cyan(" You\u2019re on the Free plan \u2014 knowledge graph + MCP only."));
|
|
11573
11865
|
console.log(
|
|
11574
|
-
|
|
11866
|
+
chalk8.dim(" Upgrade to Pro for AI-generated context docs and auto-sync on merge.")
|
|
11575
11867
|
);
|
|
11576
11868
|
}
|
|
11577
11869
|
console.log("");
|
|
11578
|
-
console.log(
|
|
11870
|
+
console.log(chalk8.cyan(" Next steps"));
|
|
11579
11871
|
console.log(
|
|
11580
|
-
` ${
|
|
11872
|
+
` ${chalk8.cyan("\u2022")} Open Claude Code / Cursor and ask: "What does this repo do?"`
|
|
11581
11873
|
);
|
|
11582
11874
|
console.log(
|
|
11583
|
-
` ${
|
|
11875
|
+
` ${chalk8.cyan("\u2022")} Head to the dashboard \u2192 "Complete Onboarding" to explore quality scores and gaps.`
|
|
11584
11876
|
);
|
|
11585
|
-
console.log(
|
|
11877
|
+
console.log(chalk8.dim(`
|
|
11586
11878
|
Total time: ${elapsed}`));
|
|
11587
11879
|
} catch (err) {
|
|
11588
11880
|
const message = err instanceof Error ? err.message : "Create failed";
|
|
11589
|
-
spinner.fail(
|
|
11881
|
+
spinner.fail(chalk8.red(message));
|
|
11590
11882
|
process.exitCode = 1;
|
|
11591
11883
|
}
|
|
11592
11884
|
}
|
|
11593
11885
|
|
|
11594
11886
|
// src/commands/member.ts
|
|
11595
11887
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11596
|
-
import { dirname as dirname16, join as
|
|
11597
|
-
import
|
|
11888
|
+
import { dirname as dirname16, join as join41, resolve, sep } from "path";
|
|
11889
|
+
import chalk9 from "chalk";
|
|
11598
11890
|
import ora2 from "ora";
|
|
11599
11891
|
var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
|
|
11600
11892
|
function formatElapsed2(ms) {
|
|
@@ -11625,10 +11917,10 @@ async function member() {
|
|
|
11625
11917
|
try {
|
|
11626
11918
|
let credentials = await getValidCredentials2();
|
|
11627
11919
|
if (!credentials) {
|
|
11628
|
-
spinner.info(
|
|
11920
|
+
spinner.info(chalk9.yellow("Not logged in. Opening browser to authenticate..."));
|
|
11629
11921
|
credentials = await performLogin();
|
|
11630
11922
|
const { email } = decodeIdToken(credentials.idToken);
|
|
11631
|
-
spinner.succeed(
|
|
11923
|
+
spinner.succeed(chalk9.green(`Authenticated as ${chalk9.bold(email)}`));
|
|
11632
11924
|
} else {
|
|
11633
11925
|
spinner.succeed("Authenticated");
|
|
11634
11926
|
}
|
|
@@ -11636,12 +11928,12 @@ async function member() {
|
|
|
11636
11928
|
const usage = await apiRequest("/v1/account/usage");
|
|
11637
11929
|
if (usage.plan && usage.plan !== "team") {
|
|
11638
11930
|
spinner.fail(
|
|
11639
|
-
|
|
11931
|
+
chalk9.yellow(
|
|
11640
11932
|
`'repowise member' is a Team-plan feature (your account is on the ${usage.plan} plan).`
|
|
11641
11933
|
)
|
|
11642
11934
|
);
|
|
11643
11935
|
console.log(
|
|
11644
|
-
|
|
11936
|
+
chalk9.dim(" The account owner sets up the repository with `repowise create`.")
|
|
11645
11937
|
);
|
|
11646
11938
|
return;
|
|
11647
11939
|
}
|
|
@@ -11658,7 +11950,7 @@ async function member() {
|
|
|
11658
11950
|
if (pending?.repoId) {
|
|
11659
11951
|
repoId = pending.repoId;
|
|
11660
11952
|
repoName = pending.repoName;
|
|
11661
|
-
spinner.succeed(`Found pending repository: ${
|
|
11953
|
+
spinner.succeed(`Found pending repository: ${chalk9.bold(repoName)}`);
|
|
11662
11954
|
apiRequest("/v1/onboarding/pending", { method: "DELETE" }).catch(() => {
|
|
11663
11955
|
});
|
|
11664
11956
|
}
|
|
@@ -11669,10 +11961,10 @@ async function member() {
|
|
|
11669
11961
|
try {
|
|
11670
11962
|
repoRoot = detectRepoRoot();
|
|
11671
11963
|
repoName = detectRepoName(repoRoot);
|
|
11672
|
-
spinner.succeed(`Repository: ${
|
|
11964
|
+
spinner.succeed(`Repository: ${chalk9.bold(repoName)}`);
|
|
11673
11965
|
} catch {
|
|
11674
11966
|
spinner.fail(
|
|
11675
|
-
|
|
11967
|
+
chalk9.red("Not in a git repository. Run this command from your project directory.")
|
|
11676
11968
|
);
|
|
11677
11969
|
process.exitCode = 1;
|
|
11678
11970
|
return;
|
|
@@ -11683,15 +11975,15 @@ async function member() {
|
|
|
11683
11975
|
const localRepoName = detectRepoName(repoRoot);
|
|
11684
11976
|
if (repoName && localRepoName !== repoName && !repoName.endsWith(`/${localRepoName}`)) {
|
|
11685
11977
|
spinner.warn(
|
|
11686
|
-
|
|
11687
|
-
`Pending repo is ${
|
|
11978
|
+
chalk9.yellow(
|
|
11979
|
+
`Pending repo is ${chalk9.bold(repoName)} but you're in ${chalk9.bold(localRepoName)}.
|
|
11688
11980
|
Make sure you're in the right project directory, or the context files will be saved here.`
|
|
11689
11981
|
)
|
|
11690
11982
|
);
|
|
11691
11983
|
}
|
|
11692
11984
|
} catch {
|
|
11693
11985
|
spinner.fail(
|
|
11694
|
-
|
|
11986
|
+
chalk9.red(
|
|
11695
11987
|
"Please navigate to your project directory first, then run `repowise member` again."
|
|
11696
11988
|
)
|
|
11697
11989
|
);
|
|
@@ -11711,14 +12003,14 @@ async function member() {
|
|
|
11711
12003
|
repoPlatform = match.platform;
|
|
11712
12004
|
repoExternalId = match.externalId;
|
|
11713
12005
|
if (!repoName) repoName = match.fullName;
|
|
11714
|
-
spinner.succeed(`Repository: ${
|
|
12006
|
+
spinner.succeed(`Repository: ${chalk9.bold(match.fullName)}`);
|
|
11715
12007
|
}
|
|
11716
12008
|
} catch {
|
|
11717
12009
|
}
|
|
11718
12010
|
}
|
|
11719
12011
|
if (!repoId) {
|
|
11720
12012
|
spinner.fail(
|
|
11721
|
-
|
|
12013
|
+
chalk9.red(
|
|
11722
12014
|
"This repository is not connected to your team. Ask your team admin to add it on the dashboard."
|
|
11723
12015
|
)
|
|
11724
12016
|
);
|
|
@@ -11731,23 +12023,23 @@ async function member() {
|
|
|
11731
12023
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
11732
12024
|
files = listResult.data?.files ?? listResult.files ?? [];
|
|
11733
12025
|
} catch {
|
|
11734
|
-
spinner.fail(
|
|
12026
|
+
spinner.fail(chalk9.red("Failed to check context files on server."));
|
|
11735
12027
|
process.exitCode = 1;
|
|
11736
12028
|
return;
|
|
11737
12029
|
}
|
|
11738
12030
|
if (files.length === 0) {
|
|
11739
12031
|
spinner.fail(
|
|
11740
|
-
|
|
12032
|
+
chalk9.red(
|
|
11741
12033
|
"No context files found for this repository. Your team admin needs to run the initial scan first."
|
|
11742
12034
|
)
|
|
11743
12035
|
);
|
|
11744
12036
|
process.exitCode = 1;
|
|
11745
12037
|
return;
|
|
11746
12038
|
}
|
|
11747
|
-
spinner.succeed(`Found ${
|
|
12039
|
+
spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
|
|
11748
12040
|
const { tools } = await selectAiTools();
|
|
11749
12041
|
spinner.start("Downloading context files...");
|
|
11750
|
-
const contextDir =
|
|
12042
|
+
const contextDir = join41(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
11751
12043
|
mkdirSync2(contextDir, { recursive: true });
|
|
11752
12044
|
let downloadedCount = 0;
|
|
11753
12045
|
let failedCount = 0;
|
|
@@ -11823,7 +12115,7 @@ async function member() {
|
|
|
11823
12115
|
}
|
|
11824
12116
|
spinner.succeed("AI tools configured");
|
|
11825
12117
|
for (const msg of configured) {
|
|
11826
|
-
console.log(
|
|
12118
|
+
console.log(chalk9.dim(` ${msg}`));
|
|
11827
12119
|
}
|
|
11828
12120
|
}
|
|
11829
12121
|
let depInstallPromise = null;
|
|
@@ -11837,6 +12129,7 @@ async function member() {
|
|
|
11837
12129
|
});
|
|
11838
12130
|
depInstallPromise = result.installPromise;
|
|
11839
12131
|
}
|
|
12132
|
+
const lspInstallPromise = (await maybeInstallLspServers({ repoRoot, spinner })).installPromise;
|
|
11840
12133
|
spinner.start("Saving configuration...");
|
|
11841
12134
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
11842
12135
|
const repoEntry = {
|
|
@@ -11881,54 +12174,78 @@ async function member() {
|
|
|
11881
12174
|
);
|
|
11882
12175
|
}
|
|
11883
12176
|
}
|
|
12177
|
+
{
|
|
12178
|
+
const LSP_INSTALL_SOFT_TIMEOUT_MS = 18e4;
|
|
12179
|
+
const lspSpinner = ora2("Finalizing language-server setup...").start();
|
|
12180
|
+
let lspTimer;
|
|
12181
|
+
const timeoutResults = new Promise((resolve5) => {
|
|
12182
|
+
lspTimer = setTimeout(() => resolve5(null), LSP_INSTALL_SOFT_TIMEOUT_MS);
|
|
12183
|
+
});
|
|
12184
|
+
const lspResults = await Promise.race([lspInstallPromise, timeoutResults]);
|
|
12185
|
+
clearTimeout(lspTimer);
|
|
12186
|
+
if (lspResults === null) {
|
|
12187
|
+
lspSpinner.info("Language servers are finishing in the background.");
|
|
12188
|
+
} else {
|
|
12189
|
+
const installed = lspResults.filter((r) => r.installed).length;
|
|
12190
|
+
const failed = lspResults.filter((r) => r.error).length;
|
|
12191
|
+
if (failed > 0) {
|
|
12192
|
+
lspSpinner.warn(`${failed.toString()} language server(s) could not be installed`);
|
|
12193
|
+
} else {
|
|
12194
|
+
lspSpinner.succeed(
|
|
12195
|
+
installed > 0 ? `Language servers ready (${installed.toString()} installed)` : "Language servers ready"
|
|
12196
|
+
);
|
|
12197
|
+
}
|
|
12198
|
+
reportLspInstallOutcomes(lspResults);
|
|
12199
|
+
}
|
|
12200
|
+
}
|
|
11884
12201
|
const elapsed = formatElapsed2(Date.now() - startTime);
|
|
11885
12202
|
console.log("");
|
|
11886
|
-
console.log(
|
|
12203
|
+
console.log(chalk9.green.bold("All done! Context downloaded and configured."));
|
|
11887
12204
|
console.log("");
|
|
11888
|
-
console.log(`Your AI tools now have access to project context for ${
|
|
12205
|
+
console.log(`Your AI tools now have access to project context for ${chalk9.bold(repoName)}.`);
|
|
11889
12206
|
console.log(
|
|
11890
|
-
`Downloaded ${
|
|
12207
|
+
`Downloaded ${chalk9.bold(downloadedCount)} context files to ./${DEFAULT_CONTEXT_FOLDER2}/`
|
|
11891
12208
|
);
|
|
11892
12209
|
console.log("");
|
|
11893
12210
|
if (listenerRunning) {
|
|
11894
12211
|
console.log(
|
|
11895
|
-
|
|
12212
|
+
chalk9.dim(
|
|
11896
12213
|
"The RepoWise listener is running in the background \u2014\nyour context will stay in sync automatically."
|
|
11897
12214
|
)
|
|
11898
12215
|
);
|
|
11899
12216
|
} else {
|
|
11900
12217
|
console.log(
|
|
11901
|
-
|
|
12218
|
+
chalk9.yellow(
|
|
11902
12219
|
"Could not start listener automatically. Run `repowise listen --install` to enable auto-sync."
|
|
11903
12220
|
)
|
|
11904
12221
|
);
|
|
11905
12222
|
}
|
|
11906
12223
|
console.log("");
|
|
11907
12224
|
console.log(
|
|
11908
|
-
|
|
12225
|
+
chalk9.dim(`Head back to the dashboard and click "Complete Onboarding" to finish setup.`)
|
|
11909
12226
|
);
|
|
11910
|
-
console.log(
|
|
12227
|
+
console.log(chalk9.dim(`Total time: ${elapsed}`));
|
|
11911
12228
|
} catch (err) {
|
|
11912
12229
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
11913
|
-
spinner.fail(
|
|
12230
|
+
spinner.fail(chalk9.red(`Setup failed: ${message}`));
|
|
11914
12231
|
process.exitCode = 1;
|
|
11915
12232
|
}
|
|
11916
12233
|
}
|
|
11917
12234
|
|
|
11918
12235
|
// src/commands/login.ts
|
|
11919
|
-
import
|
|
12236
|
+
import chalk10 from "chalk";
|
|
11920
12237
|
import ora3 from "ora";
|
|
11921
12238
|
|
|
11922
12239
|
// src/lib/tenant-graph-purge.ts
|
|
11923
|
-
import { promises as
|
|
12240
|
+
import { promises as fs18 } from "fs";
|
|
11924
12241
|
import { homedir as homedir7 } from "os";
|
|
11925
|
-
import { join as
|
|
12242
|
+
import { join as join42 } from "path";
|
|
11926
12243
|
async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
11927
|
-
const graphsDir =
|
|
12244
|
+
const graphsDir = join42(home, ".repowise", "graphs");
|
|
11928
12245
|
const result = { kept: [], removed: [] };
|
|
11929
12246
|
let entries;
|
|
11930
12247
|
try {
|
|
11931
|
-
entries = await
|
|
12248
|
+
entries = await fs18.readdir(graphsDir);
|
|
11932
12249
|
} catch (err) {
|
|
11933
12250
|
if (err.code === "ENOENT") return result;
|
|
11934
12251
|
throw err;
|
|
@@ -11942,15 +12259,15 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
|
11942
12259
|
result.kept.push(entry);
|
|
11943
12260
|
continue;
|
|
11944
12261
|
}
|
|
11945
|
-
const path =
|
|
12262
|
+
const path = join42(graphsDir, entry);
|
|
11946
12263
|
try {
|
|
11947
|
-
const stat7 = await
|
|
12264
|
+
const stat7 = await fs18.lstat(path);
|
|
11948
12265
|
if (stat7.isSymbolicLink()) {
|
|
11949
|
-
await
|
|
12266
|
+
await fs18.unlink(path);
|
|
11950
12267
|
result.removed.push(entry);
|
|
11951
12268
|
continue;
|
|
11952
12269
|
}
|
|
11953
|
-
await
|
|
12270
|
+
await fs18.rm(path, { recursive: true, force: true });
|
|
11954
12271
|
result.removed.push(entry);
|
|
11955
12272
|
} catch {
|
|
11956
12273
|
}
|
|
@@ -11972,7 +12289,7 @@ async function login(options = {}) {
|
|
|
11972
12289
|
console.log(`
|
|
11973
12290
|
Open this URL in your browser to authenticate:
|
|
11974
12291
|
`);
|
|
11975
|
-
console.log(
|
|
12292
|
+
console.log(chalk10.cyan(authorizeUrl));
|
|
11976
12293
|
console.log(`
|
|
11977
12294
|
Waiting for authentication...`);
|
|
11978
12295
|
} else {
|
|
@@ -11986,7 +12303,7 @@ Waiting for authentication...`);
|
|
|
11986
12303
|
console.log(`
|
|
11987
12304
|
Could not open browser automatically. Open this URL:
|
|
11988
12305
|
`);
|
|
11989
|
-
console.log(
|
|
12306
|
+
console.log(chalk10.cyan(authorizeUrl));
|
|
11990
12307
|
console.log(`
|
|
11991
12308
|
Waiting for authentication...`);
|
|
11992
12309
|
}
|
|
@@ -12000,14 +12317,14 @@ Waiting for authentication...`);
|
|
|
12000
12317
|
credentials.cognito = getCognitoConfigForStorage();
|
|
12001
12318
|
await storeCredentials2(credentials);
|
|
12002
12319
|
const { email } = decodeIdToken(credentials.idToken);
|
|
12003
|
-
spinner.succeed(
|
|
12320
|
+
spinner.succeed(chalk10.green(`Logged in as ${chalk10.bold(email)}`));
|
|
12004
12321
|
try {
|
|
12005
12322
|
const repos = await apiRequest("/v1/repos");
|
|
12006
12323
|
const validRepoIds = new Set(repos.map((r) => r.repoId));
|
|
12007
12324
|
const result = await purgeForeignGraphs(validRepoIds);
|
|
12008
12325
|
if (result.removed.length > 0) {
|
|
12009
12326
|
console.log(
|
|
12010
|
-
|
|
12327
|
+
chalk10.dim(
|
|
12011
12328
|
` Cleaned ${result.removed.length.toString()} graph artifact(s) from a prior tenant.`
|
|
12012
12329
|
)
|
|
12013
12330
|
);
|
|
@@ -12016,30 +12333,30 @@ Waiting for authentication...`);
|
|
|
12016
12333
|
}
|
|
12017
12334
|
} catch (err) {
|
|
12018
12335
|
const message = err instanceof Error ? err.message : "Login failed";
|
|
12019
|
-
spinner.fail(
|
|
12336
|
+
spinner.fail(chalk10.red(message));
|
|
12020
12337
|
process.exitCode = 1;
|
|
12021
12338
|
}
|
|
12022
12339
|
}
|
|
12023
12340
|
|
|
12024
12341
|
// src/commands/logout.ts
|
|
12025
|
-
import
|
|
12342
|
+
import chalk11 from "chalk";
|
|
12026
12343
|
async function logout() {
|
|
12027
12344
|
const creds = await getStoredCredentials2();
|
|
12028
12345
|
if (!creds) {
|
|
12029
|
-
console.log(
|
|
12346
|
+
console.log(chalk11.yellow("Not logged in."));
|
|
12030
12347
|
return;
|
|
12031
12348
|
}
|
|
12032
12349
|
await clearCredentials();
|
|
12033
|
-
console.log(
|
|
12350
|
+
console.log(chalk11.green("Logged out successfully."));
|
|
12034
12351
|
}
|
|
12035
12352
|
|
|
12036
12353
|
// src/commands/status.ts
|
|
12037
12354
|
import { readFile as readFile16 } from "fs/promises";
|
|
12038
|
-
import { basename as basename3, join as
|
|
12355
|
+
import { basename as basename3, join as join43 } from "path";
|
|
12039
12356
|
async function status() {
|
|
12040
12357
|
const configDir = getConfigDir2();
|
|
12041
|
-
const STATE_PATH =
|
|
12042
|
-
const CONFIG_PATH =
|
|
12358
|
+
const STATE_PATH = join43(configDir, "listener-state.json");
|
|
12359
|
+
const CONFIG_PATH = join43(configDir, "config.json");
|
|
12043
12360
|
let state = null;
|
|
12044
12361
|
try {
|
|
12045
12362
|
const data = await readFile16(STATE_PATH, "utf-8");
|
|
@@ -12087,8 +12404,8 @@ async function status() {
|
|
|
12087
12404
|
|
|
12088
12405
|
// src/commands/sync.ts
|
|
12089
12406
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
12090
|
-
import { dirname as dirname17, join as
|
|
12091
|
-
import
|
|
12407
|
+
import { dirname as dirname17, join as join44 } from "path";
|
|
12408
|
+
import chalk12 from "chalk";
|
|
12092
12409
|
import ora4 from "ora";
|
|
12093
12410
|
var POLL_INTERVAL_MS2 = 3e3;
|
|
12094
12411
|
var MAX_POLL_ATTEMPTS2 = 7200;
|
|
@@ -12106,10 +12423,10 @@ async function sync() {
|
|
|
12106
12423
|
try {
|
|
12107
12424
|
let credentials = await getValidCredentials2();
|
|
12108
12425
|
if (!credentials) {
|
|
12109
|
-
spinner.info(
|
|
12426
|
+
spinner.info(chalk12.yellow("Not logged in. Opening browser to authenticate..."));
|
|
12110
12427
|
credentials = await performLogin();
|
|
12111
12428
|
const { email } = decodeIdToken(credentials.idToken);
|
|
12112
|
-
spinner.succeed(
|
|
12429
|
+
spinner.succeed(chalk12.green(`Authenticated as ${chalk12.bold(email)}`));
|
|
12113
12430
|
} else {
|
|
12114
12431
|
spinner.succeed("Authenticated");
|
|
12115
12432
|
}
|
|
@@ -12119,10 +12436,10 @@ async function sync() {
|
|
|
12119
12436
|
try {
|
|
12120
12437
|
repoRoot = detectRepoRoot();
|
|
12121
12438
|
repoName = detectRepoName(repoRoot);
|
|
12122
|
-
spinner.succeed(`Repository: ${
|
|
12439
|
+
spinner.succeed(`Repository: ${chalk12.bold(repoName)}`);
|
|
12123
12440
|
} catch {
|
|
12124
12441
|
spinner.fail(
|
|
12125
|
-
|
|
12442
|
+
chalk12.red("Not in a git repository. Run this command from your repo directory.")
|
|
12126
12443
|
);
|
|
12127
12444
|
process.exitCode = 1;
|
|
12128
12445
|
return;
|
|
@@ -12145,10 +12462,10 @@ async function sync() {
|
|
|
12145
12462
|
}
|
|
12146
12463
|
if (!repoId) {
|
|
12147
12464
|
if (repoLookupError) {
|
|
12148
|
-
spinner.fail(
|
|
12465
|
+
spinner.fail(chalk12.red(`Failed to look up repositories: ${repoLookupError}`));
|
|
12149
12466
|
} else {
|
|
12150
12467
|
spinner.fail(
|
|
12151
|
-
|
|
12468
|
+
chalk12.red(
|
|
12152
12469
|
"Could not find this repository in your RepoWise account. Run `repowise create` first."
|
|
12153
12470
|
)
|
|
12154
12471
|
);
|
|
@@ -12186,7 +12503,7 @@ async function sync() {
|
|
|
12186
12503
|
syncId = retryResult.syncId;
|
|
12187
12504
|
} else {
|
|
12188
12505
|
syncId = active.syncId;
|
|
12189
|
-
spinner.info(
|
|
12506
|
+
spinner.info(chalk12.cyan("Resuming existing sync..."));
|
|
12190
12507
|
spinner.start();
|
|
12191
12508
|
}
|
|
12192
12509
|
}
|
|
@@ -12194,7 +12511,7 @@ async function sync() {
|
|
|
12194
12511
|
const progressRenderer = new ProgressRenderer();
|
|
12195
12512
|
while (true) {
|
|
12196
12513
|
if (++pollAttempts > MAX_POLL_ATTEMPTS2) {
|
|
12197
|
-
spinner.fail(
|
|
12514
|
+
spinner.fail(chalk12.red("Sync timed out. Check dashboard for status."));
|
|
12198
12515
|
process.exitCode = 1;
|
|
12199
12516
|
return;
|
|
12200
12517
|
}
|
|
@@ -12218,15 +12535,15 @@ async function sync() {
|
|
|
12218
12535
|
const generatedFiles = syncResult.filesGenerated ?? [];
|
|
12219
12536
|
const fileCount = generatedFiles.length;
|
|
12220
12537
|
if (fileCount > 0) {
|
|
12221
|
-
spinner.succeed(
|
|
12538
|
+
spinner.succeed(chalk12.green(`Incremental update complete \u2014 ${fileCount} files updated`));
|
|
12222
12539
|
} else {
|
|
12223
|
-
spinner.succeed(
|
|
12540
|
+
spinner.succeed(chalk12.green("Incremental sync complete \u2014 no files needed updating"));
|
|
12224
12541
|
}
|
|
12225
12542
|
break;
|
|
12226
12543
|
}
|
|
12227
12544
|
if (syncResult.status === "failed") {
|
|
12228
12545
|
progressRenderer.finalize();
|
|
12229
|
-
spinner.fail(
|
|
12546
|
+
spinner.fail(chalk12.red(`Sync failed: ${syncResult.error ?? "Unknown error"}`));
|
|
12230
12547
|
process.exitCode = 1;
|
|
12231
12548
|
return;
|
|
12232
12549
|
}
|
|
@@ -12236,7 +12553,7 @@ async function sync() {
|
|
|
12236
12553
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
12237
12554
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
12238
12555
|
if (files.length > 0) {
|
|
12239
|
-
const contextDir =
|
|
12556
|
+
const contextDir = join44(repoRoot, DEFAULT_CONTEXT_FOLDER3);
|
|
12240
12557
|
mkdirSync3(contextDir, { recursive: true });
|
|
12241
12558
|
let downloadedCount = 0;
|
|
12242
12559
|
let failedCount = 0;
|
|
@@ -12250,7 +12567,7 @@ async function sync() {
|
|
|
12250
12567
|
const response = await fetch(presignedUrl);
|
|
12251
12568
|
if (response.ok) {
|
|
12252
12569
|
const content = await response.text();
|
|
12253
|
-
const filePath =
|
|
12570
|
+
const filePath = join44(contextDir, file.fileName);
|
|
12254
12571
|
mkdirSync3(dirname17(filePath), { recursive: true });
|
|
12255
12572
|
writeFileSync4(filePath, content, "utf-8");
|
|
12256
12573
|
downloadedCount++;
|
|
@@ -12306,7 +12623,7 @@ async function sync() {
|
|
|
12306
12623
|
}
|
|
12307
12624
|
} catch (err) {
|
|
12308
12625
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
12309
|
-
spinner.warn(
|
|
12626
|
+
spinner.warn(chalk12.yellow(`Could not download context files: ${msg}
|
|
12310
12627
|
Retry when online.`));
|
|
12311
12628
|
}
|
|
12312
12629
|
if (repoRoot && repoId) {
|
|
@@ -12327,11 +12644,11 @@ Retry when online.`));
|
|
|
12327
12644
|
}
|
|
12328
12645
|
}
|
|
12329
12646
|
const elapsed = formatElapsed3(Date.now() - startTime);
|
|
12330
|
-
console.log(
|
|
12647
|
+
console.log(chalk12.dim(`
|
|
12331
12648
|
Total time: ${elapsed}`));
|
|
12332
12649
|
} catch (err) {
|
|
12333
12650
|
const message = err instanceof Error ? err.message : "Sync failed";
|
|
12334
|
-
spinner.fail(
|
|
12651
|
+
spinner.fail(chalk12.red(message));
|
|
12335
12652
|
process.exitCode = 1;
|
|
12336
12653
|
}
|
|
12337
12654
|
}
|
|
@@ -12414,7 +12731,7 @@ async function stop2() {
|
|
|
12414
12731
|
}
|
|
12415
12732
|
|
|
12416
12733
|
// src/commands/config.ts
|
|
12417
|
-
import
|
|
12734
|
+
import chalk13 from "chalk";
|
|
12418
12735
|
import ora5 from "ora";
|
|
12419
12736
|
import { select } from "@inquirer/prompts";
|
|
12420
12737
|
async function config() {
|
|
@@ -12422,10 +12739,10 @@ async function config() {
|
|
|
12422
12739
|
try {
|
|
12423
12740
|
let credentials = await getValidCredentials2();
|
|
12424
12741
|
if (!credentials) {
|
|
12425
|
-
spinner.info(
|
|
12742
|
+
spinner.info(chalk13.yellow("Not logged in. Opening browser to authenticate..."));
|
|
12426
12743
|
credentials = await performLogin();
|
|
12427
12744
|
const { email } = decodeIdToken(credentials.idToken);
|
|
12428
|
-
spinner.succeed(
|
|
12745
|
+
spinner.succeed(chalk13.green(`Authenticated as ${chalk13.bold(email)}`));
|
|
12429
12746
|
} else {
|
|
12430
12747
|
spinner.succeed("Authenticated");
|
|
12431
12748
|
}
|
|
@@ -12433,7 +12750,7 @@ async function config() {
|
|
|
12433
12750
|
const repos = await apiRequest("/v1/repos");
|
|
12434
12751
|
spinner.stop();
|
|
12435
12752
|
if (repos.length === 0) {
|
|
12436
|
-
console.log(
|
|
12753
|
+
console.log(chalk13.yellow("No repositories connected. Run `repowise create` first."));
|
|
12437
12754
|
return;
|
|
12438
12755
|
}
|
|
12439
12756
|
const repoId = await select({
|
|
@@ -12447,10 +12764,10 @@ async function config() {
|
|
|
12447
12764
|
const currentDelivery = repo.deliveryMode ?? "direct";
|
|
12448
12765
|
const currentBranch = repo.monitoredBranch ?? repo.defaultBranch;
|
|
12449
12766
|
console.log("");
|
|
12450
|
-
console.log(
|
|
12451
|
-
console.log(
|
|
12452
|
-
console.log(
|
|
12453
|
-
console.log(
|
|
12767
|
+
console.log(chalk13.bold(`Settings for ${repo.fullName}`));
|
|
12768
|
+
console.log(chalk13.dim(` Context storage: RepoWise servers`));
|
|
12769
|
+
console.log(chalk13.dim(` Delivery mode: ${currentDelivery}`));
|
|
12770
|
+
console.log(chalk13.dim(` Monitored branch: ${currentBranch}`));
|
|
12454
12771
|
console.log("");
|
|
12455
12772
|
const setting = await select({
|
|
12456
12773
|
message: "What would you like to change?",
|
|
@@ -12470,7 +12787,7 @@ async function config() {
|
|
|
12470
12787
|
default: currentDelivery
|
|
12471
12788
|
});
|
|
12472
12789
|
if (newMode === currentDelivery) {
|
|
12473
|
-
console.log(
|
|
12790
|
+
console.log(chalk13.dim("No change."));
|
|
12474
12791
|
return;
|
|
12475
12792
|
}
|
|
12476
12793
|
patch.deliveryMode = newMode;
|
|
@@ -12481,7 +12798,7 @@ async function config() {
|
|
|
12481
12798
|
default: currentBranch
|
|
12482
12799
|
});
|
|
12483
12800
|
if (newBranch === currentBranch) {
|
|
12484
|
-
console.log(
|
|
12801
|
+
console.log(chalk13.dim("No change."));
|
|
12485
12802
|
return;
|
|
12486
12803
|
}
|
|
12487
12804
|
patch.monitoredBranch = newBranch;
|
|
@@ -12491,11 +12808,11 @@ async function config() {
|
|
|
12491
12808
|
method: "PATCH",
|
|
12492
12809
|
body: JSON.stringify(patch)
|
|
12493
12810
|
});
|
|
12494
|
-
spinner.succeed(
|
|
12811
|
+
spinner.succeed(chalk13.green("Setting updated"));
|
|
12495
12812
|
} catch (err) {
|
|
12496
12813
|
spinner.stop();
|
|
12497
12814
|
const message = err instanceof Error ? err.message : "Config failed";
|
|
12498
|
-
console.error(
|
|
12815
|
+
console.error(chalk13.red(message));
|
|
12499
12816
|
process.exitCode = 1;
|
|
12500
12817
|
}
|
|
12501
12818
|
}
|
|
@@ -12503,7 +12820,7 @@ async function config() {
|
|
|
12503
12820
|
// src/commands/mcp-log.ts
|
|
12504
12821
|
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
12505
12822
|
import { mkdir as mkdir18, readFile as readFile17, stat as stat6, writeFile as writeFile18 } from "fs/promises";
|
|
12506
|
-
import { dirname as dirname18, join as
|
|
12823
|
+
import { dirname as dirname18, join as join45 } from "path";
|
|
12507
12824
|
var FLAG_FILE = "mcp-log.flag";
|
|
12508
12825
|
var LOG_FILE = "mcp-log.jsonl.enc";
|
|
12509
12826
|
var KEY_FILE = "mcp-log.key";
|
|
@@ -12511,10 +12828,10 @@ var ENDPOINT_FILE = "listener.endpoint";
|
|
|
12511
12828
|
var IV_BYTES2 = 12;
|
|
12512
12829
|
var TAG_BYTES2 = 16;
|
|
12513
12830
|
function flagPath() {
|
|
12514
|
-
return
|
|
12831
|
+
return join45(getConfigDir2(), FLAG_FILE);
|
|
12515
12832
|
}
|
|
12516
12833
|
function logPath() {
|
|
12517
|
-
return
|
|
12834
|
+
return join45(getConfigDir2(), LOG_FILE);
|
|
12518
12835
|
}
|
|
12519
12836
|
async function writeFlag(flag) {
|
|
12520
12837
|
const path = flagPath();
|
|
@@ -12555,14 +12872,14 @@ async function trySendConsentToServer() {
|
|
|
12555
12872
|
let apiUrl = null;
|
|
12556
12873
|
let token = null;
|
|
12557
12874
|
try {
|
|
12558
|
-
const body = await readFile17(
|
|
12875
|
+
const body = await readFile17(join45(getConfigDir2(), "config.json"), "utf-8");
|
|
12559
12876
|
const parsed = JSON.parse(body);
|
|
12560
12877
|
apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
|
|
12561
12878
|
} catch {
|
|
12562
12879
|
return false;
|
|
12563
12880
|
}
|
|
12564
12881
|
try {
|
|
12565
|
-
const body = await readFile17(
|
|
12882
|
+
const body = await readFile17(join45(getConfigDir2(), "credentials.json"), "utf-8");
|
|
12566
12883
|
const parsed = JSON.parse(body);
|
|
12567
12884
|
token = parsed.idToken ?? null;
|
|
12568
12885
|
} catch {
|
|
@@ -12632,7 +12949,7 @@ async function mcpLogStatus() {
|
|
|
12632
12949
|
process.stderr.write("Log size: no file yet\n");
|
|
12633
12950
|
}
|
|
12634
12951
|
try {
|
|
12635
|
-
const endpointBody = await readFile17(
|
|
12952
|
+
const endpointBody = await readFile17(join45(getConfigDir2(), ENDPOINT_FILE), "utf-8");
|
|
12636
12953
|
const match = /endpoint=([^\n]+)/.exec(endpointBody);
|
|
12637
12954
|
process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
|
|
12638
12955
|
`);
|
|
@@ -12663,7 +12980,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
12663
12980
|
const key = await readKey();
|
|
12664
12981
|
if (!key) {
|
|
12665
12982
|
process.stderr.write(
|
|
12666
|
-
`No encryption key at ${
|
|
12983
|
+
`No encryption key at ${join45(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
|
|
12667
12984
|
`
|
|
12668
12985
|
);
|
|
12669
12986
|
return;
|
|
@@ -12739,7 +13056,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
12739
13056
|
}
|
|
12740
13057
|
async function readKey() {
|
|
12741
13058
|
try {
|
|
12742
|
-
const body = await readFile17(
|
|
13059
|
+
const body = await readFile17(join45(getConfigDir2(), KEY_FILE), "utf-8");
|
|
12743
13060
|
const parsed = Buffer.from(body.trim(), "base64");
|
|
12744
13061
|
if (parsed.length !== 32) return null;
|
|
12745
13062
|
return parsed;
|
|
@@ -12779,11 +13096,11 @@ async function mcpLog(subcommand, flags = {}) {
|
|
|
12779
13096
|
}
|
|
12780
13097
|
|
|
12781
13098
|
// src/commands/query/_shared.ts
|
|
12782
|
-
import
|
|
13099
|
+
import chalk14 from "chalk";
|
|
12783
13100
|
|
|
12784
13101
|
// src/lib/graph-loader.ts
|
|
12785
|
-
import { promises as
|
|
12786
|
-
import { join as
|
|
13102
|
+
import { promises as fs19 } from "fs";
|
|
13103
|
+
import { join as join46, resolve as resolve2 } from "path";
|
|
12787
13104
|
import { gunzipSync } from "zlib";
|
|
12788
13105
|
var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
|
|
12789
13106
|
var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
|
|
@@ -12800,8 +13117,8 @@ var GraphNotFoundError = class extends Error {
|
|
|
12800
13117
|
var cache = /* @__PURE__ */ new Map();
|
|
12801
13118
|
async function loadGraph(repoRoot = process.cwd()) {
|
|
12802
13119
|
const root = resolve2(repoRoot);
|
|
12803
|
-
const gzPath =
|
|
12804
|
-
const plainPath =
|
|
13120
|
+
const gzPath = join46(root, GZIPPED_GRAPH_PATH);
|
|
13121
|
+
const plainPath = join46(root, RELATIVE_GRAPH_PATH);
|
|
12805
13122
|
const cached = cache.get(root);
|
|
12806
13123
|
if (cached) {
|
|
12807
13124
|
return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
|
|
@@ -12809,14 +13126,14 @@ async function loadGraph(repoRoot = process.cwd()) {
|
|
|
12809
13126
|
let graphPath = null;
|
|
12810
13127
|
let raw = null;
|
|
12811
13128
|
try {
|
|
12812
|
-
raw = await
|
|
13129
|
+
raw = await fs19.readFile(gzPath);
|
|
12813
13130
|
graphPath = gzPath;
|
|
12814
13131
|
} catch (err) {
|
|
12815
13132
|
if (err.code !== "ENOENT") throw err;
|
|
12816
13133
|
}
|
|
12817
13134
|
if (!raw) {
|
|
12818
13135
|
try {
|
|
12819
|
-
raw = await
|
|
13136
|
+
raw = await fs19.readFile(plainPath);
|
|
12820
13137
|
graphPath = plainPath;
|
|
12821
13138
|
} catch (err) {
|
|
12822
13139
|
if (err.code === "ENOENT") {
|
|
@@ -13019,7 +13336,7 @@ async function loadService() {
|
|
|
13019
13336
|
return createGraphQueryService(graph);
|
|
13020
13337
|
} catch (err) {
|
|
13021
13338
|
if (err instanceof GraphNotFoundError) {
|
|
13022
|
-
process.stderr.write(
|
|
13339
|
+
process.stderr.write(chalk14.red(`\u2717 ${err.message}
|
|
13023
13340
|
`));
|
|
13024
13341
|
process.exit(err.exitCode);
|
|
13025
13342
|
}
|
|
@@ -13215,14 +13532,14 @@ function registerQueryCommand(program2) {
|
|
|
13215
13532
|
}
|
|
13216
13533
|
|
|
13217
13534
|
// src/commands/uninstall.ts
|
|
13218
|
-
import { promises as
|
|
13535
|
+
import { promises as fs23 } from "fs";
|
|
13219
13536
|
import { homedir as homedir9 } from "os";
|
|
13220
|
-
import { join as
|
|
13221
|
-
import
|
|
13537
|
+
import { join as join50 } from "path";
|
|
13538
|
+
import chalk15 from "chalk";
|
|
13222
13539
|
|
|
13223
13540
|
// src/lib/cleanup/marker-blocks.ts
|
|
13224
|
-
import { promises as
|
|
13225
|
-
import { join as
|
|
13541
|
+
import { promises as fs20 } from "fs";
|
|
13542
|
+
import { join as join47 } from "path";
|
|
13226
13543
|
var MARKER_START = "<!-- repowise-start -->";
|
|
13227
13544
|
var MARKER_END = "<!-- repowise-end -->";
|
|
13228
13545
|
var CONTEXT_FILES = [
|
|
@@ -13238,7 +13555,7 @@ var CONTEXT_FILES = [
|
|
|
13238
13555
|
async function stripMarkerBlock(filePath) {
|
|
13239
13556
|
let raw;
|
|
13240
13557
|
try {
|
|
13241
|
-
raw = await
|
|
13558
|
+
raw = await fs20.readFile(filePath, "utf-8");
|
|
13242
13559
|
} catch (err) {
|
|
13243
13560
|
if (err.code === "ENOENT")
|
|
13244
13561
|
return { path: filePath, status: "missing" };
|
|
@@ -13253,16 +13570,16 @@ async function stripMarkerBlock(filePath) {
|
|
|
13253
13570
|
const after = raw.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
|
|
13254
13571
|
const stripped = (before + (before && after ? "\n\n" : "") + after).trim();
|
|
13255
13572
|
if (stripped.length === 0) {
|
|
13256
|
-
await
|
|
13573
|
+
await fs20.unlink(filePath);
|
|
13257
13574
|
return { path: filePath, status: "deleted" };
|
|
13258
13575
|
}
|
|
13259
|
-
await
|
|
13576
|
+
await fs20.writeFile(filePath, stripped + "\n", "utf-8");
|
|
13260
13577
|
return { path: filePath, status: "stripped" };
|
|
13261
13578
|
}
|
|
13262
13579
|
async function stripAllMarkerBlocks(repoRoot) {
|
|
13263
13580
|
const out = [];
|
|
13264
13581
|
for (const relative of CONTEXT_FILES) {
|
|
13265
|
-
const full =
|
|
13582
|
+
const full = join47(repoRoot, relative);
|
|
13266
13583
|
const result = await stripMarkerBlock(full).catch((err) => ({
|
|
13267
13584
|
path: full,
|
|
13268
13585
|
status: "untouched",
|
|
@@ -13274,25 +13591,25 @@ async function stripAllMarkerBlocks(repoRoot) {
|
|
|
13274
13591
|
}
|
|
13275
13592
|
|
|
13276
13593
|
// src/lib/cleanup/mcp-configs.ts
|
|
13277
|
-
import { promises as
|
|
13278
|
-
import { join as
|
|
13594
|
+
import { promises as fs21 } from "fs";
|
|
13595
|
+
import { join as join48 } from "path";
|
|
13279
13596
|
function mcpConfigPaths(repoRoot, home) {
|
|
13280
13597
|
return [
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13598
|
+
join48(repoRoot, ".mcp.json"),
|
|
13599
|
+
join48(repoRoot, ".cursor", "mcp.json"),
|
|
13600
|
+
join48(repoRoot, ".vscode", "mcp.json"),
|
|
13601
|
+
join48(repoRoot, ".roo", "mcp.json"),
|
|
13602
|
+
join48(home, ".cline", "mcp.json"),
|
|
13603
|
+
join48(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
13604
|
+
join48(home, ".gemini", "settings.json"),
|
|
13605
|
+
join48(home, ".codex", "mcp.json"),
|
|
13606
|
+
join48(home, ".roo", "mcp.json")
|
|
13290
13607
|
];
|
|
13291
13608
|
}
|
|
13292
13609
|
async function removeRepowiseFromConfig(path, serverName) {
|
|
13293
13610
|
let raw;
|
|
13294
13611
|
try {
|
|
13295
|
-
raw = await
|
|
13612
|
+
raw = await fs21.readFile(path, "utf-8");
|
|
13296
13613
|
} catch (err) {
|
|
13297
13614
|
if (err.code === "ENOENT") return { path, status: "not-found" };
|
|
13298
13615
|
return { path, status: "error", error: err.message };
|
|
@@ -13312,7 +13629,7 @@ async function removeRepowiseFromConfig(path, serverName) {
|
|
|
13312
13629
|
} else {
|
|
13313
13630
|
next.mcpServers = servers;
|
|
13314
13631
|
}
|
|
13315
|
-
await
|
|
13632
|
+
await fs21.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
13316
13633
|
return { path, status: "removed" };
|
|
13317
13634
|
}
|
|
13318
13635
|
async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
@@ -13325,17 +13642,17 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
|
13325
13642
|
}
|
|
13326
13643
|
|
|
13327
13644
|
// src/lib/cleanup/local-state.ts
|
|
13328
|
-
import { promises as
|
|
13645
|
+
import { promises as fs22 } from "fs";
|
|
13329
13646
|
import { homedir as homedir8 } from "os";
|
|
13330
|
-
import { join as
|
|
13647
|
+
import { join as join49, resolve as resolve3 } from "path";
|
|
13331
13648
|
async function clearLocalState(homeOverride) {
|
|
13332
13649
|
const home = homeOverride ?? homedir8();
|
|
13333
|
-
const target = resolve3(
|
|
13650
|
+
const target = resolve3(join49(home, ".repowise"));
|
|
13334
13651
|
if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
|
|
13335
13652
|
return { path: target, status: "error", error: "refused: not under home" };
|
|
13336
13653
|
}
|
|
13337
13654
|
try {
|
|
13338
|
-
await
|
|
13655
|
+
await fs22.rm(target, { recursive: true, force: false });
|
|
13339
13656
|
return { path: target, status: "removed" };
|
|
13340
13657
|
} catch (err) {
|
|
13341
13658
|
if (err.code === "ENOENT")
|
|
@@ -13374,7 +13691,7 @@ async function uninstall2(opts = {}) {
|
|
|
13374
13691
|
else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
|
|
13375
13692
|
if (tier === "stop") return report;
|
|
13376
13693
|
try {
|
|
13377
|
-
await
|
|
13694
|
+
await fs23.unlink(join50(home, ".repowise", "credentials.json"));
|
|
13378
13695
|
report.removed.push("credentials");
|
|
13379
13696
|
} catch (err) {
|
|
13380
13697
|
if (err.code !== "ENOENT") {
|
|
@@ -13401,7 +13718,7 @@ async function uninstall2(opts = {}) {
|
|
|
13401
13718
|
const allPaths = mcpConfigPaths(repoRoot, home);
|
|
13402
13719
|
for (const p of allPaths) {
|
|
13403
13720
|
try {
|
|
13404
|
-
await
|
|
13721
|
+
await fs23.access(p);
|
|
13405
13722
|
} catch {
|
|
13406
13723
|
}
|
|
13407
13724
|
}
|
|
@@ -13413,7 +13730,7 @@ async function uninstall2(opts = {}) {
|
|
|
13413
13730
|
}
|
|
13414
13731
|
async function defaultLoadRepoIds(home) {
|
|
13415
13732
|
try {
|
|
13416
|
-
const raw = await
|
|
13733
|
+
const raw = await fs23.readFile(join50(home, ".repowise", "config.json"), "utf-8");
|
|
13417
13734
|
const parsed = JSON.parse(raw);
|
|
13418
13735
|
return (parsed.repos ?? []).map((r) => r.repoId);
|
|
13419
13736
|
} catch {
|
|
@@ -13430,29 +13747,29 @@ async function uninstallCommand(opts = {}) {
|
|
|
13430
13747
|
default: false
|
|
13431
13748
|
});
|
|
13432
13749
|
if (!proceed) {
|
|
13433
|
-
process.stderr.write(
|
|
13750
|
+
process.stderr.write(chalk15.yellow("Uninstall cancelled.\n"));
|
|
13434
13751
|
process.exitCode = 1;
|
|
13435
13752
|
return;
|
|
13436
13753
|
}
|
|
13437
13754
|
}
|
|
13438
13755
|
}
|
|
13439
|
-
process.stderr.write(
|
|
13756
|
+
process.stderr.write(chalk15.bold(`RepoWise ${tier}
|
|
13440
13757
|
`));
|
|
13441
13758
|
const report = await uninstall2({ ...opts, tier });
|
|
13442
13759
|
for (const p of report.removed) {
|
|
13443
|
-
process.stderr.write(
|
|
13760
|
+
process.stderr.write(chalk15.green(` \u2713 removed: ${p}
|
|
13444
13761
|
`));
|
|
13445
13762
|
}
|
|
13446
13763
|
for (const p of report.preserved) {
|
|
13447
|
-
process.stderr.write(
|
|
13764
|
+
process.stderr.write(chalk15.gray(` \xB7 preserved: ${p}
|
|
13448
13765
|
`));
|
|
13449
13766
|
}
|
|
13450
13767
|
for (const s of report.skipped) {
|
|
13451
|
-
process.stderr.write(
|
|
13768
|
+
process.stderr.write(chalk15.yellow(` ! skipped: ${s.path} (${s.reason})
|
|
13452
13769
|
`));
|
|
13453
13770
|
}
|
|
13454
13771
|
process.stderr.write(
|
|
13455
|
-
|
|
13772
|
+
chalk15.bold(`
|
|
13456
13773
|
Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
13457
13774
|
`)
|
|
13458
13775
|
);
|
|
@@ -13460,12 +13777,12 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
|
13460
13777
|
|
|
13461
13778
|
// src/commands/mcp-shim.ts
|
|
13462
13779
|
init_config_dir();
|
|
13463
|
-
import { promises as
|
|
13780
|
+
import { promises as fs24 } from "fs";
|
|
13464
13781
|
import { createInterface as createInterface2 } from "readline";
|
|
13465
|
-
import { join as
|
|
13782
|
+
import { join as join51 } from "path";
|
|
13466
13783
|
var DEFAULT_MAX = 200 * 1024;
|
|
13467
13784
|
async function mcpShim(opts) {
|
|
13468
|
-
const endpointPath = opts.endpointFile ??
|
|
13785
|
+
const endpointPath = opts.endpointFile ?? join51(getConfigDir(), "listener.endpoint");
|
|
13469
13786
|
const stdin = opts.stdin ?? process.stdin;
|
|
13470
13787
|
const stdout = opts.stdout ?? process.stdout;
|
|
13471
13788
|
const stderr = opts.stderr ?? process.stderr;
|
|
@@ -13538,7 +13855,7 @@ async function mcpShim(opts) {
|
|
|
13538
13855
|
}
|
|
13539
13856
|
async function readEndpoint(path) {
|
|
13540
13857
|
try {
|
|
13541
|
-
const raw = (await
|
|
13858
|
+
const raw = (await fs24.readFile(path, "utf-8")).trim();
|
|
13542
13859
|
if (!raw) return null;
|
|
13543
13860
|
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
13544
13861
|
return { endpoint: raw.split("\n")[0].trim(), secret: null };
|
|
@@ -13780,7 +14097,7 @@ init_coursier_installer();
|
|
|
13780
14097
|
init_toolchain_installer();
|
|
13781
14098
|
import { spawn as spawn11 } from "child_process";
|
|
13782
14099
|
import { resolve as resolve4 } from "path";
|
|
13783
|
-
import
|
|
14100
|
+
import chalk16 from "chalk";
|
|
13784
14101
|
async function isOnPath(command) {
|
|
13785
14102
|
if (/[^\w./+-]/.test(command)) return false;
|
|
13786
14103
|
const isWin = process.platform === "win32";
|
|
@@ -13798,14 +14115,14 @@ async function isOnPath(command) {
|
|
|
13798
14115
|
async function lspDoctor() {
|
|
13799
14116
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13800
14117
|
if (noColor) {
|
|
13801
|
-
|
|
14118
|
+
chalk16.level = 0;
|
|
13802
14119
|
}
|
|
13803
|
-
const okGlyph = noColor ? "[OK]" :
|
|
13804
|
-
const missingGlyph = noColor ? "[MISSING]" :
|
|
13805
|
-
console.log(
|
|
13806
|
-
console.log(
|
|
14120
|
+
const okGlyph = noColor ? "[OK]" : chalk16.green("\u2713");
|
|
14121
|
+
const missingGlyph = noColor ? "[MISSING]" : chalk16.yellow("\u2717");
|
|
14122
|
+
console.log(chalk16.bold("RepoWise LSP doctor"));
|
|
14123
|
+
console.log(chalk16.dim("Probing PATH for language servers used by the listener."));
|
|
13807
14124
|
console.log(
|
|
13808
|
-
|
|
14125
|
+
chalk16.dim(
|
|
13809
14126
|
"Type-aware resolution covers 9 languages: Go, Python, Rust, Java, Ruby, Dart, Kotlin, PHP, Scala (Phase 7L + 7L++ + 7L+)."
|
|
13810
14127
|
)
|
|
13811
14128
|
);
|
|
@@ -13837,21 +14154,21 @@ async function lspDoctor() {
|
|
|
13837
14154
|
const missing = reports.filter((r) => r.status === "missing").length;
|
|
13838
14155
|
for (const r of reports) {
|
|
13839
14156
|
const head = r.status === "found" ? okGlyph : missingGlyph;
|
|
13840
|
-
const cmd = r.command ?
|
|
14157
|
+
const cmd = r.command ? chalk16.cyan(r.command) : chalk16.dim(r.candidates.join(" / "));
|
|
13841
14158
|
const effectiveConfigs = getEffectiveConfigList(r.language, process.env, lspOverrides);
|
|
13842
14159
|
const method = describeInstallMethod(effectiveConfigs);
|
|
13843
|
-
console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${
|
|
14160
|
+
console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${chalk16.dim(`[${method}]`)}`);
|
|
13844
14161
|
if (r.status === "missing" && r.hint) {
|
|
13845
|
-
console.log(` ${
|
|
14162
|
+
console.log(` ${chalk16.dim("install:")} ${r.hint}`);
|
|
13846
14163
|
}
|
|
13847
14164
|
}
|
|
13848
14165
|
console.log();
|
|
13849
14166
|
console.log(
|
|
13850
|
-
`${
|
|
14167
|
+
`${chalk16.green(found.toString())} found, ${chalk16.yellow(missing.toString())} missing of ${reports.length.toString()} languages.`
|
|
13851
14168
|
);
|
|
13852
14169
|
if (missing > 0) {
|
|
13853
14170
|
console.log(
|
|
13854
|
-
|
|
14171
|
+
chalk16.dim(
|
|
13855
14172
|
"Missing servers degrade LSP-backed MCP tools to AST-only fallback. Run `repowise lsp install` to auto-install."
|
|
13856
14173
|
)
|
|
13857
14174
|
);
|
|
@@ -13868,15 +14185,15 @@ function describeInstallMethod(configs) {
|
|
|
13868
14185
|
}
|
|
13869
14186
|
async function lspInstall(language) {
|
|
13870
14187
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13871
|
-
if (noColor)
|
|
13872
|
-
console.log(
|
|
14188
|
+
if (noColor) chalk16.level = 0;
|
|
14189
|
+
console.log(chalk16.bold("RepoWise LSP install"));
|
|
13873
14190
|
const cliConfig = await getConfig();
|
|
13874
14191
|
const lspOverrides = cliConfig.lspOverrides;
|
|
13875
14192
|
const targets = language ? [language] : Object.keys(LSP_REGISTRY);
|
|
13876
14193
|
for (const lang of targets) {
|
|
13877
14194
|
const configs = getEffectiveConfigList(lang, process.env, lspOverrides);
|
|
13878
14195
|
if (!configs || configs.length === 0) {
|
|
13879
|
-
console.log(` ${
|
|
14196
|
+
console.log(` ${chalk16.red("\u2717")} ${lang} ${chalk16.dim("(unknown language)")}`);
|
|
13880
14197
|
continue;
|
|
13881
14198
|
}
|
|
13882
14199
|
const result = await installOneLanguage(configs);
|
|
@@ -13944,11 +14261,11 @@ async function installOneLanguage(configs) {
|
|
|
13944
14261
|
};
|
|
13945
14262
|
}
|
|
13946
14263
|
function formatInstallLine(lang, outcome) {
|
|
13947
|
-
const glyph = outcome.ok ?
|
|
13948
|
-
const tag =
|
|
14264
|
+
const glyph = outcome.ok ? chalk16.green("\u2713") : chalk16.yellow("\u2717");
|
|
14265
|
+
const tag = chalk16.dim(`[${outcome.method}]`);
|
|
13949
14266
|
console.log(` ${glyph} ${lang.padEnd(12)} ${tag} ${outcome.detail}`);
|
|
13950
14267
|
if (!outcome.ok && outcome.hint) {
|
|
13951
|
-
console.log(` ${
|
|
14268
|
+
console.log(` ${chalk16.dim("install:")} ${outcome.hint}`);
|
|
13952
14269
|
}
|
|
13953
14270
|
}
|
|
13954
14271
|
var MAX_KEEP_WARM_MINUTES = 240;
|
|
@@ -13986,42 +14303,42 @@ async function autoDetectLanguages(cwd) {
|
|
|
13986
14303
|
async function lspWarm(opts = {}) {
|
|
13987
14304
|
const cwd = resolve4(opts.cwd ?? process.cwd());
|
|
13988
14305
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13989
|
-
if (noColor)
|
|
14306
|
+
if (noColor) chalk16.level = 0;
|
|
13990
14307
|
let languages;
|
|
13991
14308
|
if (opts.lang && opts.lang.length > 0) {
|
|
13992
14309
|
const valid = Object.keys(LSP_REGISTRY);
|
|
13993
14310
|
languages = opts.lang.filter((l) => valid.includes(l));
|
|
13994
14311
|
const invalid = opts.lang.filter((l) => !valid.includes(l));
|
|
13995
14312
|
if (invalid.length > 0) {
|
|
13996
|
-
console.log(
|
|
14313
|
+
console.log(chalk16.yellow(`[lsp warm] unknown languages skipped: ${invalid.join(", ")}`));
|
|
13997
14314
|
}
|
|
13998
14315
|
} else {
|
|
13999
14316
|
languages = await autoDetectLanguages(cwd);
|
|
14000
14317
|
if (languages.length === 0) {
|
|
14001
14318
|
console.log(
|
|
14002
|
-
|
|
14319
|
+
chalk16.yellow(
|
|
14003
14320
|
"[lsp warm] no recognised source files in this repo \u2014 pass --lang <id> to force a server."
|
|
14004
14321
|
)
|
|
14005
14322
|
);
|
|
14006
14323
|
return;
|
|
14007
14324
|
}
|
|
14008
|
-
console.log(
|
|
14325
|
+
console.log(chalk16.dim(`[lsp warm] auto-detected languages: ${languages.join(", ")}`));
|
|
14009
14326
|
}
|
|
14010
14327
|
let keepWarmMinutes = 0;
|
|
14011
14328
|
if (typeof opts.keepWarm === "number" && opts.keepWarm > 0) {
|
|
14012
14329
|
keepWarmMinutes = Math.min(opts.keepWarm, MAX_KEEP_WARM_MINUTES);
|
|
14013
14330
|
if (opts.keepWarm > MAX_KEEP_WARM_MINUTES) {
|
|
14014
14331
|
console.log(
|
|
14015
|
-
|
|
14332
|
+
chalk16.yellow(
|
|
14016
14333
|
`[lsp warm] --keep-warm clipped to ${MAX_KEEP_WARM_MINUTES.toString()} minutes (hard cap per Phase 7L plan).`
|
|
14017
14334
|
)
|
|
14018
14335
|
);
|
|
14019
14336
|
}
|
|
14020
14337
|
}
|
|
14021
|
-
console.log(
|
|
14022
|
-
console.log(
|
|
14338
|
+
console.log(chalk16.bold("RepoWise LSP warm \u2014 preview"));
|
|
14339
|
+
console.log(chalk16.dim(`Workspace: ${cwd}`));
|
|
14023
14340
|
console.log(
|
|
14024
|
-
|
|
14341
|
+
chalk16.dim(
|
|
14025
14342
|
"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
14343
|
)
|
|
14027
14344
|
);
|
|
@@ -14037,23 +14354,23 @@ async function lspWarm(opts = {}) {
|
|
|
14037
14354
|
if (onPath) {
|
|
14038
14355
|
foundCount += 1;
|
|
14039
14356
|
console.log(
|
|
14040
|
-
|
|
14357
|
+
chalk16.green(` \u2713 ${lang.padEnd(12)} ${config2.displayName} (${config2.command}) on PATH`)
|
|
14041
14358
|
);
|
|
14042
14359
|
} else {
|
|
14043
14360
|
missingCount += 1;
|
|
14044
|
-
console.log(
|
|
14361
|
+
console.log(chalk16.yellow(` \u2717 ${lang.padEnd(12)} ${config2.displayName} not on PATH`));
|
|
14045
14362
|
if (config2.installHint) {
|
|
14046
|
-
console.log(
|
|
14363
|
+
console.log(chalk16.dim(` install: ${config2.installHint}`));
|
|
14047
14364
|
}
|
|
14048
14365
|
}
|
|
14049
14366
|
}
|
|
14050
14367
|
console.log();
|
|
14051
14368
|
console.log(
|
|
14052
|
-
`${
|
|
14369
|
+
`${chalk16.green(foundCount.toString())} ready, ${chalk16.yellow(missingCount.toString())} missing.`
|
|
14053
14370
|
);
|
|
14054
14371
|
if (keepWarmMinutes > 0) {
|
|
14055
14372
|
console.log(
|
|
14056
|
-
|
|
14373
|
+
chalk16.dim(
|
|
14057
14374
|
`Holding for ${keepWarmMinutes.toString()} minute(s) so the listener has time to spawn on its next sync.completed; Ctrl-C to exit early.`
|
|
14058
14375
|
)
|
|
14059
14376
|
);
|
|
@@ -14070,20 +14387,20 @@ async function lspWarm(opts = {}) {
|
|
|
14070
14387
|
}
|
|
14071
14388
|
function lspStatus() {
|
|
14072
14389
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14073
|
-
if (noColor)
|
|
14074
|
-
console.log(
|
|
14390
|
+
if (noColor) chalk16.level = 0;
|
|
14391
|
+
console.log(chalk16.bold("RepoWise LSP status"));
|
|
14075
14392
|
console.log(
|
|
14076
|
-
|
|
14393
|
+
chalk16.dim(
|
|
14077
14394
|
"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
14395
|
)
|
|
14079
14396
|
);
|
|
14080
14397
|
console.log();
|
|
14081
|
-
console.log(
|
|
14398
|
+
console.log(chalk16.dim("See `repowise lsp doctor` for PATH probe + install hints."));
|
|
14082
14399
|
}
|
|
14083
14400
|
function lspStop() {
|
|
14084
|
-
console.log(
|
|
14401
|
+
console.log(chalk16.bold("RepoWise LSP stop \u2014 preview"));
|
|
14085
14402
|
console.log(
|
|
14086
|
-
|
|
14403
|
+
chalk16.dim(
|
|
14087
14404
|
"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
14405
|
)
|
|
14089
14406
|
);
|
|
@@ -14106,29 +14423,29 @@ var ENABLE_TARGETS = {
|
|
|
14106
14423
|
};
|
|
14107
14424
|
async function lspEnable(target) {
|
|
14108
14425
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14109
|
-
if (noColor)
|
|
14426
|
+
if (noColor) chalk16.level = 0;
|
|
14110
14427
|
if (!target) {
|
|
14111
|
-
console.error(
|
|
14112
|
-
console.error(
|
|
14428
|
+
console.error(chalk16.red("Usage: repowise lsp enable <target>"));
|
|
14429
|
+
console.error(chalk16.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14113
14430
|
process.exitCode = 1;
|
|
14114
14431
|
return;
|
|
14115
14432
|
}
|
|
14116
14433
|
const spec = ENABLE_TARGETS[target];
|
|
14117
14434
|
if (!spec) {
|
|
14118
|
-
console.error(
|
|
14119
|
-
console.error(
|
|
14435
|
+
console.error(chalk16.red(`\u2716 Unknown LSP override target: ${target}`));
|
|
14436
|
+
console.error(chalk16.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14120
14437
|
process.exitCode = 1;
|
|
14121
14438
|
return;
|
|
14122
14439
|
}
|
|
14123
14440
|
const config2 = await getConfig();
|
|
14124
14441
|
const existing = config2.lspOverrides?.[spec.language];
|
|
14125
14442
|
if (existing === spec.name) {
|
|
14126
|
-
console.log(
|
|
14127
|
-
console.log(
|
|
14443
|
+
console.log(chalk16.green(`\u2714 ${spec.displayName} is already enabled.`));
|
|
14444
|
+
console.log(chalk16.dim(` ${spec.postAcceptTip}`));
|
|
14128
14445
|
return;
|
|
14129
14446
|
}
|
|
14130
14447
|
console.log();
|
|
14131
|
-
console.log(
|
|
14448
|
+
console.log(chalk16.cyan.bold(` \u2500\u2500 Enable ${spec.displayName} \u2500\u2500`));
|
|
14132
14449
|
for (const line of spec.consentLines) {
|
|
14133
14450
|
console.log(` ${line}`);
|
|
14134
14451
|
}
|
|
@@ -14139,47 +14456,82 @@ async function lspEnable(target) {
|
|
|
14139
14456
|
default: false
|
|
14140
14457
|
});
|
|
14141
14458
|
if (!proceed) {
|
|
14142
|
-
console.log(
|
|
14459
|
+
console.log(
|
|
14460
|
+
chalk16.dim(
|
|
14461
|
+
` Cancelled. ${spec.language.toUpperCase()} will continue using ${spec.revertDisplay}.`
|
|
14462
|
+
)
|
|
14463
|
+
);
|
|
14143
14464
|
return;
|
|
14144
14465
|
}
|
|
14145
14466
|
const nextOverrides = { ...config2.lspOverrides ?? {}, [spec.language]: spec.name };
|
|
14146
14467
|
await mergeAndSaveConfig({ lspOverrides: nextOverrides });
|
|
14147
|
-
console.log(
|
|
14148
|
-
|
|
14468
|
+
console.log(
|
|
14469
|
+
chalk16.green(
|
|
14470
|
+
` \u2714 ${spec.displayName} enabled \u2014 listener will use it within ~5 min (reconcile cycle) or on next session restart.`
|
|
14471
|
+
)
|
|
14472
|
+
);
|
|
14473
|
+
console.log(chalk16.dim(` \u2139 ${spec.postAcceptTip}`));
|
|
14149
14474
|
}
|
|
14150
14475
|
async function lspDisable(target) {
|
|
14151
14476
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14152
|
-
if (noColor)
|
|
14477
|
+
if (noColor) chalk16.level = 0;
|
|
14153
14478
|
if (!target) {
|
|
14154
|
-
console.error(
|
|
14155
|
-
console.error(
|
|
14479
|
+
console.error(chalk16.red("Usage: repowise lsp disable <target>"));
|
|
14480
|
+
console.error(chalk16.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14156
14481
|
process.exitCode = 1;
|
|
14157
14482
|
return;
|
|
14158
14483
|
}
|
|
14159
14484
|
const spec = ENABLE_TARGETS[target];
|
|
14160
14485
|
if (!spec) {
|
|
14161
|
-
console.error(
|
|
14162
|
-
console.error(
|
|
14486
|
+
console.error(chalk16.red(`\u2716 Unknown LSP override target: ${target}`));
|
|
14487
|
+
console.error(chalk16.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14163
14488
|
process.exitCode = 1;
|
|
14164
14489
|
return;
|
|
14165
14490
|
}
|
|
14166
14491
|
const config2 = await getConfig();
|
|
14167
14492
|
const current = config2.lspOverrides?.[spec.language];
|
|
14168
14493
|
if (current !== spec.name) {
|
|
14169
|
-
console.log(
|
|
14494
|
+
console.log(chalk16.dim(` ${spec.displayName} is not enabled \u2014 nothing to do.`));
|
|
14170
14495
|
return;
|
|
14171
14496
|
}
|
|
14172
14497
|
const { [spec.language]: _removed, ...rest } = config2.lspOverrides ?? {};
|
|
14173
14498
|
void _removed;
|
|
14174
14499
|
const nextOverrides = Object.keys(rest).length > 0 ? rest : void 0;
|
|
14175
|
-
await mergeAndSaveConfig({
|
|
14176
|
-
|
|
14500
|
+
await mergeAndSaveConfig({
|
|
14501
|
+
...nextOverrides ? { lspOverrides: nextOverrides } : { lspOverrides: void 0 }
|
|
14502
|
+
});
|
|
14503
|
+
console.log(
|
|
14504
|
+
chalk16.green(
|
|
14505
|
+
` \u2714 ${spec.displayName} disabled \u2014 listener will revert to ${spec.revertDisplay} within ~5 min or on next session restart.`
|
|
14506
|
+
)
|
|
14507
|
+
);
|
|
14508
|
+
}
|
|
14509
|
+
async function lspOff() {
|
|
14510
|
+
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14511
|
+
if (noColor) chalk16.level = 0;
|
|
14512
|
+
await mergeAndSaveConfig({ lspEnabled: false });
|
|
14513
|
+
console.log(
|
|
14514
|
+
chalk16.green(
|
|
14515
|
+
" \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."
|
|
14516
|
+
)
|
|
14517
|
+
);
|
|
14518
|
+
console.log(chalk16.dim(" Re-enable with: repowise lsp on"));
|
|
14519
|
+
}
|
|
14520
|
+
async function lspOn() {
|
|
14521
|
+
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14522
|
+
if (noColor) chalk16.level = 0;
|
|
14523
|
+
await mergeAndSaveConfig({ lspEnabled: true });
|
|
14524
|
+
console.log(
|
|
14525
|
+
chalk16.green(
|
|
14526
|
+
" \u2714 LSP subsystem enabled. The listener will install + warm language servers for your repos within ~5 min (reconcile) or on next restart."
|
|
14527
|
+
)
|
|
14528
|
+
);
|
|
14177
14529
|
}
|
|
14178
14530
|
|
|
14179
14531
|
// bin/repowise.ts
|
|
14180
14532
|
var __filename = fileURLToPath4(import.meta.url);
|
|
14181
14533
|
var __dirname = dirname19(__filename);
|
|
14182
|
-
var pkg = JSON.parse(readFileSync3(
|
|
14534
|
+
var pkg = JSON.parse(readFileSync3(join52(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
14183
14535
|
var program = new Command();
|
|
14184
14536
|
program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
|
|
14185
14537
|
await showWelcome(pkg.version);
|
|
@@ -14249,6 +14601,12 @@ lspCommand.command("enable <target>").description("Opt into a non-default LSP (e
|
|
|
14249
14601
|
lspCommand.command("disable <target>").description("Revert an LSP override and fall back to the registry default").action(async (target) => {
|
|
14250
14602
|
await lspDisable(target);
|
|
14251
14603
|
});
|
|
14604
|
+
lspCommand.command("off").description("Disable the LSP subsystem entirely (kill-switch)").action(async () => {
|
|
14605
|
+
await lspOff();
|
|
14606
|
+
});
|
|
14607
|
+
lspCommand.command("on").description("Re-enable the LSP subsystem after `lsp off`").action(async () => {
|
|
14608
|
+
await lspOn();
|
|
14609
|
+
});
|
|
14252
14610
|
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
14611
|
const tier = options.tier ?? "uninstall";
|
|
14254
14612
|
await uninstallCommand({ tier, yes: options.yes });
|