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.
- package/README.md +307 -0
- package/bin/pix.mjs +219 -0
- package/dist/app/app.d.ts +96 -0
- package/dist/app/app.js +871 -0
- package/dist/app/blink-controller.d.ts +23 -0
- package/dist/app/blink-controller.js +82 -0
- package/dist/app/cli.d.ts +8 -0
- package/dist/app/cli.js +83 -0
- package/dist/app/clipboard.d.ts +1 -0
- package/dist/app/clipboard.js +24 -0
- package/dist/app/command-controller.d.ts +18 -0
- package/dist/app/command-controller.js +58 -0
- package/dist/app/command-host.d.ts +44 -0
- package/dist/app/command-host.js +1 -0
- package/dist/app/command-model-actions.d.ts +12 -0
- package/dist/app/command-model-actions.js +176 -0
- package/dist/app/command-navigation-actions.d.ts +19 -0
- package/dist/app/command-navigation-actions.js +267 -0
- package/dist/app/command-registry.d.ts +32 -0
- package/dist/app/command-registry.js +225 -0
- package/dist/app/command-runtime.d.ts +5 -0
- package/dist/app/command-runtime.js +32 -0
- package/dist/app/command-session-actions.d.ts +20 -0
- package/dist/app/command-session-actions.js +295 -0
- package/dist/app/constants.d.ts +52 -0
- package/dist/app/constants.js +103 -0
- package/dist/app/conversation-entry-renderer.d.ts +21 -0
- package/dist/app/conversation-entry-renderer.js +81 -0
- package/dist/app/conversation-shell-renderer.d.ts +5 -0
- package/dist/app/conversation-shell-renderer.js +43 -0
- package/dist/app/conversation-tool-renderer.d.ts +16 -0
- package/dist/app/conversation-tool-renderer.js +216 -0
- package/dist/app/conversation-viewport.d.ts +55 -0
- package/dist/app/conversation-viewport.js +252 -0
- package/dist/app/dcp-stats.d.ts +2 -0
- package/dist/app/dcp-stats.js +116 -0
- package/dist/app/editor-layout-renderer.d.ts +31 -0
- package/dist/app/editor-layout-renderer.js +211 -0
- package/dist/app/editor-panels.d.ts +4 -0
- package/dist/app/editor-panels.js +130 -0
- package/dist/app/extension-actions-controller.d.ts +22 -0
- package/dist/app/extension-actions-controller.js +60 -0
- package/dist/app/extension-event-bus.d.ts +3 -0
- package/dist/app/extension-event-bus.js +23 -0
- package/dist/app/extension-ui-controller.d.ts +57 -0
- package/dist/app/extension-ui-controller.js +532 -0
- package/dist/app/file-link-opener.d.ts +2 -0
- package/dist/app/file-link-opener.js +66 -0
- package/dist/app/file-links.d.ts +10 -0
- package/dist/app/file-links.js +117 -0
- package/dist/app/guards.d.ts +3 -0
- package/dist/app/guards.js +9 -0
- package/dist/app/icons.d.ts +37 -0
- package/dist/app/icons.js +97 -0
- package/dist/app/id.d.ts +1 -0
- package/dist/app/id.js +4 -0
- package/dist/app/image-click-targets.d.ts +5 -0
- package/dist/app/image-click-targets.js +32 -0
- package/dist/app/image-opener.d.ts +2 -0
- package/dist/app/image-opener.js +64 -0
- package/dist/app/input-action-controller.d.ts +47 -0
- package/dist/app/input-action-controller.js +209 -0
- package/dist/app/input-controller.d.ts +60 -0
- package/dist/app/input-controller.js +425 -0
- package/dist/app/input-paste-handler.d.ts +27 -0
- package/dist/app/input-paste-handler.js +146 -0
- package/dist/app/menu-items-controller.d.ts +32 -0
- package/dist/app/menu-items-controller.js +182 -0
- package/dist/app/message-content.d.ts +8 -0
- package/dist/app/message-content.js +115 -0
- package/dist/app/model-ref.d.ts +13 -0
- package/dist/app/model-ref.js +50 -0
- package/dist/app/model-usage-controller.d.ts +35 -0
- package/dist/app/model-usage-controller.js +99 -0
- package/dist/app/model-usage-status.d.ts +125 -0
- package/dist/app/model-usage-status.js +749 -0
- package/dist/app/mouse-controller.d.ts +182 -0
- package/dist/app/mouse-controller.js +968 -0
- package/dist/app/native-modifiers.d.ts +3 -0
- package/dist/app/native-modifiers.js +60 -0
- package/dist/app/nerd-font-controller.d.ts +11 -0
- package/dist/app/nerd-font-controller.js +90 -0
- package/dist/app/popup-action-controller.d.ts +44 -0
- package/dist/app/popup-action-controller.js +278 -0
- package/dist/app/popup-menu-controller.d.ts +183 -0
- package/dist/app/popup-menu-controller.js +1070 -0
- package/dist/app/prompt-enhancer-controller.d.ts +40 -0
- package/dist/app/prompt-enhancer-controller.js +215 -0
- package/dist/app/queued-message-controller.d.ts +62 -0
- package/dist/app/queued-message-controller.js +377 -0
- package/dist/app/render-controller.d.ts +41 -0
- package/dist/app/render-controller.js +378 -0
- package/dist/app/render-text.d.ts +19 -0
- package/dist/app/render-text.js +67 -0
- package/dist/app/request-history.d.ts +23 -0
- package/dist/app/request-history.js +131 -0
- package/dist/app/runtime.d.ts +39 -0
- package/dist/app/runtime.js +195 -0
- package/dist/app/screen-selection.d.ts +6 -0
- package/dist/app/screen-selection.js +9 -0
- package/dist/app/screen-styler.d.ts +34 -0
- package/dist/app/screen-styler.js +168 -0
- package/dist/app/scroll-controller.d.ts +51 -0
- package/dist/app/scroll-controller.js +207 -0
- package/dist/app/session-event-controller.d.ts +69 -0
- package/dist/app/session-event-controller.js +338 -0
- package/dist/app/session-history.d.ts +23 -0
- package/dist/app/session-history.js +164 -0
- package/dist/app/session-lifecycle-controller.d.ts +55 -0
- package/dist/app/session-lifecycle-controller.js +116 -0
- package/dist/app/session-search.d.ts +24 -0
- package/dist/app/session-search.js +215 -0
- package/dist/app/shell-command.d.ts +27 -0
- package/dist/app/shell-command.js +176 -0
- package/dist/app/shell-controller.d.ts +28 -0
- package/dist/app/shell-controller.js +124 -0
- package/dist/app/slash-commands.d.ts +6 -0
- package/dist/app/slash-commands.js +75 -0
- package/dist/app/startup-checks.d.ts +8 -0
- package/dist/app/startup-checks.js +59 -0
- package/dist/app/startup-info.d.ts +3 -0
- package/dist/app/startup-info.js +176 -0
- package/dist/app/status-controller.d.ts +35 -0
- package/dist/app/status-controller.js +105 -0
- package/dist/app/status-line-renderer.d.ts +68 -0
- package/dist/app/status-line-renderer.js +453 -0
- package/dist/app/subagents-files.d.ts +10 -0
- package/dist/app/subagents-files.js +193 -0
- package/dist/app/subagents-model.d.ts +23 -0
- package/dist/app/subagents-model.js +224 -0
- package/dist/app/subagents-widget-controller.d.ts +43 -0
- package/dist/app/subagents-widget-controller.js +311 -0
- package/dist/app/tab-line-renderer.d.ts +26 -0
- package/dist/app/tab-line-renderer.js +222 -0
- package/dist/app/tabs-controller.d.ts +100 -0
- package/dist/app/tabs-controller.js +885 -0
- package/dist/app/terminal-controller.d.ts +40 -0
- package/dist/app/terminal-controller.js +135 -0
- package/dist/app/terminal-edit-shortcuts.d.ts +23 -0
- package/dist/app/terminal-edit-shortcuts.js +138 -0
- package/dist/app/terminal-output-buffer.d.ts +20 -0
- package/dist/app/terminal-output-buffer.js +52 -0
- package/dist/app/toast-controller.d.ts +13 -0
- package/dist/app/toast-controller.js +40 -0
- package/dist/app/toast-renderer.d.ts +9 -0
- package/dist/app/toast-renderer.js +79 -0
- package/dist/app/todo-model.d.ts +22 -0
- package/dist/app/todo-model.js +179 -0
- package/dist/app/todo-widget-controller.d.ts +21 -0
- package/dist/app/todo-widget-controller.js +59 -0
- package/dist/app/tool-block-renderer.d.ts +26 -0
- package/dist/app/tool-block-renderer.js +439 -0
- package/dist/app/types.d.ts +550 -0
- package/dist/app/types.js +1 -0
- package/dist/app/update.d.ts +36 -0
- package/dist/app/update.js +315 -0
- package/dist/app/voice-controller.d.ts +52 -0
- package/dist/app/voice-controller.js +600 -0
- package/dist/app/workspace-actions-controller.d.ts +40 -0
- package/dist/app/workspace-actions-controller.js +215 -0
- package/dist/app/workspace-undo.d.ts +44 -0
- package/dist/app/workspace-undo.js +215 -0
- package/dist/config.d.ts +62 -0
- package/dist/config.js +527 -0
- package/dist/context-progress-bar.d.ts +17 -0
- package/dist/context-progress-bar.js +48 -0
- package/dist/default-pix-config.d.ts +1 -0
- package/dist/default-pix-config.js +375 -0
- package/dist/fuzzy.d.ts +23 -0
- package/dist/fuzzy.js +165 -0
- package/dist/input-editor-files.d.ts +15 -0
- package/dist/input-editor-files.js +62 -0
- package/dist/input-editor.d.ts +186 -0
- package/dist/input-editor.js +835 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +12 -0
- package/dist/markdown-format.d.ts +22 -0
- package/dist/markdown-format.js +542 -0
- package/dist/sdk.d.ts +3 -0
- package/dist/sdk.js +1 -0
- package/dist/syntax-highlight.d.ts +22 -0
- package/dist/syntax-highlight.js +528 -0
- package/dist/terminal-width.d.ts +6 -0
- package/dist/terminal-width.js +245 -0
- package/dist/theme.d.ts +56 -0
- package/dist/theme.js +118 -0
- package/dist/tool-renderers/apply-patch.d.ts +2 -0
- package/dist/tool-renderers/apply-patch.js +36 -0
- package/dist/tool-renderers/ast.d.ts +2 -0
- package/dist/tool-renderers/ast.js +5 -0
- package/dist/tool-renderers/compress.d.ts +2 -0
- package/dist/tool-renderers/compress.js +126 -0
- package/dist/tool-renderers/index.d.ts +3 -0
- package/dist/tool-renderers/index.js +44 -0
- package/dist/tool-renderers/question.d.ts +2 -0
- package/dist/tool-renderers/question.js +88 -0
- package/dist/tool-renderers/read.d.ts +2 -0
- package/dist/tool-renderers/read.js +36 -0
- package/dist/tool-renderers/repo.d.ts +2 -0
- package/dist/tool-renderers/repo.js +13 -0
- package/dist/tool-renderers/shell.d.ts +3 -0
- package/dist/tool-renderers/shell.js +27 -0
- package/dist/tool-renderers/skill.d.ts +2 -0
- package/dist/tool-renderers/skill.js +132 -0
- package/dist/tool-renderers/subagents.d.ts +2 -0
- package/dist/tool-renderers/subagents.js +51 -0
- package/dist/tool-renderers/todo.d.ts +2 -0
- package/dist/tool-renderers/todo.js +9 -0
- package/dist/tool-renderers/types.d.ts +42 -0
- package/dist/tool-renderers/types.js +1 -0
- package/dist/tool-renderers/utils.d.ts +31 -0
- package/dist/tool-renderers/utils.js +230 -0
- package/dist/tool-renderers/web.d.ts +3 -0
- package/dist/tool-renderers/web.js +9 -0
- package/dist/tool-renderers/write.d.ts +2 -0
- package/dist/tool-renderers/write.js +42 -0
- package/dist/ui.d.ts +56 -0
- package/dist/ui.js +94 -0
- package/docs/release.md +81 -0
- package/extensions/question/contract.ts +100 -0
- package/extensions/question/index.ts +34 -0
- package/extensions/question/render.ts +28 -0
- package/extensions/question/result.ts +86 -0
- package/extensions/question/tool-description.ts +11 -0
- package/extensions/question/tui.ts +629 -0
- package/extensions/question/types.ts +123 -0
- package/extensions/session-title/config.ts +169 -0
- package/extensions/session-title/index.ts +459 -0
- package/extensions/terminal-bell/index.ts +315 -0
- package/external/pi-tools-suite/README.md +242 -0
- package/external/pi-tools-suite/index.ts +1 -0
- package/external/pi-tools-suite/licenses/ollama-pi-web-search.MIT +21 -0
- package/external/pi-tools-suite/licenses/opencode-mystatus-MIT.txt +21 -0
- package/external/pi-tools-suite/package.json +53 -0
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +194 -0
- package/external/pi-tools-suite/src/antigravity-auth/commands.ts +80 -0
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +26 -0
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +20 -0
- package/external/pi-tools-suite/src/antigravity-auth/index.ts +104 -0
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +86 -0
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +305 -0
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +423 -0
- package/external/pi-tools-suite/src/antigravity-auth/status.ts +78 -0
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +302 -0
- package/external/pi-tools-suite/src/antigravity-auth/types.ts +113 -0
- package/external/pi-tools-suite/src/ast-grep/index.ts +6 -0
- package/external/pi-tools-suite/src/ast-grep/render.ts +70 -0
- package/external/pi-tools-suite/src/ast-grep/schema.ts +109 -0
- package/external/pi-tools-suite/src/ast-grep/tool.ts +345 -0
- package/external/pi-tools-suite/src/ast-grep/types.ts +55 -0
- package/external/pi-tools-suite/src/ast-grep/utils.ts +65 -0
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +222 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +518 -0
- package/external/pi-tools-suite/src/async-subagents/constants.ts +11 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +74 -0
- package/external/pi-tools-suite/src/async-subagents/core/attachment-bridge.ts +133 -0
- package/external/pi-tools-suite/src/async-subagents/core/cleanup.ts +66 -0
- package/external/pi-tools-suite/src/async-subagents/core/concurrency.ts +90 -0
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +819 -0
- package/external/pi-tools-suite/src/async-subagents/core/log-limits.ts +166 -0
- package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +133 -0
- package/external/pi-tools-suite/src/async-subagents/core/paths.ts +47 -0
- package/external/pi-tools-suite/src/async-subagents/core/pi-invocation.ts +35 -0
- package/external/pi-tools-suite/src/async-subagents/core/presets.ts +67 -0
- package/external/pi-tools-suite/src/async-subagents/core/process.ts +15 -0
- package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +66 -0
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +224 -0
- package/external/pi-tools-suite/src/async-subagents/core/retry.ts +191 -0
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +259 -0
- package/external/pi-tools-suite/src/async-subagents/core/sessions.ts +138 -0
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +688 -0
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +281 -0
- package/external/pi-tools-suite/src/async-subagents/core/stop.ts +131 -0
- package/external/pi-tools-suite/src/async-subagents/core/structured-result.ts +237 -0
- package/external/pi-tools-suite/src/async-subagents/core/tool-guard.ts +34 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +150 -0
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +184 -0
- package/external/pi-tools-suite/src/async-subagents/core/utils.ts +11 -0
- package/external/pi-tools-suite/src/async-subagents/format.ts +41 -0
- package/external/pi-tools-suite/src/async-subagents/index.ts +422 -0
- package/external/pi-tools-suite/src/async-subagents/lib.ts +88 -0
- package/external/pi-tools-suite/src/async-subagents/live.ts +10 -0
- package/external/pi-tools-suite/src/async-subagents/polling.ts +83 -0
- package/external/pi-tools-suite/src/async-subagents/render.ts +230 -0
- package/external/pi-tools-suite/src/async-subagents/subagent-overlay.ts +77 -0
- package/external/pi-tools-suite/src/async-subagents/tasks.ts +120 -0
- package/external/pi-tools-suite/src/async-subagents/tools/cleanup.ts +99 -0
- package/external/pi-tools-suite/src/async-subagents/tools/result.ts +179 -0
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +372 -0
- package/external/pi-tools-suite/src/async-subagents/tools/status.ts +60 -0
- package/external/pi-tools-suite/src/async-subagents/tools/stop.ts +79 -0
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +152 -0
- package/external/pi-tools-suite/src/async-subagents/tools/wait.ts +67 -0
- package/external/pi-tools-suite/src/async-subagents/types.ts +45 -0
- package/external/pi-tools-suite/src/async-subagents/ui.ts +5 -0
- package/external/pi-tools-suite/src/compress/commands.ts +440 -0
- package/external/pi-tools-suite/src/compress/compress-tool.ts +368 -0
- package/external/pi-tools-suite/src/compress/compression-blocks.ts +524 -0
- package/external/pi-tools-suite/src/compress/config.ts +310 -0
- package/external/pi-tools-suite/src/compress/dcp-tui-filter.ts +498 -0
- package/external/pi-tools-suite/src/compress/index.ts +397 -0
- package/external/pi-tools-suite/src/compress/prompts.ts +269 -0
- package/external/pi-tools-suite/src/compress/pruner-candidates.ts +176 -0
- package/external/pi-tools-suite/src/compress/pruner-compression-blocks.ts +260 -0
- package/external/pi-tools-suite/src/compress/pruner-message-ids.ts +147 -0
- package/external/pi-tools-suite/src/compress/pruner-metadata.ts +268 -0
- package/external/pi-tools-suite/src/compress/pruner-nudge.ts +315 -0
- package/external/pi-tools-suite/src/compress/pruner-tools.ts +263 -0
- package/external/pi-tools-suite/src/compress/pruner-types.ts +25 -0
- package/external/pi-tools-suite/src/compress/pruner.ts +92 -0
- package/external/pi-tools-suite/src/compress/state.ts +486 -0
- package/external/pi-tools-suite/src/compress/ui.ts +308 -0
- package/external/pi-tools-suite/src/config.ts +176 -0
- package/external/pi-tools-suite/src/context-usage.ts +31 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +355 -0
- package/external/pi-tools-suite/src/index.ts +46 -0
- package/external/pi-tools-suite/src/lib/lsp.ts +62 -0
- package/external/pi-tools-suite/src/lib/project.ts +42 -0
- package/external/pi-tools-suite/src/lib/tool-args.ts +137 -0
- package/external/pi-tools-suite/src/lsp/_shared/config.ts +156 -0
- package/external/pi-tools-suite/src/lsp/_shared/glob.ts +60 -0
- package/external/pi-tools-suite/src/lsp/_shared/output.ts +102 -0
- package/external/pi-tools-suite/src/lsp/_shared/paths.ts +138 -0
- package/external/pi-tools-suite/src/lsp/_shared/runner.ts +64 -0
- package/external/pi-tools-suite/src/lsp/_shared/template.ts +23 -0
- package/external/pi-tools-suite/src/lsp/_shared/trust.ts +116 -0
- package/external/pi-tools-suite/src/lsp/_shared/types.ts +98 -0
- package/external/pi-tools-suite/src/lsp/async.ts +29 -0
- package/external/pi-tools-suite/src/lsp/child-process.ts +81 -0
- package/external/pi-tools-suite/src/lsp/client.ts +340 -0
- package/external/pi-tools-suite/src/lsp/constants.ts +9 -0
- package/external/pi-tools-suite/src/lsp/diagnostics-store.ts +64 -0
- package/external/pi-tools-suite/src/lsp/documents.ts +24 -0
- package/external/pi-tools-suite/src/lsp/index.ts +31 -0
- package/external/pi-tools-suite/src/lsp/lsp-utils.ts +37 -0
- package/external/pi-tools-suite/src/lsp/manager.ts +190 -0
- package/external/pi-tools-suite/src/lsp/mutation-events.ts +78 -0
- package/external/pi-tools-suite/src/lsp/renderer.ts +1 -0
- package/external/pi-tools-suite/src/lsp/tool-result.ts +6 -0
- package/external/pi-tools-suite/src/lsp/tsserver.ts +107 -0
- package/external/pi-tools-suite/src/lsp/types.ts +15 -0
- package/external/pi-tools-suite/src/model-tools/apply-patch.ts +590 -0
- package/external/pi-tools-suite/src/model-tools/index.ts +430 -0
- package/external/pi-tools-suite/src/model-tools/path-utils.ts +6 -0
- package/external/pi-tools-suite/src/model-tools/tool-args.ts +11 -0
- package/external/pi-tools-suite/src/prompt-commands/index.ts +349 -0
- package/external/pi-tools-suite/src/repo-discovery/index.ts +384 -0
- package/external/pi-tools-suite/src/repo-discovery/project.ts +7 -0
- package/external/pi-tools-suite/src/startup-section.ts +13 -0
- package/external/pi-tools-suite/src/terminal-bell/index.ts +309 -0
- package/external/pi-tools-suite/src/todo/index.ts +201 -0
- package/external/pi-tools-suite/src/todo/state/auto-clear.ts +13 -0
- package/external/pi-tools-suite/src/todo/state/invariants.ts +21 -0
- package/external/pi-tools-suite/src/todo/state/persistence.ts +94 -0
- package/external/pi-tools-suite/src/todo/state/replay.ts +38 -0
- package/external/pi-tools-suite/src/todo/state/selectors.ts +49 -0
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +362 -0
- package/external/pi-tools-suite/src/todo/state/state.ts +18 -0
- package/external/pi-tools-suite/src/todo/state/store.ts +52 -0
- package/external/pi-tools-suite/src/todo/state/task-graph.ts +57 -0
- package/external/pi-tools-suite/src/todo/todo.ts +487 -0
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +143 -0
- package/external/pi-tools-suite/src/todo/tool/types.ts +188 -0
- package/external/pi-tools-suite/src/todo/view/format.ts +18 -0
- package/external/pi-tools-suite/src/todo/view/labels.ts +13 -0
- package/external/pi-tools-suite/src/tool-descriptions.ts +369 -0
- package/external/pi-tools-suite/src/usage/index.ts +152 -0
- package/external/pi-tools-suite/src/usage/lib/copilot.ts +535 -0
- package/external/pi-tools-suite/src/usage/lib/google.ts +478 -0
- package/external/pi-tools-suite/src/usage/lib/openai.ts +268 -0
- package/external/pi-tools-suite/src/usage/lib/types.ts +114 -0
- package/external/pi-tools-suite/src/usage/lib/utils.ts +134 -0
- package/external/pi-tools-suite/src/usage/lib/zhipu.ts +228 -0
- package/external/pi-tools-suite/src/web-search/index.ts +397 -0
- package/package.json +89 -0
- package/skills/context7/SKILL.md +69 -0
- package/skills/context7/scripts/context7.sh +73 -0
- package/skills/handoff/SKILL.md +15 -0
- package/skills/pdf/LICENSE.txt +30 -0
- package/skills/pdf/SKILL.md +314 -0
- package/skills/pdf/forms.md +294 -0
- package/skills/pdf/reference.md +612 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
- package/skills/pdf/scripts/check_fillable_fields.py +11 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
- package/skills/pdf/scripts/create_validation_image.py +37 -0
- package/skills/pdf/scripts/extract_form_field_info.py +122 -0
- package/skills/pdf/scripts/extract_form_structure.py +115 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- package/skills/playwright-cli/SKILL.md +388 -0
- package/skills/playwright-cli/references/element-attributes.md +23 -0
- package/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/skills/playwright-cli/references/request-mocking.md +87 -0
- package/skills/playwright-cli/references/running-code.md +241 -0
- package/skills/playwright-cli/references/session-management.md +225 -0
- package/skills/playwright-cli/references/spec-driven-testing.md +305 -0
- package/skills/playwright-cli/references/storage-state.md +275 -0
- package/skills/playwright-cli/references/test-generation.md +134 -0
- package/skills/playwright-cli/references/tracing.md +139 -0
- package/skills/playwright-cli/references/video-recording.md +143 -0
- package/skills/simplify/SKILL.md +51 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- 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
|
+
}
|