create-harness-vibe-coding 0.8.4 → 0.8.5

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-harness-vibe-coding",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "Scaffold a 0-1 product harness for AI-assisted research, PRD, planning, architecture, build, test, and feedback loops",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,14 +1,17 @@
1
- ---
2
- name: wf-remove
3
- description: Use for /wf-remove in Claude Code, $wf-remove or /skills wf-remove in Codex, or any request to uninstall Harness safely.
4
- ---
5
-
6
- # WF Remove Adapter
7
-
1
+ ---
2
+ name: wf-remove
3
+ description: Use for /wf-remove in Claude Code, $wf-remove or /skills wf-remove in Codex, or any request to uninstall Harness safely.
4
+ ---
5
+
6
+ # WF Remove Adapter
7
+
8
8
  ## Invocation
9
9
 
10
10
  - Claude Code: use `/wf-remove` or select the `wf-remove` skill.
11
11
  - Codex CLI or IDE: use `$wf-remove` or `/skills` then choose `wf-remove`.
12
+ - User-facing removal is the slash/skill command. The Node commands below are
13
+ agent-internal execution steps; do not ask the user to copy/paste them unless
14
+ the agent has no shell/tool access.
12
15
 
13
16
  ## Load
14
17
 
@@ -17,21 +20,31 @@ description: Use for /wf-remove in Claude Code, $wf-remove or /skills wf-remove
17
20
 
18
21
  ## Flow
19
22
 
20
- 1. Run `node Harness/scripts/wf-remove.mjs --json` for the machine-readable
21
- plan.
22
- 2. Auto-remove only SAFE files that still match stored checksums.
23
+ 1. On plain `/wf-remove`, run `node Harness/scripts/wf-remove.mjs --json` for
24
+ the machine-readable plan, then run the safe default apply command yourself.
25
+ 2. Auto-remove only SAFE files that still match stored checksums or exact
26
+ built-in Harness discovery files recognized by the script.
23
27
  3. Ask the user before every MODIFIED or uncertain file.
24
28
  4. Preserve USER DATA by default. For an explicit thorough uninstall, use
25
29
  `--purge-user-data` (alias `--purge`); add `--keep-tasks` when the user wants task records
26
30
  retained while project-fact Harness docs are removed.
27
- 5. Run the script, not manual deletes:
31
+ 5. Run the script yourself, not manual deletes and not user-side command copy:
28
32
  - safe default: `node Harness/scripts/wf-remove.mjs --apply --yes`
29
33
  - thorough but keep tasks: `node Harness/scripts/wf-remove.mjs --apply --yes --purge-user-data --keep-tasks`
30
34
  - exact modified decisions: add `--delete-modified <path>` for each
31
35
  user-approved MODIFIED file.
36
+ 6. After apply, verify residual discovery folders:
37
+ - `.claude/agents`
38
+ - `.claude/skills`
39
+ - `.claude/commands`
40
+ - `.claude/rules`
41
+ - `.agents/skills`
42
+ - `.codex`
43
+ Built-in Harness files in these locations should be gone. Custom user skills
44
+ or user-owned files may remain and must be reported, not blindly deleted.
32
45
 
33
46
  ## Return
34
47
 
35
48
  Report SAFE removals, MODIFIED keep/delete decisions, preserved USER DATA,
