lsd-pi 1.3.6 → 1.3.9

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 (126) hide show
  1. package/README.md +82 -0
  2. package/dist/cli.js +2 -1
  3. package/dist/lsd-settings-manager.d.ts +2 -0
  4. package/dist/lsd-settings-manager.js +5 -0
  5. package/dist/resource-loader.js +33 -3
  6. package/dist/resources/extensions/cache-timer/index.js +3 -2
  7. package/dist/resources/extensions/mcp-client/index.js +72 -4
  8. package/dist/resources/extensions/slash-commands/plan.js +5 -5
  9. package/dist/resources/extensions/usage/index.js +34 -2
  10. package/dist/resources/extensions/voice/index.js +1 -0
  11. package/dist/resources/extensions/voice/push-to-talk.js +2 -0
  12. package/dist/welcome-screen.js +2 -2
  13. package/package.json +1 -1
  14. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts +2 -0
  15. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.d.ts.map +1 -0
  16. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js +72 -0
  17. package/packages/pi-coding-agent/dist/core/agent-session.context-usage.test.js.map +1 -0
  18. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +4 -0
  19. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  20. package/packages/pi-coding-agent/dist/core/agent-session.js +29 -2
  21. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  22. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  23. package/packages/pi-coding-agent/dist/core/extensions/runner.js +1 -0
  24. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  25. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
  26. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  27. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  28. package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.d.ts +2 -0
  29. package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.d.ts.map +1 -0
  30. package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.js +35 -0
  31. package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.js.map +1 -0
  32. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
  33. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  34. package/packages/pi-coding-agent/dist/core/settings-manager.js +12 -0
  35. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  36. package/packages/pi-coding-agent/dist/core/tool-priority.js +1 -1
  37. package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -1
  38. package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +5 -0
  39. package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
  40. package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +21 -0
  41. package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
  42. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +16 -1
  43. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  44. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  45. package/packages/pi-coding-agent/dist/main.js +1 -0
  46. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  47. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +12 -4
  48. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -1
  49. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +7 -5
  50. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  51. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +86 -28
  52. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  53. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +2 -0
  54. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  55. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +16 -10
  56. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  57. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  58. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  59. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +26 -4
  60. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  61. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -1
  62. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  63. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +128 -13
  64. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  65. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +1 -0
  66. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -1
  67. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +48 -4
  68. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +137 -6
  70. package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js.map +1 -1
  71. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  72. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +64 -15
  73. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
  75. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +2 -1
  76. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
  77. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  78. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  79. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  80. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +5 -1
  81. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  82. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +73 -27
  83. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  84. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +4 -4
  85. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  86. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  87. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -0
  88. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  89. package/packages/pi-coding-agent/package.json +1 -1
  90. package/packages/pi-coding-agent/src/core/agent-session.context-usage.test.ts +87 -0
  91. package/packages/pi-coding-agent/src/core/agent-session.ts +40 -2
  92. package/packages/pi-coding-agent/src/core/extensions/runner.ts +1 -0
  93. package/packages/pi-coding-agent/src/core/extensions/types.ts +3 -0
  94. package/packages/pi-coding-agent/src/core/settings-manager.collapse-tool-calls.test.ts +46 -0
  95. package/packages/pi-coding-agent/src/core/settings-manager.ts +18 -0
  96. package/packages/pi-coding-agent/src/core/tool-priority.ts +1 -1
  97. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +20 -0
  98. package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +26 -0
  99. package/packages/pi-coding-agent/src/main.ts +1 -0
  100. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +14 -4
  101. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +105 -28
  102. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +13 -6
  103. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +31 -4
  104. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +137 -14
  105. package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +60 -4
  106. package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +174 -6
  107. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +73 -15
  108. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +2 -1
  109. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
  110. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +76 -27
  111. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +4 -4
  112. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +4 -0
  113. package/packages/pi-tui/dist/components/editor.js +3 -3
  114. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  115. package/packages/pi-tui/src/components/editor.ts +3 -3
  116. package/pkg/dist/modes/interactive/theme/themes.js +4 -4
  117. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  118. package/pkg/package.json +1 -1
  119. package/src/resources/extensions/cache-timer/index.ts +3 -2
  120. package/src/resources/extensions/mcp-client/index.ts +83 -4
  121. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +16 -0
  122. package/src/resources/extensions/slash-commands/plan.ts +6 -6
  123. package/src/resources/extensions/usage/index.ts +40 -2
  124. package/src/resources/extensions/voice/index.ts +1 -0
  125. package/src/resources/extensions/voice/push-to-talk.ts +3 -0
  126. package/src/resources/extensions/voice/tests/push-to-talk.test.ts +6 -0
