@astralyn/pi 1.4.5 → 1.4.6

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 (169) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/bundle/chunks/{chunk-I5S7H7GA.js → chunk-EYKC6ESU.js} +1 -1
  3. package/dist/bundle/chunks/chunk-KDO6L76C.js +230 -0
  4. package/dist/bundle/chunks/chunk-RBTJBQWX.js +1500 -0
  5. package/dist/bundle/chunks/{execute-GMFGC27P.js → execute-5ZQUS52M.js} +1 -1
  6. package/dist/bundle/chunks/{virtual-modules-6FUV7ZDV.js → virtual-modules-KCQU7LOC.js} +1 -1
  7. package/dist/bundle/cli.js +1 -1
  8. package/dist/bundle/index.js +1 -1
  9. package/dist/bundle/rpc-entry.js +1 -1
  10. package/dist/core/extensions/index.d.ts +1 -1
  11. package/dist/core/extensions/index.d.ts.map +1 -1
  12. package/dist/core/extensions/index.js.map +1 -1
  13. package/dist/core/isolated-session.d.ts +23 -0
  14. package/dist/core/isolated-session.d.ts.map +1 -0
  15. package/dist/core/isolated-session.js +55 -0
  16. package/dist/core/isolated-session.js.map +1 -0
  17. package/dist/core/tasks/codec.d.ts +12 -0
  18. package/dist/core/tasks/codec.d.ts.map +1 -0
  19. package/dist/core/tasks/codec.js +139 -0
  20. package/dist/core/tasks/codec.js.map +1 -0
  21. package/dist/core/tasks/execution.d.ts +64 -0
  22. package/dist/core/tasks/execution.d.ts.map +1 -0
  23. package/dist/core/tasks/execution.js +272 -0
  24. package/dist/core/tasks/execution.js.map +1 -0
  25. package/dist/core/tasks/output.d.ts +12 -6
  26. package/dist/core/tasks/output.d.ts.map +1 -1
  27. package/dist/core/tasks/output.js +38 -38
  28. package/dist/core/tasks/output.js.map +1 -1
  29. package/dist/core/tasks/presentation.d.ts +14 -5
  30. package/dist/core/tasks/presentation.d.ts.map +1 -1
  31. package/dist/core/tasks/presentation.js +56 -185
  32. package/dist/core/tasks/presentation.js.map +1 -1
  33. package/dist/core/tasks/runtime.d.ts +9 -9
  34. package/dist/core/tasks/runtime.d.ts.map +1 -1
  35. package/dist/core/tasks/runtime.js +63 -254
  36. package/dist/core/tasks/runtime.js.map +1 -1
  37. package/dist/core/tasks/scheduler.d.ts +16 -0
  38. package/dist/core/tasks/scheduler.d.ts.map +1 -0
  39. package/dist/core/tasks/scheduler.js +42 -0
  40. package/dist/core/tasks/scheduler.js.map +1 -0
  41. package/dist/core/tasks/session.d.ts +1 -0
  42. package/dist/core/tasks/session.d.ts.map +1 -1
  43. package/dist/core/tasks/session.js +15 -27
  44. package/dist/core/tasks/session.js.map +1 -1
  45. package/dist/core/tasks/store.js +4 -4
  46. package/dist/core/tasks/store.js.map +1 -1
  47. package/dist/core/tasks/types.d.ts +63 -53
  48. package/dist/core/tasks/types.d.ts.map +1 -1
  49. package/dist/core/tasks/types.js +3 -9
  50. package/dist/core/tasks/types.js.map +1 -1
  51. package/dist/core/tools/shell-execution.js +4 -4
  52. package/dist/core/tools/shell-execution.js.map +1 -1
  53. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  54. package/dist/core/tools/shell-tool.js +23 -30
  55. package/dist/core/tools/shell-tool.js.map +1 -1
  56. package/dist/core/usage-totals.d.ts +1 -3
  57. package/dist/core/usage-totals.d.ts.map +1 -1
  58. package/dist/core/usage-totals.js +17 -8
  59. package/dist/core/usage-totals.js.map +1 -1
  60. package/dist/extensions/agent/activity.d.ts +4 -4
  61. package/dist/extensions/agent/activity.d.ts.map +1 -1
  62. package/dist/extensions/agent/activity.js +15 -24
  63. package/dist/extensions/agent/activity.js.map +1 -1
  64. package/dist/extensions/agent/index.d.ts +2 -11
  65. package/dist/extensions/agent/index.d.ts.map +1 -1
  66. package/dist/extensions/agent/index.js +3 -88
  67. package/dist/extensions/agent/index.js.map +1 -1
  68. package/dist/extensions/agent/progress.d.ts +31 -0
  69. package/dist/extensions/agent/progress.d.ts.map +1 -0
  70. package/dist/extensions/agent/progress.js +145 -0
  71. package/dist/extensions/agent/progress.js.map +1 -0
  72. package/dist/extensions/agent/render.d.ts.map +1 -1
  73. package/dist/extensions/agent/render.js +8 -17
  74. package/dist/extensions/agent/render.js.map +1 -1
  75. package/dist/extensions/agent/report.d.ts +9 -0
  76. package/dist/extensions/agent/report.d.ts.map +1 -0
  77. package/dist/extensions/agent/report.js +40 -0
  78. package/dist/extensions/agent/report.js.map +1 -0
  79. package/dist/extensions/agent/settings-panel.d.ts +43 -0
  80. package/dist/extensions/agent/settings-panel.d.ts.map +1 -0
  81. package/dist/extensions/agent/settings-panel.js +125 -0
  82. package/dist/extensions/agent/settings-panel.js.map +1 -0
  83. package/dist/extensions/agent/settings.d.ts +1 -1
  84. package/dist/extensions/agent/settings.d.ts.map +1 -1
  85. package/dist/extensions/agent/settings.js +101 -83
  86. package/dist/extensions/agent/settings.js.map +1 -1
  87. package/dist/extensions/agent/tool.d.ts +13 -0
  88. package/dist/extensions/agent/tool.d.ts.map +1 -0
  89. package/dist/extensions/agent/tool.js +84 -0
  90. package/dist/extensions/agent/tool.js.map +1 -0
  91. package/dist/extensions/agent/types.d.ts +19 -21
  92. package/dist/extensions/agent/types.d.ts.map +1 -1
  93. package/dist/extensions/agent/types.js +2 -10
  94. package/dist/extensions/agent/types.js.map +1 -1
  95. package/dist/extensions/agent/worker.d.ts +16 -0
  96. package/dist/extensions/agent/worker.d.ts.map +1 -0
  97. package/dist/extensions/agent/worker.js +68 -0
  98. package/dist/extensions/agent/worker.js.map +1 -0
  99. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  100. package/dist/extensions/tasks/tool/actions.js +1 -9
  101. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  102. package/dist/extensions/tasks/tool/schema.js +1 -1
  103. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  104. package/dist/extensions/tasks/tool/types.d.ts +2 -8
  105. package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
  106. package/dist/extensions/tasks/tool/types.js +0 -2
  107. package/dist/extensions/tasks/tool/types.js.map +1 -1
  108. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  109. package/dist/extensions/tasks/ui/completion-render.js +27 -26
  110. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  111. package/dist/extensions/tasks/ui/inspector.d.ts +5 -3
  112. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
  113. package/dist/extensions/tasks/ui/inspector.js +18 -6
  114. package/dist/extensions/tasks/ui/inspector.js.map +1 -1
  115. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  116. package/dist/extensions/tasks/ui/layout.js +111 -75
  117. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  118. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  119. package/dist/extensions/tasks/ui/list.js +43 -28
  120. package/dist/extensions/tasks/ui/list.js.map +1 -1
  121. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  122. package/dist/extensions/tasks/ui/manager.js +8 -2
  123. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  124. package/dist/extensions/tasks/ui/model.d.ts +4 -0
  125. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  126. package/dist/extensions/tasks/ui/model.js +12 -1
  127. package/dist/extensions/tasks/ui/model.js.map +1 -1
  128. package/dist/extensions/tasks/ui/render.js +3 -4
  129. package/dist/extensions/tasks/ui/render.js.map +1 -1
  130. package/dist/extensions/tasks/ui/task-view.d.ts +0 -5
  131. package/dist/extensions/tasks/ui/task-view.d.ts.map +1 -1
  132. package/dist/extensions/tasks/ui/task-view.js +0 -7
  133. package/dist/extensions/tasks/ui/task-view.js.map +1 -1
  134. package/dist/extensions/tasks/ui/tree.js +1 -1
  135. package/dist/extensions/tasks/ui/tree.js.map +1 -1
  136. package/dist/extensions/tasks/ui/views.d.ts +10 -5
  137. package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
  138. package/dist/extensions/tasks/ui/views.js +61 -36
  139. package/dist/extensions/tasks/ui/views.js.map +1 -1
  140. package/dist/index.d.ts +2 -1
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.js.map +1 -1
  143. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  144. package/dist/modes/interactive/components/keybinding-hints.js +2 -1
  145. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  146. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  147. package/dist/modes/interactive/components/model-selector.js +7 -4
  148. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  149. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  150. package/dist/modes/interactive/components/thinking-selector.js +10 -3
  151. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  152. package/docs/bundled/extensions/agent.md +12 -10
  153. package/docs/bundled/extensions/statusline.md +1 -1
  154. package/docs/bundled/tasks.md +15 -14
  155. package/docs/extensions.md +22 -6
  156. package/docs/sdk.md +2 -2
  157. package/docs/session-format.md +27 -23
  158. package/npm-shrinkwrap.json +2 -2
  159. package/package.json +1 -1
  160. package/dist/bundle/chunks/chunk-FSJ45CRP.js +0 -229
  161. package/dist/bundle/chunks/chunk-W3FIUMGM.js +0 -1501
  162. package/dist/core/tasks/history.d.ts +0 -4
  163. package/dist/core/tasks/history.d.ts.map +0 -1
  164. package/dist/core/tasks/history.js +0 -131
  165. package/dist/core/tasks/history.js.map +0 -1
  166. package/dist/extensions/agent/runner.d.ts +0 -24
  167. package/dist/extensions/agent/runner.d.ts.map +0 -1
  168. package/dist/extensions/agent/runner.js +0 -274
  169. package/dist/extensions/agent/runner.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"keybinding-hints.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/keybinding-hints.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAwD,MAAM,wBAAwB,CAAC;AAC9G,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAM1C,SAAS,aAAa,CAAC,IAAY,EAAE,OAA6B;IACjE,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IACpG,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,UAAgC,EAAE;IAC5E,OAAO,GAAG;SACR,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACV,CAAC;SACC,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SAC3C,IAAI,CAAC,GAAG,CAAC,CACX;SACA,IAAI,CAAC,GAAG,CAAC,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,IAAa,EAAE,UAAgC,EAAE;IACpE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACtC,QAAQ,UAAU,EAAE,CAAC;QACpB,KAAK,KAAK;YACT,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;QACzD,KAAK,MAAM;YACV,OAAO,MAAM,CAAC;QACf,KAAK,OAAO;YACX,OAAO,OAAO,CAAC;QAChB,KAAK,QAAQ,CAAC;QACd,KAAK,KAAK;YACT,OAAO,KAAK,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACZ,OAAO,OAAO,CAAC;QAChB,KAAK,OAAO;YACX,OAAO,OAAO,CAAC;QAChB,KAAK,KAAK;YACT,OAAO,KAAK,CAAC;QACd,KAAK,MAAM;YACV,OAAO,GAAG,CAAC;QACZ,KAAK,OAAO;YACX,OAAO,GAAG,CAAC;QACZ,KAAK,IAAI;YACR,OAAO,GAAG,CAAC;QACZ,KAAK,MAAM;YACV,OAAO,GAAG,CAAC;QACZ,KAAK,QAAQ;YACZ,OAAO,MAAM,CAAC;QACf,KAAK,UAAU;YACd,OAAO,MAAM,CAAC;QACf;YACC,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/F,CAAC;AACF,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,SAAS,GAAG,GAAG,CAAC;IACpB,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK;YAAE,MAAM;QAClB,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AASD,sFAAsF;AACtF,MAAM,UAAU,QAAQ,CAAC,UAAsB,EAAE,UAA2B,EAAE;IAC7E,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3G,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,UAAsB;IAC7C,OAAO,UAAU,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAsB;IACpD,OAAO,UAAU,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,UAAsB,EAAE,WAAmB;IAClE,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,WAAmB;IAC1D,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,CAAC;AACnF,CAAC","sourcesContent":["/**\n * Utilities for formatting keybinding hints in the UI.\n */\n\nimport { getKeybindings, type Keybinding, type KeybindingsManager, type KeyId } from \"@earendil-works/pi-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface KeyTextFormatOptions {\n\tcapitalize?: boolean;\n}\n\nfunction formatKeyPart(part: string, options: KeyTextFormatOptions): string {\n\tconst displayPart = process.platform === \"darwin\" && part.toLowerCase() === \"alt\" ? \"option\" : part;\n\treturn options.capitalize ? displayPart.charAt(0).toUpperCase() + displayPart.slice(1) : displayPart;\n}\n\nexport function formatKeyText(key: string, options: KeyTextFormatOptions = {}): string {\n\treturn key\n\t\t.split(\"/\")\n\t\t.map((k) =>\n\t\t\tk\n\t\t\t\t.split(\"+\")\n\t\t\t\t.map((part) => formatKeyPart(part, options))\n\t\t\t\t.join(\"+\"),\n\t\t)\n\t\t.join(\"/\");\n}\n\nfunction formatKeys(keys: KeyId[], options: KeyTextFormatOptions = {}): string {\n\tif (keys.length === 0) return \"\";\n\treturn formatKeyText(keys.join(\"/\"), options);\n}\n\nfunction formatKeyLabelPart(part: string): string {\n\tconst normalized = part.toLowerCase();\n\tswitch (normalized) {\n\t\tcase \"alt\":\n\t\t\treturn process.platform === \"darwin\" ? \"Option\" : \"Alt\";\n\t\tcase \"ctrl\":\n\t\t\treturn \"Ctrl\";\n\t\tcase \"shift\":\n\t\t\treturn \"Shift\";\n\t\tcase \"escape\":\n\t\tcase \"esc\":\n\t\t\treturn \"Esc\";\n\t\tcase \"enter\":\n\t\tcase \"return\":\n\t\t\treturn \"Enter\";\n\t\tcase \"space\":\n\t\t\treturn \"Space\";\n\t\tcase \"tab\":\n\t\t\treturn \"Tab\";\n\t\tcase \"left\":\n\t\t\treturn \"←\";\n\t\tcase \"right\":\n\t\t\treturn \"→\";\n\t\tcase \"up\":\n\t\t\treturn \"↑\";\n\t\tcase \"down\":\n\t\t\treturn \"↓\";\n\t\tcase \"pageup\":\n\t\t\treturn \"PgUp\";\n\t\tcase \"pagedown\":\n\t\t\treturn \"PgDn\";\n\t\tdefault:\n\t\t\treturn part.length === 1 ? part.toUpperCase() : part.charAt(0).toUpperCase() + part.slice(1);\n\t}\n}\n\n/** Format one key id for compact UI labels without treating literal `/` or `+` keys as separators. */\nexport function formatKeyLabel(key: string): string {\n\tif (!key) return \"\";\n\tconst modifiers: string[] = [];\n\tlet remaining = key;\n\twhile (true) {\n\t\tconst match = /^(ctrl|shift|alt)\\+/i.exec(remaining);\n\t\tif (!match) break;\n\t\tmodifiers.push(formatKeyLabelPart(match[1]));\n\t\tremaining = remaining.slice(match[0].length);\n\t}\n\tconst keyPart = formatKeyLabelPart(remaining || \"+\");\n\treturn [...modifiers, keyPart].join(\"+\");\n}\n\nexport interface KeyLabelOptions {\n\t/** Use an injected manager for custom components instead of the global manager. */\n\tkeybindings?: Pick<KeybindingsManager, \"getKeys\">;\n\t/** Display only when the action has no configured key. */\n\tfallback?: string;\n}\n\n/** Display the first configured key for a compact hint, with human-friendly names. */\nexport function keyLabel(keybinding: Keybinding, options: KeyLabelOptions = {}): string {\n\tconst key = (options.keybindings ?? getKeybindings()).getKeys(keybinding)[0];\n\treturn key !== undefined ? formatKeyLabel(key) : options.fallback ? formatKeyLabel(options.fallback) : \"\";\n}\n\nexport function keyText(keybinding: Keybinding): string {\n\treturn formatKeys(getKeybindings().getKeys(keybinding));\n}\n\nexport function keyDisplayText(keybinding: Keybinding): string {\n\treturn formatKeys(getKeybindings().getKeys(keybinding), { capitalize: true });\n}\n\nexport function keyHint(keybinding: Keybinding, description: string): string {\n\treturn theme.fg(\"dim\", keyText(keybinding)) + theme.fg(\"muted\", ` ${description}`);\n}\n\nexport function rawKeyHint(key: string, description: string): string {\n\treturn theme.fg(\"dim\", formatKeyText(key)) + theme.fg(\"muted\", ` ${description}`);\n}\n"]}
