@kolisachint/hoocode-agent 0.4.37 → 0.4.38

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +1 -1
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/core/lifeguard.d.ts +11 -0
  6. package/dist/core/lifeguard.d.ts.map +1 -1
  7. package/dist/core/lifeguard.js +68 -3
  8. package/dist/core/lifeguard.js.map +1 -1
  9. package/dist/core/messages.d.ts +38 -3
  10. package/dist/core/messages.d.ts.map +1 -1
  11. package/dist/core/messages.js +64 -10
  12. package/dist/core/messages.js.map +1 -1
  13. package/dist/core/sdk.d.ts.map +1 -1
  14. package/dist/core/sdk.js +2 -1
  15. package/dist/core/sdk.js.map +1 -1
  16. package/dist/core/subagent-pool.d.ts +2 -1
  17. package/dist/core/subagent-pool.d.ts.map +1 -1
  18. package/dist/core/subagent-pool.js +2 -1
  19. package/dist/core/subagent-pool.js.map +1 -1
  20. package/dist/core/task-store.d.ts +6 -1
  21. package/dist/core/task-store.d.ts.map +1 -1
  22. package/dist/core/task-store.js +3 -0
  23. package/dist/core/task-store.js.map +1 -1
  24. package/dist/core/tools/subagent.d.ts.map +1 -1
  25. package/dist/core/tools/subagent.js +3 -2
  26. package/dist/core/tools/subagent.js.map +1 -1
  27. package/dist/extensions/core/hoo-core.d.ts.map +1 -1
  28. package/dist/extensions/core/hoo-core.js +17 -1
  29. package/dist/extensions/core/hoo-core.js.map +1 -1
  30. package/dist/modes/interactive/components/task-panel.d.ts +3 -1
  31. package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
  32. package/dist/modes/interactive/components/task-panel.js +27 -5
  33. package/dist/modes/interactive/components/task-panel.js.map +1 -1
  34. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  35. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  36. package/examples/extensions/sandbox/package.json +1 -1
  37. package/examples/extensions/with-deps/package.json +1 -1
  38. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"hoo-core.js","sourceRoot":"","sources":["../../../src/extensions/core/hoo-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAqB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAchD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,+EAA+E;AAC/E,qCAAqC;AACrC,+EAA+E;AAE/E,MAAM,aAAa,GAA2B;IAC7C,GAAG,EAAE;;;;2DAIqD;IAE1D,IAAI,EAAE;;;;wEAIiE;IAEvE,KAAK,EAAE;;;;;+CAKuC;IAE9C,KAAK,EAAE;;;;;+BAKuB;CAC9B,CAAC;AAEF,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;AACpC,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;AAEhE;;;GAGG;AACH,SAAS,WAAW,CAAC,GAAW,EAAE,SAAiB,EAAU;IAC5D,OAAO,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,SAAS,KAAK,CAAC,CAAC;AAAA,CACzD;AAED,uFAAuF;AACvF,SAAS,iBAAiB,CAAC,GAAW,EAAU;IAC/C,OAAO,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAAA,CACxC;AA8BD,+EAA+E;AAC/E,yBAAyB;AACzB,+EAA+E;AAE/E,SAAS,UAAU,GAAc;IAChC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAc,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AAAA,CACD;AAED,SAAS,WAAW,CAAC,MAAiB,EAAQ;IAC7C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,aAAa,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAAA,CAClF;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,MAAiB,EAAE,OAAkB,EAAa;IAC9E,MAAM,MAAM,GAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IAExC,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;QAAE,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAEhF,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,CAAC,KAAK,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG;gBACpB,GAAG,SAAS;gBACZ,GAAG,UAAU;gBACb,sEAAsE;gBACtE,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACpG,kDAAkD;gBAClD,mBAAmB,EAAE,KAAK,CAAC,IAAI,CAC9B,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,CAAC,CAC9F;gBACD,gEAAgE;gBAChE,aAAa,EAAE,UAAU,CAAC,aAAa,IAAI,SAAS,CAAC,aAAa;gBAClE,4EAA4E;gBAC5E,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC1G,wEAAwE;gBACxE,qBAAqB,EAAE,UAAU,CAAC,qBAAqB,IAAI,SAAS,CAAC,qBAAqB;gBAC1F,uFAAuF;gBACvF,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAC/B,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,CAAC,CAChG;aACD,CAAC;QACH,CAAC;IACF,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAC7C,8DAA8D;QAC9D,MAAM,CAAC,UAAU,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,WAAW,CAAC,KAAe,EAAY;IAC/C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACb,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED,SAAS,gBAAgB,CAAC,GAAG,OAAiC,EAAY;IACzE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAAA,CAC3B;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAa;IACxD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;IAC7D,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5C,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAc,CAAC;QAC3E,OAAO,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,MAAM,CAAC;IACf,CAAC;AAAA,CACD;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD;;;GAGG;AACH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,eAAyB,EAAW;IACjF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACvC,cAAc;QACd,IAAI,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACtC,8BAA8B;QAC9B,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9D,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO,IAAI,CAAC;QACvC,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;;GAGG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAAE,OAAe,EAAW;IACtE,IAAI,CAAC;QACJ,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AAAA,CACD;AAED,SAAS,YAAY,CAAC,KAAoB,EAAU;IACnD,IAAI,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,GAAI,KAAK,CAAC,KAAgC,CAAC,SAAS,IAAI,WAAW,CAAC;QAC3E,OAAO,QAAQ,CAAC,EAAE,CAAC;IACpB,CAAC;IACD,IAAI,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,GAAI,KAAK,CAAC,KAAgC,CAAC,SAAS,IAAI,WAAW,CAAC;QAC3E,OAAO,SAAS,CAAC,EAAE,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,CAAC;AAAA,CACtB;AAED,MAAM,UAAU,mBAAmB,CAAC,EAAgB,EAAQ;IAC3D,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,KAAoB,EAAE,GAAqB,EAA4C,EAAE,CAAC;QACnH,+DAA+D;QAC/D,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;QAErC,uHAA6E;QAE7E,sDAAsD;QACtD,IAAI,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrD,OAAO;gBACN,KAAK,EAAE,IAAI;gBACX,MAAM,EAAE,SAAS,KAAK,CAAC,QAAQ,wBAAwB,IAAI,IAAI;aAC/D,CAAC;QACH,CAAC;QAED,0EAA0E;QAC1E,IACC,OAAO,EAAE,aAAa;YACtB,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;YAChC,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAC9C,CAAC;YACF,OAAO;gBACN,KAAK,EAAE,IAAI;gBACX,MAAM,EACL,SAAS,KAAK,CAAC,QAAQ,6BAA6B,IAAI,IAAI;oBAC5D,aAAa,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;aAClD,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,IAAI,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;YACxC,MAAM,OAAO,GAAI,KAAK,CAAC,KAA8B,CAAC,OAAO,IAAI,EAAE,CAAC;YAEpE,qDAAqD;YACrD,IAAI,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,CAAC;gBAC3C,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;oBACpD,IAAI,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;wBAC1C,OAAO;4BACN,KAAK,EAAE,IAAI;4BACX,MAAM,EAAE,kDAAkD,IAAI,MAAM,OAAO,EAAE;yBAC7E,CAAC;oBACH,CAAC;gBACF,CAAC;YACF,CAAC;YAED,mEAAmE;YACnE,IAAI,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,CAAC;gBAC5C,MAAM,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC5F,IAAI,CAAC,SAAS,EAAE,CAAC;oBAChB,OAAO;wBACN,KAAK,EAAE,IAAI;wBACX,MAAM,EACL,0CAA0C,IAAI,KAAK;4BACnD,qBAAqB,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;qBAChE,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC;QAED,2GAA6E;QAE7E,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;YAAE,OAAO;QAE3D,MAAM,SAAS,GAAG,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC;QAE5C,sDAAsD;QACtD,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,mBAAmB,EAAE,CAAC;YAC/F,MAAM,QAAQ,GAAI,KAAK,CAAC,KAAgC,CAAC,SAAS,IAAI,EAAE,CAAC;YACzE,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAChE,OAAO;oBACN,KAAK,EAAE,IAAI;oBACX,MAAM,EACL,SAAS,IAAI,4BAA4B,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;wBACnF,gBAAgB,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI;wBAC/C,iDAAiD;iBAClD,CAAC;YACH,CAAC;QACF,CAAC;QAED,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;YAAE,OAAO;QAE/C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE;YACnE,YAAY;YACZ,YAAY;YACZ,0CAA0C;SAC1C,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC;QAC7D,CAAC;QAED,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,mDAAmD;YACnD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC;YAClD,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC;YACpB,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,UAAU,GAAG,KAAK,CAAC,IAAI,CAChD,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAC1E,CAAC;YACF,WAAW,CAAC,MAAM,CAAC,CAAC;YACpB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,mCAAmC,WAAW,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5F,CAAC;IAAA,CACD,CAAC,CAAC;AAAA,CACH;AA8CD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAyB,CAAC;AAExD,SAAS,cAAc,CAAC,MAAuB,EAAiB;IAC/D,MAAM,IAAI,GAAiB,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE;QACnE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;QAC9C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAC/B,CAAC,CAAC;IAEH,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyE,CAAC;IAEjG,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,MAAO,EAAE,CAAC,CAAC;IACpD,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;QACzB,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAI1B,CAAC;YACF,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS;gBAAE,OAAO;YACjC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/B,IAAI,CAAC,EAAE;gBAAE,OAAO;YAChB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvB,IAAI,GAAG,CAAC,KAAK;gBAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;;gBAClD,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACR,wCAAwC;QACzC,CAAC;IAAA,CACD,CAAC,CAAC;IAEH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;QACrB,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE;YAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,MAAM,CAAC,IAAI,uBAAuB,CAAC,CAAC,CAAC;QAC3G,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAAA,CACnC,CAAC,CAAC;IAEH,SAAS,GAAG,CAAC,MAAc,EAAE,MAAgB,EAAoB;QAChE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC,KAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QAAA,CACjF,CAAC,CAAC;IAAA,CACH;IAED,OAAO;QACN,GAAG;QACH,SAAS,EAAE,GAAG,EAAE,CAAC;YAChB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,IAAI,EAAE,CAAC;QAAA,CACZ;KACD,CAAC;AAAA,CACF;AAED,KAAK,UAAU,gBAAgB,CAAC,MAAuB,EAAyD;IAC/G,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC;IAE7C,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACpC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAEtC,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE;QAC5B,eAAe,EAAE,YAAY;QAC7B,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;KACjD,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAEpD,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;AAAA,CAChD;AAED,SAAS,cAAc,CAAC,IAAgB,EAAkC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,IAAI,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAmD,EAAE,CAAC;IAEjE,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,KAAqC,CAAC;QAC1C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,QAAQ,CAAC;YACd,KAAK,SAAS;gBACb,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAA8C,CAAC;gBACpG,MAAM;YACP,KAAK,SAAS;gBACb,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAA8C,CAAC;gBACrG,MAAM;YACP;gBACC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAA+C,CAAC;IAC9G,CAAC;IAED,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CAC1B;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,MAAyB,EAAE,OAAe,EAAqB;IAC9F,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAElC,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC;YACZ,IAAI;YACJ,OAAO,EAAE,YAAY,CAAC,OAAO;YAC7B,IAAI,EAAE,YAAY,CAAC,IAAI;YACvB,GAAG,EAAE,YAAY,CAAC,GAAG;YACrB,UAAU,EAAE,YAAY,CAAC,UAAU;SACnC,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,QAAgB,EAAqB;IACjE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAsB,CAAC;QACxD,OAAO,sBAAsB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AAAA,CACD;AAED,MAAM,UAAU,cAAc,CAAC,EAAgB,EAAQ;IACtD,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,EAAE,MAAyB,EAAE,GAAqB,EAAE,EAAE,CAAC;QAClF,MAAM,gBAAgB,GAAsB,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QAEpC,2CAA2C;QAC3C,iCAAiC;QACjC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;QACrF,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;YACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC3B,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;QAED,oCAAoC;QACpC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;QACtF,KAAK,MAAM,MAAM,IAAI,mBAAmB,EAAE,CAAC;YAC1C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC3B,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;QAED,4CAA4C;QAC5C,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;QAClG,KAAK,MAAM,MAAM,IAAI,mBAAmB,EAAE,CAAC;YAC1C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC3B,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;QAED,+DAA+D;QAC/D,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;QAEhG,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAE/B,IAAI,KAAe,CAAC;YACpB,IAAI,CAAC;gBACJ,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YACjE,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;YAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAChC,IAAI,YAA6B,CAAC;gBAElC,IAAI,CAAC;oBACJ,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAoB,CAAC;oBAC5E,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;wBACjD,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,IAAI,2CAA2C,EAAE,SAAS,CAAC,CAAC;wBAC1F,SAAS;oBACV,CAAC;gBACF,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,yBAAyB,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;oBACzE,SAAS;gBACV,CAAC;gBAED,8CAA8C;gBAC9C,IAAI,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAC/C,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;gBACjC,gBAAgB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;QAED,+CAA+C;QAC/C,KAAK,MAAM,YAAY,IAAI,gBAAgB,EAAE,CAAC;YAC7C,IAAI,CAAC;gBACJ,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;gBAEvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBAC1B,MAAM,QAAQ,GAAG,OAAO,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACzD,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;oBACpC,MAAM,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC;oBACzC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC;oBAC/B,qGAAqG;oBACrG,MAAM,YAAY,GAAG,YAAY,CAAC,UAAU,KAAK,KAAK,CAAC;oBAEvD,EAAE,CAAC,YAAY,CAAC;wBACf,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,SAAS,YAAY,CAAC,IAAI,QAAM,IAAI,CAAC,IAAI,EAAE;wBAClD,WAAW,EAAE,IAAI,CAAC,WAAW;wBAC7B,UAAU,EAAE,MAAM;wBAClB,UAAU,EAAE,YAAY;wBACxB,KAAK,CAAC,OAAO,CACZ,WAAmB,EACnB,MAA6B,EAC7B,MAAmB,EACnB,SAAkC,EACI;4BACtC,+EAA+E;4BAC/E,+DAA+D;4BAC/D,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,cAAc,QAAM,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;4BAChG,IAAI,IAAI;gCAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;4BAE/D,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;4BACtD,IAAI,CAAC,UAAU,EAAE,CAAC;gCACjB,IAAI,IAAI;oCAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;gCAC1D,OAAO;oCACN,OAAO,EAAE;wCACR;4CACC,IAAI,EAAE,MAAM;4CACZ,IAAI,EAAE,eAAe,cAAc,oBAAoB;yCACvD;qCACD;oCACD,OAAO,EAAE,SAAS;iCAClB,CAAC;4BACH,CAAC;4BAED,IAAI,CAAC;gCACJ,MAAM,YAAY,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;oCACtD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gCAAA,CACrE,CAAC,CAAC;gCAEH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;oCACjC,UAAU,CAAC,GAAG,CAAC,YAAY,EAAE;wCAC5B,IAAI,EAAE,YAAY;wCAClB,SAAS,EAAE,MAAM;qCACjB,CAAC;oCACF,YAAY;iCACZ,CAAC,CAAC;gCAEH,IAAI,IAAI;oCAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gCACxD,OAAO;oCACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;oCAClE,OAAO,EAAE,SAAS;iCAClB,CAAC;4BACH,CAAC;4BAAC,OAAO,KAAK,EAAE,CAAC;gCAChB,IAAI,IAAI;oCAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;gCAC1D,MAAM,KAAK,CAAC;4BACb,CAAC;wBAAA,CACD;qBACD,CAAC,CAAC;gBACJ,CAAC;gBAED,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;gBAC/E,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,mBAAmB,YAAY,CAAC,IAAI,MAAM,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,GAAG,EACzG,MAAM,CACN,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,2BAA2B,YAAY,CAAC,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACzF,CAAC;QACF,CAAC;IAAA,CACD,CAAC,CAAC;AAAA,CACH;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E,MAAM,YAAY,GAAG,OAAO,CAAC;AAE7B,SAAS,WAAW,CAAC,IAAY,EAAsB;IACtD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/C,OAAO,IAAI,IAAI,SAAS,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,IAAY,EAAE,GAAW,EAAE,YAAsB,EAAsB;IAC/F,MAAM,UAAU,GAAa;QAC5B,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC;QACjD,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC;QAC7C,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;KAC1D,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,GAAW,EAAE,OAAkC,EAAsB;IACpH,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAC3C,OAAO,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;AAAA,CACpE;AAgBD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAgB;IACpE,MAAM,MAAM,GAAiB,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC;IAElD,0EAA0E;IAC1E,sCAAsC;IACtC,MAAM,cAAc,GACnB,iGAAiG,CAAC;IAEnG,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAC1D,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAClE,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;QACvB,CAAC;aAAM,IAAI,4BAA4B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC;QAChC,CAAC;aAAM,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC3B,CAAC;aAAM,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;QACxB,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,YAAY,GAAG,OAAO,CAAC;QAC/B,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACd;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAsB,EAAU;IACnE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,0CAAwC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,qCAAmC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,iCAA+B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,2BAAyB,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,kCAAkC,QAAQ,CAAC,GAAG,EAAE,CAAC;IACzD,CAAC;IAED,OAAO,0FAA0F,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAAA,CACtH;AAED,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,MAAM,UAAU,SAAS,CAAC,EAAgB,EAAQ;IACjD,IAAI,UAAU,GAAG,YAAY,CAAC;IAC9B,IAAI,kBAAsC,CAAC;IAC3C,IAAI,cAAkC,CAAC;IAEvC,mMAA6E;IAC7E,2BAA2B;IAC3B,wDAAwD;IACxD,mEAAmE;IACnE,yDAAuD;IACvD,qDAAqD;IAErD,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,MAAyB,EAAE,GAAqB,EAAE,EAAE,CAAC;QAC5E,8CAA4C;QAC5C,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEzC,8CAA8C;QAC9C,UAAU,GAAG,MAAM,CAAC,WAAW,IAAI,YAAY,CAAC;QAChD,+CAA+C;QAC/C,4CAA4C;QAC5C,gEAAgE;QAChE,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC;QAC/E,MAAM,eAAe,GAAG,iBAAiB,CAAC,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAE9E,2EAA2E;QAC3E,wEAAwE;QACxE,cAAc,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;QACzE,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,IAAI,cAAc,CAAC;QACxE,kBAAkB,GAAG,eAAe,EAAE,OAAO,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QAEjF,iCAAiC;QACjC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC;QAED,4CAA4C;QAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,OAAO,EAAE,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC1C,CAAC;IAAA,CACD,CAAC,CAAC;IAEH,yLAA6E;IAE7E,EAAE,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,KAA4B,EAA2C,EAAE,CAAC;QACtG,IAAI,CAAC,kBAAkB;YAAE,OAAO;QAChC,OAAO;YACN,YAAY,EAAE,GAAG,KAAK,CAAC,YAAY,2BAA2B,UAAU,SAAS,kBAAkB,EAAE;SACrG,CAAC;IAAA,CACF,CAAC,CAAC;IAEH,mMAA6E;IAE7E,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAEtD,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,yDAAyD;QACtE,sBAAsB,EAAE,CAAC,MAAc,EAAE,EAAE,CAC1C,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACrF,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACX,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC;gBACpD,OAAO;YACR,CAAC;YACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,CAAC,WAAW,GAAG,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9D,WAAW,CAAC,MAAM,CAAC,CAAC;YACpB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,IAAI,oBAAgB,EAAE,MAAM,CAAC,CAAC;YAC5D,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QAAA,CACnB;KACD,CAAC,CAAC;IAEH,6IAA6E;IAE7E,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,gDAAgD;QAC7D,sBAAsB,EAAE,GAAG,EAAE,CAAC,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,KAAa,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAC9E,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC;YAC5B,WAAW,CAAC,MAAM,CAAC,CAAC;YACpB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,qCAAiC,EAAE,MAAM,CAAC,CAAC;YACzD,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QAAA,CACnB;KACD,CAAC,CAAC;IAEH,6LAA6E;IAC7E,wEAAwE;IACxE,wEAAwE;IACxE,iEAAiE;IAEjE,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE;QAC7B,WAAW,EAAE,kEAAkE;QAC/E,sBAAsB,EAAE,GAAG,EAAE,CAAC,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,KAAa,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAC9E,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;gBAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,2DAA2D,UAAU,IAAI,EAAE,SAAS,CAAC,CAAC;gBACpG,OAAO;YACR,CAAC;YAED,yEAAyE;YACzE,MAAM,eAAe,GAAG,cAAc,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC;YAClG,MAAM,cAAc,GAAG,CAAC,eAAe,EAAE,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACrE,IAAI,cAAkC,CAAC;YAEvC,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,CAAC;gBACvC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBACpC,IAAI,CAAC;oBACJ,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;oBAClD,IAAI,GAAG,EAAE,CAAC;wBACT,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;wBACxC,cAAc,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;wBAC/C,MAAM;oBACP,CAAC;gBACF,CAAC;gBAAC,MAAM,CAAC;oBACR,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;oBACpF,OAAO;gBACR,CAAC;YACF,CAAC;YAED,qCAAqC;YACrC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;YAC5B,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC;YAC7B,WAAW,CAAC,MAAM,CAAC,CAAC;YAEpB,IAAI,cAAc,EAAE,CAAC;gBACpB,mEAAmE;gBACnE,+DAA+D;gBAC/D,MAAM,GAAG,CAAC,UAAU,CAAC;oBACpB,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC;wBACnC,MAAM,WAAW,CAAC,eAAe,CAAC,cAAe,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;oBAAA,CAC9E;iBACD,CAAC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACP,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,eAAe,CAAC;gBACtE,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,8BAA8B,OAAO,oCAAkC,EAAE,MAAM,CAAC,CAAC;gBAC/F,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;YACpB,CAAC;QAAA,CACD;KACD,CAAC,CAAC;IAEH,mMAA6E;IAC7E,+EAA+E;IAC/E,iEAAiE;IACjE,4EAA0E;IAC1E,mDAAmD;IAEnD,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,2DAA2D;QACxE,sBAAsB,EAAE,GAAG,EAAE,CAAC,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,KAAa,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAE9E,MAAM,KAAK,GAAG,GAAW,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAC5F,MAAM,KAAK,GAAG,KAAK,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC3C,IAAI,cAAc,GAAG,CAAC,CAAC;YAEvB,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC;gBACrD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;oBAAE,SAAS;gBAC7E,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAC9B,IAAI,CAAC,CAAC;oBAAE,SAAS;gBACjB,cAAc,EAAE,CAAC;gBACjB,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;gBACvB,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;gBACzB,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;gBAC/B,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC;gBACjC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;gBAE3B,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC/D,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC;gBACvC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;gBACnB,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;gBACrB,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;gBAC3B,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC;gBAC7B,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;gBACvB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACtB,CAAC;YAED,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;gBAC1B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,6CAA2C,EAAE,MAAM,CAAC,CAAC;gBACnE,OAAO;YACR,CAAC;YAED,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;YAC9C,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,mBAAmB,cAAc,kBAAkB,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAClG,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACtD,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,mBAAmB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAErD,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACxB,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC7E,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACvF,CAAC;YACF,CAAC;YAED,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QAAA,CACxC;KACD,CAAC,CAAC;AAAA,CACH;AAED,+EAA+E;AAC/E,iEAA+D;AAC/D,+EAA+E;AAE/E,kGAAkG;AAClG,SAAS,oBAAoB,CAAC,IAAY,EAAiB;IAC1D,IAAI,CAAC,IAAI;QAAE,OAAO,kBAAkB,CAAC;IACrC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,mDAAmD,CAAC;IAC3F,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,0CAA0C,CAAC;IAClG,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,2CAA2C,CAAC;IAC5E,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,SAAS,aAAa,CAAC,EAAgB,EAAQ;IAC9C,2LAA6E;IAC7E,gFAAgF;IAChF,8EAA8E;IAE9E,EAAE,CAAC,eAAe,CAAC,WAAW,EAAE;QAC/B,WAAW,EAAE,gDAAgD;QAC7D,sBAAsB,EAAE,GAAG,EAAE,CAAC,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,KAAK,EAAE,CAAC;gBACX,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,KAAK,4BAA4B,EAAE,SAAS,CAAC,CAAC;gBAC3E,OAAO;YACR,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAE7C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,SAAS,iBAAiB,EAAE,SAAS,CAAC,CAAC;gBACpE,OAAO;YACR,CAAC;YAED,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,aAAa,CACZ,SAAS,EACT;gBACC,KAAK;gBACL,SAAS,IAAI,EAAE;gBACf,gBAAgB;gBAChB,4EAA0E;gBAC1E,6DAA6D;gBAC7D,2BAA2B;gBAC3B,KAAK;gBACL,EAAE;gBACF,KAAK,IAAI,EAAE;gBACX,EAAE;gBACF,0CAA0C;gBAC1C,EAAE;gBACF,iFAAiF;gBACjF,EAAE;aACF,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,MAAM,CACN,CAAC;YAEF,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,kBAAkB,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,mDAAmD,EACjH,MAAM,CACN,CAAC;QAAA,CACF;KACD,CAAC,CAAC;IAEH,2LAA6E;IAC7E,gFAAgF;IAChF,6EAA6E;IAE7E,EAAE,CAAC,eAAe,CAAC,WAAW,EAAE;QAC/B,WAAW,EAAE,mDAAmD;QAChE,sBAAsB,EAAE,GAAG,EAAE,CAAC,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,KAAK,EAAE,CAAC;gBACX,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,KAAK,4BAA4B,EAAE,SAAS,CAAC,CAAC;gBAC3E,OAAO;YACR,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YACtD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;YAEhD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,SAAS,iBAAiB,EAAE,SAAS,CAAC,CAAC;gBACpE,OAAO;YACR,CAAC;YAED,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1C,aAAa,CACZ,SAAS,EACT;gBACC,KAAK;gBACL,SAAS,IAAI,EAAE;gBACf,gBAAgB;gBAChB,gCAAgC;gBAChC,iDAAiD;gBACjD,EAAE;gBACF,mBAAmB;gBACnB,sDAAsD;gBACtD,mBAAmB;gBACnB,eAAe;gBACf,KAAK;gBACL,aAAa,IAAI,mCAAmC;gBACpD,wEAAwE;gBACxE,EAAE;gBACF,qCAAqC;gBACrC,EAAE;gBACF,4EAA0E;gBAC1E,0EAA0E;gBAC1E,EAAE;aACF,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,MAAM,CACN,CAAC;YAEF,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,kBAAkB,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,KAAK,CAAC,mDAAmD,EAC7G,MAAM,CACN,CAAC;QAAA,CACF;KACD,CAAC,CAAC;IAEH,uLAA6E;IAC7E,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAE3E,EAAE,CAAC,eAAe,CAAC,aAAa,EAAE;QACjC,WAAW,EAAE,0DAA0D;QACvE,sBAAsB,EAAE,GAAG,EAAE,CAAC,EAAE;QAChC,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,GAA4B,EAAiB,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,KAAK,EAAE,CAAC;gBACX,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,KAAK,8BAA8B,EAAE,SAAS,CAAC,CAAC;gBAC/E,OAAO;YACR,CAAC;YAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;YAEpD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC7B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,WAAW,iBAAiB,EAAE,SAAS,CAAC,CAAC;gBACxE,OAAO;YACR,CAAC;YAED,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5C,aAAa,CACZ,WAAW,EACX;gBACC,KAAK;gBACL,SAAS,IAAI,EAAE;gBACf,gBAAgB;gBAChB,0BAA0B,IAAI,2BAA2B;gBACzD,aAAa,IAAI,SAAS;gBAC1B,uBAAuB;gBACvB,KAAK;gBACL,YAAY,IAAI,0CAA0C;gBAC1D,EAAE;gBACF,8DAA8D;gBAC9D,wCAAwC;gBACxC,sCAAsC;gBACtC,MAAM,GAAG,WAAW,GAAG,8BAA8B;gBACrD,EAAE;aACF,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,MAAM,CACN,CAAC;YAEF,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,oBAAoB,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,KAAK,CAAC,mDAAmD,EACjH,MAAM,CACN,CAAC;QAAA,CACF;KACD,CAAC,CAAC;AAAA,CACH;AAED,+EAA+E;AAC/E,uCAAqC;AACrC,+EAA+E;AAE/E,6EAA6E;AAC7E,8EAA8E;AAC9E,yEAAyE;AACzE,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IACpC,SAAS,EAAE,IAAI,CAAC,KAAK,CACpB,IAAI,CAAC,MAAM,CAAC;QACX,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+BAA+B,EAAE,CAAC;QACvE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,wDAAwD,EAAE,CAAC,CAAC;QAC7G,OAAO,EAAE,IAAI,CAAC,KAAK,CAClB,IAAI,CAAC,MAAM,CAAC;YACX,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;YACtF,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,sDAAsD,EAAE,CAAC,CACpF;YACD,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,OAAO,CAAC;gBACZ,WAAW,EAAE,0EAA0E;aACvF,CAAC,CACF;SACD,CAAC,EACF,EAAE,WAAW,EAAE,uCAAuC,EAAE,CACxD;QACD,YAAY,EAAE,IAAI,CAAC,QAAQ,CAC1B,IAAI,CAAC,OAAO,CAAC;YACZ,WAAW,EAAE,gFAAgF;SAC7F,CAAC,CACF;KACD,CAAC,EACF,EAAE,WAAW,EAAE,kDAAkD,EAAE,CACnE;CACD,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,EAAgB,EAAQ;IACvD,uEAAuE;IACvE,IAAI,SAAuC,CAAC;IAC5C,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,MAAyB,EAAE,GAAqB,EAAE,EAAE,CAAC;QAC5E,SAAS,GAAG,GAAG,CAAC;IAAA,CAChB,CAAC,CAAC;IAEH,EAAE,CAAC,YAAY,CAAC;QACf,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,cAAc;QACrB,WAAW,EACV,2FAA2F;YAC3F,8FAA8F;YAC9F,2FAA2F;YAC3F,0FAA0F;QAC3F,UAAU,EAAE,gBAAgB;QAC5B,KAAK,CAAC,OAAO,CACZ,WAAmB,EACnB,MAAuC,EACvC,MAAmB,EACnB,SAAkC,EACI;YACtC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;gBACpC,OAAO;oBACN,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,yGAAyG;yBAC/G;qBACD;oBACD,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;gBAC9B,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,6BAA6B,EAAE,CAAC;oBAChE,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC;YAED,MAAM,SAAS,GAAkB,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7D,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;gBAC3G,WAAW,EAAE,CAAC,CAAC,YAAY;aAC3B,CAAC,CAAC,CAAC;YAEJ,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAErE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO;oBACN,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,yFAAyF;yBAC/F;qBACD;oBACD,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC;YAED,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,cAAc,OAAO,CAAC,CAAC,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5G,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;gBACjC,OAAO,EAAE,SAAS;aAClB,CAAC;QAAA,CACF;KACD,CAAC,CAAC;AAAA,CACH;AAED,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E,SAAS,OAAO,CAAC,EAAgB,EAAQ;IACxC,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACxB,cAAc,CAAC,EAAE,CAAC,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,CAAC;IACd,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,eAAe,CAAC,EAAE,CAAC,CAAC;AAAA,CACpB;AAED,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC;AACjC,eAAe,OAAO,CAAC","sourcesContent":["/**\n * hoo-core — HooCode built-in core extension\n *\n * A. Permission Gate — prompts before bash/write/edit; checks modes.{mode}.auto_allow\n * from the merged (global + project) config; persists \"always\"\n * choices back to the global config\n * B. MCP Server Loader — discovers ~/.hoocode/mcp-servers and ./.hoocode/mcp-servers JSON\n * configs, connects via JSON-RPC 2.0, registers server tools\n * C. Mode — resolves active mode (ask/plan/build/debug), loads the mode's\n * system prompt, filters active tools, and exposes /mode, /plan,\n * and /approve commands\n *\n * Config merge order (lowest → highest priority):\n * 1. ~/.hoocode/hoo-config.json (global defaults)\n * 2. ./.hoocode/hoo-config.json (project overrides — scalars win; arrays union)\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, relative } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { type Static, Type } from \"typebox\";\nimport { getHooCodeDir } from \"../../config.js\";\nimport type {\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAskQuestion,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tSessionStartEvent,\n\tToolCallEvent,\n\tToolCallEventResult,\n} from \"../../core/extensions/types.js\";\nimport { isToolCallEventType } from \"../../core/extensions/types.js\";\nimport { taskStore } from \"../../core/task-store.js\";\n\n// ============================================================================\n// Fallback defaults for mode prompts\n// ============================================================================\n\nconst MODE_DEFAULTS: Record<string, string> = {\n\task: `You are in ASK mode — read-only Q&A.\nAnswer questions about the codebase. Trace logic, compare approaches, explain patterns.\nYou may read any file but NEVER write, edit, or execute commands.\nIf asked to make changes, refuse and suggest switching to /mode build.\nCite specific file paths and line numbers in your answers.`,\n\n\tplan: `You are in PLAN mode — exploration and planning.\nExplore the codebase thoroughly. Understand the current structure.\nDraft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.\nWrite the plan to {{PLAN_PATH}}.\nWhen the plan is complete, tell the user to run /approve to execute it.`,\n\n\tbuild: `You are in BUILD mode — careful implementation.\nRead files before editing them. Show diffs before non-trivial changes.\nAsk for confirmation before destructive operations (delete, reformat).\nRun tests after every logical unit of work.\nPrefer the smallest change that achieves the goal.\nFollow existing code patterns and conventions.`,\n\n\tdebug: `You are in DEBUG mode — root cause analysis.\nGather evidence: read files, check logs, reproduce the issue.\nTrace the call path from entry to failure point.\nState the root cause in one sentence.\nDescribe the fix precisely but do NOT apply it.\nTo fix, switch to /mode build.`,\n};\n\n// ============================================================================\n// Shared paths\n// ============================================================================\n\nconst HOOCODE_DIR = getHooCodeDir();\nconst GLOBAL_CONFIG_PATH = join(HOOCODE_DIR, \"hoo-config.json\");\n\n/**\n * Per-session plan file path. Keying on sessionId lets concurrent or resumed\n * plan sessions keep distinct plans instead of clobbering each other.\n */\nfunction getPlanPath(cwd: string, sessionId: string): string {\n\treturn join(cwd, \".hoocode\", \"plans\", `${sessionId}.md`);\n}\n\n/** Legacy single-file plan location, retained as a read-only fallback for /approve. */\nfunction getLegacyPlanPath(cwd: string): string {\n\treturn join(cwd, \".hoocode\", \"plan.md\");\n}\n\n// ============================================================================\n// Config types\n// ============================================================================\n\ninterface ModeConfig {\n\t/** Tool names that bypass the permission gate in this mode */\n\tauto_allow?: string[];\n\t/** Tool names available in this mode (if set, only these tools are active) */\n\tenabled_tools?: string[];\n\t/** Tool names explicitly blocked in this mode regardless of enabled_tools */\n\tdenied_tools?: string[];\n\t/** Allowed write paths in this mode (glob patterns, only applies if write/edit is enabled) */\n\tallowed_write_paths?: string[];\n\t/** Regex patterns for allowed bash commands. If set, a command must match at least one to execute. */\n\tallowed_bash_commands?: string[];\n\t/** Regex patterns for denied bash commands. A command matching any pattern is blocked. */\n\tdenied_bash_commands?: string[];\n}\n\nexport interface HooConfig {\n\t/** Manually-pinned active mode (overrides default \"build\") */\n\tactive_mode?: string;\n\t/** Per-mode configuration keyed by mode name */\n\tmodes?: Record<string, ModeConfig>;\n\t/** Extra directories to search for `{name}/system.md` mode files (after project + user). */\n\tmode_paths?: string[];\n}\n\n// ============================================================================\n// Config I/O and merging\n// ============================================================================\n\nfunction readConfig(): HooConfig {\n\ttry {\n\t\treturn JSON.parse(readFileSync(GLOBAL_CONFIG_PATH, \"utf8\")) as HooConfig;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeConfig(config: HooConfig): void {\n\tif (!existsSync(HOOCODE_DIR)) mkdirSync(HOOCODE_DIR, { recursive: true });\n\twriteFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n}\n\n/**\n * Deep-merges a project-local config on top of the global config.\n *\n * Merge rules:\n * - active_mode: project wins if set\n * - modes[x].auto_allow: union of global + project arrays\n * - modes[x].allowed_write_paths: union of global + project arrays\n * - modes[x].enabled_tools: project wins if set, else falls back to global\n * - mode_paths: project list is prepended so project paths are searched first\n */\nexport function mergeConfigs(global: HooConfig, project: HooConfig): HooConfig {\n\tconst merged: HooConfig = { ...global };\n\n\tif (project.active_mode !== undefined) merged.active_mode = project.active_mode;\n\n\tif (project.modes) {\n\t\tmerged.modes = { ...(global.modes ?? {}) };\n\t\tfor (const [mode, projectCfg] of Object.entries(project.modes)) {\n\t\t\tconst globalCfg = global.modes?.[mode] ?? {};\n\t\t\tmerged.modes[mode] = {\n\t\t\t\t...globalCfg,\n\t\t\t\t...projectCfg,\n\t\t\t\t// Union both auto_allow lists so project can extend, not just replace\n\t\t\t\tauto_allow: Array.from(new Set([...(globalCfg.auto_allow ?? []), ...(projectCfg.auto_allow ?? [])])),\n\t\t\t\t// Union allowed_write_paths so project can extend\n\t\t\t\tallowed_write_paths: Array.from(\n\t\t\t\t\tnew Set([...(globalCfg.allowed_write_paths ?? []), ...(projectCfg.allowed_write_paths ?? [])]),\n\t\t\t\t),\n\t\t\t\t// enabled_tools: project wins if set, else falls back to global\n\t\t\t\tenabled_tools: projectCfg.enabled_tools ?? globalCfg.enabled_tools,\n\t\t\t\t// denied_tools: union so project can add more denied tools on top of global\n\t\t\t\tdenied_tools: Array.from(new Set([...(globalCfg.denied_tools ?? []), ...(projectCfg.denied_tools ?? [])])),\n\t\t\t\t// allowed_bash_commands: project wins if set, else falls back to global\n\t\t\t\tallowed_bash_commands: projectCfg.allowed_bash_commands ?? globalCfg.allowed_bash_commands,\n\t\t\t\t// denied_bash_commands: union so project can add more denied patterns on top of global\n\t\t\t\tdenied_bash_commands: Array.from(\n\t\t\t\t\tnew Set([...(globalCfg.denied_bash_commands ?? []), ...(projectCfg.denied_bash_commands ?? [])]),\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t}\n\n\tif (project.mode_paths || global.mode_paths) {\n\t\t// Project paths first so they're searched before global paths\n\t\tmerged.mode_paths = dedupePaths([...(project.mode_paths ?? []), ...(global.mode_paths ?? [])]);\n\t}\n\n\treturn merged;\n}\n\nfunction dedupePaths(paths: string[]): string[] {\n\tconst seen = new Set<string>();\n\tconst out: string[] = [];\n\tfor (const p of paths) {\n\t\tif (!seen.has(p)) {\n\t\t\tseen.add(p);\n\t\t\tout.push(p);\n\t\t}\n\t}\n\treturn out;\n}\n\nfunction mergeSearchPaths(...sources: (string[] | undefined)[]): string[] {\n\tconst merged: string[] = [];\n\tfor (const source of sources) {\n\t\tif (!source) continue;\n\t\tmerged.push(...source);\n\t}\n\treturn dedupePaths(merged);\n}\n\n/**\n * Reads the global config and optionally overlays the project-local config at\n * `./.hoocode/hoo-config.json`. Project values win on all scalar fields; arrays are\n * unioned (see mergeConfigs for full rules).\n */\nexport function readMergedConfig(cwd: string): HooConfig {\n\tconst global = readConfig();\n\tconst projectPath = join(cwd, \".hoocode\", \"hoo-config.json\");\n\tif (!existsSync(projectPath)) return global;\n\ttry {\n\t\tconst project = JSON.parse(readFileSync(projectPath, \"utf8\")) as HooConfig;\n\t\treturn mergeConfigs(global, project);\n\t} catch {\n\t\treturn global;\n\t}\n}\n\n// ============================================================================\n// A. Permission Gate\n// ============================================================================\n\nconst GATED_TOOLS = new Set([\"bash\", \"write\", \"edit\"]);\n\n/**\n * Checks if a file path matches any of the allowed patterns.\n * Supports glob patterns with * and exact paths.\n */\nfunction matchesAllowedPath(filePath: string, allowedPatterns: string[]): boolean {\n\tif (allowedPatterns.length === 0) return true;\n\tfor (const pattern of allowedPatterns) {\n\t\t// Exact match\n\t\tif (pattern === filePath) return true;\n\t\t// Glob pattern matching for *\n\t\tif (pattern.includes(\"*\")) {\n\t\t\tconst regex = new RegExp(`^${pattern.replace(/\\*/g, \".*\")}$`);\n\t\t\tif (regex.test(filePath)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Tests a bash command string against a regex pattern string.\n * Returns false (no match) if the pattern is an invalid regex.\n */\nfunction matchesBashPattern(pattern: string, command: string): boolean {\n\ttry {\n\t\treturn new RegExp(pattern).test(command);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction describeTool(event: ToolCallEvent): string {\n\tif (isToolCallEventType(\"bash\", event)) {\n\t\treturn `$ ${event.input.command.replace(/\\s+/g, \" \").slice(0, 100)}`;\n\t}\n\tif (isToolCallEventType(\"edit\", event)) {\n\t\tconst p = (event.input as { file_path?: string }).file_path ?? \"(unknown)\";\n\t\treturn `edit ${p}`;\n\t}\n\tif (isToolCallEventType(\"write\", event)) {\n\t\tconst p = (event.input as { file_path?: string }).file_path ?? \"(unknown)\";\n\t\treturn `write ${p}`;\n\t}\n\treturn event.toolName;\n}\n\nexport function setupPermissionGate(pi: ExtensionAPI): void {\n\tpi.on(\"tool_call\", async (event: ToolCallEvent, ctx: ExtensionContext): Promise<ToolCallEventResult | undefined> => {\n\t\t// Use the merged config so project-local entries are respected\n\t\tconst config = readMergedConfig(ctx.cwd);\n\t\tconst mode = config.active_mode ?? \"build\";\n\t\tconst modeCfg = config.modes?.[mode];\n\n\t\t// ── Hard enforcement (always applies, regardless of UI) ───────────────────\n\n\t\t// Explicitly denied tools are blocked unconditionally\n\t\tif (modeCfg?.denied_tools?.includes(event.toolName)) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: `Tool \"${event.toolName}\" is denied in mode \"${mode}\".`,\n\t\t\t};\n\t\t}\n\n\t\t// enabled_tools acts as a strict allowlist: only listed tools may execute\n\t\tif (\n\t\t\tmodeCfg?.enabled_tools &&\n\t\t\tmodeCfg.enabled_tools.length > 0 &&\n\t\t\t!modeCfg.enabled_tools.includes(event.toolName)\n\t\t) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason:\n\t\t\t\t\t`Tool \"${event.toolName}\" is not enabled in mode \"${mode}\" ` +\n\t\t\t\t\t`(enabled: ${modeCfg.enabled_tools.join(\", \")}).`,\n\t\t\t};\n\t\t}\n\n\t\t// Bash command-level filtering\n\t\tif (isToolCallEventType(\"bash\", event)) {\n\t\t\tconst command = (event.input as { command?: string }).command ?? \"\";\n\n\t\t\t// denied_bash_commands: block if any pattern matches\n\t\t\tif (modeCfg?.denied_bash_commands?.length) {\n\t\t\t\tfor (const pattern of modeCfg.denied_bash_commands) {\n\t\t\t\t\tif (matchesBashPattern(pattern, command)) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tblock: true,\n\t\t\t\t\t\t\treason: `Bash command matches a denied pattern in mode \"${mode}\": ${pattern}`,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// allowed_bash_commands: block unless at least one pattern matches\n\t\t\tif (modeCfg?.allowed_bash_commands?.length) {\n\t\t\t\tconst permitted = modeCfg.allowed_bash_commands.some((p) => matchesBashPattern(p, command));\n\t\t\t\tif (!permitted) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tblock: true,\n\t\t\t\t\t\treason:\n\t\t\t\t\t\t\t`Bash command is not permitted in mode \"${mode}\". ` +\n\t\t\t\t\t\t\t`Allowed patterns: ${modeCfg.allowed_bash_commands.join(\", \")}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// ── UI-based permission prompting (interactive sessions only) ─────────────\n\n\t\tif (!GATED_TOOLS.has(event.toolName) || !ctx.hasUI) return;\n\n\t\tconst autoAllow = modeCfg?.auto_allow ?? [];\n\n\t\t// Check allowed_write_paths for write/edit operations\n\t\tif ((event.toolName === \"write\" || event.toolName === \"edit\") && modeCfg?.allowed_write_paths) {\n\t\t\tconst filePath = (event.input as { file_path?: string }).file_path ?? \"\";\n\t\t\tif (!matchesAllowedPath(filePath, modeCfg.allowed_write_paths)) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\treason:\n\t\t\t\t\t\t`Mode \"${mode}\" only allows writes to: ${modeCfg.allowed_write_paths.join(\", \")}. ` +\n\t\t\t\t\t\t`Attempted to ${event.toolName}: ${filePath}. ` +\n\t\t\t\t\t\t`Switch to \"/mode build\" to modify source files.`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif (autoAllow.includes(event.toolName)) return;\n\n\t\tconst choice = await ctx.ui.select(`Allow: ${describeTool(event)}`, [\n\t\t\t\"Yes (once)\",\n\t\t\t\"No (block)\",\n\t\t\t\"Always (add to auto-allow for this mode)\",\n\t\t]);\n\n\t\tif (!choice || choice.startsWith(\"No\")) {\n\t\t\treturn { block: true, reason: \"Denied by permission gate\" };\n\t\t}\n\n\t\tif (choice.startsWith(\"Always\")) {\n\t\t\t// Write \"always\" choices to the global config only\n\t\t\tconst latest = readConfig();\n\t\t\tconst currentMode = latest.active_mode ?? \"build\";\n\t\t\tlatest.modes ??= {};\n\t\t\tlatest.modes[currentMode] ??= {};\n\t\t\tlatest.modes[currentMode].auto_allow = Array.from(\n\t\t\t\tnew Set([...(latest.modes[currentMode].auto_allow ?? []), event.toolName]),\n\t\t\t);\n\t\t\twriteConfig(latest);\n\t\t\tctx.ui.notify(`\"${event.toolName}\" added to auto-allow for mode \"${currentMode}\"`, \"info\");\n\t\t}\n\t});\n}\n\n// ============================================================================\n// B. MCP Server Loader\n// ============================================================================\n\ninterface McpToolDef {\n\tname: string;\n\tdescription: string;\n\tinputSchema?: {\n\t\ttype?: string;\n\t\tproperties?: Record<string, { type?: string; description?: string }>;\n\t\trequired?: string[];\n\t};\n}\n\nexport interface McpServerConfig {\n\t/** Unique server identifier used as prefix for registered tool names */\n\tname: string;\n\t/** Executable to spawn */\n\tcommand: string;\n\t/** Optional arguments passed to the command */\n\targs?: string[];\n\t/** Optional extra environment variables for the server process */\n\tenv?: Record<string, string>;\n\t/** Run MCP tools in background by default (default: true for MCP servers) */\n\tbackground?: boolean;\n}\n\n/** Standard MCP config format used by Claude Desktop and other tools */\ninterface StandardMcpServerConfig {\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n\tbackground?: boolean;\n}\n\ninterface StandardMcpConfig {\n\tmcpServers?: Record<string, StandardMcpServerConfig>;\n}\n\ninterface McpConnection {\n\trpc(method: string, params?: unknown): Promise<unknown>;\n\tterminate(): void;\n}\n\nconst mcpConnections = new Map<string, McpConnection>();\n\nfunction spawnMcpServer(config: McpServerConfig): McpConnection {\n\tconst proc: ChildProcess = spawn(config.command, config.args ?? [], {\n\t\tenv: { ...process.env, ...(config.env ?? {}) },\n\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t});\n\n\tlet nextId = 1;\n\tconst pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n\n\tconst rl = createInterface({ input: proc.stdout! });\n\trl.on(\"line\", (line) => {\n\t\tif (!line.trim()) return;\n\t\ttry {\n\t\t\tconst msg = JSON.parse(line) as {\n\t\t\t\tid?: number;\n\t\t\t\tresult?: unknown;\n\t\t\t\terror?: { message: string };\n\t\t\t};\n\t\t\tif (msg.id === undefined) return;\n\t\t\tconst cb = pending.get(msg.id);\n\t\t\tif (!cb) return;\n\t\t\tpending.delete(msg.id);\n\t\t\tif (msg.error) cb.reject(new Error(msg.error.message));\n\t\t\telse cb.resolve(msg.result);\n\t\t} catch {\n\t\t\t// ignore non-JSON server startup output\n\t\t}\n\t});\n\n\tproc.on(\"exit\", () => {\n\t\tfor (const cb of pending.values()) cb.reject(new Error(`MCP server \"${config.name}\" exited unexpectedly`));\n\t\tpending.clear();\n\t\tmcpConnections.delete(config.name);\n\t});\n\n\tfunction rpc(method: string, params?: unknown): Promise<unknown> {\n\t\tconst id = nextId++;\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tpending.set(id, { resolve, reject });\n\t\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\treturn {\n\t\trpc,\n\t\tterminate: () => {\n\t\t\trl.close();\n\t\t\tproc.kill();\n\t\t},\n\t};\n}\n\nasync function connectMcpServer(config: McpServerConfig): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tmcpConnections.get(config.name)?.terminate();\n\n\tconst conn = spawnMcpServer(config);\n\tmcpConnections.set(config.name, conn);\n\n\tawait conn.rpc(\"initialize\", {\n\t\tprotocolVersion: \"2024-11-05\",\n\t\tcapabilities: { tools: {} },\n\t\tclientInfo: { name: \"hoocode\", version: \"1.0.0\" },\n\t});\n\n\tconst toolsResult = (await conn.rpc(\"tools/list\", {})) as {\n\t\ttools?: McpToolDef[];\n\t};\n\treturn { conn, tools: toolsResult.tools ?? [] };\n}\n\nfunction buildMcpSchema(tool: McpToolDef): ReturnType<typeof Type.Object> {\n\tconst props = tool.inputSchema?.properties ?? {};\n\tconst required = new Set(tool.inputSchema?.required ?? []);\n\tconst shape: Record<string, ReturnType<typeof Type.String>> = {};\n\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tlet field: ReturnType<typeof Type.String>;\n\t\tswitch (prop.type) {\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.String({ description: prop.description });\n\t\t}\n\t\tshape[key] = required.has(key) ? field : (Type.Optional(field) as unknown as ReturnType<typeof Type.String>);\n\t}\n\n\treturn Type.Object(shape);\n}\n\n/**\n * Parse standard MCP config format (used by Claude Desktop, VS Code, etc.)\n * into hoocode's McpServerConfig format.\n */\nfunction parseStandardMcpConfig(config: StandardMcpConfig, _source: string): McpServerConfig[] {\n\tif (!config.mcpServers) return [];\n\n\tconst servers: McpServerConfig[] = [];\n\tfor (const [name, serverConfig] of Object.entries(config.mcpServers)) {\n\t\tservers.push({\n\t\t\tname,\n\t\t\tcommand: serverConfig.command,\n\t\t\targs: serverConfig.args,\n\t\t\tenv: serverConfig.env,\n\t\t\tbackground: serverConfig.background,\n\t\t});\n\t}\n\treturn servers;\n}\n\n/**\n * Load MCP servers from a standard mcp.json file.\n * Returns an array of McpServerConfig, or empty array if file doesn't exist or is invalid.\n */\nfunction loadStandardMcpFile(filePath: string): McpServerConfig[] {\n\tif (!existsSync(filePath)) return [];\n\n\ttry {\n\t\tconst content = readFileSync(filePath, \"utf8\");\n\t\tconst config = JSON.parse(content) as StandardMcpConfig;\n\t\treturn parseStandardMcpConfig(config, filePath);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function setupMcpLoader(pi: ExtensionAPI): void {\n\tpi.on(\"session_start\", async (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\tconst allServerConfigs: McpServerConfig[] = [];\n\t\tconst seenNames = new Set<string>();\n\n\t\t// 1. Load from standard mcp.json locations\n\t\t// User-level: ~/.agents/mcp.json\n\t\tconst userAgentsConfig = loadStandardMcpFile(join(homedir(), \".agents\", \"mcp.json\"));\n\t\tfor (const config of userAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Project-level: ./.agents/mcp.json\n\t\tconst projectAgentsConfig = loadStandardMcpFile(join(ctx.cwd, \".agents\", \"mcp.json\"));\n\t\tfor (const config of projectAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Claude Desktop: ~/.config/claude/mcp.json\n\t\tconst claudeDesktopConfig = loadStandardMcpFile(join(homedir(), \".config\", \"claude\", \"mcp.json\"));\n\t\tfor (const config of claudeDesktopConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// 2. Load from hoocode's per-server format (existing behavior)\n\t\tconst searchDirs = [join(HOOCODE_DIR, \"mcp-servers\"), join(ctx.cwd, \".hoocode\", \"mcp-servers\")];\n\n\t\tfor (const dir of searchDirs) {\n\t\t\tif (!existsSync(dir)) continue;\n\n\t\t\tlet files: string[];\n\t\t\ttry {\n\t\t\t\tfiles = (await readdir(dir)).filter((f) => f.endsWith(\".json\"));\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst cfgPath = join(dir, file);\n\t\t\t\tlet serverConfig: McpServerConfig;\n\n\t\t\t\ttry {\n\t\t\t\t\tserverConfig = JSON.parse(readFileSync(cfgPath, \"utf8\")) as McpServerConfig;\n\t\t\t\t\tif (!serverConfig.name || !serverConfig.command) {\n\t\t\t\t\t\tctx.ui.notify(`MCP: config \"${file}\" is missing required \"name\" or \"command\"`, \"warning\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.ui.notify(`MCP: failed to parse \"${file}\": ${String(err)}`, \"error\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Skip if already loaded from standard config\n\t\t\t\tif (seenNames.has(serverConfig.name)) continue;\n\t\t\t\tseenNames.add(serverConfig.name);\n\t\t\t\tallServerConfigs.push(serverConfig);\n\t\t\t}\n\t\t}\n\n\t\t// 3. Connect to all servers and register tools\n\t\tfor (const serverConfig of allServerConfigs) {\n\t\t\ttry {\n\t\t\t\tconst { tools } = await connectMcpServer(serverConfig);\n\n\t\t\t\tfor (const tool of tools) {\n\t\t\t\t\tconst toolName = `mcp_${serverConfig.name}_${tool.name}`;\n\t\t\t\t\tconst schema = buildMcpSchema(tool);\n\t\t\t\t\tconst capturedServer = serverConfig.name;\n\t\t\t\t\tconst capturedTool = tool.name;\n\t\t\t\t\t// MCP tools default to background mode since they are external processes with potential high latency\n\t\t\t\t\tconst isBackground = serverConfig.background !== false;\n\n\t\t\t\t\tpi.registerTool({\n\t\t\t\t\t\tname: toolName,\n\t\t\t\t\t\tlabel: `[MCP] ${serverConfig.name} › ${tool.name}`,\n\t\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\t\tparameters: schema,\n\t\t\t\t\t\tbackground: isBackground,\n\t\t\t\t\t\tasync execute(\n\t\t\t\t\t\t\t_toolCallId: string,\n\t\t\t\t\t\t\tparams: Static<typeof schema>,\n\t\t\t\t\t\t\tsignal: AbortSignal,\n\t\t\t\t\t\t\t_onUpdate: AgentToolUpdateCallback,\n\t\t\t\t\t\t): Promise<AgentToolResult<undefined>> {\n\t\t\t\t\t\t\t// Background MCP tools get a task store entry so they appear in the task pane.\n\t\t\t\t\t\t\t// Foreground tools skip this (their result is awaited inline).\n\t\t\t\t\t\t\tconst task = isBackground ? taskStore.create(`${capturedServer} › ${capturedTool}`) : undefined;\n\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"in_progress\" });\n\n\t\t\t\t\t\t\tconst activeConn = mcpConnections.get(capturedServer);\n\t\t\t\t\t\t\tif (!activeConn) {\n\t\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\t\ttext: `MCP server \"${capturedServer}\" is not connected`,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst abortPromise = new Promise<never>((_, reject) => {\n\t\t\t\t\t\t\t\t\tsignal.addEventListener(\"abort\", () => reject(new Error(\"Aborted\")));\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\t\t\t\t\tactiveConn.rpc(\"tools/call\", {\n\t\t\t\t\t\t\t\t\t\tname: capturedTool,\n\t\t\t\t\t\t\t\t\t\targuments: params,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\tabortPromise,\n\t\t\t\t\t\t\t\t]);\n\n\t\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"done\" });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst bgMode = serverConfig.background !== false ? \"background\" : \"foreground\";\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`MCP: connected \"${serverConfig.name}\" (${tools.length} tool${tools.length === 1 ? \"\" : \"s\"}, ${bgMode})`,\n\t\t\t\t\t\"info\",\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tctx.ui.notify(`MCP: failed to connect \"${serverConfig.name}\": ${String(err)}`, \"error\");\n\t\t\t}\n\t\t}\n\t});\n}\n\n// ============================================================================\n// C. Mode System\n// ============================================================================\n\nconst DEFAULT_MODE = \"build\";\n\nfunction tryReadFile(path: string): string | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst text = readFileSync(path, \"utf8\").trim();\n\t\treturn text || undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Walks search dirs in precedence order and returns the first existing\n * `modes/{name}/system.md` content. Order: project → user → externalDirs.\n */\nfunction resolveModeFile(name: string, cwd: string, externalDirs: string[]): string | undefined {\n\tconst candidates: string[] = [\n\t\tjoin(cwd, \".hoocode\", \"modes\", name, \"system.md\"),\n\t\tjoin(HOOCODE_DIR, \"modes\", name, \"system.md\"),\n\t\t...externalDirs.map((dir) => join(dir, name, \"system.md\")),\n\t];\n\tfor (const candidate of candidates) {\n\t\tconst content = tryReadFile(candidate);\n\t\tif (content !== undefined) return content;\n\t}\n\treturn undefined;\n}\n\n/**\n * Returns the system prompt for the active mode.\n *\n * Search order (first hit wins):\n * - `./.hoocode/modes/{mode}/system.md`\n * - `~/.hoocode/modes/{mode}/system.md`\n * - each of `externalDirs` in declared order (config + CLI + extension contributions)\n * - built-in MODE_DEFAULTS for the four known modes\n */\nexport function buildSystemPrompt(mode: string, cwd: string, options?: { modePaths?: string[] }): string | undefined {\n\tconst modePaths = options?.modePaths ?? [];\n\treturn resolveModeFile(mode, cwd, modePaths) ?? MODE_DEFAULTS[mode];\n}\n\n// ============================================================================\n// Plan file: section parsing and step-by-step execution message\n// ============================================================================\n\nexport interface PlanSections {\n\tgoal?: string;\n\tfilesToModify?: string;\n\tnewFiles?: string;\n\ttests?: string;\n\tverification?: string;\n\t/** Original full text, used as fallback if no sections parsed */\n\traw: string;\n}\n\n/**\n * Parses `.hoocode/plan.md` into named sections.\n *\n * Recognises both ATX headings (`## Goal`) and bold labels (`**Goal**`).\n * Section names matched (case-insensitive): Goal, Files to modify, New files,\n * Tests, Verification.\n */\nexport function parsePlanSections(planContent: string): PlanSections {\n\tconst result: PlanSections = { raw: planContent };\n\n\t// Match `## Heading text` or `**Heading text**` followed by content until\n\t// the next heading of the same style.\n\tconst sectionPattern =\n\t\t/^(?:#{1,3}\\s+(.+?)|(?:\\*\\*(.+?)\\*\\*))\\s*\\n([\\s\\S]*?)(?=(?:^#{1,3}\\s+|\\*\\*[^*\\n]+\\*\\*\\s*\\n)|$)/gm;\n\n\tfor (const match of planContent.matchAll(sectionPattern)) {\n\t\tconst heading = (match[1] ?? match[2] ?? \"\").toLowerCase().trim();\n\t\tconst content = match[3].trim();\n\t\tif (!content) continue;\n\n\t\tif (/^goal/.test(heading)) {\n\t\t\tresult.goal = content;\n\t\t} else if (/files?\\s+to\\s+modif|^modif/.test(heading)) {\n\t\t\tresult.filesToModify = content;\n\t\t} else if (/new\\s+files?/.test(heading)) {\n\t\t\tresult.newFiles = content;\n\t\t} else if (/^tests?/.test(heading)) {\n\t\t\tresult.tests = content;\n\t\t} else if (/^verif/.test(heading)) {\n\t\t\tresult.verification = content;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Builds the user message sent to the agent when `/approve` is run.\n *\n * If the plan has recognisable sections, each is presented as a numbered step\n * so the agent works through them sequentially. Otherwise the raw plan is used.\n *\n * Execution order:\n * 1. Modify existing files\n * 2. Create new files\n * 3. Update / add tests\n * 4. Run verification commands\n */\nexport function buildApproveMessage(sections: PlanSections): string {\n\tconst steps: string[] = [];\n\n\tif (sections.goal) {\n\t\tsteps.push(`**Goal:** ${sections.goal}`);\n\t}\n\tif (sections.filesToModify) {\n\t\tsteps.push(`**Step 1 — Modify existing files:**\\n${sections.filesToModify}`);\n\t}\n\tif (sections.newFiles) {\n\t\tsteps.push(`**Step 2 — Create new files:**\\n${sections.newFiles}`);\n\t}\n\tif (sections.tests) {\n\t\tsteps.push(`**Step 3 — Update tests:**\\n${sections.tests}`);\n\t}\n\tif (sections.verification) {\n\t\tsteps.push(`**Step 4 — Verify:**\\n${sections.verification}`);\n\t}\n\n\tif (steps.length === 0) {\n\t\treturn `Execute the following plan:\\n\\n${sections.raw}`;\n\t}\n\n\treturn `Execute this plan step by step. Complete each step fully before moving to the next.\\n\\n${steps.join(\"\\n\\n\")}`;\n}\n\n// ============================================================================\n// C. setupMode\n// ============================================================================\n\nexport function setupMode(pi: ExtensionAPI): void {\n\tlet cachedMode = DEFAULT_MODE;\n\tlet cachedSystemPrompt: string | undefined;\n\tlet cachedPlanPath: string | undefined;\n\n\t// ── session_start ─────────────────────────────────────────────────────────\n\t// Config resolution order:\n\t// 1. Read global config (~/.hoocode/hoo-config.json)\n\t// 2. Read project config (./.hoocode/hoo-config.json) if present\n\t// 3. Merge — project scalars win; arrays are unioned\n\t// 4. Re-resolve active_mode from the merged result\n\n\tpi.on(\"session_start\", (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\t// Steps 1–3: merge global + project configs\n\t\tconst config = readMergedConfig(ctx.cwd);\n\n\t\t// Step 4: resolve mode from the merged config\n\t\tcachedMode = config.active_mode ?? DEFAULT_MODE;\n\t\t// External search dirs come from two channels:\n\t\t// - HooConfig.mode_paths (config-declared)\n\t\t// - pi.addModeSearchPath (CLI flags + extension contributions)\n\t\tconst modePaths = mergeSearchPaths(config.mode_paths, pi.getModeSearchPaths());\n\t\tconst rawSystemPrompt = buildSystemPrompt(cachedMode, ctx.cwd, { modePaths });\n\n\t\t// Per-session plan path so concurrent sessions don't overwrite each other.\n\t\t// The `{{PLAN_PATH}}` token in plan-mode templates is substituted here.\n\t\tcachedPlanPath = getPlanPath(ctx.cwd, ctx.sessionManager.getSessionId());\n\t\tconst relPlanPath = relative(ctx.cwd, cachedPlanPath) || cachedPlanPath;\n\t\tcachedSystemPrompt = rawSystemPrompt?.replace(/\\{\\{PLAN_PATH\\}\\}/g, relPlanPath);\n\n\t\t// Update footer with active mode\n\t\tif (ctx.hasUI) {\n\t\t\tctx.ui.setMode(cachedMode);\n\t\t}\n\n\t\t// Apply tool filter from mode enabled_tools\n\t\tconst modeCfg = config.modes?.[cachedMode];\n\t\tif (modeCfg?.enabled_tools && modeCfg.enabled_tools.length > 0) {\n\t\t\tpi.setActiveTools(modeCfg.enabled_tools);\n\t\t}\n\t});\n\n\t// ── before_agent_start ────────────────────────────────────────────────────\n\n\tpi.on(\"before_agent_start\", (event: BeforeAgentStartEvent): BeforeAgentStartEventResult | undefined => {\n\t\tif (!cachedSystemPrompt) return;\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n\\n<!-- hoo-core: mode=${cachedMode} -->\\n${cachedSystemPrompt}`,\n\t\t};\n\t});\n\n\t// ── /mode command ─────────────────────────────────────────────────────────\n\n\tconst KNOWN_MODES = [\"ask\", \"plan\", \"build\", \"debug\"];\n\n\tpi.registerCommand(\"mode\", {\n\t\tdescription: \"Switch active mode. Usage: /mode <ask|plan|build|debug>\",\n\t\tgetArgumentCompletions: (prefix: string) =>\n\t\t\tKNOWN_MODES.filter((m) => m.startsWith(prefix)).map((m) => ({ value: m, label: m })),\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tif (!name) {\n\t\t\t\tctx.ui.notify(`Active mode: ${cachedMode}`, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst config = readConfig();\n\t\t\tconfig.active_mode = name === DEFAULT_MODE ? undefined : name;\n\t\t\twriteConfig(config);\n\t\t\tctx.ui.notify(`Mode set to \"${name}\" — reloading…`, \"info\");\n\t\t\tawait ctx.reload();\n\t\t},\n\t});\n\n\t// ── /plan command (shorthand for /mode plan) ──────────────────────────────\n\n\tpi.registerCommand(\"plan\", {\n\t\tdescription: \"Switch to plan mode. Shorthand for /mode plan.\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst config = readConfig();\n\t\t\tconfig.active_mode = \"plan\";\n\t\t\twriteConfig(config);\n\t\t\tctx.ui.notify(`Mode set to \"plan\" — reloading…`, \"info\");\n\t\t\tawait ctx.reload();\n\t\t},\n\t});\n\n\t// ── /approve command ──────────────────────────────────────────────────────\n\t// Reads .hoocode/plan.md, parses it into named sections (Goal, Files to\n\t// modify, New files, Tests, Verification), switches to build mode, then\n\t// injects a step-by-step execution message into the new session.\n\n\tpi.registerCommand(\"approve\", {\n\t\tdescription: \"Approve the current plan and switch to build mode to execute it.\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tif (cachedMode !== \"plan\") {\n\t\t\t\tctx.ui.notify(`/approve is only available in plan mode (current mode: \"${cachedMode}\")`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prefer the per-session plan file, fall back to the legacy single file.\n\t\t\tconst sessionPlanPath = cachedPlanPath ?? getPlanPath(ctx.cwd, ctx.sessionManager.getSessionId());\n\t\t\tconst candidatePaths = [sessionPlanPath, getLegacyPlanPath(ctx.cwd)];\n\t\t\tlet approveMessage: string | undefined;\n\n\t\t\tfor (const planPath of candidatePaths) {\n\t\t\t\tif (!existsSync(planPath)) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = readFileSync(planPath, \"utf8\").trim();\n\t\t\t\t\tif (raw) {\n\t\t\t\t\t\tconst sections = parsePlanSections(raw);\n\t\t\t\t\t\tapproveMessage = buildApproveMessage(sections);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tctx.ui.notify(`Could not read ${relative(ctx.cwd, planPath) || planPath}`, \"error\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Switch global config to build mode\n\t\t\tconst config = readConfig();\n\t\t\tconfig.active_mode = \"build\";\n\t\t\twriteConfig(config);\n\n\t\t\tif (approveMessage) {\n\t\t\t\t// Open a new build-mode session and deliver the parsed plan as the\n\t\t\t\t// first user message so the agent starts executing immediately\n\t\t\t\tawait ctx.newSession({\n\t\t\t\t\twithSession: async (replacedCtx) => {\n\t\t\t\t\t\tawait replacedCtx.sendUserMessage(approveMessage!, { deliverAs: \"followUp\" });\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst relPlan = relative(ctx.cwd, sessionPlanPath) || sessionPlanPath;\n\t\t\t\tctx.ui.notify(`Switched to build mode. No ${relPlan} found — describe what to build.`, \"info\");\n\t\t\t\tawait ctx.reload();\n\t\t\t}\n\t\t},\n\t});\n\n\t// ── /cost command ─────────────────────────────────────────────────────────\n\t// Walks every assistant message in the current session and sums tokens + cost,\n\t// then prints a session total followed by a per-model breakdown.\n\t// Per-tool attribution is intentionally not shown — tokens aren't tracked\n\t// per-tool, and any heuristic would be misleading.\n\n\tpi.registerCommand(\"cost\", {\n\t\tdescription: \"Show session token and cost totals, broken down by model.\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\ttype Totals = { input: number; output: number; cacheRead: number; cacheWrite: number; cost: number };\n\t\t\tconst empty = (): Totals => ({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 });\n\t\t\tconst total = empty();\n\t\t\tconst perModel = new Map<string, Totals>();\n\t\t\tlet assistantTurns = 0;\n\n\t\t\tfor (const entry of ctx.sessionManager.getEntries()) {\n\t\t\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\") continue;\n\t\t\t\tconst u = entry.message.usage;\n\t\t\t\tif (!u) continue;\n\t\t\t\tassistantTurns++;\n\t\t\t\ttotal.input += u.input;\n\t\t\t\ttotal.output += u.output;\n\t\t\t\ttotal.cacheRead += u.cacheRead;\n\t\t\t\ttotal.cacheWrite += u.cacheWrite;\n\t\t\t\ttotal.cost += u.cost.total;\n\n\t\t\t\tconst key = `${entry.message.provider}/${entry.message.model}`;\n\t\t\t\tconst t = perModel.get(key) ?? empty();\n\t\t\t\tt.input += u.input;\n\t\t\t\tt.output += u.output;\n\t\t\t\tt.cacheRead += u.cacheRead;\n\t\t\t\tt.cacheWrite += u.cacheWrite;\n\t\t\t\tt.cost += u.cost.total;\n\t\t\t\tperModel.set(key, t);\n\t\t\t}\n\n\t\t\tif (assistantTurns === 0) {\n\t\t\t\tctx.ui.notify(\"No assistant turns yet — nothing to cost.\", \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst fmt = (n: number) => n.toLocaleString();\n\t\t\tconst fmtCost = (n: number) => `$${n.toFixed(4)}`;\n\t\t\tconst lines: string[] = [];\n\t\t\tlines.push(`Session totals (${assistantTurns} assistant turn${assistantTurns === 1 ? \"\" : \"s\"})`);\n\t\t\tlines.push(` Input ${fmt(total.input)}`);\n\t\t\tlines.push(` Output ${fmt(total.output)}`);\n\t\t\tlines.push(` Cache read ${fmt(total.cacheRead)}`);\n\t\t\tlines.push(` Cache write ${fmt(total.cacheWrite)}`);\n\t\t\tlines.push(` Cost ${fmtCost(total.cost)}`);\n\n\t\t\tif (perModel.size > 1) {\n\t\t\t\tlines.push(\"\");\n\t\t\t\tlines.push(\"By model:\");\n\t\t\t\tconst sorted = [...perModel.entries()].sort((a, b) => b[1].cost - a[1].cost);\n\t\t\t\tfor (const [key, t] of sorted) {\n\t\t\t\t\tlines.push(` ${key}: ${fmt(t.input)} in / ${fmt(t.output)} out ${fmtCost(t.cost)}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tctx.ui.notify(lines.join(\"\\n\"), \"info\");\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Scaffold commands — /new-skill, /new-agent, and /new-command\n// ============================================================================\n\n/** Validates a resource name: lowercase a-z, 0-9, hyphens, no leading/trailing/double hyphens. */\nfunction validateResourceName(name: string): string | null {\n\tif (!name) return \"name is required\";\n\tif (!/^[a-z0-9-]+$/.test(name)) return \"name must be lowercase a-z, 0-9, and hyphens only\";\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) return \"name must not start or end with a hyphen\";\n\tif (name.includes(\"--\")) return \"name must not contain consecutive hyphens\";\n\treturn null;\n}\n\nfunction setupScaffold(pi: ExtensionAPI): void {\n\t// ── /new-skill <name> ─────────────────────────────────────────────────────\n\t// Creates .hoocode/skills/<name>/SKILL.md with a valid Agent Skills frontmatter\n\t// template so the file is ready to edit and will be picked up on next reload.\n\n\tpi.registerCommand(\"new-skill\", {\n\t\tdescription: \"Scaffold a new skill. Usage: /new-skill <name>\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tconst error = validateResourceName(name);\n\t\t\tif (error) {\n\t\t\t\tctx.ui.notify(`/new-skill: ${error}. Usage: /new-skill <name>`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst skillDir = join(ctx.cwd, \".hoocode\", \"skills\", name);\n\t\t\tconst skillFile = join(skillDir, \"SKILL.md\");\n\n\t\t\tif (existsSync(skillFile)) {\n\t\t\t\tctx.ui.notify(`/new-skill: ${skillFile} already exists`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmkdirSync(skillDir, { recursive: true });\n\t\t\twriteFileSync(\n\t\t\t\tskillFile,\n\t\t\t\t[\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`name: ${name}`,\n\t\t\t\t\t\"description: |\",\n\t\t\t\t\t\" TODO: describe when to use this skill — one clear sentence per bullet.\",\n\t\t\t\t\t\" The model reads this to decide whether to load the skill.\",\n\t\t\t\t\t\"allowed-tools: read, bash\",\n\t\t\t\t\t\"---\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t`# ${name}`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"TODO: write the skill instructions here.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"When relative paths appear below, they are resolved from this file's directory.\",\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"utf8\",\n\t\t\t);\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Skill created: ${join(\".hoocode\", \"skills\", name, \"SKILL.md\")}\\nEdit the file, then run /reload to activate it.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n\n\t// ── /new-agent <name> ─────────────────────────────────────────────────────\n\t// Creates .hoocode/agents/<name>.md following the Claude Code subagent standard\n\t// (name, description, tools comma-string, model alias, optional background).\n\n\tpi.registerCommand(\"new-agent\", {\n\t\tdescription: \"Scaffold a new subagent. Usage: /new-agent <name>\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tconst error = validateResourceName(name);\n\t\t\tif (error) {\n\t\t\t\tctx.ui.notify(`/new-agent: ${error}. Usage: /new-agent <name>`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst agentsDir = join(ctx.cwd, \".hoocode\", \"agents\");\n\t\t\tconst agentFile = join(agentsDir, `${name}.md`);\n\n\t\t\tif (existsSync(agentFile)) {\n\t\t\t\tctx.ui.notify(`/new-agent: ${agentFile} already exists`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmkdirSync(agentsDir, { recursive: true });\n\t\t\twriteFileSync(\n\t\t\t\tagentFile,\n\t\t\t\t[\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`name: ${name}`,\n\t\t\t\t\t\"description: |\",\n\t\t\t\t\t\" Use this subagent ONLY when:\",\n\t\t\t\t\t\" - TODO: describe the task(s) to delegate here\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\" DO NOT use for:\",\n\t\t\t\t\t\" - TODO: describe what this agent should NOT handle\",\n\t\t\t\t\t\"tools: read, bash\",\n\t\t\t\t\t\"model: sonnet\",\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`You are a ${name} subagent running inside hoocode.`,\n\t\t\t\t\t\"You run in an isolated context and cannot see the parent conversation.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"TODO: write the system prompt here.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Your final message must contain ONLY your answer — it is the only output\",\n\t\t\t\t\t\"the caller receives. Do not include intermediate reasoning or tool logs.\",\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"utf8\",\n\t\t\t);\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Agent created: ${join(\".hoocode\", \"agents\", `${name}.md`)}\\nEdit the file, then run /reload to activate it.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n\n\t// ── /new-command <name> ───────────────────────────────────────────────────\n\t// Creates .hoocode/commands/<name>.md with a slash-command prompt-template\n\t// frontmatter (name, description, argument-hint) so it is ready to edit and\n\t// picked up on next reload. Body supports $1, $@, $ARGUMENTS placeholders.\n\n\tpi.registerCommand(\"new-command\", {\n\t\tdescription: \"Scaffold a new slash command. Usage: /new-command <name>\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tconst error = validateResourceName(name);\n\t\t\tif (error) {\n\t\t\t\tctx.ui.notify(`/new-command: ${error}. Usage: /new-command <name>`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst commandsDir = join(ctx.cwd, \".hoocode\", \"commands\");\n\t\t\tconst commandFile = join(commandsDir, `${name}.md`);\n\n\t\t\tif (existsSync(commandFile)) {\n\t\t\t\tctx.ui.notify(`/new-command: ${commandFile} already exists`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmkdirSync(commandsDir, { recursive: true });\n\t\t\twriteFileSync(\n\t\t\t\tcommandFile,\n\t\t\t\t[\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`name: ${name}`,\n\t\t\t\t\t\"description: |\",\n\t\t\t\t\t` TODO: describe what /${name} does and when to use it.`,\n\t\t\t\t\t` Usage: /${name} <args>`,\n\t\t\t\t\t\"argument-hint: <args>\",\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`Run the /${name} command with arguments: **$ARGUMENTS**.`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"TODO: write the instructions here. Placeholders you can use:\",\n\t\t\t\t\t\"- $1, $2, ... for positional arguments\",\n\t\t\t\t\t\"- $@ or $ARGUMENTS for all arguments\",\n\t\t\t\t\t`- $${\"{\"}@:N} / $${\"{\"}@:N:L} for bash-style slices`,\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"utf8\",\n\t\t\t);\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Command created: ${join(\".hoocode\", \"commands\", `${name}.md`)}\\nEdit the file, then run /reload to activate it.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n}\n\n// ============================================================================\n// D. Options pane — ask_options tool\n// ============================================================================\n\n// The model calls this tool when it needs the user to make a decision before\n// continuing. Each question is shown in an inline options pane where the user\n// moves with up/down, advances with right, and may type a custom answer.\nconst askOptionsSchema = Type.Object({\n\tquestions: Type.Array(\n\t\tType.Object({\n\t\t\tquestion: Type.String({ description: \"The question to ask the user.\" }),\n\t\t\tdetail: Type.Optional(Type.String({ description: \"Optional clarifying sub-text shown under the question.\" })),\n\t\t\toptions: Type.Array(\n\t\t\t\tType.Object({\n\t\t\t\t\tlabel: Type.String({ description: \"The option text; returned verbatim when chosen.\" }),\n\t\t\t\t\tdescription: Type.Optional(\n\t\t\t\t\t\tType.String({ description: \"Optional short description shown next to the option.\" }),\n\t\t\t\t\t),\n\t\t\t\t\trecommended: Type.Optional(\n\t\t\t\t\t\tType.Boolean({\n\t\t\t\t\t\t\tdescription: \"When true, the option is marked '(recommended)' to help the user choose.\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t\t{ description: \"The options the user can choose from.\" },\n\t\t\t),\n\t\t\tallow_custom: Type.Optional(\n\t\t\t\tType.Boolean({\n\t\t\t\t\tdescription: \"When true, the user can type a free-form answer instead of choosing an option.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"One or more decisions to ask the user, in order.\" },\n\t),\n});\n\nexport function setupAskOptions(pi: ExtensionAPI): void {\n\t// Capture the latest context so the tool can reach the interactive UI.\n\tlet activeCtx: ExtensionContext | undefined;\n\tpi.on(\"session_start\", (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\tactiveCtx = ctx;\n\t});\n\n\tpi.registerTool({\n\t\tname: \"ask_options\",\n\t\tlabel: \"Ask the user\",\n\t\tdescription:\n\t\t\t\"Ask the user to make one or more decisions before continuing. Each question is presented \" +\n\t\t\t\"in an interactive options pane where the user selects an option (or types a custom answer). \" +\n\t\t\t\"Use this when you genuinely need input to proceed and cannot reasonably decide yourself. \" +\n\t\t\t\"Returns the user's answer for each question; if the user skips, no answers are returned.\",\n\t\tparameters: askOptionsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId: string,\n\t\t\tparams: Static<typeof askOptionsSchema>,\n\t\t\tsignal: AbortSignal,\n\t\t\t_onUpdate: AgentToolUpdateCallback,\n\t\t): Promise<AgentToolResult<undefined>> {\n\t\t\tif (!activeCtx || !activeCtx.hasUI) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Cannot ask the user: no interactive UI is available in this session. Proceed using your best judgement.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!params.questions.length) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"No questions were provided.\" }],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst questions: AskQuestion[] = params.questions.map((q) => ({\n\t\t\t\tquestion: q.question,\n\t\t\t\tdetail: q.detail,\n\t\t\t\toptions: q.options.map((o) => ({ label: o.label, description: o.description, recommended: o.recommended })),\n\t\t\t\tallowCustom: q.allow_custom,\n\t\t\t}));\n\n\t\t\tconst answers = await activeCtx.ui.askOptions(questions, { signal });\n\n\t\t\tif (!answers) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"The user skipped the question(s) without answering. Ask how they would like to proceed.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst text = questions.map((q, i) => `${q.question}\\n \\u2192 ${answers[i] ?? \"(no answer)\"}`).join(\"\\n\\n\");\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Extension entry point\n// ============================================================================\n\nfunction hooCore(pi: ExtensionAPI): void {\n\tsetupPermissionGate(pi);\n\tsetupMcpLoader(pi);\n\tsetupMode(pi);\n\tsetupScaffold(pi);\n\tsetupAskOptions(pi);\n}\n\nhooCore.displayName = \"hoo-core\";\nexport default hooCore;\n"]}
1
+ {"version":3,"file":"hoo-core.js","sourceRoot":"","sources":["../../../src/extensions/core/hoo-core.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * hoo-core — HooCode built-in core extension\n *\n * A. Permission Gate — prompts before bash/write/edit; checks modes.{mode}.auto_allow\n * from the merged (global + project) config; persists \"always\"\n * choices back to the global config\n * B. MCP Server Loader — discovers ~/.hoocode/mcp-servers and ./.hoocode/mcp-servers JSON\n * configs, connects via JSON-RPC 2.0, registers server tools\n * C. Mode — resolves active mode (ask/plan/build/debug), loads the mode's\n * system prompt, filters active tools, and exposes /mode, /plan,\n * and /approve commands\n *\n * Config merge order (lowest → highest priority):\n * 1. ~/.hoocode/hoo-config.json (global defaults)\n * 2. ./.hoocode/hoo-config.json (project overrides — scalars win; arrays union)\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, relative } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { getHooCodeDir } from \"../../config.js\";\nimport type {\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAskQuestion,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tSessionStartEvent,\n\tToolCallEvent,\n\tToolCallEventResult,\n} from \"../../core/extensions/types.js\";\nimport { isToolCallEventType } from \"../../core/extensions/types.js\";\nimport { summarizeArgs } from \"../../core/messages.js\";\nimport { taskStore } from \"../../core/task-store.js\";\n\n// ============================================================================\n// Fallback defaults for mode prompts\n// ============================================================================\n\nconst MODE_DEFAULTS: Record<string, string> = {\n\task: `You are in ASK mode — read-only Q&A.\nAnswer questions about the codebase. Trace logic, compare approaches, explain patterns.\nYou may read any file but NEVER write, edit, or execute commands.\nIf asked to make changes, refuse and suggest switching to /mode build.\nCite specific file paths and line numbers in your answers.`,\n\n\tplan: `You are in PLAN mode — exploration and planning.\nExplore the codebase thoroughly. Understand the current structure.\nDraft a complete plan with sections: Goal, Files to modify, New files, Tests, Verification.\nWrite the plan to {{PLAN_PATH}}.\nWhen the plan is complete, tell the user to run /approve to execute it.`,\n\n\tbuild: `You are in BUILD mode — careful implementation.\nRead files before editing them. Show diffs before non-trivial changes.\nAsk for confirmation before destructive operations (delete, reformat).\nRun tests after every logical unit of work.\nPrefer the smallest change that achieves the goal.\nFollow existing code patterns and conventions.`,\n\n\tdebug: `You are in DEBUG mode — root cause analysis.\nGather evidence: read files, check logs, reproduce the issue.\nTrace the call path from entry to failure point.\nState the root cause in one sentence.\nDescribe the fix precisely but do NOT apply it.\nTo fix, switch to /mode build.`,\n};\n\n// ============================================================================\n// Shared paths\n// ============================================================================\n\nconst HOOCODE_DIR = getHooCodeDir();\nconst GLOBAL_CONFIG_PATH = join(HOOCODE_DIR, \"hoo-config.json\");\n\n/**\n * Per-session plan file path. Keying on sessionId lets concurrent or resumed\n * plan sessions keep distinct plans instead of clobbering each other.\n */\nfunction getPlanPath(cwd: string, sessionId: string): string {\n\treturn join(cwd, \".hoocode\", \"plans\", `${sessionId}.md`);\n}\n\n/** Legacy single-file plan location, retained as a read-only fallback for /approve. */\nfunction getLegacyPlanPath(cwd: string): string {\n\treturn join(cwd, \".hoocode\", \"plan.md\");\n}\n\n// ============================================================================\n// Config types\n// ============================================================================\n\ninterface ModeConfig {\n\t/** Tool names that bypass the permission gate in this mode */\n\tauto_allow?: string[];\n\t/** Tool names available in this mode (if set, only these tools are active) */\n\tenabled_tools?: string[];\n\t/** Tool names explicitly blocked in this mode regardless of enabled_tools */\n\tdenied_tools?: string[];\n\t/** Allowed write paths in this mode (glob patterns, only applies if write/edit is enabled) */\n\tallowed_write_paths?: string[];\n\t/** Regex patterns for allowed bash commands. If set, a command must match at least one to execute. */\n\tallowed_bash_commands?: string[];\n\t/** Regex patterns for denied bash commands. A command matching any pattern is blocked. */\n\tdenied_bash_commands?: string[];\n}\n\nexport interface HooConfig {\n\t/** Manually-pinned active mode (overrides default \"build\") */\n\tactive_mode?: string;\n\t/** Per-mode configuration keyed by mode name */\n\tmodes?: Record<string, ModeConfig>;\n\t/** Extra directories to search for `{name}/system.md` mode files (after project + user). */\n\tmode_paths?: string[];\n}\n\n// ============================================================================\n// Config I/O and merging\n// ============================================================================\n\nfunction readConfig(): HooConfig {\n\ttry {\n\t\treturn JSON.parse(readFileSync(GLOBAL_CONFIG_PATH, \"utf8\")) as HooConfig;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeConfig(config: HooConfig): void {\n\tif (!existsSync(HOOCODE_DIR)) mkdirSync(HOOCODE_DIR, { recursive: true });\n\twriteFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n}\n\n/**\n * Deep-merges a project-local config on top of the global config.\n *\n * Merge rules:\n * - active_mode: project wins if set\n * - modes[x].auto_allow: union of global + project arrays\n * - modes[x].allowed_write_paths: union of global + project arrays\n * - modes[x].enabled_tools: project wins if set, else falls back to global\n * - mode_paths: project list is prepended so project paths are searched first\n */\nexport function mergeConfigs(global: HooConfig, project: HooConfig): HooConfig {\n\tconst merged: HooConfig = { ...global };\n\n\tif (project.active_mode !== undefined) merged.active_mode = project.active_mode;\n\n\tif (project.modes) {\n\t\tmerged.modes = { ...(global.modes ?? {}) };\n\t\tfor (const [mode, projectCfg] of Object.entries(project.modes)) {\n\t\t\tconst globalCfg = global.modes?.[mode] ?? {};\n\t\t\tmerged.modes[mode] = {\n\t\t\t\t...globalCfg,\n\t\t\t\t...projectCfg,\n\t\t\t\t// Union both auto_allow lists so project can extend, not just replace\n\t\t\t\tauto_allow: Array.from(new Set([...(globalCfg.auto_allow ?? []), ...(projectCfg.auto_allow ?? [])])),\n\t\t\t\t// Union allowed_write_paths so project can extend\n\t\t\t\tallowed_write_paths: Array.from(\n\t\t\t\t\tnew Set([...(globalCfg.allowed_write_paths ?? []), ...(projectCfg.allowed_write_paths ?? [])]),\n\t\t\t\t),\n\t\t\t\t// enabled_tools: project wins if set, else falls back to global\n\t\t\t\tenabled_tools: projectCfg.enabled_tools ?? globalCfg.enabled_tools,\n\t\t\t\t// denied_tools: union so project can add more denied tools on top of global\n\t\t\t\tdenied_tools: Array.from(new Set([...(globalCfg.denied_tools ?? []), ...(projectCfg.denied_tools ?? [])])),\n\t\t\t\t// allowed_bash_commands: project wins if set, else falls back to global\n\t\t\t\tallowed_bash_commands: projectCfg.allowed_bash_commands ?? globalCfg.allowed_bash_commands,\n\t\t\t\t// denied_bash_commands: union so project can add more denied patterns on top of global\n\t\t\t\tdenied_bash_commands: Array.from(\n\t\t\t\t\tnew Set([...(globalCfg.denied_bash_commands ?? []), ...(projectCfg.denied_bash_commands ?? [])]),\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t}\n\n\tif (project.mode_paths || global.mode_paths) {\n\t\t// Project paths first so they're searched before global paths\n\t\tmerged.mode_paths = dedupePaths([...(project.mode_paths ?? []), ...(global.mode_paths ?? [])]);\n\t}\n\n\treturn merged;\n}\n\nfunction dedupePaths(paths: string[]): string[] {\n\tconst seen = new Set<string>();\n\tconst out: string[] = [];\n\tfor (const p of paths) {\n\t\tif (!seen.has(p)) {\n\t\t\tseen.add(p);\n\t\t\tout.push(p);\n\t\t}\n\t}\n\treturn out;\n}\n\nfunction mergeSearchPaths(...sources: (string[] | undefined)[]): string[] {\n\tconst merged: string[] = [];\n\tfor (const source of sources) {\n\t\tif (!source) continue;\n\t\tmerged.push(...source);\n\t}\n\treturn dedupePaths(merged);\n}\n\n/**\n * Reads the global config and optionally overlays the project-local config at\n * `./.hoocode/hoo-config.json`. Project values win on all scalar fields; arrays are\n * unioned (see mergeConfigs for full rules).\n */\nexport function readMergedConfig(cwd: string): HooConfig {\n\tconst global = readConfig();\n\tconst projectPath = join(cwd, \".hoocode\", \"hoo-config.json\");\n\tif (!existsSync(projectPath)) return global;\n\ttry {\n\t\tconst project = JSON.parse(readFileSync(projectPath, \"utf8\")) as HooConfig;\n\t\treturn mergeConfigs(global, project);\n\t} catch {\n\t\treturn global;\n\t}\n}\n\n// ============================================================================\n// A. Permission Gate\n// ============================================================================\n\nconst GATED_TOOLS = new Set([\"bash\", \"write\", \"edit\"]);\n\n/**\n * Checks if a file path matches any of the allowed patterns.\n * Supports glob patterns with * and exact paths.\n */\nfunction matchesAllowedPath(filePath: string, allowedPatterns: string[]): boolean {\n\tif (allowedPatterns.length === 0) return true;\n\tfor (const pattern of allowedPatterns) {\n\t\t// Exact match\n\t\tif (pattern === filePath) return true;\n\t\t// Glob pattern matching for *\n\t\tif (pattern.includes(\"*\")) {\n\t\t\tconst regex = new RegExp(`^${pattern.replace(/\\*/g, \".*\")}$`);\n\t\t\tif (regex.test(filePath)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Tests a bash command string against a regex pattern string.\n * Returns false (no match) if the pattern is an invalid regex.\n */\nfunction matchesBashPattern(pattern: string, command: string): boolean {\n\ttry {\n\t\treturn new RegExp(pattern).test(command);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction describeTool(event: ToolCallEvent): string {\n\tif (isToolCallEventType(\"bash\", event)) {\n\t\treturn `$ ${event.input.command.replace(/\\s+/g, \" \").slice(0, 100)}`;\n\t}\n\tif (isToolCallEventType(\"edit\", event)) {\n\t\tconst p = (event.input as { file_path?: string }).file_path ?? \"(unknown)\";\n\t\treturn `edit ${p}`;\n\t}\n\tif (isToolCallEventType(\"write\", event)) {\n\t\tconst p = (event.input as { file_path?: string }).file_path ?? \"(unknown)\";\n\t\treturn `write ${p}`;\n\t}\n\treturn event.toolName;\n}\n\nexport function setupPermissionGate(pi: ExtensionAPI): void {\n\tpi.on(\"tool_call\", async (event: ToolCallEvent, ctx: ExtensionContext): Promise<ToolCallEventResult | undefined> => {\n\t\t// Use the merged config so project-local entries are respected\n\t\tconst config = readMergedConfig(ctx.cwd);\n\t\tconst mode = config.active_mode ?? \"build\";\n\t\tconst modeCfg = config.modes?.[mode];\n\n\t\t// ── Hard enforcement (always applies, regardless of UI) ───────────────────\n\n\t\t// Explicitly denied tools are blocked unconditionally\n\t\tif (modeCfg?.denied_tools?.includes(event.toolName)) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason: `Tool \"${event.toolName}\" is denied in mode \"${mode}\".`,\n\t\t\t};\n\t\t}\n\n\t\t// enabled_tools acts as a strict allowlist: only listed tools may execute\n\t\tif (\n\t\t\tmodeCfg?.enabled_tools &&\n\t\t\tmodeCfg.enabled_tools.length > 0 &&\n\t\t\t!modeCfg.enabled_tools.includes(event.toolName)\n\t\t) {\n\t\t\treturn {\n\t\t\t\tblock: true,\n\t\t\t\treason:\n\t\t\t\t\t`Tool \"${event.toolName}\" is not enabled in mode \"${mode}\" ` +\n\t\t\t\t\t`(enabled: ${modeCfg.enabled_tools.join(\", \")}).`,\n\t\t\t};\n\t\t}\n\n\t\t// Bash command-level filtering\n\t\tif (isToolCallEventType(\"bash\", event)) {\n\t\t\tconst command = (event.input as { command?: string }).command ?? \"\";\n\n\t\t\t// denied_bash_commands: block if any pattern matches\n\t\t\tif (modeCfg?.denied_bash_commands?.length) {\n\t\t\t\tfor (const pattern of modeCfg.denied_bash_commands) {\n\t\t\t\t\tif (matchesBashPattern(pattern, command)) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tblock: true,\n\t\t\t\t\t\t\treason: `Bash command matches a denied pattern in mode \"${mode}\": ${pattern}`,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// allowed_bash_commands: block unless at least one pattern matches\n\t\t\tif (modeCfg?.allowed_bash_commands?.length) {\n\t\t\t\tconst permitted = modeCfg.allowed_bash_commands.some((p) => matchesBashPattern(p, command));\n\t\t\t\tif (!permitted) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tblock: true,\n\t\t\t\t\t\treason:\n\t\t\t\t\t\t\t`Bash command is not permitted in mode \"${mode}\". ` +\n\t\t\t\t\t\t\t`Allowed patterns: ${modeCfg.allowed_bash_commands.join(\", \")}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// ── UI-based permission prompting (interactive sessions only) ─────────────\n\n\t\tif (!GATED_TOOLS.has(event.toolName) || !ctx.hasUI) return;\n\n\t\tconst autoAllow = modeCfg?.auto_allow ?? [];\n\n\t\t// Check allowed_write_paths for write/edit operations\n\t\tif ((event.toolName === \"write\" || event.toolName === \"edit\") && modeCfg?.allowed_write_paths) {\n\t\t\tconst filePath = (event.input as { file_path?: string }).file_path ?? \"\";\n\t\t\tif (!matchesAllowedPath(filePath, modeCfg.allowed_write_paths)) {\n\t\t\t\treturn {\n\t\t\t\t\tblock: true,\n\t\t\t\t\treason:\n\t\t\t\t\t\t`Mode \"${mode}\" only allows writes to: ${modeCfg.allowed_write_paths.join(\", \")}. ` +\n\t\t\t\t\t\t`Attempted to ${event.toolName}: ${filePath}. ` +\n\t\t\t\t\t\t`Switch to \"/mode build\" to modify source files.`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif (autoAllow.includes(event.toolName)) return;\n\n\t\tconst choice = await ctx.ui.select(`Allow: ${describeTool(event)}`, [\n\t\t\t\"Yes (once)\",\n\t\t\t\"No (block)\",\n\t\t\t\"Always (add to auto-allow for this mode)\",\n\t\t]);\n\n\t\tif (!choice || choice.startsWith(\"No\")) {\n\t\t\treturn { block: true, reason: \"Denied by permission gate\" };\n\t\t}\n\n\t\tif (choice.startsWith(\"Always\")) {\n\t\t\t// Write \"always\" choices to the global config only\n\t\t\tconst latest = readConfig();\n\t\t\tconst currentMode = latest.active_mode ?? \"build\";\n\t\t\tlatest.modes ??= {};\n\t\t\tlatest.modes[currentMode] ??= {};\n\t\t\tlatest.modes[currentMode].auto_allow = Array.from(\n\t\t\t\tnew Set([...(latest.modes[currentMode].auto_allow ?? []), event.toolName]),\n\t\t\t);\n\t\t\twriteConfig(latest);\n\t\t\tctx.ui.notify(`\"${event.toolName}\" added to auto-allow for mode \"${currentMode}\"`, \"info\");\n\t\t}\n\t});\n}\n\n// ============================================================================\n// B. MCP Server Loader\n// ============================================================================\n\ninterface McpToolDef {\n\tname: string;\n\tdescription: string;\n\tinputSchema?: {\n\t\ttype?: string;\n\t\tproperties?: Record<string, { type?: string; description?: string }>;\n\t\trequired?: string[];\n\t};\n}\n\nexport interface McpServerConfig {\n\t/** Unique server identifier used as prefix for registered tool names */\n\tname: string;\n\t/** Executable to spawn */\n\tcommand: string;\n\t/** Optional arguments passed to the command */\n\targs?: string[];\n\t/** Optional extra environment variables for the server process */\n\tenv?: Record<string, string>;\n\t/** Run MCP tools in background by default (default: true for MCP servers) */\n\tbackground?: boolean;\n}\n\n/** Standard MCP config format used by Claude Desktop and other tools */\ninterface StandardMcpServerConfig {\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n\tbackground?: boolean;\n}\n\ninterface StandardMcpConfig {\n\tmcpServers?: Record<string, StandardMcpServerConfig>;\n}\n\ninterface McpConnection {\n\trpc(method: string, params?: unknown): Promise<unknown>;\n\tterminate(): void;\n}\n\nconst mcpConnections = new Map<string, McpConnection>();\n\nfunction spawnMcpServer(config: McpServerConfig): McpConnection {\n\tconst proc: ChildProcess = spawn(config.command, config.args ?? [], {\n\t\tenv: { ...process.env, ...(config.env ?? {}) },\n\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t});\n\n\tlet nextId = 1;\n\tconst pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n\n\tconst rl = createInterface({ input: proc.stdout! });\n\trl.on(\"line\", (line) => {\n\t\tif (!line.trim()) return;\n\t\ttry {\n\t\t\tconst msg = JSON.parse(line) as {\n\t\t\t\tid?: number;\n\t\t\t\tresult?: unknown;\n\t\t\t\terror?: { message: string };\n\t\t\t};\n\t\t\tif (msg.id === undefined) return;\n\t\t\tconst cb = pending.get(msg.id);\n\t\t\tif (!cb) return;\n\t\t\tpending.delete(msg.id);\n\t\t\tif (msg.error) cb.reject(new Error(msg.error.message));\n\t\t\telse cb.resolve(msg.result);\n\t\t} catch {\n\t\t\t// ignore non-JSON server startup output\n\t\t}\n\t});\n\n\tproc.on(\"exit\", () => {\n\t\tfor (const cb of pending.values()) cb.reject(new Error(`MCP server \"${config.name}\" exited unexpectedly`));\n\t\tpending.clear();\n\t\tmcpConnections.delete(config.name);\n\t});\n\n\tfunction rpc(method: string, params?: unknown): Promise<unknown> {\n\t\tconst id = nextId++;\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tpending.set(id, { resolve, reject });\n\t\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\treturn {\n\t\trpc,\n\t\tterminate: () => {\n\t\t\trl.close();\n\t\t\tproc.kill();\n\t\t},\n\t};\n}\n\nasync function connectMcpServer(config: McpServerConfig): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tmcpConnections.get(config.name)?.terminate();\n\n\tconst conn = spawnMcpServer(config);\n\tmcpConnections.set(config.name, conn);\n\n\tawait conn.rpc(\"initialize\", {\n\t\tprotocolVersion: \"2024-11-05\",\n\t\tcapabilities: { tools: {} },\n\t\tclientInfo: { name: \"hoocode\", version: \"1.0.0\" },\n\t});\n\n\tconst toolsResult = (await conn.rpc(\"tools/list\", {})) as {\n\t\ttools?: McpToolDef[];\n\t};\n\treturn { conn, tools: toolsResult.tools ?? [] };\n}\n\nfunction buildMcpSchema(tool: McpToolDef): ReturnType<typeof Type.Object> {\n\tconst props = tool.inputSchema?.properties ?? {};\n\tconst required = new Set(tool.inputSchema?.required ?? []);\n\tconst shape: Record<string, ReturnType<typeof Type.String>> = {};\n\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tlet field: ReturnType<typeof Type.String>;\n\t\tswitch (prop.type) {\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.String({ description: prop.description });\n\t\t}\n\t\tshape[key] = required.has(key) ? field : (Type.Optional(field) as unknown as ReturnType<typeof Type.String>);\n\t}\n\n\treturn Type.Object(shape);\n}\n\n/**\n * Parse standard MCP config format (used by Claude Desktop, VS Code, etc.)\n * into hoocode's McpServerConfig format.\n */\nfunction parseStandardMcpConfig(config: StandardMcpConfig, _source: string): McpServerConfig[] {\n\tif (!config.mcpServers) return [];\n\n\tconst servers: McpServerConfig[] = [];\n\tfor (const [name, serverConfig] of Object.entries(config.mcpServers)) {\n\t\tservers.push({\n\t\t\tname,\n\t\t\tcommand: serverConfig.command,\n\t\t\targs: serverConfig.args,\n\t\t\tenv: serverConfig.env,\n\t\t\tbackground: serverConfig.background,\n\t\t});\n\t}\n\treturn servers;\n}\n\n/**\n * Load MCP servers from a standard mcp.json file.\n * Returns an array of McpServerConfig, or empty array if file doesn't exist or is invalid.\n */\nfunction loadStandardMcpFile(filePath: string): McpServerConfig[] {\n\tif (!existsSync(filePath)) return [];\n\n\ttry {\n\t\tconst content = readFileSync(filePath, \"utf8\");\n\t\tconst config = JSON.parse(content) as StandardMcpConfig;\n\t\treturn parseStandardMcpConfig(config, filePath);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function setupMcpLoader(pi: ExtensionAPI): void {\n\tpi.on(\"session_start\", async (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\tconst allServerConfigs: McpServerConfig[] = [];\n\t\tconst seenNames = new Set<string>();\n\n\t\t// 1. Load from standard mcp.json locations\n\t\t// User-level: ~/.agents/mcp.json\n\t\tconst userAgentsConfig = loadStandardMcpFile(join(homedir(), \".agents\", \"mcp.json\"));\n\t\tfor (const config of userAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Project-level: ./.agents/mcp.json\n\t\tconst projectAgentsConfig = loadStandardMcpFile(join(ctx.cwd, \".agents\", \"mcp.json\"));\n\t\tfor (const config of projectAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Claude Desktop: ~/.config/claude/mcp.json\n\t\tconst claudeDesktopConfig = loadStandardMcpFile(join(homedir(), \".config\", \"claude\", \"mcp.json\"));\n\t\tfor (const config of claudeDesktopConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// 2. Load from hoocode's per-server format (existing behavior)\n\t\tconst searchDirs = [join(HOOCODE_DIR, \"mcp-servers\"), join(ctx.cwd, \".hoocode\", \"mcp-servers\")];\n\n\t\tfor (const dir of searchDirs) {\n\t\t\tif (!existsSync(dir)) continue;\n\n\t\t\tlet files: string[];\n\t\t\ttry {\n\t\t\t\tfiles = (await readdir(dir)).filter((f) => f.endsWith(\".json\"));\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst cfgPath = join(dir, file);\n\t\t\t\tlet serverConfig: McpServerConfig;\n\n\t\t\t\ttry {\n\t\t\t\t\tserverConfig = JSON.parse(readFileSync(cfgPath, \"utf8\")) as McpServerConfig;\n\t\t\t\t\tif (!serverConfig.name || !serverConfig.command) {\n\t\t\t\t\t\tctx.ui.notify(`MCP: config \"${file}\" is missing required \"name\" or \"command\"`, \"warning\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.ui.notify(`MCP: failed to parse \"${file}\": ${String(err)}`, \"error\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Skip if already loaded from standard config\n\t\t\t\tif (seenNames.has(serverConfig.name)) continue;\n\t\t\t\tseenNames.add(serverConfig.name);\n\t\t\t\tallServerConfigs.push(serverConfig);\n\t\t\t}\n\t\t}\n\n\t\t// 3. Connect to all servers and register tools\n\t\tfor (const serverConfig of allServerConfigs) {\n\t\t\ttry {\n\t\t\t\tconst { tools } = await connectMcpServer(serverConfig);\n\n\t\t\t\tfor (const tool of tools) {\n\t\t\t\t\tconst toolName = `mcp_${serverConfig.name}_${tool.name}`;\n\t\t\t\t\tconst schema = buildMcpSchema(tool);\n\t\t\t\t\tconst capturedServer = serverConfig.name;\n\t\t\t\t\tconst capturedTool = tool.name;\n\t\t\t\t\t// MCP tools default to background mode since they are external processes with potential high latency\n\t\t\t\t\tconst isBackground = serverConfig.background !== false;\n\n\t\t\t\t\tpi.registerTool({\n\t\t\t\t\t\tname: toolName,\n\t\t\t\t\t\tlabel: `[MCP] ${serverConfig.name} › ${tool.name}`,\n\t\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\t\tparameters: schema,\n\t\t\t\t\t\tbackground: isBackground,\n\t\t\t\t\t\t// Render a clean, prefixed title in chat — `MCP [server › tool] <args>` —\n\t\t\t\t\t\t// parallel to the subagent `Task [type] <desc>` line. Without this the\n\t\t\t\t\t\t// ToolExecutionComponent falls back to the raw `mcp_<server>_<tool>` name.\n\t\t\t\t\t\t// The args summary reuses the same helper as the background start/finish\n\t\t\t\t\t\t// messages so the chat title stays in sync with them.\n\t\t\t\t\t\trenderCall(args, theme) {\n\t\t\t\t\t\t\tconst summary = summarizeArgs((args ?? {}) as Record<string, unknown>);\n\t\t\t\t\t\t\tconst text =\n\t\t\t\t\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"MCP \")) +\n\t\t\t\t\t\t\t\ttheme.fg(\"accent\", `[${capturedServer} › ${capturedTool}]`) +\n\t\t\t\t\t\t\t\t(summary ? theme.fg(\"dim\", ` ${summary}`) : \"\");\n\t\t\t\t\t\t\treturn new Text(text, 0, 0);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tasync execute(\n\t\t\t\t\t\t\t_toolCallId: string,\n\t\t\t\t\t\t\tparams: Static<typeof schema>,\n\t\t\t\t\t\t\tsignal: AbortSignal,\n\t\t\t\t\t\t\t_onUpdate: AgentToolUpdateCallback,\n\t\t\t\t\t\t): Promise<AgentToolResult<undefined>> {\n\t\t\t\t\t\t\t// Background MCP tools get a task store entry so they appear in the task pane.\n\t\t\t\t\t\t\t// Foreground tools skip this (their result is awaited inline).\n\t\t\t\t\t\t\tconst task = isBackground\n\t\t\t\t\t\t\t\t? taskStore.create(`${capturedServer} › ${capturedTool}`, { source: \"mcp\" })\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"in_progress\" });\n\n\t\t\t\t\t\t\tconst activeConn = mcpConnections.get(capturedServer);\n\t\t\t\t\t\t\tif (!activeConn) {\n\t\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\t\ttext: `MCP server \"${capturedServer}\" is not connected`,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst abortPromise = new Promise<never>((_, reject) => {\n\t\t\t\t\t\t\t\t\tsignal.addEventListener(\"abort\", () => reject(new Error(\"Aborted\")));\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\t\t\t\t\tactiveConn.rpc(\"tools/call\", {\n\t\t\t\t\t\t\t\t\t\tname: capturedTool,\n\t\t\t\t\t\t\t\t\t\targuments: params,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\tabortPromise,\n\t\t\t\t\t\t\t\t]);\n\n\t\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"done\" });\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst bgMode = serverConfig.background !== false ? \"background\" : \"foreground\";\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`MCP: connected \"${serverConfig.name}\" (${tools.length} tool${tools.length === 1 ? \"\" : \"s\"}, ${bgMode})`,\n\t\t\t\t\t\"info\",\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tctx.ui.notify(`MCP: failed to connect \"${serverConfig.name}\": ${String(err)}`, \"error\");\n\t\t\t}\n\t\t}\n\t});\n}\n\n// ============================================================================\n// C. Mode System\n// ============================================================================\n\nconst DEFAULT_MODE = \"build\";\n\nfunction tryReadFile(path: string): string | undefined {\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst text = readFileSync(path, \"utf8\").trim();\n\t\treturn text || undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Walks search dirs in precedence order and returns the first existing\n * `modes/{name}/system.md` content. Order: project → user → externalDirs.\n */\nfunction resolveModeFile(name: string, cwd: string, externalDirs: string[]): string | undefined {\n\tconst candidates: string[] = [\n\t\tjoin(cwd, \".hoocode\", \"modes\", name, \"system.md\"),\n\t\tjoin(HOOCODE_DIR, \"modes\", name, \"system.md\"),\n\t\t...externalDirs.map((dir) => join(dir, name, \"system.md\")),\n\t];\n\tfor (const candidate of candidates) {\n\t\tconst content = tryReadFile(candidate);\n\t\tif (content !== undefined) return content;\n\t}\n\treturn undefined;\n}\n\n/**\n * Returns the system prompt for the active mode.\n *\n * Search order (first hit wins):\n * - `./.hoocode/modes/{mode}/system.md`\n * - `~/.hoocode/modes/{mode}/system.md`\n * - each of `externalDirs` in declared order (config + CLI + extension contributions)\n * - built-in MODE_DEFAULTS for the four known modes\n */\nexport function buildSystemPrompt(mode: string, cwd: string, options?: { modePaths?: string[] }): string | undefined {\n\tconst modePaths = options?.modePaths ?? [];\n\treturn resolveModeFile(mode, cwd, modePaths) ?? MODE_DEFAULTS[mode];\n}\n\n// ============================================================================\n// Plan file: section parsing and step-by-step execution message\n// ============================================================================\n\nexport interface PlanSections {\n\tgoal?: string;\n\tfilesToModify?: string;\n\tnewFiles?: string;\n\ttests?: string;\n\tverification?: string;\n\t/** Original full text, used as fallback if no sections parsed */\n\traw: string;\n}\n\n/**\n * Parses `.hoocode/plan.md` into named sections.\n *\n * Recognises both ATX headings (`## Goal`) and bold labels (`**Goal**`).\n * Section names matched (case-insensitive): Goal, Files to modify, New files,\n * Tests, Verification.\n */\nexport function parsePlanSections(planContent: string): PlanSections {\n\tconst result: PlanSections = { raw: planContent };\n\n\t// Match `## Heading text` or `**Heading text**` followed by content until\n\t// the next heading of the same style.\n\tconst sectionPattern =\n\t\t/^(?:#{1,3}\\s+(.+?)|(?:\\*\\*(.+?)\\*\\*))\\s*\\n([\\s\\S]*?)(?=(?:^#{1,3}\\s+|\\*\\*[^*\\n]+\\*\\*\\s*\\n)|$)/gm;\n\n\tfor (const match of planContent.matchAll(sectionPattern)) {\n\t\tconst heading = (match[1] ?? match[2] ?? \"\").toLowerCase().trim();\n\t\tconst content = match[3].trim();\n\t\tif (!content) continue;\n\n\t\tif (/^goal/.test(heading)) {\n\t\t\tresult.goal = content;\n\t\t} else if (/files?\\s+to\\s+modif|^modif/.test(heading)) {\n\t\t\tresult.filesToModify = content;\n\t\t} else if (/new\\s+files?/.test(heading)) {\n\t\t\tresult.newFiles = content;\n\t\t} else if (/^tests?/.test(heading)) {\n\t\t\tresult.tests = content;\n\t\t} else if (/^verif/.test(heading)) {\n\t\t\tresult.verification = content;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Builds the user message sent to the agent when `/approve` is run.\n *\n * If the plan has recognisable sections, each is presented as a numbered step\n * so the agent works through them sequentially. Otherwise the raw plan is used.\n *\n * Execution order:\n * 1. Modify existing files\n * 2. Create new files\n * 3. Update / add tests\n * 4. Run verification commands\n */\nexport function buildApproveMessage(sections: PlanSections): string {\n\tconst steps: string[] = [];\n\n\tif (sections.goal) {\n\t\tsteps.push(`**Goal:** ${sections.goal}`);\n\t}\n\tif (sections.filesToModify) {\n\t\tsteps.push(`**Step 1 — Modify existing files:**\\n${sections.filesToModify}`);\n\t}\n\tif (sections.newFiles) {\n\t\tsteps.push(`**Step 2 — Create new files:**\\n${sections.newFiles}`);\n\t}\n\tif (sections.tests) {\n\t\tsteps.push(`**Step 3 — Update tests:**\\n${sections.tests}`);\n\t}\n\tif (sections.verification) {\n\t\tsteps.push(`**Step 4 — Verify:**\\n${sections.verification}`);\n\t}\n\n\tif (steps.length === 0) {\n\t\treturn `Execute the following plan:\\n\\n${sections.raw}`;\n\t}\n\n\treturn `Execute this plan step by step. Complete each step fully before moving to the next.\\n\\n${steps.join(\"\\n\\n\")}`;\n}\n\n// ============================================================================\n// C. setupMode\n// ============================================================================\n\nexport function setupMode(pi: ExtensionAPI): void {\n\tlet cachedMode = DEFAULT_MODE;\n\tlet cachedSystemPrompt: string | undefined;\n\tlet cachedPlanPath: string | undefined;\n\n\t// ── session_start ─────────────────────────────────────────────────────────\n\t// Config resolution order:\n\t// 1. Read global config (~/.hoocode/hoo-config.json)\n\t// 2. Read project config (./.hoocode/hoo-config.json) if present\n\t// 3. Merge — project scalars win; arrays are unioned\n\t// 4. Re-resolve active_mode from the merged result\n\n\tpi.on(\"session_start\", (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\t// Steps 1–3: merge global + project configs\n\t\tconst config = readMergedConfig(ctx.cwd);\n\n\t\t// Step 4: resolve mode from the merged config\n\t\tcachedMode = config.active_mode ?? DEFAULT_MODE;\n\t\t// External search dirs come from two channels:\n\t\t// - HooConfig.mode_paths (config-declared)\n\t\t// - pi.addModeSearchPath (CLI flags + extension contributions)\n\t\tconst modePaths = mergeSearchPaths(config.mode_paths, pi.getModeSearchPaths());\n\t\tconst rawSystemPrompt = buildSystemPrompt(cachedMode, ctx.cwd, { modePaths });\n\n\t\t// Per-session plan path so concurrent sessions don't overwrite each other.\n\t\t// The `{{PLAN_PATH}}` token in plan-mode templates is substituted here.\n\t\tcachedPlanPath = getPlanPath(ctx.cwd, ctx.sessionManager.getSessionId());\n\t\tconst relPlanPath = relative(ctx.cwd, cachedPlanPath) || cachedPlanPath;\n\t\tcachedSystemPrompt = rawSystemPrompt?.replace(/\\{\\{PLAN_PATH\\}\\}/g, relPlanPath);\n\n\t\t// Update footer with active mode\n\t\tif (ctx.hasUI) {\n\t\t\tctx.ui.setMode(cachedMode);\n\t\t}\n\n\t\t// Apply tool filter from mode enabled_tools\n\t\tconst modeCfg = config.modes?.[cachedMode];\n\t\tif (modeCfg?.enabled_tools && modeCfg.enabled_tools.length > 0) {\n\t\t\tpi.setActiveTools(modeCfg.enabled_tools);\n\t\t}\n\t});\n\n\t// ── before_agent_start ────────────────────────────────────────────────────\n\n\tpi.on(\"before_agent_start\", (event: BeforeAgentStartEvent): BeforeAgentStartEventResult | undefined => {\n\t\tif (!cachedSystemPrompt) return;\n\t\treturn {\n\t\t\tsystemPrompt: `${event.systemPrompt}\\n\\n<!-- hoo-core: mode=${cachedMode} -->\\n${cachedSystemPrompt}`,\n\t\t};\n\t});\n\n\t// ── /mode command ─────────────────────────────────────────────────────────\n\n\tconst KNOWN_MODES = [\"ask\", \"plan\", \"build\", \"debug\"];\n\n\tpi.registerCommand(\"mode\", {\n\t\tdescription: \"Switch active mode. Usage: /mode <ask|plan|build|debug>\",\n\t\tgetArgumentCompletions: (prefix: string) =>\n\t\t\tKNOWN_MODES.filter((m) => m.startsWith(prefix)).map((m) => ({ value: m, label: m })),\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tif (!name) {\n\t\t\t\tctx.ui.notify(`Active mode: ${cachedMode}`, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst config = readConfig();\n\t\t\tconfig.active_mode = name === DEFAULT_MODE ? undefined : name;\n\t\t\twriteConfig(config);\n\t\t\tctx.ui.notify(`Mode set to \"${name}\" — reloading…`, \"info\");\n\t\t\tawait ctx.reload();\n\t\t},\n\t});\n\n\t// ── /plan command (shorthand for /mode plan) ──────────────────────────────\n\n\tpi.registerCommand(\"plan\", {\n\t\tdescription: \"Switch to plan mode. Shorthand for /mode plan.\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst config = readConfig();\n\t\t\tconfig.active_mode = \"plan\";\n\t\t\twriteConfig(config);\n\t\t\tctx.ui.notify(`Mode set to \"plan\" — reloading…`, \"info\");\n\t\t\tawait ctx.reload();\n\t\t},\n\t});\n\n\t// ── /approve command ──────────────────────────────────────────────────────\n\t// Reads .hoocode/plan.md, parses it into named sections (Goal, Files to\n\t// modify, New files, Tests, Verification), switches to build mode, then\n\t// injects a step-by-step execution message into the new session.\n\n\tpi.registerCommand(\"approve\", {\n\t\tdescription: \"Approve the current plan and switch to build mode to execute it.\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tif (cachedMode !== \"plan\") {\n\t\t\t\tctx.ui.notify(`/approve is only available in plan mode (current mode: \"${cachedMode}\")`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prefer the per-session plan file, fall back to the legacy single file.\n\t\t\tconst sessionPlanPath = cachedPlanPath ?? getPlanPath(ctx.cwd, ctx.sessionManager.getSessionId());\n\t\t\tconst candidatePaths = [sessionPlanPath, getLegacyPlanPath(ctx.cwd)];\n\t\t\tlet approveMessage: string | undefined;\n\n\t\t\tfor (const planPath of candidatePaths) {\n\t\t\t\tif (!existsSync(planPath)) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = readFileSync(planPath, \"utf8\").trim();\n\t\t\t\t\tif (raw) {\n\t\t\t\t\t\tconst sections = parsePlanSections(raw);\n\t\t\t\t\t\tapproveMessage = buildApproveMessage(sections);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tctx.ui.notify(`Could not read ${relative(ctx.cwd, planPath) || planPath}`, \"error\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Switch global config to build mode\n\t\t\tconst config = readConfig();\n\t\t\tconfig.active_mode = \"build\";\n\t\t\twriteConfig(config);\n\n\t\t\tif (approveMessage) {\n\t\t\t\t// Open a new build-mode session and deliver the parsed plan as the\n\t\t\t\t// first user message so the agent starts executing immediately\n\t\t\t\tawait ctx.newSession({\n\t\t\t\t\twithSession: async (replacedCtx) => {\n\t\t\t\t\t\tawait replacedCtx.sendUserMessage(approveMessage!, { deliverAs: \"followUp\" });\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst relPlan = relative(ctx.cwd, sessionPlanPath) || sessionPlanPath;\n\t\t\t\tctx.ui.notify(`Switched to build mode. No ${relPlan} found — describe what to build.`, \"info\");\n\t\t\t\tawait ctx.reload();\n\t\t\t}\n\t\t},\n\t});\n\n\t// ── /cost command ─────────────────────────────────────────────────────────\n\t// Walks every assistant message in the current session and sums tokens + cost,\n\t// then prints a session total followed by a per-model breakdown.\n\t// Per-tool attribution is intentionally not shown — tokens aren't tracked\n\t// per-tool, and any heuristic would be misleading.\n\n\tpi.registerCommand(\"cost\", {\n\t\tdescription: \"Show session token and cost totals, broken down by model.\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\ttype Totals = { input: number; output: number; cacheRead: number; cacheWrite: number; cost: number };\n\t\t\tconst empty = (): Totals => ({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 });\n\t\t\tconst total = empty();\n\t\t\tconst perModel = new Map<string, Totals>();\n\t\t\tlet assistantTurns = 0;\n\n\t\t\tfor (const entry of ctx.sessionManager.getEntries()) {\n\t\t\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\") continue;\n\t\t\t\tconst u = entry.message.usage;\n\t\t\t\tif (!u) continue;\n\t\t\t\tassistantTurns++;\n\t\t\t\ttotal.input += u.input;\n\t\t\t\ttotal.output += u.output;\n\t\t\t\ttotal.cacheRead += u.cacheRead;\n\t\t\t\ttotal.cacheWrite += u.cacheWrite;\n\t\t\t\ttotal.cost += u.cost.total;\n\n\t\t\t\tconst key = `${entry.message.provider}/${entry.message.model}`;\n\t\t\t\tconst t = perModel.get(key) ?? empty();\n\t\t\t\tt.input += u.input;\n\t\t\t\tt.output += u.output;\n\t\t\t\tt.cacheRead += u.cacheRead;\n\t\t\t\tt.cacheWrite += u.cacheWrite;\n\t\t\t\tt.cost += u.cost.total;\n\t\t\t\tperModel.set(key, t);\n\t\t\t}\n\n\t\t\tif (assistantTurns === 0) {\n\t\t\t\tctx.ui.notify(\"No assistant turns yet — nothing to cost.\", \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst fmt = (n: number) => n.toLocaleString();\n\t\t\tconst fmtCost = (n: number) => `$${n.toFixed(4)}`;\n\t\t\tconst lines: string[] = [];\n\t\t\tlines.push(`Session totals (${assistantTurns} assistant turn${assistantTurns === 1 ? \"\" : \"s\"})`);\n\t\t\tlines.push(` Input ${fmt(total.input)}`);\n\t\t\tlines.push(` Output ${fmt(total.output)}`);\n\t\t\tlines.push(` Cache read ${fmt(total.cacheRead)}`);\n\t\t\tlines.push(` Cache write ${fmt(total.cacheWrite)}`);\n\t\t\tlines.push(` Cost ${fmtCost(total.cost)}`);\n\n\t\t\tif (perModel.size > 1) {\n\t\t\t\tlines.push(\"\");\n\t\t\t\tlines.push(\"By model:\");\n\t\t\t\tconst sorted = [...perModel.entries()].sort((a, b) => b[1].cost - a[1].cost);\n\t\t\t\tfor (const [key, t] of sorted) {\n\t\t\t\t\tlines.push(` ${key}: ${fmt(t.input)} in / ${fmt(t.output)} out ${fmtCost(t.cost)}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tctx.ui.notify(lines.join(\"\\n\"), \"info\");\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Scaffold commands — /new-skill, /new-agent, and /new-command\n// ============================================================================\n\n/** Validates a resource name: lowercase a-z, 0-9, hyphens, no leading/trailing/double hyphens. */\nfunction validateResourceName(name: string): string | null {\n\tif (!name) return \"name is required\";\n\tif (!/^[a-z0-9-]+$/.test(name)) return \"name must be lowercase a-z, 0-9, and hyphens only\";\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) return \"name must not start or end with a hyphen\";\n\tif (name.includes(\"--\")) return \"name must not contain consecutive hyphens\";\n\treturn null;\n}\n\nfunction setupScaffold(pi: ExtensionAPI): void {\n\t// ── /new-skill <name> ─────────────────────────────────────────────────────\n\t// Creates .hoocode/skills/<name>/SKILL.md with a valid Agent Skills frontmatter\n\t// template so the file is ready to edit and will be picked up on next reload.\n\n\tpi.registerCommand(\"new-skill\", {\n\t\tdescription: \"Scaffold a new skill. Usage: /new-skill <name>\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tconst error = validateResourceName(name);\n\t\t\tif (error) {\n\t\t\t\tctx.ui.notify(`/new-skill: ${error}. Usage: /new-skill <name>`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst skillDir = join(ctx.cwd, \".hoocode\", \"skills\", name);\n\t\t\tconst skillFile = join(skillDir, \"SKILL.md\");\n\n\t\t\tif (existsSync(skillFile)) {\n\t\t\t\tctx.ui.notify(`/new-skill: ${skillFile} already exists`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmkdirSync(skillDir, { recursive: true });\n\t\t\twriteFileSync(\n\t\t\t\tskillFile,\n\t\t\t\t[\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`name: ${name}`,\n\t\t\t\t\t\"description: |\",\n\t\t\t\t\t\" TODO: describe when to use this skill — one clear sentence per bullet.\",\n\t\t\t\t\t\" The model reads this to decide whether to load the skill.\",\n\t\t\t\t\t\"allowed-tools: read, bash\",\n\t\t\t\t\t\"---\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t`# ${name}`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"TODO: write the skill instructions here.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"When relative paths appear below, they are resolved from this file's directory.\",\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"utf8\",\n\t\t\t);\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Skill created: ${join(\".hoocode\", \"skills\", name, \"SKILL.md\")}\\nEdit the file, then run /reload to activate it.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n\n\t// ── /new-agent <name> ─────────────────────────────────────────────────────\n\t// Creates .hoocode/agents/<name>.md following the Claude Code subagent standard\n\t// (name, description, tools comma-string, model alias, optional background).\n\n\tpi.registerCommand(\"new-agent\", {\n\t\tdescription: \"Scaffold a new subagent. Usage: /new-agent <name>\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tconst error = validateResourceName(name);\n\t\t\tif (error) {\n\t\t\t\tctx.ui.notify(`/new-agent: ${error}. Usage: /new-agent <name>`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst agentsDir = join(ctx.cwd, \".hoocode\", \"agents\");\n\t\t\tconst agentFile = join(agentsDir, `${name}.md`);\n\n\t\t\tif (existsSync(agentFile)) {\n\t\t\t\tctx.ui.notify(`/new-agent: ${agentFile} already exists`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmkdirSync(agentsDir, { recursive: true });\n\t\t\twriteFileSync(\n\t\t\t\tagentFile,\n\t\t\t\t[\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`name: ${name}`,\n\t\t\t\t\t\"description: |\",\n\t\t\t\t\t\" Use this subagent ONLY when:\",\n\t\t\t\t\t\" - TODO: describe the task(s) to delegate here\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\" DO NOT use for:\",\n\t\t\t\t\t\" - TODO: describe what this agent should NOT handle\",\n\t\t\t\t\t\"tools: read, bash\",\n\t\t\t\t\t\"model: sonnet\",\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`You are a ${name} subagent running inside hoocode.`,\n\t\t\t\t\t\"You run in an isolated context and cannot see the parent conversation.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"TODO: write the system prompt here.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Your final message must contain ONLY your answer — it is the only output\",\n\t\t\t\t\t\"the caller receives. Do not include intermediate reasoning or tool logs.\",\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"utf8\",\n\t\t\t);\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Agent created: ${join(\".hoocode\", \"agents\", `${name}.md`)}\\nEdit the file, then run /reload to activate it.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n\n\t// ── /new-command <name> ───────────────────────────────────────────────────\n\t// Creates .hoocode/commands/<name>.md with a slash-command prompt-template\n\t// frontmatter (name, description, argument-hint) so it is ready to edit and\n\t// picked up on next reload. Body supports $1, $@, $ARGUMENTS placeholders.\n\n\tpi.registerCommand(\"new-command\", {\n\t\tdescription: \"Scaffold a new slash command. Usage: /new-command <name>\",\n\t\tgetArgumentCompletions: () => [],\n\t\thandler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {\n\t\t\tconst name = args.trim();\n\t\t\tconst error = validateResourceName(name);\n\t\t\tif (error) {\n\t\t\t\tctx.ui.notify(`/new-command: ${error}. Usage: /new-command <name>`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst commandsDir = join(ctx.cwd, \".hoocode\", \"commands\");\n\t\t\tconst commandFile = join(commandsDir, `${name}.md`);\n\n\t\t\tif (existsSync(commandFile)) {\n\t\t\t\tctx.ui.notify(`/new-command: ${commandFile} already exists`, \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmkdirSync(commandsDir, { recursive: true });\n\t\t\twriteFileSync(\n\t\t\t\tcommandFile,\n\t\t\t\t[\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`name: ${name}`,\n\t\t\t\t\t\"description: |\",\n\t\t\t\t\t` TODO: describe what /${name} does and when to use it.`,\n\t\t\t\t\t` Usage: /${name} <args>`,\n\t\t\t\t\t\"argument-hint: <args>\",\n\t\t\t\t\t\"---\",\n\t\t\t\t\t`Run the /${name} command with arguments: **$ARGUMENTS**.`,\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"TODO: write the instructions here. Placeholders you can use:\",\n\t\t\t\t\t\"- $1, $2, ... for positional arguments\",\n\t\t\t\t\t\"- $@ or $ARGUMENTS for all arguments\",\n\t\t\t\t\t`- $${\"{\"}@:N} / $${\"{\"}@:N:L} for bash-style slices`,\n\t\t\t\t\t\"\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\t\"utf8\",\n\t\t\t);\n\n\t\t\tctx.ui.notify(\n\t\t\t\t`Command created: ${join(\".hoocode\", \"commands\", `${name}.md`)}\\nEdit the file, then run /reload to activate it.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t},\n\t});\n}\n\n// ============================================================================\n// D. Options pane — ask_options tool\n// ============================================================================\n\n// The model calls this tool when it needs the user to make a decision before\n// continuing. Each question is shown in an inline options pane where the user\n// moves with up/down, advances with right, and may type a custom answer.\nconst askOptionsSchema = Type.Object({\n\tquestions: Type.Array(\n\t\tType.Object({\n\t\t\tquestion: Type.String({ description: \"The question to ask the user.\" }),\n\t\t\tdetail: Type.Optional(Type.String({ description: \"Optional clarifying sub-text shown under the question.\" })),\n\t\t\toptions: Type.Array(\n\t\t\t\tType.Object({\n\t\t\t\t\tlabel: Type.String({ description: \"The option text; returned verbatim when chosen.\" }),\n\t\t\t\t\tdescription: Type.Optional(\n\t\t\t\t\t\tType.String({ description: \"Optional short description shown next to the option.\" }),\n\t\t\t\t\t),\n\t\t\t\t\trecommended: Type.Optional(\n\t\t\t\t\t\tType.Boolean({\n\t\t\t\t\t\t\tdescription: \"When true, the option is marked '(recommended)' to help the user choose.\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t\t{ description: \"The options the user can choose from.\" },\n\t\t\t),\n\t\t\tallow_custom: Type.Optional(\n\t\t\t\tType.Boolean({\n\t\t\t\t\tdescription: \"When true, the user can type a free-form answer instead of choosing an option.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"One or more decisions to ask the user, in order.\" },\n\t),\n});\n\nexport function setupAskOptions(pi: ExtensionAPI): void {\n\t// Capture the latest context so the tool can reach the interactive UI.\n\tlet activeCtx: ExtensionContext | undefined;\n\tpi.on(\"session_start\", (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\tactiveCtx = ctx;\n\t});\n\n\tpi.registerTool({\n\t\tname: \"ask_options\",\n\t\tlabel: \"Ask the user\",\n\t\tdescription:\n\t\t\t\"Ask the user to make one or more decisions before continuing. Each question is presented \" +\n\t\t\t\"in an interactive options pane where the user selects an option (or types a custom answer). \" +\n\t\t\t\"Use this when you genuinely need input to proceed and cannot reasonably decide yourself. \" +\n\t\t\t\"Returns the user's answer for each question; if the user skips, no answers are returned.\",\n\t\tparameters: askOptionsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId: string,\n\t\t\tparams: Static<typeof askOptionsSchema>,\n\t\t\tsignal: AbortSignal,\n\t\t\t_onUpdate: AgentToolUpdateCallback,\n\t\t): Promise<AgentToolResult<undefined>> {\n\t\t\tif (!activeCtx || !activeCtx.hasUI) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"Cannot ask the user: no interactive UI is available in this session. Proceed using your best judgement.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!params.questions.length) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"No questions were provided.\" }],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst questions: AskQuestion[] = params.questions.map((q) => ({\n\t\t\t\tquestion: q.question,\n\t\t\t\tdetail: q.detail,\n\t\t\t\toptions: q.options.map((o) => ({ label: o.label, description: o.description, recommended: o.recommended })),\n\t\t\t\tallowCustom: q.allow_custom,\n\t\t\t}));\n\n\t\t\tconst answers = await activeCtx.ui.askOptions(questions, { signal });\n\n\t\t\tif (!answers) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: \"The user skipped the question(s) without answering. Ask how they would like to proceed.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst text = questions.map((q, i) => `${q.question}\\n \\u2192 ${answers[i] ?? \"(no answer)\"}`).join(\"\\n\\n\");\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\tdetails: undefined,\n\t\t\t};\n\t\t},\n\t});\n}\n\n// ============================================================================\n// Extension entry point\n// ============================================================================\n\nfunction hooCore(pi: ExtensionAPI): void {\n\tsetupPermissionGate(pi);\n\tsetupMcpLoader(pi);\n\tsetupMode(pi);\n\tsetupScaffold(pi);\n\tsetupAskOptions(pi);\n}\n\nhooCore.displayName = \"hoo-core\";\nexport default hooCore;\n"]}
@@ -8,7 +8,9 @@ import type { Component, TUI } from "@kolisachint/hoocode-tui";
8
8
  * done/total count on the left, the per-turn token/elapsed/cost delta on the right.
