@amplitude/wizard 1.0.0-beta.0
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/LICENSE +47 -0
- package/README.md +119 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +763 -0
- package/dist/package.json +144 -0
- package/dist/src/frameworks/android/android-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/android/android-wizard-agent.js +72 -0
- package/dist/src/frameworks/android/utils.d.ts +11 -0
- package/dist/src/frameworks/android/utils.js +32 -0
- package/dist/src/frameworks/django/django-wizard-agent.d.ts +8 -0
- package/dist/src/frameworks/django/django-wizard-agent.js +171 -0
- package/dist/src/frameworks/django/utils.d.ts +31 -0
- package/dist/src/frameworks/django/utils.js +305 -0
- package/dist/src/frameworks/fastapi/fastapi-wizard-agent.d.ts +11 -0
- package/dist/src/frameworks/fastapi/fastapi-wizard-agent.js +189 -0
- package/dist/src/frameworks/fastapi/utils.d.ts +26 -0
- package/dist/src/frameworks/fastapi/utils.js +257 -0
- package/dist/src/frameworks/flask/flask-wizard-agent.d.ts +8 -0
- package/dist/src/frameworks/flask/flask-wizard-agent.js +177 -0
- package/dist/src/frameworks/flask/utils.d.ts +28 -0
- package/dist/src/frameworks/flask/utils.js +343 -0
- package/dist/src/frameworks/flutter/flutter-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/flutter/flutter-wizard-agent.js +57 -0
- package/dist/src/frameworks/flutter/utils.d.ts +7 -0
- package/dist/src/frameworks/flutter/utils.js +64 -0
- package/dist/src/frameworks/generic/generic-wizard-agent.d.ts +2 -0
- package/dist/src/frameworks/generic/generic-wizard-agent.js +176 -0
- package/dist/src/frameworks/go/go-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/go/go-wizard-agent.js +57 -0
- package/dist/src/frameworks/go/utils.d.ts +5 -0
- package/dist/src/frameworks/go/utils.js +44 -0
- package/dist/src/frameworks/java/java-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/java/java-wizard-agent.js +73 -0
- package/dist/src/frameworks/java/utils.d.ts +15 -0
- package/dist/src/frameworks/java/utils.js +64 -0
- package/dist/src/frameworks/javascript-node/javascript-node-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/javascript-node/javascript-node-wizard-agent.js +57 -0
- package/dist/src/frameworks/javascript-web/javascript-web-wizard-agent.d.ts +3 -0
- package/dist/src/frameworks/javascript-web/javascript-web-wizard-agent.js +151 -0
- package/dist/src/frameworks/javascript-web/utils.d.ts +28 -0
- package/dist/src/frameworks/javascript-web/utils.js +153 -0
- package/dist/src/frameworks/nextjs/nextjs-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/nextjs/nextjs-wizard-agent.js +98 -0
- package/dist/src/frameworks/nextjs/utils.d.ts +12 -0
- package/dist/src/frameworks/nextjs/utils.js +51 -0
- package/dist/src/frameworks/python/python-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/python/python-wizard-agent.js +193 -0
- package/dist/src/frameworks/python/utils.d.ts +28 -0
- package/dist/src/frameworks/python/utils.js +146 -0
- package/dist/src/frameworks/react-native/react-native-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/react-native/react-native-wizard-agent.js +84 -0
- package/dist/src/frameworks/react-native/utils.d.ts +21 -0
- package/dist/src/frameworks/react-native/utils.js +82 -0
- package/dist/src/frameworks/react-router/react-router-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/react-router/react-router-wizard-agent.js +98 -0
- package/dist/src/frameworks/react-router/utils.d.ts +13 -0
- package/dist/src/frameworks/react-router/utils.js +160 -0
- package/dist/src/frameworks/swift/swift-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/swift/swift-wizard-agent.js +72 -0
- package/dist/src/frameworks/swift/utils.d.ts +12 -0
- package/dist/src/frameworks/swift/utils.js +82 -0
- package/dist/src/frameworks/unity/unity-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/unity/unity-wizard-agent.js +79 -0
- package/dist/src/frameworks/unity/utils.d.ts +12 -0
- package/dist/src/frameworks/unity/utils.js +66 -0
- package/dist/src/frameworks/unreal/unreal-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/unreal/unreal-wizard-agent.js +77 -0
- package/dist/src/frameworks/unreal/utils.d.ts +10 -0
- package/dist/src/frameworks/unreal/utils.js +29 -0
- package/dist/src/frameworks/vue/vue-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/vue/vue-wizard-agent.js +64 -0
- package/dist/src/lib/agent-hooks.d.ts +26 -0
- package/dist/src/lib/agent-hooks.js +118 -0
- package/dist/src/lib/agent-interface.d.ts +175 -0
- package/dist/src/lib/agent-interface.js +1217 -0
- package/dist/src/lib/agent-runner.d.ts +9 -0
- package/dist/src/lib/agent-runner.js +415 -0
- package/dist/src/lib/ampli-config.d.ts +105 -0
- package/dist/src/lib/ampli-config.js +178 -0
- package/dist/src/lib/api.d.ts +107 -0
- package/dist/src/lib/api.js +442 -0
- package/dist/src/lib/commandments.d.ts +1 -0
- package/dist/src/lib/commandments.js +24 -0
- package/dist/src/lib/console-query.d.ts +27 -0
- package/dist/src/lib/console-query.js +121 -0
- package/dist/src/lib/constants.d.ts +124 -0
- package/dist/src/lib/constants.js +170 -0
- package/dist/src/lib/detect-amplitude.d.ts +31 -0
- package/dist/src/lib/detect-amplitude.js +407 -0
- package/dist/src/lib/framework-config.d.ts +188 -0
- package/dist/src/lib/framework-config.js +21 -0
- package/dist/src/lib/health-checks/endpoints.d.ts +3 -0
- package/dist/src/lib/health-checks/endpoints.js +45 -0
- package/dist/src/lib/health-checks/index.d.ts +4 -0
- package/dist/src/lib/health-checks/index.js +22 -0
- package/dist/src/lib/health-checks/readiness.d.ts +24 -0
- package/dist/src/lib/health-checks/readiness.js +118 -0
- package/dist/src/lib/health-checks/statuspage.d.ts +9 -0
- package/dist/src/lib/health-checks/statuspage.js +104 -0
- package/dist/src/lib/health-checks/types.d.ts +31 -0
- package/dist/src/lib/health-checks/types.js +9 -0
- package/dist/src/lib/helper-functions.d.ts +1 -0
- package/dist/src/lib/helper-functions.js +5 -0
- package/dist/src/lib/middleware/benchmark.d.ts +54 -0
- package/dist/src/lib/middleware/benchmark.js +48 -0
- package/dist/src/lib/middleware/benchmarks/cache-tracker.d.ts +44 -0
- package/dist/src/lib/middleware/benchmarks/cache-tracker.js +80 -0
- package/dist/src/lib/middleware/benchmarks/compaction-tracker.d.ts +29 -0
- package/dist/src/lib/middleware/benchmarks/compaction-tracker.js +59 -0
- package/dist/src/lib/middleware/benchmarks/context-size-tracker.d.ts +26 -0
- package/dist/src/lib/middleware/benchmarks/context-size-tracker.js +55 -0
- package/dist/src/lib/middleware/benchmarks/cost-tracker.d.ts +16 -0
- package/dist/src/lib/middleware/benchmarks/cost-tracker.js +75 -0
- package/dist/src/lib/middleware/benchmarks/duration-tracker.d.ts +20 -0
- package/dist/src/lib/middleware/benchmarks/duration-tracker.js +39 -0
- package/dist/src/lib/middleware/benchmarks/index.d.ts +9 -0
- package/dist/src/lib/middleware/benchmarks/index.js +67 -0
- package/dist/src/lib/middleware/benchmarks/json-writer.d.ts +15 -0
- package/dist/src/lib/middleware/benchmarks/json-writer.js +144 -0
- package/dist/src/lib/middleware/benchmarks/summary.d.ts +9 -0
- package/dist/src/lib/middleware/benchmarks/summary.js +105 -0
- package/dist/src/lib/middleware/benchmarks/token-tracker.d.ts +40 -0
- package/dist/src/lib/middleware/benchmarks/token-tracker.js +76 -0
- package/dist/src/lib/middleware/benchmarks/turn-counter.d.ts +34 -0
- package/dist/src/lib/middleware/benchmarks/turn-counter.js +58 -0
- package/dist/src/lib/middleware/config.d.ts +24 -0
- package/dist/src/lib/middleware/config.js +96 -0
- package/dist/src/lib/middleware/index.d.ts +11 -0
- package/dist/src/lib/middleware/index.js +17 -0
- package/dist/src/lib/middleware/phase-detector.d.ts +8 -0
- package/dist/src/lib/middleware/phase-detector.js +63 -0
- package/dist/src/lib/middleware/pipeline.d.ts +29 -0
- package/dist/src/lib/middleware/pipeline.js +81 -0
- package/dist/src/lib/middleware/schemas.d.ts +27 -0
- package/dist/src/lib/middleware/schemas.js +84 -0
- package/dist/src/lib/middleware/types.d.ts +94 -0
- package/dist/src/lib/middleware/types.js +8 -0
- package/dist/src/lib/package-manager-detection.d.ts +42 -0
- package/dist/src/lib/package-manager-detection.js +292 -0
- package/dist/src/lib/registry.d.ts +3 -0
- package/dist/src/lib/registry.js +42 -0
- package/dist/src/lib/safe-tools.d.ts +2 -0
- package/dist/src/lib/safe-tools.js +214 -0
- package/dist/src/lib/wizard-session.d.ts +220 -0
- package/dist/src/lib/wizard-session.js +127 -0
- package/dist/src/lib/wizard-tools.d.ts +82 -0
- package/dist/src/lib/wizard-tools.js +499 -0
- package/dist/src/run.d.ts +19 -0
- package/dist/src/run.js +151 -0
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.d.ts +30 -0
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js +141 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.d.ts +29 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.js +180 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +20 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +63 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/codex.d.ts +28 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/codex.js +77 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.d.ts +24 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +60 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.d.ts +27 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.js +101 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/zed.d.ts +26 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/zed.js +102 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.d.ts +44 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js +123 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.d.ts +19 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.js +110 -0
- package/dist/src/steps/add-or-update-environment-variables.d.ts +10 -0
- package/dist/src/steps/add-or-update-environment-variables.js +188 -0
- package/dist/src/steps/index.d.ts +4 -0
- package/dist/src/steps/index.js +20 -0
- package/dist/src/steps/run-prettier.d.ts +5 -0
- package/dist/src/steps/run-prettier.js +90 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.d.ts +11 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.js +11 -0
- package/dist/src/steps/upload-environment-variables/index.d.ts +6 -0
- package/dist/src/steps/upload-environment-variables/index.js +37 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.d.ts +15 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.js +145 -0
- package/dist/src/telemetry.d.ts +2 -0
- package/dist/src/telemetry.js +12 -0
- package/dist/src/ui/index.d.ts +8 -0
- package/dist/src/ui/index.js +16 -0
- package/dist/src/ui/logging-ui.d.ts +56 -0
- package/dist/src/ui/logging-ui.js +157 -0
- package/dist/src/ui/tui/App.d.ts +6 -0
- package/dist/src/ui/tui/App.js +34 -0
- package/dist/src/ui/tui/components/AmplitudeLogo.d.ts +5 -0
- package/dist/src/ui/tui/components/AmplitudeLogo.js +81 -0
- package/dist/src/ui/tui/components/AmplitudeTextLogo.d.ts +3 -0
- package/dist/src/ui/tui/components/AmplitudeTextLogo.js +31 -0
- package/dist/src/ui/tui/components/ConsoleView.d.ts +23 -0
- package/dist/src/ui/tui/components/ConsoleView.js +220 -0
- package/dist/src/ui/tui/components/TitleBar.d.ts +6 -0
- package/dist/src/ui/tui/components/TitleBar.js +16 -0
- package/dist/src/ui/tui/console-commands.d.ts +16 -0
- package/dist/src/ui/tui/console-commands.js +31 -0
- package/dist/src/ui/tui/context/CommandModeContext.d.ts +2 -0
- package/dist/src/ui/tui/context/CommandModeContext.js +3 -0
- package/dist/src/ui/tui/flows.d.ts +48 -0
- package/dist/src/ui/tui/flows.js +154 -0
- package/dist/src/ui/tui/hooks/useScreenInput.d.ts +13 -0
- package/dist/src/ui/tui/hooks/useScreenInput.js +18 -0
- package/dist/src/ui/tui/hooks/useStdoutDimensions.d.ts +9 -0
- package/dist/src/ui/tui/hooks/useStdoutDimensions.js +29 -0
- package/dist/src/ui/tui/ink-ui.d.ts +62 -0
- package/dist/src/ui/tui/ink-ui.js +142 -0
- package/dist/src/ui/tui/primitives/CardLayout.d.ts +12 -0
- package/dist/src/ui/tui/primitives/CardLayout.js +9 -0
- package/dist/src/ui/tui/primitives/ConfirmationInput.d.ts +13 -0
- package/dist/src/ui/tui/primitives/ConfirmationInput.js +35 -0
- package/dist/src/ui/tui/primitives/DissolveTransition.d.ts +21 -0
- package/dist/src/ui/tui/primitives/DissolveTransition.js +143 -0
- package/dist/src/ui/tui/primitives/EventPlanViewer.d.ts +9 -0
- package/dist/src/ui/tui/primitives/EventPlanViewer.js +9 -0
- package/dist/src/ui/tui/primitives/KagiSmallWebViewer.d.ts +7 -0
- package/dist/src/ui/tui/primitives/KagiSmallWebViewer.js +101 -0
- package/dist/src/ui/tui/primitives/LoadingBox.d.ts +8 -0
- package/dist/src/ui/tui/primitives/LoadingBox.js +9 -0
- package/dist/src/ui/tui/primitives/LogViewer.d.ts +11 -0
- package/dist/src/ui/tui/primitives/LogViewer.js +55 -0
- package/dist/src/ui/tui/primitives/PickerMenu.d.ts +20 -0
- package/dist/src/ui/tui/primitives/PickerMenu.js +212 -0
- package/dist/src/ui/tui/primitives/ProgressList.d.ts +15 -0
- package/dist/src/ui/tui/primitives/ProgressList.js +29 -0
- package/dist/src/ui/tui/primitives/PromptLabel.d.ts +11 -0
- package/dist/src/ui/tui/primitives/PromptLabel.js +12 -0
- package/dist/src/ui/tui/primitives/ReportViewer.d.ts +12 -0
- package/dist/src/ui/tui/primitives/ReportViewer.js +99 -0
- package/dist/src/ui/tui/primitives/ScreenErrorBoundary.d.ts +26 -0
- package/dist/src/ui/tui/primitives/ScreenErrorBoundary.js +29 -0
- package/dist/src/ui/tui/primitives/SlashCommandInput.d.ts +21 -0
- package/dist/src/ui/tui/primitives/SlashCommandInput.js +85 -0
- package/dist/src/ui/tui/primitives/SnakeGame.d.ts +1 -0
- package/dist/src/ui/tui/primitives/SnakeGame.js +1 -0
- package/dist/src/ui/tui/primitives/SplitView.d.ts +11 -0
- package/dist/src/ui/tui/primitives/SplitView.js +8 -0
- package/dist/src/ui/tui/primitives/TabContainer.d.ts +18 -0
- package/dist/src/ui/tui/primitives/TabContainer.js +30 -0
- package/dist/src/ui/tui/primitives/index.d.ts +23 -0
- package/dist/src/ui/tui/primitives/index.js +19 -0
- package/dist/src/ui/tui/router.d.ts +61 -0
- package/dist/src/ui/tui/router.js +104 -0
- package/dist/src/ui/tui/screen-registry.d.ts +19 -0
- package/dist/src/ui/tui/screen-registry.js +56 -0
- package/dist/src/ui/tui/screens/ActivationOptionsScreen.d.ts +12 -0
- package/dist/src/ui/tui/screens/ActivationOptionsScreen.js +57 -0
- package/dist/src/ui/tui/screens/AuthScreen.d.ts +18 -0
- package/dist/src/ui/tui/screens/AuthScreen.js +107 -0
- package/dist/src/ui/tui/screens/ChecklistScreen.d.ts +22 -0
- package/dist/src/ui/tui/screens/ChecklistScreen.js +122 -0
- package/dist/src/ui/tui/screens/DataIngestionCheckScreen.d.ts +24 -0
- package/dist/src/ui/tui/screens/DataIngestionCheckScreen.js +113 -0
- package/dist/src/ui/tui/screens/DataSetupScreen.d.ts +17 -0
- package/dist/src/ui/tui/screens/DataSetupScreen.js +73 -0
- package/dist/src/ui/tui/screens/IntroScreen.d.ts +16 -0
- package/dist/src/ui/tui/screens/IntroScreen.js +86 -0
- package/dist/src/ui/tui/screens/LoginScreen.d.ts +15 -0
- package/dist/src/ui/tui/screens/LoginScreen.js +65 -0
- package/dist/src/ui/tui/screens/LogoutScreen.d.ts +12 -0
- package/dist/src/ui/tui/screens/LogoutScreen.js +28 -0
- package/dist/src/ui/tui/screens/McpScreen.d.ts +26 -0
- package/dist/src/ui/tui/screens/McpScreen.js +148 -0
- package/dist/src/ui/tui/screens/OutageScreen.d.ts +10 -0
- package/dist/src/ui/tui/screens/OutageScreen.js +17 -0
- package/dist/src/ui/tui/screens/OutroScreen.d.ts +11 -0
- package/dist/src/ui/tui/screens/OutroScreen.js +69 -0
- package/dist/src/ui/tui/screens/RegionSelectScreen.d.ts +17 -0
- package/dist/src/ui/tui/screens/RegionSelectScreen.js +40 -0
- package/dist/src/ui/tui/screens/RunScreen.d.ts +16 -0
- package/dist/src/ui/tui/screens/RunScreen.js +212 -0
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +10 -0
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +23 -0
- package/dist/src/ui/tui/screens/SetupScreen.d.ts +13 -0
- package/dist/src/ui/tui/screens/SetupScreen.js +73 -0
- package/dist/src/ui/tui/screens/SlackScreen.d.ts +25 -0
- package/dist/src/ui/tui/screens/SlackScreen.js +97 -0
- package/dist/src/ui/tui/services/mcp-installer.d.ts +25 -0
- package/dist/src/ui/tui/services/mcp-installer.js +82 -0
- package/dist/src/ui/tui/start-tui.d.ts +10 -0
- package/dist/src/ui/tui/start-tui.js +50 -0
- package/dist/src/ui/tui/store.d.ts +231 -0
- package/dist/src/ui/tui/store.js +568 -0
- package/dist/src/ui/tui/styles.d.ts +31 -0
- package/dist/src/ui/tui/styles.js +33 -0
- package/dist/src/ui/wizard-ui.d.ts +110 -0
- package/dist/src/ui/wizard-ui.js +18 -0
- package/dist/src/utils/ampli-settings.d.ts +37 -0
- package/dist/src/utils/ampli-settings.js +182 -0
- package/dist/src/utils/analytics.d.ts +35 -0
- package/dist/src/utils/analytics.js +133 -0
- package/dist/src/utils/anthropic-status.d.ts +17 -0
- package/dist/src/utils/anthropic-status.js +51 -0
- package/dist/src/utils/api-key-store.d.ts +35 -0
- package/dist/src/utils/api-key-store.js +176 -0
- package/dist/src/utils/bash.d.ts +2 -0
- package/dist/src/utils/bash.js +53 -0
- package/dist/src/utils/custom-headers.d.ts +9 -0
- package/dist/src/utils/custom-headers.js +23 -0
- package/dist/src/utils/debug.d.ts +23 -0
- package/dist/src/utils/debug.js +86 -0
- package/dist/src/utils/environment.d.ts +4 -0
- package/dist/src/utils/environment.js +76 -0
- package/dist/src/utils/file-utils.d.ts +2 -0
- package/dist/src/utils/file-utils.js +16 -0
- package/dist/src/utils/get-api-key.d.ts +17 -0
- package/dist/src/utils/get-api-key.js +50 -0
- package/dist/src/utils/logging.d.ts +9 -0
- package/dist/src/utils/logging.js +48 -0
- package/dist/src/utils/oauth.d.ts +53 -0
- package/dist/src/utils/oauth.js +354 -0
- package/dist/src/utils/package-json.d.ts +25 -0
- package/dist/src/utils/package-json.js +26 -0
- package/dist/src/utils/package-manager.d.ts +21 -0
- package/dist/src/utils/package-manager.js +208 -0
- package/dist/src/utils/semver.d.ts +21 -0
- package/dist/src/utils/semver.js +61 -0
- package/dist/src/utils/setup-utils.d.ts +82 -0
- package/dist/src/utils/setup-utils.js +467 -0
- package/dist/src/utils/shell-completions.d.ts +10 -0
- package/dist/src/utils/shell-completions.js +199 -0
- package/dist/src/utils/string.d.ts +1 -0
- package/dist/src/utils/string.js +8 -0
- package/dist/src/utils/types.d.ts +72 -0
- package/dist/src/utils/types.js +2 -0
- package/dist/src/utils/urls.d.ts +14 -0
- package/dist/src/utils/urls.js +69 -0
- package/dist/src/utils/vendor/is-unicorn-supported.d.ts +1 -0
- package/dist/src/utils/vendor/is-unicorn-supported.js +23 -0
- package/dist/src/utils/wizard-abort.d.ts +13 -0
- package/dist/src/utils/wizard-abort.js +56 -0
- package/man/amplitude-wizard.1 +170 -0
- package/package.json +144 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* DissolveTransition — Column-sweep inspired by TTE's Sweep effect.
|
|
4
|
+
*
|
|
5
|
+
* Uses a SequenceEaser (in_out_circ) to activate columns with eased pacing.
|
|
6
|
+
* Each activated column cycles through shade characters (░▒▓█) independently.
|
|
7
|
+
*
|
|
8
|
+
* Out phase: columns sweep, building up shade chars until solid █ (covers old content).
|
|
9
|
+
* In phase: columns sweep in reverse, dissolving █ back through shades to empty (reveals new content).
|
|
10
|
+
*/
|
|
11
|
+
import { Box, Text } from 'ink';
|
|
12
|
+
import { useState, useEffect, useRef } from 'react';
|
|
13
|
+
/** Shade characters in build-up order (light → solid). */
|
|
14
|
+
const SHADES = ['░', '▒', '▓', '█'];
|
|
15
|
+
/** How many ticks each shade character displays before advancing. */
|
|
16
|
+
const TICKS_PER_SHADE = 2;
|
|
17
|
+
/** Total ticks a column needs to complete its shade cycle. */
|
|
18
|
+
const SHADE_CYCLE_TICKS = SHADES.length * TICKS_PER_SHADE;
|
|
19
|
+
function easeInOutCirc(t) {
|
|
20
|
+
if (t < 0.5) {
|
|
21
|
+
return (1 - Math.sqrt(1 - 4 * t * t)) / 2;
|
|
22
|
+
}
|
|
23
|
+
return (Math.sqrt(1 - (2 * t - 2) ** 2) + 1) / 2;
|
|
24
|
+
}
|
|
25
|
+
var TransitionPhase;
|
|
26
|
+
(function (TransitionPhase) {
|
|
27
|
+
TransitionPhase["Idle"] = "idle";
|
|
28
|
+
TransitionPhase["Out"] = "out";
|
|
29
|
+
TransitionPhase["In"] = "in";
|
|
30
|
+
})(TransitionPhase || (TransitionPhase = {}));
|
|
31
|
+
export const DissolveTransition = ({ transitionKey, width, height, children, direction = 'left', duration = 2, }) => {
|
|
32
|
+
const [phase, setPhase] = useState(TransitionPhase.Idle);
|
|
33
|
+
const [tick, setTick] = useState(0);
|
|
34
|
+
const [activeDir, setActiveDir] = useState(direction);
|
|
35
|
+
const prevKey = useRef(transitionKey);
|
|
36
|
+
const pendingChildren = useRef(children);
|
|
37
|
+
const [displayChildren, setDisplayChildren] = useState(children);
|
|
38
|
+
// Track when each column was activated (tick number), -1 means not yet.
|
|
39
|
+
const columnActivationTick = useRef([]);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (transitionKey !== prevKey.current) {
|
|
42
|
+
prevKey.current = transitionKey;
|
|
43
|
+
pendingChildren.current = children;
|
|
44
|
+
setActiveDir(direction);
|
|
45
|
+
setPhase(TransitionPhase.Out);
|
|
46
|
+
setTick(0);
|
|
47
|
+
columnActivationTick.current = new Array(width).fill(-1);
|
|
48
|
+
}
|
|
49
|
+
else if (phase === TransitionPhase.Idle) {
|
|
50
|
+
setDisplayChildren(children);
|
|
51
|
+
}
|
|
52
|
+
}, [transitionKey, children, width, height, phase, direction]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (phase === TransitionPhase.Idle)
|
|
55
|
+
return;
|
|
56
|
+
const timer = setInterval(() => {
|
|
57
|
+
setTick((prev) => prev + 1);
|
|
58
|
+
}, duration);
|
|
59
|
+
return () => clearInterval(timer);
|
|
60
|
+
}, [phase, duration]);
|
|
61
|
+
// Easer steps = width: roughly one column activates per tick.
|
|
62
|
+
// This keeps the sweep front tight (only a few columns in-flight at once).
|
|
63
|
+
const easerSteps = width;
|
|
64
|
+
// A phase ends when the easer has completed AND all columns have finished their shade cycle.
|
|
65
|
+
const maxTicks = easerSteps + SHADE_CYCLE_TICKS;
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (phase === TransitionPhase.Idle)
|
|
68
|
+
return;
|
|
69
|
+
if (tick >= maxTicks) {
|
|
70
|
+
if (phase === TransitionPhase.Out) {
|
|
71
|
+
setDisplayChildren(pendingChildren.current);
|
|
72
|
+
setPhase(TransitionPhase.In);
|
|
73
|
+
setTick(0);
|
|
74
|
+
columnActivationTick.current = new Array(width).fill(-1);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
setPhase(TransitionPhase.Idle);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}, [tick, phase, maxTicks, width]);
|
|
81
|
+
if (phase === TransitionPhase.Idle) {
|
|
82
|
+
return _jsx(_Fragment, { children: displayChildren });
|
|
83
|
+
}
|
|
84
|
+
// --- SequenceEaser logic ---
|
|
85
|
+
// Map current tick to easer progress (0..1), apply easing,
|
|
86
|
+
// then determine how many columns should be activated.
|
|
87
|
+
const easerProgress = Math.min(tick / easerSteps, 1);
|
|
88
|
+
const easedValue = easeInOutCirc(easerProgress);
|
|
89
|
+
const activatedCount = Math.floor(easedValue * width);
|
|
90
|
+
// Build column order based on direction.
|
|
91
|
+
// "left" means sweep moves left-to-right; "right" means right-to-left.
|
|
92
|
+
// TTE's COLUMN_RIGHT_TO_LEFT activates rightmost first.
|
|
93
|
+
const columnOrder = [];
|
|
94
|
+
if (activeDir === 'left') {
|
|
95
|
+
for (let c = width - 1; c >= 0; c--)
|
|
96
|
+
columnOrder.push(c);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
for (let c = 0; c < width; c++)
|
|
100
|
+
columnOrder.push(c);
|
|
101
|
+
}
|
|
102
|
+
// Activate columns that should be active but aren't yet.
|
|
103
|
+
for (let i = 0; i < activatedCount && i < columnOrder.length; i++) {
|
|
104
|
+
const col = columnOrder[i];
|
|
105
|
+
if (columnActivationTick.current[col] === -1) {
|
|
106
|
+
columnActivationTick.current[col] = tick;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// --- Render frame ---
|
|
110
|
+
const rows = [];
|
|
111
|
+
for (let r = 0; r < height; r++) {
|
|
112
|
+
let row = '';
|
|
113
|
+
for (let c = 0; c < width; c++) {
|
|
114
|
+
const activatedAt = columnActivationTick.current[c];
|
|
115
|
+
let char;
|
|
116
|
+
if (activatedAt === -1) {
|
|
117
|
+
// Not yet activated
|
|
118
|
+
char = phase === TransitionPhase.Out ? ' ' : '█';
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Column is activated — determine shade based on ticks since activation
|
|
122
|
+
const age = tick - activatedAt;
|
|
123
|
+
const shadeIndex = Math.min(Math.floor(age / TICKS_PER_SHADE), SHADES.length - 1);
|
|
124
|
+
if (phase === TransitionPhase.Out) {
|
|
125
|
+
// Building up: ░ → ▒ → ▓ → █
|
|
126
|
+
char = SHADES[shadeIndex];
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Dissolving: █ → ▓ → ▒ → ░ → space
|
|
130
|
+
if (shadeIndex >= SHADES.length - 1 && age >= SHADE_CYCLE_TICKS) {
|
|
131
|
+
char = ' ';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
char = SHADES[SHADES.length - 1 - shadeIndex];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
row += char;
|
|
139
|
+
}
|
|
140
|
+
rows.push(row);
|
|
141
|
+
}
|
|
142
|
+
return (_jsx(Box, { flexDirection: "column", flexGrow: 1, children: rows.map((row, i) => (_jsx(Text, { dimColor: true, children: row }, i))) }));
|
|
143
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventPlanViewer — Renders a table of planned analytics events.
|
|
3
|
+
*/
|
|
4
|
+
import type { PlannedEvent } from '../store.js';
|
|
5
|
+
interface EventPlanViewerProps {
|
|
6
|
+
events: PlannedEvent[];
|
|
7
|
+
}
|
|
8
|
+
export declare const EventPlanViewer: ({ events }: EventPlanViewerProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* EventPlanViewer — Renders a table of planned analytics events.
|
|
4
|
+
*/
|
|
5
|
+
import { Box, Text } from 'ink';
|
|
6
|
+
import { Colors } from '../styles.js';
|
|
7
|
+
export const EventPlanViewer = ({ events }) => {
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, children: "Event plan" }), _jsx(Box, { height: 1 }), events.map((event) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: event.name }), _jsxs(Text, { color: Colors.muted, children: [" ", event.description] })] }, event.name)))] }));
|
|
9
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KagiSmallWebViewer — Recent posts from the Kagi Small Web feed.
|
|
3
|
+
*
|
|
4
|
+
* Fetches from the Kagi Atom feed on mount.
|
|
5
|
+
* Each post has a [1]–[0] numeral; typing it opens the post in the browser.
|
|
6
|
+
*/
|
|
7
|
+
export declare const KagiSmallWebViewer: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* KagiSmallWebViewer — Recent posts from the Kagi Small Web feed.
|
|
4
|
+
*
|
|
5
|
+
* Fetches from the Kagi Atom feed on mount.
|
|
6
|
+
* Each post has a [1]–[0] numeral; typing it opens the post in the browser.
|
|
7
|
+
*/
|
|
8
|
+
import { Box, Text } from 'ink';
|
|
9
|
+
import { useState, useEffect } from 'react';
|
|
10
|
+
import { xml2js } from 'xml-js';
|
|
11
|
+
import { useScreenInput } from '../hooks/useScreenInput.js';
|
|
12
|
+
import { Colors } from '../styles.js';
|
|
13
|
+
const FEED_URL = 'https://kagi.com/api/v1/smallweb/feed/?limit=100';
|
|
14
|
+
function parseAtom(xml) {
|
|
15
|
+
const root = xml2js(xml, { compact: true });
|
|
16
|
+
const feed = root['feed'];
|
|
17
|
+
if (!feed)
|
|
18
|
+
return [];
|
|
19
|
+
const rawEntries = feed['entry'];
|
|
20
|
+
const entries = Array.isArray(rawEntries)
|
|
21
|
+
? rawEntries
|
|
22
|
+
: rawEntries
|
|
23
|
+
? [rawEntries]
|
|
24
|
+
: [];
|
|
25
|
+
return entries.map((e) => {
|
|
26
|
+
const text = (node) => {
|
|
27
|
+
if (!node)
|
|
28
|
+
return '';
|
|
29
|
+
const n = node;
|
|
30
|
+
return n['_text'] ?? '';
|
|
31
|
+
};
|
|
32
|
+
const attr = (node, key) => {
|
|
33
|
+
if (!node)
|
|
34
|
+
return '';
|
|
35
|
+
const n = node;
|
|
36
|
+
const attrs = n['_attributes'];
|
|
37
|
+
return attrs?.[key] ?? '';
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
title: text(e['title']),
|
|
41
|
+
url: attr(e['link'], 'href'),
|
|
42
|
+
author: text(e['author']?.['name']),
|
|
43
|
+
published: text(e['published']),
|
|
44
|
+
summary: text(e['summary']),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export const KagiSmallWebViewer = () => {
|
|
49
|
+
const [entries, setEntries] = useState([]);
|
|
50
|
+
const [loading, setLoading] = useState(true);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
void (async () => {
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch(FEED_URL);
|
|
55
|
+
const xml = await res.text();
|
|
56
|
+
const all = parseAtom(xml);
|
|
57
|
+
const shuffled = all.sort(() => Math.random() - 0.5).slice(0, 10);
|
|
58
|
+
setEntries(shuffled);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Silently fail — tab stays empty
|
|
62
|
+
}
|
|
63
|
+
setLoading(false);
|
|
64
|
+
})();
|
|
65
|
+
}, []);
|
|
66
|
+
useScreenInput((input) => {
|
|
67
|
+
const num = parseInt(input, 10);
|
|
68
|
+
if (isNaN(num))
|
|
69
|
+
return;
|
|
70
|
+
const index = num === 0 ? 9 : num - 1;
|
|
71
|
+
const entry = entries[index];
|
|
72
|
+
if (!entry)
|
|
73
|
+
return;
|
|
74
|
+
void import('child_process').then(({ exec }) => {
|
|
75
|
+
exec(`open "${entry.url}" 2>/dev/null || xdg-open "${entry.url}" 2>/dev/null`);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
if (loading) {
|
|
79
|
+
return (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: Colors.muted, children: "Loading Kagi Small Web..." }) }));
|
|
80
|
+
}
|
|
81
|
+
if (entries.length === 0) {
|
|
82
|
+
return (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: Colors.muted, children: "Could not load Kagi Small Web." }) }));
|
|
83
|
+
}
|
|
84
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, color: Colors.accent, children: "Kagi Small Web" }), _jsx(Box, { height: 1 }), entries.map((entry, i) => {
|
|
85
|
+
const key = i === 9 ? '0' : String(i + 1);
|
|
86
|
+
const date = new Date(entry.published);
|
|
87
|
+
const dateStr = date.toLocaleDateString('en-US', {
|
|
88
|
+
month: 'short',
|
|
89
|
+
day: 'numeric',
|
|
90
|
+
});
|
|
91
|
+
const host = (() => {
|
|
92
|
+
try {
|
|
93
|
+
return new URL(entry.url).hostname;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return '';
|
|
97
|
+
}
|
|
98
|
+
})();
|
|
99
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: Colors.accent, bold: true, children: ["[", key, "]"] }), _jsxs(Text, { bold: true, children: [" ", entry.title] })] }), _jsx(Box, { marginLeft: 4, children: _jsxs(Text, { color: Colors.muted, children: [entry.author || host, dateStr ? `, ${dateStr}` : ''] }) })] }, entry.url));
|
|
100
|
+
})] }));
|
|
101
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* LoadingBox — Spinner with message.
|
|
4
|
+
*/
|
|
5
|
+
import { Box, Text } from 'ink';
|
|
6
|
+
import { Spinner } from '@inkjs/ui';
|
|
7
|
+
export const LoadingBox = ({ message }) => {
|
|
8
|
+
return (_jsxs(Box, { gap: 1, children: [_jsx(Spinner, {}), _jsx(Text, { children: message })] }));
|
|
9
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogViewer — Real-time log tail, pinned to available terminal height.
|
|
3
|
+
* Only renders the last N lines that fit on screen.
|
|
4
|
+
*/
|
|
5
|
+
interface LogViewerProps {
|
|
6
|
+
filePath: string;
|
|
7
|
+
/** Fixed visible height. Defaults to terminal rows minus chrome. */
|
|
8
|
+
height?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const LogViewer: ({ filePath, height }: LogViewerProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* LogViewer — Real-time log tail, pinned to available terminal height.
|
|
4
|
+
* Only renders the last N lines that fit on screen.
|
|
5
|
+
*/
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
import { Colors } from '../styles.js';
|
|
8
|
+
import { useState, useEffect } from 'react';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import { useStdoutDimensions } from '../hooks/useStdoutDimensions.js';
|
|
11
|
+
/** Rows consumed by ConsoleView border + TitleBar + spacer + separator + input + tab bar chrome */
|
|
12
|
+
const CHROME_ROWS = 8;
|
|
13
|
+
export const LogViewer = ({ filePath, height }) => {
|
|
14
|
+
const [, rows] = useStdoutDimensions();
|
|
15
|
+
const visibleLines = height ?? Math.max(5, rows - CHROME_ROWS);
|
|
16
|
+
const [lines, setLines] = useState([]);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const readTail = () => {
|
|
19
|
+
try {
|
|
20
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
21
|
+
const allLines = content.split('\n');
|
|
22
|
+
setLines(allLines.slice(-visibleLines));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
setLines(['(No log file found)']);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
readTail();
|
|
29
|
+
let watcher;
|
|
30
|
+
try {
|
|
31
|
+
watcher = fs.watch(filePath, () => {
|
|
32
|
+
readTail();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// File might not exist yet — retry when it appears
|
|
37
|
+
const interval = setInterval(() => {
|
|
38
|
+
try {
|
|
39
|
+
fs.accessSync(filePath);
|
|
40
|
+
readTail();
|
|
41
|
+
clearInterval(interval);
|
|
42
|
+
watcher = fs.watch(filePath, () => readTail());
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Still waiting
|
|
46
|
+
}
|
|
47
|
+
}, 1000);
|
|
48
|
+
return () => clearInterval(interval);
|
|
49
|
+
}
|
|
50
|
+
return () => {
|
|
51
|
+
watcher?.close();
|
|
52
|
+
};
|
|
53
|
+
}, [filePath, visibleLines]);
|
|
54
|
+
return (_jsx(Box, { flexDirection: "column", height: visibleLines, children: lines.map((line, i) => (_jsx(Text, { color: Colors.muted, wrap: "truncate", children: line }, i))) }));
|
|
55
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PickerMenu — Single and multi select.
|
|
3
|
+
* Single mode: custom renderer with small triangle indicator.
|
|
4
|
+
* Multi mode: checkbox glyphs with space to toggle.
|
|
5
|
+
*/
|
|
6
|
+
interface PickerOption<T> {
|
|
7
|
+
label: string;
|
|
8
|
+
value: T;
|
|
9
|
+
hint?: string;
|
|
10
|
+
}
|
|
11
|
+
interface PickerMenuProps<T> {
|
|
12
|
+
message?: string;
|
|
13
|
+
options: PickerOption<T>[];
|
|
14
|
+
mode?: 'single' | 'multi';
|
|
15
|
+
centered?: boolean;
|
|
16
|
+
columns?: 1 | 2 | 3 | 4;
|
|
17
|
+
onSelect: (value: T | T[]) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const PickerMenu: <T>({ message, options, mode, centered, columns, onSelect, }: PickerMenuProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* PickerMenu — Single and multi select.
|
|
4
|
+
* Single mode: custom renderer with small triangle indicator.
|
|
5
|
+
* Multi mode: checkbox glyphs with space to toggle.
|
|
6
|
+
*/
|
|
7
|
+
import { Box, Text } from 'ink';
|
|
8
|
+
import { useState, useRef } from 'react';
|
|
9
|
+
import { Icons, Colors } from '../styles.js';
|
|
10
|
+
import { PromptLabel } from './PromptLabel.js';
|
|
11
|
+
import { useScreenInput } from '../hooks/useScreenInput.js';
|
|
12
|
+
import { useStdoutDimensions } from '../hooks/useStdoutDimensions.js';
|
|
13
|
+
const PICKER_CHROME_ROWS = 16;
|
|
14
|
+
export const PickerMenu = ({ message, options, mode = 'single', centered = false, columns = 1, onSelect, }) => {
|
|
15
|
+
if (mode === 'multi') {
|
|
16
|
+
return (_jsx(MultiPickerMenu, { message: message, options: options, centered: centered, columns: columns, onSelect: onSelect }));
|
|
17
|
+
}
|
|
18
|
+
return (_jsx(SinglePickerMenu, { message: message, options: options, centered: centered, columns: columns, onSelect: onSelect }));
|
|
19
|
+
};
|
|
20
|
+
/** Returns the number key label for an option index (1-based, 0 = tenth). */
|
|
21
|
+
function numKey(index) {
|
|
22
|
+
if (index === 9)
|
|
23
|
+
return '0';
|
|
24
|
+
if (index < 9)
|
|
25
|
+
return String(index + 1);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
/** Render a single picker item row. */
|
|
29
|
+
const PickerItem = ({ opt, isFocused, index, }) => {
|
|
30
|
+
const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;
|
|
31
|
+
const key = numKey(index);
|
|
32
|
+
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: isFocused ? Colors.accent : Colors.muted, children: isFocused ? Icons.triangleSmallRight : ' ' }), key !== null && (_jsxs(Text, { color: isFocused ? Colors.accent : Colors.muted, children: ["[", key, "]"] })), _jsx(Text, { color: isFocused ? Colors.accent : Colors.muted, bold: isFocused, children: label })] }));
|
|
33
|
+
};
|
|
34
|
+
/** Custom single-select with triangle indicator and accent highlight.
|
|
35
|
+
* Single-column lists that exceed the terminal height scroll automatically. */
|
|
36
|
+
const SinglePickerMenu = ({ message, options, centered = false, columns = 1, onSelect, }) => {
|
|
37
|
+
const [focused, setFocused] = useState(0);
|
|
38
|
+
const [, termRows] = useStdoutDimensions();
|
|
39
|
+
const scrollRef = useRef(0);
|
|
40
|
+
const rowsPerCol = Math.ceil(options.length / columns);
|
|
41
|
+
const maxVisible = columns === 1
|
|
42
|
+
? Math.min(rowsPerCol, Math.max(5, termRows - PICKER_CHROME_ROWS))
|
|
43
|
+
: rowsPerCol;
|
|
44
|
+
const needsScroll = rowsPerCol > maxVisible;
|
|
45
|
+
if (needsScroll) {
|
|
46
|
+
if (focused < scrollRef.current) {
|
|
47
|
+
scrollRef.current = focused;
|
|
48
|
+
}
|
|
49
|
+
else if (focused >= scrollRef.current + maxVisible) {
|
|
50
|
+
scrollRef.current = focused - maxVisible + 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
scrollRef.current = 0;
|
|
55
|
+
}
|
|
56
|
+
const scrollOffset = scrollRef.current;
|
|
57
|
+
useScreenInput((input, key) => {
|
|
58
|
+
const col = Math.floor(focused / rowsPerCol);
|
|
59
|
+
const row = focused % rowsPerCol;
|
|
60
|
+
// Number keys 1–9 select options 0–8; 0 selects option 9
|
|
61
|
+
const digit = parseInt(input, 10);
|
|
62
|
+
if (!isNaN(digit) && !key.ctrl && !key.meta) {
|
|
63
|
+
const idx = digit === 0 ? 9 : digit - 1;
|
|
64
|
+
const opt = options[idx];
|
|
65
|
+
if (opt) {
|
|
66
|
+
onSelect(opt.value);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (key.upArrow) {
|
|
71
|
+
if (row > 0) {
|
|
72
|
+
setFocused(col * rowsPerCol + row - 1);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
setFocused(Math.min(col * rowsPerCol + rowsPerCol - 1, options.length - 1));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (key.downArrow) {
|
|
79
|
+
const next = col * rowsPerCol + row + 1;
|
|
80
|
+
if (next < options.length && row + 1 < rowsPerCol) {
|
|
81
|
+
setFocused(next);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
setFocused(col * rowsPerCol);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (key.leftArrow && columns > 1) {
|
|
88
|
+
const prevCol = col > 0 ? col - 1 : columns - 1;
|
|
89
|
+
setFocused(Math.min(prevCol * rowsPerCol + row, options.length - 1));
|
|
90
|
+
}
|
|
91
|
+
if (key.rightArrow && columns > 1) {
|
|
92
|
+
const nextCol = col < columns - 1 ? col + 1 : 0;
|
|
93
|
+
setFocused(Math.min(nextCol * rowsPerCol + row, options.length - 1));
|
|
94
|
+
}
|
|
95
|
+
if (key.return) {
|
|
96
|
+
const selected = options[focused];
|
|
97
|
+
if (selected) {
|
|
98
|
+
onSelect(selected.value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
const align = centered ? 'center' : undefined;
|
|
103
|
+
if (needsScroll) {
|
|
104
|
+
const hasAbove = scrollOffset > 0;
|
|
105
|
+
const hasBelow = scrollOffset + maxVisible < options.length;
|
|
106
|
+
const visible = options.slice(scrollOffset, scrollOffset + maxVisible);
|
|
107
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: align, children: [_jsx(PromptLabel, { message: message }), hasAbove && (_jsxs(Text, { color: Colors.muted, children: [' \u2191 ', scrollOffset, " more"] })), visible.map((opt, i) => (_jsx(PickerItem, { opt: opt, index: scrollOffset + i, isFocused: scrollOffset + i === focused }, scrollOffset + i))), hasBelow && (_jsxs(Text, { color: Colors.muted, children: [' \u2193 ', options.length - scrollOffset - maxVisible, " more"] }))] }));
|
|
108
|
+
}
|
|
109
|
+
// Multi-column / short-list: render all items in column-first grid
|
|
110
|
+
const columnArrays = [];
|
|
111
|
+
for (let c = 0; c < columns; c++) {
|
|
112
|
+
columnArrays.push(options.slice(c * rowsPerCol, c * rowsPerCol + rowsPerCol));
|
|
113
|
+
}
|
|
114
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: align, children: [_jsx(PromptLabel, { message: message }), _jsx(Box, { flexDirection: "row", gap: 4, children: columnArrays.map((colOpts, colIdx) => (_jsx(Box, { flexDirection: "column", children: colOpts.map((opt, rowIdx) => (_jsx(PickerItem, { opt: opt, index: colIdx * rowsPerCol + rowIdx, isFocused: colIdx * rowsPerCol + rowIdx === focused }, colIdx * rowsPerCol + rowIdx))) }, colIdx))) })] }));
|
|
115
|
+
};
|
|
116
|
+
/** Custom multi-select with checkbox glyphs and accent highlight. */
|
|
117
|
+
const MultiPickerMenu = ({ message, options, centered = false, columns = 1, onSelect, }) => {
|
|
118
|
+
const [focused, setFocused] = useState(0);
|
|
119
|
+
const [selected, setSelected] = useState(new Set());
|
|
120
|
+
const rows = Math.ceil(options.length / columns);
|
|
121
|
+
useScreenInput((input, key) => {
|
|
122
|
+
const col = Math.floor(focused / rows);
|
|
123
|
+
const row = focused % rows;
|
|
124
|
+
// Number keys 1–9 toggle options 0–8; 0 toggles option 9
|
|
125
|
+
const digit = parseInt(input, 10);
|
|
126
|
+
if (!isNaN(digit) && !key.ctrl && !key.meta) {
|
|
127
|
+
const idx = digit === 0 ? 9 : digit - 1;
|
|
128
|
+
if (idx < options.length) {
|
|
129
|
+
setFocused(idx);
|
|
130
|
+
setSelected((prev) => {
|
|
131
|
+
const next = new Set(prev);
|
|
132
|
+
if (next.has(idx)) {
|
|
133
|
+
next.delete(idx);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
next.add(idx);
|
|
137
|
+
}
|
|
138
|
+
return next;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (key.upArrow) {
|
|
144
|
+
if (row > 0) {
|
|
145
|
+
setFocused(col * rows + row - 1);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
setFocused(Math.min(col * rows + rows - 1, options.length - 1));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (key.downArrow) {
|
|
152
|
+
const next = col * rows + row + 1;
|
|
153
|
+
if (next < options.length && row + 1 < rows) {
|
|
154
|
+
setFocused(next);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
setFocused(col * rows);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (key.leftArrow && columns > 1) {
|
|
161
|
+
const prevCol = col > 0 ? col - 1 : columns - 1;
|
|
162
|
+
setFocused(Math.min(prevCol * rows + row, options.length - 1));
|
|
163
|
+
}
|
|
164
|
+
if (key.rightArrow && columns > 1) {
|
|
165
|
+
const nextCol = col < columns - 1 ? col + 1 : 0;
|
|
166
|
+
setFocused(Math.min(nextCol * rows + row, options.length - 1));
|
|
167
|
+
}
|
|
168
|
+
if (input === ' ') {
|
|
169
|
+
setSelected((prev) => {
|
|
170
|
+
const next = new Set(prev);
|
|
171
|
+
if (next.has(focused)) {
|
|
172
|
+
next.delete(focused);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
next.add(focused);
|
|
176
|
+
}
|
|
177
|
+
return next;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (key.return) {
|
|
181
|
+
const values = [...selected].sort().map((i) => options[i].value);
|
|
182
|
+
if (values.length === 0) {
|
|
183
|
+
// Nothing toggled — fall back to the focused item so Enter always submits
|
|
184
|
+
const focusedOpt = options[focused];
|
|
185
|
+
if (focusedOpt)
|
|
186
|
+
onSelect([focusedOpt.value]);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
onSelect(values);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
const columnArrays = [];
|
|
194
|
+
for (let c = 0; c < columns; c++) {
|
|
195
|
+
columnArrays.push(options.slice(c * rows, c * rows + rows));
|
|
196
|
+
}
|
|
197
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: centered ? 'center' : undefined, children: [_jsx(PromptLabel, { message: message }), _jsx(Text, { color: Colors.muted, children: " (space to toggle, enter to submit)" }), _jsx(Box, { flexDirection: "row", gap: 4, marginLeft: centered ? 0 : 2, marginTop: 1, children: columnArrays.map((colOpts, colIdx) => (_jsx(Box, { flexDirection: "column", children: colOpts.map((opt, rowIdx) => {
|
|
198
|
+
const flatIdx = colIdx * rows + rowIdx;
|
|
199
|
+
const isFocused = flatIdx === focused;
|
|
200
|
+
const isSelected = selected.has(flatIdx);
|
|
201
|
+
const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;
|
|
202
|
+
const checkbox = isSelected
|
|
203
|
+
? Icons.squareFilled
|
|
204
|
+
: Icons.squareOpen;
|
|
205
|
+
const key = numKey(flatIdx);
|
|
206
|
+
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: isFocused
|
|
207
|
+
? Colors.accent
|
|
208
|
+
: isSelected
|
|
209
|
+
? 'white'
|
|
210
|
+
: Colors.muted, children: checkbox }), key !== null && (_jsxs(Text, { color: isFocused ? Colors.accent : Colors.muted, children: ["[", key, "]"] })), _jsx(Text, { color: isFocused ? Colors.accent : Colors.muted, bold: isFocused, children: label })] }, flatIdx));
|
|
211
|
+
}) }, colIdx))) })] }));
|
|
212
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProgressList — Reusable task checklist with status icons.
|
|
3
|
+
* Extracted from StatusTab logic.
|
|
4
|
+
*/
|
|
5
|
+
export interface ProgressItem {
|
|
6
|
+
label: string;
|
|
7
|
+
activeForm?: string;
|
|
8
|
+
status: 'pending' | 'in_progress' | 'completed';
|
|
9
|
+
}
|
|
10
|
+
interface ProgressListProps {
|
|
11
|
+
items: ProgressItem[];
|
|
12
|
+
title?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const ProgressList: ({ items, title }: ProgressListProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ProgressList — Reusable task checklist with status icons.
|
|
4
|
+
* Extracted from StatusTab logic.
|
|
5
|
+
*/
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
import { Spinner } from '@inkjs/ui';
|
|
8
|
+
import { Colors, Icons } from '../styles.js';
|
|
9
|
+
import { LoadingBox } from './LoadingBox.js';
|
|
10
|
+
export const ProgressList = ({ items, title }) => {
|
|
11
|
+
const completed = items.filter((t) => t.status === 'completed').length;
|
|
12
|
+
const total = items.length;
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", children: [title && (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: title }), _jsx(Text, { children: " " })] })), items.length === 0 && _jsx(LoadingBox, { message: "Analyzing project..." }), items.map((item, i) => {
|
|
14
|
+
const icon = item.status === 'completed'
|
|
15
|
+
? Icons.squareFilled
|
|
16
|
+
: item.status === 'in_progress'
|
|
17
|
+
? Icons.triangleRight
|
|
18
|
+
: Icons.squareOpen;
|
|
19
|
+
const color = item.status === 'completed'
|
|
20
|
+
? Colors.success
|
|
21
|
+
: item.status === 'in_progress'
|
|
22
|
+
? Colors.primary
|
|
23
|
+
: Colors.muted;
|
|
24
|
+
const label = item.status === 'in_progress' && item.activeForm
|
|
25
|
+
? item.activeForm
|
|
26
|
+
: item.label;
|
|
27
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: color, children: icon }), _jsxs(Text, { color: item.status === 'pending' ? Colors.muted : undefined, children: [' ', label] })] }, i));
|
|
28
|
+
}), total > 0 && (_jsxs(Box, { marginTop: 1, gap: 1, children: [completed < total && _jsx(Spinner, {}), _jsxs(Text, { color: Colors.muted, children: ["Progress: ", completed, "/", total, " completed"] })] }))] }));
|
|
29
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PromptLabel — Compact inline label for input prompts.
|
|
3
|
+
*
|
|
4
|
+
* Renders: [!] message
|
|
5
|
+
* where [!] is black text on accent background.
|
|
6
|
+
*/
|
|
7
|
+
interface PromptLabelProps {
|
|
8
|
+
message?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const PromptLabel: ({ message }: PromptLabelProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* PromptLabel — Compact inline label for input prompts.
|
|
4
|
+
*
|
|
5
|
+
* Renders: [!] message
|
|
6
|
+
* where [!] is black text on accent background.
|
|
7
|
+
*/
|
|
8
|
+
import { Box, Text } from 'ink';
|
|
9
|
+
import { Colors } from '../styles.js';
|
|
10
|
+
export const PromptLabel = ({ message }) => {
|
|
11
|
+
return (_jsx(Box, { children: _jsxs(Text, { bold: true, color: Colors.accent, children: [' ', message] }) }));
|
|
12
|
+
};
|