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,40 @@
|
|
|
1
|
+
import { type AgentSessionRuntime } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { PromptEnhancerConfig } from "../config.js";
|
|
3
|
+
import type { InputEditor } from "../input-editor.js";
|
|
4
|
+
import type { ToastNotifier } from "../ui.js";
|
|
5
|
+
import type { TabInputState } from "./tabs-controller.js";
|
|
6
|
+
import type { SessionActivity } from "./types.js";
|
|
7
|
+
export type AppPromptEnhancerControllerHost = {
|
|
8
|
+
runtime(): AgentSessionRuntime | undefined;
|
|
9
|
+
inputEditor(): InputEditor;
|
|
10
|
+
activeInputTabId(): string | undefined;
|
|
11
|
+
inputStateForTab(tabId: string | undefined): TabInputState | undefined;
|
|
12
|
+
setInputStateForTab(tabId: string | undefined, state: TabInputState): void;
|
|
13
|
+
promptEnhancerConfig(): PromptEnhancerConfig;
|
|
14
|
+
resetInputAfterProgrammaticEdit(): void;
|
|
15
|
+
setStatus(status: string): void;
|
|
16
|
+
setSessionStatus(session: AgentSessionRuntime["session"] | undefined): void;
|
|
17
|
+
setSessionActivity(activity: SessionActivity): void;
|
|
18
|
+
toast: ToastNotifier;
|
|
19
|
+
render(): void;
|
|
20
|
+
};
|
|
21
|
+
type PromptEnhanceRunner = typeof enhancePromptWithPi;
|
|
22
|
+
type AppPromptEnhancerControllerOptions = {
|
|
23
|
+
enhancePromptWithPi?: PromptEnhanceRunner;
|
|
24
|
+
};
|
|
25
|
+
export declare class AppPromptEnhancerController {
|
|
26
|
+
private readonly host;
|
|
27
|
+
private enhancing;
|
|
28
|
+
private readonly enhancePromptWithPi;
|
|
29
|
+
constructor(host: AppPromptEnhancerControllerHost, options?: AppPromptEnhancerControllerOptions);
|
|
30
|
+
statusWidgetText(): string;
|
|
31
|
+
statusWidgetActive(): boolean;
|
|
32
|
+
statusWidgetEnabled(): boolean;
|
|
33
|
+
enhancePrompt(): Promise<void>;
|
|
34
|
+
private currentTarget;
|
|
35
|
+
private applyEnhancedPrompt;
|
|
36
|
+
private restoreSessionState;
|
|
37
|
+
}
|
|
38
|
+
export declare function promptEnhancerTextIsSufficient(text: string): boolean;
|
|
39
|
+
declare function enhancePromptWithPi(runtime: AgentSessionRuntime, draft: string, config: PromptEnhancerConfig): Promise<string>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createAgentSessionFromServices, createAgentSessionServices, SessionManager, } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { APP_ICONS } from "./icons.js";
|
|
3
|
+
import { stringifyUnknown } from "./message-content.js";
|
|
4
|
+
import { parseModelRef } from "./model-ref.js";
|
|
5
|
+
const PROMPT_ENHANCER_SYSTEM_PROMPT = `You improve prompts for a coding agent.
|
|
6
|
+
|
|
7
|
+
Rewrite the user's draft into a clearer, more actionable prompt.
|
|
8
|
+
Preserve the user's intent and language.
|
|
9
|
+
Do not solve the task.
|
|
10
|
+
Do not add unsupported assumptions.
|
|
11
|
+
Add useful constraints, acceptance criteria, and context requests when helpful.
|
|
12
|
+
Output only the improved prompt. No commentary, no markdown fences.`;
|
|
13
|
+
const PROMPT_ENHANCER_MIN_TEXT_LENGTH = 3;
|
|
14
|
+
export class AppPromptEnhancerController {
|
|
15
|
+
host;
|
|
16
|
+
enhancing = false;
|
|
17
|
+
enhancePromptWithPi;
|
|
18
|
+
constructor(host, options = {}) {
|
|
19
|
+
this.host = host;
|
|
20
|
+
this.enhancePromptWithPi = options.enhancePromptWithPi ?? enhancePromptWithPi;
|
|
21
|
+
}
|
|
22
|
+
statusWidgetText() {
|
|
23
|
+
return this.enhancing ? APP_ICONS.timerSand : APP_ICONS.autoFix;
|
|
24
|
+
}
|
|
25
|
+
statusWidgetActive() {
|
|
26
|
+
return this.enhancing;
|
|
27
|
+
}
|
|
28
|
+
statusWidgetEnabled() {
|
|
29
|
+
return this.enhancing || this.currentTarget() !== undefined;
|
|
30
|
+
}
|
|
31
|
+
async enhancePrompt() {
|
|
32
|
+
if (this.enhancing) {
|
|
33
|
+
this.host.toast.warning("Prompt enhancement is already running");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const runtime = this.host.runtime();
|
|
37
|
+
if (!runtime) {
|
|
38
|
+
this.host.toast.error("Prompt enhancer unavailable: runtime is not initialized");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const target = this.currentTarget();
|
|
42
|
+
if (!target) {
|
|
43
|
+
this.host.toast.warning(`Type at least ${PROMPT_ENHANCER_MIN_TEXT_LENGTH} characters to enhance`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.enhancing = true;
|
|
47
|
+
this.host.setStatus("enhancing prompt");
|
|
48
|
+
this.host.setSessionActivity("thinking");
|
|
49
|
+
this.host.render();
|
|
50
|
+
try {
|
|
51
|
+
const enhanced = await this.enhancePromptWithPi(runtime, target.text, this.host.promptEnhancerConfig());
|
|
52
|
+
const currentInputState = this.host.inputStateForTab(target.tabId);
|
|
53
|
+
if (!currentInputState || currentInputState.text !== target.originalEditorText) {
|
|
54
|
+
this.host.toast.warning("Prompt was changed before enhancement completed; result was not applied");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.applyEnhancedPrompt(target, enhanced);
|
|
58
|
+
this.host.resetInputAfterProgrammaticEdit();
|
|
59
|
+
this.host.toast.success(target.kind === "selection" ? "Selection enhanced" : "Prompt enhanced");
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.host.toast.error(`Prompt enhance failed: ${stringifyUnknown(error)}`);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
this.enhancing = false;
|
|
66
|
+
this.restoreSessionState();
|
|
67
|
+
this.host.render();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
currentTarget() {
|
|
71
|
+
const editor = this.host.inputEditor();
|
|
72
|
+
const tabId = this.host.activeInputTabId();
|
|
73
|
+
const originalEditorText = editor.text;
|
|
74
|
+
const selectedText = editor.getSelectedText();
|
|
75
|
+
if (selectedText !== undefined && selectedText.trim().length > 0 && editor.selection) {
|
|
76
|
+
if (!promptEnhancerTextIsSufficient(selectedText))
|
|
77
|
+
return undefined;
|
|
78
|
+
const start = Math.min(editor.selection.anchor, editor.selection.active);
|
|
79
|
+
const end = Math.max(editor.selection.anchor, editor.selection.active);
|
|
80
|
+
return {
|
|
81
|
+
kind: "selection",
|
|
82
|
+
tabId,
|
|
83
|
+
text: selectedText,
|
|
84
|
+
originalEditorText,
|
|
85
|
+
start,
|
|
86
|
+
end,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (!promptEnhancerTextIsSufficient(originalEditorText))
|
|
90
|
+
return undefined;
|
|
91
|
+
return {
|
|
92
|
+
kind: "input",
|
|
93
|
+
tabId,
|
|
94
|
+
text: originalEditorText,
|
|
95
|
+
originalEditorText,
|
|
96
|
+
start: 0,
|
|
97
|
+
end: originalEditorText.length,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
applyEnhancedPrompt(target, enhanced) {
|
|
101
|
+
const nextText = `${target.originalEditorText.slice(0, target.start)}${enhanced}${target.originalEditorText.slice(target.end)}`;
|
|
102
|
+
this.host.setInputStateForTab(target.tabId, {
|
|
103
|
+
text: nextText,
|
|
104
|
+
cursor: target.start + enhanced.length,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
restoreSessionState() {
|
|
108
|
+
const session = this.host.runtime()?.session;
|
|
109
|
+
this.host.setSessionStatus(session);
|
|
110
|
+
this.host.setSessionActivity(session?.isStreaming || session?.isCompacting ? "running" : "idle");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export function promptEnhancerTextIsSufficient(text) {
|
|
114
|
+
return text.trim().length >= PROMPT_ENHANCER_MIN_TEXT_LENGTH;
|
|
115
|
+
}
|
|
116
|
+
async function enhancePromptWithPi(runtime, draft, config) {
|
|
117
|
+
const parsedModel = parseModelRef(config.modelRef);
|
|
118
|
+
const services = await createAgentSessionServices({
|
|
119
|
+
cwd: runtime.cwd,
|
|
120
|
+
agentDir: runtime.services.agentDir,
|
|
121
|
+
authStorage: runtime.services.authStorage,
|
|
122
|
+
settingsManager: runtime.services.settingsManager,
|
|
123
|
+
modelRegistry: runtime.services.modelRegistry,
|
|
124
|
+
resourceLoaderOptions: {
|
|
125
|
+
noExtensions: true,
|
|
126
|
+
noSkills: true,
|
|
127
|
+
noPromptTemplates: true,
|
|
128
|
+
noThemes: true,
|
|
129
|
+
noContextFiles: true,
|
|
130
|
+
systemPrompt: PROMPT_ENHANCER_SYSTEM_PROMPT,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
services.modelRegistry.refresh();
|
|
134
|
+
const model = services.modelRegistry.find(parsedModel.provider, parsedModel.modelId);
|
|
135
|
+
if (!model) {
|
|
136
|
+
throw new Error(modelNotFoundMessage(parsedModel.provider, parsedModel.modelId, services.modelRegistry.getAll()));
|
|
137
|
+
}
|
|
138
|
+
const { session } = await createAgentSessionFromServices({
|
|
139
|
+
services,
|
|
140
|
+
sessionManager: SessionManager.inMemory(runtime.cwd),
|
|
141
|
+
model,
|
|
142
|
+
thinkingLevel: parsedModel.thinkingLevel ?? "minimal",
|
|
143
|
+
noTools: "all",
|
|
144
|
+
});
|
|
145
|
+
let output = "";
|
|
146
|
+
let streamError;
|
|
147
|
+
const unsubscribe = session.subscribe((event) => {
|
|
148
|
+
if (event.type !== "message_update")
|
|
149
|
+
return;
|
|
150
|
+
const assistantEvent = event.assistantMessageEvent;
|
|
151
|
+
if (assistantEvent.type === "text_delta")
|
|
152
|
+
output += assistantEvent.delta;
|
|
153
|
+
else if (assistantEvent.type === "error")
|
|
154
|
+
streamError = assistantEvent.error.errorMessage ?? assistantEvent.reason;
|
|
155
|
+
});
|
|
156
|
+
try {
|
|
157
|
+
await session.prompt(buildEnhancerPrompt(draft), { expandPromptTemplates: false });
|
|
158
|
+
if (streamError)
|
|
159
|
+
throw new Error(streamError);
|
|
160
|
+
const cleaned = cleanupEnhancedPrompt(output);
|
|
161
|
+
if (cleaned.length === 0)
|
|
162
|
+
throw new Error("model returned an empty prompt");
|
|
163
|
+
return cleaned;
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
unsubscribe();
|
|
167
|
+
session.dispose();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function buildEnhancerPrompt(draft) {
|
|
171
|
+
return [
|
|
172
|
+
"Rewrite this draft prompt. Output only the improved prompt.",
|
|
173
|
+
"<draft>",
|
|
174
|
+
draft,
|
|
175
|
+
"</draft>",
|
|
176
|
+
].join("\n");
|
|
177
|
+
}
|
|
178
|
+
function cleanupEnhancedPrompt(output) {
|
|
179
|
+
let text = output.replace(/\r\n/gu, "\n").trim();
|
|
180
|
+
const fenced = /^```[^\n`]*\n([\s\S]*?)\n```$/u.exec(text);
|
|
181
|
+
if (fenced)
|
|
182
|
+
text = fenced[1].trim();
|
|
183
|
+
return text;
|
|
184
|
+
}
|
|
185
|
+
function modelNotFoundMessage(provider, modelId, models) {
|
|
186
|
+
const requested = `${provider}/${modelId}`;
|
|
187
|
+
const suggestions = suggestModelRefs(provider, modelId, models);
|
|
188
|
+
return suggestions.length > 0
|
|
189
|
+
? `Model not found: ${requested}. Did you mean ${suggestions.join(", ")}?`
|
|
190
|
+
: `Model not found: ${requested}`;
|
|
191
|
+
}
|
|
192
|
+
function suggestModelRefs(provider, modelId, models) {
|
|
193
|
+
const queryTokens = tokenSet(`${provider} ${modelId}`);
|
|
194
|
+
return models
|
|
195
|
+
.map((model) => ({ ref: `${model.provider}/${model.id}`, score: modelSuggestionScore(model, provider, modelId, queryTokens) }))
|
|
196
|
+
.filter((candidate) => candidate.score > 0)
|
|
197
|
+
.sort((a, b) => b.score - a.score || a.ref.localeCompare(b.ref))
|
|
198
|
+
.slice(0, 3)
|
|
199
|
+
.map((candidate) => candidate.ref);
|
|
200
|
+
}
|
|
201
|
+
function modelSuggestionScore(model, provider, modelId, queryTokens) {
|
|
202
|
+
let score = 0;
|
|
203
|
+
if (model.provider === provider)
|
|
204
|
+
score += 8;
|
|
205
|
+
if (model.id === modelId)
|
|
206
|
+
score += 8;
|
|
207
|
+
for (const token of tokenSet(`${model.provider} ${model.id} ${model.name ?? ""}`)) {
|
|
208
|
+
if (queryTokens.has(token))
|
|
209
|
+
score += 1;
|
|
210
|
+
}
|
|
211
|
+
return score;
|
|
212
|
+
}
|
|
213
|
+
function tokenSet(value) {
|
|
214
|
+
return new Set(value.toLowerCase().split(/[^a-z0-9]+/u).filter((token) => token.length > 0));
|
|
215
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { AgentSession, AgentSessionRuntime } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { ImageContent } from "../input-editor.js";
|
|
3
|
+
import type { Entry, SessionActivity, SubmittedUserMessage } from "./types.js";
|
|
4
|
+
export type AppQueuedMessageControllerHost = {
|
|
5
|
+
runtime(): AgentSessionRuntime | undefined;
|
|
6
|
+
requireRuntime(): AgentSessionRuntime;
|
|
7
|
+
visibleEntries(): readonly Entry[];
|
|
8
|
+
isRunning(): boolean;
|
|
9
|
+
render(): void;
|
|
10
|
+
addEntry(entry: Entry): void;
|
|
11
|
+
addSessionAbortedEntry(): void;
|
|
12
|
+
setStatus(status: string): void;
|
|
13
|
+
setSessionStatus(session: AgentSession | undefined): void;
|
|
14
|
+
setSessionActivity(activity: SessionActivity): void;
|
|
15
|
+
showToast(message: string, kind: "success" | "error" | "warning" | "info"): void;
|
|
16
|
+
inputText(): string;
|
|
17
|
+
resetRequestHistoryNavigation(): void;
|
|
18
|
+
clearInput(): void;
|
|
19
|
+
setInput(value: string): void;
|
|
20
|
+
insertInput(value: string): void;
|
|
21
|
+
attachImage(data: string, mimeType: string): void;
|
|
22
|
+
};
|
|
23
|
+
export declare class AppQueuedMessageController {
|
|
24
|
+
private readonly host;
|
|
25
|
+
readonly deferredUserMessages: SubmittedUserMessage[];
|
|
26
|
+
private promptSubmissionInFlight;
|
|
27
|
+
private flushingDeferredUserMessages;
|
|
28
|
+
private immediateSendInProgress;
|
|
29
|
+
constructor(host: AppQueuedMessageControllerHost);
|
|
30
|
+
reset(): void;
|
|
31
|
+
createSubmittedUserMessage(promptText: string, displayText: string, images: ImageContent[]): SubmittedUserMessage;
|
|
32
|
+
submitUserMessage(message: SubmittedUserMessage): Promise<void>;
|
|
33
|
+
sendUserMessageToSession(message: SubmittedUserMessage, options?: {
|
|
34
|
+
streamingBehavior?: "steer" | "followUp";
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
flushDeferredUserMessages(): Promise<void>;
|
|
37
|
+
queuedMessageCounts(): {
|
|
38
|
+
steering: number;
|
|
39
|
+
followUp: number;
|
|
40
|
+
};
|
|
41
|
+
totalQueuedMessageCount(): number;
|
|
42
|
+
updateQueuedMessageStatus(): void;
|
|
43
|
+
restoreQueuedMessagesToEditorForAbort(): number;
|
|
44
|
+
cancelQueuedMessage(entryId: string): Promise<void>;
|
|
45
|
+
editQueuedMessage(entryId: string): Promise<void>;
|
|
46
|
+
sendQueuedMessageImmediately(entryId: string): Promise<void>;
|
|
47
|
+
findQueuedEntry(entryId: string): Extract<Entry, {
|
|
48
|
+
kind: "queued";
|
|
49
|
+
}> | undefined;
|
|
50
|
+
private shouldDeferUserMessage;
|
|
51
|
+
private deferUserMessage;
|
|
52
|
+
private rewriteSdkQueuedMessages;
|
|
53
|
+
private takeQueuedEntryForInterruptedSend;
|
|
54
|
+
private restoreSdkQueuedMessages;
|
|
55
|
+
private interruptSessionForImmediateSend;
|
|
56
|
+
private waitForCompactionToStop;
|
|
57
|
+
private sessionActivity;
|
|
58
|
+
private removeQueuedEntry;
|
|
59
|
+
private requeueRemovedEntry;
|
|
60
|
+
private restoreSubmittedMessageToEditor;
|
|
61
|
+
private restorableSubmittedMessageText;
|
|
62
|
+
}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { createId } from "./id.js";
|
|
2
|
+
import { stringifyUnknown, submittedUserDisplayText } from "./message-content.js";
|
|
3
|
+
export class AppQueuedMessageController {
|
|
4
|
+
host;
|
|
5
|
+
deferredUserMessages = [];
|
|
6
|
+
promptSubmissionInFlight = false;
|
|
7
|
+
flushingDeferredUserMessages = false;
|
|
8
|
+
immediateSendInProgress = false;
|
|
9
|
+
constructor(host) {
|
|
10
|
+
this.host = host;
|
|
11
|
+
}
|
|
12
|
+
reset() {
|
|
13
|
+
this.deferredUserMessages.length = 0;
|
|
14
|
+
this.promptSubmissionInFlight = false;
|
|
15
|
+
this.flushingDeferredUserMessages = false;
|
|
16
|
+
}
|
|
17
|
+
createSubmittedUserMessage(promptText, displayText, images) {
|
|
18
|
+
return {
|
|
19
|
+
id: createId("queued-user"),
|
|
20
|
+
promptText,
|
|
21
|
+
displayText: submittedUserDisplayText(displayText, promptText, images),
|
|
22
|
+
images,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async submitUserMessage(message) {
|
|
26
|
+
const session = this.host.requireRuntime().session;
|
|
27
|
+
if (this.shouldDeferUserMessage(session)) {
|
|
28
|
+
this.deferUserMessage(message);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
await this.sendUserMessageToSession(message);
|
|
32
|
+
}
|
|
33
|
+
async sendUserMessageToSession(message, options = {}) {
|
|
34
|
+
const session = this.host.requireRuntime().session;
|
|
35
|
+
const markInFlight = !session.isStreaming;
|
|
36
|
+
if (markInFlight)
|
|
37
|
+
this.promptSubmissionInFlight = true;
|
|
38
|
+
this.host.setSessionActivity("running");
|
|
39
|
+
try {
|
|
40
|
+
const opts = {};
|
|
41
|
+
if (session.isStreaming)
|
|
42
|
+
opts.streamingBehavior = options.streamingBehavior ?? "steer";
|
|
43
|
+
if (message.images.length > 0)
|
|
44
|
+
opts.images = message.images;
|
|
45
|
+
await session.prompt(message.promptText, Object.keys(opts).length > 0 ? opts : undefined);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
if (markInFlight)
|
|
49
|
+
this.promptSubmissionInFlight = false;
|
|
50
|
+
const runtime = this.host.runtime();
|
|
51
|
+
if (runtime) {
|
|
52
|
+
const activeSession = runtime.session;
|
|
53
|
+
this.host.setSessionStatus(activeSession);
|
|
54
|
+
this.host.setSessionActivity(activeSession.isStreaming || activeSession.isCompacting ? "running" : "idle");
|
|
55
|
+
}
|
|
56
|
+
if (this.totalQueuedMessageCount() > 0)
|
|
57
|
+
this.updateQueuedMessageStatus();
|
|
58
|
+
if (!this.flushingDeferredUserMessages)
|
|
59
|
+
void this.flushDeferredUserMessages();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async flushDeferredUserMessages() {
|
|
63
|
+
if (this.immediateSendInProgress || this.flushingDeferredUserMessages || this.deferredUserMessages.length === 0)
|
|
64
|
+
return;
|
|
65
|
+
const session = this.host.runtime()?.session;
|
|
66
|
+
if (!session || session.isCompacting)
|
|
67
|
+
return;
|
|
68
|
+
if (!session.isStreaming && this.promptSubmissionInFlight)
|
|
69
|
+
return;
|
|
70
|
+
this.flushingDeferredUserMessages = true;
|
|
71
|
+
try {
|
|
72
|
+
while (this.deferredUserMessages.length > 0) {
|
|
73
|
+
if (this.immediateSendInProgress)
|
|
74
|
+
break;
|
|
75
|
+
const activeSession = this.host.runtime()?.session;
|
|
76
|
+
if (!activeSession || activeSession.isCompacting)
|
|
77
|
+
break;
|
|
78
|
+
if (!activeSession.isStreaming && this.promptSubmissionInFlight)
|
|
79
|
+
break;
|
|
80
|
+
const message = this.deferredUserMessages.shift();
|
|
81
|
+
if (!message)
|
|
82
|
+
break;
|
|
83
|
+
this.updateQueuedMessageStatus();
|
|
84
|
+
if (!activeSession.isStreaming && this.deferredUserMessages.length > 0) {
|
|
85
|
+
void this.sendUserMessageToSession(message).catch((error) => {
|
|
86
|
+
this.deferredUserMessages.unshift(message);
|
|
87
|
+
this.updateQueuedMessageStatus();
|
|
88
|
+
this.host.addEntry({ id: createId("error"), kind: "error", text: `Queued message failed: ${stringifyUnknown(error)}` });
|
|
89
|
+
if (this.host.isRunning())
|
|
90
|
+
this.host.render();
|
|
91
|
+
});
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
await this.sendUserMessageToSession(message);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
this.deferredUserMessages.unshift(message);
|
|
99
|
+
this.updateQueuedMessageStatus();
|
|
100
|
+
this.host.addEntry({ id: createId("error"), kind: "error", text: `Queued message failed: ${stringifyUnknown(error)}` });
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
const shouldRetryFlush = this.deferredUserMessages.length > 0 && Boolean(this.host.runtime()?.session) && !this.host.runtime()?.session.isCompacting;
|
|
107
|
+
this.flushingDeferredUserMessages = false;
|
|
108
|
+
if (this.totalQueuedMessageCount() > 0)
|
|
109
|
+
this.updateQueuedMessageStatus();
|
|
110
|
+
if (this.host.isRunning())
|
|
111
|
+
this.host.render();
|
|
112
|
+
if (shouldRetryFlush) {
|
|
113
|
+
queueMicrotask(() => {
|
|
114
|
+
void this.flushDeferredUserMessages();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
queuedMessageCounts() {
|
|
120
|
+
const session = this.host.runtime()?.session;
|
|
121
|
+
return {
|
|
122
|
+
steering: (session?.getSteeringMessages().length ?? 0) + this.deferredUserMessages.length,
|
|
123
|
+
followUp: session?.getFollowUpMessages().length ?? 0,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
totalQueuedMessageCount() {
|
|
127
|
+
const { steering, followUp } = this.queuedMessageCounts();
|
|
128
|
+
return steering + followUp;
|
|
129
|
+
}
|
|
130
|
+
updateQueuedMessageStatus() {
|
|
131
|
+
if (this.totalQueuedMessageCount() === 0)
|
|
132
|
+
this.host.setSessionStatus(this.host.runtime()?.session);
|
|
133
|
+
}
|
|
134
|
+
restoreQueuedMessagesToEditorForAbort() {
|
|
135
|
+
const session = this.host.runtime()?.session;
|
|
136
|
+
const sdkQueued = session?.clearQueue() ?? { steering: [], followUp: [] };
|
|
137
|
+
const deferred = this.deferredUserMessages.splice(0);
|
|
138
|
+
const restoredTexts = [
|
|
139
|
+
...sdkQueued.steering,
|
|
140
|
+
...deferred.map((message) => this.restorableSubmittedMessageText(message)),
|
|
141
|
+
...sdkQueued.followUp,
|
|
142
|
+
]
|
|
143
|
+
.map((text) => text.trimEnd())
|
|
144
|
+
.filter((text) => text.trim().length > 0);
|
|
145
|
+
const images = deferred.flatMap((message) => message.images);
|
|
146
|
+
const restoredCount = sdkQueued.steering.length + sdkQueued.followUp.length + deferred.length;
|
|
147
|
+
if (restoredTexts.length > 0 || images.length > 0) {
|
|
148
|
+
const currentText = this.host.inputText().trimEnd();
|
|
149
|
+
const combinedText = [...restoredTexts, currentText]
|
|
150
|
+
.filter((text) => text.trim().length > 0)
|
|
151
|
+
.join("\n\n");
|
|
152
|
+
this.host.setInput(combinedText);
|
|
153
|
+
if (combinedText && images.length > 0)
|
|
154
|
+
this.host.insertInput("\n");
|
|
155
|
+
for (const image of images)
|
|
156
|
+
this.host.attachImage(image.data, image.mimeType);
|
|
157
|
+
}
|
|
158
|
+
this.updateQueuedMessageStatus();
|
|
159
|
+
return restoredCount;
|
|
160
|
+
}
|
|
161
|
+
async cancelQueuedMessage(entryId) {
|
|
162
|
+
const entry = this.findQueuedEntry(entryId);
|
|
163
|
+
if (!entry)
|
|
164
|
+
throw new Error("Queued message is no longer available");
|
|
165
|
+
await this.removeQueuedEntry(entry);
|
|
166
|
+
this.updateQueuedMessageStatus();
|
|
167
|
+
this.host.showToast("Queued message cancelled", "success");
|
|
168
|
+
}
|
|
169
|
+
async editQueuedMessage(entryId) {
|
|
170
|
+
const entry = this.findQueuedEntry(entryId);
|
|
171
|
+
if (!entry)
|
|
172
|
+
throw new Error("Queued message is no longer available");
|
|
173
|
+
const removed = await this.removeQueuedEntry(entry);
|
|
174
|
+
this.host.resetRequestHistoryNavigation();
|
|
175
|
+
if (typeof removed === "string") {
|
|
176
|
+
this.host.clearInput();
|
|
177
|
+
this.host.setInput(removed);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.restoreSubmittedMessageToEditor(removed);
|
|
181
|
+
}
|
|
182
|
+
this.updateQueuedMessageStatus();
|
|
183
|
+
this.host.showToast("Queued message moved to editor", "success");
|
|
184
|
+
}
|
|
185
|
+
async sendQueuedMessageImmediately(entryId) {
|
|
186
|
+
const entry = this.findQueuedEntry(entryId);
|
|
187
|
+
if (!entry)
|
|
188
|
+
throw new Error("Queued message is no longer available");
|
|
189
|
+
const session = this.host.requireRuntime().session;
|
|
190
|
+
const shouldInterrupt = session.isStreaming || session.isCompacting;
|
|
191
|
+
const taken = shouldInterrupt
|
|
192
|
+
? this.takeQueuedEntryForInterruptedSend(entry, session)
|
|
193
|
+
: { removed: await this.removeQueuedEntry(entry), sdkMessagesToRestore: undefined };
|
|
194
|
+
this.updateQueuedMessageStatus();
|
|
195
|
+
this.host.setStatus("sending queued message");
|
|
196
|
+
this.host.render();
|
|
197
|
+
this.immediateSendInProgress = true;
|
|
198
|
+
try {
|
|
199
|
+
if (shouldInterrupt)
|
|
200
|
+
await this.interruptSessionForImmediateSend(session);
|
|
201
|
+
if (taken.sdkMessagesToRestore) {
|
|
202
|
+
await this.restoreSdkQueuedMessages(taken.sdkMessagesToRestore);
|
|
203
|
+
taken.sdkMessagesToRestore = undefined;
|
|
204
|
+
}
|
|
205
|
+
const message = typeof taken.removed === "string"
|
|
206
|
+
? this.createSubmittedUserMessage(taken.removed, taken.removed, [])
|
|
207
|
+
: taken.removed;
|
|
208
|
+
await this.sendUserMessageToSession(message, { streamingBehavior: "steer" });
|
|
209
|
+
this.host.setSessionStatus(this.host.runtime()?.session);
|
|
210
|
+
this.host.showToast("Queued message sent", "success");
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
if (taken.sdkMessagesToRestore) {
|
|
214
|
+
try {
|
|
215
|
+
await this.restoreSdkQueuedMessages(taken.sdkMessagesToRestore);
|
|
216
|
+
}
|
|
217
|
+
catch { /* best-effort rollback */ }
|
|
218
|
+
}
|
|
219
|
+
await this.requeueRemovedEntry(entry, taken.removed);
|
|
220
|
+
this.updateQueuedMessageStatus();
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
this.immediateSendInProgress = false;
|
|
225
|
+
if (this.totalQueuedMessageCount() > 0)
|
|
226
|
+
this.updateQueuedMessageStatus();
|
|
227
|
+
if (!this.flushingDeferredUserMessages)
|
|
228
|
+
void this.flushDeferredUserMessages();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
findQueuedEntry(entryId) {
|
|
232
|
+
const entry = this.host.visibleEntries().find((candidate) => candidate.id === entryId);
|
|
233
|
+
return entry?.kind === "queued" ? entry : undefined;
|
|
234
|
+
}
|
|
235
|
+
shouldDeferUserMessage(session) {
|
|
236
|
+
return session.isCompacting || (!session.isStreaming && this.promptSubmissionInFlight);
|
|
237
|
+
}
|
|
238
|
+
deferUserMessage(message) {
|
|
239
|
+
this.deferredUserMessages.push(message);
|
|
240
|
+
this.updateQueuedMessageStatus();
|
|
241
|
+
this.host.render();
|
|
242
|
+
}
|
|
243
|
+
async rewriteSdkQueuedMessages(update) {
|
|
244
|
+
const session = this.host.requireRuntime().session;
|
|
245
|
+
const originalSteering = [...session.getSteeringMessages()];
|
|
246
|
+
const originalFollowUp = [...session.getFollowUpMessages()];
|
|
247
|
+
const steering = [...originalSteering];
|
|
248
|
+
const followUp = [...originalFollowUp];
|
|
249
|
+
const result = update(steering, followUp);
|
|
250
|
+
session.clearQueue();
|
|
251
|
+
try {
|
|
252
|
+
for (const text of steering)
|
|
253
|
+
await session.steer(text);
|
|
254
|
+
for (const text of followUp)
|
|
255
|
+
await session.followUp(text);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
session.clearQueue();
|
|
259
|
+
for (const text of originalSteering) {
|
|
260
|
+
try {
|
|
261
|
+
await session.steer(text);
|
|
262
|
+
}
|
|
263
|
+
catch { /* best-effort rollback */ }
|
|
264
|
+
}
|
|
265
|
+
for (const text of originalFollowUp) {
|
|
266
|
+
try {
|
|
267
|
+
await session.followUp(text);
|
|
268
|
+
}
|
|
269
|
+
catch { /* best-effort rollback */ }
|
|
270
|
+
}
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
takeQueuedEntryForInterruptedSend(entry, session) {
|
|
276
|
+
const sdkMessages = {
|
|
277
|
+
steering: [...session.getSteeringMessages()],
|
|
278
|
+
followUp: [...session.getFollowUpMessages()],
|
|
279
|
+
};
|
|
280
|
+
if (entry.queueSource === "deferred") {
|
|
281
|
+
const [message] = this.deferredUserMessages.splice(entry.queueIndex, 1);
|
|
282
|
+
if (!message)
|
|
283
|
+
throw new Error("Queued message is no longer available");
|
|
284
|
+
session.clearQueue();
|
|
285
|
+
return { removed: message, sdkMessagesToRestore: sdkMessages };
|
|
286
|
+
}
|
|
287
|
+
const messages = entry.queueSource === "sdk-steering" ? sdkMessages.steering : sdkMessages.followUp;
|
|
288
|
+
const [removed] = messages.splice(entry.queueIndex, 1);
|
|
289
|
+
if (removed === undefined)
|
|
290
|
+
throw new Error("Queued message is no longer available");
|
|
291
|
+
session.clearQueue();
|
|
292
|
+
return { removed, sdkMessagesToRestore: sdkMessages };
|
|
293
|
+
}
|
|
294
|
+
async restoreSdkQueuedMessages(messages) {
|
|
295
|
+
const session = this.host.requireRuntime().session;
|
|
296
|
+
for (const text of messages.steering)
|
|
297
|
+
await session.steer(text);
|
|
298
|
+
for (const text of messages.followUp)
|
|
299
|
+
await session.followUp(text);
|
|
300
|
+
}
|
|
301
|
+
async interruptSessionForImmediateSend(session) {
|
|
302
|
+
if (session.isCompacting) {
|
|
303
|
+
this.host.setStatus("aborting compaction");
|
|
304
|
+
session.abortCompaction();
|
|
305
|
+
this.host.render();
|
|
306
|
+
}
|
|
307
|
+
if (session.isStreaming) {
|
|
308
|
+
this.host.setStatus("aborting current response");
|
|
309
|
+
this.host.addSessionAbortedEntry();
|
|
310
|
+
this.host.render();
|
|
311
|
+
await session.abort();
|
|
312
|
+
}
|
|
313
|
+
if (session.isCompacting)
|
|
314
|
+
await this.waitForCompactionToStop(session);
|
|
315
|
+
this.host.setSessionStatus(this.host.runtime()?.session);
|
|
316
|
+
this.host.setSessionActivity(this.sessionActivity(this.host.runtime()?.session));
|
|
317
|
+
}
|
|
318
|
+
async waitForCompactionToStop(session) {
|
|
319
|
+
const startedAt = Date.now();
|
|
320
|
+
while (session.isCompacting && this.host.runtime()?.session === session) {
|
|
321
|
+
if (Date.now() - startedAt > 5000)
|
|
322
|
+
throw new Error("Timed out waiting for compaction to abort");
|
|
323
|
+
await new Promise((resolve) => {
|
|
324
|
+
const timer = setTimeout(resolve, 25);
|
|
325
|
+
timer.unref?.();
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
sessionActivity(session) {
|
|
330
|
+
return session?.isStreaming || session?.isCompacting ? "running" : "idle";
|
|
331
|
+
}
|
|
332
|
+
async removeQueuedEntry(entry) {
|
|
333
|
+
if (entry.queueSource === "deferred") {
|
|
334
|
+
const [message] = this.deferredUserMessages.splice(entry.queueIndex, 1);
|
|
335
|
+
if (!message)
|
|
336
|
+
throw new Error("Queued message is no longer available");
|
|
337
|
+
return message;
|
|
338
|
+
}
|
|
339
|
+
const removed = await this.rewriteSdkQueuedMessages((steering, followUp) => {
|
|
340
|
+
const messages = entry.queueSource === "sdk-steering" ? steering : followUp;
|
|
341
|
+
const [text] = messages.splice(entry.queueIndex, 1);
|
|
342
|
+
return text;
|
|
343
|
+
});
|
|
344
|
+
if (removed === undefined)
|
|
345
|
+
throw new Error("Queued message is no longer available");
|
|
346
|
+
return removed;
|
|
347
|
+
}
|
|
348
|
+
async requeueRemovedEntry(entry, removed) {
|
|
349
|
+
if (entry.queueSource === "deferred") {
|
|
350
|
+
if (typeof removed === "string")
|
|
351
|
+
return;
|
|
352
|
+
this.deferredUserMessages.splice(Math.min(entry.queueIndex, this.deferredUserMessages.length), 0, removed);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (typeof removed !== "string")
|
|
356
|
+
return;
|
|
357
|
+
await this.rewriteSdkQueuedMessages((steering, followUp) => {
|
|
358
|
+
const messages = entry.queueSource === "sdk-steering" ? steering : followUp;
|
|
359
|
+
messages.splice(Math.min(entry.queueIndex, messages.length), 0, removed);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
restoreSubmittedMessageToEditor(message) {
|
|
363
|
+
const text = this.restorableSubmittedMessageText(message);
|
|
364
|
+
this.host.clearInput();
|
|
365
|
+
if (text || message.images.length === 0)
|
|
366
|
+
this.host.setInput(text || message.displayText);
|
|
367
|
+
if (text && message.images.length > 0)
|
|
368
|
+
this.host.insertInput("\n");
|
|
369
|
+
for (const image of message.images)
|
|
370
|
+
this.host.attachImage(image.data, image.mimeType);
|
|
371
|
+
}
|
|
372
|
+
restorableSubmittedMessageText(message) {
|
|
373
|
+
return message.images.length > 0
|
|
374
|
+
? message.promptText.replace(/\[Image \d+(?:: [^\]]+)?\]\s*/g, "").trimEnd()
|
|
375
|
+
: message.promptText.trimEnd();
|
|
376
|
+
}
|
|
377
|
+
}
|