9
9
  * - Shows all tasks with all statuses (pending / in_progress / done / failed).
10
10
  * The active row animates a braille spinner; pending rows read `queued`.
11
- * - Subagent mode is intentionally NOT shown here (e.g. no "[explore]" tag).
11
+ * - A single-cell source glyph (⚙ subagent / MCP) sits before the id so the two
12
+ * kinds of background work are distinguishable. The subagent *mode* tag (e.g.
13
+ * "[explore]") is still intentionally NOT shown — the pane stays tag-free.
12
14
  * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).
13
15
  * - Finished tasks carry their wall-clock cost and stay visible until the next
14
16
  * user message arrives (see taskStore.reset()), not the moment they finish.
@@ -1 +1 @@
1
- {"version":3,"file":"task-panel.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAyP/D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAa;IAChC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,cAAc,CAA+C;IAErE,YAAY,EAAE,CAAC,EAAE,GAAG,EAEnB;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,6EAA6E;IAC7E,OAAO,CAAC,eAAe;IAcvB,gDAAgD;IAChD,OAAO,IAAI,IAAI,CAKd;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqB9B;CACD","sourcesContent":["import type { Component, TUI } from \"@kolisachint/hoocode-tui\";\nimport { truncateToWidth, visibleWidth } from \"@kolisachint/hoocode-tui\";\nimport type { Task, TaskStatus } from \"../../../core/task-store.js\";\nimport { taskStore } from \"../../../core/task-store.js\";\nimport { theme } from \"../theme/theme.js\";\n\nconst TASK_STATUS_ICON: Record<TaskStatus, string> = {\n\tpending: \"●\",\n\tin_progress: \"◐\",\n\tdone: \"✓\",\n\tfailed: \"✗\",\n};\n\n/** Braille spinner frames + cadence, matched to the TUI Loader so the active row animates in step. */\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_INTERVAL_MS = 80;\n\n/** A thin colored left rail groups the pane without a box, the way the design's `border-left` does. */\nconst RAIL = \"▎\";\n\n/** Cells in the deterministic progress bar (matches the design's 14-cell track). */\nconst PROGRESS_CELLS = 14;\n\n/** Overall pane state, derived from the task statuses. Drives the rail color + header stamp. */\ntype PanelState = \"working\" | \"reviewed\" | \"stopped\";\n\ninterface StatePresentation {\n\treadonly icon: string;\n\treadonly label: string;\n\treadonly color: \"warning\" | \"success\" | \"error\";\n}\n\nconst STATE_PRESENTATION: Record<PanelState, StatePresentation> = {\n\tworking: { icon: \"◐\", label: \"working\", color: \"warning\" },\n\treviewed: { icon: \"✓\", label: \"reviewed\", color: \"success\" },\n\tstopped: { icon: \"✗\", label: \"stopped\", color: \"error\" },\n};\n\nfunction panelState(tasks: readonly Task[]): PanelState {\n\tif (tasks.some((t) => t.status === \"failed\")) return \"stopped\";\n\tconst active = tasks.some((t) => t.status === \"in_progress\" || t.status === \"pending\");\n\treturn active ? \"working\" : \"reviewed\";\n}\n\nfunction taskStatusColor(status: TaskStatus): \"dim\" | \"warning\" | \"success\" | \"error\" {\n\tswitch (status) {\n\t\tcase \"in_progress\":\n\t\t\treturn \"warning\";\n\t\tcase \"done\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"dim\";\n\t}\n}\n\n/** Format a duration in seconds into a compact, terminal-friendly string. */\nfunction formatDuration(secs: number): string {\n\tconst s = Math.max(0, secs);\n\tif (s < 10) return `${s.toFixed(1)}s`;\n\tif (s < 60) return `${Math.round(s)}s`;\n\tconst mins = Math.floor(s / 60);\n\tconst rem = Math.round(s % 60);\n\treturn `${mins}m${rem.toString().padStart(2, \"0\")}s`;\n}\n\n/** Wall-clock time a task occupied, derived from its create/update stamps. */\nfunction taskElapsedSecs(task: Task): number {\n\treturn Math.max(0, (task.updatedAt - task.createdAt) / 1000);\n}\n\n/** Sum the token + cost usage reported by the tasks shown this turn. */\nfunction sumTurnUsage(tasks: readonly Task[]): { input: number; output: number; cost: number } | null {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cost = 0;\n\tfor (const task of tasks) {\n\t\tif (!task.usage) continue;\n\t\tinput += task.usage.input;\n\t\toutput += task.usage.output;\n\t\tcost += task.usage.cost;\n\t}\n\tif (input === 0 && output === 0 && cost === 0) return null;\n\treturn { input, output, cost };\n}\n\n/**\n * Deterministic block-glyph progress bar: a heavy run (━) for the completed\n * fraction over a dim track. In-progress tasks count as half, so the bar moves\n * the moment work starts. Fraction is the only input — no animation, no guess.\n */\nfunction progressBar(done: number, active: number, total: number): { plain: string; styled: string } {\n\tconst ratio = total > 0 ? Math.max(0, Math.min(1, (done + active * 0.5) / total)) : 0;\n\tconst filled = Math.round(ratio * PROGRESS_CELLS);\n\tconst fill = \"━\".repeat(filled);\n\tconst track = \"━\".repeat(PROGRESS_CELLS - filled);\n\treturn {\n\t\tplain: fill + track,\n\t\tstyled: theme.fg(\"success\", fill) + theme.fg(\"dim\", track),\n\t};\n}\n\n/**\n * Ledger header: a state stamp (◐ working / ✓ reviewed / ✗ stopped) + a\n * deterministic progress bar and done/total count on the left, and the per-turn\n * token + elapsed + cost delta (summed across the tasks below) on the right.\n */\nfunction formatHeader(tasks: readonly Task[], width: number, state: PanelState, totalSecs: number): string {\n\tconst total = tasks.length;\n\tconst done = tasks.filter((t) => t.status === \"done\").length;\n\tconst active = tasks.filter((t) => t.status === \"in_progress\").length;\n\n\tconst { icon, label, color } = STATE_PRESENTATION[state];\n\tconst stampPlain = `${icon} ${label.toUpperCase()}`;\n\tconst stamp = `${theme.fg(color, icon)} ${theme.bold(theme.fg(color, label.toUpperCase()))}`;\n\n\tconst bar = progressBar(done, active, total);\n\tconst countPlain = `${done}/${total}`;\n\tconst count = theme.fg(\"muted\", `${done}`) + theme.fg(\"dim\", \"/\") + theme.fg(\"muted\", `${total}`);\n\n\t// Left cluster has a full form (stamp · bar · count) and a compact fallback\n\t// (stamp · count) that drops the bar when the terminal is too narrow.\n\tconst leftFullPlain = `${stampPlain} ${bar.plain} ${countPlain}`;\n\tconst leftFull = `${stamp} ${bar.styled} ${count}`;\n\tconst leftMinPlain = `${stampPlain} ${countPlain}`;\n\tconst leftMin = `${stamp} ${count}`;\n\n\tconst turn = sumTurnUsage(tasks);\n\tlet turnPlain = \"\";\n\tlet turnText = \"\";\n\tif (turn) {\n\t\tconst inTok = formatTokens(turn.input);\n\t\tconst outTok = formatTokens(turn.output);\n\t\tconst elapsed = formatDuration(totalSecs);\n\t\tconst showCost = turn.cost > 0;\n\t\tconst costStr = showCost ? `$${turn.cost.toFixed(3)}` : \"\";\n\t\tturnPlain = `turn ↑${inTok} ↓${outTok} · ${elapsed}${showCost ? ` · ${costStr}` : \"\"}`;\n\t\t// Turn delta: muted framing, numbers one step brighter (bold), separators dim.\n\t\tturnText =\n\t\t\ttheme.fg(\"muted\", \"turn ↑\") +\n\t\t\ttheme.bold(inTok) +\n\t\t\ttheme.fg(\"muted\", \" ↓\") +\n\t\t\ttheme.bold(outTok) +\n\t\t\ttheme.fg(\"dim\", \" · \") +\n\t\t\ttheme.fg(\"muted\", elapsed) +\n\t\t\t(showCost ? theme.fg(\"dim\", \" · \") + theme.bold(costStr) : \"\");\n\t}\n\n\tif (turnPlain) {\n\t\tif (visibleWidth(leftFullPlain) + 2 + visibleWidth(turnPlain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftFullPlain) - visibleWidth(turnPlain));\n\t\t\treturn leftFull + \" \".repeat(pad) + turnText;\n\t\t}\n\t\tif (visibleWidth(leftMinPlain) + 2 + visibleWidth(turnPlain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftMinPlain) - visibleWidth(turnPlain));\n\t\t\treturn leftMin + \" \".repeat(pad) + turnText;\n\t\t}\n\t}\n\tif (visibleWidth(leftFullPlain) <= width) return leftFull;\n\treturn truncateToWidth(leftMin, width, \"…\");\n}\n\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\treturn `${(count / 1000000).toFixed(1)}M`;\n}\n\nfunction formatTaskLine(task: Task, width: number, frame: number): string {\n\tconst isProgress = task.status === \"in_progress\";\n\tconst iconGlyph = isProgress\n\t\t? (SPINNER_FRAMES[frame] ?? TASK_STATUS_ICON.in_progress)\n\t\t: TASK_STATUS_ICON[task.status];\n\tconst icon = theme.fg(taskStatusColor(task.status), iconGlyph);\n\n\tconst idLabel = `#${task.id}`;\n\tconst title = task.title;\n\t// The id recedes (dim); the title carries the line. Done titles fade to muted\n\t// (settled work), pending dim (not started), active goes bold, failed turns red.\n\tconst styledId = theme.fg(\"dim\", idLabel);\n\tlet styledTitle: string;\n\tswitch (task.status) {\n\t\tcase \"done\":\n\t\t\tstyledTitle = theme.fg(\"muted\", title);\n\t\t\tbreak;\n\t\tcase \"pending\":\n\t\t\tstyledTitle = theme.fg(\"dim\", title);\n\t\t\tbreak;\n\t\tcase \"failed\":\n\t\t\tstyledTitle = theme.fg(\"error\", title);\n\t\t\tbreak;\n\t\tcase \"in_progress\":\n\t\t\tstyledTitle = theme.bold(title);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstyledTitle = title;\n\t}\n\n\t// Right column: settled rows carry their audit stamp (tokens + elapsed); the\n\t// active row reads `running…`, pending rows read `queued`.\n\tlet rightPlain = \"\";\n\tlet rightStyled = \"\";\n\tif (task.status === \"done\" || task.status === \"failed\") {\n\t\tconst parts: string[] = [];\n\t\tlet tokenText = \"\";\n\t\tif (task.usage) {\n\t\t\tconst totalTok = task.usage.input + task.usage.output;\n\t\t\tif (totalTok > 0) tokenText = formatTokens(totalTok);\n\t\t}\n\t\tconst elapsed = formatDuration(taskElapsedSecs(task));\n\t\tif (tokenText) {\n\t\t\tparts.push(tokenText, elapsed);\n\t\t\trightStyled = theme.fg(\"muted\", tokenText) + theme.fg(\"dim\", ` · ${elapsed}`);\n\t\t} else {\n\t\t\tparts.push(elapsed);\n\t\t\trightStyled = theme.fg(\"dim\", elapsed);\n\t\t}\n\t\trightPlain = parts.join(\" · \");\n\t} else if (task.status === \"in_progress\") {\n\t\trightPlain = \"running…\";\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t} else if (task.status === \"pending\") {\n\t\trightPlain = \"queued\";\n\t\trightStyled = theme.fg(\"dim\", rightPlain);\n\t}\n\n\t// A warning note (e.g. inherited-model fallback, exhaustion skip) takes over the\n\t// right column as a ⚠ cue, replacing the usage/status stamp for that row.\n\tif (task.note) {\n\t\trightPlain = `⚠ ${task.note}`;\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t}\n\n\tconst rightWidth = rightPlain ? visibleWidth(rightPlain) + 1 : 0;\n\tconst leftWidth = Math.max(0, width - rightWidth);\n\n\t// truncateToWidth measures visible width (ANSI-aware), so the styled left can be\n\t// truncated against the full left budget directly. Subtracting the prefix here\n\t// (as a prior version did) truncated titles early and unevenly per id width.\n\tconst left = truncateToWidth(`${icon} ${styledId} ${styledTitle}`, leftWidth, \"…\");\n\n\tif (!rightPlain) return left;\n\n\tconst pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));\n\treturn left + \" \".repeat(pad) + rightStyled;\n}\n\n/**\n * Task panel rendered just above the editor prompt.\n *\n * - A state-colored left rail groups the pane (working=warning, reviewed=success,\n * stopped=error) without drawing a box.\n * - A ledger header tops the list: a state stamp + deterministic progress bar +\n * done/total count on the left, the per-turn token/elapsed/cost delta on the right.\n * - Shows all tasks with all statuses (pending / in_progress / done / failed).\n * The active row animates a braille spinner; pending rows read `queued`.\n * - Subagent mode is intentionally NOT shown here (e.g. no \"[explore]\" tag).\n * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).\n * - Finished tasks carry their wall-clock cost and stay visible until the next\n * user message arrives (see taskStore.reset()), not the moment they finish.\n * - Collapses to zero lines when there are no tasks.\n */\nexport class TaskPanelComponent implements Component {\n\tprivate readonly ui: TUI | null;\n\tprivate frame = 0;\n\tprivate animationTimer: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(ui?: TUI) {\n\t\tthis.ui = ui ?? null;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached rendering state.\n\t}\n\n\t/** Run the spinner timer only while a task is active, ticking re-renders. */\n\tprivate ensureAnimation(active: boolean): void {\n\t\tif (active && this.ui && !this.animationTimer) {\n\t\t\tthis.animationTimer = setInterval(() => {\n\t\t\t\tthis.frame = (this.frame + 1) % SPINNER_FRAMES.length;\n\t\t\t\tthis.ui?.requestRender();\n\t\t\t}, SPINNER_INTERVAL_MS);\n\t\t\tthis.animationTimer.unref?.();\n\t\t} else if (!active && this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t\tthis.frame = 0;\n\t\t}\n\t}\n\n\t/** Stop the spinner timer. Call on teardown. */\n\tdispose(): void {\n\t\tif (this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst tasks = taskStore.list();\n\t\tif (tasks.length === 0) {\n\t\t\tthis.ensureAnimation(false);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst hasActive = tasks.some((t) => t.status === \"in_progress\");\n\t\tthis.ensureAnimation(hasActive);\n\n\t\tconst state = panelState(tasks);\n\t\tconst totalSecs = tasks.reduce((sum, t) => sum + taskElapsedSecs(t), 0);\n\t\tconst railColor = STATE_PRESENTATION[state].color;\n\t\tconst gutter = `${theme.fg(railColor, RAIL)} `;\n\t\tconst inner = Math.max(0, width - visibleWidth(RAIL) - 1);\n\n\t\tconst lines: string[] = [gutter + formatHeader(tasks, inner, state, totalSecs)];\n\t\tfor (const task of tasks) {\n\t\t\tlines.push(gutter + formatTaskLine(task, inner, this.frame));\n\t\t}\n\t\treturn lines;\n\t}\n}\n"]}
1
+ {"version":3,"file":"task-panel.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/task-panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AA4Q/D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAa;IAChC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,cAAc,CAA+C;IAErE,YAAY,EAAE,CAAC,EAAE,GAAG,EAEnB;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,6EAA6E;IAC7E,OAAO,CAAC,eAAe;IAcvB,gDAAgD;IAChD,OAAO,IAAI,IAAI,CAKd;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAyB9B;CACD","sourcesContent":["import type { Component, TUI } from \"@kolisachint/hoocode-tui\";\nimport { truncateToWidth, visibleWidth } from \"@kolisachint/hoocode-tui\";\nimport type { Task, TaskSource, TaskStatus } from \"../../../core/task-store.js\";\nimport { taskStore } from \"../../../core/task-store.js\";\nimport { theme } from \"../theme/theme.js\";\n\nconst TASK_STATUS_ICON: Record<TaskStatus, string> = {\n\tpending: \"●\",\n\tin_progress: \"◐\",\n\tdone: \"✓\",\n\tfailed: \"✗\",\n};\n\n/**\n * A single-cell source marker placed before the id so a subagent row and an MCP\n * row are distinguishable at a glance. Plain tasks reserve the cell (blank) to keep\n * the id column aligned. Deliberately a glyph, not a text tag — the pane stays\n * tag-free (no `[explore]`); the glyph just says *where the work came from*.\n */\nconst TASK_SOURCE_GLYPH: Record<TaskSource, string> = {\n\tsubagent: \"⚙\",\n\tmcp: \"⧉\",\n};\n\n/** Braille spinner frames + cadence, matched to the TUI Loader so the active row animates in step. */\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_INTERVAL_MS = 80;\n\n/** A thin colored left rail groups the pane without a box, the way the design's `border-left` does. */\nconst RAIL = \"▎\";\n\n/** Cells in the deterministic progress bar (matches the design's 14-cell track). */\nconst PROGRESS_CELLS = 14;\n\n/** Overall pane state, derived from the task statuses. Drives the rail color + header stamp. */\ntype PanelState = \"working\" | \"reviewed\" | \"stopped\";\n\ninterface StatePresentation {\n\treadonly icon: string;\n\treadonly label: string;\n\treadonly color: \"warning\" | \"success\" | \"error\";\n}\n\nconst STATE_PRESENTATION: Record<PanelState, StatePresentation> = {\n\tworking: { icon: \"◐\", label: \"working\", color: \"warning\" },\n\treviewed: { icon: \"✓\", label: \"reviewed\", color: \"success\" },\n\tstopped: { icon: \"✗\", label: \"stopped\", color: \"error\" },\n};\n\nfunction panelState(tasks: readonly Task[]): PanelState {\n\tif (tasks.some((t) => t.status === \"failed\")) return \"stopped\";\n\tconst active = tasks.some((t) => t.status === \"in_progress\" || t.status === \"pending\");\n\treturn active ? \"working\" : \"reviewed\";\n}\n\nfunction taskStatusColor(status: TaskStatus): \"dim\" | \"warning\" | \"success\" | \"error\" {\n\tswitch (status) {\n\t\tcase \"in_progress\":\n\t\t\treturn \"warning\";\n\t\tcase \"done\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"dim\";\n\t}\n}\n\n/** Format a duration in seconds into a compact, terminal-friendly string. */\nfunction formatDuration(secs: number): string {\n\tconst s = Math.max(0, secs);\n\tif (s < 10) return `${s.toFixed(1)}s`;\n\tif (s < 60) return `${Math.round(s)}s`;\n\tconst mins = Math.floor(s / 60);\n\tconst rem = Math.round(s % 60);\n\treturn `${mins}m${rem.toString().padStart(2, \"0\")}s`;\n}\n\n/** Wall-clock time a task occupied, derived from its create/update stamps. */\nfunction taskElapsedSecs(task: Task): number {\n\treturn Math.max(0, (task.updatedAt - task.createdAt) / 1000);\n}\n\n/** Sum the token + cost usage reported by the tasks shown this turn. */\nfunction sumTurnUsage(tasks: readonly Task[]): { input: number; output: number; cost: number } | null {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cost = 0;\n\tfor (const task of tasks) {\n\t\tif (!task.usage) continue;\n\t\tinput += task.usage.input;\n\t\toutput += task.usage.output;\n\t\tcost += task.usage.cost;\n\t}\n\tif (input === 0 && output === 0 && cost === 0) return null;\n\treturn { input, output, cost };\n}\n\n/**\n * Deterministic block-glyph progress bar: a heavy run (━) for the completed\n * fraction over a dim track. In-progress tasks count as half, so the bar moves\n * the moment work starts. Fraction is the only input — no animation, no guess.\n */\nfunction progressBar(done: number, active: number, total: number): { plain: string; styled: string } {\n\tconst ratio = total > 0 ? Math.max(0, Math.min(1, (done + active * 0.5) / total)) : 0;\n\tconst filled = Math.round(ratio * PROGRESS_CELLS);\n\tconst fill = \"━\".repeat(filled);\n\tconst track = \"━\".repeat(PROGRESS_CELLS - filled);\n\treturn {\n\t\tplain: fill + track,\n\t\tstyled: theme.fg(\"success\", fill) + theme.fg(\"dim\", track),\n\t};\n}\n\n/**\n * Ledger header: a state stamp (◐ working / ✓ reviewed / ✗ stopped) + a\n * deterministic progress bar and done/total count on the left, and the per-turn\n * token + elapsed + cost delta (summed across the tasks below) on the right.\n */\nfunction formatHeader(tasks: readonly Task[], width: number, state: PanelState, totalSecs: number): string {\n\tconst total = tasks.length;\n\tconst done = tasks.filter((t) => t.status === \"done\").length;\n\tconst active = tasks.filter((t) => t.status === \"in_progress\").length;\n\n\tconst { icon, label, color } = STATE_PRESENTATION[state];\n\tconst stampPlain = `${icon} ${label.toUpperCase()}`;\n\tconst stamp = `${theme.fg(color, icon)} ${theme.bold(theme.fg(color, label.toUpperCase()))}`;\n\n\tconst bar = progressBar(done, active, total);\n\tconst countPlain = `${done}/${total}`;\n\tconst count = theme.fg(\"muted\", `${done}`) + theme.fg(\"dim\", \"/\") + theme.fg(\"muted\", `${total}`);\n\n\t// Left cluster has a full form (stamp · bar · count) and a compact fallback\n\t// (stamp · count) that drops the bar when the terminal is too narrow.\n\tconst leftFullPlain = `${stampPlain} ${bar.plain} ${countPlain}`;\n\tconst leftFull = `${stamp} ${bar.styled} ${count}`;\n\tconst leftMinPlain = `${stampPlain} ${countPlain}`;\n\tconst leftMin = `${stamp} ${count}`;\n\n\tconst turn = sumTurnUsage(tasks);\n\tlet turnPlain = \"\";\n\tlet turnText = \"\";\n\tif (turn) {\n\t\tconst inTok = formatTokens(turn.input);\n\t\tconst outTok = formatTokens(turn.output);\n\t\tconst elapsed = formatDuration(totalSecs);\n\t\tconst showCost = turn.cost > 0;\n\t\tconst costStr = showCost ? `$${turn.cost.toFixed(3)}` : \"\";\n\t\tturnPlain = `turn ↑${inTok} ↓${outTok} · ${elapsed}${showCost ? ` · ${costStr}` : \"\"}`;\n\t\t// Turn delta: muted framing, numbers one step brighter (bold), separators dim.\n\t\tturnText =\n\t\t\ttheme.fg(\"muted\", \"turn ↑\") +\n\t\t\ttheme.bold(inTok) +\n\t\t\ttheme.fg(\"muted\", \" ↓\") +\n\t\t\ttheme.bold(outTok) +\n\t\t\ttheme.fg(\"dim\", \" · \") +\n\t\t\ttheme.fg(\"muted\", elapsed) +\n\t\t\t(showCost ? theme.fg(\"dim\", \" · \") + theme.bold(costStr) : \"\");\n\t}\n\n\tif (turnPlain) {\n\t\tif (visibleWidth(leftFullPlain) + 2 + visibleWidth(turnPlain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftFullPlain) - visibleWidth(turnPlain));\n\t\t\treturn leftFull + \" \".repeat(pad) + turnText;\n\t\t}\n\t\tif (visibleWidth(leftMinPlain) + 2 + visibleWidth(turnPlain) <= width) {\n\t\t\tconst pad = Math.max(2, width - visibleWidth(leftMinPlain) - visibleWidth(turnPlain));\n\t\t\treturn leftMin + \" \".repeat(pad) + turnText;\n\t\t}\n\t}\n\tif (visibleWidth(leftFullPlain) <= width) return leftFull;\n\treturn truncateToWidth(leftMin, width, \"…\");\n}\n\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\treturn `${(count / 1000000).toFixed(1)}M`;\n}\n\nfunction formatTaskLine(task: Task, width: number, frame: number, idColWidth: number): string {\n\tconst isProgress = task.status === \"in_progress\";\n\tconst iconGlyph = isProgress\n\t\t? (SPINNER_FRAMES[frame] ?? TASK_STATUS_ICON.in_progress)\n\t\t: TASK_STATUS_ICON[task.status];\n\tconst icon = theme.fg(taskStatusColor(task.status), iconGlyph);\n\n\t// Source marker between the status icon and the id. Reserve the cell (blank) for\n\t// plain tasks so ids stay column-aligned whether or not a glyph is present.\n\tconst sourceGlyph = task.source ? TASK_SOURCE_GLYPH[task.source] : \" \";\n\tconst styledSource = task.source ? theme.fg(\"dim\", sourceGlyph) : \" \";\n\n\t// Right-pad the id to the shared column width so titles line up across rows even\n\t// when ids differ in digit count (#1 vs #10). Padding is plain spaces inside the\n\t// dim styling, so it adds no visible color.\n\tconst idLabel = `#${task.id}`.padEnd(idColWidth);\n\tconst title = task.title;\n\t// The id recedes (dim); the title carries the line. Done titles fade to muted\n\t// (settled work), pending dim (not started), active goes bold, failed turns red.\n\tconst styledId = theme.fg(\"dim\", idLabel);\n\tlet styledTitle: string;\n\tswitch (task.status) {\n\t\tcase \"done\":\n\t\t\tstyledTitle = theme.fg(\"muted\", title);\n\t\t\tbreak;\n\t\tcase \"pending\":\n\t\t\tstyledTitle = theme.fg(\"dim\", title);\n\t\t\tbreak;\n\t\tcase \"failed\":\n\t\t\tstyledTitle = theme.fg(\"error\", title);\n\t\t\tbreak;\n\t\tcase \"in_progress\":\n\t\t\tstyledTitle = theme.bold(title);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstyledTitle = title;\n\t}\n\n\t// Right column: settled rows carry their audit stamp (tokens + elapsed); the\n\t// active row reads `running…`, pending rows read `queued`.\n\tlet rightPlain = \"\";\n\tlet rightStyled = \"\";\n\tif (task.status === \"done\" || task.status === \"failed\") {\n\t\tconst parts: string[] = [];\n\t\tlet tokenText = \"\";\n\t\tif (task.usage) {\n\t\t\tconst totalTok = task.usage.input + task.usage.output;\n\t\t\tif (totalTok > 0) tokenText = formatTokens(totalTok);\n\t\t}\n\t\tconst elapsed = formatDuration(taskElapsedSecs(task));\n\t\tif (tokenText) {\n\t\t\tparts.push(tokenText, elapsed);\n\t\t\trightStyled = theme.fg(\"muted\", tokenText) + theme.fg(\"dim\", ` · ${elapsed}`);\n\t\t} else {\n\t\t\tparts.push(elapsed);\n\t\t\trightStyled = theme.fg(\"dim\", elapsed);\n\t\t}\n\t\trightPlain = parts.join(\" · \");\n\t} else if (task.status === \"in_progress\") {\n\t\trightPlain = \"running…\";\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t} else if (task.status === \"pending\") {\n\t\trightPlain = \"queued\";\n\t\trightStyled = theme.fg(\"dim\", rightPlain);\n\t}\n\n\t// A warning note (e.g. inherited-model fallback, exhaustion skip) takes over the\n\t// right column as a ⚠ cue, replacing the usage/status stamp for that row.\n\tif (task.note) {\n\t\trightPlain = `⚠ ${task.note}`;\n\t\trightStyled = theme.fg(\"warning\", rightPlain);\n\t}\n\n\tconst rightWidth = rightPlain ? visibleWidth(rightPlain) + 1 : 0;\n\tconst leftWidth = Math.max(0, width - rightWidth);\n\n\t// truncateToWidth measures visible width (ANSI-aware), so the styled left can be\n\t// truncated against the full left budget directly. Subtracting the prefix here\n\t// (as a prior version did) truncated titles early and unevenly per id width.\n\tconst left = truncateToWidth(`${icon} ${styledSource} ${styledId} ${styledTitle}`, leftWidth, \"…\");\n\n\tif (!rightPlain) return left;\n\n\tconst pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));\n\treturn left + \" \".repeat(pad) + rightStyled;\n}\n\n/**\n * Task panel rendered just above the editor prompt.\n *\n * - A state-colored left rail groups the pane (working=warning, reviewed=success,\n * stopped=error) without drawing a box.\n * - A ledger header tops the list: a state stamp + deterministic progress bar +\n * done/total count on the left, the per-turn token/elapsed/cost delta on the right.\n * - Shows all tasks with all statuses (pending / in_progress / done / failed).\n * The active row animates a braille spinner; pending rows read `queued`.\n * - A single-cell source glyph (⚙ subagent / ⧉ MCP) sits before the id so the two\n * kinds of background work are distinguishable. The subagent *mode* tag (e.g.\n * \"[explore]\") is still intentionally NOT shown — the pane stays tag-free.\n * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).\n * - Finished tasks carry their wall-clock cost and stay visible until the next\n * user message arrives (see taskStore.reset()), not the moment they finish.\n * - Collapses to zero lines when there are no tasks.\n */\nexport class TaskPanelComponent implements Component {\n\tprivate readonly ui: TUI | null;\n\tprivate frame = 0;\n\tprivate animationTimer: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(ui?: TUI) {\n\t\tthis.ui = ui ?? null;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached rendering state.\n\t}\n\n\t/** Run the spinner timer only while a task is active, ticking re-renders. */\n\tprivate ensureAnimation(active: boolean): void {\n\t\tif (active && this.ui && !this.animationTimer) {\n\t\t\tthis.animationTimer = setInterval(() => {\n\t\t\t\tthis.frame = (this.frame + 1) % SPINNER_FRAMES.length;\n\t\t\t\tthis.ui?.requestRender();\n\t\t\t}, SPINNER_INTERVAL_MS);\n\t\t\tthis.animationTimer.unref?.();\n\t\t} else if (!active && this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t\tthis.frame = 0;\n\t\t}\n\t}\n\n\t/** Stop the spinner timer. Call on teardown. */\n\tdispose(): void {\n\t\tif (this.animationTimer) {\n\t\t\tclearInterval(this.animationTimer);\n\t\t\tthis.animationTimer = null;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tconst tasks = taskStore.list();\n\t\tif (tasks.length === 0) {\n\t\t\tthis.ensureAnimation(false);\n\t\t\treturn [];\n\t\t}\n\n\t\tconst hasActive = tasks.some((t) => t.status === \"in_progress\");\n\t\tthis.ensureAnimation(hasActive);\n\n\t\tconst state = panelState(tasks);\n\t\tconst totalSecs = tasks.reduce((sum, t) => sum + taskElapsedSecs(t), 0);\n\t\tconst railColor = STATE_PRESENTATION[state].color;\n\t\tconst gutter = `${theme.fg(railColor, RAIL)} `;\n\t\tconst inner = Math.max(0, width - visibleWidth(RAIL) - 1);\n\n\t\t// Width of the id column, sized to the widest id on screen, so every title\n\t\t// starts at the same column regardless of digit count (#1 vs #10 vs #100).\n\t\tconst idColWidth = tasks.reduce((max, t) => Math.max(max, `#${t.id}`.length), 0);\n\n\t\tconst lines: string[] = [gutter + formatHeader(tasks, inner, state, totalSecs)];\n\t\tfor (const task of tasks) {\n\t\t\tlines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth));\n\t\t}\n\t\treturn lines;\n\t}\n}\n"]}
@@ -7,6 +7,16 @@ const TASK_STATUS_ICON = {
7
7
  done: "✓",
8
8
  failed: "✗",
9
9
  };
