nastech-tui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +11 -0
- package/README.md +346 -0
- package/eslint.config.mjs +111 -0
- package/package.json +51 -0
- package/packages/nastech-ink/ambient.d.ts +83 -0
- package/packages/nastech-ink/index.d.ts +40 -0
- package/packages/nastech-ink/index.js +1 -0
- package/packages/nastech-ink/nastech-ink/ambient.d.ts +83 -0
- package/packages/nastech-ink/nastech-ink/index.d.ts +40 -0
- package/packages/nastech-ink/nastech-ink/index.js +1 -0
- package/packages/nastech-ink/nastech-ink/package.json +54 -0
- package/packages/nastech-ink/nastech-ink/src/bootstrap/state.ts +9 -0
- package/packages/nastech-ink/nastech-ink/src/entry-exports.ts +32 -0
- package/packages/nastech-ink/nastech-ink/src/hooks/use-stderr.ts +15 -0
- package/packages/nastech-ink/nastech-ink/src/hooks/use-stdout.ts +15 -0
- package/packages/nastech-ink/nastech-ink/src/ink/Ansi.tsx +435 -0
- package/packages/nastech-ink/nastech-ink/src/ink/app-mouse.test.ts +123 -0
- package/packages/nastech-ink/nastech-ink/src/ink/bidi.ts +145 -0
- package/packages/nastech-ink/nastech-ink/src/ink/cache-eviction.ts +45 -0
- package/packages/nastech-ink/nastech-ink/src/ink/clearTerminal.ts +68 -0
- package/packages/nastech-ink/nastech-ink/src/ink/colorize.test.ts +60 -0
- package/packages/nastech-ink/nastech-ink/src/ink/colorize.ts +277 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/App.tsx +830 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/AppContext.ts +20 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Box.tsx +294 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Button.tsx +236 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Link.tsx +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Newline.tsx +43 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Spacer.tsx +23 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/StdinContext.ts +25 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Text.test.ts +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Text.tsx +336 -0
- package/packages/nastech-ink/nastech-ink/src/ink/constants.ts +6 -0
- package/packages/nastech-ink/nastech-ink/src/ink/cursor.ts +5 -0
- package/packages/nastech-ink/nastech-ink/src/ink/devtools.ts +2 -0
- package/packages/nastech-ink/nastech-ink/src/ink/dom.ts +495 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/click-event.ts +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/dispatcher.ts +242 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/emitter.ts +40 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/event-handlers.ts +84 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/event.ts +11 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/focus-event.ts +18 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/input-event.ts +176 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/mouse-event.ts +18 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/paste-event.ts +10 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/resize-event.ts +12 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-event.ts +107 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
- package/packages/nastech-ink/nastech-ink/src/ink/focus.ts +219 -0
- package/packages/nastech-ink/nastech-ink/src/ink/frame.ts +124 -0
- package/packages/nastech-ink/nastech-ink/src/ink/get-max-width.ts +27 -0
- package/packages/nastech-ink/nastech-ink/src/ink/global.d.ts +1 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hit-test.test.ts +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hit-test.ts +224 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-app.ts +9 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-input.ts +95 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
- package/packages/nastech-ink/package.json +57 -0
- package/packages/nastech-ink/src/bootstrap/state.ts +9 -0
- package/packages/nastech-ink/src/entry-exports.ts +32 -0
- package/packages/nastech-ink/src/hooks/use-stderr.ts +15 -0
- package/packages/nastech-ink/src/hooks/use-stdout.ts +15 -0
- package/packages/nastech-ink/src/ink/Ansi.tsx +435 -0
- package/packages/nastech-ink/src/ink/app-mouse.test.ts +123 -0
- package/packages/nastech-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
- package/packages/nastech-ink/src/ink/bidi.ts +145 -0
- package/packages/nastech-ink/src/ink/cache-eviction.ts +45 -0
- package/packages/nastech-ink/src/ink/clearTerminal.ts +68 -0
- package/packages/nastech-ink/src/ink/colorize.test.ts +60 -0
- package/packages/nastech-ink/src/ink/colorize.ts +277 -0
- package/packages/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
- package/packages/nastech-ink/src/ink/components/App.tsx +855 -0
- package/packages/nastech-ink/src/ink/components/AppContext.ts +20 -0
- package/packages/nastech-ink/src/ink/components/Box.tsx +294 -0
- package/packages/nastech-ink/src/ink/components/Button.tsx +236 -0
- package/packages/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
- package/packages/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
- package/packages/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
- package/packages/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
- package/packages/nastech-ink/src/ink/components/Link.tsx +38 -0
- package/packages/nastech-ink/src/ink/components/Newline.tsx +43 -0
- package/packages/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
- package/packages/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
- package/packages/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
- package/packages/nastech-ink/src/ink/components/Spacer.tsx +23 -0
- package/packages/nastech-ink/src/ink/components/StdinContext.ts +25 -0
- package/packages/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
- package/packages/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
- package/packages/nastech-ink/src/ink/components/Text.test.ts +38 -0
- package/packages/nastech-ink/src/ink/components/Text.tsx +336 -0
- package/packages/nastech-ink/src/ink/constants.ts +6 -0
- package/packages/nastech-ink/src/ink/cursor.ts +5 -0
- package/packages/nastech-ink/src/ink/devtools.ts +2 -0
- package/packages/nastech-ink/src/ink/dom.ts +495 -0
- package/packages/nastech-ink/src/ink/events/click-event.ts +38 -0
- package/packages/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
- package/packages/nastech-ink/src/ink/events/dispatcher.ts +242 -0
- package/packages/nastech-ink/src/ink/events/emitter.ts +40 -0
- package/packages/nastech-ink/src/ink/events/event-handlers.ts +84 -0
- package/packages/nastech-ink/src/ink/events/event.ts +11 -0
- package/packages/nastech-ink/src/ink/events/focus-event.ts +18 -0
- package/packages/nastech-ink/src/ink/events/input-event.ts +176 -0
- package/packages/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
- package/packages/nastech-ink/src/ink/events/mouse-event.ts +18 -0
- package/packages/nastech-ink/src/ink/events/paste-event.ts +10 -0
- package/packages/nastech-ink/src/ink/events/resize-event.ts +12 -0
- package/packages/nastech-ink/src/ink/events/terminal-event.ts +107 -0
- package/packages/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
- package/packages/nastech-ink/src/ink/focus.ts +219 -0
- package/packages/nastech-ink/src/ink/frame.ts +124 -0
- package/packages/nastech-ink/src/ink/get-max-width.ts +27 -0
- package/packages/nastech-ink/src/ink/global.d.ts +1 -0
- package/packages/nastech-ink/src/ink/hit-test.test.ts +38 -0
- package/packages/nastech-ink/src/ink/hit-test.ts +224 -0
- package/packages/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
- package/packages/nastech-ink/src/ink/hooks/use-app.ts +9 -0
- package/packages/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
- package/packages/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
- package/packages/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
- package/packages/nastech-ink/src/ink/hooks/use-input.ts +95 -0
- package/packages/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
- package/packages/nastech-ink/src/ink/hooks/use-search-highlight.ts +56 -0
- package/packages/nastech-ink/src/ink/hooks/use-selection.ts +101 -0
- package/packages/nastech-ink/src/ink/hooks/use-stdin.ts +9 -0
- package/packages/nastech-ink/src/ink/hooks/use-tab-status.ts +71 -0
- package/packages/nastech-ink/src/ink/hooks/use-terminal-focus.ts +18 -0
- package/packages/nastech-ink/src/ink/hooks/use-terminal-title.ts +34 -0
- package/packages/nastech-ink/src/ink/hooks/use-terminal-viewport.ts +100 -0
- package/packages/nastech-ink/src/ink/hyperlinkHover.ts +52 -0
- package/packages/nastech-ink/src/ink/ink-cursor-advance.test.ts +234 -0
- package/packages/nastech-ink/src/ink/ink-resize.test.ts +50 -0
- package/packages/nastech-ink/src/ink/ink.tsx +2705 -0
- package/packages/nastech-ink/src/ink/instances.ts +10 -0
- package/packages/nastech-ink/src/ink/layout/engine.ts +6 -0
- package/packages/nastech-ink/src/ink/layout/geometry.ts +98 -0
- package/packages/nastech-ink/src/ink/layout/node.ts +145 -0
- package/packages/nastech-ink/src/ink/layout/yoga.ts +313 -0
- package/packages/nastech-ink/src/ink/line-width-cache.ts +38 -0
- package/packages/nastech-ink/src/ink/log-update.test.ts +223 -0
- package/packages/nastech-ink/src/ink/log-update.ts +752 -0
- package/packages/nastech-ink/src/ink/lru.ts +14 -0
- package/packages/nastech-ink/src/ink/measure-element.ts +23 -0
- package/packages/nastech-ink/src/ink/measure-text.ts +50 -0
- package/packages/nastech-ink/src/ink/node-cache.ts +53 -0
- package/packages/nastech-ink/src/ink/optimizer.ts +99 -0
- package/packages/nastech-ink/src/ink/output.ts +845 -0
- package/packages/nastech-ink/src/ink/parse-keypress.test.ts +133 -0
- package/packages/nastech-ink/src/ink/parse-keypress.ts +848 -0
- package/packages/nastech-ink/src/ink/reconciler.ts +382 -0
- package/packages/nastech-ink/src/ink/render-border.ts +206 -0
- package/packages/nastech-ink/src/ink/render-node-to-output.ts +1582 -0
- package/packages/nastech-ink/src/ink/render-to-screen.ts +236 -0
- package/packages/nastech-ink/src/ink/renderer.ts +169 -0
- package/packages/nastech-ink/src/ink/root.ts +204 -0
- package/packages/nastech-ink/src/ink/screen.ts +1590 -0
- package/packages/nastech-ink/src/ink/searchHighlight.ts +91 -0
- package/packages/nastech-ink/src/ink/selection.test.ts +82 -0
- package/packages/nastech-ink/src/ink/selection.ts +1143 -0
- package/packages/nastech-ink/src/ink/squash-text-nodes.ts +74 -0
- package/packages/nastech-ink/src/ink/stringWidth.ts +341 -0
- package/packages/nastech-ink/src/ink/styles.ts +750 -0
- package/packages/nastech-ink/src/ink/supports-hyperlinks.ts +51 -0
- package/packages/nastech-ink/src/ink/tabstops.ts +44 -0
- package/packages/nastech-ink/src/ink/terminal-focus-state.ts +52 -0
- package/packages/nastech-ink/src/ink/terminal-querier.ts +222 -0
- package/packages/nastech-ink/src/ink/terminal.test.ts +15 -0
- package/packages/nastech-ink/src/ink/terminal.ts +299 -0
- package/packages/nastech-ink/src/ink/termio/ansi.ts +75 -0
- package/packages/nastech-ink/src/ink/termio/csi.ts +334 -0
- package/packages/nastech-ink/src/ink/termio/dec.ts +99 -0
- package/packages/nastech-ink/src/ink/termio/esc.ts +69 -0
- package/packages/nastech-ink/src/ink/termio/osc.test.ts +191 -0
- package/packages/nastech-ink/src/ink/termio/osc.ts +724 -0
- package/packages/nastech-ink/src/ink/termio/parser.ts +467 -0
- package/packages/nastech-ink/src/ink/termio/sgr.ts +362 -0
- package/packages/nastech-ink/src/ink/termio/tokenize.test.ts +185 -0
- package/packages/nastech-ink/src/ink/termio/tokenize.ts +350 -0
- package/packages/nastech-ink/src/ink/termio/types.ts +230 -0
- package/packages/nastech-ink/src/ink/termio.ts +42 -0
- package/packages/nastech-ink/src/ink/useTerminalNotification.ts +110 -0
- package/packages/nastech-ink/src/ink/warn.ts +15 -0
- package/packages/nastech-ink/src/ink/widest-line.ts +22 -0
- package/packages/nastech-ink/src/ink/wrap-text.test.ts +17 -0
- package/packages/nastech-ink/src/ink/wrap-text.ts +144 -0
- package/packages/nastech-ink/src/ink/wrapAnsi.ts +13 -0
- package/packages/nastech-ink/src/native-ts/yoga-layout/enums.ts +112 -0
- package/packages/nastech-ink/src/native-ts/yoga-layout/index.ts +2326 -0
- package/packages/nastech-ink/src/utils/debug.ts +6 -0
- package/packages/nastech-ink/src/utils/earlyInput.ts +131 -0
- package/packages/nastech-ink/src/utils/env.ts +66 -0
- package/packages/nastech-ink/src/utils/envUtils.ts +13 -0
- package/packages/nastech-ink/src/utils/execFileNoThrow.test.ts +146 -0
- package/packages/nastech-ink/src/utils/execFileNoThrow.ts +115 -0
- package/packages/nastech-ink/src/utils/fullscreen.ts +3 -0
- package/packages/nastech-ink/src/utils/intl.ts +87 -0
- package/packages/nastech-ink/src/utils/log.ts +7 -0
- package/packages/nastech-ink/src/utils/semver.ts +57 -0
- package/packages/nastech-ink/src/utils/sliceAnsi.ts +106 -0
- package/packages/nastech-ink/text-input.d.ts +2 -0
- package/packages/nastech-ink/text-input.js +1 -0
- package/scripts/build.mjs +61 -0
- package/scripts/profile-tui.mjs +121 -0
- package/src/__tests__/activeSessionSwitcher.test.ts +157 -0
- package/src/__tests__/appChromeStatusRule.test.tsx +84 -0
- package/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
- package/src/__tests__/approvalAction.test.ts +50 -0
- package/src/__tests__/asCommandDispatch.test.ts +27 -0
- package/src/__tests__/blockLayout.test.ts +122 -0
- package/src/__tests__/clipboard.test.ts +369 -0
- package/src/__tests__/constants.test.ts +53 -0
- package/src/__tests__/createGatewayEventHandler.test.ts +1091 -0
- package/src/__tests__/createSlashHandler.test.ts +822 -0
- package/src/__tests__/creditsCommand.test.ts +144 -0
- package/src/__tests__/cursorDriftRegression.test.ts +114 -0
- package/src/__tests__/details.test.ts +115 -0
- package/src/__tests__/emoji.test.ts +64 -0
- package/src/__tests__/externalLink.test.ts +144 -0
- package/src/__tests__/forceTruecolor.test.ts +191 -0
- package/src/__tests__/gatewayClient.test.ts +394 -0
- package/src/__tests__/gatewayRecovery.test.ts +47 -0
- package/src/__tests__/markdown.test.ts +331 -0
- package/src/__tests__/mathUnicode.test.ts +293 -0
- package/src/__tests__/memoryMonitor.test.ts +102 -0
- package/src/__tests__/messageLine.test.ts +19 -0
- package/src/__tests__/messages.test.ts +92 -0
- package/src/__tests__/orchestratorPromptSession.test.ts +64 -0
- package/src/__tests__/osc52.test.ts +67 -0
- package/src/__tests__/parentLog.test.ts +75 -0
- package/src/__tests__/paths.test.ts +70 -0
- package/src/__tests__/platform.test.ts +556 -0
- package/src/__tests__/precisionWheel.test.ts +44 -0
- package/src/__tests__/prompt.test.ts +31 -0
- package/src/__tests__/providers.test.ts +65 -0
- package/src/__tests__/reasoning.test.ts +76 -0
- package/src/__tests__/rpc.test.ts +27 -0
- package/src/__tests__/scroll.test.ts +99 -0
- package/src/__tests__/slashParity.test.ts +123 -0
- package/src/__tests__/spawnHistoryStore.test.ts +46 -0
- package/src/__tests__/stateIsolation.test.ts +46 -0
- package/src/__tests__/statusBarTicker.test.ts +18 -0
- package/src/__tests__/statusRule.test.ts +32 -0
- package/src/__tests__/streamingMarkdown.test.ts +121 -0
- package/src/__tests__/subagentTree.test.ts +407 -0
- package/src/__tests__/syntax.test.ts +45 -0
- package/src/__tests__/terminalModes.test.ts +39 -0
- package/src/__tests__/terminalParity.test.ts +77 -0
- package/src/__tests__/terminalSetup.test.ts +386 -0
- package/src/__tests__/termux.test.ts +35 -0
- package/src/__tests__/termuxComposerLayout.test.ts +40 -0
- package/src/__tests__/text.test.ts +233 -0
- package/src/__tests__/textInputBurstInput.test.ts +40 -0
- package/src/__tests__/textInputCursorSourceOfTruth.test.ts +50 -0
- package/src/__tests__/textInputFastEcho.test.ts +200 -0
- package/src/__tests__/textInputLineNav.test.ts +55 -0
- package/src/__tests__/textInputPassThrough.test.ts +59 -0
- package/src/__tests__/textInputRightClick.test.ts +48 -0
- package/src/__tests__/textInputWrap.test.ts +151 -0
- package/src/__tests__/theme.test.ts +311 -0
- package/src/__tests__/turnControllerNotice.test.ts +43 -0
- package/src/__tests__/turnStore.test.ts +66 -0
- package/src/__tests__/useCompletion.test.ts +35 -0
- package/src/__tests__/useComposerState.test.ts +59 -0
- package/src/__tests__/useConfigSync.test.ts +460 -0
- package/src/__tests__/useInputHandlers.test.ts +77 -0
- package/src/__tests__/useQueue.test.ts +28 -0
- package/src/__tests__/useSessionLifecycle.test.ts +60 -0
- package/src/__tests__/useVirtualHistoryHeights.test.ts +39 -0
- package/src/__tests__/viewport.test.ts +58 -0
- package/src/__tests__/viewportStore.test.ts +85 -0
- package/src/__tests__/virtualHeights.test.ts +96 -0
- package/src/__tests__/virtualHistoryClamp.test.ts +19 -0
- package/src/__tests__/virtualHistoryOffsetCache.test.ts +282 -0
- package/src/__tests__/wheelAccel.test.ts +138 -0
- package/src/app/createGatewayEventHandler.ts +833 -0
- package/src/app/createSlashHandler.ts +130 -0
- package/src/app/delegationStore.ts +77 -0
- package/src/app/gatewayContext.tsx +19 -0
- package/src/app/gatewayRecovery.ts +35 -0
- package/src/app/inputSelectionStore.ts +15 -0
- package/src/app/interfaces.ts +394 -0
- package/src/app/overlayStore.ts +53 -0
- package/src/app/scroll.ts +71 -0
- package/src/app/setupHandoff.ts +54 -0
- package/src/app/slash/commands/core.ts +648 -0
- package/src/app/slash/commands/credits.ts +57 -0
- package/src/app/slash/commands/debug.ts +48 -0
- package/src/app/slash/commands/ops.ts +717 -0
- package/src/app/slash/commands/session.ts +554 -0
- package/src/app/slash/commands/setup.ts +20 -0
- package/src/app/slash/registry.ts +20 -0
- package/src/app/slash/types.ts +21 -0
- package/src/app/spawnHistoryStore.ts +159 -0
- package/src/app/turnController.ts +866 -0
- package/src/app/turnStore.ts +85 -0
- package/src/app/uiStore.ts +44 -0
- package/src/app/useComposerState.ts +367 -0
- package/src/app/useConfigSync.ts +288 -0
- package/src/app/useInputHandlers.ts +576 -0
- package/src/app/useLongRunToolCharms.ts +69 -0
- package/src/app/useMainApp.ts +1039 -0
- package/src/app/useSessionLifecycle.ts +366 -0
- package/src/app/useSubmission.ts +429 -0
- package/src/app.tsx +25 -0
- package/src/banner.ts +93 -0
- package/src/components/activeSessionSwitcher.tsx +635 -0
- package/src/components/agentsOverlay.tsx +1073 -0
- package/src/components/appChrome.tsx +554 -0
- package/src/components/appLayout.tsx +444 -0
- package/src/components/appOverlays.tsx +254 -0
- package/src/components/branding.tsx +466 -0
- package/src/components/fpsOverlay.tsx +30 -0
- package/src/components/helpHint.tsx +73 -0
- package/src/components/markdown.tsx +1119 -0
- package/src/components/maskedPrompt.tsx +34 -0
- package/src/components/messageLine.tsx +237 -0
- package/src/components/modelPicker.tsx +527 -0
- package/src/components/overlayControls.tsx +50 -0
- package/src/components/pluginsHub.tsx +238 -0
- package/src/components/prompts.tsx +276 -0
- package/src/components/queuedMessages.tsx +64 -0
- package/src/components/sessionPicker.tsx +227 -0
- package/src/components/skillsHub.tsx +308 -0
- package/src/components/streamingAssistant.tsx +110 -0
- package/src/components/streamingMarkdown.tsx +174 -0
- package/src/components/textInput.tsx +1340 -0
- package/src/components/themed.tsx +30 -0
- package/src/components/thinking.tsx +1224 -0
- package/src/components/todoPanel.tsx +93 -0
- package/src/config/env.ts +64 -0
- package/src/config/limits.ts +13 -0
- package/src/config/timing.ts +6 -0
- package/src/content/charms.ts +1 -0
- package/src/content/faces.ts +17 -0
- package/src/content/fortunes.ts +30 -0
- package/src/content/hotkeys.ts +37 -0
- package/src/content/placeholders.ts +13 -0
- package/src/content/setup.ts +17 -0
- package/src/content/verbs.ts +38 -0
- package/src/domain/blockLayout.ts +146 -0
- package/src/domain/details.ts +76 -0
- package/src/domain/messages.ts +91 -0
- package/src/domain/paths.ts +16 -0
- package/src/domain/providers.ts +11 -0
- package/src/domain/roles.ts +9 -0
- package/src/domain/slash.ts +10 -0
- package/src/domain/usage.ts +3 -0
- package/src/domain/viewport.ts +51 -0
- package/src/entry.tsx +104 -0
- package/src/gatewayClient.ts +730 -0
- package/src/gatewayTypes.ts +568 -0
- package/src/hooks/useCompletion.ts +112 -0
- package/src/hooks/useGitBranch.ts +72 -0
- package/src/hooks/useInputHistory.ts +11 -0
- package/src/hooks/useQueue.ts +76 -0
- package/src/hooks/useVirtualHistory.ts +554 -0
- package/src/lib/circularBuffer.ts +48 -0
- package/src/lib/clipboard.ts +182 -0
- package/src/lib/editor.test.ts +74 -0
- package/src/lib/editor.ts +47 -0
- package/src/lib/emoji.ts +55 -0
- package/src/lib/externalCli.ts +16 -0
- package/src/lib/externalLink.ts +435 -0
- package/src/lib/forceTruecolor.ts +60 -0
- package/src/lib/fpsStore.ts +51 -0
- package/src/lib/fuzzy.test.ts +109 -0
- package/src/lib/fuzzy.ts +177 -0
- package/src/lib/gracefulExit.ts +47 -0
- package/src/lib/history.ts +82 -0
- package/src/lib/inputMetrics.ts +203 -0
- package/src/lib/liveProgress.test.ts +116 -0
- package/src/lib/liveProgress.ts +79 -0
- package/src/lib/mathUnicode.ts +770 -0
- package/src/lib/memory.test.ts +155 -0
- package/src/lib/memory.ts +188 -0
- package/src/lib/memoryMonitor.ts +109 -0
- package/src/lib/messages.test.ts +29 -0
- package/src/lib/messages.ts +8 -0
- package/src/lib/openExternalUrl.test.ts +217 -0
- package/src/lib/openExternalUrl.ts +158 -0
- package/src/lib/osc52.ts +73 -0
- package/src/lib/parentLog.ts +57 -0
- package/src/lib/perfPane.tsx +107 -0
- package/src/lib/platform.ts +409 -0
- package/src/lib/precisionWheel.ts +48 -0
- package/src/lib/prompt.ts +35 -0
- package/src/lib/reasoning.ts +55 -0
- package/src/lib/rpc.ts +41 -0
- package/src/lib/subagentTree.ts +355 -0
- package/src/lib/syntax.ts +117 -0
- package/src/lib/terminalModes.ts +51 -0
- package/src/lib/terminalParity.ts +78 -0
- package/src/lib/terminalSetup.ts +444 -0
- package/src/lib/termux.ts +29 -0
- package/src/lib/text.test.ts +18 -0
- package/src/lib/text.ts +339 -0
- package/src/lib/todo.test.ts +21 -0
- package/src/lib/todo.ts +9 -0
- package/src/lib/viewportStore.ts +124 -0
- package/src/lib/virtualHeights.ts +145 -0
- package/src/lib/wheelAccel.ts +190 -0
- package/src/protocol/interpolation.ts +3 -0
- package/src/protocol/paste.ts +1 -0
- package/src/theme.ts +589 -0
- package/src/types/nastech-ink.d.ts +176 -0
- package/src/types.ts +212 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Tokenizer - Escape sequence boundary detection
|
|
3
|
+
*
|
|
4
|
+
* Splits terminal input into tokens: text chunks and raw escape sequences.
|
|
5
|
+
* Unlike the Parser which interprets sequences semantically, this just
|
|
6
|
+
* identifies boundaries for use by keyboard input parsing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { C0, ESC_TYPE, isEscFinal } from './ansi.js'
|
|
10
|
+
import { isCSIFinal, isCSIIntermediate, isCSIParam } from './csi.js'
|
|
11
|
+
|
|
12
|
+
export type Token = { type: 'text'; value: string } | { type: 'sequence'; value: string }
|
|
13
|
+
|
|
14
|
+
type State = 'ground' | 'escape' | 'escapeIntermediate' | 'csi' | 'ss3' | 'osc' | 'dcs' | 'apc'
|
|
15
|
+
|
|
16
|
+
export type Tokenizer = {
|
|
17
|
+
/** Feed input and get resulting tokens */
|
|
18
|
+
feed(input: string): Token[]
|
|
19
|
+
/** Flush any buffered incomplete sequences */
|
|
20
|
+
flush(): Token[]
|
|
21
|
+
/** Reset tokenizer state */
|
|
22
|
+
reset(): void
|
|
23
|
+
/** Get any buffered incomplete sequence */
|
|
24
|
+
buffer(): string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type TokenizerOptions = {
|
|
28
|
+
/**
|
|
29
|
+
* Treat `CSI M` as an X10 mouse event prefix and consume 3 payload bytes.
|
|
30
|
+
* Only enable for stdin input — `\x1b[M` is also CSI DL (Delete Lines) in
|
|
31
|
+
* output streams, and enabling this there swallows display text. Default false.
|
|
32
|
+
*/
|
|
33
|
+
x10Mouse?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create a streaming tokenizer for terminal input.
|
|
38
|
+
*
|
|
39
|
+
* Usage:
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const tokenizer = createTokenizer()
|
|
42
|
+
* const tokens1 = tokenizer.feed('hello\x1b[')
|
|
43
|
+
* const tokens2 = tokenizer.feed('A') // completes the escape sequence
|
|
44
|
+
* const remaining = tokenizer.flush() // force output incomplete sequences
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function createTokenizer(options?: TokenizerOptions): Tokenizer {
|
|
48
|
+
let currentState: State = 'ground'
|
|
49
|
+
let currentBuffer = ''
|
|
50
|
+
// The control-sequence buffer kept across the previous flush, if any. Used
|
|
51
|
+
// as a one-tick truncation valve: a partial CSI mouse report normally
|
|
52
|
+
// reassembles on the very next feed, so if a flush sees the exact same
|
|
53
|
+
// buffer it kept last time (the continuation never arrived), we drop it.
|
|
54
|
+
let lastFlushedBuffer = ''
|
|
55
|
+
const x10Mouse = options?.x10Mouse ?? false
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
feed(input: string): Token[] {
|
|
59
|
+
// Real bytes arrived — any kept partial is no longer stale.
|
|
60
|
+
lastFlushedBuffer = ''
|
|
61
|
+
|
|
62
|
+
const result = tokenize(input, currentState, currentBuffer, false, x10Mouse)
|
|
63
|
+
|
|
64
|
+
currentState = result.state.state
|
|
65
|
+
currentBuffer = result.state.buffer
|
|
66
|
+
|
|
67
|
+
return result.tokens
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
flush(): Token[] {
|
|
71
|
+
const result = tokenize('', currentState, currentBuffer, true, x10Mouse)
|
|
72
|
+
currentState = result.state.state
|
|
73
|
+
currentBuffer = result.state.buffer
|
|
74
|
+
|
|
75
|
+
// tokenize() keeps (doesn't emit) an incomplete control sequence on
|
|
76
|
+
// flush. If two consecutive flushes see the same buffer with no feed in
|
|
77
|
+
// between, the continuation is never coming (truncated write / killed
|
|
78
|
+
// process) — drop it so it can't fuse with the next keypress's bytes.
|
|
79
|
+
if (currentBuffer && currentBuffer === lastFlushedBuffer) {
|
|
80
|
+
currentState = 'ground'
|
|
81
|
+
currentBuffer = ''
|
|
82
|
+
lastFlushedBuffer = ''
|
|
83
|
+
} else {
|
|
84
|
+
lastFlushedBuffer = currentBuffer
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result.tokens
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
reset(): void {
|
|
91
|
+
currentState = 'ground'
|
|
92
|
+
currentBuffer = ''
|
|
93
|
+
lastFlushedBuffer = ''
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
buffer(): string {
|
|
97
|
+
return currentBuffer
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type InternalState = {
|
|
103
|
+
state: State
|
|
104
|
+
buffer: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function tokenize(
|
|
108
|
+
input: string,
|
|
109
|
+
initialState: State,
|
|
110
|
+
initialBuffer: string,
|
|
111
|
+
flush: boolean,
|
|
112
|
+
x10Mouse: boolean
|
|
113
|
+
): { tokens: Token[]; state: InternalState } {
|
|
114
|
+
const tokens: Token[] = []
|
|
115
|
+
|
|
116
|
+
const result: InternalState = {
|
|
117
|
+
state: initialState,
|
|
118
|
+
buffer: ''
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const data = initialBuffer + input
|
|
122
|
+
let i = 0
|
|
123
|
+
let textStart = 0
|
|
124
|
+
let seqStart = 0
|
|
125
|
+
|
|
126
|
+
const flushText = (): void => {
|
|
127
|
+
if (i > textStart) {
|
|
128
|
+
const text = data.slice(textStart, i)
|
|
129
|
+
|
|
130
|
+
if (text) {
|
|
131
|
+
tokens.push({ type: 'text', value: text })
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
textStart = i
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const emitSequence = (seq: string): void => {
|
|
139
|
+
if (seq) {
|
|
140
|
+
tokens.push({ type: 'sequence', value: seq })
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
result.state = 'ground'
|
|
144
|
+
textStart = i
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
while (i < data.length) {
|
|
148
|
+
const code = data.charCodeAt(i)
|
|
149
|
+
|
|
150
|
+
switch (result.state) {
|
|
151
|
+
case 'ground':
|
|
152
|
+
if (code === C0.ESC) {
|
|
153
|
+
flushText()
|
|
154
|
+
seqStart = i
|
|
155
|
+
result.state = 'escape'
|
|
156
|
+
i++
|
|
157
|
+
} else {
|
|
158
|
+
i++
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
case 'escape':
|
|
164
|
+
if (code === ESC_TYPE.CSI) {
|
|
165
|
+
result.state = 'csi'
|
|
166
|
+
i++
|
|
167
|
+
} else if (code === ESC_TYPE.OSC) {
|
|
168
|
+
result.state = 'osc'
|
|
169
|
+
i++
|
|
170
|
+
} else if (code === ESC_TYPE.DCS) {
|
|
171
|
+
result.state = 'dcs'
|
|
172
|
+
i++
|
|
173
|
+
} else if (code === ESC_TYPE.APC) {
|
|
174
|
+
result.state = 'apc'
|
|
175
|
+
i++
|
|
176
|
+
} else if (code === 0x4f) {
|
|
177
|
+
// 'O' - SS3
|
|
178
|
+
result.state = 'ss3'
|
|
179
|
+
i++
|
|
180
|
+
} else if (isCSIIntermediate(code)) {
|
|
181
|
+
// Intermediate byte (e.g., ESC ( for charset) - continue buffering
|
|
182
|
+
result.state = 'escapeIntermediate'
|
|
183
|
+
i++
|
|
184
|
+
} else if (isEscFinal(code)) {
|
|
185
|
+
// Two-character escape sequence
|
|
186
|
+
i++
|
|
187
|
+
emitSequence(data.slice(seqStart, i))
|
|
188
|
+
} else if (code === C0.ESC) {
|
|
189
|
+
// Double escape - emit first, start new
|
|
190
|
+
emitSequence(data.slice(seqStart, i))
|
|
191
|
+
seqStart = i
|
|
192
|
+
result.state = 'escape'
|
|
193
|
+
i++
|
|
194
|
+
} else {
|
|
195
|
+
// Invalid - treat ESC as text
|
|
196
|
+
result.state = 'ground'
|
|
197
|
+
textStart = seqStart
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
break
|
|
201
|
+
|
|
202
|
+
case 'escapeIntermediate':
|
|
203
|
+
// After intermediate byte(s), wait for final byte
|
|
204
|
+
if (isCSIIntermediate(code)) {
|
|
205
|
+
// More intermediate bytes
|
|
206
|
+
i++
|
|
207
|
+
} else if (isEscFinal(code)) {
|
|
208
|
+
// Final byte - complete the sequence
|
|
209
|
+
i++
|
|
210
|
+
emitSequence(data.slice(seqStart, i))
|
|
211
|
+
} else {
|
|
212
|
+
// Invalid - treat as text
|
|
213
|
+
result.state = 'ground'
|
|
214
|
+
textStart = seqStart
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
break
|
|
218
|
+
|
|
219
|
+
case 'csi':
|
|
220
|
+
// X10 mouse: CSI M + 3 raw payload bytes (Cb+32, Cx+32, Cy+32).
|
|
221
|
+
// M immediately after [ (offset 2) means no params — SGR mouse
|
|
222
|
+
// (CSI < … M) has a `<` param byte first and reaches M at offset > 2.
|
|
223
|
+
// Terminals that ignore DECSET 1006 but honor 1000/1002 emit this
|
|
224
|
+
// legacy encoding; without this branch the 3 payload bytes leak
|
|
225
|
+
// through as text (`` `rK `` / `arK` garbage in the prompt).
|
|
226
|
+
//
|
|
227
|
+
// Gated on x10Mouse — `\x1b[M` is also CSI DL (Delete Lines) and
|
|
228
|
+
// blindly consuming 3 chars corrupts output rendering (Parser/Ansi)
|
|
229
|
+
// and fragments bracketed-paste PASTE_END. Only stdin enables this.
|
|
230
|
+
// The ≥0x20 check on each payload slot is belt-and-suspenders: X10
|
|
231
|
+
// guarantees Cb≥32, Cx≥33, Cy≥33, so a control byte (ESC=0x1B) in
|
|
232
|
+
// any slot means this is CSI DL adjacent to another sequence, not a
|
|
233
|
+
// mouse event. Checking all three slots prevents PASTE_END's ESC
|
|
234
|
+
// from being consumed when paste content ends in `\x1b[M`+0-2 chars.
|
|
235
|
+
//
|
|
236
|
+
// Known limitation: this counts JS string chars, but X10 is byte-
|
|
237
|
+
// oriented and stdin uses utf8 encoding (App.tsx). At col 162-191 ×
|
|
238
|
+
// row 96-159 the two coord bytes (0xC2-0xDF, 0x80-0xBF) form a valid
|
|
239
|
+
// UTF-8 2-byte sequence and collapse to one char — the length check
|
|
240
|
+
// fails and the event buffers until the next keypress absorbs it.
|
|
241
|
+
// Fixing this requires latin1 stdin; X10's 223-coord cap is exactly
|
|
242
|
+
// why SGR was invented, and no-SGR terminals at 162+ cols are rare.
|
|
243
|
+
if (
|
|
244
|
+
x10Mouse &&
|
|
245
|
+
code === 0x4d /* M */ &&
|
|
246
|
+
i - seqStart === 2 &&
|
|
247
|
+
(i + 1 >= data.length || data.charCodeAt(i + 1) >= 0x20) &&
|
|
248
|
+
(i + 2 >= data.length || data.charCodeAt(i + 2) >= 0x20) &&
|
|
249
|
+
(i + 3 >= data.length || data.charCodeAt(i + 3) >= 0x20)
|
|
250
|
+
) {
|
|
251
|
+
if (i + 4 <= data.length) {
|
|
252
|
+
i += 4
|
|
253
|
+
emitSequence(data.slice(seqStart, i))
|
|
254
|
+
} else {
|
|
255
|
+
// Incomplete — exit loop; end-of-input buffers from seqStart.
|
|
256
|
+
// Re-entry re-tokenizes from ground via the invalid-CSI fallthrough.
|
|
257
|
+
i = data.length
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
break
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (isCSIFinal(code)) {
|
|
264
|
+
i++
|
|
265
|
+
emitSequence(data.slice(seqStart, i))
|
|
266
|
+
} else if (isCSIParam(code) || isCSIIntermediate(code)) {
|
|
267
|
+
i++
|
|
268
|
+
} else {
|
|
269
|
+
// Invalid CSI - abort, treat as text
|
|
270
|
+
result.state = 'ground'
|
|
271
|
+
textStart = seqStart
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
break
|
|
275
|
+
|
|
276
|
+
case 'ss3':
|
|
277
|
+
// SS3 sequences: ESC O followed by a single final byte
|
|
278
|
+
if (code >= 0x40 && code <= 0x7e) {
|
|
279
|
+
i++
|
|
280
|
+
emitSequence(data.slice(seqStart, i))
|
|
281
|
+
} else {
|
|
282
|
+
// Invalid - treat as text
|
|
283
|
+
result.state = 'ground'
|
|
284
|
+
textStart = seqStart
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
break
|
|
288
|
+
|
|
289
|
+
case 'osc':
|
|
290
|
+
if (code === C0.BEL) {
|
|
291
|
+
i++
|
|
292
|
+
emitSequence(data.slice(seqStart, i))
|
|
293
|
+
} else if (code === C0.ESC && i + 1 < data.length && data.charCodeAt(i + 1) === ESC_TYPE.ST) {
|
|
294
|
+
i += 2
|
|
295
|
+
emitSequence(data.slice(seqStart, i))
|
|
296
|
+
} else {
|
|
297
|
+
i++
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
break
|
|
301
|
+
|
|
302
|
+
case 'dcs':
|
|
303
|
+
|
|
304
|
+
case 'apc':
|
|
305
|
+
if (code === C0.BEL) {
|
|
306
|
+
i++
|
|
307
|
+
emitSequence(data.slice(seqStart, i))
|
|
308
|
+
} else if (code === C0.ESC && i + 1 < data.length && data.charCodeAt(i + 1) === ESC_TYPE.ST) {
|
|
309
|
+
i += 2
|
|
310
|
+
emitSequence(data.slice(seqStart, i))
|
|
311
|
+
} else {
|
|
312
|
+
i++
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
break
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Handle end of input
|
|
320
|
+
if (result.state === 'ground') {
|
|
321
|
+
flushText()
|
|
322
|
+
} else if (flush && result.state === 'escape') {
|
|
323
|
+
// A bare ESC with nothing after it is the Escape key — the one incomplete
|
|
324
|
+
// state a flush should turn into input (the classic ESCDELAY lone-ESC
|
|
325
|
+
// disambiguation: ESC alone vs. ESC as a sequence/meta prefix).
|
|
326
|
+
const remaining = data.slice(seqStart)
|
|
327
|
+
|
|
328
|
+
if (remaining) {
|
|
329
|
+
tokens.push({ type: 'sequence', value: remaining })
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
result.state = 'ground'
|
|
333
|
+
} else {
|
|
334
|
+
// Buffer the incomplete sequence. Two paths land here:
|
|
335
|
+
// - streaming (flush=false): normal carry-over to the next feed.
|
|
336
|
+
// - flush=true while still inside a multi-byte control sequence
|
|
337
|
+
// (csi/osc/dcs/apc/ss3/escapeIntermediate): we deliberately do NOT
|
|
338
|
+
// emit it. A half-arrived CSI mouse report (ESC[<btn;col;row M) is an
|
|
339
|
+
// unfinished sequence, not user input — force-emitting it is what
|
|
340
|
+
// injects `46M`/`35;46M` shards into the prompt during a render stall.
|
|
341
|
+
// Keeping it buffered lets the continuation reassemble on the next
|
|
342
|
+
// feed (the xterm.js state-machine discipline — partial sequences
|
|
343
|
+
// never become text). createTokenizer.flush() drops the buffer if it
|
|
344
|
+
// survives a second flush with no progress (a genuine truncation), so
|
|
345
|
+
// a stuck partial can never merge into the next keypress's bytes.
|
|
346
|
+
result.buffer = data.slice(seqStart)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return { tokens, state: result }
|
|
350
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI Parser - Semantic Types
|
|
3
|
+
*
|
|
4
|
+
* These types represent the semantic meaning of ANSI escape sequences,
|
|
5
|
+
* not their string representation. Inspired by ghostty's action-based design.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Colors
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
/** Named colors from the 16-color palette */
|
|
13
|
+
export type NamedColor =
|
|
14
|
+
| 'black'
|
|
15
|
+
| 'red'
|
|
16
|
+
| 'green'
|
|
17
|
+
| 'yellow'
|
|
18
|
+
| 'blue'
|
|
19
|
+
| 'magenta'
|
|
20
|
+
| 'cyan'
|
|
21
|
+
| 'white'
|
|
22
|
+
| 'brightBlack'
|
|
23
|
+
| 'brightRed'
|
|
24
|
+
| 'brightGreen'
|
|
25
|
+
| 'brightYellow'
|
|
26
|
+
| 'brightBlue'
|
|
27
|
+
| 'brightMagenta'
|
|
28
|
+
| 'brightCyan'
|
|
29
|
+
| 'brightWhite'
|
|
30
|
+
|
|
31
|
+
/** Color specification - can be named, indexed (256), or RGB */
|
|
32
|
+
export type Color =
|
|
33
|
+
| { type: 'named'; name: NamedColor }
|
|
34
|
+
| { type: 'indexed'; index: number } // 0-255
|
|
35
|
+
| { type: 'rgb'; r: number; g: number; b: number }
|
|
36
|
+
| { type: 'default' }
|
|
37
|
+
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// Text Styles
|
|
40
|
+
// =============================================================================
|
|
41
|
+
|
|
42
|
+
/** Underline style variants */
|
|
43
|
+
export type UnderlineStyle = 'none' | 'single' | 'double' | 'curly' | 'dotted' | 'dashed'
|
|
44
|
+
|
|
45
|
+
/** Text style attributes - represents current styling state */
|
|
46
|
+
export type TextStyle = {
|
|
47
|
+
bold: boolean
|
|
48
|
+
dim: boolean
|
|
49
|
+
italic: boolean
|
|
50
|
+
underline: UnderlineStyle
|
|
51
|
+
blink: boolean
|
|
52
|
+
inverse: boolean
|
|
53
|
+
hidden: boolean
|
|
54
|
+
strikethrough: boolean
|
|
55
|
+
overline: boolean
|
|
56
|
+
fg: Color
|
|
57
|
+
bg: Color
|
|
58
|
+
underlineColor: Color
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Create a default (reset) text style */
|
|
62
|
+
export function defaultStyle(): TextStyle {
|
|
63
|
+
return {
|
|
64
|
+
bold: false,
|
|
65
|
+
dim: false,
|
|
66
|
+
italic: false,
|
|
67
|
+
underline: 'none',
|
|
68
|
+
blink: false,
|
|
69
|
+
inverse: false,
|
|
70
|
+
hidden: false,
|
|
71
|
+
strikethrough: false,
|
|
72
|
+
overline: false,
|
|
73
|
+
fg: { type: 'default' },
|
|
74
|
+
bg: { type: 'default' },
|
|
75
|
+
underlineColor: { type: 'default' }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Check if two styles are equal */
|
|
80
|
+
export function stylesEqual(a: TextStyle, b: TextStyle): boolean {
|
|
81
|
+
return (
|
|
82
|
+
a.bold === b.bold &&
|
|
83
|
+
a.dim === b.dim &&
|
|
84
|
+
a.italic === b.italic &&
|
|
85
|
+
a.underline === b.underline &&
|
|
86
|
+
a.blink === b.blink &&
|
|
87
|
+
a.inverse === b.inverse &&
|
|
88
|
+
a.hidden === b.hidden &&
|
|
89
|
+
a.strikethrough === b.strikethrough &&
|
|
90
|
+
a.overline === b.overline &&
|
|
91
|
+
colorsEqual(a.fg, b.fg) &&
|
|
92
|
+
colorsEqual(a.bg, b.bg) &&
|
|
93
|
+
colorsEqual(a.underlineColor, b.underlineColor)
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Check if two colors are equal */
|
|
98
|
+
export function colorsEqual(a: Color, b: Color): boolean {
|
|
99
|
+
if (a.type !== b.type) {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
switch (a.type) {
|
|
104
|
+
case 'named':
|
|
105
|
+
return a.name === (b as typeof a).name
|
|
106
|
+
|
|
107
|
+
case 'indexed':
|
|
108
|
+
return a.index === (b as typeof a).index
|
|
109
|
+
|
|
110
|
+
case 'rgb':
|
|
111
|
+
return a.r === (b as typeof a).r && a.g === (b as typeof a).g && a.b === (b as typeof a).b
|
|
112
|
+
|
|
113
|
+
case 'default':
|
|
114
|
+
return true
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// Cursor Actions
|
|
120
|
+
// =============================================================================
|
|
121
|
+
|
|
122
|
+
export type CursorDirection = 'up' | 'down' | 'forward' | 'back'
|
|
123
|
+
|
|
124
|
+
export type CursorAction =
|
|
125
|
+
| { type: 'move'; direction: CursorDirection; count: number }
|
|
126
|
+
| { type: 'position'; row: number; col: number }
|
|
127
|
+
| { type: 'column'; col: number }
|
|
128
|
+
| { type: 'row'; row: number }
|
|
129
|
+
| { type: 'save' }
|
|
130
|
+
| { type: 'restore' }
|
|
131
|
+
| { type: 'show' }
|
|
132
|
+
| { type: 'hide' }
|
|
133
|
+
| {
|
|
134
|
+
type: 'style'
|
|
135
|
+
style: 'block' | 'underline' | 'bar'
|
|
136
|
+
blinking: boolean
|
|
137
|
+
}
|
|
138
|
+
| { type: 'nextLine'; count: number }
|
|
139
|
+
| { type: 'prevLine'; count: number }
|
|
140
|
+
|
|
141
|
+
// =============================================================================
|
|
142
|
+
// Erase Actions
|
|
143
|
+
// =============================================================================
|
|
144
|
+
|
|
145
|
+
export type EraseAction =
|
|
146
|
+
| { type: 'display'; region: 'toEnd' | 'toStart' | 'all' | 'scrollback' }
|
|
147
|
+
| { type: 'line'; region: 'toEnd' | 'toStart' | 'all' }
|
|
148
|
+
| { type: 'chars'; count: number }
|
|
149
|
+
|
|
150
|
+
// =============================================================================
|
|
151
|
+
// Scroll Actions
|
|
152
|
+
// =============================================================================
|
|
153
|
+
|
|
154
|
+
export type ScrollAction =
|
|
155
|
+
| { type: 'up'; count: number }
|
|
156
|
+
| { type: 'down'; count: number }
|
|
157
|
+
| { type: 'setRegion'; top: number; bottom: number }
|
|
158
|
+
|
|
159
|
+
// =============================================================================
|
|
160
|
+
// Mode Actions
|
|
161
|
+
// =============================================================================
|
|
162
|
+
|
|
163
|
+
export type ModeAction =
|
|
164
|
+
| { type: 'alternateScreen'; enabled: boolean }
|
|
165
|
+
| { type: 'bracketedPaste'; enabled: boolean }
|
|
166
|
+
| { type: 'mouseTracking'; mode: 'off' | 'normal' | 'button' | 'any' }
|
|
167
|
+
| { type: 'focusEvents'; enabled: boolean }
|
|
168
|
+
|
|
169
|
+
// =============================================================================
|
|
170
|
+
// Link Actions (OSC 8)
|
|
171
|
+
// =============================================================================
|
|
172
|
+
|
|
173
|
+
export type LinkAction = { type: 'start'; url: string; params?: Record<string, string> } | { type: 'end' }
|
|
174
|
+
|
|
175
|
+
// =============================================================================
|
|
176
|
+
// Title Actions (OSC 0/1/2)
|
|
177
|
+
// =============================================================================
|
|
178
|
+
|
|
179
|
+
export type TitleAction =
|
|
180
|
+
| { type: 'windowTitle'; title: string }
|
|
181
|
+
| { type: 'iconName'; name: string }
|
|
182
|
+
| { type: 'both'; title: string }
|
|
183
|
+
|
|
184
|
+
// =============================================================================
|
|
185
|
+
// Tab Status Action (OSC 21337)
|
|
186
|
+
// =============================================================================
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Per-tab chrome metadata. Tristate for each field:
|
|
190
|
+
* - property absent → not mentioned in sequence, no change
|
|
191
|
+
* - null → explicitly cleared (bare key or key= with empty value)
|
|
192
|
+
* - value → set to this
|
|
193
|
+
*/
|
|
194
|
+
export type TabStatusAction = {
|
|
195
|
+
indicator?: Color | null
|
|
196
|
+
status?: string | null
|
|
197
|
+
statusColor?: Color | null
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// =============================================================================
|
|
201
|
+
// Parsed Segments - The output of the parser
|
|
202
|
+
// =============================================================================
|
|
203
|
+
|
|
204
|
+
/** A segment of styled text */
|
|
205
|
+
export type TextSegment = {
|
|
206
|
+
type: 'text'
|
|
207
|
+
text: string
|
|
208
|
+
style: TextStyle
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** A grapheme (visual character unit) with width info */
|
|
212
|
+
export type Grapheme = {
|
|
213
|
+
value: string
|
|
214
|
+
width: 1 | 2 // Display width in columns
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** All possible parsed actions */
|
|
218
|
+
export type Action =
|
|
219
|
+
| { type: 'text'; graphemes: Grapheme[]; style: TextStyle }
|
|
220
|
+
| { type: 'cursor'; action: CursorAction }
|
|
221
|
+
| { type: 'erase'; action: EraseAction }
|
|
222
|
+
| { type: 'scroll'; action: ScrollAction }
|
|
223
|
+
| { type: 'mode'; action: ModeAction }
|
|
224
|
+
| { type: 'link'; action: LinkAction }
|
|
225
|
+
| { type: 'title'; action: TitleAction }
|
|
226
|
+
| { type: 'tabStatus'; action: TabStatusAction }
|
|
227
|
+
| { type: 'sgr'; params: string } // Select Graphic Rendition (style change)
|
|
228
|
+
| { type: 'bell' }
|
|
229
|
+
| { type: 'reset' } // Full terminal reset (ESC c)
|
|
230
|
+
| { type: 'unknown'; sequence: string } // Unrecognized sequence
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI Parser Module
|
|
3
|
+
*
|
|
4
|
+
* A semantic ANSI escape sequence parser inspired by ghostty, tmux, and iTerm2.
|
|
5
|
+
*
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Semantic output: produces structured actions, not string tokens
|
|
8
|
+
* - Streaming: can parse input incrementally via Parser class
|
|
9
|
+
* - Style tracking: maintains text style state across parse calls
|
|
10
|
+
* - Comprehensive: supports SGR, CSI, OSC, ESC sequences
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
*
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { Parser } from './termio.js'
|
|
16
|
+
*
|
|
17
|
+
* const parser = new Parser()
|
|
18
|
+
* const actions = parser.feed('\x1b[31mred\x1b[0m')
|
|
19
|
+
* // => [{ type: 'text', graphemes: [...], style: { fg: { type: 'named', name: 'red' }, ... } }]
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Parser
|
|
24
|
+
export { Parser } from './termio/parser.js'
|
|
25
|
+
// Types
|
|
26
|
+
export type {
|
|
27
|
+
Action,
|
|
28
|
+
Color,
|
|
29
|
+
CursorAction,
|
|
30
|
+
CursorDirection,
|
|
31
|
+
EraseAction,
|
|
32
|
+
Grapheme,
|
|
33
|
+
LinkAction,
|
|
34
|
+
ModeAction,
|
|
35
|
+
NamedColor,
|
|
36
|
+
ScrollAction,
|
|
37
|
+
TextSegment,
|
|
38
|
+
TextStyle,
|
|
39
|
+
TitleAction,
|
|
40
|
+
UnderlineStyle
|
|
41
|
+
} from './termio/types.js'
|
|
42
|
+
export { colorsEqual, defaultStyle, stylesEqual } from './termio/types.js'
|