@herbertgao/pi-extensions 2026.8.2 → 2026.8.4

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 (392) hide show
  1. package/README.md +50 -2
  2. package/examples/pi-footer.json +275 -0
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +6 -8
  4. package/node_modules/@herbertgao/pi-cc-extensions/README.md +5 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +101 -0
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +1 -17
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +5 -3
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/{utils/agent-summary.ts → feature/agent-summary/core.ts} +37 -35
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-summary.ts → agent-summary/index.ts} +2 -6
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference.ts → reference/index.ts} +1 -1
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-autocomplete.ts → reference/subagent.ts} +19 -9
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-startup-header.ts → shell/startup-header.ts} +1 -1
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{working-message.ts → shell/working-message.ts} +5 -2
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +32 -28
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +379 -85
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +727 -0
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +65 -775
  18. package/node_modules/@herbertgao/pi-cc-extensions/extensions/{feature → renderer}/markdown-enhance.ts +35 -31
  19. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-hover.ts → mouse/hover.ts} +5 -5
  20. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-interaction.ts → mouse/interaction.ts} +34 -35
  21. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-layout.ts → mouse/layout.ts} +5 -21
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-packets.ts → mouse/packets.ts} +1 -1
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-scroll.ts → mouse/scroll.ts} +48 -37
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ansi-utils.ts +56 -1
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-renderer.ts +2 -2
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/line-width-safety.ts +1 -1
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +12 -0
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/write-execution.ts +1 -2
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-grouping.ts → tool/grouping.ts} +18 -8
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-result.ts → tool/result.ts} +4 -13
  31. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +0 -27
  32. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  33. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  34. package/node_modules/@herbertgao/pi-subagents/package.json +2 -2
  35. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +1 -0
  36. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +3 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/index.ts +33 -35
  38. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +26 -35
  39. package/node_modules/@herbertgao/pi-subagents/src/prompts.ts +15 -1
  40. package/node_modules/pi-footer/CHANGELOG.md +145 -0
  41. package/node_modules/pi-footer/LICENSE +21 -0
  42. package/node_modules/pi-footer/README.md +354 -0
  43. package/node_modules/pi-footer/package.json +68 -0
  44. package/node_modules/pi-footer/src/cache.ts +106 -0
  45. package/node_modules/pi-footer/src/colors.ts +237 -0
  46. package/node_modules/pi-footer/src/config.ts +202 -0
  47. package/node_modules/pi-footer/src/event-widgets.ts +41 -0
  48. package/node_modules/pi-footer/src/extension-statuses.ts +102 -0
  49. package/node_modules/pi-footer/src/git.ts +135 -0
  50. package/node_modules/pi-footer/src/index.ts +268 -0
  51. package/node_modules/pi-footer/src/metrics.ts +141 -0
  52. package/node_modules/pi-footer/src/presets.ts +383 -0
  53. package/node_modules/pi-footer/src/render.ts +114 -0
  54. package/node_modules/pi-footer/src/separators.ts +52 -0
  55. package/node_modules/pi-footer/src/types.ts +122 -0
  56. package/node_modules/pi-footer/src/ui/color-level-confirm.ts +22 -0
  57. package/node_modules/pi-footer/src/ui/color-options.ts +195 -0
  58. package/node_modules/pi-footer/src/ui/config-lifecycle.ts +61 -0
  59. package/node_modules/pi-footer/src/ui/edit-colors.ts +13 -0
  60. package/node_modules/pi-footer/src/ui/events.ts +35 -0
  61. package/node_modules/pi-footer/src/ui/extension-status-picker.ts +60 -0
  62. package/node_modules/pi-footer/src/ui/extension-statuses.ts +73 -0
  63. package/node_modules/pi-footer/src/ui/fields.ts +252 -0
  64. package/node_modules/pi-footer/src/ui/global-menu.ts +126 -0
  65. package/node_modules/pi-footer/src/ui/helpers.ts +44 -0
  66. package/node_modules/pi-footer/src/ui/layout.ts +17 -0
  67. package/node_modules/pi-footer/src/ui/line-list.ts +19 -0
  68. package/node_modules/pi-footer/src/ui/model.ts +64 -0
  69. package/node_modules/pi-footer/src/ui/navigation.ts +29 -0
  70. package/node_modules/pi-footer/src/ui/option-edit.ts +93 -0
  71. package/node_modules/pi-footer/src/ui/overlay-render.ts +103 -0
  72. package/node_modules/pi-footer/src/ui/screen-context.ts +18 -0
  73. package/node_modules/pi-footer/src/ui/screen-controller.ts +27 -0
  74. package/node_modules/pi-footer/src/ui/screen-render.ts +32 -0
  75. package/node_modules/pi-footer/src/ui/screen-state.ts +20 -0
  76. package/node_modules/pi-footer/src/ui/screen.ts +243 -0
  77. package/node_modules/pi-footer/src/ui/screens/add-widget.ts +92 -0
  78. package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +52 -0
  79. package/node_modules/pi-footer/src/ui/screens/controller.ts +12 -0
  80. package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +68 -0
  81. package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +115 -0
  82. package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +61 -0
  83. package/node_modules/pi-footer/src/ui/screens/global.ts +75 -0
  84. package/node_modules/pi-footer/src/ui/screens/line-list.ts +108 -0
  85. package/node_modules/pi-footer/src/ui/screens/main.ts +99 -0
  86. package/node_modules/pi-footer/src/ui/screens/terminal.ts +121 -0
  87. package/node_modules/pi-footer/src/ui/screens/widget-list.ts +154 -0
  88. package/node_modules/pi-footer/src/ui/terminal-menu.ts +32 -0
  89. package/node_modules/pi-footer/src/ui/theme.ts +48 -0
  90. package/node_modules/pi-footer/src/ui/title-bar.ts +100 -0
  91. package/node_modules/pi-footer/src/ui/widget-actions.ts +76 -0
  92. package/node_modules/pi-footer/src/ui.ts +66 -0
  93. package/node_modules/pi-footer/src/widgets/context.ts +28 -0
  94. package/node_modules/pi-footer/src/widgets/core/active-tools.ts +17 -0
  95. package/node_modules/pi-footer/src/widgets/core/context-window.ts +24 -0
  96. package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +19 -0
  97. package/node_modules/pi-footer/src/widgets/core/cwd.ts +108 -0
  98. package/node_modules/pi-footer/src/widgets/core/event.ts +34 -0
  99. package/node_modules/pi-footer/src/widgets/core/external-status.ts +102 -0
  100. package/node_modules/pi-footer/src/widgets/core/model-provider.ts +20 -0
  101. package/node_modules/pi-footer/src/widgets/core/model.ts +35 -0
  102. package/node_modules/pi-footer/src/widgets/core/provider.ts +17 -0
  103. package/node_modules/pi-footer/src/widgets/core/session-name.ts +17 -0
  104. package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +17 -0
  105. package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +17 -0
  106. package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +17 -0
  107. package/node_modules/pi-footer/src/widgets/git/branch.ts +81 -0
  108. package/node_modules/pi-footer/src/widgets/git/clean.ts +19 -0
  109. package/node_modules/pi-footer/src/widgets/git/deletions.ts +17 -0
  110. package/node_modules/pi-footer/src/widgets/git/diff.ts +38 -0
  111. package/node_modules/pi-footer/src/widgets/git/insertions.ts +17 -0
  112. package/node_modules/pi-footer/src/widgets/git/remote.ts +17 -0
  113. package/node_modules/pi-footer/src/widgets/git/root.ts +17 -0
  114. package/node_modules/pi-footer/src/widgets/git/sha.ts +17 -0
  115. package/node_modules/pi-footer/src/widgets/git/staged.ts +17 -0
  116. package/node_modules/pi-footer/src/widgets/git/status.ts +19 -0
  117. package/node_modules/pi-footer/src/widgets/git/unstaged.ts +17 -0
  118. package/node_modules/pi-footer/src/widgets/git/untracked.ts +17 -0
  119. package/node_modules/pi-footer/src/widgets/instance.ts +118 -0
  120. package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +18 -0
  121. package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +32 -0
  122. package/node_modules/pi-footer/src/widgets/layout/separator.ts +57 -0
  123. package/node_modules/pi-footer/src/widgets/layout/spacer.ts +31 -0
  124. package/node_modules/pi-footer/src/widgets/options.ts +122 -0
  125. package/node_modules/pi-footer/src/widgets/project/runtime.ts +361 -0
  126. package/node_modules/pi-footer/src/widgets/registry.ts +223 -0
  127. package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +17 -0
  128. package/node_modules/pi-footer/src/widgets/session/compactions.ts +17 -0
  129. package/node_modules/pi-footer/src/widgets/session/elapsed.ts +18 -0
  130. package/node_modules/pi-footer/src/widgets/session/last-activity.ts +18 -0
  131. package/node_modules/pi-footer/src/widgets/session/messages.ts +19 -0
  132. package/node_modules/pi-footer/src/widgets/session/session-id.ts +17 -0
  133. package/node_modules/pi-footer/src/widgets/session/session-start.ts +18 -0
  134. package/node_modules/pi-footer/src/widgets/session/tool-results.ts +17 -0
  135. package/node_modules/pi-footer/src/widgets/session/total-messages.ts +19 -0
  136. package/node_modules/pi-footer/src/widgets/session/total-time.ts +18 -0
  137. package/node_modules/pi-footer/src/widgets/session/user-messages.ts +17 -0
  138. package/node_modules/pi-footer/src/widgets/store.ts +26 -0
  139. package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +55 -0
  140. package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +18 -0
  141. package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +18 -0
  142. package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +108 -0
  143. package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +26 -0
  144. package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +29 -0
  145. package/node_modules/pi-footer/src/widgets/tokens/context.ts +29 -0
  146. package/node_modules/pi-footer/src/widgets/tokens/cost.ts +51 -0
  147. package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +25 -0
  148. package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +18 -0
  149. package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +25 -0
  150. package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +18 -0
  151. package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +20 -0
  152. package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +25 -0
  153. package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +18 -0
  154. package/node_modules/pi-footer/src/widgets/types.ts +181 -0
  155. package/node_modules/pi-footer/src/widgets/utils/colors.ts +11 -0
  156. package/node_modules/pi-footer/src/widgets/utils/context.ts +112 -0
  157. package/node_modules/pi-footer/src/widgets/utils/session.ts +19 -0
  158. package/node_modules/pi-footer/src/widgets/utils/token-format.ts +78 -0
  159. package/node_modules/pi-mcp-adapter/CHANGELOG.md +19 -0
  160. package/node_modules/pi-mcp-adapter/README.md +19 -4
  161. package/node_modules/pi-mcp-adapter/agent-dir.ts +40 -0
  162. package/node_modules/pi-mcp-adapter/commands.ts +12 -2
  163. package/node_modules/pi-mcp-adapter/direct-tools.ts +6 -8
  164. package/node_modules/pi-mcp-adapter/index.ts +15 -3
  165. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +87 -4
  166. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +138 -61
  167. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +43 -4
  168. package/node_modules/pi-mcp-adapter/oauth.ts +48 -0
  169. package/node_modules/pi-mcp-adapter/package.json +8 -2
  170. package/node_modules/pi-mcp-adapter/proxy-modes.ts +8 -10
  171. package/node_modules/pi-mcp-adapter/tool-registrar.ts +187 -3
  172. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  173. package/node_modules/pi-web-access/CHANGELOG.md +45 -0
  174. package/node_modules/pi-web-access/README.md +104 -29
  175. package/node_modules/pi-web-access/bocha.ts +221 -0
  176. package/node_modules/pi-web-access/curator-page.ts +113 -12
  177. package/node_modules/pi-web-access/curator-server.ts +56 -20
  178. package/node_modules/pi-web-access/datalab-pdf-extract.ts +568 -0
  179. package/node_modules/pi-web-access/duckduckgo.ts +123 -0
  180. package/node_modules/pi-web-access/extract.ts +288 -143
  181. package/node_modules/pi-web-access/feature-config.ts +29 -0
  182. package/node_modules/pi-web-access/gemini-api.ts +4 -0
  183. package/node_modules/pi-web-access/gemini-search.ts +45 -12
  184. package/node_modules/pi-web-access/gemini-web.ts +68 -3
  185. package/node_modules/pi-web-access/index.ts +160 -71
  186. package/node_modules/pi-web-access/jina-search.ts +284 -0
  187. package/node_modules/pi-web-access/kagi.ts +12 -12
  188. package/node_modules/pi-web-access/openai-search.ts +12 -2
  189. package/node_modules/pi-web-access/package.json +4 -3
  190. package/node_modules/pi-web-access/pdf-extract.ts +327 -228
  191. package/node_modules/pi-web-access/storage.ts +440 -2
  192. package/node_modules/pi-web-access/summary-model-scope.ts +1 -1
  193. package/node_modules/pi-web-access/summary-review.ts +4 -2
  194. package/node_modules/pi-web-access/video-extract.ts +10 -8
  195. package/node_modules/pi-web-access/xai-search.ts +12 -2
  196. package/node_modules/pi-web-access/youtube-extract.ts +2 -1
  197. package/node_modules/remote-pi/LICENSE +21 -0
  198. package/node_modules/remote-pi/README.md +675 -0
  199. package/node_modules/remote-pi/dist/actions/handlers.d.ts +122 -0
  200. package/node_modules/remote-pi/dist/actions/handlers.js +160 -0
  201. package/node_modules/remote-pi/dist/actions/handlers.js.map +1 -0
  202. package/node_modules/remote-pi/dist/actions/registry.d.ts +39 -0
  203. package/node_modules/remote-pi/dist/actions/registry.js +58 -0
  204. package/node_modules/remote-pi/dist/actions/registry.js.map +1 -0
  205. package/node_modules/remote-pi/dist/bin/supervisord.d.ts +2 -0
  206. package/node_modules/remote-pi/dist/bin/supervisord.js +86 -0
  207. package/node_modules/remote-pi/dist/bin/supervisord.js.map +1 -0
  208. package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +58 -0
  209. package/node_modules/remote-pi/dist/commands/builtin_mirror.js +71 -0
  210. package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +1 -0
  211. package/node_modules/remote-pi/dist/commands/list_commands.d.ts +60 -0
  212. package/node_modules/remote-pi/dist/commands/list_commands.js +73 -0
  213. package/node_modules/remote-pi/dist/commands/list_commands.js.map +1 -0
  214. package/node_modules/remote-pi/dist/config.d.ts +62 -0
  215. package/node_modules/remote-pi/dist/config.js +115 -0
  216. package/node_modules/remote-pi/dist/config.js.map +1 -0
  217. package/node_modules/remote-pi/dist/daemon/client.d.ts +20 -0
  218. package/node_modules/remote-pi/dist/daemon/client.js +131 -0
  219. package/node_modules/remote-pi/dist/daemon/client.js.map +1 -0
  220. package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +176 -0
  221. package/node_modules/remote-pi/dist/daemon/control_protocol.js +63 -0
  222. package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +1 -0
  223. package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +45 -0
  224. package/node_modules/remote-pi/dist/daemon/cron_log.js +72 -0
  225. package/node_modules/remote-pi/dist/daemon/cron_log.js.map +1 -0
  226. package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +80 -0
  227. package/node_modules/remote-pi/dist/daemon/cron_registry.js +194 -0
  228. package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +1 -0
  229. package/node_modules/remote-pi/dist/daemon/id.d.ts +24 -0
  230. package/node_modules/remote-pi/dist/daemon/id.js +36 -0
  231. package/node_modules/remote-pi/dist/daemon/id.js.map +1 -0
  232. package/node_modules/remote-pi/dist/daemon/install.d.ts +170 -0
  233. package/node_modules/remote-pi/dist/daemon/install.js +547 -0
  234. package/node_modules/remote-pi/dist/daemon/install.js.map +1 -0
  235. package/node_modules/remote-pi/dist/daemon/registry.d.ts +63 -0
  236. package/node_modules/remote-pi/dist/daemon/registry.js +153 -0
  237. package/node_modules/remote-pi/dist/daemon/registry.js.map +1 -0
  238. package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +194 -0
  239. package/node_modules/remote-pi/dist/daemon/rpc_child.js +389 -0
  240. package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +1 -0
  241. package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +93 -0
  242. package/node_modules/remote-pi/dist/daemon/supervisor.js +596 -0
  243. package/node_modules/remote-pi/dist/daemon/supervisor.js.map +1 -0
  244. package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +26 -0
  245. package/node_modules/remote-pi/dist/extension_ui_bridge.js +341 -0
  246. package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +1 -0
  247. package/node_modules/remote-pi/dist/index.d.ts +213 -0
  248. package/node_modules/remote-pi/dist/index.js +4996 -0
  249. package/node_modules/remote-pi/dist/index.js.map +1 -0
  250. package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +10 -0
  251. package/node_modules/remote-pi/dist/mcp/mesh_result.js +42 -0
  252. package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +1 -0
  253. package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +16 -0
  254. package/node_modules/remote-pi/dist/mcp/mesh_server.js +327 -0
  255. package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +1 -0
  256. package/node_modules/remote-pi/dist/mesh/canonical.d.ts +30 -0
  257. package/node_modules/remote-pi/dist/mesh/canonical.js +61 -0
  258. package/node_modules/remote-pi/dist/mesh/canonical.js.map +1 -0
  259. package/node_modules/remote-pi/dist/mesh/client.d.ts +18 -0
  260. package/node_modules/remote-pi/dist/mesh/client.js +125 -0
  261. package/node_modules/remote-pi/dist/mesh/client.js.map +1 -0
  262. package/node_modules/remote-pi/dist/mesh/encoding.d.ts +38 -0
  263. package/node_modules/remote-pi/dist/mesh/encoding.js +216 -0
  264. package/node_modules/remote-pi/dist/mesh/encoding.js.map +1 -0
  265. package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +73 -0
  266. package/node_modules/remote-pi/dist/mesh/self_revoke.js +401 -0
  267. package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +1 -0
  268. package/node_modules/remote-pi/dist/mesh/siblings.d.ts +49 -0
  269. package/node_modules/remote-pi/dist/mesh/siblings.js +159 -0
  270. package/node_modules/remote-pi/dist/mesh/siblings.js.map +1 -0
  271. package/node_modules/remote-pi/dist/mesh/types.d.ts +34 -0
  272. package/node_modules/remote-pi/dist/mesh/types.js +11 -0
  273. package/node_modules/remote-pi/dist/mesh/types.js.map +1 -0
  274. package/node_modules/remote-pi/dist/mesh/verify.d.ts +17 -0
  275. package/node_modules/remote-pi/dist/mesh/verify.js +86 -0
  276. package/node_modules/remote-pi/dist/mesh/verify.js.map +1 -0
  277. package/node_modules/remote-pi/dist/pairing/crypto.d.ts +8 -0
  278. package/node_modules/remote-pi/dist/pairing/crypto.js +22 -0
  279. package/node_modules/remote-pi/dist/pairing/crypto.js.map +1 -0
  280. package/node_modules/remote-pi/dist/pairing/handshake.d.ts +28 -0
  281. package/node_modules/remote-pi/dist/pairing/handshake.js +113 -0
  282. package/node_modules/remote-pi/dist/pairing/handshake.js.map +1 -0
  283. package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +16 -0
  284. package/node_modules/remote-pi/dist/pairing/noise-sha256.js +103 -0
  285. package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +1 -0
  286. package/node_modules/remote-pi/dist/pairing/qr.d.ts +59 -0
  287. package/node_modules/remote-pi/dist/pairing/qr.js +125 -0
  288. package/node_modules/remote-pi/dist/pairing/qr.js.map +1 -0
  289. package/node_modules/remote-pi/dist/pairing/storage.d.ts +120 -0
  290. package/node_modules/remote-pi/dist/pairing/storage.js +604 -0
  291. package/node_modules/remote-pi/dist/pairing/storage.js.map +1 -0
  292. package/node_modules/remote-pi/dist/protocol/codec.d.ts +7 -0
  293. package/node_modules/remote-pi/dist/protocol/codec.js +49 -0
  294. package/node_modules/remote-pi/dist/protocol/codec.js.map +1 -0
  295. package/node_modules/remote-pi/dist/protocol/types.d.ts +393 -0
  296. package/node_modules/remote-pi/dist/protocol/types.js +2 -0
  297. package/node_modules/remote-pi/dist/protocol/types.js.map +1 -0
  298. package/node_modules/remote-pi/dist/rooms.d.ts +29 -0
  299. package/node_modules/remote-pi/dist/rooms.js +57 -0
  300. package/node_modules/remote-pi/dist/rooms.js.map +1 -0
  301. package/node_modules/remote-pi/dist/session/address.d.ts +49 -0
  302. package/node_modules/remote-pi/dist/session/address.js +58 -0
  303. package/node_modules/remote-pi/dist/session/address.js.map +1 -0
  304. package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +55 -0
  305. package/node_modules/remote-pi/dist/session/agent_bridge.js +146 -0
  306. package/node_modules/remote-pi/dist/session/agent_bridge.js.map +1 -0
  307. package/node_modules/remote-pi/dist/session/bridge.d.ts +37 -0
  308. package/node_modules/remote-pi/dist/session/bridge.js +130 -0
  309. package/node_modules/remote-pi/dist/session/bridge.js.map +1 -0
  310. package/node_modules/remote-pi/dist/session/broker.d.ts +189 -0
  311. package/node_modules/remote-pi/dist/session/broker.js +507 -0
  312. package/node_modules/remote-pi/dist/session/broker.js.map +1 -0
  313. package/node_modules/remote-pi/dist/session/broker_remote.d.ts +74 -0
  314. package/node_modules/remote-pi/dist/session/broker_remote.js +583 -0
  315. package/node_modules/remote-pi/dist/session/broker_remote.js.map +1 -0
  316. package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +33 -0
  317. package/node_modules/remote-pi/dist/session/cwd_lock.js +126 -0
  318. package/node_modules/remote-pi/dist/session/cwd_lock.js.map +1 -0
  319. package/node_modules/remote-pi/dist/session/envelope.d.ts +33 -0
  320. package/node_modules/remote-pi/dist/session/envelope.js +117 -0
  321. package/node_modules/remote-pi/dist/session/envelope.js.map +1 -0
  322. package/node_modules/remote-pi/dist/session/global_config.d.ts +33 -0
  323. package/node_modules/remote-pi/dist/session/global_config.js +73 -0
  324. package/node_modules/remote-pi/dist/session/global_config.js.map +1 -0
  325. package/node_modules/remote-pi/dist/session/ipc.d.ts +27 -0
  326. package/node_modules/remote-pi/dist/session/ipc.js +22 -0
  327. package/node_modules/remote-pi/dist/session/ipc.js.map +1 -0
  328. package/node_modules/remote-pi/dist/session/leader_election.d.ts +32 -0
  329. package/node_modules/remote-pi/dist/session/leader_election.js +106 -0
  330. package/node_modules/remote-pi/dist/session/leader_election.js.map +1 -0
  331. package/node_modules/remote-pi/dist/session/local_config.d.ts +55 -0
  332. package/node_modules/remote-pi/dist/session/local_config.js +157 -0
  333. package/node_modules/remote-pi/dist/session/local_config.js.map +1 -0
  334. package/node_modules/remote-pi/dist/session/mesh_message.d.ts +20 -0
  335. package/node_modules/remote-pi/dist/session/mesh_message.js +28 -0
  336. package/node_modules/remote-pi/dist/session/mesh_message.js.map +1 -0
  337. package/node_modules/remote-pi/dist/session/mesh_node.d.ts +116 -0
  338. package/node_modules/remote-pi/dist/session/mesh_node.js +573 -0
  339. package/node_modules/remote-pi/dist/session/mesh_node.js.map +1 -0
  340. package/node_modules/remote-pi/dist/session/peer.d.ts +139 -0
  341. package/node_modules/remote-pi/dist/session/peer.js +451 -0
  342. package/node_modules/remote-pi/dist/session/peer.js.map +1 -0
  343. package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +13 -0
  344. package/node_modules/remote-pi/dist/session/peer_inventory.js +48 -0
  345. package/node_modules/remote-pi/dist/session/peer_inventory.js.map +1 -0
  346. package/node_modules/remote-pi/dist/session/peer_limits.d.ts +9 -0
  347. package/node_modules/remote-pi/dist/session/peer_limits.js +21 -0
  348. package/node_modules/remote-pi/dist/session/peer_limits.js.map +1 -0
  349. package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +39 -0
  350. package/node_modules/remote-pi/dist/session/setup_wizard.js +63 -0
  351. package/node_modules/remote-pi/dist/session/setup_wizard.js.map +1 -0
  352. package/node_modules/remote-pi/dist/session/tool_gate.d.ts +5 -0
  353. package/node_modules/remote-pi/dist/session/tool_gate.js +11 -0
  354. package/node_modules/remote-pi/dist/session/tool_gate.js.map +1 -0
  355. package/node_modules/remote-pi/dist/session/tools.d.ts +24 -0
  356. package/node_modules/remote-pi/dist/session/tools.js +252 -0
  357. package/node_modules/remote-pi/dist/session/tools.js.map +1 -0
  358. package/node_modules/remote-pi/dist/session/wizard.d.ts +13 -0
  359. package/node_modules/remote-pi/dist/session/wizard.js +20 -0
  360. package/node_modules/remote-pi/dist/session/wizard.js.map +1 -0
  361. package/node_modules/remote-pi/dist/settings.d.ts +15 -0
  362. package/node_modules/remote-pi/dist/settings.js +52 -0
  363. package/node_modules/remote-pi/dist/settings.js.map +1 -0
  364. package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +37 -0
  365. package/node_modules/remote-pi/dist/transport/peer_channel.js +98 -0
  366. package/node_modules/remote-pi/dist/transport/peer_channel.js.map +1 -0
  367. package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +29 -0
  368. package/node_modules/remote-pi/dist/transport/pi_forward_client.js +62 -0
  369. package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +1 -0
  370. package/node_modules/remote-pi/dist/transport/relay_client.d.ts +91 -0
  371. package/node_modules/remote-pi/dist/transport/relay_client.js +206 -0
  372. package/node_modules/remote-pi/dist/transport/relay_client.js.map +1 -0
  373. package/node_modules/remote-pi/dist/ui/footer.d.ts +32 -0
  374. package/node_modules/remote-pi/dist/ui/footer.js +34 -0
  375. package/node_modules/remote-pi/dist/ui/footer.js.map +1 -0
  376. package/node_modules/remote-pi/docs/daemon.md +289 -0
  377. package/node_modules/remote-pi/package.json +88 -0
  378. package/node_modules/remote-pi/service-templates/launchd.plist.template +35 -0
  379. package/node_modules/remote-pi/service-templates/systemd.service.template +19 -0
  380. package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +10 -0
  381. package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +38 -0
  382. package/node_modules/remote-pi/skills/agent-network/SKILL.md +310 -0
  383. package/package.json +25 -10
  384. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/write-display-utils.ts +0 -29
  385. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference-core.ts → reference/session.ts} +0 -0
  386. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-aliases.ts → shell/aliases.ts} +0 -0
  387. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ATTRIBUTION.md +0 -0
  388. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-presentation.ts +0 -0
  389. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/index.ts +0 -0
  390. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/render-utils.ts +0 -0
  391. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/shiki-highlight.ts +0 -0
  392. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/types.ts +0 -0
