chore: CI workflows, package.json updates, test fixes, docs cleanup
💘 Generated with Crush
Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
parent
f00af5b67f
commit
d9c848132a
58 changed files with 117 additions and 207 deletions
2
.github/workflows/build-native.yml
vendored
2
.github/workflows/build-native.yml
vendored
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
2
.github/workflows/cleanup-dev-versions.yml
vendored
2
.github/workflows/cleanup-dev-versions.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
4
.github/workflows/dev-publish.yml
vendored
4
.github/workflows/dev-publish.yml
vendored
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
4
.github/workflows/next-publish.yml
vendored
4
.github/workflows/next-publish.yml
vendored
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
6
.github/workflows/pipeline.yml
vendored
6
.github/workflows/pipeline.yml
vendored
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
2
.github/workflows/pr-risk.yml
vendored
2
.github/workflows/pr-risk.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
2
.github/workflows/prod-release.yml
vendored
2
.github/workflows/prod-release.yml
vendored
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
24
|
||||
24.15.0
|
||||
|
|
|
|||
2
.nvmrc
2
.nvmrc
|
|
@ -1 +1 @@
|
|||
24
|
||||
24.15.0
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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**.
|
||||
|
||||
---
|
||||
|
|
@ -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.*
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"typescript": "^5.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
"typescript": "^5.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
"dist"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@singularity-forge/engine-darwin-arm64": ">=2.75.0",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,6 @@
|
|||
"@smithy/node-http-handler": "^4.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,6 @@
|
|||
"@types/express": "^4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,18 @@ export async function execCommand(
|
|||
cwd: string,
|
||||
options?: ExecOptions,
|
||||
): Promise<ExecResult> {
|
||||
// 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));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,6 @@
|
|||
"koffi": "^2.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,6 @@
|
|||
"test": "node --test dist/rpc-client.test.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "sf",
|
||||
"version": "2.75.0",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"piConfig": {
|
||||
"name": "sf",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -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": {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -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",
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
|
|
@ -105,5 +104,4 @@ async function main(): Promise<void> {
|
|||
}
|
||||
|
||||
main();
|
||||
|
||||
});
|
||||
|
|
@ -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);
|
||||
|
||||
});
|
||||
|
|
@ -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");
|
||||
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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 ────────────────────────────────────────────────────────────────
|
||||
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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 });
|
||||
|
||||
});
|
||||
|
|
@ -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 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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();
|
||||
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"pi": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,6 +29,6 @@
|
|||
"typescript": "^5.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
},
|
||||
"extensionKind": ["workspace"],
|
||||
"engines": {
|
||||
"node": ">=24.0.0",
|
||||
"node": ">=24.15.0",
|
||||
"vscode": "^1.95.0"
|
||||
},
|
||||
"categories": [
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=24.0.0"
|
||||
"node": ">=24.15.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue