@garygentry/feature-forge 0.2.14 → 0.3.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/README.md +6 -3
- package/adapters/GENERATION-REPORT.md +20 -0
- package/adapters/claude/.feature-forge-bundle.json +1 -1
- package/adapters/claude/references/forge-config-schema.json +2 -2
- package/adapters/claude/scripts/forge-root.sh +47 -3
- package/adapters/claude/scripts/forge-session.py +30 -8
- package/adapters/claude/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/codex/.feature-forge-bundle.json +1 -1
- package/adapters/codex/references/forge-config-schema.json +2 -2
- package/adapters/codex/scripts/forge-root.sh +47 -3
- package/adapters/codex/scripts/forge-session.py +30 -8
- package/adapters/codex/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/copilot/.feature-forge-bundle.json +1 -1
- package/adapters/copilot/references/forge-config-schema.json +2 -2
- package/adapters/copilot/scripts/forge-root.sh +47 -3
- package/adapters/copilot/scripts/forge-session.py +30 -8
- package/adapters/copilot/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/cursor/.feature-forge-bundle.json +1 -1
- package/adapters/cursor/references/forge-config-schema.json +2 -2
- package/adapters/cursor/scripts/forge-root.sh +47 -3
- package/adapters/cursor/scripts/forge-session.py +30 -8
- package/adapters/cursor/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/gemini/.feature-forge-bundle.json +1 -1
- package/adapters/gemini/gemini-extension.json +1 -1
- package/adapters/gemini/references/forge-config-schema.json +2 -2
- package/adapters/gemini/scripts/forge-root.sh +47 -3
- package/adapters/gemini/scripts/forge-session.py +30 -8
- package/adapters/gemini/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-5-loop/references/forge-config-schema.json +2 -2
- package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +2 -2
- package/adapters/pi/.feature-forge-bundle.json +6 -0
- package/adapters/pi/agents/forge-researcher.md +139 -0
- package/adapters/pi/agents/forge-spec-writer.md +116 -0
- package/adapters/pi/agents/forge-verifier.md +126 -0
- package/adapters/pi/extensions/ask-user-question/LICENSE +21 -0
- package/adapters/pi/extensions/ask-user-question/README.md +91 -0
- package/adapters/pi/extensions/ask-user-question/ask-user-question.ts +298 -0
- package/adapters/pi/extensions/ask-user-question/config.ts +78 -0
- package/adapters/pi/extensions/ask-user-question/events.ts +57 -0
- package/adapters/pi/extensions/ask-user-question/index.ts +61 -0
- package/adapters/pi/extensions/ask-user-question/locales/de.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/en.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/es.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/fr.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/pt-BR.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/pt.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/ru.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/uk.json +27 -0
- package/adapters/pi/extensions/ask-user-question/locales/zh.json +29 -0
- package/adapters/pi/extensions/ask-user-question/reconcile.ts +49 -0
- package/adapters/pi/extensions/ask-user-question/rpc-fallback.ts +168 -0
- package/adapters/pi/extensions/ask-user-question/state/build-questionnaire.ts +302 -0
- package/adapters/pi/extensions/ask-user-question/state/i18n-bridge.ts +53 -0
- package/adapters/pi/extensions/ask-user-question/state/key-router.ts +277 -0
- package/adapters/pi/extensions/ask-user-question/state/questionnaire-session.ts +234 -0
- package/adapters/pi/extensions/ask-user-question/state/row-intent.ts +145 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/contract.ts +26 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/derivations.ts +42 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/focus.ts +19 -0
- package/adapters/pi/extensions/ask-user-question/state/selectors/projections.ts +101 -0
- package/adapters/pi/extensions/ask-user-question/state/state-reducer.ts +292 -0
- package/adapters/pi/extensions/ask-user-question/state/state.ts +55 -0
- package/adapters/pi/extensions/ask-user-question/tool/format-answer.ts +31 -0
- package/adapters/pi/extensions/ask-user-question/tool/response-envelope.ts +49 -0
- package/adapters/pi/extensions/ask-user-question/tool/types.ts +147 -0
- package/adapters/pi/extensions/ask-user-question/tool/validate-questionnaire.ts +58 -0
- package/adapters/pi/extensions/ask-user-question/vendor-config-shim.ts +65 -0
- package/adapters/pi/extensions/ask-user-question/view/component-binding.ts +47 -0
- package/adapters/pi/extensions/ask-user-question/view/components/inline-input.ts +98 -0
- package/adapters/pi/extensions/ask-user-question/view/components/multi-select-view.ts +193 -0
- package/adapters/pi/extensions/ask-user-question/view/components/option-list-view.ts +70 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/markdown-content-cache.ts +79 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-block-renderer.ts +111 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-box-renderer.ts +88 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-layout-decider.ts +202 -0
- package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-pane.ts +228 -0
- package/adapters/pi/extensions/ask-user-question/view/components/submit-picker.ts +67 -0
- package/adapters/pi/extensions/ask-user-question/view/components/tab-bar.ts +59 -0
- package/adapters/pi/extensions/ask-user-question/view/components/wrapping-select.ts +293 -0
- package/adapters/pi/extensions/ask-user-question/view/dialog-builder.ts +224 -0
- package/adapters/pi/extensions/ask-user-question/view/props-adapter.ts +125 -0
- package/adapters/pi/extensions/ask-user-question/view/stateful-view.ts +26 -0
- package/adapters/pi/extensions/ask-user-question/view/tab-components.ts +18 -0
- package/adapters/pi/extensions/ask-user-question/view/tab-content-strategy.ts +252 -0
- package/adapters/pi/package.json +26 -0
- package/adapters/pi/references/epic-manifest-schema.json +125 -0
- package/adapters/pi/references/forge-config-schema.json +236 -0
- package/adapters/pi/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/references/portable-root.md +71 -0
- package/adapters/pi/references/process-overview.md +143 -0
- package/adapters/pi/references/ralph-loop-contract.md +221 -0
- package/adapters/pi/references/shared-conventions.md +295 -0
- package/adapters/pi/references/skill-frontmatter.schema.json +17 -0
- package/adapters/pi/references/stack-resolution.md +54 -0
- package/adapters/pi/references/stacks/_generic.md +111 -0
- package/adapters/pi/references/stacks/go.md +157 -0
- package/adapters/pi/references/stacks/python.md +184 -0
- package/adapters/pi/references/stacks/rust.md +170 -0
- package/adapters/pi/references/stacks/typescript.md +134 -0
- package/adapters/pi/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/references/templates/specs-hygiene/AGENTS.md +32 -0
- package/adapters/pi/references/templates/specs-hygiene/CLAUDE.md +31 -0
- package/adapters/pi/references/vendor-construct-inventory.md +50 -0
- package/adapters/pi/scripts/epic-manifest.py +1694 -0
- package/adapters/pi/scripts/forge-bootstrap.py +1070 -0
- package/adapters/pi/scripts/forge-init.sh +58 -0
- package/adapters/pi/scripts/forge-root.sh +179 -0
- package/adapters/pi/scripts/forge-session.py +1888 -0
- package/adapters/pi/scripts/validate-traceability.py +150 -0
- package/adapters/pi/skills/forge/SKILL.md +243 -0
- package/adapters/pi/skills/forge/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge/references/process-overview.md +143 -0
- package/adapters/pi/skills/forge/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-0-epic/SKILL.md +308 -0
- package/adapters/pi/skills/forge-0-epic/references/edit-mode.md +266 -0
- package/adapters/pi/skills/forge-0-epic/references/epic-manifest-subcommands.md +75 -0
- package/adapters/pi/skills/forge-0-epic/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-0-epic/references/portable-root.md +71 -0
- package/adapters/pi/skills/forge-0-epic/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-1-prd/SKILL.md +164 -0
- package/adapters/pi/skills/forge-1-prd/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/pi/skills/forge-1-prd/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-2-tech/SKILL.md +225 -0
- package/adapters/pi/skills/forge-2-tech/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-2-tech/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/pi/skills/forge-2-tech/references/stack-resolution.md +54 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/_generic.md +111 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/go.md +157 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/python.md +184 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/rust.md +170 -0
- package/adapters/pi/skills/forge-2-tech/references/stacks/typescript.md +134 -0
- package/adapters/pi/skills/forge-2-tech/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-3-specs/SKILL.md +178 -0
- package/adapters/pi/skills/forge-3-specs/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-3-specs/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/pi/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/_generic.md +111 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/go.md +157 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/python.md +184 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/rust.md +170 -0
- package/adapters/pi/skills/forge-3-specs/references/stacks/typescript.md +134 -0
- package/adapters/pi/skills/forge-3-specs/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-4-backlog/SKILL.md +175 -0
- package/adapters/pi/skills/forge-4-backlog/references/forge-config-schema.json +236 -0
- package/adapters/pi/skills/forge-4-backlog/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-4-backlog/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-5-loop/SKILL.md +314 -0
- package/adapters/pi/skills/forge-5-loop/references/forge-config-schema.json +236 -0
- package/adapters/pi/skills/forge-5-loop/references/ralph-loop-contract.md +221 -0
- package/adapters/pi/skills/forge-5-loop/references/result-reporting.md +85 -0
- package/adapters/pi/skills/forge-5-loop/references/runner-contract.md +341 -0
- package/adapters/pi/skills/forge-5-loop/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-6-docs/SKILL.md +202 -0
- package/adapters/pi/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/pi/skills/forge-6-docs/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-6-docs/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-bootstrap/SKILL.md +250 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/ci/github-actions.yml +12 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/generic/run.sh +3 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/generic/test.sh +13 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/go/go.mod +3 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/go/main.go +12 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/go/main_test.go +11 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +35 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +36 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/README.md +11 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/Apache-2.0/LICENSE +198 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/MIT/LICENSE +21 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/pyproject.toml +24 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/__init__.py +5 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/main.py +13 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/python/tests/test_smoke.py +8 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/Cargo.toml +15 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/lib.rs +7 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/main.rs +5 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/rust/tests/smoke.rs +6 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/package.json +15 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/src/index.ts +4 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/test/smoke.test.ts +6 -0
- package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/tsconfig.json +14 -0
- package/adapters/pi/skills/forge-fix/SKILL.md +98 -0
- package/adapters/pi/skills/forge-fix/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +258 -0
- package/adapters/pi/skills/forge-guide/SKILL.md +192 -0
- package/adapters/pi/skills/forge-guide/references/forge-config-schema.json +236 -0
- package/adapters/pi/skills/forge-guide/references/process-overview.md +143 -0
- package/adapters/pi/skills/forge-guide/references/ralph-loop-contract.md +221 -0
- package/adapters/pi/skills/forge-guide/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-guide/references/stack-resolution.md +54 -0
- package/adapters/pi/skills/forge-guide/references/stacks/_generic.md +111 -0
- package/adapters/pi/skills/forge-guide/references/stacks/go.md +157 -0
- package/adapters/pi/skills/forge-guide/references/stacks/python.md +184 -0
- package/adapters/pi/skills/forge-guide/references/stacks/rust.md +170 -0
- package/adapters/pi/skills/forge-guide/references/stacks/typescript.md +134 -0
- package/adapters/pi/skills/forge-init/SKILL.md +72 -0
- package/adapters/pi/skills/forge-verify/SKILL.md +273 -0
- package/adapters/pi/skills/forge-verify/references/pipeline-state-schema.json +191 -0
- package/adapters/pi/skills/forge-verify/references/shared-conventions.md +295 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists.md +477 -0
- package/dist/agent-targets.d.ts +1 -1
- package/dist/agent-targets.js +23 -3
- package/dist/detect.d.ts +1 -1
- package/dist/detect.js +2 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +2 -2
- package/dist/placements.js +5 -1
- package/dist/rauf.d.ts +4 -4
- package/dist/rauf.js +3 -3
- package/dist/types.d.ts +31 -6
- package/dist/types.js +6 -3
- package/package.json +14 -3
|
@@ -1434,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
|
|
|
1434
1434
|
return flat
|
|
1435
1435
|
|
|
1436
1436
|
|
|
1437
|
+
def _host_command(command: str, host: str) -> str:
|
|
1438
|
+
"""Rewrite a `/feature-forge:` slash command to the host's surface.
|
|
1439
|
+
|
|
1440
|
+
Pi's slash-command surface is `/skill:` (matching the adapter body's
|
|
1441
|
+
`/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
|
|
1442
|
+
that body translation, so it rewrites the commands it emits here. No-op for
|
|
1443
|
+
claude/generic, which keep the canonical `/feature-forge:` form.
|
|
1444
|
+
"""
|
|
1445
|
+
return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
|
|
1446
|
+
|
|
1447
|
+
|
|
1437
1448
|
def _next_steps_block(
|
|
1438
1449
|
next_command: str, host: str, reconcile: dict | None = None
|
|
1439
1450
|
) -> str:
|
|
@@ -1463,6 +1474,18 @@ def _next_steps_block(
|
|
|
1463
1474
|
"2. Then start a fresh session and run the next stage below — or "
|
|
1464
1475
|
"re-run `/feature-forge:forge` to let the navigator resume from disk."
|
|
1465
1476
|
)
|
|
1477
|
+
elif host == "pi":
|
|
1478
|
+
# Pi's fresh-session command is `/new` (not `/clear`); its slash-command
|
|
1479
|
+
# surface is `/skill:` (the fenced command below is rewritten to match).
|
|
1480
|
+
clear_line = (
|
|
1481
|
+
"1. `/new` — recommended unconditionally at this stage boundary; every "
|
|
1482
|
+
"artifact is on disk, so the work survives starting a fresh session. "
|
|
1483
|
+
"I can't run `/new` for you — you have to run it yourself."
|
|
1484
|
+
)
|
|
1485
|
+
next_line = (
|
|
1486
|
+
"2. Then, in the new session, run the next stage below — or re-run "
|
|
1487
|
+
"`/skill:forge` to let the navigator resume from disk."
|
|
1488
|
+
)
|
|
1466
1489
|
else:
|
|
1467
1490
|
clear_line = (
|
|
1468
1491
|
"1. Clear your session / start a fresh session — recommended "
|
|
@@ -1479,7 +1502,7 @@ def _next_steps_block(
|
|
|
1479
1502
|
# epic-change request the primary is the reconcile command; otherwise it is the
|
|
1480
1503
|
# normal next-stage command. The fence sits before the sentinel, so the
|
|
1481
1504
|
# sentinel remains the absolute last line.
|
|
1482
|
-
fenced_command = reconcile["command"] if blocking else next_command
|
|
1505
|
+
fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
|
|
1483
1506
|
lines = ["**Next steps**", clear_line]
|
|
1484
1507
|
if blocking:
|
|
1485
1508
|
count = reconcile["count"]
|
|
@@ -1495,15 +1518,14 @@ def _next_steps_block(
|
|
|
1495
1518
|
lines.append("")
|
|
1496
1519
|
lines.append(f"```\n{fenced_command}\n```")
|
|
1497
1520
|
if blocking and reconcile.get("deferred"):
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
)
|
|
1521
|
+
deferred_cmd = _host_command(reconcile["deferred"], host)
|
|
1522
|
+
lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
|
|
1501
1523
|
elif reconcile and reconcile.get("reminder"):
|
|
1502
1524
|
count = reconcile["count"]
|
|
1503
1525
|
plural = "s" if count != 1 else ""
|
|
1504
1526
|
lines.append(
|
|
1505
1527
|
f"You also flagged {count} epic change{plural} to reconcile when "
|
|
1506
|
-
f"convenient: `{reconcile['command']}`"
|
|
1528
|
+
f"convenient: `{_host_command(reconcile['command'], host)}`"
|
|
1507
1529
|
)
|
|
1508
1530
|
lines.append(NEXT_STEPS_SENTINEL)
|
|
1509
1531
|
return "\n".join(lines)
|
|
@@ -1630,10 +1652,10 @@ def stage_exit(
|
|
|
1630
1652
|
"verifyGate": verify_gate,
|
|
1631
1653
|
"autoFixEligible": auto_fix_eligible,
|
|
1632
1654
|
"verifyState": verify_label,
|
|
1633
|
-
"verifyCommand": f"/feature-forge:forge-verify {feature}",
|
|
1655
|
+
"verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
|
|
1634
1656
|
"autoVerifyEffective": effective_auto_verify,
|
|
1635
1657
|
"nextStage": next_stage_id,
|
|
1636
|
-
"nextCommand": next_command,
|
|
1658
|
+
"nextCommand": _host_command(next_command, host) if next_command else next_command,
|
|
1637
1659
|
"invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
|
|
1638
1660
|
"gitRepo": git_repo,
|
|
1639
1661
|
"cleanTree": clean_tree,
|
|
@@ -1759,7 +1781,7 @@ def main() -> int:
|
|
|
1759
1781
|
p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
|
|
1760
1782
|
p_exit.add_argument("--next-feature", default=None, dest="next_feature",
|
|
1761
1783
|
help="First actionable feature (epic handoff next-command arg)")
|
|
1762
|
-
p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
|
|
1784
|
+
p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
|
|
1763
1785
|
help="Host wording for the NEXT-STEPS block")
|
|
1764
1786
|
p_exit.add_argument("--json", action="store_true", dest="json_output")
|
|
1765
1787
|
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -92,9 +92,24 @@ done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/pl
|
|
|
92
92
|
# Globs that match nothing expand to themselves; the is_root test rejects such literals. Covers
|
|
93
93
|
# every supported agent's install destination under BOTH global ($HOME) and project ($PWD) scope,
|
|
94
94
|
# matching the installer's per-agent layout: claude .claude/skills, codex .agents/skills, copilot
|
|
95
|
-
# .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions
|
|
96
|
-
# step 2a's path for a cache install that
|
|
97
|
-
# plugin.json for ls -t to key on).
|
|
95
|
+
# .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions, pi .pi/skills or
|
|
96
|
+
# $PI_CODING_AGENT_DIR/skills. The cache glob repeats step 2a's path for a cache install that
|
|
97
|
+
# carries only the neutral bundle sentinel (no plugin.json for ls -t to key on).
|
|
98
|
+
if [ -n "${PI_CODING_AGENT_DIR:-}" ]; then
|
|
99
|
+
for candidate in \
|
|
100
|
+
"$PI_CODING_AGENT_DIR/skills/feature-forge" \
|
|
101
|
+
"$PI_CODING_AGENT_DIR"/git/*/feature-forge/adapters/pi \
|
|
102
|
+
"$PI_CODING_AGENT_DIR"/git/*/*/feature-forge/adapters/pi \
|
|
103
|
+
"$PI_CODING_AGENT_DIR"/packages/*/feature-forge/adapters/pi \
|
|
104
|
+
"$PI_CODING_AGENT_DIR"/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
105
|
+
"$PI_CODING_AGENT_DIR"/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
106
|
+
; do
|
|
107
|
+
if is_root "$candidate"; then
|
|
108
|
+
accept_root "$candidate"
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
fi
|
|
112
|
+
|
|
98
113
|
for candidate in \
|
|
99
114
|
"$HOME/.claude/skills/feature-forge" \
|
|
100
115
|
"$PWD/.claude/skills/feature-forge" \
|
|
@@ -108,12 +123,41 @@ for candidate in \
|
|
|
108
123
|
"$PWD/.cursor/rules/feature-forge" \
|
|
109
124
|
"$HOME/.gemini/extensions/feature-forge" \
|
|
110
125
|
"$PWD/.gemini/extensions/feature-forge" \
|
|
126
|
+
"$HOME/.pi/agent/skills/feature-forge" \
|
|
127
|
+
"$PWD/.pi/skills/feature-forge" \
|
|
128
|
+
"$HOME"/.pi/agent/git/*/feature-forge/adapters/pi \
|
|
129
|
+
"$HOME"/.pi/agent/git/*/*/feature-forge/adapters/pi \
|
|
130
|
+
"$HOME"/.pi/agent/packages/*/feature-forge/adapters/pi \
|
|
131
|
+
"$HOME"/.pi/agent/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
132
|
+
"$HOME"/.pi/agent/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
133
|
+
"$PWD"/.pi/git/*/feature-forge/adapters/pi \
|
|
134
|
+
"$PWD"/.pi/git/*/*/feature-forge/adapters/pi \
|
|
135
|
+
"$PWD"/.pi/packages/*/feature-forge/adapters/pi \
|
|
136
|
+
"$PWD"/.pi/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
137
|
+
"$PWD"/.pi/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
111
138
|
; do
|
|
112
139
|
if is_root "$candidate"; then
|
|
113
140
|
accept_root "$candidate"
|
|
114
141
|
fi
|
|
115
142
|
done
|
|
116
143
|
|
|
144
|
+
# Project-scoped Pi installs may be discovered from a subdirectory of the repository. Probe
|
|
145
|
+
# ancestor .pi roots up to the filesystem root; this is bounded by path depth and avoids
|
|
146
|
+
# recursive globs. Scoped to .pi ONLY — every other agent's project layout is probed at $PWD
|
|
147
|
+
# in the fixed list above, and widening those to ancestors here would silently change
|
|
148
|
+
# established discovery behaviour for agents this bundle did not introduce.
|
|
149
|
+
probe_dir="$PWD"
|
|
150
|
+
while :; do
|
|
151
|
+
candidate="$probe_dir/.pi/skills/feature-forge"
|
|
152
|
+
if is_root "$candidate"; then
|
|
153
|
+
accept_root "$candidate"
|
|
154
|
+
fi
|
|
155
|
+
[ "$probe_dir" = "/" ] && break
|
|
156
|
+
next_probe_dir="$(dirname -- "$probe_dir")"
|
|
157
|
+
[ "$next_probe_dir" = "$probe_dir" ] && break
|
|
158
|
+
probe_dir="$next_probe_dir"
|
|
159
|
+
done
|
|
160
|
+
|
|
117
161
|
# ── Step 3: env fallback — neutral FEATURE_FORGE_ROOT, then the legacy CLAUDE_PLUGIN_ROOT. ─
|
|
118
162
|
# The neutral override works for every agent; CLAUDE_PLUGIN_ROOT is kept only for backwards
|
|
119
163
|
# compatibility with existing Claude installs (C-4).
|
|
@@ -1434,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
|
|
|
1434
1434
|
return flat
|
|
1435
1435
|
|
|
1436
1436
|
|
|
1437
|
+
def _host_command(command: str, host: str) -> str:
|
|
1438
|
+
"""Rewrite a `/feature-forge:` slash command to the host's surface.
|
|
1439
|
+
|
|
1440
|
+
Pi's slash-command surface is `/skill:` (matching the adapter body's
|
|
1441
|
+
`/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
|
|
1442
|
+
that body translation, so it rewrites the commands it emits here. No-op for
|
|
1443
|
+
claude/generic, which keep the canonical `/feature-forge:` form.
|
|
1444
|
+
"""
|
|
1445
|
+
return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
|
|
1446
|
+
|
|
1447
|
+
|
|
1437
1448
|
def _next_steps_block(
|
|
1438
1449
|
next_command: str, host: str, reconcile: dict | None = None
|
|
1439
1450
|
) -> str:
|
|
@@ -1463,6 +1474,18 @@ def _next_steps_block(
|
|
|
1463
1474
|
"2. Then start a fresh session and run the next stage below — or "
|
|
1464
1475
|
"re-run `/feature-forge:forge` to let the navigator resume from disk."
|
|
1465
1476
|
)
|
|
1477
|
+
elif host == "pi":
|
|
1478
|
+
# Pi's fresh-session command is `/new` (not `/clear`); its slash-command
|
|
1479
|
+
# surface is `/skill:` (the fenced command below is rewritten to match).
|
|
1480
|
+
clear_line = (
|
|
1481
|
+
"1. `/new` — recommended unconditionally at this stage boundary; every "
|
|
1482
|
+
"artifact is on disk, so the work survives starting a fresh session. "
|
|
1483
|
+
"I can't run `/new` for you — you have to run it yourself."
|
|
1484
|
+
)
|
|
1485
|
+
next_line = (
|
|
1486
|
+
"2. Then, in the new session, run the next stage below — or re-run "
|
|
1487
|
+
"`/skill:forge` to let the navigator resume from disk."
|
|
1488
|
+
)
|
|
1466
1489
|
else:
|
|
1467
1490
|
clear_line = (
|
|
1468
1491
|
"1. Clear your session / start a fresh session — recommended "
|
|
@@ -1479,7 +1502,7 @@ def _next_steps_block(
|
|
|
1479
1502
|
# epic-change request the primary is the reconcile command; otherwise it is the
|
|
1480
1503
|
# normal next-stage command. The fence sits before the sentinel, so the
|
|
1481
1504
|
# sentinel remains the absolute last line.
|
|
1482
|
-
fenced_command = reconcile["command"] if blocking else next_command
|
|
1505
|
+
fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
|
|
1483
1506
|
lines = ["**Next steps**", clear_line]
|
|
1484
1507
|
if blocking:
|
|
1485
1508
|
count = reconcile["count"]
|
|
@@ -1495,15 +1518,14 @@ def _next_steps_block(
|
|
|
1495
1518
|
lines.append("")
|
|
1496
1519
|
lines.append(f"```\n{fenced_command}\n```")
|
|
1497
1520
|
if blocking and reconcile.get("deferred"):
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
)
|
|
1521
|
+
deferred_cmd = _host_command(reconcile["deferred"], host)
|
|
1522
|
+
lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
|
|
1501
1523
|
elif reconcile and reconcile.get("reminder"):
|
|
1502
1524
|
count = reconcile["count"]
|
|
1503
1525
|
plural = "s" if count != 1 else ""
|
|
1504
1526
|
lines.append(
|
|
1505
1527
|
f"You also flagged {count} epic change{plural} to reconcile when "
|
|
1506
|
-
f"convenient: `{reconcile['command']}`"
|
|
1528
|
+
f"convenient: `{_host_command(reconcile['command'], host)}`"
|
|
1507
1529
|
)
|
|
1508
1530
|
lines.append(NEXT_STEPS_SENTINEL)
|
|
1509
1531
|
return "\n".join(lines)
|
|
@@ -1630,10 +1652,10 @@ def stage_exit(
|
|
|
1630
1652
|
"verifyGate": verify_gate,
|
|
1631
1653
|
"autoFixEligible": auto_fix_eligible,
|
|
1632
1654
|
"verifyState": verify_label,
|
|
1633
|
-
"verifyCommand": f"/feature-forge:forge-verify {feature}",
|
|
1655
|
+
"verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
|
|
1634
1656
|
"autoVerifyEffective": effective_auto_verify,
|
|
1635
1657
|
"nextStage": next_stage_id,
|
|
1636
|
-
"nextCommand": next_command,
|
|
1658
|
+
"nextCommand": _host_command(next_command, host) if next_command else next_command,
|
|
1637
1659
|
"invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
|
|
1638
1660
|
"gitRepo": git_repo,
|
|
1639
1661
|
"cleanTree": clean_tree,
|
|
@@ -1759,7 +1781,7 @@ def main() -> int:
|
|
|
1759
1781
|
p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
|
|
1760
1782
|
p_exit.add_argument("--next-feature", default=None, dest="next_feature",
|
|
1761
1783
|
help="First actionable feature (epic handoff next-command arg)")
|
|
1762
|
-
p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
|
|
1784
|
+
p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
|
|
1763
1785
|
help="Host wording for the NEXT-STEPS block")
|
|
1764
1786
|
p_exit.add_argument("--json", action="store_true", dest="json_output")
|
|
1765
1787
|
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -92,9 +92,24 @@ done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/pl
|
|
|
92
92
|
# Globs that match nothing expand to themselves; the is_root test rejects such literals. Covers
|
|
93
93
|
# every supported agent's install destination under BOTH global ($HOME) and project ($PWD) scope,
|
|
94
94
|
# matching the installer's per-agent layout: claude .claude/skills, codex .agents/skills, copilot
|
|
95
|
-
# .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions
|
|
96
|
-
# step 2a's path for a cache install that
|
|
97
|
-
# plugin.json for ls -t to key on).
|
|
95
|
+
# .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions, pi .pi/skills or
|
|
96
|
+
# $PI_CODING_AGENT_DIR/skills. The cache glob repeats step 2a's path for a cache install that
|
|
97
|
+
# carries only the neutral bundle sentinel (no plugin.json for ls -t to key on).
|
|
98
|
+
if [ -n "${PI_CODING_AGENT_DIR:-}" ]; then
|
|
99
|
+
for candidate in \
|
|
100
|
+
"$PI_CODING_AGENT_DIR/skills/feature-forge" \
|
|
101
|
+
"$PI_CODING_AGENT_DIR"/git/*/feature-forge/adapters/pi \
|
|
102
|
+
"$PI_CODING_AGENT_DIR"/git/*/*/feature-forge/adapters/pi \
|
|
103
|
+
"$PI_CODING_AGENT_DIR"/packages/*/feature-forge/adapters/pi \
|
|
104
|
+
"$PI_CODING_AGENT_DIR"/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
105
|
+
"$PI_CODING_AGENT_DIR"/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
106
|
+
; do
|
|
107
|
+
if is_root "$candidate"; then
|
|
108
|
+
accept_root "$candidate"
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
fi
|
|
112
|
+
|
|
98
113
|
for candidate in \
|
|
99
114
|
"$HOME/.claude/skills/feature-forge" \
|
|
100
115
|
"$PWD/.claude/skills/feature-forge" \
|
|
@@ -108,12 +123,41 @@ for candidate in \
|
|
|
108
123
|
"$PWD/.cursor/rules/feature-forge" \
|
|
109
124
|
"$HOME/.gemini/extensions/feature-forge" \
|
|
110
125
|
"$PWD/.gemini/extensions/feature-forge" \
|
|
126
|
+
"$HOME/.pi/agent/skills/feature-forge" \
|
|
127
|
+
"$PWD/.pi/skills/feature-forge" \
|
|
128
|
+
"$HOME"/.pi/agent/git/*/feature-forge/adapters/pi \
|
|
129
|
+
"$HOME"/.pi/agent/git/*/*/feature-forge/adapters/pi \
|
|
130
|
+
"$HOME"/.pi/agent/packages/*/feature-forge/adapters/pi \
|
|
131
|
+
"$HOME"/.pi/agent/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
132
|
+
"$HOME"/.pi/agent/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
133
|
+
"$PWD"/.pi/git/*/feature-forge/adapters/pi \
|
|
134
|
+
"$PWD"/.pi/git/*/*/feature-forge/adapters/pi \
|
|
135
|
+
"$PWD"/.pi/packages/*/feature-forge/adapters/pi \
|
|
136
|
+
"$PWD"/.pi/npm/*/@garygentry/feature-forge/adapters/pi \
|
|
137
|
+
"$PWD"/.pi/node_modules/@garygentry/feature-forge/adapters/pi \
|
|
111
138
|
; do
|
|
112
139
|
if is_root "$candidate"; then
|
|
113
140
|
accept_root "$candidate"
|
|
114
141
|
fi
|
|
115
142
|
done
|
|
116
143
|
|
|
144
|
+
# Project-scoped Pi installs may be discovered from a subdirectory of the repository. Probe
|
|
145
|
+
# ancestor .pi roots up to the filesystem root; this is bounded by path depth and avoids
|
|
146
|
+
# recursive globs. Scoped to .pi ONLY — every other agent's project layout is probed at $PWD
|
|
147
|
+
# in the fixed list above, and widening those to ancestors here would silently change
|
|
148
|
+
# established discovery behaviour for agents this bundle did not introduce.
|
|
149
|
+
probe_dir="$PWD"
|
|
150
|
+
while :; do
|
|
151
|
+
candidate="$probe_dir/.pi/skills/feature-forge"
|
|
152
|
+
if is_root "$candidate"; then
|
|
153
|
+
accept_root "$candidate"
|
|
154
|
+
fi
|
|
155
|
+
[ "$probe_dir" = "/" ] && break
|
|
156
|
+
next_probe_dir="$(dirname -- "$probe_dir")"
|
|
157
|
+
[ "$next_probe_dir" = "$probe_dir" ] && break
|
|
158
|
+
probe_dir="$next_probe_dir"
|
|
159
|
+
done
|
|
160
|
+
|
|
117
161
|
# ── Step 3: env fallback — neutral FEATURE_FORGE_ROOT, then the legacy CLAUDE_PLUGIN_ROOT. ─
|
|
118
162
|
# The neutral override works for every agent; CLAUDE_PLUGIN_ROOT is kept only for backwards
|
|
119
163
|
# compatibility with existing Claude installs (C-4).
|
|
@@ -1434,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
|
|
|
1434
1434
|
return flat
|
|
1435
1435
|
|
|
1436
1436
|
|
|
1437
|
+
def _host_command(command: str, host: str) -> str:
|
|
1438
|
+
"""Rewrite a `/feature-forge:` slash command to the host's surface.
|
|
1439
|
+
|
|
1440
|
+
Pi's slash-command surface is `/skill:` (matching the adapter body's
|
|
1441
|
+
`/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
|
|
1442
|
+
that body translation, so it rewrites the commands it emits here. No-op for
|
|
1443
|
+
claude/generic, which keep the canonical `/feature-forge:` form.
|
|
1444
|
+
"""
|
|
1445
|
+
return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
|
|
1446
|
+
|
|
1447
|
+
|
|
1437
1448
|
def _next_steps_block(
|
|
1438
1449
|
next_command: str, host: str, reconcile: dict | None = None
|
|
1439
1450
|
) -> str:
|
|
@@ -1463,6 +1474,18 @@ def _next_steps_block(
|
|
|
1463
1474
|
"2. Then start a fresh session and run the next stage below — or "
|
|
1464
1475
|
"re-run `/feature-forge:forge` to let the navigator resume from disk."
|
|
1465
1476
|
)
|
|
1477
|
+
elif host == "pi":
|
|
1478
|
+
# Pi's fresh-session command is `/new` (not `/clear`); its slash-command
|
|
1479
|
+
# surface is `/skill:` (the fenced command below is rewritten to match).
|
|
1480
|
+
clear_line = (
|
|
1481
|
+
"1. `/new` — recommended unconditionally at this stage boundary; every "
|
|
1482
|
+
"artifact is on disk, so the work survives starting a fresh session. "
|
|
1483
|
+
"I can't run `/new` for you — you have to run it yourself."
|
|
1484
|
+
)
|
|
1485
|
+
next_line = (
|
|
1486
|
+
"2. Then, in the new session, run the next stage below — or re-run "
|
|
1487
|
+
"`/skill:forge` to let the navigator resume from disk."
|
|
1488
|
+
)
|
|
1466
1489
|
else:
|
|
1467
1490
|
clear_line = (
|
|
1468
1491
|
"1. Clear your session / start a fresh session — recommended "
|
|
@@ -1479,7 +1502,7 @@ def _next_steps_block(
|
|
|
1479
1502
|
# epic-change request the primary is the reconcile command; otherwise it is the
|
|
1480
1503
|
# normal next-stage command. The fence sits before the sentinel, so the
|
|
1481
1504
|
# sentinel remains the absolute last line.
|
|
1482
|
-
fenced_command = reconcile["command"] if blocking else next_command
|
|
1505
|
+
fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
|
|
1483
1506
|
lines = ["**Next steps**", clear_line]
|
|
1484
1507
|
if blocking:
|
|
1485
1508
|
count = reconcile["count"]
|
|
@@ -1495,15 +1518,14 @@ def _next_steps_block(
|
|
|
1495
1518
|
lines.append("")
|
|
1496
1519
|
lines.append(f"```\n{fenced_command}\n```")
|
|
1497
1520
|
if blocking and reconcile.get("deferred"):
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
)
|
|
1521
|
+
deferred_cmd = _host_command(reconcile["deferred"], host)
|
|
1522
|
+
lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
|
|
1501
1523
|
elif reconcile and reconcile.get("reminder"):
|
|
1502
1524
|
count = reconcile["count"]
|
|
1503
1525
|
plural = "s" if count != 1 else ""
|
|
1504
1526
|
lines.append(
|
|
1505
1527
|
f"You also flagged {count} epic change{plural} to reconcile when "
|
|
1506
|
-
f"convenient: `{reconcile['command']}`"
|
|
1528
|
+
f"convenient: `{_host_command(reconcile['command'], host)}`"
|
|
1507
1529
|
)
|
|
1508
1530
|
lines.append(NEXT_STEPS_SENTINEL)
|
|
1509
1531
|
return "\n".join(lines)
|
|
@@ -1630,10 +1652,10 @@ def stage_exit(
|
|
|
1630
1652
|
"verifyGate": verify_gate,
|
|
1631
1653
|
"autoFixEligible": auto_fix_eligible,
|
|
1632
1654
|
"verifyState": verify_label,
|
|
1633
|
-
"verifyCommand": f"/feature-forge:forge-verify {feature}",
|
|
1655
|
+
"verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
|
|
1634
1656
|
"autoVerifyEffective": effective_auto_verify,
|
|
1635
1657
|
"nextStage": next_stage_id,
|
|
1636
|
-
"nextCommand": next_command,
|
|
1658
|
+
"nextCommand": _host_command(next_command, host) if next_command else next_command,
|
|
1637
1659
|
"invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
|
|
1638
1660
|
"gitRepo": git_repo,
|
|
1639
1661
|
"cleanTree": clean_tree,
|
|
@@ -1759,7 +1781,7 @@ def main() -> int:
|
|
|
1759
1781
|
p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
|
|
1760
1782
|
p_exit.add_argument("--next-feature", default=None, dest="next_feature",
|
|
1761
1783
|
help="First actionable feature (epic handoff next-command arg)")
|
|
1762
|
-
p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
|
|
1784
|
+
p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
|
|
1763
1785
|
help="Host wording for the NEXT-STEPS block")
|
|
1764
1786
|
p_exit.add_argument("--json", action="store_true", dest="json_output")
|
|
1765
1787
|
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|
|
@@ -217,8 +217,8 @@
|
|
|
217
217
|
},
|
|
218
218
|
"installHint": {
|
|
219
219
|
"type": "string",
|
|
220
|
-
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.
|
|
221
|
-
"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.
|
|
220
|
+
"default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
|
|
221
|
+
"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.13.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."
|
|
222
222
|
},
|
|
223
223
|
"schemaVersion": {
|
|
224
224
|
"type": "string",
|