repowisestage 0.0.79 → 0.0.81

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 +131 -72
  2. package/package.json +1 -1
@@ -3172,6 +3172,8 @@ init_config_dir();
3172
3172
  import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir16, stat as fsStat } from "fs/promises";
3173
3173
  import { join as join42, dirname as dirname18 } from "path";
3174
3174
  import { fileURLToPath as fileURLToPath3 } from "url";
3175
+ import { execFile as execFile9 } from "child_process";
3176
+ import { promisify as promisify7 } from "util";
3175
3177
  import lockfile5 from "proper-lockfile";
3176
3178
 
3177
3179
  // ../../packages/shared/dist/lib/ai-tools.js
@@ -6040,6 +6042,16 @@ function createGraphCache(options = {}) {
6040
6042
  clearTimeout(entry.evictTimer);
6041
6043
  delete entry.evictTimer;
6042
6044
  }
6045
+ if (entry.sessionCount > 0) {
6046
+ void loadFromDisk(repoId).then((fresh) => {
6047
+ if (entries.get(repoId) === entry) {
6048
+ entry.graph = fresh.graph;
6049
+ entry.loadedMtime = fresh.loadedMtime;
6050
+ }
6051
+ }, () => {
6052
+ });
6053
+ return;
6054
+ }
6043
6055
  entries.delete(repoId);
6044
6056
  },