@@ -0,0 +1,75 @@
1
+ import { Key, matchesKey } from "@earendil-works/pi-tui";
2
+
3
+ import { WidgetStore } from "../../widgets/store.js";
4
+ import {
5
+ applyGlobalMenuAction,
6
+ applyGlobalSettingsAction,
7
+ applyGlobalSettingsBackspace,
8
+ applyGlobalSettingsTextInput,
9
+ GLOBAL_MENU_ACTIONS,
10
+ GLOBAL_MENU_HINT,
11
+ globalMenuAction,
12
+ globalMenuFields,
13
+ } from "../global-menu.js";
14
+ import { isPrintable, wrap } from "../helpers.js";
15
+ import { Controller } from "./controller.js";
16
+
17
+ export class GlobalScreen extends Controller {
18
+ private selected = 0;
19
+
20
+ renderScreen(width: number): string[] {
21
+ const fields = globalMenuFields(this.ctx.state.store.settings);
22
+ return [
23
+ this.render.line(
24
+ this.render.menuTitle("Global Overrides", "Configure global settings for the pi-footer"),
25
+ width,
26
+ ),
27
+ this.render.line(this.ctx.theme.dim(GLOBAL_MENU_HINT), width),
28
+ ...fields.map((field, index) => this.render.menuLine(index === this.selected, field, width)),
29
+ ];
30
+ }
31
+
32
+ handleInput(data: string): void {
33
+ if (matchesKey(data, Key.up))
34
+ this.selected = wrap(this.selected - 1, GLOBAL_MENU_ACTIONS.length);
35
+ else if (matchesKey(data, Key.down))
36
+ this.selected = wrap(this.selected + 1, GLOBAL_MENU_ACTIONS.length);
37
+ else if (matchesKey(data, Key.left)) this.adjust(-1);
38
+ else if (matchesKey(data, Key.right) || matchesKey(data, Key.enter)) this.adjust(1);
39
+ else if (matchesKey(data, Key.backspace)) this.applyBackspace();
40
+ else if (isPrintable(data)) this.applyTextInput(data);
41
+ }
42
+
43
+ private adjust(delta: number): void {
44
+ const action = globalMenuAction(this.selected);
45
+ const settings = this.ctx.state.store.settings;
46
+
47
+ if (!applyGlobalSettingsAction(settings, action, delta)) {
48
+ this.ctx.state.store = WidgetStore.fromConfig(
49
+ applyGlobalMenuAction(this.ctx.state.store.toConfig(), action, delta),
50
+ );
51
+ }
52
+
53
+ this.ctx.emitChange();
54
+ }
55
+
56
+ private applyTextInput(data: string): void {
57
+ if (
58
+ !applyGlobalSettingsTextInput(
59
+ this.ctx.state.store.settings,
60
+ globalMenuAction(this.selected),
61
+ data,
62
+ )
63
+ )
64
+ return;
65
+ this.ctx.emitChange();
66
+ }
67
+
68
+ private applyBackspace(): void {
69
+ if (
70
+ !applyGlobalSettingsBackspace(this.ctx.state.store.settings, globalMenuAction(this.selected))
71
+ )
72
+ return;
73
+ this.ctx.emitChange();
74
+ }
75
+ }
@@ -0,0 +1,108 @@
1
+ import { Key, matchesKey } from "@earendil-works/pi-tui";
2
+
3
+ import { registry } from "../../widgets/registry.js";
4
+ import { wrap } from "../helpers.js";
5
+ import { LINE_LIST_HINT, lineListCountLabel, lineListItemLabel } from "../line-list.js";
6
+ import type { ScreenView } from "../model.js";
7
+ import { pageSelection, scrollWindow } from "../navigation.js";
8
+ import type { ScreenContext } from "../screen-context.js";
9
+ import type { ScreenRender } from "../screen-render.js";
10
+ import { addLineAfter, cloneLineAfter, deleteLine, moveLine } from "../widget-actions.js";
11
+ import { Controller } from "./controller.js";
12
+
13
+ export class LineListScreen extends Controller {
14
+ constructor(
15
+ ctx: ScreenContext,
16
+ render: ScreenRender,
17
+ private readonly title: string,
18
+ private readonly nextView: ScreenView,
19
+ ) {
20
+ super(ctx, render);
21
+ }
22
+
23
+ renderScreen(width: number): string[] {
24
+ const visibleCount = this.ctx.visibleRowCount();
25
+ const { start, end } = scrollWindow(
26
+ this.ctx.state.store.lines.length,
27
+ this.ctx.state.selectedLine,
28
+ visibleCount,
29
+ );
30
+ const visible = this.ctx.state.store.lines.slice(start, end);
31
+ const lines = [
32
+ this.render.line(
33
+ this.render.menuTitle(this.title, "Choose which status line to configure"),
34
+ width,
35
+ ),
36
+ this.render.line(this.ctx.theme.dim(LINE_LIST_HINT), width),
37
+ this.render.line(
38
+ this.ctx.theme.dim(lineListCountLabel(this.ctx.state.store.lines.length, start, end)),
39
+ width,
40
+ ),
41
+ ];
42
+ visible.forEach((line, offset) => {
43
+ const index = start + offset;
44
+ const text = lineListItemLabel(index, line.length, (value) => this.ctx.theme.dim(value));
45
+ lines.push(this.render.menuLine(index === this.ctx.state.selectedLine, text, width));
46
+ });
47
+ return lines;
48
+ }
49
+
50
+ handleInput(data: string): void {
51
+ if (matchesKey(data, Key.up))
52
+ this.ctx.state.selectedLine = wrap(
53
+ this.ctx.state.selectedLine - 1,
54
+ this.ctx.state.store.lines.length,
55
+ );
56
+ else if (matchesKey(data, Key.down))
57
+ this.ctx.state.selectedLine = wrap(
58
+ this.ctx.state.selectedLine + 1,
59
+ this.ctx.state.store.lines.length,
60
+ );
61
+ else if (matchesKey(data, Key.pageUp)) this.page(-1);
62
+ else if (matchesKey(data, Key.pageDown)) this.page(1);
63
+ else if (matchesKey(data, Key.enter)) {
64
+ this.ctx.state.selectedWidget = 0;
65
+ this.ctx.show(this.nextView);
66
+ } else if (data === "a") {
67
+ this.ctx.state.selectedLine = addLineAfter(
68
+ this.ctx.state.store.lines,
69
+ this.ctx.state.selectedLine,
70
+ );
71
+ this.ctx.emitChange();
72
+ } else if (data === "c") {
73
+ this.ctx.state.selectedLine = cloneLineAfter(
74
+ this.ctx.state.store.lines,
75
+ this.ctx.state.selectedLine,
76
+ (widget) => registry.cloneWidget(widget),
77
+ );
78
+ this.ctx.emitChange();
79
+ } else if (data === "w") this.move(-1);
80
+ else if (data === "s") this.move(1);
81
+ else if (data === "d") this.delete();
82
+ }
83
+
84
+ private page(delta: -1 | 1): void {
85
+ this.ctx.state.selectedLine = pageSelection(
86
+ this.ctx.state.selectedLine,
87
+ this.ctx.state.store.lines.length,
88
+ this.ctx.visibleRowCount(),
89
+ delta,
90
+ );
91
+ }
92
+
93
+ private move(delta: number): void {
94
+ const next = moveLine(this.ctx.state.store.lines, this.ctx.state.selectedLine, delta);
95
+ if (next === this.ctx.state.selectedLine) return;
96
+ this.ctx.state.selectedLine = next;
97
+ this.ctx.emitChange();
98
+ }
99
+
100
+ private delete(): void {
101
+ const previousLength = this.ctx.state.store.lines.length;
102
+ this.ctx.state.selectedLine = deleteLine(
103
+ this.ctx.state.store.lines,
104
+ this.ctx.state.selectedLine,
105
+ );
106
+ if (this.ctx.state.store.lines.length !== previousLength) this.ctx.emitChange();
107
+ }
108
+ }
@@ -0,0 +1,99 @@
1
+ import { Key, matchesKey } from "@earendil-works/pi-tui";
2
+
3
+ import { wrap } from "../helpers.js";
4
+ import type { ScreenView } from "../model.js";
5
+ import { Controller } from "./controller.js";
6
+
7
+ type MenuAction =
8
+ | { type: "view"; view: ScreenView }
9
+ | { type: "save-exit" }
10
+ | { type: "discard-exit" };
11
+
12
+ interface MenuItem {
13
+ label: string;
14
+ description: string;
15
+ action: MenuAction;
16
+ }
17
+
18
+ const HINT = "↑/↓ select • enter option • ctrl+s save • esc exit";
19
+
20
+ const ITEMS: readonly MenuItem[] = [
21
+ {
22
+ label: "Edit lines",
23
+ description: "Manage status lines and line widgets",
24
+ action: { type: "view", view: "line-list" },
25
+ },
26
+ {
27
+ label: "Edit colors",
28
+ description: "Configure per-widget foreground/background/bold",
29
+ action: { type: "view", view: "color-line-list" },
30
+ },
31
+ {
32
+ label: "Terminal Options",
33
+ description: "Terminal width and color level",
34
+ action: { type: "view", view: "terminal" },
35
+ },
36
+ {
37
+ label: "Global Overrides",
38
+ description: "Global presets, separators, icons, minimalist mode",
39
+ action: { type: "view", view: "global" },
40
+ },
41
+ {
42
+ label: "Pi extensions",
43
+ description: "Published statuses and extension status row visibility",
44
+ action: { type: "view", view: "extension-status-row" },
45
+ },
46
+ {
47
+ label: "Save & Exit",
48
+ description: "Persist changes and close the configuration UI",
49
+ action: { type: "save-exit" },
50
+ },
51
+ {
52
+ label: "Exit without saving",
53
+ description: "Discard unsaved changes and close immediately",
54
+ action: { type: "discard-exit" },
55
+ },
56
+ ];
57
+
58
+ export class MainScreen extends Controller {
59
+ private selected = 0;
60
+
61
+ renderScreen(width: number): string[] {
62
+ return [
63
+ this.render.line(
64
+ this.render.menuTitle(
65
+ "Main Menu",
66
+ "Configure any number of status lines with various widgets",
67
+ ),
68
+ width,
69
+ ),
70
+ this.render.line(this.ctx.theme.dim(HINT), width),
71
+ ...ITEMS.map((item, index) =>
72
+ this.render.menuLine(
73
+ index === this.selected,
74
+ `${item.label} ${this.ctx.theme.dim(item.description)}`,
75
+ width,
76
+ ),
77
+ ),
78
+ ];
79
+ }
80
+
81
+ handleInput(data: string): void {
82
+ if (matchesKey(data, Key.up)) this.selected = wrap(this.selected - 1, ITEMS.length);
83
+ else if (matchesKey(data, Key.down)) this.selected = wrap(this.selected + 1, ITEMS.length);
84
+ else if (matchesKey(data, Key.enter)) this.applySelectedAction();
85
+ }
86
+
87
+ private menuAction(index: number): MenuAction | undefined {
88
+ return ITEMS[index]?.action;
89
+ }
90
+
91
+ private applySelectedAction(): void {
92
+ const action = this.menuAction(this.selected);
93
+ if (!action) return;
94
+
95
+ if (action.type === "view") this.ctx.show(action.view);
96
+ else if (action.type === "save-exit") this.ctx.save(true);
97
+ else this.ctx.exitWithoutSaving();
98
+ }
99
+ }
@@ -0,0 +1,121 @@
1
+ import { Key, matchesKey } from "@earendil-works/pi-tui";
2
+
3
+ import type { ColorLevel } from "../../colors.js";
4
+ import {
5
+ COLOR_LEVEL_CONFIRM_HINT,
6
+ COLOR_LEVEL_CONFIRM_WARNING,
7
+ colorLevelConfirmAction,
8
+ colorLevelConfirmValueLabel,
9
+ } from "../color-level-confirm.js";
10
+ import { hasCustomAnsiColors, resetCustomAnsiColors } from "../color-options.js";
11
+ import { wrap } from "../helpers.js";
12
+ import type { ScreenContext } from "../screen-context.js";
13
+ import type { ScreenRender } from "../screen-render.js";
14
+ import {
15
+ nextTerminalColorLevel,
16
+ nextTerminalWidthMode,
17
+ TERMINAL_MENU_ACTIONS,
18
+ TERMINAL_MENU_HINT,
19
+ terminalMenuAction,
20
+ terminalMenuFields,
21
+ } from "../terminal-menu.js";
22
+ import { Controller } from "./controller.js";
23
+
24
+ export class TerminalState {
25
+ pendingColorLevel: ColorLevel | undefined;
26
+ }
27
+
28
+ export class TerminalScreen extends Controller {
29
+ private selected = 0;
30
+
31
+ constructor(
32
+ ctx: ScreenContext,
33
+ render: ScreenRender,
34
+ private readonly terminalState: TerminalState,
35
+ ) {
36
+ super(ctx, render);
37
+ }
38
+
39
+ renderScreen(width: number): string[] {
40
+ const fields = terminalMenuFields(this.ctx.state.store.settings);
41
+ return [
42
+ this.render.line(
43
+ this.render.menuTitle(
44
+ "Terminal Options",
45
+ "Configure terminal width behavior and color level",
46
+ ),
47
+ width,
48
+ ),
49
+ this.render.line(this.ctx.theme.dim(TERMINAL_MENU_HINT), width),
50
+ ...fields.map((field, index) => this.render.menuLine(index === this.selected, field, width)),
51
+ ];
52
+ }
53
+
54
+ handleInput(data: string): void {
55
+ if (matchesKey(data, Key.up))
56
+ this.selected = wrap(this.selected - 1, TERMINAL_MENU_ACTIONS.length);
57
+ else if (matchesKey(data, Key.down))
58
+ this.selected = wrap(this.selected + 1, TERMINAL_MENU_ACTIONS.length);
59
+ else if (matchesKey(data, Key.left)) this.adjust(-1);
60
+ else if (matchesKey(data, Key.right) || matchesKey(data, Key.enter)) this.adjust(1);
61
+ }
62
+
63
+ private adjust(delta: number): void {
64
+ if (terminalMenuAction(this.selected) === "width-mode") {
65
+ this.ctx.state.store.settings.terminal.widthMode = nextTerminalWidthMode(
66
+ this.ctx.state.store.settings,
67
+ delta,
68
+ );
69
+ this.ctx.emitChange();
70
+ return;
71
+ }
72
+ const settings = this.ctx.state.store.settings;
73
+ const next = nextTerminalColorLevel(settings, delta);
74
+ if (next !== settings.terminal.colorLevel && hasCustomAnsiColors(this.ctx.state.store.lines)) {
75
+ this.terminalState.pendingColorLevel = next;
76
+ this.ctx.show("confirm-color-level");
77
+ return;
78
+ }
79
+ settings.terminal.colorLevel = next;
80
+ this.ctx.emitChange();
81
+ }
82
+ }
83
+
84
+ export class ColorLevelConfirmScreen extends Controller {
85
+ constructor(
86
+ ctx: ScreenContext,
87
+ render: ScreenRender,
88
+ private readonly terminalState: TerminalState,
89
+ ) {
90
+ super(ctx, render);
91
+ }
92
+
93
+ renderScreen(width: number): string[] {
94
+ return [
95
+ this.render.line(this.ctx.theme.warning(COLOR_LEVEL_CONFIRM_WARNING), width),
96
+ this.render.line(colorLevelConfirmValueLabel(this.terminalState.pendingColorLevel), width),
97
+ this.render.line(this.ctx.theme.dim(COLOR_LEVEL_CONFIRM_HINT), width),
98
+ ];
99
+ }
100
+
101
+ handleInput(data: string): void {
102
+ const action = colorLevelConfirmAction(
103
+ data,
104
+ matchesKey(data, Key.escape),
105
+ matchesKey(data, Key.enter),
106
+ );
107
+ if (action === "cancel") {
108
+ this.terminalState.pendingColorLevel = undefined;
109
+ this.ctx.show("terminal");
110
+ return;
111
+ }
112
+ if (action === "confirm") {
113
+ if (this.terminalState.pendingColorLevel)
114
+ this.ctx.state.store.settings.terminal.colorLevel = this.terminalState.pendingColorLevel;
115
+ resetCustomAnsiColors(this.ctx.state.store.lines);
116
+ this.terminalState.pendingColorLevel = undefined;
117
+ this.ctx.show("terminal");
118
+ this.ctx.emitChange();
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,154 @@
1
+ import { Key, matchesKey } from "@earendil-works/pi-tui";
2
+
3
+ import { registry } from "../../widgets/registry.js";
4
+ import type { Widget } from "../../widgets/types.js";
5
+ import { formatWidgetColorOptions, formatWidgetOptions } from "../fields.js";
6
+ import { wrap } from "../helpers.js";
7
+ import { pageSelection, scrollWindow } from "../navigation.js";
8
+ import type { ScreenContext } from "../screen-context.js";
9
+ import type { ScreenRender } from "../screen-render.js";
10
+ import {
11
+ cloneSelectedWidget,
12
+ deleteSelectedWidget,
13
+ moveWidget,
14
+ toggleWidgetEnabled,
15
+ toggleWidgetRaw,
16
+ } from "../widget-actions.js";
17
+ import { Controller } from "./controller.js";
18
+
19
+ const HINT =
20
+ "↑/↓ select • enter options • a add • c clone • w/s move • d delete • space toggle • r raw • esc back";
21
+ const COLOR_HINT = "↑/↓ select • pgup/pgdn jump • enter colors • esc back";
22
+
23
+ export class WidgetListScreen extends Controller {
24
+ constructor(
25
+ ctx: ScreenContext,
26
+ render: ScreenRender,
27
+ private readonly colors: boolean,
28
+ ) {
29
+ super(ctx, render);
30
+ }
31
+
32
+ renderScreen(width: number): string[] {
33
+ const line = this.ctx.currentLine();
34
+ const visibleCount = this.ctx.visibleRowCount();
35
+ const { start, end } = scrollWindow(line.length, this.ctx.state.selectedWidget, visibleCount);
36
+ const visible = line.slice(start, end);
37
+ const lines = [
38
+ this.render.line(
39
+ this.render.menuTitle(
40
+ `${this.colors ? "Edit widget colors" : "Edit widgets"} / Line ${this.ctx.state.selectedLine + 1}`,
41
+ this.colors
42
+ ? "Select a widget to edit its colors"
43
+ : "Select a widget to edit its options, or add/remove/reorder widgets",
44
+ ),
45
+ width,
46
+ ),
47
+ this.render.line(this.ctx.theme.dim(this.colors ? COLOR_HINT : HINT), width),
48
+ this.render.line(this.ctx.theme.dim(this.countLabel(line.length, start, end)), width),
49
+ ];
50
+ if (line.length === 0)
51
+ lines.push(
52
+ this.render.line(this.ctx.theme.warning("Empty line. Press a to add a widget."), width),
53
+ );
54
+ visible.forEach((widget, offset) => {
55
+ const index = start + offset;
56
+ const text = this.colors ? this.colorItemLabel(index, widget) : this.itemLabel(index, widget);
57
+ lines.push(this.render.menuLine(index === this.ctx.state.selectedWidget, text, width));
58
+ });
59
+ return lines;
60
+ }
61
+
62
+ handleInput(data: string): void {
63
+ const line = this.ctx.currentLine();
64
+ if (matchesKey(data, Key.up))
65
+ this.ctx.state.selectedWidget = wrap(
66
+ this.ctx.state.selectedWidget - 1,
67
+ Math.max(1, line.length),
68
+ );
69
+ else if (matchesKey(data, Key.down))
70
+ this.ctx.state.selectedWidget = wrap(
71
+ this.ctx.state.selectedWidget + 1,
72
+ Math.max(1, line.length),
73
+ );
74
+ else if (matchesKey(data, Key.pageUp)) this.page(line.length, -1);
75
+ else if (matchesKey(data, Key.pageDown)) this.page(line.length, 1);
76
+ else if (this.colors && matchesKey(data, Key.enter)) this.ctx.show("edit-colors");
77
+ else if (!this.colors) this.handleEditListInput(data);
78
+ }
79
+
80
+ private countLabel(total: number, start: number, end: number): string {
81
+ const range = total === 0 ? "0-0" : `${start + 1}-${end}`;
82
+ return `${total} widget(s), showing ${range}`;
83
+ }
84
+
85
+ private itemLabel(index: number, widget: Widget): string {
86
+ const enabled = widget.enabled ? this.ctx.theme.success("on ") : this.ctx.theme.dim("off");
87
+ const indexPad = index < 9 ? " " : "";
88
+ const options = this.ctx.theme.dim(formatWidgetOptions(widget));
89
+ return `${enabled} ${index + 1}.${indexPad} ${registry.spec(widget.type).label} ${options}`;
90
+ }
91
+
92
+ private colorItemLabel(index: number, widget: Widget): string {
93
+ const enabled = widget.enabled ? this.ctx.theme.success("on ") : this.ctx.theme.dim("off");
94
+ const indexPad = index < 9 ? " " : "";
95
+ const options = this.ctx.theme.dim(formatWidgetColorOptions(widget));
96
+ return `${enabled} ${index + 1}.${indexPad} ${registry.spec(widget.type).label} ${options}`;
97
+ }
98
+
99
+ private handleEditListInput(data: string): void {
100
+ if (data === "a") this.ctx.show("add-widget");
101
+ else if (matchesKey(data, Key.enter) || data === "e") this.ctx.show("edit-widget");
102
+ else if (data === "c") this.cloneCurrentWidget();
103
+ else if (data === "w") this.moveWidget(-1);
104
+ else if (data === "s") this.moveWidget(1);
105
+ else if (data === "d") this.deleteCurrentWidget();
106
+ else if (matchesKey(data, Key.space)) this.toggleCurrentWidget();
107
+ else if (data === "r") this.toggleCurrentWidgetRaw();
108
+ }
109
+
110
+ private page(length: number, delta: -1 | 1): void {
111
+ this.ctx.state.selectedWidget = pageSelection(
112
+ this.ctx.state.selectedWidget,
113
+ length,
114
+ this.ctx.visibleRowCount(),
115
+ delta,
116
+ );
117
+ }
118
+
119
+ private moveWidget(delta: number): void {
120
+ const next = moveWidget(this.ctx.currentLine(), this.ctx.state.selectedWidget, delta);
121
+ if (next === this.ctx.state.selectedWidget) return;
122
+ this.ctx.state.selectedWidget = next;
123
+ this.ctx.emitChange();
124
+ }
125
+
126
+ private cloneCurrentWidget(): void {
127
+ const next = cloneSelectedWidget(
128
+ this.ctx.currentLine(),
129
+ this.ctx.state.selectedWidget,
130
+ (widget) => registry.cloneWidget(widget),
131
+ );
132
+ if (next === this.ctx.state.selectedWidget) return;
133
+ this.ctx.state.selectedWidget = next;
134
+ this.ctx.emitChange();
135
+ }
136
+
137
+ private deleteCurrentWidget(): void {
138
+ const line = this.ctx.currentLine();
139
+ const previousLength = line.length;
140
+ this.ctx.state.selectedWidget = deleteSelectedWidget(line, this.ctx.state.selectedWidget);
141
+ if (line.length === previousLength) return;
142
+ this.ctx.emitChange();
143
+ }
144
+
145
+ private toggleCurrentWidget(): void {
146
+ if (!toggleWidgetEnabled(this.ctx.currentWidget())) return;
147
+ this.ctx.emitChange();
148
+ }
149
+
150
+ private toggleCurrentWidgetRaw(): void {
151
+ if (!toggleWidgetRaw(this.ctx.currentWidget())) return;
152
+ this.ctx.emitChange();
153
+ }
154
+ }
@@ -0,0 +1,32 @@
1
+ import { COLOR_LEVEL_VALUES, type ColorLevel } from "../colors.js";
2
+ import { TERMINAL_WIDTH_MODE_VALUES, type StatuslineSettings } from "../types.js";
3
+ import { cycle } from "./helpers.js";
4
+ import { COLOR_LEVEL_LABELS, WIDTH_MODE_LABELS } from "./model.js";
5
+
6
+ export const TERMINAL_MENU_ACTIONS = ["width-mode", "color-level"] as const;
7
+
8
+ type TerminalMenuAction = (typeof TERMINAL_MENU_ACTIONS)[number];
9
+
10
+ export const TERMINAL_MENU_HINT = "↑/↓ option • ←/→ change • esc back";
11
+
12
+ export function terminalMenuFields(config: StatuslineSettings): string[] {
13
+ return [
14
+ `Terminal Width: ${WIDTH_MODE_LABELS[config.terminal.widthMode]}`,
15
+ `Color Level: ${COLOR_LEVEL_LABELS[config.terminal.colorLevel]}`,
16
+ ];
17
+ }
18
+
19
+ export function terminalMenuAction(index: number): TerminalMenuAction {
20
+ return TERMINAL_MENU_ACTIONS[index] ?? "color-level";
21
+ }
22
+
23
+ export function nextTerminalWidthMode(
24
+ config: StatuslineSettings,
25
+ delta: number,
26
+ ): StatuslineSettings["terminal"]["widthMode"] {
27
+ return cycle(TERMINAL_WIDTH_MODE_VALUES, config.terminal.widthMode, delta);
28
+ }
29
+
30
+ export function nextTerminalColorLevel(config: StatuslineSettings, delta: number): ColorLevel {
31
+ return cycle(COLOR_LEVEL_VALUES, config.terminal.colorLevel, delta);
32
+ }
@@ -0,0 +1,48 @@
1
+ import type { Theme, ThemeColor } from "@earendil-works/pi-coding-agent";
2
+
3
+ import type { ConfigState } from "./config-lifecycle.js";
4
+
5
+ export type ThemeProvider = () => Theme;
6
+
7
+ export interface UiTheme {
8
+ accent(text: string): string;
9
+ dim(text: string): string;
10
+ muted(text: string): string;
11
+ success(text: string): string;
12
+ warning(text: string): string;
13
+ error(text: string): string;
14
+ bold(text: string): string;
15
+ selected(text: string): string;
16
+ border(text: string, color?: ThemeColor): string;
17
+ previewTitle(text: string): string;
18
+ configStateLabel(state: ConfigState, label: string): string;
19
+ }
20
+
21
+ export function createUiTheme(getTheme: ThemeProvider): UiTheme {
22
+ return {
23
+ accent: (text) => getTheme().fg("accent", text),
24
+ dim: (text) => getTheme().fg("dim", text),
25
+ muted: (text) => getTheme().fg("muted", text),
26
+ success: (text) => getTheme().fg("success", text),
27
+ warning: (text) => getTheme().fg("warning", text),
28
+ error: (text) => getTheme().fg("error", text),
29
+ bold: (text) => getTheme().bold(text),
30
+ selected: (text) => {
31
+ const theme = getTheme();
32
+ return theme.bg("selectedBg", theme.fg("accent", text));
33
+ },
34
+ border: (text, color = "border") => getTheme().fg(color, text),
35
+ previewTitle: (text) => {
36
+ const theme = getTheme();
37
+ return theme.fg("accent", theme.bold(text));
38
+ },
39
+ configStateLabel: (state, label) => {
40
+ const theme = getTheme();
41
+ if (state === "saved") return theme.fg("accent", label);
42
+ if (state === "dirty") return theme.bold(theme.fg("warning", label));
43
+ if (state === "saving") return theme.fg("dim", label);
44
+ if (state === "error") return theme.bold(theme.fg("error", label));
45
+ return "";
46
+ },
47
+ };
48
+ }