@entelligentsia/forgecli 1.0.3 → 1.0.14
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/CHANGELOG.md +93 -0
- package/README.md +2 -1
- package/dist/CHANGELOG-forge-plugin.md +250 -0
- package/dist/CHANGELOG-pi.md +94 -0
- package/dist/bin/forge.js +0 -0
- package/dist/extensions/forgecli/config-layer.d.ts +16 -0
- package/dist/extensions/forgecli/config-layer.js +5 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -1
- package/dist/extensions/forgecli/dashboard/component.d.ts +102 -0
- package/dist/extensions/forgecli/dashboard/component.js +882 -0
- package/dist/extensions/forgecli/dashboard/component.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/register.d.ts +2 -0
- package/dist/extensions/forgecli/dashboard/register.js +45 -0
- package/dist/extensions/forgecli/dashboard/register.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/view-model.d.ts +35 -0
- package/dist/extensions/forgecli/dashboard/view-model.js +54 -0
- package/dist/extensions/forgecli/dashboard/view-model.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.js +72 -7
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js +27 -4
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- package/dist/extensions/forgecli/forge-cli-schema.json +4 -0
- package/dist/extensions/forgecli/forge-commands.js +1 -0
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +53 -0
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.js +6 -4
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.js +2 -2
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/index.js +5 -0
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/lib/halt-advisor.d.ts +54 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js +90 -0
- package/dist/extensions/forgecli/lib/halt-advisor.js.map +1 -0
- package/dist/extensions/forgecli/migration-engine.js +25 -12
- package/dist/extensions/forgecli/migration-engine.js.map +1 -1
- package/dist/extensions/forgecli/orchestrator-status-bar.d.ts +25 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js +183 -0
- package/dist/extensions/forgecli/orchestrator-status-bar.js.map +1 -0
- package/dist/extensions/forgecli/orchestrator-tree.d.ts +96 -0
- package/dist/extensions/forgecli/orchestrator-tree.js +390 -0
- package/dist/extensions/forgecli/orchestrator-tree.js.map +1 -0
- package/dist/extensions/forgecli/project-orientation.js +12 -8
- package/dist/extensions/forgecli/project-orientation.js.map +1 -1
- package/dist/extensions/forgecli/regenerate.d.ts +16 -0
- package/dist/extensions/forgecli/regenerate.js +110 -0
- package/dist/extensions/forgecli/regenerate.js.map +1 -1
- package/dist/extensions/forgecli/run-sprint.js +33 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +32 -0
- package/dist/extensions/forgecli/run-task.js +185 -12
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/subagent/phase-guard.js +15 -5
- package/dist/extensions/forgecli/subagent/phase-guard.js.map +1 -1
- package/dist/extensions/forgecli/subagent/phase-summary-map.d.ts +1 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.js +17 -0
- package/dist/extensions/forgecli/subagent/phase-summary-map.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +105 -764
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/viewport-events.js +32 -0
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/forge-payload/.base-pack/commands/fix-bug.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-sprint.md +1 -1
- package/dist/forge-payload/.base-pack/commands/run-task.md +1 -1
- package/dist/forge-payload/.base-pack/personas/architect.md +1 -1
- package/dist/forge-payload/.base-pack/personas/bug-fixer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/collator.md +3 -3
- package/dist/forge-payload/.base-pack/personas/engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/librarian.md +1 -1
- package/dist/forge-payload/.base-pack/personas/orchestrator.md +1 -1
- package/dist/forge-payload/.base-pack/personas/product-manager.md +1 -1
- package/dist/forge-payload/.base-pack/personas/qa-engineer.md +1 -1
- package/dist/forge-payload/.base-pack/personas/supervisor.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/.base-pack/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +29 -5
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +8 -10
- package/dist/forge-payload/.base-pack/workflows/architect_review_sprint_completion.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_intake.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/architect_sprint_plan.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/collator_agent.md +5 -7
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +7 -9
- package/dist/forge-payload/.base-pack/workflows/enhance.md +5 -5
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +9 -9
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +12 -13
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +5 -6
- package/dist/forge-payload/.base-pack/workflows/review_code.md +8 -8
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +8 -8
- package/dist/forge-payload/.base-pack/workflows/sprint_retrospective.md +3 -3
- package/dist/forge-payload/.base-pack/workflows/triage.md +13 -10
- package/dist/forge-payload/.base-pack/workflows/update_implementation.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/update_plan.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/validate_task.md +6 -8
- package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +490 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-sprint.js +416 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +608 -0
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/_defs/locator.schema.json +13 -0
- package/dist/forge-payload/.schemas/bug.schema.json +1 -0
- package/dist/forge-payload/.schemas/config.schema.json +2 -3
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/event.schema.json +16 -0
- package/dist/forge-payload/.schemas/migrations.json +299 -0
- package/dist/forge-payload/.schemas/sprint.schema.json +1 -0
- package/dist/forge-payload/.schemas/task.schema.json +1 -0
- package/dist/forge-payload/commands/health.md +29 -0
- package/dist/forge-payload/commands/rebuild.md +143 -15
- package/dist/forge-payload/commands/update.md +28 -27
- package/dist/forge-payload/hooks/preflight-session.cjs +99 -0
- package/dist/forge-payload/init/phases/phase-3-materialize.md +18 -5
- package/dist/forge-payload/integrity.json +7 -6
- package/dist/forge-payload/meta/fragments/tool-discipline.md +1 -1
- package/dist/forge-payload/meta/personas/meta-architect.md +1 -1
- package/dist/forge-payload/meta/personas/meta-bug-fixer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-collator.md +7 -7
- package/dist/forge-payload/meta/personas/meta-engineer.md +1 -1
- package/dist/forge-payload/meta/personas/meta-orchestrator.md +1 -1
- package/dist/forge-payload/meta/personas/meta-supervisor.md +1 -1
- package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/iron-laws.md +1 -1
- package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +2 -2
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +29 -5
- package/dist/forge-payload/meta/workflows/meta-approve.md +8 -10
- package/dist/forge-payload/meta/workflows/meta-bug-triage.md +13 -10
- package/dist/forge-payload/meta/workflows/meta-collate.md +6 -8
- package/dist/forge-payload/meta/workflows/meta-commit.md +7 -9
- package/dist/forge-payload/meta/workflows/meta-enhance.md +5 -5
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +35 -11
- package/dist/forge-payload/meta/workflows/meta-implement.md +18 -9
- package/dist/forge-payload/meta/workflows/meta-migrate.md +13 -14
- package/dist/forge-payload/meta/workflows/meta-new-sprint.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +175 -82
- package/dist/forge-payload/meta/workflows/meta-plan-sprint.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +12 -6
- package/dist/forge-payload/meta/workflows/meta-retro.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-retrospective.md +4 -4
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +8 -8
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +8 -8
- package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +6 -6
- package/dist/forge-payload/meta/workflows/meta-update-implementation.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-update-plan.md +2 -2
- package/dist/forge-payload/meta/workflows/meta-validate.md +6 -8
- package/dist/forge-payload/schemas/_defs/locator.schema.json +13 -0
- package/dist/forge-payload/schemas/bug.schema.json +1 -0
- package/dist/forge-payload/schemas/config.schema.json +2 -3
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/event.schema.json +16 -0
- package/dist/forge-payload/schemas/sprint.schema.json +1 -0
- package/dist/forge-payload/schemas/structure-manifest.json +76 -73
- package/dist/forge-payload/schemas/task.schema.json +1 -0
- package/dist/forge-payload/skills/refresh-kb-links/SKILL.md +14 -7
- package/dist/forge-payload/tools/artifact-store.cjs +242 -0
- package/dist/forge-payload/tools/artifact.cjs +60 -120
- package/dist/forge-payload/tools/banners.cjs +29 -10
- package/dist/forge-payload/tools/check-structure.cjs +88 -7
- package/dist/forge-payload/tools/collate.cjs +16 -2
- package/dist/forge-payload/tools/lib/artifact-kinds.cjs +95 -0
- package/dist/forge-payload/tools/lib/store-nlp.cjs +6 -0
- package/dist/forge-payload/tools/lib/store-query-exec.cjs +39 -5
- package/dist/forge-payload/tools/lib/suggest.cjs +2 -1
- package/dist/forge-payload/tools/manage-config.cjs +5 -7
- package/dist/forge-payload/tools/parse-gates.cjs +73 -1
- package/dist/forge-payload/tools/postflight-gate.cjs +252 -0
- package/dist/forge-payload/tools/preflight-gate.cjs +102 -5
- package/dist/forge-payload/tools/store-cli.cjs +50 -15
- package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -4
- package/dist/forge-payload/tools/verify-phase.cjs +17 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +19 -24
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +374 -122
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +424 -232
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +38 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +21 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +6 -10
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +3 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +159 -78
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +16 -11
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +6 -10
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
- package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -4
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +94 -0
- package/node_modules/@earendil-works/pi-coding-agent/README.md +9 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +15 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +28 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +8 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +7 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts +9 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +10 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts +6 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +75 -28
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts +5 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +1 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +59 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js.map +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/custom-provider.md +13 -10
- package/node_modules/@earendil-works/pi-coding-agent/docs/development.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +12 -6
- package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +25 -12
- package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +13 -5
- package/node_modules/@earendil-works/pi-coding-agent/docs/quickstart.md +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +2 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +6 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/session-format.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/sessions.md +8 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +7 -3
- package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/docs/tui.md +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +9 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/README.md +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/index.ts +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/input-transform-streaming.ts +39 -0
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +443 -61
- package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
- package/node_modules/@earendil-works/pi-tui/README.md +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +24 -83
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +7 -55
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +7 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +6 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +27 -15
- package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/@entelligentsia/forge-compress/LICENSE +21 -0
- package/node_modules/@entelligentsia/forge-compress/README.md +85 -0
- package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
- package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
- package/node_modules/@mariozechner/clipboard/index.js +546 -257
- package/node_modules/@mariozechner/clipboard/package.json +5 -6
- package/node_modules/@mariozechner/clipboard/package.json.prepack-backup +14 -14
- package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
- package/package.json +7 -7
- package/dist/bin/forgecli.d.ts +0 -2
- package/dist/bin/forgecli.js +0 -6
- package/dist/bin/forgecli.js.map +0 -1
- package/dist/extensions/forgecli/config-tui/index.d.ts +0 -5
- package/dist/extensions/forgecli/config-tui/index.js +0 -5
- package/dist/extensions/forgecli/config-tui/index.js.map +0 -1
- package/dist/extensions/forgecli/loaders/persona-skill-loader.d.ts +0 -45
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js +0 -227
- package/dist/extensions/forgecli/loaders/persona-skill-loader.js.map +0 -1
- package/dist/extensions/forgecli/loaders/template-render.d.ts +0 -20
- package/dist/extensions/forgecli/loaders/template-render.js +0 -85
- package/dist/extensions/forgecli/loaders/template-render.js.map +0 -1
- package/dist/extensions/forgecli/loaders/workflow-loader.d.ts +0 -41
- package/dist/extensions/forgecli/loaders/workflow-loader.js +0 -164
- package/dist/extensions/forgecli/loaders/workflow-loader.js.map +0 -1
- package/dist/forge-payload/.base-pack/commands/quiz-agent.md +0 -6
- package/dist/forge-payload/.base-pack/commands/retrospective.md +0 -6
- package/dist/forge-payload/.base-pack/commands/sprint-intake.md +0 -6
- package/dist/forge-payload/.base-pack/commands/sprint-plan.md +0 -6
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +0 -446
- package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +0 -934
- package/dist/forge-payload/.base-pack/workflows/run_sprint.md +0 -225
- package/dist/forge-payload/commands/calibrate.md +0 -10
- package/dist/forge-payload/commands/materialize.md +0 -119
- package/dist/forge-payload/commands/migrate.md +0 -12
- package/dist/forge-payload/commands/quiz-agent.md +0 -6
- package/dist/forge-payload/commands/regenerate.md +0 -6
- package/dist/forge-payload/commands/store-query.md +0 -6
- package/dist/forge-payload/commands/store-repair.md +0 -6
- package/dist/forge-payload/commands/update-tools.md +0 -10
- package/dist/forge-payload/meta/templates/meta-retrospective.md +0 -28
- package/dist/forge-payload/tools/prompts/sprint-plan-prompt.md +0 -70
- package/dist/forge-payload/tools/schemas/task-list.schema.json +0 -53
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts +0 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js +0 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts +0 -20
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js +0 -92
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts +0 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js +0 -42
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts +0 -10
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js +0 -31
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts +0 -30
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js +0 -170
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts +0 -26
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js +0 -90
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js.map +0 -1
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +0 -3
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/clipboard.linux-x64-musl.node +0 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +0 -25
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'wfl:run-task',
|
|
3
|
+
description: 'Code-orchestrated port of /forge:run-task — resolve the task pipeline, drive each phase (plan→review→implement→review→validate→approve→commit) through a subagent on its ROLE_TIER model (review/validate/approve→opus, plan/implement→sonnet, commit→haiku), hold the revision loop + verdict routing + escalation in JS.',
|
|
4
|
+
whenToUse: 'Run a single Forge task through its full plan→implement→review→approve→commit pipeline via a deterministic JS driver instead of the LLM orchestrator. Pass the task id as args, e.g. args: "FORGE-S27-T01".',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Resolve', detail: 'one agent reads the task manifest + config, returns the resolved pipeline phases and pre-task status' },
|
|
7
|
+
{ title: 'Pipeline', detail: 'per phase: one subagent runs the gate + phase workflow + emits its own event; JS owns the phase index, revision counters, verdict routing, and escalation decision' },
|
|
8
|
+
{ title: 'Report', detail: 'summarise the terminal outcome — committed / escalated / blocked' },
|
|
9
|
+
],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// wfl:run-task — a code-orchestrated port of .forge/workflows/orchestrate_task.md
|
|
14
|
+
//
|
|
15
|
+
// Why a script: orchestrate_task.md is a deterministic phase FSM — a linear
|
|
16
|
+
// pipeline with review→revision back-edges, per-phase iteration caps, declarative
|
|
17
|
+
// pre-flight gates, and escalate-don't-continue on any failure. In the LLM
|
|
18
|
+
// orchestrator that loop is hand-run turn-by-turn. Here the JS holds the phase
|
|
19
|
+
// index, the revision counters, the verdict routing, and the escalation decision;
|
|
20
|
+
// subagents only run a single phase's workflow and write artifacts/events to disk.
|
|
21
|
+
//
|
|
22
|
+
// HOW THIS DIFFERS FROM wfl:run-sprint:
|
|
23
|
+
// wfl:run-sprint ported the OUTER wave-sort FSM but delegated each whole task
|
|
24
|
+
// to ONE orchestrate_task agent — it never decomposed the per-phase loop.
|
|
25
|
+
// wfl:run-task decomposes that loop: one subagent PER PHASE. That is the only
|
|
26
|
+
// version with a reason to exist (a single orchestrate_task agent == the
|
|
27
|
+
// existing /forge:run-task, and adds nothing).
|
|
28
|
+
//
|
|
29
|
+
// SIDE-EFFECT OWNERSHIP — READ BEFORE EDITING:
|
|
30
|
+
// The vanished orchestrate_task agent used to do a stack of shell-dependent
|
|
31
|
+
// jobs for free. This script has NO filesystem/shell access, so each per-phase
|
|
32
|
+
// subagent now owns them: preflight-gate, the phase workflow (which writes its
|
|
33
|
+
// own artifacts + {PHASE}-SUMMARY.json + status), read-verdict (review phases),
|
|
34
|
+
// token sidecar, friction drain, AND its own canonical phase event.
|
|
35
|
+
//
|
|
36
|
+
// *** DELIBERATE DEVIATION from orchestrate_task.md's "the orchestrator is the
|
|
37
|
+
// sole actor that calls store-cli emit" rule: here each phase subagent emits
|
|
38
|
+
// its OWN phase event. This is defensible — the subagent is the only actor that
|
|
39
|
+
// holds its own runtime attribution (model, provider, token usage). The JS
|
|
40
|
+
// driver cannot run store-cli. This is a control-flow-authoritative port with
|
|
41
|
+
// delegated telemetry, NOT a byte-for-byte reproduction of the emit contract.
|
|
42
|
+
//
|
|
43
|
+
// Split start/complete emit contract: per orchestrate_task.md §Event Emission,
|
|
44
|
+
// each phase subagent emits a start event (action="start") BEFORE executing its
|
|
45
|
+
// phase workflow, then a complete event (action="complete") AFTER. The JS driver
|
|
46
|
+
// delegates wall-time bracketing to the subagent: subagent notes startTimestamp,
|
|
47
|
+
// runs the workflow, then computes durationMinutes = (endMs - startMs) / 60000
|
|
48
|
+
// and includes it in the complete event. The start event carries a 0-duration
|
|
49
|
+
// placeholder (startTimestamp == endTimestamp); the complete event carries the
|
|
50
|
+
// real bracket. This mirrors the orchestrate_task.md start+complete pattern. ***
|
|
51
|
+
//
|
|
52
|
+
// Honest fallback if per-phase emission ever proves too lossy: collapse to the
|
|
53
|
+
// thin port (one agent reading orchestrate_task.md, == wfl:run-sprint.dispatchTask),
|
|
54
|
+
// which inherits every side-effect for free. Do NOT ship a silently-lossy deep port.
|
|
55
|
+
//
|
|
56
|
+
// #21 STRUCTURAL LIMITATION — Progress-Monitor IPC:
|
|
57
|
+
// The JS driver has no shell access (Workflow tool sandbox) and therefore CANNOT
|
|
58
|
+
// write progress lines to a named pipe / Unix socket for the Progress-Monitor.
|
|
59
|
+
// Wiring real-time progress telemetry to the Forge UI requires the forge-cli TS
|
|
60
|
+
// layer to open the pipe before spawning the Workflow tool and inject the fd via
|
|
61
|
+
// the Pi runtime's stdio bridging API — this is a host-layer concern, not a
|
|
62
|
+
// JS workflow concern. Documenting here so future sprints know where the
|
|
63
|
+
// architectural seam is. No implementation in this file is possible or correct.
|
|
64
|
+
//
|
|
65
|
+
// MODEL CLUSTER RESOLUTION (Gap #12 — FORGE-S28-T05):
|
|
66
|
+
// Replaces the old hard-tier dispatch with three-cluster logic matching the prose:
|
|
67
|
+
// • single cluster (ANTHROPIC_DEFAULT_OPUS_MODEL == ANTHROPIC_DEFAULT_SONNET_MODEL
|
|
68
|
+
// or both absent): pass model=undefined so subagent inherits parent session model.
|
|
69
|
+
// • tiered cluster (vars differ): pass the tier NAME ('opus'|'sonnet'|'haiku').
|
|
70
|
+
// • unknown cluster (no ANTHROPIC_DEFAULT_*_MODEL vars set): pass the canonical
|
|
71
|
+
// model ID from ROLE_TIER_DEFAULTS.
|
|
72
|
+
// • per-phase override (phase.model field from resolve): highest precedence.
|
|
73
|
+
// ROLE_TIER still exists for the resolve agent to return dispatchModel per phase,
|
|
74
|
+
// but the JS loop now calls resolveModel(role, phase) instead of tierFor(role).
|
|
75
|
+
// DELIBERATE DEVIATION: Pi workflow scripts do not expose a reliable `env` or
|
|
76
|
+
// `process.env` global for reading ANTHROPIC_DEFAULT_*_MODEL vars at the JS
|
|
77
|
+
// driver level. The three-cluster logic is structurally wired (env-var guards
|
|
78
|
+
// use `typeof env !== 'undefined'` which will be false in the sandbox, causing
|
|
79
|
+
// the function to always take the unknown-cluster path → ROLE_TIER_DEFAULTS[tier]).
|
|
80
|
+
// This is the safe, predictable fallback: explicit canonical IDs per role tier.
|
|
81
|
+
// True single-cluster / tiered-cluster behavior requires the caller (forge-cli
|
|
82
|
+
// TS layer) to inject dispatchModel into the phase via RESOLVE_SCHEMA phase.model,
|
|
83
|
+
// which is the per-phase override path (highest precedence, always respected).
|
|
84
|
+
//
|
|
85
|
+
// SESSION PREFLIGHT (Gap #6 — FORGE-S28-T05):
|
|
86
|
+
// Instructed in phase-0 subagent prompt only (firstPhase=true). Reads
|
|
87
|
+
// .forge/cache/preflight-status.json; blob.ok===false halts before gate step.
|
|
88
|
+
// Port limitation: subsequent phases skip preflight to avoid redundant re-checks.
|
|
89
|
+
//
|
|
90
|
+
// FRICTION EMISSION (Gap #5 — FORGE-S28-T05):
|
|
91
|
+
// Orchestrator-experienced friction (spawn failure, FSM rejection) cannot be
|
|
92
|
+
// emitted by the JS driver because it cannot shell out to store-cli. Documented
|
|
93
|
+
// as a port limitation. Per-phase subagents are instructed to drain
|
|
94
|
+
// .forge/cache/FRICTION-*.jsonl and emit type:friction events after failures.
|
|
95
|
+
//
|
|
96
|
+
// ON_REVISION ROUTING (Gap #13 — FORGE-S28-T05):
|
|
97
|
+
// RESOLVE_SCHEMA phase items gain optional on_revision field. revisionTarget()
|
|
98
|
+
// prefers phase.on_revision (command-name lookup) over nearest-preceding-non-review.
|
|
99
|
+
//
|
|
100
|
+
// TOKEN SIDECAR MERGE (Gap #14 — FORGE-S28-T05):
|
|
101
|
+
// After each phase subagent returns, an escalate-agent pattern calls
|
|
102
|
+
// store-cli merge-sidecar with the eventId agreed before spawn.
|
|
103
|
+
// The eventId uses the _complete suffix (token usage lands on the COMPLETE event,
|
|
104
|
+
// not the start event). The driver passes eventId into runPhase() so the subagent
|
|
105
|
+
// prompt references the same eventId when writing the sidecar via --sidecar.
|
|
106
|
+
//
|
|
107
|
+
// PERSONA/SKILL INJECTION (Gap #8 — FORGE-S28-T05):
|
|
108
|
+
// ROLE_TO_NOUN maps each role to its persona noun. Subagent prompt instructs
|
|
109
|
+
// reading persona-pack.json and composing role block (reference mode, inline fallback).
|
|
110
|
+
//
|
|
111
|
+
// BUILD-OVERLAY CONTEXT (Gap #9 — FORGE-S28-T05):
|
|
112
|
+
// Raw MASTER_INDEX.md read replaced with build-overlay.cjs --task --format md.
|
|
113
|
+
// Stale direct read is a documented degradation fallback.
|
|
114
|
+
//
|
|
115
|
+
// REVIEW LOOP CONTEXT (Gap #10 — FORGE-S28-T05):
|
|
116
|
+
// REVIEW_ROLES phases receive a "Review Loop Context" block with iteration/maxIter.
|
|
117
|
+
//
|
|
118
|
+
// GATE EXIT-CODE DISTINCTION (Gap #7 — FORGE-S28-T05):
|
|
119
|
+
// Subagent prompt distinguishes exit_code==1 (gate_failed) vs exit_code==2
|
|
120
|
+
// (gate_misconfigured) in the note field.
|
|
121
|
+
//
|
|
122
|
+
// SIMPLIFIED RETRY PROMPT (Gap #11 — FORGE-S28-T05):
|
|
123
|
+
// Empty/whitespace/timeout result triggers subagent_retry event then retries
|
|
124
|
+
// with a simplified prompt (no arch block, no summary block, adds YOU MUST produce a result).
|
|
125
|
+
//
|
|
126
|
+
// Invocation (Workflow tool): { name: 'wfl:run-task', args: 'FORGE-S27-T01' }
|
|
127
|
+
// args may also be an object: { taskId: 'FORGE-S27-T01' }
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
// Task statuses that mean "do not run any phase" — orchestrate_task pre-task guard.
|
|
131
|
+
const SKIP_STATUS = ['blocked', 'escalated', 'committed', 'abandoned']
|
|
132
|
+
// Phase roles whose artifact carries a **Verdict:** that routes the FSM.
|
|
133
|
+
// NOTE: `approve` is NOT here — orchestrate_task advances it on completion like a
|
|
134
|
+
// non-review phase (the approve workflow self-escalates if it rejects).
|
|
135
|
+
const REVIEW_ROLES = ['review-plan', 'review-code', 'validate']
|
|
136
|
+
// Per-phase model tier — verbatim port of orchestrate_task.md § Role-to-Tier Mapping.
|
|
137
|
+
// The resolve agent uses this as a reference; JS loop calls resolveModel() not tierFor().
|
|
138
|
+
const ROLE_TIER = {
|
|
139
|
+
'plan': 'sonnet',
|
|
140
|
+
'implement': 'sonnet',
|
|
141
|
+
'review-plan': 'opus',
|
|
142
|
+
'review-code': 'opus',
|
|
143
|
+
'validate': 'opus',
|
|
144
|
+
'approve': 'opus',
|
|
145
|
+
'commit': 'haiku',
|
|
146
|
+
'writeback': 'haiku',
|
|
147
|
+
}
|
|
148
|
+
const tierFor = (role) => ROLE_TIER[role] || 'sonnet' // orchestrate_task's ROLE_TIER.get(role, "sonnet")
|
|
149
|
+
|
|
150
|
+
// Canonical model IDs for unknown-cluster fallback (Gap #12).
|
|
151
|
+
const ROLE_TIER_DEFAULTS = {
|
|
152
|
+
opus: 'claude-opus-4-5',
|
|
153
|
+
sonnet: 'claude-sonnet-4-6',
|
|
154
|
+
haiku: 'claude-haiku-4-5',
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Resolve the dispatch model per the three-cluster + per-phase-override logic (Gap #12).
|
|
158
|
+
// • phase.model (from resolve) — highest precedence (per-phase override).
|
|
159
|
+
// • ANTHROPIC_DEFAULT_OPUS_MODEL === ANTHROPIC_DEFAULT_SONNET_MODEL or both absent → undefined (inherit).
|
|
160
|
+
// • vars differ → tier name (tiered cluster).
|
|
161
|
+
// • no vars set → canonical ID from ROLE_TIER_DEFAULTS (unknown cluster).
|
|
162
|
+
function resolveModel(role, phase) {
|
|
163
|
+
if (phase && phase.model) return phase.model // per-phase override wins
|
|
164
|
+
const tier = tierFor(role)
|
|
165
|
+
const opusVar = (typeof env !== 'undefined' && env.ANTHROPIC_DEFAULT_OPUS_MODEL) || undefined
|
|
166
|
+
const sonnetVar = (typeof env !== 'undefined' && env.ANTHROPIC_DEFAULT_SONNET_MODEL) || undefined
|
|
167
|
+
const haikiVar = (typeof env !== 'undefined' && env.ANTHROPIC_DEFAULT_HAIKU_MODEL) || undefined
|
|
168
|
+
const anySet = opusVar || sonnetVar || haikiVar
|
|
169
|
+
if (!anySet) return ROLE_TIER_DEFAULTS[tier] // unknown cluster: canonical ID
|
|
170
|
+
// If all three are equal (or only one is set and it matches), treat as single cluster.
|
|
171
|
+
const uniqueVals = new Set([opusVar, sonnetVar, haikiVar].filter(Boolean))
|
|
172
|
+
if (uniqueVals.size <= 1) return undefined // single cluster: inherit parent
|
|
173
|
+
return tier // tiered cluster: pass tier name
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Phase banner map — visual phase identity for log lines (LOW #22).
|
|
177
|
+
// Parallel to ROLE_TO_NOUN: maps each role to the persona banner label shown at
|
|
178
|
+
// phase-announcement time so the transcript log identifies which Forge persona is active.
|
|
179
|
+
// The subagent already gets the full persona-block via ROLE_TO_NOUN; this is display-only.
|
|
180
|
+
const BANNER_MAP = {
|
|
181
|
+
'plan': 'forge-architect',
|
|
182
|
+
'review-plan': 'forge-architect',
|
|
183
|
+
'implement': 'forge-engineer',
|
|
184
|
+
'review-code': 'forge-engineer',
|
|
185
|
+
'validate': 'forge-validator',
|
|
186
|
+
'approve': 'forge-architect',
|
|
187
|
+
'commit': 'forge-engineer',
|
|
188
|
+
'writeback': 'forge-engineer',
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Role → persona noun mapping for role-block injection (Gap #8).
|
|
192
|
+
const ROLE_TO_NOUN = {
|
|
193
|
+
'plan': 'architect',
|
|
194
|
+
'review-plan': 'architect',
|
|
195
|
+
'implement': 'engineer',
|
|
196
|
+
'review-code': 'engineer',
|
|
197
|
+
'validate': 'validator',
|
|
198
|
+
'approve': 'architect',
|
|
199
|
+
'commit': 'engineer',
|
|
200
|
+
'writeback': 'engineer',
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const RESOLVE_SCHEMA = {
|
|
204
|
+
type: 'object',
|
|
205
|
+
additionalProperties: false,
|
|
206
|
+
required: ['taskId', 'sprintId', 'taskStatus', 'phases'],
|
|
207
|
+
properties: {
|
|
208
|
+
taskId: { type: 'string' },
|
|
209
|
+
sprintId: { type: 'string' },
|
|
210
|
+
taskStatus: { type: 'string' }, // status read from .forge/store/tasks/{id}.json
|
|
211
|
+
phases: {
|
|
212
|
+
type: 'array',
|
|
213
|
+
items: {
|
|
214
|
+
type: 'object',
|
|
215
|
+
additionalProperties: false,
|
|
216
|
+
required: ['command', 'role', 'workflow', 'maxIterations'],
|
|
217
|
+
properties: {
|
|
218
|
+
command: { type: 'string' }, // slash-command name, e.g. "review-plan"
|
|
219
|
+
role: { type: 'string' }, // semantic role, e.g. "review-plan"
|
|
220
|
+
workflow: { type: 'string' }, // workflow file under .forge/workflows/, e.g. "review_plan.md"
|
|
221
|
+
maxIterations: { type: 'integer' }, // revision cap for review roles (default 3)
|
|
222
|
+
on_revision: { type: 'string' }, // optional: command name to route to on revision (Gap #13)
|
|
223
|
+
model: { type: 'string' }, // optional: per-phase model override (Gap #12)
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const PHASE_RESULT_SCHEMA = {
|
|
231
|
+
type: 'object',
|
|
232
|
+
additionalProperties: false,
|
|
233
|
+
required: ['phase', 'role', 'gatePassed', 'verdict', 'escalated', 'taskStatus'],
|
|
234
|
+
properties: {
|
|
235
|
+
phase: { type: 'string' }, // the command name dispatched
|
|
236
|
+
role: { type: 'string' },
|
|
237
|
+
gatePassed: { type: 'boolean' }, // preflight-gate.cjs exit 0
|
|
238
|
+
verdict: { type: 'string', enum: ['approved', 'revision', 'malformed', 'none'] }, // 'none' for non-review phases
|
|
239
|
+
escalated: { type: 'boolean' }, // subagent set status=escalated (gate fail / malformed / self-escalation)
|
|
240
|
+
taskStatus: { type: 'string' }, // status read back after the phase
|
|
241
|
+
note: { type: 'string' },
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// --- nearest preceding non-review phase (revision target) -------------------
|
|
246
|
+
// Port of orchestrate_task.md: a "Revision Required" verdict routes back to the
|
|
247
|
+
// nearest earlier phase whose role is NOT a review role (i.e. the producer).
|
|
248
|
+
// Gap #13: if the current review phase specifies on_revision (a command name), look
|
|
249
|
+
// it up by command name in phases and return that index. Fallback to nearest-preceding.
|
|
250
|
+
function revisionTarget(phases, reviewIdx) {
|
|
251
|
+
const reviewPhase = phases[reviewIdx]
|
|
252
|
+
if (reviewPhase && reviewPhase.on_revision) {
|
|
253
|
+
const targetIdx = phases.findIndex((p) => p.command === reviewPhase.on_revision)
|
|
254
|
+
if (targetIdx !== -1) return targetIdx
|
|
255
|
+
}
|
|
256
|
+
for (let j = reviewIdx - 1; j >= 0; j--) {
|
|
257
|
+
if (!REVIEW_ROLES.includes(phases[j].role)) return j
|
|
258
|
+
}
|
|
259
|
+
return 0 // degenerate pipeline with no producer before the review — loop to start
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// --- dispatch one phase as a subagent ---------------------------------------
|
|
263
|
+
// The subagent owns ALL shell-dependent side-effects for this phase (see header).
|
|
264
|
+
// Gap #6: firstPhase=true triggers session preflight check (phase-index-0 only).
|
|
265
|
+
// Gap #11: simplified=true uses a shorter prompt (retry path, strips arch+summary block).
|
|
266
|
+
// Gap #14: eventId is the COMPLETE-event id pre-computed by the JS loop; the subagent
|
|
267
|
+
// must use this exact id when writing its token sidecar (--sidecar form) so mergeSidecar()
|
|
268
|
+
// can find the file. Use the _complete suffix because token usage lands on the COMPLETE event.
|
|
269
|
+
function runPhase(taskId, sprintId, phase, iteration, { firstPhase = false, simplified = false, eventId = null } = {}) {
|
|
270
|
+
const personaNoun = ROLE_TO_NOUN[phase.role] || 'engineer'
|
|
271
|
+
const reviewLoopCtx = REVIEW_ROLES.includes(phase.role)
|
|
272
|
+
? [
|
|
273
|
+
'',
|
|
274
|
+
'### Review Loop Context',
|
|
275
|
+
`Iteration: ${iteration} of ${phase.maxIterations}`,
|
|
276
|
+
`Is final iteration: ${iteration >= phase.maxIterations}`,
|
|
277
|
+
].join('\n')
|
|
278
|
+
: ''
|
|
279
|
+
|
|
280
|
+
// Build the prompt lines list.
|
|
281
|
+
const lines = [
|
|
282
|
+
`You are running a SINGLE pipeline phase for Forge task ${taskId} (sprint ${sprintId}).`,
|
|
283
|
+
`Phase: role="${phase.role}", command="${phase.command}", workflow="${phase.workflow}", iteration=${iteration}.`,
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
// Gap #6: Session Preflight — first phase only.
|
|
287
|
+
if (firstPhase) {
|
|
288
|
+
lines.push(
|
|
289
|
+
'',
|
|
290
|
+
'0. SESSION PREFLIGHT (first phase only). Read `.forge/cache/preflight-status.json`.',
|
|
291
|
+
' If the file is absent, run `node .forge/tools/forge-preflight.cjs` and read the JSON it writes.',
|
|
292
|
+
' If blob.ok === false in the result, HALT immediately — do NOT proceed to the gate or phase.',
|
|
293
|
+
' Set status escalated, and return gatePassed=false, escalated=true, verdict="none",',
|
|
294
|
+
' with the preflight warnings in note.',
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Gap #7: Gate exit-code distinction.
|
|
299
|
+
lines.push(
|
|
300
|
+
'',
|
|
301
|
+
'1. PRE-FLIGHT GATE. Run `node .forge/tools/preflight-gate.cjs --phase ' + phase.role + ' --task ' + taskId + '`.',
|
|
302
|
+
' Capture the exit code:',
|
|
303
|
+
' • exit_code == 0 → gate passed, continue.',
|
|
304
|
+
' • exit_code == 1 → gate failed (prerequisite missing). Set status escalated.',
|
|
305
|
+
' Return gatePassed=false, escalated=true, verdict="none", note: "gate_failed: <stderr>".',
|
|
306
|
+
' • exit_code == 2 → gate misconfigured (unknown phase or malformed block). Set status escalated.',
|
|
307
|
+
' Return gatePassed=false, escalated=true, verdict="none", note: "gate_misconfigured: <stderr>".',
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
// Gap #8: Persona/skill role-block injection.
|
|
311
|
+
lines.push(
|
|
312
|
+
'',
|
|
313
|
+
'1b. ROLE BLOCK INJECTION. Read `.forge/cache/persona-pack.json` and look up the entry for',
|
|
314
|
+
` noun="${personaNoun}" (role="${phase.role}" maps to this noun via ROLE_TO_NOUN).`,
|
|
315
|
+
' Prepend the compact persona+skill summary to your working context (reference mode).',
|
|
316
|
+
' If persona-pack.json is unavailable, read `.forge/personas/' + personaNoun + '.md` and',
|
|
317
|
+
' `.forge/skills/' + personaNoun + '-skills.md` directly (inline fallback).',
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
// Gap #9: build-overlay replaces raw MASTER_INDEX read.
|
|
321
|
+
lines.push(
|
|
322
|
+
'',
|
|
323
|
+
'2. PROJECT CONTEXT + RUN THE PHASE.',
|
|
324
|
+
' Run `node .forge/tools/build-overlay.cjs --task ' + taskId + ' --format md`',
|
|
325
|
+
' and inject its stdout as the Project Context block for this phase.',
|
|
326
|
+
' If build-overlay.cjs exits non-zero, fall back to reading `engineering/MASTER_INDEX.md`',
|
|
327
|
+
' (documented degradation path — not silent swallow).',
|
|
328
|
+
' Then read `.forge/workflows/' + phase.workflow + '` and follow it for task ' + taskId + '.',
|
|
329
|
+
' The workflow writes its own artifacts, {PHASE}-SUMMARY.json, and any task-status changes.',
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
// Gap #10: Review Loop Context — injected for review phases.
|
|
333
|
+
if (reviewLoopCtx) lines.push(reviewLoopCtx)
|
|
334
|
+
|
|
335
|
+
// Gap #3/emit: PHASE EVENTS.
|
|
336
|
+
// Gap #14: if an eventId was threaded in from the JS loop, instruct the subagent to use it
|
|
337
|
+
// for the COMPLETE event's eventId and for the --sidecar token file so mergeSidecar() matches.
|
|
338
|
+
const eventIdLine = eventId
|
|
339
|
+
? ' Use eventId="' + eventId + '" for the COMPLETE event (the driver will call merge-sidecar with this id).'
|
|
340
|
+
: ' Use a fresh crypto.randomUUID() for both start and complete event ids.'
|
|
341
|
+
lines.push(
|
|
342
|
+
'',
|
|
343
|
+
'3. EMIT YOUR PHASE EVENTS. You are the only actor that knows your runtime attribution.',
|
|
344
|
+
' 3a. BEFORE running the phase workflow: note the start timestamp (startTimestamp = new Date().toISOString()).',
|
|
345
|
+
' Emit a start event via `node .forge/tools/store-cli.cjs emit ' + sprintId + " '{event-json}'\`",
|
|
346
|
+
' with action="start", role="' + phase.role + '", iteration=' + iteration + ', startTimestamp and endTimestamp both equal to startTimestamp (0-duration placeholder).',
|
|
347
|
+
' 3b. AFTER the phase workflow completes: note the end timestamp (endTimestamp = new Date().toISOString()).',
|
|
348
|
+
' Compute durationMinutes = (new Date(endTimestamp) - new Date(startTimestamp)) / 60000.',
|
|
349
|
+
' Emit a complete event via `node .forge/tools/store-cli.cjs emit ' + sprintId + " '{event-json}'\`",
|
|
350
|
+
' conforming to `.forge/schemas/event.schema.json` (role, action="complete", phase, iteration=' + iteration + ',',
|
|
351
|
+
' startTimestamp, endTimestamp, durationMinutes, plus your own model/provider/token usage — do NOT invent placeholder model strings).',
|
|
352
|
+
' ' + eventIdLine,
|
|
353
|
+
' If `/cost` data is available, also write the token sidecar via the `--sidecar` form with the COMPLETE eventId. Best-effort; skip silently if unavailable.',
|
|
354
|
+
'',
|
|
355
|
+
' Gap #5 FRICTION DRAIN: After any failure event (malformed verdict, null dispatch, max-iter exhaustion),',
|
|
356
|
+
' drain any `.forge/cache/FRICTION-*.jsonl` files and emit each record as type "friction" with',
|
|
357
|
+
' `persona:"orchestrator"` and the appropriate issue token.',
|
|
358
|
+
' Also emit a type:friction event with persona="orchestrator" for any orchestrator-experienced failures.',
|
|
359
|
+
' Then drain any FRICTION-*.jsonl records you produced as phase subagent and emit them as type "friction".',
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
// Gap #4: Verdict or non-review.
|
|
363
|
+
lines.push(
|
|
364
|
+
'',
|
|
365
|
+
REVIEW_ROLES.includes(phase.role)
|
|
366
|
+
? '4. READ VERDICT. This is a REVIEW phase. The phase workflow records its verdict into the store '
|
|
367
|
+
+ 'summary (`summaries.' + phase.role + '.verdict`) via set-summary — make sure that write happened. '
|
|
368
|
+
+ 'Then resolve it with the canonical tool `node .forge/tools/read-verdict.cjs --phase ' + phase.role + ' --task ' + taskId + '` '
|
|
369
|
+
+ '(reads the structured summary, NOT a markdown artifact path). '
|
|
370
|
+
+ 'Route on the STDOUT token the tool prints (approved | revision | n/a | unknown), NOT on the exit code. '
|
|
371
|
+
+ 'Map STDOUT token → verdict: "approved"→"approved", "revision"→"revision", "n/a"→"malformed", "unknown"→"malformed". '
|
|
372
|
+
+ 'The exit code is unreliable (exits 1 for both revision AND missing/n/a). NEVER guess.'
|
|
373
|
+
: '4. NON-REVIEW phase: return verdict="none".',
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
lines.push(
|
|
377
|
+
'',
|
|
378
|
+
'5. Read `.forge/store/tasks/' + taskId + '.json` and return its final status as taskStatus, plus a one-line note.',
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
// Gap #11: simplified retry strips arch+summary block and adds strong directive.
|
|
382
|
+
if (simplified) {
|
|
383
|
+
lines.push(
|
|
384
|
+
'',
|
|
385
|
+
'IMPORTANT: You MUST produce a result. This is a retry after a failed dispatch.',
|
|
386
|
+
'Skip the architecture context block and the summary block. Proceed directly to the phase workflow.',
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return agent(
|
|
391
|
+
lines.join('\n'),
|
|
392
|
+
{ label: `${taskId}:${phase.role}:${iteration}`, phase: 'Pipeline', schema: PHASE_RESULT_SCHEMA, model: resolveModel(phase.role, phase) }
|
|
393
|
+
)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// --- emit task_skipped event (LOW #19) --------------------------------------
|
|
397
|
+
// When the pre-task status guard finds a SKIP_STATUS, the task is silently
|
|
398
|
+
// skipped. To give the event log a complete picture, emit a task-dispatch event
|
|
399
|
+
// with action:"skip" so downstream collators can account for every task.
|
|
400
|
+
// Pattern: mirrors escalateTask / mergeSidecar agent delegation (JS cannot shell out).
|
|
401
|
+
function emitSkip(taskId, sprintId, taskStatus) {
|
|
402
|
+
return agent(
|
|
403
|
+
[
|
|
404
|
+
`Emit a task_skipped event for Forge task ${taskId} (sprint ${sprintId}).`,
|
|
405
|
+
`node .forge/tools/store-cli.cjs emit ${sprintId}`,
|
|
406
|
+
`'{"type":"task-dispatch","action":"skip","taskId":"${taskId}","sprintId":"${sprintId}",`,
|
|
407
|
+
`"role":"orchestrator","phase":"pre-task","iteration":0,`,
|
|
408
|
+
`"notes":"pre-task SKIP_STATUS guard: task status is ${taskStatus}",`,
|
|
409
|
+
`"startTimestamp":"<ISO-now>","endTimestamp":"<ISO-now>","durationMinutes":0,`,
|
|
410
|
+
`"model":"<your-model-id>","provider":"anthropic"}'`,
|
|
411
|
+
'Replace <ISO-now> with the current UTC ISO 8601 timestamp and <your-model-id> with your actual model id.',
|
|
412
|
+
'Best-effort — if the emit fails, log and continue. Return "ok".',
|
|
413
|
+
].join(' '),
|
|
414
|
+
{ label: `skip-event:${taskId}`, phase: 'Resolve', model: resolveModel('commit', {}) }
|
|
415
|
+
)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// --- escalate from the JS driver (maxIterations exhaustion / null dispatch) --
|
|
419
|
+
// The script can't write the store, so a tiny agent performs the status write + event.
|
|
420
|
+
function escalateTask(taskId, sprintId, reason) {
|
|
421
|
+
return agent(
|
|
422
|
+
[
|
|
423
|
+
`Escalate Forge task ${taskId} to a human.`,
|
|
424
|
+
`run \`node .forge/tools/store-cli.cjs update-status task ${taskId} status escalated\``,
|
|
425
|
+
`and emit one event (sprint ${sprintId}) with verdict="escalated" and notes="${reason}".`,
|
|
426
|
+
`Return the task's final status as taskStatus, gatePassed=true, verdict="none", escalated=true, phase="escalate", role="escalate".`,
|
|
427
|
+
].join(' '),
|
|
428
|
+
{ label: `${taskId}:escalate`, phase: 'Pipeline', schema: PHASE_RESULT_SCHEMA, model: resolveModel('commit', {}) }
|
|
429
|
+
)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// --- emit subagent_retry event (Gap #11) ------------------------------------
|
|
433
|
+
// The JS driver cannot shell out; a tiny agent writes the event.
|
|
434
|
+
function emitRetryEvent(taskId, sprintId, role, iteration, reason) {
|
|
435
|
+
return agent(
|
|
436
|
+
[
|
|
437
|
+
`Emit a subagent_retry event for Forge task ${taskId} (sprint ${sprintId}).`,
|
|
438
|
+
`node .forge/tools/store-cli.cjs emit ${sprintId} '{"type":"task-implemented","action":"subagent_retry","role":"${role}","taskId":"${taskId}","phase":"${role}","iteration":${iteration},"notes":"${reason}"}'`,
|
|
439
|
+
`(fill in eventId, sprintId, startTimestamp, endTimestamp, durationMinutes=0, model, provider from runtime.)`,
|
|
440
|
+
`Return "ok".`,
|
|
441
|
+
].join(' '),
|
|
442
|
+
{ label: `${taskId}:retry-event:${iteration}`, phase: 'Pipeline', model: resolveModel('commit', {}) }
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// --- merge token sidecar (Gap #14) ------------------------------------------
|
|
447
|
+
// After each phase, call merge-sidecar to merge the phase subagent's token sidecar.
|
|
448
|
+
function mergeSidecar(sprintId, eventId) {
|
|
449
|
+
return agent(
|
|
450
|
+
[
|
|
451
|
+
`Merge the token sidecar for sprint ${sprintId}, eventId ${eventId}.`,
|
|
452
|
+
`node .forge/tools/store-cli.cjs merge-sidecar ${sprintId} ${eventId}`,
|
|
453
|
+
`Best-effort — if the sidecar file does not exist, skip silently. Return "ok".`,
|
|
454
|
+
].join(' '),
|
|
455
|
+
{ label: `merge-sidecar:${eventId}`, phase: 'Pipeline', model: resolveModel('commit', {}) }
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// --- Main -------------------------------------------------------------------
|
|
460
|
+
const taskId = (typeof args === 'string' ? args : args?.taskId)
|
|
461
|
+
if (!taskId) throw new Error('wfl:run-task requires a task id — pass args: "FORGE-S27-T01"')
|
|
462
|
+
|
|
463
|
+
// Phase 1 — Resolve the pipeline + pre-task status (agent does the store/config I/O).
|
|
464
|
+
phase('Resolve')
|
|
465
|
+
const resolved = await agent(
|
|
466
|
+
[
|
|
467
|
+
`Resolve the run-task pipeline for Forge task ${taskId}..`,
|
|
468
|
+
`Read \`node .forge/tools/store-cli.cjs read task ${taskId} --json\` for its current status and sprintId.`,
|
|
469
|
+
'Then resolve the phase pipeline EXACTLY as `.forge/workflows/orchestrate_task.md` § Pipeline Resolution prescribes:',
|
|
470
|
+
'if task.pipeline names a key in `.forge/config.json` pipelines, use those phases; otherwise use the default pipeline.',
|
|
471
|
+
// LOW #20: writeback added to hardcoded default pipeline (orchestrate_task.md §3 full default).
|
|
472
|
+
'The hardcoded default is: plan → review-plan → implement → review-code → validate → approve → writeback → commit,',
|
|
473
|
+
'mapping roles to workflow files: plan→plan_task.md, review-plan→review_plan.md, implement→implement_plan.md,',
|
|
474
|
+
'review-code→review_code.md, validate→validate_task.md, approve→architect_approve.md,',
|
|
475
|
+
'writeback→update_implementation.md, commit→commit_task.md.',
|
|
476
|
+
'maxIterations defaults to 3 for review roles (review-plan, review-code, validate) and 1 otherwise.',
|
|
477
|
+
'Return taskId, sprintId, taskStatus, and the ordered phases[]. Read-only — do NOT modify anything.',
|
|
478
|
+
].join(' '),
|
|
479
|
+
{ label: `resolve:${taskId}`, phase: 'Resolve', schema: RESOLVE_SCHEMA }
|
|
480
|
+
)
|
|
481
|
+
if (!resolved) throw new Error(`Could not resolve pipeline for task ${taskId}`)
|
|
482
|
+
|
|
483
|
+
const { sprintId, phases } = resolved
|
|
484
|
+
// Pre-task status guard — orchestrate_task skips already-terminal/blocked tasks.
|
|
485
|
+
// LOW #19: emit task_skipped event so the event log accounts for every task.
|
|
486
|
+
if (SKIP_STATUS.includes(resolved.taskStatus)) {
|
|
487
|
+
log(`⚠ ${taskId} — status is ${resolved.taskStatus}, nothing to run.`)
|
|
488
|
+
await emitSkip(taskId, sprintId, resolved.taskStatus)
|
|
489
|
+
return { taskId, sprintId, skipped: true, taskStatus: resolved.taskStatus, results: [] }
|
|
490
|
+
}
|
|
491
|
+
log(`Task ${taskId} (sprint ${sprintId}) — ${phases.length} phases: ${phases.map(p => p.role).join(' → ')}`)
|
|
492
|
+
|
|
493
|
+
// Phase 2 — drive the phase FSM. JS owns sequencing, counters, routing, escalation.
|
|
494
|
+
phase('Pipeline')
|
|
495
|
+
const iterationCounts = {} // keyed by phase command
|
|
496
|
+
const results = []
|
|
497
|
+
let i = 0
|
|
498
|
+
let escalated = false
|
|
499
|
+
let escalationReason = null
|
|
500
|
+
|
|
501
|
+
while (i < phases.length) {
|
|
502
|
+
const p = phases[i]
|
|
503
|
+
const iteration = (iterationCounts[p.command] || 0) + 1
|
|
504
|
+
const isFirstPhase = i === 0 && iteration === 1
|
|
505
|
+
// LOW #22: use BANNER_MAP for phase-announcement log identity.
|
|
506
|
+
const banner = BANNER_MAP[p.role] || p.role
|
|
507
|
+
log(`→ ${taskId} [${banner}] ${p.role} [${resolveModel(p.role, p) || 'inherit'}] (iteration ${iteration})`)
|
|
508
|
+
|
|
509
|
+
// Gap #11: Simplified-retry-prompt — detect empty/whitespace/timeout result.
|
|
510
|
+
// Emit subagent_retry event, then retry with simplified prompt.
|
|
511
|
+
// Gap #14: Compute eventId using _complete suffix (token usage lands on COMPLETE event,
|
|
512
|
+
// not start). Pass eventId into runPhase so subagent uses it for sidecar agreement.
|
|
513
|
+
// Determinism: eventId must NOT read the wall clock — new Date()/Date.now() throw in the
|
|
514
|
+
// workflow sandbox (breaks resume) and surface as a runtime throw because nested-by-name
|
|
515
|
+
// workflows aren't statically pre-scanned. A deterministic key unique per
|
|
516
|
+
// (sprint, task, role, iteration) is sufficient: controller and subagent only need to AGREE
|
|
517
|
+
// on the same string; event time-ordering comes from payload timestamps the subagent emits.
|
|
518
|
+
const eventId = `${sprintId}_${taskId}_${p.role}_iter${iteration}_complete`
|
|
519
|
+
let r = await runPhase(taskId, sprintId, p, iteration, { firstPhase: isFirstPhase, eventId })
|
|
520
|
+
const isEmpty = !r || (typeof r === 'string' && !r.trim())
|
|
521
|
+
if (isEmpty) {
|
|
522
|
+
// Emit subagent_retry event (best-effort, non-blocking).
|
|
523
|
+
await emitRetryEvent(taskId, sprintId, p.role, iteration, 'empty_or_null_dispatch')
|
|
524
|
+
log(`↺ ${taskId} ${p.role} — empty/null dispatch, retrying with simplified prompt`)
|
|
525
|
+
r = await runPhase(taskId, sprintId, p, iteration, { firstPhase: false, simplified: true, eventId })
|
|
526
|
+
}
|
|
527
|
+
if (!r) {
|
|
528
|
+
escalated = true
|
|
529
|
+
escalationReason = `phase ${p.role} dispatch returned null after retry`
|
|
530
|
+
log(`✗ ${taskId} ${p.role} — dispatch failed twice, escalating`)
|
|
531
|
+
break
|
|
532
|
+
}
|
|
533
|
+
// Gap #14: merge token sidecar after each phase.
|
|
534
|
+
await mergeSidecar(sprintId, eventId)
|
|
535
|
+
results.push(r)
|
|
536
|
+
|
|
537
|
+
// Gate failure or subagent self-escalation (already wrote status=escalated).
|
|
538
|
+
if (!r.gatePassed || r.escalated) {
|
|
539
|
+
escalated = true
|
|
540
|
+
escalationReason = r.note || `${p.role} gate failed / self-escalated`
|
|
541
|
+
log(`⚠ ${taskId} ${p.role} — escalated (${escalationReason})`)
|
|
542
|
+
break
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Review phases route on verdict; non-review phases advance on completion.
|
|
546
|
+
if (REVIEW_ROLES.includes(p.role)) {
|
|
547
|
+
if (r.verdict === 'approved') {
|
|
548
|
+
log(`✓ ${taskId} ${p.role} — Approved`)
|
|
549
|
+
i += 1
|
|
550
|
+
} else if (r.verdict === 'revision') {
|
|
551
|
+
iterationCounts[p.command] = (iterationCounts[p.command] || 0) + 1
|
|
552
|
+
log(`↻ ${taskId} ${p.role} — Revision Required (iteration ${iterationCounts[p.command]})`)
|
|
553
|
+
if (iterationCounts[p.command] >= p.maxIterations) {
|
|
554
|
+
escalated = true
|
|
555
|
+
escalationReason = `max iterations (${p.maxIterations}) reached at ${p.role}`
|
|
556
|
+
break
|
|
557
|
+
}
|
|
558
|
+
i = revisionTarget(phases, i) // loop back to the producing phase
|
|
559
|
+
} else {
|
|
560
|
+
// 'malformed' (or unexpected 'none' from a review phase) — never guess.
|
|
561
|
+
escalated = true
|
|
562
|
+
escalationReason = `verdict malformed at ${p.role}`
|
|
563
|
+
break
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
log(`✓ ${taskId} ${p.role} — completed`)
|
|
567
|
+
i += 1
|
|
568
|
+
}
|
|
569
|
+
// #22 PARITY SEAM — Post-phase exit guard (FORGE-S26-T19):
|
|
570
|
+
// forge-cli/run-task.ts owns hard enforcement: runPostflightGate() is called
|
|
571
|
+
// after runForgeSubagent returns and before currentPhaseIndex++ — if the
|
|
572
|
+
// outputs block is unsatisfied the FSM does not advance and runHaltAdvisor
|
|
573
|
+
// is invoked. This JS driver delegates post-phase output verification to
|
|
574
|
+
// each per-phase subagent (which receives postflight-gate.cjs via its phase
|
|
575
|
+
// prompt and is instructed to satisfy the outputs block before returning
|
|
576
|
+
// gatePassed=true in its StructuredOutput). The JS driver owns advance/halt
|
|
577
|
+
// on the returned `gatePassed` field already present in the StructuredOutput
|
|
578
|
+
// schema (see wfl-run-task.js lines above). No shell execution of
|
|
579
|
+
// postflight-gate.cjs in this JS driver (matches no-shell constraint, #21).
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// If the JS driver decided to escalate (not the subagent), perform the status write.
|
|
583
|
+
const lastWroteEscalation = results.length && results[results.length - 1].escalated
|
|
584
|
+
if (escalated && !lastWroteEscalation) {
|
|
585
|
+
await escalateTask(taskId, sprintId, escalationReason)
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Phase 3 — Report terminal outcome.
|
|
589
|
+
phase('Report')
|
|
590
|
+
const reachedEnd = !escalated && i >= phases.length
|
|
591
|
+
const finalStatus = reachedEnd ? 'committed' : 'escalated'
|
|
592
|
+
if (reachedEnd) {
|
|
593
|
+
log(`🌱 Task ${taskId} complete — pipeline reached terminal (committed).`)
|
|
594
|
+
} else {
|
|
595
|
+
log(`⚠ Task ${taskId} escalated: ${escalationReason}`)
|
|
596
|
+
log(` Resume with the failing phase command after addressing the issue, or re-run wfl:run-task.`)
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return {
|
|
600
|
+
taskId,
|
|
601
|
+
sprintId,
|
|
602
|
+
finalStatus,
|
|
603
|
+
escalated,
|
|
604
|
+
escalationReason,
|
|
605
|
+
phasesRun: results.length,
|
|
606
|
+
iterationCounts,
|
|
607
|
+
results,
|
|
608
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "forge/_defs/locator.schema.json",
|
|
4
|
+
"title": "ArtifactLocator",
|
|
5
|
+
"description": "Backend-agnostic artifact locator (ADR doc/decisions/artifact-resolution-abstraction.md, issue #111 Phase 3). Single-sourced under _defs/ and $ref'd from task/bug/sprint schemas. `record.path` remains the required back-compat alias during migration; `locator` is the forward-looking form so a non-fs backend (s3/cms/db) is a drop-in. `ref` is an opaque, backend-specific reference (a URI is a fine encoding): fs → 'engineering/sprints/<dir>/<task>/', s3 → 's3://bucket/key', cms → 'cms://collection/<id>', db → 'blob:<uuid>'.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["backend", "ref"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"backend": { "type": "string", "description": "Storage backend identifier — e.g. fs, s3, gcs, azure, cms, db." },
|
|
10
|
+
"ref": { "type": "string", "description": "Opaque backend-specific reference (URI-encodable)." }
|
|
11
|
+
},
|
|
12
|
+
"additionalProperties": false
|
|
13
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"severity": { "type": "string", "enum": ["critical", "major", "minor"] },
|
|
12
12
|
"status": { "type": "string", "enum": ["reported", "triaged", "in-progress", "fixed"] },
|
|
13
13
|
"path": { "type": "string" },
|
|
14
|
+
"locator": { "$ref": "_defs/locator.schema.json" },
|
|
14
15
|
"rootCauseCategory": {
|
|
15
16
|
"type": "string",
|
|
16
17
|
"enum": ["validation", "auth", "business-rule", "data-integrity", "race-condition", "integration", "configuration", "regression"]
|