@entelligentsia/forgecli 0.10.0 → 0.11.2
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 +95 -0
- package/README.md +21 -3
- package/dist/CHANGELOG-forge-plugin.md +90 -0
- package/dist/bin/config.js +6 -0
- package/dist/bin/config.js.map +1 -1
- package/dist/extensions/forgecli/add-pipeline.d.ts +19 -0
- package/dist/extensions/forgecli/add-pipeline.js +143 -0
- package/dist/extensions/forgecli/add-pipeline.js.map +1 -0
- package/dist/extensions/forgecli/add-task.d.ts +20 -0
- package/dist/extensions/forgecli/add-task.js +154 -0
- package/dist/extensions/forgecli/add-task.js.map +1 -0
- package/dist/extensions/forgecli/calibrate.d.ts +61 -0
- package/dist/extensions/forgecli/calibrate.js +488 -0
- package/dist/extensions/forgecli/calibrate.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.d.ts +9 -1
- package/dist/extensions/forgecli/fix-bug.js +155 -45
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-commands.js +15 -22
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +16 -1
- package/dist/extensions/forgecli/forge-subagent.js +45 -8
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-update-command.d.ts +9 -0
- package/dist/extensions/forgecli/forge-update-command.js +106 -7
- package/dist/extensions/forgecli/forge-update-command.js.map +1 -1
- package/dist/extensions/forgecli/health-check.d.ts +22 -1
- package/dist/extensions/forgecli/health-check.js +177 -4
- package/dist/extensions/forgecli/health-check.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.d.ts +25 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +104 -9
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/hooks/check-update.d.ts +81 -0
- package/dist/extensions/forgecli/hooks/check-update.js +308 -0
- package/dist/extensions/forgecli/hooks/check-update.js.map +1 -0
- package/dist/extensions/forgecli/hooks/forge-permissions.d.ts +32 -0
- package/dist/extensions/forgecli/hooks/forge-permissions.js +119 -0
- package/dist/extensions/forgecli/hooks/forge-permissions.js.map +1 -0
- package/dist/extensions/forgecli/hooks/triage-error.d.ts +23 -0
- package/dist/extensions/forgecli/hooks/triage-error.js +62 -0
- package/dist/extensions/forgecli/hooks/triage-error.js.map +1 -0
- package/dist/extensions/forgecli/hooks/write-guard.d.ts +28 -0
- package/dist/extensions/forgecli/hooks/write-guard.js +225 -0
- package/dist/extensions/forgecli/hooks/write-guard.js.map +1 -0
- package/dist/extensions/forgecli/index.js +60 -0
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/init-context.d.ts +1 -1
- package/dist/extensions/forgecli/init-context.js +21 -6
- package/dist/extensions/forgecli/init-context.js.map +1 -1
- package/dist/extensions/forgecli/materialize.d.ts +16 -0
- package/dist/extensions/forgecli/materialize.js +195 -0
- package/dist/extensions/forgecli/materialize.js.map +1 -0
- package/dist/extensions/forgecli/migrate.d.ts +19 -0
- package/dist/extensions/forgecli/migrate.js +258 -0
- package/dist/extensions/forgecli/migrate.js.map +1 -0
- package/dist/extensions/forgecli/migration-engine.d.ts +111 -0
- package/dist/extensions/forgecli/migration-engine.js +533 -0
- package/dist/extensions/forgecli/migration-engine.js.map +1 -0
- package/dist/extensions/forgecli/quiz-agent.d.ts +17 -0
- package/dist/extensions/forgecli/quiz-agent.js +98 -0
- package/dist/extensions/forgecli/quiz-agent.js.map +1 -0
- package/dist/extensions/forgecli/remove-command.d.ts +17 -0
- package/dist/extensions/forgecli/remove-command.js +124 -0
- package/dist/extensions/forgecli/remove-command.js.map +1 -0
- package/dist/extensions/forgecli/report-bug.d.ts +25 -0
- package/dist/extensions/forgecli/report-bug.js +159 -0
- package/dist/extensions/forgecli/report-bug.js.map +1 -0
- package/dist/extensions/forgecli/retrospective.d.ts +19 -0
- package/dist/extensions/forgecli/retrospective.js +156 -0
- package/dist/extensions/forgecli/retrospective.js.map +1 -0
- package/dist/extensions/forgecli/run-sprint.js +36 -3
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.d.ts +9 -1
- package/dist/extensions/forgecli/run-task.js +66 -13
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/session-registry.d.ts +40 -2
- package/dist/extensions/forgecli/session-registry.js +71 -1
- package/dist/extensions/forgecli/session-registry.js.map +1 -1
- package/dist/extensions/forgecli/status-command.d.ts +19 -0
- package/dist/extensions/forgecli/status-command.js +140 -0
- package/dist/extensions/forgecli/status-command.js.map +1 -0
- package/dist/extensions/forgecli/store-query.d.ts +22 -0
- package/dist/extensions/forgecli/store-query.js +107 -0
- package/dist/extensions/forgecli/store-query.js.map +1 -0
- package/dist/extensions/forgecli/store-repair.d.ts +17 -0
- package/dist/extensions/forgecli/store-repair.js +123 -0
- package/dist/extensions/forgecli/store-repair.js.map +1 -0
- package/dist/extensions/forgecli/test-orchestrate.js +1 -0
- package/dist/extensions/forgecli/test-orchestrate.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +286 -41
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/transition-guard.js +7 -2
- package/dist/extensions/forgecli/transition-guard.js.map +1 -1
- package/dist/extensions/forgecli/update-tools.d.ts +23 -0
- package/dist/extensions/forgecli/update-tools.js +136 -0
- package/dist/extensions/forgecli/update-tools.js.map +1 -0
- package/dist/extensions/forgecli/viewport-events.js +10 -0
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/extensions/forgecli/viewport-renderer.d.ts +18 -0
- package/dist/extensions/forgecli/viewport-renderer.js +27 -0
- package/dist/extensions/forgecli/viewport-renderer.js.map +1 -1
- package/dist/extensions/forgecli/viewport-theme.js +4 -0
- package/dist/extensions/forgecli/viewport-theme.js.map +1 -1
- package/dist/extensions/forgecli/whats-new-widget.d.ts +13 -8
- package/dist/extensions/forgecli/whats-new-widget.js +111 -42
- package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
- package/dist/forge-payload/.base-pack/workflows/architect_approve.md +29 -3
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +15 -8
- package/dist/forge-payload/.base-pack/workflows/fix_bug.md +327 -185
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +18 -10
- package/dist/forge-payload/.base-pack/workflows/plan_task.md +15 -9
- package/dist/forge-payload/.base-pack/workflows/review_code.md +14 -6
- package/dist/forge-payload/.base-pack/workflows/review_plan.md +18 -10
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/bug.schema.json +3 -2
- package/dist/forge-payload/.schemas/config.schema.json +83 -0
- package/dist/forge-payload/.schemas/migrations.json +2049 -0
- package/dist/forge-payload/commands/regenerate.md +17 -1
- package/dist/forge-payload/meta/personas/README.md +16 -0
- package/dist/forge-payload/meta/personas/meta-architect.md +70 -0
- package/dist/forge-payload/meta/personas/meta-bug-fixer.md +73 -0
- package/dist/forge-payload/meta/personas/meta-collator.md +72 -0
- package/dist/forge-payload/meta/personas/meta-engineer.md +70 -0
- package/dist/forge-payload/meta/personas/meta-orchestrator.md +71 -0
- package/dist/forge-payload/meta/personas/meta-product-manager.md +82 -0
- package/dist/forge-payload/meta/personas/meta-qa-engineer.md +91 -0
- package/dist/forge-payload/meta/personas/meta-supervisor.md +92 -0
- package/dist/forge-payload/meta/skill-recommendations.md +154 -0
- package/dist/forge-payload/meta/skills/meta-architect-skills.md +43 -0
- package/dist/forge-payload/meta/skills/meta-bug-fixer-skills.md +43 -0
- package/dist/forge-payload/meta/skills/meta-collator-skills.md +41 -0
- package/dist/forge-payload/meta/skills/meta-engineer-skills.md +43 -0
- package/dist/forge-payload/meta/skills/meta-generic-skills.md +58 -0
- package/dist/forge-payload/meta/skills/meta-qa-engineer-skills.md +46 -0
- package/dist/forge-payload/meta/skills/meta-supervisor-skills.md +43 -0
- package/dist/forge-payload/meta/store-schema/bug.schema.md +71 -0
- package/dist/forge-payload/meta/store-schema/event.schema.md +76 -0
- package/dist/forge-payload/meta/store-schema/feature.schema.md +65 -0
- package/dist/forge-payload/meta/store-schema/sprint.schema.md +64 -0
- package/dist/forge-payload/meta/store-schema/task.schema.md +78 -0
- package/dist/forge-payload/meta/templates/meta-code-review.md +26 -0
- package/dist/forge-payload/meta/templates/meta-plan-review.md +28 -0
- package/dist/forge-payload/meta/templates/meta-plan.md +28 -0
- package/dist/forge-payload/meta/templates/meta-progress.md +25 -0
- package/dist/forge-payload/meta/templates/meta-retrospective.md +28 -0
- package/dist/forge-payload/meta/templates/meta-sprint-manifest.md +26 -0
- package/dist/forge-payload/meta/templates/meta-sprint-requirements.md +91 -0
- package/dist/forge-payload/meta/templates/meta-task-prompt.md +26 -0
- package/dist/forge-payload/meta/tool-specs/collate.spec.md +88 -0
- package/dist/forge-payload/meta/tool-specs/generation-manifest.spec.md +139 -0
- package/dist/forge-payload/meta/tool-specs/manage-config.spec.md +143 -0
- package/dist/forge-payload/meta/tool-specs/seed-store.spec.md +91 -0
- package/dist/forge-payload/meta/tool-specs/store-cli.spec.md +328 -0
- package/dist/forge-payload/meta/tool-specs/validate-store.spec.md +191 -0
- package/dist/forge-payload/meta/workflows/_fragments/context-injection.md +75 -0
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +73 -0
- package/dist/forge-payload/meta/workflows/_fragments/finalize.md +13 -0
- package/dist/forge-payload/meta/workflows/_fragments/friction-emit.md +73 -0
- package/dist/forge-payload/meta/workflows/_fragments/progress-reporting.md +38 -0
- package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +39 -0
- package/dist/forge-payload/meta/workflows/meta-approve.md +119 -0
- package/dist/forge-payload/meta/workflows/meta-collate.md +89 -0
- package/dist/forge-payload/meta/workflows/meta-commit.md +93 -0
- package/dist/forge-payload/meta/workflows/meta-enhance.md +286 -0
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +501 -0
- package/dist/forge-payload/meta/workflows/meta-implement.md +132 -0
- package/dist/forge-payload/meta/workflows/meta-migrate.md +455 -0
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +993 -0
- package/dist/forge-payload/meta/workflows/meta-plan-task.md +133 -0
- package/dist/forge-payload/meta/workflows/meta-quiz-agent.md +135 -0
- package/dist/forge-payload/meta/workflows/meta-retrospective.md +65 -0
- package/dist/forge-payload/meta/workflows/meta-review-implementation.md +119 -0
- package/dist/forge-payload/meta/workflows/meta-review-plan.md +108 -0
- package/dist/forge-payload/meta/workflows/meta-review-sprint-completion.md +65 -0
- package/dist/forge-payload/meta/workflows/meta-sprint-intake.md +76 -0
- package/dist/forge-payload/meta/workflows/meta-sprint-plan.md +147 -0
- package/dist/forge-payload/meta/workflows/meta-update-implementation.md +76 -0
- package/dist/forge-payload/meta/workflows/meta-update-plan.md +76 -0
- package/dist/forge-payload/meta/workflows/meta-validate.md +111 -0
- package/dist/forge-payload/tools/check-structure.cjs +344 -0
- package/dist/forge-payload/tools/collate.cjs +34 -9
- package/dist/forge-payload/tools/list-skills.js +76 -0
- package/dist/forge-payload/tools/parse-gates.cjs +8 -2
- package/dist/forge-payload/tools/store-cli.cjs +56 -11
- package/dist/forge-payload/tools/store.cjs +61 -0
- package/dist/forge-payload/tools/substitute-placeholders.cjs +60 -8
- package/dist/forge-payload/tools/validate-store.cjs +6 -2
- package/dist/forge-payload/tools/verify-integrity.cjs +86 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-orchestrate.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/test-orchestrate.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,EAAE;AACF,iFAAiF;AACjF,8EAA8E;AAC9E,iEAAiE;AACjE,EAAE;AACF,SAAS;AACT,+BAA+B;AAC/B,8CAA8C;AAC9C,EAAE;AACF,kEAAkE;AAClE,4EAA4E;AAE5E,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EAEN,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAEtC,MAAM,eAAe,GAAiB;IACrC,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,iDAAiD;IAC9D,YAAY,EAAE;QACb,qEAAqE;QACrE,4FAA4F;QAC5F,sEAAsE;QACtE,0FAA0F;KAC1F,CAAC,IAAI,CAAC,GAAG,CAAC;IACX,QAAQ,EAAE,UAAU;CACpB,CAAC;AASF,SAAS,SAAS,CAAC,IAAY,EAAE,GAAW;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;IAClE,CAAC;IAED,yCAAyC;IACzC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;IAC9D,CAAC;IAED,0BAA0B;IAC1B,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAClE,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,OAAO,GAAG,gBAAgB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IACrD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,EAAgB;IACvD,EAAE,CAAC,eAAe,CAAC,kBAAkB,EAAE;QACtC,WAAW,EACV,oEAAoE;YACpE,6EAA6E;QAC9E,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,GAA4B;YACvD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAC1B,IAAI,MAAkB,CAAC;YACvB,IAAI,CAAC;gBACJ,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/B,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACvB,MAAM,CAAC,GAAG,GAA2B,CAAC;gBACtC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,OAAO,IAAI,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC;gBACnF,OAAO;YACR,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBACzB,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,iHAAiH,EACjH,OAAO,CACP,CAAC;gBACF,OAAO;YACR,CAAC;YAED,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;YACjC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,aAAa,MAAM,CAAC,OAAO,CAAC,IAAI,YAAY,CAAC,CAAC;YAE7E,6DAA6D;YAC7D,MAAM,QAAQ,GAAG,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,EAAE,CAAC,CAAC,gCAAgC;YACxD,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,IAAI,IAAI,GAAG,CAAC,CAAC;YACb,IAAI,YAAY,GAAG,EAAE,CAAC;YACtB,IAAI,UAAU,GAAG,EAAE,CAAC,CAAC,oDAAoD;YAEzE,MAAM,aAAa,GAAG,GAAG,EAAE;gBAC1B,MAAM,MAAM,GAAG,cAAc,MAAM,CAAC,OAAO,CAAC,IAAI,WAAW,IAAI,EAAE,CAAC;gBAClE,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACjD,IAAI,UAAU,EAAE,CAAC;oBAChB,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;oBACtE,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;gBAC7B,CAAC;gBACD,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACvC,CAAC,CAAC;YAEF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;gBAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChB,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,CAAC;oBAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;gBACvE,aAAa,EAAE,CAAC;YACjB,CAAC,CAAC;YAEF,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;oBACrC,OAAO,EAAE,MAAM,CAAC,OAAO;oBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,GAAG;oBACH,MAAM,EAAE,EAAE,CAAC,MAAM;oBACjB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;wBAClB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;4BACpB,KAAK,aAAa;gCACjB,IAAI,CAAC,eAAe,CAAC,CAAC;gCACtB,MAAM;4BACP,KAAK,eAAe;gCACnB,UAAU,GAAG,EAAE,CAAC;gCAChB,IAAI,CAAC,iBAAiB,CAAC,CAAC;gCACxB,MAAM;4BACP,KAAK,gBAAgB,CAAC,CAAC,CAAC;gCACvB,MAAM,GAAG,GAAG,KAAK,CAAC,qBAAqB,CAAC;gCACxC,IAAI,GAAG,EAAE,IAAI,KAAK,YAAY,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oCACjE,UAAU,IAAI,GAAG,CAAC,KAAK,CAAC;oCACxB,aAAa,EAAE,CAAC;gCACjB,CAAC;qCAAM,IAAI,GAAG,EAAE,IAAI,KAAK,gBAAgB,EAAE,CAAC;oCAC3C,IAAI,CAAC,cAAc,CAAC,CAAC;gCACtB,CAAC;gCACD,MAAM;4BACP,CAAC;4BACD,KAAK,sBAAsB;gCAC1B,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC;gCAC9B,IAAI,CAAC,kBAAkB,YAAY,EAAE,CAAC,CAAC;gCACvC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CACjB,UAAU,EACV,aAAa,MAAM,CAAC,OAAO,CAAC,IAAI,WAAW,IAAI,YAAY,YAAY,EAAE,CACzE,CAAC;gCACF,MAAM;4BACP,KAAK,uBAAuB;gCAC3B,aAAa,EAAE,CAAC;gCAChB,MAAM;4BACP,KAAK,oBAAoB,CAAC,CAAC,CAAC;gCAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gCAC1C,IAAI,CAAC,GAAG,OAAO,eAAe,YAAY,EAAE,CAAC,CAAC;gCAC9C,MAAM;4BACP,CAAC;4BACD,KAAK,aAAa;gCACjB,IAAI,CAAC,eAAe,CAAC,CAAC;gCACtB,MAAM;4BACP,KAAK,UAAU,CAAC,CAAC,CAAC;gCACjB,IAAI,EAAE,CAAC;gCACP,MAAM,CAAC,GAAI,KAAK,CAAC,OAAkG,EAAE,KAAK,CAAC;gCAC3H,MAAM,QAAQ,GAAG,CAAC;oCACjB,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE;wCACxC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oCACtD,CAAC,CAAC,EAAE,CAAC;gCACN,IAAI,CAAC,WAAW,IAAI,GAAG,QAAQ,KAAK,CAAC,CAAC;gCACtC,UAAU,GAAG,EAAE,CAAC;gCAChB,MAAM;4BACP,CAAC;4BACD,KAAK,WAAW;gCACf,IAAI,CAAC,aAAa,CAAC,CAAC;gCACpB,MAAM;wBACR,CAAC;oBACF,CAAC;iBACD,CAAC,CAAC;gBAEH,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBAC1C,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBAE1C,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;oBAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,yCAAyC,MAAM,CAAC,QAAQ,EAAE;wBACzD,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACvD,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EACrD,OAAO,CACP,CAAC;oBACF,OAAO;gBACR,CAAC;gBAED,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACpD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC3B,MAAM,OAAO,GAAG;oBACf,yBAAyB,MAAM,CAAC,OAAO,CAAC,IAAI,QAAQ;oBACpD,UAAU,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,SAAS,MAAM,KAAK,CAAC,UAAU,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;oBAChI,UAAU,MAAM,CAAC,KAAK,IAAI,SAAS,EAAE;oBACrC,EAAE;oBACF,cAAc;oBACd,WAAW,IAAI,8BAA8B;iBAC7C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEb,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACvB,MAAM,CAAC,GAAG,GAA2B,CAAC;gBACtC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBAC1C,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBAC1C,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC,OAAO,IAAI,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;YAC1F,CAAC;QACF,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"test-orchestrate.js","sourceRoot":"","sources":["../../../src/extensions/forgecli/test-orchestrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
42
42
|
import { getInputRouter } from "./input-router.js";
|
|
43
43
|
import { getSessionRegistry } from "./session-registry.js";
|
|
44
|
-
import { fmtTokenFooter } from "./viewport-renderer.js";
|
|
44
|
+
import { fmtModelAndTokenFooter, fmtModelLabel, fmtTokenFooter } from "./viewport-renderer.js";
|
|
45
45
|
import { paintFooterLine, paintTailLine } from "./viewport-theme.js";
|
|
46
46
|
const WIDGET_KEY = "forge:thread-switcher";
|
|
47
47
|
const FOOTER_WIDGET_KEY = "forge:viewport-footer";
|
|
@@ -73,7 +73,7 @@ class TailViewComponent {
|
|
|
73
73
|
const lines = this.registry.getTailLines(this.taskId, this.phaseRole);
|
|
74
74
|
const session = this.registry.getSession(this.taskId);
|
|
75
75
|
const phase = session?.phases.find((p) => p.role === this.phaseRole);
|
|
76
|
-
const footerText =
|
|
76
|
+
const footerText = fmtModelAndTokenFooter(phase ? { provider: phase.provider, model: phase.model } : undefined, phase?.usage);
|
|
77
77
|
const bodyLines = lines.length === 0
|
|
78
78
|
? [truncateToWidth(`(no output yet for ${this.phaseRole})`, width)]
|
|
79
79
|
: lines.map((line) => {
|
|
@@ -105,10 +105,20 @@ class TailViewComponent {
|
|
|
105
105
|
class ViewportFooterComponent {
|
|
106
106
|
registry;
|
|
107
107
|
theme;
|
|
108
|
+
getOrchestratorModel;
|
|
108
109
|
invalidationCb;
|
|
109
|
-
constructor(registry, theme
|
|
110
|
+
constructor(registry, theme,
|
|
111
|
+
/**
|
|
112
|
+
* Returns the parent pi session's current (provider, model) — the
|
|
113
|
+
* "outer orchestrator" model. Caller closes over ExtensionContext
|
|
114
|
+
* and is responsible for guarding stale-ctx access; return undefined
|
|
115
|
+
* on failure or when no model is set. When undefined, the footer
|
|
116
|
+
* just shows `Σ ↑X ↓Y`.
|
|
117
|
+
*/
|
|
118
|
+
getOrchestratorModel) {
|
|
110
119
|
this.registry = registry;
|
|
111
120
|
this.theme = theme;
|
|
121
|
+
this.getOrchestratorModel = getOrchestratorModel;
|
|
112
122
|
const onChange = () => this.invalidationCb?.();
|
|
113
123
|
registry.on("change", onChange);
|
|
114
124
|
registry.on("tail", onChange);
|
|
@@ -120,10 +130,22 @@ class ViewportFooterComponent {
|
|
|
120
130
|
};
|
|
121
131
|
}
|
|
122
132
|
render(width) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
// Only show the footer when an orchestrator session is active.
|
|
134
|
+
// When all sessions are terminal (completed/failed/cancelled) or
|
|
135
|
+
// when no session exists, hide the footer — main viewport has no
|
|
136
|
+
// subagent aggregate to display.
|
|
137
|
+
const sessions = this.registry.listSessions();
|
|
138
|
+
const hasActive = sessions.some((s) => s.status === "running" || s.status === "cancelling");
|
|
139
|
+
if (!hasActive)
|
|
140
|
+
return [];
|
|
141
|
+
const tokens = fmtTokenFooter(this.registry.getAggregateUsage());
|
|
142
|
+
const orchModel = fmtModelLabel(this.getOrchestratorModel?.());
|
|
143
|
+
if (!tokens && !orchModel)
|
|
144
|
+
return [];
|
|
145
|
+
const left = orchModel ? `⌂ ${orchModel}` : "";
|
|
146
|
+
const right = tokens ? `Σ ${tokens}` : "";
|
|
147
|
+
const text = left && right ? `${left} ${right}` : (left || right);
|
|
148
|
+
return [paintFooterLine(text, width, this.theme)];
|
|
127
149
|
}
|
|
128
150
|
invalidate() {
|
|
129
151
|
// Re-render driven by external invalidationCb → tui.requestRender().
|
|
@@ -143,6 +165,9 @@ class ChipStripComponent {
|
|
|
143
165
|
focusedChipId = "main";
|
|
144
166
|
stripActive = false;
|
|
145
167
|
invalidationCb;
|
|
168
|
+
/** When non-null, the strip shows a cancellation confirmation prompt
|
|
169
|
+
* for this chip instead of the normal chip view. */
|
|
170
|
+
cancelTarget = null;
|
|
146
171
|
constructor(registry, theme) {
|
|
147
172
|
this.registry = registry;
|
|
148
173
|
this.theme = theme;
|
|
@@ -213,11 +238,20 @@ class ChipStripComponent {
|
|
|
213
238
|
chipGlyph(chip) {
|
|
214
239
|
if (chip.id === "main")
|
|
215
240
|
return this.focusedChipId === "main" ? "●" : "○";
|
|
241
|
+
const session = this.activeSession();
|
|
216
242
|
const p = this.chipPhase(chip);
|
|
217
243
|
if (!p)
|
|
218
244
|
return "·";
|
|
219
245
|
if (this.focusedChipId === chip.id)
|
|
220
246
|
return "●";
|
|
247
|
+
// Cancelling/cancelled glyphs are session-level, not phase-level.
|
|
248
|
+
// Show ⏳ for any phase when the session is cancelling, ⊘ when cancelled.
|
|
249
|
+
if (session?.status === "cancelled" && p.status !== "completed" && p.status !== "failed")
|
|
250
|
+
return "⊘";
|
|
251
|
+
if (session?.status === "cancelling" && p.status === "running")
|
|
252
|
+
return "⏳";
|
|
253
|
+
if (p.status === "cancelled")
|
|
254
|
+
return "⊘";
|
|
221
255
|
if (p.status === "completed")
|
|
222
256
|
return "✓";
|
|
223
257
|
if (p.status === "failed")
|
|
@@ -236,7 +270,7 @@ class ChipStripComponent {
|
|
|
236
270
|
return session.phases[session.phases.length - 1]?.role;
|
|
237
271
|
}
|
|
238
272
|
spinnerFrame(session) {
|
|
239
|
-
if (session.status !== "running")
|
|
273
|
+
if (session.status !== "running" && session.status !== "cancelling")
|
|
240
274
|
return "";
|
|
241
275
|
const idx = Math.floor(Date.now() / SPINNER_INTERVAL_MS) % SPINNER_FRAMES.length;
|
|
242
276
|
return SPINNER_FRAMES[idx];
|
|
@@ -245,6 +279,10 @@ class ChipStripComponent {
|
|
|
245
279
|
const session = this.activeSession();
|
|
246
280
|
if (!session)
|
|
247
281
|
return []; // UX-B: hide entirely when no session.
|
|
282
|
+
// If user is confirming cancellation, show the confirmation prompt.
|
|
283
|
+
if (this.cancelTarget) {
|
|
284
|
+
return this.renderCancelPrompt(width, this.cancelTarget);
|
|
285
|
+
}
|
|
248
286
|
const chips = this.chips();
|
|
249
287
|
// Clamp cursor.
|
|
250
288
|
if (this.cursorIdx >= chips.length)
|
|
@@ -256,29 +294,47 @@ class ChipStripComponent {
|
|
|
256
294
|
renderInactive(width, session) {
|
|
257
295
|
const dim = (s) => this.theme.fg("dim", s);
|
|
258
296
|
const accent = (s) => this.theme.fg("accent", s);
|
|
259
|
-
const spin = this.spinnerFrame(session);
|
|
260
297
|
const chips = this.chips();
|
|
261
|
-
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
// This makes phase progression visible at a glance without expanding
|
|
265
|
-
// the strip.
|
|
298
|
+
const spin = this.spinnerFrame(session);
|
|
299
|
+
// Orchestrator chip: bracketed + accent-colored (anchor identity).
|
|
300
|
+
// Subagent chips: <glyph> <role>, dimmed.
|
|
266
301
|
const orchChip = accent(`[${session.taskId}]`);
|
|
267
302
|
const phaseChips = chips
|
|
268
303
|
.filter((c) => c.id !== "main")
|
|
269
304
|
.map((c) => dim(`${this.chipGlyph(c)} ${c.label}`));
|
|
270
305
|
const chipsLine = [orchChip, ...phaseChips].join(" ");
|
|
271
|
-
|
|
272
|
-
|
|
306
|
+
// Right-side: status · spinner · command hints.
|
|
307
|
+
// Cancelled sessions show "r resume" affordance; all others show "↓ to navigate".
|
|
308
|
+
const statusLabel = session.status === "cancelled" ? "cancelled"
|
|
309
|
+
: session.status === "cancelling" ? "cancelling…"
|
|
310
|
+
: "";
|
|
311
|
+
const statusPart = statusLabel ? dim(` ${statusLabel}`) : "";
|
|
273
312
|
const spinPart = spin ? ` ${spin}` : "";
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
313
|
+
const hint = session.status === "cancelled"
|
|
314
|
+
? dim(" ↓ nav · r resume")
|
|
315
|
+
: dim(" ↓ to navigate");
|
|
316
|
+
// Truncate preview text from the MIDDLE of the line to keep chips and hints visible.
|
|
317
|
+
const previewText = session.currentTurnPreview ? `"${session.currentTurnPreview}"` : "";
|
|
318
|
+
// Priority: chips + status + spinner + hint are fixed.
|
|
319
|
+
// Truncate preview first, then truncate from the right as fallback.
|
|
320
|
+
const fixedRight = visibleWidth(statusPart) + visibleWidth(spinPart) + visibleWidth(hint);
|
|
321
|
+
const previewBudget = Math.max(0, width - fixedRight - 4); // 4 = safety margin
|
|
322
|
+
let preview = "";
|
|
323
|
+
if (previewText) {
|
|
324
|
+
// Truncate the preview text itself to fit the budget
|
|
325
|
+
const truncated = truncateToWidth(previewText, previewBudget);
|
|
326
|
+
if (visibleWidth(truncated) > 0)
|
|
327
|
+
preview = dim(` ${truncated}`);
|
|
328
|
+
}
|
|
329
|
+
// Build line; truncate from the right (preview tail) if still over-width.
|
|
330
|
+
let line = `${chipsLine}${statusPart}${spinPart}${preview}${hint}`;
|
|
331
|
+
if (visibleWidth(line) > width) {
|
|
332
|
+
// Truncate preview tail first (not chips)
|
|
333
|
+
const budget = Math.max(0, width - visibleWidth(chipsLine) - fixedRight);
|
|
334
|
+
const previewOnly = truncateToWidth(previewText, budget);
|
|
335
|
+
preview = previewOnly ? dim(` ${previewOnly}`) : "";
|
|
336
|
+
line = `${chipsLine}${statusPart}${spinPart}${preview}${hint}`;
|
|
337
|
+
}
|
|
282
338
|
if (visibleWidth(line) > width)
|
|
283
339
|
line = truncateToWidth(line, width);
|
|
284
340
|
return [line];
|
|
@@ -298,8 +354,18 @@ class ChipStripComponent {
|
|
|
298
354
|
return bold(inner);
|
|
299
355
|
return dim(inner);
|
|
300
356
|
});
|
|
301
|
-
const prefix =
|
|
302
|
-
|
|
357
|
+
const prefix = "";
|
|
358
|
+
// "r resume" shown only for cancelled sessions; "x cancel" for running ones.
|
|
359
|
+
const cancelWord = session.status === "cancelled" ? dim("r resume") : dim("x cancel");
|
|
360
|
+
const navHints = dim(" ←→ · enter · ↑ back · esc back+main");
|
|
361
|
+
// Show status-based text for non-running sessions
|
|
362
|
+
let statusPart = "";
|
|
363
|
+
if (session.status === "cancelling") {
|
|
364
|
+
statusPart = " cancelling…";
|
|
365
|
+
}
|
|
366
|
+
else if (session.status === "cancelled") {
|
|
367
|
+
statusPart = " cancelled";
|
|
368
|
+
}
|
|
303
369
|
const spin = this.spinnerFrame(session);
|
|
304
370
|
const spinPart = spin ? ` ${spin}` : "";
|
|
305
371
|
const previewText = session.currentTurnPreview ? ` "${session.currentTurnPreview}"` : "";
|
|
@@ -308,15 +374,44 @@ class ChipStripComponent {
|
|
|
308
374
|
const fixed = visibleWidth(prefix) +
|
|
309
375
|
visibleWidth(chipsJoined) +
|
|
310
376
|
visibleWidth(spinPart) +
|
|
311
|
-
visibleWidth(
|
|
377
|
+
visibleWidth(statusPart) +
|
|
378
|
+
visibleWidth(cancelWord) +
|
|
379
|
+
visibleWidth(navHints);
|
|
312
380
|
const previewBudget = Math.max(0, width - fixed);
|
|
313
381
|
const preview = previewText ? dim(truncateToWidth(previewText, previewBudget)) : "";
|
|
314
|
-
let line = `${prefix}${chipsJoined}${spinPart}${preview}${
|
|
382
|
+
let line = `${prefix}${chipsJoined}${spinPart}${statusPart}${preview} ${cancelWord} ${navHints}`;
|
|
315
383
|
// Hard cap as last-resort defence (visibleWidth is best-effort).
|
|
316
384
|
if (visibleWidth(line) > width)
|
|
317
385
|
line = truncateToWidth(line, width);
|
|
318
386
|
return [line];
|
|
319
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Render the cancellation confirmation prompt. Replaces the normal
|
|
390
|
+
* chip strip when cancelTarget is non-null.
|
|
391
|
+
* ⚠ Cancel [taskId] → [phaseRole]? y/n · esc to abort
|
|
392
|
+
*/
|
|
393
|
+
renderCancelPrompt(width, target) {
|
|
394
|
+
const dim = (s) => this.theme.fg("dim", s);
|
|
395
|
+
const warning = (s) => this.theme.fg("warning", s);
|
|
396
|
+
const bold = (s) => this.theme.bold(s);
|
|
397
|
+
const taskLabel = target.taskId ?? target.label;
|
|
398
|
+
const phaseLabel = target.id === "main" ? "session" : target.label;
|
|
399
|
+
// "cancel" sits right after the prompt — most visible position.
|
|
400
|
+
// Truncation sacrifices the dim dismiss-hints from the END, keeping
|
|
401
|
+
// the action word and the warning always readable.
|
|
402
|
+
const actionWord = dim("cancel");
|
|
403
|
+
const hints = dim(" · n/esc dismiss · y confirm");
|
|
404
|
+
const prompt = warning(`⚠ Cancel ${bold(taskLabel)} → ${bold(phaseLabel)}? `);
|
|
405
|
+
const budget = Math.max(0, width - visibleWidth(prompt) - visibleWidth(actionWord));
|
|
406
|
+
const tail = budget > 0 ? dim(` · n/esc dismiss · y confirm`) : "";
|
|
407
|
+
const budgetedTail = visibleWidth(tail) > budget
|
|
408
|
+
? dim(truncateToWidth(` · n/esc dismiss · y confirm`, budget))
|
|
409
|
+
: tail;
|
|
410
|
+
let line = `${prompt}${actionWord}${budgetedTail}`;
|
|
411
|
+
if (visibleWidth(line) > width)
|
|
412
|
+
line = truncateToWidth(line, width);
|
|
413
|
+
return [line];
|
|
414
|
+
}
|
|
320
415
|
invalidate() {
|
|
321
416
|
// Re-render driven by external invalidationCb → tui.requestRender().
|
|
322
417
|
}
|
|
@@ -328,6 +423,47 @@ class ChipStripComponent {
|
|
|
328
423
|
this.stripActive = active;
|
|
329
424
|
this.invalidationCb?.();
|
|
330
425
|
}
|
|
426
|
+
/** Initiate cancel confirmation for a chip. Sets cancelTarget so the
|
|
427
|
+
* next render shows the confirmation prompt. */
|
|
428
|
+
requestCancelChip(chip) {
|
|
429
|
+
this.cancelTarget = chip;
|
|
430
|
+
this.invalidationCb?.();
|
|
431
|
+
}
|
|
432
|
+
/** Confirm the pending cancellation (user pressed y). */
|
|
433
|
+
confirmCancel() {
|
|
434
|
+
const target = this.cancelTarget;
|
|
435
|
+
this.cancelTarget = null;
|
|
436
|
+
this.invalidationCb?.();
|
|
437
|
+
return target;
|
|
438
|
+
}
|
|
439
|
+
/** Dismiss the cancel prompt (user pressed n/Esc). */
|
|
440
|
+
dismissCancel() {
|
|
441
|
+
this.cancelTarget = null;
|
|
442
|
+
this.invalidationCb?.();
|
|
443
|
+
}
|
|
444
|
+
/** Whether a cancel confirmation prompt is active. */
|
|
445
|
+
isCancelPromptActive() {
|
|
446
|
+
return this.cancelTarget !== null;
|
|
447
|
+
}
|
|
448
|
+
/** Check if the chip at the current cursor is a running phase that can be cancelled. */
|
|
449
|
+
isCursorCancellable() {
|
|
450
|
+
const chip = this.cursorChip();
|
|
451
|
+
if (!chip)
|
|
452
|
+
return false;
|
|
453
|
+
if (chip.id === "main") {
|
|
454
|
+
const session = this.activeSession();
|
|
455
|
+
return (session?.status ?? "") === "running";
|
|
456
|
+
}
|
|
457
|
+
const p = this.chipPhase(chip);
|
|
458
|
+
if (!p)
|
|
459
|
+
return false;
|
|
460
|
+
return p.status === "running";
|
|
461
|
+
}
|
|
462
|
+
/** True when the current session is cancelled — r key triggers resume. */
|
|
463
|
+
isCursorResumable() {
|
|
464
|
+
const session = this.activeSession();
|
|
465
|
+
return session?.status === "cancelled";
|
|
466
|
+
}
|
|
331
467
|
getStripActive() {
|
|
332
468
|
return this.stripActive;
|
|
333
469
|
}
|
|
@@ -394,6 +530,18 @@ function isEsc(d) {
|
|
|
394
530
|
// by the arrow checks above first.
|
|
395
531
|
return d === "\x1b";
|
|
396
532
|
}
|
|
533
|
+
function isXKey(d) {
|
|
534
|
+
return d === "x";
|
|
535
|
+
}
|
|
536
|
+
function isRKey(d) {
|
|
537
|
+
return d === "r" || d === "R";
|
|
538
|
+
}
|
|
539
|
+
function isYKey(d) {
|
|
540
|
+
return d === "y" || d === "Y";
|
|
541
|
+
}
|
|
542
|
+
function isNKey(d) {
|
|
543
|
+
return d === "n" || d === "N";
|
|
544
|
+
}
|
|
397
545
|
// ── Registrar ───────────────────────────────────────────────────────────────
|
|
398
546
|
/**
|
|
399
547
|
* Custom renderer for the `forge:turn` chat-history rows we append on every
|
|
@@ -434,15 +582,22 @@ export function registerThreadSwitcher(pi) {
|
|
|
434
582
|
let themeRef;
|
|
435
583
|
let spinnerTimer;
|
|
436
584
|
let mounted = false;
|
|
585
|
+
// Pi invalidates the ExtensionContext after newSession / fork /
|
|
586
|
+
// switchSession / reload. The input-router handler and the focus
|
|
587
|
+
// helpers are registered once at mount but fire after arbitrary
|
|
588
|
+
// session replacements — they must read the *live* ctx, not the
|
|
589
|
+
// one captured at mount time. We refresh this on every
|
|
590
|
+
// session_start and on every forge:threads command invocation.
|
|
591
|
+
let currentCtx;
|
|
437
592
|
function ensureSpinnerTimer() {
|
|
438
|
-
// Tick re-renders while any session is "running" so the
|
|
439
|
-
// glyph animates and the preview text refreshes between user input.
|
|
593
|
+
// Tick re-renders while any session is "running" or "cancelling" so the
|
|
594
|
+
// spinner glyph animates and the preview text refreshes between user input.
|
|
440
595
|
// When all sessions are terminal, the timer stops itself.
|
|
441
596
|
if (spinnerTimer)
|
|
442
597
|
return;
|
|
443
598
|
spinnerTimer = setInterval(() => {
|
|
444
|
-
const
|
|
445
|
-
if (!
|
|
599
|
+
const anyActive = registry.listSessions().some((s) => s.status === "running" || s.status === "cancelling");
|
|
600
|
+
if (!anyActive) {
|
|
446
601
|
if (spinnerTimer)
|
|
447
602
|
clearInterval(spinnerTimer);
|
|
448
603
|
spinnerTimer = undefined;
|
|
@@ -454,6 +609,7 @@ export function registerThreadSwitcher(pi) {
|
|
|
454
609
|
}, SPINNER_INTERVAL_MS);
|
|
455
610
|
}
|
|
456
611
|
function mount(ctx) {
|
|
612
|
+
currentCtx = ctx;
|
|
457
613
|
if (mounted)
|
|
458
614
|
return;
|
|
459
615
|
process.stderr.write("[forge:threads] mount() invoked\n");
|
|
@@ -470,7 +626,21 @@ export function registerThreadSwitcher(pi) {
|
|
|
470
626
|
// viewport (mirrors the per-phase footer rendered inside TailView
|
|
471
627
|
// when a subagent chip is focused).
|
|
472
628
|
ctx.ui.setWidget(FOOTER_WIDGET_KEY, (tui, theme) => {
|
|
473
|
-
|
|
629
|
+
// Guard against stale-ctx access after session replacement
|
|
630
|
+
// (newSession / fork / switchSession / reload) — touching
|
|
631
|
+
// ctx.model on a stale ctx throws and would crash the row.
|
|
632
|
+
const getOrchestratorModel = () => {
|
|
633
|
+
try {
|
|
634
|
+
const m = ctx.model;
|
|
635
|
+
if (!m)
|
|
636
|
+
return undefined;
|
|
637
|
+
return { provider: m.provider, model: m.id };
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
return undefined;
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
const footer = new ViewportFooterComponent(registry, theme, getOrchestratorModel);
|
|
474
644
|
footer.setInvalidationCallback(() => tui.requestRender());
|
|
475
645
|
return footer;
|
|
476
646
|
}, { placement: "aboveEditor" });
|
|
@@ -509,21 +679,81 @@ export function registerThreadSwitcher(pi) {
|
|
|
509
679
|
getInputRouter().register((data) => {
|
|
510
680
|
if (!stripRef)
|
|
511
681
|
return undefined;
|
|
682
|
+
const live = currentCtx;
|
|
683
|
+
if (!live)
|
|
684
|
+
return undefined;
|
|
512
685
|
if (!stripRef.getStripActive()) {
|
|
513
686
|
if (!isDownArrow(data))
|
|
514
687
|
return undefined;
|
|
515
|
-
|
|
688
|
+
let editorText = "";
|
|
689
|
+
try {
|
|
690
|
+
editorText = live.ui.getEditorText();
|
|
691
|
+
}
|
|
692
|
+
catch {
|
|
693
|
+
return undefined;
|
|
694
|
+
}
|
|
516
695
|
if (editorText.includes("\n"))
|
|
517
696
|
return undefined; // multi-line nav
|
|
518
697
|
if (!stripRef.hasSession())
|
|
519
698
|
return undefined; // strip hidden anyway
|
|
520
699
|
stripRef.setStripActive(true);
|
|
521
|
-
// Park cursor on the currently-running subagent — that's
|
|
522
|
-
// the chip the user almost always wants to see. Falls back
|
|
523
|
-
// to orchestrator (index 0) when no phase is live.
|
|
524
700
|
stripRef.parkCursorOnCurrentPhase();
|
|
525
701
|
return { consume: true };
|
|
526
702
|
}
|
|
703
|
+
// ── Cancel-confirmation handling (cancelTarget active) ────────
|
|
704
|
+
// When the strip shows a cancel prompt, y/Enter confirms,
|
|
705
|
+
// n/Esc dismisses. All other keys are consumed (no passthrough).
|
|
706
|
+
if (stripRef.isCancelPromptActive()) {
|
|
707
|
+
if (isYKey(data) || isEnter(data)) {
|
|
708
|
+
const target = stripRef.confirmCancel();
|
|
709
|
+
if (target?.taskId) {
|
|
710
|
+
registry.requestCancel(target.taskId);
|
|
711
|
+
}
|
|
712
|
+
stripRef.setStripActive(false);
|
|
713
|
+
setFocusToMain(live);
|
|
714
|
+
return { consume: true };
|
|
715
|
+
}
|
|
716
|
+
// Dismiss: n, Esc
|
|
717
|
+
if (isNKey(data) || isEsc(data)) {
|
|
718
|
+
stripRef.dismissCancel();
|
|
719
|
+
stripRef.setStripActive(false);
|
|
720
|
+
return { consume: true };
|
|
721
|
+
}
|
|
722
|
+
// Any other key in cancel-confirmation mode is consumed silently.
|
|
723
|
+
return { consume: true };
|
|
724
|
+
}
|
|
725
|
+
if (isXKey(data)) {
|
|
726
|
+
const chip = stripRef.cursorChip();
|
|
727
|
+
if (chip && stripRef.isCursorCancellable()) {
|
|
728
|
+
stripRef.requestCancelChip(chip);
|
|
729
|
+
return { consume: true };
|
|
730
|
+
}
|
|
731
|
+
return undefined;
|
|
732
|
+
}
|
|
733
|
+
if (isRKey(data)) {
|
|
734
|
+
// Resume a cancelled session. The state file is preserved on cancel
|
|
735
|
+
// (ADR-S21-01). Write the slash command to the editor and simulate
|
|
736
|
+
// Enter — exactly mirrors how a user types and submits the command.
|
|
737
|
+
const session = registry.listSessions()[0];
|
|
738
|
+
if (session && stripRef.isCursorResumable()) {
|
|
739
|
+
const entityId = session.taskId;
|
|
740
|
+
const cmd = entityId.startsWith("FORGE-BUG-")
|
|
741
|
+
? `forge:fix-bug ${entityId}`
|
|
742
|
+
: `forge:run-task ${entityId}`;
|
|
743
|
+
stripRef.setStripActive(false);
|
|
744
|
+
try {
|
|
745
|
+
live.ui.setEditorText(`/${cmd}`);
|
|
746
|
+
}
|
|
747
|
+
catch {
|
|
748
|
+
// Non-fatal — editor may not be accessible in all contexts.
|
|
749
|
+
live.ui.notify(`↻ Resume: /${cmd}`, "info");
|
|
750
|
+
}
|
|
751
|
+
// Return Enter to submit the command. The router dispatches
|
|
752
|
+
// normally; pi processes it as a slash-command submit.
|
|
753
|
+
return { data: "\r" };
|
|
754
|
+
}
|
|
755
|
+
return undefined;
|
|
756
|
+
}
|
|
527
757
|
if (isLeftArrow(data)) {
|
|
528
758
|
stripRef.moveCursor(-1);
|
|
529
759
|
return { consume: true };
|
|
@@ -537,12 +767,12 @@ export function registerThreadSwitcher(pi) {
|
|
|
537
767
|
return { consume: true };
|
|
538
768
|
}
|
|
539
769
|
if (isEnter(data)) {
|
|
540
|
-
commitFocus(
|
|
770
|
+
commitFocus(live);
|
|
541
771
|
return { consume: true };
|
|
542
772
|
}
|
|
543
773
|
if (isEsc(data)) {
|
|
544
774
|
stripRef.setStripActive(false);
|
|
545
|
-
setFocusToMain(
|
|
775
|
+
setFocusToMain(live);
|
|
546
776
|
return { consume: true };
|
|
547
777
|
}
|
|
548
778
|
return undefined;
|
|
@@ -571,14 +801,25 @@ export function registerThreadSwitcher(pi) {
|
|
|
571
801
|
if (tuiRef)
|
|
572
802
|
tail.setInvalidationCallback(() => tuiRef?.requestRender());
|
|
573
803
|
tailRef = tail;
|
|
574
|
-
|
|
804
|
+
try {
|
|
805
|
+
ctx.ui.setOutputSource(tail);
|
|
806
|
+
}
|
|
807
|
+
catch {
|
|
808
|
+
// ctx went stale between keypress and dispatch — drop quietly;
|
|
809
|
+
// the next session_start will refresh currentCtx.
|
|
810
|
+
}
|
|
575
811
|
registry.markRead(chip.taskId, chip.id);
|
|
576
812
|
}
|
|
577
813
|
function setFocusToMain(ctx) {
|
|
578
814
|
stripRef?.setFocusedChipId("main");
|
|
579
815
|
tailRef?.dispose?.();
|
|
580
816
|
tailRef = undefined;
|
|
581
|
-
|
|
817
|
+
try {
|
|
818
|
+
ctx.ui.setOutputSource(null);
|
|
819
|
+
}
|
|
820
|
+
catch {
|
|
821
|
+
// see commitFocus
|
|
822
|
+
}
|
|
582
823
|
}
|
|
583
824
|
pi.registerCommand("forge:threads", {
|
|
584
825
|
description: "Activate the Forge thread-switcher strip below the editor. " +
|
|
@@ -591,6 +832,10 @@ export function registerThreadSwitcher(pi) {
|
|
|
591
832
|
});
|
|
592
833
|
// Mount at session_start so the Down listener + chip strip are live
|
|
593
834
|
// from the first keystroke. mount() is idempotent.
|
|
835
|
+
// session_start fires for the initial session and for every
|
|
836
|
+
// post-replacement session (newSession / fork / switchSession /
|
|
837
|
+
// reload), so mount() refreshing currentCtx here is the single
|
|
838
|
+
// chokepoint for keeping the input-router handler's ctx live.
|
|
594
839
|
pi.on("session_start", async (_event, ctx) => {
|
|
595
840
|
mount(ctx);
|
|
596
841
|
});
|