1
+ {"version":3,"file":"keybinding-hints.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/keybinding-hints.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Utilities for formatting keybinding hints in the UI.\n */\n\nimport { getKeybindings, type Keybinding, type KeybindingsManager, type KeyId } from \"@earendil-works/pi-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface KeyTextFormatOptions {\n\tcapitalize?: boolean;\n}\n\nfunction formatKeyPart(part: string, options: KeyTextFormatOptions): string {\n\tconst displayPart = process.platform === \"darwin\" && part.toLowerCase() === \"alt\" ? \"option\" : part;\n\treturn options.capitalize ? displayPart.charAt(0).toUpperCase() + displayPart.slice(1) : displayPart;\n}\n\nexport function formatKeyText(key: string, options: KeyTextFormatOptions = {}): string {\n\treturn key\n\t\t.split(\"/\")\n\t\t.map((k) =>\n\t\t\tk\n\t\t\t\t.split(\"+\")\n\t\t\t\t.map((part) => formatKeyPart(part, options))\n\t\t\t\t.join(\"+\"),\n\t\t)\n\t\t.join(\"/\");\n}\n\nfunction formatKeys(keys: KeyId[], options: KeyTextFormatOptions = {}): string {\n\tif (keys.length === 0) return \"\";\n\treturn formatKeyText(keys.join(\"/\"), options);\n}\n\nfunction formatKeyLabelPart(part: string): string {\n\tconst normalized = part.toLowerCase();\n\tswitch (normalized) {\n\t\tcase \"alt\":\n\t\t\treturn process.platform === \"darwin\" ? \"Option\" : \"Alt\";\n\t\tcase \"ctrl\":\n\t\t\treturn \"Ctrl\";\n\t\tcase \"shift\":\n\t\t\treturn \"Shift\";\n\t\tcase \"escape\":\n\t\tcase \"esc\":\n\t\t\treturn \"Esc\";\n\t\tcase \"enter\":\n\t\tcase \"return\":\n\t\t\treturn \"Enter\";\n\t\tcase \"space\":\n\t\t\treturn \"Space\";\n\t\tcase \"tab\":\n\t\t\treturn \"Tab\";\n\t\tcase \"left\":\n\t\t\treturn \"←\";\n\t\tcase \"right\":\n\t\t\treturn \"→\";\n\t\tcase \"up\":\n\t\t\treturn \"↑\";\n\t\tcase \"down\":\n\t\t\treturn \"↓\";\n\t\tcase \"pageup\":\n\t\t\treturn \"PgUp\";\n\t\tcase \"pagedown\":\n\t\t\treturn \"PgDn\";\n\t\tdefault:\n\t\t\treturn part.length === 1 ? part.toUpperCase() : part.charAt(0).toUpperCase() + part.slice(1);\n\t}\n}\n\n/** Format one key id for compact UI labels without treating literal `/` or `+` keys as separators. */\nexport function formatKeyLabel(key: string): string {\n\tif (!key) return \"\";\n\tconst modifiers: string[] = [];\n\tlet remaining = key;\n\twhile (true) {\n\t\tconst match = /^(ctrl|shift|alt)\\+/i.exec(remaining);\n\t\tif (!match) break;\n\t\tmodifiers.push(formatKeyLabelPart(match[1]));\n\t\tremaining = remaining.slice(match[0].length);\n\t}\n\t// A bare letter stays lowercase: an uppercase \"K\" alone reads as Shift+K.\n\tconst keyPart =\n\t\t!modifiers.length && /^[a-z]$/i.test(remaining) ? remaining.toLowerCase() : formatKeyLabelPart(remaining || \"+\");\n\treturn [...modifiers, keyPart].join(\"+\");\n}\n\nexport interface KeyLabelOptions {\n\t/** Use an injected manager for custom components instead of the global manager. */\n\tkeybindings?: Pick<KeybindingsManager, \"getKeys\">;\n\t/** Display only when the action has no configured key. */\n\tfallback?: string;\n}\n\n/** Display the first configured key for a compact hint, with human-friendly names. */\nexport function keyLabel(keybinding: Keybinding, options: KeyLabelOptions = {}): string {\n\tconst key = (options.keybindings ?? getKeybindings()).getKeys(keybinding)[0];\n\treturn key !== undefined ? formatKeyLabel(key) : options.fallback ? formatKeyLabel(options.fallback) : \"\";\n}\n\nexport function keyText(keybinding: Keybinding): string {\n\treturn formatKeys(getKeybindings().getKeys(keybinding));\n}\n\nexport function keyDisplayText(keybinding: Keybinding): string {\n\treturn formatKeys(getKeybindings().getKeys(keybinding), { capitalize: true });\n}\n\nexport function keyHint(keybinding: Keybinding, description: string): string {\n\treturn theme.fg(\"dim\", keyText(keybinding)) + theme.fg(\"muted\", ` ${description}`);\n}\n\nexport function rawKeyHint(key: string, description: string): string {\n\treturn theme.fg(\"dim\", formatKeyText(key)) + theme.fg(\"muted\", ` ${description}`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAkB,MAAM,uBAAuB,CAAC;AACnE,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAGd,KAAK,EAGL,KAAK,GAAG,EACR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAanE,UAAU,eAAe;IACxB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,qBAAqB;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACX;AAID;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,SAAU,YAAW,SAAS;IACzE,OAAO,CAAC,WAAW,CAAQ;IAG3B,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IACD,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,YAAY,CAAC,CAAa;IAClC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,yBAAyB,CAAC,CAA8B;IAChE,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,oBAAoB,CAAgC;IAC5D,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,YAAY,CAAC,CAAwB;IAC7C,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,SAAS,CAAC,CAAO;IACzB,OAAO,CAAC,aAAa,CAAC,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAyB;IAChE,OAAO,CAAC,cAAc,CAAC,CAAgC;IACvD,OAAO,CAAC,MAAM,CAAS;gBAGtB,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,aAAa,CAAC,eAAe,CAAC,EAC5C,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EACrC,QAAQ,EAAE,MAAM,IAAI,EACpB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAC/C,YAAY,CAAC,EAAE,qBAAqB;IA4ErC,OAAO,CAAC,sBAAsB;YAuBhB,aAAa;IAwC3B,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,UAAU;IAyDlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAmDlC,OAAO,CAAC,YAAY;IAKpB,cAAc,IAAI,KAAK;CAGvB"}
1
+ {"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAkB,MAAM,uBAAuB,CAAC;AACnE,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAGd,KAAK,EAGL,KAAK,GAAG,EACR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAanE,UAAU,eAAe;IACxB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,qBAAqB;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACX;AAID;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,SAAU,YAAW,SAAS;IACzE,OAAO,CAAC,WAAW,CAAQ;IAG3B,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IACD,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,YAAY,CAAC,CAAa;IAClC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,yBAAyB,CAAC,CAA8B;IAChE,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,oBAAoB,CAAgC;IAC5D,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,YAAY,CAAC,CAAwB;IAC7C,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,SAAS,CAAC,CAAO;IACzB,OAAO,CAAC,aAAa,CAAC,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAyB;IAChE,OAAO,CAAC,cAAc,CAAC,CAAgC;IACvD,OAAO,CAAC,MAAM,CAAS;gBAGtB,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,aAAa,CAAC,eAAe,CAAC,EAC5C,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EACrC,QAAQ,EAAE,MAAM,IAAI,EACpB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,EAC/C,YAAY,CAAC,EAAE,qBAAqB;IAsErC,OAAO,CAAC,sBAAsB;YAuBhB,aAAa;IAwC3B,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,UAAU;IAyDlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAmDlC,OAAO,CAAC,YAAY;IAKpB,cAAc,IAAI,KAAK;CAGvB"}
@@ -71,10 +71,13 @@ export class ModelSelectorComponent extends Container {
71
71
  this.listContainer = new Container();
72
72
  this.addChild(this.listContainer);
73
73
  this.addChild(new Spacer(1));
74
- // Hint
75
- if (this.onSelectAsDefaultCallback) {
76
- this.addChild(new Text(theme.fg("dim", ` ${keyDisplayText("tui.select.confirm")} to select · ${keyDisplayText("app.models.save")} to set as default · ${keyDisplayText("tui.select.cancel")} to cancel`), 0, 0));
77
- }
74
+ // Selection-only consumers have no global-default action.
75
+ const hints = [
76
+ `${keyDisplayText("tui.select.confirm")} to select`,
77
+ ...(this.onSelectAsDefaultCallback ? [`${keyDisplayText("app.models.save")} to set as default`] : []),
78
+ `${keyDisplayText("tui.select.cancel")} to cancel`,
79
+ ];
80
+ this.addChild(new Text(theme.fg("dim", ` ${hints.join(" · ")}`), 0, 0));
78
81
  // Add bottom border
79
82
  this.addChild(new DynamicBorder());
80
83
  // Render the current snapshot immediately, then refresh in the background.
@@ -1 +1 @@
1
- {"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Model, modelsAreEqual } from \"@earendil-works/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@earendil-works/pi-tui\";\nimport type { ModelRuntime } from \"../../../core/model-runtime.ts\";\nimport { refreshModelCatalogs } from \"../model-catalog-refresh.ts\";\nimport { getModelSelectorSearchText } from \"../model-search.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText, keyHint } from \"./keybinding-hints.ts\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ninterface DefaultModelReference {\n\tprovider: string;\n\tid: string;\n}\n\ntype ModelScope = \"all\" | \"scoped\";\n\n/**\n * Component that renders a model selector with search\n */\nexport class ModelSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\n\t// Focusable implementation - propagate to searchInput for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\tprivate listContainer: Container;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModelItems: ModelItem[] = [];\n\tprivate activeModels: ModelItem[] = [];\n\tprivate filteredModels: ModelItem[] = [];\n\tprivate selectedIndex: number = 0;\n\tprivate currentModel?: Model<any>;\n\tprivate modelRuntime: ModelRuntime;\n\tprivate onSelectCallback: (model: Model<any>) => void;\n\tprivate onSelectAsDefaultCallback?: (model: Model<any>) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate errorMessage?: string;\n\tprivate refreshStatusMessage = \"Refreshing model catalogs…\";\n\tprivate refreshStatusSuccess = false;\n\tprivate tui: TUI;\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\tprivate defaultModel?: DefaultModelReference;\n\tprivate scope: ModelScope = \"all\";\n\tprivate scopeText?: Text;\n\tprivate scopeHintText?: Text;\n\tprivate readonly refreshAbortController = new AbortController();\n\tprivate refreshTimeout?: ReturnType<typeof setTimeout>;\n\tprivate closed = false;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tmodelRuntime: ModelRuntime,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tonSelect: (model: Model<any>) => void,\n\t\tonCancel: () => void,\n\t\tinitialSearchInput?: string,\n\t\tonSelectAsDefault?: (model: Model<any>) => void,\n\t\tdefaultModel?: DefaultModelReference,\n\t) {\n\t\tsuper();\n\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.modelRuntime = modelRuntime;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.defaultModel = defaultModel;\n\t\tthis.scope = scopedModels.length > 0 ? \"scoped\" : \"all\";\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onSelectAsDefaultCallback = onSelectAsDefault;\n\t\tthis.onCancelCallback = onCancel;\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add hint about model filtering\n\t\tif (scopedModels.length > 0) {\n\t\t\tthis.scopeText = new Text(this.getScopeText(), 0, 0);\n\t\t\tthis.addChild(this.scopeText);\n\t\t\tthis.scopeHintText = new Text(this.getScopeHintText(), 0, 0);\n\t\t\tthis.addChild(this.scopeHintText);\n\t\t} else {\n\t\t\tconst hintText = \"Only showing models from configured providers. Use /login to add providers.\";\n\t\t\tthis.addChild(new Text(theme.fg(\"warning\", hintText), 0, 0));\n\t\t}\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create search input\n\t\tthis.searchInput = new Input();\n\t\tif (initialSearchInput) {\n\t\t\tthis.searchInput.setValue(initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => {\n\t\t\t// Enter on search input selects the first filtered item\n\t\t\tif (this.filteredModels[this.selectedIndex]) {\n\t\t\t\tthis.handleSelect(this.filteredModels[this.selectedIndex].model);\n\t\t\t}\n\t\t};\n\t\tthis.addChild(this.searchInput);\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create list container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Hint\n\t\tif (this.onSelectAsDefaultCallback) {\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\t` ${keyDisplayText(\"tui.select.confirm\")} to select · ${keyDisplayText(\"app.models.save\")} to set as default · ${keyDisplayText(\"tui.select.cancel\")} to cancel`,\n\t\t\t\t\t),\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\n\t\t// Render the current snapshot immediately, then refresh in the background.\n\t\tthis.loadModelsFromSnapshot();\n\t\tif (initialSearchInput) this.filterModels(initialSearchInput);\n\t\telse this.updateList();\n\t\tthis.tui.requestRender();\n\t\tvoid this.refreshModels();\n\t}\n\n\tprivate loadModelsFromSnapshot(): void {\n\t\tconst models = this.modelRuntime.getAvailableSnapshot().map((model: Model<any>) => ({\n\t\t\tprovider: model.provider,\n\t\t\tid: model.id,\n\t\t\tmodel,\n\t\t}));\n\t\tthis.allModels = this.sortModels(models);\n\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\tconst refreshed = this.modelRuntime.getModel(scoped.model.provider, scoped.model.id);\n\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t});\n\t\tthis.scopedModelItems = this.scopedModels.map((scoped) => ({\n\t\t\tprovider: scoped.model.provider,\n\t\t\tid: scoped.model.id,\n\t\t\tmodel: scoped.model,\n\t\t}));\n\t\tthis.activeModels = this.scope === \"scoped\" ? this.scopedModelItems : this.allModels;\n\t\tthis.filteredModels = this.activeModels;\n\t\tconst currentIndex = this.filteredModels.findIndex((item) => modelsAreEqual(this.currentModel, item.model));\n\t\tthis.selectedIndex =\n\t\t\tcurrentIndex >= 0 ? currentIndex : Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));\n\t}\n\n\tprivate async refreshModels(): Promise<void> {\n\t\tconst timeoutMs = 15_000;\n\t\tlet timedOut = false;\n\t\tthis.refreshTimeout = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tthis.refreshAbortController.abort();\n\t\t}, timeoutMs);\n\t\ttry {\n\t\t\tconst result = await refreshModelCatalogs(this.modelRuntime, this.refreshAbortController.signal);\n\t\t\tif (this.closed) return;\n\t\t\tthis.refreshStatusMessage = \"\";\n\t\t\tif (result.aborted && timedOut) {\n\t\t\t\tthis.errorMessage = \"Model refresh timed out; showing cached models.\";\n\t\t\t} else if (result.errors.size === 1) {\n\t\t\t\tthis.errorMessage = `Could not refresh ${result.errors.keys().next().value}; showing cached models.`;\n\t\t\t} else if (result.errors.size > 1) {\n\t\t\t\tthis.errorMessage = `Could not refresh ${result.errors.size} model catalogs (${[...result.errors.keys()].join(\", \")}); showing cached models.`;\n\t\t\t} else {\n\t\t\t\tthis.errorMessage = this.modelRuntime.getError();\n\t\t\t\tif (!this.errorMessage) {\n\t\t\t\t\tthis.refreshStatusMessage = \"Model catalogs refreshed.\";\n\t\t\t\t\tthis.refreshStatusSuccess = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.loadModelsFromSnapshot();\n\t\t\tthis.filterModels(this.searchInput.getValue());\n\t\t\tthis.tui.requestRender();\n\t\t} catch (error) {\n\t\t\tif (this.closed) return;\n\t\t\tthis.refreshStatusMessage = \"\";\n\t\t\tthis.errorMessage = timedOut\n\t\t\t\t? \"Model refresh timed out; showing cached models.\"\n\t\t\t\t: `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`;\n\t\t\tthis.updateList();\n\t\t\tthis.tui.requestRender();\n\t\t} finally {\n\t\t\tif (this.refreshTimeout) clearTimeout(this.refreshTimeout);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tif (this.refreshTimeout) clearTimeout(this.refreshTimeout);\n\t\tthis.refreshAbortController.abort();\n\t}\n\n\tprivate sortModels(models: ModelItem[]): ModelItem[] {\n\t\tconst sorted = [...models];\n\t\t// Sort: current model first, default model second, then by provider.\n\t\tsorted.sort((a, b) => {\n\t\t\tconst aIsCurrent = modelsAreEqual(this.currentModel, a.model);\n\t\t\tconst bIsCurrent = modelsAreEqual(this.currentModel, b.model);\n\t\t\tif (aIsCurrent && !bIsCurrent) return -1;\n\t\t\tif (!aIsCurrent && bIsCurrent) return 1;\n\t\t\tconst aIsDefault = this.isDefaultModel(a.model);\n\t\t\tconst bIsDefault = this.isDefaultModel(b.model);\n\t\t\tif (aIsDefault && !bIsDefault) return -1;\n\t\t\tif (!aIsDefault && bIsDefault) return 1;\n\t\t\treturn a.provider.localeCompare(b.provider);\n\t\t});\n\t\treturn sorted;\n\t}\n\n\tprivate getScopeText(): string {\n\t\tconst allText = this.scope === \"all\" ? theme.fg(\"accent\", \"all\") : theme.fg(\"muted\", \"all\");\n\t\tconst scopedText = this.scope === \"scoped\" ? theme.fg(\"accent\", \"scoped\") : theme.fg(\"muted\", \"scoped\");\n\t\treturn `${theme.fg(\"muted\", \"Scope: \")}${allText}${theme.fg(\"muted\", \" | \")}${scopedText}`;\n\t}\n\n\tprivate getScopeHintText(): string {\n\t\treturn keyHint(\"tui.input.tab\", \"scope\") + theme.fg(\"muted\", \" (all/scoped)\");\n\t}\n\n\tprivate isDefaultModel(model: Model<any>): boolean {\n\t\treturn this.defaultModel?.provider === model.provider && this.defaultModel.id === model.id;\n\t}\n\n\tprivate isDefaultSearch(query: string): boolean {\n\t\tconst normalized = query.trim().toLowerCase();\n\t\treturn normalized.length > 0 && \"default\".startsWith(normalized);\n\t}\n\n\tprivate setScope(scope: ModelScope): void {\n\t\tif (this.scope === scope) return;\n\t\tthis.scope = scope;\n\t\tthis.activeModels = this.scope === \"scoped\" ? this.scopedModelItems : this.allModels;\n\t\tconst currentIndex = this.activeModels.findIndex((item) => modelsAreEqual(this.currentModel, item.model));\n\t\tthis.selectedIndex = currentIndex >= 0 ? currentIndex : 0;\n\t\tthis.filterModels(this.searchInput.getValue());\n\t\tif (this.scopeText) {\n\t\t\tthis.scopeText.setText(this.getScopeText());\n\t\t}\n\t}\n\n\tprivate filterModels(query: string): void {\n\t\tif (query) {\n\t\t\tconst filtered = fuzzyFilter(this.activeModels, query, (item) => {\n\t\t\t\tconst defaultText = this.isDefaultModel(item.model) ? \" default\" : \"\";\n\t\t\t\treturn `${getModelSelectorSearchText({ id: item.id, provider: item.provider, name: item.model.name })}${defaultText}`;\n\t\t\t});\n\t\t\tif (this.isDefaultSearch(query)) {\n\t\t\t\tconst defaultItems = this.activeModels.filter((item) => this.isDefaultModel(item.model));\n\t\t\t\tconst defaultKeys = new Set(defaultItems.map((item) => `${item.provider}\\0${item.id}`));\n\t\t\t\tthis.filteredModels = [\n\t\t\t\t\t...defaultItems,\n\t\t\t\t\t...filtered.filter((item) => !defaultKeys.has(`${item.provider}\\0${item.id}`)),\n\t\t\t\t];\n\t\t\t} else {\n\t\t\t\tthis.filteredModels = filtered;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.filteredModels = this.activeModels;\n\t\t}\n\t\t// When filtering by a query, move the selector to the top row so the best\n\t\t// match is highlighted. When the query is cleared, keep the current position\n\t\t// clamped to the (restored) list length.\n\t\tthis.selectedIndex = query ? 0 : Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst maxVisible = 10;\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredModels.length - maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + maxVisible, this.filteredModels.length);\n\n\t\t// Show visible slice of filtered models\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredModels[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, item.model);\n\t\t\tconst isDefault = this.isDefaultModel(item.model);\n\t\t\tconst defaultBadge = isDefault ? theme.fg(\"muted\", \" · default\") : \"\";\n\n\t\t\tconst cursor = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst currentMarker = isCurrent ? theme.fg(\"accent\", \"✓ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.id) : item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", `[${item.provider}]`);\n\t\t\tconst line = `${cursor}${currentMarker}${modelText} ${providerBadge}${defaultBadge}`;\n\n\t\t\tthis.listContainer.addChild(new Text(line, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredModels.length) {\n\t\t\tconst scrollInfo = theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredModels.length})`);\n\t\t\tthis.listContainer.addChild(new Text(scrollInfo, 0, 0));\n\t\t}\n\n\t\t// Show error message or \"no results\" if empty\n\t\tif (this.errorMessage) {\n\t\t\t// Show error in red\n\t\t\tconst errorLines = this.errorMessage.split(\"\\n\");\n\t\t\tfor (const line of errorLines) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t} else if (this.filteredModels.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t} else {\n\t\t\tconst selected = this.filteredModels[this.selectedIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` Model Name: ${selected.model.name}`), 0, 0));\n\t\t}\n\t\tif (this.refreshStatusMessage) {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(this.refreshStatusSuccess ? \"success\" : \"muted\", ` ${this.refreshStatusMessage}`), 0, 0),\n\t\t\t);\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tif (this.scopedModelItems.length > 0) {\n\t\t\t\tconst nextScope: ModelScope = this.scope === \"all\" ? \"scoped\" : \"all\";\n\t\t\t\tthis.setScope(nextScope);\n\t\t\t\tif (this.scopeHintText) {\n\t\t\t\t\tthis.scopeHintText.setText(this.getScopeHintText());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Up arrow - wrap to bottom when at top\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.filteredModels.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredModels.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t}\n\t\t// Down arrow - wrap to top when at bottom\n\t\telse if (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.filteredModels.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredModels.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t}\n\t\t// Enter\n\t\telse if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst selectedModel = this.filteredModels[this.selectedIndex];\n\t\t\tif (selectedModel) {\n\t\t\t\tthis.handleSelect(selectedModel.model);\n\t\t\t}\n\t\t}\n\t\t// Escape or Ctrl+C\n\t\telse if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.dispose();\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t\t// Select and save as default\n\t\telse if (kb.matches(keyData, \"app.models.save\") && this.onSelectAsDefaultCallback) {\n\t\t\tconst selectedModel = this.filteredModels[this.selectedIndex];\n\t\t\tif (selectedModel) {\n\t\t\t\tthis.dispose();\n\t\t\t\tthis.onSelectAsDefaultCallback(selectedModel.model);\n\t\t\t}\n\t\t}\n\t\t// Pass everything else to search input\n\t\telse {\n\t\t\tthis.searchInput.handleInput(keyData);\n\t\t\tthis.filterModels(this.searchInput.getValue());\n\t\t}\n\t}\n\n\tprivate handleSelect(model: Model<any>): void {\n\t\tthis.dispose();\n\t\tthis.onSelectCallback(model);\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
1
+ {"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Model, modelsAreEqual } from \"@earendil-works/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@earendil-works/pi-tui\";\nimport type { ModelRuntime } from \"../../../core/model-runtime.ts\";\nimport { refreshModelCatalogs } from \"../model-catalog-refresh.ts\";\nimport { getModelSelectorSearchText } from \"../model-search.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText, keyHint } from \"./keybinding-hints.ts\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ninterface DefaultModelReference {\n\tprovider: string;\n\tid: string;\n}\n\ntype ModelScope = \"all\" | \"scoped\";\n\n/**\n * Component that renders a model selector with search\n */\nexport class ModelSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\n\t// Focusable implementation - propagate to searchInput for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\tprivate listContainer: Container;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModelItems: ModelItem[] = [];\n\tprivate activeModels: ModelItem[] = [];\n\tprivate filteredModels: ModelItem[] = [];\n\tprivate selectedIndex: number = 0;\n\tprivate currentModel?: Model<any>;\n\tprivate modelRuntime: ModelRuntime;\n\tprivate onSelectCallback: (model: Model<any>) => void;\n\tprivate onSelectAsDefaultCallback?: (model: Model<any>) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate errorMessage?: string;\n\tprivate refreshStatusMessage = \"Refreshing model catalogs…\";\n\tprivate refreshStatusSuccess = false;\n\tprivate tui: TUI;\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\tprivate defaultModel?: DefaultModelReference;\n\tprivate scope: ModelScope = \"all\";\n\tprivate scopeText?: Text;\n\tprivate scopeHintText?: Text;\n\tprivate readonly refreshAbortController = new AbortController();\n\tprivate refreshTimeout?: ReturnType<typeof setTimeout>;\n\tprivate closed = false;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tmodelRuntime: ModelRuntime,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tonSelect: (model: Model<any>) => void,\n\t\tonCancel: () => void,\n\t\tinitialSearchInput?: string,\n\t\tonSelectAsDefault?: (model: Model<any>) => void,\n\t\tdefaultModel?: DefaultModelReference,\n\t) {\n\t\tsuper();\n\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.modelRuntime = modelRuntime;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.defaultModel = defaultModel;\n\t\tthis.scope = scopedModels.length > 0 ? \"scoped\" : \"all\";\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onSelectAsDefaultCallback = onSelectAsDefault;\n\t\tthis.onCancelCallback = onCancel;\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Add hint about model filtering\n\t\tif (scopedModels.length > 0) {\n\t\t\tthis.scopeText = new Text(this.getScopeText(), 0, 0);\n\t\t\tthis.addChild(this.scopeText);\n\t\t\tthis.scopeHintText = new Text(this.getScopeHintText(), 0, 0);\n\t\t\tthis.addChild(this.scopeHintText);\n\t\t} else {\n\t\t\tconst hintText = \"Only showing models from configured providers. Use /login to add providers.\";\n\t\t\tthis.addChild(new Text(theme.fg(\"warning\", hintText), 0, 0));\n\t\t}\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create search input\n\t\tthis.searchInput = new Input();\n\t\tif (initialSearchInput) {\n\t\t\tthis.searchInput.setValue(initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => {\n\t\t\t// Enter on search input selects the first filtered item\n\t\t\tif (this.filteredModels[this.selectedIndex]) {\n\t\t\t\tthis.handleSelect(this.filteredModels[this.selectedIndex].model);\n\t\t\t}\n\t\t};\n\t\tthis.addChild(this.searchInput);\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create list container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Selection-only consumers have no global-default action.\n\t\tconst hints = [\n\t\t\t`${keyDisplayText(\"tui.select.confirm\")} to select`,\n\t\t\t...(this.onSelectAsDefaultCallback ? [`${keyDisplayText(\"app.models.save\")} to set as default`] : []),\n\t\t\t`${keyDisplayText(\"tui.select.cancel\")} to cancel`,\n\t\t];\n\t\tthis.addChild(new Text(theme.fg(\"dim\", ` ${hints.join(\" · \")}`), 0, 0));\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\n\t\t// Render the current snapshot immediately, then refresh in the background.\n\t\tthis.loadModelsFromSnapshot();\n\t\tif (initialSearchInput) this.filterModels(initialSearchInput);\n\t\telse this.updateList();\n\t\tthis.tui.requestRender();\n\t\tvoid this.refreshModels();\n\t}\n\n\tprivate loadModelsFromSnapshot(): void {\n\t\tconst models = this.modelRuntime.getAvailableSnapshot().map((model: Model<any>) => ({\n\t\t\tprovider: model.provider,\n\t\t\tid: model.id,\n\t\t\tmodel,\n\t\t}));\n\t\tthis.allModels = this.sortModels(models);\n\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\tconst refreshed = this.modelRuntime.getModel(scoped.model.provider, scoped.model.id);\n\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t});\n\t\tthis.scopedModelItems = this.scopedModels.map((scoped) => ({\n\t\t\tprovider: scoped.model.provider,\n\t\t\tid: scoped.model.id,\n\t\t\tmodel: scoped.model,\n\t\t}));\n\t\tthis.activeModels = this.scope === \"scoped\" ? this.scopedModelItems : this.allModels;\n\t\tthis.filteredModels = this.activeModels;\n\t\tconst currentIndex = this.filteredModels.findIndex((item) => modelsAreEqual(this.currentModel, item.model));\n\t\tthis.selectedIndex =\n\t\t\tcurrentIndex >= 0 ? currentIndex : Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));\n\t}\n\n\tprivate async refreshModels(): Promise<void> {\n\t\tconst timeoutMs = 15_000;\n\t\tlet timedOut = false;\n\t\tthis.refreshTimeout = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tthis.refreshAbortController.abort();\n\t\t}, timeoutMs);\n\t\ttry {\n\t\t\tconst result = await refreshModelCatalogs(this.modelRuntime, this.refreshAbortController.signal);\n\t\t\tif (this.closed) return;\n\t\t\tthis.refreshStatusMessage = \"\";\n\t\t\tif (result.aborted && timedOut) {\n\t\t\t\tthis.errorMessage = \"Model refresh timed out; showing cached models.\";\n\t\t\t} else if (result.errors.size === 1) {\n\t\t\t\tthis.errorMessage = `Could not refresh ${result.errors.keys().next().value}; showing cached models.`;\n\t\t\t} else if (result.errors.size > 1) {\n\t\t\t\tthis.errorMessage = `Could not refresh ${result.errors.size} model catalogs (${[...result.errors.keys()].join(\", \")}); showing cached models.`;\n\t\t\t} else {\n\t\t\t\tthis.errorMessage = this.modelRuntime.getError();\n\t\t\t\tif (!this.errorMessage) {\n\t\t\t\t\tthis.refreshStatusMessage = \"Model catalogs refreshed.\";\n\t\t\t\t\tthis.refreshStatusSuccess = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.loadModelsFromSnapshot();\n\t\t\tthis.filterModels(this.searchInput.getValue());\n\t\t\tthis.tui.requestRender();\n\t\t} catch (error) {\n\t\t\tif (this.closed) return;\n\t\t\tthis.refreshStatusMessage = \"\";\n\t\t\tthis.errorMessage = timedOut\n\t\t\t\t? \"Model refresh timed out; showing cached models.\"\n\t\t\t\t: `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`;\n\t\t\tthis.updateList();\n\t\t\tthis.tui.requestRender();\n\t\t} finally {\n\t\t\tif (this.refreshTimeout) clearTimeout(this.refreshTimeout);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tif (this.refreshTimeout) clearTimeout(this.refreshTimeout);\n\t\tthis.refreshAbortController.abort();\n\t}\n\n\tprivate sortModels(models: ModelItem[]): ModelItem[] {\n\t\tconst sorted = [...models];\n\t\t// Sort: current model first, default model second, then by provider.\n\t\tsorted.sort((a, b) => {\n\t\t\tconst aIsCurrent = modelsAreEqual(this.currentModel, a.model);\n\t\t\tconst bIsCurrent = modelsAreEqual(this.currentModel, b.model);\n\t\t\tif (aIsCurrent && !bIsCurrent) return -1;\n\t\t\tif (!aIsCurrent && bIsCurrent) return 1;\n\t\t\tconst aIsDefault = this.isDefaultModel(a.model);\n\t\t\tconst bIsDefault = this.isDefaultModel(b.model);\n\t\t\tif (aIsDefault && !bIsDefault) return -1;\n\t\t\tif (!aIsDefault && bIsDefault) return 1;\n\t\t\treturn a.provider.localeCompare(b.provider);\n\t\t});\n\t\treturn sorted;\n\t}\n\n\tprivate getScopeText(): string {\n\t\tconst allText = this.scope === \"all\" ? theme.fg(\"accent\", \"all\") : theme.fg(\"muted\", \"all\");\n\t\tconst scopedText = this.scope === \"scoped\" ? theme.fg(\"accent\", \"scoped\") : theme.fg(\"muted\", \"scoped\");\n\t\treturn `${theme.fg(\"muted\", \"Scope: \")}${allText}${theme.fg(\"muted\", \" | \")}${scopedText}`;\n\t}\n\n\tprivate getScopeHintText(): string {\n\t\treturn keyHint(\"tui.input.tab\", \"scope\") + theme.fg(\"muted\", \" (all/scoped)\");\n\t}\n\n\tprivate isDefaultModel(model: Model<any>): boolean {\n\t\treturn this.defaultModel?.provider === model.provider && this.defaultModel.id === model.id;\n\t}\n\n\tprivate isDefaultSearch(query: string): boolean {\n\t\tconst normalized = query.trim().toLowerCase();\n\t\treturn normalized.length > 0 && \"default\".startsWith(normalized);\n\t}\n\n\tprivate setScope(scope: ModelScope): void {\n\t\tif (this.scope === scope) return;\n\t\tthis.scope = scope;\n\t\tthis.activeModels = this.scope === \"scoped\" ? this.scopedModelItems : this.allModels;\n\t\tconst currentIndex = this.activeModels.findIndex((item) => modelsAreEqual(this.currentModel, item.model));\n\t\tthis.selectedIndex = currentIndex >= 0 ? currentIndex : 0;\n\t\tthis.filterModels(this.searchInput.getValue());\n\t\tif (this.scopeText) {\n\t\t\tthis.scopeText.setText(this.getScopeText());\n\t\t}\n\t}\n\n\tprivate filterModels(query: string): void {\n\t\tif (query) {\n\t\t\tconst filtered = fuzzyFilter(this.activeModels, query, (item) => {\n\t\t\t\tconst defaultText = this.isDefaultModel(item.model) ? \" default\" : \"\";\n\t\t\t\treturn `${getModelSelectorSearchText({ id: item.id, provider: item.provider, name: item.model.name })}${defaultText}`;\n\t\t\t});\n\t\t\tif (this.isDefaultSearch(query)) {\n\t\t\t\tconst defaultItems = this.activeModels.filter((item) => this.isDefaultModel(item.model));\n\t\t\t\tconst defaultKeys = new Set(defaultItems.map((item) => `${item.provider}\\0${item.id}`));\n\t\t\t\tthis.filteredModels = [\n\t\t\t\t\t...defaultItems,\n\t\t\t\t\t...filtered.filter((item) => !defaultKeys.has(`${item.provider}\\0${item.id}`)),\n\t\t\t\t];\n\t\t\t} else {\n\t\t\t\tthis.filteredModels = filtered;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.filteredModels = this.activeModels;\n\t\t}\n\t\t// When filtering by a query, move the selector to the top row so the best\n\t\t// match is highlighted. When the query is cleared, keep the current position\n\t\t// clamped to the (restored) list length.\n\t\tthis.selectedIndex = query ? 0 : Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst maxVisible = 10;\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredModels.length - maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + maxVisible, this.filteredModels.length);\n\n\t\t// Show visible slice of filtered models\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredModels[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, item.model);\n\t\t\tconst isDefault = this.isDefaultModel(item.model);\n\t\t\tconst defaultBadge = isDefault ? theme.fg(\"muted\", \" · default\") : \"\";\n\n\t\t\tconst cursor = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst currentMarker = isCurrent ? theme.fg(\"accent\", \"✓ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.id) : item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", `[${item.provider}]`);\n\t\t\tconst line = `${cursor}${currentMarker}${modelText} ${providerBadge}${defaultBadge}`;\n\n\t\t\tthis.listContainer.addChild(new Text(line, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredModels.length) {\n\t\t\tconst scrollInfo = theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredModels.length})`);\n\t\t\tthis.listContainer.addChild(new Text(scrollInfo, 0, 0));\n\t\t}\n\n\t\t// Show error message or \"no results\" if empty\n\t\tif (this.errorMessage) {\n\t\t\t// Show error in red\n\t\t\tconst errorLines = this.errorMessage.split(\"\\n\");\n\t\t\tfor (const line of errorLines) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t} else if (this.filteredModels.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t} else {\n\t\t\tconst selected = this.filteredModels[this.selectedIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` Model Name: ${selected.model.name}`), 0, 0));\n\t\t}\n\t\tif (this.refreshStatusMessage) {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(this.refreshStatusSuccess ? \"success\" : \"muted\", ` ${this.refreshStatusMessage}`), 0, 0),\n\t\t\t);\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tif (this.scopedModelItems.length > 0) {\n\t\t\t\tconst nextScope: ModelScope = this.scope === \"all\" ? \"scoped\" : \"all\";\n\t\t\t\tthis.setScope(nextScope);\n\t\t\t\tif (this.scopeHintText) {\n\t\t\t\t\tthis.scopeHintText.setText(this.getScopeHintText());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Up arrow - wrap to bottom when at top\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.filteredModels.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredModels.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t}\n\t\t// Down arrow - wrap to top when at bottom\n\t\telse if (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.filteredModels.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredModels.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t}\n\t\t// Enter\n\t\telse if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst selectedModel = this.filteredModels[this.selectedIndex];\n\t\t\tif (selectedModel) {\n\t\t\t\tthis.handleSelect(selectedModel.model);\n\t\t\t}\n\t\t}\n\t\t// Escape or Ctrl+C\n\t\telse if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.dispose();\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t\t// Select and save as default\n\t\telse if (kb.matches(keyData, \"app.models.save\") && this.onSelectAsDefaultCallback) {\n\t\t\tconst selectedModel = this.filteredModels[this.selectedIndex];\n\t\t\tif (selectedModel) {\n\t\t\t\tthis.dispose();\n\t\t\t\tthis.onSelectAsDefaultCallback(selectedModel.model);\n\t\t\t}\n\t\t}\n\t\t// Pass everything else to search input\n\t\telse {\n\t\t\tthis.searchInput.handleInput(keyData);\n\t\t\tthis.filterModels(this.searchInput.getValue());\n\t\t}\n\t}\n\n\tprivate handleSelect(model: Model<any>): void {\n\t\tthis.dispose();\n\t\tthis.onSelectCallback(model);\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"thinking-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAKd,UAAU,EAIV,MAAM,wBAAwB,CAAC;AAoBhC;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAU,YAAW,SAAS;IAC5E,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,iBAAiB,CAAC,CAAiC;IAC3D,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;gBAGA,YAAY,EAAE,aAAa,EAC3B,eAAe,EAAE,aAAa,EAAE,EAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACxC,QAAQ,EAAE,MAAM,IAAI,EACpB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAClD,oBAAoB,CAAC,EAAE,aAAa;IA+CrC,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,WAAW;IAUnB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAsBlC,aAAa,IAAI,UAAU;CAG3B"}
1
+ {"version":3,"file":"thinking-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAKd,UAAU,EAIV,MAAM,wBAAwB,CAAC;AAoBhC;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAU,YAAW,SAAS;IAC5E,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,iBAAiB,CAAC,CAAiC;IAC3D,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;gBAGA,YAAY,EAAE,aAAa,EAC3B,eAAe,EAAE,aAAa,EAAE,EAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACxC,QAAQ,EAAE,MAAM,IAAI,EACpB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAClD,oBAAoB,CAAC,EAAE,aAAa;IA6CrC,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,WAAW;IAUnB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAsBlC,aAAa,IAAI,UAAU;CAG3B"}
@@ -42,8 +42,10 @@ export class ThinkingSelectorComponent extends Container {
42
42
  this.addChild(new Spacer(1));
43
43
  this.addChild(new Text("Thinking Level", 0, 0));
44
44
  this.addChild(new Spacer(1));
45
- this.addChild(new Text(`${keyDisplayText("app.thinking.cycle")} cycles thinking levels in-session`, 0, 0));
46
- this.addChild(new Spacer(1));
45
+ if (onSelectAsDefault) {
46
+ this.addChild(new Text(`${keyDisplayText("app.thinking.cycle")} cycles thinking levels in-session`, 0, 0));
47
+ this.addChild(new Spacer(1));
48
+ }
47
49
  this.searchInput = new Input();
48
50
  this.searchInput.onSubmit = () => this.selectList.handleInput("\r");
49
51
  this.addChild(this.searchInput);
@@ -53,7 +55,12 @@ export class ThinkingSelectorComponent extends Container {
53
55
  this.selectListChildIndex = this.children.length;
54
56
  this.addChild(this.selectList);
55
57
  this.addChild(new Spacer(1));
56
- this.addChild(new Text(theme.fg("dim", ` ${keyDisplayText("tui.select.confirm")} to select · ${keyDisplayText("app.thinking.save")} to set as default · ${keyDisplayText("tui.select.cancel")} to cancel`), 0, 0));
58
+ const hints = [
59
+ `${keyDisplayText("tui.select.confirm")} to select`,
60
+ ...(onSelectAsDefault ? [`${keyDisplayText("app.thinking.save")} to set as default`] : []),
61
+ `${keyDisplayText("tui.select.cancel")} to cancel`,
62
+ ];
63
+ this.addChild(new Text(theme.fg("dim", ` ${hints.join(" · ")}`), 0, 0));
57
64
  // Add bottom border
58
65
  this.addChild(new DynamicBorder());
59
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"thinking-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport { getSelectListTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText } from \"./keybinding-hints.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: `${level === currentLevel ? \"✓ \" : \" \"}${level}`,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"dim\",\n\t\t\t\t\t` ${keyDisplayText(\"tui.select.confirm\")} to select · ${keyDisplayText(\"app.thinking.save\")} to set as default · ${keyDisplayText(\"tui.select.cancel\")} to cancel`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.thinking.save\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
1
+ {"version":3,"file":"thinking-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/thinking-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\tSpacer,\n\tText,\n} from \"@earendil-works/pi-tui\";\nimport { getSelectListTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText } from \"./keybinding-hints.ts\";\n\nconst THINKING_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\n/**\n * Component that renders a thinking level selector with borders\n */\nexport class ThinkingSelectorComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate selectList: SelectList;\n\tprivate selectListChildIndex: number;\n\tprivate allItems: SelectItem[];\n\tprivate onSelect: (level: ThinkingLevel) => void;\n\tprivate onCancel: () => void;\n\tprivate onSelectAsDefault?: (level: ThinkingLevel) => void;\n\tprivate _focused = false;\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(\n\t\tcurrentLevel: ThinkingLevel,\n\t\tavailableLevels: ThinkingLevel[],\n\t\tonSelect: (level: ThinkingLevel) => void,\n\t\tonCancel: () => void,\n\t\tonSelectAsDefault?: (level: ThinkingLevel) => void,\n\t\tdefaultThinkingLevel?: ThinkingLevel,\n\t) {\n\t\tsuper();\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.onSelectAsDefault = onSelectAsDefault;\n\n\t\tthis.allItems = availableLevels.map((level) => ({\n\t\t\tvalue: level,\n\t\t\tlabel: `${level === currentLevel ? \"✓ \" : \" \"}${level}`,\n\t\t\tdescription:\n\t\t\t\tlevel === defaultThinkingLevel ? `${LEVEL_DESCRIPTIONS[level]} · default` : LEVEL_DESCRIPTIONS[level],\n\t\t}));\n\n\t\t// Add top border\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(\"Thinking Level\", 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tif (onSelectAsDefault) {\n\t\t\tthis.addChild(new Text(`${keyDisplayText(\"app.thinking.cycle\")} cycles thinking levels in-session`, 0, 0));\n\t\t\tthis.addChild(new Spacer(1));\n\t\t}\n\n\t\tthis.searchInput = new Input();\n\t\tthis.searchInput.onSubmit = () => this.selectList.handleInput(\"\\r\");\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Create selector\n\t\tthis.selectList = this.buildSelectList(this.allItems, currentLevel);\n\t\tthis.selectListChildIndex = this.children.length;\n\t\tthis.addChild(this.selectList);\n\t\tthis.addChild(new Spacer(1));\n\t\tconst hints = [\n\t\t\t`${keyDisplayText(\"tui.select.confirm\")} to select`,\n\t\t\t...(onSelectAsDefault ? [`${keyDisplayText(\"app.thinking.save\")} to set as default`] : []),\n\t\t\t`${keyDisplayText(\"tui.select.cancel\")} to cancel`,\n\t\t];\n\t\tthis.addChild(new Text(theme.fg(\"dim\", ` ${hints.join(\" · \")}`), 0, 0));\n\n\t\t// Add bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate buildSelectList(items: SelectItem[], preselect?: ThinkingLevel): SelectList {\n\t\tconst list = new SelectList(items, Math.max(1, items.length), getSelectListTheme(), THINKING_SELECT_LIST_LAYOUT);\n\t\tconst currentIndex = items.findIndex((item) => item.value === preselect);\n\t\tif (currentIndex !== -1) {\n\t\t\tlist.setSelectedIndex(currentIndex);\n\t\t}\n\t\tlist.onSelect = (item) => this.onSelect(item.value as ThinkingLevel);\n\t\tlist.onCancel = () => this.onCancel();\n\t\treturn list;\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tconst filtered = query\n\t\t\t? fuzzyFilter(this.allItems, query, (item) => `${item.value} ${item.description ?? \"\"}`)\n\t\t\t: this.allItems;\n\t\tconst selectedValue = this.selectList.getSelectedItem()?.value as ThinkingLevel | undefined;\n\t\tconst newList = this.buildSelectList(filtered, selectedValue);\n\t\tthis.children[this.selectListChildIndex] = newList;\n\t\tthis.selectList = newList;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.thinking.save\") && this.onSelectAsDefault) {\n\t\t\tconst item = this.selectList.getSelectedItem();\n\t\t\tif (item) this.onSelectAsDefault(item.value as ThinkingLevel);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNav =\n\t\t\tkb.matches(keyData, \"tui.select.up\") ||\n\t\t\tkb.matches(keyData, \"tui.select.down\") ||\n\t\t\tkb.matches(keyData, \"tui.select.confirm\") ||\n\t\t\tkb.matches(keyData, \"tui.select.cancel\");\n\t\tif (isNav) {\n\t\t\tthis.selectList.handleInput(keyData);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applyFilter(this.searchInput.getValue());\n\t}\n\n\tgetSelectList(): SelectList {\n\t\treturn this.selectList;\n\t}\n}\n"]}
@@ -1,22 +1,22 @@
1
1
  # Agent — lightweight delegation
2
2
 
3
- The bundled `Agent` extension adds the `Agent` tool and `/agent` settings command. One call delegates one self-contained task to a temporary Agent and returns its final report. Use it sparingly for independent work that clearly benefits from separate context or parallel execution. There are no General/Explore profiles, batch arrays, persistent worker identities, or chain modes.
3
+ The bundled `Agent` extension adds the `Agent` tool and `/agent` settings command. One call delegates one self-contained task to a temporary Agent and returns its final report; the Agent does not converse with its parent while it runs. Use it sparingly for independent work that clearly benefits from separate context or parallel execution. There are no General/Explore profiles, batch arrays, persistent worker identities, chain modes, or mid-run messaging and steering.
4
4
 
5
5
  ## Tool contract
6
6
 
7
7
  ```json
8
8
  {
9
9
  "description": "Inspect Tasks persistence",
10
- "prompt": "Trace task-result restoration and report the relevant paths and invariants. Do not edit files.",
10
+ "prompt": "Trace task-record restoration and report the relevant paths and invariants. Do not edit files.",
11
11
  "background": false
12
12
  }
13
13
  ```
14
14
 
15
15
  - `prompt` is required, must be self-contained, and is limited to 16 KiB. The Agent cannot see the parent conversation.
16
16
  - `description` is an optional short label for the Transcript and `/tasks`; otherwise Pi derives one from the prompt.
17
- - `background` is optional. Foreground waits for the report; `true` returns a Task ID after initialization and delivers the report automatically. Interactive **Ctrl+B** can detach a foreground call without restarting it.
17
+ - `background` is optional. Foreground waits for the report; `true` returns a Task ID once the Agent has initialized, or at once while it waits for a slot, and delivers the report automatically. Interactive **Ctrl+B** can detach a foreground call without restarting it.
18
18
 
19
- Issue parallel `Agent` calls for independent work. Each call is a separate Transcript row and Task, including its own completion notification; there is no aggregate batch view. At most four Agents run concurrently in one extension runtime, with additional calls queued visibly in Tasks. Parallel tasks must not perform overlapping writes.
19
+ Issue parallel `Agent` calls for independent work. Each call is a separate Transcript row and Task, including its own completion notification; there is no aggregate batch view. At most four Agents run at once in a session; additional calls wait as queued Tasks and start when a slot frees. A queued background call returns its Task ID immediately, and **Ctrl+B** can move a queued foreground call to the background before it starts. Parallel tasks must not perform overlapping writes.
20
20
 
21
21
  Agents use the parent's working directory and share its canonical model/authentication runtime. Their isolated in-memory sessions have `read`, `bash`, `edit`, and `write`, with shell commands covering file discovery and search. They load applicable repository instructions and do not load extensions, skills, prompt templates, or themes. They cannot recursively delegate or start managed background work. The full child conversation is not persisted separately.
22
22
 
@@ -24,7 +24,9 @@ Resource discovery preserves the parent's project-trust decision. Declining trus
24
24
 
25
25
  ## Model and thinking settings
26
26
 
27
- Run `/agent` to choose **Model** or **Thinking**. The model picker is searchable; either setting can follow the current session. Choices apply only to future Agents and never switch the parent session or change running work.
27
+ Run `/agent` to choose **Model** or **Effort**, reusing the searchable `/model` and `/thinking` selectors. The compact panel shows the full `provider/model-id` and current effort on aligned single lines. An unset field adds `· Follow current session`; when the requested effort is unsupported, the panel shows the requested and effective levels, such as `max → high · Follow current session`. Fixed overrides also show a conversion when necessary, without the inheritance suffix. Choices apply only to future Agents and never switch the parent session or change running work.
28
+
29
+ **Reset to follow current session** is always available and clears both Agent overrides in one save, preserving unrelated settings. Resetting fields that already inherit is a no-op. Choosing a specific model or effort makes that field fixed, even when it equals the inherited value. Picker confirmation never changes global model or thinking defaults.
28
30
 
29
31
  Settings are stored in the global `settings.json`:
30
32
 
@@ -41,7 +43,7 @@ Settings are stored in the global `settings.json`:
41
43
 
42
44
  Omit either field to inherit it. Thinking is clamped to the effective model's supported levels. A configured model that no longer exists or has no authentication fails explicitly instead of silently selecting another model.
43
45
 
44
- Malformed model or thinking fields are marked `[invalid]` in `/agent`, where you can replace them or explicitly reset each field to follow the current session. Escape leaves settings unchanged, and repairs preserve the other fields and extension namespaces. Invalid JSON or a malformed namespace object must be repaired in `settings.json`; Pi does not overwrite that damaged configuration automatically.
46
+ Malformed model or thinking fields are marked `[invalid]` in `/agent`, where you can replace them through their native picker or explicitly reset both fields to follow the current session. A missing model is marked `[unavailable]`, and effort stays `[unresolved]` rather than using the parent model's capabilities. Cancelling a picker leaves its setting unchanged; closing the panel retains earlier confirmed saves. Repairs preserve the other fields and extension namespaces. Invalid JSON or a malformed namespace object must be repaired in `settings.json`; Pi does not overwrite that damaged configuration automatically.
45
47
 
46
48
  ## Transcript and Tasks
47
49
 
@@ -54,13 +56,13 @@ The Transcript only describes status and current work. It never includes the Pro
54
56
  | Completed | One duration and `/tasks` status line | Identical |
55
57
  | Failed or cancelled | One short diagnostic or cancellation line | Identical |
56
58
 
57
- Shell activity shows only the first non-empty command line and retains the actual tool name. Tasks Output holds bounded argument summaries and tool-failure excerpts while the Agent runs; successful intermediate tool output is not retained in the parent Tasks record. The final report replaces live activity.
59
+ Shell activity shows only the first non-empty command line and retains the actual tool name. The human-only Tasks display holds bounded argument summaries and tool-failure excerpts; successful intermediate tool output is not retained in the parent Tasks record. While running, model-facing `tasks read` returns one status line, such as `Agent running · 3 tool calls · latest: bash npm test`; after settlement it returns the final report. Intermediate assistant text and Tool calls never reach the parent model. To change direction, kill the Agent and delegate again with a better briefing.
58
60
 
59
61
  In `/tasks`, each Agent remains an independent row:
60
62
 
61
- - **Output** shows actual tool activity while running and the final report with Markdown formatting after successful completion. Oversized reports remain available through their managed output file.
63
+ - **Output** shows the status line and compact Tool calls while running, written like the expanded Transcript: `✓ read README.md · 4ms`. A successful final report uses Markdown formatting, followed by the retained Tool calls. Oversized reports remain available through their managed output file.
62
64
  - **Details** shows the full Prompt, working directory, model, and thinking level.
63
65
 
64
- Use `tasks read`, `tasks wait`, or `tasks kill` with the Task ID. Selection, scrolling, cancellation, foreground detach, history, and completion delivery are owned by the shared Tasks implementation. Parent cancellation stops foreground-owned work, including cancellation received during startup; detached work continues until it finishes or is killed. Reload, session replacement, and shutdown cancel active Agents.
66
+ Use `tasks read`, `tasks wait`, or `tasks kill` with the Task ID. Reading requires no view options: the status line or report is the model projection, while the `/tasks` panel adds the human-only Tool-call display. Selection, scrolling, cancellation, foreground detach, history, and completion delivery are owned by the shared Tasks implementation. Parent cancellation stops foreground-owned work, including cancellation received during startup; detached work continues until it finishes or is killed. Reload, session replacement, and shutdown cancel active Agents.
65
67
 
66
- Inline reports are bounded to 24 KiB. Longer reports are written in full to a managed temporary Markdown file, and the tool result includes a bash-style `Full output: <path>` notice. Use `read` on that path or `tasks read` for retained output; a failure to save the file falls back to a bounded report without changing the Agent's outcome. Activity history is limited to the latest 50 tool calls, and published task results use the shared Tasks limits. Inline report previews, static Details, usage, and completion state restore through the parent session branch. Managed output files follow the Tasks lifecycle and never survive restart; live execution never resumes either.
68
+ Inline reports are bounded to 24 KiB. Longer reports are written in full to a managed temporary Markdown file, and the tool result includes a bash-style `Full output: <path>` notice. Use `read` on that path or `tasks read` for retained output; a failure to save the file falls back to a bounded report without changing the Agent's outcome. Activity history is limited to the latest 50 tool calls, and published task results use the shared Tasks limits. A background completion delivers the report from its beginning, whole when it fits the notification budget, so the parent reads the same report a foreground call would have returned. Inline report previews, Details, usage, and completion state restore through the parent session branch. Managed output files follow the Tasks lifecycle and never survive restart; live execution never resumes either.
@@ -42,7 +42,7 @@ CTX 2.1%/1.0M ↑13k ↓13k R440k CH99.4% $0.074
42
42
 
43
43
  - Extension status text from `ctx.ui.setStatus()` is sorted by key and pinned to the center of the line — anchored to the absolute line center so it does not drift as the usage cluster grows, falling back to balancing the free space when the side zones collide with the center anchor. When space runs out it is dropped so CTX and usage stay readable. Plain text is muted; strings that already carry ANSI color are left unchanged.
44
44
 
45
- Background billing uses the first valid `task-usage` record per execution ID; managed foreground results omit duplicate `usage`. Opening `/tasks`, detaching, or repeating `tasks read`/`wait` does not add billing. Accrued worker retry, cancellation, failure, and provider-supplied compaction usage is included when settled; missing usage is not fabricated. Quarantined late settlements are excluded from active totals. This does not change the footer's active-branch scope (session-wide statistics can include other branches), parent CTX estimate, or latest-parent-request `CH`. See the [persisted record format](../../session-format.md#background-records).
45
+ Background billing uses the first valid task usage settlement per execution ID, from a `task-record` or a released session's `task-usage` entry; managed foreground results omit duplicate `usage`. Opening `/tasks`, detaching, or repeating `tasks read`/`wait` does not add billing. Accrued worker retry, cancellation, failure, and provider-supplied compaction usage is included when settled; missing usage is not fabricated. Quarantined late settlements are excluded from active totals. This does not change the footer's active-branch scope (session-wide statistics can include other branches), parent CTX estimate, or latest-parent-request `CH`. See the [persisted record format](../../session-format.md#background-records).
46
46
 
47
47
  The built-in Tasks UI can supply centered status text such as `tasks 2 active · 1 finished`. These counts cover backgrounded executions; worker rows are not separate groups. The old prompt-stall watchdog and `waiting for input` counts are no longer generated.
48
48
 
@@ -27,7 +27,7 @@ Hosts can prohibit background execution with `backgroundAllowed: false`. This re
27
27
  | Action | Parameters | Behavior |
28
28
  |---|---|---|
29
29
  | `list` | — | Lists active and up to five retained finished records, at most 100 rows; foreground executions are omitted with a count (they deliver inline in the transcript) |
30
- | `read` | `taskId`, optional `mode`, `bytes` | Reads bounded output/report while running or after completion |
30
+ | `read` | `taskId`, optional `mode`, `bytes` | Reads bounded model-readable output/report while running or after completion; running Agents return a one-line status without Tool calls |
31
31
  | `wait` | optional `taskId`, `waitMs`, `sinceBytes` | Waits for one task, or for any task running at call time when `taskId` is omitted |
32
32
  | `kill` | `taskId` | Requests cancellation of the selected task |
33
33
 
@@ -37,7 +37,7 @@ Use the execution ID returned by the native tool or `tasks list`. An unknown or
37
37
  { "action": "read", "taskId": "<execution-id>", "mode": "tail", "bytes": 8192 }
38
38
  ```
39
39
 
40
- Reads default to an 8KB tail. `bytes` clamps between 256 bytes and 48KB; `mode` can be `head` or `tail`. A Bash output path is included when available. Tasks without a log return their bounded published result. Every read and settled wait reports its byte range and where to continue, for example `bytes 92160–100352 of 100352 · next sinceBytes 100352`. Use a returned offset with that task's ID; waitAny does not accept a cross-task offset.
40
+ Reads default to an 8KB tail. `bytes` clamps between 256 bytes and 48KB; `mode` can be `head` or `tail`. A Bash output path is included when available. Tasks without a log return their bounded published result. Executors can separately attach human-only display text: `/tasks` shows it, while `tasks read`, settled waits, and completion context exclude it. Agent Tool calls use this display channel, so no read-view parameter is needed. Every read and settled wait reports its byte range and where to continue, for example `bytes 92160–100352 of 100352 · next sinceBytes 100352`. Use a returned offset with that task's ID; waitAny does not accept a cross-task offset.
41
41
 
42
42
  ```json
43
43
  { "action": "wait", "taskId": "<execution-id>", "waitMs": 20000, "sinceBytes": 4096 }
@@ -63,32 +63,33 @@ All model-facing management responses, including listings and error messages, ar
63
63
 
64
64
  ## `/tasks` panel
65
65
 
66
- The fullscreen panel has one scrollable list. **Active** groups queued, running and stopping work; **Finished** groups all retained results on the selected branch, including foreground shell results, newest first. Empty groups are hidden. Task summaries show status and elapsed time; foreground/background mode is available in Details. Durations omit zero components and separate remaining units (`8s`, `1m`, `1m 5s`, `1h 5m`). The background action is offered only when the selected task can move.
66
+ The fullscreen panel has one scrollable list. **Active** groups queued, running and stopping work; **Finished** groups all retained results on the selected branch, including foreground shell results, newest first. Empty groups are hidden. Each task is one row: its status glyph, its source label such as Bash or Agent in an aligned dim column, the title, and right-aligned metadata. The metadata shows elapsed time, the status name for every status except running, completed and failed, whose glyphs are unambiguous, and an ID suffix when two titles are identical. Foreground/background mode is available in Details. Durations omit zero components and separate remaining units (`8s`, `1m`, `1m 5s`, `1h 5m`). The background action is offered only when the selected task can move.
67
67
 
68
- Selection follows the task when it finishes; new work does not steal focus or replace browsed output. The list preserves the selected row's screen position where space permits. Reopening remembers the selected ID and right-hand tab while the runtime remains available. Runtime replacement resets these preferences, and branch navigation removes results outside the visible branch. History remains bounded by the retention limits below.
68
+ Selection follows the task when it finishes; new work does not steal focus or replace browsed output. The list preserves the selected row's screen position where space permits. Reopening selects the newest task started since the panel last closed; when nothing new started, it keeps the remembered selection. The right-hand tab is remembered as well, while the runtime remains available. Runtime replacement resets these preferences, and branch navigation removes results outside the visible branch. History remains bounded by the retention limits below.
69
69
 
70
- At 100 columns or more, the task list sits beside an inspector. **Output** shows the result directly; **Details** holds the full command, directory, task ID, log location and executor-specific details. Each task and tab keeps its reading position for the lifetime of the panel. Tab switches between the two panes, preserving the right-hand tab. Left/Right switch Output/Details only when the inspector has focus.
70
+ At 100 columns or more, the task list sits beside an inspector. The inspector's first row names the selected task — `Bash · Running · 12s` — with the **Output** and **Details** tabs at its right. **Output** shows the result directly; **Details** starts with the source, task ID and status, then holds what the executor declared — its input such as the full command or prompt, and facts such as the directory, model or exit code — plus the log location. Each task and tab keeps its reading position for the lifetime of the panel. Tab switches between the two panes, preserving the right-hand tab. Left/Right switch Output/Details only when the inspector has focus.
71
71
 
72
72
  The focused pane has a highlighted border. Task selection uses a persistent row background, and the selected right-hand tab uses an underline; neither changes when focus moves. When the system theme has no background colors, the selected row uses inverse text. There are no focus arrows or extra title colors. Narrow terminals show one pane at full width with the same Tab navigation and no focus highlight. The inspector includes task context when the list is hidden. Escape closes the panel from either pane. The minimum supported size is 60 columns by 14 rows; below it, a centered dialog asks for a larger window and covers the screen, because the panel keeps input focus while open.
73
73
 
74
- Bash and PowerShell show live plain-text output. Other executors show their published result, and a task without a command is labeled by its title. Completed Agent reports use the native Markdown renderer; running Agent activity and other executor output remain literal text. An executor can also supply bounded static `info` text: Output remains the published result while Details shows that executor-owned context instead of the generic command fields. Missing logs fall back to the saved result. Task status, failure reasons and output-read errors remain distinct.
74
+ Every executor is presented the same way, from data it declares: a label such as Bash or Agent, an input, labelled facts, and whether its output is a log or a report. Logs show live plain-text output; other executors show their published result plus any human-only display suffix, updated as soon as the executor publishes rather than on the log poll. A completed report, such as an Agent's, uses the native Markdown renderer while its retained activity remains literal text. Agent Output combines its status line or report with compact Tool calls, written as in the transcript: `✓ read README.md · 4ms`. A task without an input shows its title in Details. Missing logs fall back to the saved result. Task status, failure reasons and output-read errors remain distinct.
75
75
 
76
76
  | Default key | Action |
77
77
  |---|---|
78
- | `/` | Locate any retained task by title, command, kind or ID; Up/Down choose a candidate, Enter or clicking locates it and restores the full list, Escape restores the prior selection and focus |
78
+ | `/` | Locate any retained task by title, input, label, kind or ID; Up/Down choose a candidate, Enter or clicking locates it and restores the full list, Escape restores the prior selection and focus |
79
79
  | Left / Right | Output / Details, only while the inspector has focus |
80
80
  | Tab / Shift+Tab | Switch between list and inspector, preserving the current tab |
81
81
  | Up / Down | Select a task or scroll the focused region |
82
+ | Enter | Open the selected task: focus the inspector, or show it full width in a narrow terminal |
82
83
  | Page Up / Page Down | Page the focused list or region |
83
84
  | Home / End | Top / bottom of the list or bounded preview |
84
85
  | `f` | Follow the latest output, or load the final output after completion, while Output has focus |
85
86
  | `b` | Move only the selected eligible foreground task to the background |
86
- | `k`, then Enter | Request cancellation of the selected whole task; Escape cancels confirmation. Confirmation has no time limit and closes if its target finishes |
87
- | `?` | Show configurable controls; Up/Down scroll the help |
87
+ | `k`, then Enter | Request cancellation of the selected whole task. The footer asks `Stop Bash "npm test"?` while the list and inspector stay visible; Escape cancels. Confirmation has no time limit and closes if its target finishes |
88
+ | `?` | Show configurable controls, grouped into Navigate, View and Act; Up/Down scroll the help |
88
89
  | Escape | Close the current search, help or confirmation first; otherwise close the panel |
89
90
  | Ctrl+B | Detach **all** eligible foreground executions through the host |
90
91
 
91
- Click a pane to focus it, a task row to select it, or a tab label to display it. The mouse wheel scrolls the pane under the pointer without changing keyboard focus or task selection. Footer hints are clickable as well, including while a transient confirmation owns that row: the click dismisses it and performs the hint's action. Search, help and confirmation consume their own input without activating the panel behind them.
92
+ Click a pane to focus it, a task row to select it, or a tab label to display it. The mouse wheel scrolls the pane under the pointer without changing keyboard focus or task selection. Footer hints are clickable as well, including while transient feedback owns that row: the click dismisses it and performs the hint's action. While a stop question owns the footer, only its stop and cancel actions respond. Search, help and confirmation consume their own input without activating the panel behind them.
92
93
 
93
94
  Shell output initially follows the tail, marked **Live** next to the output. Scrolling up enters **Browsing**, which holds a bounded output snapshot while status continues updating. In Output, press `f`, End, or scroll down to the bottom to resume following. If the task finishes while browsing, the panel offers to load its final output. Closing or scrolling never pauses, restarts or cancels execution.
94
95
 
@@ -102,11 +103,11 @@ The statusline counts only queued, running and stopping background tasks: `1 bac
102
103
 
103
104
  ## Completion notifications
104
105
 
105
- Interactive `task-completion` messages have a compact collapsed summary: outcome, execution kind, duration, short ID, and the command or, without one, the task title. Failures retain a short reason; log paths, output and worker reports stay out of the collapsed view. In fullscreen mode, left-click the notification to expand or collapse that message independently. The blank spacer above it is not a click target. The configured tool-output expansion binding (default Ctrl+O) remains available for toggling output expansion across the transcript.
106
+ Interactive `task-completion` messages have a compact collapsed summary: the executor's label, outcome, duration, short ID, and the task title. Failures retain a short reason; log paths, output and worker reports stay out of the collapsed view. In fullscreen mode, left-click the notification to expand or collapse that message independently. The blank spacer above it is not a click target. The configured tool-output expansion binding (default Ctrl+O) remains available for toggling output expansion across the transcript.
106
107
 
107
- Expanded notifications separate **Command** (or **Task** for a titled task), **Directory**, **Result** or **Error** with the recorded exit code, a bounded plain-text **Output** tail, **Log** and the full execution ID. The saved output keeps the end of the result, where the outcome is, and carries an explicit truncation flag. Screen line limits are independent of source truncation. These are previews of the saved bounded completion.
108
+ Expanded notifications separate the input under its own label, such as **Command** or **Prompt** (or **Task** without one), **Details** with the declared facts such as directory and exit code, **Result** or **Error**, a bounded plain-text **Output** preview, **Log** and the full execution ID. A log's saved output keeps its end, where the outcome is; a report's keeps its beginning, where the conclusion is. Both carry an explicit truncation flag. Screen line limits are independent of source truncation. These are previews of the saved bounded completion.
108
109
 
109
- Rendering reads the self-contained `TaskCompletionSnapshot` in message `details`, so `/reload`, history eviction, expired logs and restart do not require a live task lookup. The session generates model-facing `content` from the same facts; `details` never enters model context or usage accounting. Replay details retain a 40 KiB output tail, while the automatic model-facing notification includes only an 8 KiB tail plus the log path and truncation guidance for `tasks read`. Commands containing `Output:` and literal truncation notices remain ordinary data. See the [snapshot contract](../session-format.md#background-records).
110
+ Rendering reads the self-contained terminal snapshot in message `details`, so `/reload`, history eviction, expired logs and restart do not require a live task lookup. The session generates model-facing `content` from the same facts; `details` never enters model context or usage accounting. Replay details retain up to 40 KiB of output. The automatic model-facing notification includes only an 8 KiB tail of a log, plus the log path and truncation guidance for `tasks read`; a report arrives from its beginning, whole when it fits the 48 KiB budget, as its foreground result would. Commands containing `Output:` and literal truncation notices remain ordinary data. See the [snapshot contract](../session-format.md#background-records).
110
111
 
111
112
  Only the current structured completion format (version 2) is specialized. Older completions, including version-1 shell and report completions, and malformed details receive a bounded plain **Details** view of their saved message; no text reconstruction or migration is performed. Legacy `background-task` notifications show as plain messages. HTML export and `/tree` selector labels continue to display the saved message content.
112
113
 
@@ -122,7 +123,7 @@ Managed shell output is collected continuously from startup, including before de
122
123
 
123
124
  Managed logs are ephemeral: they are retained with the runtime record and cleaned up when that record is evicted or the runtime shuts down. Save needed output elsewhere before then. The core defaults to eight concurrent background executions and two independent terminal histories: 32 background results plus 32 foreground results. Foreground work of any kind can only evict older foreground records. Pending delivery, pins, active reads and cleanup use a separate allowance within the bounded total; pins temporarily defer history eviction, not runtime shutdown. These are service limits, not new user settings.
124
125
 
125
- Terminal snapshots persist as version-2 `task-result` custom entries; usage remains in independent version-1 `task-usage` entries. A foreground snapshot omits its output, which the transcript already saves in the tool result, and restoration reads it back from there. The runtime restores version-2 terminal history from the selected branch for programmatic reads and the panel's Finished group, selecting the newest records independently for each history. Older result records are left in the session file and are not migrated or restored. Live execution never resumes after restart, and restoration does not replay accounting or completion events. Restored records drop their log path: logs never outlive the runtime that wrote them. See [session format](../session-format.md#background-records).
126
+ Each settlement appends one version-3 `task-record` custom entry holding the terminal snapshot and its usage. A foreground snapshot omits its output, which the transcript already saves in the tool result, and restoration reads it back from there. The runtime restores version-3 terminal history from the selected branch for programmatic reads and the panel's Finished group, selecting the newest records independently for each history. Older `task-result` records are left in the session file and are not migrated or restored; usage from released sessions still counts. Live execution never resumes after restart, and restoration does not replay accounting or completion events. Restored records drop their log path: logs never outlive the runtime that wrote them. See [session format](../session-format.md#background-records).
126
127
 
127
128
  Delivered history outside the selected branch can be released and restored on return, so it does not fill the new branch's history budget. Undelivered completions stay protected while their branch is hidden. Pending delivery, pins and active reads use a separate allowance within the total runtime retention cap; restoration respects the same cap.
128
129
 
@@ -1256,9 +1256,9 @@ Session-bound `TasksContext` supervises native and extension-owned execution. Fo
1256
1256
 
1257
1257
  | Method | Contract |
1258
1258
  |---|---|
1259
- | `execute<T>(execution)` | Returns `{ kind: "result", result, status?, error? }` or `{ kind: "background", task }` |
1259
+ | `execute<T>(execution)` | Returns `{ kind: "result", result, status, error? }` or `{ kind: "background", task }` |
1260
1260
  | `list()` / `get(id)` | Bounded, read-only (frozen) retained snapshots; IDs support unique prefixes |
1261
- | `read(id, options?)` | Bounded head, tail, or byte-offset output |
1261
+ | `read(id, options?)` | Bounded head, tail, or byte-offset model-readable output; excludes human-only display text |
1262
1262
  | `wait(id, timeoutMs?, signal?, interruptSignal?)` | Observation only; timeout, cancellation, or `interruptSignal` ends the wait, not execution |
1263
1263
  | `waitAny(timeoutMs?, signal?, interruptSignal?)` | Observes the first task running at call time to settle; returns `undefined` for an empty cohort, timeout, interruption, or closed host. Later tasks are excluded |
1264
1264
  | `kill(id)` | Requests cancellation; `stopping` is not a terminal status |
@@ -1268,18 +1268,34 @@ Session-bound `TasksContext` supervises native and extension-owned execution. Fo
1268
1268
  | `retain(id)` | Returns an idempotent release function protecting retained data, without delaying notifications |
1269
1269
  | `holdDelivery(id)` | Explicitly retains data and delays automatic delivery until released |
1270
1270
 
1271
- `TaskExecution<T>` supplies `kind`, `title`, `toolCallId`, `run(control)`, optional `command`, `cwd`, `info`, `background`, `signal`, and `onUpdate`. Bounded static `info` text appears in the panel's Details tab; Output continues to show published results. It restores with terminal task history but never enters model context. `kind` is an executor-owned source label matching `[a-z][a-z0-9-]{0,63}`; the runtime never dispatches on it. At most eight background executions run at once; foreground executions are not limited by them. Foreground and background results have separate history quotas.
1271
+ `TaskExecution<T>` supplies `kind`, `title`, `toolCallId`, and `run(control)`, plus optional fields:
1272
1272
 
1273
- `run` returns `TaskCompletion<T>`: `{ result, status?, error?, exitCode?, usage? }`. The original tool result is returned to a foreground caller; private `result.details` is not copied into task history. Explicit terminal statuses are `completed`, `partial`, `failed`, `cancelled`, and `timeout`. Usage is settled by the host once; managed foreground results omit usage to avoid billing it twice.
1273
+ | Field | Contract |
1274
+ |---|---|
1275
+ | `label` | Human source name for the panel and completion card, such as `Bash` or `Agent`; defaults to `kind` |
1276
+ | `output` | `"log"` (default) or `"report"`. A log's outcome is at its end, so a background completion gives the model an 8 KiB tail. A report leads with its conclusion, so it arrives from its beginning, whole when it fits the 48 KiB context budget, as its foreground result would; a completed report renders as Markdown in `/tasks` |
1277
+ | `input` | `{ label, text, truncated, language? }`: what the task was asked to do, such as a command or briefing. Shown in Details and the expanded completion card, highlighted when `language` is set |
1278
+ | `facts` | Up to 16 labelled `[label, value]` Details rows, such as `["Directory", cwd]` |
1279
+ | `concurrency` | `{ key, limit }`: at most `limit` executions sharing `key` run at once. Later ones wait as `queued` tasks and `run` starts when a slot frees |
1280
+ | `background`, `signal`, `onUpdate` | Requested handoff, parent cancellation, and foreground progress forwarding |
1281
+
1282
+ `kind` is an executor-owned source label matching `[a-z][a-z0-9-]{0,63}`; the runtime never dispatches on it. Presentation is declared data: the panel and completion card render `label`, `input`, `facts`, and `output` the same way for every executor. Input and facts restore with terminal task history; facts also appear in the completion notification. At most eight background executions, queued ones included, are retained as active at once; foreground executions are not limited by them. Foreground and background results have separate history quotas.
1283
+
1284
+ A caller can be handed off to the background while its task is queued, before `run` starts, or after `run` calls `accept()`. A queued task becomes `running` when its `run` starts; cancelling it settles it as `cancelled` without starting it.
1285
+
1286
+ `run` returns `TaskCompletion<T>`: `{ result, status?, display?, error?, facts?, usage? }`. The original tool result is returned to a foreground caller; task history keeps only its bounded text. Optional `display` is bounded human-only Output suffix text, excluded from `tasks read`, settled waits, and completion context. Terminal `facts` replace launch facts with the same label, as the shell does with `["Exit", "42"]`. Explicit terminal statuses are `completed`, `partial`, `failed`, `cancelled`, and `timeout`. The host settles usage once, preferring `usage`, then `result.usage`, then the latest published usage; managed foreground results omit usage to avoid billing it twice.
1274
1287
 
1275
- `TaskControl<T>` exposes `id`, `signal`, `mode`, `accept()`, `publish(result)`, `setOutputPath(path, cleanup?)`, `onModeChange(listener)`, and `requestCancel()`. `publish` replaces the task's bounded text result, which the `/tasks` panel, `tasks read`, and the completion notification show; a task with an output path is read from that log instead. Call `accept()` after whole-invocation preflight, before allowing a background handoff. Use the control's signal throughout execution. Parent-call cancellation is disconnected after handoff, while runtime shutdown still cancels the task. Mode subscriptions concern only this task; executors do not need the global registry to observe their own handoff or cancel themselves.
1288
+ `TaskControl<T>` exposes `id`, `signal`, `mode`, `onModeChange(listener)`, `accept()`, `publish(update)`, `attachOutput(path, cleanup?)`, and `cancel()`. `publish({ result, display?, usage? })` replaces the bounded model-readable result and optionally the human-only Output suffix and cumulative usage; `/tasks` combines result and display, while model reads and completion notifications use only the result. A task with an attached output file is read from that file instead. Call `accept()` after whole-invocation preflight, before allowing a background handoff. Use the control's signal throughout execution. Parent-call cancellation is disconnected after handoff, while runtime shutdown still cancels the task. Mode subscriptions concern only this task; executors do not need the global registry to observe their own handoff or cancel themselves.
1276
1289
 
1277
- Completion messages store a self-contained `TaskCompletionSnapshot`; only their bounded `content` enters model context, with an 8 KiB output tail while replay details retain 40 KiB. Built-in `tasks wait` binds delivery to the actual tool call, and the host confirms it after successful persistence; a settled waitAny binds only its winning task. Ordinary extension reads/waits, including `waitAny`, do not acknowledge delivery, and arbitrary tool-result detail fields cannot acknowledge a task.
1290
+ Completion messages store `{ version: 3, task }` in `details`, a bounded terminal `TaskSnapshot`; only their bounded `content` enters model context. Built-in `tasks wait` binds delivery to the actual tool call, and the host confirms it after successful persistence; a settled waitAny binds only its winning task. Ordinary extension reads/waits, including `waitAny`, do not acknowledge delivery, and arbitrary tool-result detail fields cannot acknowledge a task.
1278
1291
 
1279
1292
  ```typescript
1280
1293
  const outcome = await ctx.tasks.execute({
1281
1294
  kind: "report-job",
1295
+ label: "Review",
1282
1296
  title: "Inspect project",
1297
+ output: "report",
1298
+ facts: [["Directory", ctx.cwd]],
1283
1299
  toolCallId,
1284
1300
  signal,
1285
1301
  background: params.background,