repowisestage 0.0.62 → 0.0.64
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 +347 -74
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -3015,7 +3015,7 @@ var init_telemetry = __esm({
|
|
|
3015
3015
|
// bin/repowise.ts
|
|
3016
3016
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3017
3017
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3018
|
-
import { dirname as
|
|
3018
|
+
import { dirname as dirname21, join as join60 } from "path";
|
|
3019
3019
|
import { Command } from "commander";
|
|
3020
3020
|
|
|
3021
3021
|
// ../listener/dist/main.js
|
|
@@ -10614,6 +10614,28 @@ async function reconcileAgentInstructions(repos) {
|
|
|
10614
10614
|
}
|
|
10615
10615
|
}
|
|
10616
10616
|
}
|
|
10617
|
+
async function reconcileToolConfigs(repos, state) {
|
|
10618
|
+
const toolConfig = await readRawToolConfig();
|
|
10619
|
+
let changed = false;
|
|
10620
|
+
for (const repo of repos) {
|
|
10621
|
+
const before = state.repos[repo.repoId]?.lastToolConfigHash;
|
|
10622
|
+
try {
|
|
10623
|
+
await updateToolConfigsForRepo(repo.localPath, toolConfig, state, repo.repoId);
|
|
10624
|
+
} catch (err) {
|
|
10625
|
+
console.warn(`[ai-tools] reconcile failed for ${repo.repoId}:`, err instanceof Error ? err.message : String(err));
|
|
10626
|
+
continue;
|
|
10627
|
+
}
|
|
10628
|
+
if (state.repos[repo.repoId]?.lastToolConfigHash !== before)
|
|
10629
|
+
changed = true;
|
|
10630
|
+
}
|
|
10631
|
+
if (changed) {
|
|
10632
|
+
try {
|
|
10633
|
+
await saveState(state);
|
|
10634
|
+
} catch (err) {
|
|
10635
|
+
console.warn("[ai-tools] reconcile state save failed:", err instanceof Error ? err.message : String(err));
|
|
10636
|
+
}
|
|
10637
|
+
}
|
|
10638
|
+
}
|
|
10617
10639
|
async function startListener() {
|
|
10618
10640
|
running = true;
|
|
10619
10641
|
installProcessGuards();
|
|
@@ -10828,6 +10850,11 @@ async function startListener() {
|
|
|
10828
10850
|
} catch (err) {
|
|
10829
10851
|
console.warn("[reconcile] Initial agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
|
|
10830
10852
|
}
|
|
10853
|
+
try {
|
|
10854
|
+
await reconcileToolConfigs(config2.repos, state);
|
|
10855
|
+
} catch (err) {
|
|
10856
|
+
console.warn("[ai-tools] Initial tool config reconciliation failed:", err instanceof Error ? err.message : String(err));
|
|
10857
|
+
}
|
|
10831
10858
|
void (async () => {
|
|
10832
10859
|
try {
|
|
10833
10860
|
await reconcileMcpConfigs(config2.repos, packageName);
|
|
@@ -10959,6 +10986,40 @@ async function startListener() {
|
|
|
10959
10986
|
pollCycleCount++;
|
|
10960
10987
|
const shouldReconcile = pollCycleCount % RECONCILE_EVERY_N_CYCLES === 0;
|
|
10961
10988
|
let latestCliVersion;
|
|
10989
|
+
try {
|
|
10990
|
+
const freshRepos = (await getListenerConfig()).repos;
|
|
10991
|
+
const known = /* @__PURE__ */ new Set();
|
|
10992
|
+
for (const g of groups) {
|
|
10993
|
+
for (const id of g.repoLocalPaths.keys())
|
|
10994
|
+
known.add(id);
|
|
10995
|
+
}
|
|
10996
|
+
const newRepos = freshRepos.filter((r) => r.localPath && !known.has(r.repoId));
|
|
10997
|
+
if (newRepos.length > 0) {
|
|
10998
|
+
config2.repos = freshRepos;
|
|
10999
|
+
for (const g of groups) {
|
|
11000
|
+
g.repoIds = freshRepos.filter((r) => (r.apiUrl ?? config2.defaultApiUrl) === g.apiUrl).map((r) => r.repoId);
|
|
11001
|
+
g.repoLocalPaths.clear();
|
|
11002
|
+
for (const r of freshRepos) {
|
|
11003
|
+
if ((r.apiUrl ?? config2.defaultApiUrl) === g.apiUrl) {
|
|
11004
|
+
g.repoLocalPaths.set(r.repoId, r.localPath);
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11007
|
+
}
|
|
11008
|
+
if (mcpRuntime) {
|
|
11009
|
+
mcpRuntime.updateRepos(freshRepos.map((r) => ({
|
|
11010
|
+
repoId: r.repoId,
|
|
11011
|
+
apiUrl: r.apiUrl ?? config2.defaultApiUrl,
|
|
11012
|
+
...r.localPath ? { localPath: r.localPath } : {}
|
|
11013
|
+
})));
|
|
11014
|
+
}
|
|
11015
|
+
console.log(`[config-sync] wired ${newRepos.length} newly-registered repo(s)`);
|
|
11016
|
+
if (config2.lspEnabled !== false && config2.lspAutoWarm !== false && mcpRuntime?.lspWorkspaces) {
|
|
11017
|
+
void warmReposLsp(newRepos, mcpRuntime.lspWorkspaces, config2.lspOverrides).catch(() => {
|
|
11018
|
+
});
|
|
11019
|
+
}
|
|
11020
|
+
}
|
|
11021
|
+
} catch {
|
|
11022
|
+
}
|
|
10962
11023
|
for (const group of groups) {
|
|
10963
11024
|
if (!running)
|
|
10964
11025
|
break;
|
|
@@ -11124,11 +11185,30 @@ async function startListener() {
|
|
|
11124
11185
|
} catch (err) {
|
|
11125
11186
|
console.warn("[reconcile] Agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
|
|
11126
11187
|
}
|
|
11188
|
+
try {
|
|
11189
|
+
await reconcileToolConfigs(config2.repos, state);
|
|
11190
|
+
} catch (err) {
|
|
11191
|
+
console.warn("[ai-tools] Tool config reconciliation failed:", err instanceof Error ? err.message : String(err));
|
|
11192
|
+
}
|
|
11127
11193
|
try {
|
|
11128
11194
|
await reconcileMcpConfigs(config2.repos, packageName);
|
|
11129
11195
|
} catch (err) {
|
|
11130
11196
|
console.warn("[mcp-config] Reconciliation failed:", err instanceof Error ? err.message : String(err));
|
|
11131
11197
|
}
|
|
11198
|
+
if (mcpRuntime) {
|
|
11199
|
+
try {
|
|
11200
|
+
const polled = await mcpRuntime.pollDownloads();
|
|
11201
|
+
for (const r of polled) {
|
|
11202
|
+
if (r.state === "downloaded") {
|
|
11203
|
+
console.log(`[mcp] Refreshed graph for ${r.repoId} (periodic safety-net)`);
|
|
11204
|
+
} else if (r.state === "error") {
|
|
11205
|
+
console.warn(`[mcp] Periodic graph fetch failed for ${r.repoId}: ${r.message ?? ""}`);
|
|
11206
|
+
}
|
|
11207
|
+
}
|
|
11208
|
+
} catch (err) {
|
|
11209
|
+
console.warn("[mcp] Periodic graph safety-net poll failed:", err instanceof Error ? err.message : String(err));
|
|
11210
|
+
}
|
|
11211
|
+
}
|
|
11132
11212
|
}
|
|
11133
11213
|
if (latestCliVersion && currentVersion && !config2.noAutoUpdate && (state.crashCount ?? 0) < CRASH_LOOP_THRESHOLD) {
|
|
11134
11214
|
if (latestCliVersion !== state.lastUpdateTargetVersion) {
|
|
@@ -11367,8 +11447,8 @@ async function showWelcome(currentVersion) {
|
|
|
11367
11447
|
}
|
|
11368
11448
|
|
|
11369
11449
|
// src/commands/create.ts
|
|
11370
|
-
import { mkdirSync, writeFileSync as
|
|
11371
|
-
import { dirname as
|
|
11450
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11451
|
+
import { dirname as dirname17, join as join48 } from "path";
|
|
11372
11452
|
init_src();
|
|
11373
11453
|
import chalk8 from "chalk";
|
|
11374
11454
|
import ora from "ora";
|
|
@@ -11786,6 +11866,130 @@ function ensureGitignore(repoRoot, entry) {
|
|
|
11786
11866
|
}
|
|
11787
11867
|
}
|
|
11788
11868
|
|
|
11869
|
+
// src/lib/graph-cache.ts
|
|
11870
|
+
init_config_dir();
|
|
11871
|
+
import { mkdirSync, writeFileSync as writeFileSync2, renameSync, unlinkSync } from "fs";
|
|
11872
|
+
import { dirname as dirname16, join as join45 } from "path";
|
|
11873
|
+
var SAFE_REPO_ID = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
11874
|
+
function assertSafeRepoId2(repoId) {
|
|
11875
|
+
if (!repoId || typeof repoId !== "string" || !SAFE_REPO_ID.test(repoId) || repoId === "." || repoId === ".." || repoId.startsWith(".")) {
|
|
11876
|
+
throw new Error(`invalid repoId: ${String(repoId)}`);
|
|
11877
|
+
}
|
|
11878
|
+
}
|
|
11879
|
+
function graphCachePath(repoId) {
|
|
11880
|
+
assertSafeRepoId2(repoId);
|
|
11881
|
+
return join45(getConfigDir(), "graphs", `${repoId}.json`);
|
|
11882
|
+
}
|
|
11883
|
+
function isUsableGraph(parsed) {
|
|
11884
|
+
if (typeof parsed !== "object" || parsed === null) return false;
|
|
11885
|
+
const g = parsed;
|
|
11886
|
+
if (typeof g.commitSha !== "string" || g.commitSha.length === 0) return false;
|
|
11887
|
+
const nodeCount = Array.isArray(g.nodes) ? g.nodes.length : 0;
|
|
11888
|
+
const edgeCount = Array.isArray(g.edges) ? g.edges.length : 0;
|
|
11889
|
+
return nodeCount > 0 || edgeCount > 0;
|
|
11890
|
+
}
|
|
11891
|
+
function readErrorCode(body) {
|
|
11892
|
+
try {
|
|
11893
|
+
const parsed = JSON.parse(body);
|
|
11894
|
+
return parsed.code ?? parsed.error?.code;
|
|
11895
|
+
} catch {
|
|
11896
|
+
return void 0;
|
|
11897
|
+
}
|
|
11898
|
+
}
|
|
11899
|
+
async function ensureGraphDownloaded(opts) {
|
|
11900
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
11901
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
11902
|
+
const maxRetries = opts.maxRetries ?? 3;
|
|
11903
|
+
const sleep2 = opts.sleepFn ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
11904
|
+
let targetPath;
|
|
11905
|
+
try {
|
|
11906
|
+
targetPath = graphCachePath(opts.repoId);
|
|
11907
|
+
} catch (err) {
|
|
11908
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
11909
|
+
}
|
|
11910
|
+
const url = `${opts.apiUrl.replace(/\/+$/, "")}/v1/repos/${encodeURIComponent(opts.repoId)}/graph`;
|
|
11911
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
11912
|
+
const ctrl = new AbortController();
|
|
11913
|
+
const timer = setTimeout(() => {
|
|
11914
|
+
ctrl.abort();
|
|
11915
|
+
}, timeoutMs);
|
|
11916
|
+
let res;
|
|
11917
|
+
try {
|
|
11918
|
+
res = await fetchFn(url, {
|
|
11919
|
+
headers: { Authorization: `Bearer ${opts.accessToken}` },
|
|
11920
|
+
signal: ctrl.signal
|
|
11921
|
+
});
|
|
11922
|
+
} catch (err) {
|
|
11923
|
+
clearTimeout(timer);
|
|
11924
|
+
if (attempt < maxRetries) {
|
|
11925
|
+
await sleep2(2e3 * attempt);
|
|
11926
|
+
continue;
|
|
11927
|
+
}
|
|
11928
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
11929
|
+
}
|
|
11930
|
+
clearTimeout(timer);
|
|
11931
|
+
if (res.status === 404) {
|
|
11932
|
+
let code = "GRAPH_NOT_FOUND";
|
|
11933
|
+
try {
|
|
11934
|
+
const c = readErrorCode(await res.text());
|
|
11935
|
+
if (c) code = c;
|
|
11936
|
+
} catch {
|
|
11937
|
+
}
|
|
11938
|
+
return { status: "not_found", message: code };
|
|
11939
|
+
}
|
|
11940
|
+
if (res.status >= 500) {
|
|
11941
|
+
let code;
|
|
11942
|
+
try {
|
|
11943
|
+
code = readErrorCode(await res.text());
|
|
11944
|
+
} catch {
|
|
11945
|
+
}
|
|
11946
|
+
if (code === "NO_BUCKET" || code === "REPO_NOT_FOUND" || code === "RepoNotFound") {
|
|
11947
|
+
return { status: "misconfig", message: code };
|
|
11948
|
+
}
|
|
11949
|
+
if (attempt < maxRetries) {
|
|
11950
|
+
await sleep2(2e3 * attempt);
|
|
11951
|
+
continue;
|
|
11952
|
+
}
|
|
11953
|
+
return { status: "error", message: `HTTP ${String(res.status)}` };
|
|
11954
|
+
}
|
|
11955
|
+
if (!res.ok) {
|
|
11956
|
+
return { status: "error", message: `HTTP ${String(res.status)}` };
|
|
11957
|
+
}
|
|
11958
|
+
const body = await res.text();
|
|
11959
|
+
let parsed;
|
|
11960
|
+
try {
|
|
11961
|
+
parsed = JSON.parse(body);
|
|
11962
|
+
} catch {
|
|
11963
|
+
if (attempt < maxRetries) {
|
|
11964
|
+
await sleep2(2e3 * attempt);
|
|
11965
|
+
continue;
|
|
11966
|
+
}
|
|
11967
|
+
return { status: "error", message: "graph parse failed" };
|
|
11968
|
+
}
|
|
11969
|
+
if (!isUsableGraph(parsed)) {
|
|
11970
|
+
return { status: "not_found", message: "EMPTY_GRAPH" };
|
|
11971
|
+
}
|
|
11972
|
+
try {
|
|
11973
|
+
mkdirSync(dirname16(targetPath), { recursive: true });
|
|
11974
|
+
const tmp = `${targetPath}.${String(process.pid)}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
11975
|
+
try {
|
|
11976
|
+
writeFileSync2(tmp, body, { encoding: "utf-8", mode: 384 });
|
|
11977
|
+
renameSync(tmp, targetPath);
|
|
11978
|
+
} catch (e) {
|
|
11979
|
+
try {
|
|
11980
|
+
unlinkSync(tmp);
|
|
11981
|
+
} catch {
|
|
11982
|
+
}
|
|
11983
|
+
throw e;
|
|
11984
|
+
}
|
|
11985
|
+
} catch (err) {
|
|
11986
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
11987
|
+
}
|
|
11988
|
+
return { status: "downloaded", bytes: Buffer.byteLength(body) };
|
|
11989
|
+
}
|
|
11990
|
+
return { status: "error", message: "exhausted retries" };
|
|
11991
|
+
}
|
|
11992
|
+
|
|
11789
11993
|
// src/lib/git.ts
|
|
11790
11994
|
import { execSync as execSync2 } from "child_process";
|
|
11791
11995
|
function detectRepoRoot() {
|
|
@@ -12339,7 +12543,7 @@ import chalk6 from "chalk";
|
|
|
12339
12543
|
|
|
12340
12544
|
// src/lib/dep-installer.ts
|
|
12341
12545
|
import { promises as fs21 } from "fs";
|
|
12342
|
-
import { join as
|
|
12546
|
+
import { join as join46 } from "path";
|
|
12343
12547
|
var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
12344
12548
|
"typescript",
|
|
12345
12549
|
"javascript",
|
|
@@ -12356,7 +12560,7 @@ var exists = async (p) => {
|
|
|
12356
12560
|
}
|
|
12357
12561
|
};
|
|
12358
12562
|
async function fileExists16(repoRoot, name) {
|
|
12359
|
-
return exists(
|
|
12563
|
+
return exists(join46(repoRoot, name));
|
|
12360
12564
|
}
|
|
12361
12565
|
async function detectNodePackageManager(repoRoot) {
|
|
12362
12566
|
if (await fileExists16(repoRoot, "pnpm-lock.yaml")) {
|
|
@@ -12434,11 +12638,11 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
|
|
|
12434
12638
|
import { spawn as spawn11 } from "child_process";
|
|
12435
12639
|
import { createWriteStream as createWriteStream3 } from "fs";
|
|
12436
12640
|
import { promises as fs22 } from "fs";
|
|
12437
|
-
import { join as
|
|
12641
|
+
import { join as join47 } from "path";
|
|
12438
12642
|
var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12439
12643
|
async function runMissingDepInstalls(opts) {
|
|
12440
12644
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
12441
|
-
const logPath2 =
|
|
12645
|
+
const logPath2 = join47(getConfigDir2(), `install-log.${safeRepoId}.txt`);
|
|
12442
12646
|
await fs22.mkdir(getConfigDir2(), { recursive: true });
|
|
12443
12647
|
const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
|
|
12444
12648
|
stream.on("error", () => {
|
|
@@ -12485,7 +12689,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
|
|
|
12485
12689
|
}
|
|
12486
12690
|
async function runPipFlow(repoRoot, stream, timeoutMs) {
|
|
12487
12691
|
await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
|
|
12488
|
-
const venvPip = process.platform === "win32" ?
|
|
12692
|
+
const venvPip = process.platform === "win32" ? join47(".venv", "Scripts", "pip.exe") : join47(".venv", "bin", "pip");
|
|
12489
12693
|
await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
|
|
12490
12694
|
}
|
|
12491
12695
|
function runSimple(cmd, repoRoot, stream, timeoutMs) {
|
|
@@ -12652,6 +12856,17 @@ function formatElapsed(ms) {
|
|
|
12652
12856
|
var POLL_INTERVAL_MS = 3e3;
|
|
12653
12857
|
var MAX_POLL_ATTEMPTS = 7200;
|
|
12654
12858
|
var DEFAULT_CONTEXT_FOLDER = "repowise-context";
|
|
12859
|
+
function buildWatchedRepoEntry(args) {
|
|
12860
|
+
const entry = {
|
|
12861
|
+
repoId: args.repoId,
|
|
12862
|
+
localPath: args.localPath,
|
|
12863
|
+
apiUrl: getEnvConfig().apiUrl
|
|
12864
|
+
};
|
|
12865
|
+
if (args.platform) entry.platform = args.platform;
|
|
12866
|
+
if (args.externalId) entry.externalId = args.externalId;
|
|
12867
|
+
if (args.autoInstallDeps !== void 0) entry.autoInstallDeps = args.autoInstallDeps;
|
|
12868
|
+
return entry;
|
|
12869
|
+
}
|
|
12655
12870
|
async function create() {
|
|
12656
12871
|
const startTime = Date.now();
|
|
12657
12872
|
const spinner = ora("Checking authentication...").start();
|
|
@@ -12802,6 +13017,26 @@ async function create() {
|
|
|
12802
13017
|
)
|
|
12803
13018
|
);
|
|
12804
13019
|
}
|
|
13020
|
+
if (repoRoot) {
|
|
13021
|
+
try {
|
|
13022
|
+
const earlyConfig = {
|
|
13023
|
+
aiTools: tools,
|
|
13024
|
+
contextFolder: DEFAULT_CONTEXT_FOLDER,
|
|
13025
|
+
repos: [
|
|
13026
|
+
buildWatchedRepoEntry({
|
|
13027
|
+
repoId,
|
|
13028
|
+
localPath: repoRoot,
|
|
13029
|
+
platform: repoPlatform,
|
|
13030
|
+
externalId: repoExternalId
|
|
13031
|
+
})
|
|
13032
|
+
]
|
|
13033
|
+
};
|
|
13034
|
+
await mergeAndSaveConfig(earlyConfig);
|
|
13035
|
+
await ensureListenerRunning().catch(() => {
|
|
13036
|
+
});
|
|
13037
|
+
} catch {
|
|
13038
|
+
}
|
|
13039
|
+
}
|
|
12805
13040
|
const contextStorage = "server";
|
|
12806
13041
|
spinner.start("Starting context generation pipeline...");
|
|
12807
13042
|
let syncId = "";
|
|
@@ -12996,8 +13231,8 @@ async function create() {
|
|
|
12996
13231
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
12997
13232
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
12998
13233
|
if (files.length > 0) {
|
|
12999
|
-
const contextDir =
|
|
13000
|
-
|
|
13234
|
+
const contextDir = join48(repoRoot, DEFAULT_CONTEXT_FOLDER);
|
|
13235
|
+
mkdirSync2(contextDir, { recursive: true });
|
|
13001
13236
|
let downloadedCount = 0;
|
|
13002
13237
|
let failedCount = 0;
|
|
13003
13238
|
for (const file of files) {
|
|
@@ -13010,9 +13245,9 @@ async function create() {
|
|
|
13010
13245
|
const response = await fetch(presignedUrl);
|
|
13011
13246
|
if (response.ok) {
|
|
13012
13247
|
const content = await response.text();
|
|
13013
|
-
const filePath =
|
|
13014
|
-
|
|
13015
|
-
|
|
13248
|
+
const filePath = join48(contextDir, file.fileName);
|
|
13249
|
+
mkdirSync2(dirname17(filePath), { recursive: true });
|
|
13250
|
+
writeFileSync3(filePath, content, "utf-8");
|
|
13016
13251
|
downloadedCount++;
|
|
13017
13252
|
} else {
|
|
13018
13253
|
failedCount++;
|
|
@@ -13042,6 +13277,44 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13042
13277
|
);
|
|
13043
13278
|
}
|
|
13044
13279
|
}
|
|
13280
|
+
if (repoRoot) {
|
|
13281
|
+
spinner.start("Downloading code graph...");
|
|
13282
|
+
const graphCreds = await getValidCredentials2();
|
|
13283
|
+
if (!graphCreds) {
|
|
13284
|
+
spinner.warn(chalk8.yellow("Skipped code graph \u2014 run `repowise login` and retry."));
|
|
13285
|
+
} else {
|
|
13286
|
+
const graphResult = await ensureGraphDownloaded({
|
|
13287
|
+
repoId,
|
|
13288
|
+
accessToken: graphCreds.accessToken,
|
|
13289
|
+
apiUrl: getEnvConfig().apiUrl
|
|
13290
|
+
});
|
|
13291
|
+
if (graphResult.status === "downloaded") {
|
|
13292
|
+
spinner.succeed("Code graph ready \u2014 MCP enabled.");
|
|
13293
|
+
} else if (graphResult.status === "not_found") {
|
|
13294
|
+
if (graphOnly) {
|
|
13295
|
+
spinner.warn(
|
|
13296
|
+
chalk8.yellow(
|
|
13297
|
+
"Code graph not ready yet \u2014 run `repowise sync` shortly to finish setup."
|
|
13298
|
+
)
|
|
13299
|
+
);
|
|
13300
|
+
} else {
|
|
13301
|
+
spinner.info("Code graph still finishing \u2014 the listener will fetch it shortly.");
|
|
13302
|
+
}
|
|
13303
|
+
} else if (graphResult.status === "misconfig") {
|
|
13304
|
+
spinner.warn(
|
|
13305
|
+
chalk8.yellow(
|
|
13306
|
+
"Code graph unavailable (server configuration). Contact support if this persists."
|
|
13307
|
+
)
|
|
13308
|
+
);
|
|
13309
|
+
} else {
|
|
13310
|
+
spinner.warn(
|
|
13311
|
+
chalk8.yellow(
|
|
13312
|
+
"Could not download the code graph now; the listener will fetch it when ready."
|
|
13313
|
+
)
|
|
13314
|
+
);
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
13317
|
+
}
|
|
13045
13318
|
const contextFolder = DEFAULT_CONTEXT_FOLDER;
|
|
13046
13319
|
let contextFiles = [];
|
|
13047
13320
|
if (repoRoot) {
|
|
@@ -13095,15 +13368,15 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13095
13368
|
const priorAutoInstall = await getPriorConsent(repoId);
|
|
13096
13369
|
const updatedRepos = [];
|
|
13097
13370
|
if (repoRoot) {
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13371
|
+
updatedRepos.push(
|
|
13372
|
+
buildWatchedRepoEntry({
|
|
13373
|
+
repoId,
|
|
13374
|
+
localPath: repoRoot,
|
|
13375
|
+
platform: repoPlatform,
|
|
13376
|
+
externalId: repoExternalId,
|
|
13377
|
+
autoInstallDeps: priorAutoInstall
|
|
13378
|
+
})
|
|
13379
|
+
);
|
|
13107
13380
|
}
|
|
13108
13381
|
const configUpdate = { aiTools: tools, contextFolder };
|
|
13109
13382
|
if (updatedRepos.length > 0) configUpdate.repos = updatedRepos;
|
|
@@ -13212,8 +13485,8 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13212
13485
|
}
|
|
13213
13486
|
|
|
13214
13487
|
// src/commands/member.ts
|
|
13215
|
-
import { mkdirSync as
|
|
13216
|
-
import { dirname as
|
|
13488
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
13489
|
+
import { dirname as dirname18, join as join49, resolve, sep } from "path";
|
|
13217
13490
|
import chalk9 from "chalk";
|
|
13218
13491
|
import ora2 from "ora";
|
|
13219
13492
|
var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
|
|
@@ -13367,8 +13640,8 @@ async function member() {
|
|
|
13367
13640
|
spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
|
|
13368
13641
|
const { tools } = await selectAiTools();
|
|
13369
13642
|
spinner.start("Downloading context files...");
|
|
13370
|
-
const contextDir =
|
|
13371
|
-
|
|
13643
|
+
const contextDir = join49(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
13644
|
+
mkdirSync3(contextDir, { recursive: true });
|
|
13372
13645
|
let downloadedCount = 0;
|
|
13373
13646
|
let failedCount = 0;
|
|
13374
13647
|
const resolvedContextDir = resolve(contextDir);
|
|
@@ -13388,8 +13661,8 @@ async function member() {
|
|
|
13388
13661
|
const response = await fetch(presignedUrl);
|
|
13389
13662
|
if (response.ok) {
|
|
13390
13663
|
const content = await response.text();
|
|
13391
|
-
|
|
13392
|
-
|
|
13664
|
+
mkdirSync3(dirname18(safePath), { recursive: true });
|
|
13665
|
+
writeFileSync4(safePath, content, "utf-8");
|
|
13393
13666
|
downloadedCount++;
|
|
13394
13667
|
} else {
|
|
13395
13668
|
failedCount++;
|
|
@@ -13567,9 +13840,9 @@ import ora3 from "ora";
|
|
|
13567
13840
|
// src/lib/tenant-graph-purge.ts
|
|
13568
13841
|
import { promises as fs23 } from "fs";
|
|
13569
13842
|
import { homedir as homedir7 } from "os";
|
|
13570
|
-
import { join as
|
|
13843
|
+
import { join as join50 } from "path";
|
|
13571
13844
|
async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
13572
|
-
const graphsDir =
|
|
13845
|
+
const graphsDir = join50(home, ".repowise", "graphs");
|
|
13573
13846
|
const result = { kept: [], removed: [] };
|
|
13574
13847
|
let entries;
|
|
13575
13848
|
try {
|
|
@@ -13587,7 +13860,7 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
|
13587
13860
|
result.kept.push(entry);
|
|
13588
13861
|
continue;
|
|
13589
13862
|
}
|
|
13590
|
-
const path =
|
|
13863
|
+
const path = join50(graphsDir, entry);
|
|
13591
13864
|
try {
|
|
13592
13865
|
const stat8 = await fs23.lstat(path);
|
|
13593
13866
|
if (stat8.isSymbolicLink()) {
|
|
@@ -13680,11 +13953,11 @@ async function logout() {
|
|
|
13680
13953
|
|
|
13681
13954
|
// src/commands/status.ts
|
|
13682
13955
|
import { readFile as readFile16 } from "fs/promises";
|
|
13683
|
-
import { basename as basename4, join as
|
|
13956
|
+
import { basename as basename4, join as join51 } from "path";
|
|
13684
13957
|
async function status() {
|
|
13685
13958
|
const configDir = getConfigDir2();
|
|
13686
|
-
const STATE_PATH =
|
|
13687
|
-
const CONFIG_PATH =
|
|
13959
|
+
const STATE_PATH = join51(configDir, "listener-state.json");
|
|
13960
|
+
const CONFIG_PATH = join51(configDir, "config.json");
|
|
13688
13961
|
let state = null;
|
|
13689
13962
|
try {
|
|
13690
13963
|
const data = await readFile16(STATE_PATH, "utf-8");
|
|
@@ -13731,8 +14004,8 @@ async function status() {
|
|
|
13731
14004
|
}
|
|
13732
14005
|
|
|
13733
14006
|
// src/commands/sync.ts
|
|
13734
|
-
import { mkdirSync as
|
|
13735
|
-
import { dirname as
|
|
14007
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
14008
|
+
import { dirname as dirname19, join as join52 } from "path";
|
|
13736
14009
|
import chalk12 from "chalk";
|
|
13737
14010
|
import ora4 from "ora";
|
|
13738
14011
|
var POLL_INTERVAL_MS2 = 3e3;
|
|
@@ -13881,8 +14154,8 @@ async function sync() {
|
|
|
13881
14154
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
13882
14155
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
13883
14156
|
if (files.length > 0) {
|
|
13884
|
-
const contextDir =
|
|
13885
|
-
|
|
14157
|
+
const contextDir = join52(repoRoot, DEFAULT_CONTEXT_FOLDER3);
|
|
14158
|
+
mkdirSync4(contextDir, { recursive: true });
|
|
13886
14159
|
let downloadedCount = 0;
|
|
13887
14160
|
let failedCount = 0;
|
|
13888
14161
|
for (const file of files) {
|
|
@@ -13895,9 +14168,9 @@ async function sync() {
|
|
|
13895
14168
|
const response = await fetch(presignedUrl);
|
|
13896
14169
|
if (response.ok) {
|
|
13897
14170
|
const content = await response.text();
|
|
13898
|
-
const filePath =
|
|
13899
|
-
|
|
13900
|
-
|
|
14171
|
+
const filePath = join52(contextDir, file.fileName);
|
|
14172
|
+
mkdirSync4(dirname19(filePath), { recursive: true });
|
|
14173
|
+
writeFileSync5(filePath, content, "utf-8");
|
|
13901
14174
|
downloadedCount++;
|
|
13902
14175
|
} else {
|
|
13903
14176
|
failedCount++;
|
|
@@ -14148,7 +14421,7 @@ async function config() {
|
|
|
14148
14421
|
// src/commands/mcp-log.ts
|
|
14149
14422
|
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
14150
14423
|
import { mkdir as mkdir19, readFile as readFile17, stat as stat7, writeFile as writeFile18 } from "fs/promises";
|
|
14151
|
-
import { dirname as
|
|
14424
|
+
import { dirname as dirname20, join as join53 } from "path";
|
|
14152
14425
|
var FLAG_FILE = "mcp-log.flag";
|
|
14153
14426
|
var LOG_FILE = "mcp-log.jsonl.enc";
|
|
14154
14427
|
var KEY_FILE = "mcp-log.key";
|
|
@@ -14156,14 +14429,14 @@ var ENDPOINT_FILE = "listener.endpoint";
|
|
|
14156
14429
|
var IV_BYTES2 = 12;
|
|
14157
14430
|
var TAG_BYTES2 = 16;
|
|
14158
14431
|
function flagPath() {
|
|
14159
|
-
return
|
|
14432
|
+
return join53(getConfigDir2(), FLAG_FILE);
|
|
14160
14433
|
}
|
|
14161
14434
|
function logPath() {
|
|
14162
|
-
return
|
|
14435
|
+
return join53(getConfigDir2(), LOG_FILE);
|
|
14163
14436
|
}
|
|
14164
14437
|
async function writeFlag(flag) {
|
|
14165
14438
|
const path = flagPath();
|
|
14166
|
-
await mkdir19(
|
|
14439
|
+
await mkdir19(dirname20(path), { recursive: true });
|
|
14167
14440
|
await writeFile18(path, JSON.stringify(flag, null, 2), { encoding: "utf-8", mode: 384 });
|
|
14168
14441
|
}
|
|
14169
14442
|
async function mcpLogOn() {
|
|
@@ -14200,14 +14473,14 @@ async function trySendConsentToServer() {
|
|
|
14200
14473
|
let apiUrl = null;
|
|
14201
14474
|
let token = null;
|
|
14202
14475
|
try {
|
|
14203
|
-
const body = await readFile17(
|
|
14476
|
+
const body = await readFile17(join53(getConfigDir2(), "config.json"), "utf-8");
|
|
14204
14477
|
const parsed = JSON.parse(body);
|
|
14205
14478
|
apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
|
|
14206
14479
|
} catch {
|
|
14207
14480
|
return false;
|
|
14208
14481
|
}
|
|
14209
14482
|
try {
|
|
14210
|
-
const body = await readFile17(
|
|
14483
|
+
const body = await readFile17(join53(getConfigDir2(), "credentials.json"), "utf-8");
|
|
14211
14484
|
const parsed = JSON.parse(body);
|
|
14212
14485
|
token = parsed.idToken ?? null;
|
|
14213
14486
|
} catch {
|
|
@@ -14277,7 +14550,7 @@ async function mcpLogStatus() {
|
|
|
14277
14550
|
process.stderr.write("Log size: no file yet\n");
|
|
14278
14551
|
}
|
|
14279
14552
|
try {
|
|
14280
|
-
const endpointBody = await readFile17(
|
|
14553
|
+
const endpointBody = await readFile17(join53(getConfigDir2(), ENDPOINT_FILE), "utf-8");
|
|
14281
14554
|
const match = /endpoint=([^\n]+)/.exec(endpointBody);
|
|
14282
14555
|
process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
|
|
14283
14556
|
`);
|
|
@@ -14308,7 +14581,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14308
14581
|
const key = await readKey();
|
|
14309
14582
|
if (!key) {
|
|
14310
14583
|
process.stderr.write(
|
|
14311
|
-
`No encryption key at ${
|
|
14584
|
+
`No encryption key at ${join53(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
|
|
14312
14585
|
`
|
|
14313
14586
|
);
|
|
14314
14587
|
return;
|
|
@@ -14384,7 +14657,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14384
14657
|
}
|
|
14385
14658
|
async function readKey() {
|
|
14386
14659
|
try {
|
|
14387
|
-
const body = await readFile17(
|
|
14660
|
+
const body = await readFile17(join53(getConfigDir2(), KEY_FILE), "utf-8");
|
|
14388
14661
|
const parsed = Buffer.from(body.trim(), "base64");
|
|
14389
14662
|
if (parsed.length !== 32) return null;
|
|
14390
14663
|
return parsed;
|
|
@@ -14428,7 +14701,7 @@ import chalk14 from "chalk";
|
|
|
14428
14701
|
|
|
14429
14702
|
// src/lib/graph-loader.ts
|
|
14430
14703
|
import { promises as fs24 } from "fs";
|
|
14431
|
-
import { join as
|
|
14704
|
+
import { join as join54, resolve as resolve2 } from "path";
|
|
14432
14705
|
import { gunzipSync } from "zlib";
|
|
14433
14706
|
var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
|
|
14434
14707
|
var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
|
|
@@ -14445,8 +14718,8 @@ var GraphNotFoundError = class extends Error {
|
|
|
14445
14718
|
var cache = /* @__PURE__ */ new Map();
|
|
14446
14719
|
async function loadGraph(repoRoot = process.cwd()) {
|
|
14447
14720
|
const root = resolve2(repoRoot);
|
|
14448
|
-
const gzPath =
|
|
14449
|
-
const plainPath =
|
|
14721
|
+
const gzPath = join54(root, GZIPPED_GRAPH_PATH);
|
|
14722
|
+
const plainPath = join54(root, RELATIVE_GRAPH_PATH);
|
|
14450
14723
|
const cached = cache.get(root);
|
|
14451
14724
|
if (cached) {
|
|
14452
14725
|
return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
|
|
@@ -14862,12 +15135,12 @@ function registerQueryCommand(program2) {
|
|
|
14862
15135
|
// src/commands/uninstall.ts
|
|
14863
15136
|
import { promises as fs28 } from "fs";
|
|
14864
15137
|
import { homedir as homedir9 } from "os";
|
|
14865
|
-
import { join as
|
|
15138
|
+
import { join as join58 } from "path";
|
|
14866
15139
|
import chalk15 from "chalk";
|
|
14867
15140
|
|
|
14868
15141
|
// src/lib/cleanup/marker-blocks.ts
|
|
14869
15142
|
import { promises as fs25 } from "fs";
|
|
14870
|
-
import { join as
|
|
15143
|
+
import { join as join55 } from "path";
|
|
14871
15144
|
var MARKER_START = "<!-- repowise-start -->";
|
|
14872
15145
|
var MARKER_END = "<!-- repowise-end -->";
|
|
14873
15146
|
var CONTEXT_FILES = [
|
|
@@ -14907,7 +15180,7 @@ async function stripMarkerBlock(filePath) {
|
|
|
14907
15180
|
async function stripAllMarkerBlocks(repoRoot) {
|
|
14908
15181
|
const out = [];
|
|
14909
15182
|
for (const relative of CONTEXT_FILES) {
|
|
14910
|
-
const full =
|
|
15183
|
+
const full = join55(repoRoot, relative);
|
|
14911
15184
|
const result = await stripMarkerBlock(full).catch((err) => ({
|
|
14912
15185
|
path: full,
|
|
14913
15186
|
status: "untouched",
|
|
@@ -14920,18 +15193,18 @@ async function stripAllMarkerBlocks(repoRoot) {
|
|
|
14920
15193
|
|
|
14921
15194
|
// src/lib/cleanup/mcp-configs.ts
|
|
14922
15195
|
import { promises as fs26 } from "fs";
|
|
14923
|
-
import { join as
|
|
15196
|
+
import { join as join56 } from "path";
|
|
14924
15197
|
function mcpConfigPaths(repoRoot, home) {
|
|
14925
15198
|
return [
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
15199
|
+
join56(repoRoot, ".mcp.json"),
|
|
15200
|
+
join56(repoRoot, ".cursor", "mcp.json"),
|
|
15201
|
+
join56(repoRoot, ".vscode", "mcp.json"),
|
|
15202
|
+
join56(repoRoot, ".roo", "mcp.json"),
|
|
15203
|
+
join56(home, ".cline", "mcp.json"),
|
|
15204
|
+
join56(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
15205
|
+
join56(home, ".gemini", "settings.json"),
|
|
15206
|
+
join56(home, ".codex", "mcp.json"),
|
|
15207
|
+
join56(home, ".roo", "mcp.json")
|
|
14935
15208
|
];
|
|
14936
15209
|
}
|
|
14937
15210
|
async function removeRepowiseFromConfig(path, serverName) {
|
|
@@ -14972,10 +15245,10 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
|
14972
15245
|
// src/lib/cleanup/local-state.ts
|
|
14973
15246
|
import { promises as fs27 } from "fs";
|
|
14974
15247
|
import { homedir as homedir8 } from "os";
|
|
14975
|
-
import { join as
|
|
15248
|
+
import { join as join57, resolve as resolve3 } from "path";
|
|
14976
15249
|
async function clearLocalState(homeOverride) {
|
|
14977
15250
|
const home = homeOverride ?? homedir8();
|
|
14978
|
-
const target = resolve3(
|
|
15251
|
+
const target = resolve3(join57(home, ".repowise"));
|
|
14979
15252
|
if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
|
|
14980
15253
|
return { path: target, status: "error", error: "refused: not under home" };
|
|
14981
15254
|
}
|
|
@@ -15019,7 +15292,7 @@ async function uninstall2(opts = {}) {
|
|
|
15019
15292
|
else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
|
|
15020
15293
|
if (tier === "stop") return report;
|
|
15021
15294
|
try {
|
|
15022
|
-
await fs28.unlink(
|
|
15295
|
+
await fs28.unlink(join58(home, ".repowise", "credentials.json"));
|
|
15023
15296
|
report.removed.push("credentials");
|
|
15024
15297
|
} catch (err) {
|
|
15025
15298
|
if (err.code !== "ENOENT") {
|
|
@@ -15058,7 +15331,7 @@ async function uninstall2(opts = {}) {
|
|
|
15058
15331
|
}
|
|
15059
15332
|
async function defaultLoadRepoIds(home) {
|
|
15060
15333
|
try {
|
|
15061
|
-
const raw = await fs28.readFile(
|
|
15334
|
+
const raw = await fs28.readFile(join58(home, ".repowise", "config.json"), "utf-8");
|
|
15062
15335
|
const parsed = JSON.parse(raw);
|
|
15063
15336
|
return (parsed.repos ?? []).map((r) => r.repoId);
|
|
15064
15337
|
} catch {
|
|
@@ -15107,10 +15380,10 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
|
15107
15380
|
init_config_dir();
|
|
15108
15381
|
import { promises as fs29 } from "fs";
|
|
15109
15382
|
import { createInterface as createInterface2 } from "readline";
|
|
15110
|
-
import { join as
|
|
15383
|
+
import { join as join59 } from "path";
|
|
15111
15384
|
var DEFAULT_MAX = 200 * 1024;
|
|
15112
15385
|
async function mcpShim(opts) {
|
|
15113
|
-
const endpointPath = opts.endpointFile ??
|
|
15386
|
+
const endpointPath = opts.endpointFile ?? join59(getConfigDir(), "listener.endpoint");
|
|
15114
15387
|
const stdin = opts.stdin ?? process.stdin;
|
|
15115
15388
|
const stdout = opts.stdout ?? process.stdout;
|
|
15116
15389
|
const stderr = opts.stderr ?? process.stderr;
|
|
@@ -15858,8 +16131,8 @@ async function lspOn() {
|
|
|
15858
16131
|
|
|
15859
16132
|
// bin/repowise.ts
|
|
15860
16133
|
var __filename = fileURLToPath4(import.meta.url);
|
|
15861
|
-
var __dirname =
|
|
15862
|
-
var pkg = JSON.parse(readFileSync3(
|
|
16134
|
+
var __dirname = dirname21(__filename);
|
|
16135
|
+
var pkg = JSON.parse(readFileSync3(join60(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
15863
16136
|
var program = new Command();
|
|
15864
16137
|
program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
|
|
15865
16138
|
await showWelcome(pkg.version);
|