@alumbwe/anvil 1.0.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/README.md +84 -0
- package/bin/anvil +2 -0
- package/bin/tree-sitter.wasm +0 -0
- package/package.json +67 -0
- package/src/__tests__/README.md +256 -0
- package/src/__tests__/bash-mode.test.ts +442 -0
- package/src/__tests__/cli-args.test.ts +181 -0
- package/src/__tests__/cli-harness.test.ts +52 -0
- package/src/__tests__/e2e/first-time-login.test.ts +173 -0
- package/src/__tests__/e2e/logout-relogin-flow.test.ts +110 -0
- package/src/__tests__/e2e/returning-user-auth.test.ts +113 -0
- package/src/__tests__/e2e-cli.test.ts +183 -0
- package/src/__tests__/helpers/launcher-disconnect-fixture.cjs +176 -0
- package/src/__tests__/helpers/mock-api-client.ts +64 -0
- package/src/__tests__/helpers/renderer-cleanup-fixture.tsx +89 -0
- package/src/__tests__/helpers/terminal-watchdog-fixture.ts +75 -0
- package/src/__tests__/home-directory-detection.test.ts +213 -0
- package/src/__tests__/integration/api-integration.test.ts +288 -0
- package/src/__tests__/integration/credentials-storage.test.ts +486 -0
- package/src/__tests__/integration/local-agents.test.ts +1187 -0
- package/src/__tests__/integration/login-flow-instrumentation.test.ts +134 -0
- package/src/__tests__/integration/login-polling-working.test.ts +285 -0
- package/src/__tests__/integration/queue-editing.test.tsx +261 -0
- package/src/__tests__/integration/usage-refresh-on-completion.test.ts +168 -0
- package/src/__tests__/integration-tmux.test.ts +188 -0
- package/src/__tests__/launcher-avx2-fallback.test.ts +630 -0
- package/src/__tests__/launcher-disconnect.test.ts +104 -0
- package/src/__tests__/mocks/hover-toggle-controller.ts +71 -0
- package/src/__tests__/open-tui-native-bundle.test.ts +378 -0
- package/src/__tests__/path-completion.test.ts +243 -0
- package/src/__tests__/project-files-chat-id.test.ts +34 -0
- package/src/__tests__/release/proxy-http-get.test.ts +667 -0
- package/src/__tests__/release/wrapper-safety.test.ts +412 -0
- package/src/__tests__/renderer-cleanup.test.ts +174 -0
- package/src/__tests__/rerender-perf.integration.test.ts +283 -0
- package/src/__tests__/terminal-reset-sequences.test.ts +36 -0
- package/src/__tests__/terminal-watchdog.test.ts +388 -0
- package/src/__tests__/test-utils.ts +271 -0
- package/src/__tests__/tmux-poc.ts +150 -0
- package/src/__tests__/unit/agent-mode-toggle.test.ts +137 -0
- package/src/__tests__/unit/copy-button.test.ts +157 -0
- package/src/__tests__/unit/create-run-config.test.ts +66 -0
- package/src/__tests__/unit/publish-confirmation.test.ts +70 -0
- package/src/__tests__/unit/segmented-control.test.ts +152 -0
- package/src/__tests__/utils/env.test.ts +169 -0
- package/src/__tests__/utils/project-picker.test.ts +39 -0
- package/src/agents/bundled-agents.generated.d.ts +14 -0
- package/src/agents/bundled-agents.generated.ts +3692 -0
- package/src/app.tsx +399 -0
- package/src/chat.tsx +1698 -0
- package/src/cli-args.ts +134 -0
- package/src/commands/__tests__/bash-command.test.ts +445 -0
- package/src/commands/__tests__/command-args.test.ts +349 -0
- package/src/commands/__tests__/copy-conversation-clipboard.test.ts +108 -0
- package/src/commands/__tests__/copy-conversation.test.ts +226 -0
- package/src/commands/__tests__/diagnostics-command.test.ts +35 -0
- package/src/commands/__tests__/freebuff-command-aliases.test.ts +56 -0
- package/src/commands/__tests__/image.test.ts +99 -0
- package/src/commands/__tests__/init.test.ts +456 -0
- package/src/commands/__tests__/new-command-rotates-chat.test.ts +91 -0
- package/src/commands/__tests__/process-diagnostics.test.ts +54 -0
- package/src/commands/__tests__/prompt-builders.test.ts +28 -0
- package/src/commands/__tests__/router-input.test.ts +298 -0
- package/src/commands/ads.ts +44 -0
- package/src/commands/command-registry.ts +726 -0
- package/src/commands/copy-conversation.ts +392 -0
- package/src/commands/help.ts +13 -0
- package/src/commands/image.ts +20 -0
- package/src/commands/init.ts +121 -0
- package/src/commands/process-diagnostics.ts +120 -0
- package/src/commands/prompt-builders.ts +100 -0
- package/src/commands/publish.ts +203 -0
- package/src/commands/router-utils.ts +80 -0
- package/src/commands/router.ts +487 -0
- package/src/commands/usage.ts +26 -0
- package/src/components/__tests__/ad-banner.test.tsx +83 -0
- package/src/components/__tests__/chat-input-bar.test.tsx +130 -0
- package/src/components/__tests__/freebuff-landing-heading-row.test.tsx +91 -0
- package/src/components/__tests__/freebuff-model-selector.test.tsx +519 -0
- package/src/components/__tests__/freebuff-offer-invariants.test.ts +54 -0
- package/src/components/__tests__/freebuff-takeover-prompt.test.tsx +212 -0
- package/src/components/__tests__/grid-layout.integration.test.tsx +304 -0
- package/src/components/__tests__/grid-layout.test.tsx +1051 -0
- package/src/components/__tests__/message-block.completion.test.tsx +104 -0
- package/src/components/__tests__/message-block.streaming.test.tsx +78 -0
- package/src/components/__tests__/message-with-agents.test.tsx +579 -0
- package/src/components/__tests__/multiline-input.test.tsx +1132 -0
- package/src/components/__tests__/queue-panel.test.tsx +398 -0
- package/src/components/__tests__/selectable-list.test.ts +232 -0
- package/src/components/__tests__/status-bar.test.tsx +44 -0
- package/src/components/__tests__/status-indicator.test.tsx +204 -0
- package/src/components/__tests__/terminal-thinking-orb.test.tsx +111 -0
- package/src/components/__tests__/user-error-banner.test.tsx +102 -0
- package/src/components/ad-banner.tsx +323 -0
- package/src/components/agent-checklist.tsx +350 -0
- package/src/components/agent-mode-toggle.tsx +241 -0
- package/src/components/anvil-mark.tsx +52 -0
- package/src/components/ask-user/__tests__/multiple-choice-form.test.ts +432 -0
- package/src/components/ask-user/__tests__/validation.test.ts +213 -0
- package/src/components/ask-user/components/accordion-question.tsx +153 -0
- package/src/components/ask-user/components/custom-answer-input.tsx +66 -0
- package/src/components/ask-user/components/options-list.tsx +133 -0
- package/src/components/ask-user/components/question-header.tsx +80 -0
- package/src/components/ask-user/components/question-option.tsx +89 -0
- package/src/components/ask-user/constants.ts +38 -0
- package/src/components/ask-user/index.tsx +631 -0
- package/src/components/ask-user/utils/validation.ts +85 -0
- package/src/components/attachment-card.tsx +65 -0
- package/src/components/blocks/agent-block-grid.tsx +58 -0
- package/src/components/blocks/agent-branch-item.tsx +311 -0
- package/src/components/blocks/agent-branch-wrapper.tsx +493 -0
- package/src/components/blocks/agent-list-branch.tsx +77 -0
- package/src/components/blocks/ask-user-branch.tsx +81 -0
- package/src/components/blocks/block-helpers.ts +11 -0
- package/src/components/blocks/blocks-renderer.tsx +289 -0
- package/src/components/blocks/content-with-markdown.tsx +33 -0
- package/src/components/blocks/image-block.tsx +128 -0
- package/src/components/blocks/implementor-row.tsx +429 -0
- package/src/components/blocks/single-block.tsx +201 -0
- package/src/components/blocks/thinking-block.tsx +67 -0
- package/src/components/blocks/tool-block-group.tsx +57 -0
- package/src/components/blocks/tool-branch.tsx +206 -0
- package/src/components/blocks/user-content-copy.tsx +157 -0
- package/src/components/bottom-banner.tsx +136 -0
- package/src/components/build-mode-buttons.tsx +110 -0
- package/src/components/button.tsx +66 -0
- package/src/components/chat-header.tsx +77 -0
- package/src/components/chat-history-screen.tsx +413 -0
- package/src/components/chat-input-bar.tsx +523 -0
- package/src/components/clickable-title-box.tsx +66 -0
- package/src/components/clickable.tsx +119 -0
- package/src/components/collapse-button.tsx +34 -0
- package/src/components/copy-button.tsx +203 -0
- package/src/components/elapsed-timer.tsx +55 -0
- package/src/components/error-boundary.tsx +55 -0
- package/src/components/feedback-container.tsx +181 -0
- package/src/components/feedback-icon-button.tsx +89 -0
- package/src/components/feedback-input-mode.tsx +344 -0
- package/src/components/file-attachment-card.tsx +98 -0
- package/src/components/freebuff-active-session-summary.tsx +63 -0
- package/src/components/freebuff-landing-screen.tsx +865 -0
- package/src/components/freebuff-model-selector.tsx +1087 -0
- package/src/components/freebuff-referral-banner.tsx +604 -0
- package/src/components/freebuff-superseded-screen.tsx +62 -0
- package/src/components/grid-layout.tsx +80 -0
- package/src/components/help-banner.tsx +127 -0
- package/src/components/highlighted-text.tsx +52 -0
- package/src/components/image-card.tsx +167 -0
- package/src/components/image-thumbnail.tsx +114 -0
- package/src/components/input-cursor.tsx +77 -0
- package/src/components/input-mode-banner.tsx +57 -0
- package/src/components/load-previous-button.tsx +48 -0
- package/src/components/login-modal.tsx +475 -0
- package/src/components/message-block.tsx +346 -0
- package/src/components/message-footer.tsx +258 -0
- package/src/components/message-with-agents.tsx +506 -0
- package/src/components/mode-divider.tsx +43 -0
- package/src/components/multiline-input.tsx +1241 -0
- package/src/components/out-of-credits-banner.tsx +160 -0
- package/src/components/pending-attachments-banner.tsx +116 -0
- package/src/components/pending-bash-message.tsx +59 -0
- package/src/components/progress-bar.tsx +81 -0
- package/src/components/project-picker-screen.tsx +485 -0
- package/src/components/publish-confirmation.tsx +493 -0
- package/src/components/publish-container.tsx +687 -0
- package/src/components/queue-panel.tsx +310 -0
- package/src/components/raised-pill.tsx +95 -0
- package/src/components/renderers/plan-box.tsx +59 -0
- package/src/components/review-screen.tsx +112 -0
- package/src/components/scroll-to-bottom-button.tsx +34 -0
- package/src/components/segmented-control.tsx +187 -0
- package/src/components/selectable-list.tsx +248 -0
- package/src/components/selected-chips.tsx +80 -0
- package/src/components/separator.tsx +40 -0
- package/src/components/session-ended-banner.tsx +226 -0
- package/src/components/shimmer-text.tsx +248 -0
- package/src/components/status-bar.tsx +313 -0
- package/src/components/subscription-limit-banner.tsx +206 -0
- package/src/components/suggested-prompts.tsx +184 -0
- package/src/components/suggestion-menu.tsx +215 -0
- package/src/components/terminal-command-display.tsx +151 -0
- package/src/components/terminal-link.tsx +97 -0
- package/src/components/terminal-thinking-orb.tsx +95 -0
- package/src/components/text-attachment-card.tsx +77 -0
- package/src/components/thinking.tsx +109 -0
- package/src/components/tools/__tests__/apply-patch.test.tsx +84 -0
- package/src/components/tools/__tests__/code-search.test.tsx +45 -0
- package/src/components/tools/__tests__/gravity-index.test.ts +76 -0
- package/src/components/tools/__tests__/render-ui.test.tsx +92 -0
- package/src/components/tools/__tests__/run-terminal-command.test.ts +233 -0
- package/src/components/tools/apply-patch.tsx +95 -0
- package/src/components/tools/code-search.tsx +45 -0
- package/src/components/tools/composio.tsx +152 -0
- package/src/components/tools/diff-viewer.tsx +76 -0
- package/src/components/tools/glob.tsx +61 -0
- package/src/components/tools/gravity-index.tsx +77 -0
- package/src/components/tools/list-directory.tsx +61 -0
- package/src/components/tools/read-docs.tsx +37 -0
- package/src/components/tools/read-files.tsx +91 -0
- package/src/components/tools/read-subtree.tsx +44 -0
- package/src/components/tools/read-url.tsx +33 -0
- package/src/components/tools/registry.ts +126 -0
- package/src/components/tools/render-ui.tsx +122 -0
- package/src/components/tools/run-terminal-command.tsx +79 -0
- package/src/components/tools/skill.tsx +29 -0
- package/src/components/tools/str-replace.tsx +77 -0
- package/src/components/tools/suggest-followups.tsx +369 -0
- package/src/components/tools/task-completed.tsx +16 -0
- package/src/components/tools/tool-call-item.tsx +273 -0
- package/src/components/tools/types.ts +55 -0
- package/src/components/tools/web-search.tsx +33 -0
- package/src/components/tools/write-file.tsx +16 -0
- package/src/components/tools/write-todos.tsx +95 -0
- package/src/components/top-banner.tsx +178 -0
- package/src/components/usage-banner.tsx +244 -0
- package/src/components/user-error-banner.tsx +56 -0
- package/src/components/validation-error-popover.tsx +192 -0
- package/src/contexts/__tests__/chat-runtime-context.test.tsx +149 -0
- package/src/contexts/chat-runtime-context.tsx +240 -0
- package/src/data/slash-commands.test.ts +24 -0
- package/src/data/slash-commands.ts +249 -0
- package/src/entry.ts +12 -0
- package/src/hooks/__tests__/holds-live-freebuff-slot.test.ts +49 -0
- package/src/hooks/__tests__/session-fetch-signal.test.ts +63 -0
- package/src/hooks/__tests__/use-activity-query.test.ts +1000 -0
- package/src/hooks/__tests__/use-ask-user-bridge.test.ts +176 -0
- package/src/hooks/__tests__/use-auth-query.test.ts +21 -0
- package/src/hooks/__tests__/use-chat-input-remount.test.tsx +66 -0
- package/src/hooks/__tests__/use-clipboard.test.tsx +73 -0
- package/src/hooks/__tests__/use-connection-status.test.ts +112 -0
- package/src/hooks/__tests__/use-directory-browser.test.ts +203 -0
- package/src/hooks/__tests__/use-gravity-ad.test.ts +73 -0
- package/src/hooks/__tests__/use-grid-layout.test.ts +349 -0
- package/src/hooks/__tests__/use-input-history.test.ts +699 -0
- package/src/hooks/__tests__/use-message-queue-editing.test.tsx +209 -0
- package/src/hooks/__tests__/use-message-queue.test.tsx +71 -0
- package/src/hooks/__tests__/use-path-tab-completion.test.ts +315 -0
- package/src/hooks/__tests__/use-queue-controls.test.ts +68 -0
- package/src/hooks/__tests__/use-queue-ui.test.tsx +83 -0
- package/src/hooks/__tests__/use-searchable-list.test.ts +359 -0
- package/src/hooks/__tests__/use-send-message-timer.test.ts +146 -0
- package/src/hooks/__tests__/use-suggestion-engine-mention.test.ts +361 -0
- package/src/hooks/__tests__/use-suggestion-engine.test.ts +485 -0
- package/src/hooks/__tests__/use-terminal-focus.test.ts +66 -0
- package/src/hooks/__tests__/use-terminal-layout.test.ts +675 -0
- package/src/hooks/__tests__/use-timeout.test.ts +330 -0
- package/src/hooks/__tests__/use-usage-query.test.ts +502 -0
- package/src/hooks/__tests__/use-user-details-query.test.ts +195 -0
- package/src/hooks/helpers/__tests__/send-message.test.ts +1918 -0
- package/src/hooks/helpers/send-message.ts +654 -0
- package/src/hooks/stream-state.ts +83 -0
- package/src/hooks/use-activity-query.ts +668 -0
- package/src/hooks/use-agent-validation.ts +74 -0
- package/src/hooks/use-ask-user-bridge.ts +92 -0
- package/src/hooks/use-auth-query.ts +253 -0
- package/src/hooks/use-auth-state.ts +152 -0
- package/src/hooks/use-chat-input.ts +105 -0
- package/src/hooks/use-chat-keyboard.ts +321 -0
- package/src/hooks/use-chat-messages.ts +254 -0
- package/src/hooks/use-chat-state.ts +165 -0
- package/src/hooks/use-chat-streaming.ts +180 -0
- package/src/hooks/use-chat-ui.ts +131 -0
- package/src/hooks/use-clipboard.ts +151 -0
- package/src/hooks/use-connection-status.ts +142 -0
- package/src/hooks/use-directory-browser.ts +88 -0
- package/src/hooks/use-elapsed-time.ts +116 -0
- package/src/hooks/use-event.ts +34 -0
- package/src/hooks/use-exit-handler.ts +66 -0
- package/src/hooks/use-fetch-login-url.ts +65 -0
- package/src/hooks/use-fingerprint.ts +61 -0
- package/src/hooks/use-freebuff-ctrl-c-exit.ts +23 -0
- package/src/hooks/use-freebuff-session-progress.ts +34 -0
- package/src/hooks/use-freebuff-session.ts +806 -0
- package/src/hooks/use-freebuff-streak-query.ts +61 -0
- package/src/hooks/use-gravity-ad.ts +656 -0
- package/src/hooks/use-grid-layout.ts +73 -0
- package/src/hooks/use-input-history.ts +173 -0
- package/src/hooks/use-login-keyboard-handlers.ts +75 -0
- package/src/hooks/use-login-polling.ts +114 -0
- package/src/hooks/use-logo.tsx +161 -0
- package/src/hooks/use-message-queue.ts +387 -0
- package/src/hooks/use-now.ts +20 -0
- package/src/hooks/use-path-tab-completion.ts +88 -0
- package/src/hooks/use-publish-mutation.ts +60 -0
- package/src/hooks/use-queue-controls.ts +68 -0
- package/src/hooks/use-queue-ui.ts +74 -0
- package/src/hooks/use-scroll-management.ts +184 -0
- package/src/hooks/use-searchable-list.ts +98 -0
- package/src/hooks/use-send-message.ts +773 -0
- package/src/hooks/use-sheen-animation.tsx +88 -0
- package/src/hooks/use-subscription-query.ts +71 -0
- package/src/hooks/use-suggestion-engine.ts +783 -0
- package/src/hooks/use-terminal-breakpoints.ts +77 -0
- package/src/hooks/use-terminal-dimensions.ts +46 -0
- package/src/hooks/use-terminal-focus.ts +29 -0
- package/src/hooks/use-terminal-layout.ts +189 -0
- package/src/hooks/use-theme.tsx +140 -0
- package/src/hooks/use-timeout.ts +85 -0
- package/src/hooks/use-update-preference.ts +66 -0
- package/src/hooks/use-usage-monitor.ts +55 -0
- package/src/hooks/use-usage-query.ts +124 -0
- package/src/hooks/use-user-details-query.ts +93 -0
- package/src/hooks/use-why-did-you-update.ts +177 -0
- package/src/index.tsx +441 -0
- package/src/init/__tests__/init-direnv.test.ts +526 -0
- package/src/init/init-app.ts +34 -0
- package/src/init/init-direnv.ts +133 -0
- package/src/login/constants.ts +60 -0
- package/src/login/login-flow.ts +204 -0
- package/src/login/plain-login.ts +108 -0
- package/src/login/utils.ts +183 -0
- package/src/native/ripgrep.ts +80 -0
- package/src/polyfills/bun-strip-ansi.ts +12 -0
- package/src/pre-init/tree-sitter-wasm.ts +96 -0
- package/src/project-files.ts +102 -0
- package/src/smoke/terminal-command-broker.ts +439 -0
- package/src/state/__tests__/chat-store-focus.test.ts +22 -0
- package/src/state/__tests__/feedback-store.test.ts +257 -0
- package/src/state/chat-history-store.ts +30 -0
- package/src/state/chat-store.ts +544 -0
- package/src/state/feedback-store.ts +160 -0
- package/src/state/freebuff-model-store.ts +42 -0
- package/src/state/freebuff-session-store.ts +53 -0
- package/src/state/login-store.ts +150 -0
- package/src/state/message-block-store.ts +149 -0
- package/src/state/publish-store.ts +146 -0
- package/src/state/queue-panel-store.ts +26 -0
- package/src/state/review-store.ts +24 -0
- package/src/testing/env.ts +46 -0
- package/src/types/chat-state.ts +15 -0
- package/src/types/chat.ts +241 -0
- package/src/types/contracts/send-message.ts +12 -0
- package/src/types/env.ts +98 -0
- package/src/types/freebuff-session.ts +17 -0
- package/src/types/function-params.ts +28 -0
- package/src/types/react19-compat.d.ts +19 -0
- package/src/types/store.ts +111 -0
- package/src/types/theme-system.ts +144 -0
- package/src/types/utils.ts +3 -0
- package/src/utils/__tests__/active-run.test.ts +140 -0
- package/src/utils/__tests__/activity-tracker.test.ts +440 -0
- package/src/utils/__tests__/agent-display.test.ts +139 -0
- package/src/utils/__tests__/analytics-client.test.ts +262 -0
- package/src/utils/__tests__/anonymous-id.test.ts +74 -0
- package/src/utils/__tests__/anvil-api.test.ts +578 -0
- package/src/utils/__tests__/arrays.test.ts +264 -0
- package/src/utils/__tests__/bash-context-processor.test.ts +38 -0
- package/src/utils/__tests__/block-processor.test.ts +810 -0
- package/src/utils/__tests__/chat-history.test.ts +203 -0
- package/src/utils/__tests__/chat-input-key-intercept.test.ts +40 -0
- package/src/utils/__tests__/chat-meta.test.ts +130 -0
- package/src/utils/__tests__/clipboard-linux.test.ts +359 -0
- package/src/utils/__tests__/clipboard.test.ts +910 -0
- package/src/utils/__tests__/code-search-summary.test.ts +84 -0
- package/src/utils/__tests__/collapse-helpers.test.ts +1109 -0
- package/src/utils/__tests__/error-handling.test.ts +658 -0
- package/src/utils/__tests__/exit-cleanly.test.ts +110 -0
- package/src/utils/__tests__/feedback-helpers.test.ts +444 -0
- package/src/utils/__tests__/feedback-submission.test.ts +26 -0
- package/src/utils/__tests__/fetch-usage.test.ts +355 -0
- package/src/utils/__tests__/fingerprint.test.ts +144 -0
- package/src/utils/__tests__/fixtures/terminal-command-broker-child.ts +7 -0
- package/src/utils/__tests__/fixtures/terminal-command-broker-entry.ts +3 -0
- package/src/utils/__tests__/fixtures/terminal-command-broker-owner.ts +33 -0
- package/src/utils/__tests__/format-elapsed-time.test.ts +103 -0
- package/src/utils/__tests__/format-timeout.test.ts +87 -0
- package/src/utils/__tests__/freebuff-instance-owner.test.ts +69 -0
- package/src/utils/__tests__/freebuff-model-navigation.test.ts +102 -0
- package/src/utils/__tests__/freebuff-premium-reset.test.ts +79 -0
- package/src/utils/__tests__/freebuff-referral-cache.test.ts +116 -0
- package/src/utils/__tests__/freebuff-session-api.test.ts +215 -0
- package/src/utils/__tests__/freebuff-session-display.test.ts +23 -0
- package/src/utils/__tests__/freebuff-streak-line.test.ts +217 -0
- package/src/utils/__tests__/image-dimensions.test.ts +249 -0
- package/src/utils/__tests__/image-processor.test.ts +209 -0
- package/src/utils/__tests__/implementor-helpers.test.ts +1458 -0
- package/src/utils/__tests__/keyboard-actions.test.ts +660 -0
- package/src/utils/__tests__/layout-helpers.test.ts +36 -0
- package/src/utils/__tests__/lazy-response-ads.test.ts +167 -0
- package/src/utils/__tests__/log-shipper.test.ts +53 -0
- package/src/utils/__tests__/markdown-renderer.test.tsx +421 -0
- package/src/utils/__tests__/message-block-helpers.test.ts +1263 -0
- package/src/utils/__tests__/message-updater.test.ts +645 -0
- package/src/utils/__tests__/osc-timeout-scenarios.test.ts +172 -0
- package/src/utils/__tests__/pending-attachments.test.ts +277 -0
- package/src/utils/__tests__/polling-backoff.test.ts +51 -0
- package/src/utils/__tests__/queue-panel-actions.test.ts +148 -0
- package/src/utils/__tests__/run-state-storage.test.ts +919 -0
- package/src/utils/__tests__/safe-json.test.ts +77 -0
- package/src/utils/__tests__/sdk-event-handlers.test.ts +685 -0
- package/src/utils/__tests__/send-message-helpers.test.ts +1898 -0
- package/src/utils/__tests__/send-message-timer.test.ts +64 -0
- package/src/utils/__tests__/settings.test.ts +99 -0
- package/src/utils/__tests__/strings.test.ts +192 -0
- package/src/utils/__tests__/terminal-color-detection.test.ts +425 -0
- package/src/utils/__tests__/terminal-command-broker.test.ts +528 -0
- package/src/utils/__tests__/terminal-enter-detection.test.ts +77 -0
- package/src/utils/__tests__/terminal-io.test.ts +137 -0
- package/src/utils/__tests__/terminal-protocol-controller.test.ts +119 -0
- package/src/utils/__tests__/text-layout.test.ts +82 -0
- package/src/utils/__tests__/theme-platform-detection.test.ts +125 -0
- package/src/utils/__tests__/think-tag-parser.test.ts +159 -0
- package/src/utils/__tests__/trace-writer.test.ts +223 -0
- package/src/utils/__tests__/trim-chat-logs.test.ts +78 -0
- package/src/utils/__tests__/usage-banner-state.test.ts +298 -0
- package/src/utils/__tests__/validation-error-formatting.test.ts +126 -0
- package/src/utils/__tests__/windows-terminal-health.test.ts +101 -0
- package/src/utils/__tests__/write-file-atomic.test.ts +127 -0
- package/src/utils/active-run.ts +131 -0
- package/src/utils/activity-tracker.ts +66 -0
- package/src/utils/agent-display.ts +87 -0
- package/src/utils/agent-helpers.ts +27 -0
- package/src/utils/agent-id-utils.ts +14 -0
- package/src/utils/ai-message-id.ts +12 -0
- package/src/utils/analytics.ts +361 -0
- package/src/utils/anonymous-id.ts +87 -0
- package/src/utils/anvil-api.ts +612 -0
- package/src/utils/anvil-client.ts +217 -0
- package/src/utils/arrays.ts +117 -0
- package/src/utils/auth.ts +258 -0
- package/src/utils/bash-context-processor.ts +47 -0
- package/src/utils/bash-messages.ts +108 -0
- package/src/utils/block-margins.ts +35 -0
- package/src/utils/block-operations.ts +523 -0
- package/src/utils/block-processor.ts +213 -0
- package/src/utils/chat-history.ts +253 -0
- package/src/utils/chat-input-key-intercept.ts +52 -0
- package/src/utils/chat-meta.ts +90 -0
- package/src/utils/chat-scroll-accel.ts +151 -0
- package/src/utils/clipboard-image.ts +588 -0
- package/src/utils/clipboard.ts +397 -0
- package/src/utils/code-search-summary.ts +70 -0
- package/src/utils/collapse-helpers.ts +256 -0
- package/src/utils/config-dir.ts +24 -0
- package/src/utils/constants.ts +190 -0
- package/src/utils/create-event-handler-state.ts +73 -0
- package/src/utils/create-run-config.ts +121 -0
- package/src/utils/detect-shell.ts +116 -0
- package/src/utils/directory-browser.ts +72 -0
- package/src/utils/engagement.ts +55 -0
- package/src/utils/env.ts +92 -0
- package/src/utils/error-handling.ts +255 -0
- package/src/utils/error-messages.ts +62 -0
- package/src/utils/exit-cleanly.ts +86 -0
- package/src/utils/feedback-helpers.ts +103 -0
- package/src/utils/feedback-submission.ts +22 -0
- package/src/utils/fetch-usage.ts +76 -0
- package/src/utils/fingerprint.ts +245 -0
- package/src/utils/format-elapsed-time.ts +33 -0
- package/src/utils/format-session-units.ts +6 -0
- package/src/utils/format-timeout.ts +28 -0
- package/src/utils/format-validation-errors-for-message.ts +84 -0
- package/src/utils/freebuff-agent-selection.ts +33 -0
- package/src/utils/freebuff-instance-owner.ts +66 -0
- package/src/utils/freebuff-model-navigation.ts +50 -0
- package/src/utils/freebuff-premium-reset.ts +55 -0
- package/src/utils/freebuff-referral-cache.ts +51 -0
- package/src/utils/freebuff-session-api.ts +243 -0
- package/src/utils/freebuff-session-display.ts +21 -0
- package/src/utils/freebuff-streak-line.ts +93 -0
- package/src/utils/git.ts +17 -0
- package/src/utils/helpers.ts +47 -0
- package/src/utils/image-display.ts +67 -0
- package/src/utils/image-handler.ts +325 -0
- package/src/utils/image-processor.ts +133 -0
- package/src/utils/image-thumbnail.ts +78 -0
- package/src/utils/implementor-helpers.ts +787 -0
- package/src/utils/input-modes.ts +174 -0
- package/src/utils/keyboard-actions.ts +392 -0
- package/src/utils/keypad-keys.ts +47 -0
- package/src/utils/layout-helpers.ts +33 -0
- package/src/utils/lazy-response-ads.ts +1 -0
- package/src/utils/local-agent-registry.ts +474 -0
- package/src/utils/log-shipper.ts +126 -0
- package/src/utils/logger.ts +327 -0
- package/src/utils/markdown-renderer.tsx +1090 -0
- package/src/utils/math.ts +3 -0
- package/src/utils/message-block-helpers.ts +684 -0
- package/src/utils/message-history.ts +143 -0
- package/src/utils/message-tree-utils.ts +67 -0
- package/src/utils/message-updater.ts +279 -0
- package/src/utils/open-file.ts +146 -0
- package/src/utils/open-url.ts +63 -0
- package/src/utils/path-completion.ts +111 -0
- package/src/utils/path-helpers.ts +38 -0
- package/src/utils/pending-attachments.ts +360 -0
- package/src/utils/polling-backoff.ts +59 -0
- package/src/utils/project-picker.ts +12 -0
- package/src/utils/queue-panel-actions.ts +70 -0
- package/src/utils/recent-projects.ts +156 -0
- package/src/utils/renderer-cleanup.ts +233 -0
- package/src/utils/response-ad-positions.ts +1 -0
- package/src/utils/run-state-storage.ts +603 -0
- package/src/utils/safe-json.ts +153 -0
- package/src/utils/sdk-event-handlers.ts +571 -0
- package/src/utils/send-message-helpers.ts +210 -0
- package/src/utils/send-message-timer.ts +110 -0
- package/src/utils/settings.ts +226 -0
- package/src/utils/skill-registry.ts +94 -0
- package/src/utils/spawn-agent-matcher.ts +55 -0
- package/src/utils/status-indicator-state.ts +107 -0
- package/src/utils/stream-chunk-processor.ts +57 -0
- package/src/utils/strings.ts +271 -0
- package/src/utils/subscription.ts +31 -0
- package/src/utils/syntax-highlighter.tsx +19 -0
- package/src/utils/terminal-color-detection.ts +474 -0
- package/src/utils/terminal-command-broker.ts +467 -0
- package/src/utils/terminal-enter-detection.ts +63 -0
- package/src/utils/terminal-images.ts +229 -0
- package/src/utils/terminal-io.ts +85 -0
- package/src/utils/terminal-protocol-controller.ts +173 -0
- package/src/utils/terminal-reset-sequences.ts +33 -0
- package/src/utils/terminal-title.ts +84 -0
- package/src/utils/terminal-watchdog.ts +366 -0
- package/src/utils/text-layout.ts +149 -0
- package/src/utils/theme-config.ts +141 -0
- package/src/utils/theme-system.ts +1206 -0
- package/src/utils/think-tag-parser.ts +95 -0
- package/src/utils/time-format.ts +21 -0
- package/src/utils/trace-writer.ts +162 -0
- package/src/utils/ui-constants.ts +69 -0
- package/src/utils/update-checker.ts +110 -0
- package/src/utils/usage-banner-state.ts +146 -0
- package/src/utils/validation-error-formatting.ts +86 -0
- package/src/utils/validation-error-helpers.ts +19 -0
- package/src/utils/windows-terminal-health.ts +124 -0
- package/src/utils/word-wrap-utils.ts +53 -0
- package/src/utils/write-file-atomic.ts +54 -0
- package/src/utils/yield-to-event-loop.ts +9 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Color Detection using OSC 10/11 Escape Sequences
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for detecting terminal theme (dark/light) by querying
|
|
5
|
+
* the terminal's foreground and background colors using OSC (Operating System Command)
|
|
6
|
+
* escape sequences.
|
|
7
|
+
*
|
|
8
|
+
* OSC 10: Query foreground (text) color
|
|
9
|
+
* OSC 11: Query background color
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { openSync, closeSync, writeSync, constants } from 'fs'
|
|
13
|
+
|
|
14
|
+
import { getCliEnv } from './env'
|
|
15
|
+
|
|
16
|
+
import type { CliEnv } from '../types/env'
|
|
17
|
+
|
|
18
|
+
// Timeout constants
|
|
19
|
+
const OSC_QUERY_TIMEOUT_MS = 500 // Timeout for individual OSC query
|
|
20
|
+
const GLOBAL_OSC_TIMEOUT_MS = 2000 // Global timeout for entire detection process
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wrap a promise with a timeout
|
|
24
|
+
* @param promise - The promise to wrap
|
|
25
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
26
|
+
* @param timeoutValue - Value to return on timeout
|
|
27
|
+
*/
|
|
28
|
+
export function withTimeout<T>(
|
|
29
|
+
promise: Promise<T>,
|
|
30
|
+
timeoutMs: number,
|
|
31
|
+
timeoutValue: T,
|
|
32
|
+
): Promise<T> {
|
|
33
|
+
let timeoutId: NodeJS.Timeout | null = null
|
|
34
|
+
|
|
35
|
+
const timeoutPromise = new Promise<T>((resolve) => {
|
|
36
|
+
timeoutId = setTimeout(() => {
|
|
37
|
+
resolve(timeoutValue)
|
|
38
|
+
}, timeoutMs)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
42
|
+
if (timeoutId) {
|
|
43
|
+
clearTimeout(timeoutId)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if the current terminal supports OSC color queries
|
|
50
|
+
*/
|
|
51
|
+
export function terminalSupportsOSC(
|
|
52
|
+
env: CliEnv = getCliEnv(),
|
|
53
|
+
): boolean {
|
|
54
|
+
const term = env.TERM || ''
|
|
55
|
+
const termProgram = env.TERM_PROGRAM || ''
|
|
56
|
+
|
|
57
|
+
// Known compatible terminals
|
|
58
|
+
const supportedPrograms = [
|
|
59
|
+
'iTerm.app',
|
|
60
|
+
'Apple_Terminal',
|
|
61
|
+
'WezTerm',
|
|
62
|
+
'Alacritty',
|
|
63
|
+
'kitty',
|
|
64
|
+
'Ghostty',
|
|
65
|
+
'vscode',
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
if (supportedPrograms.some((p) => termProgram.includes(p))) {
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const supportedTerms = [
|
|
73
|
+
'xterm-256color',
|
|
74
|
+
'xterm-kitty',
|
|
75
|
+
'alacritty',
|
|
76
|
+
'wezterm',
|
|
77
|
+
'ghostty',
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
if (supportedTerms.some((t) => term.includes(t))) {
|
|
81
|
+
return true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if we have a TTY
|
|
85
|
+
return process.stdin.isTTY === true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Build OSC query string
|
|
90
|
+
* @param oscCode - The OSC code (10 for foreground, 11 for background)
|
|
91
|
+
*/
|
|
92
|
+
function buildOscQuery(oscCode: number): string {
|
|
93
|
+
return `\x1b]${oscCode};?\x07`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Query the terminal for OSC color information.
|
|
98
|
+
*
|
|
99
|
+
* IMPORTANT: This function reads from stdin because OSC responses come through
|
|
100
|
+
* the PTY which appears on stdin. This means it MUST be run BEFORE any other
|
|
101
|
+
* stdin listeners (like OpenTUI) are attached. OSC detection runs at the very
|
|
102
|
+
* start of main() in index.tsx, before OpenTUI is initialized.
|
|
103
|
+
*
|
|
104
|
+
* @param ttyPath - Path to TTY for writing the query
|
|
105
|
+
* @param query - The OSC query string to send
|
|
106
|
+
* @returns The raw response string or null if query failed
|
|
107
|
+
*/
|
|
108
|
+
async function sendOscQuery(
|
|
109
|
+
ttyPath: string,
|
|
110
|
+
query: string,
|
|
111
|
+
): Promise<string | null> {
|
|
112
|
+
return new Promise((resolve) => {
|
|
113
|
+
// Guard: Must have TTY for both reading and writing
|
|
114
|
+
if (!process.stdin.isTTY) {
|
|
115
|
+
resolve(null)
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let ttyWriteFd: number | null = null
|
|
120
|
+
let timeoutId: NodeJS.Timeout | null = null
|
|
121
|
+
let resolved = false
|
|
122
|
+
let response = ''
|
|
123
|
+
let wasRawMode = false
|
|
124
|
+
let dataHandler: ((data: Buffer) => void) | null = null
|
|
125
|
+
|
|
126
|
+
const cleanup = () => {
|
|
127
|
+
if (resolved) return
|
|
128
|
+
resolved = true
|
|
129
|
+
|
|
130
|
+
if (timeoutId) {
|
|
131
|
+
clearTimeout(timeoutId)
|
|
132
|
+
timeoutId = null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Remove data handler from stdin
|
|
136
|
+
if (dataHandler) {
|
|
137
|
+
process.stdin.removeListener('data', dataHandler)
|
|
138
|
+
dataHandler = null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Restore raw mode state
|
|
142
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
143
|
+
try {
|
|
144
|
+
process.stdin.setRawMode(wasRawMode)
|
|
145
|
+
} catch {
|
|
146
|
+
// Ignore errors restoring raw mode
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Pause stdin so we leave it non-flowing before other listeners attach
|
|
151
|
+
try {
|
|
152
|
+
process.stdin.pause()
|
|
153
|
+
} catch {
|
|
154
|
+
// Ignore pause errors
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Close TTY write fd
|
|
158
|
+
if (ttyWriteFd !== null) {
|
|
159
|
+
try {
|
|
160
|
+
closeSync(ttyWriteFd)
|
|
161
|
+
} catch {
|
|
162
|
+
// Ignore close errors
|
|
163
|
+
}
|
|
164
|
+
ttyWriteFd = null
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const resolveWith = (value: string | null) => {
|
|
169
|
+
if (resolved) return
|
|
170
|
+
cleanup()
|
|
171
|
+
resolve(value)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
// Open TTY for writing the query
|
|
176
|
+
try {
|
|
177
|
+
ttyWriteFd = openSync(ttyPath, constants.O_WRONLY)
|
|
178
|
+
} catch {
|
|
179
|
+
resolveWith(null)
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Save current raw mode state and enable raw mode to capture escape sequences.
|
|
184
|
+
// Without raw mode, the terminal buffers input line-by-line and OSC responses
|
|
185
|
+
// (which don't end with newlines) would never be delivered.
|
|
186
|
+
wasRawMode = process.stdin.isRaw ?? false
|
|
187
|
+
if (process.stdin.setRawMode) {
|
|
188
|
+
try {
|
|
189
|
+
process.stdin.setRawMode(true)
|
|
190
|
+
} catch {
|
|
191
|
+
// Continue anyway - some terminals might work without raw mode
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Set up timeout
|
|
196
|
+
timeoutId = setTimeout(() => {
|
|
197
|
+
resolveWith(response.length > 0 ? response : null)
|
|
198
|
+
}, OSC_QUERY_TIMEOUT_MS)
|
|
199
|
+
|
|
200
|
+
// Set up event-based reading from stdin.
|
|
201
|
+
// OSC responses come through the PTY which appears on stdin.
|
|
202
|
+
dataHandler = (data: Buffer) => {
|
|
203
|
+
if (resolved) return
|
|
204
|
+
|
|
205
|
+
const chunk = data.toString('utf8')
|
|
206
|
+
response += chunk
|
|
207
|
+
|
|
208
|
+
// Check for complete response
|
|
209
|
+
const hasBEL = response.includes('\x07')
|
|
210
|
+
const hasST = response.includes('\x1b\\')
|
|
211
|
+
const hasRGB =
|
|
212
|
+
/rgb:[0-9a-fA-F]{2,4}\/[0-9a-fA-F]{2,4}\/[0-9a-fA-F]{2,4}/.test(
|
|
213
|
+
response,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
// A complete response has RGB data AND a terminator (BEL or ST)
|
|
217
|
+
// Some terminals might send RGB without proper terminator, so we accept that too
|
|
218
|
+
if (hasRGB && (hasBEL || hasST || response.length > 30)) {
|
|
219
|
+
resolveWith(response)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
process.stdin.on('data', dataHandler)
|
|
224
|
+
process.stdin.resume()
|
|
225
|
+
|
|
226
|
+
// Write the OSC query to TTY
|
|
227
|
+
try {
|
|
228
|
+
writeSync(ttyWriteFd, query)
|
|
229
|
+
} catch {
|
|
230
|
+
resolveWith(null)
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
} catch {
|
|
234
|
+
resolveWith(null)
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Query terminal for OSC color
|
|
241
|
+
*/
|
|
242
|
+
export async function queryTerminalOSC(
|
|
243
|
+
oscCode: number,
|
|
244
|
+
): Promise<string | null> {
|
|
245
|
+
const ttyPath = process.platform === 'win32' ? 'CON' : '/dev/tty'
|
|
246
|
+
const query = buildOscQuery(oscCode)
|
|
247
|
+
return sendOscQuery(ttyPath, query)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Parse RGB values from OSC response
|
|
252
|
+
* @param response - The raw OSC response string
|
|
253
|
+
* @returns RGB tuple [r, g, b] normalized to 0-255, or null if parsing failed
|
|
254
|
+
*/
|
|
255
|
+
export function parseOSCResponse(
|
|
256
|
+
response: string,
|
|
257
|
+
): [number, number, number] | null {
|
|
258
|
+
// Extract RGB values from response
|
|
259
|
+
const match = response.match(
|
|
260
|
+
/rgb:([0-9a-fA-F]{2,4})\/([0-9a-fA-F]{2,4})\/([0-9a-fA-F]{2,4})/,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
if (!match) return null
|
|
264
|
+
|
|
265
|
+
const [, rHex, gHex, bHex] = match
|
|
266
|
+
if (!rHex || !gHex || !bHex) return null
|
|
267
|
+
|
|
268
|
+
// Convert hex to decimal
|
|
269
|
+
let r = parseInt(rHex, 16)
|
|
270
|
+
let g = parseInt(gHex, 16)
|
|
271
|
+
let b = parseInt(bHex, 16)
|
|
272
|
+
|
|
273
|
+
// Normalize 16-bit (4 hex digits) to 8-bit
|
|
274
|
+
if (rHex.length === 4) {
|
|
275
|
+
r = Math.floor(r / 257)
|
|
276
|
+
g = Math.floor(g / 257)
|
|
277
|
+
b = Math.floor(b / 257)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return [r, g, b]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const XTERM_COLOR_STEPS = [0, 95, 135, 175, 215, 255]
|
|
284
|
+
const ANSI_16_COLORS: [number, number, number][] = [
|
|
285
|
+
[0, 0, 0],
|
|
286
|
+
[205, 0, 0],
|
|
287
|
+
[0, 205, 0],
|
|
288
|
+
[205, 205, 0],
|
|
289
|
+
[0, 0, 238],
|
|
290
|
+
[205, 0, 205],
|
|
291
|
+
[0, 205, 205],
|
|
292
|
+
[229, 229, 229],
|
|
293
|
+
[127, 127, 127],
|
|
294
|
+
[255, 0, 0],
|
|
295
|
+
[0, 255, 0],
|
|
296
|
+
[255, 255, 0],
|
|
297
|
+
[92, 92, 255],
|
|
298
|
+
[255, 0, 255],
|
|
299
|
+
[0, 255, 255],
|
|
300
|
+
[255, 255, 255],
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
function xtermColorToRGB(index: number): [number, number, number] | null {
|
|
304
|
+
if (!Number.isFinite(index) || index < 0) {
|
|
305
|
+
return null
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (index < ANSI_16_COLORS.length) {
|
|
309
|
+
return ANSI_16_COLORS[index]
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (index >= 16 && index <= 231) {
|
|
313
|
+
const base = index - 16
|
|
314
|
+
const r = Math.floor(base / 36)
|
|
315
|
+
const g = Math.floor((base % 36) / 6)
|
|
316
|
+
const b = base % 6
|
|
317
|
+
return [
|
|
318
|
+
XTERM_COLOR_STEPS[r] ?? 0,
|
|
319
|
+
XTERM_COLOR_STEPS[g] ?? 0,
|
|
320
|
+
XTERM_COLOR_STEPS[b] ?? 0,
|
|
321
|
+
]
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (index >= 232 && index <= 255) {
|
|
325
|
+
const level = 8 + (index - 232) * 10
|
|
326
|
+
return [level, level, level]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return null
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function detectBgColorFromEnv(
|
|
333
|
+
env: CliEnv = getCliEnv(),
|
|
334
|
+
): [number, number, number] | null {
|
|
335
|
+
const termBackground = env.TERM_BACKGROUND?.toLowerCase()
|
|
336
|
+
if (termBackground === 'dark') {
|
|
337
|
+
return [0, 0, 0]
|
|
338
|
+
}
|
|
339
|
+
if (termBackground === 'light') {
|
|
340
|
+
return [255, 255, 255]
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const colorFgBg = env.COLORFGBG
|
|
344
|
+
if (!colorFgBg) return null
|
|
345
|
+
|
|
346
|
+
const parts = colorFgBg
|
|
347
|
+
.split(';')
|
|
348
|
+
.map((part) => parseInt(part, 10))
|
|
349
|
+
.filter((value) => Number.isFinite(value))
|
|
350
|
+
|
|
351
|
+
if (parts.length === 0) {
|
|
352
|
+
return null
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const bgIndex = parts[parts.length - 1]
|
|
356
|
+
return xtermColorToRGB(bgIndex)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Calculate brightness using ITU-R BT.709 luminance formula
|
|
361
|
+
* @param rgb - RGB tuple [r, g, b] in 0-255 range
|
|
362
|
+
* @returns Brightness value 0-255
|
|
363
|
+
*/
|
|
364
|
+
export function calculateBrightness([r, g, b]: [
|
|
365
|
+
number,
|
|
366
|
+
number,
|
|
367
|
+
number,
|
|
368
|
+
]): number {
|
|
369
|
+
// Relative luminance coefficients (ITU-R BT.709)
|
|
370
|
+
const LUMINANCE_RED = 0.2126
|
|
371
|
+
const LUMINANCE_GREEN = 0.7152
|
|
372
|
+
const LUMINANCE_BLUE = 0.0722
|
|
373
|
+
|
|
374
|
+
return Math.floor(
|
|
375
|
+
LUMINANCE_RED * r + LUMINANCE_GREEN * g + LUMINANCE_BLUE * b,
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Determine theme from background color
|
|
381
|
+
* @param rgb - RGB tuple [r, g, b]
|
|
382
|
+
* @returns 'dark' if background is dark, 'light' if background is light
|
|
383
|
+
*/
|
|
384
|
+
export function themeFromBgColor(
|
|
385
|
+
rgb: [number, number, number],
|
|
386
|
+
): 'dark' | 'light' {
|
|
387
|
+
const brightness = calculateBrightness(rgb)
|
|
388
|
+
const THRESHOLD = 128 // Middle of 0-255 range
|
|
389
|
+
|
|
390
|
+
return brightness > THRESHOLD ? 'light' : 'dark'
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Determine theme from foreground color (inverted logic)
|
|
395
|
+
* @param rgb - RGB tuple [r, g, b]
|
|
396
|
+
* @returns 'dark' if foreground is bright (dark background), 'light' if foreground is dark
|
|
397
|
+
*/
|
|
398
|
+
export function themeFromFgColor(
|
|
399
|
+
rgb: [number, number, number],
|
|
400
|
+
): 'dark' | 'light' {
|
|
401
|
+
const brightness = calculateBrightness(rgb)
|
|
402
|
+
// Bright foreground = dark background theme
|
|
403
|
+
return brightness > 128 ? 'dark' : 'light'
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Core detection logic without any timeout wrapping
|
|
408
|
+
* This is the actual detection implementation
|
|
409
|
+
*/
|
|
410
|
+
async function detectTerminalThemeCore(
|
|
411
|
+
env: CliEnv = getCliEnv(),
|
|
412
|
+
): Promise<'dark' | 'light' | null> {
|
|
413
|
+
// Check if terminal supports OSC
|
|
414
|
+
if (!terminalSupportsOSC(env)) {
|
|
415
|
+
return null
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Try background color first (OSC 11) - more reliable
|
|
419
|
+
const bgResponse = await queryTerminalOSC(11)
|
|
420
|
+
if (bgResponse) {
|
|
421
|
+
const bgRgb = parseOSCResponse(bgResponse)
|
|
422
|
+
if (bgRgb) {
|
|
423
|
+
return themeFromBgColor(bgRgb)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Fallback to foreground color (OSC 10)
|
|
428
|
+
const fgResponse = await queryTerminalOSC(10)
|
|
429
|
+
if (fgResponse) {
|
|
430
|
+
const fgRgb = parseOSCResponse(fgResponse)
|
|
431
|
+
if (fgRgb) {
|
|
432
|
+
return themeFromFgColor(fgRgb)
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Fallback to COLORFGBG environment variable if available
|
|
437
|
+
const envBgRgb = detectBgColorFromEnv(env)
|
|
438
|
+
if (envBgRgb) {
|
|
439
|
+
return themeFromBgColor(envBgRgb)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return null
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Detect terminal theme by querying OSC 10/11
|
|
447
|
+
* Wrapped with a global timeout to prevent hanging
|
|
448
|
+
* @returns 'dark', 'light', or null if detection failed
|
|
449
|
+
*/
|
|
450
|
+
export async function detectTerminalTheme(): Promise<'dark' | 'light' | null> {
|
|
451
|
+
try {
|
|
452
|
+
return await withTimeout(
|
|
453
|
+
detectTerminalThemeCore(),
|
|
454
|
+
GLOBAL_OSC_TIMEOUT_MS,
|
|
455
|
+
null,
|
|
456
|
+
)
|
|
457
|
+
} catch {
|
|
458
|
+
return null
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Get the global OSC timeout value (for testing/debugging)
|
|
464
|
+
*/
|
|
465
|
+
export function getGlobalOscTimeout(): number {
|
|
466
|
+
return GLOBAL_OSC_TIMEOUT_MS
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Get the per-query OSC timeout value (for testing/debugging)
|
|
471
|
+
*/
|
|
472
|
+
export function getQueryOscTimeout(): number {
|
|
473
|
+
return OSC_QUERY_TIMEOUT_MS
|
|
474
|
+
}
|