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.
Files changed (2) hide show
  1. package/dist/bin/repowise.js +355 -76
  2. package/package.json +1 -1
@@ -2426,7 +2426,8 @@ __export(sidecar_client_exports, {
2426
2426
  uploadSidecar: () => uploadSidecar
2427
2427
  });
2428
2428
  async function uploadSidecar(req, fetchImpl = fetch) {
2429
- const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution`;
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 = 8 * 1024 * 1024;
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 dirname20, join as join59 } from "path";
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 writeFileSync2 } from "fs";
11403
- import { dirname as dirname16, join as join47 } from "path";
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 join45 } from "path";
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(join45(repoRoot, name));
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 join46 } from "path";
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 = join46(getConfigDir2(), `install-log.${safeRepoId}.txt`);
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" ? join46(".venv", "Scripts", "pip.exe") : join46(".venv", "bin", "pip");
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 = join47(repoRoot, DEFAULT_CONTEXT_FOLDER);
13032
- mkdirSync(contextDir, { recursive: true });
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 = join47(contextDir, file.fileName);
13046
- mkdirSync(dirname16(filePath), { recursive: true });
13047
- writeFileSync2(filePath, content, "utf-8");
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
- const repoEntry = {
13131
- repoId,
13132
- localPath: repoRoot,
13133
- apiUrl: getEnvConfig().apiUrl
13134
- };
13135
- if (repoPlatform) repoEntry.platform = repoPlatform;
13136
- if (repoExternalId) repoEntry.externalId = repoExternalId;
13137
- if (priorAutoInstall !== void 0) repoEntry.autoInstallDeps = priorAutoInstall;
13138
- updatedRepos.push(repoEntry);
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 mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
13248
- import { dirname as dirname17, join as join48, resolve, sep } from "path";
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 = join48(repoRoot, DEFAULT_CONTEXT_FOLDER2);
13403
- mkdirSync2(contextDir, { recursive: true });
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
- mkdirSync2(dirname17(safePath), { recursive: true });
13424
- writeFileSync3(safePath, content, "utf-8");
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 join49 } from "path";
13881
+ import { join as join50 } from "path";
13603
13882
  async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
13604
- const graphsDir = join49(home, ".repowise", "graphs");
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 = join49(graphsDir, entry);
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 join50 } from "path";
13994
+ import { basename as basename4, join as join51 } from "path";
13716
13995
  async function status() {
13717
13996
  const configDir = getConfigDir2();
13718
- const STATE_PATH = join50(configDir, "listener-state.json");
13719
- const CONFIG_PATH = join50(configDir, "config.json");
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 mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
13767
- import { dirname as dirname18, join as join51 } from "path";
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 = join51(repoRoot, DEFAULT_CONTEXT_FOLDER3);
13917
- mkdirSync3(contextDir, { recursive: true });
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 = join51(contextDir, file.fileName);
13931
- mkdirSync3(dirname18(filePath), { recursive: true });
13932
- writeFileSync4(filePath, content, "utf-8");
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 dirname19, join as join52 } from "path";
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 join52(getConfigDir2(), FLAG_FILE);
14470
+ return join53(getConfigDir2(), FLAG_FILE);
14192
14471
  }
14193
14472
  function logPath() {
14194
- return join52(getConfigDir2(), LOG_FILE);
14473
+ return join53(getConfigDir2(), LOG_FILE);
14195
14474
  }
14196
14475
  async function writeFlag(flag) {
14197
14476
  const path = flagPath();
14198
- await mkdir19(dirname19(path), { recursive: true });
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(join52(getConfigDir2(), "config.json"), "utf-8");
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(join52(getConfigDir2(), "credentials.json"), "utf-8");
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(join52(getConfigDir2(), ENDPOINT_FILE), "utf-8");
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 ${join52(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
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(join52(getConfigDir2(), KEY_FILE), "utf-8");
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 join53, resolve as resolve2 } from "path";
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 = join53(root, GZIPPED_GRAPH_PATH);
14481
- const plainPath = join53(root, RELATIVE_GRAPH_PATH);
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 join57 } from "path";
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 join54 } from "path";
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 = join54(repoRoot, relative);
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 join55 } from "path";
15234
+ import { join as join56 } from "path";
14956
15235
  function mcpConfigPaths(repoRoot, home) {
14957
15236
  return [
14958
- join55(repoRoot, ".mcp.json"),
14959
- join55(repoRoot, ".cursor", "mcp.json"),
14960
- join55(repoRoot, ".vscode", "mcp.json"),
14961
- join55(repoRoot, ".roo", "mcp.json"),
14962
- join55(home, ".cline", "mcp.json"),
14963
- join55(home, ".codeium", "windsurf", "mcp_config.json"),
14964
- join55(home, ".gemini", "settings.json"),
14965
- join55(home, ".codex", "mcp.json"),
14966
- join55(home, ".roo", "mcp.json")
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 join56, resolve as resolve3 } from "path";
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(join56(home, ".repowise"));
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(join57(home, ".repowise", "credentials.json"));
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(join57(home, ".repowise", "config.json"), "utf-8");
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 join58 } from "path";
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 ?? join58(getConfigDir(), "listener.endpoint");
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 = dirname20(__filename);
15894
- var pkg = JSON.parse(readFileSync3(join59(__dirname, "..", "..", "package.json"), "utf-8"));
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repowise",
3
- "version": "0.1.91",
3
+ "version": "0.1.93",
4
4
  "type": "module",
5
5
  "description": "AI-optimized codebase context generator",
6
6
  "bin": {