forge-orkes 0.72.2 → 0.74.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.
@@ -619,10 +619,12 @@ function runPostUpgradeMigrationChecks(installedVersion) {
619
619
 
620
620
  let stdout = '';
621
621
  try {
622
- // Trust model: guides were re-synced from the (trusted) npm package in
623
- // step 2 above before this runs, so the on-disk content is not
624
- // attacker-controlled here; the only residual risk is a runaway/buggy
625
- // detection block, bounded by `timeout`.
622
+ // Trust model: template-only sync (step 2 above) never overwrites a
623
+ // project-local extra in-range migration guide, so a guide the project
624
+ // added itself runs its Detection block verbatim here too — the trust
625
+ // boundary is "guides present in the template + anything the project
626
+ // chose to keep", not "template-authored only". Residual risk is a
627
+ // runaway/buggy detection block, bounded by `timeout`.
626
628
  stdout = execSync(script, {
627
629
  cwd: targetDir,
628
630
  shell: '/bin/bash',
@@ -60,8 +60,8 @@ Three stderr line patterns:
60
60
 
61
61
  ## Contracts
62
62
 
63
- - Tool schemas + semantics: `.forge/phases/m10-01-orchestration/contracts/mcp-tools.md`
64
- - Data model + retention: `.forge/phases/m10-01-orchestration/data-model.md`
63
+ - Tool schemas + semantics: `.forge/phases/milestone-10/01-orchestration/contracts/mcp-tools.md`
64
+ - Data model + retention: `.forge/phases/milestone-10/01-orchestration/data-model.md`
65
65
  - Architecture rationale: `.forge/decisions/ADR-003-awareness-mcp-sqlite.md`
66
66
  - Lifecycle rationale: `.forge/decisions/ADR-005-session-lifecycle.md`
67
67
 
@@ -5,8 +5,8 @@
5
5
  // server process; concurrent state shared via SQLite WAL on claims.db. Server exits when
6
6
  // client stdin closes (orphan defense for Claude Code #33947 without pidfile sibling-kill).
7
7
  // #40207 mitigation: 8s stderr keepalive.
8
- // Contract: .forge/phases/m10-01-orchestration/contracts/mcp-tools.md
9
- // Schema: .forge/phases/m10-01-orchestration/data-model.md
8
+ // Contract: .forge/phases/milestone-10/01-orchestration/contracts/mcp-tools.md
9
+ // Schema: .forge/phases/milestone-10/01-orchestration/data-model.md
10
10
 
11
11
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -118,6 +118,7 @@ Relocate the session into the worktree, then return control to caller (typically
118
118
 
119
119
  - **If the `EnterWorktree` tool is available**, call `EnterWorktree({path: {lifecycle.worktree_path}})` to relocate the session into the worktree before returning control, then log `Relocated into worktree {lifecycle.worktree_path} ({lifecycle.worktree_branch})` (independent of any prompt, so the cwd move is visible).
120
120
  - **If `EnterWorktree` is unavailable** (older Claude Code CLI, or a non-Claude-Code adapter), fall back to instructing the caller to `cd {path}` (here `cd {lifecycle.worktree_path}`) before continuing — today's implicit assumption stated explicitly.
121
+ - **On an EnterWorktree error/rejection** (not just tool absence) — e.g. a worktree→worktree relocation rejects the call under the tool's path constraint (ADR-010 roots live outside `.claude/worktrees/`) — fall back to the same printed `cd` instruction above, exactly as if the tool were unavailable.
121
122
  - Exit stays `ExitWorktree({action: "keep"})`; teardown remains Step 5 / `git worktree remove` — the native tool never removes the worktree.
122
123
 
123
124
  All subsequent work runs inside `lifecycle.worktree_path`. Caller honors claim convention.
@@ -152,14 +153,17 @@ Triggered when caller signals work complete OR user requests teardown.
152
153
 
153
154
  ### Step 5.0: Human Verification Gate (hard block — runs first)
154
155
 
155
- Before any merge or worktree removal, read `current.human_verified` from `.forge/state/milestone-{id}.yml`.
156
+ **Merged-ness split (operator ruling 2026-07-16 — binding-independent).** Teardown is not a release event: what the human gate protects *at teardown* is **un-landed work**, and merged-ness is exactly that predicate, machine-checkable. Before any `human_verified` read, compute the unit's state: `.claude/hooks/forge-release-fold.sh m-{id}` (any dir in the repo).
157
+
158
+ - **`merged` or `validated`** → teardown **auto-proceeds** — the work is on main; removing the worktree loses nothing. Note it in the teardown report (*"teardown auto-proceeded: unit renders {release_state} — work already on main"*) and skip to the merge below. The milestone **close** gate is untouched by this split — close keeps its own binding rule (`reviewing`'s hard block; FORGE.md → Human Verification Gate).
159
+ - **`unmerged`** (or the fold exits 2 — unknown unit; treat as un-merged) → the human gate applies. Read `current.human_verified` from `.forge/state/milestone-{id}.yml` and run the hard block below, unchanged. (Under `promotion_approval`, `verifying` deliberately never captures `human_verified` — so abandoning **un-merged** work under that binding goes through the **recorded override** path below, the expected route for discarding work that never landed.)
156
160
 
157
161
  - **Present** (`{at, method, ...}`, including a recorded `override`) → gate satisfied, proceed to the merge below.
158
162
  - **Absent / null** → **REFUSE teardown.** Code-clean + FF-clean is **not** enough to close a milestone (FORGE.md → Human Verification Gate). Do **not** present teardown as an option, and never offer it as a peer alternative to the outstanding verification. Respond with what's still unverified and offer exactly two paths:
159
163
  1. **Verify now** → run the human verification (device session / visual / e2e walk). Have `verifying` (or this step) record `current.human_verified`, then re-invoke teardown.
160
164
  2. **Record override** → only on an explicit human instruction to close without verifying: write `current.human_verified: {at: "<ISO 8601>", method: "override", override: true, reason}` to the milestone file, surface it, then proceed.
161
165
 
162
- Never merge + remove a worktree while `human_verified` is unset.
166
+ Never merge + remove a worktree holding **un-merged** work while `human_verified` is unset.
163
167
 
164
168
  ```
165
169
  forge_queue_commit(branch=forge/m-{id}-{session_id}, base_sha={merge_base})
@@ -167,7 +171,7 @@ forge_queue_commit(branch=forge/m-{id}-{session_id}, base_sha={merge_base})
167
171
 
168
172
  Branch on response status:
169
173
 
170
- - **`merged`** (response has `new_main_sha`) → **reconcile the working tree first** — `forge_queue_commit` merges *ref-only* (`update-ref`), so the main checkout is now behind HEAD: `git checkout HEAD -- $(git diff --name-only {base_sha} {new_main_sha})` — surgical, merged files only; **never** `git checkout HEAD -- .` (would clobber unrelated WIP) → `forge_release_claims(claim_session_id)` (the Claude session id, not the worktree uuid) → `git worktree remove --force --force "$(yq '.lifecycle.worktree_path' .forge/state/milestone-{id}.yml)"` (double `--force`: Step 2 created the worktree `--lock`ed, and a single `--force` refuses to remove a locked worktree; read the path from state rather than re-deriving it so a moved/non-default worktree still removes cleanly) → `git branch -d forge/m-{id}-{session_id}` → clear `lifecycle.*` (set `worktree_mode: complete`, retain `session_id` for audit) → **State reconcile = Rollup:** regenerate `state/index.yml` from the now-merged `milestone-*.yml` files (`forge` Rollup 1.0) and commit it (`chore(forge): rollup state after teardown {session_id}`). The merged milestone files are the source of truth; index.yml is never hand-merged.
174
+ - **`merged`** (response has `new_main_sha`) → **reconcile the working tree first** — `forge_queue_commit` merges *ref-only* (`update-ref`), so the main checkout is now behind HEAD: `git checkout HEAD -- $(git diff --name-only {base_sha} {new_main_sha})` — surgical, merged files only; **never** `git checkout HEAD -- .` (would clobber unrelated WIP) → `forge_release_claims(claim_session_id)` (the Claude session id, not the worktree uuid) → `git worktree remove --force --force "$(yq '.lifecycle.worktree_path' .forge/state/milestone-{id}.yml)"` (double `--force`: Step 2 created the worktree `--lock`ed, and a single `--force` refuses to remove a locked worktree; read the path from state rather than re-deriving it so a moved/non-default worktree still removes cleanly) → `git branch -d forge/m-{id}-{session_id}` → clear `lifecycle.*` (set `worktree_mode: complete`, retain `session_id` for audit) → **State reconcile = Rollup:** regenerate `state/index.yml` from the now-merged `milestone-*.yml` files (`forge` Rollup 1.0) **locally** — since 0.53.0 `index.yml` is a **git-ignored render-on-read cache**, so **do not commit it** (a scoped `git add .forge/` no-ops on the ignored path; force-committing it would reintroduce the drift render-on-read exists to kill). No teardown state-commit is needed for the registry: the merged `milestone-*.yml` files are the source of truth and are already committed by the merge; index.yml is never hand-merged and never committed.
171
175
  - **`conflict`** → invoke `Skill(debugging)` with payload `{ conflicted_files, base_sha, messages, branch }`. Teardown blocks until debugging signals resolution (re-invoke teardown after fix).
172
176
  - **`stale_base`** → caller rebases worktree branch onto `current_target_sha` from response, retries `forge_queue_commit`. Max 3 retries → escalate to conflict path.
173
177
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-orkes",
3
- "version": "0.72.2",
3
+ "version": "0.74.0",
4
4
  "description": "Set up the Forge meta-prompting framework for Claude Code in your project",
5
5
  "bin": {
6
6
  "create-forge": "./bin/create-forge.js"