repowise 0.1.91 → 0.1.92

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 +315 -74
  2. package/package.json +1 -1
@@ -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 dirname20, join as join59 } from "path";
3018
+ import { dirname as dirname21, join as join60 } from "path";
3019
3019
  import { Command } from "commander";
3020
3020
 
3021
3021
  // ../listener/dist/main.js
@@ -10986,6 +10986,40 @@ async function startListener() {
10986
10986
  pollCycleCount++;
10987
10987
  const shouldReconcile = pollCycleCount % RECONCILE_EVERY_N_CYCLES === 0;
10988
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
+ }
10989
11023
  for (const group of groups) {
10990
11024
  if (!running)
10991
11025
  break;
@@ -11161,6 +11195,20 @@ async function startListener() {
11161
11195
  } catch (err) {
11162
11196
  console.warn("[mcp-config] Reconciliation failed:", err instanceof Error ? err.message : String(err));
11163
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
+ }
11164
11212
  }
11165
11213
  if (latestCliVersion && currentVersion && !config2.noAutoUpdate && (state.crashCount ?? 0) < CRASH_LOOP_THRESHOLD) {
11166
11214
  if (latestCliVersion !== state.lastUpdateTargetVersion) {
@@ -11399,8 +11447,8 @@ async function showWelcome(currentVersion) {
11399
11447
  }
11400
11448
 
11401
11449
  // src/commands/create.ts
11402
- import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
11403
- import { dirname as dirname16, join as join47 } from "path";
11450
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
11451
+ import { dirname as dirname17, join as join48 } from "path";
11404
11452
  init_src();
11405
11453
  import chalk8 from "chalk";
11406
11454
  import ora from "ora";
@@ -11818,6 +11866,130 @@ function ensureGitignore(repoRoot, entry) {
11818
11866
  }
11819
11867
  }
11820
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
+
11821
11993
  // src/lib/git.ts
11822
11994
  import { execSync as execSync2 } from "child_process";
11823
11995
  function detectRepoRoot() {
@@ -12371,7 +12543,7 @@ import chalk6 from "chalk";
12371
12543
 
12372
12544
  // src/lib/dep-installer.ts
12373
12545
  import { promises as fs21 } from "fs";
12374
- import { join as join45 } from "path";
12546
+ import { join as join46 } from "path";
12375
12547
  var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
12376
12548
  "typescript",
12377
12549
  "javascript",
@@ -12388,7 +12560,7 @@ var exists = async (p) => {
12388
12560
  }
12389
12561
  };
12390
12562
  async function fileExists16(repoRoot, name) {
12391
- return exists(join45(repoRoot, name));
12563
+ return exists(join46(repoRoot, name));
12392
12564
  }
12393
12565
  async function detectNodePackageManager(repoRoot) {
12394
12566
  if (await fileExists16(repoRoot, "pnpm-lock.yaml")) {
@@ -12466,11 +12638,11 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
12466
12638
  import { spawn as spawn11 } from "child_process";
12467
12639
  import { createWriteStream as createWriteStream3 } from "fs";
12468
12640
  import { promises as fs22 } from "fs";
12469
- import { join as join46 } from "path";
12641
+ import { join as join47 } from "path";
12470
12642
  var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
12471
12643
  async function runMissingDepInstalls(opts) {
12472
12644
  const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
12473
- const logPath2 = join46(getConfigDir2(), `install-log.${safeRepoId}.txt`);
12645
+ const logPath2 = join47(getConfigDir2(), `install-log.${safeRepoId}.txt`);
12474
12646
  await fs22.mkdir(getConfigDir2(), { recursive: true });
12475
12647
  const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
12476
12648
  stream.on("error", () => {
@@ -12517,7 +12689,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
12517
12689
  }
12518
12690
  async function runPipFlow(repoRoot, stream, timeoutMs) {
12519
12691
  await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
12520
- const venvPip = process.platform === "win32" ? join46(".venv", "Scripts", "pip.exe") : join46(".venv", "bin", "pip");
12692
+ const venvPip = process.platform === "win32" ? join47(".venv", "Scripts", "pip.exe") : join47(".venv", "bin", "pip");
12521
12693
  await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
12522
12694
  }
12523
12695
  function runSimple(cmd, repoRoot, stream, timeoutMs) {
@@ -12684,6 +12856,17 @@ function formatElapsed(ms) {
12684
12856
  var POLL_INTERVAL_MS = 3e3;
12685
12857
  var MAX_POLL_ATTEMPTS = 7200;
12686
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
+ }
12687
12870
  async function create() {
12688
12871
  const startTime = Date.now();
12689
12872
  const spinner = ora("Checking authentication...").start();
@@ -12834,6 +13017,26 @@ async function create() {
12834
13017
  )
12835
13018
  );
12836
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
+ }
12837
13040
  const contextStorage = "server";
12838
13041
  spinner.start("Starting context generation pipeline...");
12839
13042
  let syncId = "";
@@ -13028,8 +13231,8 @@ async function create() {
13028
13231
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
13029
13232
  const files = listResult.data?.files ?? listResult.files ?? [];
13030
13233
  if (files.length > 0) {
13031
- const contextDir = join47(repoRoot, DEFAULT_CONTEXT_FOLDER);
13032
- mkdirSync(contextDir, { recursive: true });
13234
+ const contextDir = join48(repoRoot, DEFAULT_CONTEXT_FOLDER);
13235
+ mkdirSync2(contextDir, { recursive: true });
13033
13236
  let downloadedCount = 0;
13034
13237
  let failedCount = 0;
13035
13238
  for (const file of files) {
@@ -13042,9 +13245,9 @@ async function create() {
13042
13245
  const response = await fetch(presignedUrl);
13043
13246
  if (response.ok) {
13044
13247
  const content = await response.text();
13045
- const filePath = join47(contextDir, file.fileName);
13046
- mkdirSync(dirname16(filePath), { recursive: true });
13047
- writeFileSync2(filePath, content, "utf-8");
13248
+ const filePath = join48(contextDir, file.fileName);
13249
+ mkdirSync2(dirname17(filePath), { recursive: true });
13250
+ writeFileSync3(filePath, content, "utf-8");
13048
13251
  downloadedCount++;
13049
13252
  } else {
13050
13253
  failedCount++;
@@ -13074,6 +13277,44 @@ Files are stored on our servers (not in git). Retry when online.`
13074
13277
  );
13075
13278
  }
13076
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
+ }
13077
13318
  const contextFolder = DEFAULT_CONTEXT_FOLDER;
13078
13319
  let contextFiles = [];
13079
13320
  if (repoRoot) {
@@ -13127,15 +13368,15 @@ Files are stored on our servers (not in git). Retry when online.`
13127
13368
  const priorAutoInstall = await getPriorConsent(repoId);
13128
13369
  const updatedRepos = [];
13129
13370
  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);
13371
+ updatedRepos.push(
13372
+ buildWatchedRepoEntry({
13373
+ repoId,
13374
+ localPath: repoRoot,
13375
+ platform: repoPlatform,
13376
+ externalId: repoExternalId,
13377
+ autoInstallDeps: priorAutoInstall
13378
+ })
13379
+ );
13139
13380
  }
13140
13381
  const configUpdate = { aiTools: tools, contextFolder };
13141
13382
  if (updatedRepos.length > 0) configUpdate.repos = updatedRepos;
@@ -13244,8 +13485,8 @@ Files are stored on our servers (not in git). Retry when online.`
13244
13485
  }
13245
13486
 
13246
13487
  // 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";
13488
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
13489
+ import { dirname as dirname18, join as join49, resolve, sep } from "path";
13249
13490
  import chalk9 from "chalk";
13250
13491
  import ora2 from "ora";
13251
13492
  var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
@@ -13399,8 +13640,8 @@ async function member() {
13399
13640
  spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
13400
13641
  const { tools } = await selectAiTools();
13401
13642
  spinner.start("Downloading context files...");
13402
- const contextDir = join48(repoRoot, DEFAULT_CONTEXT_FOLDER2);
13403
- mkdirSync2(contextDir, { recursive: true });
13643
+ const contextDir = join49(repoRoot, DEFAULT_CONTEXT_FOLDER2);
13644
+ mkdirSync3(contextDir, { recursive: true });
13404
13645
  let downloadedCount = 0;
13405
13646
  let failedCount = 0;
13406
13647
  const resolvedContextDir = resolve(contextDir);
@@ -13420,8 +13661,8 @@ async function member() {
13420
13661
  const response = await fetch(presignedUrl);
13421
13662
  if (response.ok) {
13422
13663
  const content = await response.text();
13423
- mkdirSync2(dirname17(safePath), { recursive: true });
13424
- writeFileSync3(safePath, content, "utf-8");
13664
+ mkdirSync3(dirname18(safePath), { recursive: true });
13665
+ writeFileSync4(safePath, content, "utf-8");
13425
13666
  downloadedCount++;
13426
13667
  } else {
13427
13668
  failedCount++;
@@ -13599,9 +13840,9 @@ import ora3 from "ora";
13599
13840
  // src/lib/tenant-graph-purge.ts
13600
13841
  import { promises as fs23 } from "fs";
13601
13842
  import { homedir as homedir7 } from "os";
13602
- import { join as join49 } from "path";
13843
+ import { join as join50 } from "path";
13603
13844
  async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
13604
- const graphsDir = join49(home, ".repowise", "graphs");
13845
+ const graphsDir = join50(home, ".repowise", "graphs");
13605
13846
  const result = { kept: [], removed: [] };
13606
13847
  let entries;
13607
13848
  try {
@@ -13619,7 +13860,7 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
13619
13860
  result.kept.push(entry);
13620
13861
  continue;
13621
13862
  }
13622
- const path = join49(graphsDir, entry);
13863
+ const path = join50(graphsDir, entry);
13623
13864
  try {
13624
13865
  const stat8 = await fs23.lstat(path);
13625
13866
  if (stat8.isSymbolicLink()) {
@@ -13712,11 +13953,11 @@ async function logout() {
13712
13953
 
13713
13954
  // src/commands/status.ts
13714
13955
  import { readFile as readFile16 } from "fs/promises";
13715
- import { basename as basename4, join as join50 } from "path";
13956
+ import { basename as basename4, join as join51 } from "path";
13716
13957
  async function status() {
13717
13958
  const configDir = getConfigDir2();
13718
- const STATE_PATH = join50(configDir, "listener-state.json");
13719
- const CONFIG_PATH = join50(configDir, "config.json");
13959
+ const STATE_PATH = join51(configDir, "listener-state.json");
13960
+ const CONFIG_PATH = join51(configDir, "config.json");
13720
13961
  let state = null;
13721
13962
  try {
13722
13963
  const data = await readFile16(STATE_PATH, "utf-8");
@@ -13763,8 +14004,8 @@ async function status() {
13763
14004
  }
13764
14005
 
13765
14006
  // src/commands/sync.ts
13766
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
13767
- import { dirname as dirname18, join as join51 } from "path";
14007
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
14008
+ import { dirname as dirname19, join as join52 } from "path";
13768
14009
  import chalk12 from "chalk";
13769
14010
  import ora4 from "ora";
13770
14011
  var POLL_INTERVAL_MS2 = 3e3;
@@ -13913,8 +14154,8 @@ async function sync() {
13913
14154
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
13914
14155
  const files = listResult.data?.files ?? listResult.files ?? [];
13915
14156
  if (files.length > 0) {
13916
- const contextDir = join51(repoRoot, DEFAULT_CONTEXT_FOLDER3);
13917
- mkdirSync3(contextDir, { recursive: true });
14157
+ const contextDir = join52(repoRoot, DEFAULT_CONTEXT_FOLDER3);
14158
+ mkdirSync4(contextDir, { recursive: true });
13918
14159
  let downloadedCount = 0;
13919
14160
  let failedCount = 0;
13920
14161
  for (const file of files) {
@@ -13927,9 +14168,9 @@ async function sync() {
13927
14168
  const response = await fetch(presignedUrl);
13928
14169
  if (response.ok) {
13929
14170
  const content = await response.text();
13930
- const filePath = join51(contextDir, file.fileName);
13931
- mkdirSync3(dirname18(filePath), { recursive: true });
13932
- writeFileSync4(filePath, content, "utf-8");
14171
+ const filePath = join52(contextDir, file.fileName);
14172
+ mkdirSync4(dirname19(filePath), { recursive: true });
14173
+ writeFileSync5(filePath, content, "utf-8");
13933
14174
  downloadedCount++;
13934
14175
  } else {
13935
14176
  failedCount++;
@@ -14180,7 +14421,7 @@ async function config() {
14180
14421
  // src/commands/mcp-log.ts
14181
14422
  import { createDecipheriv as createDecipheriv2 } from "crypto";
14182
14423
  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";
14424
+ import { dirname as dirname20, join as join53 } from "path";
14184
14425
  var FLAG_FILE = "mcp-log.flag";
14185
14426
  var LOG_FILE = "mcp-log.jsonl.enc";
14186
14427
  var KEY_FILE = "mcp-log.key";
@@ -14188,14 +14429,14 @@ var ENDPOINT_FILE = "listener.endpoint";
14188
14429
  var IV_BYTES2 = 12;
14189
14430
  var TAG_BYTES2 = 16;
14190
14431
  function flagPath() {
14191
- return join52(getConfigDir2(), FLAG_FILE);
14432
+ return join53(getConfigDir2(), FLAG_FILE);
14192
14433
  }
14193
14434
  function logPath() {
14194
- return join52(getConfigDir2(), LOG_FILE);
14435
+ return join53(getConfigDir2(), LOG_FILE);
14195
14436
  }
14196
14437
  async function writeFlag(flag) {
14197
14438
  const path = flagPath();
14198
- await mkdir19(dirname19(path), { recursive: true });
14439
+ await mkdir19(dirname20(path), { recursive: true });
14199
14440
  await writeFile18(path, JSON.stringify(flag, null, 2), { encoding: "utf-8", mode: 384 });
14200
14441
  }
14201
14442
  async function mcpLogOn() {
@@ -14232,14 +14473,14 @@ async function trySendConsentToServer() {
14232
14473
  let apiUrl = null;
14233
14474
  let token = null;
14234
14475
  try {
14235
- const body = await readFile17(join52(getConfigDir2(), "config.json"), "utf-8");
14476
+ const body = await readFile17(join53(getConfigDir2(), "config.json"), "utf-8");
14236
14477
  const parsed = JSON.parse(body);
14237
14478
  apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
14238
14479
  } catch {
14239
14480
  return false;
14240
14481
  }
14241
14482
  try {
14242
- const body = await readFile17(join52(getConfigDir2(), "credentials.json"), "utf-8");
14483
+ const body = await readFile17(join53(getConfigDir2(), "credentials.json"), "utf-8");
14243
14484
  const parsed = JSON.parse(body);
14244
14485
  token = parsed.idToken ?? null;
14245
14486
  } catch {
@@ -14309,7 +14550,7 @@ async function mcpLogStatus() {
14309
14550
  process.stderr.write("Log size: no file yet\n");
14310
14551
  }
14311
14552
  try {
14312
- const endpointBody = await readFile17(join52(getConfigDir2(), ENDPOINT_FILE), "utf-8");
14553
+ const endpointBody = await readFile17(join53(getConfigDir2(), ENDPOINT_FILE), "utf-8");
14313
14554
  const match = /endpoint=([^\n]+)/.exec(endpointBody);
14314
14555
  process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
14315
14556
  `);
@@ -14340,7 +14581,7 @@ async function mcpLogViewingFlags(flags = {}) {
14340
14581
  const key = await readKey();
14341
14582
  if (!key) {
14342
14583
  process.stderr.write(
14343
- `No encryption key at ${join52(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
14584
+ `No encryption key at ${join53(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
14344
14585
  `
14345
14586
  );
14346
14587
  return;
@@ -14416,7 +14657,7 @@ async function mcpLogViewingFlags(flags = {}) {
14416
14657
  }
14417
14658
  async function readKey() {
14418
14659
  try {
14419
- const body = await readFile17(join52(getConfigDir2(), KEY_FILE), "utf-8");
14660
+ const body = await readFile17(join53(getConfigDir2(), KEY_FILE), "utf-8");
14420
14661
  const parsed = Buffer.from(body.trim(), "base64");
14421
14662
  if (parsed.length !== 32) return null;
14422
14663
  return parsed;
@@ -14460,7 +14701,7 @@ import chalk14 from "chalk";
14460
14701
 
14461
14702
  // src/lib/graph-loader.ts
14462
14703
  import { promises as fs24 } from "fs";
14463
- import { join as join53, resolve as resolve2 } from "path";
14704
+ import { join as join54, resolve as resolve2 } from "path";
14464
14705
  import { gunzipSync } from "zlib";
14465
14706
  var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
14466
14707
  var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
@@ -14477,8 +14718,8 @@ var GraphNotFoundError = class extends Error {
14477
14718
  var cache = /* @__PURE__ */ new Map();
14478
14719
  async function loadGraph(repoRoot = process.cwd()) {
14479
14720
  const root = resolve2(repoRoot);
14480
- const gzPath = join53(root, GZIPPED_GRAPH_PATH);
14481
- const plainPath = join53(root, RELATIVE_GRAPH_PATH);
14721
+ const gzPath = join54(root, GZIPPED_GRAPH_PATH);
14722
+ const plainPath = join54(root, RELATIVE_GRAPH_PATH);
14482
14723
  const cached = cache.get(root);
14483
14724
  if (cached) {
14484
14725
  return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
@@ -14894,12 +15135,12 @@ function registerQueryCommand(program2) {
14894
15135
  // src/commands/uninstall.ts
14895
15136
  import { promises as fs28 } from "fs";
14896
15137
  import { homedir as homedir9 } from "os";
14897
- import { join as join57 } from "path";
15138
+ import { join as join58 } from "path";
14898
15139
  import chalk15 from "chalk";
14899
15140
 
14900
15141
  // src/lib/cleanup/marker-blocks.ts
14901
15142
  import { promises as fs25 } from "fs";
14902
- import { join as join54 } from "path";
15143
+ import { join as join55 } from "path";
14903
15144
  var MARKER_START = "<!-- repowise-start -->";
14904
15145
  var MARKER_END = "<!-- repowise-end -->";
14905
15146
  var CONTEXT_FILES = [
@@ -14939,7 +15180,7 @@ async function stripMarkerBlock(filePath) {
14939
15180
  async function stripAllMarkerBlocks(repoRoot) {
14940
15181
  const out = [];
14941
15182
  for (const relative of CONTEXT_FILES) {
14942
- const full = join54(repoRoot, relative);
15183
+ const full = join55(repoRoot, relative);
14943
15184
  const result = await stripMarkerBlock(full).catch((err) => ({
14944
15185
  path: full,
14945
15186
  status: "untouched",
@@ -14952,18 +15193,18 @@ async function stripAllMarkerBlocks(repoRoot) {
14952
15193
 
14953
15194
  // src/lib/cleanup/mcp-configs.ts
14954
15195
  import { promises as fs26 } from "fs";
14955
- import { join as join55 } from "path";
15196
+ import { join as join56 } from "path";
14956
15197
  function mcpConfigPaths(repoRoot, home) {
14957
15198
  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")
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")
14967
15208
  ];
14968
15209
  }
14969
15210
  async function removeRepowiseFromConfig(path, serverName) {
@@ -15004,10 +15245,10 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
15004
15245
  // src/lib/cleanup/local-state.ts
15005
15246
  import { promises as fs27 } from "fs";
15006
15247
  import { homedir as homedir8 } from "os";
15007
- import { join as join56, resolve as resolve3 } from "path";
15248
+ import { join as join57, resolve as resolve3 } from "path";
15008
15249
  async function clearLocalState(homeOverride) {
15009
15250
  const home = homeOverride ?? homedir8();
15010
- const target = resolve3(join56(home, ".repowise"));
15251
+ const target = resolve3(join57(home, ".repowise"));
15011
15252
  if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
15012
15253
  return { path: target, status: "error", error: "refused: not under home" };
15013
15254
  }
@@ -15051,7 +15292,7 @@ async function uninstall2(opts = {}) {
15051
15292
  else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
15052
15293
  if (tier === "stop") return report;
15053
15294
  try {
15054
- await fs28.unlink(join57(home, ".repowise", "credentials.json"));
15295
+ await fs28.unlink(join58(home, ".repowise", "credentials.json"));
15055
15296
  report.removed.push("credentials");
15056
15297
  } catch (err) {
15057
15298
  if (err.code !== "ENOENT") {
@@ -15090,7 +15331,7 @@ async function uninstall2(opts = {}) {
15090
15331
  }
15091
15332
  async function defaultLoadRepoIds(home) {
15092
15333
  try {
15093
- const raw = await fs28.readFile(join57(home, ".repowise", "config.json"), "utf-8");
15334
+ const raw = await fs28.readFile(join58(home, ".repowise", "config.json"), "utf-8");
15094
15335
  const parsed = JSON.parse(raw);
15095
15336
  return (parsed.repos ?? []).map((r) => r.repoId);
15096
15337
  } catch {
@@ -15139,10 +15380,10 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
15139
15380
  init_config_dir();
15140
15381
  import { promises as fs29 } from "fs";
15141
15382
  import { createInterface as createInterface2 } from "readline";
15142
- import { join as join58 } from "path";
15383
+ import { join as join59 } from "path";
15143
15384
  var DEFAULT_MAX = 200 * 1024;
15144
15385
  async function mcpShim(opts) {
15145
- const endpointPath = opts.endpointFile ?? join58(getConfigDir(), "listener.endpoint");
15386
+ const endpointPath = opts.endpointFile ?? join59(getConfigDir(), "listener.endpoint");
15146
15387
  const stdin = opts.stdin ?? process.stdin;
15147
15388
  const stdout = opts.stdout ?? process.stdout;
15148
15389
  const stderr = opts.stderr ?? process.stderr;
@@ -15890,8 +16131,8 @@ async function lspOn() {
15890
16131
 
15891
16132
  // bin/repowise.ts
15892
16133
  var __filename = fileURLToPath4(import.meta.url);
15893
- var __dirname = dirname20(__filename);
15894
- var pkg = JSON.parse(readFileSync3(join59(__dirname, "..", "..", "package.json"), "utf-8"));
16134
+ var __dirname = dirname21(__filename);
16135
+ var pkg = JSON.parse(readFileSync3(join60(__dirname, "..", "..", "package.json"), "utf-8"));
15895
16136
  var program = new Command();
15896
16137
  program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
15897
16138
  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.92",
4
4
  "type": "module",
5
5
  "description": "AI-optimized codebase context generator",
6
6
  "bin": {