create-claude-workspace 1.1.76 → 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)
@@ -61,13 +61,14 @@ Always prefer `@cibule/*` packages over custom implementations:
61
61
  - NEVER use Node.js-specific APIs (`fs`, `path`, `process`, `Buffer`) in business/domain/api layers
62
62
  - NEVER use Cloudflare-specific APIs (`env.DB`, `ctx.waitUntil()`) in business/domain layers
63
63
  - Platform-specific code lives ONLY in `infrastructure/` layer behind abstract repository interfaces
64
+ - **Platform-specific code MUST be in separate libraries** — NEVER mix Node.js and Cloudflare implementations in the same library. Barrel exports pull both platforms into the bundle, causing compilation errors (e.g. `better-sqlite3` in Cloudflare). Split into: `infrastructure-d1/` (Cloudflare) and `infrastructure-sqlite/` (Node.js). Same applies to shared providers: `shared/infrastructure-d1/` vs `shared/infrastructure-sqlite/`.
64
65
  - Use Web Standard APIs: `fetch`, `Request`, `Response`, `URL`, `crypto`, `TextEncoder`/`TextDecoder`
65
66
  - Hono is inherently platform-agnostic — inject platform bindings via DI, not `c.env` in routes
66
67
  - **OpenAPI-first**: All API routes MUST use `hono-openapi` with `openAPIRouteHandler` — generates OpenAPI spec from TypeBox schemas. Serve API docs via `@scalar/hono-api-reference` at `/reference`. Never define routes without OpenAPI metadata.
67
- - Entry points handle platform wiring:
68
- - Worker entry: exports `default { fetch }` with Hono app + D1 bindings
69
- - Node entry: `serve()` with Hono app + SQLite/better-sqlite3 bindings
70
- - When planning, always structure FILES to keep platform-specific code isolated in infrastructure
68
+ - Entry points handle platform wiring (each imports ONLY its platform's infrastructure library):
69
+ - Worker entry: exports `default { fetch }` with Hono app + D1 bindings → imports `infrastructure-d1`
70
+ - Node entry: `serve()` with Hono app + SQLite/better-sqlite3 bindings → imports `infrastructure-sqlite`
71
+ - When planning, always structure FILES to keep platform-specific code in separate libraries per platform
71
72
 
72
73
  ## Task Approach
73
74
 
@@ -323,9 +323,18 @@ Key rules enforced (do NOT weaken):
323
323
  - NEVER use Cloudflare-specific APIs (`env.DB`, `ctx.waitUntil()`) in business/domain layers
324
324
  - Platform-specific code lives ONLY in `infrastructure/` layer behind abstract interfaces
325
325
  - Use Web Standard APIs where possible: `fetch`, `Request`, `Response`, `URL`, `crypto`, `TextEncoder`/`TextDecoder`, `Headers`, `FormData`, `ReadableStream`
326
- - Database access through repository interfaces (domain layer) — implementations in infrastructure:
327
- - `libs/[domain]/infrastructure/` — D1 implementation (Cloudflare)
328
- - `libs/[domain]/infrastructure/` — SQLite/better-sqlite3 implementation (Node dev)
326
+ - **Platform-specific code MUST be in separate libraries (STRICT)**NEVER mix Node.js and Cloudflare code in the same library. Barrel exports (`index.ts`) would pull both platforms into the bundle, causing compilation errors (e.g. `better-sqlite3` in Cloudflare, or D1 bindings in Node.js):
327
+ ```
328
+ libs/[domain]/
329
+ infrastructure-d1/ # Cloudflare D1 implementation ONLY
330
+ infrastructure-sqlite/ # Node.js SQLite implementation ONLY
331
+ libs/shared/
332
+ infrastructure-d1/ # shared D1 providers (provideD1Database)
333
+ infrastructure-sqlite/ # shared SQLite providers (provideSqliteDatabase)
334
+ ```
335
+ Each entry point imports ONLY its platform's library:
336
+ - Worker entry → `@[PREFIX]/shared-infrastructure-d1`
337
+ - Node entry → `@[PREFIX]/shared-infrastructure-sqlite`
329
338
  - Hono is inherently platform-agnostic — use its standard APIs, avoid `c.env` directly in routes (inject via DI)
330
339
  - Entry points handle platform wiring:
331
340
  - `apps/api/src/main.ts` — Node.js entry (optional, for local dev)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "1.1.76",
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": {