Files
Julius Brussee 82864c8f4c feat: ship Caveman 2.0.0 — engine, proxy, SDKs, unified CLI
Single-commit port of the Caveman 2 tree onto the original repo history
(candidate caveman-2@88878a4 applied over main@3098342). No unrelated-history
merge; original history untouched.

Preserved v1 surfaces:
- skills/caveman/SKILL.md byte-for-byte, plus plugin mirror and caveman.skill zip
- legacy CI (Node 18/20/22 installer + Python 3.11 suites) alongside engine-ci
- cli/install.js compatibility shim forwarding to bin/install.js
- .codex/config.toml ships both hooks and codex_hooks for older Codex (#617)
- README Trendshift + Skills.sh badges and local star-history asset
- v1.10.0-pinned curl installs; benchmarks/tmp-starcharts ignore rules

Fixed for public same-repo release:
- SECURITY.md vulnerability reporting points at this repository
- release-binaries.yml publishes to this repo via job-scoped GITHUB_TOKEN
  (cross-repo PAT removed); binary-release environment still gates signing
- packages/cli/PUBLISHING.md rewritten for packages/ layout and same-repo flow
- profile-contract and provider-catalog lanes skip lane-scope gates on
  initial import so the launch PR can gate on their real validation steps
- ANNOUNCEMENT.md network claim corrected: compression is local; requests
  still go to the provider you configured

Caveman 2 stays opt-in: bin-v1.0.0 binaries and @caveman-ai/cli publish
separately after this lands and soaks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BLvb5QniwYjmcawyssQNw9
2026-08-11 16:46:10 +02:00

58 lines
2.5 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { isolatedCliEnv, runCli } from "./_cli.mjs";
test("learn implement launches a supported agent with the guarded learn prompt", async () => {
const isolated = isolatedCliEnv();
const cwd = mkdtempSync(join(tmpdir(), "caveman-learn-implement-"));
const argvPath = join(isolated.home, "agent-argv.json");
const claude = join(isolated.home, "bin", "claude");
writeFileSync(claude, `#!/usr/bin/env node
import { writeFileSync } from "node:fs";
writeFileSync(process.env.AGENT_ARGV_PATH, JSON.stringify(process.argv.slice(2)));
`, { mode: 0o755 });
mkdirSync(join(isolated.home, ".caveman-cloud"), { recursive: true });
writeFileSync(join(isolated.home, ".caveman-cloud", "config.json"), JSON.stringify({
wrap: { proxy: false, shrink: false, mcp: false, browse: false },
}));
isolated.env.PATH = `${join(isolated.home, "bin")}:${process.env.PATH}`;
isolated.env.AGENT_ARGV_PATH = argvPath;
try {
const out = await runCli(
["learn", "implement", "claude", "--prompt", "Focus on project instructions first."],
{ env: isolated.env, cwd },
);
assert.equal(out.code, 0, out.stderr);
const argv = JSON.parse(readFileSync(argvPath, "utf8"));
const prompt = argv.at(-1);
assert.match(prompt, /Use the caveman-learn skill/);
assert.match(prompt, /caveman learn report --json/);
assert.match(prompt, /Never edit load_bearing findings/);
assert.match(prompt, /ask before every edit/);
assert.match(prompt, /Focus on project instructions first/);
const skill = join(cwd, ".claude", "skills", "caveman-learn", "SKILL.md");
assert.equal(existsSync(skill), true, "agent handoff must install its safety guide");
assert.match(readFileSync(skill, "utf8"), /Consent per edit/);
assert.match(out.stderr, /learn guide installed/);
} finally {
isolated.cleanup();
}
});
test("learn implement help is short and does not launch an agent", async () => {
const isolated = isolatedCliEnv();
try {
const out = await runCli(["learn", "implement", "--help"], { env: isolated.env });
assert.equal(out.code, 0, out.stderr);
assert.match(out.stdout, /caveman learn implement \[claude\|codex\]/);
assert.match(out.stdout, /asks before every edit/);
} finally {
isolated.cleanup();
}
});