@compilr-dev/cli 0.4.0 → 0.5.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 +254 -68
- package/dist/.tsbuildinfo.app +1 -0
- package/dist/.tsbuildinfo.data +1 -0
- package/dist/.tsbuildinfo.domain +1 -0
- package/dist/.tsbuildinfo.foundation +1 -0
- package/dist/agent.d.ts +134 -4
- package/dist/agent.js +345 -166
- package/dist/anchors/index.d.ts +9 -0
- package/dist/anchors/index.js +9 -0
- package/dist/anchors/project-anchors.d.ts +79 -0
- package/dist/anchors/project-anchors.js +202 -0
- package/dist/auth/api-client.d.ts +124 -0
- package/dist/auth/api-client.js +261 -0
- package/dist/auth/index.d.ts +172 -0
- package/dist/auth/index.js +545 -0
- package/dist/auth/storage.d.ts +52 -0
- package/dist/auth/storage.js +118 -0
- package/dist/changelog/index.d.ts +16 -0
- package/dist/changelog/index.js +24 -0
- package/dist/changelog/releases.d.ts +17 -0
- package/dist/changelog/releases.js +63 -0
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands-v2/handlers/auth.d.ts +10 -0
- package/dist/commands-v2/handlers/auth.js +118 -0
- package/dist/commands-v2/handlers/background.d.ts +14 -0
- package/dist/commands-v2/handlers/background.js +276 -0
- package/dist/commands-v2/handlers/context.d.ts +13 -0
- package/dist/commands-v2/handlers/context.js +533 -0
- package/dist/commands-v2/handlers/core.d.ts +14 -0
- package/dist/commands-v2/handlers/core.js +290 -0
- package/dist/commands-v2/handlers/debug.d.ts +11 -0
- package/dist/commands-v2/handlers/debug.js +177 -0
- package/dist/commands-v2/handlers/delegations.d.ts +8 -0
- package/dist/commands-v2/handlers/delegations.js +29 -0
- package/dist/commands-v2/handlers/files.d.ts +8 -0
- package/dist/commands-v2/handlers/files.js +162 -0
- package/dist/commands-v2/handlers/filter.d.ts +9 -0
- package/dist/commands-v2/handlers/filter.js +130 -0
- package/dist/commands-v2/handlers/games.d.ts +7 -0
- package/dist/commands-v2/handlers/games.js +57 -0
- package/dist/commands-v2/handlers/index.d.ts +25 -0
- package/dist/commands-v2/handlers/index.js +63 -0
- package/dist/commands-v2/handlers/mcp.d.ts +8 -0
- package/dist/commands-v2/handlers/mcp.js +39 -0
- package/dist/commands-v2/handlers/notifications.d.ts +9 -0
- package/dist/commands-v2/handlers/notifications.js +34 -0
- package/dist/commands-v2/handlers/project.d.ts +22 -0
- package/dist/commands-v2/handlers/project.js +1035 -0
- package/dist/commands-v2/handlers/reset.d.ts +11 -0
- package/dist/commands-v2/handlers/reset.js +118 -0
- package/dist/commands-v2/handlers/session.d.ts +161 -0
- package/dist/commands-v2/handlers/session.js +805 -0
- package/dist/commands-v2/handlers/settings.d.ts +17 -0
- package/dist/commands-v2/handlers/settings.js +417 -0
- package/dist/commands-v2/handlers/tasks.d.ts +5 -0
- package/dist/commands-v2/handlers/tasks.js +36 -0
- package/dist/commands-v2/handlers/team.d.ts +9 -0
- package/dist/commands-v2/handlers/team.js +549 -0
- package/dist/commands-v2/handlers/terminals.d.ts +9 -0
- package/dist/commands-v2/handlers/terminals.js +34 -0
- package/dist/commands-v2/index.d.ts +14 -0
- package/dist/commands-v2/index.js +18 -0
- package/dist/commands-v2/registry.d.ts +52 -0
- package/dist/commands-v2/registry.js +114 -0
- package/dist/commands-v2/types.d.ts +153 -0
- package/dist/commands-v2/types.js +7 -0
- package/dist/commands.js +123 -7
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/db/index.js +98 -4
- package/dist/db/repositories/document-repository.d.ts +2 -0
- package/dist/db/repositories/document-repository.js +5 -1
- package/dist/db/repositories/index.d.ts +2 -0
- package/dist/db/repositories/index.js +1 -0
- package/dist/db/repositories/plan-repository.d.ts +101 -0
- package/dist/db/repositories/plan-repository.js +275 -0
- package/dist/db/repositories/project-repository.d.ts +6 -0
- package/dist/db/repositories/project-repository.js +41 -0
- package/dist/db/repositories/work-item-repository.d.ts +15 -0
- package/dist/db/repositories/work-item-repository.js +69 -4
- package/dist/db/schema.d.ts +40 -3
- package/dist/db/schema.js +66 -3
- package/dist/episodes/index.d.ts +20 -0
- package/dist/episodes/index.js +27 -0
- package/dist/episodes/recorder.d.ts +51 -0
- package/dist/episodes/recorder.js +195 -0
- package/dist/episodes/significant-work.d.ts +21 -0
- package/dist/episodes/significant-work.js +56 -0
- package/dist/episodes/store.d.ts +38 -0
- package/dist/episodes/store.js +199 -0
- package/dist/episodes/types.d.ts +35 -0
- package/dist/episodes/types.js +6 -0
- package/dist/episodes/work-at-risk.d.ts +12 -0
- package/dist/episodes/work-at-risk.js +38 -0
- package/dist/episodes/work-summary-anchor.d.ts +23 -0
- package/dist/episodes/work-summary-anchor.js +73 -0
- package/dist/games/coins.d.ts +66 -0
- package/dist/games/coins.js +165 -0
- package/dist/games/game-base.d.ts +84 -0
- package/dist/games/game-base.js +204 -0
- package/dist/games/index.d.ts +16 -0
- package/dist/games/index.js +49 -0
- package/dist/games/scores.d.ts +69 -0
- package/dist/games/scores.js +191 -0
- package/dist/games/tetris/board.d.ts +59 -0
- package/dist/games/tetris/board.js +170 -0
- package/dist/games/tetris/index.d.ts +109 -0
- package/dist/games/tetris/index.js +610 -0
- package/dist/games/tetris/pieces.d.ts +44 -0
- package/dist/games/tetris/pieces.js +271 -0
- package/dist/games/tetris/renderer.d.ts +26 -0
- package/dist/games/tetris/renderer.js +77 -0
- package/dist/guide/guide-content.d.ts +23 -0
- package/dist/guide/guide-content.js +196 -0
- package/dist/guide/index.d.ts +8 -0
- package/dist/guide/index.js +7 -0
- package/dist/guide/shared-content.d.ts +37 -0
- package/dist/guide/shared-content.js +1272 -0
- package/dist/guide/tutorial-helpers.d.ts +57 -0
- package/dist/guide/tutorial-helpers.js +147 -0
- package/dist/handlers/ask-user-handlers.d.ts +32 -0
- package/dist/handlers/ask-user-handlers.js +104 -0
- package/dist/handlers/delegation-handlers.d.ts +34 -0
- package/dist/handlers/delegation-handlers.js +291 -0
- package/dist/handlers/permission-handler.d.ts +30 -0
- package/dist/handlers/permission-handler.js +205 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +615 -179
- package/dist/input-handlers/index.d.ts +7 -0
- package/dist/input-handlers/index.js +7 -0
- package/dist/input-handlers/memory-handler.d.ts +26 -0
- package/dist/input-handlers/memory-handler.js +69 -0
- package/dist/models/index.d.ts +10 -0
- package/dist/models/index.js +12 -0
- package/dist/models/model-registry.d.ts +38 -0
- package/dist/models/model-registry.js +69 -0
- package/dist/models/model-tiers.d.ts +28 -0
- package/dist/models/model-tiers.js +71 -0
- package/dist/models/model-validation.d.ts +25 -0
- package/dist/models/model-validation.js +291 -0
- package/dist/models/ollama-models.d.ts +73 -0
- package/dist/models/ollama-models.js +178 -0
- package/dist/models/provider-types.d.ts +6 -0
- package/dist/models/provider-types.js +1 -0
- package/dist/models/providers.d.ts +35 -0
- package/dist/models/providers.js +58 -0
- package/dist/models/types.d.ts +4 -0
- package/dist/models/types.js +4 -0
- package/dist/multi-agent/activity.d.ts +21 -0
- package/dist/multi-agent/activity.js +34 -0
- package/dist/multi-agent/agent-selection.d.ts +55 -0
- package/dist/multi-agent/agent-selection.js +90 -0
- package/dist/multi-agent/artifacts.d.ts +197 -0
- package/dist/multi-agent/artifacts.js +379 -0
- package/dist/multi-agent/checkpointer.d.ts +138 -0
- package/dist/multi-agent/checkpointer.js +471 -0
- package/dist/multi-agent/collision-utils.d.ts +16 -0
- package/dist/multi-agent/collision-utils.js +28 -0
- package/dist/multi-agent/context-resolver.d.ts +97 -0
- package/dist/multi-agent/context-resolver.js +316 -0
- package/dist/multi-agent/custom-agents.d.ts +83 -0
- package/dist/multi-agent/custom-agents.js +227 -0
- package/dist/multi-agent/delegation-tracker.d.ts +157 -0
- package/dist/multi-agent/delegation-tracker.js +243 -0
- package/dist/multi-agent/file-lock-hook.d.ts +29 -0
- package/dist/multi-agent/file-lock-hook.js +97 -0
- package/dist/multi-agent/file-locks.d.ts +58 -0
- package/dist/multi-agent/file-locks.js +194 -0
- package/dist/multi-agent/index.d.ts +24 -0
- package/dist/multi-agent/index.js +30 -0
- package/dist/multi-agent/mention-parser.d.ts +64 -0
- package/dist/multi-agent/mention-parser.js +146 -0
- package/dist/multi-agent/notification-manager.d.ts +84 -0
- package/dist/multi-agent/notification-manager.js +224 -0
- package/dist/multi-agent/pending-requests.d.ts +122 -0
- package/dist/multi-agent/pending-requests.js +155 -0
- package/dist/multi-agent/session-registry.d.ts +139 -0
- package/dist/multi-agent/session-registry.js +514 -0
- package/dist/multi-agent/shared-context.d.ts +293 -0
- package/dist/multi-agent/shared-context.js +671 -0
- package/dist/multi-agent/skill-requirements.d.ts +66 -0
- package/dist/multi-agent/skill-requirements.js +178 -0
- package/dist/multi-agent/task-assignment.d.ts +69 -0
- package/dist/multi-agent/task-assignment.js +123 -0
- package/dist/multi-agent/task-suggestion.d.ts +31 -0
- package/dist/multi-agent/task-suggestion.js +72 -0
- package/dist/multi-agent/team-agent.d.ts +201 -0
- package/dist/multi-agent/team-agent.js +488 -0
- package/dist/multi-agent/team.d.ts +286 -0
- package/dist/multi-agent/team.js +610 -0
- package/dist/multi-agent/tool-config.d.ts +110 -0
- package/dist/multi-agent/tool-config.js +661 -0
- package/dist/multi-agent/types.d.ts +211 -0
- package/dist/multi-agent/types.js +617 -0
- package/dist/prompts/plan-mode-prompt.d.ts +11 -0
- package/dist/prompts/plan-mode-prompt.js +95 -0
- package/dist/repl-helpers.d.ts +63 -0
- package/dist/repl-helpers.js +319 -0
- package/dist/repl-v2.d.ts +554 -0
- package/dist/repl-v2.js +3286 -0
- package/dist/session/index.d.ts +6 -0
- package/dist/session/index.js +6 -0
- package/dist/session/project-session-manager.d.ts +158 -0
- package/dist/session/project-session-manager.js +650 -0
- package/dist/settings/index.d.ts +156 -13
- package/dist/settings/index.js +377 -24
- package/dist/settings/mcp-config.d.ts +76 -0
- package/dist/settings/mcp-config.js +143 -0
- package/dist/settings/paths.d.ts +114 -0
- package/dist/settings/paths.js +270 -0
- package/dist/shared-handlers.d.ts +62 -0
- package/dist/shared-handlers.js +48 -0
- package/dist/system-prompt/builder.d.ts +5 -0
- package/dist/system-prompt/builder.js +4 -0
- package/dist/system-prompt/index.d.ts +18 -0
- package/dist/system-prompt/index.js +18 -0
- package/dist/system-prompt/modules.d.ts +5 -0
- package/dist/system-prompt/modules.js +4 -0
- package/dist/tabbed-menu.js +2 -1
- package/dist/templates/compilr-md-import.d.ts +16 -0
- package/dist/templates/compilr-md-import.js +241 -0
- package/dist/templates/compilr-md.js +10 -58
- package/dist/templates/config-json.d.ts +1 -25
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.js +35 -75
- package/dist/themes/colors.js +3 -1
- package/dist/themes/registry.d.ts +5 -36
- package/dist/themes/registry.js +11 -95
- package/dist/themes/types.d.ts +3 -38
- package/dist/themes/types.js +2 -2
- package/dist/tool-names.d.ts +108 -0
- package/dist/tool-names.js +227 -0
- package/dist/tools/anchor-tools.d.ts +31 -0
- package/dist/tools/anchor-tools.js +255 -0
- package/dist/tools/artifact-tools.d.ts +42 -0
- package/dist/tools/artifact-tools.js +328 -0
- package/dist/tools/ask-user-simple.d.ts +1 -1
- package/dist/tools/ask-user-simple.js +2 -1
- package/dist/tools/ask-user.d.ts +1 -1
- package/dist/tools/ask-user.js +2 -1
- package/dist/tools/backlog-wrappers.d.ts +56 -0
- package/dist/tools/backlog-wrappers.js +353 -0
- package/dist/tools/backlog.d.ts +2 -2
- package/dist/tools/backlog.js +2 -2
- package/dist/tools/db-tools.d.ts +12 -0
- package/dist/tools/db-tools.js +14 -0
- package/dist/tools/delegate-background.d.ts +27 -0
- package/dist/tools/delegate-background.js +115 -0
- package/dist/tools/delegate.d.ts +22 -0
- package/dist/tools/delegate.js +97 -0
- package/dist/tools/delegation-status.d.ts +16 -0
- package/dist/tools/delegation-status.js +128 -0
- package/dist/tools/document-db.d.ts +43 -0
- package/dist/tools/document-db.js +220 -0
- package/dist/tools/guide-tool.d.ts +12 -0
- package/dist/tools/guide-tool.js +59 -0
- package/dist/tools/handoff.d.ts +25 -0
- package/dist/tools/handoff.js +99 -0
- package/dist/tools/meta-tools.d.ts +26 -0
- package/dist/tools/meta-tools.js +47 -0
- package/dist/tools/plan-tools.d.ts +54 -0
- package/dist/tools/plan-tools.js +338 -0
- package/dist/tools/platform-adapter.d.ts +29 -0
- package/dist/tools/platform-adapter.js +394 -0
- package/dist/tools/project-db.d.ts +34 -0
- package/dist/tools/project-db.js +39 -0
- package/dist/tools/recall-work-tool.d.ts +18 -0
- package/dist/tools/recall-work-tool.js +82 -0
- package/dist/tools/workitem-db.d.ts +135 -0
- package/dist/tools/workitem-db.js +730 -0
- package/dist/tools.d.ts +67 -2
- package/dist/tools.js +238 -38
- package/dist/ui/ask-user-overlay.d.ts +2 -2
- package/dist/ui/ask-user-overlay.js +443 -535
- package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
- package/dist/ui/ask-user-simple-overlay.js +182 -209
- package/dist/ui/autocomplete-controller.d.ts +42 -0
- package/dist/ui/autocomplete-controller.js +384 -0
- package/dist/ui/base/index.d.ts +26 -0
- package/dist/ui/base/index.js +33 -0
- package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
- package/dist/ui/base/inline-overlay-utils.js +320 -0
- package/dist/ui/base/inline-overlay.d.ts +159 -0
- package/dist/ui/base/inline-overlay.js +257 -0
- package/dist/ui/base/key-utils.d.ts +15 -0
- package/dist/ui/base/key-utils.js +30 -0
- package/dist/ui/base/overlay-base-v2.d.ts +203 -0
- package/dist/ui/base/overlay-base-v2.js +260 -0
- package/dist/ui/base/overlay-base.d.ts +156 -0
- package/dist/ui/base/overlay-base.js +238 -0
- package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
- package/dist/ui/base/overlay-lifecycle.js +159 -0
- package/dist/ui/base/overlay-types.d.ts +185 -0
- package/dist/ui/base/overlay-types.js +7 -0
- package/dist/ui/base/render-utils.d.ts +27 -0
- package/dist/ui/base/render-utils.js +36 -0
- package/dist/ui/base/screen-stack.d.ts +148 -0
- package/dist/ui/base/screen-stack.js +184 -0
- package/dist/ui/base/tabbed-list-overlay-v2.d.ts +118 -0
- package/dist/ui/base/tabbed-list-overlay-v2.js +335 -0
- package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
- package/dist/ui/base/tabbed-list-overlay.js +369 -0
- package/dist/ui/constants/labels.d.ts +14 -0
- package/dist/ui/constants/labels.js +51 -0
- package/dist/ui/conversation-store.d.ts +55 -0
- package/dist/ui/conversation-store.js +107 -0
- package/dist/ui/conversation.d.ts +75 -4
- package/dist/ui/conversation.js +376 -165
- package/dist/ui/diff.d.ts +7 -1
- package/dist/ui/diff.js +85 -48
- package/dist/ui/ephemeral.d.ts +1 -1
- package/dist/ui/ephemeral.js +4 -10
- package/dist/ui/features/index.d.ts +34 -0
- package/dist/ui/features/index.js +34 -0
- package/dist/ui/features/input-feature.d.ts +85 -0
- package/dist/ui/features/input-feature.js +238 -0
- package/dist/ui/features/list-feature.d.ts +155 -0
- package/dist/ui/features/list-feature.js +244 -0
- package/dist/ui/features/pagination-feature.d.ts +154 -0
- package/dist/ui/features/pagination-feature.js +238 -0
- package/dist/ui/features/search-feature.d.ts +148 -0
- package/dist/ui/features/search-feature.js +185 -0
- package/dist/ui/features/tab-feature.d.ts +194 -0
- package/dist/ui/features/tab-feature.js +307 -0
- package/dist/ui/file-autocomplete.d.ts +24 -0
- package/dist/ui/file-autocomplete.js +56 -0
- package/dist/ui/footer-renderer.d.ts +69 -0
- package/dist/ui/footer-renderer.js +431 -0
- package/dist/ui/footer.d.ts +181 -7
- package/dist/ui/footer.js +523 -74
- package/dist/ui/guardrail-overlay.d.ts +29 -0
- package/dist/ui/guardrail-overlay.js +145 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -3
- package/dist/ui/input-controller.d.ts +51 -0
- package/dist/ui/input-controller.js +176 -0
- package/dist/ui/input-prompt.d.ts +135 -33
- package/dist/ui/input-prompt.js +728 -337
- package/dist/ui/iteration-limit-overlay.d.ts +2 -2
- package/dist/ui/iteration-limit-overlay.js +92 -128
- package/dist/ui/keyboard-handler.d.ts +57 -0
- package/dist/ui/keyboard-handler.js +557 -0
- package/dist/ui/keys-overlay.d.ts +1 -0
- package/dist/ui/keys-overlay.js +203 -141
- package/dist/ui/line-utils.d.ts +88 -0
- package/dist/ui/line-utils.js +150 -0
- package/dist/ui/live-region-facade.d.ts +42 -0
- package/dist/ui/live-region-facade.js +205 -0
- package/dist/ui/live-region.d.ts +157 -0
- package/dist/ui/live-region.js +379 -0
- package/dist/ui/mascot/expressions.d.ts +32 -0
- package/dist/ui/mascot/expressions.js +213 -0
- package/dist/ui/mascot/index.d.ts +8 -0
- package/dist/ui/mascot/index.js +8 -0
- package/dist/ui/mascot/renderer.d.ts +19 -0
- package/dist/ui/mascot/renderer.js +132 -0
- package/dist/ui/overlay/data/tutorial-content.d.ts +9 -0
- package/dist/ui/overlay/data/tutorial-content.js +9 -0
- package/dist/ui/overlay/data/tutorial-registry.d.ts +12 -0
- package/dist/ui/overlay/data/tutorial-registry.js +116 -0
- package/dist/ui/overlay/data/tutorial-types.d.ts +35 -0
- package/dist/ui/overlay/data/tutorial-types.js +6 -0
- package/dist/ui/overlay/data/tutorials/basics/first-conversation.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/basics/first-conversation.js +220 -0
- package/dist/ui/overlay/data/tutorials/basics/first-project.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/basics/first-project.js +284 -0
- package/dist/ui/overlay/data/tutorials/basics/navigation.d.ts +8 -0
- package/dist/ui/overlay/data/tutorials/basics/navigation.js +22 -0
- package/dist/ui/overlay/data/tutorials/basics/welcome.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/basics/welcome.js +174 -0
- package/dist/ui/overlay/data/tutorials/config/context-management.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/config/context-management.js +158 -0
- package/dist/ui/overlay/data/tutorials/config/mcp-servers.d.ts +8 -0
- package/dist/ui/overlay/data/tutorials/config/mcp-servers.js +155 -0
- package/dist/ui/overlay/data/tutorials/config/model-selection.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/config/model-selection.js +162 -0
- package/dist/ui/overlay/data/tutorials/config/permissions-safety.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/config/permissions-safety.js +163 -0
- package/dist/ui/overlay/data/tutorials/config/settings-config.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/config/settings-config.js +166 -0
- package/dist/ui/overlay/data/tutorials/planning/arch.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/arch.js +168 -0
- package/dist/ui/overlay/data/tutorials/planning/backlog.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/backlog.js +103 -0
- package/dist/ui/overlay/data/tutorials/planning/build.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/build.js +173 -0
- package/dist/ui/overlay/data/tutorials/planning/design.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/design.js +205 -0
- package/dist/ui/overlay/data/tutorials/planning/docs.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/docs.js +143 -0
- package/dist/ui/overlay/data/tutorials/planning/prd.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/prd.js +173 -0
- package/dist/ui/overlay/data/tutorials/planning/scaffold.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/scaffold.js +164 -0
- package/dist/ui/overlay/data/tutorials/planning/sketch.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/planning/sketch.js +58 -0
- package/dist/ui/overlay/data/tutorials/projects/anchors.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/projects/anchors.js +248 -0
- package/dist/ui/overlay/data/tutorials/projects/import-project.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/projects/import-project.js +172 -0
- package/dist/ui/overlay/data/tutorials/projects/managing-projects.d.ts +8 -0
- package/dist/ui/overlay/data/tutorials/projects/managing-projects.js +212 -0
- package/dist/ui/overlay/data/tutorials/projects/new-project.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/projects/new-project.js +251 -0
- package/dist/ui/overlay/data/tutorials/projects/session-management.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/projects/session-management.js +169 -0
- package/dist/ui/overlay/data/tutorials/teams/background-execution.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/teams/background-execution.js +171 -0
- package/dist/ui/overlay/data/tutorials/teams/multi-terminal.d.ts +8 -0
- package/dist/ui/overlay/data/tutorials/teams/multi-terminal.js +147 -0
- package/dist/ui/overlay/data/tutorials/teams/task-assignment.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/teams/task-assignment.js +204 -0
- package/dist/ui/overlay/data/tutorials/teams/team-overview.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/teams/team-overview.js +165 -0
- package/dist/ui/overlay/data/tutorials/teams/working-with-agents.d.ts +7 -0
- package/dist/ui/overlay/data/tutorials/teams/working-with-agents.js +172 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.js +814 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.js +749 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
- package/dist/ui/overlay/impl/artifact-detail-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +232 -0
- package/dist/ui/overlay/impl/artifact-overlay-v2.d.ts +40 -0
- package/dist/ui/overlay/impl/artifact-overlay-v2.js +115 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.js +581 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
- package/dist/ui/overlay/impl/background-overlay-v2.d.ts +40 -0
- package/dist/ui/overlay/impl/background-overlay-v2.js +147 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +52 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.js +681 -0
- package/dist/ui/overlay/impl/changelog-overlay-v2.d.ts +44 -0
- package/dist/ui/overlay/impl/changelog-overlay-v2.js +165 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.js +439 -0
- package/dist/ui/overlay/impl/config-overlay-v2.d.ts +111 -0
- package/dist/ui/overlay/impl/config-overlay-v2.js +718 -0
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +83 -0
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +711 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +57 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.js +382 -0
- package/dist/ui/overlay/impl/delegations-overlay-v2.d.ts +28 -0
- package/dist/ui/overlay/impl/delegations-overlay-v2.js +279 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.js +117 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +84 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1112 -0
- package/dist/ui/overlay/impl/filter-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/filter-overlay-v2.js +110 -0
- package/dist/ui/overlay/impl/games-overlay-v2.d.ts +31 -0
- package/dist/ui/overlay/impl/games-overlay-v2.js +135 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/help-overlay-v2.d.ts +57 -0
- package/dist/ui/overlay/impl/help-overlay-v2.js +287 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
- package/dist/ui/overlay/impl/login-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/login-overlay-v2.js +277 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
- package/dist/ui/overlay/impl/mcp-overlay-v2.d.ts +63 -0
- package/dist/ui/overlay/impl/mcp-overlay-v2.js +907 -0
- package/dist/ui/overlay/impl/model-overlay-v2.d.ts +93 -0
- package/dist/ui/overlay/impl/model-overlay-v2.js +1143 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +108 -0
- package/dist/ui/overlay/impl/new-overlay-v2.js +1243 -0
- package/dist/ui/overlay/impl/notifications-overlay-v2.d.ts +20 -0
- package/dist/ui/overlay/impl/notifications-overlay-v2.js +116 -0
- package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.d.ts +76 -0
- package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.js +728 -0
- package/dist/ui/overlay/impl/pending-overlay-v2.d.ts +51 -0
- package/dist/ui/overlay/impl/pending-overlay-v2.js +445 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
- package/dist/ui/overlay/impl/permissions-overlay-v2.d.ts +85 -0
- package/dist/ui/overlay/impl/permissions-overlay-v2.js +820 -0
- package/dist/ui/overlay/impl/plan-approval-overlay-v2.d.ts +35 -0
- package/dist/ui/overlay/impl/plan-approval-overlay-v2.js +181 -0
- package/dist/ui/overlay/impl/project-edit-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/project-edit-overlay-v2.js +195 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +37 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.js +733 -0
- package/dist/ui/overlay/impl/reset-overlay-v2.d.ts +39 -0
- package/dist/ui/overlay/impl/reset-overlay-v2.js +107 -0
- package/dist/ui/overlay/impl/resume-overlay-v2.d.ts +60 -0
- package/dist/ui/overlay/impl/resume-overlay-v2.js +414 -0
- package/dist/ui/overlay/impl/session-mode-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/session-mode-overlay-v2.js +124 -0
- package/dist/ui/overlay/impl/tasks-overlay-v2.d.ts +28 -0
- package/dist/ui/overlay/impl/tasks-overlay-v2.js +283 -0
- package/dist/ui/overlay/impl/team-overlay-v2.d.ts +86 -0
- package/dist/ui/overlay/impl/team-overlay-v2.js +692 -0
- package/dist/ui/overlay/impl/terminals-overlay-v2.d.ts +26 -0
- package/dist/ui/overlay/impl/terminals-overlay-v2.js +217 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.js +214 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.js +212 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.js +641 -0
- package/dist/ui/overlay/index.d.ts +52 -0
- package/dist/ui/overlay/index.js +54 -0
- package/dist/ui/overlay/key-utils.d.ts +6 -0
- package/dist/ui/overlay/key-utils.js +6 -0
- package/dist/ui/overlay/types.d.ts +140 -0
- package/dist/ui/overlay/types.js +22 -0
- package/dist/ui/overlay-manager.d.ts +43 -0
- package/dist/ui/overlay-manager.js +238 -0
- package/dist/ui/overlays.d.ts +0 -4
- package/dist/ui/overlays.js +4 -460
- package/dist/ui/permission-overlay.d.ts +1 -1
- package/dist/ui/permission-overlay.js +189 -300
- package/dist/ui/providers/types.d.ts +178 -0
- package/dist/ui/providers/types.js +9 -0
- package/dist/ui/render-modes.d.ts +36 -0
- package/dist/ui/render-modes.js +44 -0
- package/dist/ui/startup-menu.d.ts +36 -0
- package/dist/ui/startup-menu.js +236 -0
- package/dist/ui/status-bar-controller.d.ts +33 -0
- package/dist/ui/status-bar-controller.js +99 -0
- package/dist/ui/subagent-renderer.d.ts +117 -0
- package/dist/ui/subagent-renderer.js +318 -0
- package/dist/ui/terminal-autocomplete-utils.d.ts +23 -0
- package/dist/ui/terminal-autocomplete-utils.js +83 -0
- package/dist/ui/terminal-codes.d.ts +94 -0
- package/dist/ui/terminal-codes.js +124 -0
- package/dist/ui/terminal-line-builders.d.ts +17 -0
- package/dist/ui/terminal-line-builders.js +42 -0
- package/dist/ui/terminal-render-item.d.ts +16 -0
- package/dist/ui/terminal-render-item.js +267 -0
- package/dist/ui/terminal-renderer.d.ts +220 -0
- package/dist/ui/terminal-renderer.js +750 -0
- package/dist/ui/terminal-types.d.ts +179 -0
- package/dist/ui/terminal-types.js +34 -0
- package/dist/ui/terminal-ui.d.ts +331 -0
- package/dist/ui/terminal-ui.js +819 -0
- package/dist/ui/terminal.d.ts +20 -0
- package/dist/ui/terminal.js +72 -0
- package/dist/ui/todo-zone.d.ts +19 -1
- package/dist/ui/todo-zone.js +124 -38
- package/dist/ui/tool-formatters.d.ts +16 -0
- package/dist/ui/tool-formatters.js +1027 -0
- package/dist/ui/turn-metrics.d.ts +56 -0
- package/dist/ui/turn-metrics.js +75 -0
- package/dist/ui/types.d.ts +28 -0
- package/dist/ui/types.js +1 -0
- package/dist/ui/vscode-diff-ipc.d.ts +102 -0
- package/dist/ui/vscode-diff-ipc.js +385 -0
- package/dist/utils/credentials.d.ts +24 -5
- package/dist/utils/credentials.js +123 -9
- package/dist/utils/debug-log.d.ts +28 -0
- package/dist/utils/debug-log.js +57 -0
- package/dist/utils/format-tokens.d.ts +13 -0
- package/dist/utils/format-tokens.js +18 -0
- package/dist/utils/git-config.d.ts +26 -0
- package/dist/utils/git-config.js +54 -0
- package/dist/utils/message-utils.d.ts +61 -0
- package/dist/utils/message-utils.js +72 -0
- package/dist/utils/model-tiers.d.ts +8 -1
- package/dist/utils/model-tiers.js +39 -17
- package/dist/utils/open-browser.d.ts +5 -0
- package/dist/utils/open-browser.js +32 -0
- package/dist/utils/path-safety.d.ts +56 -0
- package/dist/utils/path-safety.js +240 -0
- package/dist/utils/project-detection.d.ts +58 -0
- package/dist/utils/project-detection.js +424 -0
- package/dist/utils/project-memory.js +2 -1
- package/dist/utils/project-status.d.ts +2 -2
- package/dist/utils/startup-perf.d.ts +18 -0
- package/dist/utils/startup-perf.js +60 -0
- package/dist/utils/token-tracker.d.ts +62 -0
- package/dist/utils/token-tracker.js +150 -0
- package/dist/utils/token-types.d.ts +23 -0
- package/dist/utils/token-types.js +18 -0
- package/dist/utils/types/config-types.d.ts +32 -0
- package/dist/utils/types/config-types.js +8 -0
- package/dist/utils/update-checker.d.ts +28 -0
- package/dist/utils/update-checker.js +106 -0
- package/dist/utils/version.d.ts +7 -0
- package/dist/utils/version.js +10 -0
- package/dist/utils/vscode-detect.d.ts +39 -0
- package/dist/utils/vscode-detect.js +137 -0
- package/dist/workflow/guided-mode-injector.d.ts +42 -0
- package/dist/workflow/guided-mode-injector.js +191 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.js +8 -0
- package/dist/workflow/step-criteria.d.ts +62 -0
- package/dist/workflow/step-criteria.js +150 -0
- package/dist/workflow/step-tracker.d.ts +92 -0
- package/dist/workflow/step-tracker.js +141 -0
- package/package.json +32 -12
- package/dist/index.old.d.ts +0 -7
- package/dist/index.old.js +0 -1014
- package/dist/repl.d.ts +0 -121
- package/dist/repl.js +0 -1878
- package/dist/templates/claude-md.d.ts +0 -7
- package/dist/templates/claude-md.js +0 -189
- package/dist/test-autocomplete.d.ts +0 -7
- package/dist/test-autocomplete.js +0 -85
- package/dist/test-tabbed-menu.d.ts +0 -7
- package/dist/test-tabbed-menu.js +0 -25
- package/dist/tool-selector.d.ts +0 -71
- package/dist/tool-selector.js +0 -184
- package/dist/ui/agents-overlay.d.ts +0 -12
- package/dist/ui/agents-overlay.js +0 -501
- package/dist/ui/arch-type-overlay.d.ts +0 -20
- package/dist/ui/arch-type-overlay.js +0 -229
- package/dist/ui/backlog-overlay.d.ts +0 -17
- package/dist/ui/backlog-overlay.js +0 -786
- package/dist/ui/commands-overlay.d.ts +0 -11
- package/dist/ui/commands-overlay.js +0 -410
- package/dist/ui/config-overlay.d.ts +0 -34
- package/dist/ui/config-overlay.js +0 -977
- package/dist/ui/init-overlay.d.ts +0 -24
- package/dist/ui/init-overlay.js +0 -525
- package/dist/ui/input-prompt-v2.d.ts +0 -179
- package/dist/ui/input-prompt-v2.js +0 -991
- package/dist/ui/model-warning-overlay.d.ts +0 -30
- package/dist/ui/model-warning-overlay.js +0 -171
- package/dist/ui/tools-overlay.d.ts +0 -26
- package/dist/ui/tools-overlay.js +0 -278
- package/dist/ui/tutorial-overlay.d.ts +0 -10
- package/dist/ui/tutorial-overlay.js +0 -936
package/dist/ui/input-prompt.js
CHANGED
|
@@ -1,83 +1,174 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Input Prompt
|
|
2
|
+
* Input Prompt v2 (Event-Driven)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Refactored input handling with event-driven architecture.
|
|
5
|
+
* - Emits events instead of blocking with getInput()
|
|
6
|
+
* - Supports queue mode for capturing input during agent execution
|
|
7
|
+
* - Always captures keystrokes (no blocking)
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Events:
|
|
10
|
+
* - 'submit' - User pressed Enter with input
|
|
11
|
+
* - 'command' - User submitted a slash command
|
|
12
|
+
* - 'cancel' - User pressed Ctrl+C
|
|
13
|
+
* - 'escape' - User pressed Esc (for aborting agent)
|
|
14
|
+
* - 'change' - Input text changed
|
|
10
15
|
*/
|
|
11
|
-
import
|
|
16
|
+
import { EventEmitter } from 'events';
|
|
17
|
+
import { Chalk } from 'chalk';
|
|
18
|
+
import { getStyles } from '../themes/index.js';
|
|
12
19
|
import * as terminal from './terminal.js';
|
|
20
|
+
import { getFileMatches, extractAtMention, replaceAtMention, extractDollarMention, replaceDollarMention, } from './file-autocomplete.js';
|
|
21
|
+
import { debugRender } from '../utils/debug-log.js';
|
|
22
|
+
import { stripAnsi as unifiedStripAnsi, getPhysicalLineCountWithOffset, } from './line-utils.js';
|
|
13
23
|
// =============================================================================
|
|
14
24
|
// Constants
|
|
15
25
|
// =============================================================================
|
|
26
|
+
// Force color output (level 3 = 24-bit true color)
|
|
27
|
+
const chalk = new Chalk({ level: 3 });
|
|
16
28
|
const MAX_VISIBLE_COMMANDS = 10;
|
|
17
29
|
// =============================================================================
|
|
18
|
-
// Default Commands
|
|
30
|
+
// Default Commands (from central registry)
|
|
19
31
|
// =============================================================================
|
|
20
|
-
export const DEFAULT_COMMANDS = [
|
|
21
|
-
{ command: '/help', description: 'Show available commands' },
|
|
22
|
-
{ command: '/exit', description: 'Quit the demo' },
|
|
23
|
-
{ command: '/clear', description: 'Clear conversation history' },
|
|
24
|
-
{ command: '/compact', description: 'Summarize old messages' },
|
|
25
|
-
{ command: '/tools', description: 'List available tools' },
|
|
26
|
-
{ command: '/tokens', description: 'Show session token usage' },
|
|
27
|
-
{ command: '/context', description: 'Show context window usage' },
|
|
28
|
-
];
|
|
32
|
+
export const DEFAULT_COMMANDS = [];
|
|
29
33
|
// =============================================================================
|
|
30
34
|
// Helper Functions
|
|
31
35
|
// =============================================================================
|
|
32
36
|
/**
|
|
33
37
|
* Strip ANSI codes from string
|
|
38
|
+
* Uses unified line-utils for consistent behavior across components.
|
|
34
39
|
*/
|
|
35
40
|
export function stripAnsi(str) {
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
return unifiedStripAnsi(str);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Format input text with syntax highlighting for special prefixes.
|
|
45
|
+
* - $agent references: bold + secondary color
|
|
46
|
+
* - @path references: secondary color
|
|
47
|
+
* - /commands: primary color
|
|
48
|
+
*/
|
|
49
|
+
function formatInputText(text) {
|
|
50
|
+
const s = getStyles();
|
|
51
|
+
let result = text;
|
|
52
|
+
// Format $agent references - bold + secondary
|
|
53
|
+
// Match $word at word boundaries (not inside other text)
|
|
54
|
+
result = result.replace(/(?<![$\w])\$([a-zA-Z_][a-zA-Z0-9_]*)\b/g, (_match, agentId) => chalk.bold(s.secondary(`$${agentId}`)));
|
|
55
|
+
// Format @path references - secondary (not bold, paths can be long)
|
|
56
|
+
// Match @word or @path/to/file patterns
|
|
57
|
+
result = result.replace(/(?<![@\w])@([\w./-]+)/g, (_match, path) => s.secondary(`@${path}`));
|
|
58
|
+
// Format /commands at start of input - primary color
|
|
59
|
+
// Only match at start of line (after optional whitespace)
|
|
60
|
+
result = result.replace(/^(\s*)(\/[a-zA-Z][a-zA-Z0-9_-]*)/g, (_match, space, cmd) => space + s.primary(cmd));
|
|
61
|
+
return result;
|
|
38
62
|
}
|
|
39
63
|
/**
|
|
40
64
|
* Calculate physical lines for wrapped text
|
|
65
|
+
* Uses unified line-utils for consistent behavior across components.
|
|
41
66
|
*/
|
|
42
67
|
function calcPhysicalLines(text, startCol, termWidth) {
|
|
43
|
-
|
|
44
|
-
return 1;
|
|
45
|
-
const totalLen = startCol + text.length;
|
|
46
|
-
return Math.ceil(totalLen / termWidth) || 1;
|
|
68
|
+
return getPhysicalLineCountWithOffset(text, startCol, termWidth);
|
|
47
69
|
}
|
|
48
70
|
/**
|
|
49
|
-
*
|
|
71
|
+
* Calculate fuzzy match score for a query against a target string.
|
|
72
|
+
* Higher score = better match.
|
|
73
|
+
* Returns -1 if no match.
|
|
74
|
+
*/
|
|
75
|
+
function fuzzyMatchScore(query, target) {
|
|
76
|
+
const queryLower = query.toLowerCase();
|
|
77
|
+
const targetLower = target.toLowerCase();
|
|
78
|
+
// Exact prefix match - highest priority (score 1000+)
|
|
79
|
+
if (targetLower.startsWith(queryLower)) {
|
|
80
|
+
return 1000 + (100 - target.length); // Shorter commands rank higher
|
|
81
|
+
}
|
|
82
|
+
// Contiguous substring match - high priority (score 500+)
|
|
83
|
+
if (targetLower.includes(queryLower)) {
|
|
84
|
+
const index = targetLower.indexOf(queryLower);
|
|
85
|
+
return 500 + (100 - index); // Earlier matches rank higher
|
|
86
|
+
}
|
|
87
|
+
// Fuzzy match - characters appear in order (score 100+)
|
|
88
|
+
let queryIdx = 0;
|
|
89
|
+
let consecutiveBonus = 0;
|
|
90
|
+
let lastMatchIdx = -1;
|
|
91
|
+
for (let i = 0; i < targetLower.length && queryIdx < queryLower.length; i++) {
|
|
92
|
+
if (targetLower[i] === queryLower[queryIdx]) {
|
|
93
|
+
// Bonus for consecutive matches
|
|
94
|
+
if (lastMatchIdx === i - 1) {
|
|
95
|
+
consecutiveBonus += 10;
|
|
96
|
+
}
|
|
97
|
+
lastMatchIdx = i;
|
|
98
|
+
queryIdx++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// All query characters found in order
|
|
102
|
+
if (queryIdx === queryLower.length) {
|
|
103
|
+
return 100 + consecutiveBonus + (100 - target.length);
|
|
104
|
+
}
|
|
105
|
+
// No match
|
|
106
|
+
return -1;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Filter and rank commands matching input using fuzzy matching
|
|
50
110
|
*/
|
|
51
111
|
function filterCommands(input, commands) {
|
|
52
|
-
|
|
53
|
-
|
|
112
|
+
// Score all commands
|
|
113
|
+
const scored = commands
|
|
114
|
+
.map((cmd) => ({
|
|
115
|
+
cmd,
|
|
116
|
+
score: fuzzyMatchScore(input, cmd.command),
|
|
117
|
+
}))
|
|
118
|
+
.filter((item) => item.score >= 0);
|
|
119
|
+
// Sort by score (highest first)
|
|
120
|
+
scored.sort((a, b) => b.score - a.score);
|
|
121
|
+
return scored.map((item) => item.cmd);
|
|
54
122
|
}
|
|
55
123
|
// =============================================================================
|
|
56
124
|
// Input Prompt Class
|
|
57
125
|
// =============================================================================
|
|
58
|
-
export class InputPrompt {
|
|
126
|
+
export class InputPrompt extends EventEmitter {
|
|
59
127
|
// Configuration
|
|
60
128
|
prompt;
|
|
61
129
|
promptLen;
|
|
62
130
|
showSeparators;
|
|
63
131
|
commands;
|
|
64
|
-
|
|
132
|
+
getAgentSuggestions;
|
|
133
|
+
getCommands;
|
|
65
134
|
// Input state
|
|
66
135
|
state = {
|
|
67
136
|
lines: [''],
|
|
68
137
|
currentLine: 0,
|
|
69
138
|
cursorPos: 0,
|
|
70
139
|
};
|
|
71
|
-
//
|
|
140
|
+
// Command autocomplete (for /commands)
|
|
72
141
|
autocomplete = {
|
|
73
142
|
active: false,
|
|
74
143
|
matches: [],
|
|
75
144
|
selectedIndex: 0,
|
|
145
|
+
scrollOffset: 0,
|
|
146
|
+
};
|
|
147
|
+
// File autocomplete (for @paths)
|
|
148
|
+
fileAutocomplete = {
|
|
149
|
+
active: false,
|
|
150
|
+
matches: [],
|
|
151
|
+
selectedIndex: 0,
|
|
152
|
+
scrollOffset: 0,
|
|
153
|
+
partial: '',
|
|
154
|
+
};
|
|
155
|
+
// Agent autocomplete (for $agents)
|
|
156
|
+
agentAutocomplete = {
|
|
157
|
+
active: false,
|
|
158
|
+
matches: [],
|
|
159
|
+
selectedIndex: 0,
|
|
160
|
+
scrollOffset: 0,
|
|
161
|
+
partial: '',
|
|
162
|
+
startPos: 0,
|
|
163
|
+
lineIndex: 0,
|
|
76
164
|
};
|
|
77
165
|
// History
|
|
78
166
|
history = [];
|
|
79
167
|
historyIndex = -1;
|
|
80
168
|
savedInput = '';
|
|
169
|
+
// Queue mode
|
|
170
|
+
queueMode = false;
|
|
171
|
+
queuedInputs = [];
|
|
81
172
|
// Rendering tracking
|
|
82
173
|
renderedLines = 0;
|
|
83
174
|
dropdownLines = 0;
|
|
@@ -85,29 +176,56 @@ export class InputPrompt {
|
|
|
85
176
|
hasSeparators = false;
|
|
86
177
|
// Control
|
|
87
178
|
isRunning = false;
|
|
88
|
-
|
|
179
|
+
// Double Esc detection
|
|
180
|
+
lastEscTime = 0;
|
|
181
|
+
DOUBLE_ESC_THRESHOLD_MS = 500; // 500ms window for double Esc
|
|
182
|
+
// Suggestion (ghost text for next action)
|
|
183
|
+
suggestion = null;
|
|
89
184
|
constructor(options = {}) {
|
|
90
|
-
|
|
185
|
+
super();
|
|
186
|
+
this.prompt = options.prompt ?? getStyles().primary('❯ ');
|
|
91
187
|
this.promptLen = stripAnsi(this.prompt).length;
|
|
92
188
|
this.showSeparators = options.showSeparators ?? true;
|
|
93
189
|
this.commands = options.commands ?? DEFAULT_COMMANDS;
|
|
94
|
-
this.
|
|
190
|
+
this.getAgentSuggestions = options.getAgentSuggestions;
|
|
191
|
+
this.getCommands = options.getCommands;
|
|
95
192
|
}
|
|
96
193
|
// ===========================================================================
|
|
97
194
|
// Public API
|
|
98
195
|
// ===========================================================================
|
|
99
196
|
/**
|
|
100
|
-
*
|
|
101
|
-
* Returns when user submits or cancels
|
|
197
|
+
* Update the prompt string (for dynamic theme changes)
|
|
102
198
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
199
|
+
setPrompt(prompt) {
|
|
200
|
+
this.prompt = prompt;
|
|
201
|
+
this.promptLen = stripAnsi(prompt).length;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Set a suggestion for the next action (ghost text)
|
|
205
|
+
*/
|
|
206
|
+
setSuggestion(action) {
|
|
207
|
+
this.suggestion = action;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get the current suggestion
|
|
211
|
+
*/
|
|
212
|
+
getSuggestion() {
|
|
213
|
+
return this.suggestion;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Clear the current suggestion
|
|
217
|
+
*/
|
|
218
|
+
clearSuggestion() {
|
|
219
|
+
this.suggestion = null;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Set the callback to get available team agents for $ autocomplete
|
|
223
|
+
*/
|
|
224
|
+
setAgentSuggestionsCallback(callback) {
|
|
225
|
+
this.getAgentSuggestions = callback;
|
|
108
226
|
}
|
|
109
227
|
/**
|
|
110
|
-
* Start input
|
|
228
|
+
* Start input capture (non-blocking, event-driven)
|
|
111
229
|
*/
|
|
112
230
|
start() {
|
|
113
231
|
if (this.isRunning)
|
|
@@ -115,17 +233,67 @@ export class InputPrompt {
|
|
|
115
233
|
this.isRunning = true;
|
|
116
234
|
terminal.enableRawMode();
|
|
117
235
|
this.resetState();
|
|
118
|
-
this.render();
|
|
119
236
|
process.stdin.on('data', this.handleData);
|
|
120
237
|
}
|
|
121
238
|
/**
|
|
122
|
-
* Stop input
|
|
239
|
+
* Stop input capture
|
|
123
240
|
*/
|
|
124
241
|
stop() {
|
|
242
|
+
if (!this.isRunning)
|
|
243
|
+
return;
|
|
125
244
|
this.isRunning = false;
|
|
126
245
|
terminal.disableRawMode();
|
|
127
246
|
process.stdin.removeListener('data', this.handleData);
|
|
128
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Check if running
|
|
250
|
+
*/
|
|
251
|
+
isActive() {
|
|
252
|
+
return this.isRunning;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Enable/disable queue mode
|
|
256
|
+
* In queue mode, Enter adds to queue instead of emitting 'submit'
|
|
257
|
+
*/
|
|
258
|
+
setQueueMode(enabled) {
|
|
259
|
+
this.queueMode = enabled;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Check if in queue mode
|
|
263
|
+
*/
|
|
264
|
+
isQueueMode() {
|
|
265
|
+
return this.queueMode;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get all queued inputs (FIFO order)
|
|
269
|
+
*/
|
|
270
|
+
getQueuedInputs() {
|
|
271
|
+
return [...this.queuedInputs];
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Pop the first queued input
|
|
275
|
+
*/
|
|
276
|
+
popQueuedInput() {
|
|
277
|
+
return this.queuedInputs.shift() ?? null;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Check if there are queued inputs
|
|
281
|
+
*/
|
|
282
|
+
hasQueuedInput() {
|
|
283
|
+
return this.queuedInputs.length > 0;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Get number of queued inputs
|
|
287
|
+
*/
|
|
288
|
+
getQueueLength() {
|
|
289
|
+
return this.queuedInputs.length;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Clear the queue
|
|
293
|
+
*/
|
|
294
|
+
clearQueue() {
|
|
295
|
+
this.queuedInputs = [];
|
|
296
|
+
}
|
|
129
297
|
/**
|
|
130
298
|
* Get current buffer value
|
|
131
299
|
*/
|
|
@@ -139,37 +307,235 @@ export class InputPrompt {
|
|
|
139
307
|
this.state.lines = value.split('\n');
|
|
140
308
|
this.state.currentLine = this.state.lines.length - 1;
|
|
141
309
|
this.state.cursorPos = this.state.lines[this.state.currentLine].length;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
310
|
+
this.updateAutocomplete();
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Clear input buffer
|
|
314
|
+
*/
|
|
315
|
+
clearInput() {
|
|
316
|
+
this.state = {
|
|
317
|
+
lines: [''],
|
|
318
|
+
currentLine: 0,
|
|
319
|
+
cursorPos: 0,
|
|
320
|
+
};
|
|
321
|
+
this.autocomplete = {
|
|
322
|
+
active: false,
|
|
323
|
+
matches: [],
|
|
324
|
+
selectedIndex: 0,
|
|
325
|
+
scrollOffset: 0,
|
|
326
|
+
};
|
|
327
|
+
this.fileAutocomplete = {
|
|
328
|
+
active: false,
|
|
329
|
+
matches: [],
|
|
330
|
+
selectedIndex: 0,
|
|
331
|
+
scrollOffset: 0,
|
|
332
|
+
partial: '',
|
|
333
|
+
};
|
|
334
|
+
this.agentAutocomplete = {
|
|
335
|
+
active: false,
|
|
336
|
+
matches: [],
|
|
337
|
+
selectedIndex: 0,
|
|
338
|
+
scrollOffset: 0,
|
|
339
|
+
partial: '',
|
|
340
|
+
startPos: 0,
|
|
341
|
+
lineIndex: 0,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Add command to history
|
|
346
|
+
*/
|
|
347
|
+
addToHistory(input) {
|
|
348
|
+
if (input.trim() && (this.history.length === 0 || this.history[this.history.length - 1] !== input)) {
|
|
349
|
+
this.history.push(input);
|
|
145
350
|
}
|
|
146
351
|
}
|
|
147
352
|
/**
|
|
148
|
-
*
|
|
353
|
+
* Render the input prompt - returns array of lines
|
|
354
|
+
* Does NOT write to terminal (Footer handles that)
|
|
149
355
|
*/
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
356
|
+
render() {
|
|
357
|
+
const lines = [];
|
|
358
|
+
// Top separator
|
|
359
|
+
if (this.showSeparators) {
|
|
360
|
+
lines.push(this.getSeparatorLine());
|
|
155
361
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
362
|
+
// Input lines
|
|
363
|
+
const s = getStyles();
|
|
364
|
+
for (let i = 0; i < this.state.lines.length; i++) {
|
|
365
|
+
const linePrompt = i === 0 ? this.prompt : s.muted(' \\ ');
|
|
366
|
+
const lineContent = this.state.lines[i];
|
|
367
|
+
// Show suggestion as ghost text on first line when input is empty
|
|
368
|
+
if (i === 0 && lineContent === '' && this.suggestion && !this.autocomplete.active && !this.fileAutocomplete.active) {
|
|
369
|
+
const hint = s.muted(' (tab to accept)');
|
|
370
|
+
lines.push(linePrompt + s.muted(this.suggestion) + hint);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// Format special prefixes: $agent, @path, /command
|
|
374
|
+
const formattedContent = formatInputText(lineContent);
|
|
375
|
+
lines.push(linePrompt + formattedContent);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// Bottom separator
|
|
379
|
+
if (this.showSeparators) {
|
|
380
|
+
lines.push(this.getSeparatorLine());
|
|
381
|
+
}
|
|
382
|
+
return lines;
|
|
159
383
|
}
|
|
160
384
|
/**
|
|
161
|
-
* Get
|
|
385
|
+
* Get the cursor position info for rendering
|
|
162
386
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
387
|
+
getCursorInfo() {
|
|
388
|
+
const termWidth = terminal.getTerminalWidth();
|
|
389
|
+
const currentLinePromptLen = this.state.currentLine === 0 ? this.promptLen : 5;
|
|
390
|
+
const cursorAbsPos = currentLinePromptLen + this.state.cursorPos;
|
|
391
|
+
// Calculate which row within input (accounting for separators)
|
|
392
|
+
let row = this.showSeparators ? 1 : 0; // Start after top separator
|
|
393
|
+
for (let i = 0; i < this.state.currentLine; i++) {
|
|
394
|
+
const lp = i === 0 ? this.promptLen : 5;
|
|
395
|
+
row += calcPhysicalLines(this.state.lines[i], lp, termWidth);
|
|
396
|
+
}
|
|
397
|
+
row += Math.floor(cursorAbsPos / termWidth);
|
|
398
|
+
const col = cursorAbsPos % termWidth;
|
|
399
|
+
debugRender('InputPrompt:getCursorInfo', `termWidth=${String(termWidth)} cursorPos=${String(this.state.cursorPos)} currentLine=${String(this.state.currentLine)} promptLen=${String(this.promptLen)}`);
|
|
400
|
+
debugRender('InputPrompt:getCursorInfo', `cursorAbsPos=${String(cursorAbsPos)} row=${String(row)} col=${String(col)}`);
|
|
401
|
+
return { row, col };
|
|
165
402
|
}
|
|
166
403
|
/**
|
|
167
|
-
*
|
|
404
|
+
* Get autocomplete dropdown lines (if active)
|
|
168
405
|
*/
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
406
|
+
getAutocompleteLines() {
|
|
407
|
+
const s = getStyles();
|
|
408
|
+
// Agent autocomplete takes highest priority
|
|
409
|
+
if (this.agentAutocomplete.active && this.agentAutocomplete.matches.length > 0) {
|
|
410
|
+
const lines = [];
|
|
411
|
+
const offset = this.agentAutocomplete.scrollOffset;
|
|
412
|
+
const visible = this.agentAutocomplete.matches.slice(offset, offset + MAX_VISIBLE_COMMANDS);
|
|
413
|
+
const total = this.agentAutocomplete.matches.length;
|
|
414
|
+
// Show scroll indicator if there are more items above
|
|
415
|
+
if (offset > 0) {
|
|
416
|
+
lines.push(s.muted(` ↑ ${String(offset)} more above`));
|
|
417
|
+
}
|
|
418
|
+
for (let i = 0; i < visible.length; i++) {
|
|
419
|
+
const agent = visible[i];
|
|
420
|
+
const actualIndex = offset + i;
|
|
421
|
+
const isSelected = actualIndex === this.agentAutocomplete.selectedIndex;
|
|
422
|
+
const prefix = isSelected ? s.primary('❯ ') : ' ';
|
|
423
|
+
const mascot = agent.mascot + ' ';
|
|
424
|
+
const name = isSelected ? s.primary(chalk.bold('$' + agent.id)) : '$' + agent.id;
|
|
425
|
+
const desc = s.muted(` - ${agent.displayName}`);
|
|
426
|
+
lines.push(`${prefix}${mascot}${name}${desc}`);
|
|
427
|
+
}
|
|
428
|
+
// Show scroll indicator if there are more items below
|
|
429
|
+
const remaining = total - offset - visible.length;
|
|
430
|
+
if (remaining > 0) {
|
|
431
|
+
lines.push(s.muted(` ↓ ${String(remaining)} more below`));
|
|
432
|
+
}
|
|
433
|
+
return lines;
|
|
434
|
+
}
|
|
435
|
+
// File autocomplete takes second priority
|
|
436
|
+
if (this.fileAutocomplete.active && this.fileAutocomplete.matches.length > 0) {
|
|
437
|
+
const lines = [];
|
|
438
|
+
const offset = this.fileAutocomplete.scrollOffset;
|
|
439
|
+
const visible = this.fileAutocomplete.matches.slice(offset, offset + MAX_VISIBLE_COMMANDS);
|
|
440
|
+
const total = this.fileAutocomplete.matches.length;
|
|
441
|
+
// Show scroll indicator if there are more items above
|
|
442
|
+
if (offset > 0) {
|
|
443
|
+
lines.push(s.muted(` ↑ ${String(offset)} more above`));
|
|
444
|
+
}
|
|
445
|
+
for (let i = 0; i < visible.length; i++) {
|
|
446
|
+
const file = visible[i];
|
|
447
|
+
const actualIndex = offset + i;
|
|
448
|
+
const isSelected = actualIndex === this.fileAutocomplete.selectedIndex;
|
|
449
|
+
const prefix = isSelected ? s.primary('❯ ') : ' ';
|
|
450
|
+
const icon = file.isDirectory ? s.warning('📁 ') : s.info('📄 ');
|
|
451
|
+
const name = isSelected ? s.primary(chalk.bold(file.path)) : file.path;
|
|
452
|
+
lines.push(`${prefix}${icon}${name}`);
|
|
453
|
+
}
|
|
454
|
+
// Show scroll indicator if there are more items below
|
|
455
|
+
const remaining = total - offset - visible.length;
|
|
456
|
+
if (remaining > 0) {
|
|
457
|
+
lines.push(s.muted(` ↓ ${String(remaining)} more below`));
|
|
458
|
+
}
|
|
459
|
+
return lines;
|
|
460
|
+
}
|
|
461
|
+
// Command autocomplete
|
|
462
|
+
if (!this.autocomplete.active || this.autocomplete.matches.length === 0) {
|
|
463
|
+
return [];
|
|
172
464
|
}
|
|
465
|
+
const lines = [];
|
|
466
|
+
const offset = this.autocomplete.scrollOffset;
|
|
467
|
+
const visible = this.autocomplete.matches.slice(offset, offset + MAX_VISIBLE_COMMANDS);
|
|
468
|
+
const total = this.autocomplete.matches.length;
|
|
469
|
+
// Show scroll indicator if there are more items above
|
|
470
|
+
if (offset > 0) {
|
|
471
|
+
lines.push(s.muted(` ↑ ${String(offset)} more above`));
|
|
472
|
+
}
|
|
473
|
+
for (let i = 0; i < visible.length; i++) {
|
|
474
|
+
const cmd = visible[i];
|
|
475
|
+
const actualIndex = offset + i;
|
|
476
|
+
const isSelected = actualIndex === this.autocomplete.selectedIndex;
|
|
477
|
+
const prefix = isSelected ? s.primary('❯ ') : ' ';
|
|
478
|
+
const name = isSelected ? s.primary(chalk.bold(cmd.command)) : cmd.command;
|
|
479
|
+
const desc = s.muted(` - ${cmd.description}`);
|
|
480
|
+
lines.push(`${prefix}${name}${desc}`);
|
|
481
|
+
}
|
|
482
|
+
// Show scroll indicator if there are more items below
|
|
483
|
+
const remaining = total - offset - visible.length;
|
|
484
|
+
if (remaining > 0) {
|
|
485
|
+
lines.push(s.muted(` ↓ ${String(remaining)} more below`));
|
|
486
|
+
}
|
|
487
|
+
return lines;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Check if autocomplete is showing
|
|
491
|
+
*/
|
|
492
|
+
isAutocompleteActive() {
|
|
493
|
+
return ((this.autocomplete.active && this.autocomplete.matches.length > 0) ||
|
|
494
|
+
(this.fileAutocomplete.active && this.fileAutocomplete.matches.length > 0) ||
|
|
495
|
+
(this.agentAutocomplete.active && this.agentAutocomplete.matches.length > 0));
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Get height of rendered content
|
|
499
|
+
*/
|
|
500
|
+
getHeight() {
|
|
501
|
+
let height = this.state.lines.length;
|
|
502
|
+
if (this.showSeparators)
|
|
503
|
+
height += 2;
|
|
504
|
+
return height;
|
|
505
|
+
}
|
|
506
|
+
// ===========================================================================
|
|
507
|
+
// Legacy API (for backwards compatibility during migration)
|
|
508
|
+
// ===========================================================================
|
|
509
|
+
/**
|
|
510
|
+
* @deprecated Use event-driven start() instead
|
|
511
|
+
* Kept for backwards compatibility during migration
|
|
512
|
+
*/
|
|
513
|
+
async getInput() {
|
|
514
|
+
return new Promise((resolve) => {
|
|
515
|
+
const onSubmit = (input) => {
|
|
516
|
+
cleanup();
|
|
517
|
+
resolve({ action: 'submit', value: input });
|
|
518
|
+
};
|
|
519
|
+
const onCommand = (command, args) => {
|
|
520
|
+
cleanup();
|
|
521
|
+
resolve({ action: 'command', command, args });
|
|
522
|
+
};
|
|
523
|
+
const onCancel = () => {
|
|
524
|
+
cleanup();
|
|
525
|
+
resolve({ action: 'cancel' });
|
|
526
|
+
};
|
|
527
|
+
const cleanup = () => {
|
|
528
|
+
this.removeListener('submit', onSubmit);
|
|
529
|
+
this.removeListener('command', onCommand);
|
|
530
|
+
this.removeListener('cancel', onCancel);
|
|
531
|
+
};
|
|
532
|
+
this.on('submit', onSubmit);
|
|
533
|
+
this.on('command', onCommand);
|
|
534
|
+
this.on('cancel', onCancel);
|
|
535
|
+
if (!this.isRunning) {
|
|
536
|
+
this.start();
|
|
537
|
+
}
|
|
538
|
+
});
|
|
173
539
|
}
|
|
174
540
|
// ===========================================================================
|
|
175
541
|
// Private: State Management
|
|
@@ -184,6 +550,23 @@ export class InputPrompt {
|
|
|
184
550
|
active: false,
|
|
185
551
|
matches: [],
|
|
186
552
|
selectedIndex: 0,
|
|
553
|
+
scrollOffset: 0,
|
|
554
|
+
};
|
|
555
|
+
this.fileAutocomplete = {
|
|
556
|
+
active: false,
|
|
557
|
+
matches: [],
|
|
558
|
+
selectedIndex: 0,
|
|
559
|
+
scrollOffset: 0,
|
|
560
|
+
partial: '',
|
|
561
|
+
};
|
|
562
|
+
this.agentAutocomplete = {
|
|
563
|
+
active: false,
|
|
564
|
+
matches: [],
|
|
565
|
+
selectedIndex: 0,
|
|
566
|
+
scrollOffset: 0,
|
|
567
|
+
partial: '',
|
|
568
|
+
startPos: 0,
|
|
569
|
+
lineIndex: 0,
|
|
187
570
|
};
|
|
188
571
|
this.historyIndex = -1;
|
|
189
572
|
this.savedInput = '';
|
|
@@ -194,229 +577,89 @@ export class InputPrompt {
|
|
|
194
577
|
}
|
|
195
578
|
updateAutocomplete() {
|
|
196
579
|
const fullInput = this.getValue();
|
|
580
|
+
const currentLine = this.state.lines[this.state.currentLine];
|
|
581
|
+
const cursorPos = this.state.cursorPos;
|
|
582
|
+
// Check for @ file path autocomplete first
|
|
583
|
+
const atMention = extractAtMention(currentLine, cursorPos);
|
|
584
|
+
if (atMention !== null) {
|
|
585
|
+
// File autocomplete mode
|
|
586
|
+
this.autocomplete.active = false;
|
|
587
|
+
this.autocomplete.matches = [];
|
|
588
|
+
this.autocomplete.selectedIndex = 0;
|
|
589
|
+
this.autocomplete.scrollOffset = 0;
|
|
590
|
+
this.agentAutocomplete.active = false;
|
|
591
|
+
this.agentAutocomplete.matches = [];
|
|
592
|
+
this.fileAutocomplete.active = true;
|
|
593
|
+
this.fileAutocomplete.partial = atMention;
|
|
594
|
+
this.fileAutocomplete.matches = getFileMatches(atMention);
|
|
595
|
+
if (this.fileAutocomplete.selectedIndex >= this.fileAutocomplete.matches.length) {
|
|
596
|
+
this.fileAutocomplete.selectedIndex = Math.max(0, this.fileAutocomplete.matches.length - 1);
|
|
597
|
+
this.fileAutocomplete.scrollOffset = 0;
|
|
598
|
+
}
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
// Reset file autocomplete
|
|
602
|
+
this.fileAutocomplete.active = false;
|
|
603
|
+
this.fileAutocomplete.matches = [];
|
|
604
|
+
this.fileAutocomplete.selectedIndex = 0;
|
|
605
|
+
this.fileAutocomplete.scrollOffset = 0;
|
|
606
|
+
this.fileAutocomplete.partial = '';
|
|
607
|
+
// Check for $ agent autocomplete (anywhere in the current line)
|
|
608
|
+
if (this.getAgentSuggestions) {
|
|
609
|
+
const currentLine = this.state.lines[this.state.currentLine];
|
|
610
|
+
const dollarMention = extractDollarMention(currentLine, this.state.cursorPos);
|
|
611
|
+
if (dollarMention !== null) {
|
|
612
|
+
const partial = dollarMention.partial.toLowerCase();
|
|
613
|
+
const allAgents = this.getAgentSuggestions();
|
|
614
|
+
// Filter agents by partial match
|
|
615
|
+
const matches = allAgents.filter(agent => agent.id.toLowerCase().startsWith(partial) ||
|
|
616
|
+
agent.displayName.toLowerCase().includes(partial));
|
|
617
|
+
if (matches.length > 0) {
|
|
618
|
+
this.agentAutocomplete.active = true;
|
|
619
|
+
this.agentAutocomplete.partial = partial;
|
|
620
|
+
this.agentAutocomplete.matches = matches;
|
|
621
|
+
this.agentAutocomplete.startPos = dollarMention.startPos;
|
|
622
|
+
this.agentAutocomplete.lineIndex = this.state.currentLine;
|
|
623
|
+
if (this.agentAutocomplete.selectedIndex >= matches.length) {
|
|
624
|
+
this.agentAutocomplete.selectedIndex = Math.max(0, matches.length - 1);
|
|
625
|
+
this.agentAutocomplete.scrollOffset = 0;
|
|
626
|
+
}
|
|
627
|
+
// Reset other autocompletes
|
|
628
|
+
this.autocomplete.active = false;
|
|
629
|
+
this.autocomplete.matches = [];
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
// Reset agent autocomplete
|
|
635
|
+
this.agentAutocomplete.active = false;
|
|
636
|
+
this.agentAutocomplete.matches = [];
|
|
637
|
+
this.agentAutocomplete.selectedIndex = 0;
|
|
638
|
+
this.agentAutocomplete.scrollOffset = 0;
|
|
639
|
+
this.agentAutocomplete.partial = '';
|
|
640
|
+
this.agentAutocomplete.startPos = 0;
|
|
641
|
+
this.agentAutocomplete.lineIndex = 0;
|
|
642
|
+
// Check for / command autocomplete
|
|
197
643
|
if (fullInput.startsWith('/') && this.state.lines.length === 1) {
|
|
198
644
|
this.autocomplete.active = true;
|
|
199
|
-
|
|
645
|
+
// Refresh commands dynamically to include newly created custom commands
|
|
646
|
+
const freshCommands = this.getCommands?.() ?? this.commands;
|
|
647
|
+
this.autocomplete.matches = filterCommands(fullInput, freshCommands);
|
|
200
648
|
if (this.autocomplete.selectedIndex >= this.autocomplete.matches.length) {
|
|
201
649
|
this.autocomplete.selectedIndex = Math.max(0, this.autocomplete.matches.length - 1);
|
|
650
|
+
this.autocomplete.scrollOffset = 0;
|
|
202
651
|
}
|
|
203
652
|
}
|
|
204
653
|
else {
|
|
205
654
|
this.autocomplete.active = false;
|
|
206
655
|
this.autocomplete.matches = [];
|
|
207
656
|
this.autocomplete.selectedIndex = 0;
|
|
657
|
+
this.autocomplete.scrollOffset = 0;
|
|
208
658
|
}
|
|
209
659
|
}
|
|
210
|
-
// ===========================================================================
|
|
211
|
-
// Private: Layout Calculation
|
|
212
|
-
// ===========================================================================
|
|
213
|
-
/**
|
|
214
|
-
* Get physical layout of current buffer
|
|
215
|
-
*/
|
|
216
|
-
getPhysicalLayout() {
|
|
217
|
-
const termWidth = terminal.getTerminalWidth();
|
|
218
|
-
const lines = [];
|
|
219
|
-
let cursorRow = 0;
|
|
220
|
-
let cursorCol = 0;
|
|
221
|
-
let totalRows = 0;
|
|
222
|
-
for (let i = 0; i < this.state.lines.length; i++) {
|
|
223
|
-
const linePromptLen = i === 0 ? this.promptLen : 5; // " \ "
|
|
224
|
-
const lineText = this.state.lines[i];
|
|
225
|
-
const physicalLines = calcPhysicalLines(lineText, linePromptLen, termWidth);
|
|
226
|
-
for (let p = 0; p < physicalLines; p++) {
|
|
227
|
-
const start = p * termWidth - (p === 0 ? 0 : linePromptLen);
|
|
228
|
-
const end = start + termWidth;
|
|
229
|
-
lines.push(lineText.slice(Math.max(0, start), end));
|
|
230
|
-
}
|
|
231
|
-
if (i === this.state.currentLine) {
|
|
232
|
-
const cursorAbsPos = linePromptLen + this.state.cursorPos;
|
|
233
|
-
cursorRow = totalRows + Math.floor(cursorAbsPos / termWidth);
|
|
234
|
-
cursorCol = cursorAbsPos % termWidth;
|
|
235
|
-
}
|
|
236
|
-
totalRows += physicalLines;
|
|
237
|
-
}
|
|
238
|
-
return { lines, cursorRow, cursorCol, totalRows };
|
|
239
|
-
}
|
|
240
|
-
// ===========================================================================
|
|
241
|
-
// Private: Rendering
|
|
242
|
-
// ===========================================================================
|
|
243
660
|
getSeparatorLine() {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
renderTodos() {
|
|
247
|
-
if (!this.getTodos)
|
|
248
|
-
return 0;
|
|
249
|
-
const todos = this.getTodos();
|
|
250
|
-
if (todos.length === 0)
|
|
251
|
-
return 0;
|
|
252
|
-
let linesRendered = 0;
|
|
253
|
-
// Group todos by status for display
|
|
254
|
-
const inProgress = todos.filter(t => t.status === 'in_progress');
|
|
255
|
-
const pending = todos.filter(t => t.status === 'pending');
|
|
256
|
-
const completed = todos.filter(t => t.status === 'completed');
|
|
257
|
-
// Show in-progress task prominently
|
|
258
|
-
for (const todo of inProgress) {
|
|
259
|
-
const label = todo.activeForm || todo.content;
|
|
260
|
-
terminal.write(pc.cyan('⟳ ') + pc.bold(label) + '\n');
|
|
261
|
-
linesRendered++;
|
|
262
|
-
}
|
|
263
|
-
// Show pending tasks
|
|
264
|
-
for (const todo of pending) {
|
|
265
|
-
terminal.write(pc.dim('○ ') + pc.dim(todo.content) + '\n');
|
|
266
|
-
linesRendered++;
|
|
267
|
-
}
|
|
268
|
-
// Show completed tasks (dimmed)
|
|
269
|
-
for (const todo of completed) {
|
|
270
|
-
terminal.write(pc.green('✓ ') + pc.dim(pc.strikethrough(todo.content)) + '\n');
|
|
271
|
-
linesRendered++;
|
|
272
|
-
}
|
|
273
|
-
if (linesRendered > 0) {
|
|
274
|
-
terminal.write('\n');
|
|
275
|
-
linesRendered++;
|
|
276
|
-
}
|
|
277
|
-
return linesRendered;
|
|
278
|
-
}
|
|
279
|
-
render() {
|
|
280
|
-
const termWidth = terminal.getTerminalWidth();
|
|
281
|
-
// Clear previous render
|
|
282
|
-
this.clearDropdown();
|
|
283
|
-
if (this.linesAboveCursor > 0) {
|
|
284
|
-
terminal.moveCursorToLineStart();
|
|
285
|
-
terminal.moveCursorUp(this.linesAboveCursor);
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
terminal.moveCursorToLineStart();
|
|
289
|
-
}
|
|
290
|
-
terminal.clearToEndOfScreen();
|
|
291
|
-
// Render todos (above input area)
|
|
292
|
-
let physicalLinesRendered = 0;
|
|
293
|
-
physicalLinesRendered += this.renderTodos();
|
|
294
|
-
// Render top separator
|
|
295
|
-
if (this.showSeparators) {
|
|
296
|
-
terminal.write(this.getSeparatorLine() + '\n');
|
|
297
|
-
physicalLinesRendered += 1;
|
|
298
|
-
}
|
|
299
|
-
// Render input lines
|
|
300
|
-
let physicalLinesBeforeCursor = 0;
|
|
301
|
-
for (let i = 0; i < this.state.lines.length; i++) {
|
|
302
|
-
const linePrompt = i === 0 ? this.prompt : pc.dim(' \\ ');
|
|
303
|
-
const linePromptLen = i === 0 ? this.promptLen : 5;
|
|
304
|
-
if (i < this.state.currentLine) {
|
|
305
|
-
physicalLinesBeforeCursor += calcPhysicalLines(this.state.lines[i], linePromptLen, termWidth);
|
|
306
|
-
}
|
|
307
|
-
terminal.write(linePrompt + this.state.lines[i]);
|
|
308
|
-
if (i < this.state.lines.length - 1) {
|
|
309
|
-
terminal.write('\n');
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
// Render bottom separator
|
|
313
|
-
if (this.showSeparators) {
|
|
314
|
-
terminal.write('\n' + this.getSeparatorLine());
|
|
315
|
-
}
|
|
316
|
-
// Track state
|
|
317
|
-
this.renderedLines = this.state.lines.length;
|
|
318
|
-
this.hasSeparators = this.showSeparators;
|
|
319
|
-
// Position cursor
|
|
320
|
-
const currentLinePromptLen = this.state.currentLine === 0 ? this.promptLen : 5;
|
|
321
|
-
const cursorAbsPos = currentLinePromptLen + this.state.cursorPos;
|
|
322
|
-
const currentLinePhysical = calcPhysicalLines(this.state.lines[this.state.currentLine], currentLinePromptLen, termWidth);
|
|
323
|
-
const cursorPhysicalRow = Math.floor(cursorAbsPos / termWidth);
|
|
324
|
-
// Move up from bottom to cursor position
|
|
325
|
-
let linesToMoveUp = this.showSeparators ? 1 : 0;
|
|
326
|
-
for (let i = this.state.currentLine + 1; i < this.state.lines.length; i++) {
|
|
327
|
-
const lp = i === 0 ? this.promptLen : 5;
|
|
328
|
-
linesToMoveUp += calcPhysicalLines(this.state.lines[i], lp, termWidth);
|
|
329
|
-
}
|
|
330
|
-
linesToMoveUp += currentLinePhysical - 1 - cursorPhysicalRow;
|
|
331
|
-
if (linesToMoveUp > 0) {
|
|
332
|
-
terminal.moveCursorUp(linesToMoveUp);
|
|
333
|
-
}
|
|
334
|
-
const cursorCol = (cursorAbsPos % termWidth) + 1;
|
|
335
|
-
terminal.moveCursorToColumn(cursorCol);
|
|
336
|
-
// Track cursor position for next render
|
|
337
|
-
this.linesAboveCursor = physicalLinesRendered + physicalLinesBeforeCursor + cursorPhysicalRow;
|
|
338
|
-
// Render dropdown
|
|
339
|
-
this.renderDropdown();
|
|
340
|
-
}
|
|
341
|
-
renderDropdown() {
|
|
342
|
-
if (!this.autocomplete.active || this.autocomplete.matches.length === 0) {
|
|
343
|
-
this.dropdownLines = 0;
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
const termWidth = terminal.getTerminalWidth();
|
|
347
|
-
const currentLinePromptLen = this.state.currentLine === 0 ? this.promptLen : 5;
|
|
348
|
-
// Move down past remaining input lines and bottom separator
|
|
349
|
-
let linesToMoveDown = this.state.lines.length - 1 - this.state.currentLine;
|
|
350
|
-
if (this.hasSeparators)
|
|
351
|
-
linesToMoveDown += 1;
|
|
352
|
-
// Account for wrapped lines
|
|
353
|
-
for (let i = this.state.currentLine; i < this.state.lines.length; i++) {
|
|
354
|
-
const lp = i === 0 ? this.promptLen : 5;
|
|
355
|
-
const physical = calcPhysicalLines(this.state.lines[i], lp, termWidth);
|
|
356
|
-
if (i === this.state.currentLine) {
|
|
357
|
-
const cursorAbsPos = currentLinePromptLen + this.state.cursorPos;
|
|
358
|
-
const cursorRow = Math.floor(cursorAbsPos / termWidth);
|
|
359
|
-
linesToMoveDown += physical - 1 - cursorRow;
|
|
360
|
-
}
|
|
361
|
-
else {
|
|
362
|
-
linesToMoveDown += physical - 1;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
if (linesToMoveDown > 0) {
|
|
366
|
-
terminal.moveCursorDown(linesToMoveDown);
|
|
367
|
-
}
|
|
368
|
-
terminal.write('\n');
|
|
369
|
-
const visible = this.autocomplete.matches.slice(0, MAX_VISIBLE_COMMANDS);
|
|
370
|
-
for (let i = 0; i < visible.length; i++) {
|
|
371
|
-
const cmd = visible[i];
|
|
372
|
-
const isSelected = i === this.autocomplete.selectedIndex;
|
|
373
|
-
const prefix = isSelected ? pc.cyan('❯ ') : ' ';
|
|
374
|
-
const name = isSelected ? pc.cyan(pc.bold(cmd.command)) : cmd.command;
|
|
375
|
-
const desc = pc.dim(` - ${cmd.description}`);
|
|
376
|
-
terminal.write(`${prefix}${name}${desc}\n`);
|
|
377
|
-
}
|
|
378
|
-
// Move back up to cursor position
|
|
379
|
-
this.dropdownLines = visible.length;
|
|
380
|
-
const linesToMoveUp = this.dropdownLines + linesToMoveDown + 1;
|
|
381
|
-
terminal.moveCursorUp(linesToMoveUp);
|
|
382
|
-
const cursorAbsPos = currentLinePromptLen + this.state.cursorPos;
|
|
383
|
-
const cursorCol = (cursorAbsPos % termWidth) + 1;
|
|
384
|
-
terminal.moveCursorToColumn(cursorCol);
|
|
385
|
-
}
|
|
386
|
-
clearDropdown() {
|
|
387
|
-
if (this.dropdownLines === 0)
|
|
388
|
-
return;
|
|
389
|
-
const termWidth = terminal.getTerminalWidth();
|
|
390
|
-
const currentLinePromptLen = this.state.currentLine === 0 ? this.promptLen : 5;
|
|
391
|
-
// Move down past remaining lines and separator
|
|
392
|
-
let linesToMoveDown = this.state.lines.length - 1 - this.state.currentLine;
|
|
393
|
-
if (this.hasSeparators)
|
|
394
|
-
linesToMoveDown += 1;
|
|
395
|
-
for (let i = this.state.currentLine; i < this.state.lines.length; i++) {
|
|
396
|
-
const lp = i === 0 ? this.promptLen : 5;
|
|
397
|
-
const physical = calcPhysicalLines(this.state.lines[i], lp, termWidth);
|
|
398
|
-
if (i === this.state.currentLine) {
|
|
399
|
-
const cursorAbsPos = currentLinePromptLen + this.state.cursorPos;
|
|
400
|
-
const cursorRow = Math.floor(cursorAbsPos / termWidth);
|
|
401
|
-
linesToMoveDown += physical - 1 - cursorRow;
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
linesToMoveDown += physical - 1;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
if (linesToMoveDown > 0) {
|
|
408
|
-
terminal.moveCursorDown(linesToMoveDown);
|
|
409
|
-
}
|
|
410
|
-
terminal.write('\n');
|
|
411
|
-
// Clear dropdown lines
|
|
412
|
-
for (let i = 0; i < this.dropdownLines; i++) {
|
|
413
|
-
terminal.clearLine();
|
|
414
|
-
terminal.write('\n');
|
|
415
|
-
}
|
|
416
|
-
// Move back up
|
|
417
|
-
const linesToMoveUp = this.dropdownLines + linesToMoveDown + 1;
|
|
418
|
-
terminal.moveCursorUp(linesToMoveUp);
|
|
419
|
-
this.dropdownLines = 0;
|
|
661
|
+
const s = getStyles();
|
|
662
|
+
return s.muted('─'.repeat(terminal.getTerminalWidth()));
|
|
420
663
|
}
|
|
421
664
|
// ===========================================================================
|
|
422
665
|
// Private: Input Handling
|
|
@@ -433,7 +676,10 @@ export class InputPrompt {
|
|
|
433
676
|
const isEnter = key === '\r' || key === '\n';
|
|
434
677
|
const isBackspace = key === '\x7f' || key === '\b';
|
|
435
678
|
const isTab = key === '\t';
|
|
679
|
+
const isShiftTab = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x5a;
|
|
436
680
|
const isCtrlC = key === '\x03';
|
|
681
|
+
const isCtrlO = key === '\x0f'; // Ctrl+O for toggle subagent expand
|
|
682
|
+
const isCtrlB = key === '\x02'; // Ctrl+B for background tasks
|
|
437
683
|
const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
|
|
438
684
|
const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
|
|
439
685
|
const isLeftArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x44;
|
|
@@ -460,16 +706,50 @@ export class InputPrompt {
|
|
|
460
706
|
const isEnd = key === '\x05' || (data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x46);
|
|
461
707
|
// Ctrl+C - cancel
|
|
462
708
|
if (isCtrlC) {
|
|
463
|
-
this.
|
|
709
|
+
this.emit('cancel');
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
// Ctrl+O - toggle subagent expand (only when agent is running)
|
|
713
|
+
if (isCtrlO) {
|
|
714
|
+
this.emit('toggleSubagentExpand');
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
// Ctrl+B - show background tasks overlay
|
|
718
|
+
if (isCtrlB) {
|
|
719
|
+
this.emit('showTasks');
|
|
464
720
|
return;
|
|
465
721
|
}
|
|
466
|
-
// Escape - close autocomplete
|
|
722
|
+
// Escape - close autocomplete, double Esc clears input, or emit escape for agent abort
|
|
467
723
|
if (isEscape) {
|
|
468
|
-
|
|
469
|
-
|
|
724
|
+
const now = Date.now();
|
|
725
|
+
const isDoubleEsc = now - this.lastEscTime < this.DOUBLE_ESC_THRESHOLD_MS;
|
|
726
|
+
this.lastEscTime = now;
|
|
727
|
+
if (this.agentAutocomplete.active) {
|
|
728
|
+
// First priority: close agent autocomplete
|
|
729
|
+
this.agentAutocomplete.active = false;
|
|
730
|
+
this.agentAutocomplete.matches = [];
|
|
731
|
+
this.emit('change', this.getValue());
|
|
732
|
+
}
|
|
733
|
+
else if (this.fileAutocomplete.active) {
|
|
734
|
+
// Second priority: close file autocomplete
|
|
735
|
+
this.fileAutocomplete.active = false;
|
|
736
|
+
this.fileAutocomplete.matches = [];
|
|
737
|
+
this.emit('change', this.getValue());
|
|
738
|
+
}
|
|
739
|
+
else if (this.autocomplete.active) {
|
|
740
|
+
// Third priority: close command autocomplete
|
|
470
741
|
this.autocomplete.active = false;
|
|
471
742
|
this.autocomplete.matches = [];
|
|
472
|
-
this.
|
|
743
|
+
this.emit('change', this.getValue());
|
|
744
|
+
}
|
|
745
|
+
else if (isDoubleEsc && this.getValue().length > 0) {
|
|
746
|
+
// Fourth priority: double Esc clears input (if there's content)
|
|
747
|
+
this.clearInput();
|
|
748
|
+
this.emit('change', this.getValue());
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
// Fifth priority: emit escape for agent abort
|
|
752
|
+
this.emit('escape');
|
|
473
753
|
}
|
|
474
754
|
return;
|
|
475
755
|
}
|
|
@@ -478,6 +758,11 @@ export class InputPrompt {
|
|
|
478
758
|
this.handleEnter();
|
|
479
759
|
return;
|
|
480
760
|
}
|
|
761
|
+
// Shift+Tab - cycle modes
|
|
762
|
+
if (isShiftTab) {
|
|
763
|
+
this.emit('modeChange');
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
481
766
|
// Tab - accept autocomplete or insert spaces
|
|
482
767
|
if (isTab) {
|
|
483
768
|
this.handleTab();
|
|
@@ -512,12 +797,12 @@ export class InputPrompt {
|
|
|
512
797
|
// Home/End
|
|
513
798
|
if (isHome) {
|
|
514
799
|
this.state.cursorPos = 0;
|
|
515
|
-
this.
|
|
800
|
+
this.emit('change', this.getValue());
|
|
516
801
|
return;
|
|
517
802
|
}
|
|
518
803
|
if (isEnd) {
|
|
519
804
|
this.state.cursorPos = this.state.lines[this.state.currentLine].length;
|
|
520
|
-
this.
|
|
805
|
+
this.emit('change', this.getValue());
|
|
521
806
|
return;
|
|
522
807
|
}
|
|
523
808
|
// Backspace
|
|
@@ -532,13 +817,17 @@ export class InputPrompt {
|
|
|
532
817
|
.filter((c) => c.charCodeAt(0) >= 32)
|
|
533
818
|
.join('');
|
|
534
819
|
if (printable.length > 0) {
|
|
820
|
+
// Clear suggestion when user starts typing
|
|
821
|
+
if (this.suggestion) {
|
|
822
|
+
this.suggestion = null;
|
|
823
|
+
}
|
|
535
824
|
const line = this.state.lines[this.state.currentLine];
|
|
536
825
|
this.state.lines[this.state.currentLine] =
|
|
537
826
|
line.slice(0, this.state.cursorPos) + printable + line.slice(this.state.cursorPos);
|
|
538
827
|
this.state.cursorPos += printable.length;
|
|
539
828
|
this.historyIndex = -1;
|
|
540
829
|
this.updateAutocomplete();
|
|
541
|
-
this.
|
|
830
|
+
this.emit('change', this.getValue());
|
|
542
831
|
}
|
|
543
832
|
}
|
|
544
833
|
}
|
|
@@ -551,35 +840,114 @@ export class InputPrompt {
|
|
|
551
840
|
this.state.currentLine++;
|
|
552
841
|
this.state.cursorPos = 0;
|
|
553
842
|
this.autocomplete.active = false;
|
|
554
|
-
this.
|
|
555
|
-
|
|
843
|
+
this.emit('change', this.getValue());
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
// Agent autocomplete selection - replace with $agentId and add space
|
|
847
|
+
if (this.agentAutocomplete.active && this.agentAutocomplete.matches.length > 0) {
|
|
848
|
+
const selectedAgent = this.agentAutocomplete.matches[this.agentAutocomplete.selectedIndex];
|
|
849
|
+
const lineIdx = this.agentAutocomplete.lineIndex;
|
|
850
|
+
const line = this.state.lines[lineIdx];
|
|
851
|
+
const result = replaceDollarMention(line, this.state.cursorPos, selectedAgent.id);
|
|
852
|
+
this.state.lines[lineIdx] = result.input;
|
|
853
|
+
this.state.currentLine = lineIdx;
|
|
854
|
+
this.state.cursorPos = result.cursorPos;
|
|
855
|
+
this.agentAutocomplete.active = false;
|
|
856
|
+
this.agentAutocomplete.matches = [];
|
|
857
|
+
this.emit('change', this.getValue());
|
|
858
|
+
// Return - let user type message after selecting agent
|
|
556
859
|
return;
|
|
557
860
|
}
|
|
558
|
-
//
|
|
861
|
+
// File autocomplete selection - accept the path and continue
|
|
862
|
+
if (this.fileAutocomplete.active && this.fileAutocomplete.matches.length > 0) {
|
|
863
|
+
const selectedFile = this.fileAutocomplete.matches[this.fileAutocomplete.selectedIndex];
|
|
864
|
+
const result = replaceAtMention(currentLine, this.state.cursorPos, selectedFile.path);
|
|
865
|
+
this.state.lines[this.state.currentLine] = result.input;
|
|
866
|
+
this.state.cursorPos = result.cursorPos;
|
|
867
|
+
this.fileAutocomplete.active = false;
|
|
868
|
+
this.fileAutocomplete.matches = [];
|
|
869
|
+
// Don't return - fall through to submit
|
|
870
|
+
}
|
|
871
|
+
// Command autocomplete selection - accept the command and continue to execute it
|
|
559
872
|
if (this.autocomplete.active && this.autocomplete.matches.length > 0) {
|
|
560
873
|
this.state.lines[0] = this.autocomplete.matches[this.autocomplete.selectedIndex].command;
|
|
561
874
|
this.state.cursorPos = this.state.lines[0].length;
|
|
875
|
+
this.autocomplete.active = false;
|
|
876
|
+
// Don't return - fall through to execute the command
|
|
562
877
|
}
|
|
563
878
|
const input = this.getValue();
|
|
879
|
+
// Empty input - ignore
|
|
880
|
+
if (!input.trim()) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
// Add to history
|
|
884
|
+
this.addToHistory(input);
|
|
885
|
+
// Queue mode - add to queue instead of emitting
|
|
886
|
+
if (this.queueMode) {
|
|
887
|
+
this.queuedInputs.push(input);
|
|
888
|
+
this.clearInput();
|
|
889
|
+
this.emit('change', this.getValue());
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
564
892
|
// Check if it's a command
|
|
565
893
|
if (input.startsWith('/')) {
|
|
566
894
|
const parts = input.slice(1).split(/\s+/);
|
|
567
895
|
const command = parts[0];
|
|
568
896
|
const args = parts.slice(1).join(' ');
|
|
569
|
-
this.
|
|
897
|
+
this.clearInput();
|
|
898
|
+
this.emit('command', command, args);
|
|
570
899
|
}
|
|
571
900
|
else {
|
|
572
|
-
|
|
901
|
+
// Strip @ prefix from file paths (autocomplete uses @ but agent doesn't need it)
|
|
902
|
+
// Matches @word or @path/to/file patterns
|
|
903
|
+
const cleanedInput = input.replace(/(?<![@\w])@([\w./-]+)/g, '$1');
|
|
904
|
+
this.clearInput();
|
|
905
|
+
this.emit('submit', cleanedInput);
|
|
573
906
|
}
|
|
574
907
|
}
|
|
575
908
|
handleTab() {
|
|
909
|
+
// Accept suggestion if present and input is empty
|
|
910
|
+
if (this.suggestion && this.getValue() === '') {
|
|
911
|
+
this.state.lines[0] = this.suggestion;
|
|
912
|
+
this.state.cursorPos = this.suggestion.length;
|
|
913
|
+
this.suggestion = null;
|
|
914
|
+
this.emit('change', this.getValue());
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
// Agent autocomplete completion - replace with $agentId and add space
|
|
918
|
+
if (this.agentAutocomplete.active && this.agentAutocomplete.matches.length > 0) {
|
|
919
|
+
const selectedAgent = this.agentAutocomplete.matches[this.agentAutocomplete.selectedIndex];
|
|
920
|
+
const lineIdx = this.agentAutocomplete.lineIndex;
|
|
921
|
+
const line = this.state.lines[lineIdx];
|
|
922
|
+
const result = replaceDollarMention(line, this.state.cursorPos, selectedAgent.id);
|
|
923
|
+
this.state.lines[lineIdx] = result.input;
|
|
924
|
+
this.state.currentLine = lineIdx;
|
|
925
|
+
this.state.cursorPos = result.cursorPos;
|
|
926
|
+
this.agentAutocomplete.active = false;
|
|
927
|
+
this.agentAutocomplete.matches = [];
|
|
928
|
+
this.emit('change', this.getValue());
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
// File autocomplete completion
|
|
932
|
+
if (this.fileAutocomplete.active && this.fileAutocomplete.matches.length > 0) {
|
|
933
|
+
const selectedFile = this.fileAutocomplete.matches[this.fileAutocomplete.selectedIndex];
|
|
934
|
+
const currentLine = this.state.lines[this.state.currentLine];
|
|
935
|
+
const result = replaceAtMention(currentLine, this.state.cursorPos, selectedFile.path);
|
|
936
|
+
this.state.lines[this.state.currentLine] = result.input;
|
|
937
|
+
this.state.cursorPos = result.cursorPos;
|
|
938
|
+
this.fileAutocomplete.active = false;
|
|
939
|
+
this.fileAutocomplete.matches = [];
|
|
940
|
+
this.updateAutocomplete(); // Check if still in @ context (e.g., directory selected)
|
|
941
|
+
this.emit('change', this.getValue());
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
// Command autocomplete completion
|
|
576
945
|
if (this.autocomplete.active && this.autocomplete.matches.length > 0) {
|
|
577
946
|
this.state.lines[this.state.currentLine] =
|
|
578
947
|
this.autocomplete.matches[this.autocomplete.selectedIndex].command;
|
|
579
948
|
this.state.cursorPos = this.state.lines[this.state.currentLine].length;
|
|
580
949
|
this.autocomplete.active = false;
|
|
581
950
|
this.autocomplete.matches = [];
|
|
582
|
-
this.clearDropdown();
|
|
583
951
|
}
|
|
584
952
|
else {
|
|
585
953
|
// Insert 2 spaces
|
|
@@ -590,13 +958,37 @@ export class InputPrompt {
|
|
|
590
958
|
this.historyIndex = -1;
|
|
591
959
|
this.updateAutocomplete();
|
|
592
960
|
}
|
|
593
|
-
this.
|
|
961
|
+
this.emit('change', this.getValue());
|
|
594
962
|
}
|
|
595
963
|
handleArrowUp() {
|
|
596
|
-
//
|
|
964
|
+
// Agent autocomplete navigation
|
|
965
|
+
if (this.agentAutocomplete.active && this.agentAutocomplete.selectedIndex > 0) {
|
|
966
|
+
this.agentAutocomplete.selectedIndex--;
|
|
967
|
+
// Adjust scroll offset if selection goes above visible area
|
|
968
|
+
if (this.agentAutocomplete.selectedIndex < this.agentAutocomplete.scrollOffset) {
|
|
969
|
+
this.agentAutocomplete.scrollOffset = this.agentAutocomplete.selectedIndex;
|
|
970
|
+
}
|
|
971
|
+
this.emit('change', this.getValue());
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
// File autocomplete navigation
|
|
975
|
+
if (this.fileAutocomplete.active && this.fileAutocomplete.selectedIndex > 0) {
|
|
976
|
+
this.fileAutocomplete.selectedIndex--;
|
|
977
|
+
// Adjust scroll offset if selection goes above visible area
|
|
978
|
+
if (this.fileAutocomplete.selectedIndex < this.fileAutocomplete.scrollOffset) {
|
|
979
|
+
this.fileAutocomplete.scrollOffset = this.fileAutocomplete.selectedIndex;
|
|
980
|
+
}
|
|
981
|
+
this.emit('change', this.getValue());
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
// Command autocomplete navigation
|
|
597
985
|
if (this.autocomplete.active && this.autocomplete.selectedIndex > 0) {
|
|
598
986
|
this.autocomplete.selectedIndex--;
|
|
599
|
-
|
|
987
|
+
// Adjust scroll offset if selection goes above visible area
|
|
988
|
+
if (this.autocomplete.selectedIndex < this.autocomplete.scrollOffset) {
|
|
989
|
+
this.autocomplete.scrollOffset = this.autocomplete.selectedIndex;
|
|
990
|
+
}
|
|
991
|
+
this.emit('change', this.getValue());
|
|
600
992
|
return;
|
|
601
993
|
}
|
|
602
994
|
const termWidth = terminal.getTerminalWidth();
|
|
@@ -609,7 +1001,7 @@ export class InputPrompt {
|
|
|
609
1001
|
const newAbsPos = (currentPhysicalRow - 1) * termWidth + cursorColInRow;
|
|
610
1002
|
this.state.cursorPos = Math.max(0, newAbsPos - currentLinePromptLen);
|
|
611
1003
|
this.state.cursorPos = Math.min(this.state.cursorPos, this.state.lines[this.state.currentLine].length);
|
|
612
|
-
this.
|
|
1004
|
+
this.emit('change', this.getValue());
|
|
613
1005
|
return;
|
|
614
1006
|
}
|
|
615
1007
|
// Navigate to previous logical line
|
|
@@ -622,7 +1014,7 @@ export class InputPrompt {
|
|
|
622
1014
|
const targetAbsPos = lastRowStart + cursorColInRow;
|
|
623
1015
|
this.state.cursorPos = Math.max(0, targetAbsPos - prevLinePromptLen);
|
|
624
1016
|
this.state.cursorPos = Math.min(this.state.cursorPos, prevLineLen);
|
|
625
|
-
this.
|
|
1017
|
+
this.emit('change', this.getValue());
|
|
626
1018
|
return;
|
|
627
1019
|
}
|
|
628
1020
|
// History navigation (at top of input)
|
|
@@ -636,17 +1028,45 @@ export class InputPrompt {
|
|
|
636
1028
|
this.state.lines = [historyEntry];
|
|
637
1029
|
this.state.currentLine = 0;
|
|
638
1030
|
this.state.cursorPos = historyEntry.length;
|
|
639
|
-
this.
|
|
1031
|
+
this.emit('change', this.getValue());
|
|
640
1032
|
}
|
|
641
1033
|
}
|
|
642
1034
|
}
|
|
643
1035
|
handleArrowDown() {
|
|
644
|
-
//
|
|
1036
|
+
// Agent autocomplete navigation
|
|
1037
|
+
if (this.agentAutocomplete.active &&
|
|
1038
|
+
this.agentAutocomplete.selectedIndex < this.agentAutocomplete.matches.length - 1) {
|
|
1039
|
+
this.agentAutocomplete.selectedIndex++;
|
|
1040
|
+
// Adjust scroll offset if selection goes below visible area
|
|
1041
|
+
const maxVisibleIndex = this.agentAutocomplete.scrollOffset + MAX_VISIBLE_COMMANDS - 1;
|
|
1042
|
+
if (this.agentAutocomplete.selectedIndex > maxVisibleIndex) {
|
|
1043
|
+
this.agentAutocomplete.scrollOffset = this.agentAutocomplete.selectedIndex - MAX_VISIBLE_COMMANDS + 1;
|
|
1044
|
+
}
|
|
1045
|
+
this.emit('change', this.getValue());
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
// File autocomplete navigation
|
|
1049
|
+
if (this.fileAutocomplete.active &&
|
|
1050
|
+
this.fileAutocomplete.selectedIndex < this.fileAutocomplete.matches.length - 1) {
|
|
1051
|
+
this.fileAutocomplete.selectedIndex++;
|
|
1052
|
+
// Adjust scroll offset if selection goes below visible area
|
|
1053
|
+
const maxVisibleIndex = this.fileAutocomplete.scrollOffset + MAX_VISIBLE_COMMANDS - 1;
|
|
1054
|
+
if (this.fileAutocomplete.selectedIndex > maxVisibleIndex) {
|
|
1055
|
+
this.fileAutocomplete.scrollOffset = this.fileAutocomplete.selectedIndex - MAX_VISIBLE_COMMANDS + 1;
|
|
1056
|
+
}
|
|
1057
|
+
this.emit('change', this.getValue());
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
// Command autocomplete navigation
|
|
645
1061
|
if (this.autocomplete.active &&
|
|
646
|
-
this.autocomplete.selectedIndex < this.autocomplete.matches.length - 1
|
|
647
|
-
this.autocomplete.selectedIndex < MAX_VISIBLE_COMMANDS - 1) {
|
|
1062
|
+
this.autocomplete.selectedIndex < this.autocomplete.matches.length - 1) {
|
|
648
1063
|
this.autocomplete.selectedIndex++;
|
|
649
|
-
|
|
1064
|
+
// Adjust scroll offset if selection goes below visible area
|
|
1065
|
+
const maxVisibleIndex = this.autocomplete.scrollOffset + MAX_VISIBLE_COMMANDS - 1;
|
|
1066
|
+
if (this.autocomplete.selectedIndex > maxVisibleIndex) {
|
|
1067
|
+
this.autocomplete.scrollOffset = this.autocomplete.selectedIndex - MAX_VISIBLE_COMMANDS + 1;
|
|
1068
|
+
}
|
|
1069
|
+
this.emit('change', this.getValue());
|
|
650
1070
|
return;
|
|
651
1071
|
}
|
|
652
1072
|
const termWidth = terminal.getTerminalWidth();
|
|
@@ -660,7 +1080,7 @@ export class InputPrompt {
|
|
|
660
1080
|
const newAbsPos = (currentPhysicalRow + 1) * termWidth + cursorColInRow;
|
|
661
1081
|
this.state.cursorPos = Math.max(0, newAbsPos - currentLinePromptLen);
|
|
662
1082
|
this.state.cursorPos = Math.min(this.state.cursorPos, this.state.lines[this.state.currentLine].length);
|
|
663
|
-
this.
|
|
1083
|
+
this.emit('change', this.getValue());
|
|
664
1084
|
return;
|
|
665
1085
|
}
|
|
666
1086
|
// Navigate to next logical line
|
|
@@ -670,7 +1090,7 @@ export class InputPrompt {
|
|
|
670
1090
|
const nextLineLen = this.state.lines[this.state.currentLine].length;
|
|
671
1091
|
this.state.cursorPos = Math.max(0, cursorColInRow - nextLinePromptLen);
|
|
672
1092
|
this.state.cursorPos = Math.min(this.state.cursorPos, nextLineLen);
|
|
673
|
-
this.
|
|
1093
|
+
this.emit('change', this.getValue());
|
|
674
1094
|
return;
|
|
675
1095
|
}
|
|
676
1096
|
// History forward
|
|
@@ -688,29 +1108,29 @@ export class InputPrompt {
|
|
|
688
1108
|
this.state.cursorPos = historyEntry.length;
|
|
689
1109
|
}
|
|
690
1110
|
this.updateAutocomplete();
|
|
691
|
-
this.
|
|
1111
|
+
this.emit('change', this.getValue());
|
|
692
1112
|
}
|
|
693
1113
|
}
|
|
694
1114
|
handleArrowLeft() {
|
|
695
1115
|
if (this.state.cursorPos > 0) {
|
|
696
1116
|
this.state.cursorPos--;
|
|
697
|
-
|
|
1117
|
+
this.emit('change', this.getValue());
|
|
698
1118
|
}
|
|
699
1119
|
else if (this.state.currentLine > 0) {
|
|
700
1120
|
this.state.currentLine--;
|
|
701
1121
|
this.state.cursorPos = this.state.lines[this.state.currentLine].length;
|
|
702
|
-
this.
|
|
1122
|
+
this.emit('change', this.getValue());
|
|
703
1123
|
}
|
|
704
1124
|
}
|
|
705
1125
|
handleArrowRight() {
|
|
706
1126
|
if (this.state.cursorPos < this.state.lines[this.state.currentLine].length) {
|
|
707
1127
|
this.state.cursorPos++;
|
|
708
|
-
|
|
1128
|
+
this.emit('change', this.getValue());
|
|
709
1129
|
}
|
|
710
1130
|
else if (this.state.currentLine < this.state.lines.length - 1) {
|
|
711
1131
|
this.state.currentLine++;
|
|
712
1132
|
this.state.cursorPos = 0;
|
|
713
|
-
this.
|
|
1133
|
+
this.emit('change', this.getValue());
|
|
714
1134
|
}
|
|
715
1135
|
}
|
|
716
1136
|
handleWordLeft() {
|
|
@@ -722,12 +1142,12 @@ export class InputPrompt {
|
|
|
722
1142
|
while (pos > 0 && line[pos - 1] !== ' ')
|
|
723
1143
|
pos--;
|
|
724
1144
|
this.state.cursorPos = pos;
|
|
725
|
-
this.
|
|
1145
|
+
this.emit('change', this.getValue());
|
|
726
1146
|
}
|
|
727
1147
|
else if (this.state.currentLine > 0) {
|
|
728
1148
|
this.state.currentLine--;
|
|
729
1149
|
this.state.cursorPos = this.state.lines[this.state.currentLine].length;
|
|
730
|
-
this.
|
|
1150
|
+
this.emit('change', this.getValue());
|
|
731
1151
|
}
|
|
732
1152
|
}
|
|
733
1153
|
handleWordRight() {
|
|
@@ -739,12 +1159,12 @@ export class InputPrompt {
|
|
|
739
1159
|
while (pos < line.length && line[pos] === ' ')
|
|
740
1160
|
pos++;
|
|
741
1161
|
this.state.cursorPos = pos;
|
|
742
|
-
this.
|
|
1162
|
+
this.emit('change', this.getValue());
|
|
743
1163
|
}
|
|
744
1164
|
else if (this.state.currentLine < this.state.lines.length - 1) {
|
|
745
1165
|
this.state.currentLine++;
|
|
746
1166
|
this.state.cursorPos = 0;
|
|
747
|
-
this.
|
|
1167
|
+
this.emit('change', this.getValue());
|
|
748
1168
|
}
|
|
749
1169
|
}
|
|
750
1170
|
handleBackspace() {
|
|
@@ -755,7 +1175,7 @@ export class InputPrompt {
|
|
|
755
1175
|
line.slice(0, this.state.cursorPos - 1) + line.slice(this.state.cursorPos);
|
|
756
1176
|
this.state.cursorPos--;
|
|
757
1177
|
this.updateAutocomplete();
|
|
758
|
-
this.
|
|
1178
|
+
this.emit('change', this.getValue());
|
|
759
1179
|
}
|
|
760
1180
|
else if (this.state.currentLine > 0) {
|
|
761
1181
|
const currentLine = this.state.lines[this.state.currentLine];
|
|
@@ -765,36 +1185,7 @@ export class InputPrompt {
|
|
|
765
1185
|
this.state.currentLine--;
|
|
766
1186
|
this.state.cursorPos = prevLine.length;
|
|
767
1187
|
this.updateAutocomplete();
|
|
768
|
-
this.
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
finishInput(result) {
|
|
772
|
-
// Clear display
|
|
773
|
-
this.clearDropdown();
|
|
774
|
-
if (this.linesAboveCursor > 0) {
|
|
775
|
-
terminal.moveCursorToLineStart();
|
|
776
|
-
terminal.moveCursorUp(this.linesAboveCursor);
|
|
777
|
-
}
|
|
778
|
-
terminal.clearToEndOfScreen();
|
|
779
|
-
// Print clean input (without separators)
|
|
780
|
-
for (let i = 0; i < this.state.lines.length; i++) {
|
|
781
|
-
const linePrompt = i === 0 ? this.prompt : pc.dim(' \\ ');
|
|
782
|
-
terminal.write(linePrompt + this.state.lines[i]);
|
|
783
|
-
if (i < this.state.lines.length - 1) {
|
|
784
|
-
terminal.write('\n');
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
terminal.writeLine('');
|
|
788
|
-
// Save to history if submitting
|
|
789
|
-
if (result.action === 'submit' || result.action === 'command') {
|
|
790
|
-
const input = this.getValue();
|
|
791
|
-
this.addToHistory(input);
|
|
792
|
-
}
|
|
793
|
-
// Stop and resolve
|
|
794
|
-
this.stop();
|
|
795
|
-
if (this.resolveInput) {
|
|
796
|
-
this.resolveInput(result);
|
|
797
|
-
this.resolveInput = null;
|
|
1188
|
+
this.emit('change', this.getValue());
|
|
798
1189
|
}
|
|
799
1190
|
}
|
|
800
1191
|
}
|