pi-ui-extend 0.1.1

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 (420) hide show
  1. package/README.md +307 -0
  2. package/bin/pix.mjs +219 -0
  3. package/dist/app/app.d.ts +96 -0
  4. package/dist/app/app.js +871 -0
  5. package/dist/app/blink-controller.d.ts +23 -0
  6. package/dist/app/blink-controller.js +82 -0
  7. package/dist/app/cli.d.ts +8 -0
  8. package/dist/app/cli.js +83 -0
  9. package/dist/app/clipboard.d.ts +1 -0
  10. package/dist/app/clipboard.js +24 -0
  11. package/dist/app/command-controller.d.ts +18 -0
  12. package/dist/app/command-controller.js +58 -0
  13. package/dist/app/command-host.d.ts +44 -0
  14. package/dist/app/command-host.js +1 -0
  15. package/dist/app/command-model-actions.d.ts +12 -0
  16. package/dist/app/command-model-actions.js +176 -0
  17. package/dist/app/command-navigation-actions.d.ts +19 -0
  18. package/dist/app/command-navigation-actions.js +267 -0
  19. package/dist/app/command-registry.d.ts +32 -0
  20. package/dist/app/command-registry.js +225 -0
  21. package/dist/app/command-runtime.d.ts +5 -0
  22. package/dist/app/command-runtime.js +32 -0
  23. package/dist/app/command-session-actions.d.ts +20 -0
  24. package/dist/app/command-session-actions.js +295 -0
  25. package/dist/app/constants.d.ts +52 -0
  26. package/dist/app/constants.js +103 -0
  27. package/dist/app/conversation-entry-renderer.d.ts +21 -0
  28. package/dist/app/conversation-entry-renderer.js +81 -0
  29. package/dist/app/conversation-shell-renderer.d.ts +5 -0
  30. package/dist/app/conversation-shell-renderer.js +43 -0
  31. package/dist/app/conversation-tool-renderer.d.ts +16 -0
  32. package/dist/app/conversation-tool-renderer.js +216 -0
  33. package/dist/app/conversation-viewport.d.ts +55 -0
  34. package/dist/app/conversation-viewport.js +252 -0
  35. package/dist/app/dcp-stats.d.ts +2 -0
  36. package/dist/app/dcp-stats.js +116 -0
  37. package/dist/app/editor-layout-renderer.d.ts +31 -0
  38. package/dist/app/editor-layout-renderer.js +211 -0
  39. package/dist/app/editor-panels.d.ts +4 -0
  40. package/dist/app/editor-panels.js +130 -0
  41. package/dist/app/extension-actions-controller.d.ts +22 -0
  42. package/dist/app/extension-actions-controller.js +60 -0
  43. package/dist/app/extension-event-bus.d.ts +3 -0
  44. package/dist/app/extension-event-bus.js +23 -0
  45. package/dist/app/extension-ui-controller.d.ts +57 -0
  46. package/dist/app/extension-ui-controller.js +532 -0
  47. package/dist/app/file-link-opener.d.ts +2 -0
  48. package/dist/app/file-link-opener.js +66 -0
  49. package/dist/app/file-links.d.ts +10 -0
  50. package/dist/app/file-links.js +117 -0
  51. package/dist/app/guards.d.ts +3 -0
  52. package/dist/app/guards.js +9 -0
  53. package/dist/app/icons.d.ts +37 -0
  54. package/dist/app/icons.js +97 -0
  55. package/dist/app/id.d.ts +1 -0
  56. package/dist/app/id.js +4 -0
  57. package/dist/app/image-click-targets.d.ts +5 -0
  58. package/dist/app/image-click-targets.js +32 -0
  59. package/dist/app/image-opener.d.ts +2 -0
  60. package/dist/app/image-opener.js +64 -0
  61. package/dist/app/input-action-controller.d.ts +47 -0
  62. package/dist/app/input-action-controller.js +209 -0
  63. package/dist/app/input-controller.d.ts +60 -0
  64. package/dist/app/input-controller.js +425 -0
  65. package/dist/app/input-paste-handler.d.ts +27 -0
  66. package/dist/app/input-paste-handler.js +146 -0
  67. package/dist/app/menu-items-controller.d.ts +32 -0
  68. package/dist/app/menu-items-controller.js +182 -0
  69. package/dist/app/message-content.d.ts +8 -0
  70. package/dist/app/message-content.js +115 -0
  71. package/dist/app/model-ref.d.ts +13 -0
  72. package/dist/app/model-ref.js +50 -0
  73. package/dist/app/model-usage-controller.d.ts +35 -0
  74. package/dist/app/model-usage-controller.js +99 -0
  75. package/dist/app/model-usage-status.d.ts +125 -0
  76. package/dist/app/model-usage-status.js +749 -0
  77. package/dist/app/mouse-controller.d.ts +182 -0
  78. package/dist/app/mouse-controller.js +968 -0
  79. package/dist/app/native-modifiers.d.ts +3 -0
  80. package/dist/app/native-modifiers.js +60 -0
  81. package/dist/app/nerd-font-controller.d.ts +11 -0
  82. package/dist/app/nerd-font-controller.js +90 -0
  83. package/dist/app/popup-action-controller.d.ts +44 -0
  84. package/dist/app/popup-action-controller.js +278 -0
  85. package/dist/app/popup-menu-controller.d.ts +183 -0
  86. package/dist/app/popup-menu-controller.js +1070 -0
  87. package/dist/app/prompt-enhancer-controller.d.ts +40 -0
  88. package/dist/app/prompt-enhancer-controller.js +215 -0
  89. package/dist/app/queued-message-controller.d.ts +62 -0
  90. package/dist/app/queued-message-controller.js +377 -0
  91. package/dist/app/render-controller.d.ts +41 -0
  92. package/dist/app/render-controller.js +378 -0
  93. package/dist/app/render-text.d.ts +19 -0
  94. package/dist/app/render-text.js +67 -0
  95. package/dist/app/request-history.d.ts +23 -0
  96. package/dist/app/request-history.js +131 -0
  97. package/dist/app/runtime.d.ts +39 -0
  98. package/dist/app/runtime.js +195 -0
  99. package/dist/app/screen-selection.d.ts +6 -0
  100. package/dist/app/screen-selection.js +9 -0
  101. package/dist/app/screen-styler.d.ts +34 -0
  102. package/dist/app/screen-styler.js +168 -0
  103. package/dist/app/scroll-controller.d.ts +51 -0
  104. package/dist/app/scroll-controller.js +207 -0
  105. package/dist/app/session-event-controller.d.ts +69 -0
  106. package/dist/app/session-event-controller.js +338 -0
  107. package/dist/app/session-history.d.ts +23 -0
  108. package/dist/app/session-history.js +164 -0
  109. package/dist/app/session-lifecycle-controller.d.ts +55 -0
  110. package/dist/app/session-lifecycle-controller.js +116 -0
  111. package/dist/app/session-search.d.ts +24 -0
  112. package/dist/app/session-search.js +215 -0
  113. package/dist/app/shell-command.d.ts +27 -0
  114. package/dist/app/shell-command.js +176 -0
  115. package/dist/app/shell-controller.d.ts +28 -0
  116. package/dist/app/shell-controller.js +124 -0
  117. package/dist/app/slash-commands.d.ts +6 -0
  118. package/dist/app/slash-commands.js +75 -0
  119. package/dist/app/startup-checks.d.ts +8 -0
  120. package/dist/app/startup-checks.js +59 -0
  121. package/dist/app/startup-info.d.ts +3 -0
  122. package/dist/app/startup-info.js +176 -0
  123. package/dist/app/status-controller.d.ts +35 -0
  124. package/dist/app/status-controller.js +105 -0
  125. package/dist/app/status-line-renderer.d.ts +68 -0
  126. package/dist/app/status-line-renderer.js +453 -0
  127. package/dist/app/subagents-files.d.ts +10 -0
  128. package/dist/app/subagents-files.js +193 -0
  129. package/dist/app/subagents-model.d.ts +23 -0
  130. package/dist/app/subagents-model.js +224 -0
  131. package/dist/app/subagents-widget-controller.d.ts +43 -0
  132. package/dist/app/subagents-widget-controller.js +311 -0
  133. package/dist/app/tab-line-renderer.d.ts +26 -0
  134. package/dist/app/tab-line-renderer.js +222 -0
  135. package/dist/app/tabs-controller.d.ts +100 -0
  136. package/dist/app/tabs-controller.js +885 -0
  137. package/dist/app/terminal-controller.d.ts +40 -0
  138. package/dist/app/terminal-controller.js +135 -0
  139. package/dist/app/terminal-edit-shortcuts.d.ts +23 -0
  140. package/dist/app/terminal-edit-shortcuts.js +138 -0
  141. package/dist/app/terminal-output-buffer.d.ts +20 -0
  142. package/dist/app/terminal-output-buffer.js +52 -0
  143. package/dist/app/toast-controller.d.ts +13 -0
  144. package/dist/app/toast-controller.js +40 -0
  145. package/dist/app/toast-renderer.d.ts +9 -0
  146. package/dist/app/toast-renderer.js +79 -0
  147. package/dist/app/todo-model.d.ts +22 -0
  148. package/dist/app/todo-model.js +179 -0
  149. package/dist/app/todo-widget-controller.d.ts +21 -0
  150. package/dist/app/todo-widget-controller.js +59 -0
  151. package/dist/app/tool-block-renderer.d.ts +26 -0
  152. package/dist/app/tool-block-renderer.js +439 -0
  153. package/dist/app/types.d.ts +550 -0
  154. package/dist/app/types.js +1 -0
  155. package/dist/app/update.d.ts +36 -0
  156. package/dist/app/update.js +315 -0
  157. package/dist/app/voice-controller.d.ts +52 -0
  158. package/dist/app/voice-controller.js +600 -0
  159. package/dist/app/workspace-actions-controller.d.ts +40 -0
  160. package/dist/app/workspace-actions-controller.js +215 -0
  161. package/dist/app/workspace-undo.d.ts +44 -0
  162. package/dist/app/workspace-undo.js +215 -0
  163. package/dist/config.d.ts +62 -0
  164. package/dist/config.js +527 -0
  165. package/dist/context-progress-bar.d.ts +17 -0
  166. package/dist/context-progress-bar.js +48 -0
  167. package/dist/default-pix-config.d.ts +1 -0
  168. package/dist/default-pix-config.js +375 -0
  169. package/dist/fuzzy.d.ts +23 -0
  170. package/dist/fuzzy.js +165 -0
  171. package/dist/input-editor-files.d.ts +15 -0
  172. package/dist/input-editor-files.js +62 -0
  173. package/dist/input-editor.d.ts +186 -0
  174. package/dist/input-editor.js +835 -0
  175. package/dist/main.d.ts +1 -0
  176. package/dist/main.js +12 -0
  177. package/dist/markdown-format.d.ts +22 -0
  178. package/dist/markdown-format.js +542 -0
  179. package/dist/sdk.d.ts +3 -0
  180. package/dist/sdk.js +1 -0
  181. package/dist/syntax-highlight.d.ts +22 -0
  182. package/dist/syntax-highlight.js +528 -0
  183. package/dist/terminal-width.d.ts +6 -0
  184. package/dist/terminal-width.js +245 -0
  185. package/dist/theme.d.ts +56 -0
  186. package/dist/theme.js +118 -0
  187. package/dist/tool-renderers/apply-patch.d.ts +2 -0
  188. package/dist/tool-renderers/apply-patch.js +36 -0
  189. package/dist/tool-renderers/ast.d.ts +2 -0
  190. package/dist/tool-renderers/ast.js +5 -0
  191. package/dist/tool-renderers/compress.d.ts +2 -0
  192. package/dist/tool-renderers/compress.js +126 -0
  193. package/dist/tool-renderers/index.d.ts +3 -0
  194. package/dist/tool-renderers/index.js +44 -0
  195. package/dist/tool-renderers/question.d.ts +2 -0
  196. package/dist/tool-renderers/question.js +88 -0
  197. package/dist/tool-renderers/read.d.ts +2 -0
  198. package/dist/tool-renderers/read.js +36 -0
  199. package/dist/tool-renderers/repo.d.ts +2 -0
  200. package/dist/tool-renderers/repo.js +13 -0
  201. package/dist/tool-renderers/shell.d.ts +3 -0
  202. package/dist/tool-renderers/shell.js +27 -0
  203. package/dist/tool-renderers/skill.d.ts +2 -0
  204. package/dist/tool-renderers/skill.js +132 -0
  205. package/dist/tool-renderers/subagents.d.ts +2 -0
  206. package/dist/tool-renderers/subagents.js +51 -0
  207. package/dist/tool-renderers/todo.d.ts +2 -0
  208. package/dist/tool-renderers/todo.js +9 -0
  209. package/dist/tool-renderers/types.d.ts +42 -0
  210. package/dist/tool-renderers/types.js +1 -0
  211. package/dist/tool-renderers/utils.d.ts +31 -0
  212. package/dist/tool-renderers/utils.js +230 -0
  213. package/dist/tool-renderers/web.d.ts +3 -0
  214. package/dist/tool-renderers/web.js +9 -0
  215. package/dist/tool-renderers/write.d.ts +2 -0
  216. package/dist/tool-renderers/write.js +42 -0
  217. package/dist/ui.d.ts +56 -0
  218. package/dist/ui.js +94 -0
  219. package/docs/release.md +81 -0
  220. package/extensions/question/contract.ts +100 -0
  221. package/extensions/question/index.ts +34 -0
  222. package/extensions/question/render.ts +28 -0
  223. package/extensions/question/result.ts +86 -0
  224. package/extensions/question/tool-description.ts +11 -0
  225. package/extensions/question/tui.ts +629 -0
  226. package/extensions/question/types.ts +123 -0
  227. package/extensions/session-title/config.ts +169 -0
  228. package/extensions/session-title/index.ts +459 -0
  229. package/extensions/terminal-bell/index.ts +315 -0
  230. package/external/pi-tools-suite/README.md +242 -0
  231. package/external/pi-tools-suite/index.ts +1 -0
  232. package/external/pi-tools-suite/licenses/ollama-pi-web-search.MIT +21 -0
  233. package/external/pi-tools-suite/licenses/opencode-mystatus-MIT.txt +21 -0
  234. package/external/pi-tools-suite/package.json +53 -0
  235. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +194 -0
  236. package/external/pi-tools-suite/src/antigravity-auth/commands.ts +80 -0
  237. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +26 -0
  238. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +20 -0
  239. package/external/pi-tools-suite/src/antigravity-auth/index.ts +104 -0
  240. package/external/pi-tools-suite/src/antigravity-auth/models.ts +86 -0
  241. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +305 -0
  242. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +423 -0
  243. package/external/pi-tools-suite/src/antigravity-auth/status.ts +78 -0
  244. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +302 -0
  245. package/external/pi-tools-suite/src/antigravity-auth/types.ts +113 -0
  246. package/external/pi-tools-suite/src/ast-grep/index.ts +6 -0
  247. package/external/pi-tools-suite/src/ast-grep/render.ts +70 -0
  248. package/external/pi-tools-suite/src/ast-grep/schema.ts +109 -0
  249. package/external/pi-tools-suite/src/ast-grep/tool.ts +345 -0
  250. package/external/pi-tools-suite/src/ast-grep/types.ts +55 -0
  251. package/external/pi-tools-suite/src/ast-grep/utils.ts +65 -0
  252. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +222 -0
  253. package/external/pi-tools-suite/src/async-subagents/commands.ts +518 -0
  254. package/external/pi-tools-suite/src/async-subagents/constants.ts +11 -0
  255. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +74 -0
  256. package/external/pi-tools-suite/src/async-subagents/core/attachment-bridge.ts +133 -0
  257. package/external/pi-tools-suite/src/async-subagents/core/cleanup.ts +66 -0
  258. package/external/pi-tools-suite/src/async-subagents/core/concurrency.ts +90 -0
  259. package/external/pi-tools-suite/src/async-subagents/core/config.ts +819 -0
  260. package/external/pi-tools-suite/src/async-subagents/core/log-limits.ts +166 -0
  261. package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +133 -0
  262. package/external/pi-tools-suite/src/async-subagents/core/paths.ts +47 -0
  263. package/external/pi-tools-suite/src/async-subagents/core/pi-invocation.ts +35 -0
  264. package/external/pi-tools-suite/src/async-subagents/core/presets.ts +67 -0
  265. package/external/pi-tools-suite/src/async-subagents/core/process.ts +15 -0
  266. package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +66 -0
  267. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +224 -0
  268. package/external/pi-tools-suite/src/async-subagents/core/retry.ts +191 -0
  269. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +259 -0
  270. package/external/pi-tools-suite/src/async-subagents/core/sessions.ts +138 -0
  271. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +688 -0
  272. package/external/pi-tools-suite/src/async-subagents/core/state.ts +281 -0
  273. package/external/pi-tools-suite/src/async-subagents/core/stop.ts +131 -0
  274. package/external/pi-tools-suite/src/async-subagents/core/structured-result.ts +237 -0
  275. package/external/pi-tools-suite/src/async-subagents/core/tool-guard.ts +34 -0
  276. package/external/pi-tools-suite/src/async-subagents/core/types.ts +150 -0
  277. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +184 -0
  278. package/external/pi-tools-suite/src/async-subagents/core/utils.ts +11 -0
  279. package/external/pi-tools-suite/src/async-subagents/format.ts +41 -0
  280. package/external/pi-tools-suite/src/async-subagents/index.ts +422 -0
  281. package/external/pi-tools-suite/src/async-subagents/lib.ts +88 -0
  282. package/external/pi-tools-suite/src/async-subagents/live.ts +10 -0
  283. package/external/pi-tools-suite/src/async-subagents/polling.ts +83 -0
  284. package/external/pi-tools-suite/src/async-subagents/render.ts +230 -0
  285. package/external/pi-tools-suite/src/async-subagents/subagent-overlay.ts +77 -0
  286. package/external/pi-tools-suite/src/async-subagents/tasks.ts +120 -0
  287. package/external/pi-tools-suite/src/async-subagents/tools/cleanup.ts +99 -0
  288. package/external/pi-tools-suite/src/async-subagents/tools/result.ts +179 -0
  289. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +372 -0
  290. package/external/pi-tools-suite/src/async-subagents/tools/status.ts +60 -0
  291. package/external/pi-tools-suite/src/async-subagents/tools/stop.ts +79 -0
  292. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +152 -0
  293. package/external/pi-tools-suite/src/async-subagents/tools/wait.ts +67 -0
  294. package/external/pi-tools-suite/src/async-subagents/types.ts +45 -0
  295. package/external/pi-tools-suite/src/async-subagents/ui.ts +5 -0
  296. package/external/pi-tools-suite/src/compress/commands.ts +440 -0
  297. package/external/pi-tools-suite/src/compress/compress-tool.ts +368 -0
  298. package/external/pi-tools-suite/src/compress/compression-blocks.ts +524 -0
  299. package/external/pi-tools-suite/src/compress/config.ts +310 -0
  300. package/external/pi-tools-suite/src/compress/dcp-tui-filter.ts +498 -0
  301. package/external/pi-tools-suite/src/compress/index.ts +397 -0
  302. package/external/pi-tools-suite/src/compress/prompts.ts +269 -0
  303. package/external/pi-tools-suite/src/compress/pruner-candidates.ts +176 -0
  304. package/external/pi-tools-suite/src/compress/pruner-compression-blocks.ts +260 -0
  305. package/external/pi-tools-suite/src/compress/pruner-message-ids.ts +147 -0
  306. package/external/pi-tools-suite/src/compress/pruner-metadata.ts +268 -0
  307. package/external/pi-tools-suite/src/compress/pruner-nudge.ts +315 -0
  308. package/external/pi-tools-suite/src/compress/pruner-tools.ts +263 -0
  309. package/external/pi-tools-suite/src/compress/pruner-types.ts +25 -0
  310. package/external/pi-tools-suite/src/compress/pruner.ts +92 -0
  311. package/external/pi-tools-suite/src/compress/state.ts +486 -0
  312. package/external/pi-tools-suite/src/compress/ui.ts +308 -0
  313. package/external/pi-tools-suite/src/config.ts +176 -0
  314. package/external/pi-tools-suite/src/context-usage.ts +31 -0
  315. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +355 -0
  316. package/external/pi-tools-suite/src/index.ts +46 -0
  317. package/external/pi-tools-suite/src/lib/lsp.ts +62 -0
  318. package/external/pi-tools-suite/src/lib/project.ts +42 -0
  319. package/external/pi-tools-suite/src/lib/tool-args.ts +137 -0
  320. package/external/pi-tools-suite/src/lsp/_shared/config.ts +156 -0
  321. package/external/pi-tools-suite/src/lsp/_shared/glob.ts +60 -0
  322. package/external/pi-tools-suite/src/lsp/_shared/output.ts +102 -0
  323. package/external/pi-tools-suite/src/lsp/_shared/paths.ts +138 -0
  324. package/external/pi-tools-suite/src/lsp/_shared/runner.ts +64 -0
  325. package/external/pi-tools-suite/src/lsp/_shared/template.ts +23 -0
  326. package/external/pi-tools-suite/src/lsp/_shared/trust.ts +116 -0
  327. package/external/pi-tools-suite/src/lsp/_shared/types.ts +98 -0
  328. package/external/pi-tools-suite/src/lsp/async.ts +29 -0
  329. package/external/pi-tools-suite/src/lsp/child-process.ts +81 -0
  330. package/external/pi-tools-suite/src/lsp/client.ts +340 -0
  331. package/external/pi-tools-suite/src/lsp/constants.ts +9 -0
  332. package/external/pi-tools-suite/src/lsp/diagnostics-store.ts +64 -0
  333. package/external/pi-tools-suite/src/lsp/documents.ts +24 -0
  334. package/external/pi-tools-suite/src/lsp/index.ts +31 -0
  335. package/external/pi-tools-suite/src/lsp/lsp-utils.ts +37 -0
  336. package/external/pi-tools-suite/src/lsp/manager.ts +190 -0
  337. package/external/pi-tools-suite/src/lsp/mutation-events.ts +78 -0
  338. package/external/pi-tools-suite/src/lsp/renderer.ts +1 -0
  339. package/external/pi-tools-suite/src/lsp/tool-result.ts +6 -0
  340. package/external/pi-tools-suite/src/lsp/tsserver.ts +107 -0
  341. package/external/pi-tools-suite/src/lsp/types.ts +15 -0
  342. package/external/pi-tools-suite/src/model-tools/apply-patch.ts +590 -0
  343. package/external/pi-tools-suite/src/model-tools/index.ts +430 -0
  344. package/external/pi-tools-suite/src/model-tools/path-utils.ts +6 -0
  345. package/external/pi-tools-suite/src/model-tools/tool-args.ts +11 -0
  346. package/external/pi-tools-suite/src/prompt-commands/index.ts +349 -0
  347. package/external/pi-tools-suite/src/repo-discovery/index.ts +384 -0
  348. package/external/pi-tools-suite/src/repo-discovery/project.ts +7 -0
  349. package/external/pi-tools-suite/src/startup-section.ts +13 -0
  350. package/external/pi-tools-suite/src/terminal-bell/index.ts +309 -0
  351. package/external/pi-tools-suite/src/todo/index.ts +201 -0
  352. package/external/pi-tools-suite/src/todo/state/auto-clear.ts +13 -0
  353. package/external/pi-tools-suite/src/todo/state/invariants.ts +21 -0
  354. package/external/pi-tools-suite/src/todo/state/persistence.ts +94 -0
  355. package/external/pi-tools-suite/src/todo/state/replay.ts +38 -0
  356. package/external/pi-tools-suite/src/todo/state/selectors.ts +49 -0
  357. package/external/pi-tools-suite/src/todo/state/state-reducer.ts +362 -0
  358. package/external/pi-tools-suite/src/todo/state/state.ts +18 -0
  359. package/external/pi-tools-suite/src/todo/state/store.ts +52 -0
  360. package/external/pi-tools-suite/src/todo/state/task-graph.ts +57 -0
  361. package/external/pi-tools-suite/src/todo/todo.ts +487 -0
  362. package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +143 -0
  363. package/external/pi-tools-suite/src/todo/tool/types.ts +188 -0
  364. package/external/pi-tools-suite/src/todo/view/format.ts +18 -0
  365. package/external/pi-tools-suite/src/todo/view/labels.ts +13 -0
  366. package/external/pi-tools-suite/src/tool-descriptions.ts +369 -0
  367. package/external/pi-tools-suite/src/usage/index.ts +152 -0
  368. package/external/pi-tools-suite/src/usage/lib/copilot.ts +535 -0
  369. package/external/pi-tools-suite/src/usage/lib/google.ts +478 -0
  370. package/external/pi-tools-suite/src/usage/lib/openai.ts +268 -0
  371. package/external/pi-tools-suite/src/usage/lib/types.ts +114 -0
  372. package/external/pi-tools-suite/src/usage/lib/utils.ts +134 -0
  373. package/external/pi-tools-suite/src/usage/lib/zhipu.ts +228 -0
  374. package/external/pi-tools-suite/src/web-search/index.ts +397 -0
  375. package/package.json +89 -0
  376. package/skills/context7/SKILL.md +69 -0
  377. package/skills/context7/scripts/context7.sh +73 -0
  378. package/skills/handoff/SKILL.md +15 -0
  379. package/skills/pdf/LICENSE.txt +30 -0
  380. package/skills/pdf/SKILL.md +314 -0
  381. package/skills/pdf/forms.md +294 -0
  382. package/skills/pdf/reference.md +612 -0
  383. package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
  384. package/skills/pdf/scripts/check_fillable_fields.py +11 -0
  385. package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  386. package/skills/pdf/scripts/create_validation_image.py +37 -0
  387. package/skills/pdf/scripts/extract_form_field_info.py +122 -0
  388. package/skills/pdf/scripts/extract_form_structure.py +115 -0
  389. package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
  390. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  391. package/skills/playwright-cli/SKILL.md +388 -0
  392. package/skills/playwright-cli/references/element-attributes.md +23 -0
  393. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  394. package/skills/playwright-cli/references/request-mocking.md +87 -0
  395. package/skills/playwright-cli/references/running-code.md +241 -0
  396. package/skills/playwright-cli/references/session-management.md +225 -0
  397. package/skills/playwright-cli/references/spec-driven-testing.md +305 -0
  398. package/skills/playwright-cli/references/storage-state.md +275 -0
  399. package/skills/playwright-cli/references/test-generation.md +134 -0
  400. package/skills/playwright-cli/references/tracing.md +139 -0
  401. package/skills/playwright-cli/references/video-recording.md +143 -0
  402. package/skills/simplify/SKILL.md +51 -0
  403. package/skills/skill-creator/LICENSE.txt +202 -0
  404. package/skills/skill-creator/SKILL.md +485 -0
  405. package/skills/skill-creator/agents/analyzer.md +274 -0
  406. package/skills/skill-creator/agents/comparator.md +202 -0
  407. package/skills/skill-creator/agents/grader.md +223 -0
  408. package/skills/skill-creator/assets/eval_review.html +146 -0
  409. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  410. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  411. package/skills/skill-creator/references/schemas.md +430 -0
  412. package/skills/skill-creator/scripts/__init__.py +0 -0
  413. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  414. package/skills/skill-creator/scripts/generate_report.py +326 -0
  415. package/skills/skill-creator/scripts/improve_description.py +247 -0
  416. package/skills/skill-creator/scripts/package_skill.py +136 -0
  417. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  418. package/skills/skill-creator/scripts/run_eval.py +310 -0
  419. package/skills/skill-creator/scripts/run_loop.py +328 -0
  420. package/skills/skill-creator/scripts/utils.py +47 -0
