@tigorhutasuhut/claude-retry 0.1.5 → 0.1.6

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/monitor.js +35 -15
  2. package/package.json +1 -1
package/dist/monitor.js CHANGED
@@ -115,8 +115,7 @@ export async function tick(paneId, state, deps, marginSeconds, fallbackHours) {
115
115
  const screenText = await deps.capture(paneId);
116
116
  return stepState(state, screenText, deps.now(), () => deps.inject(paneId, 'continue'), marginSeconds, fallbackHours);
117
117
  }
118
- async function tickTarget(target, state, deps, marginSeconds, fallbackHours, snapshot) {
119
- const screenText = await deps.capture(target);
118
+ async function tickTarget(target, state, screenText, deps, marginSeconds, fallbackHours, snapshot) {
120
119
  return stepState(state, screenText, deps.now(), () => deps.inject(target, 'continue'), marginSeconds, fallbackHours, snapshot, deps.resolvePaneAccount, target, deps.log);
121
120
  }
122
121
  export async function runMonitor(paneId, deps, pollIntervalMs, marginSeconds, fallbackHours) {
@@ -150,16 +149,6 @@ export async function multiTick(states, deps, marginSeconds, fallbackHours) {
150
149
  log('scan failed: could not list sessions/panes (will retry)');
151
150
  return;
152
151
  }
153
- // Fetch account snapshot once per pass (swallow errors → undefined).
154
- let snapshot;
155
- if (deps.getAccountSnapshot !== undefined) {
156
- try {
157
- snapshot = await deps.getAccountSnapshot();
158
- }
159
- catch {
160
- snapshot = undefined;
161
- }
162
- }
163
152
  // Prune state for panes that no longer exist, using miss counter to tolerate
164
153
  // transient list-panes failures.
165
154
  const live = new Set(targets.map((t) => t.label));
@@ -179,7 +168,38 @@ export async function multiTick(states, deps, marginSeconds, fallbackHours) {
179
168
  log(targets.length === 0
180
169
  ? 'scan: no Claude panes found'
181
170
  : `scan: watching ${targets.length} Claude pane(s) [${targets.map((t) => t.label).join(', ')}]`);
171
+ // Capture each target's screen once, collecting successes into a map.
172
+ // Capture failures are logged and that pane is skipped this round.
173
+ const screens = new Map();
174
+ for (const target of targets) {
175
+ try {
176
+ screens.set(target.label, await deps.capture(target));
177
+ }
178
+ catch {
179
+ log(`${target.label} — capture error (skipped this round)`);
180
+ }
181
+ }
182
+ // Decide whether usage API is needed this pass:
183
+ // - any pane already in 'waiting' state (among current targets), OR
184
+ // - any captured screen has a limit banner.
185
+ const anyWaiting = targets.some((t) => states.get(t.label)?.status === 'waiting');
186
+ const anyBanner = [...screens.values()].some((s) => match(s).limited);
187
+ const needUsage = anyWaiting || anyBanner;
188
+ // Fetch account snapshot only when needed (swallow errors → undefined).
189
+ let snapshot;
190
+ if (needUsage && deps.getAccountSnapshot !== undefined) {
191
+ try {
192
+ snapshot = await deps.getAccountSnapshot();
193
+ }
194
+ catch {
195
+ snapshot = undefined;
196
+ }
197
+ }
182
198
  for (const target of targets) {
199
+ const screenText = screens.get(target.label);
200
+ // Skip panes whose capture failed this round.
201
+ if (screenText === undefined)
202
+ continue;
183
203
  let state = states.get(target.label);
184
204
  if (!state) {
185
205
  state = createState();
@@ -190,12 +210,12 @@ export async function multiTick(states, deps, marginSeconds, fallbackHours) {
190
210
  state.missCount = 0;
191
211
  const before = state.status;
192
212
  try {
193
- const status = await tickTarget(target, state, deps, marginSeconds, fallbackHours, snapshot);
213
+ const status = await tickTarget(target, state, screenText, deps, marginSeconds, fallbackHours, snapshot);
194
214
  logPaneStatus(log, target.label, before, state, status);
195
215
  }
196
216
  catch {
197
- // This pane's capture/inject failed — leave its state, keep going.
198
- log(`${target.label} — capture/inject error (skipped this round)`);
217
+ // This pane's inject failed — leave its state, keep going.
218
+ log(`${target.label} — inject error (skipped this round)`);
199
219
  }
200
220
  }
201
221
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tigorhutasuhut/claude-retry",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Monitor Claude CLI in a zellij pane, auto-inject continue on rate-limit",
5
5
  "type": "module",
6
6
  "license": "MIT",