10
+ /**
11
+ * A single-cell source marker placed before the id so a subagent row and an MCP
12
+ * row are distinguishable at a glance. Plain tasks reserve the cell (blank) to keep
13
+ * the id column aligned. Deliberately a glyph, not a text tag — the pane stays
14
+ * tag-free (no `[explore]`); the glyph just says *where the work came from*.
15
+ */
16
+ const TASK_SOURCE_GLYPH = {
17
+ subagent: "⚙",
18
+ mcp: "⧉",
19
+ };
10
20
  /** Braille spinner frames + cadence, matched to the TUI Loader so the active row animates in step. */
11
21
  const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
12
22
  const SPINNER_INTERVAL_MS = 80;
@@ -147,13 +157,20 @@ function formatTokens(count) {
147
157
  return `${Math.round(count / 1000)}k`;
148
158
  return `${(count / 1000000).toFixed(1)}M`;
149
159
  }
150
- function formatTaskLine(task, width, frame) {
160
+ function formatTaskLine(task, width, frame, idColWidth) {
151
161
  const isProgress = task.status === "in_progress";
152
162
  const iconGlyph = isProgress
153
163
  ? (SPINNER_FRAMES[frame] ?? TASK_STATUS_ICON.in_progress)
154
164
  : TASK_STATUS_ICON[task.status];
155
165
  const icon = theme.fg(taskStatusColor(task.status), iconGlyph);
156
- const idLabel = `#${task.id}`;
166
+ // Source marker between the status icon and the id. Reserve the cell (blank) for
167
+ // plain tasks so ids stay column-aligned whether or not a glyph is present.
168
+ const sourceGlyph = task.source ? TASK_SOURCE_GLYPH[task.source] : " ";
169
+ const styledSource = task.source ? theme.fg("dim", sourceGlyph) : " ";
170
+ // Right-pad the id to the shared column width so titles line up across rows even
171
+ // when ids differ in digit count (#1 vs #10). Padding is plain spaces inside the
172
+ // dim styling, so it adds no visible color.
173
+ const idLabel = `#${task.id}`.padEnd(idColWidth);
157
174
  const title = task.title;
158
175
  // The id recedes (dim); the title carries the line. Done titles fade to muted
159
176
  // (settled work), pending dim (not started), active goes bold, failed turns red.
@@ -217,7 +234,7 @@ function formatTaskLine(task, width, frame) {
217
234
  // truncateToWidth measures visible width (ANSI-aware), so the styled left can be
218
235
  // truncated against the full left budget directly. Subtracting the prefix here
219
236
  // (as a prior version did) truncated titles early and unevenly per id width.
220
- const left = truncateToWidth(`${icon} ${styledId} ${styledTitle}`, leftWidth, "…");
237
+ const left = truncateToWidth(`${icon} ${styledSource} ${styledId} ${styledTitle}`, leftWidth, "…");
221
238
  if (!rightPlain)
222
239
  return left;
223
240
  const pad = Math.max(1, width - visibleWidth(left) - visibleWidth(rightPlain));
@@ -232,7 +249,9 @@ function formatTaskLine(task, width, frame) {
232
249
  * done/total count on the left, the per-turn token/elapsed/cost delta on the right.
233
250
  * - Shows all tasks with all statuses (pending / in_progress / done / failed).
234
251
  * The active row animates a braille spinner; pending rows read `queued`.
235
- * - Subagent mode is intentionally NOT shown here (e.g. no "[explore]" tag).
252
+ * - A single-cell source glyph (⚙ subagent / MCP) sits before the id so the two
253
+ * kinds of background work are distinguishable. The subagent *mode* tag (e.g.
254
+ * "[explore]") is still intentionally NOT shown — the pane stays tag-free.
236
255
  * - LIFO within the window: newest tasks appear at the bottom (closest to the prompt).
237
256
  * - Finished tasks carry their wall-clock cost and stay visible until the next
238
257
  * user message arrives (see taskStore.reset()), not the moment they finish.
@@ -283,9 +302,12 @@ export class TaskPanelComponent {
283
302
  const railColor = STATE_PRESENTATION[state].color;
284
303
  const gutter = `${theme.fg(railColor, RAIL)} `;
285
304
  const inner = Math.max(0, width - visibleWidth(RAIL) - 1);
305
+ // Width of the id column, sized to the widest id on screen, so every title
306
+ // starts at the same column regardless of digit count (#1 vs #10 vs #100).
307
+ const idColWidth = tasks.reduce((max, t) => Math.max(max, `#${t.id}`.length), 0);
286
308
  const lines = [gutter + formatHeader(tasks, inner, state, totalSecs)];
287
309
  for (const task of tasks) {
288
- lines.push(gutter + formatTaskLine(task, inner, this.frame));
310
+ lines.push(gutter + formatTaskLine(task, inner, this.frame, idColWidth));
289
311
  }
290
312
  return lines;
291
313
  }