repowisestage 0.0.74 → 0.0.76
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 +115 -33
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -4535,21 +4535,38 @@ async function storeCredentials(credentials) {
|
|
|
4535
4535
|
}
|
|
4536
4536
|
}
|
|
4537
4537
|
var refreshInFlight = null;
|
|
4538
|
+
var refreshInFlightToken = null;
|
|
4539
|
+
var terminalRefreshTokens = /* @__PURE__ */ new Set();
|
|
4540
|
+
var lastSeenRefreshToken = null;
|
|
4538
4541
|
async function getValidCredentials(options) {
|
|
4539
4542
|
const creds = await getStoredCredentials();
|
|
4540
4543
|
if (!creds) {
|
|
4541
4544
|
lastRefreshOutcome = "no-creds";
|
|
4542
4545
|
return null;
|
|
4543
4546
|
}
|
|
4547
|
+
if (creds.refreshToken !== lastSeenRefreshToken) {
|
|
4548
|
+
terminalRefreshTokens.clear();
|
|
4549
|
+
lastSeenRefreshToken = creds.refreshToken;
|
|
4550
|
+
}
|
|
4544
4551
|
const now = Date.now();
|
|
4545
4552
|
const needsRefresh = options?.forceRefresh || now > creds.expiresAt - 5 * 60 * 1e3;
|
|
4546
4553
|
if (!needsRefresh) {
|
|
4547
4554
|
lastRefreshOutcome = "success";
|
|
4548
4555
|
return creds;
|
|
4549
4556
|
}
|
|
4550
|
-
if (
|
|
4551
|
-
|
|
4552
|
-
|
|
4557
|
+
if (terminalRefreshTokens.has(creds.refreshToken)) {
|
|
4558
|
+
lastRefreshOutcome = "terminal";
|
|
4559
|
+
return null;
|
|
4560
|
+
}
|
|
4561
|
+
if (!refreshInFlight || refreshInFlightToken !== creds.refreshToken) {
|
|
4562
|
+
const inflight = doRefresh(creds);
|
|
4563
|
+
refreshInFlight = inflight;
|
|
4564
|
+
refreshInFlightToken = creds.refreshToken;
|
|
4565
|
+
void inflight.finally(() => {
|
|
4566
|
+
if (refreshInFlight === inflight) {
|
|
4567
|
+
refreshInFlight = null;
|
|
4568
|
+
refreshInFlightToken = null;
|
|
4569
|
+
}
|
|
4553
4570
|
});
|
|
4554
4571
|
}
|
|
4555
4572
|
return refreshInFlight;
|
|
@@ -4566,6 +4583,7 @@ async function doRefresh(creds) {
|
|
|
4566
4583
|
const message = err instanceof Error ? err.message : String(err);
|
|
4567
4584
|
if (kind === "terminal") {
|
|
4568
4585
|
lastRefreshOutcome = "terminal";
|
|
4586
|
+
terminalRefreshTokens.add(creds.refreshToken);
|
|
4569
4587
|
console.warn(`Token refresh rejected (terminal): ${message}`);
|
|
4570
4588
|
return null;
|
|
4571
4589
|
}
|
|
@@ -7657,7 +7675,20 @@ async function startMcpServer(options) {
|
|
|
7657
7675
|
throw err;
|
|
7658
7676
|
}
|
|
7659
7677
|
},
|
|
7660
|
-
resumeEndpoint: () =>
|
|
7678
|
+
resumeEndpoint: async () => {
|
|
7679
|
+
let lastErr;
|
|
7680
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
7681
|
+
try {
|
|
7682
|
+
await writeEndpointFile(endpointFilePath, endpoint, secretState.value.current);
|
|
7683
|
+
return;
|
|
7684
|
+
} catch (err) {
|
|
7685
|
+
lastErr = err;
|
|
7686
|
+
if (attempt < 3)
|
|
7687
|
+
await new Promise((r) => setTimeout(r, 100 * attempt));
|
|
7688
|
+
}
|
|
7689
|
+
}
|
|
7690
|
+
throw lastErr;
|
|
7691
|
+
}
|
|
7661
7692
|
};
|
|
7662
7693
|
}
|
|
7663
7694
|
function handleRequest(req, res, options, sessions, secretCtx) {
|
|
@@ -8514,6 +8545,9 @@ import { join as join25 } from "path";
|
|
|
8514
8545
|
// ../listener/dist/mcp/auto-config/markers.js
|
|
8515
8546
|
import { promises as fs5 } from "fs";
|
|
8516
8547
|
import { dirname as dirname15 } from "path";
|
|
8548
|
+
function repoWiseServerName(ctx) {
|
|
8549
|
+
return `RepoWise MCP for ${ctx.repoName}${ctx.envSuffix ?? ""}`;
|
|
8550
|
+
}
|
|
8517
8551
|
async function writeMergedConfig(params) {
|
|
8518
8552
|
const current = await readConfig(params.path);
|
|
8519
8553
|
const servers = { ...current.mcpServers ?? {} };
|
|
@@ -8596,14 +8630,14 @@ var claudeCodeWriter = {
|
|
|
8596
8630
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8597
8631
|
const status2 = await writeMergedConfig({
|
|
8598
8632
|
path,
|
|
8599
|
-
serverName:
|
|
8633
|
+
serverName: repoWiseServerName(ctx),
|
|
8600
8634
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
8601
8635
|
});
|
|
8602
8636
|
return { status: status2, path };
|
|
8603
8637
|
},
|
|
8604
8638
|
async remove(ctx) {
|
|
8605
8639
|
const path = join25(ctx.repoRoot, ".mcp.json");
|
|
8606
|
-
await removeFromConfig(path,
|
|
8640
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
8607
8641
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8608
8642
|
}
|
|
8609
8643
|
};
|
|
@@ -8657,14 +8691,14 @@ var clineWriter = {
|
|
|
8657
8691
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8658
8692
|
const status2 = await writeMergedConfig({
|
|
8659
8693
|
path,
|
|
8660
|
-
serverName:
|
|
8694
|
+
serverName: repoWiseServerName(ctx),
|
|
8661
8695
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
8662
8696
|
});
|
|
8663
8697
|
return { status: status2, path };
|
|
8664
8698
|
},
|
|
8665
8699
|
async remove(ctx) {
|
|
8666
8700
|
const path = join27(ctx.home, ".cline", "mcp.json");
|
|
8667
|
-
await removeFromConfig(path,
|
|
8701
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
8668
8702
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8669
8703
|
}
|
|
8670
8704
|
};
|
|
@@ -8765,14 +8799,14 @@ var codexWriter = {
|
|
|
8765
8799
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8766
8800
|
const status2 = await writeMergedConfig({
|
|
8767
8801
|
path,
|
|
8768
|
-
serverName:
|
|
8802
|
+
serverName: repoWiseServerName(ctx),
|
|
8769
8803
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
8770
8804
|
});
|
|
8771
8805
|
return { status: status2, path };
|
|
8772
8806
|
},
|
|
8773
8807
|
async remove(ctx) {
|
|
8774
8808
|
const path = join29(ctx.home, ".codex", "mcp.json");
|
|
8775
|
-
await removeFromConfig(path,
|
|
8809
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
8776
8810
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8777
8811
|
}
|
|
8778
8812
|
};
|
|
@@ -8865,14 +8899,14 @@ var copilotWriter = {
|
|
|
8865
8899
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8866
8900
|
const status2 = await writeMergedConfig({
|
|
8867
8901
|
path,
|
|
8868
|
-
serverName:
|
|
8902
|
+
serverName: repoWiseServerName(ctx),
|
|
8869
8903
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
8870
8904
|
});
|
|
8871
8905
|
return { status: status2, path };
|
|
8872
8906
|
},
|
|
8873
8907
|
async remove(ctx) {
|
|
8874
8908
|
const path = join31(ctx.repoRoot, ".vscode", "mcp.json");
|
|
8875
|
-
await removeFromConfig(path,
|
|
8909
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
8876
8910
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8877
8911
|
}
|
|
8878
8912
|
};
|
|
@@ -8959,14 +8993,14 @@ var cursorWriter = {
|
|
|
8959
8993
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8960
8994
|
const status2 = await writeMergedConfig({
|
|
8961
8995
|
path,
|
|
8962
|
-
serverName:
|
|
8996
|
+
serverName: repoWiseServerName(ctx),
|
|
8963
8997
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
8964
8998
|
});
|
|
8965
8999
|
return { status: status2, path };
|
|
8966
9000
|
},
|
|
8967
9001
|
async remove(ctx) {
|
|
8968
9002
|
const path = join33(ctx.repoRoot, ".cursor", "mcp.json");
|
|
8969
|
-
await removeFromConfig(path,
|
|
9003
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
8970
9004
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8971
9005
|
}
|
|
8972
9006
|
};
|
|
@@ -8992,14 +9026,14 @@ var geminiCliWriter = {
|
|
|
8992
9026
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8993
9027
|
const status2 = await writeMergedConfig({
|
|
8994
9028
|
path,
|
|
8995
|
-
serverName:
|
|
9029
|
+
serverName: repoWiseServerName(ctx),
|
|
8996
9030
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
8997
9031
|
});
|
|
8998
9032
|
return { status: status2, path };
|
|
8999
9033
|
},
|
|
9000
9034
|
async remove(ctx) {
|
|
9001
9035
|
const path = join34(ctx.home, ".gemini", "settings.json");
|
|
9002
|
-
await removeFromConfig(path,
|
|
9036
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
9003
9037
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
9004
9038
|
}
|
|
9005
9039
|
};
|
|
@@ -9102,7 +9136,7 @@ var rooWriter = {
|
|
|
9102
9136
|
const homeConfig = join36(ctx.home, ".roo", "mcp.json");
|
|
9103
9137
|
const homeSettings = join36(ctx.home, ".roo", "settings.json");
|
|
9104
9138
|
for (const path of [repoConfig, homeConfig, homeSettings]) {
|
|
9105
|
-
await removeFromConfig(path,
|
|
9139
|
+
await removeFromConfig(path, repoWiseServerName(ctx)).catch(() => {
|
|
9106
9140
|
});
|
|
9107
9141
|
await removeFromConfig(path, `repowise-${ctx.repoId}`).catch(() => {
|
|
9108
9142
|
});
|
|
@@ -9138,14 +9172,14 @@ var windsurfWriter = {
|
|
|
9138
9172
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
9139
9173
|
const status2 = await writeMergedConfig({
|
|
9140
9174
|
path,
|
|
9141
|
-
serverName:
|
|
9175
|
+
serverName: repoWiseServerName(ctx),
|
|
9142
9176
|
spec: { command: ctx.shimCmd, args: ["mcp-shim", "--repo-id", ctx.repoId] }
|
|
9143
9177
|
});
|
|
9144
9178
|
return { status: status2, path };
|
|
9145
9179
|
},
|
|
9146
9180
|
async remove(ctx) {
|
|
9147
9181
|
const path = join37(ctx.home, ".codeium", "windsurf", "mcp_config.json");
|
|
9148
|
-
await removeFromConfig(path,
|
|
9182
|
+
await removeFromConfig(path, repoWiseServerName(ctx));
|
|
9149
9183
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
9150
9184
|
}
|
|
9151
9185
|
};
|
|
@@ -9205,7 +9239,8 @@ async function runAutoConfig(opts) {
|
|
|
9205
9239
|
home,
|
|
9206
9240
|
contextFolder: opts.contextFolder,
|
|
9207
9241
|
selectedTools: opts.selectedTools,
|
|
9208
|
-
variant: opts.variant
|
|
9242
|
+
variant: opts.variant,
|
|
9243
|
+
envSuffix: opts.envSuffix
|
|
9209
9244
|
});
|
|
9210
9245
|
results.push({ tool: writer.tool, detected: true, outcome });
|
|
9211
9246
|
} catch (err) {
|
|
@@ -11064,6 +11099,14 @@ function decodeEmailFromIdToken(idToken) {
|
|
|
11064
11099
|
return null;
|
|
11065
11100
|
}
|
|
11066
11101
|
}
|
|
11102
|
+
async function maybeRefreshOnWake(wakeDrift, pollIntervalMs) {
|
|
11103
|
+
if (wakeDrift <= pollIntervalMs + 6e4)
|
|
11104
|
+
return false;
|
|
11105
|
+
console.log(`[wake] ~${Math.round(wakeDrift / 1e3).toString()}s gap detected (likely sleep) \u2014 verifying token (refresh only if stale)`);
|
|
11106
|
+
await getValidCredentials().catch(() => {
|
|
11107
|
+
});
|
|
11108
|
+
return true;
|
|
11109
|
+
}
|
|
11067
11110
|
async function handleSyncCompleted(notif, ctx) {
|
|
11068
11111
|
if (!notif.commitSha) {
|
|
11069
11112
|
console.warn(`sync.completed for ${notif.repoId} has no commitSha`);
|
|
@@ -11294,6 +11337,7 @@ function mcpAiToolsKey(aiTools) {
|
|
|
11294
11337
|
}
|
|
11295
11338
|
async function reconcileMcpConfigs(repos, packageName) {
|
|
11296
11339
|
const shimCmd = packageName;
|
|
11340
|
+
const envSuffix = getConfigDir().endsWith("-staging") ? " (staging)" : "";
|
|
11297
11341
|
const { contextFolder, aiTools, graphOnly } = await readRawToolConfig();
|
|
11298
11342
|
for (const repo of repos) {
|
|
11299
11343
|
if (!repo.localPath)
|
|
@@ -11314,7 +11358,8 @@ async function reconcileMcpConfigs(repos, packageName) {
|
|
|
11314
11358
|
shimCmd,
|
|
11315
11359
|
contextFolder,
|
|
11316
11360
|
selectedTools: aiTools,
|
|
11317
|
-
variant
|
|
11361
|
+
variant,
|
|
11362
|
+
envSuffix
|
|
11318
11363
|
});
|
|
11319
11364
|
const written = results.filter((r) => r.detected && r.outcome?.status === "written");
|
|
11320
11365
|
if (written.length > 0) {
|
|
@@ -11736,14 +11781,25 @@ async function startListener() {
|
|
|
11736
11781
|
proactiveRefreshTimer.unref();
|
|
11737
11782
|
}
|
|
11738
11783
|
let lastCycleAt = Date.now();
|
|
11784
|
+
let endpointResumeFailed = false;
|
|
11785
|
+
let endpointResumeRetries = 0;
|
|
11739
11786
|
while (running) {
|
|
11740
11787
|
const wakeDrift = Date.now() - lastCycleAt;
|
|
11741
|
-
|
|
11742
|
-
console.log(`[wake] ~${Math.round(wakeDrift / 1e3).toString()}s gap detected (likely sleep) \u2014 refreshing credentials`);
|
|
11743
|
-
await getValidCredentials({ forceRefresh: true }).catch(() => {
|
|
11744
|
-
});
|
|
11745
|
-
}
|
|
11788
|
+
await maybeRefreshOnWake(wakeDrift, pollIntervalMs);
|
|
11746
11789
|
lastCycleAt = Date.now();
|
|
11790
|
+
if (endpointResumeFailed) {
|
|
11791
|
+
try {
|
|
11792
|
+
await mcpRuntime?.server?.resumeEndpoint();
|
|
11793
|
+
endpointResumeFailed = false;
|
|
11794
|
+
endpointResumeRetries = 0;
|
|
11795
|
+
console.log("[mcp] endpoint file restored on retry");
|
|
11796
|
+
} catch {
|
|
11797
|
+
endpointResumeRetries++;
|
|
11798
|
+
if (endpointResumeRetries % 12 === 0) {
|
|
11799
|
+
console.warn(`[mcp] endpoint file still not restored after ${endpointResumeRetries.toString()} retries \u2014 MCP remains unreachable`);
|
|
11800
|
+
}
|
|
11801
|
+
}
|
|
11802
|
+
}
|
|
11747
11803
|
let anyAuthError = null;
|
|
11748
11804
|
let authErrorGroup = null;
|
|
11749
11805
|
let minPollInterval = pollIntervalMs;
|
|
@@ -12093,7 +12149,9 @@ async function startListener() {
|
|
|
12093
12149
|
try {
|
|
12094
12150
|
await mcpRuntime?.server?.resumeEndpoint();
|
|
12095
12151
|
} catch (err) {
|
|
12096
|
-
console.warn("[mcp] resumeEndpoint failed:", err instanceof Error ? err.message : String(err));
|
|
12152
|
+
console.warn("[mcp] resumeEndpoint failed (will retry each poll cycle):", err instanceof Error ? err.message : String(err));
|
|
12153
|
+
endpointResumeFailed = true;
|
|
12154
|
+
endpointResumeRetries = 0;
|
|
12097
12155
|
}
|
|
12098
12156
|
}
|
|
12099
12157
|
continue;
|
|
@@ -16769,8 +16827,10 @@ async function mcpShim(opts) {
|
|
|
16769
16827
|
const message = authState === "logged-out" ? (
|
|
16770
16828
|
// Agent-directed: the calling LLM can run this itself for a smoother UX
|
|
16771
16829
|
// (it auto-opens the browser; the user still completes sign-in). The
|
|
16772
|
-
// command is a fixed, argument-free string (nothing injectable).
|
|
16773
|
-
|
|
16830
|
+
// command is a fixed, argument-free string (nothing injectable). Use the
|
|
16831
|
+
// build-flavor binary (`repowise` vs `repowisestage`) so staging users
|
|
16832
|
+
// get the command that matches their install.
|
|
16833
|
+
`RepoWise isn't authenticated (this is rare \u2014 the session lasts about a year). To fix it, run the shell command \`${getPackageName()} login\` on the user's behalf \u2014 it opens a browser for them to sign in and blocks until they finish. Run it once, wait for it to complete, then retry this request. Do not repeat the command.`
|
|
16774
16834
|
) : "listener endpoint unavailable \u2014 is the listener running?";
|
|
16775
16835
|
writeJson(stdout, {
|
|
16776
16836
|
jsonrpc: "2.0",
|
|
@@ -16792,16 +16852,24 @@ async function mcpShim(opts) {
|
|
|
16792
16852
|
);
|
|
16793
16853
|
writeJson(stdout, response);
|
|
16794
16854
|
} catch (err) {
|
|
16795
|
-
stderr.write(`mcp-shim: ${err.message}
|
|
16796
|
-
`);
|
|
16797
16855
|
const name = err.name;
|
|
16798
16856
|
const detail = err.message;
|
|
16799
16857
|
const isTimeout = name === "TimeoutError" || name === "AbortError" || /timeout|aborted|abort/i.test(detail);
|
|
16858
|
+
if (!isTimeout && isConnectionError(err)) {
|
|
16859
|
+
stderr.write(
|
|
16860
|
+
`mcp-shim: listener unreachable (${detail}) \u2014 exiting so the client respawns a fresh shim.
|
|
16861
|
+
`,
|
|
16862
|
+
() => process.exit(1)
|
|
16863
|
+
);
|
|
16864
|
+
return;
|
|
16865
|
+
}
|
|
16866
|
+
stderr.write(`mcp-shim: ${detail}
|
|
16867
|
+
`);
|
|
16800
16868
|
writeJson(stdout, {
|
|
16801
16869
|
jsonrpc: "2.0",
|
|
16802
16870
|
error: isTimeout ? {
|
|
16803
16871
|
code: -32001,
|
|
16804
|
-
message:
|
|
16872
|
+
message: `RepoWise listener did not respond in time \u2014 it may be stuck. Restart it with \`${getPackageName()} restart\`, then retry.`,
|
|
16805
16873
|
data: { detail }
|
|
16806
16874
|
} : {
|
|
16807
16875
|
code: -32001,
|
|
@@ -16812,6 +16880,20 @@ async function mcpShim(opts) {
|
|
|
16812
16880
|
}
|
|
16813
16881
|
}
|
|
16814
16882
|
}
|
|
16883
|
+
function isConnectionError(err) {
|
|
16884
|
+
const CONN_CODES = /* @__PURE__ */ new Set([
|
|
16885
|
+
"ECONNREFUSED",
|
|
16886
|
+
"ECONNRESET",
|
|
16887
|
+
"EHOSTUNREACH",
|
|
16888
|
+
"ENETUNREACH",
|
|
16889
|
+
"ECONNABORTED"
|
|
16890
|
+
]);
|
|
16891
|
+
const e = err;
|
|
16892
|
+
if (e && typeof e.code === "string" && CONN_CODES.has(e.code)) return true;
|
|
16893
|
+
if (e && e.cause && typeof e.cause.code === "string" && CONN_CODES.has(e.cause.code)) return true;
|
|
16894
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
16895
|
+
return /ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH|fetch failed|socket hang up/i.test(msg);
|
|
16896
|
+
}
|
|
16815
16897
|
async function readEndpoint(path) {
|
|
16816
16898
|
try {
|
|
16817
16899
|
const raw = (await fs30.readFile(path, "utf-8")).trim();
|
|
@@ -16862,7 +16944,7 @@ async function routeMessage(endpoint, repoId, message, postJson, getJson, header
|
|
|
16862
16944
|
id: rpcId,
|
|
16863
16945
|
result: {
|
|
16864
16946
|
protocolVersion: "2024-11-05",
|
|
16865
|
-
serverInfo: { name:
|
|
16947
|
+
serverInfo: { name: getPackageName(), version: "0.0.0" },
|
|
16866
16948
|
capabilities: { tools: { listChanged: false } }
|
|
16867
16949
|
}
|
|
16868
16950
|
};
|