From d9c848132a9e30b5ddcf0ee4efade60ad9442e4d Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 2 May 2026 06:30:45 +0200 Subject: [PATCH] chore: CI workflows, package.json updates, test fixes, docs cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit šŸ’˜ Generated with Crush Assisted-by: GLM-5.1 via Crush --- .github/workflows/build-native.yml | 2 +- .github/workflows/ci.yml | 10 +-- .github/workflows/cleanup-dev-versions.yml | 2 +- .github/workflows/dev-publish.yml | 4 +- .github/workflows/next-publish.yml | 4 +- .github/workflows/pipeline.yml | 6 +- .github/workflows/pr-risk.yml | 2 +- .github/workflows/prod-release.yml | 2 +- .node-version | 2 +- .nvmrc | 2 +- Dockerfile | 2 +- docs/dev/agent-knowledge-index.md | 1 - ...6-maximizing-agent-autonomy-superpowers.md | 44 ----------- docs/dev/building-coding-agents/README.md | 2 - package.json | 4 +- packages/daemon/package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/native/package.json | 2 +- packages/pi-agent-core/package.json | 2 +- packages/pi-ai/package.json | 2 +- packages/pi-coding-agent/package.json | 2 +- packages/pi-coding-agent/src/core/exec.ts | 79 +++++++++---------- packages/pi-tui/package.json | 2 +- packages/rpc-client/package.json | 2 +- pkg/package.json | 2 +- src/headless-query.ts | 3 +- .../extensions/browser-tools/package.json | 2 +- .../extensions/claude-code-cli/package.json | 2 +- src/resources/extensions/cmux/package.json | 2 +- .../extensions/context7/package.json | 2 +- .../extensions/genai-proxy/package.json | 2 +- .../extensions/google-search/package.json | 2 +- src/resources/extensions/package.json | 2 +- .../extensions/sf-permissions/package.json | 2 +- src/resources/extensions/sf/package.json | 2 +- .../extensions/sf/tests/complete-task.test.ts | 6 +- .../derive-state-db-disk-reconcile.test.ts | 6 +- .../extensions/sf/tests/detection.test.ts | 2 +- .../sf/tests/doctor-fix-flag.test.ts | 6 +- .../sf/tests/draft-promotion.test.ts | 6 +- .../tests/integration/git-self-heal.test.ts | 6 +- .../queue-completed-milestone-perf.test.ts | 6 +- .../tests/integration/token-savings.test.ts | 6 +- .../tests/merge-conflict-stops-loop.test.ts | 6 +- .../sf/tests/planning-crossval.test.ts | 8 +- .../sf/tests/recovery-attempts-reset.test.ts | 6 +- .../sf/tests/slice-disk-reconcile.test.ts | 6 +- .../sf/tests/survivor-branch-complete.test.ts | 6 +- .../extensions/sf/tests/unit-runtime.test.ts | 6 +- .../sf/tests/worker-registry.test.ts | 6 +- .../sf/tests/worktree-health-monorepo.test.ts | 6 +- .../tests/worktree-submodule-safety.test.ts | 6 +- .../worktree-sync-overwrite-loop.test.ts | 6 +- .../extensions/universal-config/package.json | 2 +- src/worktree-cli.ts | 3 +- studio/package.json | 2 +- vscode-extension/package.json | 2 +- web/package.json | 2 +- 58 files changed, 117 insertions(+), 207 deletions(-) delete mode 100644 docs/dev/building-coding-agents/06-maximizing-agent-autonomy-superpowers.md diff --git a/.github/workflows/build-native.yml b/.github/workflows/build-native.yml index b385e72a7..7914613f6 100644 --- a/.github/workflows/build-native.yml +++ b/.github/workflows/build-native.yml @@ -106,7 +106,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: "24" + node-version: '24.15' registry-url: "https://registry.npmjs.org" cache: "npm" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e305aae48..efa6d329c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '24' + node-version: '24.15' - name: Validate skill references run: node scripts/check-skill-references.mjs @@ -129,7 +129,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '24' + node-version: '24.15' cache: 'npm' - name: Install dependencies @@ -181,7 +181,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '24' + node-version: '24.15' cache: 'npm' - name: Install dependencies @@ -225,7 +225,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '24' + node-version: '24.15' cache: 'npm' - name: Install dependencies @@ -273,7 +273,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '24' + node-version: '24.15' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/cleanup-dev-versions.yml b/.github/workflows/cleanup-dev-versions.yml index b4447b7a2..38a7b2b9c 100644 --- a/.github/workflows/cleanup-dev-versions.yml +++ b/.github/workflows/cleanup-dev-versions.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org - name: Unpublish old dev versions diff --git a/.github/workflows/dev-publish.yml b/.github/workflows/dev-publish.yml index c60889728..5be9bf7ea 100644 --- a/.github/workflows/dev-publish.yml +++ b/.github/workflows/dev-publish.yml @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' @@ -111,7 +111,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' diff --git a/.github/workflows/next-publish.yml b/.github/workflows/next-publish.yml index 61a6d26f7..70d440f6c 100644 --- a/.github/workflows/next-publish.yml +++ b/.github/workflows/next-publish.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' @@ -102,7 +102,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 4c18f864f..fdcc9b5bf 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -38,7 +38,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' @@ -96,7 +96,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' @@ -165,7 +165,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' diff --git a/.github/workflows/pr-risk.yml b/.github/workflows/pr-risk.yml index 2b96c9bb9..ddaa1a943 100644 --- a/.github/workflows/pr-risk.yml +++ b/.github/workflows/pr-risk.yml @@ -26,7 +26,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: '24' + node-version: '24.15' # Use the GitHub API to get changed files — no fork code is executed. - name: Get changed files diff --git a/.github/workflows/prod-release.yml b/.github/workflows/prod-release.yml index 69c5e1a32..341b13c9c 100644 --- a/.github/workflows/prod-release.yml +++ b/.github/workflows/prod-release.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: 24 + node-version: '24.15' registry-url: https://registry.npmjs.org cache: 'npm' diff --git a/.node-version b/.node-version index a45fd52cc..5bf4400f2 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -24 +24.15.0 diff --git a/.nvmrc b/.nvmrc index a45fd52cc..5bf4400f2 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24 +24.15.0 diff --git a/Dockerfile b/Dockerfile index 743615415..995b56f8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Image: ghcr.io/singularity-ng/singularity-foundry # Used by: end users via docker run # ────────────────────────────────────────────── -FROM node:24-slim AS runtime +FROM node:24.15-slim AS runtime # Git is required for SF's git operations RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/docs/dev/agent-knowledge-index.md b/docs/dev/agent-knowledge-index.md index ca7ce2999..7e75f0ef8 100644 --- a/docs/dev/agent-knowledge-index.md +++ b/docs/dev/agent-knowledge-index.md @@ -162,7 +162,6 @@ Use when: Read first: - `/Users/lexchristopherson/.sf/docs/building-coding-agents/01-work-decomposition.md` -- `/Users/lexchristopherson/.sf/docs/building-coding-agents/06-maximizing-agent-autonomy-superpowers.md` - `/Users/lexchristopherson/.sf/docs/building-coding-agents/11-god-tier-context-engineering.md` - `/Users/lexchristopherson/.sf/docs/building-coding-agents/12-handling-ambiguity-contradiction.md` - `/Users/lexchristopherson/.sf/docs/building-coding-agents/26-cross-cutting-themes-where-all-4-models-converge.md` diff --git a/docs/dev/building-coding-agents/06-maximizing-agent-autonomy-superpowers.md b/docs/dev/building-coding-agents/06-maximizing-agent-autonomy-superpowers.md deleted file mode 100644 index 2d5802580..000000000 --- a/docs/dev/building-coding-agents/06-maximizing-agent-autonomy-superpowers.md +++ /dev/null @@ -1,44 +0,0 @@ -# Maximizing Agent Autonomy & Superpowers - -### The Foundational Insight - -> Autonomy comes from **self-correction**, not from getting it right the first time. The power isn't in the initial generation — it's in iteration speed and feedback signal quality. - -### The Essential Tool Arsenal - -| Category | Tools | Why | -|----------|-------|-----| -| **Execution Environment** | Terminal, filesystem, git, package manager | Closes the write → run → debug → verify loop | -| **Verification** | Test runner, linter, type checker, security scanner | Ground truth over self-assessment | -| **Observation** | Logs, browser/renderer, performance profiler | Sees what users would see | -| **Exploration** | Code search, documentation lookup, web research | Self-directed learning | -| **Recovery** | Git revert, branch management, checkpoints | Safety net that enables boldness | - -### Self-Verification Architecture - -Every task completion should self-evaluate against a checklist: -1. Does the code compile? -2. Do all existing tests still pass? -3. Do new tests pass? -4. Does the application actually start? -5. Can I exercise the feature and see expected behavior? -6. Does this match acceptance criteria point by point? - -### Debugging Superpowers - -- **Temporary instrumentation:** Add logging, remove after diagnosis -- **Bisection:** Walk back through changes to find where regression was introduced -- **Minimal reproduction:** Strip away everything except exact conditions that trigger failure -- **Exploratory tests:** Quick throwaway scripts to test hypotheses - -### Meta-Cognitive Layer - -- **Scratchpad:** External reasoning space to track hypotheses, attempts, and outcomes -- **Stuck detection:** After N failed attempts, trigger step-back with fresh context and explicitly different approach -- **Structured escalation:** "Here's what I'm trying, here's what I've tried, here's what I think the issue is, here's what I need from you" - -### The Philosophy - -> You're not trying to build an agent that doesn't make mistakes. You're building one that **catches and fixes its own mistakes faster than a human would notice them**. Not intelligence — **closed-loop execution with rich feedback**. - ---- diff --git a/docs/dev/building-coding-agents/README.md b/docs/dev/building-coding-agents/README.md index ea5b8eb81..921400bf6 100644 --- a/docs/dev/building-coding-agents/README.md +++ b/docs/dev/building-coding-agents/README.md @@ -9,7 +9,6 @@ - [03. State Machine & Context Management](./03-state-machine-context-management.md) - [04. Optimal Storage for Project Context](./04-optimal-storage-for-project-context.md) - [05. Parallelization Strategy](./05-parallelization-strategy.md) -- [06. Maximizing Agent Autonomy & Superpowers](./06-maximizing-agent-autonomy-superpowers.md) - [07. System Prompt & LLM vs Deterministic Split](./07-system-prompt-llm-vs-deterministic-split.md) - [08. Speed Optimization](./08-speed-optimization.md) - [09. Top 10 Tips for a World-Class Agent](./09-top-10-tips-for-a-world-class-agent.md) @@ -34,4 +33,3 @@ --- *Split into per-section files for surgical context loading.* - diff --git a/package.json b/package.json index a38968293..2c422bbc9 100644 --- a/package.json +++ b/package.json @@ -37,9 +37,9 @@ "configDir": ".sf" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, - "packageManager": "npm@10.9.3", + "packageManager": "npm@11.13.0", "scripts": { "build:pi-tui": "npm --workspace @singularity-forge/pi-tui run build", "build:pi-ai": "npm --workspace @singularity-forge/pi-ai run build", diff --git a/packages/daemon/package.json b/packages/daemon/package.json index 32b135756..5ce3715a5 100644 --- a/packages/daemon/package.json +++ b/packages/daemon/package.json @@ -39,7 +39,7 @@ "typescript": "^5.4.0" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "files": [ "dist", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index d804205d2..117c05361 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -37,7 +37,7 @@ "typescript": "^5.4.0" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "files": [ "dist", diff --git a/packages/native/package.json b/packages/native/package.json index 55192ad75..10c834afb 100644 --- a/packages/native/package.json +++ b/packages/native/package.json @@ -89,7 +89,7 @@ "dist" ], "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "optionalDependencies": { "@singularity-forge/engine-darwin-arm64": ">=2.75.0", diff --git a/packages/pi-agent-core/package.json b/packages/pi-agent-core/package.json index d5fadba8c..90fcb7334 100644 --- a/packages/pi-agent-core/package.json +++ b/packages/pi-agent-core/package.json @@ -16,6 +16,6 @@ }, "dependencies": {}, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/packages/pi-ai/package.json b/packages/pi-ai/package.json index 44d3d9cb4..e57b3fcb7 100644 --- a/packages/pi-ai/package.json +++ b/packages/pi-ai/package.json @@ -44,6 +44,6 @@ "@smithy/node-http-handler": "^4.5.0" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/packages/pi-coding-agent/package.json b/packages/pi-coding-agent/package.json index da8102125..97f8e899b 100644 --- a/packages/pi-coding-agent/package.json +++ b/packages/pi-coding-agent/package.json @@ -45,6 +45,6 @@ "@types/express": "^4.17.21" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/packages/pi-coding-agent/src/core/exec.ts b/packages/pi-coding-agent/src/core/exec.ts index 9d12e8c23..3225ac881 100644 --- a/packages/pi-coding-agent/src/core/exec.ts +++ b/packages/pi-coding-agent/src/core/exec.ts @@ -36,6 +36,18 @@ export async function execCommand( cwd: string, options?: ExecOptions, ): Promise { + // Combine user abort + timeout into one signal (Node 19+ AbortSignal.any). + const sigs: AbortSignal[] = []; + if (options?.signal) sigs.push(options.signal); + if (options?.timeout && options.timeout > 0) + sigs.push(AbortSignal.timeout(options.timeout)); + const signal = + sigs.length === 0 + ? undefined + : sigs.length === 1 + ? sigs[0] + : AbortSignal.any(sigs); + return new Promise((resolve) => { const proc = spawn(command, args, { cwd, @@ -43,41 +55,25 @@ export async function execCommand( // resolution. Without this, spawn fails with ENOENT or EINVAL (#2854). shell: process.platform === "win32", stdio: ["ignore", "pipe", "pipe"], + // spawn auto-sends killSignal when this aborts. + signal, + killSignal: "SIGTERM", }); let stdout = ""; let stderr = ""; - let killed = false; - let timeoutId: NodeJS.Timeout | undefined; + let killTimer: NodeJS.Timeout | undefined; - const killProcess = () => { - if (!killed) { - killed = true; - proc.kill("SIGTERM"); - // Force kill after 5 seconds if SIGTERM doesn't work - setTimeout(() => { - if (!proc.killed) { - proc.kill("SIGKILL"); - } + // Force SIGKILL 5s after SIGTERM if the process refuses to exit. + signal?.addEventListener( + "abort", + () => { + killTimer = setTimeout(() => { + if (!proc.killed) proc.kill("SIGKILL"); }, 5000); - } - }; - - // Handle abort signal - if (options?.signal) { - if (options.signal.aborted) { - killProcess(); - } else { - options.signal.addEventListener("abort", killProcess, { once: true }); - } - } - - // Handle timeout - if (options?.timeout && options.timeout > 0) { - timeoutId = setTimeout(() => { - killProcess(); - }, options.timeout); - } + }, + { once: true }, + ); proc.stdout?.on("data", (data) => { stdout += data.toString(); @@ -87,20 +83,17 @@ export async function execCommand( stderr += data.toString(); }); - proc.on("close", (code) => { - if (timeoutId) clearTimeout(timeoutId); - if (options?.signal) { - options.signal.removeEventListener("abort", killProcess); - } - resolve({ stdout, stderr, code: code ?? 0, killed }); - }); + const finish = (code: number) => { + if (killTimer) clearTimeout(killTimer); + resolve({ + stdout, + stderr, + code, + killed: signal?.aborted ?? false, + }); + }; - proc.on("error", (_err) => { - if (timeoutId) clearTimeout(timeoutId); - if (options?.signal) { - options.signal.removeEventListener("abort", killProcess); - } - resolve({ stdout, stderr, code: 1, killed }); - }); + proc.on("close", (code) => finish(code ?? 0)); + proc.on("error", () => finish(1)); }); } diff --git a/packages/pi-tui/package.json b/packages/pi-tui/package.json index 20c06069a..67cc053b1 100644 --- a/packages/pi-tui/package.json +++ b/packages/pi-tui/package.json @@ -28,6 +28,6 @@ "koffi": "^2.9.0" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/packages/rpc-client/package.json b/packages/rpc-client/package.json index 29e8eb910..ecd3e868f 100644 --- a/packages/rpc-client/package.json +++ b/packages/rpc-client/package.json @@ -29,6 +29,6 @@ "test": "node --test dist/rpc-client.test.js" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/pkg/package.json b/pkg/package.json index 6e33047c6..b2eda74b8 100644 --- a/pkg/package.json +++ b/pkg/package.json @@ -2,7 +2,7 @@ "name": "sf", "version": "2.75.0", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "piConfig": { "name": "sf", diff --git a/src/headless-query.ts b/src/headless-query.ts index 76e3b5028..caa9d2ecd 100644 --- a/src/headless-query.ts +++ b/src/headless-query.ts @@ -17,12 +17,11 @@ import { homedir } from "node:os"; import { join } from "node:path"; -import { fileURLToPath } from "node:url"; import { createJiti } from "@mariozechner/jiti"; import { resolveBundledSourceResource } from "./bundled-resource-path.js"; import type { SFState } from "./resources/extensions/sf/types.js"; -const jiti = createJiti(fileURLToPath(import.meta.url), { +const jiti = createJiti(import.meta.filename, { interopDefault: true, debug: false, }); diff --git a/src/resources/extensions/browser-tools/package.json b/src/resources/extensions/browser-tools/package.json index 6d6869ef1..8b38b927d 100644 --- a/src/resources/extensions/browser-tools/package.json +++ b/src/resources/extensions/browser-tools/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "scripts": { "test": "node --test tests/*.test.mjs" diff --git a/src/resources/extensions/claude-code-cli/package.json b/src/resources/extensions/claude-code-cli/package.json index dd35d104d..476cd0564 100644 --- a/src/resources/extensions/claude-code-cli/package.json +++ b/src/resources/extensions/claude-code-cli/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/resources/extensions/cmux/package.json b/src/resources/extensions/cmux/package.json index b82299376..97308c7be 100644 --- a/src/resources/extensions/cmux/package.json +++ b/src/resources/extensions/cmux/package.json @@ -4,7 +4,7 @@ "type": "module", "description": "cmux integration library — used by other extensions, not an extension itself", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": {} } diff --git a/src/resources/extensions/context7/package.json b/src/resources/extensions/context7/package.json index ec5c63fc1..04f1919b2 100644 --- a/src/resources/extensions/context7/package.json +++ b/src/resources/extensions/context7/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/resources/extensions/genai-proxy/package.json b/src/resources/extensions/genai-proxy/package.json index aa0b951fe..bb2b3f8ea 100644 --- a/src/resources/extensions/genai-proxy/package.json +++ b/src/resources/extensions/genai-proxy/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/resources/extensions/google-search/package.json b/src/resources/extensions/google-search/package.json index ef576ff93..b6bfecf35 100644 --- a/src/resources/extensions/google-search/package.json +++ b/src/resources/extensions/google-search/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/resources/extensions/package.json b/src/resources/extensions/package.json index 5711d93c7..b0c212573 100644 --- a/src/resources/extensions/package.json +++ b/src/resources/extensions/package.json @@ -1,6 +1,6 @@ { "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/src/resources/extensions/sf-permissions/package.json b/src/resources/extensions/sf-permissions/package.json index c7c369a37..14f5bfe46 100644 --- a/src/resources/extensions/sf-permissions/package.json +++ b/src/resources/extensions/sf-permissions/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/resources/extensions/sf/package.json b/src/resources/extensions/sf/package.json index ba5eca5ad..041f6e50a 100644 --- a/src/resources/extensions/sf/package.json +++ b/src/resources/extensions/sf/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/resources/extensions/sf/tests/complete-task.test.ts b/src/resources/extensions/sf/tests/complete-task.test.ts index c1c2fae58..042c3d815 100644 --- a/src/resources/extensions/sf/tests/complete-task.test.ts +++ b/src/resources/extensions/sf/tests/complete-task.test.ts @@ -4,9 +4,6 @@ import * as path from "node:path"; import { AutoSession } from "../auto/session.ts"; import { resolveDispatch } from "../auto-dispatch.ts"; import { -import { test } from "vitest"; - -test("complete task.test", () => { _getAdapter, closeDatabase, getSliceTasks, @@ -21,7 +18,9 @@ test("complete task.test", () => { import { handleCompleteTask } from "../tools/complete-task.ts"; import { executeTaskComplete } from "../tools/workflow-tool-executors.ts"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("complete task.test", async () => { const { assertEq, assertTrue, assertMatch, report } = createTestContext(); // ═══════════════════════════════════════════════════════════════════════════ @@ -981,5 +980,4 @@ console.log("\n=== complete-task: semantic validation hardening ==="); // ═══════════════════════════════════════════════════════════════════════════ report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/derive-state-db-disk-reconcile.test.ts b/src/resources/extensions/sf/tests/derive-state-db-disk-reconcile.test.ts index 760695b2b..ad977f61d 100644 --- a/src/resources/extensions/sf/tests/derive-state-db-disk-reconcile.test.ts +++ b/src/resources/extensions/sf/tests/derive-state-db-disk-reconcile.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("derive state db disk reconcile.test", () => { * derive-state-db-disk-reconcile.test.ts — #2416 * * After migration to DB-backed state, milestones that exist on disk @@ -21,7 +18,9 @@ import { } from "../sf-db.ts"; import { deriveStateFromDb, invalidateStateCache } from "../state.ts"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("derive state db disk reconcile.test", () => { const { assertEq, assertTrue, report } = createTestContext(); function createFixtureBase(): string { @@ -135,5 +134,4 @@ main().catch((err) => { console.error(err); process.exit(1); }); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/detection.test.ts b/src/resources/extensions/sf/tests/detection.test.ts index 2f5b42d96..44ad674dd 100644 --- a/src/resources/extensions/sf/tests/detection.test.ts +++ b/src/resources/extensions/sf/tests/detection.test.ts @@ -313,7 +313,7 @@ test("detectProjectSignals: packageManager field overrides lockfile heuristic", writeFileSync(join(dir, "bun.lockb"), "", "utf-8"); writeFileSync( join(dir, "package.json"), - JSON.stringify({ packageManager: "npm@10.9.3" }), + JSON.stringify({ packageManager: "npm@11.13.0" }), "utf-8", ); diff --git a/src/resources/extensions/sf/tests/doctor-fix-flag.test.ts b/src/resources/extensions/sf/tests/doctor-fix-flag.test.ts index 8b3de6a53..454f6217d 100644 --- a/src/resources/extensions/sf/tests/doctor-fix-flag.test.ts +++ b/src/resources/extensions/sf/tests/doctor-fix-flag.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("doctor fix flag.test", () => { * Regression test for #1919: --fix flag not stripped before positional parse. * * parseDoctorArgs("--fix") must: @@ -12,7 +9,9 @@ test("doctor fix flag.test", () => { import { parseDoctorArgs } from "../commands-handlers.js"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("doctor fix flag.test", () => { const { assertEq, assertTrue, report } = createTestContext(); async function main(): Promise { @@ -105,5 +104,4 @@ async function main(): Promise { } main(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/draft-promotion.test.ts b/src/resources/extensions/sf/tests/draft-promotion.test.ts index b7859b512..d8e6528e0 100644 --- a/src/resources/extensions/sf/tests/draft-promotion.test.ts +++ b/src/resources/extensions/sf/tests/draft-promotion.test.ts @@ -1,7 +1,4 @@ import { -import { test } from "vitest"; - -test("draft promotion.test", () => { existsSync, mkdirSync, mkdtempSync, @@ -13,7 +10,9 @@ import { join } from "node:path"; import { invalidateAllCaches } from "../cache.js"; import { resolveMilestoneFile } from "../paths.js"; import { deriveState } from "../state.js"; +import { test } from "vitest"; +test("draft promotion.test", async () => { let passed = 0; let failed = 0; @@ -182,5 +181,4 @@ rmSync(tmpBase3, { recursive: true, force: true }); console.log(`\ndraft-promotion: ${passed} passed, ${failed} failed`); if (failed > 0) process.exit(1); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/integration/git-self-heal.test.ts b/src/resources/extensions/sf/tests/integration/git-self-heal.test.ts index 2ae3e6cc5..efa5c7e6e 100644 --- a/src/resources/extensions/sf/tests/integration/git-self-heal.test.ts +++ b/src/resources/extensions/sf/tests/integration/git-self-heal.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("git self heal.test", () => { * git-self-heal.test.ts — Integration tests for git self-healing utilities. * * Uses real temporary git repos with deliberately broken state. @@ -14,7 +11,9 @@ import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { abortAndReset, formatGitError } from "../../git-self-heal.js"; +import { test } from "vitest"; +test("git self heal.test", () => { // ─── Helpers ───────────────────────────────────────────────────────── function makeTempRepo(): string { @@ -184,5 +183,4 @@ console.log("── formatGitError ──"); } console.log("\nāœ… All git-self-heal tests passed"); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/integration/queue-completed-milestone-perf.test.ts b/src/resources/extensions/sf/tests/integration/queue-completed-milestone-perf.test.ts index b5157f297..4d5b4cd3a 100644 --- a/src/resources/extensions/sf/tests/integration/queue-completed-milestone-perf.test.ts +++ b/src/resources/extensions/sf/tests/integration/queue-completed-milestone-perf.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("queue completed milestone perf.test", () => { * Regression test for #2379: /sf queue fails with 429 rate limit on projects * with many completed milestones. * @@ -21,7 +18,9 @@ import { join } from "node:path"; import { buildExistingMilestonesContext } from "../../guided-flow-queue.ts"; import type { MilestoneRegistryEntry, SFState } from "../../types.ts"; import { createTestContext } from "../test-helpers.ts"; +import { test } from "vitest"; +test("queue completed milestone perf.test", async () => { const { assertTrue, report } = createTestContext(); // ─── Fixture: project with many completed milestones ───────────────────── @@ -171,5 +170,4 @@ assertTrue( rmSync(tmpBase, { recursive: true, force: true }); report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/integration/token-savings.test.ts b/src/resources/extensions/sf/tests/integration/token-savings.test.ts index 0a6ad3b77..abb744823 100644 --- a/src/resources/extensions/sf/tests/integration/token-savings.test.ts +++ b/src/resources/extensions/sf/tests/integration/token-savings.test.ts @@ -8,9 +8,6 @@ import assert from "node:assert/strict"; import { -import { test } from "vitest"; - -test("token savings.test", () => { mkdirSync, mkdtempSync, readFileSync, @@ -27,7 +24,9 @@ import { } from "../../context-store.ts"; import { migrateFromMarkdown } from "../../md-importer.ts"; import { closeDatabase, openDatabase } from "../../sf-db.ts"; +import { test } from "vitest"; +test("token savings.test", () => { // ─── Fixture Generators ──────────────────────────────────────────────────── /** @@ -534,5 +533,4 @@ assert.match( ); // ─── Report ──────────────────────────────────────────────────────────────── - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/merge-conflict-stops-loop.test.ts b/src/resources/extensions/sf/tests/merge-conflict-stops-loop.test.ts index a00a875dd..cdeba9edd 100644 --- a/src/resources/extensions/sf/tests/merge-conflict-stops-loop.test.ts +++ b/src/resources/extensions/sf/tests/merge-conflict-stops-loop.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("merge conflict stops loop.test", () => { * merge-conflict-stops-loop.test.ts — #2330 * * When a squash merge has real code conflicts (not just .sf/ files), @@ -14,7 +11,9 @@ test("merge conflict stops loop.test", () => { import { readFileSync } from "node:fs"; import { join } from "node:path"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("merge conflict stops loop.test", () => { const { assertTrue, report } = createTestContext(); const resolverPath = join(import.meta.dirname, "..", "worktree-resolver.ts"); @@ -70,5 +69,4 @@ if (instanceofIdx > 0) { } report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/planning-crossval.test.ts b/src/resources/extensions/sf/tests/planning-crossval.test.ts index efef44be4..fcb836506 100644 --- a/src/resources/extensions/sf/tests/planning-crossval.test.ts +++ b/src/resources/extensions/sf/tests/planning-crossval.test.ts @@ -10,9 +10,6 @@ import { renderPlanFromDb, renderRoadmapFromDb } from "../markdown-renderer.ts"; import { parsePlan } from "../parsers.ts"; import { parseRoadmapSlices } from "../roadmap-slices.ts"; import { -import { test } from "vitest"; - -test("planning crossval.test", () => { closeDatabase, getMilestoneSlices, insertMilestone, @@ -21,7 +18,9 @@ test("planning crossval.test", () => { openDatabase, } from "../sf-db.ts"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("planning crossval.test", async () => { const { assertEq, assertTrue, report } = createTestContext(); // ─── Fixture Helpers ─────────────────────────────────────────────────────── @@ -424,5 +423,4 @@ console.log("\n=== planning-crossval Test 3: Sequence ordering parity ==="); } report(); - -}); \ No newline at end of file +}); diff --git a/src/resources/extensions/sf/tests/recovery-attempts-reset.test.ts b/src/resources/extensions/sf/tests/recovery-attempts-reset.test.ts index 733268e2b..bd4a98664 100644 --- a/src/resources/extensions/sf/tests/recovery-attempts-reset.test.ts +++ b/src/resources/extensions/sf/tests/recovery-attempts-reset.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("recovery attempts reset.test", () => { * Regression test for #2322: recoveryAttempts persists across re-dispatches, * causing instant task skip. * @@ -23,7 +20,9 @@ import { writeUnitRuntimeRecord, } from "../unit-runtime.ts"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("recovery attempts reset.test", () => { const { assertEq, assertTrue, report } = createTestContext(); // ═══ Setup ════════════════════════════════════════════════════════════════════ @@ -198,5 +197,4 @@ try { } report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/slice-disk-reconcile.test.ts b/src/resources/extensions/sf/tests/slice-disk-reconcile.test.ts index ecb1d24de..96a789ec9 100644 --- a/src/resources/extensions/sf/tests/slice-disk-reconcile.test.ts +++ b/src/resources/extensions/sf/tests/slice-disk-reconcile.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("slice disk reconcile.test", () => { * slice-disk-reconcile.test.ts — #2533 * * Slices that exist on disk (in ROADMAP.md) but are missing from the SQLite @@ -27,7 +24,9 @@ import { } from "../sf-db.ts"; import { deriveStateFromDb, invalidateStateCache } from "../state.ts"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("slice disk reconcile.test", () => { const { assertEq, assertTrue, report } = createTestContext(); function createFixtureBase(): string { @@ -296,5 +295,4 @@ main().catch((err) => { console.error(err); process.exit(1); }); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/survivor-branch-complete.test.ts b/src/resources/extensions/sf/tests/survivor-branch-complete.test.ts index b91795204..fde13ca92 100644 --- a/src/resources/extensions/sf/tests/survivor-branch-complete.test.ts +++ b/src/resources/extensions/sf/tests/survivor-branch-complete.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("survivor branch complete.test", () => { * Regression test for #2358: Survivor branch recovery skipped in phase=complete. * * When bootstrapAutoSession finds a survivor milestone branch and the derived @@ -16,7 +13,9 @@ test("survivor branch complete.test", () => { */ import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("survivor branch complete.test", () => { const { assertEq, report } = createTestContext(); // ═══ Test: survivor branch detection conditions ══════════════════════════════ @@ -140,5 +139,4 @@ const { assertEq, report } = createTestContext(); } report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/unit-runtime.test.ts b/src/resources/extensions/sf/tests/unit-runtime.test.ts index a950cf241..d9d67a1f0 100644 --- a/src/resources/extensions/sf/tests/unit-runtime.test.ts +++ b/src/resources/extensions/sf/tests/unit-runtime.test.ts @@ -1,8 +1,5 @@ import assert from "node:assert/strict"; import { -import { test } from "vitest"; - -test("unit runtime.test", () => { mkdirSync, mkdtempSync, readdirSync, @@ -19,7 +16,9 @@ import { readUnitRuntimeRecord, writeUnitRuntimeRecord, } from "../unit-runtime.ts"; +import { test } from "vitest"; +test("unit runtime.test", async () => { const base = mkdtempSync(join(tmpdir(), "sf-unit-runtime-test-")); const tasksDir = join( base, @@ -522,5 +521,4 @@ console.log("\n=== must-haves: substring matching (no backtick tokens) ==="); rmSync(mhBase, { recursive: true, force: true }); rmSync(base, { recursive: true, force: true }); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/worker-registry.test.ts b/src/resources/extensions/sf/tests/worker-registry.test.ts index 58d4459f1..6b23dacd2 100644 --- a/src/resources/extensions/sf/tests/worker-registry.test.ts +++ b/src/resources/extensions/sf/tests/worker-registry.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("worker registry.test", () => { * Tests for the parallel worker registry used by the dashboard overlay. * * Verifies worker lifecycle (register → update → cleanup), batch grouping, @@ -17,7 +14,9 @@ import { resetWorkerRegistry, updateWorker, } from "../../subagent/worker-registry.ts"; +import { test } from "vitest"; +test("worker registry.test", () => { // ─── Setup ──────────────────────────────────────────────────────────────────── resetWorkerRegistry(); @@ -169,5 +168,4 @@ assert.deepStrictEqual( ); // ─── Summary ────────────────────────────────────────────────────────────────── - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/worktree-health-monorepo.test.ts b/src/resources/extensions/sf/tests/worktree-health-monorepo.test.ts index 3cd4832d2..91551aebb 100644 --- a/src/resources/extensions/sf/tests/worktree-health-monorepo.test.ts +++ b/src/resources/extensions/sf/tests/worktree-health-monorepo.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("worktree health monorepo.test", () => { * worktree-health-monorepo.test.ts — #2347 * * The worktree health check in auto/phases.ts falsely rejects monorepos @@ -12,7 +9,9 @@ test("worktree health monorepo.test", () => { import { readFileSync } from "node:fs"; import { join } from "node:path"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("worktree health monorepo.test", () => { const { assertTrue, report } = createTestContext(); const srcPath = join(import.meta.dirname, "..", "auto", "phases.ts"); @@ -81,5 +80,4 @@ assertTrue( ); report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/worktree-submodule-safety.test.ts b/src/resources/extensions/sf/tests/worktree-submodule-safety.test.ts index fd8331cb9..c13d1682b 100644 --- a/src/resources/extensions/sf/tests/worktree-submodule-safety.test.ts +++ b/src/resources/extensions/sf/tests/worktree-submodule-safety.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("worktree submodule safety.test", () => { * worktree-submodule-safety.test.ts — #2337 * * Worktree teardown (removeWorktree) uses --force which destroys @@ -12,7 +9,9 @@ test("worktree submodule safety.test", () => { import { readFileSync } from "node:fs"; import { join } from "node:path"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("worktree submodule safety.test", () => { const { assertTrue, report } = createTestContext(); const srcPath = join(import.meta.dirname, "..", "worktree-manager.ts"); @@ -66,5 +65,4 @@ assertTrue( ); report(); - }); \ No newline at end of file diff --git a/src/resources/extensions/sf/tests/worktree-sync-overwrite-loop.test.ts b/src/resources/extensions/sf/tests/worktree-sync-overwrite-loop.test.ts index 2dd3ca564..4f62e60c1 100644 --- a/src/resources/extensions/sf/tests/worktree-sync-overwrite-loop.test.ts +++ b/src/resources/extensions/sf/tests/worktree-sync-overwrite-loop.test.ts @@ -1,7 +1,4 @@ /** -import { test } from "vitest"; - -test("worktree sync overwrite loop.test", () => { * worktree-sync-overwrite-loop.test.ts — Regression tests for #1886. * * Reproduces the infinite validate-milestone loop caused by two bugs @@ -34,7 +31,9 @@ import { join } from "node:path"; import { syncProjectRootToWorktree } from "../auto-worktree.ts"; import { createTestContext } from "./test-helpers.ts"; +import { test } from "vitest"; +test("worktree sync overwrite loop.test", () => { const { assertTrue, assertEq, report } = createTestContext(); function createBase(name: string): string { @@ -209,5 +208,4 @@ main().catch((error) => { console.error(error); process.exit(1); }); - }); \ No newline at end of file diff --git a/src/resources/extensions/universal-config/package.json b/src/resources/extensions/universal-config/package.json index dfa821dc2..2a6bf796e 100644 --- a/src/resources/extensions/universal-config/package.json +++ b/src/resources/extensions/universal-config/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "pi": { "extensions": [ diff --git a/src/worktree-cli.ts b/src/worktree-cli.ts index 65e5df61c..6452a3ca5 100644 --- a/src/worktree-cli.ts +++ b/src/worktree-cli.ts @@ -19,13 +19,12 @@ */ import { existsSync } from "node:fs"; -import { fileURLToPath } from "node:url"; import { createJiti } from "@mariozechner/jiti"; import chalk from "chalk"; import { resolveBundledSourceResource } from "./bundled-resource-path.js"; import { generateWorktreeName } from "./worktree-name-gen.js"; -const jiti = createJiti(fileURLToPath(import.meta.url), { +const jiti = createJiti(import.meta.filename, { interopDefault: true, debug: false, }); diff --git a/studio/package.json b/studio/package.json index 3ca77cf30..4407339e2 100644 --- a/studio/package.json +++ b/studio/package.json @@ -29,6 +29,6 @@ "typescript": "^5.9.3" }, "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" } } diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 30e8a6606..04eddc7c2 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -31,7 +31,7 @@ }, "extensionKind": ["workspace"], "engines": { - "node": ">=24.0.0", + "node": ">=24.15.0", "vscode": "^1.95.0" }, "categories": [ diff --git a/web/package.json b/web/package.json index aeaa38f08..ce1a33968 100644 --- a/web/package.json +++ b/web/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "engines": { - "node": ">=24.0.0" + "node": ">=24.15.0" }, "scripts": { "dev": "next dev",