@garygentry/feature-forge 0.2.2 → 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
|
|
package/dist/manifest.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export interface BuildManifestArgs {
|
|
|
28
28
|
readonly skills: readonly string[];
|
|
29
29
|
/** SHA-256 over the source bundle's canonical (sorted-path) file set — drift anchor (spec 03). */
|
|
30
30
|
readonly sourceHash: string;
|
|
31
|
-
/** Recorded pinned rauf coordinate (e.g. "@garygentry/rauf@0.
|
|
31
|
+
/** Recorded pinned rauf coordinate (e.g. "@garygentry/rauf@0.11.0"); `null` when `--skip-rauf` (spec 06). */
|
|
32
32
|
readonly raufPin: string | null;
|
|
33
33
|
/** Symlink mode only: the source bundle the namespace dir links to (REQ-SAFE-02). */
|
|
34
34
|
readonly link?: {
|
package/dist/rauf.d.ts
CHANGED
|
@@ -19,13 +19,13 @@ import { type Result } from "./types.js";
|
|
|
19
19
|
*
|
|
20
20
|
* Shape: `<name>@<version>` — the SCOPED package `@garygentry/rauf` (the unscoped `rauf` name is
|
|
21
21
|
* blocked by npm's similarity filter). Advanced on each feature-forge release to a new
|
|
22
|
-
* known-compatible rauf (REQ-RAUF-03). The current rauf version is 0.
|
|
22
|
+
* known-compatible rauf (REQ-RAUF-03). The current rauf version is 0.11.0.
|
|
23
23
|
*
|
|
24
|
-
* rauf is now PUBLISHED (rauf#28): `@garygentry/rauf@0.
|
|
24
|
+
* rauf is now PUBLISHED (rauf#28): `@garygentry/rauf@0.11.0` resolves from the npm registry, so the
|
|
25
25
|
* preflight below passes by default. (Historically this pin pointed at an unpublished package and
|
|
26
26
|
* the preflight was a designed-to-fail check — see the `--skip-rauf` escape hatch.)
|
|
27
27
|
*/
|
|
28
|
-
export declare const RAUF_PIN = "@garygentry/rauf@0.
|
|
28
|
+
export declare const RAUF_PIN = "@garygentry/rauf@0.11.0";
|
|
29
29
|
/**
|
|
30
30
|
* An injectable, READ-ONLY registry query (D1). Given a coordinate `name@version`, returns the
|
|
31
31
|
* resolved version string on success, or an `InstallerError` if it is not resolvable.
|
|
@@ -37,7 +37,7 @@ export declare const RAUF_PIN = "@garygentry/rauf@0.10.1";
|
|
|
37
37
|
* Contract: the query MUST be read-only — it MUST NOT install, MUST NOT mutate global npm
|
|
38
38
|
* state, and MUST NOT execute rauf. `npm view` satisfies this (it only reads registry metadata).
|
|
39
39
|
*
|
|
40
|
-
* @param coordinate - the `name@version` to resolve, e.g. "@garygentry/rauf@0.
|
|
40
|
+
* @param coordinate - the `name@version` to resolve, e.g. "@garygentry/rauf@0.11.0"
|
|
41
41
|
* @returns Result<string> — the resolved version on success; RAUF_UNRESOLVABLE on failure.
|
|
42
42
|
*/
|
|
43
43
|
export type RegistryQuery = (coordinate: string) => Result<string>;
|
package/dist/rauf.js
CHANGED
|
@@ -20,13 +20,13 @@ import { err, ok } from "./types.js";
|
|
|
20
20
|
*
|
|
21
21
|
* Shape: `<name>@<version>` — the SCOPED package `@garygentry/rauf` (the unscoped `rauf` name is
|
|
22
22
|
* blocked by npm's similarity filter). Advanced on each feature-forge release to a new
|
|
23
|
-
* known-compatible rauf (REQ-RAUF-03). The current rauf version is 0.
|
|
23
|
+
* known-compatible rauf (REQ-RAUF-03). The current rauf version is 0.11.0.
|
|
24
24
|
*
|
|
25
|
-
* rauf is now PUBLISHED (rauf#28): `@garygentry/rauf@0.
|
|
25
|
+
* rauf is now PUBLISHED (rauf#28): `@garygentry/rauf@0.11.0` resolves from the npm registry, so the
|
|
26
26
|
* preflight below passes by default. (Historically this pin pointed at an unpublished package and
|
|
27
27
|
* the preflight was a designed-to-fail check — see the `--skip-rauf` escape hatch.)
|
|
28
28
|
*/
|
|
29
|
-
export const RAUF_PIN = "@garygentry/rauf@0.
|
|
29
|
+
export const RAUF_PIN = "@garygentry/rauf@0.11.0";
|
|
30
30
|
/**
|
|
31
31
|
* Resolvability preflight for the pinned default loop runner (D1; REQ-RAUF-01/02/03, OQ-1).
|
|
32
32
|
*
|
package/dist/types.d.ts
CHANGED
|
@@ -216,7 +216,7 @@ export interface InstallManifest {
|
|
|
216
216
|
readonly featureForgeVersion: string | null;
|
|
217
217
|
/** SHA-256 over the source bundle's canonical (sorted-path) file set — drift anchor (OQ-4, spec 03). */
|
|
218
218
|
readonly sourceHash: string;
|
|
219
|
-
/** Pinned rauf coordinate recorded at install, e.g. "@garygentry/rauf@0.
|
|
219
|
+
/** Pinned rauf coordinate recorded at install, e.g. "@garygentry/rauf@0.11.0"; `null` if `--skip-rauf` (spec 06). */
|
|
220
220
|
readonly raufPin: string | null;
|
|
221
221
|
/** ISO-8601 timestamps. */
|
|
222
222
|
readonly installedAt: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@garygentry/feature-forge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Cross-agent installer for the feature-forge skill suite — installs the canonical forge pipeline into Claude, Codex, Copilot, Cursor, or Gemini.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|