@@ -1 +1 @@
1
- {"version":3,"file":"tool-summary-line.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-summary-line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO1C,MAAM,OAAO,eAAgB,SAAQ,SAAS;IAK7C;QACC,KAAK,EAAE,CAAC;QALD,UAAK,GAAoB,EAAE,CAAC;QAC5B,WAAM,GAAG,KAAK,CAAC;QAKtB,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,OAAe;QACpC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAED,SAAS,CAAC,MAAe;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEQ,MAAM,CAAC,KAAa;QAC5B,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAEO,aAAa;QACpB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7B,OAAO;QACR,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC;QAC9B,CAAC;QAED,MAAM,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aAChE,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,MAAM,OAAO,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACnE,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,YAAY,MAAM,OAAO,GAAG,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,SAAS,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC;CACD","sourcesContent":["import { Container, Text } from \"@gsd/pi-tui\";\n\nimport { theme } from \"../theme/theme.js\";\n\ninterface CollapsedTool {\n\tname: string;\n\telapsed: number;\n}\n\nexport class ToolSummaryLine extends Container {\n\tprivate tools: CollapsedTool[] = [];\n\tprivate hidden = false;\n\tprivate contentText: Text;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.contentText = new Text(\"\", 1, 0);\n\t\tthis.addChild(this.contentText);\n\t}\n\n\taddTool(name: string, elapsed: number): void {\n\t\tthis.tools.push({ name, elapsed });\n\t\tthis.updateDisplay();\n\t}\n\n\tsetHidden(hidden: boolean): void {\n\t\tthis.hidden = hidden;\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hidden || this.tools.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\treturn super.render(width);\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tif (this.tools.length === 0) {\n\t\t\tthis.contentText.setText(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst counts = new Map<string, number>();\n\t\tlet totalElapsed = 0;\n\t\tfor (const tool of this.tools) {\n\t\t\tcounts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\ttotalElapsed += tool.elapsed;\n\t\t}\n\n\t\tconst groupedTools = [...counts.entries()]\n\t\t\t.map(([name, count]) => (count > 1 ? `${name} ×${count}` : name))\n\t\t\t.join(\" · \");\n\t\tconst elapsed = (totalElapsed / 1000).toFixed(1);\n\t\tconst indicator = theme.fg(\"success\", \"●\");\n\t\tconst title = theme.fg(\"toolTitle\", theme.bold(\"collapsed tools\"));\n\t\tconst details = theme.fg(\"muted\", `${groupedTools} · ${elapsed}s`);\n\t\tthis.contentText.setText(`${indicator} ${title} ${details}`);\n\t}\n}\n"]}
1
+ {"version":3,"file":"tool-summary-line.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-summary-line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO1C,uDAAuD;AACvD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACrC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK;CACnC,CAAC,CAAC;AAQH,MAAM,wBAAwB,GAAsC;IACnE,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAC9D,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAC/D,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAC9D,IAAI,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE;IAC1E,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IAC9D,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE;IACvE,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE;IACpE,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE;IACpE,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,EAAE,qBAAqB,EAAE;IAC9F,UAAU,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE;IACpE,eAAe,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE;IACtF,gBAAgB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE;IACxE,UAAU,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE;IACjF,gBAAgB,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE;IACvF,eAAe,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;IAC/E,aAAa,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE;CACpF,CAAC;AAEF,SAAS,WAAW,CAAC,KAAa,EAAE,QAAgB,EAAE,MAAc;IACnE,OAAO,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY,EAAE,KAAa;IACtD,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,OAAO,qBAAqB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,MAAM,UAAU,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/C,CAAC;IAED,OAAO,GAAG,UAAU,CAAC,MAAM,IAAI,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AAC7F,CAAC;AAED,MAAM,OAAO,eAAgB,SAAQ,SAAS;IAK7C,YAAY,CAAC,QAAgB;QAC5B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,qEAAqE;QACrE,IAAI,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACvG,OAAO,IAAI,CAAC;QACb,CAAC;QACD,oCAAoC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED;QACC,KAAK,EAAE,CAAC;QAfD,UAAK,GAAoB,EAAE,CAAC;QAC5B,WAAM,GAAG,KAAK,CAAC;QAetB,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,OAAe;QACpC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAED,SAAS,CAAC,MAAe;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEQ,UAAU;QAClB,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEQ,MAAM,CAAC,KAAa;QAC5B,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,OAAO,EAAE,CAAC;QACX,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAEO,aAAa;QACpB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7B,OAAO;QACR,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC;QAC9B,CAAC;QAED,MAAM,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;aACvD,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,MAAM,OAAO,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,CAAC,CAAC;QACrF,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;CACD","sourcesContent":["import { Container, Text } from \"@gsd/pi-tui\";\n\nimport { theme } from \"../theme/theme.js\";\n\ninterface CollapsedTool {\n\tname: string;\n\telapsed: number;\n}\n\n// Tools that can be mixed together in one summary line\nconst MIXED_GROUPABLE_TOOLS = new Set([\n\t\"read\", \"find\", \"ls\", \"grep\", \"lsp\",\n]);\n\ntype SummaryDescriptor = {\n\taction: string;\n\tsingular: string;\n\tplural: string;\n};\n\nconst TOOL_SUMMARY_DESCRIPTORS: Record<string, SummaryDescriptor> = {\n\tread: { action: \"reading\", singular: \"file\", plural: \"files\" },\n\twrite: { action: \"editing\", singular: \"file\", plural: \"files\" },\n\tedit: { action: \"editing\", singular: \"file\", plural: \"files\" },\n\tgrep: { action: \"searching for\", singular: \"pattern\", plural: \"patterns\" },\n\tfind: { action: \"finding\", singular: \"path\", plural: \"paths\" },\n\tls: { action: \"listing\", singular: \"directory\", plural: \"directories\" },\n\tlsp: { action: \"looking up\", singular: \"symbol\", plural: \"symbols\" },\n\tbash: { action: \"running\", singular: \"command\", plural: \"commands\" },\n\tbg_shell: { action: \"running\", singular: \"background command\", plural: \"background commands\" },\n\tfetch_page: { action: \"reading\", singular: \"page\", plural: \"pages\" },\n\tresolve_library: { action: \"searching for\", singular: \"library\", plural: \"libraries\" },\n\tget_library_docs: { action: \"reading\", singular: \"doc\", plural: \"docs\" },\n\tweb_search: { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n\t\"search-the-web\": { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n\tsearch_and_read: { action: \"researching\", singular: \"topic\", plural: \"topics\" },\n\tgoogle_search: { action: \"searching web for\", singular: \"query\", plural: \"queries\" },\n};\n\nfunction formatCount(count: number, singular: string, plural: string): string {\n\treturn `${count} ${count === 1 ? singular : plural}`;\n}\n\nfunction summarizeToolGroup(name: string, count: number): string {\n\tif (name.startsWith(\"browser_\")) {\n\t\treturn `using browser for ${formatCount(count, \"step\", \"steps\")}`;\n\t}\n\n\tconst descriptor = TOOL_SUMMARY_DESCRIPTORS[name];\n\tif (!descriptor) {\n\t\treturn count > 1 ? `${name} ×${count}` : name;\n\t}\n\n\treturn `${descriptor.action} ${formatCount(count, descriptor.singular, descriptor.plural)}`;\n}\n\nexport class ToolSummaryLine extends Container {\n\tprivate tools: CollapsedTool[] = [];\n\tprivate hidden = false;\n\tprivate contentText: Text;\n\n\tcanGroupWith(toolName: string): boolean {\n\t\tif (this.tools.length === 0) return true;\n\t\t// Mixed-groupable tools can share a summary line regardless of order\n\t\tif (MIXED_GROUPABLE_TOOLS.has(toolName) && this.tools.every((t) => MIXED_GROUPABLE_TOOLS.has(t.name))) {\n\t\t\treturn true;\n\t\t}\n\t\t// Otherwise only same-tool grouping\n\t\treturn this.tools.every((tool) => tool.name === toolName);\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.contentText = new Text(\"\", 1, 0);\n\t\tthis.addChild(this.contentText);\n\t}\n\n\taddTool(name: string, elapsed: number): void {\n\t\tthis.tools.push({ name, elapsed });\n\t\tthis.updateDisplay();\n\t}\n\n\tsetHidden(hidden: boolean): void {\n\t\tthis.hidden = hidden;\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\toverride render(width: number): string[] {\n\t\tif (this.hidden || this.tools.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\treturn super.render(width);\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tif (this.tools.length === 0) {\n\t\t\tthis.contentText.setText(\"\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst counts = new Map<string, number>();\n\t\tlet totalElapsed = 0;\n\t\tfor (const tool of this.tools) {\n\t\t\tcounts.set(tool.name, (counts.get(tool.name) ?? 0) + 1);\n\t\t\ttotalElapsed += tool.elapsed;\n\t\t}\n\n\t\tconst groupedTools = [...counts.entries()]\n\t\t\t.map(([name, count]) => summarizeToolGroup(name, count))\n\t\t\t.join(\" · \");\n\t\tconst elapsed = (totalElapsed / 1000).toFixed(1);\n\t\tconst indicator = theme.fg(\"success\", \"●\");\n\t\tconst details = theme.fg(\"text\", groupedTools) + theme.fg(\"muted\", ` · ${elapsed}s`);\n\t\tthis.contentText.setText(`${indicator} ${details}`);\n\t}\n}\n"]}
@@ -12,6 +12,14 @@ function assistantMessage(content = []) {
12
12
  timestamp: Date.now(),
13
13
  };