36
- PURGE removals, directory cleanup, CLAUDE/AGENTS status, `.harness-version`
37
- status, and `git status` guidance.
49
+ PURGE removals, directory cleanup, `.claude` / `.agents` / `.codex` residual
50
+ status, `.harness-version` status, and `git status` guidance.
@@ -1,6 +1,6 @@
1
1
  {
2
- "generator": "0.8.4",
3
- "generated": "2026-07-02T09:50:07.142Z",
2
+ "generator": "0.8.5",
3
+ "generated": "2026-07-02T10:09:05.492Z",
4
4
  "options": [],
5
5
  "autoCheck": true,
6
6
  "source": "https://raw.githubusercontent.com/zingspark/create-harness-vibe-coding/main/templates/common/",
@@ -12,7 +12,7 @@
12
12
  ".agents/skills/wf-learn/SKILL.md": "sha256-7f3e1ee0aa83cbb76707698d0c26b703ad5c74b2df95a7dc4d751939a4ba05b2",
13
13
  ".agents/skills/wf-max/SKILL.md": "sha256-9b37cc3385f6d1a285b617169e91fbf71ffec76135b7b46ec1de2fe94ca220da",
14
14
  ".agents/skills/wf-readme/SKILL.md": "sha256-4d34ee3b6b305fa2581f5d8cb31e9152759f3df8bf8fa08efbb43782f128bdcd",
15
- ".agents/skills/wf-remove/SKILL.md": "sha256-f27aee81d4d6988186f468ccc5dfd02c7605967636a5aea93d92443e030dbcc2",
15
+ ".agents/skills/wf-remove/SKILL.md": "sha256-21ebef1a1fa8645d094c8ceeca78b33f036b6c42cda6db8be425d38d9e91af75",
16
16
  ".agents/skills/wf-review/SKILL.md": "sha256-cc6d536ec6de25546a0ba96e686f195da50ed11bc03763a76ef46d77243d3537",
17
17
  ".agents/skills/wf-update/SKILL.md": "sha256-d57cd89e271b2af63b6a1264af552a30f8d44959cf4782b42f0ab082a90be9cf",
18
18
  ".agents/skills/wf/SKILL.md": "sha256-70766bd2cb02bc489b5cc021797af62596a005d444a026abb511054a1a820a67",
@@ -42,7 +42,7 @@
42
42
  ".claude/skills/wf-learn/SKILL.md": "sha256-7f3e1ee0aa83cbb76707698d0c26b703ad5c74b2df95a7dc4d751939a4ba05b2",
43
43
  ".claude/skills/wf-max/SKILL.md": "sha256-9b37cc3385f6d1a285b617169e91fbf71ffec76135b7b46ec1de2fe94ca220da",
44
44
  ".claude/skills/wf-readme/SKILL.md": "sha256-4d34ee3b6b305fa2581f5d8cb31e9152759f3df8bf8fa08efbb43782f128bdcd",
45
- ".claude/skills/wf-remove/SKILL.md": "sha256-f27aee81d4d6988186f468ccc5dfd02c7605967636a5aea93d92443e030dbcc2",
45
+ ".claude/skills/wf-remove/SKILL.md": "sha256-21ebef1a1fa8645d094c8ceeca78b33f036b6c42cda6db8be425d38d9e91af75",
46
46
  ".claude/skills/wf-review/SKILL.md": "sha256-cc6d536ec6de25546a0ba96e686f195da50ed11bc03763a76ef46d77243d3537",
47
47
  ".claude/skills/wf-update/SKILL.md": "sha256-d57cd89e271b2af63b6a1264af552a30f8d44959cf4782b42f0ab082a90be9cf",
48
48
  ".claude/skills/wf/SKILL.md": "sha256-70766bd2cb02bc489b5cc021797af62596a005d444a026abb511054a1a820a67",
@@ -70,8 +70,8 @@
70
70
  "Harness/lifecycle.md": "sha256-a2d025e52f3b4412d8439083aca0d2cf7a4458ad0e30de4fc6465f990379190f",
71
71
  "Harness/research/README.md": "sha256-956c154df01cb9376972eb8b88bb3be0fe4e2dda802a72457c0126e3476fa755",
72
72
  "Harness/scripts/scan-clean.mjs": "sha256-7f693faf762c9c8e7657143d651f7c8369ed4823f18babe21daec58a55025593",
73
- "Harness/scripts/validate-harness.mjs": "sha256-e584959476265d53408484ec3653dd652a0f64922c785db97f0638c26f19e04c",
74
- "Harness/scripts/wf-remove.mjs": "sha256-4eb136ab26a9e20a949835e8cc6ff716b4beb3496c81ae3a4c03c049db60895c",
73
+ "Harness/scripts/validate-harness.mjs": "sha256-31dc33729034656d24ec163ff310164e2fc77289212b2278ab4a2f3d4b9294dc",
74
+ "Harness/scripts/wf-remove.mjs": "sha256-944e5da9dc1abcfb8f410bca743c3f5fbee2bc74d09b97e04ceaaf53da0cb9f1",
75
75
  "Harness/scripts/wf-update-check.mjs": "sha256-d14ce08f4c05ba118362a56a4b7d5965b114bc2b15a023c08e21d57f32b2cf93",
76
76
  "Harness/subagents.md": "sha256-16255092bab9011bb67359b4399d27ab292c14a717e67123e8a76e40e8669661",
77
77
  "Harness/templates/ACCEPTANCE.template.md": "sha256-394a6c08b155b1d121f1d51da774f7988bdb891224c6d5f2ca2c131e8c95ffb3",
@@ -541,6 +541,9 @@ requireText('Harness/templates/TEST_PLAN.template.md', 'syntax-only checks', 'te
541
541
  requireText('.claude/skills/tdd/SKILL.md', 'Harness/ACCEPTANCE_PROTOCOL.md', 'tdd skill loads acceptance protocol');
542
542
  requireText('.claude/skills/tdd/SKILL.md', 'Harness/HARNESS_BRIDGE.md', 'tdd skill loads harness bridge');
543
543
  requireText('.claude/skills/tdd/SKILL.md', 'No syntax-only acceptance', 'tdd skill forbids syntax-only acceptance');
544
+ requireText('.claude/skills/wf-remove/SKILL.md', 'User-facing removal is the slash/skill command', 'wf-remove slash command is user-facing');
545
+ requireText('.claude/skills/wf-remove/SKILL.md', 'agent-internal execution steps', 'wf-remove script commands are agent-internal');
546
+ requireText('.claude/skills/wf-remove/SKILL.md', 'verify residual discovery folders', 'wf-remove residual discovery verification');
544
547
  requireText('.claude/agents/tdd-guide.md', 'Browser Acceptance Rules', 'tdd-guide browser acceptance rules');
545
548
  requireText('.claude/agents/tdd-guide.md', 'real user actions', 'tdd-guide real user action requirement');
546
549
  requireText('.claude/agents/test-writer.md', 'Harness/ACCEPTANCE_PROTOCOL.md', 'test-writer loads acceptance protocol');
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * wf-remove.mjs Safely remove Harness framework files.
3
+ * wf-remove.mjs �?Safely remove Harness framework files.
4
4
  *
5
5
  * Classifies all Harness-owned files into:
6
- * SAFE framework files matching stored checksums auto-remove
7
- * MODIFIED framework files edited by user MUST confirm
8
- * USER user data files NEVER remove
6
+ * SAFE �?framework files matching stored checksums �?auto-remove
7
+ * MODIFIED �?framework files edited by user �?MUST confirm
8
+ * USER �?user data files �?NEVER remove
9
9
  *
10
10
  * Usage:
11
11
  * node Harness/scripts/wf-remove.mjs # dry-run: show plan
@@ -23,12 +23,12 @@ import { resolve, dirname, join, sep } from 'path';
23
23
  import { fileURLToPath } from 'url';
24
24
  import { createInterface } from 'readline';
25
25
 
26
- const __dirname = dirname(fileURLToPath(import.meta.url));
26
+ const SCRIPT_FILE = fileURLToPath(import.meta.url);
27
+ const __dirname = dirname(SCRIPT_FILE);
28
+ const SCRIPT_ROOT = resolve(__dirname, '..', '..');
27
29
  const ROOT = process.env.WF_ROOT
28
30
  ? resolve(process.env.WF_ROOT)
29
- : (existsSync(resolve(process.cwd(), 'Harness', '.harness-version'))
30
- ? process.cwd()
31
- : resolve(__dirname, '..', '..'));
31
+ : SCRIPT_ROOT;
32
32
  const VERSION_FILE = resolve(ROOT, 'Harness', '.harness-version');
33
33
 
34
34
  // ── Classification ─────────────────────────────────────────────────
@@ -45,7 +45,7 @@ const HARNESS_PREFIXES = [
45
45
  'tests/.gitkeep',
46
46
  ];
47
47
 
48
- /** Files the user owns NEVER remove. Consistent with wf-update-check PRESERVE_PATTERNS. */
48
+ /** Files the user owns �?NEVER remove. Consistent with wf-update-check PRESERVE_PATTERNS. */
49
49
  const USER_DATA_PATTERNS = [
50
50
  /^Harness\/PROGRESS\.md$/,
51
51
  /^Harness\/tasks\//,
@@ -97,14 +97,67 @@ function isPurgeableHarnessData(file, { keepTasks }) {
97
97
  if (keepTasks && /^Harness\/tasks\//.test(file) && !isFrameworkTaskFile(file)) return false;
98
98
  return PURGEABLE_HARNESS_DATA_PATTERNS.some(p => p.test(file));
99
99
  }
100
-
101
- /** Framework files that should always exist (not part of removal). */
102
- const KEEP_FRAMEWORK = new Set([
103
- 'Harness/.harness-version',
104
- ]);
105
-
106
- /** Directories to clean up if empty after file removal. */
107
- const CLEANUP_DIRS = [
100
+
101
+ /** Framework files that should always exist (not part of removal). */
102
+ const KEEP_FRAMEWORK = new Set([
103
+ 'Harness/.harness-version',
104
+ ]);
105
+
106
+ const BUILT_IN_AGENT_NAMES = [
107
+ 'architect-manager',
108
+ 'architect',
109
+ 'context-master',
110
+ 'debugger',
111
+ 'docs-researcher',
112
+ 'explore-manager',
113
+ 'implement-manager',
114
+ 'implementer',
115
+ 'memory-master',
116
+ 'planner',
117
+ 'researcher',
118
+ 'review-manager',
119
+ 'reviewer',
120
+ 'tdd-guide',
121
+ 'test-writer',
122
+ 'verifier',
123
+ ];
124
+
125
+ const BUILT_IN_SKILL_NAMES = [
126
+ 'browser-e2e',
127
+ 'github-pr-review',
128
+ 'python-backend',
129
+ 'subagent-orchestrator',
130
+ 'tdd',
131
+ 'ts-react-frontend',
132
+ 'ui-ux-review',
133
+ 'wf',
134
+ 'wf-auto',
135
+ 'wf-auto-spark',
136
+ 'wf-browser',
137
+ 'wf-learn',
138
+ 'wf-max',
139
+ 'wf-readme',
140
+ 'wf-remove',
141
+ 'wf-review',
142
+ 'wf-update',
143
+ ];
144
+
145
+ const KNOWN_FRAMEWORK_FILES = new Set([
146
+ ...BUILT_IN_AGENT_NAMES.map(name => `.claude/agents/${name}.md`),
147
+ ...BUILT_IN_SKILL_NAMES.flatMap(name => [
148
+ `.claude/skills/${name}/SKILL.md`,
149
+ `.agents/skills/${name}/SKILL.md`,
150
+ ]),
151
+ '.claude/commands/wf-help.md',
152
+ '.claude/rules/ecc/common.md',
153
+ ]);
154
+
155
+ function isKnownFrameworkFile(file) {
156
+ return KNOWN_FRAMEWORK_FILES.has(file);
157
+ }
158
+
159
+ /** Directories to clean up if empty after file removal. */
160
+ const CLEANUP_DIRS = [
108
161
  '.claude/agents',
109
162
  '.claude/skills/wf-auto',
110
163
  '.claude/skills/wf-browser',
@@ -251,7 +304,7 @@ function removeEmptyDirs(startDir) {
251
304
 
252
305
  async function askUser(question) {
253
306
  if (!process.stdin.isTTY) {
254
- console.log(' (non-interactive defaulting to KEEP)');
307
+ console.log(' (non-interactive �?defaulting to KEEP)');
255
308
  return 'k';
256
309
  }
257
310
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -300,8 +353,9 @@ async function main() {
300
353
  addFilesUnder(allFiles, dir, scanIssues);
301
354
  }
302
355
 
303
- // Add framework files that might not be in checksums (newer additions)
356
+ // Add framework files that might not be in checksums (newer additions)
304
357
  const extraPatterns = [
358
+ ...KNOWN_FRAMEWORK_FILES,
305
359
  '.claude/skills/wf/SKILL.md',
306
360
  '.agents/skills/wf/SKILL.md',
307
361
  '.claude/skills/tdd/SKILL.md',
@@ -323,9 +377,9 @@ async function main() {
323
377
  }
324
378
 
325
379
  // 2. Classify every file
326
- const safe = []; // SAFE matches checksum, auto-remove
327
- const modified = []; // MODIFIED user edited, must confirm
328
- const user = []; // USER never remove
380
+ const safe = []; // SAFE �?matches checksum, auto-remove
381
+ const modified = []; // MODIFIED �?user edited, must confirm
382
+ const user = []; // USER �?never remove
329
383
  const skipped = []; // File not on disk, traversal rejected, or framework-keep
330
384
  const purge = []; // Explicitly requested Harness user-data removal
331
385
  skipped.push(...scanIssues);
@@ -347,13 +401,13 @@ async function main() {
347
401
  });
348
402
  continue;
349
403
  }
350
- user.push({ file, reason: 'user data NEVER removed' });
404
+ user.push({ file, reason: 'user data �?NEVER removed' });
351
405
  continue;
352
406
  }
353
407
 
354
408
  // Only allow deletion of files under harness-owned prefixes
355
409
  if (!isHarnessOwned(canonical)) {
356
- user.push({ file, reason: 'outside harness prefix NEVER removed' });
410
+ user.push({ file, reason: 'outside harness prefix �?NEVER removed' });
357
411
  continue;
358
412
  }
359
413
 
@@ -366,15 +420,24 @@ async function main() {
366
420
  skipped.push({ file, reason: 'not on disk' });
367
421
  continue;
368
422
  }
369
-
370
- const currentHash = sha256File(diskPath);
371
- const storedHash = storedChecksums[file];
372
-
373
- if (!storedHash) {
374
- modified.push({ file, currentHash, storedHash: 'none', reason: 'not in checksums' });
375
- } else if (currentHash === storedHash) {
376
- safe.push({ file, currentHash, storedHash });
377
- } else {
423
+
424
+ const currentHash = sha256File(diskPath);
425
+ const storedHash = storedChecksums[file];
426
+
427
+ if (!storedHash) {
428
+ if (isKnownFrameworkFile(canonical)) {
429
+ safe.push({
430
+ file,
431
+ currentHash,
432
+ storedHash: currentHash,
433
+ reason: 'known framework file missing from legacy checksums',
434
+ });
435
+ } else {
436
+ modified.push({ file, currentHash, storedHash: 'none', reason: 'not in checksums' });
437
+ }
438
+ } else if (currentHash === storedHash) {
439
+ safe.push({ file, currentHash, storedHash });
440
+ } else {
378
441
  modified.push({ file, currentHash, storedHash, reason: 'user modified' });
379
442
  }
380
443
  }
@@ -385,7 +448,7 @@ async function main() {
385
448
  const settingsHash = sha256File(settingsFile);
386
449
  const storedSettingsHash = storedChecksums['.claude/settings.json'];
387
450
  if (storedSettingsHash && settingsHash !== storedSettingsHash) {
388
- // User modified settings move to modified
451
+ // User modified settings �?move to modified
389
452
  // Remove from safe if it was there
390
453
  const idx = safe.findIndex(s => s.file === '.claude/settings.json');
391
454
  if (idx >= 0) {
@@ -429,16 +492,16 @@ async function main() {
429
492
  return;
430
493
  }
431
494
 
432
- console.log('\n🧹 WF-REMOVE Harness framework removal plan\n');
495
+ console.log('\n🧹 WF-REMOVE �?Harness framework removal plan\n');
433
496
 
434
497
  if (safe.length > 0) {
435
- console.log(`✅ SAFE (${safe.length} files auto-remove, unmodified framework):`);
436
- for (const s of safe) console.log(` ✕ ${s.file}`);
498
+ console.log(`�?SAFE (${safe.length} files �?auto-remove, unmodified framework):`);
499
+ for (const s of safe) console.log(` �?${s.file}`);
437
500
  console.log('');
438
501
  }
439
502
 
440
503
  if (modified.length > 0) {
441
- console.log(`⚠ MODIFIED (${modified.length} files REQUIRE CONFIRMATION):`);
504
+ console.log(`�?MODIFIED (${modified.length} files �?REQUIRE CONFIRMATION):`);
442
505
  for (const m of modified) {
443
506
  console.log(` ? ${m.file} [${m.reason}]`);
444
507
  }
@@ -446,8 +509,8 @@ async function main() {
446
509
  }
447
510
 
448
511
  if (user.length > 0) {
449
- console.log(`🔒 USER DATA (${user.length} files NEVER removed):`);
450
- for (const u of user) console.log(` ○ ${u.file} [${u.reason}]`);
512
+ console.log(`🔒 USER DATA (${user.length} files �?NEVER removed):`);
513
+ for (const u of user) console.log(` �?${u.file} [${u.reason}]`);
451
514
  console.log('');
452
515
  }
453
516
 
@@ -464,17 +527,17 @@ async function main() {
464
527
  return;
465
528
  }
466
529
 
467
- // 4. Apply remove SAFE files automatically (rehash before unlink)
530
+ // 4. Apply �?remove SAFE files automatically (rehash before unlink)
468
531
  let safeRemoved = 0;
469
532
  let safeFailed = 0;
470
533
  for (const s of safe) {
471
534
  const diskPath = safePath(s.file);
472
- if (!diskPath) { console.error(` Traversal rejected: ${s.file}`); safeFailed++; continue; }
535
+ if (!diskPath) { console.error(` �?Traversal rejected: ${s.file}`); safeFailed++; continue; }
473
536
  if (!existsSync(diskPath)) continue;
474
537
  // Re-verify hash hasn't changed since classification
475
538
  const currentHash = sha256File(diskPath);
476
539
  if (currentHash !== s.storedHash) {
477
- console.log(` Skipped (modified since classification): ${s.file}`);
540
+ console.log(` �?Skipped (modified since classification): ${s.file}`);
478
541
  safeFailed++;
479
542
  continue;
480
543
  }
@@ -482,13 +545,13 @@ async function main() {
482
545
  unlinkSync(diskPath);
483
546
  safeRemoved++;
484
547
  } catch (e) {
485
- console.error(` Failed to remove: ${s.file} — ${e.message}`);
548
+ console.error(` �?Failed to remove: ${s.file} �?${e.message}`);
486
549
  safeFailed++;
487
550
  }
488
551
  }
489
- console.log(`✓ Removed ${safeRemoved} safe files.`);
552
+ console.log(`�?Removed ${safeRemoved} safe files.`);
490
553
 
491
- // 5. Handle MODIFIED files prompt user
554
+ // 5. Handle MODIFIED files �?prompt user
492
555
  let modifiedRemoved = 0;
493
556
  let modifiedKept = 0;
494
557
  let modifiedFailed = 0;
@@ -508,7 +571,7 @@ async function main() {
508
571
  }
509
572
  if (yes) {
510
573
  // Non-interactive mode: skip all modified
511
- console.log(` Skipped (modified): ${m.file}`);
574
+ console.log(` �?Skipped (modified): ${m.file}`);
512
575
  modifiedKept++;
513
576
  continue;
514
577
  }
@@ -520,17 +583,17 @@ async function main() {
520
583
  const answer = await askUser(' Choose [d/k]: ');
521
584
  if (answer === 'd' || answer === 'delete') {
522
585
  const diskPath = safePath(m.file);
523
- if (!diskPath) { console.error(` Traversal rejected: ${m.file}`); modifiedFailed++; continue; }
586
+ if (!diskPath) { console.error(` �?Traversal rejected: ${m.file}`); modifiedFailed++; continue; }
524
587
  try {
525
588
  unlinkSync(diskPath);
526
- console.log(` Deleted: ${m.file}`);
589
+ console.log(` �?Deleted: ${m.file}`);
527
590
  modifiedRemoved++;
528
591
  } catch (e) {
529
- console.error(` Failed: ${m.file} — ${e.message}`);
592
+ console.error(` �?Failed: ${m.file} �?${e.message}`);
530
593
  modifiedFailed++;
531
594
  }
532
595
  } else {
533
- console.log(` Kept: ${m.file}`);
596
+ console.log(` �?Kept: ${m.file}`);
534
597
  modifiedKept++;
535
598
  }
536
599
  }
@@ -591,7 +654,7 @@ async function main() {
591
654
  }
592
655
  } else if (!existsSync(harPath) || (existsSync(harPath) && readdirSync(harPath).filter(f => f !== '.harness-version').length === 0)) {
593
656
  unlinkSync(VERSION_FILE);
594
- console.log('Removed .harness-version (Harness directory empty).');
657
+ console.log('�?Removed .harness-version (Harness directory empty).');
595
658
  }
596
659
  }
597
660
 
@@ -610,7 +673,7 @@ async function main() {
610
673
  if (pruned > 0) {
611
674
  versionData.checksums = checksums;
612
675
  writeFileSync(VERSION_FILE, JSON.stringify(versionData, null, 2) + '\n', 'utf-8');
613
- console.log(`✓ Pruned ${pruned} stale checksum(s) from .harness-version.`);
676
+ console.log(`�?Pruned ${pruned} stale checksum(s) from .harness-version.`);
614
677
  }
615
678
  }
616
679
 
@@ -624,7 +687,7 @@ async function main() {
624
687
  // Strip the harness section: everything from "## 1. Harness Binding" to the next "## "
625
688
  const cleaned = content.replace(/## 1\. Harness Binding[\s\S]*?(?=## 2\.)/, '');
626
689
  writeFileSync(claudePath, cleaned, 'utf-8');
627
- console.log('Stripped Harness binding section from CLAUDE.md.');
690
+ console.log('�?Stripped Harness binding section from CLAUDE.md.');
628
691
  }
629
692
  }
630
693
  }