@cloverleaf/reference-impl 0.8.3 → 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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.3
1
+ 0.8.5
@@ -5,7 +5,15 @@ const here = dirname(fileURLToPath(import.meta.url));
5
5
  const PACKAGE_DEFAULT = join(here, '..', 'config', 'discovery.json');
6
6
  export function loadDiscoveryConfig(repoRoot) {
7
7
  const override = join(repoRoot, '.cloverleaf', 'config', 'discovery.json');
8
- const fallback = JSON.parse(readFileSync(PACKAGE_DEFAULT, 'utf-8'));
8
+ const rawFallback = JSON.parse(readFileSync(PACKAGE_DEFAULT, 'utf-8'));
9
+ const fallback = {
10
+ docContextUri: typeof rawFallback.docContextUri === 'string' ? rawFallback.docContextUri : '',
11
+ projectId: typeof rawFallback.projectId === 'string' ? rawFallback.projectId : '',
12
+ idStart: typeof rawFallback.idStart === 'number' ? rawFallback.idStart : 1,
13
+ prep_copy_dirs: Array.isArray(rawFallback.prep_copy_dirs)
14
+ ? rawFallback.prep_copy_dirs.filter((p) => typeof p === 'string')
15
+ : [],
16
+ };
9
17
  if (existsSync(override)) {
10
18
  try {
11
19
  const doc = JSON.parse(readFileSync(override, 'utf-8'));
@@ -22,5 +30,8 @@ function normalise(doc, fallback) {
22
30
  docContextUri: typeof doc.docContextUri === 'string' ? doc.docContextUri : fallback.docContextUri,
23
31
  projectId: typeof doc.projectId === 'string' ? doc.projectId : fallback.projectId,
24
32
  idStart: typeof doc.idStart === 'number' ? doc.idStart : fallback.idStart,
33
+ prep_copy_dirs: Array.isArray(doc.prep_copy_dirs)
34
+ ? doc.prep_copy_dirs.filter((p) => typeof p === 'string')
35
+ : fallback.prep_copy_dirs,
25
36
  };
26
37
  }
@@ -1,6 +1,7 @@
1
1
  import { cpSync, existsSync, rmSync } from 'node:fs';
2
2
  import { execSync } from 'node:child_process';
3
3
  import { join, dirname } from 'node:path';
4
+ import { loadDiscoveryConfig } from './discovery-config.mjs';
4
5
  /**
5
6
  * Prepare a freshly-created git worktree of the cloverleaf monorepo for running reference-impl
6
7
  * tests. Addresses the v0.5 dogfood finding (CLV-16, CLV-17 Delivery runs) where Reviewer/QA
@@ -116,6 +117,19 @@ export function prepWorktree(mainRoot, worktreePath) {
116
117
  primeCopy(mainStandardNm, wtStandardNm);
117
118
  primeCopy(mainRefImplNm, wtRefImplNm);
118
119
  primeCopy(join(resolvedMain, 'reference-impl', 'dist'), join(worktreePath, 'reference-impl', 'dist'));
120
+ // Honor discovery_config.prep_copy_dirs: copy each listed gitignored directory
121
+ // (e.g., docs/superpowers) from mainRoot into the worktree. Walker briefs reference
122
+ // these paths but git checkouts of main don't carry gitignored content.
123
+ const discoveryConfig = loadDiscoveryConfig(resolvedMain);
124
+ for (const dir of discoveryConfig.prep_copy_dirs) {
125
+ const srcPath = join(resolvedMain, dir);
126
+ const dstPath = join(worktreePath, dir);
127
+ if (!existsSync(srcPath)) {
128
+ process.stderr.write(`prep-worktree: prep_copy_dirs entry '${dir}' not found at ${srcPath} — skipping.\n`);
129
+ continue;
130
+ }
131
+ primeCopy(srcPath, dstPath);
132
+ }
119
133
  execSync('npm run build', {
120
134
  cwd: join(worktreePath, 'standard'),
121
135
  stdio: 'pipe',
@@ -1,5 +1,8 @@
1
1
  function escape(s) {
2
- return s
2
+ if (s === undefined || s === null)
3
+ return '';
4
+ const str = typeof s === 'string' ? s : String(s);
5
+ return str
3
6
  .replace(/&/g, '&')
4
7
  .replace(/</g, '&lt;')
5
8
  .replace(/>/g, '&gt;')
@@ -9,11 +9,20 @@ export interface DiscoveryConfig {
9
9
  docContextUri: string;
10
10
  projectId: string;
11
11
  idStart: number;
12
+ prep_copy_dirs: string[];
12
13
  }
13
14
 
14
15
  export function loadDiscoveryConfig(repoRoot: string): DiscoveryConfig {
15
16
  const override = join(repoRoot, '.cloverleaf', 'config', 'discovery.json');
16
- const fallback = JSON.parse(readFileSync(PACKAGE_DEFAULT, 'utf-8')) as DiscoveryConfig;
17
+ const rawFallback = JSON.parse(readFileSync(PACKAGE_DEFAULT, 'utf-8')) as Partial<DiscoveryConfig>;
18
+ const fallback: DiscoveryConfig = {
19
+ docContextUri: typeof rawFallback.docContextUri === 'string' ? rawFallback.docContextUri : '',
20
+ projectId: typeof rawFallback.projectId === 'string' ? rawFallback.projectId : '',
21
+ idStart: typeof rawFallback.idStart === 'number' ? rawFallback.idStart : 1,
22
+ prep_copy_dirs: Array.isArray(rawFallback.prep_copy_dirs)
23
+ ? (rawFallback.prep_copy_dirs as unknown[]).filter((p): p is string => typeof p === 'string')
24
+ : [],
25
+ };
17
26
 
18
27
  if (existsSync(override)) {
19
28
  try {
@@ -31,5 +40,8 @@ function normalise(doc: Partial<DiscoveryConfig>, fallback: DiscoveryConfig): Di
31
40
  docContextUri: typeof doc.docContextUri === 'string' ? doc.docContextUri : fallback.docContextUri,
32
41
  projectId: typeof doc.projectId === 'string' ? doc.projectId : fallback.projectId,
33
42
  idStart: typeof doc.idStart === 'number' ? doc.idStart : fallback.idStart,
43
+ prep_copy_dirs: Array.isArray(doc.prep_copy_dirs)
44
+ ? (doc.prep_copy_dirs as unknown[]).filter((p): p is string => typeof p === 'string')
45
+ : fallback.prep_copy_dirs,
34
46
  };
35
47
  }
@@ -1,6 +1,7 @@
1
1
  import { cpSync, existsSync, rmSync } from 'node:fs';
2
2
  import { execSync } from 'node:child_process';
3
3
  import { join, dirname } from 'node:path';
4
+ import { loadDiscoveryConfig } from './discovery-config.js';
4
5
 
5
6
  /**
6
7
  * Prepare a freshly-created git worktree of the cloverleaf monorepo for running reference-impl
@@ -130,6 +131,20 @@ export function prepWorktree(mainRoot: string, worktreePath: string): void {
130
131
  primeCopy(mainRefImplNm, wtRefImplNm);
131
132
  primeCopy(join(resolvedMain, 'reference-impl', 'dist'), join(worktreePath, 'reference-impl', 'dist'));
132
133
 
134
+ // Honor discovery_config.prep_copy_dirs: copy each listed gitignored directory
135
+ // (e.g., docs/superpowers) from mainRoot into the worktree. Walker briefs reference
136
+ // these paths but git checkouts of main don't carry gitignored content.
137
+ const discoveryConfig = loadDiscoveryConfig(resolvedMain);
138
+ for (const dir of discoveryConfig.prep_copy_dirs) {
139
+ const srcPath = join(resolvedMain, dir);
140
+ const dstPath = join(worktreePath, dir);
141
+ if (!existsSync(srcPath)) {
142
+ process.stderr.write(`prep-worktree: prep_copy_dirs entry '${dir}' not found at ${srcPath} — skipping.\n`);
143
+ continue;
144
+ }
145
+ primeCopy(srcPath, dstPath);
146
+ }
147
+
133
148
  execSync('npm run build', {
134
149
  cwd: join(worktreePath, 'standard'),
135
150
  stdio: 'pipe',
package/lib/qa-report.ts CHANGED
@@ -8,8 +8,10 @@ export interface QaRunResult {
8
8
  stderrTail: string;
9
9
  }
10
10
 
11
- function escape(s: string): string {
12
- return s
11
+ function escape(s: unknown): string {
12
+ if (s === undefined || s === null) return '';
13
+ const str = typeof s === 'string' ? s : String(s);
14
+ return str
13
15
  .replace(/&/g, '&amp;')
14
16
  .replace(/</g, '&lt;')
15
17
  .replace(/>/g, '&gt;')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloverleaf/reference-impl",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Reference implementation of the Cloverleaf methodology as Claude Code skills. Implements the Tight Loop (Implementer + Reviewer).",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/prompts/qa.md CHANGED
@@ -72,6 +72,11 @@ The Standard's QA contract requires a `preview_uri`. You were passed the sentine
72
72
  - Read-only. Do NOT edit source files.
73
73
  - Use `git worktree`: do NOT `git checkout` in the main working directory.
74
74
  - Always teardown the worktree, even on error.
75
+ - **Loading or running a module directly.** Do not improvise `node -e "import('./lib/x.js')"` to spot-check a module — sources are `.ts` and the build emits `.mjs`, so a bare `.js` import resolves to neither and fails with `ERR_MODULE_NOT_FOUND`. Use `npx tsx` instead (already in the worktree's `node_modules`): it resolves `.ts` sources **and** the project's `.js`-style import specifiers, so the natural import works. Run it from the worktree's `reference-impl/` directory; for anything the test suite already covers, prefer `npm test`.
76
+
77
+ ```bash
78
+ npx tsx -e "import('./lib/<module>.js').then(m => console.log(Object.keys(m)))"
79
+ ```
75
80
 
76
81
  ## QA Report (v0.4)
77
82
 
@@ -65,5 +65,10 @@ A `pass` verdict MAY have an empty `findings` array or omit it. A `bounce` verdi
65
65
  Use `--detach` with a SHA rather than a branch name: when running inside a walker worktree, the feature branch (and main) may already be checked out in another worktree, causing `git worktree add` to fail with "fatal: branch … is already checked out". Detaching at a SHA bypasses this constraint entirely.
66
66
 
67
67
  This keeps `.cloverleaf/` on main intact.
68
+ - **Loading or running a module directly.** Do not improvise `node -e "import('./lib/x.js')"` to spot-check a module — sources are `.ts` and the build emits `.mjs`, so a bare `.js` import resolves to neither and fails with `ERR_MODULE_NOT_FOUND`. Use `npx tsx` instead (already in the worktree's `node_modules`): it resolves `.ts` sources **and** the project's `.js`-style import specifiers, so the natural import works. Run it from the worktree's `reference-impl/` directory; for anything the test suite already covers, prefer `npm test`.
69
+
70
+ ```bash
71
+ npx tsx -e "import('./lib/<module>.js').then(m => console.log(Object.keys(m)))"
72
+ ```
68
73
  - Severities (per the Cloverleaf feedback schema): `blocker` = wrong behavior / missing AC / broken tests; `error` = notable defect that should be fixed but doesn't break AC; `warning` = should fix; `info` = nit / style. Use `blocker` and `error` for bounces.
69
74
  - If a criterion is subjective, lean toward pass — the task author chose those words deliberately.