From 7be540480e166000e9b4e344b57fff42b2e1813e Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 25 Apr 2026 18:56:03 +0200 Subject: [PATCH] docs: add CLAUDE.md with dev guide for build pipeline and test runner Documents the dist-vs-source distinction that caused the memoriesSection fix to not take effect, the c8 coverage runner process leak, and the template variable maintenance contract. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..fdf64b1ff --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,69 @@ +# Claude Code — Dev Guide for singularity-foundry + +## Build pipeline (MUST READ before editing extension source) + +Source TypeScript files under `src/resources/extensions/sf/` are **not loaded +directly at runtime**. The loader (`src/loader.ts`) resolves extension entry +points from `dist/resources/extensions/sf/` (compiled `.js`) and copies them +to `~/.sf/agent/extensions/sf/` via `initResources`. Editing a `.ts` source +file has **no effect** until you recompile: + +```bash +npm run copy-resources # tsc --project tsconfig.resources.json + file copy +``` + +This clears and rebuilds `dist/resources/` in one shot. Expect ~60–90 s on +first run; subsequent runs reuse tsc's incremental cache if you keep one. + +The `dist-redirect.mjs` resolver (used by tests and `dev-cli.js`) only +redirects `.js → .ts` for imports whose `parentURL` is inside `/src/`. Files +loaded from `~/.sf/agent/extensions/sf/` (compiled JS) are **not** redirected. + +## Running tests + +**Use the lightweight `--test` runner, not `npm run test:coverage`.** + +The coverage runner (`c8` + `--cpu-prof` + `--heap-prof`) spawns 10–15 heavy +worker processes per invocation. If a background run is killed or times out, +those workers are left alive, saturating all CPUs (~700% observed). + +```bash +# Run a specific test file (fast, no coverage overhead): +node --import ./src/resources/extensions/sf/tests/resolve-ts.mjs \ + --experimental-strip-types \ + --test src/resources/extensions/sf/tests/.test.ts + +# Run the full SF extension test suite: +npm test +``` + +If the machine feels slow, check for stray workers: +```bash +ps aux | grep "heap-prof-interval" | grep -v grep +# Kill them: ... | awk '{print $2}' | xargs kill -9 +``` + +## Key directories + +| Path | Purpose | +|------|---------| +| `src/resources/extensions/sf/` | Extension TypeScript source (edit here) | +| `dist/resources/extensions/sf/` | Compiled output (rebuilt by `copy-resources`) | +| `~/.sf/agent/extensions/sf/` | Installed copy (synced from dist on startup) | +| `src/resources/extensions/sf/prompts/` | Prompt templates (`.md`) | +| `src/resources/extensions/sf/tests/dist-redirect.mjs` | Module resolver hook for tests | + +## Template variables + +When adding a new `{{variable}}` to a prompt template in `prompts/`, you must: + +1. Pass it in every `loadPrompt("template-name", { ..., newVar })` call site + (`auto-prompts.ts` is the main one for execute-task). +2. Add it (with a sensible placeholder value) to any test that calls + `loadPrompt("template-name", {...})` — see + `src/resources/extensions/sf/tests/plan-slice-prompt.test.ts`. +3. Run `npm run copy-resources` to land the change in dist. + +`loadPrompt` throws at runtime if any `{{var}}` in the template has no +corresponding key in the vars object — this is intentional to catch +template/code drift early.