repowisestage 0.0.52 → 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 +769 -314
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -944,38 +944,99 @@ var init_platforms = __esm({
|
|
|
944
944
|
});
|
|
945
945
|
|
|
946
946
|
// ../../packages/shared/src/constants/tiers.ts
|
|
947
|
-
var SUBSCRIPTION_TIERS, TIER_LIMITS;
|
|
947
|
+
var SUBSCRIPTION_TIERS, TIER_LIMITS, TIER_FEATURES;
|
|
948
948
|
var init_tiers = __esm({
|
|
949
949
|
"../../packages/shared/src/constants/tiers.ts"() {
|
|
950
950
|
"use strict";
|
|
951
951
|
SUBSCRIPTION_TIERS = {
|
|
952
|
+
FREE: "free",
|
|
953
|
+
// `starter` is the legacy $15 tier — kept as a migration alias (with its OLD limits)
|
|
954
|
+
// until existing Starter subs are price-swapped to Free (pricing v3). Removed after M7.
|
|
952
955
|
STARTER: "starter",
|
|
953
956
|
PRO: "pro",
|
|
954
957
|
TEAM: "team"
|
|
955
958
|
};
|
|
956
959
|
TIER_LIMITS = {
|
|
960
|
+
[SUBSCRIPTION_TIERS.FREE]: {
|
|
961
|
+
maxRepos: 1,
|
|
962
|
+
maxSeats: 1,
|
|
963
|
+
minSeats: 1,
|
|
964
|
+
maxSyncsPerMonth: 4,
|
|
965
|
+
// manual-only, hard cap (no overage)
|
|
966
|
+
maxConcurrentSyncs: 1,
|
|
967
|
+
freeFullScans: 0,
|
|
968
|
+
// graph-only: no LLM full scan
|
|
969
|
+
bedrockEndpoint: "public"
|
|
970
|
+
},
|
|
971
|
+
// Legacy alias — retains the OLD Starter limits until existing Starter subs are
|
|
972
|
+
// migrated to Free, then removed (M7). Do NOT reference for new logic.
|
|
957
973
|
[SUBSCRIPTION_TIERS.STARTER]: {
|
|
958
974
|
maxRepos: 1,
|
|
959
975
|
maxSeats: 1,
|
|
976
|
+
minSeats: 1,
|
|
960
977
|
maxSyncsPerMonth: 10,
|
|
961
978
|
maxConcurrentSyncs: 1,
|
|
979
|
+
freeFullScans: 1,
|
|
962
980
|
bedrockEndpoint: "public"
|
|
963
981
|
},
|
|
964
982
|
[SUBSCRIPTION_TIERS.PRO]: {
|
|
965
|
-
maxRepos:
|
|
983
|
+
maxRepos: 1,
|
|
966
984
|
maxSeats: 1,
|
|
967
|
-
|
|
985
|
+
minSeats: 1,
|
|
986
|
+
maxSyncsPerMonth: 20,
|
|
968
987
|
maxConcurrentSyncs: 2,
|
|
988
|
+
freeFullScans: 1,
|
|
969
989
|
bedrockEndpoint: "public"
|
|
970
990
|
},
|
|
971
991
|
[SUBSCRIPTION_TIERS.TEAM]: {
|
|
972
|
-
maxRepos:
|
|
992
|
+
maxRepos: 1,
|
|
973
993
|
maxSeats: 999999,
|
|
994
|
+
minSeats: 3,
|
|
974
995
|
maxSyncsPerMonth: 30,
|
|
975
996
|
maxConcurrentSyncs: 10,
|
|
997
|
+
freeFullScans: 1,
|
|
976
998
|
bedrockEndpoint: "public"
|
|
977
999
|
}
|
|
978
1000
|
};
|
|
1001
|
+
TIER_FEATURES = {
|
|
1002
|
+
[SUBSCRIPTION_TIERS.FREE]: {
|
|
1003
|
+
knowledgeGraph: true,
|
|
1004
|
+
mcp: true,
|
|
1005
|
+
context: false,
|
|
1006
|
+
// LLM-generated narrative context docs
|
|
1007
|
+
docs: false,
|
|
1008
|
+
// RepoWise Docs
|
|
1009
|
+
autoSync: false,
|
|
1010
|
+
// auto-sync on merge (Free is manual-only)
|
|
1011
|
+
overage: false
|
|
1012
|
+
// pay-as-you-go syncs (Free is hard-capped)
|
|
1013
|
+
},
|
|
1014
|
+
// Legacy alias — full features until existing Starter subs migrate to Free.
|
|
1015
|
+
[SUBSCRIPTION_TIERS.STARTER]: {
|
|
1016
|
+
knowledgeGraph: true,
|
|
1017
|
+
mcp: true,
|
|
1018
|
+
context: true,
|
|
1019
|
+
docs: true,
|
|
1020
|
+
autoSync: true,
|
|
1021
|
+
overage: true
|
|
1022
|
+
},
|
|
1023
|
+
[SUBSCRIPTION_TIERS.PRO]: {
|
|
1024
|
+
knowledgeGraph: true,
|
|
1025
|
+
mcp: true,
|
|
1026
|
+
context: true,
|
|
1027
|
+
docs: true,
|
|
1028
|
+
autoSync: true,
|
|
1029
|
+
overage: true
|
|
1030
|
+
},
|
|
1031
|
+
[SUBSCRIPTION_TIERS.TEAM]: {
|
|
1032
|
+
knowledgeGraph: true,
|
|
1033
|
+
mcp: true,
|
|
1034
|
+
context: true,
|
|
1035
|
+
docs: true,
|
|
1036
|
+
autoSync: true,
|
|
1037
|
+
overage: true
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
979
1040
|
}
|
|
980
1041
|
});
|
|
981
1042
|
|
|
@@ -1958,6 +2019,7 @@ var init_toolchain_installer = __esm({
|
|
|
1958
2019
|
import { promises as fs4 } from "fs";
|
|
1959
2020
|
import { join as join17, dirname as dirname6 } from "path";
|
|
1960
2021
|
import { spawn as spawn7 } from "child_process";
|
|
2022
|
+
import lockfile3 from "proper-lockfile";
|
|
1961
2023
|
function getLspInstallDir() {
|
|
1962
2024
|
return join17(getConfigDir(), "lsp-servers");
|
|
1963
2025
|
}
|
|
@@ -1974,18 +2036,42 @@ async function ensureNpmLspInstalled(config2) {
|
|
|
1974
2036
|
}
|
|
1975
2037
|
try {
|
|
1976
2038
|
await fs4.mkdir(installDir, { recursive: true });
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
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
|
+
}
|
|
1980
2050
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
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
|
+
}
|
|
1987
2074
|
}
|
|
1988
|
-
return { installed: true };
|
|
1989
2075
|
} catch (err) {
|
|
1990
2076
|
return {
|
|
1991
2077
|
installed: false,
|
|
@@ -2465,7 +2551,9 @@ __export(lsp_tools_exports, {
|
|
|
2465
2551
|
lspImplementation: () => lspImplementation,
|
|
2466
2552
|
lspReferences: () => lspReferences,
|
|
2467
2553
|
lspTypeHierarchy: () => lspTypeHierarchy,
|
|
2468
|
-
lspWorkspaceSymbol: () => lspWorkspaceSymbol
|
|
2554
|
+
lspWorkspaceSymbol: () => lspWorkspaceSymbol,
|
|
2555
|
+
pickAvailableConfig: () => pickAvailableConfig,
|
|
2556
|
+
probeBinary: () => probeBinary
|
|
2469
2557
|
});
|
|
2470
2558
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2471
2559
|
import { relative as pathRelative, resolve as pathResolve3, join as pathJoin } from "path";
|
|
@@ -2912,15 +3000,15 @@ var init_telemetry = __esm({
|
|
|
2912
3000
|
// bin/repowise.ts
|
|
2913
3001
|
import { readFileSync as readFileSync3 } from "fs";
|
|
2914
3002
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2915
|
-
import { dirname as dirname19, join as
|
|
3003
|
+
import { dirname as dirname19, join as join52 } from "path";
|
|
2916
3004
|
import { Command } from "commander";
|
|
2917
3005
|
|
|
2918
3006
|
// ../listener/dist/main.js
|
|
2919
3007
|
init_config_dir();
|
|
2920
3008
|
import { readFile as readFile12, writeFile as writeFile14, mkdir as mkdir14, stat as fsStat } from "fs/promises";
|
|
2921
|
-
import { join as
|
|
3009
|
+
import { join as join32, dirname as dirname14 } from "path";
|
|
2922
3010
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2923
|
-
import
|
|
3011
|
+
import lockfile4 from "proper-lockfile";
|
|
2924
3012
|
|
|
2925
3013
|
// ../../packages/shared/dist/lib/ai-tools.js
|
|
2926
3014
|
import { readFile, writeFile, mkdir, readdir, stat, unlink } from "fs/promises";
|
|
@@ -3328,10 +3416,19 @@ async function getListenerConfig() {
|
|
|
3328
3416
|
repos: validRepos,
|
|
3329
3417
|
autoDiscoverRepos: raw.autoDiscoverRepos ?? false,
|
|
3330
3418
|
noAutoUpdate: raw.noAutoUpdate ?? false,
|
|
3419
|
+
lspEnabled: raw.lspEnabled ?? true,
|
|
3420
|
+
lspAutoWarm: raw.lspAutoWarm ?? true,
|
|
3331
3421
|
...lspOverrides ? { lspOverrides } : {}
|
|
3332
3422
|
};
|
|
3333
3423
|
} catch {
|
|
3334
|
-
return {
|
|
3424
|
+
return {
|
|
3425
|
+
defaultApiUrl: apiUrl,
|
|
3426
|
+
repos: [],
|
|
3427
|
+
autoDiscoverRepos: false,
|
|
3428
|
+
noAutoUpdate: false,
|
|
3429
|
+
lspEnabled: true,
|
|
3430
|
+
lspAutoWarm: true
|
|
3431
|
+
};
|
|
3335
3432
|
}
|
|
3336
3433
|
}
|
|
3337
3434
|
async function saveListenerConfig(config2) {
|
|
@@ -3355,6 +3452,12 @@ async function saveListenerConfig(config2) {
|
|
|
3355
3452
|
...raw,
|
|
3356
3453
|
apiUrl: config2.defaultApiUrl,
|
|
3357
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,
|
|
3358
3461
|
...config2.lspOverrides ? { lspOverrides: config2.lspOverrides } : {}
|
|
3359
3462
|
};
|
|
3360
3463
|
const tmpPath = configPath + ".tmp";
|
|
@@ -6677,41 +6780,83 @@ function handleRequest(req, res, options, sessions, secretCtx) {
|
|
|
6677
6780
|
return {
|
|
6678
6781
|
"/mcp/tools/lsp_definition": async (body, root) => {
|
|
6679
6782
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6680
|
-
return mod.lspDefinition({
|
|
6783
|
+
return mod.lspDefinition({
|
|
6784
|
+
workspaces: ws,
|
|
6785
|
+
repoRoot: root,
|
|
6786
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6787
|
+
}, body);
|
|
6681
6788
|
},
|
|
6682
6789
|
"/mcp/tools/lsp_references": async (body, root) => {
|
|
6683
6790
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6684
|
-
return mod.lspReferences({
|
|
6791
|
+
return mod.lspReferences({
|
|
6792
|
+
workspaces: ws,
|
|
6793
|
+
repoRoot: root,
|
|
6794
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6795
|
+
}, body);
|
|
6685
6796
|
},
|
|
6686
6797
|
"/mcp/tools/lsp_hover": async (body, root) => {
|
|
6687
6798
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6688
|
-
return mod.lspHover({
|
|
6799
|
+
return mod.lspHover({
|
|
6800
|
+
workspaces: ws,
|
|
6801
|
+
repoRoot: root,
|
|
6802
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6803
|
+
}, body);
|
|
6689
6804
|
},
|
|
6690
6805
|
"/mcp/tools/lsp_workspace_symbol": async (body, root) => {
|
|
6691
6806
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6692
|
-
return mod.lspWorkspaceSymbol({
|
|
6807
|
+
return mod.lspWorkspaceSymbol({
|
|
6808
|
+
workspaces: ws,
|
|
6809
|
+
repoRoot: root,
|
|
6810
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6811
|
+
}, body);
|
|
6693
6812
|
},
|
|
6694
6813
|
"/mcp/tools/lsp_document_symbol": async (body, root) => {
|
|
6695
6814
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6696
|
-
return mod.lspDocumentSymbol({
|
|
6815
|
+
return mod.lspDocumentSymbol({
|
|
6816
|
+
workspaces: ws,
|
|
6817
|
+
repoRoot: root,
|
|
6818
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6819
|
+
}, body);
|
|
6697
6820
|
},
|
|
6698
6821
|
"/mcp/tools/lsp_call_hierarchy": async (body, root) => {
|
|
6699
6822
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6700
|
-
return mod.lspCallHierarchy({
|
|
6823
|
+
return mod.lspCallHierarchy({
|
|
6824
|
+
workspaces: ws,
|
|
6825
|
+
repoRoot: root,
|
|
6826
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6827
|
+
}, body);
|
|
6701
6828
|
},
|
|
6702
6829
|
"/mcp/tools/lsp_implementation": async (body, root) => {
|
|
6703
6830
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6704
|
-
return mod.lspImplementation({
|
|
6831
|
+
return mod.lspImplementation({
|
|
6832
|
+
workspaces: ws,
|
|
6833
|
+
repoRoot: root,
|
|
6834
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6835
|
+
}, body);
|
|
6705
6836
|
},
|
|
6706
6837
|
"/mcp/tools/lsp_type_hierarchy": async (body, root) => {
|
|
6707
6838
|
const mod = await Promise.resolve().then(() => (init_lsp_tools(), lsp_tools_exports));
|
|
6708
|
-
return mod.lspTypeHierarchy({
|
|
6839
|
+
return mod.lspTypeHierarchy({
|
|
6840
|
+
workspaces: ws,
|
|
6841
|
+
repoRoot: root,
|
|
6842
|
+
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {}
|
|
6843
|
+
}, body);
|
|
6709
6844
|
}
|
|
6710
6845
|
};
|
|
6711
6846
|
})();
|
|
6712
6847
|
if (method === "POST" && lspDispatch[url]) {
|
|
6713
6848
|
const lspHandler = lspDispatch[url];
|
|
6714
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
|
+
}
|
|
6715
6860
|
const root = getRepoIdToRoot().get(session.repoId) ?? fallbackRoot;
|
|
6716
6861
|
if (!root) {
|
|
6717
6862
|
return {
|
|
@@ -7013,6 +7158,7 @@ async function startMcp(options) {
|
|
|
7013
7158
|
...firstRepoLocal ? { defaultRepoRoot: firstRepoLocal } : {},
|
|
7014
7159
|
repoIdToRoot: () => repoIdToRoot,
|
|
7015
7160
|
...options.getLspOverrides ? { getLspOverrides: options.getLspOverrides } : {},
|
|
7161
|
+
...options.getLspEnabled ? { getLspEnabled: options.getLspEnabled } : {},
|
|
7016
7162
|
mcpLogger
|
|
7017
7163
|
});
|
|
7018
7164
|
const reapInterval = lspWorkspaces ? setInterval(() => {
|
|
@@ -7178,10 +7324,10 @@ async function ensureServerConsent(opts) {
|
|
|
7178
7324
|
});
|
|
7179
7325
|
if (!res.ok)
|
|
7180
7326
|
return;
|
|
7181
|
-
const
|
|
7327
|
+
const fs25 = await import("fs/promises");
|
|
7182
7328
|
const path = await import("path");
|
|
7183
|
-
await
|
|
7184
|
-
await
|
|
7329
|
+
await fs25.mkdir(path.dirname(opts.markerPath), { recursive: true });
|
|
7330
|
+
await fs25.writeFile(opts.markerPath, (/* @__PURE__ */ new Date()).toISOString() + "\n", {
|
|
7185
7331
|
encoding: "utf-8",
|
|
7186
7332
|
mode: 384
|
|
7187
7333
|
});
|
|
@@ -7597,12 +7743,100 @@ async function runAutoConfig(opts) {
|
|
|
7597
7743
|
// ../listener/dist/main.js
|
|
7598
7744
|
init_installer();
|
|
7599
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
|
+
|
|
7600
7834
|
// ../listener/dist/lib/workspace-prep.js
|
|
7601
7835
|
init_config_dir();
|
|
7602
|
-
import { promises as
|
|
7836
|
+
import { promises as fs15 } from "fs";
|
|
7603
7837
|
import { spawn as spawn9, execFile as execFile4 } from "child_process";
|
|
7604
7838
|
import { createWriteStream as createWriteStream2 } from "fs";
|
|
7605
|
-
import { join as
|
|
7839
|
+
import { join as join31 } from "path";
|
|
7606
7840
|
import { promisify as promisify3 } from "util";
|
|
7607
7841
|
var execFileAsync3 = promisify3(execFile4);
|
|
7608
7842
|
async function isCommandOnPath2(cmd) {
|
|
@@ -7656,7 +7890,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
7656
7890
|
return;
|
|
7657
7891
|
let ents;
|
|
7658
7892
|
try {
|
|
7659
|
-
ents = await
|
|
7893
|
+
ents = await fs15.readdir(dir, { withFileTypes: true });
|
|
7660
7894
|
} catch {
|
|
7661
7895
|
return;
|
|
7662
7896
|
}
|
|
@@ -7666,7 +7900,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
7666
7900
|
if (e.isDirectory()) {
|
|
7667
7901
|
if (skip.has(e.name) || e.name.startsWith("."))
|
|
7668
7902
|
continue;
|
|
7669
|
-
await rec(
|
|
7903
|
+
await rec(join31(dir, e.name));
|
|
7670
7904
|
continue;
|
|
7671
7905
|
}
|
|
7672
7906
|
const dot = e.name.lastIndexOf(".");
|
|
@@ -7675,7 +7909,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
7675
7909
|
const ext = e.name.slice(dot);
|
|
7676
7910
|
if (!C_EXTS.has(ext) && !CPP_EXTS.has(ext))
|
|
7677
7911
|
continue;
|
|
7678
|
-
sources.push({ path:
|
|
7912
|
+
sources.push({ path: join31(dir, e.name), ext });
|
|
7679
7913
|
}
|
|
7680
7914
|
}
|
|
7681
7915
|
await rec(repoRoot);
|
|
@@ -7691,10 +7925,10 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
7691
7925
|
command: `${driver} ${std} -I. -I./include -c "${src}"`
|
|
7692
7926
|
};
|
|
7693
7927
|
});
|
|
7694
|
-
const outDir =
|
|
7695
|
-
await
|
|
7696
|
-
const outPath =
|
|
7697
|
-
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));
|
|
7698
7932
|
const capHit = sources.length >= MAX_STUB_SOURCES;
|
|
7699
7933
|
console.log(`[workspace-prep] ${repoId}: wrote ${entries.length.toString()}-entry compile_commands stub to .repowise/${capHit ? " (cap reached \u2014 additional sources truncated)" : ""}`);
|
|
7700
7934
|
return true;
|
|
@@ -7702,7 +7936,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
7702
7936
|
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
7703
7937
|
async function fileExists10(repoRoot, name) {
|
|
7704
7938
|
try {
|
|
7705
|
-
await
|
|
7939
|
+
await fs15.access(join31(repoRoot, name));
|
|
7706
7940
|
return true;
|
|
7707
7941
|
} catch {
|
|
7708
7942
|
return false;
|
|
@@ -7713,7 +7947,7 @@ async function detectWorkspaceDeps(repoRoot) {
|
|
|
7713
7947
|
if (await fileExists10(repoRoot, "package.json")) {
|
|
7714
7948
|
let pkgRaw = "";
|
|
7715
7949
|
try {
|
|
7716
|
-
pkgRaw = await
|
|
7950
|
+
pkgRaw = await fs15.readFile(join31(repoRoot, "package.json"), "utf8");
|
|
7717
7951
|
} catch {
|
|
7718
7952
|
}
|
|
7719
7953
|
if (pkgRaw) {
|
|
@@ -7816,8 +8050,8 @@ async function runWorkspacePreps(opts) {
|
|
|
7816
8050
|
if (opts.missing.length === 0)
|
|
7817
8051
|
return [];
|
|
7818
8052
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7819
|
-
const logPath2 =
|
|
7820
|
-
await
|
|
8053
|
+
const logPath2 = join31(getConfigDir(), `install-log.${safeRepoId}.txt`);
|
|
8054
|
+
await fs15.mkdir(getConfigDir(), { recursive: true });
|
|
7821
8055
|
const stream = opts.logStream ?? createWriteStream2(logPath2, { flags: "a" });
|
|
7822
8056
|
stream.on("error", () => {
|
|
7823
8057
|
});
|
|
@@ -8704,7 +8938,7 @@ var CRASH_LOOP_WINDOW_MS = 3e4;
|
|
|
8704
8938
|
var CRASH_LOOP_THRESHOLD = 3;
|
|
8705
8939
|
async function readRawToolConfig() {
|
|
8706
8940
|
try {
|
|
8707
|
-
const configPath =
|
|
8941
|
+
const configPath = join32(getConfigDir(), "config.json");
|
|
8708
8942
|
const data = await readFile12(configPath, "utf-8");
|
|
8709
8943
|
const raw = JSON.parse(data);
|
|
8710
8944
|
return {
|
|
@@ -8767,8 +9001,8 @@ function resolveAuditRoots() {
|
|
|
8767
9001
|
const out = /* @__PURE__ */ new Set();
|
|
8768
9002
|
let dir = dirname14(process.execPath);
|
|
8769
9003
|
for (let i = 0; i < 8; i += 1) {
|
|
8770
|
-
out.add(
|
|
8771
|
-
out.add(
|
|
9004
|
+
out.add(join32(dir, "node_modules"));
|
|
9005
|
+
out.add(join32(dir, "lib", "node_modules"));
|
|
8772
9006
|
const parent = dirname14(dir);
|
|
8773
9007
|
if (parent === dir)
|
|
8774
9008
|
break;
|
|
@@ -8988,7 +9222,7 @@ async function checkStaleContext(repos, state, groups) {
|
|
|
8988
9222
|
if (group?.offline.isOffline)
|
|
8989
9223
|
continue;
|
|
8990
9224
|
const { statSync: statSync2, readdirSync: readdirSync2 } = await import("fs");
|
|
8991
|
-
const contextPath =
|
|
9225
|
+
const contextPath = join32(repo.localPath, "repowise-context");
|
|
8992
9226
|
let isMissingOrEmpty = false;
|
|
8993
9227
|
try {
|
|
8994
9228
|
const s = statSync2(contextPath);
|
|
@@ -9046,7 +9280,7 @@ async function reconcileMcpConfigs(repos, packageName) {
|
|
|
9046
9280
|
}
|
|
9047
9281
|
async function reconcileAgentInstructions(repos) {
|
|
9048
9282
|
for (const repo of repos) {
|
|
9049
|
-
const path =
|
|
9283
|
+
const path = join32(repo.localPath, "repowise-context", "project-overview.md");
|
|
9050
9284
|
let content;
|
|
9051
9285
|
try {
|
|
9052
9286
|
content = await readFile12(path, "utf-8");
|
|
@@ -9108,11 +9342,11 @@ async function startListener() {
|
|
|
9108
9342
|
}
|
|
9109
9343
|
const configDir = getConfigDir();
|
|
9110
9344
|
await mkdir14(configDir, { recursive: true });
|
|
9111
|
-
const lockPath =
|
|
9345
|
+
const lockPath = join32(configDir, "listener.lock");
|
|
9112
9346
|
await writeFile14(lockPath, "", { flag: "a" });
|
|
9113
9347
|
let lockIsHeld = false;
|
|
9114
9348
|
try {
|
|
9115
|
-
lockIsHeld = await
|
|
9349
|
+
lockIsHeld = await lockfile4.check(lockPath, { stale: 3e4, realpath: false });
|
|
9116
9350
|
} catch {
|
|
9117
9351
|
}
|
|
9118
9352
|
if (!lockIsHeld) {
|
|
@@ -9126,7 +9360,7 @@ async function startListener() {
|
|
|
9126
9360
|
}
|
|
9127
9361
|
}
|
|
9128
9362
|
try {
|
|
9129
|
-
releaseLock = await
|
|
9363
|
+
releaseLock = await lockfile4.lock(lockPath, { stale: 3e4, realpath: false });
|
|
9130
9364
|
} catch {
|
|
9131
9365
|
console.error(`Listener already running. Stop it first with \`${true ? "repowisestage" : "repowise"} stop\`.`);
|
|
9132
9366
|
process.exitCode = 1;
|
|
@@ -9151,7 +9385,7 @@ async function startListener() {
|
|
|
9151
9385
|
return;
|
|
9152
9386
|
}
|
|
9153
9387
|
if (config2.repos.length === 0 && !config2.autoDiscoverRepos) {
|
|
9154
|
-
console.error(`No repos configured. Add repos to ${
|
|
9388
|
+
console.error(`No repos configured. Add repos to ${join32(configDir, "config.json")}`);
|
|
9155
9389
|
await releaseLockAndExit();
|
|
9156
9390
|
process.exitCode = 1;
|
|
9157
9391
|
return;
|
|
@@ -9219,7 +9453,7 @@ async function startListener() {
|
|
|
9219
9453
|
let currentVersion = "";
|
|
9220
9454
|
try {
|
|
9221
9455
|
const selfDir = dirname14(fileURLToPath3(import.meta.url));
|
|
9222
|
-
const pkgJsonPath =
|
|
9456
|
+
const pkgJsonPath = join32(selfDir, "..", "..", "package.json");
|
|
9223
9457
|
const pkgJson = JSON.parse(await readFile12(pkgJsonPath, "utf-8"));
|
|
9224
9458
|
currentVersion = pkgJson.version;
|
|
9225
9459
|
} catch (err) {
|
|
@@ -9263,7 +9497,14 @@ async function startListener() {
|
|
|
9263
9497
|
// Read at each lsp_* dispatch from the live (reconcile-refreshed)
|
|
9264
9498
|
// config so `repowise lsp enable intelephense` takes effect within
|
|
9265
9499
|
// the 5-min reconcile window without a listener restart.
|
|
9266
|
-
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
|
|
9267
9508
|
});
|
|
9268
9509
|
if (mcpRuntime.server) {
|
|
9269
9510
|
console.log(`[mcp] Listening at ${mcpRuntime.server.endpoint}`);
|
|
@@ -9284,6 +9525,10 @@ async function startListener() {
|
|
|
9284
9525
|
}
|
|
9285
9526
|
})();
|
|
9286
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
|
+
}
|
|
9287
9532
|
try {
|
|
9288
9533
|
const lspResults = await prepareLspServersForRepos(config2.repos, {
|
|
9289
9534
|
...config2.lspOverrides ? { lspOverrides: config2.lspOverrides } : {}
|
|
@@ -9318,6 +9563,14 @@ async function startListener() {
|
|
|
9318
9563
|
}
|
|
9319
9564
|
}
|
|
9320
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
|
+
}
|
|
9321
9574
|
} catch (err) {
|
|
9322
9575
|
console.warn("[lsp-install] Pre-install scan failed:", err instanceof Error ? err.message : String(err));
|
|
9323
9576
|
}
|
|
@@ -9455,6 +9708,27 @@ async function startListener() {
|
|
|
9455
9708
|
console.warn(`[self-heal] Context download failed for ${addedRepo.repoId}:`, fetchErr instanceof Error ? fetchErr.message : String(fetchErr));
|
|
9456
9709
|
}
|
|
9457
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
|
+
}
|
|
9458
9732
|
}
|
|
9459
9733
|
}
|
|
9460
9734
|
} catch (reconcileErr) {
|
|
@@ -9602,12 +9876,12 @@ async function startListener() {
|
|
|
9602
9876
|
} catch {
|
|
9603
9877
|
}
|
|
9604
9878
|
}
|
|
9605
|
-
const credentialsPath =
|
|
9879
|
+
const credentialsPath = join32(getConfigDir(), "credentials.json");
|
|
9606
9880
|
let credentialsChanged = false;
|
|
9607
9881
|
let watcher = null;
|
|
9608
9882
|
try {
|
|
9609
|
-
const
|
|
9610
|
-
watcher =
|
|
9883
|
+
const fs25 = await import("fs");
|
|
9884
|
+
watcher = fs25.watch(credentialsPath, () => {
|
|
9611
9885
|
credentialsChanged = true;
|
|
9612
9886
|
});
|
|
9613
9887
|
} catch {
|
|
@@ -9648,7 +9922,7 @@ if (isDirectRun) {
|
|
|
9648
9922
|
|
|
9649
9923
|
// src/lib/env.ts
|
|
9650
9924
|
import { homedir as homedir6 } from "os";
|
|
9651
|
-
import { join as
|
|
9925
|
+
import { join as join33 } from "path";
|
|
9652
9926
|
var IS_STAGING2 = true ? true : false;
|
|
9653
9927
|
var PRODUCTION = {
|
|
9654
9928
|
apiUrl: "https://api.repowise.ai",
|
|
@@ -9668,7 +9942,7 @@ function getEnvConfig() {
|
|
|
9668
9942
|
return IS_STAGING2 ? STAGING : PRODUCTION;
|
|
9669
9943
|
}
|
|
9670
9944
|
function getConfigDir2() {
|
|
9671
|
-
return
|
|
9945
|
+
return join33(homedir6(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
|
|
9672
9946
|
}
|
|
9673
9947
|
function getPackageName() {
|
|
9674
9948
|
return true ? "repowisestage" : "repowise";
|
|
@@ -9679,11 +9953,11 @@ import chalk from "chalk";
|
|
|
9679
9953
|
|
|
9680
9954
|
// src/lib/config.ts
|
|
9681
9955
|
import { readFile as readFile13, writeFile as writeFile15, mkdir as mkdir15, rename as rename4, unlink as unlink9 } from "fs/promises";
|
|
9682
|
-
import { join as
|
|
9683
|
-
import
|
|
9956
|
+
import { join as join34 } from "path";
|
|
9957
|
+
import lockfile5 from "proper-lockfile";
|
|
9684
9958
|
async function getConfig() {
|
|
9685
9959
|
try {
|
|
9686
|
-
const data = await readFile13(
|
|
9960
|
+
const data = await readFile13(join34(getConfigDir2(), "config.json"), "utf-8");
|
|
9687
9961
|
return JSON.parse(data);
|
|
9688
9962
|
} catch {
|
|
9689
9963
|
return {};
|
|
@@ -9691,7 +9965,7 @@ async function getConfig() {
|
|
|
9691
9965
|
}
|
|
9692
9966
|
async function saveConfig(config2) {
|
|
9693
9967
|
const dir = getConfigDir2();
|
|
9694
|
-
const path =
|
|
9968
|
+
const path = join34(dir, "config.json");
|
|
9695
9969
|
await mkdir15(dir, { recursive: true });
|
|
9696
9970
|
const tmpPath = path + ".tmp";
|
|
9697
9971
|
try {
|
|
@@ -9707,7 +9981,7 @@ async function saveConfig(config2) {
|
|
|
9707
9981
|
}
|
|
9708
9982
|
async function mergeAndSaveConfig(updates) {
|
|
9709
9983
|
const dir = getConfigDir2();
|
|
9710
|
-
const path =
|
|
9984
|
+
const path = join34(dir, "config.json");
|
|
9711
9985
|
await mkdir15(dir, { recursive: true });
|
|
9712
9986
|
try {
|
|
9713
9987
|
await writeFile15(path, "", { flag: "a" });
|
|
@@ -9715,7 +9989,7 @@ async function mergeAndSaveConfig(updates) {
|
|
|
9715
9989
|
}
|
|
9716
9990
|
let release = null;
|
|
9717
9991
|
try {
|
|
9718
|
-
release = await
|
|
9992
|
+
release = await lockfile5.lock(path, { stale: 1e4, retries: 3, realpath: false });
|
|
9719
9993
|
let raw = {};
|
|
9720
9994
|
try {
|
|
9721
9995
|
raw = JSON.parse(await readFile13(path, "utf-8"));
|
|
@@ -9778,16 +10052,16 @@ async function showWelcome(currentVersion) {
|
|
|
9778
10052
|
|
|
9779
10053
|
// src/commands/create.ts
|
|
9780
10054
|
import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
9781
|
-
import { dirname as dirname15, join as
|
|
10055
|
+
import { dirname as dirname15, join as join40 } from "path";
|
|
9782
10056
|
init_src();
|
|
9783
|
-
import
|
|
10057
|
+
import chalk8 from "chalk";
|
|
9784
10058
|
import ora from "ora";
|
|
9785
10059
|
|
|
9786
10060
|
// src/lib/auth.ts
|
|
9787
10061
|
import { createHash as createHash4, randomBytes as randomBytes3 } from "crypto";
|
|
9788
10062
|
import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir16, chmod as chmod4, unlink as unlink10 } from "fs/promises";
|
|
9789
10063
|
import http from "http";
|
|
9790
|
-
import { join as
|
|
10064
|
+
import { join as join35 } from "path";
|
|
9791
10065
|
var CLI_CALLBACK_PORT = 19876;
|
|
9792
10066
|
var CALLBACK_TIMEOUT_MS = 12e4;
|
|
9793
10067
|
function getCognitoConfigForStorage() {
|
|
@@ -9953,7 +10227,7 @@ async function refreshTokens2(refreshToken) {
|
|
|
9953
10227
|
}
|
|
9954
10228
|
async function getStoredCredentials2() {
|
|
9955
10229
|
try {
|
|
9956
|
-
const credPath =
|
|
10230
|
+
const credPath = join35(getConfigDir2(), "credentials.json");
|
|
9957
10231
|
const data = await readFile14(credPath, "utf-8");
|
|
9958
10232
|
return JSON.parse(data);
|
|
9959
10233
|
} catch (err) {
|
|
@@ -9965,14 +10239,14 @@ async function getStoredCredentials2() {
|
|
|
9965
10239
|
}
|
|
9966
10240
|
async function storeCredentials2(credentials) {
|
|
9967
10241
|
const dir = getConfigDir2();
|
|
9968
|
-
const credPath =
|
|
10242
|
+
const credPath = join35(dir, "credentials.json");
|
|
9969
10243
|
await mkdir16(dir, { recursive: true, mode: 448 });
|
|
9970
10244
|
await writeFile16(credPath, JSON.stringify(credentials, null, 2));
|
|
9971
10245
|
await chmod4(credPath, 384);
|
|
9972
10246
|
}
|
|
9973
10247
|
async function clearCredentials() {
|
|
9974
10248
|
try {
|
|
9975
|
-
await unlink10(
|
|
10249
|
+
await unlink10(join35(getConfigDir2(), "credentials.json"));
|
|
9976
10250
|
} catch (err) {
|
|
9977
10251
|
if (err.code !== "ENOENT") throw err;
|
|
9978
10252
|
}
|
|
@@ -10125,7 +10399,7 @@ async function apiRequest(path, options) {
|
|
|
10125
10399
|
if (body.error?.code) code = body.error.code;
|
|
10126
10400
|
} catch {
|
|
10127
10401
|
}
|
|
10128
|
-
if (code === "BILLING_LIMIT_EXCEEDED" || code === "SYNC_LIMIT_EXCEEDED" || code === "BILLING_SUBSCRIPTION_INACTIVE") {
|
|
10402
|
+
if (code === "BILLING_LIMIT_EXCEEDED" || code === "SYNC_LIMIT_EXCEEDED" || code === "SEAT_LIMIT_EXCEEDED" || code === "BILLING_SUBSCRIPTION_INACTIVE") {
|
|
10129
10403
|
throw new Error(`${message} Visit ${BILLING_URL} to manage your plan.`);
|
|
10130
10404
|
}
|
|
10131
10405
|
throw new Error(message);
|
|
@@ -10179,10 +10453,10 @@ async function selectAiTools() {
|
|
|
10179
10453
|
|
|
10180
10454
|
// src/lib/ai-tools.ts
|
|
10181
10455
|
import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir17 } from "fs/promises";
|
|
10182
|
-
import { join as
|
|
10456
|
+
import { join as join36 } from "path";
|
|
10183
10457
|
var REPOWISE_HOOK_MARKER = "repowise-context";
|
|
10184
10458
|
async function writeClaudeSubagentHook(repoRoot, contextFolder) {
|
|
10185
|
-
const settingsPath =
|
|
10459
|
+
const settingsPath = join36(repoRoot, ".claude", "settings.json");
|
|
10186
10460
|
let settings = {};
|
|
10187
10461
|
try {
|
|
10188
10462
|
const raw = await readFile15(settingsPath, "utf-8");
|
|
@@ -10217,15 +10491,15 @@ async function writeClaudeSubagentHook(repoRoot, contextFolder) {
|
|
|
10217
10491
|
}
|
|
10218
10492
|
hooks["SubagentStart"] = subagentStart;
|
|
10219
10493
|
settings["hooks"] = hooks;
|
|
10220
|
-
await mkdir17(
|
|
10494
|
+
await mkdir17(join36(repoRoot, ".claude"), { recursive: true });
|
|
10221
10495
|
await writeFile17(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
10222
10496
|
}
|
|
10223
10497
|
|
|
10224
10498
|
// src/lib/gitignore.ts
|
|
10225
10499
|
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
|
|
10226
|
-
import { join as
|
|
10500
|
+
import { join as join37 } from "path";
|
|
10227
10501
|
function ensureGitignore(repoRoot, entry) {
|
|
10228
|
-
const gitignorePath =
|
|
10502
|
+
const gitignorePath = join37(repoRoot, ".gitignore");
|
|
10229
10503
|
if (existsSync2(gitignorePath)) {
|
|
10230
10504
|
const content = readFileSync2(gitignorePath, "utf-8");
|
|
10231
10505
|
const lines = content.split("\n").map((l) => l.trim());
|
|
@@ -10791,8 +11065,8 @@ async function promptDepInstallConsent(missing, opts) {
|
|
|
10791
11065
|
import chalk6 from "chalk";
|
|
10792
11066
|
|
|
10793
11067
|
// src/lib/dep-installer.ts
|
|
10794
|
-
import { promises as
|
|
10795
|
-
import { join as
|
|
11068
|
+
import { promises as fs16 } from "fs";
|
|
11069
|
+
import { join as join38 } from "path";
|
|
10796
11070
|
var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
10797
11071
|
"typescript",
|
|
10798
11072
|
"javascript",
|
|
@@ -10802,14 +11076,14 @@ var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
|
10802
11076
|
]);
|
|
10803
11077
|
var exists = async (p) => {
|
|
10804
11078
|
try {
|
|
10805
|
-
await
|
|
11079
|
+
await fs16.access(p);
|
|
10806
11080
|
return true;
|
|
10807
11081
|
} catch {
|
|
10808
11082
|
return false;
|
|
10809
11083
|
}
|
|
10810
11084
|
};
|
|
10811
11085
|
async function fileExists11(repoRoot, name) {
|
|
10812
|
-
return exists(
|
|
11086
|
+
return exists(join38(repoRoot, name));
|
|
10813
11087
|
}
|
|
10814
11088
|
async function detectNodePackageManager(repoRoot) {
|
|
10815
11089
|
if (await fileExists11(repoRoot, "pnpm-lock.yaml")) {
|
|
@@ -10886,13 +11160,13 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
|
|
|
10886
11160
|
// src/lib/dep-installer-runner.ts
|
|
10887
11161
|
import { spawn as spawn10 } from "child_process";
|
|
10888
11162
|
import { createWriteStream as createWriteStream3 } from "fs";
|
|
10889
|
-
import { promises as
|
|
10890
|
-
import { join as
|
|
11163
|
+
import { promises as fs17 } from "fs";
|
|
11164
|
+
import { join as join39 } from "path";
|
|
10891
11165
|
var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
10892
11166
|
async function runMissingDepInstalls(opts) {
|
|
10893
11167
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
10894
|
-
const logPath2 =
|
|
10895
|
-
await
|
|
11168
|
+
const logPath2 = join39(getConfigDir2(), `install-log.${safeRepoId}.txt`);
|
|
11169
|
+
await fs17.mkdir(getConfigDir2(), { recursive: true });
|
|
10896
11170
|
const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
|
|
10897
11171
|
stream.on("error", () => {
|
|
10898
11172
|
});
|
|
@@ -10938,7 +11212,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
|
|
|
10938
11212
|
}
|
|
10939
11213
|
async function runPipFlow(repoRoot, stream, timeoutMs) {
|
|
10940
11214
|
await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
|
|
10941
|
-
const venvPip = process.platform === "win32" ?
|
|
11215
|
+
const venvPip = process.platform === "win32" ? join39(".venv", "Scripts", "pip.exe") : join39(".venv", "bin", "pip");
|
|
10942
11216
|
await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
|
|
10943
11217
|
}
|
|
10944
11218
|
function runSimple(cmd, repoRoot, stream, timeoutMs) {
|
|
@@ -11049,6 +11323,51 @@ function reportInstallOutcomes(repoId, outcomes) {
|
|
|
11049
11323
|
);
|
|
11050
11324
|
}
|
|
11051
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
|
+
|
|
11052
11371
|
// src/commands/create.ts
|
|
11053
11372
|
function formatElapsed(ms) {
|
|
11054
11373
|
const totalSeconds = Math.round(ms / 1e3);
|
|
@@ -11066,10 +11385,10 @@ async function create() {
|
|
|
11066
11385
|
try {
|
|
11067
11386
|
let credentials = await getValidCredentials2();
|
|
11068
11387
|
if (!credentials) {
|
|
11069
|
-
spinner.info(
|
|
11388
|
+
spinner.info(chalk8.yellow("Not logged in. Opening browser to authenticate..."));
|
|
11070
11389
|
credentials = await performLogin();
|
|
11071
11390
|
const { email } = decodeIdToken(credentials.idToken);
|
|
11072
|
-
spinner.succeed(
|
|
11391
|
+
spinner.succeed(chalk8.green(`Authenticated as ${chalk8.bold(email)}`));
|
|
11073
11392
|
} else {
|
|
11074
11393
|
spinner.succeed("Authenticated");
|
|
11075
11394
|
}
|
|
@@ -11085,7 +11404,7 @@ async function create() {
|
|
|
11085
11404
|
if (pending?.repoId) {
|
|
11086
11405
|
repoId = pending.repoId;
|
|
11087
11406
|
repoName = pending.repoName;
|
|
11088
|
-
spinner.succeed(`Found pending repository: ${
|
|
11407
|
+
spinner.succeed(`Found pending repository: ${chalk8.bold(repoName)}`);
|
|
11089
11408
|
apiRequest("/v1/onboarding/pending", { method: "DELETE" }).catch(() => {
|
|
11090
11409
|
});
|
|
11091
11410
|
}
|
|
@@ -11096,10 +11415,10 @@ async function create() {
|
|
|
11096
11415
|
try {
|
|
11097
11416
|
repoRoot = detectRepoRoot();
|
|
11098
11417
|
repoName = detectRepoName(repoRoot);
|
|
11099
|
-
spinner.succeed(`Repository: ${
|
|
11418
|
+
spinner.succeed(`Repository: ${chalk8.bold(repoName)}`);
|
|
11100
11419
|
} catch {
|
|
11101
11420
|
spinner.fail(
|
|
11102
|
-
|
|
11421
|
+
chalk8.red(
|
|
11103
11422
|
"Not in a git repository. Run this command from your repo directory, or select a repo on the dashboard first."
|
|
11104
11423
|
)
|
|
11105
11424
|
);
|
|
@@ -11125,10 +11444,10 @@ async function create() {
|
|
|
11125
11444
|
}
|
|
11126
11445
|
if (!repoId) {
|
|
11127
11446
|
if (repoLookupError) {
|
|
11128
|
-
spinner.fail(
|
|
11447
|
+
spinner.fail(chalk8.red(`Failed to look up repositories: ${repoLookupError}`));
|
|
11129
11448
|
} else {
|
|
11130
11449
|
spinner.fail(
|
|
11131
|
-
|
|
11450
|
+
chalk8.red(
|
|
11132
11451
|
"Could not find this repository in your RepoWise account. Connect it on the dashboard first."
|
|
11133
11452
|
)
|
|
11134
11453
|
);
|
|
@@ -11146,11 +11465,11 @@ async function create() {
|
|
|
11146
11465
|
const role = resolveRole(groups ?? []);
|
|
11147
11466
|
const canRescan = hasPermission(role, "connectRepos");
|
|
11148
11467
|
if (!canRescan) {
|
|
11149
|
-
spinner.fail(
|
|
11468
|
+
spinner.fail(chalk8.red("This repository already has context generated."));
|
|
11150
11469
|
console.log(
|
|
11151
|
-
|
|
11470
|
+
chalk8.cyan(
|
|
11152
11471
|
`
|
|
11153
|
-
As a team member, run: ${
|
|
11472
|
+
As a team member, run: ${chalk8.bold("repowise member")}
|
|
11154
11473
|
This will download context and configure your AI tools.
|
|
11155
11474
|
`
|
|
11156
11475
|
)
|
|
@@ -11159,20 +11478,20 @@ async function create() {
|
|
|
11159
11478
|
return;
|
|
11160
11479
|
}
|
|
11161
11480
|
if (pricing.allowed && pricing.isFree) {
|
|
11162
|
-
spinner.succeed(
|
|
11481
|
+
spinner.succeed(chalk8.cyan("Free rescan available. Will trigger a full rescan."));
|
|
11163
11482
|
useFreeRescan = true;
|
|
11164
11483
|
} else if (pricing.allowed) {
|
|
11165
11484
|
spinner.stop();
|
|
11166
11485
|
const costText = pricing.estimatedCost && pricing.estimatedCost > 0 ? `$${pricing.estimatedCost.toFixed(2)}` : "pay-as-you-go (based on actual processing cost)";
|
|
11167
11486
|
console.log(
|
|
11168
|
-
|
|
11487
|
+
chalk8.yellow(
|
|
11169
11488
|
`
|
|
11170
11489
|
This repository already has context generated.
|
|
11171
|
-
A full rescan will cost: ${
|
|
11490
|
+
A full rescan will cost: ${chalk8.bold(costText)}`
|
|
11172
11491
|
)
|
|
11173
11492
|
);
|
|
11174
11493
|
if (pricing.costWarning) {
|
|
11175
|
-
console.log(
|
|
11494
|
+
console.log(chalk8.dim(` ${pricing.costWarning}`));
|
|
11176
11495
|
}
|
|
11177
11496
|
const { confirm: confirm3 } = await import("@inquirer/prompts");
|
|
11178
11497
|
const proceed = await confirm3({
|
|
@@ -11180,13 +11499,13 @@ async function create() {
|
|
|
11180
11499
|
default: false
|
|
11181
11500
|
});
|
|
11182
11501
|
if (!proceed) {
|
|
11183
|
-
console.log(
|
|
11502
|
+
console.log(chalk8.dim("\n To sync recent changes, use: repowise sync\n"));
|
|
11184
11503
|
process.exitCode = 0;
|
|
11185
11504
|
return;
|
|
11186
11505
|
}
|
|
11187
11506
|
useFreeRescan = true;
|
|
11188
11507
|
} else {
|
|
11189
|
-
spinner.fail(
|
|
11508
|
+
spinner.fail(chalk8.red(pricing.reason ?? "Cannot rescan at this time."));
|
|
11190
11509
|
process.exitCode = 1;
|
|
11191
11510
|
return;
|
|
11192
11511
|
}
|
|
@@ -11196,14 +11515,14 @@ async function create() {
|
|
|
11196
11515
|
const { tools, hasOther } = await selectAiTools();
|
|
11197
11516
|
if (hasOther) {
|
|
11198
11517
|
console.log(
|
|
11199
|
-
|
|
11518
|
+
chalk8.cyan(
|
|
11200
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"
|
|
11201
11520
|
)
|
|
11202
11521
|
);
|
|
11203
11522
|
}
|
|
11204
11523
|
if (tools.length === 0 && !hasOther) {
|
|
11205
11524
|
console.log(
|
|
11206
|
-
|
|
11525
|
+
chalk8.yellow(
|
|
11207
11526
|
"\nNo AI tools selected. You can configure them later with `repowise config`."
|
|
11208
11527
|
)
|
|
11209
11528
|
);
|
|
@@ -11240,13 +11559,19 @@ async function create() {
|
|
|
11240
11559
|
syncId = retryResult.syncId;
|
|
11241
11560
|
} else {
|
|
11242
11561
|
syncId = active.syncId;
|
|
11243
|
-
spinner.info(
|
|
11562
|
+
spinner.info(chalk8.cyan("Resuming existing pipeline..."));
|
|
11244
11563
|
spinner.start();
|
|
11245
11564
|
}
|
|
11246
11565
|
}
|
|
11247
11566
|
if (!syncId) {
|
|
11248
11567
|
throw new Error("Free rescan retry did not return a syncId");
|
|
11249
11568
|
}
|
|
11569
|
+
let graphOnly = false;
|
|
11570
|
+
try {
|
|
11571
|
+
const usage = await apiRequest("/v1/account/usage");
|
|
11572
|
+
graphOnly = usage.plan === "free";
|
|
11573
|
+
} catch {
|
|
11574
|
+
}
|
|
11250
11575
|
let pollAttempts = 0;
|
|
11251
11576
|
let pollErrors = 0;
|
|
11252
11577
|
const MAX_POLL_ERRORS = 5;
|
|
@@ -11254,9 +11579,10 @@ async function create() {
|
|
|
11254
11579
|
let depInstallShown = false;
|
|
11255
11580
|
let seenAwaitingInput = false;
|
|
11256
11581
|
let depInstallPromise = null;
|
|
11582
|
+
let lspInstallPromise = null;
|
|
11257
11583
|
while (true) {
|
|
11258
11584
|
if (++pollAttempts > MAX_POLL_ATTEMPTS) {
|
|
11259
|
-
spinner.fail(
|
|
11585
|
+
spinner.fail(chalk8.red("Pipeline timed out. Check dashboard for status."));
|
|
11260
11586
|
process.exitCode = 1;
|
|
11261
11587
|
return;
|
|
11262
11588
|
}
|
|
@@ -11302,6 +11628,8 @@ async function create() {
|
|
|
11302
11628
|
resumeText: "Resuming pipeline..."
|
|
11303
11629
|
});
|
|
11304
11630
|
depInstallPromise = result.installPromise;
|
|
11631
|
+
const lspResult = await maybeInstallLspServers({ repoRoot, spinner });
|
|
11632
|
+
lspInstallPromise = lspResult.installPromise;
|
|
11305
11633
|
}
|
|
11306
11634
|
if (syncResult.status === "completed") {
|
|
11307
11635
|
progressRenderer.finalize();
|
|
@@ -11315,10 +11643,12 @@ async function create() {
|
|
|
11315
11643
|
spinner.succeed(
|
|
11316
11644
|
`Context generation complete \u2014 ${coreCount} core + ${tailoredCount} tailored files`
|
|
11317
11645
|
);
|
|
11646
|
+
} else if (graphOnly) {
|
|
11647
|
+
spinner.succeed("Knowledge graph built \u2014 MCP ready (Free plan).");
|
|
11318
11648
|
} else {
|
|
11319
|
-
spinner.warn(
|
|
11649
|
+
spinner.warn(chalk8.yellow("Pipeline completed but no context files were generated."));
|
|
11320
11650
|
console.log(
|
|
11321
|
-
|
|
11651
|
+
chalk8.yellow(
|
|
11322
11652
|
" This may be due to AI throttling or a parsing issue. Try running `repowise create` again."
|
|
11323
11653
|
)
|
|
11324
11654
|
);
|
|
@@ -11327,18 +11657,18 @@ async function create() {
|
|
|
11327
11657
|
}
|
|
11328
11658
|
if (syncResult.status === "failed") {
|
|
11329
11659
|
progressRenderer.finalize();
|
|
11330
|
-
spinner.fail(
|
|
11660
|
+
spinner.fail(chalk8.red(`Pipeline failed: ${syncResult.error ?? "Unknown error"}`));
|
|
11331
11661
|
process.exitCode = 1;
|
|
11332
11662
|
return;
|
|
11333
11663
|
}
|
|
11334
11664
|
}
|
|
11335
|
-
if (repoRoot) {
|
|
11665
|
+
if (repoRoot && !graphOnly) {
|
|
11336
11666
|
spinner.start("Downloading context files from server...");
|
|
11337
11667
|
try {
|
|
11338
11668
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
11339
11669
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
11340
11670
|
if (files.length > 0) {
|
|
11341
|
-
const contextDir =
|
|
11671
|
+
const contextDir = join40(repoRoot, DEFAULT_CONTEXT_FOLDER);
|
|
11342
11672
|
mkdirSync(contextDir, { recursive: true });
|
|
11343
11673
|
let downloadedCount = 0;
|
|
11344
11674
|
let failedCount = 0;
|
|
@@ -11352,7 +11682,7 @@ async function create() {
|
|
|
11352
11682
|
const response = await fetch(presignedUrl);
|
|
11353
11683
|
if (response.ok) {
|
|
11354
11684
|
const content = await response.text();
|
|
11355
|
-
const filePath =
|
|
11685
|
+
const filePath = join40(contextDir, file.fileName);
|
|
11356
11686
|
mkdirSync(dirname15(filePath), { recursive: true });
|
|
11357
11687
|
writeFileSync2(filePath, content, "utf-8");
|
|
11358
11688
|
downloadedCount++;
|
|
@@ -11377,7 +11707,7 @@ async function create() {
|
|
|
11377
11707
|
} catch (err) {
|
|
11378
11708
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
11379
11709
|
spinner.warn(
|
|
11380
|
-
|
|
11710
|
+
chalk8.yellow(
|
|
11381
11711
|
`Cannot reach RepoWise servers to download context: ${msg}
|
|
11382
11712
|
Files are stored on our servers (not in git). Retry when online.`
|
|
11383
11713
|
)
|
|
@@ -11389,9 +11719,9 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11389
11719
|
if (repoRoot) {
|
|
11390
11720
|
contextFiles = await scanLocalContextFiles(repoRoot, contextFolder);
|
|
11391
11721
|
}
|
|
11392
|
-
if (contextFiles.length === 0) {
|
|
11722
|
+
if (contextFiles.length === 0 && !graphOnly) {
|
|
11393
11723
|
console.log(
|
|
11394
|
-
|
|
11724
|
+
chalk8.yellow(
|
|
11395
11725
|
` No context files found in ${contextFolder}/. Try re-running \`repowise create\`.`
|
|
11396
11726
|
)
|
|
11397
11727
|
);
|
|
@@ -11432,7 +11762,7 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11432
11762
|
results.push(" Configured .claude/settings.json (SubagentStart hook)");
|
|
11433
11763
|
}
|
|
11434
11764
|
spinner.succeed("AI tools configured");
|
|
11435
|
-
console.log(
|
|
11765
|
+
console.log(chalk8.dim(results.join("\n")));
|
|
11436
11766
|
}
|
|
11437
11767
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
11438
11768
|
const updatedRepos = [];
|
|
@@ -11458,11 +11788,11 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11458
11788
|
}
|
|
11459
11789
|
if (!listenerRunning) {
|
|
11460
11790
|
console.log(
|
|
11461
|
-
|
|
11791
|
+
chalk8.yellow(
|
|
11462
11792
|
"Warning: Could not start listener automatically. Run the following to enable it:"
|
|
11463
11793
|
)
|
|
11464
11794
|
);
|
|
11465
|
-
console.log(
|
|
11795
|
+
console.log(chalk8.yellow(` $ repowise listen --install`));
|
|
11466
11796
|
}
|
|
11467
11797
|
if (depInstallPromise) {
|
|
11468
11798
|
const installSpinner = ora("Finalizing dependency installs...").start();
|
|
@@ -11479,40 +11809,84 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
11479
11809
|
);
|
|
11480
11810
|
}
|
|
11481
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
|
+
}
|
|
11482
11836
|
const elapsed = formatElapsed(Date.now() - startTime);
|
|
11483
11837
|
console.log("");
|
|
11484
|
-
console.log(
|
|
11838
|
+
console.log(chalk8.green.bold(` \u2728 Setup complete \u2014 ${repoName} is ready.`));
|
|
11485
11839
|
if (listenerRunning) {
|
|
11486
11840
|
console.log("");
|
|
11487
|
-
console.log(
|
|
11841
|
+
console.log(chalk8.cyan(" What\u2019s running now"));
|
|
11488
11842
|
console.log(
|
|
11489
|
-
` ${
|
|
11843
|
+
` ${chalk8.green("\u2022")} The RepoWise Listener is Live \u2014 context auto-updates on every push.`
|
|
11490
11844
|
);
|
|
11491
11845
|
console.log(
|
|
11492
|
-
` ${
|
|
11846
|
+
` ${chalk8.green("\u2022")} The RepoWise MCP is Live \u2014 your AI tools can query the knowledge graph directly.`
|
|
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
|
+
}
|
|
11861
|
+
}
|
|
11862
|
+
if (graphOnly) {
|
|
11863
|
+
console.log("");
|
|
11864
|
+
console.log(chalk8.cyan(" You\u2019re on the Free plan \u2014 knowledge graph + MCP only."));
|
|
11865
|
+
console.log(
|
|
11866
|
+
chalk8.dim(" Upgrade to Pro for AI-generated context docs and auto-sync on merge.")
|
|
11493
11867
|
);
|
|
11494
11868
|
}
|
|
11495
11869
|
console.log("");
|
|
11496
|
-
console.log(
|
|
11870
|
+
console.log(chalk8.cyan(" Next steps"));
|
|
11497
11871
|
console.log(
|
|
11498
|
-
` ${
|
|
11872
|
+
` ${chalk8.cyan("\u2022")} Open Claude Code / Cursor and ask: "What does this repo do?"`
|
|
11499
11873
|
);
|
|
11500
11874
|
console.log(
|
|
11501
|
-
` ${
|
|
11875
|
+
` ${chalk8.cyan("\u2022")} Head to the dashboard \u2192 "Complete Onboarding" to explore quality scores and gaps.`
|
|
11502
11876
|
);
|
|
11503
|
-
console.log(
|
|
11877
|
+
console.log(chalk8.dim(`
|
|
11504
11878
|
Total time: ${elapsed}`));
|
|
11505
11879
|
} catch (err) {
|
|
11506
11880
|
const message = err instanceof Error ? err.message : "Create failed";
|
|
11507
|
-
spinner.fail(
|
|
11881
|
+
spinner.fail(chalk8.red(message));
|
|
11508
11882
|
process.exitCode = 1;
|
|
11509
11883
|
}
|
|
11510
11884
|
}
|
|
11511
11885
|
|
|
11512
11886
|
// src/commands/member.ts
|
|
11513
11887
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11514
|
-
import { dirname as dirname16, join as
|
|
11515
|
-
import
|
|
11888
|
+
import { dirname as dirname16, join as join41, resolve, sep } from "path";
|
|
11889
|
+
import chalk9 from "chalk";
|
|
11516
11890
|
import ora2 from "ora";
|
|
11517
11891
|
var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
|
|
11518
11892
|
function formatElapsed2(ms) {
|
|
@@ -11543,13 +11917,28 @@ async function member() {
|
|
|
11543
11917
|
try {
|
|
11544
11918
|
let credentials = await getValidCredentials2();
|
|
11545
11919
|
if (!credentials) {
|
|
11546
|
-
spinner.info(
|
|
11920
|
+
spinner.info(chalk9.yellow("Not logged in. Opening browser to authenticate..."));
|
|
11547
11921
|
credentials = await performLogin();
|
|
11548
11922
|
const { email } = decodeIdToken(credentials.idToken);
|
|
11549
|
-
spinner.succeed(
|
|
11923
|
+
spinner.succeed(chalk9.green(`Authenticated as ${chalk9.bold(email)}`));
|
|
11550
11924
|
} else {
|
|
11551
11925
|
spinner.succeed("Authenticated");
|
|
11552
11926
|
}
|
|
11927
|
+
try {
|
|
11928
|
+
const usage = await apiRequest("/v1/account/usage");
|
|
11929
|
+
if (usage.plan && usage.plan !== "team") {
|
|
11930
|
+
spinner.fail(
|
|
11931
|
+
chalk9.yellow(
|
|
11932
|
+
`'repowise member' is a Team-plan feature (your account is on the ${usage.plan} plan).`
|
|
11933
|
+
)
|
|
11934
|
+
);
|
|
11935
|
+
console.log(
|
|
11936
|
+
chalk9.dim(" The account owner sets up the repository with `repowise create`.")
|
|
11937
|
+
);
|
|
11938
|
+
return;
|
|
11939
|
+
}
|
|
11940
|
+
} catch {
|
|
11941
|
+
}
|
|
11553
11942
|
let repoId;
|
|
11554
11943
|
let repoName;
|
|
11555
11944
|
let repoRoot;
|
|
@@ -11561,7 +11950,7 @@ async function member() {
|
|
|
11561
11950
|
if (pending?.repoId) {
|
|
11562
11951
|
repoId = pending.repoId;
|
|
11563
11952
|
repoName = pending.repoName;
|
|
11564
|
-
spinner.succeed(`Found pending repository: ${
|
|
11953
|
+
spinner.succeed(`Found pending repository: ${chalk9.bold(repoName)}`);
|
|
11565
11954
|
apiRequest("/v1/onboarding/pending", { method: "DELETE" }).catch(() => {
|
|
11566
11955
|
});
|
|
11567
11956
|
}
|
|
@@ -11572,10 +11961,10 @@ async function member() {
|
|
|
11572
11961
|
try {
|
|
11573
11962
|
repoRoot = detectRepoRoot();
|
|
11574
11963
|
repoName = detectRepoName(repoRoot);
|
|
11575
|
-
spinner.succeed(`Repository: ${
|
|
11964
|
+
spinner.succeed(`Repository: ${chalk9.bold(repoName)}`);
|
|
11576
11965
|
} catch {
|
|
11577
11966
|
spinner.fail(
|
|
11578
|
-
|
|
11967
|
+
chalk9.red("Not in a git repository. Run this command from your project directory.")
|
|
11579
11968
|
);
|
|
11580
11969
|
process.exitCode = 1;
|
|
11581
11970
|
return;
|
|
@@ -11586,15 +11975,15 @@ async function member() {
|
|
|
11586
11975
|
const localRepoName = detectRepoName(repoRoot);
|
|
11587
11976
|
if (repoName && localRepoName !== repoName && !repoName.endsWith(`/${localRepoName}`)) {
|
|
11588
11977
|
spinner.warn(
|
|
11589
|
-
|
|
11590
|
-
`Pending repo is ${
|
|
11978
|
+
chalk9.yellow(
|
|
11979
|
+
`Pending repo is ${chalk9.bold(repoName)} but you're in ${chalk9.bold(localRepoName)}.
|
|
11591
11980
|
Make sure you're in the right project directory, or the context files will be saved here.`
|
|
11592
11981
|
)
|
|
11593
11982
|
);
|
|
11594
11983
|
}
|
|
11595
11984
|
} catch {
|
|
11596
11985
|
spinner.fail(
|
|
11597
|
-
|
|
11986
|
+
chalk9.red(
|
|
11598
11987
|
"Please navigate to your project directory first, then run `repowise member` again."
|
|
11599
11988
|
)
|
|
11600
11989
|
);
|
|
@@ -11614,14 +12003,14 @@ async function member() {
|
|
|
11614
12003
|
repoPlatform = match.platform;
|
|
11615
12004
|
repoExternalId = match.externalId;
|
|
11616
12005
|
if (!repoName) repoName = match.fullName;
|
|
11617
|
-
spinner.succeed(`Repository: ${
|
|
12006
|
+
spinner.succeed(`Repository: ${chalk9.bold(match.fullName)}`);
|
|
11618
12007
|
}
|
|
11619
12008
|
} catch {
|
|
11620
12009
|
}
|
|
11621
12010
|
}
|
|
11622
12011
|
if (!repoId) {
|
|
11623
12012
|
spinner.fail(
|
|
11624
|
-
|
|
12013
|
+
chalk9.red(
|
|
11625
12014
|
"This repository is not connected to your team. Ask your team admin to add it on the dashboard."
|
|
11626
12015
|
)
|
|
11627
12016
|
);
|
|
@@ -11634,23 +12023,23 @@ async function member() {
|
|
|
11634
12023
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
11635
12024
|
files = listResult.data?.files ?? listResult.files ?? [];
|
|
11636
12025
|
} catch {
|
|
11637
|
-
spinner.fail(
|
|
12026
|
+
spinner.fail(chalk9.red("Failed to check context files on server."));
|
|
11638
12027
|
process.exitCode = 1;
|
|
11639
12028
|
return;
|
|
11640
12029
|
}
|
|
11641
12030
|
if (files.length === 0) {
|
|
11642
12031
|
spinner.fail(
|
|
11643
|
-
|
|
12032
|
+
chalk9.red(
|
|
11644
12033
|
"No context files found for this repository. Your team admin needs to run the initial scan first."
|
|
11645
12034
|
)
|
|
11646
12035
|
);
|
|
11647
12036
|
process.exitCode = 1;
|
|
11648
12037
|
return;
|
|
11649
12038
|
}
|
|
11650
|
-
spinner.succeed(`Found ${
|
|
12039
|
+
spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
|
|
11651
12040
|
const { tools } = await selectAiTools();
|
|
11652
12041
|
spinner.start("Downloading context files...");
|
|
11653
|
-
const contextDir =
|
|
12042
|
+
const contextDir = join41(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
11654
12043
|
mkdirSync2(contextDir, { recursive: true });
|
|
11655
12044
|
let downloadedCount = 0;
|
|
11656
12045
|
let failedCount = 0;
|
|
@@ -11726,7 +12115,7 @@ async function member() {
|
|
|
11726
12115
|
}
|
|
11727
12116
|
spinner.succeed("AI tools configured");
|
|
11728
12117
|
for (const msg of configured) {
|
|
11729
|
-
console.log(
|
|
12118
|
+
console.log(chalk9.dim(` ${msg}`));
|
|
11730
12119
|
}
|
|
11731
12120
|
}
|
|
11732
12121
|
let depInstallPromise = null;
|
|
@@ -11740,6 +12129,7 @@ async function member() {
|
|
|
11740
12129
|
});
|
|
11741
12130
|
depInstallPromise = result.installPromise;
|
|
11742
12131
|
}
|
|
12132
|
+
const lspInstallPromise = (await maybeInstallLspServers({ repoRoot, spinner })).installPromise;
|
|
11743
12133
|
spinner.start("Saving configuration...");
|
|
11744
12134
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
11745
12135
|
const repoEntry = {
|
|
@@ -11784,54 +12174,78 @@ async function member() {
|
|
|
11784
12174
|
);
|
|
11785
12175
|
}
|
|
11786
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
|
+
}
|
|
11787
12201
|
const elapsed = formatElapsed2(Date.now() - startTime);
|
|
11788
12202
|
console.log("");
|
|
11789
|
-
console.log(
|
|
12203
|
+
console.log(chalk9.green.bold("All done! Context downloaded and configured."));
|
|
11790
12204
|
console.log("");
|
|
11791
|
-
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)}.`);
|
|
11792
12206
|
console.log(
|
|
11793
|
-
`Downloaded ${
|
|
12207
|
+
`Downloaded ${chalk9.bold(downloadedCount)} context files to ./${DEFAULT_CONTEXT_FOLDER2}/`
|
|
11794
12208
|
);
|
|
11795
12209
|
console.log("");
|
|
11796
12210
|
if (listenerRunning) {
|
|
11797
12211
|
console.log(
|
|
11798
|
-
|
|
12212
|
+
chalk9.dim(
|
|
11799
12213
|
"The RepoWise listener is running in the background \u2014\nyour context will stay in sync automatically."
|
|
11800
12214
|
)
|
|
11801
12215
|
);
|
|
11802
12216
|
} else {
|
|
11803
12217
|
console.log(
|
|
11804
|
-
|
|
12218
|
+
chalk9.yellow(
|
|
11805
12219
|
"Could not start listener automatically. Run `repowise listen --install` to enable auto-sync."
|
|
11806
12220
|
)
|
|
11807
12221
|
);
|
|
11808
12222
|
}
|
|
11809
12223
|
console.log("");
|
|
11810
12224
|
console.log(
|
|
11811
|
-
|
|
12225
|
+
chalk9.dim(`Head back to the dashboard and click "Complete Onboarding" to finish setup.`)
|
|
11812
12226
|
);
|
|
11813
|
-
console.log(
|
|
12227
|
+
console.log(chalk9.dim(`Total time: ${elapsed}`));
|
|
11814
12228
|
} catch (err) {
|
|
11815
12229
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
11816
|
-
spinner.fail(
|
|
12230
|
+
spinner.fail(chalk9.red(`Setup failed: ${message}`));
|
|
11817
12231
|
process.exitCode = 1;
|
|
11818
12232
|
}
|
|
11819
12233
|
}
|
|
11820
12234
|
|
|
11821
12235
|
// src/commands/login.ts
|
|
11822
|
-
import
|
|
12236
|
+
import chalk10 from "chalk";
|
|
11823
12237
|
import ora3 from "ora";
|
|
11824
12238
|
|
|
11825
12239
|
// src/lib/tenant-graph-purge.ts
|
|
11826
|
-
import { promises as
|
|
12240
|
+
import { promises as fs18 } from "fs";
|
|
11827
12241
|
import { homedir as homedir7 } from "os";
|
|
11828
|
-
import { join as
|
|
12242
|
+
import { join as join42 } from "path";
|
|
11829
12243
|
async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
11830
|
-
const graphsDir =
|
|
12244
|
+
const graphsDir = join42(home, ".repowise", "graphs");
|
|
11831
12245
|
const result = { kept: [], removed: [] };
|
|
11832
12246
|
let entries;
|
|
11833
12247
|
try {
|
|
11834
|
-
entries = await
|
|
12248
|
+
entries = await fs18.readdir(graphsDir);
|
|
11835
12249
|
} catch (err) {
|
|
11836
12250
|
if (err.code === "ENOENT") return result;
|
|
11837
12251
|
throw err;
|
|
@@ -11845,15 +12259,15 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
|
11845
12259
|
result.kept.push(entry);
|
|
11846
12260
|
continue;
|
|
11847
12261
|
}
|
|
11848
|
-
const path =
|
|
12262
|
+
const path = join42(graphsDir, entry);
|
|
11849
12263
|
try {
|
|
11850
|
-
const stat7 = await
|
|
12264
|
+
const stat7 = await fs18.lstat(path);
|
|
11851
12265
|
if (stat7.isSymbolicLink()) {
|
|
11852
|
-
await
|
|
12266
|
+
await fs18.unlink(path);
|
|
11853
12267
|
result.removed.push(entry);
|
|
11854
12268
|
continue;
|
|
11855
12269
|
}
|
|
11856
|
-
await
|
|
12270
|
+
await fs18.rm(path, { recursive: true, force: true });
|
|
11857
12271
|
result.removed.push(entry);
|
|
11858
12272
|
} catch {
|
|
11859
12273
|
}
|
|
@@ -11875,7 +12289,7 @@ async function login(options = {}) {
|
|
|
11875
12289
|
console.log(`
|
|
11876
12290
|
Open this URL in your browser to authenticate:
|
|
11877
12291
|
`);
|
|
11878
|
-
console.log(
|
|
12292
|
+
console.log(chalk10.cyan(authorizeUrl));
|
|
11879
12293
|
console.log(`
|
|
11880
12294
|
Waiting for authentication...`);
|
|
11881
12295
|
} else {
|
|
@@ -11889,7 +12303,7 @@ Waiting for authentication...`);
|
|
|
11889
12303
|
console.log(`
|
|
11890
12304
|
Could not open browser automatically. Open this URL:
|
|
11891
12305
|
`);
|
|
11892
|
-
console.log(
|
|
12306
|
+
console.log(chalk10.cyan(authorizeUrl));
|
|
11893
12307
|
console.log(`
|
|
11894
12308
|
Waiting for authentication...`);
|
|
11895
12309
|
}
|
|
@@ -11903,14 +12317,14 @@ Waiting for authentication...`);
|
|
|
11903
12317
|
credentials.cognito = getCognitoConfigForStorage();
|
|
11904
12318
|
await storeCredentials2(credentials);
|
|
11905
12319
|
const { email } = decodeIdToken(credentials.idToken);
|
|
11906
|
-
spinner.succeed(
|
|
12320
|
+
spinner.succeed(chalk10.green(`Logged in as ${chalk10.bold(email)}`));
|
|
11907
12321
|
try {
|
|
11908
12322
|
const repos = await apiRequest("/v1/repos");
|
|
11909
12323
|
const validRepoIds = new Set(repos.map((r) => r.repoId));
|
|
11910
12324
|
const result = await purgeForeignGraphs(validRepoIds);
|
|
11911
12325
|
if (result.removed.length > 0) {
|
|
11912
12326
|
console.log(
|
|
11913
|
-
|
|
12327
|
+
chalk10.dim(
|
|
11914
12328
|
` Cleaned ${result.removed.length.toString()} graph artifact(s) from a prior tenant.`
|
|
11915
12329
|
)
|
|
11916
12330
|
);
|
|
@@ -11919,30 +12333,30 @@ Waiting for authentication...`);
|
|
|
11919
12333
|
}
|
|
11920
12334
|
} catch (err) {
|
|
11921
12335
|
const message = err instanceof Error ? err.message : "Login failed";
|
|
11922
|
-
spinner.fail(
|
|
12336
|
+
spinner.fail(chalk10.red(message));
|
|
11923
12337
|
process.exitCode = 1;
|
|
11924
12338
|
}
|
|
11925
12339
|
}
|
|
11926
12340
|
|
|
11927
12341
|
// src/commands/logout.ts
|
|
11928
|
-
import
|
|
12342
|
+
import chalk11 from "chalk";
|
|
11929
12343
|
async function logout() {
|
|
11930
12344
|
const creds = await getStoredCredentials2();
|
|
11931
12345
|
if (!creds) {
|
|
11932
|
-
console.log(
|
|
12346
|
+
console.log(chalk11.yellow("Not logged in."));
|
|
11933
12347
|
return;
|
|
11934
12348
|
}
|
|
11935
12349
|
await clearCredentials();
|
|
11936
|
-
console.log(
|
|
12350
|
+
console.log(chalk11.green("Logged out successfully."));
|
|
11937
12351
|
}
|
|
11938
12352
|
|
|
11939
12353
|
// src/commands/status.ts
|
|
11940
12354
|
import { readFile as readFile16 } from "fs/promises";
|
|
11941
|
-
import { basename as basename3, join as
|
|
12355
|
+
import { basename as basename3, join as join43 } from "path";
|
|
11942
12356
|
async function status() {
|
|
11943
12357
|
const configDir = getConfigDir2();
|
|
11944
|
-
const STATE_PATH =
|
|
11945
|
-
const CONFIG_PATH =
|
|
12358
|
+
const STATE_PATH = join43(configDir, "listener-state.json");
|
|
12359
|
+
const CONFIG_PATH = join43(configDir, "config.json");
|
|
11946
12360
|
let state = null;
|
|
11947
12361
|
try {
|
|
11948
12362
|
const data = await readFile16(STATE_PATH, "utf-8");
|
|
@@ -11990,8 +12404,8 @@ async function status() {
|
|
|
11990
12404
|
|
|
11991
12405
|
// src/commands/sync.ts
|
|
11992
12406
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
11993
|
-
import { dirname as dirname17, join as
|
|
11994
|
-
import
|
|
12407
|
+
import { dirname as dirname17, join as join44 } from "path";
|
|
12408
|
+
import chalk12 from "chalk";
|
|
11995
12409
|
import ora4 from "ora";
|
|
11996
12410
|
var POLL_INTERVAL_MS2 = 3e3;
|
|
11997
12411
|
var MAX_POLL_ATTEMPTS2 = 7200;
|
|
@@ -12009,10 +12423,10 @@ async function sync() {
|
|
|
12009
12423
|
try {
|
|
12010
12424
|
let credentials = await getValidCredentials2();
|
|
12011
12425
|
if (!credentials) {
|
|
12012
|
-
spinner.info(
|
|
12426
|
+
spinner.info(chalk12.yellow("Not logged in. Opening browser to authenticate..."));
|
|
12013
12427
|
credentials = await performLogin();
|
|
12014
12428
|
const { email } = decodeIdToken(credentials.idToken);
|
|
12015
|
-
spinner.succeed(
|
|
12429
|
+
spinner.succeed(chalk12.green(`Authenticated as ${chalk12.bold(email)}`));
|
|
12016
12430
|
} else {
|
|
12017
12431
|
spinner.succeed("Authenticated");
|
|
12018
12432
|
}
|
|
@@ -12022,10 +12436,10 @@ async function sync() {
|
|
|
12022
12436
|
try {
|
|
12023
12437
|
repoRoot = detectRepoRoot();
|
|
12024
12438
|
repoName = detectRepoName(repoRoot);
|
|
12025
|
-
spinner.succeed(`Repository: ${
|
|
12439
|
+
spinner.succeed(`Repository: ${chalk12.bold(repoName)}`);
|
|
12026
12440
|
} catch {
|
|
12027
12441
|
spinner.fail(
|
|
12028
|
-
|
|
12442
|
+
chalk12.red("Not in a git repository. Run this command from your repo directory.")
|
|
12029
12443
|
);
|
|
12030
12444
|
process.exitCode = 1;
|
|
12031
12445
|
return;
|
|
@@ -12048,10 +12462,10 @@ async function sync() {
|
|
|
12048
12462
|
}
|
|
12049
12463
|
if (!repoId) {
|
|
12050
12464
|
if (repoLookupError) {
|
|
12051
|
-
spinner.fail(
|
|
12465
|
+
spinner.fail(chalk12.red(`Failed to look up repositories: ${repoLookupError}`));
|
|
12052
12466
|
} else {
|
|
12053
12467
|
spinner.fail(
|
|
12054
|
-
|
|
12468
|
+
chalk12.red(
|
|
12055
12469
|
"Could not find this repository in your RepoWise account. Run `repowise create` first."
|
|
12056
12470
|
)
|
|
12057
12471
|
);
|
|
@@ -12089,7 +12503,7 @@ async function sync() {
|
|
|
12089
12503
|
syncId = retryResult.syncId;
|
|
12090
12504
|
} else {
|
|
12091
12505
|
syncId = active.syncId;
|
|
12092
|
-
spinner.info(
|
|
12506
|
+
spinner.info(chalk12.cyan("Resuming existing sync..."));
|
|
12093
12507
|
spinner.start();
|
|
12094
12508
|
}
|
|
12095
12509
|
}
|
|
@@ -12097,7 +12511,7 @@ async function sync() {
|
|
|
12097
12511
|
const progressRenderer = new ProgressRenderer();
|
|
12098
12512
|
while (true) {
|
|
12099
12513
|
if (++pollAttempts > MAX_POLL_ATTEMPTS2) {
|
|
12100
|
-
spinner.fail(
|
|
12514
|
+
spinner.fail(chalk12.red("Sync timed out. Check dashboard for status."));
|
|
12101
12515
|
process.exitCode = 1;
|
|
12102
12516
|
return;
|
|
12103
12517
|
}
|
|
@@ -12121,15 +12535,15 @@ async function sync() {
|
|
|
12121
12535
|
const generatedFiles = syncResult.filesGenerated ?? [];
|
|
12122
12536
|
const fileCount = generatedFiles.length;
|
|
12123
12537
|
if (fileCount > 0) {
|
|
12124
|
-
spinner.succeed(
|
|
12538
|
+
spinner.succeed(chalk12.green(`Incremental update complete \u2014 ${fileCount} files updated`));
|
|
12125
12539
|
} else {
|
|
12126
|
-
spinner.succeed(
|
|
12540
|
+
spinner.succeed(chalk12.green("Incremental sync complete \u2014 no files needed updating"));
|
|
12127
12541
|
}
|
|
12128
12542
|
break;
|
|
12129
12543
|
}
|
|
12130
12544
|
if (syncResult.status === "failed") {
|
|
12131
12545
|
progressRenderer.finalize();
|
|
12132
|
-
spinner.fail(
|
|
12546
|
+
spinner.fail(chalk12.red(`Sync failed: ${syncResult.error ?? "Unknown error"}`));
|
|
12133
12547
|
process.exitCode = 1;
|
|
12134
12548
|
return;
|
|
12135
12549
|
}
|
|
@@ -12139,7 +12553,7 @@ async function sync() {
|
|
|
12139
12553
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
12140
12554
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
12141
12555
|
if (files.length > 0) {
|
|
12142
|
-
const contextDir =
|
|
12556
|
+
const contextDir = join44(repoRoot, DEFAULT_CONTEXT_FOLDER3);
|
|
12143
12557
|
mkdirSync3(contextDir, { recursive: true });
|
|
12144
12558
|
let downloadedCount = 0;
|
|
12145
12559
|
let failedCount = 0;
|
|
@@ -12153,7 +12567,7 @@ async function sync() {
|
|
|
12153
12567
|
const response = await fetch(presignedUrl);
|
|
12154
12568
|
if (response.ok) {
|
|
12155
12569
|
const content = await response.text();
|
|
12156
|
-
const filePath =
|
|
12570
|
+
const filePath = join44(contextDir, file.fileName);
|
|
12157
12571
|
mkdirSync3(dirname17(filePath), { recursive: true });
|
|
12158
12572
|
writeFileSync4(filePath, content, "utf-8");
|
|
12159
12573
|
downloadedCount++;
|
|
@@ -12209,7 +12623,7 @@ async function sync() {
|
|
|
12209
12623
|
}
|
|
12210
12624
|
} catch (err) {
|
|
12211
12625
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
12212
|
-
spinner.warn(
|
|
12626
|
+
spinner.warn(chalk12.yellow(`Could not download context files: ${msg}
|
|
12213
12627
|
Retry when online.`));
|
|
12214
12628
|
}
|
|
12215
12629
|
if (repoRoot && repoId) {
|
|
@@ -12230,11 +12644,11 @@ Retry when online.`));
|
|
|
12230
12644
|
}
|
|
12231
12645
|
}
|
|
12232
12646
|
const elapsed = formatElapsed3(Date.now() - startTime);
|
|
12233
|
-
console.log(
|
|
12647
|
+
console.log(chalk12.dim(`
|
|
12234
12648
|
Total time: ${elapsed}`));
|
|
12235
12649
|
} catch (err) {
|
|
12236
12650
|
const message = err instanceof Error ? err.message : "Sync failed";
|
|
12237
|
-
spinner.fail(
|
|
12651
|
+
spinner.fail(chalk12.red(message));
|
|
12238
12652
|
process.exitCode = 1;
|
|
12239
12653
|
}
|
|
12240
12654
|
}
|
|
@@ -12317,7 +12731,7 @@ async function stop2() {
|
|
|
12317
12731
|
}
|
|
12318
12732
|
|
|
12319
12733
|
// src/commands/config.ts
|
|
12320
|
-
import
|
|
12734
|
+
import chalk13 from "chalk";
|
|
12321
12735
|
import ora5 from "ora";
|
|
12322
12736
|
import { select } from "@inquirer/prompts";
|
|
12323
12737
|
async function config() {
|
|
@@ -12325,10 +12739,10 @@ async function config() {
|
|
|
12325
12739
|
try {
|
|
12326
12740
|
let credentials = await getValidCredentials2();
|
|
12327
12741
|
if (!credentials) {
|
|
12328
|
-
spinner.info(
|
|
12742
|
+
spinner.info(chalk13.yellow("Not logged in. Opening browser to authenticate..."));
|
|
12329
12743
|
credentials = await performLogin();
|
|
12330
12744
|
const { email } = decodeIdToken(credentials.idToken);
|
|
12331
|
-
spinner.succeed(
|
|
12745
|
+
spinner.succeed(chalk13.green(`Authenticated as ${chalk13.bold(email)}`));
|
|
12332
12746
|
} else {
|
|
12333
12747
|
spinner.succeed("Authenticated");
|
|
12334
12748
|
}
|
|
@@ -12336,7 +12750,7 @@ async function config() {
|
|
|
12336
12750
|
const repos = await apiRequest("/v1/repos");
|
|
12337
12751
|
spinner.stop();
|
|
12338
12752
|
if (repos.length === 0) {
|
|
12339
|
-
console.log(
|
|
12753
|
+
console.log(chalk13.yellow("No repositories connected. Run `repowise create` first."));
|
|
12340
12754
|
return;
|
|
12341
12755
|
}
|
|
12342
12756
|
const repoId = await select({
|
|
@@ -12350,10 +12764,10 @@ async function config() {
|
|
|
12350
12764
|
const currentDelivery = repo.deliveryMode ?? "direct";
|
|
12351
12765
|
const currentBranch = repo.monitoredBranch ?? repo.defaultBranch;
|
|
12352
12766
|
console.log("");
|
|
12353
|
-
console.log(
|
|
12354
|
-
console.log(
|
|
12355
|
-
console.log(
|
|
12356
|
-
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}`));
|
|
12357
12771
|
console.log("");
|
|
12358
12772
|
const setting = await select({
|
|
12359
12773
|
message: "What would you like to change?",
|
|
@@ -12373,7 +12787,7 @@ async function config() {
|
|
|
12373
12787
|
default: currentDelivery
|
|
12374
12788
|
});
|
|
12375
12789
|
if (newMode === currentDelivery) {
|
|
12376
|
-
console.log(
|
|
12790
|
+
console.log(chalk13.dim("No change."));
|
|
12377
12791
|
return;
|
|
12378
12792
|
}
|
|
12379
12793
|
patch.deliveryMode = newMode;
|
|
@@ -12384,7 +12798,7 @@ async function config() {
|
|
|
12384
12798
|
default: currentBranch
|
|
12385
12799
|
});
|
|
12386
12800
|
if (newBranch === currentBranch) {
|
|
12387
|
-
console.log(
|
|
12801
|
+
console.log(chalk13.dim("No change."));
|
|
12388
12802
|
return;
|
|
12389
12803
|
}
|
|
12390
12804
|
patch.monitoredBranch = newBranch;
|
|
@@ -12394,11 +12808,11 @@ async function config() {
|
|
|
12394
12808
|
method: "PATCH",
|
|
12395
12809
|
body: JSON.stringify(patch)
|
|
12396
12810
|
});
|
|
12397
|
-
spinner.succeed(
|
|
12811
|
+
spinner.succeed(chalk13.green("Setting updated"));
|
|
12398
12812
|
} catch (err) {
|
|
12399
12813
|
spinner.stop();
|
|
12400
12814
|
const message = err instanceof Error ? err.message : "Config failed";
|
|
12401
|
-
console.error(
|
|
12815
|
+
console.error(chalk13.red(message));
|
|
12402
12816
|
process.exitCode = 1;
|
|
12403
12817
|
}
|
|
12404
12818
|
}
|
|
@@ -12406,7 +12820,7 @@ async function config() {
|
|
|
12406
12820
|
// src/commands/mcp-log.ts
|
|
12407
12821
|
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
12408
12822
|
import { mkdir as mkdir18, readFile as readFile17, stat as stat6, writeFile as writeFile18 } from "fs/promises";
|
|
12409
|
-
import { dirname as dirname18, join as
|
|
12823
|
+
import { dirname as dirname18, join as join45 } from "path";
|
|
12410
12824
|
var FLAG_FILE = "mcp-log.flag";
|
|
12411
12825
|
var LOG_FILE = "mcp-log.jsonl.enc";
|
|
12412
12826
|
var KEY_FILE = "mcp-log.key";
|
|
@@ -12414,10 +12828,10 @@ var ENDPOINT_FILE = "listener.endpoint";
|
|
|
12414
12828
|
var IV_BYTES2 = 12;
|
|
12415
12829
|
var TAG_BYTES2 = 16;
|
|
12416
12830
|
function flagPath() {
|
|
12417
|
-
return
|
|
12831
|
+
return join45(getConfigDir2(), FLAG_FILE);
|
|
12418
12832
|
}
|
|
12419
12833
|
function logPath() {
|
|
12420
|
-
return
|
|
12834
|
+
return join45(getConfigDir2(), LOG_FILE);
|
|
12421
12835
|
}
|
|
12422
12836
|
async function writeFlag(flag) {
|
|
12423
12837
|
const path = flagPath();
|
|
@@ -12458,14 +12872,14 @@ async function trySendConsentToServer() {
|
|
|
12458
12872
|
let apiUrl = null;
|
|
12459
12873
|
let token = null;
|
|
12460
12874
|
try {
|
|
12461
|
-
const body = await readFile17(
|
|
12875
|
+
const body = await readFile17(join45(getConfigDir2(), "config.json"), "utf-8");
|
|
12462
12876
|
const parsed = JSON.parse(body);
|
|
12463
12877
|
apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
|
|
12464
12878
|
} catch {
|
|
12465
12879
|
return false;
|
|
12466
12880
|
}
|
|
12467
12881
|
try {
|
|
12468
|
-
const body = await readFile17(
|
|
12882
|
+
const body = await readFile17(join45(getConfigDir2(), "credentials.json"), "utf-8");
|
|
12469
12883
|
const parsed = JSON.parse(body);
|
|
12470
12884
|
token = parsed.idToken ?? null;
|
|
12471
12885
|
} catch {
|
|
@@ -12535,7 +12949,7 @@ async function mcpLogStatus() {
|
|
|
12535
12949
|
process.stderr.write("Log size: no file yet\n");
|
|
12536
12950
|
}
|
|
12537
12951
|
try {
|
|
12538
|
-
const endpointBody = await readFile17(
|
|
12952
|
+
const endpointBody = await readFile17(join45(getConfigDir2(), ENDPOINT_FILE), "utf-8");
|
|
12539
12953
|
const match = /endpoint=([^\n]+)/.exec(endpointBody);
|
|
12540
12954
|
process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
|
|
12541
12955
|
`);
|
|
@@ -12566,7 +12980,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
12566
12980
|
const key = await readKey();
|
|
12567
12981
|
if (!key) {
|
|
12568
12982
|
process.stderr.write(
|
|
12569
|
-
`No encryption key at ${
|
|
12983
|
+
`No encryption key at ${join45(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
|
|
12570
12984
|
`
|
|
12571
12985
|
);
|
|
12572
12986
|
return;
|
|
@@ -12642,7 +13056,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
12642
13056
|
}
|
|
12643
13057
|
async function readKey() {
|
|
12644
13058
|
try {
|
|
12645
|
-
const body = await readFile17(
|
|
13059
|
+
const body = await readFile17(join45(getConfigDir2(), KEY_FILE), "utf-8");
|
|
12646
13060
|
const parsed = Buffer.from(body.trim(), "base64");
|
|
12647
13061
|
if (parsed.length !== 32) return null;
|
|
12648
13062
|
return parsed;
|
|
@@ -12682,11 +13096,11 @@ async function mcpLog(subcommand, flags = {}) {
|
|
|
12682
13096
|
}
|
|
12683
13097
|
|
|
12684
13098
|
// src/commands/query/_shared.ts
|
|
12685
|
-
import
|
|
13099
|
+
import chalk14 from "chalk";
|
|
12686
13100
|
|
|
12687
13101
|
// src/lib/graph-loader.ts
|
|
12688
|
-
import { promises as
|
|
12689
|
-
import { join as
|
|
13102
|
+
import { promises as fs19 } from "fs";
|
|
13103
|
+
import { join as join46, resolve as resolve2 } from "path";
|
|
12690
13104
|
import { gunzipSync } from "zlib";
|
|
12691
13105
|
var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
|
|
12692
13106
|
var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
|
|
@@ -12703,8 +13117,8 @@ var GraphNotFoundError = class extends Error {
|
|
|
12703
13117
|
var cache = /* @__PURE__ */ new Map();
|
|
12704
13118
|
async function loadGraph(repoRoot = process.cwd()) {
|
|
12705
13119
|
const root = resolve2(repoRoot);
|
|
12706
|
-
const gzPath =
|
|
12707
|
-
const plainPath =
|
|
13120
|
+
const gzPath = join46(root, GZIPPED_GRAPH_PATH);
|
|
13121
|
+
const plainPath = join46(root, RELATIVE_GRAPH_PATH);
|
|
12708
13122
|
const cached = cache.get(root);
|
|
12709
13123
|
if (cached) {
|
|
12710
13124
|
return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
|
|
@@ -12712,14 +13126,14 @@ async function loadGraph(repoRoot = process.cwd()) {
|
|
|
12712
13126
|
let graphPath = null;
|
|
12713
13127
|
let raw = null;
|
|
12714
13128
|
try {
|
|
12715
|
-
raw = await
|
|
13129
|
+
raw = await fs19.readFile(gzPath);
|
|
12716
13130
|
graphPath = gzPath;
|
|
12717
13131
|
} catch (err) {
|
|
12718
13132
|
if (err.code !== "ENOENT") throw err;
|
|
12719
13133
|
}
|
|
12720
13134
|
if (!raw) {
|
|
12721
13135
|
try {
|
|
12722
|
-
raw = await
|
|
13136
|
+
raw = await fs19.readFile(plainPath);
|
|
12723
13137
|
graphPath = plainPath;
|
|
12724
13138
|
} catch (err) {
|
|
12725
13139
|
if (err.code === "ENOENT") {
|
|
@@ -12922,7 +13336,7 @@ async function loadService() {
|
|
|
12922
13336
|
return createGraphQueryService(graph);
|
|
12923
13337
|
} catch (err) {
|
|
12924
13338
|
if (err instanceof GraphNotFoundError) {
|
|
12925
|
-
process.stderr.write(
|
|
13339
|
+
process.stderr.write(chalk14.red(`\u2717 ${err.message}
|
|
12926
13340
|
`));
|
|
12927
13341
|
process.exit(err.exitCode);
|
|
12928
13342
|
}
|
|
@@ -13118,14 +13532,14 @@ function registerQueryCommand(program2) {
|
|
|
13118
13532
|
}
|
|
13119
13533
|
|
|
13120
13534
|
// src/commands/uninstall.ts
|
|
13121
|
-
import { promises as
|
|
13535
|
+
import { promises as fs23 } from "fs";
|
|
13122
13536
|
import { homedir as homedir9 } from "os";
|
|
13123
|
-
import { join as
|
|
13124
|
-
import
|
|
13537
|
+
import { join as join50 } from "path";
|
|
13538
|
+
import chalk15 from "chalk";
|
|
13125
13539
|
|
|
13126
13540
|
// src/lib/cleanup/marker-blocks.ts
|
|
13127
|
-
import { promises as
|
|
13128
|
-
import { join as
|
|
13541
|
+
import { promises as fs20 } from "fs";
|
|
13542
|
+
import { join as join47 } from "path";
|
|
13129
13543
|
var MARKER_START = "<!-- repowise-start -->";
|
|
13130
13544
|
var MARKER_END = "<!-- repowise-end -->";
|
|
13131
13545
|
var CONTEXT_FILES = [
|
|
@@ -13141,7 +13555,7 @@ var CONTEXT_FILES = [
|
|
|
13141
13555
|
async function stripMarkerBlock(filePath) {
|
|
13142
13556
|
let raw;
|
|
13143
13557
|
try {
|
|
13144
|
-
raw = await
|
|
13558
|
+
raw = await fs20.readFile(filePath, "utf-8");
|
|
13145
13559
|
} catch (err) {
|
|
13146
13560
|
if (err.code === "ENOENT")
|
|
13147
13561
|
return { path: filePath, status: "missing" };
|
|
@@ -13156,16 +13570,16 @@ async function stripMarkerBlock(filePath) {
|
|
|
13156
13570
|
const after = raw.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
|
|
13157
13571
|
const stripped = (before + (before && after ? "\n\n" : "") + after).trim();
|
|
13158
13572
|
if (stripped.length === 0) {
|
|
13159
|
-
await
|
|
13573
|
+
await fs20.unlink(filePath);
|
|
13160
13574
|
return { path: filePath, status: "deleted" };
|
|
13161
13575
|
}
|
|
13162
|
-
await
|
|
13576
|
+
await fs20.writeFile(filePath, stripped + "\n", "utf-8");
|
|
13163
13577
|
return { path: filePath, status: "stripped" };
|
|
13164
13578
|
}
|
|
13165
13579
|
async function stripAllMarkerBlocks(repoRoot) {
|
|
13166
13580
|
const out = [];
|
|
13167
13581
|
for (const relative of CONTEXT_FILES) {
|
|
13168
|
-
const full =
|
|
13582
|
+
const full = join47(repoRoot, relative);
|
|
13169
13583
|
const result = await stripMarkerBlock(full).catch((err) => ({
|
|
13170
13584
|
path: full,
|
|
13171
13585
|
status: "untouched",
|
|
@@ -13177,25 +13591,25 @@ async function stripAllMarkerBlocks(repoRoot) {
|
|
|
13177
13591
|
}
|
|
13178
13592
|
|
|
13179
13593
|
// src/lib/cleanup/mcp-configs.ts
|
|
13180
|
-
import { promises as
|
|
13181
|
-
import { join as
|
|
13594
|
+
import { promises as fs21 } from "fs";
|
|
13595
|
+
import { join as join48 } from "path";
|
|
13182
13596
|
function mcpConfigPaths(repoRoot, home) {
|
|
13183
13597
|
return [
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
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")
|
|
13193
13607
|
];
|
|
13194
13608
|
}
|
|
13195
13609
|
async function removeRepowiseFromConfig(path, serverName) {
|
|
13196
13610
|
let raw;
|
|
13197
13611
|
try {
|
|
13198
|
-
raw = await
|
|
13612
|
+
raw = await fs21.readFile(path, "utf-8");
|
|
13199
13613
|
} catch (err) {
|
|
13200
13614
|
if (err.code === "ENOENT") return { path, status: "not-found" };
|
|
13201
13615
|
return { path, status: "error", error: err.message };
|
|
@@ -13215,7 +13629,7 @@ async function removeRepowiseFromConfig(path, serverName) {
|
|
|
13215
13629
|
} else {
|
|
13216
13630
|
next.mcpServers = servers;
|
|
13217
13631
|
}
|
|
13218
|
-
await
|
|
13632
|
+
await fs21.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
13219
13633
|
return { path, status: "removed" };
|
|
13220
13634
|
}
|
|
13221
13635
|
async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
@@ -13228,17 +13642,17 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
|
13228
13642
|
}
|
|
13229
13643
|
|
|
13230
13644
|
// src/lib/cleanup/local-state.ts
|
|
13231
|
-
import { promises as
|
|
13645
|
+
import { promises as fs22 } from "fs";
|
|
13232
13646
|
import { homedir as homedir8 } from "os";
|
|
13233
|
-
import { join as
|
|
13647
|
+
import { join as join49, resolve as resolve3 } from "path";
|
|
13234
13648
|
async function clearLocalState(homeOverride) {
|
|
13235
13649
|
const home = homeOverride ?? homedir8();
|
|
13236
|
-
const target = resolve3(
|
|
13650
|
+
const target = resolve3(join49(home, ".repowise"));
|
|
13237
13651
|
if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
|
|
13238
13652
|
return { path: target, status: "error", error: "refused: not under home" };
|
|
13239
13653
|
}
|
|
13240
13654
|
try {
|
|
13241
|
-
await
|
|
13655
|
+
await fs22.rm(target, { recursive: true, force: false });
|
|
13242
13656
|
return { path: target, status: "removed" };
|
|
13243
13657
|
} catch (err) {
|
|
13244
13658
|
if (err.code === "ENOENT")
|
|
@@ -13277,7 +13691,7 @@ async function uninstall2(opts = {}) {
|
|
|
13277
13691
|
else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
|
|
13278
13692
|
if (tier === "stop") return report;
|
|
13279
13693
|
try {
|
|
13280
|
-
await
|
|
13694
|
+
await fs23.unlink(join50(home, ".repowise", "credentials.json"));
|
|
13281
13695
|
report.removed.push("credentials");
|
|
13282
13696
|
} catch (err) {
|
|
13283
13697
|
if (err.code !== "ENOENT") {
|
|
@@ -13304,7 +13718,7 @@ async function uninstall2(opts = {}) {
|
|
|
13304
13718
|
const allPaths = mcpConfigPaths(repoRoot, home);
|
|
13305
13719
|
for (const p of allPaths) {
|
|
13306
13720
|
try {
|
|
13307
|
-
await
|
|
13721
|
+
await fs23.access(p);
|
|
13308
13722
|
} catch {
|
|
13309
13723
|
}
|
|
13310
13724
|
}
|
|
@@ -13316,7 +13730,7 @@ async function uninstall2(opts = {}) {
|
|
|
13316
13730
|
}
|
|
13317
13731
|
async function defaultLoadRepoIds(home) {
|
|
13318
13732
|
try {
|
|
13319
|
-
const raw = await
|
|
13733
|
+
const raw = await fs23.readFile(join50(home, ".repowise", "config.json"), "utf-8");
|
|
13320
13734
|
const parsed = JSON.parse(raw);
|
|
13321
13735
|
return (parsed.repos ?? []).map((r) => r.repoId);
|
|
13322
13736
|
} catch {
|
|
@@ -13333,29 +13747,29 @@ async function uninstallCommand(opts = {}) {
|
|
|
13333
13747
|
default: false
|
|
13334
13748
|
});
|
|
13335
13749
|
if (!proceed) {
|
|
13336
|
-
process.stderr.write(
|
|
13750
|
+
process.stderr.write(chalk15.yellow("Uninstall cancelled.\n"));
|
|
13337
13751
|
process.exitCode = 1;
|
|
13338
13752
|
return;
|
|
13339
13753
|
}
|
|
13340
13754
|
}
|
|
13341
13755
|
}
|
|
13342
|
-
process.stderr.write(
|
|
13756
|
+
process.stderr.write(chalk15.bold(`RepoWise ${tier}
|
|
13343
13757
|
`));
|
|
13344
13758
|
const report = await uninstall2({ ...opts, tier });
|
|
13345
13759
|
for (const p of report.removed) {
|
|
13346
|
-
process.stderr.write(
|
|
13760
|
+
process.stderr.write(chalk15.green(` \u2713 removed: ${p}
|
|
13347
13761
|
`));
|
|
13348
13762
|
}
|
|
13349
13763
|
for (const p of report.preserved) {
|
|
13350
|
-
process.stderr.write(
|
|
13764
|
+
process.stderr.write(chalk15.gray(` \xB7 preserved: ${p}
|
|
13351
13765
|
`));
|
|
13352
13766
|
}
|
|
13353
13767
|
for (const s of report.skipped) {
|
|
13354
|
-
process.stderr.write(
|
|
13768
|
+
process.stderr.write(chalk15.yellow(` ! skipped: ${s.path} (${s.reason})
|
|
13355
13769
|
`));
|
|
13356
13770
|
}
|
|
13357
13771
|
process.stderr.write(
|
|
13358
|
-
|
|
13772
|
+
chalk15.bold(`
|
|
13359
13773
|
Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
13360
13774
|
`)
|
|
13361
13775
|
);
|
|
@@ -13363,12 +13777,12 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
|
13363
13777
|
|
|
13364
13778
|
// src/commands/mcp-shim.ts
|
|
13365
13779
|
init_config_dir();
|
|
13366
|
-
import { promises as
|
|
13780
|
+
import { promises as fs24 } from "fs";
|
|
13367
13781
|
import { createInterface as createInterface2 } from "readline";
|
|
13368
|
-
import { join as
|
|
13782
|
+
import { join as join51 } from "path";
|
|
13369
13783
|
var DEFAULT_MAX = 200 * 1024;
|
|
13370
13784
|
async function mcpShim(opts) {
|
|
13371
|
-
const endpointPath = opts.endpointFile ??
|
|
13785
|
+
const endpointPath = opts.endpointFile ?? join51(getConfigDir(), "listener.endpoint");
|
|
13372
13786
|
const stdin = opts.stdin ?? process.stdin;
|
|
13373
13787
|
const stdout = opts.stdout ?? process.stdout;
|
|
13374
13788
|
const stderr = opts.stderr ?? process.stderr;
|
|
@@ -13441,7 +13855,7 @@ async function mcpShim(opts) {
|
|
|
13441
13855
|
}
|
|
13442
13856
|
async function readEndpoint(path) {
|
|
13443
13857
|
try {
|
|
13444
|
-
const raw = (await
|
|
13858
|
+
const raw = (await fs24.readFile(path, "utf-8")).trim();
|
|
13445
13859
|
if (!raw) return null;
|
|
13446
13860
|
if (raw.startsWith("http://") || raw.startsWith("https://")) {
|
|
13447
13861
|
return { endpoint: raw.split("\n")[0].trim(), secret: null };
|
|
@@ -13683,7 +14097,7 @@ init_coursier_installer();
|
|
|
13683
14097
|
init_toolchain_installer();
|
|
13684
14098
|
import { spawn as spawn11 } from "child_process";
|
|
13685
14099
|
import { resolve as resolve4 } from "path";
|
|
13686
|
-
import
|
|
14100
|
+
import chalk16 from "chalk";
|
|
13687
14101
|
async function isOnPath(command) {
|
|
13688
14102
|
if (/[^\w./+-]/.test(command)) return false;
|
|
13689
14103
|
const isWin = process.platform === "win32";
|
|
@@ -13701,14 +14115,14 @@ async function isOnPath(command) {
|
|
|
13701
14115
|
async function lspDoctor() {
|
|
13702
14116
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13703
14117
|
if (noColor) {
|
|
13704
|
-
|
|
14118
|
+
chalk16.level = 0;
|
|
13705
14119
|
}
|
|
13706
|
-
const okGlyph = noColor ? "[OK]" :
|
|
13707
|
-
const missingGlyph = noColor ? "[MISSING]" :
|
|
13708
|
-
console.log(
|
|
13709
|
-
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."));
|
|
13710
14124
|
console.log(
|
|
13711
|
-
|
|
14125
|
+
chalk16.dim(
|
|
13712
14126
|
"Type-aware resolution covers 9 languages: Go, Python, Rust, Java, Ruby, Dart, Kotlin, PHP, Scala (Phase 7L + 7L++ + 7L+)."
|
|
13713
14127
|
)
|
|
13714
14128
|
);
|
|
@@ -13740,21 +14154,21 @@ async function lspDoctor() {
|
|
|
13740
14154
|
const missing = reports.filter((r) => r.status === "missing").length;
|
|
13741
14155
|
for (const r of reports) {
|
|
13742
14156
|
const head = r.status === "found" ? okGlyph : missingGlyph;
|
|
13743
|
-
const cmd = r.command ?
|
|
14157
|
+
const cmd = r.command ? chalk16.cyan(r.command) : chalk16.dim(r.candidates.join(" / "));
|
|
13744
14158
|
const effectiveConfigs = getEffectiveConfigList(r.language, process.env, lspOverrides);
|
|
13745
14159
|
const method = describeInstallMethod(effectiveConfigs);
|
|
13746
|
-
console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${
|
|
14160
|
+
console.log(` ${head} ${r.language.padEnd(12)} ${cmd} ${chalk16.dim(`[${method}]`)}`);
|
|
13747
14161
|
if (r.status === "missing" && r.hint) {
|
|
13748
|
-
console.log(` ${
|
|
14162
|
+
console.log(` ${chalk16.dim("install:")} ${r.hint}`);
|
|
13749
14163
|
}
|
|
13750
14164
|
}
|
|
13751
14165
|
console.log();
|
|
13752
14166
|
console.log(
|
|
13753
|
-
`${
|
|
14167
|
+
`${chalk16.green(found.toString())} found, ${chalk16.yellow(missing.toString())} missing of ${reports.length.toString()} languages.`
|
|
13754
14168
|
);
|
|
13755
14169
|
if (missing > 0) {
|
|
13756
14170
|
console.log(
|
|
13757
|
-
|
|
14171
|
+
chalk16.dim(
|
|
13758
14172
|
"Missing servers degrade LSP-backed MCP tools to AST-only fallback. Run `repowise lsp install` to auto-install."
|
|
13759
14173
|
)
|
|
13760
14174
|
);
|
|
@@ -13771,15 +14185,15 @@ function describeInstallMethod(configs) {
|
|
|
13771
14185
|
}
|
|
13772
14186
|
async function lspInstall(language) {
|
|
13773
14187
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13774
|
-
if (noColor)
|
|
13775
|
-
console.log(
|
|
14188
|
+
if (noColor) chalk16.level = 0;
|
|
14189
|
+
console.log(chalk16.bold("RepoWise LSP install"));
|
|
13776
14190
|
const cliConfig = await getConfig();
|
|
13777
14191
|
const lspOverrides = cliConfig.lspOverrides;
|
|
13778
14192
|
const targets = language ? [language] : Object.keys(LSP_REGISTRY);
|
|
13779
14193
|
for (const lang of targets) {
|
|
13780
14194
|
const configs = getEffectiveConfigList(lang, process.env, lspOverrides);
|
|
13781
14195
|
if (!configs || configs.length === 0) {
|
|
13782
|
-
console.log(` ${
|
|
14196
|
+
console.log(` ${chalk16.red("\u2717")} ${lang} ${chalk16.dim("(unknown language)")}`);
|
|
13783
14197
|
continue;
|
|
13784
14198
|
}
|
|
13785
14199
|
const result = await installOneLanguage(configs);
|
|
@@ -13847,11 +14261,11 @@ async function installOneLanguage(configs) {
|
|
|
13847
14261
|
};
|
|
13848
14262
|
}
|
|
13849
14263
|
function formatInstallLine(lang, outcome) {
|
|
13850
|
-
const glyph = outcome.ok ?
|
|
13851
|
-
const tag =
|
|
14264
|
+
const glyph = outcome.ok ? chalk16.green("\u2713") : chalk16.yellow("\u2717");
|
|
14265
|
+
const tag = chalk16.dim(`[${outcome.method}]`);
|
|
13852
14266
|
console.log(` ${glyph} ${lang.padEnd(12)} ${tag} ${outcome.detail}`);
|
|
13853
14267
|
if (!outcome.ok && outcome.hint) {
|
|
13854
|
-
console.log(` ${
|
|
14268
|
+
console.log(` ${chalk16.dim("install:")} ${outcome.hint}`);
|
|
13855
14269
|
}
|
|
13856
14270
|
}
|
|
13857
14271
|
var MAX_KEEP_WARM_MINUTES = 240;
|
|
@@ -13889,42 +14303,42 @@ async function autoDetectLanguages(cwd) {
|
|
|
13889
14303
|
async function lspWarm(opts = {}) {
|
|
13890
14304
|
const cwd = resolve4(opts.cwd ?? process.cwd());
|
|
13891
14305
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13892
|
-
if (noColor)
|
|
14306
|
+
if (noColor) chalk16.level = 0;
|
|
13893
14307
|
let languages;
|
|
13894
14308
|
if (opts.lang && opts.lang.length > 0) {
|
|
13895
14309
|
const valid = Object.keys(LSP_REGISTRY);
|
|
13896
14310
|
languages = opts.lang.filter((l) => valid.includes(l));
|
|
13897
14311
|
const invalid = opts.lang.filter((l) => !valid.includes(l));
|
|
13898
14312
|
if (invalid.length > 0) {
|
|
13899
|
-
console.log(
|
|
14313
|
+
console.log(chalk16.yellow(`[lsp warm] unknown languages skipped: ${invalid.join(", ")}`));
|
|
13900
14314
|
}
|
|
13901
14315
|
} else {
|
|
13902
14316
|
languages = await autoDetectLanguages(cwd);
|
|
13903
14317
|
if (languages.length === 0) {
|
|
13904
14318
|
console.log(
|
|
13905
|
-
|
|
14319
|
+
chalk16.yellow(
|
|
13906
14320
|
"[lsp warm] no recognised source files in this repo \u2014 pass --lang <id> to force a server."
|
|
13907
14321
|
)
|
|
13908
14322
|
);
|
|
13909
14323
|
return;
|
|
13910
14324
|
}
|
|
13911
|
-
console.log(
|
|
14325
|
+
console.log(chalk16.dim(`[lsp warm] auto-detected languages: ${languages.join(", ")}`));
|
|
13912
14326
|
}
|
|
13913
14327
|
let keepWarmMinutes = 0;
|
|
13914
14328
|
if (typeof opts.keepWarm === "number" && opts.keepWarm > 0) {
|
|
13915
14329
|
keepWarmMinutes = Math.min(opts.keepWarm, MAX_KEEP_WARM_MINUTES);
|
|
13916
14330
|
if (opts.keepWarm > MAX_KEEP_WARM_MINUTES) {
|
|
13917
14331
|
console.log(
|
|
13918
|
-
|
|
14332
|
+
chalk16.yellow(
|
|
13919
14333
|
`[lsp warm] --keep-warm clipped to ${MAX_KEEP_WARM_MINUTES.toString()} minutes (hard cap per Phase 7L plan).`
|
|
13920
14334
|
)
|
|
13921
14335
|
);
|
|
13922
14336
|
}
|
|
13923
14337
|
}
|
|
13924
|
-
console.log(
|
|
13925
|
-
console.log(
|
|
14338
|
+
console.log(chalk16.bold("RepoWise LSP warm \u2014 preview"));
|
|
14339
|
+
console.log(chalk16.dim(`Workspace: ${cwd}`));
|
|
13926
14340
|
console.log(
|
|
13927
|
-
|
|
14341
|
+
chalk16.dim(
|
|
13928
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."
|
|
13929
14343
|
)
|
|
13930
14344
|
);
|
|
@@ -13940,23 +14354,23 @@ async function lspWarm(opts = {}) {
|
|
|
13940
14354
|
if (onPath) {
|
|
13941
14355
|
foundCount += 1;
|
|
13942
14356
|
console.log(
|
|
13943
|
-
|
|
14357
|
+
chalk16.green(` \u2713 ${lang.padEnd(12)} ${config2.displayName} (${config2.command}) on PATH`)
|
|
13944
14358
|
);
|
|
13945
14359
|
} else {
|
|
13946
14360
|
missingCount += 1;
|
|
13947
|
-
console.log(
|
|
14361
|
+
console.log(chalk16.yellow(` \u2717 ${lang.padEnd(12)} ${config2.displayName} not on PATH`));
|
|
13948
14362
|
if (config2.installHint) {
|
|
13949
|
-
console.log(
|
|
14363
|
+
console.log(chalk16.dim(` install: ${config2.installHint}`));
|
|
13950
14364
|
}
|
|
13951
14365
|
}
|
|
13952
14366
|
}
|
|
13953
14367
|
console.log();
|
|
13954
14368
|
console.log(
|
|
13955
|
-
`${
|
|
14369
|
+
`${chalk16.green(foundCount.toString())} ready, ${chalk16.yellow(missingCount.toString())} missing.`
|
|
13956
14370
|
);
|
|
13957
14371
|
if (keepWarmMinutes > 0) {
|
|
13958
14372
|
console.log(
|
|
13959
|
-
|
|
14373
|
+
chalk16.dim(
|
|
13960
14374
|
`Holding for ${keepWarmMinutes.toString()} minute(s) so the listener has time to spawn on its next sync.completed; Ctrl-C to exit early.`
|
|
13961
14375
|
)
|
|
13962
14376
|
);
|
|
@@ -13973,20 +14387,20 @@ async function lspWarm(opts = {}) {
|
|
|
13973
14387
|
}
|
|
13974
14388
|
function lspStatus() {
|
|
13975
14389
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
13976
|
-
if (noColor)
|
|
13977
|
-
console.log(
|
|
14390
|
+
if (noColor) chalk16.level = 0;
|
|
14391
|
+
console.log(chalk16.bold("RepoWise LSP status"));
|
|
13978
14392
|
console.log(
|
|
13979
|
-
|
|
14393
|
+
chalk16.dim(
|
|
13980
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+)."
|
|
13981
14395
|
)
|
|
13982
14396
|
);
|
|
13983
14397
|
console.log();
|
|
13984
|
-
console.log(
|
|
14398
|
+
console.log(chalk16.dim("See `repowise lsp doctor` for PATH probe + install hints."));
|
|
13985
14399
|
}
|
|
13986
14400
|
function lspStop() {
|
|
13987
|
-
console.log(
|
|
14401
|
+
console.log(chalk16.bold("RepoWise LSP stop \u2014 preview"));
|
|
13988
14402
|
console.log(
|
|
13989
|
-
|
|
14403
|
+
chalk16.dim(
|
|
13990
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."
|
|
13991
14405
|
)
|
|
13992
14406
|
);
|
|
@@ -14009,29 +14423,29 @@ var ENABLE_TARGETS = {
|
|
|
14009
14423
|
};
|
|
14010
14424
|
async function lspEnable(target) {
|
|
14011
14425
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14012
|
-
if (noColor)
|
|
14426
|
+
if (noColor) chalk16.level = 0;
|
|
14013
14427
|
if (!target) {
|
|
14014
|
-
console.error(
|
|
14015
|
-
console.error(
|
|
14428
|
+
console.error(chalk16.red("Usage: repowise lsp enable <target>"));
|
|
14429
|
+
console.error(chalk16.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14016
14430
|
process.exitCode = 1;
|
|
14017
14431
|
return;
|
|
14018
14432
|
}
|
|
14019
14433
|
const spec = ENABLE_TARGETS[target];
|
|
14020
14434
|
if (!spec) {
|
|
14021
|
-
console.error(
|
|
14022
|
-
console.error(
|
|
14435
|
+
console.error(chalk16.red(`\u2716 Unknown LSP override target: ${target}`));
|
|
14436
|
+
console.error(chalk16.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14023
14437
|
process.exitCode = 1;
|
|
14024
14438
|
return;
|
|
14025
14439
|
}
|
|
14026
14440
|
const config2 = await getConfig();
|
|
14027
14441
|
const existing = config2.lspOverrides?.[spec.language];
|
|
14028
14442
|
if (existing === spec.name) {
|
|
14029
|
-
console.log(
|
|
14030
|
-
console.log(
|
|
14443
|
+
console.log(chalk16.green(`\u2714 ${spec.displayName} is already enabled.`));
|
|
14444
|
+
console.log(chalk16.dim(` ${spec.postAcceptTip}`));
|
|
14031
14445
|
return;
|
|
14032
14446
|
}
|
|
14033
14447
|
console.log();
|
|
14034
|
-
console.log(
|
|
14448
|
+
console.log(chalk16.cyan.bold(` \u2500\u2500 Enable ${spec.displayName} \u2500\u2500`));
|
|
14035
14449
|
for (const line of spec.consentLines) {
|
|
14036
14450
|
console.log(` ${line}`);
|
|
14037
14451
|
}
|
|
@@ -14042,47 +14456,82 @@ async function lspEnable(target) {
|
|
|
14042
14456
|
default: false
|
|
14043
14457
|
});
|
|
14044
14458
|
if (!proceed) {
|
|
14045
|
-
console.log(
|
|
14459
|
+
console.log(
|
|
14460
|
+
chalk16.dim(
|
|
14461
|
+
` Cancelled. ${spec.language.toUpperCase()} will continue using ${spec.revertDisplay}.`
|
|
14462
|
+
)
|
|
14463
|
+
);
|
|
14046
14464
|
return;
|
|
14047
14465
|
}
|
|
14048
14466
|
const nextOverrides = { ...config2.lspOverrides ?? {}, [spec.language]: spec.name };
|
|
14049
14467
|
await mergeAndSaveConfig({ lspOverrides: nextOverrides });
|
|
14050
|
-
console.log(
|
|
14051
|
-
|
|
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}`));
|
|
14052
14474
|
}
|
|
14053
14475
|
async function lspDisable(target) {
|
|
14054
14476
|
const noColor = Boolean(process.env.NO_COLOR) || !process.stdout.isTTY;
|
|
14055
|
-
if (noColor)
|
|
14477
|
+
if (noColor) chalk16.level = 0;
|
|
14056
14478
|
if (!target) {
|
|
14057
|
-
console.error(
|
|
14058
|
-
console.error(
|
|
14479
|
+
console.error(chalk16.red("Usage: repowise lsp disable <target>"));
|
|
14480
|
+
console.error(chalk16.dim(` Supported targets: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14059
14481
|
process.exitCode = 1;
|
|
14060
14482
|
return;
|
|
14061
14483
|
}
|
|
14062
14484
|
const spec = ENABLE_TARGETS[target];
|
|
14063
14485
|
if (!spec) {
|
|
14064
|
-
console.error(
|
|
14065
|
-
console.error(
|
|
14486
|
+
console.error(chalk16.red(`\u2716 Unknown LSP override target: ${target}`));
|
|
14487
|
+
console.error(chalk16.dim(` Supported: ${Object.keys(ENABLE_TARGETS).join(", ")}`));
|
|
14066
14488
|
process.exitCode = 1;
|
|
14067
14489
|
return;
|
|
14068
14490
|
}
|
|
14069
14491
|
const config2 = await getConfig();
|
|
14070
14492
|
const current = config2.lspOverrides?.[spec.language];
|
|
14071
14493
|
if (current !== spec.name) {
|
|
14072
|
-
console.log(
|
|
14494
|
+
console.log(chalk16.dim(` ${spec.displayName} is not enabled \u2014 nothing to do.`));
|
|
14073
14495
|
return;
|
|
14074
14496
|
}
|
|
14075
14497
|
const { [spec.language]: _removed, ...rest } = config2.lspOverrides ?? {};
|
|
14076
14498
|
void _removed;
|
|
14077
14499
|
const nextOverrides = Object.keys(rest).length > 0 ? rest : void 0;
|
|
14078
|
-
await mergeAndSaveConfig({
|
|
14079
|
-
|
|
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
|
+
);
|
|
14080
14529
|
}
|
|
14081
14530
|
|
|
14082
14531
|
// bin/repowise.ts
|
|
14083
14532
|
var __filename = fileURLToPath4(import.meta.url);
|
|
14084
14533
|
var __dirname = dirname19(__filename);
|
|
14085
|
-
var pkg = JSON.parse(readFileSync3(
|
|
14534
|
+
var pkg = JSON.parse(readFileSync3(join52(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
14086
14535
|
var program = new Command();
|
|
14087
14536
|
program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
|
|
14088
14537
|
await showWelcome(pkg.version);
|
|
@@ -14152,6 +14601,12 @@ lspCommand.command("enable <target>").description("Opt into a non-default LSP (e
|
|
|
14152
14601
|
lspCommand.command("disable <target>").description("Revert an LSP override and fall back to the registry default").action(async (target) => {
|
|
14153
14602
|
await lspDisable(target);
|
|
14154
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
|
+
});
|
|
14155
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) => {
|
|
14156
14611
|
const tier = options.tier ?? "uninstall";
|
|
14157
14612
|
await uninstallCommand({ tier, yes: options.yes });
|