Skip to content

Commit c0080e9

Browse files
JuliusBrusseeclaude
andcommitted
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
1 parent 3098342 commit c0080e9

1,199 files changed

Lines changed: 263173 additions & 2492 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
# Auto detect text files and perform LF normalization
2-
* text=auto
1+
# Text files check out with LF everywhere. Byte-compared fixtures (golden
2+
# files), hook checksums, and generated-output tests break on CRLF checkouts
3+
# otherwise. PowerShell 5.1+ parses LF scripts fine, so .ps1 stays LF too.
4+
* text=auto eol=lf
5+
6+
# Byte-exact fixture committed with CRLF on purpose — never convert.
7+
engine/evals/fixtures/terminal_session.txt -text

.github/workflows/engine-ci.yml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
name: engine-ci
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
go:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
16+
with:
17+
persist-credentials: false
18+
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
19+
with:
20+
go-version-file: go.mod
21+
- run: go build ./...
22+
- run: go vet ./...
23+
- run: go test ./...
24+
25+
typescript:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
29+
with:
30+
persist-credentials: false
31+
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
32+
with:
33+
go-version-file: go.mod
34+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
35+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
36+
with:
37+
node-version: 22
38+
cache: pnpm
39+
# Ubuntu 23.10+ runners restrict unprivileged user namespaces via
40+
# AppArmor; the agent sandbox tests exercise the real userns sandbox.
41+
- name: Allow unprivileged user namespaces for sandbox tests
42+
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
43+
# The CLI conformance suite needs the real proxy; building it here with
44+
# the cached Go toolchain keeps the test inside its 90s budget.
45+
- name: Prebuild caveman-proxy for conformance tests
46+
run: go build -o "$RUNNER_TEMP/caveman-proxy" ./proxy/cmd/caveman-proxy
47+
- run: pnpm install --frozen-lockfile
48+
- run: pnpm -r build
49+
- run: pnpm -r test
50+
env:
51+
CAVEMAN_TEST_PROXY_BIN: ${{ runner.temp }}/caveman-proxy
52+
53+
python:
54+
runs-on: ubuntu-latest
55+
steps:
56+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
57+
with:
58+
persist-credentials: false
59+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
60+
with:
61+
python-version: "3.13"
62+
- run: python -m pip install pytest
63+
- run: python -m pytest -q
64+
working-directory: packages/sdk/python
65+
66+
root-surfaces:
67+
runs-on: ubuntu-latest
68+
steps:
69+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
70+
with:
71+
persist-credentials: false
72+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
73+
with:
74+
node-version: 22
75+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
76+
with:
77+
python-version: "3.13"
78+
- run: python -m pip install pytest==9.0.3
79+
- run: npm test
80+
- run: node --test tests/*.js
81+
- run: python -m unittest discover -s tests -p 'test_*.py'
82+
env:
83+
XDG_DATA_HOME: ${{ runner.temp }}/caveman-xdg
84+
- run: python -m pytest -q tests
85+
working-directory: mem/py
86+
- run: python tests/verify_repo.py
87+
88+
extension:
89+
runs-on: ubuntu-latest
90+
defaults:
91+
run:
92+
working-directory: extension
93+
steps:
94+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
95+
with:
96+
persist-credentials: false
97+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
98+
with:
99+
node-version: 22
100+
cache: npm
101+
cache-dependency-path: extension/package-lock.json
102+
- run: npm ci
103+
- run: npx playwright install --with-deps chromium
104+
- run: npm run package
105+
106+
windows:
107+
runs-on: windows-latest
108+
steps:
109+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
110+
with:
111+
persist-credentials: false
112+
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
113+
with:
114+
go-version-file: go.mod
115+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
116+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
117+
with:
118+
node-version: 22
119+
cache: pnpm
120+
- run: pnpm install --frozen-lockfile
121+
- run: go test ./...
122+
- run: npm test
123+
- run: pnpm --dir packages/subagent-tax test
124+
- run: npm run test:windows

.github/workflows/profiles.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: profile-contract
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "agents/profiles/**"
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: profile-contract-${{ github.event.pull_request.number }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
profiles:
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 10
19+
steps:
20+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
21+
with:
22+
fetch-depth: 0
23+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
24+
with:
25+
node-version: "24.16.0"
26+
- name: Reject mixed profile and product changes
27+
env:
28+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
29+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
30+
run: |
31+
if ! git cat-file -e "$BASE_SHA:agents/agents.json" 2>/dev/null; then
32+
echo "profile registry absent at base (initial import); skipping lane-scope gate"
33+
exit 0
34+
fi
35+
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > /tmp/changed-files
36+
profile_touched=false
37+
while IFS= read -r file; do
38+
case "$file" in
39+
agents/profiles/*)
40+
profile_touched=true
41+
;;
42+
agents/agents.json|packages/cli/src/agents.generated.ts|packages/cli/src/reserved-verbs.generated.ts)
43+
;;
44+
*)
45+
echo "profile lane rejects out-of-scope path: $file"
46+
exit 1
47+
;;
48+
esac
49+
done < /tmp/changed-files
50+
if [[ "$profile_touched" != "true" ]]; then
51+
echo "profile lane requires one agents/profiles change"
52+
exit 1
53+
fi
54+
- name: Validate profile registry
55+
run: node agents/compile.mjs
56+
- name: Require generated artifacts in pull request
57+
run: git diff --exit-code -- agents/agents.json packages/cli/src/agents.generated.ts packages/cli/src/reserved-verbs.generated.ts
58+
- name: Install CLI build dependencies
59+
run: npm install --ignore-scripts --no-audit --no-fund --no-package-lock --prefix packages/cli
60+
- name: Build CLI
61+
run: npm --prefix packages/cli run build
62+
- name: Run fake-harness matrix and help fixture
63+
run: node --test packages/cli/tests/agent-registry.runtime.mjs packages/cli/tests/agent-shortcut.runtime.mjs packages/cli/tests/porcelain.runtime.mjs
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: provider-catalog-contract
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "shared/provider-catalog/catalog/**"
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: provider-catalog-contract-${{ github.event.pull_request.number }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
catalog:
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 10
19+
steps:
20+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
21+
with:
22+
fetch-depth: 0
23+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
24+
with:
25+
python-version: "3.13"
26+
- name: Reject mixed changes and rewritten snapshots
27+
env:
28+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
29+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
30+
run: |
31+
if ! git cat-file -e "$BASE_SHA:shared/provider-catalog/catalog/current.yaml" 2>/dev/null; then
32+
echo "catalog absent at base (initial import); skipping lane-scope gate"
33+
exit 0
34+
fi
35+
current_touched=false
36+
new_snapshot=false
37+
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > /tmp/changed-files
38+
while IFS= read -r file; do
39+
case "$file" in
40+
shared/provider-catalog/catalog/current.yaml)
41+
current_touched=true
42+
;;
43+
shared/provider-catalog/catalog/????-??-??.yaml)
44+
if git cat-file -e "$BASE_SHA:$file" 2>/dev/null; then
45+
echo "dated catalog snapshots are immutable: $file"
46+
exit 1
47+
fi
48+
new_snapshot=true
49+
;;
50+
*)
51+
echo "catalog lane rejects out-of-scope path: $file"
52+
exit 1
53+
;;
54+
esac
55+
done < /tmp/changed-files
56+
if [[ "$current_touched" != "true" || "$new_snapshot" != "true" ]]; then
57+
echo "catalog PR requires current.yaml plus one new dated snapshot"
58+
exit 1
59+
fi
60+
- name: Install pinned validator dependency
61+
run: python -m pip install -r shared/provider-catalog/requirements-dev.txt
62+
- name: Validate catalog
63+
run: python shared/provider-catalog/validate_catalog.py
64+
- name: Test validator failure modes
65+
run: python -m unittest discover -s shared/provider-catalog/tests -p 'test_*.py'
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: release-binaries
2+
3+
on:
4+
push:
5+
tags:
6+
- "bin-v*"
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: release-binaries-${{ github.ref }}
13+
cancel-in-progress: false
14+
15+
jobs:
16+
build-sign-publish:
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 30
19+
environment: binary-release
20+
permissions:
21+
contents: write
22+
steps:
23+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
24+
with:
25+
fetch-depth: 0
26+
persist-credentials: false
27+
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
28+
with:
29+
go-version-file: go.mod
30+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
31+
with:
32+
node-version: "24.16.0"
33+
- name: Require protected, annotated, verified tag and release pin
34+
env:
35+
GH_TOKEN: ${{ github.token }}
36+
run: |
37+
set -euo pipefail
38+
tag_ref="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$GITHUB_REF_NAME" --jq .object.sha)"
39+
tag_type="$(gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$GITHUB_REF_NAME" --jq .object.type)"
40+
[[ "$tag_type" == "tag" ]] || { echo "binary release tag must be annotated" >&2; exit 1; }
41+
verified="$(gh api "repos/$GITHUB_REPOSITORY/git/tags/$tag_ref" --jq .verification.verified)"
42+
[[ "$verified" == "true" ]] || { echo "binary release tag signature is not GitHub-verified" >&2; exit 1; }
43+
target="$(gh api "repos/$GITHUB_REPOSITORY/git/tags/$tag_ref" --jq .object.sha)"
44+
git merge-base --is-ancestor "$target" origin/main
45+
[[ "$(tr -d '\r\n' < packages/cli/BINARY_RELEASE)" == "$GITHUB_REF_NAME" ]] || {
46+
echo "packages/cli/BINARY_RELEASE does not match $GITHUB_REF_NAME" >&2
47+
exit 1
48+
}
49+
- name: Build deterministic cross-platform artifacts
50+
run: node scripts/build-release-binaries.mjs --out dist/binaries
51+
- name: Require complete 36-artifact matrix
52+
run: |
53+
set -euo pipefail
54+
expected="$(node scripts/build-release-binaries.mjs --list | sort)"
55+
actual="$(find dist/binaries -maxdepth 1 -type f ! -name checksums.txt -printf '%f\n' | sort)"
56+
[[ "$actual" == "$expected" ]] || {
57+
diff -u <(printf '%s\n' "$expected") <(printf '%s\n' "$actual")
58+
exit 1
59+
}
60+
- name: Sign checksum manifest with pinned release key
61+
env:
62+
CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM: ${{ secrets.CAVEMAN_BINARY_SIGNING_PRIVATE_KEY_PEM }}
63+
run: >-
64+
node scripts/sign-binary-checksums.mjs
65+
dist/binaries/checksums.txt
66+
dist/binaries/checksums.txt.keysig
67+
packages/cli/BINARY_SIGNING_PUBKEY.pub
68+
- name: Publish binary-only release
69+
env:
70+
GH_TOKEN: ${{ github.token }}
71+
run: |
72+
set -euo pipefail
73+
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
74+
echo "release $GITHUB_REF_NAME already exists; refusing overwrite" >&2
75+
exit 1
76+
fi
77+
gh release create "$GITHUB_REF_NAME" dist/binaries/* \
78+
--repo "$GITHUB_REPOSITORY" \
79+
--title "$GITHUB_REF_NAME" \
80+
--notes "Signed Caveman runtime companions for macOS, Linux, and Windows."

0 commit comments

Comments
 (0)