@@ -0,0 +1,176 @@
1
+ import type { DcpConfig } from "./config.js";
2
+ import type { DcpState } from "./state.js";
3
+ import type { CompressionCandidate, MessageCompressionCandidate } from "./pruner-types.js";
4
+ import {
5
+ estimateMessageTokens,
6
+ extractBlockId,
7
+ extractMessageId,
8
+ messageText,
9
+ } from "./pruner-metadata.js";
10
+
11
+ interface CandidateBoundary {
12
+ id: string;
13
+ role: string;
14
+ timestamp: number;
15
+ tokenEstimate: number;
16
+ blockId?: number;
17
+ isSystemReminder: boolean;
18
+ }
19
+
20
+ export function detectCompressionCandidate(
21
+ messages: any[],
22
+ _state: DcpState,
23
+ config: DcpConfig,
24
+ contextPercent: number,
25
+ ): CompressionCandidate | null {
26
+ const settings = config.compress.autoCandidates;
27
+ if (!settings.enabled) return null;
28
+ if (contextPercent < settings.minContextPercent) return null;
29
+
30
+ const boundaries: CandidateBoundary[] = [];
31
+ for (const msg of messages) {
32
+ const text = messageText(msg);
33
+ const blockId = extractBlockId(text);
34
+ const messageId = extractMessageId(text);
35
+ const id = blockId !== undefined ? `b${blockId}` : messageId;
36
+ if (!id) continue;
37
+ if (!Number.isFinite(msg.timestamp)) continue;
38
+ boundaries.push({
39
+ id,
40
+ role: msg.role ?? "",
41
+ timestamp: msg.timestamp,
42
+ tokenEstimate: estimateMessageTokens(msg),
43
+ blockId,
44
+ isSystemReminder: text.includes("<dcp-system-reminder>"),
45
+ });
46
+ }
47
+
48
+ if (boundaries.length < settings.minMessages) return null;
49
+
50
+ const keepRecentTurns = Math.max(1, settings.keepRecentTurns);
51
+ let recentUserTurns = 0;
52
+ let cutoffIndex = -1;
53
+
54
+ for (let i = boundaries.length - 1; i >= 0; i--) {
55
+ const boundary = boundaries[i]!;
56
+ const isRealUserMessage =
57
+ boundary.role === "user" && boundary.blockId === undefined && !boundary.isSystemReminder;
58
+ if (!isRealUserMessage) continue;
59
+ recentUserTurns++;
60
+ if (recentUserTurns >= keepRecentTurns) {
61
+ cutoffIndex = i - 1;
62
+ break;
63
+ }
64
+ }
65
+
66
+ if (cutoffIndex < 0) return null;
67
+
68
+ let candidate = boundaries.slice(0, cutoffIndex + 1);
69
+ while (candidate.length > 0 && candidate[0]!.isSystemReminder) candidate = candidate.slice(1);
70
+ while (candidate.length > 0 && candidate[candidate.length - 1]!.isSystemReminder) {
71
+ candidate = candidate.slice(0, -1);
72
+ }
73
+
74
+ if (candidate.length < settings.minMessages) return null;
75
+
76
+ const estimatedTokens = candidate.reduce((sum, item) => sum + item.tokenEstimate, 0);
77
+ if (estimatedTokens < settings.minTokens) return null;
78
+
79
+ const includedBlockIds = Array.from(
80
+ new Set(candidate.map((item) => item.blockId).filter((id): id is number => id !== undefined)),
81
+ );
82
+
83
+ return {
84
+ startId: candidate[0]!.id,
85
+ endId: candidate[candidate.length - 1]!.id,
86
+ messageCount: candidate.length,
87
+ estimatedTokens,
88
+ includedBlockIds,
89
+ reason: `older than the most recent ${keepRecentTurns} user turn(s)`,
90
+ };
91
+ }
92
+
93
+ export function formatCompressionCandidateHint(candidate: CompressionCandidate): string {
94
+ const blockHint = candidate.includedBlockIds.length > 0
95
+ ? `\nThis candidate includes compressed block(s): ${candidate.includedBlockIds
96
+ .map((id) => `b${id}`)
97
+ .join(", ")}. If you compress this range, include each required \`(bN)\` placeholder exactly once in the summary.`
98
+ : "";
99
+
100
+ return `\n\nSuggested compression candidate: ${candidate.startId}..${candidate.endId} (${candidate.messageCount} messages, ~${candidate.estimatedTokens} tokens, ${candidate.reason}).${blockHint}`;
101
+ }
102
+
103
+ export function detectMessageCompressionCandidates(
104
+ messages: any[],
105
+ config: DcpConfig,
106
+ contextPercent: number,
107
+ ): MessageCompressionCandidate[] {
108
+ const settings = config.compress.messageMode;
109
+ if (!settings?.enabled) return [];
110
+ if (contextPercent < settings.minContextPercent) return [];
111
+
112
+ const boundaries: CandidateBoundary[] = [];
113
+ for (const msg of messages) {
114
+ const text = messageText(msg);
115
+ const blockId = extractBlockId(text);
116
+ const messageId = extractMessageId(text);
117
+ if (!messageId || blockId !== undefined) continue;
118
+ if (!Number.isFinite(msg.timestamp)) continue;
119
+ boundaries.push({
120
+ id: messageId,
121
+ role: msg.role ?? "",
122
+ timestamp: msg.timestamp,
123
+ tokenEstimate: estimateMessageTokens(msg),
124
+ blockId,
125
+ isSystemReminder: text.includes("<dcp-system-reminder>"),
126
+ });
127
+ }
128
+
129
+ const keepRecentTurns = Math.max(1, settings.keepRecentTurns ?? 2);
130
+ let recentUserTurns = 0;
131
+ let cutoffIndex = boundaries.length - 1;
132
+
133
+ for (let i = boundaries.length - 1; i >= 0; i--) {
134
+ const boundary = boundaries[i]!;
135
+ const isRealUserMessage = boundary.role === "user" && !boundary.isSystemReminder;
136
+ if (!isRealUserMessage) continue;
137
+ recentUserTurns++;
138
+ if (recentUserTurns >= keepRecentTurns) {
139
+ cutoffIndex = i - 1;
140
+ break;
141
+ }
142
+ }
143
+
144
+ if (cutoffIndex < 0) return [];
145
+
146
+ const mediumTokens = Math.max(1, settings.mediumTokens ?? 500);
147
+ const highTokens = Math.max(mediumTokens, settings.highTokens ?? 5000);
148
+ const maxSuggestions = Math.max(1, settings.maxSuggestions ?? 5);
149
+
150
+ return boundaries
151
+ .slice(0, cutoffIndex + 1)
152
+ .filter((candidate) => !candidate.isSystemReminder)
153
+ .filter((candidate) => candidate.role !== "user" || !config.compress.protectUserMessages)
154
+ .filter((candidate) => candidate.tokenEstimate >= mediumTokens)
155
+ .map((candidate): MessageCompressionCandidate => ({
156
+ messageId: candidate.id,
157
+ role: candidate.role,
158
+ estimatedTokens: candidate.tokenEstimate,
159
+ priority: candidate.tokenEstimate >= highTokens ? "high" : "medium",
160
+ reason: `older than the most recent ${keepRecentTurns} user turn(s)`,
161
+ }))
162
+ .sort((a, b) => {
163
+ const priorityDiff = (b.priority === "high" ? 1 : 0) - (a.priority === "high" ? 1 : 0);
164
+ if (priorityDiff !== 0) return priorityDiff;
165
+ return b.estimatedTokens - a.estimatedTokens;
166
+ })
167
+ .slice(0, maxSuggestions);
168
+ }
169
+
170
+ export function formatMessageCompressionCandidateHint(candidates: MessageCompressionCandidate[]): string {
171
+ if (candidates.length === 0) return "";
172
+ const entries = candidates
173
+ .map((candidate) => `${candidate.messageId} (${candidate.priority}, ${candidate.role}, ~${candidate.estimatedTokens} tokens)`)
174
+ .join(", ");
175
+ return `\n\nSuggested individual message compression candidates: ${entries}. To compress individual messages, call \`compress\` with a \`messages\` array: { messageId, topic, summary }. Use this for large stale messages when a full range would be too broad.`;
176
+ }
@@ -0,0 +1,260 @@
1
+ import type { DcpState } from "./state.js";
2
+ import { PASSTHROUGH_ROLES, estimateMessageTokens } from "./pruner-metadata.js";
3
+ import { stableMessageId } from "./pruner-message-ids.js";
4
+
5
+ function messageMatchesBoundary(msg: any, messageIndex: number, stableId: string | undefined, timestamp: number): boolean {
6
+ if (stableId && stableMessageId(msg, messageIndex) === stableId) return true;
7
+ return msg.timestamp === timestamp;
8
+ }
9
+
10
+ function findBoundaryIndex(messages: any[], stableId: string | undefined, timestamp: number): number {
11
+ return messages.findIndex((m, index) => messageMatchesBoundary(m, index, stableId, timestamp));
12
+ }
13
+
14
+ function collectToolCallIds(messages: any[]): Set<string> {
15
+ const ids = new Set<string>();
16
+ for (const msg of messages) {
17
+ if (typeof msg?.toolCallId === "string") ids.add(msg.toolCallId);
18
+ if (msg?.role !== "assistant" || !Array.isArray(msg.content)) continue;
19
+ for (const block of msg.content) {
20
+ if (block?.type === "toolCall" && typeof block.id === "string") ids.add(block.id);
21
+ }
22
+ }
23
+ return ids;
24
+ }
25
+
26
+ export function syncCompressionBlocks(messages: any[], state: DcpState): void {
27
+ if (state.compressionBlocks.length === 0) return;
28
+
29
+ const toolCallIds = collectToolCallIds(messages);
30
+
31
+ for (const block of state.compressionBlocks) {
32
+ if (!block.active || block.deactivatedByUser) continue;
33
+
34
+ if (
35
+ typeof block.createdByToolCallId === "string" &&
36
+ state.toolCalls.has(block.createdByToolCallId) &&
37
+ !toolCallIds.has(block.createdByToolCallId)
38
+ ) {
39
+ block.active = false;
40
+ block.deactivatedReason = "missing-origin-compress-call";
41
+ continue;
42
+ }
43
+
44
+ const hasStableBoundaries = !!block.startMessageId && !!block.endMessageId;
45
+ if (!hasStableBoundaries) continue;
46
+
47
+ const startIdx = findBoundaryIndex(messages, block.startMessageId, block.startTimestamp);
48
+ const endIdx = findBoundaryIndex(messages, block.endMessageId, block.endTimestamp);
49
+ if (startIdx === -1 || endIdx === -1) {
50
+ block.active = false;
51
+ block.deactivatedReason = "missing-origin-message";
52
+ }
53
+ }
54
+ }
55
+
56
+ export function applyCompressionBlocks(messages: any[], state: DcpState): any[] {
57
+ const activeBlocks = state.compressionBlocks
58
+ .filter((b) => b.active)
59
+ .sort((a, b) => a.startTimestamp - b.startTimestamp);
60
+ if (activeBlocks.length === 0) return messages;
61
+
62
+ for (const block of activeBlocks) {
63
+ // Skip blocks with corrupted timestamps (from pre-fix sessions)
64
+ if (!Number.isFinite(block.startTimestamp) || !Number.isFinite(block.endTimestamp)) continue;
65
+
66
+ // Find start and end indices by timestamp
67
+ const startIdx = findBoundaryIndex(messages, block.startMessageId, block.startTimestamp);
68
+ const endIdx = findBoundaryIndex(messages, block.endMessageId, block.endTimestamp);
69
+
70
+ if (startIdx === -1 || endIdx === -1) continue;
71
+
72
+ let lo = Math.min(startIdx, endIdx);
73
+ let hi = Math.max(startIdx, endIdx);
74
+
75
+ // Expand lo backward: if there is an assistant before lo whose tool_use
76
+ // blocks have matching tool_results inside [lo..hi], pull the entire
77
+ // assistant + any intermediate result messages into the range so the
78
+ // group is always removed atomically.
79
+ //
80
+ // Critically we must skip backward past any toolResult / bashExecution
81
+ // messages before lo, because an assistant with multiple tool_calls emits
82
+ // N consecutive result messages — the assistant itself sits further back.
83
+ while (lo > 0) {
84
+ // Walk backward past tool-result messages to find the preceding assistant
85
+ let scanIdx = lo - 1;
86
+ while (scanIdx >= 0) {
87
+ const r = (messages[scanIdx] as any).role as string;
88
+ if (r !== "toolResult" && r !== "bashExecution" && !PASSTHROUGH_ROLES.has(r)) break;
89
+ scanIdx--;
90
+ }
91
+ if (scanIdx < 0 || (messages[scanIdx] as any).role !== "assistant") break;
92
+
93
+ const prev = messages[scanIdx] as any;
94
+ const toolCallIdsInRange = new Set<string>();
95
+ for (let i = lo; i <= hi; i++) {
96
+ const m = messages[i] as any;
97
+ if (
98
+ (m.role === "toolResult" || m.role === "bashExecution") &&
99
+ typeof m.toolCallId === "string"
100
+ ) {
101
+ toolCallIdsInRange.add(m.toolCallId);
102
+ }
103
+ }
104
+ const prevContent: any[] = Array.isArray(prev.content) ? prev.content : [];
105
+ const hasMatchingToolCalls = prevContent.some(
106
+ (contentBlock: any) => contentBlock.type === "toolCall" && toolCallIdsInRange.has(contentBlock.id),
107
+ );
108
+ if (!hasMatchingToolCalls) break;
109
+ // Pull assistant + all intermediate result messages into the range
110
+ lo = scanIdx;
111
+ }
112
+
113
+ // Expand hi forward: for every assistant message in [lo..hi] that has
114
+ // tool_use blocks, include any immediately-following tool_result messages
115
+ // that correspond to those blocks. Loop to fixed point because expanding
116
+ // hi could expose more assistants in theory.
117
+ let prevHi: number;
118
+ do {
119
+ prevHi = hi;
120
+ const assistantToolCallIds = new Set<string>();
121
+ for (let i = lo; i <= hi; i++) {
122
+ const m = messages[i] as any;
123
+ if (m.role !== "assistant") continue;
124
+ const content: any[] = Array.isArray(m.content) ? m.content : [];
125
+ for (const contentBlock of content) {
126
+ if (contentBlock.type === "toolCall" && typeof contentBlock.id === "string") {
127
+ assistantToolCallIds.add(contentBlock.id);
128
+ }
129
+ }
130
+ }
131
+ while (hi + 1 < messages.length) {
132
+ const next = messages[hi + 1] as any;
133
+ if (
134
+ (next.role === "toolResult" || next.role === "bashExecution") &&
135
+ assistantToolCallIds.has(next.toolCallId)
136
+ ) {
137
+ hi++;
138
+ } else if (PASSTHROUGH_ROLES.has(next.role)) {
139
+ hi++;
140
+ } else {
141
+ break;
142
+ }
143
+ }
144
+ } while (hi !== prevHi);
145
+
146
+ // Estimate tokens removed
147
+ let removedTokens = 0;
148
+ for (let i = lo; i <= hi; i++) {
149
+ removedTokens += estimateMessageTokens(messages[i]);
150
+ }
151
+
152
+ // Remove the range (inclusive)
153
+ messages.splice(lo, hi - lo + 1);
154
+
155
+ // Build synthetic user message for the compressed block
156
+ const syntheticMsg = {
157
+ role: "user",
158
+ content: [
159
+ {
160
+ type: "text",
161
+ text:
162
+ "[Compressed section: " +
163
+ block.topic +
164
+ "]\n\n" +
165
+ block.summary +
166
+ "\n\n[dcp-block-id]: # (b" +
167
+ block.id +
168
+ ")",
169
+ },
170
+ ],
171
+ // anchorTimestamp is always finite (resolveAnchorTimestamp returns
172
+ // endTimestamp + 1 instead of Infinity), but guard against corrupted
173
+ // state from older sessions where Infinity/null could leak in.
174
+ timestamp: Number.isFinite(block.anchorTimestamp) ? block.anchorTimestamp - 0.5 : block.endTimestamp + 0.5,
175
+ };
176
+
177
+ // Estimate tokens added by the summary
178
+ const addedTokens = estimateMessageTokens(syntheticMsg);
179
+
180
+ // Insert the synthetic message
181
+ messages.push(syntheticMsg);
182
+
183
+ // Re-sort by timestamp
184
+ messages.sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
185
+
186
+ // Update tokens saved exactly once per compression block.
187
+ if (!state.accountedCompressionBlockIds.has(block.id)) {
188
+ state.accountedCompressionBlockIds.add(block.id);
189
+ state.totalPruneCount++;
190
+ const rawSaved = Math.max(0, removedTokens - addedTokens);
191
+ const coveredSavings = (block.coveredBlockIds ?? []).reduce(
192
+ (sum, id) => sum + (state.compressionTokenSavings.get(id) ?? 0),
193
+ 0,
194
+ );
195
+ const adjustment = rawSaved - coveredSavings;
196
+ state.tokensSaved = Math.max(0, state.tokensSaved + adjustment);
197
+ state.compressionTokenSavings.set(block.id, rawSaved);
198
+ }
199
+ }
200
+
201
+ return messages;
202
+ }
203
+
204
+ /**
205
+ * Remove orphaned toolResult/bashExecution messages whose corresponding
206
+ * assistant toolCall was removed, and strip orphaned toolCall blocks from
207
+ * assistant messages whose toolResult was removed.
208
+ *
209
+ * This is a safety net that runs after all compression blocks are applied.
210
+ */
211
+ export function repairOrphanedToolPairs(messages: any[]): void {
212
+ // 1. Build set of all toolCall IDs present in assistant messages
213
+ const assistantToolCallIds = new Set<string>();
214
+ for (const msg of messages) {
215
+ if (msg.role !== "assistant") continue;
216
+ const content: any[] = Array.isArray(msg.content) ? msg.content : [];
217
+ for (const contentBlock of content) {
218
+ if (contentBlock.type === "toolCall" && typeof contentBlock.id === "string") {
219
+ assistantToolCallIds.add(contentBlock.id);
220
+ }
221
+ }
222
+ }
223
+
224
+ // 2. Build set of all toolCallIds present in toolResult/bashExecution messages
225
+ const resultToolCallIds = new Set<string>();
226
+ for (const msg of messages) {
227
+ if (msg.role !== "toolResult" && msg.role !== "bashExecution") continue;
228
+ if (typeof msg.toolCallId === "string") {
229
+ resultToolCallIds.add(msg.toolCallId);
230
+ }
231
+ }
232
+
233
+ // 3. Remove orphaned toolResult/bashExecution messages (no matching assistant toolCall)
234
+ for (let i = messages.length - 1; i >= 0; i--) {
235
+ const msg = messages[i];
236
+ if (msg.role !== "toolResult" && msg.role !== "bashExecution") continue;
237
+ if (typeof msg.toolCallId === "string" && !assistantToolCallIds.has(msg.toolCallId)) {
238
+ messages.splice(i, 1);
239
+ }
240
+ }
241
+
242
+ // 4. Strip orphaned toolCall blocks from assistant messages (no matching toolResult)
243
+ for (const msg of messages) {
244
+ if (msg.role !== "assistant") continue;
245
+ const content: any[] = Array.isArray(msg.content) ? msg.content : [];
246
+ const hasToolCalls = content.some((b: any) => b.type === "toolCall");
247
+ if (!hasToolCalls) continue;
248
+
249
+ const filtered = content.filter((contentBlock: any) => {
250
+ if (contentBlock.type !== "toolCall") return true;
251
+ return typeof contentBlock.id === "string" && resultToolCallIds.has(contentBlock.id);
252
+ });
253
+
254
+ // Only update if we actually removed something
255
+ if (filtered.length !== content.length) {
256
+ // If the assistant has no content left at all, keep at least an empty array
257
+ msg.content = filtered.length > 0 ? filtered : [];
258
+ }
259
+ }
260
+ }
@@ -0,0 +1,147 @@
1
+ import type { DcpState } from "./state.js";
2
+ import type { DcpConfig } from "./config.js";
3
+ import {
4
+ ID_ELIGIBLE_ROLES,
5
+ PASSTHROUGH_ROLES,
6
+ estimateMessageTokens,
7
+ extractBlockId,
8
+ messageText,
9
+ } from "./pruner-metadata.js";
10
+
11
+ export interface InjectMessageIdsOptions {
12
+ /**
13
+ * When false, rebuild internal mNNN snapshots without appending visible
14
+ * DCP marker lines to provider-visible message content.
15
+ */
16
+ visible?: boolean;
17
+ /** Config enables priority markers for message-mode candidates. */
18
+ config?: DcpConfig;
19
+ }
20
+
21
+ export function stableMessageId(msg: any, fallbackIndex = 0): string {
22
+ const candidates = [
23
+ msg?.id,
24
+ msg?.entryId,
25
+ msg?.messageId,
26
+ msg?._dcpEntryId,
27
+ msg?.metadata?.id,
28
+ msg?.metadata?.entryId,
29
+ ];
30
+ for (const candidate of candidates) {
31
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
32
+ return `id:${candidate.trim()}`;
33
+ }
34
+ }
35
+
36
+ if (typeof msg?.toolCallId === "string" && msg.toolCallId.trim().length > 0) {
37
+ return `tool:${msg.toolCallId.trim()}`;
38
+ }
39
+
40
+ if (Number.isFinite(msg?.timestamp)) return `ts:${msg.timestamp}`;
41
+ return `idx:${fallbackIndex}`;
42
+ }
43
+
44
+ function priorityForMessage(tokenEstimate: number, config: DcpConfig | undefined): "low" | "medium" | "high" {
45
+ const settings = config?.compress?.messageMode;
46
+ const mediumTokens = Math.max(1, settings?.mediumTokens ?? 500);
47
+ const highTokens = Math.max(mediumTokens, settings?.highTokens ?? 5000);
48
+
49
+ if (tokenEstimate >= highTokens) return "high";
50
+ if (tokenEstimate >= mediumTokens) return "medium";
51
+ return "low";
52
+ }
53
+
54
+ function formatIdTag(id: string, _priority: "low" | "medium" | "high"): string {
55
+ // Keep the provider-visible marker itself short and single-line. Priority is
56
+ // retained in state and emitted in message-compression candidate hints.
57
+ return `\n[dcp-id]: # (${id})`;
58
+ }
59
+
60
+ export function injectMessageIds(
61
+ messages: any[],
62
+ state: DcpState,
63
+ options: InjectMessageIdsOptions = {},
64
+ ): void {
65
+ const visible = options.visible ?? true;
66
+
67
+ // Clear the snapshots and rebuild
68
+ state.messageIdSnapshot.clear();
69
+ state.messageMetaSnapshot.clear();
70
+
71
+ let counter = 1;
72
+
73
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
74
+ const msg = messages[messageIndex];
75
+ const role: string = msg.role ?? "";
76
+
77
+ // Skip PI-internal passthrough messages
78
+ if (PASSTHROUGH_ROLES.has(role)) continue;
79
+ // Skip non-eligible roles
80
+ if (!ID_ELIGIBLE_ROLES.has(role)) continue;
81
+
82
+ const id = "m" + String(counter).padStart(3, "0");
83
+ counter++;
84
+
85
+ const originalText = messageText(msg);
86
+ const blockId = extractBlockId(originalText);
87
+ const tokenEstimate = estimateMessageTokens(msg);
88
+ const priority = priorityForMessage(tokenEstimate, options.config);
89
+ const idTag = formatIdTag(id, priority);
90
+ const rawStableId = stableMessageId(msg, messageIndex);
91
+
92
+ if (!visible) {
93
+ // Snapshot-only mode: keep mNNN mappings fresh for DCP internals, but
94
+ // do not expose synthetic IDs to the agent.
95
+ } else if (role === "user") {
96
+ if (typeof msg.content === "string") {
97
+ msg.content = msg.content + `\n${idTag}`;
98
+ } else if (Array.isArray(msg.content)) {
99
+ msg.content = [...msg.content, { type: "text", text: idTag }];
100
+ }
101
+ } else if (role === "toolResult" || role === "bashExecution") {
102
+ if (Array.isArray(msg.content)) {
103
+ msg.content = [...msg.content, { type: "text", text: idTag }];
104
+ } else if (typeof msg.content === "string") {
105
+ msg.content = msg.content + idTag;
106
+ }
107
+ } else if (role === "assistant") {
108
+ if (Array.isArray(msg.content)) {
109
+ // Insert the ID tag before any tool_use (toolCall) blocks.
110
+ // Anthropic requires: thinking → text → tool_use.
111
+ // Appending after tool_use blocks violates that constraint.
112
+ const firstToolCallIdx = msg.content.findIndex(
113
+ (b: any) => b.type === "toolCall",
114
+ );
115
+ const idBlock = { type: "text", text: idTag };
116
+ if (firstToolCallIdx === -1) {
117
+ // No tool_use blocks — append as usual
118
+ msg.content = [...msg.content, idBlock];
119
+ } else {
120
+ // Insert immediately before the first tool_use block
121
+ msg.content = [
122
+ ...msg.content.slice(0, firstToolCallIdx),
123
+ idBlock,
124
+ ...msg.content.slice(firstToolCallIdx),
125
+ ];
126
+ }
127
+ } else if (typeof msg.content === "string") {
128
+ msg.content = msg.content + idTag;
129
+ }
130
+ }
131
+
132
+ if (msg.timestamp !== undefined) {
133
+ state.messageIdSnapshot.set(id, msg.timestamp);
134
+ state.messageMetaSnapshot.set(id, {
135
+ timestamp: msg.timestamp,
136
+ stableId: rawStableId,
137
+ role,
138
+ blockId,
139
+ toolCallId: typeof msg.toolCallId === "string" ? msg.toolCallId : undefined,
140
+ toolName: typeof msg.toolName === "string" ? msg.toolName : undefined,
141
+ text: originalText,
142
+ tokenEstimate,
143
+ priority,
144
+ });
145
+ }
146
+ }
147
+ }