chore: consolidate test files into __tests__/ dirs and clean stray engine artifacts

- Move all co-located *.test.* files into sibling __tests__/ directories so the
  layout is consistent across packages (159 renames + content-rewrite moves).
  Updates relative imports, vi.mock specifiers, and __dirname/import.meta.url
  path resolutions where tests read fixtures from disk.
- Drop tracked tsc-emit alongside engine .ts sources (auth-storage/logger/
  skill-resolver/context-limit-detector/pi.{js,d.ts,*.map}). These were
  accidentally committed in a merge and the stale pi.js was masking a real
  test-mock vs source mismatch (tests imported "../pi.js" and vite preferred
  the stale build over pi.ts).
- Add packages/engine/.gitignore to block future src/*.{js,d.ts,map}.
- Refactor plugin pi-module seams (openclaw/paperclip/hermes) to ESM-import
  createFnAgent / promptWithFallback / describeModel from @fusion/engine
  instead of require()-ing packages/engine/src/pi.js. Adds @fusion/engine to
  the two plugin package.jsons that were missing it; exports describeModel
  from the engine public API.
- Fix engine test mocks now that they run against current pi.ts: add
  ModelRegistry.create static to mocks in pi.test.ts and pi-create-fn-agent
  .test.ts; switch three boundary-result toEqual assertions to toMatchObject
  so the new content/isError fields don't trip exact-match comparison.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-24 18:45:10 -07:00
parent ab98cc3719
commit bce7dbd96f
232 changed files with 1311 additions and 26008 deletions

View File

@@ -0,0 +1,91 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { generateWorktreeName, ADJECTIVES, NOUNS } from "../worktree-names.js";
describe("generateWorktreeName", () => {
let tempDir: string;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "fn-wt-test-"));
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
it("returns a name matching adjective-noun pattern", () => {
const name = generateWorktreeName(tempDir);
expect(name).toMatch(/^[a-z]+-[a-z]+$/);
});
it("returns different names on subsequent calls (not deterministic)", () => {
// Generate several names — at least some should differ
const names = new Set<string>();
for (let i = 0; i < 20; i++) {
names.add(generateWorktreeName(tempDir));
}
// With 2500 combinations and 20 draws, we'd expect multiple unique names
expect(names.size).toBeGreaterThan(1);
});
it("avoids collision with existing .worktrees/ directories", () => {
// Create .worktrees dir with a known name
const worktreesDir = join(tempDir, ".worktrees");
mkdirSync(worktreesDir, { recursive: true });
// We need to force a collision — mock Math.random to always pick the same words
const originalRandom = Math.random;
Math.random = () => 0; // Will always pick first adjective and first noun
try {
// First call: should get the base name (e.g., "amber-badger")
const firstName = generateWorktreeName(tempDir);
expect(firstName).toMatch(/^[a-z]+-[a-z]+$/);
expect(firstName).not.toMatch(/-\d+$/); // no suffix
// Create that directory to simulate collision
mkdirSync(join(worktreesDir, firstName));
// Second call: should get a suffixed name
const secondName = generateWorktreeName(tempDir);
expect(secondName).toBe(`${firstName}-2`);
// Create that too
mkdirSync(join(worktreesDir, secondName));
// Third call: should get -3
const thirdName = generateWorktreeName(tempDir);
expect(thirdName).toBe(`${firstName}-3`);
} finally {
Math.random = originalRandom;
}
});
it("works when .worktrees/ directory does not exist", () => {
// tempDir has no .worktrees/ subdirectory
const name = generateWorktreeName(tempDir);
expect(name).toMatch(/^[a-z]+-[a-z]+$/);
});
it("ADJECTIVES and NOUNS share no common elements", () => {
const overlap = ADJECTIVES.filter((w) => NOUNS.includes(w));
expect(overlap).toEqual([]);
});
it("ADJECTIVES and NOUNS each have exactly 50 entries", () => {
expect(ADJECTIVES).toHaveLength(50);
expect(NOUNS).toHaveLength(50);
});
it("never generates a tautological name (adjective === noun)", () => {
const names: string[] = [];
for (let i = 0; i < 250; i++) {
names.push(generateWorktreeName(tempDir));
}
for (const name of names) {
const parts = name.split("-");
expect(parts[0]).not.toBe(parts[1]);
}
});
});