repowisestage 0.0.45 → 0.0.47
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 +364 -256
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -721,6 +721,200 @@ var init_registry = __esm({
|
|
|
721
721
|
}
|
|
722
722
|
});
|
|
723
723
|
|
|
724
|
+
// ../listener/dist/lsp/installer.js
|
|
725
|
+
import { promises as fs } from "fs";
|
|
726
|
+
import { join as join14, dirname as dirname5 } from "path";
|
|
727
|
+
import { spawn as spawn3 } from "child_process";
|
|
728
|
+
function getLspInstallDir() {
|
|
729
|
+
return join14(getConfigDir(), "lsp-servers");
|
|
730
|
+
}
|
|
731
|
+
function getLspBinDir() {
|
|
732
|
+
return join14(getLspInstallDir(), "node_modules", ".bin");
|
|
733
|
+
}
|
|
734
|
+
async function ensureNpmLspInstalled(config2) {
|
|
735
|
+
if (!config2.npmPackage)
|
|
736
|
+
return { installed: false, skipped: "no-npm-package" };
|
|
737
|
+
const installDir = getLspInstallDir();
|
|
738
|
+
const binPath = join14(installDir, "node_modules", ".bin", config2.command);
|
|
739
|
+
if (await pathExists(binPath)) {
|
|
740
|
+
return { installed: false, skipped: "already-present" };
|
|
741
|
+
}
|
|
742
|
+
try {
|
|
743
|
+
await fs.mkdir(installDir, { recursive: true });
|
|
744
|
+
const pkgJsonPath = join14(installDir, "package.json");
|
|
745
|
+
if (!await pathExists(pkgJsonPath)) {
|
|
746
|
+
await fs.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
|
|
747
|
+
}
|
|
748
|
+
await runNpmInstall(installDir, config2.npmPackage);
|
|
749
|
+
if (!await pathExists(binPath)) {
|
|
750
|
+
return {
|
|
751
|
+
installed: false,
|
|
752
|
+
error: `npm install completed but ${config2.command} still not at ${binPath}`
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
return { installed: true };
|
|
756
|
+
} catch (err) {
|
|
757
|
+
return {
|
|
758
|
+
installed: false,
|
|
759
|
+
error: err instanceof Error ? err.message : String(err)
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
async function resolveNpmCommand() {
|
|
764
|
+
const nodeDir = dirname5(process.execPath);
|
|
765
|
+
for (const candidate of [join14(nodeDir, "npm"), join14(nodeDir, "npm.cmd")]) {
|
|
766
|
+
try {
|
|
767
|
+
await fs.access(candidate);
|
|
768
|
+
return candidate;
|
|
769
|
+
} catch {
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
for (const candidate of ["/opt/homebrew/bin/npm", "/usr/local/bin/npm", "/usr/bin/npm"]) {
|
|
773
|
+
try {
|
|
774
|
+
await fs.access(candidate);
|
|
775
|
+
return candidate;
|
|
776
|
+
} catch {
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
return "npm";
|
|
780
|
+
}
|
|
781
|
+
async function runNpmInstall(cwd, pkg2) {
|
|
782
|
+
const npmCmd = await resolveNpmCommand();
|
|
783
|
+
const nodeDir = dirname5(process.execPath);
|
|
784
|
+
const augmentedPath = process.env.PATH ? `${nodeDir}:${process.env.PATH}` : nodeDir;
|
|
785
|
+
return new Promise((resolve4, reject) => {
|
|
786
|
+
const child = spawn3(npmCmd, ["install", "--no-audit", "--no-fund", "--silent", pkg2], {
|
|
787
|
+
cwd,
|
|
788
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
789
|
+
env: { ...process.env, PATH: augmentedPath }
|
|
790
|
+
});
|
|
791
|
+
let stderr = "";
|
|
792
|
+
child.stderr.on("data", (chunk) => {
|
|
793
|
+
stderr += chunk.toString();
|
|
794
|
+
});
|
|
795
|
+
child.on("error", (err) => reject(err));
|
|
796
|
+
child.on("close", (code) => {
|
|
797
|
+
if (code === 0) {
|
|
798
|
+
resolve4();
|
|
799
|
+
} else {
|
|
800
|
+
reject(new Error(`npm install ${pkg2} exited ${(code ?? -1).toString()}: ${sanitizeNpmStderr(stderr)}`));
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
function sanitizeNpmStderr(raw) {
|
|
806
|
+
const truncated = raw.split("\n").slice(0, 3).join(" ").trim();
|
|
807
|
+
return truncated.replace(/(https?:\/\/)[^@\s/]*@/g, (_match, scheme) => `${scheme}<redacted>@`);
|
|
808
|
+
}
|
|
809
|
+
async function pathExists(p) {
|
|
810
|
+
try {
|
|
811
|
+
await fs.access(p);
|
|
812
|
+
return true;
|
|
813
|
+
} catch {
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
async function detectRepoLanguages(repoRoot) {
|
|
818
|
+
const found = /* @__PURE__ */ new Set();
|
|
819
|
+
let inspected = 0;
|
|
820
|
+
const MAX_INSPECT = 200;
|
|
821
|
+
async function inspect(dir) {
|
|
822
|
+
if (inspected >= MAX_INSPECT)
|
|
823
|
+
return;
|
|
824
|
+
let entries;
|
|
825
|
+
try {
|
|
826
|
+
entries = await fs.readdir(dir);
|
|
827
|
+
} catch {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
for (const name of entries) {
|
|
831
|
+
if (inspected >= MAX_INSPECT)
|
|
832
|
+
return;
|
|
833
|
+
if (name.startsWith("."))
|
|
834
|
+
continue;
|
|
835
|
+
if (name === "node_modules" || name === "dist" || name === "build")
|
|
836
|
+
continue;
|
|
837
|
+
const lang = detectLanguage(name);
|
|
838
|
+
if (lang) {
|
|
839
|
+
found.add(lang);
|
|
840
|
+
inspected += 1;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
await inspect(repoRoot);
|
|
845
|
+
let topEntries = [];
|
|
846
|
+
try {
|
|
847
|
+
topEntries = await fs.readdir(repoRoot);
|
|
848
|
+
} catch {
|
|
849
|
+
return found;
|
|
850
|
+
}
|
|
851
|
+
for (const name of topEntries) {
|
|
852
|
+
if (name.startsWith("."))
|
|
853
|
+
continue;
|
|
854
|
+
if (name === "node_modules" || name === "dist" || name === "build")
|
|
855
|
+
continue;
|
|
856
|
+
const sub = join14(repoRoot, name);
|
|
857
|
+
try {
|
|
858
|
+
const stat7 = await fs.stat(sub);
|
|
859
|
+
if (stat7.isDirectory())
|
|
860
|
+
await inspect(sub);
|
|
861
|
+
} catch {
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
return found;
|
|
865
|
+
}
|
|
866
|
+
async function prepareLspServersForRepos(repos) {
|
|
867
|
+
const detected = /* @__PURE__ */ new Set();
|
|
868
|
+
for (const r of repos) {
|
|
869
|
+
if (!r.localPath)
|
|
870
|
+
continue;
|
|
871
|
+
try {
|
|
872
|
+
const stat7 = await fs.stat(r.localPath);
|
|
873
|
+
if (!stat7.isDirectory())
|
|
874
|
+
continue;
|
|
875
|
+
} catch {
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
try {
|
|
879
|
+
const langs = await detectRepoLanguages(r.localPath);
|
|
880
|
+
for (const l of langs)
|
|
881
|
+
detected.add(l);
|
|
882
|
+
} catch {
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
const results = [];
|
|
886
|
+
for (const language of detected) {
|
|
887
|
+
const configs = LSP_REGISTRY[language];
|
|
888
|
+
const npmConfig = configs.find((c) => c.npmPackage);
|
|
889
|
+
if (!npmConfig) {
|
|
890
|
+
results.push({
|
|
891
|
+
language,
|
|
892
|
+
installed: false,
|
|
893
|
+
alreadyPresent: false,
|
|
894
|
+
skippedNoNpmPackage: true,
|
|
895
|
+
hint: configs[0]?.installHint
|
|
896
|
+
});
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
const outcome = await ensureNpmLspInstalled(npmConfig);
|
|
900
|
+
results.push({
|
|
901
|
+
language,
|
|
902
|
+
installed: outcome.installed,
|
|
903
|
+
alreadyPresent: outcome.skipped === "already-present",
|
|
904
|
+
skippedNoNpmPackage: false,
|
|
905
|
+
error: outcome.error
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
return results;
|
|
909
|
+
}
|
|
910
|
+
var init_installer = __esm({
|
|
911
|
+
"../listener/dist/lsp/installer.js"() {
|
|
912
|
+
"use strict";
|
|
913
|
+
init_config_dir();
|
|
914
|
+
init_registry();
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
|
|
724
918
|
// ../../packages/shared/src/types/typed-resolution.ts
|
|
725
919
|
function typedResolutionKey(filePath, propertyName, line, column) {
|
|
726
920
|
return `${filePath}\0${propertyName}\0${line.toString()}\0${column.toString()}`;
|
|
@@ -1132,7 +1326,8 @@ __export(lsp_tools_exports, {
|
|
|
1132
1326
|
lspWorkspaceSymbol: () => lspWorkspaceSymbol
|
|
1133
1327
|
});
|
|
1134
1328
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1135
|
-
import { relative as pathRelative, resolve as pathResolve3 } from "path";
|
|
1329
|
+
import { relative as pathRelative, resolve as pathResolve3, join as pathJoin } from "path";
|
|
1330
|
+
import { existsSync } from "fs";
|
|
1136
1331
|
import { execSync } from "child_process";
|
|
1137
1332
|
function probeBinary(command) {
|
|
1138
1333
|
if (process.env["VITEST"])
|
|
@@ -1142,8 +1337,12 @@ function probeBinary(command) {
|
|
|
1142
1337
|
return cached;
|
|
1143
1338
|
let found = false;
|
|
1144
1339
|
try {
|
|
1145
|
-
|
|
1146
|
-
|
|
1340
|
+
if (existsSync(pathJoin(getLspBinDir(), command))) {
|
|
1341
|
+
found = true;
|
|
1342
|
+
} else {
|
|
1343
|
+
execSync(`which ${command}`, { stdio: "ignore", timeout: 200 });
|
|
1344
|
+
found = true;
|
|
1345
|
+
}
|
|
1147
1346
|
} catch {
|
|
1148
1347
|
found = false;
|
|
1149
1348
|
}
|
|
@@ -1465,6 +1664,7 @@ var init_lsp_tools = __esm({
|
|
|
1465
1664
|
"../listener/dist/lsp/lsp-tools.js"() {
|
|
1466
1665
|
"use strict";
|
|
1467
1666
|
init_registry();
|
|
1667
|
+
init_installer();
|
|
1468
1668
|
binaryProbeCache = /* @__PURE__ */ new Map();
|
|
1469
1669
|
}
|
|
1470
1670
|
});
|
|
@@ -3042,196 +3242,8 @@ var LspClient = class extends EventEmitter {
|
|
|
3042
3242
|
}
|
|
3043
3243
|
};
|
|
3044
3244
|
|
|
3045
|
-
// ../listener/dist/lsp/installer.js
|
|
3046
|
-
init_config_dir();
|
|
3047
|
-
init_registry();
|
|
3048
|
-
import { promises as fs } from "fs";
|
|
3049
|
-
import { join as join14, dirname as dirname5 } from "path";
|
|
3050
|
-
import { spawn as spawn3 } from "child_process";
|
|
3051
|
-
function getLspInstallDir() {
|
|
3052
|
-
return join14(getConfigDir(), "lsp-servers");
|
|
3053
|
-
}
|
|
3054
|
-
function getLspBinDir() {
|
|
3055
|
-
return join14(getLspInstallDir(), "node_modules", ".bin");
|
|
3056
|
-
}
|
|
3057
|
-
async function ensureNpmLspInstalled(config2) {
|
|
3058
|
-
if (!config2.npmPackage)
|
|
3059
|
-
return { installed: false, skipped: "no-npm-package" };
|
|
3060
|
-
const installDir = getLspInstallDir();
|
|
3061
|
-
const binPath = join14(installDir, "node_modules", ".bin", config2.command);
|
|
3062
|
-
if (await pathExists(binPath)) {
|
|
3063
|
-
return { installed: false, skipped: "already-present" };
|
|
3064
|
-
}
|
|
3065
|
-
try {
|
|
3066
|
-
await fs.mkdir(installDir, { recursive: true });
|
|
3067
|
-
const pkgJsonPath = join14(installDir, "package.json");
|
|
3068
|
-
if (!await pathExists(pkgJsonPath)) {
|
|
3069
|
-
await fs.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
|
|
3070
|
-
}
|
|
3071
|
-
await runNpmInstall(installDir, config2.npmPackage);
|
|
3072
|
-
if (!await pathExists(binPath)) {
|
|
3073
|
-
return {
|
|
3074
|
-
installed: false,
|
|
3075
|
-
error: `npm install completed but ${config2.command} still not at ${binPath}`
|
|
3076
|
-
};
|
|
3077
|
-
}
|
|
3078
|
-
return { installed: true };
|
|
3079
|
-
} catch (err) {
|
|
3080
|
-
return {
|
|
3081
|
-
installed: false,
|
|
3082
|
-
error: err instanceof Error ? err.message : String(err)
|
|
3083
|
-
};
|
|
3084
|
-
}
|
|
3085
|
-
}
|
|
3086
|
-
async function resolveNpmCommand() {
|
|
3087
|
-
const nodeDir = dirname5(process.execPath);
|
|
3088
|
-
for (const candidate of [join14(nodeDir, "npm"), join14(nodeDir, "npm.cmd")]) {
|
|
3089
|
-
try {
|
|
3090
|
-
await fs.access(candidate);
|
|
3091
|
-
return candidate;
|
|
3092
|
-
} catch {
|
|
3093
|
-
}
|
|
3094
|
-
}
|
|
3095
|
-
for (const candidate of ["/opt/homebrew/bin/npm", "/usr/local/bin/npm", "/usr/bin/npm"]) {
|
|
3096
|
-
try {
|
|
3097
|
-
await fs.access(candidate);
|
|
3098
|
-
return candidate;
|
|
3099
|
-
} catch {
|
|
3100
|
-
}
|
|
3101
|
-
}
|
|
3102
|
-
return "npm";
|
|
3103
|
-
}
|
|
3104
|
-
async function runNpmInstall(cwd, pkg2) {
|
|
3105
|
-
const npmCmd = await resolveNpmCommand();
|
|
3106
|
-
const nodeDir = dirname5(process.execPath);
|
|
3107
|
-
const augmentedPath = process.env.PATH ? `${nodeDir}:${process.env.PATH}` : nodeDir;
|
|
3108
|
-
return new Promise((resolve4, reject) => {
|
|
3109
|
-
const child = spawn3(npmCmd, ["install", "--no-audit", "--no-fund", "--silent", pkg2], {
|
|
3110
|
-
cwd,
|
|
3111
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
3112
|
-
env: { ...process.env, PATH: augmentedPath }
|
|
3113
|
-
});
|
|
3114
|
-
let stderr = "";
|
|
3115
|
-
child.stderr.on("data", (chunk) => {
|
|
3116
|
-
stderr += chunk.toString();
|
|
3117
|
-
});
|
|
3118
|
-
child.on("error", (err) => reject(err));
|
|
3119
|
-
child.on("close", (code) => {
|
|
3120
|
-
if (code === 0) {
|
|
3121
|
-
resolve4();
|
|
3122
|
-
} else {
|
|
3123
|
-
reject(new Error(`npm install ${pkg2} exited ${(code ?? -1).toString()}: ${sanitizeNpmStderr(stderr)}`));
|
|
3124
|
-
}
|
|
3125
|
-
});
|
|
3126
|
-
});
|
|
3127
|
-
}
|
|
3128
|
-
function sanitizeNpmStderr(raw) {
|
|
3129
|
-
const truncated = raw.split("\n").slice(0, 3).join(" ").trim();
|
|
3130
|
-
return truncated.replace(/(https?:\/\/)[^@\s/]*@/g, (_match, scheme) => `${scheme}<redacted>@`);
|
|
3131
|
-
}
|
|
3132
|
-
async function pathExists(p) {
|
|
3133
|
-
try {
|
|
3134
|
-
await fs.access(p);
|
|
3135
|
-
return true;
|
|
3136
|
-
} catch {
|
|
3137
|
-
return false;
|
|
3138
|
-
}
|
|
3139
|
-
}
|
|
3140
|
-
async function detectRepoLanguages(repoRoot) {
|
|
3141
|
-
const found = /* @__PURE__ */ new Set();
|
|
3142
|
-
let inspected = 0;
|
|
3143
|
-
const MAX_INSPECT = 200;
|
|
3144
|
-
async function inspect(dir) {
|
|
3145
|
-
if (inspected >= MAX_INSPECT)
|
|
3146
|
-
return;
|
|
3147
|
-
let entries;
|
|
3148
|
-
try {
|
|
3149
|
-
entries = await fs.readdir(dir);
|
|
3150
|
-
} catch {
|
|
3151
|
-
return;
|
|
3152
|
-
}
|
|
3153
|
-
for (const name of entries) {
|
|
3154
|
-
if (inspected >= MAX_INSPECT)
|
|
3155
|
-
return;
|
|
3156
|
-
if (name.startsWith("."))
|
|
3157
|
-
continue;
|
|
3158
|
-
if (name === "node_modules" || name === "dist" || name === "build")
|
|
3159
|
-
continue;
|
|
3160
|
-
const lang = detectLanguage(name);
|
|
3161
|
-
if (lang) {
|
|
3162
|
-
found.add(lang);
|
|
3163
|
-
inspected += 1;
|
|
3164
|
-
}
|
|
3165
|
-
}
|
|
3166
|
-
}
|
|
3167
|
-
await inspect(repoRoot);
|
|
3168
|
-
let topEntries = [];
|
|
3169
|
-
try {
|
|
3170
|
-
topEntries = await fs.readdir(repoRoot);
|
|
3171
|
-
} catch {
|
|
3172
|
-
return found;
|
|
3173
|
-
}
|
|
3174
|
-
for (const name of topEntries) {
|
|
3175
|
-
if (name.startsWith("."))
|
|
3176
|
-
continue;
|
|
3177
|
-
if (name === "node_modules" || name === "dist" || name === "build")
|
|
3178
|
-
continue;
|
|
3179
|
-
const sub = join14(repoRoot, name);
|
|
3180
|
-
try {
|
|
3181
|
-
const stat7 = await fs.stat(sub);
|
|
3182
|
-
if (stat7.isDirectory())
|
|
3183
|
-
await inspect(sub);
|
|
3184
|
-
} catch {
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3187
|
-
return found;
|
|
3188
|
-
}
|
|
3189
|
-
async function prepareLspServersForRepos(repos) {
|
|
3190
|
-
const detected = /* @__PURE__ */ new Set();
|
|
3191
|
-
for (const r of repos) {
|
|
3192
|
-
if (!r.localPath)
|
|
3193
|
-
continue;
|
|
3194
|
-
try {
|
|
3195
|
-
const stat7 = await fs.stat(r.localPath);
|
|
3196
|
-
if (!stat7.isDirectory())
|
|
3197
|
-
continue;
|
|
3198
|
-
} catch {
|
|
3199
|
-
continue;
|
|
3200
|
-
}
|
|
3201
|
-
try {
|
|
3202
|
-
const langs = await detectRepoLanguages(r.localPath);
|
|
3203
|
-
for (const l of langs)
|
|
3204
|
-
detected.add(l);
|
|
3205
|
-
} catch {
|
|
3206
|
-
}
|
|
3207
|
-
}
|
|
3208
|
-
const results = [];
|
|
3209
|
-
for (const language of detected) {
|
|
3210
|
-
const configs = LSP_REGISTRY[language];
|
|
3211
|
-
const npmConfig = configs.find((c) => c.npmPackage);
|
|
3212
|
-
if (!npmConfig) {
|
|
3213
|
-
results.push({
|
|
3214
|
-
language,
|
|
3215
|
-
installed: false,
|
|
3216
|
-
alreadyPresent: false,
|
|
3217
|
-
skippedNoNpmPackage: true,
|
|
3218
|
-
hint: configs[0]?.installHint
|
|
3219
|
-
});
|
|
3220
|
-
continue;
|
|
3221
|
-
}
|
|
3222
|
-
const outcome = await ensureNpmLspInstalled(npmConfig);
|
|
3223
|
-
results.push({
|
|
3224
|
-
language,
|
|
3225
|
-
installed: outcome.installed,
|
|
3226
|
-
alreadyPresent: outcome.skipped === "already-present",
|
|
3227
|
-
skippedNoNpmPackage: false,
|
|
3228
|
-
error: outcome.error
|
|
3229
|
-
});
|
|
3230
|
-
}
|
|
3231
|
-
return results;
|
|
3232
|
-
}
|
|
3233
|
-
|
|
3234
3245
|
// ../listener/dist/lsp/workspace-session.js
|
|
3246
|
+
init_installer();
|
|
3235
3247
|
function keyOf(args) {
|
|
3236
3248
|
return `${args.repoRoot}\0${args.language}`;
|
|
3237
3249
|
}
|
|
@@ -4866,24 +4878,49 @@ function batchQuery(graphJson, req) {
|
|
|
4866
4878
|
const allQueries = req.queries ?? [];
|
|
4867
4879
|
const queries = allQueries.slice(0, BATCH_CAP);
|
|
4868
4880
|
const droppedCount = Math.max(0, allQueries.length - queries.length);
|
|
4869
|
-
const results = queries.map((
|
|
4881
|
+
const results = queries.map((rawQ) => {
|
|
4882
|
+
const q = rawQ;
|
|
4883
|
+
const toolName = q.tool ?? "";
|
|
4884
|
+
const params = q.params ?? q.arguments;
|
|
4885
|
+
if (!params || typeof params !== "object" || Array.isArray(params)) {
|
|
4886
|
+
return {
|
|
4887
|
+
ok: false,
|
|
4888
|
+
tool: toolName,
|
|
4889
|
+
error: "params required (object) \u2014 pass `params` or `arguments` per sub-query"
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
const args = params;
|
|
4870
4893
|
try {
|
|
4871
|
-
switch (
|
|
4894
|
+
switch (toolName) {
|
|
4872
4895
|
case "find_symbol":
|
|
4873
|
-
return {
|
|
4896
|
+
return {
|
|
4897
|
+
ok: true,
|
|
4898
|
+
tool: toolName,
|
|
4899
|
+
result: findSymbol(graph, args)
|
|
4900
|
+
};
|
|
4874
4901
|
case "get_symbol":
|
|
4875
|
-
return { ok: true, tool:
|
|
4902
|
+
return { ok: true, tool: toolName, result: getSymbol(graph, args) };
|
|
4876
4903
|
case "get_impact":
|
|
4877
|
-
return { ok: true, tool:
|
|
4904
|
+
return { ok: true, tool: toolName, result: getImpact(graph, args) };
|
|
4878
4905
|
case "list_edges":
|
|
4879
|
-
return { ok: true, tool:
|
|
4906
|
+
return { ok: true, tool: toolName, result: listEdges(graph, args) };
|
|
4880
4907
|
case "search_pattern":
|
|
4881
|
-
return {
|
|
4908
|
+
return {
|
|
4909
|
+
ok: true,
|
|
4910
|
+
tool: toolName,
|
|
4911
|
+
result: searchPattern(graph, args)
|
|
4912
|
+
};
|
|
4913
|
+
default:
|
|
4914
|
+
return {
|
|
4915
|
+
ok: false,
|
|
4916
|
+
tool: toolName,
|
|
4917
|
+
error: `unsupported sub-query tool: ${String(toolName)}`
|
|
4918
|
+
};
|
|
4882
4919
|
}
|
|
4883
4920
|
} catch (err) {
|
|
4884
4921
|
return {
|
|
4885
4922
|
ok: false,
|
|
4886
|
-
tool:
|
|
4923
|
+
tool: toolName,
|
|
4887
4924
|
error: err instanceof Error ? err.message : String(err)
|
|
4888
4925
|
};
|
|
4889
4926
|
}
|
|
@@ -5121,7 +5158,14 @@ function handleRequest(req, res, options, sessions, secretCtx) {
|
|
|
5121
5158
|
sessions.set(sessionId, { repoId: body.repoId });
|
|
5122
5159
|
return sendJson(res, 200, { sessionId });
|
|
5123
5160
|
});
|
|
5124
|
-
}).catch((err) =>
|
|
5161
|
+
}).catch((err) => {
|
|
5162
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
5163
|
+
const safeMsg = stripAbsolutePaths(rawMsg);
|
|
5164
|
+
if (err?.code === "ENOENT") {
|
|
5165
|
+
return sendJson(res, 404, { error: "unknown_repo" });
|
|
5166
|
+
}
|
|
5167
|
+
sendJson(res, 500, { error: safeMsg });
|
|
5168
|
+
});
|
|
5125
5169
|
return;
|
|
5126
5170
|
}
|
|
5127
5171
|
if (method === "POST" && url === "/mcp/disconnect") {
|
|
@@ -5305,6 +5349,7 @@ function dispatchSessionTool(req, res, url, sessions, logger, handler) {
|
|
|
5305
5349
|
latencyMs: Date.now() - startedAt,
|
|
5306
5350
|
error: "unknown_session"
|
|
5307
5351
|
});
|
|
5352
|
+
logToStdout("rejected", tool, null, Date.now() - startedAt, "unknown_session");
|
|
5308
5353
|
return sendJson(res, 404, { error: "unknown_session" });
|
|
5309
5354
|
}
|
|
5310
5355
|
try {
|
|
@@ -5319,8 +5364,10 @@ function dispatchSessionTool(req, res, url, sessions, logger, handler) {
|
|
|
5319
5364
|
status: "ok",
|
|
5320
5365
|
latencyMs: Date.now() - startedAt
|
|
5321
5366
|
});
|
|
5367
|
+
logToStdout("ok", tool, session.repoId, Date.now() - startedAt);
|
|
5322
5368
|
return sendJson(res, 200, result.value);
|
|
5323
5369
|
}
|
|
5370
|
+
const rejectErr = typeof result.body["error"] === "string" ? result.body["error"] : "tool_rejected";
|
|
5324
5371
|
recordLog(logger, {
|
|
5325
5372
|
ts: new Date(startedAt).toISOString(),
|
|
5326
5373
|
sessionId: body.sessionId,
|
|
@@ -5329,8 +5376,9 @@ function dispatchSessionTool(req, res, url, sessions, logger, handler) {
|
|
|
5329
5376
|
args: redactArgs(body),
|
|
5330
5377
|
status: "rejected",
|
|
5331
5378
|
latencyMs: Date.now() - startedAt,
|
|
5332
|
-
error:
|
|
5379
|
+
error: rejectErr
|
|
5333
5380
|
});
|
|
5381
|
+
logToStdout("rejected", tool, session.repoId, Date.now() - startedAt, rejectErr);
|
|
5334
5382
|
return sendJson(res, result.status, result.body);
|
|
5335
5383
|
} catch (err) {
|
|
5336
5384
|
const isTimeout = err instanceof ToolTimeoutError;
|
|
@@ -5346,6 +5394,7 @@ function dispatchSessionTool(req, res, url, sessions, logger, handler) {
|
|
|
5346
5394
|
latencyMs: Date.now() - startedAt,
|
|
5347
5395
|
error: safeMsg
|
|
5348
5396
|
});
|
|
5397
|
+
logToStdout("error", tool, session.repoId, Date.now() - startedAt, safeMsg);
|
|
5349
5398
|
if (isTimeout) {
|
|
5350
5399
|
return sendJson(res, 504, { error: "tool-timeout", tool });
|
|
5351
5400
|
}
|
|
@@ -5365,6 +5414,11 @@ function recordLog(logger, entry) {
|
|
|
5365
5414
|
return;
|
|
5366
5415
|
void logger.append(entry);
|
|
5367
5416
|
}
|
|
5417
|
+
function logToStdout(status2, tool, repoId, latencyMs, error) {
|
|
5418
|
+
const repoFrag = repoId ? `repo=${repoId}` : "repo=\u2014";
|
|
5419
|
+
const errFrag = error ? ` error=${error}` : "";
|
|
5420
|
+
console.log(`[mcp] ${status2} ${tool} ${repoFrag} ${latencyMs}ms${errFrag}`);
|
|
5421
|
+
}
|
|
5368
5422
|
var REDACT_FIELDS = /* @__PURE__ */ new Set([
|
|
5369
5423
|
"query",
|
|
5370
5424
|
"pattern",
|
|
@@ -5641,6 +5695,7 @@ function defaultMcpHome() {
|
|
|
5641
5695
|
|
|
5642
5696
|
// ../listener/dist/mcp/auto-config/index.js
|
|
5643
5697
|
import { homedir as homedir4 } from "os";
|
|
5698
|
+
import { basename as basename2 } from "path";
|
|
5644
5699
|
|
|
5645
5700
|
// ../listener/dist/mcp/auto-config/writers/claude-code.js
|
|
5646
5701
|
import { promises as fs3 } from "fs";
|
|
@@ -5728,15 +5783,18 @@ var claudeCodeWriter = {
|
|
|
5728
5783
|
},
|
|
5729
5784
|
async write(ctx) {
|
|
5730
5785
|
const path = join19(ctx.repoRoot, ".mcp.json");
|
|
5786
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5731
5787
|
const status2 = await writeMergedConfig({
|
|
5732
5788
|
path,
|
|
5733
|
-
serverName: `
|
|
5789
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5734
5790
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5735
5791
|
});
|
|
5736
5792
|
return { status: status2, path };
|
|
5737
5793
|
},
|
|
5738
5794
|
async remove(ctx) {
|
|
5739
|
-
|
|
5795
|
+
const path = join19(ctx.repoRoot, ".mcp.json");
|
|
5796
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
5797
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5740
5798
|
}
|
|
5741
5799
|
};
|
|
5742
5800
|
async function fileExists2(path) {
|
|
@@ -5761,15 +5819,18 @@ var clineWriter = {
|
|
|
5761
5819
|
},
|
|
5762
5820
|
async write(ctx) {
|
|
5763
5821
|
const path = join20(ctx.home, ".cline", "mcp.json");
|
|
5822
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5764
5823
|
const status2 = await writeMergedConfig({
|
|
5765
5824
|
path,
|
|
5766
|
-
serverName: `
|
|
5825
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5767
5826
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5768
5827
|
});
|
|
5769
5828
|
return { status: status2, path };
|
|
5770
5829
|
},
|
|
5771
5830
|
async remove(ctx) {
|
|
5772
|
-
|
|
5831
|
+
const path = join20(ctx.home, ".cline", "mcp.json");
|
|
5832
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
5833
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5773
5834
|
}
|
|
5774
5835
|
};
|
|
5775
5836
|
async function fileExists3(path) {
|
|
@@ -5791,15 +5852,18 @@ var codexWriter = {
|
|
|
5791
5852
|
},
|
|
5792
5853
|
async write(ctx) {
|
|
5793
5854
|
const path = join21(ctx.home, ".codex", "mcp.json");
|
|
5855
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5794
5856
|
const status2 = await writeMergedConfig({
|
|
5795
5857
|
path,
|
|
5796
|
-
serverName: `
|
|
5858
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5797
5859
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5798
5860
|
});
|
|
5799
5861
|
return { status: status2, path };
|
|
5800
5862
|
},
|
|
5801
5863
|
async remove(ctx) {
|
|
5802
|
-
|
|
5864
|
+
const path = join21(ctx.home, ".codex", "mcp.json");
|
|
5865
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
5866
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5803
5867
|
}
|
|
5804
5868
|
};
|
|
5805
5869
|
async function fileExists4(path) {
|
|
@@ -5821,15 +5885,18 @@ var copilotWriter = {
|
|
|
5821
5885
|
},
|
|
5822
5886
|
async write(ctx) {
|
|
5823
5887
|
const path = join22(ctx.repoRoot, ".vscode", "mcp.json");
|
|
5888
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5824
5889
|
const status2 = await writeMergedConfig({
|
|
5825
5890
|
path,
|
|
5826
|
-
serverName: `
|
|
5891
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5827
5892
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5828
5893
|
});
|
|
5829
5894
|
return { status: status2, path };
|
|
5830
5895
|
},
|
|
5831
5896
|
async remove(ctx) {
|
|
5832
|
-
|
|
5897
|
+
const path = join22(ctx.repoRoot, ".vscode", "mcp.json");
|
|
5898
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
5899
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5833
5900
|
}
|
|
5834
5901
|
};
|
|
5835
5902
|
async function fileExists5(path) {
|
|
@@ -5851,15 +5918,18 @@ var cursorWriter = {
|
|
|
5851
5918
|
},
|
|
5852
5919
|
async write(ctx) {
|
|
5853
5920
|
const path = join23(ctx.repoRoot, ".cursor", "mcp.json");
|
|
5921
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5854
5922
|
const status2 = await writeMergedConfig({
|
|
5855
5923
|
path,
|
|
5856
|
-
serverName: `
|
|
5924
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5857
5925
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5858
5926
|
});
|
|
5859
5927
|
return { status: status2, path };
|
|
5860
5928
|
},
|
|
5861
5929
|
async remove(ctx) {
|
|
5862
|
-
|
|
5930
|
+
const path = join23(ctx.repoRoot, ".cursor", "mcp.json");
|
|
5931
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
5932
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5863
5933
|
}
|
|
5864
5934
|
};
|
|
5865
5935
|
async function fileExists6(path) {
|
|
@@ -5881,15 +5951,18 @@ var geminiCliWriter = {
|
|
|
5881
5951
|
},
|
|
5882
5952
|
async write(ctx) {
|
|
5883
5953
|
const path = join24(ctx.home, ".gemini", "settings.json");
|
|
5954
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5884
5955
|
const status2 = await writeMergedConfig({
|
|
5885
5956
|
path,
|
|
5886
|
-
serverName: `
|
|
5957
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5887
5958
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5888
5959
|
});
|
|
5889
5960
|
return { status: status2, path };
|
|
5890
5961
|
},
|
|
5891
5962
|
async remove(ctx) {
|
|
5892
|
-
|
|
5963
|
+
const path = join24(ctx.home, ".gemini", "settings.json");
|
|
5964
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
5965
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5893
5966
|
}
|
|
5894
5967
|
};
|
|
5895
5968
|
async function fileExists7(path) {
|
|
@@ -5913,16 +5986,21 @@ var rooWriter = {
|
|
|
5913
5986
|
const repoConfig = join25(ctx.repoRoot, ".roo", "mcp.json");
|
|
5914
5987
|
const useRepoScope = await fileExists8(join25(ctx.repoRoot, ".roo"));
|
|
5915
5988
|
const path = useRepoScope ? repoConfig : join25(ctx.home, ".roo", "mcp.json");
|
|
5989
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5916
5990
|
const status2 = await writeMergedConfig({
|
|
5917
5991
|
path,
|
|
5918
|
-
serverName: `
|
|
5992
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5919
5993
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5920
5994
|
});
|
|
5921
5995
|
return { status: status2, path };
|
|
5922
5996
|
},
|
|
5923
5997
|
async remove(ctx) {
|
|
5924
|
-
|
|
5925
|
-
|
|
5998
|
+
const repoConfig = join25(ctx.repoRoot, ".roo", "mcp.json");
|
|
5999
|
+
const homeConfig = join25(ctx.home, ".roo", "mcp.json");
|
|
6000
|
+
await removeFromConfig(repoConfig, `RepoWise MCP for ${ctx.repoName}`);
|
|
6001
|
+
await removeFromConfig(repoConfig, `repowise-${ctx.repoId}`);
|
|
6002
|
+
await removeFromConfig(homeConfig, `RepoWise MCP for ${ctx.repoName}`);
|
|
6003
|
+
await removeFromConfig(homeConfig, `repowise-${ctx.repoId}`);
|
|
5926
6004
|
}
|
|
5927
6005
|
};
|
|
5928
6006
|
async function fileExists8(path) {
|
|
@@ -5944,15 +6022,18 @@ var windsurfWriter = {
|
|
|
5944
6022
|
},
|
|
5945
6023
|
async write(ctx) {
|
|
5946
6024
|
const path = join26(ctx.home, ".codeium", "windsurf", "mcp_config.json");
|
|
6025
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5947
6026
|
const status2 = await writeMergedConfig({
|
|
5948
6027
|
path,
|
|
5949
|
-
serverName: `
|
|
6028
|
+
serverName: `RepoWise MCP for ${ctx.repoName}`,
|
|
5950
6029
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
5951
6030
|
});
|
|
5952
6031
|
return { status: status2, path };
|
|
5953
6032
|
},
|
|
5954
6033
|
async remove(ctx) {
|
|
5955
|
-
|
|
6034
|
+
const path = join26(ctx.home, ".codeium", "windsurf", "mcp_config.json");
|
|
6035
|
+
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
6036
|
+
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
5956
6037
|
}
|
|
5957
6038
|
};
|
|
5958
6039
|
async function fileExists9(path) {
|
|
@@ -6000,6 +6081,7 @@ async function runAutoConfig(opts) {
|
|
|
6000
6081
|
try {
|
|
6001
6082
|
const outcome = await writer.write({
|
|
6002
6083
|
repoRoot: opts.repoRoot,
|
|
6084
|
+
repoName: basename2(opts.repoRoot),
|
|
6003
6085
|
repoId: opts.repoId,
|
|
6004
6086
|
shimCmd: opts.shimCmd,
|
|
6005
6087
|
home
|
|
@@ -6016,6 +6098,9 @@ async function runAutoConfig(opts) {
|
|
|
6016
6098
|
return results;
|
|
6017
6099
|
}
|
|
6018
6100
|
|
|
6101
|
+
// ../listener/dist/main.js
|
|
6102
|
+
init_installer();
|
|
6103
|
+
|
|
6019
6104
|
// ../listener/dist/typed-resolution/resolver-loop.js
|
|
6020
6105
|
init_src();
|
|
6021
6106
|
init_registry();
|
|
@@ -7699,11 +7784,11 @@ async function writeClaudeSubagentHook(repoRoot, contextFolder) {
|
|
|
7699
7784
|
}
|
|
7700
7785
|
|
|
7701
7786
|
// src/lib/gitignore.ts
|
|
7702
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync } from "fs";
|
|
7787
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
|
|
7703
7788
|
import { join as join32 } from "path";
|
|
7704
7789
|
function ensureGitignore(repoRoot, entry) {
|
|
7705
7790
|
const gitignorePath = join32(repoRoot, ".gitignore");
|
|
7706
|
-
if (
|
|
7791
|
+
if (existsSync2(gitignorePath)) {
|
|
7707
7792
|
const content = readFileSync2(gitignorePath, "utf-8");
|
|
7708
7793
|
const lines = content.split("\n").map((l) => l.trim());
|
|
7709
7794
|
if (lines.includes(entry) || lines.includes(entry + "/")) {
|
|
@@ -9032,7 +9117,7 @@ async function logout() {
|
|
|
9032
9117
|
|
|
9033
9118
|
// src/commands/status.ts
|
|
9034
9119
|
import { readFile as readFile16 } from "fs/promises";
|
|
9035
|
-
import { basename as
|
|
9120
|
+
import { basename as basename3, join as join36 } from "path";
|
|
9036
9121
|
async function status() {
|
|
9037
9122
|
const configDir = getConfigDir2();
|
|
9038
9123
|
const STATE_PATH = join36(configDir, "listener-state.json");
|
|
@@ -9068,7 +9153,7 @@ async function status() {
|
|
|
9068
9153
|
const configData = await readFile16(CONFIG_PATH, "utf-8");
|
|
9069
9154
|
const config2 = JSON.parse(configData);
|
|
9070
9155
|
for (const repo of config2.repos ?? []) {
|
|
9071
|
-
repoNames.set(repo.repoId,
|
|
9156
|
+
repoNames.set(repo.repoId, basename3(repo.localPath));
|
|
9072
9157
|
}
|
|
9073
9158
|
} catch {
|
|
9074
9159
|
}
|
|
@@ -10493,6 +10578,7 @@ async function mcpShim(opts) {
|
|
|
10493
10578
|
const stderr = opts.stderr ?? process.stderr;
|
|
10494
10579
|
const maxBytes = opts.maxRequestBytes ?? DEFAULT_MAX;
|
|
10495
10580
|
const postJson = opts.postJson ?? defaultPostJson;
|
|
10581
|
+
const getJson = opts.getJson ?? defaultGetJson;
|
|
10496
10582
|
const sessionState = { sessionId: null };
|
|
10497
10583
|
const rl = createInterface2({ input: stdin, crlfDelay: Infinity });
|
|
10498
10584
|
for await (const rawLine of rl) {
|
|
@@ -10538,6 +10624,7 @@ async function mcpShim(opts) {
|
|
|
10538
10624
|
opts.repoId,
|
|
10539
10625
|
parsed,
|
|
10540
10626
|
postJson,
|
|
10627
|
+
getJson,
|
|
10541
10628
|
headers,
|
|
10542
10629
|
sessionState
|
|
10543
10630
|
);
|
|
@@ -10580,7 +10667,7 @@ function writeJson(stream, value) {
|
|
|
10580
10667
|
stream.write(`${JSON.stringify(value)}
|
|
10581
10668
|
`);
|
|
10582
10669
|
}
|
|
10583
|
-
async function routeMessage(endpoint, repoId, message, postJson, headers, sessionState) {
|
|
10670
|
+
async function routeMessage(endpoint, repoId, message, postJson, getJson, headers, sessionState) {
|
|
10584
10671
|
const msg = message;
|
|
10585
10672
|
const rpcId = msg.id;
|
|
10586
10673
|
const method = msg.method;
|
|
@@ -10596,41 +10683,28 @@ async function routeMessage(endpoint, repoId, message, postJson, headers, sessio
|
|
|
10596
10683
|
};
|
|
10597
10684
|
}
|
|
10598
10685
|
if (method === "tools/list") {
|
|
10599
|
-
const
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
"
|
|
10603
|
-
"
|
|
10604
|
-
|
|
10605
|
-
"batch_query",
|
|
10606
|
-
"find_callers",
|
|
10607
|
-
"find_references",
|
|
10608
|
-
"get_deps",
|
|
10609
|
-
"get_call_graph",
|
|
10610
|
-
"find_tests_for_symbol",
|
|
10611
|
-
"get_todos",
|
|
10612
|
-
"get_freshness",
|
|
10613
|
-
"lsp_definition",
|
|
10614
|
-
"lsp_references",
|
|
10615
|
-
"lsp_hover",
|
|
10616
|
-
"lsp_workspace_symbol",
|
|
10617
|
-
"lsp_document_symbol",
|
|
10618
|
-
"lsp_call_hierarchy",
|
|
10619
|
-
"lsp_implementation",
|
|
10620
|
-
"lsp_type_hierarchy"
|
|
10621
|
-
].map((name) => ({ name, description: "", inputSchema: { type: "object" } }));
|
|
10686
|
+
const catalog = await getJson(`${endpoint}/mcp/tools`, headers);
|
|
10687
|
+
const tools = (catalog.tools ?? []).map((t) => ({
|
|
10688
|
+
name: t.name,
|
|
10689
|
+
description: [t.description, t.whenToUse].filter((s) => s && s.length > 0).join("\n\n"),
|
|
10690
|
+
inputSchema: t.inputSchema ?? { type: "object" }
|
|
10691
|
+
}));
|
|
10622
10692
|
return { jsonrpc: "2.0", id: rpcId, result: { tools } };
|
|
10623
10693
|
}
|
|
10624
|
-
|
|
10694
|
+
async function connect() {
|
|
10625
10695
|
const connectResp = await postJson(`${endpoint}/mcp/connect`, { repoId }, headers);
|
|
10626
|
-
|
|
10696
|
+
return connectResp.sessionId ?? null;
|
|
10697
|
+
}
|
|
10698
|
+
if (!sessionState.sessionId) {
|
|
10699
|
+
const sid = await connect();
|
|
10700
|
+
if (!sid) {
|
|
10627
10701
|
return {
|
|
10628
10702
|
jsonrpc: "2.0",
|
|
10629
10703
|
id: rpcId,
|
|
10630
10704
|
error: { code: -32002, message: "failed to establish MCP session" }
|
|
10631
10705
|
};
|
|
10632
10706
|
}
|
|
10633
|
-
sessionState.sessionId =
|
|
10707
|
+
sessionState.sessionId = sid;
|
|
10634
10708
|
}
|
|
10635
10709
|
if (method === "tools/call") {
|
|
10636
10710
|
const params = msg.params ?? {};
|
|
@@ -10644,12 +10718,33 @@ async function routeMessage(endpoint, repoId, message, postJson, headers, sessio
|
|
|
10644
10718
|
error: { code: -32602, message: "tools/call missing name" }
|
|
10645
10719
|
};
|
|
10646
10720
|
}
|
|
10647
|
-
const
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
)
|
|
10652
|
-
|
|
10721
|
+
const callTool = (sid) => postJson(`${endpoint}/mcp/tools/${name}`, { sessionId: sid, ...args }, headers);
|
|
10722
|
+
let result;
|
|
10723
|
+
try {
|
|
10724
|
+
result = await callTool(sessionState.sessionId);
|
|
10725
|
+
} catch (err) {
|
|
10726
|
+
const detail = err.message;
|
|
10727
|
+
const isStaleSession = /HTTP (401|404)/.test(detail) || /session/i.test(detail) || /unknown_session/i.test(detail);
|
|
10728
|
+
if (!isStaleSession) throw err;
|
|
10729
|
+
sessionState.sessionId = null;
|
|
10730
|
+
const fresh = await connect();
|
|
10731
|
+
if (!fresh) {
|
|
10732
|
+
return {
|
|
10733
|
+
jsonrpc: "2.0",
|
|
10734
|
+
id: rpcId,
|
|
10735
|
+
error: { code: -32002, message: "failed to establish MCP session (after retry)" }
|
|
10736
|
+
};
|
|
10737
|
+
}
|
|
10738
|
+
sessionState.sessionId = fresh;
|
|
10739
|
+
result = await callTool(fresh);
|
|
10740
|
+
}
|
|
10741
|
+
return {
|
|
10742
|
+
jsonrpc: "2.0",
|
|
10743
|
+
id: rpcId,
|
|
10744
|
+
result: {
|
|
10745
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
10746
|
+
}
|
|
10747
|
+
};
|
|
10653
10748
|
}
|
|
10654
10749
|
return {
|
|
10655
10750
|
jsonrpc: "2.0",
|
|
@@ -10674,6 +10769,19 @@ async function defaultPostJson(url, body, headers = { "content-type": "applicati
|
|
|
10674
10769
|
}
|
|
10675
10770
|
return await res.json();
|
|
10676
10771
|
}
|
|
10772
|
+
async function defaultGetJson(url, headers = {}) {
|
|
10773
|
+
const res = await fetch(url, { method: "GET", headers });
|
|
10774
|
+
if (!res.ok) {
|
|
10775
|
+
let detail = "";
|
|
10776
|
+
try {
|
|
10777
|
+
const errBody = await res.json();
|
|
10778
|
+
detail = errBody.message ?? errBody.error ?? "";
|
|
10779
|
+
} catch {
|
|
10780
|
+
}
|
|
10781
|
+
throw new Error(`HTTP ${res.status.toString()}${detail ? `: ${detail}` : ""}`);
|
|
10782
|
+
}
|
|
10783
|
+
return await res.json();
|
|
10784
|
+
}
|
|
10677
10785
|
|
|
10678
10786
|
// src/commands/mcp-serve.ts
|
|
10679
10787
|
import { createInterface as createInterface3 } from "readline";
|