create-claude-cabinet 0.29.0 → 0.29.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-cabinet",
3
- "version": "0.29.0",
3
+ "version": "0.29.2",
4
4
  "description": "Claude Cabinet — opinionated process scaffolding for Claude Code projects",
5
5
  "bin": {
6
6
  "create-claude-cabinet": "bin/create-claude-cabinet.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-cabinet/site-audit",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Comprehensive deployed-site quality audit engine for Claude Cabinet. Runs checks across performance, accessibility, security, SEO, content, DNS, and privacy against a deployed URL; single-site and comparison modes; standalone HTML report.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -286,24 +286,41 @@ the skill handles all `e2e/` directory navigation internally.** No
286
286
  on macOS — Playwright inherits display access) and human verdicts
287
287
  (file-based IPC when stdin is not a TTY).
288
288
 
289
+ **Progress streaming:** Immediately after starting the background
290
+ command, arm a Monitor on the progress file:
291
+
292
+ ```
293
+ Monitor({
294
+ description: "verify progress",
295
+ command: "tail -f e2e/.verify-progress.jsonl | grep -E --line-buffered 'check-fail|scenario-start|scenario-end|run-end|verdict-pending'",
296
+ persistent: true
297
+ })
298
+ ```
299
+
300
+ This streams scenario starts, failures, and verdict requests as
301
+ real-time conversation notifications. Check passes are filtered
302
+ out to avoid noise. When a `verdict-pending` event arrives,
303
+ handle it immediately (see below).
304
+
289
305
  **Human verdict orchestration:** When the runtime hits a human
290
306
  verdict step in non-TTY mode, it writes
291
- `e2e/.verdict-pending.json` and polls for `e2e/.verdict-response.json`.
292
- The skill monitors for the pending file while the background
293
- command runs:
294
-
295
- 1. Start the npm command via Bash with `run_in_background: true`
296
- 2. Poll `e2e/.verdict-pending.json` (check every 3-5 seconds)
297
- 3. When found, read it contains `checkId`, `description`,
298
- `screenshotPath` (absolute path to the screenshot)
299
- 4. Read the screenshot image and show it to the user
300
- 5. Ask the user for their verdict (P/I/S/N + optional notes)
301
- 6. Write `e2e/.verdict-response.json`:
307
+ `e2e/.verdict-pending.json` and emits a `verdict-pending` event
308
+ to the progress file. The Monitor delivers the event as a
309
+ notification. On receiving a `verdict-pending` notification:
310
+
311
+ 1. Read `e2e/.verdict-pending.json` contains `checkId`,
312
+ `description`, `screenshotPath` (absolute path to screenshot)
313
+ 2. Read the screenshot image and show it to the user
314
+ 3. Ask the user for their verdict (P/I/S/N + optional notes)
315
+ 4. Write `e2e/.verdict-response.json`:
302
316
  ```json
303
317
  { "verdict": "P", "notes": "looks great" }
304
318
  ```
305
- 7. The runtime picks up the response, records it, continues
306
- 8. Go back to step 2 until the background command completes
319
+ 5. The runtime picks up the response, records it, continues
320
+
321
+ When a `check-fail` notification arrives, surface it immediately:
322
+ show the step text and error message so the user knows what failed
323
+ without waiting for the end summary.
307
324
 
308
325
  The runtime times out after 10 minutes per verdict (auto-skips
309
326
  with `human:S` if no response). The pending/response files are
@@ -452,7 +452,7 @@ fi
452
452
 
453
453
  # .gitignore updates at project root.
454
454
  GITIGNORE_ROOT=".gitignore"
455
- GITIGNORE_ENTRIES=("e2e/reports/" "e2e/screenshots/" "e2e/traces/" "e2e/fixtures/articles/" "e2e/.env.local" "e2e/node_modules/" "e2e/.last-verify-run" "e2e/.verdict-pending.json" "e2e/.verdict-response.json")
455
+ GITIGNORE_ENTRIES=("e2e/reports/" "e2e/screenshots/" "e2e/traces/" "e2e/fixtures/articles/" "e2e/.env.local" "e2e/node_modules/" "e2e/.last-verify-run" "e2e/.verdict-pending.json" "e2e/.verdict-response.json" "e2e/.verify-progress.jsonl")
456
456
 
457
457
  if [[ $DRY_RUN -eq 1 ]]; then
458
458
  for entry in "${GITIGNORE_ENTRIES[@]}"; do
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabinet-verify",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Walkthrough verification harness for Claude Cabinet. Cucumber + Playwright scenarios with human-in-the-loop verdict pause.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -4,6 +4,7 @@ import * as fs from 'fs/promises';
4
4
  import * as path from 'path';
5
5
  import * as readline from 'readline';
6
6
  import { recordVerdict, getCurrentScenarioFile } from './verdict-recorder.js';
7
+ import { emitProgress } from './progress.js';
7
8
  import { getFreshPass } from './fresh-pass-cache.js';
8
9
  import { computePathHash } from './path-hash.js';
9
10
  import { out } from './output.js';
@@ -155,6 +156,7 @@ export async function askHumanVerdict(
155
156
  acItemId: options?.acItemId ?? null,
156
157
  }), 'utf8');
157
158
 
159
+ emitProgress({ event: 'verdict-pending', checkId, description, screenshotPath: path.resolve(screenshotPath) });
158
160
  process.stderr.write(`\n ${out.c.yellow('⏳')} Waiting for verdict on ${out.c.bold(checkId)} via file IPC...\n`);
159
161
 
160
162
  // Poll for response (500ms intervals, 10 min timeout)
@@ -49,6 +49,11 @@ export {
49
49
  traceFilePath,
50
50
  } from './trace.js';
51
51
 
