forge-orkes 0.62.0 → 0.63.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/bin/create-forge.js +250 -99
- package/experimental/conventions/README.md +87 -0
- package/experimental/conventions/install.sh +179 -0
- package/experimental/conventions/source/rules/code-quality.md +17 -0
- package/experimental/conventions/source/rules/laravel-http.md +21 -0
- package/experimental/conventions/source/rules/laravel-jobs.md +19 -0
- package/experimental/conventions/source/rules/laravel-migrations.md +19 -0
- package/experimental/conventions/source/rules/laravel-services.md +21 -0
- package/experimental/conventions/source/rules/python.md +14 -0
- package/experimental/conventions/source/rules/testing.md +15 -0
- package/experimental/conventions/source/rules/vue-inertia.md +24 -0
- package/experimental/conventions/source/skills/laravel-conventions/SKILL.md +124 -0
- package/experimental/conventions/source/skills/python-conventions/SKILL.md +100 -0
- package/experimental/conventions/source/skills/testing-standards/SKILL.md +142 -0
- package/experimental/conventions/source/skills/vue-conventions/SKILL.md +92 -0
- package/experimental/conventions/uninstall.sh +97 -0
- package/experimental/m10/README.md +130 -0
- package/experimental/m10/install.sh +198 -0
- package/experimental/m10/source/hooks/forge-branch-guard.sh +61 -0
- package/experimental/m10/source/hooks/forge-claim-check-doctor.sh +77 -0
- package/experimental/m10/source/hooks/forge-claim-check.sh +113 -0
- package/experimental/m10/source/hooks/forge-session-id.sh +22 -0
- package/experimental/m10/source/mcp-server/README.md +74 -0
- package/experimental/m10/source/mcp-server/example.mcp.json +8 -0
- package/experimental/m10/source/mcp-server/index.js +460 -0
- package/experimental/m10/source/mcp-server/package.json +17 -0
- package/experimental/m10/source/skills/orchestrating/SKILL.md +223 -0
- package/experimental/m10/source/skills/orchestrating/bootstrap-checks.md +70 -0
- package/experimental/m10/uninstall.sh +69 -0
- package/package.json +3 -2
- package/template/.claude/settings.json +1 -7
- package/template/.claude/skills/upgrading/SKILL.md +105 -176
- package/template/.forge/FORGE.md +2 -2
- package/template/.forge/migrations/0.63.0-origin-first-upgrading.md +49 -0
|
@@ -1,231 +1,160 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: upgrading
|
|
3
|
-
description: "
|
|
3
|
+
description: "Upgrade Forge framework files from the npm registry (origin-first default), or sync from a local dev repo in explicit dev mode. Use when applying updates to an installed project or developing Forge itself."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Upgrading:
|
|
6
|
+
# Upgrading: Origin-First Registry Upgrade
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The default upgrade path is the npm registry. This skill wraps the published bin (`forge-orkes`) as the **one sync engine** and layers the agent-only steps on top: the bin computes and applies the file sync; the skill renders the report and drives the consent-gated conversations. One computation, two renderings — never re-detect what the bin already reported. Local-clone sync survives only as explicit **Dev Mode** (`/upgrading dev`).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Mode Gate (first)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
| Invocation | Mode |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `/upgrading dev` | **Dev Mode** (below) — local-clone sync for developing Forge itself |
|
|
15
|
+
| `/upgrading X.Y.Z` | Default path with the engine pinned: `npx forge-orkes@{version} upgrade --yes --json` |
|
|
16
|
+
| `/upgrading` | Default path at `@latest` |
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
## Default Path (registry)
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
- **Missing:** Ask the user for the local Forge repo path, validate it has `packages/create-forge/template/`, save to `.forge/dev-source`.
|
|
20
|
+
### 1. Preflight
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
- Read the installed version: `.claude/settings.json` → `forge.version` (absent → treat as `unknown`).
|
|
23
|
+
- `.forge/dev-source` present → emit exactly ONE notice line — *"dev mode available — `/upgrading dev`"* — and continue on the registry path. Presence of `.forge/dev-source` NEVER selects dev mode.
|
|
20
24
|
|
|
21
|
-
###
|
|
22
|
-
|
|
23
|
-
`upgrading` is the one skill that bridges this project and a local Forge clone (`{source}`), so it harvests framework-scope desire paths the project has queued (ADR-012). After resolving `{source}`:
|
|
24
|
-
|
|
25
|
-
1. Glob this project's `.forge/state/desire-paths/upstream/*.md`. None → skip silently.
|
|
26
|
-
2. Any present → list them and offer to copy each into `{source}/docs/desire-paths-inbox/` (create the dir if missing) — a **tracked** location in the Forge repo where it won't be lost on machine swap.
|
|
27
|
-
3. On copy → move the project-side block to `.forge/state/desire-paths/upstream/harvested/` so it isn't re-offered. Report counts like other steps.
|
|
28
|
-
|
|
29
|
-
Advisory — never blocks the sync. This is the **convenience tier**: the primary close is the GH issue offered by `forge` review at capture time. Harvest just catches anything written when `gh`/the repo URL wasn't available.
|
|
30
|
-
|
|
31
|
-
### Downgrade guard
|
|
32
|
-
|
|
33
|
-
Read the source version (`{source}/packages/create-forge/package.json` `version`) and the installed version (`.claude/settings.json` `forge.version`). **If source < installed, STOP** — do not sync. Report: *"Refusing to downgrade: installed v{installed} is newer than source v{source}. Point dev-source at a newer checkout, or confirm an intentional downgrade."* Only proceed on explicit user override. (Rolling backward overwrites newer framework files and deletes files newer versions added — and with `.claude/` often gitignored, it is unrecoverable.)
|
|
34
|
-
|
|
35
|
-
## Step 2: File Classification
|
|
36
|
-
|
|
37
|
-
| Category | Paths | Behavior |
|
|
38
|
-
|----------|-------|----------|
|
|
39
|
-
| **Framework-owned** | `.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `.forge/FORGE.md` | Overwrite |
|
|
40
|
-
| **Import-managed** | `CLAUDE.md` | Never overwrite content; migrate legacy forge sections + guarantee the `@.forge/FORGE.md` import line (Step 5) |
|
|
41
|
-
| **Merge-owned** | `.claude/settings.json` | Smart-merge `forge.*` keys only (Step 5) |
|
|
42
|
-
| **Template-only** | `.forge/templates/**`, `.forge/migrations/**`, `.forge/gitignore` → `.forge/.gitignore` | Overwrite |
|
|
43
|
-
| **Additive-sync** | `.claude/hooks/**` (incl. `tests/`), `.claude/rules/**`, `.forge/checks/**` (incl. `tests/`) | Add + overwrite template-shipped files; never delete local extras (Step 4a) |
|
|
44
|
-
|
|
45
|
-
**Never touch** user-generated files: `.forge/project.yml`, `.forge/state/`, `.forge/constitution.md`, `.forge/context.md`, `.forge/requirements/`, `.forge/roadmap.yml`, `.forge/design-system.md`, `.forge/refactor-backlog.yml`.
|
|
46
|
-
|
|
47
|
-
**Experimental skills — re-sync, don't blanket-skip.** Opt-in skills installed separately (e.g. `.claude/skills/orchestrating/` from `experimental/m10/`) are not in the base template, so they never appear in the Step 3 base sync. Earlier guidance was to leave them *untouched* — but that silently froze them at install-time content, so a base-template migration that changes behavior living only in an experimental skill became a no-op (the version stamp advanced and the migration doc shipped, yet the behavior never landed — e.g. the 0.28.0 repo-scoped worktree root). Step 3b now gives experimental skills their own **detect-and-offer-re-sync** pass against their `experimental/*/source/` origin. Never auto-overwrite and never flag them "removed from template" — but never leave staleness invisible either.
|
|
48
|
-
|
|
49
|
-
## Step 3: Sync Framework-Owned Files
|
|
50
|
-
|
|
51
|
-
For each framework-owned file in the source template:
|
|
52
|
-
|
|
53
|
-
1. Read source and local content
|
|
54
|
-
2. Different → overwrite local, report **updated**
|
|
55
|
-
3. Same → report **unchanged**
|
|
56
|
-
4. Source has new file → copy, report **added**
|
|
57
|
-
5. Local has file not in source → it may be an **experimental** skill — defer the verdict to Step 3b, which distinguishes "experimental, has a known source" from "genuinely removed from template." Only skills with no experimental source are reported **removed from template** (don't delete -- let user decide).
|
|
58
|
-
|
|
59
|
-
## Step 3b: Re-sync Experimental Skills (detect + offer, never blanket-skip)
|
|
60
|
-
|
|
61
|
-
Experimental skills are installed from `{source}/packages/create-forge/experimental/<pkg>/source/skills/<name>/`, not the base template — so Step 3 never sees them. Without this pass they freeze at install-time content forever (issue #5). This pass makes staleness **visible and one-click-fixable** while staying non-destructive.
|
|
62
|
-
|
|
63
|
-
For each skill dir present in the project's `.claude/skills/` but **absent from the base template**:
|
|
64
|
-
|
|
65
|
-
1. Search the source for a matching experimental origin: `{source}/packages/create-forge/experimental/*/source/skills/<name>/`.
|
|
66
|
-
2. **No match** → genuinely local / removed-from-template. Report **removed from template** (don't delete) as before. Done.
|
|
67
|
-
3. **Match found** → it is an experimental skill with a known upstream. Diff each markdown file in the installed dir against the source dir (`SKILL.md` and any siblings, e.g. `bootstrap-checks.md`):
|
|
68
|
-
- **All identical** → report `{name}: experimental, unchanged`.
|
|
69
|
-
- **Differs** → report `{name}: experimental, STALE (pinned at install; source has changes)` and **offer** a re-sync with the same preview/confirm UX as base skills:
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
{name} is an experimental skill (from experimental/{pkg}/) pinned at install time.
|
|
73
|
-
The release ships newer content. Files that differ: {list}.
|
|
74
|
-
Re-sync from experimental/{pkg}/source? (yes / show diff / no)
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
- **yes** → overwrite the installed skill's markdown files from source; report **updated (experimental)**.
|
|
78
|
-
- **show diff** → display the diff(s), then re-ask.
|
|
79
|
-
- **no** → leave untouched; note in the report that it stays pinned.
|
|
25
|
+
### 2. Run the engine
|
|
80
26
|
|
|
81
|
-
|
|
27
|
+
One Bash invocation:
|
|
82
28
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
**Also sync the forge gitignore:** the source ships it as `.forge/gitignore` (npm strips files literally named `.gitignore` from a published tarball). Copy/refresh the source's `.forge/gitignore` into the project as `.forge/.gitignore` (overwrite — it is framework-owned). Report added/updated/unchanged like any template-only file.
|
|
88
|
-
|
|
89
|
-
**Sync the framework prose file `.forge/FORGE.md`** (framework-owned single file — it holds the `# Forge` prose, formerly embedded in CLAUDE.md). Copy/refresh `{source}/packages/create-forge/template/.forge/FORGE.md` → `.forge/FORGE.md` (overwrite when different; report added/updated/unchanged). **Run this BEFORE the Step 5 CLAUDE.md pass** so a migrated import line never points at a missing file.
|
|
90
|
-
|
|
91
|
-
## Step 4a: Sync Hooks + Rules + Checks (additive — mirrors the npm bin)
|
|
29
|
+
```bash
|
|
30
|
+
npx forge-orkes@latest upgrade --yes --json
|
|
31
|
+
# pinned: npx forge-orkes@{version} upgrade --yes --json
|
|
32
|
+
```
|
|
92
33
|
|
|
93
|
-
|
|
34
|
+
- stdout is exactly ONE JSON document; stderr is human prose — ignore it.
|
|
35
|
+
- `--yes` auto-confirms stale-framework-file removal ONLY; it never bypasses the downgrade guard.
|
|
36
|
+
- **Non-zero exit** → the bin refused or failed and still emitted `{error, reason}` on stdout. Surface the reason and **STOP**. The downgrade-guard refusal names `--force`; that stays a human decision — never re-run with `--force` yourself.
|
|
94
37
|
|
|
95
|
-
|
|
38
|
+
### 3. Parse the JSON
|
|
96
39
|
|
|
97
|
-
1
|
|
98
|
-
2. Present but differs → overwrite, report **updated**.
|
|
99
|
-
3. Identical → report **unchanged**.
|
|
100
|
-
4. **Additive only** — never delete a local file the template lacks. Project-local and experimental hooks (e.g. M10 `forge-claim-check*.sh`) and pack-installed path-scoped rules are preserved; no "removed from template" verdicts in this pass.
|
|
101
|
-
5. `chmod +x` every synced `*.sh` (a copy can strip the execute bit; guard hooks and CI checks must be runnable).
|
|
40
|
+
Top-level keys (all always present; `schemaVersion: 1`): `installedVersion` (pre-stamp; `"unknown"` if unstamped), `packageVersion`, `packageRoot` (the bin's own package dir — an npx cache path, valid at emit time only), `results` (`{updated, added, unchanged, removed, preserved}`, repo-relative paths), `claudeMd` (`created|migrated|appended|unchanged`), `settings` (`updated|unchanged|missing`), `experimental` (`[{name, pkg, status: unchanged|stale, files}]` — detection only; the bin never rewrites), `migrations` (`[{version, guide, reason}]` — applying guides only, pre-filtered), `codexAdapterPresent`, `worktrees` (`[{path, branch}]` — live `forge/m-*`).
|
|
102
41
|
|
|
103
|
-
|
|
42
|
+
`schemaVersion` ≠ 1 → warn (*"engine emitted schema {n}; this skill reads 1"*) and render best-effort — never silently misread.
|
|
104
43
|
|
|
105
|
-
|
|
44
|
+
### 4. Render the report
|
|
106
45
|
|
|
107
|
-
|
|
46
|
+
From the JSON only — no re-scanning:
|
|
108
47
|
|
|
109
|
-
|
|
48
|
+
```
|
|
49
|
+
Forge Upgrade Complete (registry)
|
|
50
|
+
─────────────────────────────────
|
|
51
|
+
Source: npm registry — forge-orkes@{packageVersion}
|
|
52
|
+
Version: {installedVersion} → {packageVersion}
|
|
53
|
+
|
|
54
|
+
Updated / Added: listed from results
|
|
55
|
+
Experimental skills: {N} (name, pkg, status)
|
|
56
|
+
Codex adapter: present / not present (layer c updates this line)
|
|
57
|
+
Removed from template: {N} (removal confirmed via --yes)
|
|
58
|
+
CLAUDE.md: {claudeMd} (migrated/appended render as Migrated:/Restored:)
|
|
59
|
+
Settings: {settings}
|
|
60
|
+
Unchanged: {N} · Preserved: {N} (user-owned, never touched)
|
|
61
|
+
```
|
|
110
62
|
|
|
111
|
-
|
|
112
|
-
2. **Either exists → report + offer.** The Codex adapter is present and may be stale relative to the `.claude/` source just synced in Steps 3–4. Offer regeneration:
|
|
113
|
-
```
|
|
114
|
-
Codex adapter detected (.agents/ / .codex/). It may be stale vs the .claude/
|
|
115
|
-
source just synced. Regenerate it now? (yes / no)
|
|
116
|
-
```
|
|
117
|
-
- **yes** → invoke `quick-tasking`, handing it `.forge/adapters/codex-generation.md` as the task definition (the **same delegation pattern as Step 7 migrations**). The protocol instructs an agent-as-Codex to author `.agents/` + `.codex/` from source using native primitives; a human reviews the diff before commit. `upgrading` itself **never** writes `.agents/` and never performs the translation.
|
|
118
|
-
- **no** → record `Codex adapter: stale, declined` for the Step 6 report.
|
|
119
|
-
3. **Report line.** Add a `Codex adapter:` line to the Step 6 report — one of `regenerated` / `stale, declined` / `not present`.
|
|
63
|
+
## Agent Layers (after the report — consent-gated, keyed to the JSON)
|
|
120
64
|
|
|
121
|
-
|
|
65
|
+
The engine changed; the conversation did not. Each layer consumes one JSON field and preserves the legacy consent UX exactly. Trust the JSON — never re-run detection the bin already did (no second worktree scan, no second migration Detection pass).
|
|
122
66
|
|
|
123
|
-
|
|
67
|
+
### a. Migrations — `migrations[]`
|
|
124
68
|
|
|
125
|
-
|
|
69
|
+
For each entry in the migrations array `[{version, guide, reason}]` from the JSON, the uniform prompt:
|
|
126
70
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
71
|
+
```
|
|
72
|
+
{version} migration available — {reason}
|
|
73
|
+
Guide: {guide}
|
|
74
|
+
Migrate now? (yes/no/show guide)
|
|
75
|
+
```
|
|
132
76
|
|
|
133
|
-
|
|
77
|
+
- **yes** → invoke `quick-tasking`, handing it the guide path as the task definition. Migrations are never applied inline by upgrading; lossy steps are confirmed inside quick-tasking.
|
|
78
|
+
- **show guide** → display the guide, re-ask.
|
|
79
|
+
- **no** → note in the report (split-brain until migrated — recommend before the next planning/review cycle).
|
|
134
80
|
|
|
135
|
-
|
|
136
|
-
1. Read source and local versions
|
|
137
|
-
2. Compare `forge.*` keys only
|
|
138
|
-
3. If different → update `forge.*` keys in local, preserve user's `hooks` and custom keys
|
|
139
|
-
4. Set `forge.version` to match the source package version
|
|
140
|
-
5. **Additively merge the template's framework hook wiring** (ADR-017, mirrors the bin's `upgradeSettingsHooks`): for each hook group in the template's `hooks`, add it to the local `hooks` unless a deep-equal group already exists. Never remove or rewrite a user's own hook entries. Without this, the scripts synced in Step 4a exist on disk but never fire on projects whose settings.json predates the wiring.
|
|
81
|
+
### b. Experimental re-sync — `experimental[]`
|
|
141
82
|
|
|
142
|
-
|
|
83
|
+
For each entry with `status: stale` (detection is bin-side; the bin never rewrites experimental skills):
|
|
143
84
|
|
|
144
85
|
```
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
86
|
+
{name} is an experimental skill (from experimental/{pkg}/) pinned at install time.
|
|
87
|
+
The release ships newer content. Files that differ: {files}.
|
|
88
|
+
Re-sync from the release package? (yes / show diff / no)
|
|
89
|
+
```
|
|
149
90
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
91
|
+
- Source path: `{packageRoot}/experimental/{pkg}/source/skills/{name}/` from the JSON. `packageRoot` is an npx cache path valid at emit time — use it immediately in this session; absent/invalid → fall back to offering `experimental/{pkg}/install.sh` guidance.
|
|
92
|
+
- **yes** → overwrite the installed skill's **markdown** files only (hooks, MCP server, settings/`.mcp.json` wiring stay owned by the package installer). Report *updated (experimental)* and add: *"Hooks / MCP server for {pkg} are not re-synced here — re-run `experimental/{pkg}/install.sh` if the release changed them."*
|
|
93
|
+
- **show diff** → display, re-ask. **no** → stays pinned; note it.
|
|
153
94
|
|
|
154
|
-
|
|
155
|
-
- .claude/skills/new-skill/SKILL.md
|
|
156
|
-
- ...
|
|
95
|
+
### c. Codex adapter — `codexAdapterPresent`
|
|
157
96
|
|
|
158
|
-
|
|
159
|
-
- orchestrating (from experimental/m10) — updated [or: unchanged / STALE, declined]
|
|
160
|
-
- ...
|
|
97
|
+
`false` → skip silently. `true` → the adapter may be stale vs the `.claude/` source the bin just upgraded — offer regeneration (never auto; upgrading never writes `.agents/`):
|
|
161
98
|
|
|
162
|
-
|
|
99
|
+
```
|
|
100
|
+
Codex adapter detected (.agents/ / .codex/). It may be stale vs the .claude/ source just upgraded.
|
|
101
|
+
Regenerate it now? (yes / no)
|
|
102
|
+
```
|
|
163
103
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
- ...
|
|
104
|
+
- **yes** → invoke `quick-tasking`, handing it `.forge/adapters/codex-generation.md` as the task definition (an agent-as-Codex authors the adapter natively; a human reviews the diff before commit).
|
|
105
|
+
- **no** → report line `Codex adapter: stale, declined`.
|
|
167
106
|
|
|
168
|
-
|
|
169
|
-
- CLAUDE.md (forge section extracted to .forge/FORGE.md — @import)
|
|
107
|
+
### d. Worktree propagation — `worktrees[]`
|
|
170
108
|
|
|
171
|
-
|
|
172
|
-
- CLAUDE.md (@.forge/FORGE.md import line re-appended)
|
|
109
|
+
Non-empty → the upgrade landed in this checkout only; each live worktree keeps its branch-point framework files until it rebases. **Commit the upgrade first** — a worktree can only rebase onto committed history; if the sync is uncommitted, prompt (*"Commit this upgrade before propagating? e.g. `chore(forge): upgrade to v{packageVersion}`"*) and wait. Then offer — never auto (a rebase can conflict and needs human judgment):
|
|
173
110
|
|
|
174
|
-
Unchanged: {N} files
|
|
175
111
|
```
|
|
112
|
+
{N} live worktree(s) lag this upgrade (v{installedVersion} → v{packageVersion}):
|
|
113
|
+
- {path} ({branch})
|
|
114
|
+
Pick up v{packageVersion} in each: git -C {path} rebase main
|
|
115
|
+
Rebase now? (each / list-only / skip)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **each** → run `git -C {path} rebase main` per worktree; on conflict, stop that one, report it, move on — never force, never auto-resolve.
|
|
119
|
+
- **list-only / skip** → print the commands; the operator runs them at a safe stopping point.
|
|
120
|
+
- Gitignored carve-outs (`.mcp.json`, experimental hooks) are not carried by a rebase — whenever layer (b) re-synced anything, add: each worktree must re-run `experimental/{pkg}/install.sh`.
|
|
176
121
|
|
|
177
|
-
|
|
122
|
+
## Dev Mode (`/upgrading dev` — explicit only)
|
|
178
123
|
|
|
179
|
-
|
|
124
|
+
Local-clone sync for developing Forge itself: test framework changes in a project without publishing to npm. Presence of `.forge/dev-source` NEVER selects this mode — only the explicit `dev` argument does.
|
|
180
125
|
|
|
181
|
-
|
|
126
|
+
### Source resolution
|
|
182
127
|
|
|
183
|
-
|
|
128
|
+
`.forge/dev-source` exists → read the path (first line, trimmed) and confirm it contains `packages/create-forge/template/`. Missing → ask for the local Forge repo path, validate it, save to `.forge/dev-source`.
|
|
184
129
|
|
|
185
|
-
###
|
|
130
|
+
### Harvest upstream desire paths (advisory)
|
|
186
131
|
|
|
187
|
-
|
|
188
|
-
2. **`source`** = `{source}/packages/create-forge/package.json` `version`. This is the authoritative new version. (Again: never the template `settings.json` literal.)
|
|
189
|
-
3. Glob the just-synced guides: `.forge/migrations/{v}-*.md`. Parse `{v}` (the leading `MAJOR.MINOR.PATCH`) from each filename. Select guides where **`installed < v <= source`** (semver compare on dotted numerics).
|
|
190
|
-
4. For each selected guide, ascending by version: run its `## Detection` fenced bash block from the project root (via the Bash tool, under `bash`).
|
|
191
|
-
- stdout contains **`MIGRATE`** → the migration applies; surface the prompt (below). The text after `MIGRATE —` is the reason; show it.
|
|
192
|
-
- prints nothing / no `MIGRATE` → **no-op**; report `{v}: no action` and move on.
|
|
193
|
-
- the block errors → report `{v}: detection error (skipped)`; do **not** abort the loop.
|
|
132
|
+
Dev mode is the one route that bridges this project and a local Forge clone, so it harvests framework-scope desire paths (ADR-012): glob `.forge/state/desire-paths/upstream/*.md`; none → skip silently. Any present → offer to copy each into `{source}/docs/desire-paths-inbox/` (create if missing); on copy, move the project-side block to `.forge/state/desire-paths/upstream/harvested/` so it isn't re-offered. Convenience tier only — the GH issue offered at capture time remains the primary channel. Never blocks the sync.
|
|
194
133
|
|
|
195
|
-
###
|
|
134
|
+
### Downgrade guard
|
|
196
135
|
|
|
197
|
-
|
|
136
|
+
Source version (`{source}/packages/create-forge/package.json`) **<** installed (`.claude/settings.json` `forge.version`) → **STOP**: *"Refusing to downgrade: installed v{installed} is newer than source v{source}. Point dev-source at a newer checkout, or confirm an intentional downgrade."* Proceed only on explicit user override — rolling backward overwrites newer framework files and deletes files newer versions added, and with `.claude/` often gitignored that is unrecoverable.
|
|
198
137
|
|
|
199
|
-
|
|
200
|
-
{v} migration available — {reason from the MIGRATE line, or the guide title}
|
|
201
|
-
Guide: .forge/migrations/{v}-{slug}.md
|
|
202
|
-
(canonical: https://github.com/Attuned-Media/forge/blob/main/docs/migrations/{v}-{slug}.md)
|
|
138
|
+
### Local sync
|
|
203
139
|
|
|
204
|
-
|
|
205
|
-
```
|
|
140
|
+
Dev mode syncs from a checkout, so it keeps file-classification semantics — **the npm bin's sync behavior is the spec**; do not re-derive it here. Categories:
|
|
206
141
|
|
|
207
|
-
- **
|
|
208
|
-
- **
|
|
209
|
-
- **
|
|
142
|
+
- **Framework-owned** (`.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `.forge/FORGE.md`) → overwrite when different; a local skill dir absent from the template defers to the experimental pass below (only no-source dirs report *removed from template* — never deleted).
|
|
143
|
+
- **Template-only** (`.forge/templates/**`, `.forge/migrations/**`, `.forge/adapters/**`, `.forge/gitignore` → `.forge/.gitignore`) → overwrite; `.forge/FORGE.md` lands BEFORE the CLAUDE.md pass.
|
|
144
|
+
- **Additive** (`.claude/hooks/**` incl. `tests/`, `.claude/rules/**`, `.forge/checks/**`) → add + overwrite template-shipped files, never delete local extras, `chmod +x` synced `*.sh`.
|
|
145
|
+
- **Import-managed** `CLAUDE.md` → the bin's `ensureClaudeMdImport()` cases verbatim; user content outside a forge section is never modified.
|
|
146
|
+
- **Merge-owned** `.claude/settings.json` → `forge.*` keys + additive hook-group wiring only; stamp `forge.version` last.
|
|
147
|
+
- **Never touch** user-generated files: `.forge/project.yml`, `.forge/state/`, `.forge/constitution.md`, `.forge/context.md`, `.forge/requirements/`, `.forge/roadmap.yml`, `.forge/design-system.md`, `.forge/refactor-backlog.yml`.
|
|
210
148
|
|
|
211
|
-
|
|
149
|
+
Render the same report shape as the default path, with `Source: {path}` instead of the registry line.
|
|
212
150
|
|
|
213
|
-
|
|
151
|
+
### Post-sync layers
|
|
214
152
|
|
|
215
|
-
|
|
153
|
+
Re-use layers (a)–(d) with dev-derived inputs — this is the one mode that computes them itself, since there is no engine JSON:
|
|
216
154
|
|
|
217
|
-
|
|
155
|
+
- **(a) Migrations** — the data-driven Detection loop: select freshly-synced guides `.forge/migrations/{v}-*.md` where `installed < v <= source` (semver on the PRE-stamp installed version), run each guide's `## Detection` bash block from the project root; `MIGRATE` on stdout → the layer-(a) prompt with the text after `MIGRATE —` as the reason; no output → `{v}: no action`; block errors → `{v}: detection error (skipped)`, never abort the loop. Range bookkeeping is implicit: once `forge.version` is stamped, crossed guides fall out of the next run's range — no ledger.
|
|
156
|
+
- **(b) Experimental staleness** — diff installed non-template skill dirs against `{source}/packages/create-forge/experimental/*/source/skills/{name}/`; stale → the layer-(b) offer with `{source}` as the source path.
|
|
157
|
+
- **(c) Codex** — presence glob (`.agents/` / `.codex/`) → the layer-(c) offer.
|
|
158
|
+
- **(d) Worktrees** — `git worktree list --porcelain` filtered to `refs/heads/forge/m-*`, main checkout only (`git rev-parse --git-dir` == `--git-common-dir`; from a worktree, skip and say so) → the layer-(d) offer.
|
|
218
159
|
|
|
219
|
-
|
|
220
|
-
2. **Commit the sync first** — a worktree can only rebase onto committed history, so uncommitted synced files won't propagate. If the sync is unstaged, prompt: *"Commit this upgrade on main before propagating? (e.g. `chore(forge): upgrade to v{new}`)"* and wait.
|
|
221
|
-
3. **Enumerate live worktrees:** `git worktree list --porcelain`, branches matching `refs/heads/forge/m-*` (same scan as the `forge` boot preflight). None → done, silent.
|
|
222
|
-
4. **Offer — never auto** (a rebase can conflict and needs human judgment):
|
|
223
|
-
```
|
|
224
|
-
{N} live worktree(s) lag this upgrade (v{old} → v{new}):
|
|
225
|
-
- {path} ({branch})
|
|
226
|
-
Pick up v{new} in each: git -C {path} rebase main
|
|
227
|
-
Rebase now? (each / list-only / skip)
|
|
228
|
-
```
|
|
229
|
-
- **each** → run `git -C {path} rebase main` per worktree; on conflict, **stop that one**, report it, and move on — never force, never auto-resolve.
|
|
230
|
-
- **list-only / skip** → print the commands; the operator runs them when each worktree is at a safe stopping point.
|
|
231
|
-
5. **Gitignored carve-outs don't rebase.** `.mcp.json`, experimental hooks (e.g. M10 `forge-claim-check*.sh`), and anything else gitignored is **not** carried by a rebase. If the upgrade changed them (e.g. an experimental skill was re-synced in Step 3b), each worktree must re-run the experimental installer (`experimental/{pkg}/install.sh`) — a rebase alone leaves them stale. Surface this line whenever Step 3b reported an experimental re-sync.
|
|
160
|
+
Same consent gates, same report lines as the registry path.
|
package/template/.forge/FORGE.md
CHANGED
|
@@ -104,7 +104,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
|
|
|
104
104
|
| Security review | `securing` | When auth/data/API |
|
|
105
105
|
| E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` | When UI/flows or flaky suite |
|
|
106
106
|
| Systematic debugging | `debugging` | When stuck |
|
|
107
|
-
| Upgrade Forge files | `upgrading` | On-demand |
|
|
107
|
+
| Upgrade Forge files from the npm registry (default; local dev sync only via explicit `/upgrading dev`) | `upgrading` | On-demand |
|
|
108
108
|
| Cross-session memory | `beads-integration` | When Beads installed |
|
|
109
109
|
| Project/read Forge work in Notion | `notion-integration` | When Notion configured |
|
|
110
110
|
| Multi-agent backend (experimental) | `orchestrating` | Optional, usually selected by Chief/Streams |
|
|
@@ -239,7 +239,7 @@ git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
|
|
|
239
239
|
| **Append-only shared** | `releases.yml`, `reservations.yml`, `state/desire-paths/*`, `deferred-issues/*` | Many writers OK; structure prevents collision (append-only entries / distinct filenames). |
|
|
240
240
|
| **Machine-local runtime** | `.git/forge/id-reservations`, `.git/forge/integration-pending` | Git common dir — shared across a machine's worktrees, never git-tracked, excluded from framework context. |
|
|
241
241
|
| **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` | Write only your milestone/stream block; within a block, append-only — strike through instead of rewriting. |
|
|
242
|
-
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading
|
|
242
|
+
| **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading` (registry default — the npm bin is the sync engine; local dev sync only via explicit `/upgrading dev`). Canonical on main; worktrees lag until they rebase. An upgrade touches only its own checkout — `upgrading` Step 8 offers live-worktree rebases (never auto); opt-in `forge.worktree_rebase_check` is the boot-time net. Gitignored carve-outs (`.mcp.json`, experimental hooks) propagate via the experimental installer, not git. |
|
|
243
243
|
|
|
244
244
|
Ownership rules (quick reference):
|
|
245
245
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Migration Guide: Origin-First Upgrading (Forge 0.63.0)
|
|
2
|
+
|
|
3
|
+
Applies to projects whose installed `upgrading` skill predates 0.63.0. The default `/upgrading` path changed from "sync from a local Forge clone at `.forge/dev-source`" to "wrap the npm registry bin": `/upgrading` now runs `npx forge-orkes@latest upgrade --yes --json` as the one sync engine and layers the agent-only steps (migration prompts, experimental re-sync, Codex offer, worktree propagation) on the bin's JSON report. Local-clone sync survives only as explicit **Dev Mode** (`/upgrading dev`) — presence of `.forge/dev-source` never selects it (ADR-026).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
1. Network access to the npm registry (the new default path runs `npx forge-orkes`).
|
|
8
|
+
2. Nothing else — the migration IS the upgrade run; no files need hand-editing.
|
|
9
|
+
|
|
10
|
+
## Detection
|
|
11
|
+
|
|
12
|
+
Prints `MIGRATE` when the installed upgrading skill is old-shape (it lacks the registry engine invocation the 0.63.0 skill always carries); silent + exit 0 otherwise.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Old-shape upgrading skill: exists but lacks the registry engine invocation.
|
|
16
|
+
S=.claude/skills/upgrading/SKILL.md
|
|
17
|
+
[ -f "$S" ] || exit 0 # skill not installed → nothing to do
|
|
18
|
+
if ! grep -q 'forge-orkes@latest upgrade --yes --json' "$S" 2>/dev/null; then
|
|
19
|
+
echo "MIGRATE — installed upgrading skill predates the origin-first default (registry engine); re-running the upgrade replaces it"
|
|
20
|
+
fi
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Migration steps
|
|
24
|
+
|
|
25
|
+
### 1. Re-run the upgrade
|
|
26
|
+
|
|
27
|
+
The sync itself replaces the skill — that is the whole migration. Either route works:
|
|
28
|
+
|
|
29
|
+
- `npx forge-orkes@latest upgrade` (any machine, no clone needed), or
|
|
30
|
+
- `/upgrading` in a Claude Code session **on 0.63.0+ framework files** (the run that installs this guide already synced the new skill; this Detection then stops firing).
|
|
31
|
+
|
|
32
|
+
### 2. Understand what changed in daily use
|
|
33
|
+
|
|
34
|
+
- **`/upgrading`** now upgrades from the npm registry. If `.forge/dev-source` exists you will see exactly one notice line — *"dev mode available — `/upgrading dev`"* — and the registry upgrade proceeds anyway.
|
|
35
|
+
- **`/upgrading X.Y.Z`** pins the engine to that release (`npx forge-orkes@X.Y.Z upgrade --yes --json`).
|
|
36
|
+
- **`/upgrading dev`** is the only way to sync from a local clone (framework development). Its flow — source resolution, downgrade guard, upstream desire-path harvest — is unchanged, just explicit.
|
|
37
|
+
- Experimental skills now re-sync from the release tarball itself (`experimental/` ships in the package since 0.63.0), so registry-only machines get staleness detection + consent-gated re-sync too (closes issue #5).
|
|
38
|
+
|
|
39
|
+
### 3. Optional: drop `.forge/dev-source` on non-dev machines
|
|
40
|
+
|
|
41
|
+
On machines that never develop Forge itself, the file now only produces the notice line. Removing it is safe and silences the notice. Keep it on your framework-dev machine(s) for `/upgrading dev`.
|
|
42
|
+
|
|
43
|
+
## Validation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
grep -q 'forge-orkes@latest upgrade --yes --json' .claude/skills/upgrading/SKILL.md \
|
|
47
|
+
&& echo "upgrading skill is origin-first (0.63.0+)" \
|
|
48
|
+
|| echo "still old-shape — re-run the upgrade"
|
|
49
|
+
```
|