@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,237 @@
1
+ import type { Theme, ThemeColor } from "@earendil-works/pi-coding-agent";
2
+ import { Chalk } from "chalk";
3
+
4
+ const chalk = {
5
+ level: 2,
6
+ c: new Chalk({ level: 2 }),
7
+ };
8
+
9
+ export const COLOR_LEVEL_VALUES = ["truecolor", "ansi256", "ansi16", "none"] as const;
10
+
11
+ export type ColorLevel = (typeof COLOR_LEVEL_VALUES)[number];
12
+ export type ColorName =
13
+ | "default"
14
+ | "black"
15
+ | "red"
16
+ | "green"
17
+ | "yellow"
18
+ | "blue"
19
+ | "magenta"
20
+ | "cyan"
21
+ | "white"
22
+ | "brightBlack"
23
+ | "brightRed"
24
+ | "brightGreen"
25
+ | "brightYellow"
26
+ | "brightBlue"
27
+ | "brightMagenta"
28
+ | "brightCyan"
29
+ | "brightWhite"
30
+ | `ansi256:${number}`
31
+ | `pi:${ThemeColor}`;
32
+
33
+ interface ColorChoice {
34
+ label: string;
35
+ value: ColorName;
36
+ }
37
+
38
+ export const STANDARD_COLORS: ColorChoice[] = [
39
+ { label: "Default", value: "default" },
40
+ { label: "Black", value: "black" },
41
+ { label: "Red", value: "red" },
42
+ { label: "Green", value: "green" },
43
+ { label: "Yellow", value: "yellow" },
44
+ { label: "Blue", value: "blue" },
45
+ { label: "Magenta", value: "magenta" },
46
+ { label: "Cyan", value: "cyan" },
47
+ { label: "White", value: "white" },
48
+ { label: "Bright Black", value: "brightBlack" },
49
+ { label: "Bright Red", value: "brightRed" },
50
+ { label: "Bright Green", value: "brightGreen" },
51
+ { label: "Bright Yellow", value: "brightYellow" },
52
+ { label: "Bright Blue", value: "brightBlue" },
53
+ { label: "Bright Magenta", value: "brightMagenta" },
54
+ { label: "Bright Cyan", value: "brightCyan" },
55
+ { label: "Bright White", value: "brightWhite" },
56
+ ];
57
+
58
+ const PI_THEME_COLORS: ThemeColor[] = [
59
+ "accent",
60
+ "border",
61
+ "borderAccent",
62
+ "borderMuted",
63
+ "success",
64
+ "error",
65
+ "warning",
66
+ "muted",
67
+ "dim",
68
+ "text",
69
+ "thinkingText",
70
+ "userMessageText",
71
+ "customMessageText",
72
+ "customMessageLabel",
73
+ "toolTitle",
74
+ "toolOutput",
75
+ "toolDiffAdded",
76
+ "toolDiffRemoved",
77
+ "toolDiffContext",
78
+ "syntaxType",
79
+ "thinkingOff",
80
+ "thinkingMinimal",
81
+ "thinkingLow",
82
+ "thinkingMedium",
83
+ "thinkingHigh",
84
+ "thinkingXhigh",
85
+ "bashMode",
86
+ ];
87
+
88
+ const PI_FOREGROUND_COLORS: ColorChoice[] = PI_THEME_COLORS.map((color) => ({
89
+ label: `Pi ${themeColorDisplayName(color)}`,
90
+ value: `pi:${color}`,
91
+ }));
92
+
93
+ export const FOREGROUND_COLORS: ColorChoice[] = [...STANDARD_COLORS, ...PI_FOREGROUND_COLORS];
94
+
95
+ const ANSI16_FG: Record<
96
+ Exclude<ColorName, `ansi256:${number}` | `pi:${ThemeColor}`>,
97
+ [number, number]
98
+ > = {
99
+ default: [39, 49],
100
+ black: [30, 40],
101
+ red: [31, 41],
102
+ green: [32, 42],
103
+ yellow: [33, 43],
104
+ blue: [34, 44],
105
+ magenta: [35, 45],
106
+ cyan: [36, 46],
107
+ white: [37, 47],
108
+ brightBlack: [90, 100],
109
+ brightRed: [91, 101],
110
+ brightGreen: [92, 102],
111
+ brightYellow: [93, 103],
112
+ brightBlue: [94, 104],
113
+ brightMagenta: [95, 105],
114
+ brightCyan: [96, 106],
115
+ brightWhite: [97, 107],
116
+ };
117
+
118
+ export function normalizeColor(value: unknown): ColorName | undefined {
119
+ if (typeof value !== "string") return undefined;
120
+ if (STANDARD_COLORS.some((color) => color.value === value)) return value as ColorName;
121
+ if (PI_FOREGROUND_COLORS.some((color) => color.value === value)) return value as ColorName;
122
+ const match = /^ansi256:([0-9]{1,3})$/.exec(value);
123
+ if (!match) return undefined;
124
+ const code = Number(match[1]);
125
+ return Number.isInteger(code) && code >= 0 && code <= 255
126
+ ? (`ansi256:${code}` as ColorName)
127
+ : undefined;
128
+ }
129
+
130
+ export function colorDisplayName(color: ColorName | undefined): string {
131
+ if (!color || color === "default") return "Default";
132
+ if (color.startsWith("ansi256:")) return `ANSI256 ${color.slice("ansi256:".length)}`;
133
+ if (color.startsWith("pi:"))
134
+ return PI_FOREGROUND_COLORS.find((entry) => entry.value === color)?.label ?? color;
135
+ return STANDARD_COLORS.find((entry) => entry.value === color)?.label ?? color;
136
+ }
137
+
138
+ export function ansi256Digits(color: ColorName | undefined): string {
139
+ return color?.startsWith("ansi256:") ? String(Number(color.slice("ansi256:".length))) : "0";
140
+ }
141
+
142
+ export function appendAnsi256Digit(color: ColorName | undefined, digit: string): ColorName {
143
+ const digits = ansi256Digits(color);
144
+ const next = Number(`${digits}${digit}`);
145
+ return `ansi256:${Math.min(255, next)}`;
146
+ }
147
+
148
+ export function deleteAnsi256Digit(color: ColorName | undefined): ColorName {
149
+ const digits = ansi256Digits(color) || "0";
150
+ const next = digits.slice(0, -1);
151
+ return `ansi256:${next === "" ? 0 : Number(next)}`;
152
+ }
153
+
154
+ function useColorLevel(level: ColorLevel) {
155
+ const next = level === "truecolor" ? 3 : level === "ansi256" ? 2 : 1;
156
+ if (chalk.level === next) return;
157
+ chalk.level = next;
158
+ chalk.c = new Chalk({ level: next });
159
+ }
160
+
161
+ export function applyColors(
162
+ text: string,
163
+ foreground: ColorName | undefined,
164
+ background: ColorName | undefined,
165
+ bold: boolean | undefined,
166
+ level: ColorLevel,
167
+ theme?: Theme,
168
+ ): string {
169
+ if (level === "none") return text;
170
+ useColorLevel(level);
171
+
172
+ let output = text;
173
+ if (foreground && foreground !== "default")
174
+ output = applyOne(output, foreground, false, level, theme);
175
+ if (background && background !== "default") output = applyOne(output, background, true, level);
176
+ if (bold) output = chalk.c.bold(output);
177
+ return output;
178
+ }
179
+
180
+ // The styleable color bag shared by widget options and the context conditional-color helper.
181
+ // fg/bg are validated ColorName (color picker); the warning/danger quartet is raw text input
182
+ // (kind: "text" properties) normalized via normalizeColor() at read time.
183
+ export interface ConditionalColorFields {
184
+ fg?: ColorName;
185
+ bg?: ColorName;
186
+ warningFg?: string;
187
+ warningBg?: string;
188
+ dangerFg?: string;
189
+ dangerBg?: string;
190
+ }
191
+
192
+ export function resetAnsi256Colors<T extends ConditionalColorFields>(options: T): T {
193
+ const next = { ...options };
194
+ if (next.fg?.startsWith("ansi256:")) next.fg = "default";
195
+ if (next.bg?.startsWith("ansi256:")) next.bg = "default";
196
+ if (next.warningFg?.startsWith("ansi256:")) next.warningFg = "default";
197
+ if (next.warningBg?.startsWith("ansi256:")) next.warningBg = "default";
198
+ if (next.dangerFg?.startsWith("ansi256:")) next.dangerFg = "default";
199
+ if (next.dangerBg?.startsWith("ansi256:")) next.dangerBg = "default";
200
+ return next;
201
+ }
202
+
203
+ function themeColorDisplayName(color: ThemeColor): string {
204
+ return color.replace(/([A-Z])/g, " $1").replace(/^./, (char) => char.toUpperCase());
205
+ }
206
+
207
+ function applyOne(
208
+ text: string,
209
+ color: ColorName,
210
+ background: boolean,
211
+ level: ColorLevel,
212
+ theme?: Theme,
213
+ ): string {
214
+ if (color.startsWith("pi:")) {
215
+ if (background || !theme) return text;
216
+ return theme.fg(color.slice("pi:".length) as ThemeColor, text);
217
+ }
218
+ if (color.startsWith("ansi256:")) {
219
+ const code = Number(color.slice("ansi256:".length));
220
+ if (level === "ansi256" || level === "truecolor") {
221
+ return background ? chalk.c.bgAnsi256(code)(text) : chalk.c.ansi256(code)(text);
222
+ }
223
+ return text;
224
+ }
225
+
226
+ const codes = ANSI16_FG[color as Exclude<ColorName, `ansi256:${number}` | `pi:${ThemeColor}`>];
227
+ if (!codes || color === "default") return text;
228
+ return `\x1b[${background ? codes[1] : codes[0]}m${text}\x1b[${background ? 49 : 39}m`;
229
+ }
230
+
231
+ // Keep the escape byte out of a regex literal so oxlint's no-control-regex rule does not
232
+ // flag the intentional ANSI matcher. RegExp still receives the ESC sequence at runtime.
233
+ const ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\x1B\[[0-?]*[ -/]*[@-~]`, "g");
234
+
235
+ export function stripAnsi(text: string): string {
236
+ return text.replace(ANSI_ESCAPE_PATTERN, "");
237
+ }
@@ -0,0 +1,202 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+
4
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
5
+
6
+ import type { ColorLevel } from "./colors.js";
7
+ import { COLOR_LEVEL_VALUES, normalizeColor } from "./colors.js";
8
+ import {
9
+ cloneExtensionStatusRow,
10
+ DEFAULT_EXTENSION_STATUS_ROW,
11
+ normalizeExtensionStatusRow,
12
+ } from "./extension-statuses.js";
13
+ import {
14
+ PRESET_DEFINITIONS,
15
+ type Preset,
16
+ type PresetDefinition,
17
+ type PresetWidget,
18
+ } from "./presets.js";
19
+ import { SEPARATOR_VALUES, type SeparatorStyle } from "./separators.js";
20
+ import type {
21
+ IconMode,
22
+ StatuslineConfig,
23
+ StatuslineSettings,
24
+ TerminalOptions,
25
+ TerminalWidthMode,
26
+ WidgetEntry,
27
+ } from "./types.js";
28
+ import { ICON_MODE_VALUES, isRecord, TERMINAL_WIDTH_MODE_VALUES } from "./types.js";
29
+ import { registry, type WidgetType } from "./widgets/registry.js";
30
+
31
+ export const STATUS_KEY = "pi-footer";
32
+
33
+ const CONFIG_ENV = "PI_FOOTER_CONFIG";
34
+ const DEFAULT_CONFIG_PATH = join(getAgentDir(), "extensions", "pi-footer.json");
35
+ const SEPARATORS = new Set<SeparatorStyle>(SEPARATOR_VALUES);
36
+
37
+ const DEFAULT_TERMINAL_OPTIONS: TerminalOptions = {
38
+ widthMode: "full",
39
+ colorLevel: "ansi256",
40
+ };
41
+
42
+ export const DEFAULT_CONFIG: StatuslineConfig = {
43
+ version: 1,
44
+ enabled: true,
45
+ preset: "default",
46
+ lines: linesForPreset("default"),
47
+ separator: "dot",
48
+ separatorFg: "default",
49
+ separatorBg: "default",
50
+ iconMode: "emoji",
51
+ minimalist: false,
52
+ terminal: DEFAULT_TERMINAL_OPTIONS,
53
+ extensionStatusRow: DEFAULT_EXTENSION_STATUS_ROW,
54
+ };
55
+
56
+ export function getConfigPath(): string {
57
+ return process.env[CONFIG_ENV] ?? DEFAULT_CONFIG_PATH;
58
+ }
59
+
60
+ function linesForPreset(preset: Preset): WidgetEntry[][] {
61
+ return PRESET_DEFINITIONS[preset].lines.map((line) => widgetsFromPresetLine(line));
62
+ }
63
+
64
+ export function configWithPreset(config: StatuslineConfig, preset: Preset): StatuslineConfig {
65
+ const definition: PresetDefinition = PRESET_DEFINITIONS[preset];
66
+ return {
67
+ ...config,
68
+ preset,
69
+ lines: linesForPreset(preset),
70
+ separator: definition.separator ?? config.separator,
71
+ iconMode: definition.iconMode ?? config.iconMode,
72
+ terminal: { ...config.terminal, ...definition.terminal },
73
+ };
74
+ }
75
+
76
+ function widgetsFromPresetLine(line: readonly PresetWidget[]): WidgetEntry[] {
77
+ return line.map((widget) => registry.createEntry(widget.type, widget.options));
78
+ }
79
+
80
+ export function normalizeConfig(input: unknown): StatuslineConfig {
81
+ if (!isRecord(input)) return cloneConfig(DEFAULT_CONFIG);
82
+
83
+ const preset = isPreset(input.preset) ? input.preset : DEFAULT_CONFIG.preset;
84
+ const lines = normalizeLines(input.lines, preset);
85
+
86
+ return {
87
+ version: 1,
88
+ enabled: typeof input.enabled === "boolean" ? input.enabled : DEFAULT_CONFIG.enabled,
89
+ preset,
90
+ lines,
91
+ separator: isSeparatorStyle(input.separator)
92
+ ? input.separator
93
+ : (PRESET_DEFINITIONS[preset].separator ?? DEFAULT_CONFIG.separator),
94
+ separatorFg: normalizeColor(input.separatorFg) ?? DEFAULT_CONFIG.separatorFg,
95
+ separatorBg: normalizeColor(input.separatorBg) ?? DEFAULT_CONFIG.separatorBg,
96
+ iconMode: isIconMode(input.iconMode) ? input.iconMode : DEFAULT_CONFIG.iconMode,
97
+ minimalist:
98
+ typeof input.minimalist === "boolean" ? input.minimalist : DEFAULT_CONFIG.minimalist,
99
+ terminal: normalizeTerminalOptions(input.terminal, PRESET_DEFINITIONS[preset].terminal),
100
+ extensionStatusRow: normalizeExtensionStatusRow(input.extensionStatusRow),
101
+ };
102
+ }
103
+
104
+ export function cloneSettings(settings: StatuslineSettings): StatuslineSettings {
105
+ return {
106
+ ...settings,
107
+ terminal: { ...settings.terminal },
108
+ extensionStatusRow: cloneExtensionStatusRow(settings.extensionStatusRow),
109
+ };
110
+ }
111
+
112
+ export function cloneConfig(config: StatuslineConfig): StatuslineConfig {
113
+ return {
114
+ ...cloneSettings(config),
115
+ lines: config.lines.map((line) =>
116
+ line.map((widget) => ({ ...widget, options: { ...widget.options } })),
117
+ ),
118
+ };
119
+ }
120
+
121
+ export async function loadConfig(path = getConfigPath()): Promise<StatuslineConfig> {
122
+ try {
123
+ const raw = await readFile(path, "utf8");
124
+ return normalizeConfig(JSON.parse(raw));
125
+ } catch (error) {
126
+ if (isNodeError(error) && error.code === "ENOENT") {
127
+ return cloneConfig(DEFAULT_CONFIG);
128
+ }
129
+ throw error;
130
+ }
131
+ }
132
+
133
+ export async function saveConfig(config: StatuslineConfig, path = getConfigPath()): Promise<void> {
134
+ await mkdir(dirname(path), { recursive: true });
135
+ await writeFile(path, `${JSON.stringify(normalizeConfig(config), null, 2)}\n`, "utf8");
136
+ }
137
+
138
+ function normalizeLines(linesValue: unknown, preset: Preset): WidgetEntry[][] {
139
+ if (!Array.isArray(linesValue)) return linesForPreset(preset);
140
+ return linesValue.map((line) => normalizeWidgets(line));
141
+ }
142
+
143
+ function normalizeWidgets(value: unknown): WidgetEntry[] {
144
+ if (!Array.isArray(value)) return [];
145
+
146
+ const widgets: WidgetEntry[] = [];
147
+ for (const item of value) {
148
+ if (!isRecord(item) || typeof item.type !== "string") continue;
149
+ const spec = registry.maybeSpec(item.type);
150
+ if (!spec) continue;
151
+ widgets.push({
152
+ id:
153
+ typeof item.id === "string" && item.id.length > 0
154
+ ? item.id
155
+ : registry.createEntry(spec.type as WidgetType).id,
156
+ type: spec.type as WidgetType,
157
+ enabled: typeof item.enabled === "boolean" ? item.enabled : true,
158
+ options: registry.normalizeOptions(
159
+ spec.type as WidgetType,
160
+ isRecord(item.options) ? item.options : {},
161
+ ),
162
+ });
163
+ }
164
+
165
+ return widgets;
166
+ }
167
+
168
+ function normalizeTerminalOptions(
169
+ value: unknown,
170
+ defaults: Partial<TerminalOptions> = {},
171
+ ): TerminalOptions {
172
+ const base = { ...DEFAULT_TERMINAL_OPTIONS, ...defaults };
173
+ if (!isRecord(value)) return base;
174
+ return {
175
+ widthMode:
176
+ typeof value.widthMode === "string" &&
177
+ TERMINAL_WIDTH_MODE_VALUES.includes(value.widthMode as TerminalWidthMode)
178
+ ? (value.widthMode as TerminalWidthMode)
179
+ : base.widthMode,
180
+ colorLevel:
181
+ typeof value.colorLevel === "string" &&
182
+ COLOR_LEVEL_VALUES.includes(value.colorLevel as ColorLevel)
183
+ ? (value.colorLevel as ColorLevel)
184
+ : base.colorLevel,
185
+ };
186
+ }
187
+
188
+ export function isPreset(value: unknown): value is Preset {
189
+ return typeof value === "string" && Object.hasOwn(PRESET_DEFINITIONS, value);
190
+ }
191
+
192
+ function isSeparatorStyle(value: unknown): value is SeparatorStyle {
193
+ return typeof value === "string" && SEPARATORS.has(value as SeparatorStyle);
194
+ }
195
+
196
+ function isIconMode(value: unknown): value is IconMode {
197
+ return typeof value === "string" && ICON_MODE_VALUES.includes(value as IconMode);
198
+ }
199
+
200
+ function isNodeError(error: unknown): error is NodeJS.ErrnoException {
201
+ return error instanceof Error && "code" in error;
202
+ }
@@ -0,0 +1,41 @@
1
+ import { isRecord } from "./types.js";
2
+
3
+ export const UPDATE_EVENT_WIDGET_EVENT = "pi-footer:update-widget";
4
+
5
+ interface UpdateEventWidgetPayload {
6
+ widgetId: string;
7
+ value: string | null;
8
+ }
9
+
10
+ const EVENT_WIDGET_ID_PREFIX = "event_";
11
+
12
+ export function createEventWidgetId(): string {
13
+ return `${EVENT_WIDGET_ID_PREFIX}${Math.random().toString(36).slice(2, 10)}`;
14
+ }
15
+
16
+ export class EventWidgetValues {
17
+ private readonly valuesById = new Map<string, string>();
18
+
19
+ get values(): ReadonlyMap<string, string> {
20
+ return this.valuesById;
21
+ }
22
+
23
+ update(payload: unknown): boolean {
24
+ if (!isUpdatePayload(payload)) return false;
25
+ if (payload.value === null) {
26
+ return this.valuesById.delete(payload.widgetId);
27
+ }
28
+ const previous = this.valuesById.get(payload.widgetId);
29
+ this.valuesById.set(payload.widgetId, payload.value);
30
+ return previous !== payload.value;
31
+ }
32
+ }
33
+
34
+ function isUpdatePayload(value: unknown): value is UpdateEventWidgetPayload {
35
+ if (!isRecord(value)) return false;
36
+ return (
37
+ typeof value.widgetId === "string" &&
38
+ value.widgetId.length > 0 &&
39
+ (typeof value.value === "string" || value.value === null)
40
+ );
41
+ }
@@ -0,0 +1,102 @@
1
+ import { isRecord } from "./types.js";
2
+
3
+ export const EMPTY_STATUS_LABEL = "[Empty status]";
4
+
5
+ export interface ExtensionStatusRowConfig {
6
+ hiddenKeys: string[];
7
+ knownKeys: string[];
8
+ }
9
+
10
+ interface ExtensionStatusEntry {
11
+ key: string;
12
+ value: string;
13
+ published: boolean;
14
+ }
15
+
16
+ export type GetExtensionStatuses = () => ReadonlyMap<string, string>;
17
+
18
+ export const DEFAULT_EXTENSION_STATUS_ROW: ExtensionStatusRowConfig = {
19
+ hiddenKeys: [],
20
+ knownKeys: [],
21
+ };
22
+
23
+ export const EMPTY_EXTENSION_STATUSES: ReadonlyMap<string, string> = new Map<string, string>();
24
+
25
+ export function extensionStatusEntries(
26
+ statuses: ReadonlyMap<string, string>,
27
+ ownStatusKey: string,
28
+ ): ExtensionStatusEntry[] {
29
+ return [...statuses.entries()]
30
+ .filter(([key, value]) => key !== ownStatusKey && value.length > 0)
31
+ .sort(([left], [right]) => left.localeCompare(right))
32
+ .map(([key, value]) => ({ key, value, published: true }));
33
+ }
34
+
35
+ export function allExtensionStatusEntries(
36
+ statuses: ReadonlyMap<string, string>,
37
+ rowConfig: ExtensionStatusRowConfig,
38
+ ownStatusKey: string,
39
+ ): ExtensionStatusEntry[] {
40
+ const keys = new Set([...statuses.keys(), ...rowConfig.hiddenKeys, ...rowConfig.knownKeys]);
41
+ return [...keys]
42
+ .filter((key) => key.length > 0 && key !== ownStatusKey)
43
+ .sort((left, right) => left.localeCompare(right))
44
+ .map((key) => {
45
+ const value = statuses.get(key) ?? "";
46
+ return {
47
+ key,
48
+ value: value.length > 0 ? value : EMPTY_STATUS_LABEL,
49
+ published: value.length > 0,
50
+ };
51
+ });
52
+ }
53
+
54
+ export function visibleExtensionStatusRowEntries(
55
+ statuses: ReadonlyMap<string, string>,
56
+ hiddenKeys: readonly string[],
57
+ ownStatusKey: string,
58
+ ): ExtensionStatusEntry[] {
59
+ const hidden = new Set(hiddenKeys);
60
+ return extensionStatusEntries(statuses, ownStatusKey).filter((entry) => !hidden.has(entry.key));
61
+ }
62
+
63
+ export function toggleExtensionStatusRowKey(
64
+ rowConfig: ExtensionStatusRowConfig,
65
+ key: string,
66
+ ): ExtensionStatusRowConfig {
67
+ const hidden = new Set(rowConfig.hiddenKeys);
68
+ const known = new Set(rowConfig.knownKeys);
69
+ known.add(key);
70
+ if (hidden.has(key)) hidden.delete(key);
71
+ else hidden.add(key);
72
+ return {
73
+ hiddenKeys: sortedKeys(hidden),
74
+ knownKeys: sortedKeys(known),
75
+ };
76
+ }
77
+
78
+ export function normalizeExtensionStatusRow(value: unknown): ExtensionStatusRowConfig {
79
+ if (!isRecord(value)) return cloneExtensionStatusRow(DEFAULT_EXTENSION_STATUS_ROW);
80
+ return {
81
+ hiddenKeys: normalizeKeyList(value.hiddenKeys),
82
+ knownKeys: normalizeKeyList(value.knownKeys),
83
+ };
84
+ }
85
+
86
+ export function cloneExtensionStatusRow(value: ExtensionStatusRowConfig): ExtensionStatusRowConfig {
87
+ return {
88
+ hiddenKeys: [...value.hiddenKeys],
89
+ knownKeys: [...value.knownKeys],
90
+ };
91
+ }
92
+
93
+ function normalizeKeyList(value: unknown): string[] {
94
+ if (!Array.isArray(value)) return [];
95
+ return sortedKeys(
96
+ new Set(value.filter((key): key is string => typeof key === "string" && key.length > 0)),
97
+ );
98
+ }
99
+
100
+ function sortedKeys(keys: Iterable<string>): string[] {
101
+ return [...keys].sort((left, right) => left.localeCompare(right));
102
+ }