gsd-pi 2.29.0 → 2.30.0-dev.7e1bbce
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 +24 -17
- package/dist/cli.js +51 -0
- package/dist/extension-registry.d.ts +63 -0
- package/dist/extension-registry.js +166 -0
- package/dist/headless.js +4 -0
- package/dist/help-text.js +35 -0
- package/dist/loader.js +10 -1
- package/dist/resource-loader.js +11 -1
- package/dist/resources/extensions/async-jobs/extension-manifest.json +13 -0
- package/dist/resources/extensions/bg-shell/extension-manifest.json +14 -0
- package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/dist/resources/extensions/browser-tools/extension-manifest.json +37 -0
- package/dist/resources/extensions/context7/extension-manifest.json +12 -0
- package/dist/resources/extensions/google-search/extension-manifest.json +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +31 -0
- package/dist/resources/extensions/gsd/auto-dispatch.ts +32 -3
- package/dist/resources/extensions/gsd/auto-post-unit.ts +45 -13
- package/dist/resources/extensions/gsd/auto-prompts.ts +40 -17
- package/dist/resources/extensions/gsd/auto-recovery.ts +18 -23
- package/dist/resources/extensions/gsd/auto-start.ts +18 -32
- package/dist/resources/extensions/gsd/auto-worktree.ts +21 -182
- package/dist/resources/extensions/gsd/auto.ts +2 -24
- package/dist/resources/extensions/gsd/captures.ts +4 -10
- package/dist/resources/extensions/gsd/commands-extensions.ts +328 -0
- package/dist/resources/extensions/gsd/commands-handlers.ts +22 -2
- package/dist/resources/extensions/gsd/commands-logs.ts +13 -14
- package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
- package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/dist/resources/extensions/gsd/commands.ts +108 -24
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/dist/resources/extensions/gsd/detection.ts +2 -1
- package/dist/resources/extensions/gsd/doctor-checks.ts +49 -1
- package/dist/resources/extensions/gsd/doctor-types.ts +3 -1
- package/dist/resources/extensions/gsd/extension-manifest.json +18 -0
- package/dist/resources/extensions/gsd/forensics.ts +2 -2
- package/dist/resources/extensions/gsd/git-service.ts +3 -2
- package/dist/resources/extensions/gsd/gitignore.ts +9 -63
- package/dist/resources/extensions/gsd/gsd-db.ts +1 -165
- package/dist/resources/extensions/gsd/guided-flow.ts +8 -5
- package/dist/resources/extensions/gsd/index.ts +16 -3
- package/dist/resources/extensions/gsd/json-persistence.ts +16 -1
- package/dist/resources/extensions/gsd/md-importer.ts +3 -2
- package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +3 -2
- package/dist/resources/extensions/gsd/migrate/writer.ts +2 -1
- package/dist/resources/extensions/gsd/migrate-external.ts +123 -0
- package/dist/resources/extensions/gsd/paths.ts +24 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +6 -5
- package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
- package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/dist/resources/extensions/gsd/preferences.ts +10 -5
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/dist/resources/extensions/gsd/queue-order.ts +10 -11
- package/dist/resources/extensions/gsd/repo-identity.ts +148 -0
- package/dist/resources/extensions/gsd/resource-version.ts +99 -0
- package/dist/resources/extensions/gsd/roadmap-slices.ts +22 -7
- package/dist/resources/extensions/gsd/session-forensics.ts +4 -3
- package/dist/resources/extensions/gsd/session-lock.ts +53 -4
- package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
- package/dist/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
- package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
- package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
- package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +10 -37
- package/dist/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
- package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/dist/resources/extensions/gsd/triage-resolution.ts +2 -1
- package/dist/resources/extensions/gsd/types.ts +2 -0
- package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +1 -11
- package/dist/resources/extensions/gsd/worktree-manager.ts +3 -2
- package/dist/resources/extensions/gsd/worktree.ts +42 -5
- package/dist/resources/extensions/mac-tools/extension-manifest.json +16 -0
- package/dist/resources/extensions/mcp-client/index.ts +459 -0
- package/dist/resources/extensions/mcporter/extension-manifest.json +12 -0
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +8 -19
- package/dist/resources/extensions/remote-questions/extension-manifest.json +11 -0
- package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -17
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -19
- package/dist/resources/extensions/search-the-web/extension-manifest.json +13 -0
- package/dist/resources/extensions/slash-commands/extension-manifest.json +11 -0
- package/dist/resources/extensions/subagent/extension-manifest.json +13 -0
- package/dist/resources/extensions/ttsr/extension-manifest.json +11 -0
- package/dist/resources/extensions/universal-config/extension-manifest.json +13 -0
- package/dist/resources/extensions/voice/extension-manifest.json +12 -0
- package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/dist/resources/skills/create-skill/SKILL.md +184 -0
- package/dist/resources/skills/create-skill/references/api-security.md +226 -0
- package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
- package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/dist/resources/skills/react-best-practices/SKILL.md +1 -1
- package/dist/worktree-cli.d.ts +34 -0
- package/dist/worktree-cli.js +294 -0
- package/dist/worktree-name-gen.d.ts +7 -0
- package/dist/worktree-name-gen.js +44 -0
- package/package.json +1 -1
- package/packages/native/dist/native.d.ts +2 -0
- package/packages/native/dist/native.js +19 -5
- package/packages/native/src/native.ts +23 -9
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/extension-manifest.json +13 -0
- package/src/resources/extensions/bg-shell/extension-manifest.json +14 -0
- package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/src/resources/extensions/browser-tools/extension-manifest.json +37 -0
- package/src/resources/extensions/context7/extension-manifest.json +12 -0
- package/src/resources/extensions/google-search/extension-manifest.json +12 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +31 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +32 -3
- package/src/resources/extensions/gsd/auto-post-unit.ts +45 -13
- package/src/resources/extensions/gsd/auto-prompts.ts +40 -17
- package/src/resources/extensions/gsd/auto-recovery.ts +18 -23
- package/src/resources/extensions/gsd/auto-start.ts +18 -32
- package/src/resources/extensions/gsd/auto-worktree.ts +21 -182
- package/src/resources/extensions/gsd/auto.ts +2 -24
- package/src/resources/extensions/gsd/captures.ts +4 -10
- package/src/resources/extensions/gsd/commands-extensions.ts +328 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +22 -2
- package/src/resources/extensions/gsd/commands-logs.ts +13 -14
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/src/resources/extensions/gsd/commands.ts +108 -24
- package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/src/resources/extensions/gsd/detection.ts +2 -1
- package/src/resources/extensions/gsd/doctor-checks.ts +49 -1
- package/src/resources/extensions/gsd/doctor-types.ts +3 -1
- package/src/resources/extensions/gsd/extension-manifest.json +18 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +3 -2
- package/src/resources/extensions/gsd/gitignore.ts +9 -63
- package/src/resources/extensions/gsd/gsd-db.ts +1 -165
- package/src/resources/extensions/gsd/guided-flow.ts +8 -5
- package/src/resources/extensions/gsd/index.ts +16 -3
- package/src/resources/extensions/gsd/json-persistence.ts +16 -1
- package/src/resources/extensions/gsd/md-importer.ts +3 -2
- package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
- package/src/resources/extensions/gsd/migrate/command.ts +3 -2
- package/src/resources/extensions/gsd/migrate/writer.ts +2 -1
- package/src/resources/extensions/gsd/migrate-external.ts +123 -0
- package/src/resources/extensions/gsd/paths.ts +24 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +6 -5
- package/src/resources/extensions/gsd/preferences-models.ts +7 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
- package/src/resources/extensions/gsd/preferences.ts +10 -5
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
- package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/src/resources/extensions/gsd/queue-order.ts +10 -11
- package/src/resources/extensions/gsd/repo-identity.ts +148 -0
- package/src/resources/extensions/gsd/resource-version.ts +99 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +22 -7
- package/src/resources/extensions/gsd/session-forensics.ts +4 -3
- package/src/resources/extensions/gsd/session-lock.ts +53 -4
- package/src/resources/extensions/gsd/session-status-io.ts +23 -41
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
- package/src/resources/extensions/gsd/tests/git-service.test.ts +10 -37
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -1
- package/src/resources/extensions/gsd/types.ts +2 -0
- package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/src/resources/extensions/gsd/worktree-command.ts +1 -11
- package/src/resources/extensions/gsd/worktree-manager.ts +3 -2
- package/src/resources/extensions/gsd/worktree.ts +42 -5
- package/src/resources/extensions/mac-tools/extension-manifest.json +16 -0
- package/src/resources/extensions/mcp-client/index.ts +459 -0
- package/src/resources/extensions/mcporter/extension-manifest.json +12 -0
- package/src/resources/extensions/remote-questions/discord-adapter.ts +8 -19
- package/src/resources/extensions/remote-questions/extension-manifest.json +11 -0
- package/src/resources/extensions/remote-questions/http-client.ts +76 -0
- package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -17
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -19
- package/src/resources/extensions/search-the-web/extension-manifest.json +13 -0
- package/src/resources/extensions/slash-commands/extension-manifest.json +11 -0
- package/src/resources/extensions/subagent/extension-manifest.json +13 -0
- package/src/resources/extensions/ttsr/extension-manifest.json +11 -0
- package/src/resources/extensions/universal-config/extension-manifest.json +13 -0
- package/src/resources/extensions/voice/extension-manifest.json +12 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/src/resources/skills/create-skill/SKILL.md +184 -0
- package/src/resources/skills/create-skill/references/api-security.md +226 -0
- package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/src/resources/skills/create-skill/references/core-principles.md +437 -0
- package/src/resources/skills/create-skill/references/executable-code.md +175 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/src/resources/skills/create-skill/references/using-templates.md +112 -0
- package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/src/resources/skills/react-best-practices/SKILL.md +1 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +0 -198
- package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
- package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
- package/dist/resources/extensions/mcporter/index.ts +0 -525
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -198
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
- package/src/resources/extensions/mcporter/index.ts +0 -525
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
Complete custom UI reference — dialogs, persistent elements, custom components, overlays, custom editors, built-in components, keyboard input, performance, theming, and common mistakes.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<ui_architecture>
|
|
6
|
+
```
|
|
7
|
+
┌─────────────────────────────────────────────────┐
|
|
8
|
+
│ Custom Header (ctx.ui.setHeader) │
|
|
9
|
+
├─────────────────────────────────────────────────┤
|
|
10
|
+
│ Message Area │
|
|
11
|
+
│ - User/assistant messages │
|
|
12
|
+
│ - Tool calls ◄── renderCall/renderResult │
|
|
13
|
+
│ - Custom messages ◄── registerMessageRenderer │
|
|
14
|
+
├─────────────────────────────────────────────────┤
|
|
15
|
+
│ Widgets (above editor) ◄── ctx.ui.setWidget │
|
|
16
|
+
├─────────────────────────────────────────────────┤
|
|
17
|
+
│ Editor ◄── ctx.ui.custom() / setEditorComponent│
|
|
18
|
+
├─────────────────────────────────────────────────┤
|
|
19
|
+
│ Widgets (below editor) ◄── ctx.ui.setWidget │
|
|
20
|
+
├─────────────────────────────────────────────────┤
|
|
21
|
+
│ Footer ◄── ctx.ui.setFooter / setStatus │
|
|
22
|
+
└─────────────────────────────────────────────────┘
|
|
23
|
+
┌─────────────────────┐
|
|
24
|
+
│ Overlay (floating) │ ◄── ctx.ui.custom({ overlay })
|
|
25
|
+
└─────────────────────┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**11 ways to get UI on screen:**
|
|
29
|
+
|
|
30
|
+
| Method | Blocks? | Replaces editor? |
|
|
31
|
+
|--------|---------|-------------------|
|
|
32
|
+
| `ctx.ui.select/confirm/input/editor` | Yes | Temporarily |
|
|
33
|
+
| `ctx.ui.notify` | No | No |
|
|
34
|
+
| `ctx.ui.setStatus` | No | No (footer) |
|
|
35
|
+
| `ctx.ui.setWidget` | No | No |
|
|
36
|
+
| `ctx.ui.setFooter` | No | No (replaces footer) |
|
|
37
|
+
| `ctx.ui.setHeader` | No | No (replaces header) |
|
|
38
|
+
| `ctx.ui.custom()` | Yes | Temporarily |
|
|
39
|
+
| `ctx.ui.custom({overlay})` | Yes | No (renders on top) |
|
|
40
|
+
| `ctx.ui.setEditorComponent` | No | Yes (permanently) |
|
|
41
|
+
| `renderCall/renderResult` | No | No (inline in messages) |
|
|
42
|
+
| `registerMessageRenderer` | No | No (inline in messages) |
|
|
43
|
+
</ui_architecture>
|
|
44
|
+
|
|
45
|
+
<component_interface>
|
|
46
|
+
Every visual element implements:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
interface Component {
|
|
50
|
+
render(width: number): string[]; // Required — each line ≤ width visible chars
|
|
51
|
+
handleInput?(data: string): void; // Optional — receive keyboard input
|
|
52
|
+
wantsKeyRelease?: boolean; // Optional — receive key release events (Kitty protocol)
|
|
53
|
+
invalidate(): void; // Required — clear cached render state
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Render contract:**
|
|
58
|
+
- Return array of strings, one per line
|
|
59
|
+
- Each string MUST NOT exceed `width` in visible characters
|
|
60
|
+
- ANSI escape codes don't count toward visible width
|
|
61
|
+
- **Styles are reset at end of each line** — reapply per line
|
|
62
|
+
- Return `[]` for zero-height component
|
|
63
|
+
|
|
64
|
+
**Invalidation contract:**
|
|
65
|
+
- Clear ALL cached render output
|
|
66
|
+
- Clear any pre-baked themed strings
|
|
67
|
+
- Call `super.invalidate()` if extending a built-in component
|
|
68
|
+
</component_interface>
|
|
69
|
+
|
|
70
|
+
<dialogs>
|
|
71
|
+
Blocking dialog methods on `ctx.ui`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const choice = await ctx.ui.select("Pick one:", ["A", "B", "C"]); // string | undefined
|
|
75
|
+
const ok = await ctx.ui.confirm("Delete?", "This cannot be undone"); // boolean
|
|
76
|
+
const name = await ctx.ui.input("Name:", "placeholder"); // string | undefined
|
|
77
|
+
const text = await ctx.ui.editor("Edit:", "prefilled text"); // string | undefined
|
|
78
|
+
|
|
79
|
+
// Timed auto-dismiss with countdown
|
|
80
|
+
const ok = await ctx.ui.confirm("Proceed?", "Auto-continues in 5s", { timeout: 5000 });
|
|
81
|
+
// Returns false on timeout, undefined for select/input
|
|
82
|
+
|
|
83
|
+
// Manual dismissal with AbortSignal (distinguish timeout from cancel)
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
86
|
+
const ok = await ctx.ui.confirm("Timed", "Auto-cancels in 5s", { signal: controller.signal });
|
|
87
|
+
clearTimeout(timeoutId);
|
|
88
|
+
if (controller.signal.aborted) { /* timed out */ }
|
|
89
|
+
```
|
|
90
|
+
</dialogs>
|
|
91
|
+
|
|
92
|
+
<persistent_ui>
|
|
93
|
+
```typescript
|
|
94
|
+
// Footer status (multiple extensions can set independent entries)
|
|
95
|
+
ctx.ui.setStatus("my-ext", "● Active");
|
|
96
|
+
ctx.ui.setStatus("my-ext", undefined); // Clear
|
|
97
|
+
|
|
98
|
+
// Widgets
|
|
99
|
+
ctx.ui.setWidget("my-id", ["Line 1", "Line 2"]); // Above editor
|
|
100
|
+
ctx.ui.setWidget("my-id", ["Below"], { placement: "belowEditor" }); // Below editor
|
|
101
|
+
ctx.ui.setWidget("my-id", (_tui, theme) => ({ // Themed
|
|
102
|
+
render: () => [theme.fg("accent", "Styled")],
|
|
103
|
+
invalidate: () => {},
|
|
104
|
+
}));
|
|
105
|
+
ctx.ui.setWidget("my-id", undefined); // Clear
|
|
106
|
+
|
|
107
|
+
// Working message during streaming
|
|
108
|
+
ctx.ui.setWorkingMessage("Analyzing code...");
|
|
109
|
+
ctx.ui.setWorkingMessage(); // Restore default
|
|
110
|
+
|
|
111
|
+
// Custom footer (full replacement)
|
|
112
|
+
ctx.ui.setFooter((tui, theme, footerData) => ({
|
|
113
|
+
render(width) {
|
|
114
|
+
const branch = footerData.getGitBranch(); // Only available here
|
|
115
|
+
const statuses = footerData.getExtensionStatuses(); // All setStatus values
|
|
116
|
+
return [truncateToWidth(`${branch} | model`, width)];
|
|
117
|
+
},
|
|
118
|
+
invalidate() {},
|
|
119
|
+
dispose: footerData.onBranchChange(() => tui.requestRender()), // Reactive
|
|
120
|
+
}));
|
|
121
|
+
ctx.ui.setFooter(undefined); // Restore default
|
|
122
|
+
|
|
123
|
+
// Custom header
|
|
124
|
+
ctx.ui.setHeader((tui, theme) => ({
|
|
125
|
+
render(width) { return [theme.fg("accent", theme.bold("My Header"))]; },
|
|
126
|
+
invalidate() {},
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
// Editor control
|
|
130
|
+
ctx.ui.setEditorText("Prefill");
|
|
131
|
+
const current = ctx.ui.getEditorText();
|
|
132
|
+
ctx.ui.pasteToEditor("pasted content"); // Triggers paste handling
|
|
133
|
+
|
|
134
|
+
// Tool expansion
|
|
135
|
+
ctx.ui.setToolsExpanded(true);
|
|
136
|
+
const expanded = ctx.ui.getToolsExpanded();
|
|
137
|
+
|
|
138
|
+
// Theme management
|
|
139
|
+
const themes = ctx.ui.getAllThemes();
|
|
140
|
+
ctx.ui.setTheme("light");
|
|
141
|
+
ctx.ui.theme.fg("accent", "text"); // Access current theme
|
|
142
|
+
```
|
|
143
|
+
</persistent_ui>
|
|
144
|
+
|
|
145
|
+
<custom_components>
|
|
146
|
+
`ctx.ui.custom()` temporarily replaces the editor. Returns a value when `done()` is called.
|
|
147
|
+
|
|
148
|
+
**Factory callback args:**
|
|
149
|
+
|
|
150
|
+
| Argument | Type | Purpose |
|
|
151
|
+
|----------|------|---------|
|
|
152
|
+
| `tui` | `TUI` | `tui.requestRender()` triggers re-render after state changes |
|
|
153
|
+
| `theme` | `Theme` | Current theme for styling |
|
|
154
|
+
| `keybindings` | `KeybindingsManager` | App keybinding config |
|
|
155
|
+
| `done` | `(value: T) => void` | Close component and return value |
|
|
156
|
+
|
|
157
|
+
**Inline pattern:**
|
|
158
|
+
```typescript
|
|
159
|
+
const result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) => ({
|
|
160
|
+
render(width: number): string[] {
|
|
161
|
+
return [truncateToWidth("Press Enter to confirm, Escape to cancel", width)];
|
|
162
|
+
},
|
|
163
|
+
handleInput(data: string) {
|
|
164
|
+
if (matchesKey(data, Key.enter)) done("confirmed");
|
|
165
|
+
if (matchesKey(data, Key.escape)) done(null);
|
|
166
|
+
},
|
|
167
|
+
invalidate() {},
|
|
168
|
+
}));
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Class-based pattern (recommended for complex UI):**
|
|
172
|
+
```typescript
|
|
173
|
+
class MyComponent {
|
|
174
|
+
private selected = 0;
|
|
175
|
+
private cachedWidth?: number;
|
|
176
|
+
private cachedLines?: string[];
|
|
177
|
+
|
|
178
|
+
constructor(
|
|
179
|
+
private tui: { requestRender: () => void },
|
|
180
|
+
private theme: Theme,
|
|
181
|
+
private items: string[],
|
|
182
|
+
private done: (value: string | null) => void,
|
|
183
|
+
) {}
|
|
184
|
+
|
|
185
|
+
handleInput(data: string) {
|
|
186
|
+
if (matchesKey(data, Key.up) && this.selected > 0) this.selected--;
|
|
187
|
+
else if (matchesKey(data, Key.down) && this.selected < this.items.length - 1) this.selected++;
|
|
188
|
+
else if (matchesKey(data, Key.enter)) { this.done(this.items[this.selected]); return; }
|
|
189
|
+
else if (matchesKey(data, Key.escape)) { this.done(null); return; }
|
|
190
|
+
else return;
|
|
191
|
+
this.invalidate();
|
|
192
|
+
this.tui.requestRender();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
render(width: number): string[] {
|
|
196
|
+
if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
|
|
197
|
+
this.cachedLines = this.items.map((item, i) =>
|
|
198
|
+
truncateToWidth((i === this.selected ? "> " : " ") + item, width)
|
|
199
|
+
);
|
|
200
|
+
this.cachedWidth = width;
|
|
201
|
+
return this.cachedLines;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) =>
|
|
208
|
+
new MyComponent(tui, theme, ["A", "B", "C"], done)
|
|
209
|
+
);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Composing with built-in components:**
|
|
213
|
+
```typescript
|
|
214
|
+
const result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
|
|
215
|
+
const container = new Container();
|
|
216
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
217
|
+
container.addChild(new Text(theme.fg("accent", theme.bold("Title")), 1, 0));
|
|
218
|
+
|
|
219
|
+
const selectList = new SelectList(items, 10, {
|
|
220
|
+
selectedPrefix: (t) => theme.fg("accent", t),
|
|
221
|
+
selectedText: (t) => theme.fg("accent", t),
|
|
222
|
+
description: (t) => theme.fg("muted", t),
|
|
223
|
+
scrollInfo: (t) => theme.fg("dim", t),
|
|
224
|
+
noMatch: (t) => theme.fg("warning", t),
|
|
225
|
+
});
|
|
226
|
+
selectList.onSelect = (item) => done(item.value);
|
|
227
|
+
selectList.onCancel = () => done(null);
|
|
228
|
+
container.addChild(selectList);
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
render: (w) => container.render(w),
|
|
232
|
+
invalidate: () => container.invalidate(),
|
|
233
|
+
handleInput: (data) => { selectList.handleInput(data); tui.requestRender(); },
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
</custom_components>
|
|
238
|
+
|
|
239
|
+
<overlays>
|
|
240
|
+
Floating modals rendered on top of everything:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
const result = await ctx.ui.custom<string | null>(
|
|
244
|
+
(tui, theme, _kb, done) => new MyDialog({ onClose: done }),
|
|
245
|
+
{
|
|
246
|
+
overlay: true,
|
|
247
|
+
overlayOptions: {
|
|
248
|
+
anchor: "center", // 9 positions (see below)
|
|
249
|
+
width: "50%", // number = columns, string = percentage
|
|
250
|
+
minWidth: 40,
|
|
251
|
+
maxHeight: "80%",
|
|
252
|
+
margin: 2, // All sides, or { top, right, bottom, left }
|
|
253
|
+
offsetX: 0, offsetY: 0, // Fine-tune position
|
|
254
|
+
visible: (w, h) => w >= 80, // Hide on narrow terminals
|
|
255
|
+
},
|
|
256
|
+
onHandle: (handle) => {
|
|
257
|
+
// handle.setHidden(true/false) — temporarily hide
|
|
258
|
+
// handle.hide() — permanently remove
|
|
259
|
+
},
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Anchor positions:**
|
|
265
|
+
```
|
|
266
|
+
top-left top-center top-right
|
|
267
|
+
left-center center right-center
|
|
268
|
+
bottom-left bottom-center bottom-right
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Stacked overlays:** Multiple overlays stack (newest on top). Closing one gives focus to the one below.
|
|
272
|
+
|
|
273
|
+
**⚠️ Overlay lifecycle:** Components are disposed when closed. Never reuse references — create fresh instances each time.
|
|
274
|
+
</overlays>
|
|
275
|
+
|
|
276
|
+
<custom_editor>
|
|
277
|
+
Replace the main input editor permanently:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import { CustomEditor } from "@mariozechner/pi-coding-agent";
|
|
281
|
+
|
|
282
|
+
class VimEditor extends CustomEditor {
|
|
283
|
+
private mode: "normal" | "insert" = "insert";
|
|
284
|
+
|
|
285
|
+
handleInput(data: string): void {
|
|
286
|
+
if (matchesKey(data, "escape") && this.mode === "insert") {
|
|
287
|
+
this.mode = "normal"; return;
|
|
288
|
+
}
|
|
289
|
+
if (this.mode === "insert") { super.handleInput(data); return; }
|
|
290
|
+
switch (data) {
|
|
291
|
+
case "i": this.mode = "insert"; return;
|
|
292
|
+
case "h": super.handleInput("\x1b[D"); return; // Left
|
|
293
|
+
case "j": super.handleInput("\x1b[B"); return; // Down
|
|
294
|
+
case "k": super.handleInput("\x1b[A"); return; // Up
|
|
295
|
+
case "l": super.handleInput("\x1b[C"); return; // Right
|
|
296
|
+
}
|
|
297
|
+
if (data.length === 1 && data.charCodeAt(0) >= 32) return; // Block printable in normal
|
|
298
|
+
super.handleInput(data);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
ctx.ui.setEditorComponent((_tui, theme, keybindings) => new VimEditor(theme, keybindings));
|
|
303
|
+
ctx.ui.setEditorComponent(undefined); // Restore default
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Critical:** Extend `CustomEditor` (NOT `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching).
|
|
307
|
+
</custom_editor>
|
|
308
|
+
|
|
309
|
+
<built_in_components>
|
|
310
|
+
**From `@mariozechner/pi-tui`:**
|
|
311
|
+
|
|
312
|
+
| Component | Constructor | Purpose |
|
|
313
|
+
|-----------|-------------|---------|
|
|
314
|
+
| `Text` | `new Text(content, paddingX, paddingY, bgFn?)` | Multi-line text with word wrap |
|
|
315
|
+
| `Box` | `new Box(paddingX, paddingY, bgFn)` | Container with padding+background, `.addChild()` |
|
|
316
|
+
| `Container` | `new Container()` | Vertical stack, `.addChild()`, `.removeChild()`, `.clear()` |
|
|
317
|
+
| `Spacer` | `new Spacer(lines)` | Empty vertical space |
|
|
318
|
+
| `Markdown` | `new Markdown(content, padX, padY, getMarkdownTheme())` | Rendered markdown with syntax highlighting |
|
|
319
|
+
| `Image` | `new Image(base64, mimeType, theme, opts?)` | Image rendering (Kitty, iTerm2) |
|
|
320
|
+
| `SelectList` | `new SelectList(items, maxVisible, themeOpts)` | Interactive selection with search and scrolling |
|
|
321
|
+
| `SettingsList` | `new SettingsList(items, maxVisible, theme, onChange, onClose, opts?)` | Toggle settings with left/right arrows |
|
|
322
|
+
| `Input` | `new Input()` | Text input field |
|
|
323
|
+
| `Editor` | `new Editor(tui, editorTheme)` | Multi-line editor with undo |
|
|
324
|
+
|
|
325
|
+
**SelectList usage:**
|
|
326
|
+
```typescript
|
|
327
|
+
const items: SelectItem[] = [
|
|
328
|
+
{ value: "opt1", label: "Option 1", description: "First option" },
|
|
329
|
+
{ value: "opt2", label: "Option 2" },
|
|
330
|
+
];
|
|
331
|
+
const selectList = new SelectList(items, 10, {
|
|
332
|
+
selectedPrefix: (t) => theme.fg("accent", t),
|
|
333
|
+
selectedText: (t) => theme.fg("accent", t),
|
|
334
|
+
description: (t) => theme.fg("muted", t),
|
|
335
|
+
scrollInfo: (t) => theme.fg("dim", t),
|
|
336
|
+
noMatch: (t) => theme.fg("warning", t),
|
|
337
|
+
});
|
|
338
|
+
selectList.onSelect = (item) => { /* item.value */ };
|
|
339
|
+
selectList.onCancel = () => { /* escape pressed */ };
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**SettingsList usage:**
|
|
343
|
+
```typescript
|
|
344
|
+
const items: SettingItem[] = [
|
|
345
|
+
{ id: "verbose", label: "Verbose mode", currentValue: "off", values: ["on", "off"] },
|
|
346
|
+
{ id: "theme", label: "Theme", currentValue: "dark", values: ["dark", "light", "auto"] },
|
|
347
|
+
];
|
|
348
|
+
const settings = new SettingsList(items, 15, getSettingsListTheme(),
|
|
349
|
+
(id, newValue) => { /* setting changed */ },
|
|
350
|
+
() => { /* close requested */ },
|
|
351
|
+
{ enableSearch: true },
|
|
352
|
+
);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**From `@mariozechner/pi-coding-agent`:**
|
|
356
|
+
|
|
357
|
+
| Component | Constructor | Purpose |
|
|
358
|
+
|-----------|-------------|---------|
|
|
359
|
+
| `DynamicBorder` | `new DynamicBorder((s: string) => theme.fg("accent", s))` | Border line |
|
|
360
|
+
| `BorderedLoader` | — | Spinner with cancel support |
|
|
361
|
+
| `CustomEditor` | `new CustomEditor(theme, keybindings)` | Base class for custom editors |
|
|
362
|
+
</built_in_components>
|
|
363
|
+
|
|
364
|
+
<keyboard_input>
|
|
365
|
+
```typescript
|
|
366
|
+
import { matchesKey, Key } from "@mariozechner/pi-tui";
|
|
367
|
+
|
|
368
|
+
handleInput(data: string) {
|
|
369
|
+
// Basic keys
|
|
370
|
+
if (matchesKey(data, Key.up)) {}
|
|
371
|
+
if (matchesKey(data, Key.down)) {}
|
|
372
|
+
if (matchesKey(data, Key.enter)) {}
|
|
373
|
+
if (matchesKey(data, Key.escape)) {}
|
|
374
|
+
if (matchesKey(data, Key.tab)) {}
|
|
375
|
+
if (matchesKey(data, Key.space)) {}
|
|
376
|
+
if (matchesKey(data, Key.backspace)) {}
|
|
377
|
+
if (matchesKey(data, Key.home)) {}
|
|
378
|
+
if (matchesKey(data, Key.end)) {}
|
|
379
|
+
|
|
380
|
+
// With modifiers
|
|
381
|
+
if (matchesKey(data, Key.ctrl("c"))) {}
|
|
382
|
+
if (matchesKey(data, Key.shift("tab"))) {}
|
|
383
|
+
if (matchesKey(data, Key.alt("left"))) {}
|
|
384
|
+
if (matchesKey(data, Key.ctrlShift("p"))) {}
|
|
385
|
+
|
|
386
|
+
// String format also works: "enter", "ctrl+c", "shift+tab"
|
|
387
|
+
|
|
388
|
+
// Printable character detection
|
|
389
|
+
if (data.length === 1 && data.charCodeAt(0) >= 32) {
|
|
390
|
+
// Letter, number, symbol
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**handleInput contract:**
|
|
396
|
+
1. Check for your keys
|
|
397
|
+
2. Update state
|
|
398
|
+
3. Call `this.invalidate()` if render output changes
|
|
399
|
+
4. Call `tui.requestRender()` to trigger re-render
|
|
400
|
+
</keyboard_input>
|
|
401
|
+
|
|
402
|
+
<line_width_rule>
|
|
403
|
+
**Cardinal rule: each line from render() must not exceed `width` visible characters.**
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import { visibleWidth, truncateToWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";
|
|
407
|
+
|
|
408
|
+
visibleWidth("\x1b[32mHello\x1b[0m"); // Returns 5 (ignores ANSI codes)
|
|
409
|
+
truncateToWidth("Very long text here", 10); // "Very lo..."
|
|
410
|
+
truncateToWidth("Very long text here", 10, ""); // "Very long " (no ellipsis)
|
|
411
|
+
wrapTextWithAnsi("\x1b[32mLong green text\x1b[0m", 10); // Word wrap preserving ANSI
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
If lines exceed `width`, terminal wraps cause visual corruption.
|
|
415
|
+
</line_width_rule>
|
|
416
|
+
|
|
417
|
+
<performance_caching>
|
|
418
|
+
Always cache render output:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
class CachedComponent {
|
|
422
|
+
private cachedWidth?: number;
|
|
423
|
+
private cachedLines?: string[];
|
|
424
|
+
|
|
425
|
+
render(width: number): string[] {
|
|
426
|
+
if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
|
|
427
|
+
const lines = this.computeLines(width);
|
|
428
|
+
this.cachedWidth = width;
|
|
429
|
+
this.cachedLines = lines;
|
|
430
|
+
return lines;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Update cycle:** State changes → `invalidate()` → `tui.requestRender()` → `render(width)` called
|
|
438
|
+
|
|
439
|
+
**Game loop pattern** (real-time updates):
|
|
440
|
+
```typescript
|
|
441
|
+
this.interval = setInterval(() => {
|
|
442
|
+
this.tick();
|
|
443
|
+
this.version++;
|
|
444
|
+
this.tui.requestRender();
|
|
445
|
+
}, 100); // 10 FPS
|
|
446
|
+
|
|
447
|
+
// Clean up in dispose()
|
|
448
|
+
clearInterval(this.interval);
|
|
449
|
+
```
|
|
450
|
+
</performance_caching>
|
|
451
|
+
|
|
452
|
+
<theme_colors>
|
|
453
|
+
Always use theme from callback params, never import directly.
|
|
454
|
+
|
|
455
|
+
**All foreground colors:**
|
|
456
|
+
|
|
457
|
+
| Category | Colors |
|
|
458
|
+
|----------|--------|
|
|
459
|
+
| General | `text`, `accent`, `muted`, `dim` |
|
|
460
|
+
| Status | `success`, `error`, `warning` |
|
|
461
|
+
| Borders | `border`, `borderAccent`, `borderMuted` |
|
|
462
|
+
| Messages | `userMessageText`, `customMessageText`, `customMessageLabel` |
|
|
463
|
+
| Tools | `toolTitle`, `toolOutput` |
|
|
464
|
+
| Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` |
|
|
465
|
+
| Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` |
|
|
466
|
+
| Syntax | `syntaxComment`, `syntaxKeyword`, `syntaxFunction`, `syntaxVariable`, `syntaxString`, `syntaxNumber`, `syntaxType`, `syntaxOperator`, `syntaxPunctuation` |
|
|
467
|
+
| Thinking | `thinkingOff`, `thinkingMinimal`, `thinkingLow`, `thinkingMedium`, `thinkingHigh`, `thinkingXhigh` |
|
|
468
|
+
|
|
469
|
+
**All background colors:** `selectedBg`, `userMessageBg`, `customMessageBg`, `toolPendingBg`, `toolSuccessBg`, `toolErrorBg`
|
|
470
|
+
|
|
471
|
+
**Syntax highlighting:**
|
|
472
|
+
```typescript
|
|
473
|
+
import { highlightCode, getLanguageFromPath } from "@mariozechner/pi-coding-agent";
|
|
474
|
+
const lang = getLanguageFromPath("/file.rs"); // "rust"
|
|
475
|
+
const highlighted = highlightCode(code, lang, theme);
|
|
476
|
+
```
|
|
477
|
+
</theme_colors>
|
|
478
|
+
|
|
479
|
+
<common_mistakes>
|
|
480
|
+
1. **Lines exceed width** → Visual corruption. Use `truncateToWidth()` on every line.
|
|
481
|
+
2. **Forgetting `tui.requestRender()`** → UI doesn't update. Call after invalidate().
|
|
482
|
+
3. **Importing theme directly** → Wrong colors after theme switch. Use theme from callback.
|
|
483
|
+
4. **Not typing DynamicBorder param** → `new DynamicBorder((s: string) => theme.fg("accent", s))`.
|
|
484
|
+
5. **Reusing disposed overlay components** → Create fresh instances each time.
|
|
485
|
+
6. **Styles bleeding across lines** → TUI resets per line. Reapply styles, or use `wrapTextWithAnsi()`.
|
|
486
|
+
7. **Not implementing invalidate()** → Theme changes don't take effect.
|
|
487
|
+
8. **Forgetting super.invalidate()** → `override invalidate() { super.invalidate(); /* cleanup */ }`
|
|
488
|
+
9. **Timer not cleaned up** → Call `clearInterval` before `done()`.
|
|
489
|
+
10. **Using ctx.ui in non-interactive mode** → Check `ctx.hasUI` first.
|
|
490
|
+
</common_mistakes>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
Complete event reference with handler signatures, return types, and type narrowing utilities.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<event_categories>
|
|
6
|
+
|
|
7
|
+
**Session events:** `session_start`, `session_before_switch`, `session_switch`, `session_before_fork`, `session_fork`, `session_before_compact`, `session_compact`, `session_before_tree`, `session_tree`, `session_shutdown`
|
|
8
|
+
|
|
9
|
+
**Agent events:** `before_agent_start`, `agent_start`, `agent_end`, `turn_start`, `turn_end`, `context`, `before_provider_request`, `message_start`, `message_update`, `message_end`
|
|
10
|
+
|
|
11
|
+
**Tool events:** `tool_call`, `tool_execution_start`, `tool_execution_update`, `tool_execution_end`, `tool_result`
|
|
12
|
+
|
|
13
|
+
**Input events:** `input`
|
|
14
|
+
|
|
15
|
+
**Model events:** `model_select`
|
|
16
|
+
|
|
17
|
+
**User bash events:** `user_bash`
|
|
18
|
+
|
|
19
|
+
**Special:** `session_directory` (CLI startup only, no `ctx` — receives only event)
|
|
20
|
+
|
|
21
|
+
</event_categories>
|
|
22
|
+
|
|
23
|
+
<handler_signature>
|
|
24
|
+
```typescript
|
|
25
|
+
pi.on("event_name", async (event, ctx: ExtensionContext) => {
|
|
26
|
+
// event — typed payload for this event
|
|
27
|
+
// ctx — access to UI, session, model, control flow
|
|
28
|
+
// Return undefined for no action, or a typed response
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
</handler_signature>
|
|
32
|
+
|
|
33
|
+
<key_events>
|
|
34
|
+
|
|
35
|
+
**before_agent_start** — Fired after user prompt, before agent loop. Primary hook for context injection and system prompt modification.
|
|
36
|
+
```typescript
|
|
37
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
38
|
+
// event.prompt — user's prompt text
|
|
39
|
+
// event.images — attached images
|
|
40
|
+
// event.systemPrompt — current system prompt
|
|
41
|
+
return {
|
|
42
|
+
message: { customType: "my-ext", content: "Extra context", display: true },
|
|
43
|
+
systemPrompt: event.systemPrompt + "\n\nExtra instructions...",
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**tool_call** — Fired before tool executes. Can block.
|
|
49
|
+
```typescript
|
|
50
|
+
import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
|
|
51
|
+
|
|
52
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
53
|
+
if (isToolCallEventType("bash", event)) {
|
|
54
|
+
// event.input is typed as { command: string; timeout?: number }
|
|
55
|
+
if (event.input.command.includes("rm -rf")) {
|
|
56
|
+
return { block: true, reason: "Dangerous command" };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**tool_result** — Fired after tool executes. Can modify result. Handlers chain like middleware.
|
|
63
|
+
```typescript
|
|
64
|
+
import { isBashToolResult } from "@mariozechner/pi-coding-agent";
|
|
65
|
+
|
|
66
|
+
pi.on("tool_result", async (event, ctx) => {
|
|
67
|
+
if (isBashToolResult(event)) {
|
|
68
|
+
// event.details is typed as BashToolDetails
|
|
69
|
+
}
|
|
70
|
+
// Return partial patch: { content, details, isError }
|
|
71
|
+
// Omitted fields keep current values
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**context** — Fired before each LLM call. Modify messages non-destructively.
|
|
76
|
+
```typescript
|
|
77
|
+
pi.on("context", async (event, ctx) => {
|
|
78
|
+
// event.messages is a deep copy — safe to modify
|
|
79
|
+
const filtered = event.messages.filter(m => !shouldPrune(m));
|
|
80
|
+
return { messages: filtered };
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**input** — Fired when user input is received, before skill/template expansion.
|
|
85
|
+
```typescript
|
|
86
|
+
pi.on("input", async (event, ctx) => {
|
|
87
|
+
// event.text — raw input
|
|
88
|
+
// event.source — "interactive", "rpc", or "extension"
|
|
89
|
+
if (event.text.startsWith("?quick "))
|
|
90
|
+
return { action: "transform", text: `Respond briefly: ${event.text.slice(7)}` };
|
|
91
|
+
return { action: "continue" };
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**model_select** — Fired when model changes.
|
|
96
|
+
```typescript
|
|
97
|
+
pi.on("model_select", async (event, ctx) => {
|
|
98
|
+
// event.model, event.previousModel, event.source ("set"|"cycle"|"restore")
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
</key_events>
|
|
103
|
+
|
|
104
|
+
<type_narrowing>
|
|
105
|
+
Built-in type guards for tool events:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { isToolCallEventType, isBashToolResult } from "@mariozechner/pi-coding-agent";
|
|
109
|
+
|
|
110
|
+
// Tool calls — narrows event.input type
|
|
111
|
+
if (isToolCallEventType("bash", event)) { /* event.input: { command, timeout? } */ }
|
|
112
|
+
if (isToolCallEventType("read", event)) { /* event.input: { path, offset?, limit? } */ }
|
|
113
|
+
if (isToolCallEventType("write", event)) { /* event.input: { path, content } */ }
|
|
114
|
+
if (isToolCallEventType("edit", event)) { /* event.input: { path, oldText, newText } */ }
|
|
115
|
+
|
|
116
|
+
// Tool results — narrows event.details type
|
|
117
|
+
if (isBashToolResult(event)) { /* event.details: BashToolDetails */ }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For custom tools, export your input type and use explicit type params:
|
|
121
|
+
```typescript
|
|
122
|
+
if (isToolCallEventType<"my_tool", MyToolInput>("my_tool", event)) {
|
|
123
|
+
event.input.action; // typed
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
</type_narrowing>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
The extension lifecycle from load to shutdown, including the full event flow.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<loading>
|
|
6
|
+
Extensions load when GSD starts (or on `/reload`). The default export function runs synchronously — subscribe to events and register tools/commands during this call.
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
GSD starts
|
|
10
|
+
└─► Extension default function runs
|
|
11
|
+
├── pi.on("event", handler) ← Subscribe
|
|
12
|
+
├── pi.registerTool({...}) ← Register tools
|
|
13
|
+
├── pi.registerCommand(...) ← Register commands
|
|
14
|
+
└── pi.registerShortcut(...) ← Register shortcuts
|
|
15
|
+
└─► session_start fires
|
|
16
|
+
```
|
|
17
|
+
</loading>
|
|
18
|
+
|
|
19
|
+
<event_flow>
|
|
20
|
+
Full event flow per user prompt:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
user sends prompt
|
|
24
|
+
├─► Extension commands checked (bypass if match)
|
|
25
|
+
├─► input event (can intercept/transform/handle)
|
|
26
|
+
├─► Skill/template expansion
|
|
27
|
+
├─► before_agent_start (inject message, modify system prompt)
|
|
28
|
+
├─► agent_start
|
|
29
|
+
│
|
|
30
|
+
│ ┌── Turn loop (repeats while LLM calls tools) ──┐
|
|
31
|
+
│ │ turn_start │
|
|
32
|
+
│ │ context (can modify messages sent to LLM) │
|
|
33
|
+
│ │ before_provider_request (inspect/replace payload)│
|
|
34
|
+
│ │ LLM responds → may call tools: │
|
|
35
|
+
│ │ tool_call (can BLOCK) │
|
|
36
|
+
│ │ tool_execution_start/update/end │
|
|
37
|
+
│ │ tool_result (can MODIFY) │
|
|
38
|
+
│ │ turn_end │
|
|
39
|
+
│ └────────────────────────────────────────────────┘
|
|
40
|
+
│
|
|
41
|
+
└─► agent_end
|
|
42
|
+
```
|
|
43
|
+
</event_flow>
|
|
44
|
+
|
|
45
|
+
<session_events>
|
|
46
|
+
| Event | When | Can Return |
|
|
47
|
+
|-------|------|------------|
|
|
48
|
+
| `session_start` | Session loads | — |
|
|
49
|
+
| `session_before_switch` | Before `/new` or `/resume` | `{ cancel: true }` |
|
|
50
|
+
| `session_switch` | After switch | — |
|
|
51
|
+
| `session_before_fork` | Before `/fork` | `{ cancel: true }`, `{ skipConversationRestore: true }` |
|
|
52
|
+
| `session_fork` | After fork | — |
|
|
53
|
+
| `session_before_compact` | Before compaction | `{ cancel: true }`, `{ compaction: {...} }` |
|
|
54
|
+
| `session_compact` | After compaction | — |
|
|
55
|
+
| `session_shutdown` | On exit | — |
|
|
56
|
+
</session_events>
|
|
57
|
+
|
|
58
|
+
<hot_reload>
|
|
59
|
+
Extensions in auto-discovered locations hot-reload with `/reload`:
|
|
60
|
+
- `session_shutdown` fires for old runtime
|
|
61
|
+
- Resources re-scanned
|
|
62
|
+
- `session_start` fires for new runtime
|
|
63
|
+
- Code after `await ctx.reload()` still runs from the pre-reload version — treat as terminal
|
|
64
|
+
</hot_reload>
|