repowisestage 0.0.77 → 0.0.79
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 +190 -71
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -2382,7 +2382,9 @@ var init_service_installer = __esm({
|
|
|
2382
2382
|
var sidecar_cache_exports = {};
|
|
2383
2383
|
__export(sidecar_cache_exports, {
|
|
2384
2384
|
loadMergedSidecar: () => loadMergedSidecar,
|
|
2385
|
+
loadSidecarEtag: () => loadSidecarEtag,
|
|
2385
2386
|
persistMergedSidecar: () => persistMergedSidecar,
|
|
2387
|
+
persistSidecarEtag: () => persistSidecarEtag,
|
|
2386
2388
|
sidecarCachePaths: () => sidecarCachePaths
|
|
2387
2389
|
});
|
|
2388
2390
|
import { mkdir as mkdir9, readFile as readFile9, readdir as readdir3, stat as stat2, unlink as unlink9, writeFile as writeFile10 } from "fs/promises";
|
|
@@ -2409,8 +2411,8 @@ async function persistMergedSidecar(repoId, commitSha, sidecar) {
|
|
|
2409
2411
|
await mkdir9(repoDir, { recursive: true });
|
|
2410
2412
|
const tmpPath = `${fullPath}.tmp`;
|
|
2411
2413
|
await writeFile10(tmpPath, JSON.stringify(sidecar), "utf-8");
|
|
2412
|
-
const { rename:
|
|
2413
|
-
await
|
|
2414
|
+
const { rename: rename9 } = await import("fs/promises");
|
|
2415
|
+
await rename9(tmpPath, fullPath);
|
|
2414
2416
|
try {
|
|
2415
2417
|
await sweepSidecarDir(repoDir);
|
|
2416
2418
|
} catch {
|
|
@@ -2438,9 +2440,32 @@ async function sweepSidecarDir(repoDir) {
|
|
|
2438
2440
|
await unlink9(join21(repoDir, name));
|
|
2439
2441
|
} catch {
|
|
2440
2442
|
}
|
|
2443
|
+
try {
|
|
2444
|
+
await unlink9(join21(repoDir, `${name}.etag`));
|
|
2445
|
+
} catch {
|
|
2446
|
+
}
|
|
2441
2447
|
}
|
|
2442
2448
|
}
|
|
2443
2449
|
}
|
|
2450
|
+
async function persistSidecarEtag(repoId, commitSha, etag) {
|
|
2451
|
+
const { fullPath, repoDir } = sidecarCachePaths(repoId, commitSha);
|
|
2452
|
+
await mkdir9(repoDir, { recursive: true });
|
|
2453
|
+
const etagPath = `${fullPath}.etag`;
|
|
2454
|
+
const tmpPath = `${etagPath}.tmp`;
|
|
2455
|
+
await writeFile10(tmpPath, etag, "utf-8");
|
|
2456
|
+
const { rename: rename9 } = await import("fs/promises");
|
|
2457
|
+
await rename9(tmpPath, etagPath);
|
|
2458
|
+
}
|
|
2459
|
+
async function loadSidecarEtag(repoId, commitSha) {
|
|
2460
|
+
try {
|
|
2461
|
+
const { fullPath } = sidecarCachePaths(repoId, commitSha);
|
|
2462
|
+
const body = await readFile9(`${fullPath}.etag`, "utf-8");
|
|
2463
|
+
const trimmed = body.trim();
|
|
2464
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2465
|
+
} catch {
|
|
2466
|
+
return null;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2444
2469
|
function isValidSidecarEntry(e) {
|
|
2445
2470
|
if (!e || typeof e !== "object")
|
|
2446
2471
|
return false;
|
|
@@ -2576,22 +2601,28 @@ async function uploadSidecarLegacy(req, body, fetchImpl) {
|
|
|
2576
2601
|
}
|
|
2577
2602
|
async function downloadMergedSidecar(req, fetchImpl = fetch) {
|
|
2578
2603
|
const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution/${encodeURIComponent(req.commitSha)}`;
|
|
2579
|
-
const
|
|
2580
|
-
|
|
2581
|
-
headers
|
|
2582
|
-
});
|
|
2604
|
+
const headers = { authorization: `Bearer ${req.authToken}` };
|
|
2605
|
+
if (req.ifNoneMatch)
|
|
2606
|
+
headers["if-none-match"] = req.ifNoneMatch;
|
|
2607
|
+
const res = await fetchImpl(url, { method: "GET", headers });
|
|
2608
|
+
if (res.status === 304)
|
|
2609
|
+
return { status: "not-modified" };
|
|
2583
2610
|
if (res.status === 404)
|
|
2584
|
-
return
|
|
2611
|
+
return { status: "absent" };
|
|
2585
2612
|
if (!res.ok) {
|
|
2586
2613
|
throw new Error(`download failed: HTTP ${res.status.toString()}`);
|
|
2587
2614
|
}
|
|
2588
2615
|
const body = await res.json();
|
|
2589
2616
|
if (typeof body.schemaVersion !== "number" || !ACCEPTED_TYPED_RESOLUTION_SCHEMA_VERSIONS.includes(body.schemaVersion)) {
|
|
2590
|
-
return
|
|
2617
|
+
return { status: "absent" };
|
|
2591
2618
|
}
|
|
2592
2619
|
if (!Array.isArray(body.resolutions))
|
|
2593
|
-
return
|
|
2594
|
-
return
|
|
2620
|
+
return { status: "absent" };
|
|
2621
|
+
return {
|
|
2622
|
+
status: "sidecar",
|
|
2623
|
+
sidecar: body,
|
|
2624
|
+
etag: res.headers.get("etag")
|
|
2625
|
+
};
|
|
2595
2626
|
}
|
|
2596
2627
|
function buildSidecarIndex(sidecar) {
|
|
2597
2628
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -6445,8 +6476,8 @@ function createFileKeyStore(keyPath) {
|
|
|
6445
6476
|
encoding: "utf-8",
|
|
6446
6477
|
mode: 384
|
|
6447
6478
|
});
|
|
6448
|
-
const { rename:
|
|
6449
|
-
await
|
|
6479
|
+
const { rename: rename9 } = await import("fs/promises");
|
|
6480
|
+
await rename9(tmp, keyPath);
|
|
6450
6481
|
cached = fresh;
|
|
6451
6482
|
try {
|
|
6452
6483
|
const s = await stat4(keyPath);
|
|
@@ -6695,9 +6726,9 @@ async function writePendingBatch(watermarkPath, batchId) {
|
|
|
6695
6726
|
await writeFile14(pendingPath(watermarkPath), batchId, { encoding: "utf-8", mode: 384 });
|
|
6696
6727
|
}
|
|
6697
6728
|
async function clearPendingBatch(watermarkPath) {
|
|
6698
|
-
const { unlink:
|
|
6729
|
+
const { unlink: unlink15 } = await import("fs/promises");
|
|
6699
6730
|
try {
|
|
6700
|
-
await
|
|
6731
|
+
await unlink15(pendingPath(watermarkPath));
|
|
6701
6732
|
} catch {
|
|
6702
6733
|
}
|
|
6703
6734
|
}
|
|
@@ -6716,8 +6747,8 @@ async function writeWatermark(path, offset) {
|
|
|
6716
6747
|
await mkdir13(dirname14(path), { recursive: true });
|
|
6717
6748
|
const tmp = `${path}.tmp`;
|
|
6718
6749
|
await writeFile14(tmp, offset.toString() + "\n", { encoding: "utf-8", mode: 384 });
|
|
6719
|
-
const { rename:
|
|
6720
|
-
await
|
|
6750
|
+
const { rename: rename9 } = await import("fs/promises");
|
|
6751
|
+
await rename9(tmp, path);
|
|
6721
6752
|
}
|
|
6722
6753
|
async function isLocallyConsented(flagPath2) {
|
|
6723
6754
|
try {
|
|
@@ -6732,9 +6763,37 @@ async function isLocallyConsented(flagPath2) {
|
|
|
6732
6763
|
// ../listener/dist/mcp/mcp-server.js
|
|
6733
6764
|
init_config_dir();
|
|
6734
6765
|
import { createServer } from "http";
|
|
6735
|
-
import {
|
|
6736
|
-
import {
|
|
6737
|
-
import { createHash as createHash4, randomUUID as
|
|
6766
|
+
import { unlink as unlink12 } from "fs/promises";
|
|
6767
|
+
import { join as join23 } from "path";
|
|
6768
|
+
import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
|
|
6769
|
+
|
|
6770
|
+
// ../listener/dist/lib/atomic-write.js
|
|
6771
|
+
import { mkdir as mkdir14, writeFile as writeFile15, chmod as chmod4, rename as rename6, unlink as unlink11, open as open5 } from "fs/promises";
|
|
6772
|
+
import { dirname as dirname15 } from "path";
|
|
6773
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6774
|
+
async function writeFileAtomic(path, contents, opts = {}) {
|
|
6775
|
+
const mode = opts.mode ?? 384;
|
|
6776
|
+
await mkdir14(dirname15(path), { recursive: true });
|
|
6777
|
+
const tmpPath = `${path}.${randomUUID3()}.tmp`;
|
|
6778
|
+
try {
|
|
6779
|
+
await writeFile15(tmpPath, contents, { encoding: "utf-8", mode });
|
|
6780
|
+
await chmod4(tmpPath, mode);
|
|
6781
|
+
let fh;
|
|
6782
|
+
try {
|
|
6783
|
+
fh = await open5(tmpPath, "r+");
|
|
6784
|
+
await fh.datasync();
|
|
6785
|
+
} finally {
|
|
6786
|
+
await fh?.close();
|
|
6787
|
+
}
|
|
6788
|
+
await rename6(tmpPath, path);
|
|
6789
|
+
} catch (err) {
|
|
6790
|
+
try {
|
|
6791
|
+
await unlink11(tmpPath);
|
|
6792
|
+
} catch {
|
|
6793
|
+
}
|
|
6794
|
+
throw err;
|
|
6795
|
+
}
|
|
6796
|
+
}
|
|
6738
6797
|
|
|
6739
6798
|
// ../listener/dist/mcp/sanitize.js
|
|
6740
6799
|
var MCP_RESPONSE_BYTE_CAP = 200 * 1024;
|
|
@@ -7768,6 +7827,25 @@ async function startMcpServer(options) {
|
|
|
7768
7827
|
const clock = options.clock ?? Date.now;
|
|
7769
7828
|
const requireAuth = options.requireAuth ?? true;
|
|
7770
7829
|
const secretState = { value: createRotatingSecret(clock()) };
|
|
7830
|
+
const endpointFilePath = options.endpointFilePath ?? defaultEndpointFile();
|
|
7831
|
+
let endpointUrl = null;
|
|
7832
|
+
let lastPersistedSecret = null;
|
|
7833
|
+
let suspended = false;
|
|
7834
|
+
let persisting = false;
|
|
7835
|
+
let currentPersist = null;
|
|
7836
|
+
const persistSecretIfStale = () => {
|
|
7837
|
+
const live = secretState.value.current;
|
|
7838
|
+
if (endpointUrl === null || suspended || persisting || live === lastPersistedSecret)
|
|
7839
|
+
return;
|
|
7840
|
+
persisting = true;
|
|
7841
|
+
currentPersist = writeEndpointFileWithRetry(endpointFilePath, endpointUrl, live).then(() => {
|
|
7842
|
+
lastPersistedSecret = live;
|
|
7843
|
+
}).catch((err) => {
|
|
7844
|
+
console.warn("[mcp] endpoint secret persist failed (will retry on next request):", err instanceof Error ? err.message : String(err));
|
|
7845
|
+
}).finally(() => {
|
|
7846
|
+
persisting = false;
|
|
7847
|
+
});
|
|
7848
|
+
};
|
|
7771
7849
|
const server = createServer((req, res) => handleRequest(req, res, options, sessions, {
|
|
7772
7850
|
getSecret: () => secretState.value,
|
|
7773
7851
|
rotate: () => {
|
|
@@ -7775,6 +7853,7 @@ async function startMcpServer(options) {
|
|
|
7775
7853
|
if (next !== secretState.value) {
|
|
7776
7854
|
secretState.value = next;
|
|
7777
7855
|
}
|
|
7856
|
+
persistSecretIfStale();
|
|
7778
7857
|
return secretState.value;
|
|
7779
7858
|
},
|
|
7780
7859
|
requireAuth,
|
|
@@ -7788,38 +7867,34 @@ async function startMcpServer(options) {
|
|
|
7788
7867
|
});
|
|
7789
7868
|
});
|
|
7790
7869
|
const addr = server.address();
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7870
|
+
endpointUrl = `http://127.0.0.1:${addr.port}`;
|
|
7871
|
+
await writeEndpointFileWithRetry(endpointFilePath, endpointUrl, secretState.value.current);
|
|
7872
|
+
lastPersistedSecret = secretState.value.current;
|
|
7794
7873
|
return {
|
|
7795
|
-
endpoint,
|
|
7874
|
+
endpoint: endpointUrl,
|
|
7796
7875
|
port: addr.port,
|
|
7797
7876
|
secret: secretState.value.current,
|
|
7877
|
+
currentSecret: () => secretState.value.current,
|
|
7798
7878
|
close: () => new Promise((resolve5, reject) => {
|
|
7799
7879
|
server.close((err) => err ? reject(err) : resolve5());
|
|
7800
7880
|
}),
|
|
7801
7881
|
suspendEndpoint: async () => {
|
|
7882
|
+
suspended = true;
|
|
7883
|
+
await currentPersist?.catch(() => void 0);
|
|
7884
|
+
lastPersistedSecret = null;
|
|
7802
7885
|
try {
|
|
7803
|
-
await
|
|
7886
|
+
await unlink12(endpointFilePath);
|
|
7804
7887
|
} catch (err) {
|
|
7805
7888
|
if (err.code !== "ENOENT")
|
|
7806
7889
|
throw err;
|
|
7807
7890
|
}
|
|
7808
7891
|
},
|
|
7809
7892
|
resumeEndpoint: async () => {
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
} catch (err) {
|
|
7816
|
-
lastErr = err;
|
|
7817
|
-
if (attempt < 3)
|
|
7818
|
-
await new Promise((r) => setTimeout(r, 100 * attempt));
|
|
7819
|
-
}
|
|
7820
|
-
}
|
|
7821
|
-
throw lastErr;
|
|
7822
|
-
}
|
|
7893
|
+
suspended = false;
|
|
7894
|
+
await writeEndpointFileWithRetry(endpointFilePath, endpointUrl, secretState.value.current);
|
|
7895
|
+
lastPersistedSecret = secretState.value.current;
|
|
7896
|
+
},
|
|
7897
|
+
retryPendingPersist: () => persistSecretIfStale()
|
|
7823
7898
|
};
|
|
7824
7899
|
}
|
|
7825
7900
|
function handleRequest(req, res, options, sessions, secretCtx) {
|
|
@@ -7859,7 +7934,7 @@ function handleRequest(req, res, options, sessions, secretCtx) {
|
|
|
7859
7934
|
if (!body?.repoId)
|
|
7860
7935
|
return sendJson(res, 400, { error: "missing_repoId" });
|
|
7861
7936
|
return options.graphCache.acquire(body.repoId).then(() => {
|
|
7862
|
-
const sessionId =
|
|
7937
|
+
const sessionId = randomUUID4();
|
|
7863
7938
|
sessions.set(sessionId, { repoId: body.repoId });
|
|
7864
7939
|
return sendJson(res, 200, { sessionId });
|
|
7865
7940
|
});
|
|
@@ -8352,11 +8427,21 @@ async function readJson(req) {
|
|
|
8352
8427
|
}
|
|
8353
8428
|
}
|
|
8354
8429
|
async function writeEndpointFile(path, endpoint, secret) {
|
|
8355
|
-
await
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8430
|
+
await writeFileAtomic(path, formatEndpointFile({ endpoint, secret }), { mode: 384 });
|
|
8431
|
+
}
|
|
8432
|
+
async function writeEndpointFileWithRetry(path, endpoint, secret) {
|
|
8433
|
+
let lastErr;
|
|
8434
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
8435
|
+
try {
|
|
8436
|
+
await writeEndpointFile(path, endpoint, secret);
|
|
8437
|
+
return;
|
|
8438
|
+
} catch (err) {
|
|
8439
|
+
lastErr = err;
|
|
8440
|
+
if (attempt < 3)
|
|
8441
|
+
await new Promise((r) => setTimeout(r, 100 * attempt));
|
|
8442
|
+
}
|
|
8443
|
+
}
|
|
8444
|
+
throw lastErr;
|
|
8360
8445
|
}
|
|
8361
8446
|
function extractBearer(header) {
|
|
8362
8447
|
const raw = Array.isArray(header) ? header[0] : header;
|
|
@@ -8432,6 +8517,7 @@ async function startMcp(options) {
|
|
|
8432
8517
|
sink: createHeartbeatSink({
|
|
8433
8518
|
apiUrl: heartbeatApiUrl,
|
|
8434
8519
|
getAuthToken: options.getAuthToken,
|
|
8520
|
+
...options.getAuthTokenForceRefresh ? { getAuthTokenForceRefresh: options.getAuthTokenForceRefresh } : {},
|
|
8435
8521
|
flagFilePath,
|
|
8436
8522
|
...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
|
|
8437
8523
|
}),
|
|
@@ -8584,6 +8670,7 @@ async function startMcp(options) {
|
|
|
8584
8670
|
}
|
|
8585
8671
|
};
|
|
8586
8672
|
}
|
|
8673
|
+
var HEARTBEAT_UPLOAD_TIMEOUT_MS = 3e4;
|
|
8587
8674
|
function createHeartbeatSink(deps) {
|
|
8588
8675
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
8589
8676
|
return {
|
|
@@ -8598,21 +8685,35 @@ function createHeartbeatSink(deps) {
|
|
|
8598
8685
|
try {
|
|
8599
8686
|
token = await deps.getAuthToken();
|
|
8600
8687
|
} catch {
|
|
8601
|
-
|
|
8688
|
+
throw new Error("mcp-heartbeat: no auth token (transient \u2014 will retry)");
|
|
8602
8689
|
}
|
|
8603
8690
|
if (!token)
|
|
8604
|
-
|
|
8605
|
-
const
|
|
8691
|
+
throw new Error("mcp-heartbeat: no auth token (transient \u2014 will retry)");
|
|
8692
|
+
const doPost = (bearer) => fetchImpl(`${deps.apiUrl}/v1/listeners/mcp-heartbeat`, {
|
|
8606
8693
|
method: "POST",
|
|
8607
8694
|
headers: {
|
|
8608
8695
|
"Content-Type": "application/json",
|
|
8609
|
-
Authorization: `Bearer ${
|
|
8696
|
+
Authorization: `Bearer ${bearer}`
|
|
8610
8697
|
},
|
|
8611
|
-
body: JSON.stringify(payload)
|
|
8698
|
+
body: JSON.stringify(payload),
|
|
8699
|
+
signal: AbortSignal.timeout(HEARTBEAT_UPLOAD_TIMEOUT_MS)
|
|
8612
8700
|
});
|
|
8613
|
-
|
|
8614
|
-
|
|
8701
|
+
let res = await doPost(token);
|
|
8702
|
+
if (res.status === 401 && deps.getAuthTokenForceRefresh) {
|
|
8703
|
+
try {
|
|
8704
|
+
const fresh = await deps.getAuthTokenForceRefresh();
|
|
8705
|
+
if (fresh)
|
|
8706
|
+
res = await doPost(fresh);
|
|
8707
|
+
} catch {
|
|
8708
|
+
}
|
|
8615
8709
|
}
|
|
8710
|
+
if (res.ok)
|
|
8711
|
+
return;
|
|
8712
|
+
const retryable = res.status >= 500 || res.status === 401 || res.status === 408 || res.status === 429;
|
|
8713
|
+
if (retryable) {
|
|
8714
|
+
throw new Error(`mcp-heartbeat: upload failed (HTTP ${res.status.toString()}) \u2014 will retry`);
|
|
8715
|
+
}
|
|
8716
|
+
console.warn(`[mcp-heartbeat] upload rejected (HTTP ${res.status.toString()}) \u2014 dropping (payload/contract or permission drift)`);
|
|
8616
8717
|
}
|
|
8617
8718
|
};
|
|
8618
8719
|
}
|
|
@@ -10613,16 +10714,28 @@ async function runProducerCycle(input, fetchImpl = fetch) {
|
|
|
10613
10714
|
async function runDownloaderCycle(input, fetchImpl = fetch) {
|
|
10614
10715
|
if (isDisabled())
|
|
10615
10716
|
return null;
|
|
10616
|
-
const
|
|
10717
|
+
const cached = await loadMergedSidecar(input.repoId, input.commitSha);
|
|
10718
|
+
const cachedEtag = cached ? await loadSidecarEtag(input.repoId, input.commitSha) : null;
|
|
10719
|
+
const res = await downloadMergedSidecar({
|
|
10617
10720
|
apiUrl: input.apiUrl,
|
|
10618
10721
|
authToken: input.authToken,
|
|
10619
10722
|
repoId: input.repoId,
|
|
10620
|
-
commitSha: input.commitSha
|
|
10723
|
+
commitSha: input.commitSha,
|
|
10724
|
+
...cachedEtag ? { ifNoneMatch: cachedEtag } : {}
|
|
10621
10725
|
}, fetchImpl);
|
|
10622
|
-
if (
|
|
10726
|
+
if (res.status === "not-modified") {
|
|
10727
|
+
if (!cached || !input.graph?.edges)
|
|
10728
|
+
return { downloaded: false, edgesUpgraded: 0 };
|
|
10729
|
+
const cachedResult = overlayMergedSidecar(input.graph.edges, cached);
|
|
10730
|
+
return { downloaded: false, edgesUpgraded: cachedResult.edgesUpgraded };
|
|
10731
|
+
}
|
|
10732
|
+
if (res.status === "absent")
|
|
10623
10733
|
return { downloaded: false, edgesUpgraded: 0 };
|
|
10734
|
+
const sidecar = res.sidecar;
|
|
10624
10735
|
try {
|
|
10625
10736
|
await persistMergedSidecar(input.repoId, input.commitSha, sidecar);
|
|
10737
|
+
if (res.etag)
|
|
10738
|
+
await persistSidecarEtag(input.repoId, input.commitSha, res.etag);
|
|
10626
10739
|
} catch (persistErr) {
|
|
10627
10740
|
console.warn(`[typed-resolution] persist failed for ${input.repoId}: ${persistErr instanceof Error ? persistErr.message : String(persistErr)}`);
|
|
10628
10741
|
}
|
|
@@ -11302,14 +11415,17 @@ async function runProducerHook(notif, localPath, ctx) {
|
|
|
11302
11415
|
console.warn(`[typed-resolution] producer failed for ${notif.repoId}: ${prodErr instanceof Error ? prodErr.message : String(prodErr)}`);
|
|
11303
11416
|
}
|
|
11304
11417
|
}
|
|
11305
|
-
var processedSideEffectNotifs = /* @__PURE__ */ new
|
|
11418
|
+
var processedSideEffectNotifs = /* @__PURE__ */ new Map();
|
|
11306
11419
|
var MAX_PROCESSED_SIDE_EFFECT_NOTIFS = 512;
|
|
11307
|
-
|
|
11308
|
-
|
|
11420
|
+
var SIDECAR_MERGED_RECHECK_MS = 5 * 60 * 1e3;
|
|
11421
|
+
function alreadyProcessedSideEffect(notificationId, ttlMs) {
|
|
11422
|
+
const now = Date.now();
|
|
11423
|
+
const expiresAt = processedSideEffectNotifs.get(notificationId);
|
|
11424
|
+
if (expiresAt !== void 0 && now < expiresAt)
|
|
11309
11425
|
return true;
|
|
11310
|
-
processedSideEffectNotifs.
|
|
11426
|
+
processedSideEffectNotifs.set(notificationId, ttlMs === void 0 ? Infinity : now + ttlMs);
|
|
11311
11427
|
if (processedSideEffectNotifs.size > MAX_PROCESSED_SIDE_EFFECT_NOTIFS) {
|
|
11312
|
-
const oldest = processedSideEffectNotifs.
|
|
11428
|
+
const oldest = processedSideEffectNotifs.keys().next().value;
|
|
11313
11429
|
if (oldest !== void 0)
|
|
11314
11430
|
processedSideEffectNotifs.delete(oldest);
|
|
11315
11431
|
}
|
|
@@ -11346,6 +11462,8 @@ async function handleGraphReady(notif, ctx) {
|
|
|
11346
11462
|
async function handleSidecarMerged(notif, ctx) {
|
|
11347
11463
|
if (!ctx.typedResolutionHooks || !notif.commitSha)
|
|
11348
11464
|
return;
|
|
11465
|
+
if (alreadyProcessedSideEffect(notif.notificationId, SIDECAR_MERGED_RECHECK_MS))
|
|
11466
|
+
return;
|
|
11349
11467
|
try {
|
|
11350
11468
|
await ctx.typedResolutionHooks.onSidecarMerged(notif.repoId, notif.commitSha);
|
|
11351
11469
|
} catch (dlErr) {
|
|
@@ -11935,6 +12053,7 @@ async function startListener() {
|
|
|
11935
12053
|
}
|
|
11936
12054
|
}
|
|
11937
12055
|
}
|
|
12056
|
+
mcpRuntime?.server?.retryPendingPersist?.();
|
|
11938
12057
|
let anyAuthError = null;
|
|
11939
12058
|
let authErrorGroup = null;
|
|
11940
12059
|
let minPollInterval = pollIntervalMs;
|
|
@@ -12342,7 +12461,7 @@ function getPackageName() {
|
|
|
12342
12461
|
import chalk from "chalk";
|
|
12343
12462
|
|
|
12344
12463
|
// src/lib/config.ts
|
|
12345
|
-
import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir17, rename as
|
|
12464
|
+
import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir17, rename as rename7, unlink as unlink13 } from "fs/promises";
|
|
12346
12465
|
import { join as join44 } from "path";
|
|
12347
12466
|
import lockfile6 from "proper-lockfile";
|
|
12348
12467
|
async function getConfig() {
|
|
@@ -12360,10 +12479,10 @@ async function saveConfig(config2) {
|
|
|
12360
12479
|
const tmpPath = path + ".tmp";
|
|
12361
12480
|
try {
|
|
12362
12481
|
await writeFile17(tmpPath, JSON.stringify(config2, null, 2));
|
|
12363
|
-
await
|
|
12482
|
+
await rename7(tmpPath, path);
|
|
12364
12483
|
} catch (err) {
|
|
12365
12484
|
try {
|
|
12366
|
-
await
|
|
12485
|
+
await unlink13(tmpPath);
|
|
12367
12486
|
} catch {
|
|
12368
12487
|
}
|
|
12369
12488
|
throw err;
|
|
@@ -12449,7 +12568,7 @@ import ora from "ora";
|
|
|
12449
12568
|
|
|
12450
12569
|
// src/lib/auth.ts
|
|
12451
12570
|
import { createHash as createHash6, randomBytes as randomBytes3 } from "crypto";
|
|
12452
|
-
import { readFile as readFile16, writeFile as writeFile18, mkdir as mkdir18, chmod as
|
|
12571
|
+
import { readFile as readFile16, writeFile as writeFile18, mkdir as mkdir18, chmod as chmod5, unlink as unlink14, rename as rename8, open as open6 } from "fs/promises";
|
|
12453
12572
|
import http from "http";
|
|
12454
12573
|
import { join as join45 } from "path";
|
|
12455
12574
|
import lockfile7 from "proper-lockfile";
|
|
@@ -12692,16 +12811,16 @@ async function storeCredentials2(credentials) {
|
|
|
12692
12811
|
await writeFile18(tmpPath, JSON.stringify(credentials, null, 2), { mode: 384 });
|
|
12693
12812
|
let fh;
|
|
12694
12813
|
try {
|
|
12695
|
-
fh = await
|
|
12814
|
+
fh = await open6(tmpPath, "r+");
|
|
12696
12815
|
await fh.datasync();
|
|
12697
12816
|
} finally {
|
|
12698
12817
|
await fh?.close();
|
|
12699
12818
|
}
|
|
12700
|
-
await
|
|
12701
|
-
await
|
|
12819
|
+
await rename8(tmpPath, credPath);
|
|
12820
|
+
await chmod5(credPath, 384);
|
|
12702
12821
|
} catch (err) {
|
|
12703
12822
|
try {
|
|
12704
|
-
await
|
|
12823
|
+
await unlink14(tmpPath);
|
|
12705
12824
|
} catch {
|
|
12706
12825
|
}
|
|
12707
12826
|
throw err;
|
|
@@ -12717,7 +12836,7 @@ async function storeCredentials2(credentials) {
|
|
|
12717
12836
|
}
|
|
12718
12837
|
async function clearCredentials() {
|
|
12719
12838
|
try {
|
|
12720
|
-
await
|
|
12839
|
+
await unlink14(join45(getConfigDir2(), "credentials.json"));
|
|
12721
12840
|
} catch (err) {
|
|
12722
12841
|
if (err.code !== "ENOENT") throw err;
|
|
12723
12842
|
}
|
|
@@ -12758,8 +12877,8 @@ async function performLogin() {
|
|
|
12758
12877
|
const authorizeUrl = getAuthorizeUrl(codeChallenge, state);
|
|
12759
12878
|
const callbackPromise = startCallbackServer();
|
|
12760
12879
|
try {
|
|
12761
|
-
const
|
|
12762
|
-
await
|
|
12880
|
+
const open7 = (await import("open")).default;
|
|
12881
|
+
await open7(authorizeUrl);
|
|
12763
12882
|
} catch {
|
|
12764
12883
|
console.log(`
|
|
12765
12884
|
Open this URL in your browser to authenticate:
|
|
@@ -15217,8 +15336,8 @@ Waiting for authentication...`);
|
|
|
15217
15336
|
} else {
|
|
15218
15337
|
spinner.text = "Opening browser for authentication...";
|
|
15219
15338
|
try {
|
|
15220
|
-
const
|
|
15221
|
-
await
|
|
15339
|
+
const open7 = (await import("open")).default;
|
|
15340
|
+
await open7(authorizeUrl);
|
|
15222
15341
|
spinner.text = "Waiting for authentication in browser...";
|
|
15223
15342
|
} catch {
|
|
15224
15343
|
spinner.stop();
|