create-claude-workspace 1.1.77 → 1.1.78

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.
@@ -390,13 +390,16 @@ async function main() {
390
390
  i--; // Retry this iteration
391
391
  continue;
392
392
  }
393
- // Can't parse reset time — stop
394
- checkpoint.consecutiveFailures++;
395
- log.error('Account usage limit reached. Could not parse reset time from output.');
396
- log.error('Restart the loop after your limit resets.');
397
- notify(opts.notifyCommand, 'stopped', 'Account usage limit (unknown reset time)', i);
393
+ // Can't parse reset time — poll every 5 minutes instead of stopping
394
+ const USAGE_POLL_MS = 5 * 60_000;
395
+ log.warn(`Account usage limit reached. Could not parse reset time polling every ${formatDuration(USAGE_POLL_MS)}.`);
396
+ notify(opts.notifyCommand, 'error', `Usage limit polling every ${formatDuration(USAGE_POLL_MS)}`, i);
398
397
  writeCheckpoint(opts.projectDir, checkpoint, log);
399
- break;
398
+ await sleep(USAGE_POLL_MS, stoppingRef);
399
+ if (stopping)
400
+ break;
401
+ i--; // Retry this iteration
402
+ continue;
400
403
  }
401
404
  // Handle stop — try OAuth refresh for auth errors before giving up
402
405
  if (action.type === 'stop') {
@@ -344,6 +344,17 @@ export function runClaude(opts, log, runOpts = {}) {
344
344
  if (event.type === 'rate_limit_event')
345
345
  isRateLimit = true;
346
346
  detectErrorSignals(event);
347
+ // Detect error signals in assistant text content (e.g. "You've hit your limit" as text, not error event)
348
+ if (event.type === 'assistant') {
349
+ const blocks = getContentBlocks(event);
350
+ if (blocks) {
351
+ for (const block of blocks) {
352
+ if (block.type === 'text' && block.text) {
353
+ detectTextSignals(block.text.toLowerCase());
354
+ }
355
+ }
356
+ }
357
+ }
347
358
  // Display
348
359
  const formatted = formatStreamEvent(event);
349
360
  if (formatted)
@@ -7,11 +7,12 @@ import { createInterface } from 'node:readline';
7
7
  // Node.js runtime accepts `true` for shell but @types expects string
8
8
  const SHELL = process.platform === 'win32' ? 'cmd.exe' : '/bin/sh';
9
9
  // ─── Usage limit reset time parser ───
10
- /** Parse "resets Xpm (UTC)" / "resets X:XX AM (UTC)" / "resets HH:MM (UTC)" from stderr text.
11
- * Returns milliseconds to wait, or null if unparseable. */
10
+ /** Parse "resets Xpm (UTC)" / "resets X:XX AM" / "resets 3am" from stderr text.
11
+ * Returns milliseconds to wait, or null if unparseable.
12
+ * Accepts with or without (UTC) — assumes UTC when timezone not specified. */
12
13
  export function parseUsageLimitResetMs(text) {
13
- // Match patterns: "resets 6pm (UTC)", "resets 6:30pm (UTC)", "resets 18:00 (UTC)", "resets 6 PM (UTC)"
14
- const match = text.match(/resets\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\s*\(UTC\)/i);
14
+ // Match patterns: "resets 6pm (UTC)", "resets 6:30pm", "resets 18:00 (UTC)", "resets 6 PM", "resets 3am"
15
+ const match = text.match(/resets\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?(?:\s*\(UTC\))?/i);
15
16
  if (!match)
16
17
  return null;
17
18
  let hours = parseInt(match[1], 10);
@@ -129,8 +129,15 @@ describe('parseUsageLimitResetMs', () => {
129
129
  it('returns null for invalid minutes', () => {
130
130
  expect(parseUsageLimitResetMs('resets 6:99pm (UTC)')).toBeNull();
131
131
  });
132
- it('returns null for no UTC marker', () => {
133
- expect(parseUsageLimitResetMs('resets 6pm')).toBeNull();
132
+ it('parses "resets 6pm" without UTC marker (assumes UTC)', () => {
133
+ const ms = parseUsageLimitResetMs('resets 6pm');
134
+ expect(ms).toBeTypeOf('number');
135
+ expect(ms).toBeGreaterThan(0);
136
+ });
137
+ it('parses "resets 3am" bare format', () => {
138
+ const ms = parseUsageLimitResetMs("You've hit your limit · resets 3am");
139
+ expect(ms).toBeTypeOf('number');
140
+ expect(ms).toBeGreaterThan(0);
134
141
  });
135
142
  it('result is always positive (wraps to next day if time passed)', () => {
136
143
  // Use a time that's definitely in the past today (1am UTC if test runs after 1am)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "1.1.77",
3
+ "version": "1.1.78",
4
4
  "description": "Scaffold a project with Claude Code agents for autonomous AI-driven development",
5
5
  "type": "module",
6
6
  "bin": {