6045
6057
  stats() {
@@ -10976,6 +10988,7 @@ async function fetchProducerGraph(apiUrl, authToken, repoId, fetchImpl = fetch)
10976
10988
  // ../listener/dist/typed-resolution/hooks.js
10977
10989
  function buildTypedResolutionHooks(options) {
10978
10990
  const producer = options.producer ?? "repowise-listener/0.0.0";
10991
+ const inFlightProducers = /* @__PURE__ */ new Set();
10979
10992
  async function resolveToken() {
10980
10993
  try {
10981
10994
  return await options.getAuthToken();
@@ -11030,85 +11043,93 @@ function buildTypedResolutionHooks(options) {
11030
11043
  }
11031
11044
  },
11032
11045
  async onGraphReady(repoId, commitSha, localPath) {
11033
- const apiUrl = options.repoApiUrls.get(repoId);
11034
- if (!apiUrl)
11035
- return;
11036
- const token = await resolveToken();
11037
- if (!token)
11046
+ const inFlightKey = `${repoId} ${commitSha}`;
11047
+ if (inFlightProducers.has(inFlightKey))
11038
11048
  return;
11039
- const graph = await fetchProducerGraph(apiUrl, token, repoId);
11040
- const shaMatches = graph !== null && (graph.commitSha === commitSha || graph.commitSha.startsWith(commitSha) || commitSha.startsWith(graph.commitSha));
11041
- if (!graph || !shaMatches) {
11042
- console.warn(`[typed-resolution] graph.ready for ${repoId}@${commitSha.slice(0, 12)} but fetched graph is ${graph ? `at ${graph.commitSha.slice(0, 12)}` : "missing"} \u2014 skipping`);
11043
- return;
11044
- }
11045
- const receivers = graph.unresolvedReceivers ?? [];
11046
- const snapshot = {
11047
- resolvedCount: 0,
11048
- remainingReceivers: receivers.length,
11049
- // Until the first receiver completes, session spawn + server
11050
- // indexing is the activity signal that keeps the wait alive.
11051
- indexingActive: true
11052
- };
11053
- const reporter = createStatusReporter({
11054
- apiUrl,
11055
- repoId,
11056
- commitSha: graph.commitSha,
11057
- getAuthToken: options.getAuthToken,
11058
- ...options.getAuthTokenForceRefresh ? { getAuthTokenForceRefresh: options.getAuthTokenForceRefresh } : {},
11059
- getSnapshot: () => ({ ...snapshot })
11060
- });
11061
- reporter.start();
11062
- let prepared = null;
11049
+ inFlightProducers.add(inFlightKey);
11063
11050
  try {
11064
- if (receivers.length === 0) {
11065
- await reporter.reportCompleted();
11051
+ const apiUrl = options.repoApiUrls.get(repoId);
11052
+ if (!apiUrl)
11066
11053
  return;
11067
- }
11068
- prepared = await prepareCommittedTree(localPath, graph.commitSha);
11069
- if (!prepared) {
11070
- await reporter.reportCrashed();
11054
+ const token = await resolveToken();
11055
+ if (!token)
11056
+ return;
11057
+ const graph = await fetchProducerGraph(apiUrl, token, repoId);
11058
+ const shaMatches = graph !== null && (graph.commitSha === commitSha || graph.commitSha.startsWith(commitSha) || commitSha.startsWith(graph.commitSha));
11059
+ if (!graph || !shaMatches) {
11060
+ console.warn(`[typed-resolution] graph.ready for ${repoId}@${commitSha.slice(0, 12)} but fetched graph is ${graph ? `at ${graph.commitSha.slice(0, 12)}` : "missing"} \u2014 skipping`);
11071
11061
  return;
11072
11062
  }
11073
- const buildResult = await ensureIndexable(prepared.indexRoot, "swift", {
11074
- onActivity: () => {
11075
- snapshot.indexingActive = true;
11076
- }
11077
- });
11078
- if (!buildResult.ready) {
11079
- console.warn(`[typed-resolution] swift build unavailable for ${repoId}: ${buildResult.reason ?? "unknown"} \u2014 continuing without it`);
11080
- }
11081
- const lspOverrides = options.getLspOverrides?.();
11082
- const result = await runProducerCycle({
11063
+ const receivers = graph.unresolvedReceivers ?? [];
11064
+ const snapshot = {
11065
+ resolvedCount: 0,
11066
+ remainingReceivers: receivers.length,
11067
+ // Until the first receiver completes, session spawn + server
11068
+ // indexing is the activity signal that keeps the wait alive.
11069
+ indexingActive: true
11070
+ };
11071
+ const reporter = createStatusReporter({
11083
11072
  apiUrl,
11084
- authToken: token,
11085
11073
  repoId,
11086
- repoRoot: prepared.indexRoot,
11087
- graph,
11088
- workspaces: options.workspaces,
11089
- producer,
11090
- ...lspOverrides ? { lspOverrides } : {},
11091
- onReceiverProcessed: (processed, total, resolvedCount) => {
11092
- snapshot.resolvedCount = resolvedCount;
11093
- snapshot.remainingReceivers = Math.max(0, total - processed);
11094
- snapshot.indexingActive = false;
11095
- }
11074
+ commitSha: graph.commitSha,
11075
+ getAuthToken: options.getAuthToken,
11076
+ ...options.getAuthTokenForceRefresh ? { getAuthTokenForceRefresh: options.getAuthTokenForceRefresh } : {},
11077
+ getSnapshot: () => ({ ...snapshot })
11096
11078
  });
11097
- if (result) {
11098
- await reporter.reportCompleted();
11099
- } else {
11100
- await reporter.reportCrashed();
11101
- }
11102
- } catch (err) {
11103
- console.warn(`[typed-resolution] graph.ready producer failed for ${repoId}: ${err instanceof Error ? err.message : String(err)}`);
11104
- await reporter.reportCrashed().catch(() => void 0);
11105
- } finally {
11106
- reporter.stop();
11107
- if (prepared) {
11108
- await prepared.cleanup().catch((cleanupErr) => {
11109
- console.warn(`[typed-resolution] worktree cleanup failed: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`);
11079
+ reporter.start();
11080
+ let prepared = null;
11081
+ try {
11082
+ if (receivers.length === 0) {
11083
+ await reporter.reportCompleted();
11084
+ return;
11085
+ }
11086
+ prepared = await prepareCommittedTree(localPath, graph.commitSha);
11087
+ if (!prepared) {
11088
+ await reporter.reportCrashed();
11089
+ return;
11090
+ }
11091
+ const buildResult = await ensureIndexable(prepared.indexRoot, "swift", {
11092
+ onActivity: () => {
11093
+ snapshot.indexingActive = true;
11094
+ }
11095
+ });
11096
+ if (!buildResult.ready) {
11097
+ console.warn(`[typed-resolution] swift build unavailable for ${repoId}: ${buildResult.reason ?? "unknown"} \u2014 continuing without it`);
11098
+ }
11099
+ const lspOverrides = options.getLspOverrides?.();
11100
+ const result = await runProducerCycle({
11101
+ apiUrl,
11102
+ authToken: token,
11103
+ repoId,
11104
+ repoRoot: prepared.indexRoot,
11105
+ graph,
11106
+ workspaces: options.workspaces,
11107
+ producer,
11108
+ ...lspOverrides ? { lspOverrides } : {},
11109
+ onReceiverProcessed: (processed, total, resolvedCount) => {
11110
+ snapshot.resolvedCount = resolvedCount;
11111
+ snapshot.remainingReceivers = Math.max(0, total - processed);
11112
+ snapshot.indexingActive = false;
11113
+ }
11110
11114
  });
11115
+ if (result) {
11116
+ await reporter.reportCompleted();
11117
+ } else {
11118
+ await reporter.reportCrashed();
11119
+ }
11120
+ } catch (err) {
11121
+ console.warn(`[typed-resolution] graph.ready producer failed for ${repoId}: ${err instanceof Error ? err.message : String(err)}`);
11122
+ await reporter.reportCrashed().catch(() => void 0);
11123
+ } finally {
11124
+ reporter.stop();
11125
+ if (prepared) {
11126
+ await prepared.cleanup().catch((cleanupErr) => {
11127
+ console.warn(`[typed-resolution] worktree cleanup failed: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`);
11128
+ });
11129
+ }
11111
11130
  }
11131
+ } finally {
11132
+ inFlightProducers.delete(inFlightKey);
11112
11133
  }
11113
11134
  },
11114
11135
  async onSidecarMerged(repoId, commitSha) {
@@ -11132,6 +11153,16 @@ function buildTypedResolutionHooks(options) {
11132
11153
 
11133
11154
  // ../listener/dist/main.js
11134
11155
  var TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1e3;
11156
+ var execFileAsync4 = promisify7(execFile9);
11157
+ async function resolveHeadSha(localPath) {
11158
+ try {
11159
+ const { stdout } = await execFileAsync4("git", ["-C", localPath, "rev-parse", "HEAD"]);
11160
+ const sha = stdout.trim();
11161
+ return /^[0-9a-f]{7,40}$/.test(sha) ? sha : null;
11162
+ } catch {
11163
+ return null;
11164
+ }
11165
+ }
11135
11166
  var STALE_CHECK_COOLDOWN_MS = 60 * 60 * 1e3;
11136
11167
  var CRASH_LOOP_WINDOW_MS = 3e4;
11137
11168
  var CRASH_LOOP_THRESHOLD = 3;
@@ -11526,16 +11557,24 @@ async function handleCatchUp(offlineState, pollClient, repoIds, state, repoLocal
11526
11557
  lastSyncCommitSha: null
11527
11558
  // unknown from catch-up, but timestamp prevents re-download
11528
11559
  };
11560
+ const onGraphReady = typedResolutionHooks?.onGraphReady;
11561
+ if (onGraphReady) {
11562
+ void resolveHeadSha(localPath).then((headSha) => headSha ? onGraphReady(repoId, headSha, localPath) : void 0).catch((err) => {
11563
+ console.warn(`[catch-up] typed-resolution producer failed for ${repoId}: ${err instanceof Error ? err.message : String(err)}`);
11564
+ });
11565
+ }
11529
11566
  }
11530
11567
  }
11531
11568
  await saveState(state);
11532
- notifyBackOnline(syncCount);
11569
+ if (!offlineState.fromRestart)
11570
+ notifyBackOnline(syncCount);
11533
11571
  } else {
11534
11572
  const sinceTimestamp = offlineState.offlineSince;
11535
11573
  const response = await pollClient.poll(repoIds, sinceTimestamp);
11536
11574
  const updateCount = await processNotifications(response.notifications, state, repoLocalPaths, apiUrl, lspWorkspaces, typedResolutionHooks);
11537
11575
  await saveState(state);
11538
- notifyBackOnline(updateCount);
11576
+ if (!offlineState.fromRestart)
11577
+ notifyBackOnline(updateCount);
11539
11578
  }
11540
11579
  }
11541
11580
  async function checkStaleContext(repos, state, groups) {
@@ -11798,13 +11837,20 @@ async function startListener() {
11798
11837
  const apiUrl = repo.apiUrl ?? config2.defaultApiUrl;
11799
11838
  let group = groupMap.get(apiUrl);
11800
11839
  if (!group) {
11840
+ const persistedOfflineSince = state.offlineCursors?.[apiUrl] ?? null;
11801
11841
  group = {
11802
11842
  apiUrl,
11803
11843
  pollClient: new PollClient(apiUrl),
11804
11844
  backoff: new BackoffCalculator(),
11805
11845
  repoIds: [],
11806
11846
  repoLocalPaths: /* @__PURE__ */ new Map(),
11807
- offline: { isOffline: false, offlineSince: null, attemptCount: 0, nextRetryAt: 0 }
11847
+ offline: {
11848
+ isOffline: persistedOfflineSince !== null,
11849
+ offlineSince: persistedOfflineSince,
11850
+ attemptCount: 0,
11851
+ nextRetryAt: 0,
11852
+ fromRestart: persistedOfflineSince !== null
11853
+ }
11808
11854
  };
11809
11855
  groupMap.set(apiUrl, group);
11810
11856
  }
@@ -12223,7 +12269,12 @@ async function startListener() {
12223
12269
  group.offline.offlineSince = null;
12224
12270
  group.offline.attemptCount = 0;
12225
12271
  group.offline.nextRetryAt = 0;
12272
+ group.offline.fromRestart = false;
12226
12273
  group.backoff.reset();
12274
+ if (state.offlineCursors?.[group.apiUrl]) {
12275
+ delete state.offlineCursors[group.apiUrl];
12276
+ await saveState(state);
12277
+ }
12227
12278
  } else if (response.notifications.length > 0) {
12228
12279
  await processNotifications(response.notifications, state, group.repoLocalPaths, group.apiUrl, mcpRuntime?.lspWorkspaces, typedResolutionHooks);
12229
12280
  await saveState(state);
@@ -12264,11 +12315,19 @@ async function startListener() {
12264
12315
  group.offline.isOffline = true;
12265
12316
  group.offline.offlineSince = (/* @__PURE__ */ new Date()).toISOString();
12266
12317
  group.offline.attemptCount = 0;
12318
+ group.offline.fromRestart = false;
12267
12319
  if (!connectionLostNotified) {
12268
12320
  notifyConnectionLost();
12269
12321
  connectionLostNotified = true;
12270
12322
  }
12271
12323
  }
12324
+ if (group.offline.offlineSince) {
12325
+ state.offlineCursors = {
12326
+ ...state.offlineCursors,
12327
+ [group.apiUrl]: group.offline.offlineSince
12328
+ };
12329
+ await saveState(state);
12330
+ }
12272
12331
  group.offline.attemptCount++;
12273
12332
  const delay3 = group.backoff.nextDelay();
12274
12333
  group.offline.nextRetryAt = Date.now() + delay3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repowisestage",
3
- "version": "0.0.79",
3
+ "version": "0.0.81",
4
4
  "type": "module",
5
5
  "description": "AI-optimized codebase context generator",
6
6
  "bin": {