Skip to content

Commit 02b81c8

Browse files
authored
Merge pull request #2262 from fullsend-ai/worktree-adr-0045-phase2-pr5
feat(cli): add --all flag to fullsend lock for batch harness locking
2 parents 93a5ae5 + acecfc3 commit 02b81c8

8 files changed

Lines changed: 1134 additions & 64 deletions

File tree

docs/ADRs/0038-universal-harness-access.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ harnesses:
338338

339339
**Rationale:** Lock files provide dependency pinning (reproducible builds), transitive closure visibility (auditability), and automated updates (tools can rewrite lock files when dependencies change). Similar to `package-lock.json` in npm.
340340

341-
**Lock file workflow:** `fullsend lock <harness>` resolves all dependencies, generates/updates the lock file. `fullsend run <harness>` prefers lock file entries if present, warns if lock file is stale (resource hash doesn't match).
341+
**Lock file workflow:** `fullsend lock <harness>` (or `fullsend lock --all`) resolves all dependencies, generates/updates the lock file. `fullsend run <harness>` prefers lock file entries if present, warns if lock file is stale (resource hash doesn't match).
342342

343343
#### 7. URL scheme: bare https:// vs git+https://
344344

docs/guides/dev/cli-internals.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ fullsend
3636
│ ├── status <org> # Analyze GitHub-side state
3737
│ ├── uninstall <org> # Remove fullsend GitHub configuration
3838
│ └── sync-scaffold <org> # Update workflow templates
39-
├── lock <agent-name> # Pin remote deps to lock.yaml
39+
├── lock [agent-name] # Pin remote deps to lock.yaml
40+
│ ├── --all # Lock all harnesses in the harness directory
4041
│ ├── --fullsend-dir <path> # Base directory with .fullsend layout
4142
│ ├── --forge <platform> # Lock only this forge variant; omit for all
4243
│ ├── --update # Force re-resolve even if current

docs/guides/user/running-agents-locally.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ generated. Generate or update a lock file with:
208208
fullsend lock code --fullsend-dir /path/to/.fullsend
209209
```
210210

211+
To lock all harnesses in the directory at once:
212+
213+
```bash
214+
fullsend lock --all --fullsend-dir /path/to/.fullsend
215+
```
216+
211217
When `--forge` is specified, only that platform variant is locked. When omitted,
212218
all forge variants defined in the harness are resolved and the union of their
213219
dependencies is locked.

docs/plans/adr-0045-forge-portable-harness-phase2.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ PRs 1, 2, 3, 5 can start in parallel. PR 4 depends on PR 3 (needs the base URL b
9292
- For each file, calls `LoadRaw(path)` (unmarshal only, no validation)
9393
- Extracts `h.Role` and `h.Slug`; skips files where both are empty (not harness identity files, or legacy harnesses without role/slug)
9494
- Returns sorted by `Role` for deterministic output
95-
- Errors on individual files are collected and returned as a multi-error (one bad YAML file should not prevent discovery of others). This partial-result semantic is intentional: discovery is a read-only inventory operation where returning what we can find is more useful than failing entirely. Contrast with `lock --all` (PR 5), which uses all-or-nothing semantics because writing an incomplete lock file would silently leave some dependencies unpinned.
95+
- Errors on individual files are collected and returned as a multi-error (one bad YAML file should not prevent discovery of others). This partial-result semantic is intentional: discovery is a read-only inventory operation where returning what we can find is more useful than failing entirely. `lock --all` (PR 5) uses similar partial-progress semantics: successfully resolved harnesses are saved before returning the error, so they don't need to be re-resolved on retry.
9696
- Does NOT resolve `base:` chains -- reads only the top-level `role`/`slug` from each file. This is correct because generated wrappers set `role`/`slug` at the top level (not inherited from base).
9797

9898
**Create `internal/harness/discover_test.go`:**
@@ -317,14 +317,14 @@ The `HarnessWrappersLayer` maintains this mapping. A helper function `harnessNam
317317

318318
**Modify `internal/cli/lock.go`:**
319319

320-
- Change `cobra.ExactArgs(1)` to `cobra.MaximumNArgs(1)` -- accept zero or one positional argument
320+
- Change `cobra.ExactArgs(1)` to `cobra.RangeArgs(0, 1)` -- accept zero or one positional argument
321321
- Add `--all` bool flag
322322
- Validation:
323323
- `--all` and a positional argument are mutually exclusive -> error
324324
- Neither `--all` nor a positional argument -> error with usage hint
325325
- When `--all` is set:
326326
1. Glob `filepath.Join(absFullsendDir, "harness", "*.yaml")` and `*.yml` to get all harness files. Uses `filepath.Glob` directly rather than `DiscoverAgents` to avoid coupling lock to the discover API -- lock only needs filenames, not role/slug.
327-
2. For each harness file found, run the existing lock logic (load, resolve, hash, record in lockfile). If any individual file fails to parse, the entire `lock --all` invocation fails with no partial lock file written (all-or-nothing semantics, matching the single-file lock behavior).
327+
2. For each harness file found, run the existing lock logic (load, resolve, hash, record in lockfile). If any individual file fails, previously resolved harnesses are saved to the lock file (partial-progress semantics) so they don't need to be re-resolved on retry. The error message includes the failing harness name.
328328
3. Write the combined lock file once at the end with all harness entries.
329329
4. Report summary: `Locked N harnesses: triage, code, review, fix, retro, prioritize`
330330

@@ -338,7 +338,7 @@ The `HarnessWrappersLayer` maintains this mapping. A helper function `harnessNam
338338
- `--all` with no harness files -> warning, empty lock file
339339
- `--all` with multiple harnesses -> all locked, lock file contains entries for each
340340
- `--all` with one harness having URL base, others local-only -> only URL-bearing harnesses get lock entries (or all get entries with empty deps -- follow existing convention)
341-
- `--all` with one harness failing to parse -> error with harness name in message, no partial lock file written (all-or-nothing)
341+
- `--all` with one harness failing to parse -> error with harness name in message, partial progress saved for already-resolved harnesses
342342

343343
**After merge:** `fullsend lock --all` locks every harness in the directory. Combined with PR 4's wrapper generation, running `fullsend lock --all` after install pins all base URLs in `lock.yaml`.
344344

0 commit comments

Comments
 (0)