compound-agent 2.5.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +64 -27
- package/bin/ca +5 -3
- package/package.json +9 -6
- package/scripts/postinstall.cjs +48 -25
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [2.6.0] - 2026-04-01
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`--compact-pct` flag** for `ca loop`, `ca improve`, and `ca polish`: Sets `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` in generated scripts to trigger context compaction earlier during autonomous workflows. Default 0 (use Claude Code default). Suggested value: 50 for Opus 1M sessions. Only affects generated scripts, not interactive sessions. Validates range 0-100.
|
|
17
|
+
- **Windows Native Support**: Native Windows binaries (amd64 + arm64) distributed via npm. Pure-Go SQLite driver eliminates CGO requirement. Real `LockFileEx`/`UnlockFileEx` file locking, `OpenProcess`/`GetExitCodeProcess` process detection, and `cmd /c start` URL opening with command injection prevention. Search gracefully degrades to keyword-only FTS5 (embed daemon is Unix-only). CI matrix includes `windows-latest`.
|
|
18
|
+
- **Self-Explaining System (`ca info`)** (Epic 4): New CLI command displaying comprehensive system health — version, hooks, skills, phase state, telemetry, and lesson corpus stats. 13 tests.
|
|
19
|
+
- **Skill Phase Metadata** (Epic 3): Structured `phase` field in YAML frontmatter of all SKILL.md files with pre-compiled `skills_index.json` for fast runtime skill lookup. Phase guard uses `ResolveSkillPath` for phase-aware routing.
|
|
20
|
+
- **Telemetry Foundation** (Epic 2): Schema v7 with telemetry table, `ca health` command, file-based lock for concurrent access, and hook execution instrumentation.
|
|
21
|
+
- **V3.0 Harness Overhaul Specification**: Spec and advisory brief for upcoming harness overhaul.
|
|
22
|
+
- **GOTCHA.md for architect skill**: Documented common pitfalls for architect workflows.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **SQLite driver**: Replaced `mattn/go-sqlite3` (CGO) with `modernc.org/sqlite` (pure Go). Enables `CGO_ENABLED=0` builds and Windows cross-compilation. DSN format uses `_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)`. FTS5 included by default — no build tags required.
|
|
27
|
+
- **Build pipeline**: All builds now use `CGO_ENABLED=0`. Removed `-tags sqlite_fts5` from Makefile, CI, GoReleaser, and lint config. Added `windows-amd64` and `windows-arm64` targets to GoReleaser, CI matrix, and Makefile.
|
|
28
|
+
- **npm distribution**: Added `@syottos/win32-x64` and `@syottos/win32-arm64` platform packages. Updated `bin/ca` wrapper, `postinstall.cjs`, and `publish-platforms.cjs` for `.exe` handling and embed daemon exclusion on Windows.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **Documentation inaccuracies** (Epic 1): Fixed TypeScript/npm references across docs and templates, corrected hook counts, rewrote README with Mermaid diagram, added WSL2 doctor check.
|
|
33
|
+
- **Screen session name collisions**: Unique session names using `compound-loop-$(basename $(pwd))` pattern to avoid host-level collisions (PR #10).
|
|
34
|
+
- **6 golangci-lint violations**: gofmt alignment in map literals, extracted `checkHooks`/`printDoctorResults` helpers to reduce cyclop/funlen, handled `flockUnlock` error return.
|
|
35
|
+
- **Review findings**: Multiple rounds of P0-P3 fixes from external reviewers across Epics 1-4.
|
|
36
|
+
- **Command injection in `openURL`**: Windows `cmd /c start` now validates URL scheme (`http://`/`https://` only) and uses `exec.Command` argument splitting to prevent shell metacharacter injection.
|
|
37
|
+
|
|
38
|
+
### Dependencies
|
|
39
|
+
|
|
40
|
+
- **modernc.org/sqlite**: v1.48.0 — pure-Go SQLite driver replacing mattn/go-sqlite3 (CGO). Enables Windows native builds.
|
|
41
|
+
- **golang.org/x/sys**: v0.42.0 — Windows `LockFileEx`/`UnlockFileEx` and process APIs.
|
|
42
|
+
- **thiserror**: 1.0.69 to 2.0.18 in Rust embed daemon — major version bump with no-std support and improved diagnostics (PR #8).
|
|
43
|
+
- **tokenizers**: 0.21.4 to 0.22.2 in Rust embed daemon — PyO3 0.26, faster vocab loading, GIL-free (PR #7).
|
|
44
|
+
|
|
12
45
|
## [2.5.2] - 2026-03-31
|
|
13
46
|
|
|
14
47
|
### Added
|
package/README.md
CHANGED
|
@@ -14,12 +14,12 @@ AI coding agents forget everything between sessions. Each session starts with wh
|
|
|
14
14
|
|
|
15
15
|
## What gets installed
|
|
16
16
|
|
|
17
|
-
`
|
|
17
|
+
`ca setup` injects a complete development environment into your repository:
|
|
18
18
|
|
|
19
19
|
| Component | What ships |
|
|
20
20
|
|-----------|-----------|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
21
|
+
| 16 slash commands | `/compound:architect`, `cook-it`, `spec-dev`, `plan`, `work`, `review`, `compound`, `learn-that`, `check-that`, and more |
|
|
22
|
+
| 26 agent role skills | TDD pair, drift detector, audit, research specialist, external reviewers, and more |
|
|
23
23
|
| 7 automatic hooks | Fire on session start, prompt submit, tool use, tool failure, pre-compact, phase guard, and session stop |
|
|
24
24
|
| 5 phase skill files | Full workflow instructions for `architect`, `spec-dev`, `cook-it`, `work`, and `review` |
|
|
25
25
|
| 5 deployed docs | Workflow reference, CLI reference, skills guide, integration guide, and overview |
|
|
@@ -202,9 +202,9 @@ Once installed, seven Claude Code hooks fire without any commands:
|
|
|
202
202
|
| `PreToolUse` | During cook-it | Enforces phase gates — prevents jumping ahead |
|
|
203
203
|
| `PostToolUse` | After tool success | Clears failure tracking state |
|
|
204
204
|
| `PostToolUseFailure` | After tool failure | Tracks failures; suggests memory search after repeated errors |
|
|
205
|
-
| `Stop` | Session end |
|
|
205
|
+
| `Stop` | Session end | Enforces phase gates — prevents skipping required steps |
|
|
206
206
|
|
|
207
|
-
No configuration needed. `
|
|
207
|
+
No configuration needed. `ca setup` wires them into your `.claude/settings.json`.
|
|
208
208
|
|
|
209
209
|
## `/compound:architect`
|
|
210
210
|
|
|
@@ -235,25 +235,20 @@ npx ca setup
|
|
|
235
235
|
|
|
236
236
|
### Requirements
|
|
237
237
|
|
|
238
|
-
- Node.js >= 20
|
|
238
|
+
- Node.js >= 20 (for `npx` wrapper — the CLI itself is a Go binary)
|
|
239
239
|
- ~278MB disk space for the embedding model (one-time download, shared across projects)
|
|
240
|
-
-
|
|
240
|
+
- Embedding runs via `ca-embed` Rust daemon (nomic-embed-text-v1.5 ONNX)
|
|
241
241
|
|
|
242
|
-
###
|
|
242
|
+
### Windows Users
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
Compound-agent runs natively on Windows (amd64 and arm64). Install and use it the same way as on macOS/Linux:
|
|
245
245
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
{
|
|
250
|
-
"pnpm": {
|
|
251
|
-
"onlyBuiltDependencies": ["better-sqlite3", "onnxruntime-node"]
|
|
252
|
-
}
|
|
253
|
-
}
|
|
246
|
+
```bash
|
|
247
|
+
pnpm add -D compound-agent
|
|
248
|
+
npx ca setup
|
|
254
249
|
```
|
|
255
250
|
|
|
256
|
-
|
|
251
|
+
**Note**: The embedding daemon (`ca-embed`) is not available on Windows. Search automatically falls back to keyword-only mode (FTS5). All other features work identically. WSL2 users get full functionality including vector search.
|
|
257
252
|
|
|
258
253
|
## CLI Reference
|
|
259
254
|
|
|
@@ -380,16 +375,16 @@ confirmation_boost: confirmed=1.3, unconfirmed=1.0
|
|
|
380
375
|
A: mem0 is a cloud memory layer for general AI agents. Compound Agent is local-first with git-tracked storage and local embeddings — no API keys or cloud services needed. It also goes beyond memory with structured workflows, multi-agent review, and issue tracking.
|
|
381
376
|
|
|
382
377
|
**Q: Does this work offline?**
|
|
383
|
-
A: Yes, completely. Embeddings run locally via
|
|
378
|
+
A: Yes, completely. Embeddings run locally via the `ca-embed` Rust daemon (nomic-embed-text-v1.5 ONNX). No network requests after the initial model download.
|
|
384
379
|
|
|
385
380
|
**Q: How much disk space does it need?**
|
|
386
381
|
A: ~278MB for the embedding model (one-time download, shared across projects) plus negligible space for lessons.
|
|
387
382
|
|
|
388
383
|
**Q: Can I use it with other AI coding tools?**
|
|
389
|
-
A: The CLI (`ca`) works standalone with any tool. Full hook integration is available for Claude Code and Gemini CLI.
|
|
384
|
+
A: The CLI (`ca`) works standalone with any tool. Full hook integration is available for Claude Code and Gemini CLI.
|
|
390
385
|
|
|
391
386
|
**Q: What happens if the embedding model isn't available?**
|
|
392
|
-
A: Search gracefully falls back to keyword-only mode. Other commands that require embeddings will tell you what's missing. Run `
|
|
387
|
+
A: Search gracefully falls back to keyword-only mode. Other commands that require embeddings will tell you what's missing. Run `ca doctor` to diagnose issues.
|
|
393
388
|
|
|
394
389
|
**Q: Is the loop production-ready?**
|
|
395
390
|
A: The loop works and has been used to ship real projects, including compound-agent itself. Long-duration autonomous runs across many epics are the current area of hardening. For 3–5 epic sequences, it is reliable today.
|
|
@@ -397,9 +392,9 @@ A: The loop works and has been used to ship real projects, including compound-ag
|
|
|
397
392
|
## Development
|
|
398
393
|
|
|
399
394
|
```bash
|
|
400
|
-
cd go && go build
|
|
401
|
-
cd go && go test
|
|
402
|
-
cd go && go vet
|
|
395
|
+
cd go && go build ./cmd/ca # Build CLI binary
|
|
396
|
+
cd go && go test ./... # Full test suite
|
|
397
|
+
cd go && go vet ./... # Static analysis
|
|
403
398
|
```
|
|
404
399
|
|
|
405
400
|
## Technology Stack
|
|
@@ -408,14 +403,56 @@ cd go && go vet -tags sqlite_fts5 ./... # Static analysis
|
|
|
408
403
|
|-----------|------------|
|
|
409
404
|
| Language | Go |
|
|
410
405
|
| Package Manager | Go modules (+ pnpm for npm wrapper) |
|
|
411
|
-
| Build | go build with
|
|
406
|
+
| Build | go build with CGO_ENABLED=0 (pure Go) |
|
|
412
407
|
| Testing | go test + table-driven tests |
|
|
413
|
-
| Storage |
|
|
408
|
+
| Storage | modernc.org/sqlite + FTS5 (pure Go, no CGO) |
|
|
414
409
|
| Embeddings | ca-embed (Rust daemon via IPC) |
|
|
415
410
|
| CLI | Cobra |
|
|
416
411
|
| Release | GoReleaser |
|
|
417
412
|
| Issue Tracking | Beads (bd) |
|
|
418
413
|
|
|
414
|
+
## Architecture
|
|
415
|
+
|
|
416
|
+
```mermaid
|
|
417
|
+
graph TD
|
|
418
|
+
subgraph "Claude Code Session"
|
|
419
|
+
H[Hooks] -->|SessionStart| P[ca prime]
|
|
420
|
+
H -->|UserPromptSubmit| UP[user-prompt hook]
|
|
421
|
+
H -->|PostToolUseFailure| TF[failure tracker]
|
|
422
|
+
H -->|PreToolUse| PG[phase guard]
|
|
423
|
+
H -->|Stop| SA[stop audit]
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
subgraph "CLI (Go + Cobra)"
|
|
427
|
+
CA[ca binary] --> LEARN[ca learn]
|
|
428
|
+
CA --> SEARCH[ca search]
|
|
429
|
+
CA --> LOOP[ca loop]
|
|
430
|
+
CA --> SETUP[ca setup]
|
|
431
|
+
CA --> DOCTOR[ca doctor]
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
subgraph "Storage"
|
|
435
|
+
JSONL[".claude/lessons/index.jsonl<br/>(git-tracked source of truth)"]
|
|
436
|
+
SQLITE[".claude/.cache/lessons.sqlite<br/>(FTS5 search index)"]
|
|
437
|
+
JSONL -->|rebuild| SQLITE
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
subgraph "Embeddings"
|
|
441
|
+
EMBED["ca-embed (Rust daemon)"] -->|IPC via Unix socket| VEC[Vector similarity]
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
UP -->|inject lessons| SEARCH
|
|
445
|
+
TF -->|suggest search| SEARCH
|
|
446
|
+
LEARN --> JSONL
|
|
447
|
+
SEARCH --> SQLITE
|
|
448
|
+
SEARCH --> VEC
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Three layers work together:
|
|
452
|
+
- **Portable storage**: JSONL in git for conflict-free collaboration
|
|
453
|
+
- **Fast index**: SQLite + FTS5 for keyword search, rebuilt from JSONL on demand
|
|
454
|
+
- **Semantic search**: Rust embedding daemon for vector similarity, falls back to keyword-only if unavailable
|
|
455
|
+
|
|
419
456
|
## Documentation
|
|
420
457
|
|
|
421
458
|
| Document | Purpose |
|
|
@@ -447,4 +484,4 @@ Bug reports and feature requests are welcome via [Issues](https://github.com/Nat
|
|
|
447
484
|
|
|
448
485
|
MIT — see [LICENSE](LICENSE) for details.
|
|
449
486
|
|
|
450
|
-
> The embedding model (
|
|
487
|
+
> The embedding model (nomic-embed-text-v1.5) is downloaded on-demand from Hugging Face under the Apache 2.0 license. See [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md) for full dependency license information.
|
package/bin/ca
CHANGED
|
@@ -19,9 +19,10 @@ const require = createRequire(import.meta.url);
|
|
|
19
19
|
|
|
20
20
|
function resolvePlatformBinary() {
|
|
21
21
|
const pkg = `@syottos/${process.platform}-${process.arch}`;
|
|
22
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
22
23
|
try {
|
|
23
24
|
const pkgDir = dirname(require.resolve(`${pkg}/package.json`));
|
|
24
|
-
const bin = resolve(pkgDir, "bin",
|
|
25
|
+
const bin = resolve(pkgDir, "bin", `ca${ext}`);
|
|
25
26
|
if (existsSync(bin)) return bin;
|
|
26
27
|
} catch {
|
|
27
28
|
// Platform package not installed
|
|
@@ -30,11 +31,12 @@ function resolvePlatformBinary() {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function findBinary() {
|
|
34
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
33
35
|
const candidates = [
|
|
34
36
|
process.env.CA_BINARY_PATH,
|
|
35
37
|
resolvePlatformBinary(),
|
|
36
|
-
resolve(__dirname,
|
|
37
|
-
resolve(__dirname, "..", "go", "dist",
|
|
38
|
+
resolve(__dirname, `ca-binary${ext}`),
|
|
39
|
+
resolve(__dirname, "..", "go", "dist", `ca${ext}`),
|
|
38
40
|
].filter(Boolean);
|
|
39
41
|
|
|
40
42
|
return candidates.find((p) => existsSync(p)) || null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compound-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Learning system for Claude Code — avoids repeating mistakes across sessions",
|
|
6
6
|
"bin": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
],
|
|
22
22
|
"os": [
|
|
23
23
|
"darwin",
|
|
24
|
-
"linux"
|
|
24
|
+
"linux",
|
|
25
|
+
"win32"
|
|
25
26
|
],
|
|
26
27
|
"cpu": [
|
|
27
28
|
"x64",
|
|
@@ -50,10 +51,12 @@
|
|
|
50
51
|
"knowledge-management"
|
|
51
52
|
],
|
|
52
53
|
"optionalDependencies": {
|
|
53
|
-
"@syottos/darwin-arm64": "2.
|
|
54
|
-
"@syottos/darwin-x64": "2.
|
|
55
|
-
"@syottos/linux-arm64": "2.
|
|
56
|
-
"@syottos/linux-x64": "2.
|
|
54
|
+
"@syottos/darwin-arm64": "2.6.0",
|
|
55
|
+
"@syottos/darwin-x64": "2.6.0",
|
|
56
|
+
"@syottos/linux-arm64": "2.6.0",
|
|
57
|
+
"@syottos/linux-x64": "2.6.0",
|
|
58
|
+
"@syottos/win32-x64": "2.6.0",
|
|
59
|
+
"@syottos/win32-arm64": "2.6.0"
|
|
57
60
|
},
|
|
58
61
|
"author": "Nathan Delacrétaz",
|
|
59
62
|
"license": "MIT",
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -12,7 +12,7 @@ const path = require("path");
|
|
|
12
12
|
const { execFileSync } = require("child_process");
|
|
13
13
|
const { createHash } = require("crypto");
|
|
14
14
|
|
|
15
|
-
const PLATFORM_MAP = { darwin: "darwin", linux: "linux" };
|
|
15
|
+
const PLATFORM_MAP = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
16
16
|
const ARCH_MAP = { x64: "amd64", arm64: "arm64" };
|
|
17
17
|
const REPO = "Nathandela/compound-agent";
|
|
18
18
|
|
|
@@ -21,7 +21,7 @@ function getPlatformKey(platform, arch) {
|
|
|
21
21
|
const a = ARCH_MAP[arch];
|
|
22
22
|
if (!p || !a) {
|
|
23
23
|
throw new Error(
|
|
24
|
-
`Unsupported platform: ${platform}-${arch}. Supported: darwin-amd64, darwin-arm64, linux-amd64, linux-arm64`
|
|
24
|
+
`Unsupported platform: ${platform}-${arch}. Supported: darwin-amd64, darwin-arm64, linux-amd64, linux-arm64, windows-amd64, windows-arm64`
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
27
|
return `${p}-${a}`;
|
|
@@ -51,12 +51,13 @@ function verifyChecksum(filePath, artifactName, checksumsPath) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function shouldSkipDownload(binDir, expectedVersion) {
|
|
54
|
-
const
|
|
54
|
+
const isWindows = require("os").platform() === "win32";
|
|
55
|
+
const caPath = path.join(binDir, isWindows ? "ca-binary.exe" : "ca-binary");
|
|
55
56
|
const embedPath = path.join(binDir, "ca-embed");
|
|
56
57
|
|
|
57
|
-
if (!fs.existsSync(caPath)
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
if (!fs.existsSync(caPath)) return false;
|
|
59
|
+
// ca-embed is not available on Windows — only require it on Unix
|
|
60
|
+
if (!isWindows && !fs.existsSync(embedPath)) return false;
|
|
60
61
|
|
|
61
62
|
try {
|
|
62
63
|
const output = execFileSync(caPath, ["version"], { stdio: "pipe", encoding: "utf-8" });
|
|
@@ -133,16 +134,21 @@ async function downloadBinary(binDir, url, destName, label) {
|
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
function cleanupBinaries(binDir) {
|
|
136
|
-
for (const name of [
|
|
137
|
+
for (const name of [
|
|
138
|
+
"ca-binary", "ca-binary.tmp", "ca-binary.exe", "ca-binary.exe.tmp",
|
|
139
|
+
"ca-embed", "ca-embed.tmp", "checksums.txt",
|
|
140
|
+
]) {
|
|
137
141
|
try { fs.unlinkSync(path.join(binDir, name)); } catch { /* ignore */ }
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
function platformPackageInstalled() {
|
|
142
|
-
const
|
|
146
|
+
const platform = require("os").platform();
|
|
147
|
+
const pkg = `@syottos/${platform}-${require("os").arch()}`;
|
|
148
|
+
const ext = platform === "win32" ? ".exe" : "";
|
|
143
149
|
try {
|
|
144
150
|
const pkgDir = path.dirname(require.resolve(`${pkg}/package.json`));
|
|
145
|
-
return fs.existsSync(path.join(pkgDir, "bin",
|
|
151
|
+
return fs.existsSync(path.join(pkgDir, "bin", `ca${ext}`));
|
|
146
152
|
} catch {
|
|
147
153
|
return false;
|
|
148
154
|
}
|
|
@@ -187,20 +193,34 @@ async function main() {
|
|
|
187
193
|
const checksumsPath = path.join(binDir, "checksums.txt");
|
|
188
194
|
await downloadFile(`${baseUrl}/checksums.txt`, checksumsPath);
|
|
189
195
|
|
|
190
|
-
// Download
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
196
|
+
// Download binaries in parallel (to .tmp names)
|
|
197
|
+
const isWindows = require("os").platform() === "win32";
|
|
198
|
+
const caExt = isWindows ? ".exe" : "";
|
|
199
|
+
const caArtifact = `ca-${platformKey}${caExt}`;
|
|
200
|
+
|
|
201
|
+
const downloads = [
|
|
202
|
+
downloadBinary(binDir, `${baseUrl}/${caArtifact}`, `ca-binary${caExt}`, "CLI binary"),
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
// ca-embed is not available on Windows
|
|
206
|
+
let embedArtifact = null;
|
|
207
|
+
if (!isWindows) {
|
|
208
|
+
// No x86_64 macOS embed build (ort-sys limitation) — use arm64 via Rosetta
|
|
209
|
+
const embedKey = platformKey === "darwin-amd64" ? "darwin-arm64" : platformKey;
|
|
210
|
+
embedArtifact = `ca-embed-${embedKey}`;
|
|
211
|
+
downloads.push(
|
|
212
|
+
downloadBinary(binDir, `${baseUrl}/${embedArtifact}`, "ca-embed", "Embed daemon"),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
195
215
|
|
|
196
|
-
await Promise.all(
|
|
197
|
-
downloadBinary(binDir, `${baseUrl}/${caArtifact}`, "ca-binary", "CLI binary"),
|
|
198
|
-
downloadBinary(binDir, `${baseUrl}/${embedArtifact}`, "ca-embed", "Embed daemon"),
|
|
199
|
-
]);
|
|
216
|
+
await Promise.all(downloads);
|
|
200
217
|
|
|
201
218
|
// Verify checksums against .tmp files
|
|
202
|
-
const caOk = verifyChecksum(path.join(binDir,
|
|
203
|
-
|
|
219
|
+
const caOk = verifyChecksum(path.join(binDir, `ca-binary${caExt}.tmp`), caArtifact, checksumsPath);
|
|
220
|
+
let embedOk = true;
|
|
221
|
+
if (embedArtifact) {
|
|
222
|
+
embedOk = verifyChecksum(path.join(binDir, "ca-embed.tmp"), embedArtifact, checksumsPath);
|
|
223
|
+
}
|
|
204
224
|
|
|
205
225
|
if (!caOk || !embedOk) {
|
|
206
226
|
const failed = [];
|
|
@@ -214,14 +234,17 @@ async function main() {
|
|
|
214
234
|
console.log("[compound-agent] Checksums verified");
|
|
215
235
|
|
|
216
236
|
// Checksums passed — rename .tmp to final names and set executable
|
|
217
|
-
|
|
218
|
-
fs.
|
|
219
|
-
fs.
|
|
220
|
-
|
|
237
|
+
const caFinal = path.join(binDir, `ca-binary${caExt}`);
|
|
238
|
+
fs.renameSync(path.join(binDir, `ca-binary${caExt}.tmp`), caFinal);
|
|
239
|
+
fs.chmodSync(caFinal, 0o755);
|
|
240
|
+
if (embedArtifact) {
|
|
241
|
+
fs.renameSync(path.join(binDir, "ca-embed.tmp"), path.join(binDir, "ca-embed"));
|
|
242
|
+
fs.chmodSync(path.join(binDir, "ca-embed"), 0o755);
|
|
243
|
+
}
|
|
221
244
|
|
|
222
245
|
// Functional verification (P1-2 fix: use execFileSync)
|
|
223
246
|
try {
|
|
224
|
-
execFileSync(
|
|
247
|
+
execFileSync(caFinal, ["version"], { stdio: "pipe" });
|
|
225
248
|
console.log("[compound-agent] Functional check passed");
|
|
226
249
|
} catch {
|
|
227
250
|
cleanupBinaries(binDir);
|