52
+ export {
53
+ initProgress,
54
+ emitProgress,
55
+ } from './progress.js';
56
+
52
57
  export {
53
58
  computePathHash,
54
59
  computePathHashSafe,
@@ -20,9 +20,12 @@ export function resolveLaunchOptions(env: Record<string, string | undefined>): L
20
20
  slowMo = 1000;
21
21
  }
22
22
 
23
- return {
24
- headless,
25
- slowMo,
26
- args: ['--window-size=1500,1000'],
27
- };
23
+ const windowSize = env.CABINET_VERIFY_WINDOW_SIZE || (demo ? '1100,750' : '1500,1000');
24
+ const args = [`--window-size=${windowSize}`];
25
+ if (demo) {
26
+ const windowPos = env.CABINET_VERIFY_WINDOW_POSITION || '0,0';
27
+ args.push(`--window-position=${windowPos}`);
28
+ }
29
+
30
+ return { headless, slowMo, args };
28
31
  }
@@ -0,0 +1,17 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+
4
+ const PROGRESS_FILE = '.verify-progress.jsonl';
5
+
6
+ let progressPath = '';
7
+
8
+ export function initProgress(cwd: string): void {
9
+ progressPath = path.resolve(cwd, PROGRESS_FILE);
10
+ try { fs.writeFileSync(progressPath, '', 'utf8'); } catch { /* tolerate */ }
11
+ }
12
+
13
+ export function emitProgress(event: Record<string, unknown>): void {
14
+ if (!progressPath) return;
15
+ const line = JSON.stringify({ ...event, ts: new Date().toISOString() });
16
+ try { fs.appendFileSync(progressPath, line + '\n', 'utf8'); } catch { /* tolerate */ }
17
+ }
@@ -53,6 +53,7 @@ import { resolveLaunchOptions, isDemoMode } from './launch-options.js';
53
53
  import { initDemo, drainDemo } from './demo-recorder.js';
54
54
  import { pauseOnFailure } from './pause-on-failure.js';
55
55
  import { traceEnabled, traceFilePath } from './trace.js';
56
+ import { initProgress, emitProgress } from './progress.js';
56
57
 
57
58
  // Default 240s — catches real hangs without killing legit long steps.
58
59
  // Steps that legitimately take longer (rewrites, manual think-time)
@@ -64,6 +65,7 @@ let browser: Browser | undefined;
64
65
  BeforeAll(async () => {
65
66
  const opts = resolveLaunchOptions(process.env);
66
67
  initDemo(process.env);
68
+ initProgress(process.cwd());
67
69
  if (isDemoMode(process.env) && opts.slowMo > 0) {
68
70
  out.writeln(` ${out.c.dim('[demo] slowMo: ' + opts.slowMo + 'ms')}`);
69
71
  }
@@ -97,6 +99,7 @@ BeforeAll(async () => {
97
99
  AfterAll(async () => {
98
100
  drainDemo();
99
101
  const summary = await endRun();
102
+ emitProgress({ event: 'run-end', passed: summary.passed, failed: summary.failed, total: summary.total });
100
103
  out.runSummary({
101
104
  runId: summary.runId,
102
105
  total: summary.total,
@@ -183,6 +186,7 @@ Before(async function (this: CabinetVerifyWorld, scenario) {
183
186
 
184
187
  out.scenarioStart(scenario.pickle.name, scenario.gherkinDocument.uri || 'unknown');
185
188
  setScenarioContext(scenario.gherkinDocument.uri || 'unknown', scenario.pickle.name, this.role);
189
+ emitProgress({ event: 'scenario-start', name: scenario.pickle.name, file: scenario.gherkinDocument.uri || 'unknown' });
186
190
  });
187
191
 
188
192
  After(async function (this: CabinetVerifyWorld, scenario) {
@@ -212,6 +216,7 @@ After(async function (this: CabinetVerifyWorld, scenario) {
212
216
  this.tracing = false;
213
217
  }
214
218
 
219
+ emitProgress({ event: 'scenario-end', name: scenario.pickle.name, status: scenario.result?.status ?? 'UNKNOWN' });
215
220
  await this.context?.close();
216
221
  });
217
222
 
@@ -225,6 +230,15 @@ AfterStep(async function (this: CabinetVerifyWorld, { result, pickleStep }) {
225
230
  }
226
231
  }
227
232
 
233
+ if (result && pickleStep?.text) {
234
+ const stepStatus = result.status.toString();
235
+ if (stepStatus === 'PASSED') {
236
+ emitProgress({ event: 'check-pass', step: pickleStep.text });
237
+ } else if (stepStatus === 'FAILED') {
238
+ emitProgress({ event: 'check-fail', step: pickleStep.text, error: (result as { message?: string }).message ?? '' });
239
+ }
240
+ }
241
+
228
242
  if (result) {
229
243
  await pauseOnFailure(
230
244
  this.page,
@@ -19,10 +19,12 @@ describe('isDemoMode', () => {
19
19
  });
20
20
 
21
21
  describe('resolveLaunchOptions', () => {
22
- it('DEMO=1 defaults slowMo to 1000 when SLOW_MO unset', () => {
22
+ it('DEMO=1 defaults slowMo to 1000, smaller window, positioned top-left', () => {
23
23
  const opts = resolveLaunchOptions({ CABINET_VERIFY_DEMO: '1' });
24
24
  assert.equal(opts.slowMo, 1000);
25
25
  assert.equal(opts.headless, false);
26
+ assert.ok(opts.args.includes('--window-size=1100,750'));
27
+ assert.ok(opts.args.includes('--window-position=0,0'));
26
28
  });
27
29
 
28
30
  it('DEMO=1 respects explicit SLOW_MO=250', () => {