repowise 0.1.91 → 0.1.93
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 +355 -76
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -2426,7 +2426,8 @@ __export(sidecar_client_exports, {
|
|
|
2426
2426
|
uploadSidecar: () => uploadSidecar
|
|
2427
2427
|
});
|
|
2428
2428
|
async function uploadSidecar(req, fetchImpl = fetch) {
|
|
2429
|
-
const
|
|
2429
|
+
const base = req.apiUrl.replace(/\/$/, "");
|
|
2430
|
+
const repoSeg = encodeURIComponent(req.repoId);
|
|
2430
2431
|
const body = JSON.stringify({ ...req.sidecar, commitSha: req.commitSha });
|
|
2431
2432
|
const byteLength = Buffer.byteLength(body, "utf8");
|
|
2432
2433
|
if (byteLength > UPLOAD_BODY_BYTE_LIMIT) {
|
|
@@ -2439,6 +2440,43 @@ async function uploadSidecar(req, fetchImpl = fetch) {
|
|
|
2439
2440
|
error: msg
|
|
2440
2441
|
};
|
|
2441
2442
|
}
|
|
2443
|
+
const urlRes = await fetchImpl(`${base}/v1/repos/${repoSeg}/typed-resolution/upload-url`, {
|
|
2444
|
+
method: "POST",
|
|
2445
|
+
headers: {
|
|
2446
|
+
"content-type": "application/json",
|
|
2447
|
+
authorization: `Bearer ${req.authToken}`
|
|
2448
|
+
},
|
|
2449
|
+
body: JSON.stringify({ commitSha: req.commitSha })
|
|
2450
|
+
});
|
|
2451
|
+
if (urlRes.status === 404) {
|
|
2452
|
+
return uploadSidecarLegacy(req, body, fetchImpl);
|
|
2453
|
+
}
|
|
2454
|
+
if (!urlRes.ok) {
|
|
2455
|
+
const text = await urlRes.text().catch(() => "");
|
|
2456
|
+
throw new Error(`upload-url request failed: HTTP ${urlRes.status.toString()} ${text}`);
|
|
2457
|
+
}
|
|
2458
|
+
const urlPayload = await urlRes.json();
|
|
2459
|
+
const presignedUrl = urlPayload.data?.url;
|
|
2460
|
+
const uploadKey = urlPayload.data?.key ?? "";
|
|
2461
|
+
if (!presignedUrl)
|
|
2462
|
+
throw new Error("upload-url response missing `data.url`");
|
|
2463
|
+
const putRes = await fetchImpl(presignedUrl, {
|
|
2464
|
+
method: "PUT",
|
|
2465
|
+
headers: { "content-type": "application/json" },
|
|
2466
|
+
body
|
|
2467
|
+
});
|
|
2468
|
+
if (!putRes.ok) {
|
|
2469
|
+
const text = await putRes.text().catch(() => "");
|
|
2470
|
+
throw new Error(`S3 sidecar PUT failed: HTTP ${putRes.status.toString()} ${text}`);
|
|
2471
|
+
}
|
|
2472
|
+
return {
|
|
2473
|
+
uploaded: true,
|
|
2474
|
+
resolutionCount: req.sidecar.resolutions.length,
|
|
2475
|
+
uploadKey
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
async function uploadSidecarLegacy(req, body, fetchImpl) {
|
|
2479
|
+
const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution`;
|
|
2442
2480
|
const res = await fetchImpl(url, {
|
|
2443
2481
|
method: "POST",
|
|
2444
2482
|
headers: {
|
|
@@ -2551,7 +2589,7 @@ var init_sidecar_client = __esm({
|
|
|
2551
2589
|
"../listener/dist/typed-resolution/sidecar-client.js"() {
|
|
2552
2590
|
"use strict";
|
|
2553
2591
|
init_src();
|
|
2554
|
-
UPLOAD_BODY_BYTE_LIMIT =
|
|
2592
|
+
UPLOAD_BODY_BYTE_LIMIT = 32 * 1024 * 1024;
|
|
2555
2593
|
}
|
|
2556
2594
|
});
|
|
2557
2595
|
|
|
@@ -3015,7 +3053,7 @@ var init_telemetry = __esm({
|
|
|
3015
3053
|
// bin/repowise.ts
|
|
3016
3054
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3017
3055
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3018
|
-
import { dirname as
|
|
3056
|
+
import { dirname as dirname21, join as join60 } from "path";
|
|
3019
3057
|
import { Command } from "commander";
|
|
3020
3058
|
|
|
3021
3059
|
// ../listener/dist/main.js
|
|
@@ -10986,6 +11024,40 @@ async function startListener() {
|
|
|
10986
11024
|
pollCycleCount++;
|
|
10987
11025
|
const shouldReconcile = pollCycleCount % RECONCILE_EVERY_N_CYCLES === 0;
|
|
10988
11026
|
let latestCliVersion;
|
|
11027
|
+
try {
|
|
11028
|
+
const freshRepos = (await getListenerConfig()).repos;
|
|
11029
|
+
const known = /* @__PURE__ */ new Set();
|
|
11030
|
+
for (const g of groups) {
|
|
11031
|
+
for (const id of g.repoLocalPaths.keys())
|
|
11032
|
+
known.add(id);
|
|
11033
|
+
}
|
|
11034
|
+
const newRepos = freshRepos.filter((r) => r.localPath && !known.has(r.repoId));
|
|
11035
|
+
if (newRepos.length > 0) {
|
|
11036
|
+
config2.repos = freshRepos;
|
|
11037
|
+
for (const g of groups) {
|
|
11038
|
+
g.repoIds = freshRepos.filter((r) => (r.apiUrl ?? config2.defaultApiUrl) === g.apiUrl).map((r) => r.repoId);
|
|
11039
|
+
g.repoLocalPaths.clear();
|
|
11040
|
+
for (const r of freshRepos) {
|
|
11041
|
+
if ((r.apiUrl ?? config2.defaultApiUrl) === g.apiUrl) {
|
|
11042
|
+
g.repoLocalPaths.set(r.repoId, r.localPath);
|
|
11043
|
+
}
|
|
11044
|
+
}
|
|
11045
|
+
}
|
|
11046
|
+
if (mcpRuntime) {
|
|
11047
|
+
mcpRuntime.updateRepos(freshRepos.map((r) => ({
|
|
11048
|
+
repoId: r.repoId,
|
|
11049
|
+
apiUrl: r.apiUrl ?? config2.defaultApiUrl,
|
|
11050
|
+
...r.localPath ? { localPath: r.localPath } : {}
|
|
11051
|
+
})));
|
|
11052
|
+
}
|
|
11053
|
+
console.log(`[config-sync] wired ${newRepos.length} newly-registered repo(s)`);
|
|
11054
|
+
if (config2.lspEnabled !== false && config2.lspAutoWarm !== false && mcpRuntime?.lspWorkspaces) {
|
|
11055
|
+
void warmReposLsp(newRepos, mcpRuntime.lspWorkspaces, config2.lspOverrides).catch(() => {
|
|
11056
|
+
});
|
|
11057
|
+
}
|
|
11058
|
+
}
|
|
11059
|
+
} catch {
|
|
11060
|
+
}
|
|
10989
11061
|
for (const group of groups) {
|
|
10990
11062
|
if (!running)
|
|
10991
11063
|
break;
|
|
@@ -11161,6 +11233,20 @@ async function startListener() {
|
|
|
11161
11233
|
} catch (err) {
|
|
11162
11234
|
console.warn("[mcp-config] Reconciliation failed:", err instanceof Error ? err.message : String(err));
|
|
11163
11235
|
}
|
|
11236
|
+
if (mcpRuntime) {
|
|
11237
|
+
try {
|
|
11238
|
+
const polled = await mcpRuntime.pollDownloads();
|
|
11239
|
+
for (const r of polled) {
|
|
11240
|
+
if (r.state === "downloaded") {
|
|
11241
|
+
console.log(`[mcp] Refreshed graph for ${r.repoId} (periodic safety-net)`);
|
|
11242
|
+
} else if (r.state === "error") {
|
|
11243
|
+
console.warn(`[mcp] Periodic graph fetch failed for ${r.repoId}: ${r.message ?? ""}`);
|
|
11244
|
+
}
|
|
11245
|
+
}
|
|
11246
|
+
} catch (err) {
|
|
11247
|
+
console.warn("[mcp] Periodic graph safety-net poll failed:", err instanceof Error ? err.message : String(err));
|
|
11248
|
+
}
|
|
11249
|
+
}
|
|
11164
11250
|
}
|
|
11165
11251
|
if (latestCliVersion && currentVersion && !config2.noAutoUpdate && (state.crashCount ?? 0) < CRASH_LOOP_THRESHOLD) {
|
|
11166
11252
|
if (latestCliVersion !== state.lastUpdateTargetVersion) {
|
|
@@ -11399,8 +11485,8 @@ async function showWelcome(currentVersion) {
|
|
|
11399
11485
|
}
|
|
11400
11486
|
|
|
11401
11487
|
// src/commands/create.ts
|
|
11402
|
-
import { mkdirSync, writeFileSync as
|
|
11403
|
-
import { dirname as
|
|
11488
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11489
|
+
import { dirname as dirname17, join as join48 } from "path";
|
|
11404
11490
|
init_src();
|
|
11405
11491
|
import chalk8 from "chalk";
|
|
11406
11492
|
import ora from "ora";
|
|
@@ -11818,6 +11904,130 @@ function ensureGitignore(repoRoot, entry) {
|
|
|
11818
11904
|
}
|
|
11819
11905
|
}
|
|
11820
11906
|
|
|
11907
|
+
// src/lib/graph-cache.ts
|
|
11908
|
+
init_config_dir();
|
|
11909
|
+
import { mkdirSync, writeFileSync as writeFileSync2, renameSync, unlinkSync } from "fs";
|
|
11910
|
+
import { dirname as dirname16, join as join45 } from "path";
|
|
11911
|
+
var SAFE_REPO_ID = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
11912
|
+
function assertSafeRepoId2(repoId) {
|
|
11913
|
+
if (!repoId || typeof repoId !== "string" || !SAFE_REPO_ID.test(repoId) || repoId === "." || repoId === ".." || repoId.startsWith(".")) {
|
|
11914
|
+
throw new Error(`invalid repoId: ${String(repoId)}`);
|
|
11915
|
+
}
|
|
11916
|
+
}
|
|
11917
|
+
function graphCachePath(repoId) {
|
|
11918
|
+
assertSafeRepoId2(repoId);
|
|
11919
|
+
return join45(getConfigDir(), "graphs", `${repoId}.json`);
|
|
11920
|
+
}
|
|
11921
|
+
function isUsableGraph(parsed) {
|
|
11922
|
+
if (typeof parsed !== "object" || parsed === null) return false;
|
|
11923
|
+
const g = parsed;
|
|
11924
|
+
if (typeof g.commitSha !== "string" || g.commitSha.length === 0) return false;
|
|
11925
|
+
const nodeCount = Array.isArray(g.nodes) ? g.nodes.length : 0;
|
|
11926
|
+
const edgeCount = Array.isArray(g.edges) ? g.edges.length : 0;
|
|
11927
|
+
return nodeCount > 0 || edgeCount > 0;
|
|
11928
|
+
}
|
|
11929
|
+
function readErrorCode(body) {
|
|
11930
|
+
try {
|
|
11931
|
+
const parsed = JSON.parse(body);
|
|
11932
|
+
return parsed.code ?? parsed.error?.code;
|
|
11933
|
+
} catch {
|
|
11934
|
+
return void 0;
|
|
11935
|
+
}
|
|
11936
|
+
}
|
|
11937
|
+
async function ensureGraphDownloaded(opts) {
|
|
11938
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
11939
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
11940
|
+
const maxRetries = opts.maxRetries ?? 3;
|
|
11941
|
+
const sleep2 = opts.sleepFn ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
11942
|
+
let targetPath;
|
|
11943
|
+
try {
|
|
11944
|
+
targetPath = graphCachePath(opts.repoId);
|
|
11945
|
+
} catch (err) {
|
|
11946
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
11947
|
+
}
|
|
11948
|
+
const url = `${opts.apiUrl.replace(/\/+$/, "")}/v1/repos/${encodeURIComponent(opts.repoId)}/graph`;
|
|
11949
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
11950
|
+
const ctrl = new AbortController();
|
|
11951
|
+
const timer = setTimeout(() => {
|
|
11952
|
+
ctrl.abort();
|
|
11953
|
+
}, timeoutMs);
|
|
11954
|
+
let res;
|
|
11955
|
+
try {
|
|
11956
|
+
res = await fetchFn(url, {
|
|
11957
|
+
headers: { Authorization: `Bearer ${opts.accessToken}` },
|
|
11958
|
+
signal: ctrl.signal
|
|
11959
|
+
});
|
|
11960
|
+
} catch (err) {
|
|
11961
|
+
clearTimeout(timer);
|
|
11962
|
+
if (attempt < maxRetries) {
|
|
11963
|
+
await sleep2(2e3 * attempt);
|
|
11964
|
+
continue;
|
|
11965
|
+
}
|
|
11966
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
11967
|
+
}
|
|
11968
|
+
clearTimeout(timer);
|
|
11969
|
+
if (res.status === 404) {
|
|
11970
|
+
let code = "GRAPH_NOT_FOUND";
|
|
11971
|
+
try {
|
|
11972
|
+
const c = readErrorCode(await res.text());
|
|
11973
|
+
if (c) code = c;
|
|
11974
|
+
} catch {
|
|
11975
|
+
}
|
|
11976
|
+
return { status: "not_found", message: code };
|
|
11977
|
+
}
|
|
11978
|
+
if (res.status >= 500) {
|
|
11979
|
+
let code;
|
|
11980
|
+
try {
|
|
11981
|
+
code = readErrorCode(await res.text());
|
|
11982
|
+
} catch {
|
|
11983
|
+
}
|
|
11984
|
+
if (code === "NO_BUCKET" || code === "REPO_NOT_FOUND" || code === "RepoNotFound") {
|
|
11985
|
+
return { status: "misconfig", message: code };
|
|
11986
|
+
}
|
|
11987
|
+
if (attempt < maxRetries) {
|
|
11988
|
+
await sleep2(2e3 * attempt);
|
|
11989
|
+
continue;
|
|
11990
|
+
}
|
|
11991
|
+
return { status: "error", message: `HTTP ${String(res.status)}` };
|
|
11992
|
+
}
|
|
11993
|
+
if (!res.ok) {
|
|
11994
|
+
return { status: "error", message: `HTTP ${String(res.status)}` };
|
|
11995
|
+
}
|
|
11996
|
+
const body = await res.text();
|
|
11997
|
+
let parsed;
|
|
11998
|
+
try {
|
|
11999
|
+
parsed = JSON.parse(body);
|
|
12000
|
+
} catch {
|
|
12001
|
+
if (attempt < maxRetries) {
|
|
12002
|
+
await sleep2(2e3 * attempt);
|
|
12003
|
+
continue;
|
|
12004
|
+
}
|
|
12005
|
+
return { status: "error", message: "graph parse failed" };
|
|
12006
|
+
}
|
|
12007
|
+
if (!isUsableGraph(parsed)) {
|
|
12008
|
+
return { status: "not_found", message: "EMPTY_GRAPH" };
|
|
12009
|
+
}
|
|
12010
|
+
try {
|
|
12011
|
+
mkdirSync(dirname16(targetPath), { recursive: true });
|
|
12012
|
+
const tmp = `${targetPath}.${String(process.pid)}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
12013
|
+
try {
|
|
12014
|
+
writeFileSync2(tmp, body, { encoding: "utf-8", mode: 384 });
|
|
12015
|
+
renameSync(tmp, targetPath);
|
|
12016
|
+
} catch (e) {
|
|
12017
|
+
try {
|
|
12018
|
+
unlinkSync(tmp);
|
|
12019
|
+
} catch {
|
|
12020
|
+
}
|
|
12021
|
+
throw e;
|
|
12022
|
+
}
|
|
12023
|
+
} catch (err) {
|
|
12024
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
12025
|
+
}
|
|
12026
|
+
return { status: "downloaded", bytes: Buffer.byteLength(body) };
|
|
12027
|
+
}
|
|
12028
|
+
return { status: "error", message: "exhausted retries" };
|
|
12029
|
+
}
|
|
12030
|
+
|
|
11821
12031
|
// src/lib/git.ts
|
|
11822
12032
|
import { execSync as execSync2 } from "child_process";
|
|
11823
12033
|
function detectRepoRoot() {
|
|
@@ -12371,7 +12581,7 @@ import chalk6 from "chalk";
|
|
|
12371
12581
|
|
|
12372
12582
|
// src/lib/dep-installer.ts
|
|
12373
12583
|
import { promises as fs21 } from "fs";
|
|
12374
|
-
import { join as
|
|
12584
|
+
import { join as join46 } from "path";
|
|
12375
12585
|
var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
12376
12586
|
"typescript",
|
|
12377
12587
|
"javascript",
|
|
@@ -12388,7 +12598,7 @@ var exists = async (p) => {
|
|
|
12388
12598
|
}
|
|
12389
12599
|
};
|
|
12390
12600
|
async function fileExists16(repoRoot, name) {
|
|
12391
|
-
return exists(
|
|
12601
|
+
return exists(join46(repoRoot, name));
|
|
12392
12602
|
}
|
|
12393
12603
|
async function detectNodePackageManager(repoRoot) {
|
|
12394
12604
|
if (await fileExists16(repoRoot, "pnpm-lock.yaml")) {
|
|
@@ -12466,11 +12676,11 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
|
|
|
12466
12676
|
import { spawn as spawn11 } from "child_process";
|
|
12467
12677
|
import { createWriteStream as createWriteStream3 } from "fs";
|
|
12468
12678
|
import { promises as fs22 } from "fs";
|
|
12469
|
-
import { join as
|
|
12679
|
+
import { join as join47 } from "path";
|
|
12470
12680
|
var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12471
12681
|
async function runMissingDepInstalls(opts) {
|
|
12472
12682
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
12473
|
-
const logPath2 =
|
|
12683
|
+
const logPath2 = join47(getConfigDir2(), `install-log.${safeRepoId}.txt`);
|
|
12474
12684
|
await fs22.mkdir(getConfigDir2(), { recursive: true });
|
|
12475
12685
|
const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
|
|
12476
12686
|
stream.on("error", () => {
|
|
@@ -12517,7 +12727,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
|
|
|
12517
12727
|
}
|
|
12518
12728
|
async function runPipFlow(repoRoot, stream, timeoutMs) {
|
|
12519
12729
|
await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
|
|
12520
|
-
const venvPip = process.platform === "win32" ?
|
|
12730
|
+
const venvPip = process.platform === "win32" ? join47(".venv", "Scripts", "pip.exe") : join47(".venv", "bin", "pip");
|
|
12521
12731
|
await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
|
|
12522
12732
|
}
|
|
12523
12733
|
function runSimple(cmd, repoRoot, stream, timeoutMs) {
|
|
@@ -12684,6 +12894,17 @@ function formatElapsed(ms) {
|
|
|
12684
12894
|
var POLL_INTERVAL_MS = 3e3;
|
|
12685
12895
|
var MAX_POLL_ATTEMPTS = 7200;
|
|
12686
12896
|
var DEFAULT_CONTEXT_FOLDER = "repowise-context";
|
|
12897
|
+
function buildWatchedRepoEntry(args) {
|
|
12898
|
+
const entry = {
|
|
12899
|
+
repoId: args.repoId,
|
|
12900
|
+
localPath: args.localPath,
|
|
12901
|
+
apiUrl: getEnvConfig().apiUrl
|
|
12902
|
+
};
|
|
12903
|
+
if (args.platform) entry.platform = args.platform;
|
|
12904
|
+
if (args.externalId) entry.externalId = args.externalId;
|
|
12905
|
+
if (args.autoInstallDeps !== void 0) entry.autoInstallDeps = args.autoInstallDeps;
|
|
12906
|
+
return entry;
|
|
12907
|
+
}
|
|
12687
12908
|
async function create() {
|
|
12688
12909
|
const startTime = Date.now();
|
|
12689
12910
|
const spinner = ora("Checking authentication...").start();
|
|
@@ -12834,6 +13055,26 @@ async function create() {
|
|
|
12834
13055
|
)
|
|
12835
13056
|
);
|
|
12836
13057
|
}
|
|
13058
|
+
if (repoRoot) {
|
|
13059
|
+
try {
|
|
13060
|
+
const earlyConfig = {
|
|
13061
|
+
aiTools: tools,
|
|
13062
|
+
contextFolder: DEFAULT_CONTEXT_FOLDER,
|
|
13063
|
+
repos: [
|
|
13064
|
+
buildWatchedRepoEntry({
|
|
13065
|
+
repoId,
|
|
13066
|
+
localPath: repoRoot,
|
|
13067
|
+
platform: repoPlatform,
|
|
13068
|
+
externalId: repoExternalId
|
|
13069
|
+
})
|
|
13070
|
+
]
|
|
13071
|
+
};
|
|
13072
|
+
await mergeAndSaveConfig(earlyConfig);
|
|
13073
|
+
await ensureListenerRunning().catch(() => {
|
|
13074
|
+
});
|
|
13075
|
+
} catch {
|
|
13076
|
+
}
|
|
13077
|
+
}
|
|
12837
13078
|
const contextStorage = "server";
|
|
12838
13079
|
spinner.start("Starting context generation pipeline...");
|
|
12839
13080
|
let syncId = "";
|
|
@@ -13028,8 +13269,8 @@ async function create() {
|
|
|
13028
13269
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
13029
13270
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
13030
13271
|
if (files.length > 0) {
|
|
13031
|
-
const contextDir =
|
|
13032
|
-
|
|
13272
|
+
const contextDir = join48(repoRoot, DEFAULT_CONTEXT_FOLDER);
|
|
13273
|
+
mkdirSync2(contextDir, { recursive: true });
|
|
13033
13274
|
let downloadedCount = 0;
|
|
13034
13275
|
let failedCount = 0;
|
|
13035
13276
|
for (const file of files) {
|
|
@@ -13042,9 +13283,9 @@ async function create() {
|
|
|
13042
13283
|
const response = await fetch(presignedUrl);
|
|
13043
13284
|
if (response.ok) {
|
|
13044
13285
|
const content = await response.text();
|
|
13045
|
-
const filePath =
|
|
13046
|
-
|
|
13047
|
-
|
|
13286
|
+
const filePath = join48(contextDir, file.fileName);
|
|
13287
|
+
mkdirSync2(dirname17(filePath), { recursive: true });
|
|
13288
|
+
writeFileSync3(filePath, content, "utf-8");
|
|
13048
13289
|
downloadedCount++;
|
|
13049
13290
|
} else {
|
|
13050
13291
|
failedCount++;
|
|
@@ -13074,6 +13315,44 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13074
13315
|
);
|
|
13075
13316
|
}
|
|
13076
13317
|
}
|
|
13318
|
+
if (repoRoot) {
|
|
13319
|
+
spinner.start("Downloading code graph...");
|
|
13320
|
+
const graphCreds = await getValidCredentials2();
|
|
13321
|
+
if (!graphCreds) {
|
|
13322
|
+
spinner.warn(chalk8.yellow("Skipped code graph \u2014 run `repowise login` and retry."));
|
|
13323
|
+
} else {
|
|
13324
|
+
const graphResult = await ensureGraphDownloaded({
|
|
13325
|
+
repoId,
|
|
13326
|
+
accessToken: graphCreds.accessToken,
|
|
13327
|
+
apiUrl: getEnvConfig().apiUrl
|
|
13328
|
+
});
|
|
13329
|
+
if (graphResult.status === "downloaded") {
|
|
13330
|
+
spinner.succeed("Code graph ready \u2014 MCP enabled.");
|
|
13331
|
+
} else if (graphResult.status === "not_found") {
|
|
13332
|
+
if (graphOnly) {
|
|
13333
|
+
spinner.warn(
|
|
13334
|
+
chalk8.yellow(
|
|
13335
|
+
"Code graph not ready yet \u2014 run `repowise sync` shortly to finish setup."
|
|
13336
|
+
)
|
|
13337
|
+
);
|
|
13338
|
+
} else {
|
|
13339
|
+
spinner.info("Code graph still finishing \u2014 the listener will fetch it shortly.");
|
|
13340
|
+
}
|
|
13341
|
+
} else if (graphResult.status === "misconfig") {
|
|
13342
|
+
spinner.warn(
|
|
13343
|
+
chalk8.yellow(
|
|
13344
|
+
"Code graph unavailable (server configuration). Contact support if this persists."
|
|
13345
|
+
)
|
|
13346
|
+
);
|
|
13347
|
+
} else {
|
|
13348
|
+
spinner.warn(
|
|
13349
|
+
chalk8.yellow(
|
|
13350
|
+
"Could not download the code graph now; the listener will fetch it when ready."
|
|
13351
|
+
)
|
|
13352
|
+
);
|
|
13353
|
+
}
|
|
13354
|
+
}
|
|
13355
|
+
}
|
|
13077
13356
|
const contextFolder = DEFAULT_CONTEXT_FOLDER;
|
|
13078
13357
|
let contextFiles = [];
|
|
13079
13358
|
if (repoRoot) {
|
|
@@ -13127,15 +13406,15 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13127
13406
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
13128
13407
|
const updatedRepos = [];
|
|
13129
13408
|
if (repoRoot) {
|
|
13130
|
-
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13409
|
+
updatedRepos.push(
|
|
13410
|
+
buildWatchedRepoEntry({
|
|
13411
|
+
repoId,
|
|
13412
|
+
localPath: repoRoot,
|
|
13413
|
+
platform: repoPlatform,
|
|
13414
|
+
externalId: repoExternalId,
|
|
13415
|
+
autoInstallDeps: priorAutoInstall
|
|
13416
|
+
})
|
|
13417
|
+
);
|
|
13139
13418
|
}
|
|
13140
13419
|
const configUpdate = { aiTools: tools, contextFolder };
|
|
13141
13420
|
if (updatedRepos.length > 0) configUpdate.repos = updatedRepos;
|
|
@@ -13244,8 +13523,8 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13244
13523
|
}
|
|
13245
13524
|
|
|
13246
13525
|
// src/commands/member.ts
|
|
13247
|
-
import { mkdirSync as
|
|
13248
|
-
import { dirname as
|
|
13526
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
13527
|
+
import { dirname as dirname18, join as join49, resolve, sep } from "path";
|
|
13249
13528
|
import chalk9 from "chalk";
|
|
13250
13529
|
import ora2 from "ora";
|
|
13251
13530
|
var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
|
|
@@ -13399,8 +13678,8 @@ async function member() {
|
|
|
13399
13678
|
spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
|
|
13400
13679
|
const { tools } = await selectAiTools();
|
|
13401
13680
|
spinner.start("Downloading context files...");
|
|
13402
|
-
const contextDir =
|
|
13403
|
-
|
|
13681
|
+
const contextDir = join49(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
13682
|
+
mkdirSync3(contextDir, { recursive: true });
|
|
13404
13683
|
let downloadedCount = 0;
|
|
13405
13684
|
let failedCount = 0;
|
|
13406
13685
|
const resolvedContextDir = resolve(contextDir);
|
|
@@ -13420,8 +13699,8 @@ async function member() {
|
|
|
13420
13699
|
const response = await fetch(presignedUrl);
|
|
13421
13700
|
if (response.ok) {
|
|
13422
13701
|
const content = await response.text();
|
|
13423
|
-
|
|
13424
|
-
|
|
13702
|
+
mkdirSync3(dirname18(safePath), { recursive: true });
|
|
13703
|
+
writeFileSync4(safePath, content, "utf-8");
|
|
13425
13704
|
downloadedCount++;
|
|
13426
13705
|
} else {
|
|
13427
13706
|
failedCount++;
|
|
@@ -13599,9 +13878,9 @@ import ora3 from "ora";
|
|
|
13599
13878
|
// src/lib/tenant-graph-purge.ts
|
|
13600
13879
|
import { promises as fs23 } from "fs";
|
|
13601
13880
|
import { homedir as homedir7 } from "os";
|
|
13602
|
-
import { join as
|
|
13881
|
+
import { join as join50 } from "path";
|
|
13603
13882
|
async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
13604
|
-
const graphsDir =
|
|
13883
|
+
const graphsDir = join50(home, ".repowise", "graphs");
|
|
13605
13884
|
const result = { kept: [], removed: [] };
|
|
13606
13885
|
let entries;
|
|
13607
13886
|
try {
|
|
@@ -13619,7 +13898,7 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
|
13619
13898
|
result.kept.push(entry);
|
|
13620
13899
|
continue;
|
|
13621
13900
|
}
|
|
13622
|
-
const path =
|
|
13901
|
+
const path = join50(graphsDir, entry);
|
|
13623
13902
|
try {
|
|
13624
13903
|
const stat8 = await fs23.lstat(path);
|
|
13625
13904
|
if (stat8.isSymbolicLink()) {
|
|
@@ -13712,11 +13991,11 @@ async function logout() {
|
|
|
13712
13991
|
|
|
13713
13992
|
// src/commands/status.ts
|
|
13714
13993
|
import { readFile as readFile16 } from "fs/promises";
|
|
13715
|
-
import { basename as basename4, join as
|
|
13994
|
+
import { basename as basename4, join as join51 } from "path";
|
|
13716
13995
|
async function status() {
|
|
13717
13996
|
const configDir = getConfigDir2();
|
|
13718
|
-
const STATE_PATH =
|
|
13719
|
-
const CONFIG_PATH =
|
|
13997
|
+
const STATE_PATH = join51(configDir, "listener-state.json");
|
|
13998
|
+
const CONFIG_PATH = join51(configDir, "config.json");
|
|
13720
13999
|
let state = null;
|
|
13721
14000
|
try {
|
|
13722
14001
|
const data = await readFile16(STATE_PATH, "utf-8");
|
|
@@ -13763,8 +14042,8 @@ async function status() {
|
|
|
13763
14042
|
}
|
|
13764
14043
|
|
|
13765
14044
|
// src/commands/sync.ts
|
|
13766
|
-
import { mkdirSync as
|
|
13767
|
-
import { dirname as
|
|
14045
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
14046
|
+
import { dirname as dirname19, join as join52 } from "path";
|
|
13768
14047
|
import chalk12 from "chalk";
|
|
13769
14048
|
import ora4 from "ora";
|
|
13770
14049
|
var POLL_INTERVAL_MS2 = 3e3;
|
|
@@ -13913,8 +14192,8 @@ async function sync() {
|
|
|
13913
14192
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
13914
14193
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
13915
14194
|
if (files.length > 0) {
|
|
13916
|
-
const contextDir =
|
|
13917
|
-
|
|
14195
|
+
const contextDir = join52(repoRoot, DEFAULT_CONTEXT_FOLDER3);
|
|
14196
|
+
mkdirSync4(contextDir, { recursive: true });
|
|
13918
14197
|
let downloadedCount = 0;
|
|
13919
14198
|
let failedCount = 0;
|
|
13920
14199
|
for (const file of files) {
|
|
@@ -13927,9 +14206,9 @@ async function sync() {
|
|
|
13927
14206
|
const response = await fetch(presignedUrl);
|
|
13928
14207
|
if (response.ok) {
|
|
13929
14208
|
const content = await response.text();
|
|
13930
|
-
const filePath =
|
|
13931
|
-
|
|
13932
|
-
|
|
14209
|
+
const filePath = join52(contextDir, file.fileName);
|
|
14210
|
+
mkdirSync4(dirname19(filePath), { recursive: true });
|
|
14211
|
+
writeFileSync5(filePath, content, "utf-8");
|
|
13933
14212
|
downloadedCount++;
|
|
13934
14213
|
} else {
|
|
13935
14214
|
failedCount++;
|
|
@@ -14180,7 +14459,7 @@ async function config() {
|
|
|
14180
14459
|
// src/commands/mcp-log.ts
|
|
14181
14460
|
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
14182
14461
|
import { mkdir as mkdir19, readFile as readFile17, stat as stat7, writeFile as writeFile18 } from "fs/promises";
|
|
14183
|
-
import { dirname as
|
|
14462
|
+
import { dirname as dirname20, join as join53 } from "path";
|
|
14184
14463
|
var FLAG_FILE = "mcp-log.flag";
|
|
14185
14464
|
var LOG_FILE = "mcp-log.jsonl.enc";
|
|
14186
14465
|
var KEY_FILE = "mcp-log.key";
|
|
@@ -14188,14 +14467,14 @@ var ENDPOINT_FILE = "listener.endpoint";
|
|
|
14188
14467
|
var IV_BYTES2 = 12;
|
|
14189
14468
|
var TAG_BYTES2 = 16;
|
|
14190
14469
|
function flagPath() {
|
|
14191
|
-
return
|
|
14470
|
+
return join53(getConfigDir2(), FLAG_FILE);
|
|
14192
14471
|
}
|
|
14193
14472
|
function logPath() {
|
|
14194
|
-
return
|
|
14473
|
+
return join53(getConfigDir2(), LOG_FILE);
|
|
14195
14474
|
}
|
|
14196
14475
|
async function writeFlag(flag) {
|
|
14197
14476
|
const path = flagPath();
|
|
14198
|
-
await mkdir19(
|
|
14477
|
+
await mkdir19(dirname20(path), { recursive: true });
|
|
14199
14478
|
await writeFile18(path, JSON.stringify(flag, null, 2), { encoding: "utf-8", mode: 384 });
|
|
14200
14479
|
}
|
|
14201
14480
|
async function mcpLogOn() {
|
|
@@ -14232,14 +14511,14 @@ async function trySendConsentToServer() {
|
|
|
14232
14511
|
let apiUrl = null;
|
|
14233
14512
|
let token = null;
|
|
14234
14513
|
try {
|
|
14235
|
-
const body = await readFile17(
|
|
14514
|
+
const body = await readFile17(join53(getConfigDir2(), "config.json"), "utf-8");
|
|
14236
14515
|
const parsed = JSON.parse(body);
|
|
14237
14516
|
apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
|
|
14238
14517
|
} catch {
|
|
14239
14518
|
return false;
|
|
14240
14519
|
}
|
|
14241
14520
|
try {
|
|
14242
|
-
const body = await readFile17(
|
|
14521
|
+
const body = await readFile17(join53(getConfigDir2(), "credentials.json"), "utf-8");
|
|
14243
14522
|
const parsed = JSON.parse(body);
|
|
14244
14523
|
token = parsed.idToken ?? null;
|
|
14245
14524
|
} catch {
|
|
@@ -14309,7 +14588,7 @@ async function mcpLogStatus() {
|
|
|
14309
14588
|
process.stderr.write("Log size: no file yet\n");
|
|
14310
14589
|
}
|
|
14311
14590
|
try {
|
|
14312
|
-
const endpointBody = await readFile17(
|
|
14591
|
+
const endpointBody = await readFile17(join53(getConfigDir2(), ENDPOINT_FILE), "utf-8");
|
|
14313
14592
|
const match = /endpoint=([^\n]+)/.exec(endpointBody);
|
|
14314
14593
|
process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
|
|
14315
14594
|
`);
|
|
@@ -14340,7 +14619,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14340
14619
|
const key = await readKey();
|
|
14341
14620
|
if (!key) {
|
|
14342
14621
|
process.stderr.write(
|
|
14343
|
-
`No encryption key at ${
|
|
14622
|
+
`No encryption key at ${join53(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
|
|
14344
14623
|
`
|
|
14345
14624
|
);
|
|
14346
14625
|
return;
|
|
@@ -14416,7 +14695,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14416
14695
|
}
|
|
14417
14696
|
async function readKey() {
|
|
14418
14697
|
try {
|
|
14419
|
-
const body = await readFile17(
|
|
14698
|
+
const body = await readFile17(join53(getConfigDir2(), KEY_FILE), "utf-8");
|
|
14420
14699
|
const parsed = Buffer.from(body.trim(), "base64");
|
|
14421
14700
|
if (parsed.length !== 32) return null;
|
|
14422
14701
|
return parsed;
|
|
@@ -14460,7 +14739,7 @@ import chalk14 from "chalk";
|
|
|
14460
14739
|
|
|
14461
14740
|
// src/lib/graph-loader.ts
|
|
14462
14741
|
import { promises as fs24 } from "fs";
|
|
14463
|
-
import { join as
|
|
14742
|
+
import { join as join54, resolve as resolve2 } from "path";
|
|
14464
14743
|
import { gunzipSync } from "zlib";
|
|
14465
14744
|
var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
|
|
14466
14745
|
var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
|
|
@@ -14477,8 +14756,8 @@ var GraphNotFoundError = class extends Error {
|
|
|
14477
14756
|
var cache = /* @__PURE__ */ new Map();
|
|
14478
14757
|
async function loadGraph(repoRoot = process.cwd()) {
|
|
14479
14758
|
const root = resolve2(repoRoot);
|
|
14480
|
-
const gzPath =
|
|
14481
|
-
const plainPath =
|
|
14759
|
+
const gzPath = join54(root, GZIPPED_GRAPH_PATH);
|
|
14760
|
+
const plainPath = join54(root, RELATIVE_GRAPH_PATH);
|
|
14482
14761
|
const cached = cache.get(root);
|
|
14483
14762
|
if (cached) {
|
|
14484
14763
|
return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
|
|
@@ -14894,12 +15173,12 @@ function registerQueryCommand(program2) {
|
|
|
14894
15173
|
// src/commands/uninstall.ts
|
|
14895
15174
|
import { promises as fs28 } from "fs";
|
|
14896
15175
|
import { homedir as homedir9 } from "os";
|
|
14897
|
-
import { join as
|
|
15176
|
+
import { join as join58 } from "path";
|
|
14898
15177
|
import chalk15 from "chalk";
|
|
14899
15178
|
|
|
14900
15179
|
// src/lib/cleanup/marker-blocks.ts
|
|
14901
15180
|
import { promises as fs25 } from "fs";
|
|
14902
|
-
import { join as
|
|
15181
|
+
import { join as join55 } from "path";
|
|
14903
15182
|
var MARKER_START = "<!-- repowise-start -->";
|
|
14904
15183
|
var MARKER_END = "<!-- repowise-end -->";
|
|
14905
15184
|
var CONTEXT_FILES = [
|
|
@@ -14939,7 +15218,7 @@ async function stripMarkerBlock(filePath) {
|
|
|
14939
15218
|
async function stripAllMarkerBlocks(repoRoot) {
|
|
14940
15219
|
const out = [];
|
|
14941
15220
|
for (const relative of CONTEXT_FILES) {
|
|
14942
|
-
const full =
|
|
15221
|
+
const full = join55(repoRoot, relative);
|
|
14943
15222
|
const result = await stripMarkerBlock(full).catch((err) => ({
|
|
14944
15223
|
path: full,
|
|
14945
15224
|
status: "untouched",
|
|
@@ -14952,18 +15231,18 @@ async function stripAllMarkerBlocks(repoRoot) {
|
|
|
14952
15231
|
|
|
14953
15232
|
// src/lib/cleanup/mcp-configs.ts
|
|
14954
15233
|
import { promises as fs26 } from "fs";
|
|
14955
|
-
import { join as
|
|
15234
|
+
import { join as join56 } from "path";
|
|
14956
15235
|
function mcpConfigPaths(repoRoot, home) {
|
|
14957
15236
|
return [
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
14963
|
-
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
|
|
15237
|
+
join56(repoRoot, ".mcp.json"),
|
|
15238
|
+
join56(repoRoot, ".cursor", "mcp.json"),
|
|
15239
|
+
join56(repoRoot, ".vscode", "mcp.json"),
|
|
15240
|
+
join56(repoRoot, ".roo", "mcp.json"),
|
|
15241
|
+
join56(home, ".cline", "mcp.json"),
|
|
15242
|
+
join56(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
15243
|
+
join56(home, ".gemini", "settings.json"),
|
|
15244
|
+
join56(home, ".codex", "mcp.json"),
|
|
15245
|
+
join56(home, ".roo", "mcp.json")
|
|
14967
15246
|
];
|
|
14968
15247
|
}
|
|
14969
15248
|
async function removeRepowiseFromConfig(path, serverName) {
|
|
@@ -15004,10 +15283,10 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
|
15004
15283
|
// src/lib/cleanup/local-state.ts
|
|
15005
15284
|
import { promises as fs27 } from "fs";
|
|
15006
15285
|
import { homedir as homedir8 } from "os";
|
|
15007
|
-
import { join as
|
|
15286
|
+
import { join as join57, resolve as resolve3 } from "path";
|
|
15008
15287
|
async function clearLocalState(homeOverride) {
|
|
15009
15288
|
const home = homeOverride ?? homedir8();
|
|
15010
|
-
const target = resolve3(
|
|
15289
|
+
const target = resolve3(join57(home, ".repowise"));
|
|
15011
15290
|
if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
|
|
15012
15291
|
return { path: target, status: "error", error: "refused: not under home" };
|
|
15013
15292
|
}
|
|
@@ -15051,7 +15330,7 @@ async function uninstall2(opts = {}) {
|
|
|
15051
15330
|
else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
|
|
15052
15331
|
if (tier === "stop") return report;
|
|
15053
15332
|
try {
|
|
15054
|
-
await fs28.unlink(
|
|
15333
|
+
await fs28.unlink(join58(home, ".repowise", "credentials.json"));
|
|
15055
15334
|
report.removed.push("credentials");
|
|
15056
15335
|
} catch (err) {
|
|
15057
15336
|
if (err.code !== "ENOENT") {
|
|
@@ -15090,7 +15369,7 @@ async function uninstall2(opts = {}) {
|
|
|
15090
15369
|
}
|
|
15091
15370
|
async function defaultLoadRepoIds(home) {
|
|
15092
15371
|
try {
|
|
15093
|
-
const raw = await fs28.readFile(
|
|
15372
|
+
const raw = await fs28.readFile(join58(home, ".repowise", "config.json"), "utf-8");
|
|
15094
15373
|
const parsed = JSON.parse(raw);
|
|
15095
15374
|
return (parsed.repos ?? []).map((r) => r.repoId);
|
|
15096
15375
|
} catch {
|
|
@@ -15139,10 +15418,10 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
|
15139
15418
|
init_config_dir();
|
|
15140
15419
|
import { promises as fs29 } from "fs";
|
|
15141
15420
|
import { createInterface as createInterface2 } from "readline";
|
|
15142
|
-
import { join as
|
|
15421
|
+
import { join as join59 } from "path";
|
|
15143
15422
|
var DEFAULT_MAX = 200 * 1024;
|
|
15144
15423
|
async function mcpShim(opts) {
|
|
15145
|
-
const endpointPath = opts.endpointFile ??
|
|
15424
|
+
const endpointPath = opts.endpointFile ?? join59(getConfigDir(), "listener.endpoint");
|
|
15146
15425
|
const stdin = opts.stdin ?? process.stdin;
|
|
15147
15426
|
const stdout = opts.stdout ?? process.stdout;
|
|
15148
15427
|
const stderr = opts.stderr ?? process.stderr;
|
|
@@ -15890,8 +16169,8 @@ async function lspOn() {
|
|
|
15890
16169
|
|
|
15891
16170
|
// bin/repowise.ts
|
|
15892
16171
|
var __filename = fileURLToPath4(import.meta.url);
|
|
15893
|
-
var __dirname =
|
|
15894
|
-
var pkg = JSON.parse(readFileSync3(
|
|
16172
|
+
var __dirname = dirname21(__filename);
|
|
16173
|
+
var pkg = JSON.parse(readFileSync3(join60(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
15895
16174
|
var program = new Command();
|
|
15896
16175
|
program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
|
|
15897
16176
|
await showWelcome(pkg.version);
|