@garygentry/feature-forge 0.2.1 → 0.2.3
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/README.md +1 -1
- package/adapters/claude/references/forge-config-schema.json +20 -3
- package/adapters/claude/references/shared-conventions.md +3 -0
- package/adapters/claude/scripts/forge-init.sh +7 -1
- package/adapters/claude/scripts/forge-session.py +491 -0
- package/adapters/claude/skills/forge/SKILL.md +43 -1
- package/adapters/claude/skills/forge-5-loop/SKILL.md +2 -1
- package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +41 -15
- package/adapters/claude/skills/forge-init/SKILL.md +3 -0
- package/adapters/codex/references/forge-config-schema.json +20 -3
- package/adapters/codex/references/shared-conventions.md +3 -0
- package/adapters/codex/scripts/forge-init.sh +7 -1
- package/adapters/codex/scripts/forge-session.py +491 -0
- package/adapters/codex/skills/forge/SKILL.md +43 -1
- package/adapters/codex/skills/forge-5-loop/SKILL.md +2 -1
- package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +41 -15
- package/adapters/codex/skills/forge-init/SKILL.md +3 -0
- package/adapters/copilot/references/forge-config-schema.json +20 -3
- package/adapters/copilot/references/shared-conventions.md +3 -0
- package/adapters/copilot/scripts/forge-init.sh +7 -1
- package/adapters/copilot/scripts/forge-session.py +491 -0
- package/adapters/copilot/skills/forge/forge.md +43 -1
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +2 -1
- package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +41 -15
- package/adapters/copilot/skills/forge-init/forge-init.md +3 -0
- package/adapters/cursor/references/forge-config-schema.json +20 -3
- package/adapters/cursor/references/shared-conventions.md +3 -0
- package/adapters/cursor/scripts/forge-init.sh +7 -1
- package/adapters/cursor/scripts/forge-session.py +491 -0
- package/adapters/cursor/skills/forge/forge.mdc +43 -1
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +2 -1
- package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +41 -15
- package/adapters/cursor/skills/forge-init/forge-init.mdc +3 -0
- package/adapters/gemini/references/forge-config-schema.json +20 -3
- package/adapters/gemini/references/shared-conventions.md +3 -0
- package/adapters/gemini/scripts/forge-init.sh +7 -1
- package/adapters/gemini/scripts/forge-session.py +491 -0
- package/adapters/gemini/skills/forge/forge.md +43 -1
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +2 -1
- package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +41 -15
- package/adapters/gemini/skills/forge-init/forge-init.md +3 -0
- package/dist/manifest.d.ts +1 -1
- package/dist/rauf.d.ts +4 -4
- package/dist/rauf.js +3 -3
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -121,8 +121,7 @@ user requests additional flags, append them to the rendered run command.
|
|
|
121
121
|
## Launch detail (Step 3b — background process)
|
|
122
122
|
|
|
123
123
|
Launch the loop **backgrounded** so it survives session end and does not block the
|
|
124
|
-
session,
|
|
125
|
-
it live.
|
|
124
|
+
session, then supervise it live via the runner's structured event file.
|
|
126
125
|
|
|
127
126
|
> **Clean-tree precondition.** rauf refuses to run with uncommitted changes
|
|
128
127
|
> (*"Refusing to run the loop with uncommitted changes… pass --force"*). Step 3a's
|
|
@@ -132,22 +131,41 @@ it live.
|
|
|
132
131
|
> changes after that commit, surface it and let the user commit/stash or pass
|
|
133
132
|
> `--force`; never auto-pass `--force`.
|
|
134
133
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
**Do NOT redirect the run's stdout into `{loopRunner.stateDir}`.** rauf **persists
|
|
135
|
+
its own** `{stateDir}/events.ndjson` (structured) and `{stateDir}/{logFile}` (human)
|
|
136
|
+
natively, and **rotates** them at the start of every run (the prior run's files are
|
|
137
|
+
renamed into `{stateDir}/archive/`). A redirect like `… --ndjson >
|
|
138
|
+
{stateDir}/events.ndjson` therefore (a) is **redundant** — the runner writes that
|
|
139
|
+
file regardless — and (b) **collides** with the runner's own writer: the shell holds
|
|
140
|
+
a descriptor on the file the runner immediately rotates away, so the redirected
|
|
141
|
+
`--ndjson` stdout is orphaned into a bogus `archive/` file while the live
|
|
142
|
+
`events.ndjson` is the runner's native stream. It only *looks* clean by accident of
|
|
143
|
+
rotation timing. So:
|
|
144
|
+
|
|
145
|
+
- **Self-persisting runner (default — rauf writes `{stateDir}/events.ndjson`):**
|
|
146
|
+
launch the **plain `runCommand`** with `run_in_background: true` and **no
|
|
147
|
+
redirect** — the Bash tool already captures the run's stdout/stderr to the
|
|
148
|
+
background task's output file (use it to diagnose a launch refusal). Supervise by
|
|
149
|
+
arming the Monitor on the runner's **native** `{backlogDir}/{stateDir}/events.ndjson`
|
|
150
|
+
(Step 3d). Guard the very first run with the state dir:
|
|
138
151
|
|
|
139
152
|
```
|
|
140
|
-
mkdir -p {backlogDir}/{loopRunner.stateDir} && {rendered
|
|
153
|
+
mkdir -p {backlogDir}/{loopRunner.stateDir} && {rendered runCommand}
|
|
141
154
|
```
|
|
142
155
|
|
|
143
|
-
(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
with
|
|
148
|
-
human log (3d fallback) instead of the NDJSON file.
|
|
156
|
+
(Note: the `--ndjson` stdout stream and `loopRunner.eventStreamCommand` are **not**
|
|
157
|
+
used on this path — the native file already carries the same structured records.)
|
|
158
|
+
- **Stdout-only runner (no native event file):** render `eventStreamCommand` (it adds
|
|
159
|
+
`--ndjson`) and redirect its stdout to a file **outside `{stateDir}`** so it cannot
|
|
160
|
+
collide with any native file or be swept into `archive/`, then Monitor that file:
|
|
149
161
|
|
|
150
|
-
|
|
162
|
+
```
|
|
163
|
+
mkdir -p {backlogDir}/{loopRunner.stateDir} && {rendered eventStreamCommand} > {backlogDir}/forge-events.ndjson 2>&1
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The background task's exit notification remains the single authoritative terminal
|
|
167
|
+
signal (Step 4). Loop runs can take significant time (minutes to hours depending on
|
|
168
|
+
backlog size).
|
|
151
169
|
|
|
152
170
|
## Arm a Monitor on the event stream (Step 3d)
|
|
153
171
|
|
|
@@ -161,16 +179,24 @@ terminal and exception state, not just the happy path — otherwise a crash or h
|
|
|
161
179
|
looks identical to "still running." Monitor command (NDJSON path):
|
|
162
180
|
|
|
163
181
|
```
|
|
164
|
-
tail -n +1 -
|
|
182
|
+
tail -n +1 -F {backlogDir}/{loopRunner.stateDir}/events.ndjson 2>/dev/null \
|
|
165
183
|
| jq -rc --unbuffered 'select(.type | test("item_completed|item_blocked|needs_human|signal_parsed|loop_completed|loop_error|loop_cancelled|llm_stuck_warning"))'
|
|
166
184
|
```
|
|
167
185
|
|
|
186
|
+
> **Use `tail -F` (follow by name), not `-f` (follow by descriptor).** The runner
|
|
187
|
+
> **rotates** `events.ndjson` at the start of each run (renames the prior file into
|
|
188
|
+
> `archive/`, creates a fresh one). A Monitor that attaches with `-f` during that
|
|
189
|
+
> brief rotation window would follow the **archived** inode and then see silence —
|
|
190
|
+
> indistinguishable from a healthy quiet loop. `-F` re-opens the live file by name,
|
|
191
|
+
> so it always tracks the runner's current native stream. (Send `tail`'s own
|
|
192
|
+
> rotation chatter to `/dev/null` so it can't reach the `jq` filter.)
|
|
193
|
+
|
|
168
194
|
- **Fallback (log tail, no NDJSON):** match the runner's **structured prose
|
|
169
195
|
prefixes**, never the `RAUF_*` tokens (those leak inside agent output and
|
|
170
196
|
false-match). For rauf:
|
|
171
197
|
|
|
172
198
|
```
|
|
173
|
-
tail -n +1 -
|
|
199
|
+
tail -n +1 -F {backlogDir}/{loopRunner.stateDir}/{loopRunner.logFile} 2>/dev/null \
|
|
174
200
|
| grep -E --line-buffered 'Item [^ ]+ (completed|blocked):|Item [^ ]+ needs human input|Loop completed|Loop error:|Circuit breaker:'
|
|
175
201
|
```
|
|
176
202
|
|
|
@@ -23,6 +23,9 @@ After initialization, the config file will contain defaults for:
|
|
|
23
23
|
- `stack`: `null` (detected during `/feature-forge:forge-2-tech`)
|
|
24
24
|
- `typeCheckCommand`: `null` (set during `/feature-forge:forge-2-tech`)
|
|
25
25
|
- `testCommand`: `null` (set during `/feature-forge:forge-2-tech`)
|
|
26
|
+
- `autoInvokeNextStage`: `true` (the navigator auto-starts the next stage after you confirm; set `false` to only print the command)
|
|
27
|
+
- `contextWindowTokens`: `null` (the navigator infers the context window; set to your model's window, e.g. `1000000` for a 1M-context model, for accurate context-usage advice)
|
|
28
|
+
- `contextWarnThreshold`: `0.7` (fraction of the window past which the navigator suggests a clean session)
|
|
26
29
|
|
|
27
30
|
If `forge.config.json` already exists, the script will not overwrite it.
|
|
28
31
|
|
|
@@ -56,6 +56,23 @@
|
|
|
56
56
|
"minimum": 1,
|
|
57
57
|
"description": "Multiplier applied to pending backlog item count to calculate loop iterations. Higher values allow more retries. Default: 1.5 (e.g., 10 items = 15 iterations)."
|
|
58
58
|
},
|
|
59
|
+
"autoInvokeNextStage": {
|
|
60
|
+
"type": "boolean",
|
|
61
|
+
"default": true,
|
|
62
|
+
"description": "When true (default), the /feature-forge:forge navigator auto-invokes the next pipeline stage via the Skill tool after the user confirms it, instead of only printing the command to copy. Set false to keep the old copy-paste behavior (the navigator suggests the command but never launches it). Ignored on non-Claude hosts, which always fall back to printing the command."
|
|
63
|
+
},
|
|
64
|
+
"contextWindowTokens": {
|
|
65
|
+
"type": ["integer", "null"],
|
|
66
|
+
"default": null,
|
|
67
|
+
"description": "Context window size (tokens) used by the navigator's context-usage check to compute how full the current session is. Null (default) lets the helper infer from the session model and fall back to 200000 — and if observed usage already exceeds 200000 it auto-bumps the assumed window to 1000000 (proof a 1M-beta window is active). Set this explicitly to your model's window (e.g. 1000000 for a 1M-context model) for accurate percentages below 200000 too, since 1M cannot be detected from the transcript until usage crosses 200000."
|
|
68
|
+
},
|
|
69
|
+
"contextWarnThreshold": {
|
|
70
|
+
"type": "number",
|
|
71
|
+
"default": 0.7,
|
|
72
|
+
"minimum": 0,
|
|
73
|
+
"maximum": 1,
|
|
74
|
+
"description": "Fraction of the context window (0-1) past which the navigator recommends starting the next stage in a clean session rather than continuing. Default: 0.7."
|
|
75
|
+
},
|
|
59
76
|
"workspaces": {
|
|
60
77
|
"type": "array",
|
|
61
78
|
"description": "Monorepo members. Absent for single-package projects.",
|
|
@@ -94,7 +111,7 @@
|
|
|
94
111
|
"eventStreamCommand": {
|
|
95
112
|
"type": "string",
|
|
96
113
|
"default": "{bin} loop run . --backlog {backlogDir} --iterations {iterations} --ndjson",
|
|
97
|
-
"description": "
|
|
114
|
+
"description": "Stdout NDJSON launch command for a runner that does NOT persist its own event file — same as runCommand but emits one machine-readable JSON event per stdout line: item_completed / item_blocked / needs_human / signal_parsed / loop_completed / loop_error / loop_cancelled / llm_stuck_warning, each with {type, timestamp, projectPath} plus payload (a circuit-breaker halt surfaces as loop_error). NOTE: rauf (the default runner) ALREADY persists {stateDir}/events.ndjson natively and rotates it per run, so forge-5 launches the plain runCommand and monitors that native file — it does NOT use this field, and must NOT redirect --ndjson into {stateDir} (redundant, and it collides with the runner's own writer / archive rotation). This field is only for a stdout-only runner with no native event file; forge-5 then redirects its stdout to a file OUTSIDE {stateDir} and monitors that. Omit it entirely for a runner that self-persists or cannot emit NDJSON."
|
|
98
115
|
},
|
|
99
116
|
"validateCommand": {
|
|
100
117
|
"type": "string",
|
|
@@ -173,8 +190,8 @@
|
|
|
173
190
|
},
|
|
174
191
|
"installHint": {
|
|
175
192
|
"type": "string",
|
|
176
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
177
|
-
"description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.
|
|
193
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.11.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.11.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
194
|
+
"description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.11.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
|
|
178
195
|
},
|
|
179
196
|
"schemaVersion": {
|
|
180
197
|
"type": "string",
|
|
@@ -68,6 +68,9 @@ Extract these config values (use defaults if not present):
|
|
|
68
68
|
- `branchPerFeature` (default: true)
|
|
69
69
|
- `branchPrefix` (default: `forge/`)
|
|
70
70
|
- `loopIterationMultiplier` (default: `1.5`)
|
|
71
|
+
- `autoInvokeNextStage` (default: `true` — the `/feature-forge:forge` navigator auto-invokes the next stage via the `Skill` tool after the user confirms; `false` keeps copy-paste behavior. Navigator-only.)
|
|
72
|
+
- `contextWindowTokens` (default: `null` — context window used by the navigator's context-usage check; `null` infers from the session model and falls back to 200000. Set to the model's window, e.g. `1000000` on a 1M model. Navigator-only.)
|
|
73
|
+
- `contextWarnThreshold` (default: `0.7` — fraction of the window past which the navigator recommends a clean session. Navigator-only.)
|
|
71
74
|
- `loopRunner` (optional object — the loop runner to drive; **defaults to rauf** when absent, with every command templated. See `references/forge-config-schema.json` and `references/ralph-loop-contract.md`.)
|
|
72
75
|
|
|
73
76
|
## Feature Directory Resolution
|
|
@@ -21,7 +21,10 @@ cat > "$CONFIG_FILE" << 'EOF'
|
|
|
21
21
|
"stack": null,
|
|
22
22
|
"typeCheckCommand": null,
|
|
23
23
|
"testCommand": null,
|
|
24
|
-
"loopIterationMultiplier": 1.5
|
|
24
|
+
"loopIterationMultiplier": 1.5,
|
|
25
|
+
"autoInvokeNextStage": true,
|
|
26
|
+
"contextWindowTokens": null,
|
|
27
|
+
"contextWarnThreshold": 0.7
|
|
25
28
|
}
|
|
26
29
|
EOF
|
|
27
30
|
|
|
@@ -37,6 +40,9 @@ echo " stack: null (auto-detected during forge-2-tech)"
|
|
|
37
40
|
echo " typeCheckCommand: null (auto-detected during forge-2-tech)"
|
|
38
41
|
echo " testCommand: null (auto-detected during forge-2-tech)"
|
|
39
42
|
echo " loopIterationMultiplier: 1.5 (multiplier for loop iterations)"
|
|
43
|
+
echo " autoInvokeNextStage: true (navigator auto-starts the next stage after you confirm)"
|
|
44
|
+
echo " contextWindowTokens: null (infer; set to 1000000 on a 1M-context model)"
|
|
45
|
+
echo " contextWarnThreshold: 0.7 (suggest a clean session past this fraction of the window)"
|
|
40
46
|
echo ""
|
|
41
47
|
echo "The loop runner defaults to rauf. To target a different ralph-style runner,"
|
|
42
48
|
echo "add a \"loopRunner\" block (see references/forge-config-schema.json)."
|