forge-workflow 0.1.0-beta.4 → 0.1.0-beta.6
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/AGENTS.md +18 -7
- package/CHANGELOG.md +79 -1
- package/CLAUDE.md +0 -12
- package/CODING_STANDARDS.md +72 -0
- package/README.md +6 -2
- package/bin/forge-cmd.js +20 -0
- package/bin/forge.js +28 -375
- package/docs/INDEX.md +1 -1
- package/docs/guides/BEADS_GITHUB_SYNC.md +2 -31
- package/docs/guides/MIGRATION.md +4 -4
- package/docs/guides/SETUP.md +16 -16
- package/docs/reference/COMMANDS.md +8 -5
- package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
- package/docs/reference/INSIGHTS_RECAP.md +9 -20
- package/docs/reference/INSTALL.md +4 -0
- package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
- package/docs/reference/RELEASE.md +5 -3
- package/docs/reference/TOOLCHAIN.md +8 -0
- package/docs/reference/github-accounts.md +134 -0
- package/docs/reference/protected-state-surfaces.md +4 -4
- package/docs/reference/shepherd.md +114 -35
- package/lefthook.yml +12 -0
- package/lib/activation/ensure-forge-home.js +33 -15
- package/lib/adapters/pr-state-adapter.js +359 -144
- package/lib/audit-evidence.js +71 -110
- package/lib/base-remote.js +138 -0
- package/lib/beta5-compatibility-evidence.js +1093 -0
- package/lib/bun-lockfile-proof.js +413 -0
- package/lib/bun-workflow-pins.js +461 -0
- package/lib/capabilities/index.js +9 -0
- package/lib/capabilities/model.js +141 -0
- package/lib/capabilities/probes.js +347 -0
- package/lib/capped-jsonl-log.js +236 -0
- package/lib/codex-skills.js +2 -2
- package/lib/commands/_manifest.js +1 -0
- package/lib/commands/_registry.js +50 -20
- package/lib/commands/clean.js +252 -32
- package/lib/commands/dev.js +4 -33
- package/lib/commands/doctor.js +37 -6
- package/lib/commands/gate.js +197 -27
- package/lib/commands/github.js +215 -0
- package/lib/commands/hooks.js +276 -30
- package/lib/commands/insights.js +8 -3
- package/lib/commands/memory.js +66 -2
- package/lib/commands/merge.js +1265 -58
- package/lib/commands/plan.js +33 -2
- package/lib/commands/pr.js +3 -1
- package/lib/commands/preflight.js +21 -4
- package/lib/commands/prime.js +21 -8
- package/lib/commands/push.js +146 -54
- package/lib/commands/recall.js +127 -49
- package/lib/commands/recap.js +6 -1
- package/lib/commands/release.js +39 -3
- package/lib/commands/remember.js +28 -4
- package/lib/commands/serve.js +26 -9
- package/lib/commands/setup.js +323 -98
- package/lib/commands/shepherd.js +591 -73
- package/lib/commands/ship.js +36 -91
- package/lib/commands/skill.js +127 -11
- package/lib/commands/status.js +17 -1
- package/lib/commands/team.js +47 -8
- package/lib/commands/test.js +187 -38
- package/lib/commands/validate.js +65 -21
- package/lib/commands/worktree.js +359 -45
- package/lib/core/runtime-graph.js +1 -1
- package/lib/doc-assertions.js +297 -0
- package/lib/existing-tdd-gate.js +253 -0
- package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
- package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
- package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
- package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
- package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
- package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
- package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
- package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
- package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
- package/lib/forge-context.js +1 -4
- package/lib/forge-issues.js +134 -32
- package/lib/gate-events.js +98 -10
- package/lib/git-defaults.js +56 -0
- package/lib/github-context.js +308 -0
- package/lib/global-flags.js +1 -0
- package/lib/harness-capability-matrix.js +3 -3
- package/lib/hook-renderer.js +122 -5
- package/lib/insights.js +96 -80
- package/lib/issue-render.js +19 -0
- package/lib/kernel/backing-issue.js +14 -2
- package/lib/kernel/broker.js +739 -31
- package/lib/kernel/claim-reconciler.js +238 -0
- package/lib/kernel/cli-broker-factory.js +12 -1
- package/lib/kernel/close-on-merge.js +154 -0
- package/lib/kernel/fs-class.js +42 -25
- package/lib/kernel/lease-enforcer.js +9 -4
- package/lib/kernel/legacy-claim-repair.js +442 -0
- package/lib/kernel/live-claim-projection.js +26 -0
- package/lib/kernel/migrations.js +118 -3
- package/lib/kernel/readiness-model.js +184 -12
- package/lib/kernel/schema.js +49 -1
- package/lib/kernel/sqlite-driver.js +3435 -172
- package/lib/kernel/taxonomy-validator.js +4 -1
- package/lib/kernel/windows-private-acl.js +239 -0
- package/lib/lefthook-wiring.js +21 -1
- package/lib/memory/hygiene.js +191 -0
- package/lib/memory/router.js +110 -28
- package/lib/memory/usage-evidence.js +4 -0
- package/lib/memory-digest.js +106 -15
- package/lib/memory-recall-events.js +145 -0
- package/lib/memory-recall.js +71 -10
- package/lib/merge-rules.js +143 -21
- package/lib/npm-publish-workflow.js +465 -0
- package/lib/orientation.js +68 -43
- package/lib/package-root.js +2 -0
- package/lib/plugin-catalog.js +14 -4
- package/lib/pr-bundle.js +5 -6
- package/lib/pr-monitor/auto-actions.js +169 -28
- package/lib/pr-monitor/differ.js +110 -4
- package/lib/pr-monitor/events.js +0 -0
- package/lib/pr-monitor/flow-monitor.js +1424 -0
- package/lib/pr-monitor/gather.js +251 -44
- package/lib/pr-monitor/journal.js +18 -39
- package/lib/pr-monitor/monitor.js +117 -10
- package/lib/pr-monitor/process-identity.js +117 -0
- package/lib/pr-monitor/reconcile-executor.js +1129 -470
- package/lib/pr-monitor/reconcile.js +0 -0
- package/lib/pr-monitor/render-summary.js +293 -0
- package/lib/pr-monitor/review-preflight.js +269 -0
- package/lib/pr-monitor/shepherd-lease.js +38 -20
- package/lib/pr-monitor/verdict.js +438 -0
- package/lib/pr-monitor/watch-lifecycle.js +145 -27
- package/lib/pr-monitor/watch-owner.js +1414 -0
- package/lib/pr-monitor/watch.js +129 -58
- package/lib/pr-pull.js +33 -14
- package/lib/pr-shepherd.js +51 -11
- package/lib/preflight/gates.js +65 -18
- package/lib/preflight/runner.js +5 -0
- package/lib/project-memory.js +178 -4
- package/lib/protected-state-authority.js +1100 -0
- package/lib/protected-state-surfaces.js +243 -45
- package/lib/release-readiness.js +53 -7
- package/lib/review-adapter.js +65 -0
- package/lib/shell-utils.js +1 -1
- package/lib/skills-sync.js +71 -35
- package/lib/smart-merge.js +28 -4
- package/lib/symlink-utils.js +74 -26
- package/lib/upgrade-safety.js +39 -0
- package/lib/using-forge.js +19 -6
- package/lib/validation/risk-manifest.js +339 -0
- package/lib/workflow/enforce-stage.js +44 -0
- package/lib/workflow/plan-authority.js +225 -0
- package/package.json +12 -9
- package/scripts/commitlint.js +13 -15
- package/scripts/doc-asserting-tests.js +158 -0
- package/scripts/generate-risk-manifest.js +91 -0
- package/scripts/github-context-bridge.sh +10 -0
- package/scripts/legacy-claim-repair.js +145 -0
- package/scripts/lib/behavioral-eval-runner.js +310 -0
- package/scripts/lib/behavioral-eval-runtime.js +457 -0
- package/scripts/lib/eval-evidence.js +328 -0
- package/scripts/lib/eval-runner.js +81 -41
- package/scripts/lib/immutable-eval-corpus.js +309 -0
- package/scripts/lib/promotion-evidence-loader.js +94 -0
- package/scripts/lib/promotion-scorecard.js +314 -0
- package/scripts/npm-release-receipt.js +134 -0
- package/scripts/process-tree.js +773 -0
- package/scripts/protected-state-check.js +479 -31
- package/scripts/run-command-eval.js +29 -1
- package/scripts/sync-agent-skills.js +333 -34
- package/scripts/sync-d20-audit.js +172 -0
- package/scripts/test-full-suite.js +935 -37
- package/scripts/test-profile.js +13 -3
- package/scripts/test.js +271 -57
- package/skills/coverage.json +1 -0
- package/skills/review/SKILL.md +6 -11
- package/skills/review/evals/scorecard.json +4 -4
- package/skills/rollback/SKILL.md +4 -11
- package/skills/rollback/evals/scorecard.json +3 -3
- package/skills/setup/SKILL.md +18 -0
- package/skills/setup/evals/scorecard.json +3 -3
- package/skills/shepherd/SKILL.md +39 -16
- package/skills/shepherd/evals/scorecard.json +4 -4
- package/skills/ship/SKILL.md +4 -12
- package/skills/ship/evals/scorecard.json +3 -3
- package/skills/validate/SKILL.md +3 -0
- package/skills/validate/evals/scorecard.json +1 -1
- package/skills/worktree/SKILL.md +6 -1
- package/skills/worktree/evals/scorecard.json +2 -2
- package/lib/beads-setup.js +0 -538
- package/lib/beads-sync-scaffold.js +0 -189
- package/lib/pat-setup.js +0 -207
- package/lib/pr-monitor/render-sticky.js +0 -206
- package/lib/pr-monitor/upsert-sticky.js +0 -169
- package/scripts/beads-context.sh +0 -577
- package/scripts/beads-migrate-to-dolt.sh +0 -7
- package/scripts/beads-upgrade-smoke.sh +0 -284
- package/scripts/lib/beads-migrate-to-dolt.mjs +0 -503
|
@@ -21,30 +21,57 @@ forge shepherd events <pr-number> --since <seq> # read new journal events back
|
|
|
21
21
|
There are two ways to run the shepherd, both under the single `forge shepherd`
|
|
22
22
|
verb:
|
|
23
23
|
|
|
24
|
-
- **`forge shepherd daemon` — the singleton reconcile daemon
|
|
25
|
-
|
|
24
|
+
- **`forge shepherd daemon` — the singleton reconcile daemon, the default
|
|
25
|
+
coordinator.** It acquires the machine-wide election lease for this repo
|
|
26
26
|
(exiting immediately as a clean no-op if a live daemon already owns it),
|
|
27
27
|
heartbeats, and converges the *entire* PR world every ~60s: self-registering
|
|
28
|
-
hand-opened PRs,
|
|
28
|
+
hand-opened PRs, recovering dead watcher generations, requesting cooperative
|
|
29
|
+
stops,
|
|
29
30
|
converging CI check state into kernel verdicts, and retiring merged/closed PRs.
|
|
30
|
-
It **self-retires** — releases the lease
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
the
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
It **self-retires** — releases the election lease and exits — once no PRs
|
|
32
|
+
remain open. Per-PR ownership is never stored in that lease. Forge wakes it
|
|
33
|
+
automatically after a successful
|
|
34
|
+
supported session start, every successful push, and every successful
|
|
35
|
+
non-dry-run ship. These are the only automatic firing seams; ordinary commands
|
|
36
|
+
do not launch it. Once running, an agent does not poll: the daemon owns the
|
|
37
|
+
convergence loop.
|
|
38
|
+
- **`forge shepherd <pr>` — one bounded convergence pass.** Runs local review
|
|
39
|
+
preflight, reads one PR's state, takes at most one Tier-A action, persists
|
|
40
|
+
bounded deltas/receipts, and exits. The point-in-time surface for a single PR
|
|
41
|
+
(see *Bounded-pass model* below).
|
|
39
42
|
- **`forge shepherd watch <pr>` / `watch --adopt`** — foreground streaming watch of
|
|
40
|
-
one PR, or (`--adopt`)
|
|
43
|
+
one PR, or (`--adopt`) reserve owner rows and start watchers for every
|
|
44
|
+
currently-open PR.
|
|
41
45
|
- **`forge shepherd events <pr> --since <seq>`** — the event deltas for a PR since a
|
|
42
46
|
cursor; **`forge shepherd <pr> --pull --json` / `--bundle`** read the kernel verdict
|
|
43
47
|
+ rollup without taking any action.
|
|
44
48
|
|
|
45
|
-
Session start
|
|
46
|
-
harness background
|
|
47
|
-
|
|
49
|
+
Session start automatically wakes the daemon. When an embedding caller supplies
|
|
50
|
+
an executable harness background-shell capability, Forge uses it so the process is reaped with the session;
|
|
51
|
+
bare CLI use falls back to a detached launch from the stable common repository
|
|
52
|
+
root, never a disposable worktree cwd. No liveness check is needed first — the
|
|
53
|
+
O_EXCL singleton lease makes a duplicate start a clean no-op.
|
|
54
|
+
|
|
55
|
+
The daemon never kills watcher PIDs. A stop is a generation-conditional
|
|
56
|
+
`running -> stop_requested` transition in the Kernel; the matching watcher sees
|
|
57
|
+
that state, exits its loop, and releases only its own generation. A dead watcher
|
|
58
|
+
is recovered only after fresh PID and provider evidence is gathered outside the
|
|
59
|
+
transaction and the exact owner-row snapshot still matches inside it.
|
|
60
|
+
|
|
61
|
+
Embedding boundary:
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
hooks.handler(['session-start', '--harness', 'claude'], {}, projectRoot, {
|
|
65
|
+
harness: {
|
|
66
|
+
hasBgShell: true,
|
|
67
|
+
runBgShell: (argv, options) => host.backgroundShell(argv, options),
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The host must explicitly provide both `hasBgShell: true` and `runBgShell`;
|
|
73
|
+
Forge never infers this capability from a harness name. The adapter receives
|
|
74
|
+
the stable Git common-root as `options.cwd`; a missing or throwing adapter uses the contained detached fallback.
|
|
48
75
|
(A `forge prime` open-PR + daemon-liveness line is a planned follow-up — W-S5 —
|
|
49
76
|
not yet wired.)
|
|
50
77
|
|
|
@@ -98,26 +125,37 @@ project's documented ergonomic — poll briefly, then stop and hand off. A pass
|
|
|
98
125
|
that finds checks still pending returns `PENDING`; the next scheduled pass picks
|
|
99
126
|
up from there.
|
|
100
127
|
|
|
128
|
+
Before remote mutation, the plain pass consolidates a probed CodeRabbit CLI with
|
|
129
|
+
strict lint, structural drift, Sonar parity, and affected tests. The result is
|
|
130
|
+
returned as `localPreflight`; CodeRabbit absence/auth loss is explicitly
|
|
131
|
+
`UNAVAILABLE`/`INCOMPLETE`, not green. Deterministic failure or actual local
|
|
132
|
+
review findings makes the remote decision dry-run for that pass. A local
|
|
133
|
+
checkout that is not the exact PR head is explicitly `NOT_APPLICABLE`. Output is
|
|
134
|
+
bounded to 128 `deltas` plus receipt IDs and one outcome handoff: `review` for
|
|
135
|
+
semantic feedback, explicit human-approved `merge` at `MERGE_READY`, or `verify`
|
|
136
|
+
after merged evidence. Shepherd never resolves threads and never merges.
|
|
137
|
+
|
|
101
138
|
`--watch`-style behavior, if desired, belongs in an external scheduler (cron, or
|
|
102
139
|
a `/loop`) that re-invokes the bounded pass with a debounce of at least 60
|
|
103
140
|
seconds and cancel-in-progress. The shepherd itself never waits in-process.
|
|
104
141
|
|
|
105
|
-
##
|
|
142
|
+
## Automatic singleton attachment (`rail.auto_shepherd`)
|
|
106
143
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
**never fails ship** (a spawn or config-read error degrades to "not started"),
|
|
113
|
-
and it is idempotent — the watch-lifecycle PID/journal lock prevents a second
|
|
114
|
-
watcher for the same PR.
|
|
144
|
+
Successful supported session start, push, and non-dry-run ship operations wake the
|
|
145
|
+
repository-wide singleton. Push never requires a locally resolved PR number:
|
|
146
|
+
the daemon owns GitHub enumeration, so even a push with no local open-PR match
|
|
147
|
+
still fires and can adopt open or draft PRs created elsewhere. Push and ship no
|
|
148
|
+
longer start separate per-PR detached watchers.
|
|
115
149
|
|
|
116
150
|
This auto-start is governed by the default-ON, unlocked **`rail.auto_shepherd`**
|
|
117
151
|
rail. Opt out with `forge gate disable rail.auto_shepherd` (re-enable with
|
|
118
|
-
`forge gate enable rail.auto_shepherd`)
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
`forge gate enable rail.auto_shepherd`). `FORGE_SHEPHERD_DISABLE=1` is the
|
|
153
|
+
environment kill-switch. CI/test detection is deterministic and injectable via
|
|
154
|
+
the trigger environment: `NODE_ENV=test`, `BUN_ENV=test`, or a set `CI`,
|
|
155
|
+
`GITHUB_ACTIONS`, or `GITLAB_CI` disables automatic fire. These environment
|
|
156
|
+
guards run before repository initialization, lease, Kernel-state, or process
|
|
157
|
+
work; dry-run, uninitialized repositories, and a disabled rail are likewise
|
|
158
|
+
zero-side-effect paths. The manual `forge shepherd` surface remains available.
|
|
121
159
|
|
|
122
160
|
## Surfacing events back to the agent (`forge hooks shepherd-events`)
|
|
123
161
|
|
|
@@ -146,6 +184,7 @@ same verb (or `forge shepherd events`) on its own cadence.
|
|
|
146
184
|
| `MERGE_READY` | Required checks are green and the branch is up to date. The shepherd hands off — **a human merges in the GitHub UI.** |
|
|
147
185
|
| `ESCALATE` | A Tier-C condition (conflict, unreadable required set, persistent failure, oscillation, budget exhaustion). Context is posted to the PR. |
|
|
148
186
|
| `PENDING` | A Tier-A action was taken, or checks are still pending. Exit and await the next scheduled pass. |
|
|
187
|
+
| `INCOMPLETE` | Exact-head local review or durable convergence evidence is unavailable. Fail closed and retry after evidence is restored. |
|
|
149
188
|
| `HARD_STOP` | A permanent auth/scope failure that retrying cannot fix. Escalate to a human to widen token scope. |
|
|
150
189
|
|
|
151
190
|
## Action ladder
|
|
@@ -171,6 +210,13 @@ same verb (or `forge shepherd events`) on its own cadence.
|
|
|
171
210
|
- **HEAD-changed abort.** Before any mutating action it re-reads the head SHA; if
|
|
172
211
|
HEAD moved during the pass, the action aborts. The `shepherd:active` marker is
|
|
173
212
|
advisory only — it is not mutual exclusion.
|
|
213
|
+
- **One per-PR authority.** `kernel_pr_watch_owners` is the sole watcher owner
|
|
214
|
+
record. The daemon lease elects one reconciler but contains no watcher list;
|
|
215
|
+
journals and legacy PID/marker files cannot authorize a transition.
|
|
216
|
+
- **Fail-closed evidence.** Kernel unavailability, corrupt owner rows, stale
|
|
217
|
+
generations, changed provider/PID/receipt evidence, and an incomplete legacy
|
|
218
|
+
migration gate block mutation and are retried. No unlocked or filesystem
|
|
219
|
+
fallback becomes authority.
|
|
174
220
|
- **Auth taxonomy.** 401 (expiry) pauses and surfaces; 403 insufficient-scope is
|
|
175
221
|
a hard-stop; 403 with `Retry-After` honors the delay and resumes next pass.
|
|
176
222
|
|
|
@@ -210,17 +256,50 @@ workflow behaves exactly as before (no regression) — it just cannot auto-run C
|
|
|
210
256
|
the updated head. Forge only wires the code path and reads the secret; **creating
|
|
211
257
|
the secret is the maintainer's responsibility** — Forge never fabricates a token.
|
|
212
258
|
|
|
259
|
+
## GitHub Actions PR-monitor summary
|
|
260
|
+
|
|
261
|
+
The repository PR-monitor workflow writes detailed review-thread and check
|
|
262
|
+
diagnostics to the Actions job summary (`GITHUB_STEP_SUMMARY`) and keeps the
|
|
263
|
+
machine-readable view available through `forge shepherd <pr> --pull --json`.
|
|
264
|
+
It projects that same canonical verdict onto exactly one `pr-verdict:*` label
|
|
265
|
+
for a cheap agent-agnostic read. The label is visibility only: merge authority
|
|
266
|
+
continues to use live protected required checks, the current head, and
|
|
267
|
+
unresolved review threads. The workflow does not create PR comments or a
|
|
268
|
+
neutral `forge/pr-monitor` check.
|
|
269
|
+
|
|
213
270
|
## Per-harness behavior
|
|
214
271
|
|
|
215
|
-
- **Claude Code / Codex:**
|
|
216
|
-
|
|
272
|
+
- **Claude Code / Codex:** automatic session-start attachment wakes the singleton;
|
|
273
|
+
invoke `forge shepherd <pr>` directly for a bounded point-in-time read.
|
|
217
274
|
- **Cursor:** manually-invoked only — run it from a terminal. No polling-loop
|
|
218
275
|
affordance and no hook reliance on this surface.
|
|
219
276
|
|
|
220
277
|
## State
|
|
221
278
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
279
|
+
The shared Kernel database stores one versioned `kernel_pr_watch_owners` row per
|
|
280
|
+
canonical `(repo, pr)`. Its generation-conditional phases are `starting`,
|
|
281
|
+
`running`, `stop_requested`, `terminal_pending`, `complete`, and `blocked`.
|
|
282
|
+
Starts reserve a store-minted generation before spawning; the child binds its
|
|
283
|
+
PID to that exact generation; heartbeats, stop requests, terminal receipts,
|
|
284
|
+
recovery, release, and reopen are narrow compare-and-swap transitions. Provider,
|
|
285
|
+
PID, and receipt checks happen outside the short SQLite transaction, followed by
|
|
286
|
+
an exact snapshot check inside it.
|
|
287
|
+
|
|
288
|
+
Public Memory and the per-PR journal under
|
|
289
|
+
`.forge/pr-monitor/<repo>-<pr>/` remain durable delivery and replay surfaces for
|
|
290
|
+
monitor events, verdicts, `forge shepherd watch`, and `events --since`; neither
|
|
291
|
+
is watcher ownership authority. A terminal receipt first moves the owner row to
|
|
292
|
+
`terminal_pending`; a later transaction completes it only after the watcher PID
|
|
293
|
+
is confirmed dead and the receipt/provider evidence still matches.
|
|
294
|
+
|
|
295
|
+
Upgrade from the retired filesystem model is fenced by the repository-local
|
|
296
|
+
`kernel_pr_watch_migration_gate`. The importer publishes `quarantined`, obtains
|
|
297
|
+
two identical bounded snapshots of the old lease/PID/marker evidence, binds that
|
|
298
|
+
snapshot hash before importing one PR per transaction, durably rereads the rows
|
|
299
|
+
and source, and then completes the exact gate/hash. Corrupt, changed, live-PID,
|
|
300
|
+
or unmappable evidence stays fail-closed as `blocked` or `conflict`. After the
|
|
301
|
+
gate is complete, legacy evidence is cleanup-only and never regains authority.
|
|
302
|
+
|
|
303
|
+
For 0.1, no receipt grants continuing lease authority. Consequential paths
|
|
304
|
+
re-probe live ownership, while canonical LeaseReceipt epoch/scope and the
|
|
305
|
+
same-actor/session release-reclaim ABA fix remain explicitly deferred.
|
package/lefthook.yml
CHANGED
|
@@ -21,6 +21,14 @@ pre-commit:
|
|
|
21
21
|
stage_fixed: false
|
|
22
22
|
tags: skills
|
|
23
23
|
glob: "skills/**"
|
|
24
|
+
# Keep the D20 Beads call-site kill-list current with the census it audits.
|
|
25
|
+
# Self-gating: the script exits early unless a staged path actually counts toward
|
|
26
|
+
# the census, because those scan roots are resolved at run time (plugin manifests +
|
|
27
|
+
# .forge/sync-manifest.json) and a static glob here would drift from the gate.
|
|
28
|
+
sync-d20-audit:
|
|
29
|
+
run: node scripts/sync-d20-audit.js
|
|
30
|
+
stage_fixed: false
|
|
31
|
+
tags: release
|
|
24
32
|
protected-state:
|
|
25
33
|
run: node scripts/protected-state-check.js
|
|
26
34
|
stage_fixed: false
|
|
@@ -50,6 +58,10 @@ pre-push:
|
|
|
50
58
|
- run: node scripts/check-forge-token.js
|
|
51
59
|
|
|
52
60
|
# 3. Test suite (cross-platform Node.js script detects package manager)
|
|
61
|
+
# `forge push --quick` sets FORGE_PUSH_LANE=quick on the git push it spawns;
|
|
62
|
+
# scripts/test.js honors that declaration and skips this job with a loud
|
|
63
|
+
# notice so the quick lane is lint-only end to end. Only this job reads it —
|
|
64
|
+
# branch protection and lint above always run, and CI runs the full matrix.
|
|
53
65
|
tests:
|
|
54
66
|
run: node scripts/test.js
|
|
55
67
|
tags: tests
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* bare repo stays untouched until the user actually changes state.
|
|
12
12
|
*
|
|
13
13
|
* "Bare-minimum" here is strictly LESS than `forge init --minimal`: this writes
|
|
14
|
-
* ONLY `.forge/config.yaml` with
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* ONLY `.forge/config.yaml` with Forge's canonical default enforcement posture.
|
|
15
|
+
* It installs NO git hooks, NO lefthook.yml, NO protected-paths manifest, NO
|
|
16
|
+
* `.mcp.json`, and NO scripts tree — those remain the opt-in payload of
|
|
17
|
+
* `forge setup`, never forced. Progressive growth: heavier slices initialize
|
|
18
|
+
* themselves on first use.
|
|
19
19
|
*
|
|
20
20
|
* @module activation/ensure-forge-home
|
|
21
21
|
*/
|
|
@@ -78,26 +78,33 @@ function isMutatingVerb(name, command) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
|
-
* Render the bare-minimum
|
|
81
|
+
* Render the bare-minimum config body with Forge's default enforcement posture.
|
|
82
82
|
*
|
|
83
|
-
* Reuses the canonical `
|
|
84
|
-
* schema-valid and
|
|
85
|
-
*
|
|
86
|
-
*
|
|
83
|
+
* Reuses the canonical `standard` adoption profile so the produced YAML is
|
|
84
|
+
* schema-valid and keeps default gates enabled. Overridable via
|
|
85
|
+
* `deps.renderConfig` for tests that don't want to depend on the profile
|
|
86
|
+
* renderer.
|
|
87
87
|
*
|
|
88
88
|
* @param {object} [deps]
|
|
89
89
|
* @returns {string} config.yaml contents
|
|
90
90
|
*/
|
|
91
|
-
function
|
|
92
|
-
const render = deps.renderConfig || (() => renderAdoptionConfigYaml('
|
|
91
|
+
function renderDefaultConfig(deps = {}) {
|
|
92
|
+
const render = deps.renderConfig || (() => renderAdoptionConfigYaml('standard'));
|
|
93
93
|
return render();
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Backward-compatible export name for callers of the previously exported
|
|
98
|
+
* helper. New code should use `renderDefaultConfig`; lazy initialization no
|
|
99
|
+
* longer creates a minimal/disabled configuration.
|
|
100
|
+
*/
|
|
101
|
+
const renderMinimalConfig = renderDefaultConfig;
|
|
102
|
+
|
|
96
103
|
/**
|
|
97
104
|
* Idempotently create the bare-minimum `.forge/` skeleton for a mutating verb.
|
|
98
105
|
*
|
|
99
|
-
* No-clobber by construction:
|
|
100
|
-
*
|
|
106
|
+
* No-clobber by construction: an existing config is a NO-OP. A partial home
|
|
107
|
+
* whose `.forge/` directory exists without `config.yaml` is completed safely.
|
|
101
108
|
* The kernel/issue store (`.forge/kernel/…`) is created lazily by the broker on
|
|
102
109
|
* the mutating verb itself — this function only guarantees the config skeleton.
|
|
103
110
|
*
|
|
@@ -123,13 +130,24 @@ function ensureForgeHome(projectRoot = process.cwd(), deps = {}) {
|
|
|
123
130
|
}
|
|
124
131
|
|
|
125
132
|
fsImpl.mkdirSync(forgeDir, { recursive: true });
|
|
126
|
-
|
|
133
|
+
try {
|
|
134
|
+
fsImpl.writeFileSync(configPath, renderDefaultConfig(deps), {
|
|
135
|
+
encoding: 'utf8',
|
|
136
|
+
flag: 'wx',
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (error?.code === 'EEXIST') {
|
|
140
|
+
return { created: false, reason: 'config-exists', configPath };
|
|
141
|
+
}
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
127
144
|
return { created: true, configPath };
|
|
128
145
|
}
|
|
129
146
|
|
|
130
147
|
module.exports = {
|
|
131
148
|
ensureForgeHome,
|
|
132
149
|
isMutatingVerb,
|
|
150
|
+
renderDefaultConfig,
|
|
133
151
|
renderMinimalConfig,
|
|
134
152
|
MUTATING_VERBS,
|
|
135
153
|
};
|