14
14
  }
15
+ function toolStartEvent(toolCallId, toolName, args = {}) {
16
+ return {
17
+ type: "tool_execution_start",
18
+ toolCallId,
19
+ toolName,
20
+ args,
21
+ };
22
+ }
15
23
  function toolEndEvent(toolCallId, toolName) {
16
24
  return {
17
25
  type: "tool_execution_end",
@@ -38,7 +46,7 @@ function createChatContainer() {
38
46
  },
39
47
  };
40
48
  }
41
- function createHost() {
49
+ function createHost(options = {}) {
42
50
  const chatContainer = createChatContainer();
43
51
  return {
44
52
  isInitialized: true,
@@ -55,10 +63,12 @@ function createHost() {
55
63
  getShowImages: () => true,
56
64
  getToolOutputMode: () => "normal",
57
65
  getEditorScheme: () => "auto",
66
+ getCollapseToolCalls: () => options.collapseToolCalls ?? true,
58
67
  },
59
68
  pendingTools: new Map(),
60
69
  collapsedToolSummaryLine: undefined,
61
- toolOutputExpanded: false,
70
+ collapsedToolCallsExpanded: options.collapsedToolCallsExpanded ?? options.toolOutputExpanded ?? false,
71
+ toolOutputExpanded: options.toolOutputExpanded ?? false,
62
72
  hideThinkingBlock: false,
63
73
  notificationSoundEnabled: false,
64
74
  defaultEditor: { onEscape: undefined, bottomHint: "" },
@@ -115,7 +125,61 @@ function summaryLines(host) {
115
125
  return host.chatContainer.children.filter((child) => child instanceof ToolSummaryLine);
116
126
  }
117
127
  describe("chat-controller collapsed tool summary lifecycle", () => {
118
- it("keeps single grouped summary across text-only message updates", async () => {
128
+ it("hides collapsible tool calls immediately to avoid blink before grouping", async () => {
129
+ const host = createHost();
130
+ await handleAgentEvent(host, {
131
+ type: "message_start",
132
+ message: assistantMessage(),
133
+ });
134
+ await handleAgentEvent(host, toolStartEvent("tool-1", "read", { path: "README.md" }));
135
+ const pending = host.pendingTools.get("tool-1");
136
+ assert.ok(pending);
137
+ assert.equal(pending.isHidden(), true);
138
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
139
+ assert.equal(summaryLines(host).length, 1);
140
+ });
141
+ it("hides streamed tool-call blocks immediately to avoid blink before grouping", async () => {
142
+ const host = createHost();
143
+ await handleAgentEvent(host, {
144
+ type: "message_start",
145
+ message: assistantMessage(),
146
+ });
147
+ await handleAgentEvent(host, {
148
+ type: "message_update",
149
+ message: assistantMessage([
150
+ { type: "toolCall", id: "tool-1", name: "read", arguments: { path: "README.md" } },
151
+ ]),
152
+ });
153
+ const pending = host.pendingTools.get("tool-1");
154
+ assert.ok(pending);
155
+ assert.equal(pending.isHidden(), true);
156
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
157
+ assert.equal(summaryLines(host).length, 1);
158
+ });
159
+ it("reveals initially hidden on-error tools when they fail", async () => {
160
+ const host = createHost();
161
+ await handleAgentEvent(host, {
162
+ type: "message_start",
163
+ message: assistantMessage(),
164
+ });
165
+ await handleAgentEvent(host, toolStartEvent("tool-1", "bash", { command: "exit 1" }));
166
+ const pending = host.pendingTools.get("tool-1");
167
+ assert.ok(pending);
168
+ assert.equal(pending.isHidden(), true);
169
+ await handleAgentEvent(host, {
170
+ type: "tool_execution_end",
171
+ toolCallId: "tool-1",
172
+ toolName: "bash",
173
+ isError: true,
174
+ result: {
175
+ content: [{ type: "text", text: "failed" }],
176
+ details: {},
177
+ },
178
+ });
179
+ assert.equal(summaryLines(host).length, 0);
180
+ assert.equal(pending.isHidden(), false);
181
+ });
182
+ it("groups consecutive identical collapsed tools", async () => {
119
183
  const host = createHost();
120
184
  await handleAgentEvent(host, {
121
185
  type: "message_start",
@@ -132,7 +196,37 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
132
196
  await handleAgentEvent(host, toolEndEvent("tool-2", "read"));
133
197
  const summaries = summaryLines(host);
134
198
  assert.equal(summaries.length, 1);
135
- assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("read ×2 · 1.0s"));
199
+ assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 2 files · 1.0s"));
200
+ });
201
+ it("does not group web fetches", async () => {
202
+ const host = createHost();
203
+ await handleAgentEvent(host, {
204
+ type: "message_start",
205
+ message: assistantMessage(),
206
+ });
207
+ addPendingTool(host, "tool-1", 200);
208
+ await handleAgentEvent(host, toolEndEvent("tool-1", "fetch_page"));
209
+ addPendingTool(host, "tool-2", 300);
210
+ await handleAgentEvent(host, toolEndEvent("tool-2", "fetch_page"));
211
+ const summaries = summaryLines(host);
212
+ assert.equal(summaries.length, 2);
213
+ assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 1 page · 0.2s"));
214
+ assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("reading 1 page · 0.3s"));
215
+ });
216
+ it("keeps different collapsed tool types in separate summaries", async () => {
217
+ const host = createHost();
218
+ await handleAgentEvent(host, {
219
+ type: "message_start",
220
+ message: assistantMessage(),
221
+ });
222
+ addPendingTool(host, "tool-1", 200);
223
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
224
+ addPendingTool(host, "tool-2", 300);
225
+ await handleAgentEvent(host, toolEndEvent("tool-2", "find"));
226
+ const summaries = summaryLines(host);
227
+ assert.equal(summaries.length, 2);
228
+ assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 1 file · 0.2s"));
229
+ assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("finding 1 path · 0.3s"));
136
230
  });
137
231
  it("resets grouping after visible tool result", async () => {
138
232
  const host = createHost();
@@ -152,7 +246,7 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
152
246
  assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("0.2s"));
153
247
  assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("0.4s"));
154
248
  });
155
- it("merges adjacent collapsed groups across empty assistant message boundaries", async () => {
249
+ it("groups identical collapsed tools across empty assistant message boundaries", async () => {
156
250
  const host = createHost();
157
251
  await handleAgentEvent(host, {
158
252
  type: "message_start",
@@ -168,7 +262,7 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
168
262
  await handleAgentEvent(host, toolEndEvent("tool-2", "read"));
169
263
  const summaries = summaryLines(host);
170
264
  assert.equal(summaries.length, 1);
171
- assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("read ×2 · 0.7s"));
265
+ assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("reading 2 files · 0.7s"));
172
266
  });
173
267
  it("starts new collapsed group after visible assistant content", async () => {
174
268
  const host = createHost();
@@ -193,5 +287,42 @@ describe("chat-controller collapsed tool summary lifecycle", () => {
193
287
  assert.ok(stripAnsi(summaries[0].render(160).join("\n")).includes("0.3s"));
194
288
  assert.ok(stripAnsi(summaries[1].render(160).join("\n")).includes("0.4s"));
195
289
  });
290
+ it("keeps collapsed tool calls visible in intermediate mode", async () => {
291
+ const host = createHost({ collapseToolCalls: true, collapsedToolCallsExpanded: true });
292
+ await handleAgentEvent(host, {
293
+ type: "message_start",
294
+ message: assistantMessage(),
295
+ });
296
+ const tool = addPendingTool(host, "tool-1", 250);
297
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
298
+ const summaries = summaryLines(host);
299
+ assert.equal(tool.hidden, false);
300
+ assert.equal(summaries.length, 1);
301
+ assert.deepEqual(summaries[0].render(160), []);
302
+ });
303
+ it("keeps collapsed tools visible when verbose mode is active", async () => {
304
+ const host = createHost({ collapseToolCalls: true, toolOutputExpanded: true });
305
+ await handleAgentEvent(host, {
306
+ type: "message_start",
307
+ message: assistantMessage(),
308
+ });
309
+ const tool = addPendingTool(host, "tool-1", 250);
310
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
311
+ const summaries = summaryLines(host);
312
+ assert.equal(tool.hidden, false);
313
+ assert.equal(summaries.length, 1);
314
+ assert.deepEqual(summaries[0].render(160), []);
315
+ });
316
+ it("does not collapse tool calls when setting is disabled", async () => {
317
+ const host = createHost({ collapseToolCalls: false });
318
+ await handleAgentEvent(host, {
319
+ type: "message_start",
320
+ message: assistantMessage(),
321
+ });
322
+ const tool = addPendingTool(host, "tool-1", 250);
323
+ await handleAgentEvent(host, toolEndEvent("tool-1", "read"));
324
+ assert.equal(tool.hidden, false);
325
+ assert.equal(summaryLines(host).length, 0);
326
+ });
196
327
  });
197
328
  //# sourceMappingURL=chat-controller.collapsed-tool-summary.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.collapsed-tool-summary.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { handleAgentEvent } from \"../chat-controller.js\";\nimport { ToolSummaryLine } from \"../../components/tool-summary-line.js\";\nimport { getMarkdownTheme, initTheme } from \"../../theme/theme.js\";\n\ninitTheme(\"dark\");\n\nfunction assistantMessage(content: any[] = []): any {\n return {\n role: \"assistant\",\n content,\n timestamp: Date.now(),\n };\n}\n\nfunction toolEndEvent(toolCallId: string, toolName: string): any {\n return {\n type: \"tool_execution_end\",\n toolCallId,\n toolName,\n isError: false,\n result: {\n content: [],\n details: {},\n },\n };\n}\n\nfunction createChatContainer() {\n return {\n children: [] as any[],\n addChild(child: any) {\n this.children.push(child);\n },\n removeChild(child: any) {\n this.children = this.children.filter((c) => c !== child);\n },\n clear() {\n this.children = [];\n },\n };\n}\n\nfunction createHost(): any {\n const chatContainer = createChatContainer();\n return {\n isInitialized: true,\n init: async () => { },\n ui: {\n requestRender: () => { },\n terminal: { write: () => { } },\n },\n footer: { invalidate: () => { } },\n statusContainer: { clear: () => { }, addChild: () => { } },\n chatContainer,\n settingsManager: {\n getTimestampFormat: () => \"date-time-iso\",\n getShowImages: () => true,\n getToolOutputMode: () => \"normal\",\n getEditorScheme: () => \"auto\",\n },\n pendingTools: new Map(),\n collapsedToolSummaryLine: undefined,\n toolOutputExpanded: false,\n hideThinkingBlock: false,\n notificationSoundEnabled: false,\n defaultEditor: { onEscape: undefined, bottomHint: \"\" },\n session: {\n thinkingLevel: \"off\",\n retryAttempt: 0,\n abortCompaction: () => { },\n abortRetry: () => { },\n },\n keybindings: {},\n pendingMessagesContainer: { clear: () => { } },\n compactionQueuedMessages: [],\n defaultWorkingMessage: \"\",\n workingMessages: [],\n startLoadingTips: () => { },\n stopLoadingTips: () => { },\n getMarkdownThemeWithSettings: () => getMarkdownTheme(),\n addMessageToChat: () => { },\n formatWebSearchResult: () => \"\",\n getRegisteredToolDefinition: () => undefined,\n checkShutdownRequested: async () => { },\n rebuildChatFromMessages: () => { },\n flushCompactionQueue: async () => { },\n showStatus: () => { },\n showError: () => { },\n updatePendingMessagesDisplay: () => { },\n updateTerminalTitle: () => { },\n updateEditorBorderColor: () => { },\n updateEditorExpandHint: () => { },\n getAgentPtyComponent: () => undefined,\n ensureAgentPtyComponent: () => undefined,\n updateAgentPtyComponent: () => { },\n clearAgentPtyComponents: () => { },\n };\n}\n\nfunction addPendingTool(host: any, toolCallId: string, elapsed: number): { hidden?: boolean; component: any } {\n const state: { hidden?: boolean; component: any } = { hidden: false, component: undefined };\n const component = {\n render: () => (state.hidden ? [] : [\"tool\"]),\n updateResult: () => { },\n setHidden: (hidden: boolean) => {\n state.hidden = hidden;\n },\n isHidden: () => !!state.hidden,\n setArgsComplete: () => { },\n getElapsed: () => elapsed,\n };\n state.component = component;\n host.chatContainer.addChild(component);\n host.pendingTools.set(toolCallId, component);\n return state;\n}\n\nfunction summaryLines(host: any): ToolSummaryLine[] {\n return host.chatContainer.children.filter((child: any) => child instanceof ToolSummaryLine);\n}\n\ndescribe(\"chat-controller collapsed tool summary lifecycle\", () => {\n it(\"keeps single grouped summary across text-only message updates\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const first = addPendingTool(host, \"tool-1\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(host.chatContainer.children.indexOf(summaryLines(host)[0]), host.chatContainer.children.indexOf(first.component) - 1);\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"streaming text\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 600);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"read ×2 · 1.0s\"));\n });\n\n it(\"resets grouping after visible tool result\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const visibleTool = addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"write\"));\n assert.equal(visibleTool.hidden, false);\n\n addPendingTool(host, \"tool-3\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-3\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"merges adjacent collapsed groups across empty assistant message boundaries\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"read ×2 · 0.7s\"));\n });\n\n it(\"starts new collapsed group after visible assistant content\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"visible reply\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.3s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n});\n"]}
1
+ {"version":3,"file":"chat-controller.collapsed-tool-summary.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport stripAnsi from \"strip-ansi\";\n\nimport { handleAgentEvent } from \"../chat-controller.js\";\nimport { ToolSummaryLine } from \"../../components/tool-summary-line.js\";\nimport { getMarkdownTheme, initTheme } from \"../../theme/theme.js\";\n\ninitTheme(\"dark\");\n\nfunction assistantMessage(content: any[] = []): any {\n return {\n role: \"assistant\",\n content,\n timestamp: Date.now(),\n };\n}\n\nfunction toolStartEvent(toolCallId: string, toolName: string, args: Record<string, unknown> = {}): any {\n return {\n type: \"tool_execution_start\",\n toolCallId,\n toolName,\n args,\n };\n}\n\nfunction toolEndEvent(toolCallId: string, toolName: string): any {\n return {\n type: \"tool_execution_end\",\n toolCallId,\n toolName,\n isError: false,\n result: {\n content: [],\n details: {},\n },\n };\n}\n\nfunction createChatContainer() {\n return {\n children: [] as any[],\n addChild(child: any) {\n this.children.push(child);\n },\n removeChild(child: any) {\n this.children = this.children.filter((c) => c !== child);\n },\n clear() {\n this.children = [];\n },\n };\n}\n\nfunction createHost(options: { collapseToolCalls?: boolean; collapsedToolCallsExpanded?: boolean; toolOutputExpanded?: boolean } = {}): any {\n const chatContainer = createChatContainer();\n return {\n isInitialized: true,\n init: async () => { },\n ui: {\n requestRender: () => { },\n terminal: { write: () => { } },\n },\n footer: { invalidate: () => { } },\n statusContainer: { clear: () => { }, addChild: () => { } },\n chatContainer,\n settingsManager: {\n getTimestampFormat: () => \"date-time-iso\",\n getShowImages: () => true,\n getToolOutputMode: () => \"normal\",\n getEditorScheme: () => \"auto\",\n getCollapseToolCalls: () => options.collapseToolCalls ?? true,\n },\n pendingTools: new Map(),\n collapsedToolSummaryLine: undefined,\n collapsedToolCallsExpanded: options.collapsedToolCallsExpanded ?? options.toolOutputExpanded ?? false,\n toolOutputExpanded: options.toolOutputExpanded ?? false,\n hideThinkingBlock: false,\n notificationSoundEnabled: false,\n defaultEditor: { onEscape: undefined, bottomHint: \"\" },\n session: {\n thinkingLevel: \"off\",\n retryAttempt: 0,\n abortCompaction: () => { },\n abortRetry: () => { },\n },\n keybindings: {},\n pendingMessagesContainer: { clear: () => { } },\n compactionQueuedMessages: [],\n defaultWorkingMessage: \"\",\n workingMessages: [],\n startLoadingTips: () => { },\n stopLoadingTips: () => { },\n getMarkdownThemeWithSettings: () => getMarkdownTheme(),\n addMessageToChat: () => { },\n formatWebSearchResult: () => \"\",\n getRegisteredToolDefinition: () => undefined,\n checkShutdownRequested: async () => { },\n rebuildChatFromMessages: () => { },\n flushCompactionQueue: async () => { },\n showStatus: () => { },\n showError: () => { },\n updatePendingMessagesDisplay: () => { },\n updateTerminalTitle: () => { },\n updateEditorBorderColor: () => { },\n updateEditorExpandHint: () => { },\n getAgentPtyComponent: () => undefined,\n ensureAgentPtyComponent: () => undefined,\n updateAgentPtyComponent: () => { },\n clearAgentPtyComponents: () => { },\n };\n}\n\nfunction addPendingTool(host: any, toolCallId: string, elapsed: number): { hidden?: boolean; component: any } {\n const state: { hidden?: boolean; component: any } = { hidden: false, component: undefined };\n const component = {\n render: () => (state.hidden ? [] : [\"tool\"]),\n updateResult: () => { },\n setHidden: (hidden: boolean) => {\n state.hidden = hidden;\n },\n isHidden: () => !!state.hidden,\n setArgsComplete: () => { },\n getElapsed: () => elapsed,\n };\n state.component = component;\n host.chatContainer.addChild(component);\n host.pendingTools.set(toolCallId, component);\n return state;\n}\n\nfunction summaryLines(host: any): ToolSummaryLine[] {\n return host.chatContainer.children.filter((child: any) => child instanceof ToolSummaryLine);\n}\n\ndescribe(\"chat-controller collapsed tool summary lifecycle\", () => {\n it(\"hides collapsible tool calls immediately to avoid blink before grouping\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"read\", { path: \"README.md\" }));\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(summaryLines(host).length, 1);\n });\n\n it(\"hides streamed tool-call blocks immediately to avoid blink before grouping\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([\n { type: \"toolCall\", id: \"tool-1\", name: \"read\", arguments: { path: \"README.md\" } },\n ]),\n } as any);\n\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(summaryLines(host).length, 1);\n });\n\n it(\"reveals initially hidden on-error tools when they fail\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n await handleAgentEvent(host, toolStartEvent(\"tool-1\", \"bash\", { command: \"exit 1\" }));\n const pending = host.pendingTools.get(\"tool-1\");\n assert.ok(pending);\n assert.equal(pending.isHidden(), true);\n\n await handleAgentEvent(host, {\n type: \"tool_execution_end\",\n toolCallId: \"tool-1\",\n toolName: \"bash\",\n isError: true,\n result: {\n content: [{ type: \"text\", text: \"failed\" }],\n details: {},\n },\n });\n\n assert.equal(summaryLines(host).length, 0);\n assert.equal(pending.isHidden(), false);\n });\n\n it(\"groups consecutive identical collapsed tools\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const first = addPendingTool(host, \"tool-1\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n assert.equal(host.chatContainer.children.indexOf(summaryLines(host)[0]), host.chatContainer.children.indexOf(first.component) - 1);\n\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"streaming text\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 600);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 2 files · 1.0s\"));\n });\n\n it(\"does not group web fetches\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"fetch_page\"));\n\n addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"fetch_page\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 1 page · 0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"reading 1 page · 0.3s\"));\n });\n\n it(\"keeps different collapsed tool types in separate summaries\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"find\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 1 file · 0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"finding 1 path · 0.3s\"));\n });\n\n it(\"resets grouping after visible tool result\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 200);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const visibleTool = addPendingTool(host, \"tool-2\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"write\"));\n assert.equal(visibleTool.hidden, false);\n\n addPendingTool(host, \"tool-3\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-3\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.2s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"groups identical collapsed tools across empty assistant message boundaries\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 1);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"reading 2 files · 0.7s\"));\n });\n\n it(\"starts new collapsed group after visible assistant content\", async () => {\n const host = createHost();\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n addPendingTool(host, \"tool-1\", 300);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n await handleAgentEvent(host, {\n type: \"message_update\",\n message: assistantMessage([{ type: \"text\", text: \"visible reply\" }]),\n } as any);\n\n addPendingTool(host, \"tool-2\", 400);\n await handleAgentEvent(host, toolEndEvent(\"tool-2\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(summaries.length, 2);\n assert.ok(stripAnsi(summaries[0].render(160).join(\"\\n\")).includes(\"0.3s\"));\n assert.ok(stripAnsi(summaries[1].render(160).join(\"\\n\")).includes(\"0.4s\"));\n });\n\n it(\"keeps collapsed tool calls visible in intermediate mode\", async () => {\n const host = createHost({ collapseToolCalls: true, collapsedToolCallsExpanded: true });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(tool.hidden, false);\n assert.equal(summaries.length, 1);\n assert.deepEqual(summaries[0].render(160), []);\n });\n\n it(\"keeps collapsed tools visible when verbose mode is active\", async () => {\n const host = createHost({ collapseToolCalls: true, toolOutputExpanded: true });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n const summaries = summaryLines(host);\n assert.equal(tool.hidden, false);\n assert.equal(summaries.length, 1);\n assert.deepEqual(summaries[0].render(160), []);\n });\n\n it(\"does not collapse tool calls when setting is disabled\", async () => {\n const host = createHost({ collapseToolCalls: false });\n\n await handleAgentEvent(host, {\n type: \"message_start\",\n message: assistantMessage(),\n });\n\n const tool = addPendingTool(host, \"tool-1\", 250);\n await handleAgentEvent(host, toolEndEvent(\"tool-1\", \"read\"));\n\n assert.equal(tool.hidden, false);\n assert.equal(summaryLines(host).length, 0);\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAQnG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACpE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,CAAC;IACjD,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;IACtE,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvK,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwe7C"}
1
+ {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAiBnG,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACpE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,CAAC;IACjD,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;IACtE,uBAAuB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvK,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyhB7C"}
@@ -6,6 +6,13 @@ import { ToolExecutionComponent } from "../components/tool-execution.js";
6
6
  import { ToolSummaryLine } from "../components/tool-summary-line.js";
7
7
  import { shouldCollapse } from "../../../core/tool-priority.js";
8
8
  import { appKey } from "../components/keybinding-hints.js";
9
+ const GROUPABLE_COLLAPSED_TOOLS = new Set([
10
+ "read",
11
+ "find",
12
+ "ls",
13
+ "grep",
14
+ "lsp",
15
+ ]);
9
16
  export async function handleAgentEvent(host, event) {
10
17
  if (!host.isInitialized) {
11
18
  await host.init();
@@ -14,6 +21,13 @@ export async function handleAgentEvent(host, event) {
14
21
  const resetCollapsedToolSummary = () => {
15
22
  host.collapsedToolSummaryLine = undefined;
16
23
  };
24
+ // Tools that always render as their own visible row, never folded into a summary line
25
+ const ALWAYS_DIRECT_TOOLS = new Set([
26
+ "bash", "bg_shell",
27
+ "web_search", "search-the-web", "google_search", "search_and_read",
28
+ "fetch_page", "resolve_library", "get_library_docs",
29
+ "subagent", "await_subagent",
30
+ ]);
17
31
  const hasVisibleRender = (child) => {
18
32
  if (!child?.render)
19
33
  return true;
@@ -24,12 +38,16 @@ export async function handleAgentEvent(host, event) {
24
38
  return true;
25
39
  }
26
40
  };
27
- const findAdjacentCollapsedToolSummary = (anchor) => {
41
+ const canGroupCollapsedTool = (toolName) => GROUPABLE_COLLAPSED_TOOLS.has(toolName);
42
+ const findAdjacentCollapsedToolSummary = (toolName, anchor) => {
43
+ if (!canGroupCollapsedTool(toolName)) {
44
+ return undefined;
45
+ }
28
46
  const anchorIndex = anchor ? host.chatContainer.children.indexOf(anchor) : host.chatContainer.children.length;
29
47
  for (let i = anchorIndex - 1; i >= 0; i--) {
30
48
  const child = host.chatContainer.children[i];
31
49
  if (child instanceof ToolSummaryLine) {
32
- return child;
50
+ return child.canGroupWith(toolName) ? child : undefined;
33
51
  }
34
52
  if (child instanceof ToolExecutionComponent && child.isHidden()) {
35
53
  continue;
@@ -42,16 +60,10 @@ export async function handleAgentEvent(host, event) {
42
60
  return undefined;
43
61
  };
44
62
  const appendCollapsedToolSummary = (toolName, elapsed, anchor) => {
45
- let summary = host.collapsedToolSummaryLine;
46
- if ((!summary || !host.chatContainer.children.includes(summary)) && anchor) {
47
- summary = findAdjacentCollapsedToolSummary(anchor);
48
- if (summary) {
49
- host.collapsedToolSummaryLine = summary;
50
- }
51
- }
52
- if (!summary || !host.chatContainer.children.includes(summary)) {
63
+ let summary = findAdjacentCollapsedToolSummary(toolName, anchor);
64
+ if (!summary) {
53
65
  summary = new ToolSummaryLine();
54
- summary.setHidden(host.toolOutputExpanded);
66
+ summary.setHidden(host.collapsedToolCallsExpanded);
55
67
  if (anchor) {
56
68
  const anchorIndex = host.chatContainer.children.indexOf(anchor);
57
69
  if (anchorIndex >= 0) {
@@ -64,9 +76,10 @@ export async function handleAgentEvent(host, event) {
64
76
  else {
65
77
  host.chatContainer.addChild(summary);
66
78
  }
67
- host.collapsedToolSummaryLine = summary;
68
79
  }
80
+ host.collapsedToolSummaryLine = summary;
69
81
  summary.addTool(toolName, elapsed);
82
+ return summary;
70
83
  };
71
84
  switch (event.type) {
72
85
  case "session_state_changed":
@@ -124,7 +137,7 @@ export async function handleAgentEvent(host, event) {
124
137
  }
125
138
  host.statusContainer.clear();
126
139
  host.loadingAnimation = new Loader(host.ui, (spinner) => theme.fg("text", spinner), (text) => theme.fg("accent", text), host.defaultWorkingMessage);
127
- host.loadingAnimation.setCycleMessages(host.workingMessages, 3000);
140
+ host.loadingAnimation.setCycleMessages(host.workingMessages, 10_000);
128
141
  host.statusContainer.addChild(host.loadingAnimation);
129
142
  host.startLoadingTips();
130
143
  // Show steer/queue + expand hint in editor bottom border while agent is running
@@ -175,8 +188,19 @@ export async function handleAgentEvent(host, event) {
175
188
  editorScheme: host.settingsManager.getEditorScheme(),
176
189
  }, host.getRegisteredToolDefinition(content.name), host.ui);
177
190
  component.setExpanded(host.toolOutputExpanded);
191
+ const collapseToolCalls = host.settingsManager.getCollapseToolCalls?.() ?? false;
192
+ const shouldHide = collapseToolCalls && !host.collapsedToolCallsExpanded && shouldCollapse(content.name, false) && !ALWAYS_DIRECT_TOOLS.has(content.name);
178
193
  host.chatContainer.addChild(component);
194
+ if (shouldHide) {
195
+ // Check for adjacent summary AFTER adding to container so indexOf works
196
+ const adjacentSummary = findAdjacentCollapsedToolSummary(content.name, component);
197
+ if (adjacentSummary) {
198
+ component.setIndented(true);
199
+ }
200
+ }
201
+ component.setHidden(shouldHide);
179
202
  host.pendingTools.set(content.id, component);
203
+ host.updateEditorExpandHint();
180
204
  }
181
205
  else {
182
206
  host.pendingTools.get(content.id)?.updateArgs(content.arguments);
@@ -190,8 +214,19 @@ export async function handleAgentEvent(host, event) {
190
214
  editorScheme: host.settingsManager.getEditorScheme(),
191
215
  }, undefined, host.ui);
192
216
  component.setExpanded(host.toolOutputExpanded);
217
+ const collapseToolCalls = host.settingsManager.getCollapseToolCalls?.() ?? false;
218
+ const shouldHide = collapseToolCalls && !host.collapsedToolCallsExpanded && shouldCollapse(content.name, false) && !ALWAYS_DIRECT_TOOLS.has(content.name);
193
219
  host.chatContainer.addChild(component);
220
+ if (shouldHide) {
221
+ // Check for adjacent summary AFTER adding to container so indexOf works
222
+ const adjacentSummary = findAdjacentCollapsedToolSummary(content.name, component);
223
+ if (adjacentSummary) {
224
+ component.setIndented(true);
225
+ }
226
+ }
227
+ component.setHidden(shouldHide);
194
228
  host.pendingTools.set(content.id, component);
229
+ host.updateEditorExpandHint();
195
230
  }
196
231
  }
197
232
  else if (content.type === "webSearchResult") {
@@ -268,8 +303,19 @@ export async function handleAgentEvent(host, event) {
268
303
  editorScheme: host.settingsManager.getEditorScheme(),
269
304
  }, host.getRegisteredToolDefinition(event.toolName), host.ui);
270
305
  component.setExpanded(host.toolOutputExpanded);
306
+ const collapseToolCalls = host.settingsManager.getCollapseToolCalls?.() ?? false;
307
+ const shouldHide = collapseToolCalls && !host.collapsedToolCallsExpanded && shouldCollapse(event.toolName, false) && !ALWAYS_DIRECT_TOOLS.has(event.toolName);
271
308
  host.chatContainer.addChild(component);
309
+ if (shouldHide) {
310
+ // Check for adjacent summary AFTER adding to container so indexOf works
311
+ const adjacentSummary = findAdjacentCollapsedToolSummary(event.toolName, component);
312
+ if (adjacentSummary) {
313
+ component.setIndented(true);
314
+ }
315
+ }
316
+ component.setHidden(shouldHide);
272
317
  host.pendingTools.set(event.toolCallId, component);
318
+ host.updateEditorExpandHint();
273
319
  host.ui.requestRender();
274
320
  }
275
321
  break;
@@ -315,9 +361,12 @@ export async function handleAgentEvent(host, event) {
315
361
  const component = host.pendingTools.get(event.toolCallId);
316
362
  if (component) {
317
363
  component.updateResult({ ...event.result, isError: event.isError });
318
- if (shouldCollapse(event.toolName, event.isError)) {
364
+ const collapseToolCalls = host.settingsManager.getCollapseToolCalls?.() ?? false;
365
+ if (collapseToolCalls && shouldCollapse(event.toolName, event.isError) && !ALWAYS_DIRECT_TOOLS.has(event.toolName)) {
319
366
  appendCollapsedToolSummary(event.toolName, component.getElapsed(), component);
320
- component.setHidden(true);
367
+ component.setHidden(!host.collapsedToolCallsExpanded);
368
+ component.setIndented(false);
369
+ host.updateEditorExpandHint();
321
370
  }
322
371
  else {
323
372
  component.setHidden(false);