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,230 @@
|
|
|
1
|
+
export function normalizeToolName(toolName) {
|
|
2
|
+
const lastPart = toolName.split(/[.:/]/).filter(Boolean).at(-1) ?? toolName;
|
|
3
|
+
return lastPart.trim();
|
|
4
|
+
}
|
|
5
|
+
export function parseArgsText(argsText) {
|
|
6
|
+
const trimmed = argsText.trim();
|
|
7
|
+
if (!trimmed)
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(trimmed);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return trimmed;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function argsRecord(input) {
|
|
17
|
+
const parsed = parseArgsText(input.argsText);
|
|
18
|
+
return isPlainRecord(parsed) ? parsed : undefined;
|
|
19
|
+
}
|
|
20
|
+
export function stringArg(input, keys) {
|
|
21
|
+
const record = argsRecord(input);
|
|
22
|
+
if (!record)
|
|
23
|
+
return undefined;
|
|
24
|
+
for (const key of keys) {
|
|
25
|
+
const value = record[key];
|
|
26
|
+
if (typeof value === "string" && value.trim())
|
|
27
|
+
return value.trim();
|
|
28
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
29
|
+
return String(value);
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
export function numberArg(input, keys) {
|
|
34
|
+
const record = argsRecord(input);
|
|
35
|
+
if (!record)
|
|
36
|
+
return undefined;
|
|
37
|
+
for (const key of keys) {
|
|
38
|
+
const value = record[key];
|
|
39
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
export function defaultToolRender(input) {
|
|
45
|
+
const args = parseArgsText(input.argsText);
|
|
46
|
+
const argsInline = formatArgsInline(args);
|
|
47
|
+
const argsBlock = formatArgsBlock(args);
|
|
48
|
+
const expanded = argsAndResultExpandedText(input, argsBlock);
|
|
49
|
+
return {
|
|
50
|
+
headerArgs: argsInline,
|
|
51
|
+
collapsedBody: input.output || argsBlock,
|
|
52
|
+
...expanded,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function renderWithArgsAndResult(input, options = {}) {
|
|
56
|
+
const args = parseArgsText(input.argsText);
|
|
57
|
+
const argsBlock = options.argumentsBody ?? formatArgsBlock(args);
|
|
58
|
+
const expanded = argsAndResultExpandedText(input, argsBlock);
|
|
59
|
+
return {
|
|
60
|
+
headerArgs: options.headerArgs ?? formatArgsInline(args),
|
|
61
|
+
collapsedBody: (options.collapsedBody ?? input.output) || argsBlock,
|
|
62
|
+
...expanded,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function resultSection(input) {
|
|
66
|
+
if (input.output)
|
|
67
|
+
return input.isError ? labeledBlock("error", input.output) : input.output;
|
|
68
|
+
return input.status === "running" ? "running…" : "(empty)";
|
|
69
|
+
}
|
|
70
|
+
export function argsAndResultExpandedText(input, argsBlock) {
|
|
71
|
+
const formattedArgs = argsBlock.trimEnd();
|
|
72
|
+
const showArgs = formattedArgs.length > 0 && formattedArgs !== "(empty)";
|
|
73
|
+
return expandedTextFromParts(...(showArgs ? [{ text: formattedArgs, color: "muted" }] : []), { text: resultText(input, { empty: !showArgs }) });
|
|
74
|
+
}
|
|
75
|
+
export function resultText(input, options = {}) {
|
|
76
|
+
if (input.output)
|
|
77
|
+
return input.isError ? labeledBlock("error", input.output) : input.output;
|
|
78
|
+
if (input.status === "running")
|
|
79
|
+
return "running…";
|
|
80
|
+
return options.empty === false ? "" : "(empty)";
|
|
81
|
+
}
|
|
82
|
+
export function expandedTextFromParts(...parts) {
|
|
83
|
+
const textParts = [];
|
|
84
|
+
const bodyLineStyles = [];
|
|
85
|
+
let startLine = 0;
|
|
86
|
+
for (const part of parts) {
|
|
87
|
+
const text = part.text?.trimEnd();
|
|
88
|
+
if (!text)
|
|
89
|
+
continue;
|
|
90
|
+
if (textParts.length > 0)
|
|
91
|
+
startLine += 1;
|
|
92
|
+
textParts.push(text);
|
|
93
|
+
const partLines = lineCount(text);
|
|
94
|
+
if (part.color || part.foreground || part.bold || part.underline || part.strikethrough) {
|
|
95
|
+
bodyLineStyles.push({
|
|
96
|
+
startLine,
|
|
97
|
+
endLine: startLine + partLines,
|
|
98
|
+
...(part.color ? { color: part.color } : {}),
|
|
99
|
+
...(part.foreground ? { foreground: part.foreground } : {}),
|
|
100
|
+
...(part.bold != null ? { bold: part.bold } : {}),
|
|
101
|
+
...(part.underline != null ? { underline: part.underline } : {}),
|
|
102
|
+
...(part.strikethrough != null ? { strikethrough: part.strikethrough } : {}),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
startLine += partLines;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
expandedText: joinSections(...textParts),
|
|
109
|
+
...(bodyLineStyles.length > 0 ? { bodyLineStyles } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export function labeledBlock(title, body) {
|
|
113
|
+
const content = body?.trimEnd();
|
|
114
|
+
return content ? `${title}\n${content}` : "";
|
|
115
|
+
}
|
|
116
|
+
export function joinSections(...parts) {
|
|
117
|
+
const joined = parts.filter((part) => part.trim()).join("\n\n");
|
|
118
|
+
return joined || "(empty)";
|
|
119
|
+
}
|
|
120
|
+
export function indent(text, spaces = 2) {
|
|
121
|
+
const prefix = " ".repeat(spaces);
|
|
122
|
+
return text.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
123
|
+
}
|
|
124
|
+
export function lineCount(text) {
|
|
125
|
+
return text.split("\n").length;
|
|
126
|
+
}
|
|
127
|
+
export function formatArgsInline(args, preferredKeys) {
|
|
128
|
+
if (args == null)
|
|
129
|
+
return "";
|
|
130
|
+
if (typeof args === "string")
|
|
131
|
+
return oneLine(args);
|
|
132
|
+
if (!isPlainRecord(args))
|
|
133
|
+
return formatInlineValue(args);
|
|
134
|
+
const entries = orderedEntries(args, preferredKeys);
|
|
135
|
+
return entries.map(([key, value]) => `${key}: ${formatInlineValue(value)}`).join(" · ");
|
|
136
|
+
}
|
|
137
|
+
export function formatArgsBlock(args, preferredKeys) {
|
|
138
|
+
if (args == null)
|
|
139
|
+
return "(empty)";
|
|
140
|
+
if (typeof args === "string")
|
|
141
|
+
return args;
|
|
142
|
+
if (!isPlainRecord(args))
|
|
143
|
+
return formatBlockValue(args, 0);
|
|
144
|
+
const entries = orderedEntries(args, preferredKeys);
|
|
145
|
+
if (entries.length === 0)
|
|
146
|
+
return "(empty)";
|
|
147
|
+
return entries.map(([key, value]) => formatRecordEntry(key, value, 0)).join("\n");
|
|
148
|
+
}
|
|
149
|
+
export function summarizePatch(text) {
|
|
150
|
+
if (!text)
|
|
151
|
+
return undefined;
|
|
152
|
+
const files = new Set();
|
|
153
|
+
for (const line of text.split("\n")) {
|
|
154
|
+
const trimmed = line.trim();
|
|
155
|
+
const match = /^(?:\*\*\* (?:Update|Add|Delete) File:\s*|Index:\s+|---\s+(?:a\/)?|\+\+\+\s+(?:b\/)?|diff --git a\/)(.+?)(?:\s|$)/.exec(trimmed);
|
|
156
|
+
const file = match?.[1]?.trim();
|
|
157
|
+
if (file && !file.startsWith("/dev/null"))
|
|
158
|
+
files.add(file.replace(/^[ab]\//, ""));
|
|
159
|
+
}
|
|
160
|
+
if (files.size === 0)
|
|
161
|
+
return undefined;
|
|
162
|
+
const list = [...files];
|
|
163
|
+
const shown = list.slice(0, 3).join(", ");
|
|
164
|
+
return list.length > 3 ? `${shown}, +${list.length - 3}` : shown;
|
|
165
|
+
}
|
|
166
|
+
export function compactCommand(command) {
|
|
167
|
+
return command ? command.replace(/\s+/g, " ").trim() : undefined;
|
|
168
|
+
}
|
|
169
|
+
function orderedEntries(record, preferredKeys) {
|
|
170
|
+
const entries = Object.entries(record).filter(([, value]) => value !== undefined);
|
|
171
|
+
if (!preferredKeys || preferredKeys.length === 0)
|
|
172
|
+
return entries;
|
|
173
|
+
const order = new Map(preferredKeys.map((key, index) => [key, index]));
|
|
174
|
+
return entries.sort(([left], [right]) => (order.get(left) ?? Number.MAX_SAFE_INTEGER) - (order.get(right) ?? Number.MAX_SAFE_INTEGER));
|
|
175
|
+
}
|
|
176
|
+
function formatRecordEntry(key, value, depth) {
|
|
177
|
+
if (isPlainRecord(value) || Array.isArray(value)) {
|
|
178
|
+
return `${key}:\n${indent(formatBlockValue(value, depth + 1))}`;
|
|
179
|
+
}
|
|
180
|
+
return `${key}: ${formatBlockValue(value, depth)}`;
|
|
181
|
+
}
|
|
182
|
+
function formatBlockValue(value, depth) {
|
|
183
|
+
if (value == null)
|
|
184
|
+
return String(value);
|
|
185
|
+
if (typeof value === "string")
|
|
186
|
+
return value;
|
|
187
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint")
|
|
188
|
+
return String(value);
|
|
189
|
+
if (Array.isArray(value)) {
|
|
190
|
+
if (value.length === 0)
|
|
191
|
+
return "[]";
|
|
192
|
+
if (depth >= 2)
|
|
193
|
+
return `[${value.length} items]`;
|
|
194
|
+
return value.map((item) => `- ${formatBlockValue(item, depth + 1).replace(/\n/g, "\n ")}`).join("\n");
|
|
195
|
+
}
|
|
196
|
+
if (isPlainRecord(value)) {
|
|
197
|
+
const entries = Object.entries(value);
|
|
198
|
+
if (entries.length === 0)
|
|
199
|
+
return "{}";
|
|
200
|
+
if (depth >= 2)
|
|
201
|
+
return `{${entries.map(([key]) => key).join(", ")}}`;
|
|
202
|
+
return entries.map(([key, nested]) => formatRecordEntry(key, nested, depth + 1)).join("\n");
|
|
203
|
+
}
|
|
204
|
+
return String(value);
|
|
205
|
+
}
|
|
206
|
+
function formatInlineValue(value) {
|
|
207
|
+
if (value == null)
|
|
208
|
+
return String(value);
|
|
209
|
+
if (typeof value === "string")
|
|
210
|
+
return oneLine(value);
|
|
211
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint")
|
|
212
|
+
return String(value);
|
|
213
|
+
if (Array.isArray(value)) {
|
|
214
|
+
if (value.length === 0)
|
|
215
|
+
return "[]";
|
|
216
|
+
const preview = value.slice(0, 3).map(formatInlineValue).join(", ");
|
|
217
|
+
return value.length > 3 ? `[${preview}, +${value.length - 3}]` : `[${preview}]`;
|
|
218
|
+
}
|
|
219
|
+
if (isPlainRecord(value)) {
|
|
220
|
+
const keys = Object.keys(value);
|
|
221
|
+
return keys.length === 0 ? "{}" : `{${keys.slice(0, 4).join(", ")}${keys.length > 4 ? ", …" : ""}}`;
|
|
222
|
+
}
|
|
223
|
+
return String(value);
|
|
224
|
+
}
|
|
225
|
+
function oneLine(text) {
|
|
226
|
+
return text.replace(/\s+/g, " ").trim();
|
|
227
|
+
}
|
|
228
|
+
function isPlainRecord(value) {
|
|
229
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
230
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { renderWithArgsAndResult, stringArg } from "./utils.js";
|
|
2
|
+
export const renderWebSearchTool = (input) => {
|
|
3
|
+
const query = stringArg(input, ["query"]);
|
|
4
|
+
return renderWithArgsAndResult(input, { headerArgs: query, collapsedBody: input.output });
|
|
5
|
+
};
|
|
6
|
+
export const renderWebFetchTool = (input) => {
|
|
7
|
+
const url = stringArg(input, ["url"]);
|
|
8
|
+
return renderWithArgsAndResult(input, { headerArgs: url, collapsedBody: input.output });
|
|
9
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isAbsolute, relative, sep } from "node:path";
|
|
2
|
+
import { syntaxHighlightLanguageForPath } from "../syntax-highlight.js";
|
|
3
|
+
import { argsRecord, expandedTextFromParts, lineCount, resultText, stringArg } from "./utils.js";
|
|
4
|
+
export const renderWriteTool = (input) => {
|
|
5
|
+
const filePath = stringArg(input, ["path", "file_path", "filePath"]);
|
|
6
|
+
if (!filePath)
|
|
7
|
+
return undefined;
|
|
8
|
+
const displayPath = pathForDisplay(filePath, input.cwd);
|
|
9
|
+
const content = writeContent(input);
|
|
10
|
+
const expanded = expandedTextFromParts({ text: content !== undefined ? content || "(empty)" : "" }, { text: resultText(input, { empty: content === undefined }) });
|
|
11
|
+
const rendered = {
|
|
12
|
+
headerArgs: displayPath,
|
|
13
|
+
collapsedBody: content ?? input.output,
|
|
14
|
+
...expanded,
|
|
15
|
+
};
|
|
16
|
+
if (content === undefined)
|
|
17
|
+
return rendered;
|
|
18
|
+
const syntaxLanguage = !input.isError ? syntaxHighlightLanguageForPath(filePath) : undefined;
|
|
19
|
+
if (!syntaxLanguage)
|
|
20
|
+
return rendered;
|
|
21
|
+
return {
|
|
22
|
+
...rendered,
|
|
23
|
+
syntaxHighlight: {
|
|
24
|
+
language: syntaxLanguage,
|
|
25
|
+
startLine: 0,
|
|
26
|
+
endLine: lineCount(content || "(empty)"),
|
|
27
|
+
startColumn: 0,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
function writeContent(input) {
|
|
32
|
+
const content = argsRecord(input)?.content;
|
|
33
|
+
return typeof content === "string" ? content : undefined;
|
|
34
|
+
}
|
|
35
|
+
function pathForDisplay(filePath, cwd) {
|
|
36
|
+
if (!cwd || !isAbsolute(filePath))
|
|
37
|
+
return filePath;
|
|
38
|
+
const relativePath = relative(cwd, filePath);
|
|
39
|
+
if (!relativePath)
|
|
40
|
+
return ".";
|
|
41
|
+
return relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath) ? filePath : relativePath.replace(/\\/gu, "/");
|
|
42
|
+
}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type PopupMenuItem<T> = {
|
|
2
|
+
value: T;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
};
|
|
6
|
+
export type VisiblePopupMenuItem<T> = PopupMenuItem<T> & {
|
|
7
|
+
index: number;
|
|
8
|
+
selected: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare class PopupMenu<T> {
|
|
11
|
+
readonly maxVisibleRows: number;
|
|
12
|
+
items: PopupMenuItem<T>[];
|
|
13
|
+
selectedIndex: number;
|
|
14
|
+
scrollOffset: number;
|
|
15
|
+
open: boolean;
|
|
16
|
+
constructor(options: {
|
|
17
|
+
maxVisibleRows: number;
|
|
18
|
+
});
|
|
19
|
+
setItems(items: readonly PopupMenuItem<T>[]): void;
|
|
20
|
+
openWithItems(items: readonly PopupMenuItem<T>[]): void;
|
|
21
|
+
close(): void;
|
|
22
|
+
selectedItem(): PopupMenuItem<T> | undefined;
|
|
23
|
+
moveSelection(delta: number): void;
|
|
24
|
+
scroll(delta: number): void;
|
|
25
|
+
visibleItems(): VisiblePopupMenuItem<T>[];
|
|
26
|
+
maxScrollOffset(): number;
|
|
27
|
+
private ensureSelectedVisible;
|
|
28
|
+
}
|
|
29
|
+
export declare const TOAST_KINDS: readonly ["success", "error", "warning", "info"];
|
|
30
|
+
export type ToastKind = (typeof TOAST_KINDS)[number];
|
|
31
|
+
export type ToastState = {
|
|
32
|
+
message: string;
|
|
33
|
+
kind: ToastKind;
|
|
34
|
+
};
|
|
35
|
+
export type ToastEntry = ToastState & {
|
|
36
|
+
id: number;
|
|
37
|
+
createdAt: number;
|
|
38
|
+
};
|
|
39
|
+
export type ToastNotifier = {
|
|
40
|
+
show(message: string, kind?: ToastKind): void;
|
|
41
|
+
success(message: string): void;
|
|
42
|
+
error(message: string): void;
|
|
43
|
+
warning(message: string): void;
|
|
44
|
+
info(message: string): void;
|
|
45
|
+
};
|
|
46
|
+
export declare function isToastKind(value: unknown): value is ToastKind;
|
|
47
|
+
export declare class Toast {
|
|
48
|
+
private readonly entries;
|
|
49
|
+
private nextId;
|
|
50
|
+
show(message: string, kind?: ToastKind): number;
|
|
51
|
+
hide(id?: number): void;
|
|
52
|
+
get state(): ToastState | undefined;
|
|
53
|
+
get visibleStates(): readonly ToastEntry[];
|
|
54
|
+
entry(toastId: number): ToastEntry | undefined;
|
|
55
|
+
get visible(): boolean;
|
|
56
|
+
}
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export class PopupMenu {
|
|
2
|
+
maxVisibleRows;
|
|
3
|
+
items = [];
|
|
4
|
+
selectedIndex = 0;
|
|
5
|
+
scrollOffset = 0;
|
|
6
|
+
open = false;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.maxVisibleRows = Math.max(1, options.maxVisibleRows);
|
|
9
|
+
}
|
|
10
|
+
setItems(items) {
|
|
11
|
+
this.items = [...items];
|
|
12
|
+
this.selectedIndex = clamp(this.selectedIndex, 0, Math.max(0, this.items.length - 1));
|
|
13
|
+
this.scrollOffset = clamp(this.scrollOffset, 0, this.maxScrollOffset());
|
|
14
|
+
this.ensureSelectedVisible();
|
|
15
|
+
}
|
|
16
|
+
openWithItems(items) {
|
|
17
|
+
this.open = true;
|
|
18
|
+
this.setItems(items);
|
|
19
|
+
}
|
|
20
|
+
close() {
|
|
21
|
+
this.open = false;
|
|
22
|
+
}
|
|
23
|
+
selectedItem() {
|
|
24
|
+
return this.items[this.selectedIndex];
|
|
25
|
+
}
|
|
26
|
+
moveSelection(delta) {
|
|
27
|
+
if (this.items.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
this.selectedIndex = clamp(this.selectedIndex + delta, 0, this.items.length - 1);
|
|
30
|
+
this.ensureSelectedVisible();
|
|
31
|
+
}
|
|
32
|
+
scroll(delta) {
|
|
33
|
+
this.scrollOffset = clamp(this.scrollOffset + delta, 0, this.maxScrollOffset());
|
|
34
|
+
this.selectedIndex = clamp(this.selectedIndex, this.scrollOffset, Math.min(this.items.length - 1, this.scrollOffset + this.maxVisibleRows - 1));
|
|
35
|
+
}
|
|
36
|
+
visibleItems() {
|
|
37
|
+
return this.items.slice(this.scrollOffset, this.scrollOffset + this.maxVisibleRows).map((item, offset) => {
|
|
38
|
+
const index = this.scrollOffset + offset;
|
|
39
|
+
return { ...item, index, selected: index === this.selectedIndex };
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
maxScrollOffset() {
|
|
43
|
+
return Math.max(0, this.items.length - this.maxVisibleRows);
|
|
44
|
+
}
|
|
45
|
+
ensureSelectedVisible() {
|
|
46
|
+
if (this.selectedIndex < this.scrollOffset) {
|
|
47
|
+
this.scrollOffset = this.selectedIndex;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const lastVisibleIndex = this.scrollOffset + this.maxVisibleRows - 1;
|
|
51
|
+
if (this.selectedIndex > lastVisibleIndex) {
|
|
52
|
+
this.scrollOffset = this.selectedIndex - this.maxVisibleRows + 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export const TOAST_KINDS = ["success", "error", "warning", "info"];
|
|
57
|
+
export function isToastKind(value) {
|
|
58
|
+
return typeof value === "string" && TOAST_KINDS.includes(value);
|
|
59
|
+
}
|
|
60
|
+
export class Toast {
|
|
61
|
+
entries = [];
|
|
62
|
+
nextId = 1;
|
|
63
|
+
show(message, kind = "info") {
|
|
64
|
+
const id = this.nextId;
|
|
65
|
+
this.nextId += 1;
|
|
66
|
+
this.entries.push({ id, message, kind, createdAt: Date.now() });
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
hide(id) {
|
|
70
|
+
if (id === undefined) {
|
|
71
|
+
this.entries.splice(0, this.entries.length);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const index = this.entries.findIndex((entry) => entry.id === id);
|
|
75
|
+
if (index >= 0)
|
|
76
|
+
this.entries.splice(index, 1);
|
|
77
|
+
}
|
|
78
|
+
get state() {
|
|
79
|
+
const entry = this.entries.at(-1);
|
|
80
|
+
return entry ? { message: entry.message, kind: entry.kind } : undefined;
|
|
81
|
+
}
|
|
82
|
+
get visibleStates() {
|
|
83
|
+
return this.entries;
|
|
84
|
+
}
|
|
85
|
+
entry(toastId) {
|
|
86
|
+
return this.entries.find((entry) => entry.id === toastId);
|
|
87
|
+
}
|
|
88
|
+
get visible() {
|
|
89
|
+
return this.entries.length > 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function clamp(value, min, max) {
|
|
93
|
+
return Math.min(max, Math.max(min, value));
|
|
94
|
+
}
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Release and update verification
|
|
2
|
+
|
|
3
|
+
Use this checklist before publishing `pi-ui-extend` so installs work on macOS, Linux, and Windows and the `pi-tools-suite` extension payload is included.
|
|
4
|
+
|
|
5
|
+
## Local release check
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --ignore-scripts
|
|
9
|
+
npm run release:check
|
|
10
|
+
npm run smoke-test
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`release:check` runs type checking, the test suite, a production build, and `npm pack --dry-run`.
|
|
14
|
+
`smoke-test` packs the real tarball, installs it into an isolated temp directory, checks the bundled files, and runs non-interactive `pix` commands from the installed package.
|
|
15
|
+
|
|
16
|
+
## Publish a new npm version
|
|
17
|
+
|
|
18
|
+
Pix uses the same release style as `indexer-cli`: a local command bumps the version, smoke-tests the tarball, then pushes the release commit and tag. GitHub Actions publishes the tag to npm using the `NPM_TOKEN` repository secret.
|
|
19
|
+
|
|
20
|
+
One-time setup:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
gh secret set NPM_TOKEN
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Release commands:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm run publish-npm # patch release
|
|
30
|
+
npm run publish-npm -- minor # minor release
|
|
31
|
+
npm run publish-npm -- major # major release
|
|
32
|
+
npm run publish-npm -- 0.2.0 # exact version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The command requires a clean working tree on `master`, pulls latest from `origin/master`, runs `release:check`, runs `npm version`, runs the tarball smoke test, then pushes the branch and `v*` tag. The tag workflow verifies that `package.json` matches the tag before `npm publish --access public`.
|
|
36
|
+
|
|
37
|
+
Only the root `package.json` version is bumped for Pix releases. Do not bump `external/pi-tools-suite/package.json` unless publishing the suite as a separate package.
|
|
38
|
+
|
|
39
|
+
## Tarball smoke test
|
|
40
|
+
|
|
41
|
+
From a clean temporary directory:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm pack /path/to/pi-ui-extend
|
|
45
|
+
npm install -g ./pi-ui-extend-*.tgz --ignore-scripts
|
|
46
|
+
pix update --check
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Confirm the dry-run/pack output contains:
|
|
50
|
+
|
|
51
|
+
- `bin/pix.mjs`
|
|
52
|
+
- `dist/**`
|
|
53
|
+
- `extensions/**`
|
|
54
|
+
- `external/pi-tools-suite/**`
|
|
55
|
+
- `README.md` and `docs/release.md`
|
|
56
|
+
|
|
57
|
+
## External suite checks
|
|
58
|
+
|
|
59
|
+
`external/pi-tools-suite` is a real checked-in package directory, not a symlink. Pix links it into the standard user extension location (`~/.pi/agent/extensions/pi-tools-suite` on macOS/Linux) before creating SDK services. The normal test suite verifies both the renderer-owned bundled extensions and the suite installer/link behavior.
|
|
60
|
+
|
|
61
|
+
When Bun is available, also run the suite's own checks:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm --prefix external/pi-tools-suite test
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Some modules have optional runtime dependencies or host services:
|
|
68
|
+
|
|
69
|
+
- `web-search` requires a local Ollama web-search/web-fetch API.
|
|
70
|
+
- `terminal-bell` uses optional platform notification helpers when present.
|
|
71
|
+
- `async-subagents` writes run state under the workspace `.pi/subagents/` directory.
|
|
72
|
+
|
|
73
|
+
## Update UX
|
|
74
|
+
|
|
75
|
+
- `/update` inside Pix performs a non-mutating npm latest-version check and tells the user what to run.
|
|
76
|
+
- `pix update --check` performs the same check without a TTY.
|
|
77
|
+
- `pix update` updates package-manager installs of Pix and therefore also updates the `external/pi-tools-suite` payload. The next Pix startup refreshes the user extension link.
|
|
78
|
+
- Source checkouts are intentionally not self-mutated; update them with `git pull`, `npm install --ignore-scripts`, `npm run build:pix`, and `npm run link:pix`.
|
|
79
|
+
- Separately installed Pi packages are updated by Pi itself with `pi update --extensions` or `pi update`.
|
|
80
|
+
|
|
81
|
+
Update checks respect `PI_OFFLINE=1`, `PI_SKIP_VERSION_CHECK=1`, and `PIX_SKIP_VERSION_CHECK=1`.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
|
|
3
|
+
import type { NormalizedQuestion, QuestionToolInput } from "./types";
|
|
4
|
+
|
|
5
|
+
export const CUSTOM_ANSWER_LABEL = "Something else…";
|
|
6
|
+
export const CUSTOM_ANSWER_SENTINEL_VALUE = "__question_custom_answer__";
|
|
7
|
+
export const MIN_QUESTIONS = 1;
|
|
8
|
+
export const MAX_QUESTIONS = 5;
|
|
9
|
+
export const MIN_CHOICES = 2;
|
|
10
|
+
export const MAX_CHOICES = 5;
|
|
11
|
+
export const QUESTION_ID_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
12
|
+
|
|
13
|
+
export const questionParameters = Type.Object({
|
|
14
|
+
questions: Type.Array(Type.Object({
|
|
15
|
+
id: Type.String({ description: "Unique stable question id." }),
|
|
16
|
+
label: Type.String({ description: "Short label for the question." }),
|
|
17
|
+
prompt: Type.String({ description: "Full question prompt to show the user." }),
|
|
18
|
+
choices: Type.Array(Type.Object({
|
|
19
|
+
value: Type.String({ description: "Value returned if this choice is selected." }),
|
|
20
|
+
label: Type.String({ description: "Display label for this choice." }),
|
|
21
|
+
description: Type.Optional(Type.String({ description: "Optional supporting text for this choice." })),
|
|
22
|
+
}), {
|
|
23
|
+
minItems: MIN_CHOICES,
|
|
24
|
+
maxItems: MAX_CHOICES,
|
|
25
|
+
description: "Two to five meaningful predefined choices.",
|
|
26
|
+
}),
|
|
27
|
+
}), {
|
|
28
|
+
minItems: MIN_QUESTIONS,
|
|
29
|
+
maxItems: MAX_QUESTIONS,
|
|
30
|
+
description: "One to five questions to ask the user.",
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export function normalizeQuestionInput(input: QuestionToolInput): NormalizedQuestion[] {
|
|
35
|
+
const questions = input.questions;
|
|
36
|
+
if (!Array.isArray(questions) || questions.length < MIN_QUESTIONS || questions.length > MAX_QUESTIONS) {
|
|
37
|
+
throwInvalid(`question requires ${MIN_QUESTIONS} to ${MAX_QUESTIONS} questions; received ${Array.isArray(questions) ? questions.length : "no"}.`, "Retry with a questions array containing one to five questions.");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const seenQuestionIds = new Set<string>();
|
|
41
|
+
const seenQuestionLabels = new Set<string>();
|
|
42
|
+
return questions.map((question, questionIndex) => {
|
|
43
|
+
const questionNumber = questionIndex + 1;
|
|
44
|
+
const id = trimString(question.id, `question ${questionNumber} id`);
|
|
45
|
+
const label = trimString(question.label, `question ${questionNumber} label`);
|
|
46
|
+
const prompt = trimString(question.prompt, `question ${questionNumber} prompt`);
|
|
47
|
+
if (!QUESTION_ID_PATTERN.test(id)) throwInvalid(`Question ${questionNumber} has invalid id "${id}". IDs must match ${QUESTION_ID_PATTERN.source}.`, "Retry with a stable id starting with a lowercase letter and containing only lowercase letters, numbers, underscores, or hyphens.");
|
|
48
|
+
if (seenQuestionIds.has(id)) throwInvalid(`Duplicate question id "${id}" makes question answers ambiguous.`, "Retry with a unique stable id for each question.");
|
|
49
|
+
seenQuestionIds.add(id);
|
|
50
|
+
|
|
51
|
+
const normalizedLabel = normalizeForUniqueness(label);
|
|
52
|
+
if (seenQuestionLabels.has(normalizedLabel)) throwInvalid(`Duplicate question label "${label}" makes question summaries ambiguous.`, "Retry with a unique short label for each question; labels are compared case-insensitively.");
|
|
53
|
+
seenQuestionLabels.add(normalizedLabel);
|
|
54
|
+
if (label.includes("\n") || label.includes("\r")) throwInvalid(`Question ${questionNumber} label must be single-line.`, "Retry with a short single-line label and put longer text in the prompt.");
|
|
55
|
+
|
|
56
|
+
if (!Array.isArray(question.choices) || question.choices.length < MIN_CHOICES || question.choices.length > MAX_CHOICES) {
|
|
57
|
+
throwInvalid(`Question "${id}" requires ${MIN_CHOICES} to ${MAX_CHOICES} predefined Choices; received ${Array.isArray(question.choices) ? question.choices.length : "no"}.`, "Retry with two to five meaningful predefined Choices for each question.");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const seenChoiceValues = new Set<string>();
|
|
61
|
+
const seenChoiceLabels = new Set<string>();
|
|
62
|
+
return {
|
|
63
|
+
id,
|
|
64
|
+
label,
|
|
65
|
+
prompt,
|
|
66
|
+
choices: question.choices.map((choice, choiceIndex) => {
|
|
67
|
+
const choiceNumber = choiceIndex + 1;
|
|
68
|
+
const value = trimString(choice.value, `question "${id}" Choice ${choiceNumber} value`);
|
|
69
|
+
const choiceLabel = trimString(choice.label, `question "${id}" Choice ${choiceNumber} label`);
|
|
70
|
+
const description = choice.description === undefined ? undefined : choice.description.trim();
|
|
71
|
+
if (value === CUSTOM_ANSWER_SENTINEL_VALUE) throwInvalid(`Question "${id}" Choice ${choiceNumber} uses the reserved Custom Answer sentinel value "${CUSTOM_ANSWER_SENTINEL_VALUE}".`, "Retry with a different Choice value; ordinary values like other or custom are allowed.");
|
|
72
|
+
|
|
73
|
+
const normalizedValue = normalizeForUniqueness(value);
|
|
74
|
+
if (seenChoiceValues.has(normalizedValue)) throwInvalid(`Question "${id}" has duplicate Choice value "${value}".`, "Retry with unique Choice values within each question; values are compared case-insensitively.");
|
|
75
|
+
seenChoiceValues.add(normalizedValue);
|
|
76
|
+
|
|
77
|
+
const normalizedChoiceLabel = normalizeForUniqueness(choiceLabel);
|
|
78
|
+
if (seenChoiceLabels.has(normalizedChoiceLabel)) throwInvalid(`Question "${id}" has duplicate Choice label "${choiceLabel}".`, "Retry with unique visible Choice labels within each question; labels are compared case-insensitively.");
|
|
79
|
+
seenChoiceLabels.add(normalizedChoiceLabel);
|
|
80
|
+
if (normalizedChoiceLabel === normalizeForUniqueness(CUSTOM_ANSWER_LABEL)) throwInvalid(`Question "${id}" Choice label "${choiceLabel}" collides with the implicit Custom Answer row label "${CUSTOM_ANSWER_LABEL}".`, "Retry with a different predefined Choice label; the Custom Answer row is added automatically.");
|
|
81
|
+
|
|
82
|
+
return description === undefined ? { value, label: choiceLabel } : { value, label: choiceLabel, description };
|
|
83
|
+
}),
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function trimString(value: string, field: string): string {
|
|
89
|
+
const trimmed = value.trim();
|
|
90
|
+
if (!trimmed) throwInvalid(`${field} must not be empty after trimming.`, "Retry with non-empty text for every required question field.");
|
|
91
|
+
return trimmed;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function normalizeForUniqueness(value: string): string {
|
|
95
|
+
return value.toLocaleLowerCase();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function throwInvalid(problem: string, repair: string): never {
|
|
99
|
+
throw new Error(`Invalid question input: ${problem} ${repair}`);
|
|
100
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { QUESTION_TOOL_DESCRIPTION } from "./tool-description";
|
|
2
|
+
import { questionParameters, normalizeQuestionInput } from "./contract";
|
|
3
|
+
import { renderQuestionCall, renderQuestionResult } from "./render";
|
|
4
|
+
import { createCanceledQuestionResult, createQuestionToolResult, createSuccessfulQuestionResult } from "./result";
|
|
5
|
+
import { runQuestionnaire } from "./tui";
|
|
6
|
+
import type { QuestionToolInput, QuestionUiContext } from "./types";
|
|
7
|
+
|
|
8
|
+
interface ExtensionApiLike {
|
|
9
|
+
registerTool(tool: unknown): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function questionExtension(pi: ExtensionApiLike): void {
|
|
13
|
+
pi.registerTool({
|
|
14
|
+
...QUESTION_TOOL_DESCRIPTION,
|
|
15
|
+
parameters: questionParameters,
|
|
16
|
+
renderCall(args: Partial<QuestionToolInput>, theme: any) {
|
|
17
|
+
return renderQuestionCall(args, theme);
|
|
18
|
+
},
|
|
19
|
+
renderResult(result: any, _options: unknown, theme: any, context: { args?: Partial<QuestionToolInput> }) {
|
|
20
|
+
return renderQuestionResult(result, theme, context.args);
|
|
21
|
+
},
|
|
22
|
+
async execute(_toolCallId: string, params: QuestionToolInput, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: QuestionUiContext) {
|
|
23
|
+
const questions = normalizeQuestionInput(params);
|
|
24
|
+
if (!ctx.hasUI) return createQuestionToolResult(createCanceledQuestionResult("ui_unavailable", questions), questions);
|
|
25
|
+
const selections = await runQuestionnaire(questions, ctx);
|
|
26
|
+
if (selections === null) return createQuestionToolResult(createCanceledQuestionResult("user_canceled"), questions);
|
|
27
|
+
return createQuestionToolResult(createSuccessfulQuestionResult(questions, selections), questions);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { questionParameters, normalizeQuestionInput } from "./contract";
|
|
33
|
+
export { createCanceledQuestionResult, createFallbackPrompt, createQuestionToolResult, createSuccessfulQuestionResult, summarizeQuestionResult } from "./result";
|
|
34
|
+
export type { QuestionResultDetails, QuestionToolInput } from "./types";
|