asdf
Squash the current repository state back into one baseline commit while preserving the README reframing and repository contents. Constraint: User explicitly requested a single squashed commit with subject "asdf" Confidence: high Scope-risk: broad Reversibility: clean Directive: This commit intentionally rewrites published history; coordinate before future force-pushes Tested: git status clean; local history rewritten to one commit; force-pushed main to origin and instructkr Not-tested: Fresh clone verification after push
This commit is contained in:
commit
d2542c9a62
136
src/components/AgentProgressLine.tsx
Normal file
136
src/components/AgentProgressLine.tsx
Normal file
File diff suppressed because one or more lines are too long
56
src/components/App.tsx
Normal file
56
src/components/App.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React from 'react';
|
||||
import { FpsMetricsProvider } from '../context/fpsMetrics.js';
|
||||
import { StatsProvider, type StatsStore } from '../context/stats.js';
|
||||
import { type AppState, AppStateProvider } from '../state/AppState.js';
|
||||
import { onChangeAppState } from '../state/onChangeAppState.js';
|
||||
import type { FpsMetrics } from '../utils/fpsTracker.js';
|
||||
type Props = {
|
||||
getFpsMetrics: () => FpsMetrics | undefined;
|
||||
stats?: StatsStore;
|
||||
initialState: AppState;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Top-level wrapper for interactive sessions.
|
||||
* Provides FPS metrics, stats context, and app state to the component tree.
|
||||
*/
|
||||
export function App(t0) {
|
||||
const $ = _c(9);
|
||||
const {
|
||||
getFpsMetrics,
|
||||
stats,
|
||||
initialState,
|
||||
children
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== children || $[1] !== initialState) {
|
||||
t1 = <AppStateProvider initialState={initialState} onChangeAppState={onChangeAppState}>{children}</AppStateProvider>;
|
||||
$[0] = children;
|
||||
$[1] = initialState;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[3] !== stats || $[4] !== t1) {
|
||||
t2 = <StatsProvider store={stats}>{t1}</StatsProvider>;
|
||||
$[3] = stats;
|
||||
$[4] = t1;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
let t3;
|
||||
if ($[6] !== getFpsMetrics || $[7] !== t2) {
|
||||
t3 = <FpsMetricsProvider getFpsMetrics={getFpsMetrics}>{t2}</FpsMetricsProvider>;
|
||||
$[6] = getFpsMetrics;
|
||||
$[7] = t2;
|
||||
$[8] = t3;
|
||||
} else {
|
||||
t3 = $[8];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkZwc01ldHJpY3NQcm92aWRlciIsIlN0YXRzUHJvdmlkZXIiLCJTdGF0c1N0b3JlIiwiQXBwU3RhdGUiLCJBcHBTdGF0ZVByb3ZpZGVyIiwib25DaGFuZ2VBcHBTdGF0ZSIsIkZwc01ldHJpY3MiLCJQcm9wcyIsImdldEZwc01ldHJpY3MiLCJzdGF0cyIsImluaXRpYWxTdGF0ZSIsImNoaWxkcmVuIiwiUmVhY3ROb2RlIiwiQXBwIiwidDAiLCIkIiwiX2MiLCJ0MSIsInQyIiwidDMiXSwic291cmNlcyI6WyJBcHAudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IEZwc01ldHJpY3NQcm92aWRlciB9IGZyb20gJy4uL2NvbnRleHQvZnBzTWV0cmljcy5qcydcbmltcG9ydCB7IFN0YXRzUHJvdmlkZXIsIHR5cGUgU3RhdHNTdG9yZSB9IGZyb20gJy4uL2NvbnRleHQvc3RhdHMuanMnXG5pbXBvcnQgeyB0eXBlIEFwcFN0YXRlLCBBcHBTdGF0ZVByb3ZpZGVyIH0gZnJvbSAnLi4vc3RhdGUvQXBwU3RhdGUuanMnXG5pbXBvcnQgeyBvbkNoYW5nZUFwcFN0YXRlIH0gZnJvbSAnLi4vc3RhdGUvb25DaGFuZ2VBcHBTdGF0ZS5qcydcbmltcG9ydCB0eXBlIHsgRnBzTWV0cmljcyB9IGZyb20gJy4uL3V0aWxzL2Zwc1RyYWNrZXIuanMnXG5cbnR5cGUgUHJvcHMgPSB7XG4gIGdldEZwc01ldHJpY3M6ICgpID0+IEZwc01ldHJpY3MgfCB1bmRlZmluZWRcbiAgc3RhdHM/OiBTdGF0c1N0b3JlXG4gIGluaXRpYWxTdGF0ZTogQXBwU3RhdGVcbiAgY2hpbGRyZW46IFJlYWN0LlJlYWN0Tm9kZVxufVxuXG4vKipcbiAqIFRvcC1sZXZlbCB3cmFwcGVyIGZvciBpbnRlcmFjdGl2ZSBzZXNzaW9ucy5cbiAqIFByb3ZpZGVzIEZQUyBtZXRyaWNzLCBzdGF0cyBjb250ZXh0LCBhbmQgYXBwIHN0YXRlIHRvIHRoZSBjb21wb25lbnQgdHJlZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFwcCh7XG4gIGdldEZwc01ldHJpY3MsXG4gIHN0YXRzLFxuICBpbml0aWFsU3RhdGUsXG4gIGNoaWxkcmVuLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxGcHNNZXRyaWNzUHJvdmlkZXIgZ2V0RnBzTWV0cmljcz17Z2V0RnBzTWV0cmljc30+XG4gICAgICA8U3RhdHNQcm92aWRlciBzdG9yZT17c3RhdHN9PlxuICAgICAgICA8QXBwU3RhdGVQcm92aWRlclxuICAgICAgICAgIGluaXRpYWxTdGF0ZT17aW5pdGlhbFN0YXRlfVxuICAgICAgICAgIG9uQ2hhbmdlQXBwU3RhdGU9e29uQ2hhbmdlQXBwU3RhdGV9XG4gICAgICAgID5cbiAgICAgICAgICB7Y2hpbGRyZW59XG4gICAgICAgIDwvQXBwU3RhdGVQcm92aWRlcj5cbiAgICAgIDwvU3RhdHNQcm92aWRlcj5cbiAgICA8L0Zwc01ldHJpY3NQcm92aWRlcj5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsU0FBU0Msa0JBQWtCLFFBQVEsMEJBQTBCO0FBQzdELFNBQVNDLGFBQWEsRUFBRSxLQUFLQyxVQUFVLFFBQVEscUJBQXFCO0FBQ3BFLFNBQVMsS0FBS0MsUUFBUSxFQUFFQyxnQkFBZ0IsUUFBUSxzQkFBc0I7QUFDdEUsU0FBU0MsZ0JBQWdCLFFBQVEsOEJBQThCO0FBQy9ELGNBQWNDLFVBQVUsUUFBUSx3QkFBd0I7QUFFeEQsS0FBS0MsS0FBSyxHQUFHO0VBQ1hDLGFBQWEsRUFBRSxHQUFHLEdBQUdGLFVBQVUsR0FBRyxTQUFTO0VBQzNDRyxLQUFLLENBQUMsRUFBRVAsVUFBVTtFQUNsQlEsWUFBWSxFQUFFUCxRQUFRO0VBQ3RCUSxRQUFRLEVBQUVaLEtBQUssQ0FBQ2EsU0FBUztBQUMzQixDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFBQyxJQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQWE7SUFBQVIsYUFBQTtJQUFBQyxLQUFBO0lBQUFDLFlBQUE7SUFBQUM7RUFBQSxJQUFBRyxFQUtaO0VBQUEsSUFBQUcsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUosUUFBQSxJQUFBSSxDQUFBLFFBQUFMLFlBQUE7SUFJQU8sRUFBQSxJQUFDLGdCQUFnQixDQUNEUCxZQUFZLENBQVpBLGFBQVcsQ0FBQyxDQUNSTCxnQkFBZ0IsQ0FBaEJBLGlCQUFlLENBQUMsQ0FFakNNLFNBQU8sQ0FDVixFQUxDLGdCQUFnQixDQUtFO0lBQUFJLENBQUEsTUFBQUosUUFBQTtJQUFBSSxDQUFBLE1BQUFMLFlBQUE7SUFBQUssQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxJQUFBRyxFQUFBO0VBQUEsSUFBQUgsQ0FBQSxRQUFBTixLQUFBLElBQUFNLENBQUEsUUFBQUUsRUFBQTtJQU5yQkMsRUFBQSxJQUFDLGFBQWEsQ0FBUVQsS0FBSyxDQUFMQSxNQUFJLENBQUMsQ0FDekIsQ0FBQVEsRUFLa0IsQ0FDcEIsRUFQQyxhQUFhLENBT0U7SUFBQUYsQ0FBQSxNQUFBTixLQUFBO0lBQUFNLENBQUEsTUFBQUUsRUFBQTtJQUFBRixDQUFBLE1BQUFHLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFILENBQUE7RUFBQTtFQUFBLElBQUFJLEVBQUE7RUFBQSxJQUFBSixDQUFBLFFBQUFQLGFBQUEsSUFBQU8sQ0FBQSxRQUFBRyxFQUFBO0lBUmxCQyxFQUFBLElBQUMsa0JBQWtCLENBQWdCWCxhQUFhLENBQWJBLGNBQVksQ0FBQyxDQUM5QyxDQUFBVSxFQU9lLENBQ2pCLEVBVEMsa0JBQWtCLENBU0U7SUFBQUgsQ0FBQSxNQUFBUCxhQUFBO0lBQUFPLENBQUEsTUFBQUcsRUFBQTtJQUFBSCxDQUFBLE1BQUFJLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFKLENBQUE7RUFBQTtFQUFBLE9BVHJCSSxFQVNxQjtBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
123
src/components/ApproveApiKey.tsx
Normal file
123
src/components/ApproveApiKey.tsx
Normal file
File diff suppressed because one or more lines are too long
142
src/components/AutoModeOptInDialog.tsx
Normal file
142
src/components/AutoModeOptInDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
198
src/components/AutoUpdater.tsx
Normal file
198
src/components/AutoUpdater.tsx
Normal file
File diff suppressed because one or more lines are too long
91
src/components/AutoUpdaterWrapper.tsx
Normal file
91
src/components/AutoUpdaterWrapper.tsx
Normal file
File diff suppressed because one or more lines are too long
82
src/components/AwsAuthStatusBox.tsx
Normal file
82
src/components/AwsAuthStatusBox.tsx
Normal file
File diff suppressed because one or more lines are too long
136
src/components/BaseTextInput.tsx
Normal file
136
src/components/BaseTextInput.tsx
Normal file
File diff suppressed because one or more lines are too long
56
src/components/BashModeProgress.tsx
Normal file
56
src/components/BashModeProgress.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React from 'react';
|
||||
import { Box } from '../ink.js';
|
||||
import { BashTool } from '../tools/BashTool/BashTool.js';
|
||||
import type { ShellProgress } from '../types/tools.js';
|
||||
import { UserBashInputMessage } from './messages/UserBashInputMessage.js';
|
||||
import { ShellProgressMessage } from './shell/ShellProgressMessage.js';
|
||||
type Props = {
|
||||
input: string;
|
||||
progress: ShellProgress | null;
|
||||
verbose: boolean;
|
||||
};
|
||||
export function BashModeProgress(t0) {
|
||||
const $ = _c(8);
|
||||
const {
|
||||
input,
|
||||
progress,
|
||||
verbose
|
||||
} = t0;
|
||||
const t1 = `<bash-input>${input}</bash-input>`;
|
||||
let t2;
|
||||
if ($[0] !== t1) {
|
||||
t2 = <UserBashInputMessage addMargin={false} param={{
|
||||
text: t1,
|
||||
type: "text"
|
||||
}} />;
|
||||
$[0] = t1;
|
||||
$[1] = t2;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
}
|
||||
let t3;
|
||||
if ($[2] !== progress || $[3] !== verbose) {
|
||||
t3 = progress ? <ShellProgressMessage fullOutput={progress.fullOutput} output={progress.output} elapsedTimeSeconds={progress.elapsedTimeSeconds} totalLines={progress.totalLines} verbose={verbose} /> : BashTool.renderToolUseProgressMessage?.([], {
|
||||
verbose,
|
||||
tools: [],
|
||||
terminalSize: undefined
|
||||
});
|
||||
$[2] = progress;
|
||||
$[3] = verbose;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
let t4;
|
||||
if ($[5] !== t2 || $[6] !== t3) {
|
||||
t4 = <Box flexDirection="column" marginTop={1}>{t2}{t3}</Box>;
|
||||
$[5] = t2;
|
||||
$[6] = t3;
|
||||
$[7] = t4;
|
||||
} else {
|
||||
t4 = $[7];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIkJhc2hUb29sIiwiU2hlbGxQcm9ncmVzcyIsIlVzZXJCYXNoSW5wdXRNZXNzYWdlIiwiU2hlbGxQcm9ncmVzc01lc3NhZ2UiLCJQcm9wcyIsImlucHV0IiwicHJvZ3Jlc3MiLCJ2ZXJib3NlIiwiQmFzaE1vZGVQcm9ncmVzcyIsInQwIiwiJCIsIl9jIiwidDEiLCJ0MiIsInRleHQiLCJ0eXBlIiwidDMiLCJmdWxsT3V0cHV0Iiwib3V0cHV0IiwiZWxhcHNlZFRpbWVTZWNvbmRzIiwidG90YWxMaW5lcyIsInJlbmRlclRvb2xVc2VQcm9ncmVzc01lc3NhZ2UiLCJ0b29scyIsInRlcm1pbmFsU2l6ZSIsInVuZGVmaW5lZCIsInQ0Il0sInNvdXJjZXMiOlsiQmFzaE1vZGVQcm9ncmVzcy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgQm94IH0gZnJvbSAnLi4vaW5rLmpzJ1xuaW1wb3J0IHsgQmFzaFRvb2wgfSBmcm9tICcuLi90b29scy9CYXNoVG9vbC9CYXNoVG9vbC5qcydcbmltcG9ydCB0eXBlIHsgU2hlbGxQcm9ncmVzcyB9IGZyb20gJy4uL3R5cGVzL3Rvb2xzLmpzJ1xuaW1wb3J0IHsgVXNlckJhc2hJbnB1dE1lc3NhZ2UgfSBmcm9tICcuL21lc3NhZ2VzL1VzZXJCYXNoSW5wdXRNZXNzYWdlLmpzJ1xuaW1wb3J0IHsgU2hlbGxQcm9ncmVzc01lc3NhZ2UgfSBmcm9tICcuL3NoZWxsL1NoZWxsUHJvZ3Jlc3NNZXNzYWdlLmpzJ1xuXG50eXBlIFByb3BzID0ge1xuICBpbnB1dDogc3RyaW5nXG4gIHByb2dyZXNzOiBTaGVsbFByb2dyZXNzIHwgbnVsbFxuICB2ZXJib3NlOiBib29sZWFuXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBCYXNoTW9kZVByb2dyZXNzKHtcbiAgaW5wdXQsXG4gIHByb2dyZXNzLFxuICB2ZXJib3NlLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiIG1hcmdpblRvcD17MX0+XG4gICAgICA8VXNlckJhc2hJbnB1dE1lc3NhZ2VcbiAgICAgICAgYWRkTWFyZ2luPXtmYWxzZX1cbiAgICAgICAgcGFyYW09e3sgdGV4dDogYDxiYXNoLWlucHV0PiR7aW5wdXR9PC9iYXNoLWlucHV0PmAsIHR5cGU6ICd0ZXh0JyB9fVxuICAgICAgLz5cbiAgICAgIHtwcm9ncmVzcyA/IChcbiAgICAgICAgPFNoZWxsUHJvZ3Jlc3NNZXNzYWdlXG4gICAgICAgICAgZnVsbE91dHB1dD17cHJvZ3Jlc3MuZnVsbE91dHB1dH1cbiAgICAgICAgICBvdXRwdXQ9e3Byb2dyZXNzLm91dHB1dH1cbiAgICAgICAgICBlbGFwc2VkVGltZVNlY29uZHM9e3Byb2dyZXNzLmVsYXBzZWRUaW1lU2Vjb25kc31cbiAgICAgICAgICB0b3RhbExpbmVzPXtwcm9ncmVzcy50b3RhbExpbmVzfVxuICAgICAgICAgIHZlcmJvc2U9e3ZlcmJvc2V9XG4gICAgICAgIC8+XG4gICAgICApIDogKFxuICAgICAgICBCYXNoVG9vbC5yZW5kZXJUb29sVXNlUHJvZ3Jlc3NNZXNzYWdlPy4oW10sIHtcbiAgICAgICAgICB2ZXJib3NlLFxuICAgICAgICAgIHRvb2xzOiBbXSxcbiAgICAgICAgICB0ZXJtaW5hbFNpemU6IHVuZGVmaW5lZCxcbiAgICAgICAgfSlcbiAgICAgICl9XG4gICAgPC9Cb3g+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU9BLEtBQUssTUFBTSxPQUFPO0FBQ3pCLFNBQVNDLEdBQUcsUUFBUSxXQUFXO0FBQy9CLFNBQVNDLFFBQVEsUUFBUSwrQkFBK0I7QUFDeEQsY0FBY0MsYUFBYSxRQUFRLG1CQUFtQjtBQUN0RCxTQUFTQyxvQkFBb0IsUUFBUSxvQ0FBb0M7QUFDekUsU0FBU0Msb0JBQW9CLFFBQVEsaUNBQWlDO0FBRXRFLEtBQUtDLEtBQUssR0FBRztFQUNYQyxLQUFLLEVBQUUsTUFBTTtFQUNiQyxRQUFRLEVBQUVMLGFBQWEsR0FBRyxJQUFJO0VBQzlCTSxPQUFPLEVBQUUsT0FBTztBQUNsQixDQUFDO0FBRUQsT0FBTyxTQUFBQyxpQkFBQUMsRUFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUEwQjtJQUFBTixLQUFBO0lBQUFDLFFBQUE7SUFBQUM7RUFBQSxJQUFBRSxFQUl6QjtFQUtlLE1BQUFHLEVBQUEsa0JBQWVQLEtBQUssZUFBZTtFQUFBLElBQUFRLEVBQUE7RUFBQSxJQUFBSCxDQUFBLFFBQUFFLEVBQUE7SUFGcERDLEVBQUEsSUFBQyxvQkFBb0IsQ0FDUixTQUFLLENBQUwsTUFBSSxDQUFDLENBQ1QsS0FBMkQsQ0FBM0Q7TUFBQUMsSUFBQSxFQUFRRixFQUFtQztNQUFBRyxJQUFBLEVBQVE7SUFBTyxFQUFDLEdBQ2xFO0lBQUFMLENBQUEsTUFBQUUsRUFBQTtJQUFBRixDQUFBLE1BQUFHLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFILENBQUE7RUFBQTtFQUFBLElBQUFNLEVBQUE7RUFBQSxJQUFBTixDQUFBLFFBQUFKLFFBQUEsSUFBQUksQ0FBQSxRQUFBSCxPQUFBO0lBQ0RTLEVBQUEsR0FBQVYsUUFBUSxHQUNQLENBQUMsb0JBQW9CLENBQ1AsVUFBbUIsQ0FBbkIsQ0FBQUEsUUFBUSxDQUFBVyxVQUFVLENBQUMsQ0FDdkIsTUFBZSxDQUFmLENBQUFYLFFBQVEsQ0FBQVksTUFBTSxDQUFDLENBQ0gsa0JBQTJCLENBQTNCLENBQUFaLFFBQVEsQ0FBQWEsa0JBQWtCLENBQUMsQ0FDbkMsVUFBbUIsQ0FBbkIsQ0FBQWIsUUFBUSxDQUFBYyxVQUFVLENBQUMsQ0FDdEJiLE9BQU8sQ0FBUEEsUUFBTSxDQUFDLEdBUW5CLEdBTENQLFFBQVEsQ0FBQXFCLDRCQUlOLEdBSnNDLEVBQUUsRUFBRTtNQUFBZCxPQUFBO01BQUFlLEtBQUEsRUFFbkMsRUFBRTtNQUFBQyxZQUFBLEVBQ0tDO0lBQ2hCLENBQ0YsQ0FBQztJQUFBZCxDQUFBLE1BQUFKLFFBQUE7SUFBQUksQ0FBQSxNQUFBSCxPQUFBO0lBQUFHLENBQUEsTUFBQU0sRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQU4sQ0FBQTtFQUFBO0VBQUEsSUFBQWUsRUFBQTtFQUFBLElBQUFmLENBQUEsUUFBQUcsRUFBQSxJQUFBSCxDQUFBLFFBQUFNLEVBQUE7SUFuQkhTLEVBQUEsSUFBQyxHQUFHLENBQWUsYUFBUSxDQUFSLFFBQVEsQ0FBWSxTQUFDLENBQUQsR0FBQyxDQUN0QyxDQUFBWixFQUdDLENBQ0EsQ0FBQUcsRUFjRCxDQUNGLEVBcEJDLEdBQUcsQ0FvQkU7SUFBQU4sQ0FBQSxNQUFBRyxFQUFBO0lBQUFILENBQUEsTUFBQU0sRUFBQTtJQUFBTixDQUFBLE1BQUFlLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFmLENBQUE7RUFBQTtFQUFBLE9BcEJOZSxFQW9CTTtBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
401
src/components/BridgeDialog.tsx
Normal file
401
src/components/BridgeDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
87
src/components/BypassPermissionsModeDialog.tsx
Normal file
87
src/components/BypassPermissionsModeDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
102
src/components/ChannelDowngradeDialog.tsx
Normal file
102
src/components/ChannelDowngradeDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
78
src/components/ClaudeCodeHint/PluginHintMenu.tsx
Normal file
78
src/components/ClaudeCodeHint/PluginHintMenu.tsx
Normal file
File diff suppressed because one or more lines are too long
121
src/components/ClaudeInChromeOnboarding.tsx
Normal file
121
src/components/ClaudeInChromeOnboarding.tsx
Normal file
File diff suppressed because one or more lines are too long
137
src/components/ClaudeMdExternalIncludesDialog.tsx
Normal file
137
src/components/ClaudeMdExternalIncludesDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
73
src/components/ClickableImageRef.tsx
Normal file
73
src/components/ClickableImageRef.tsx
Normal file
File diff suppressed because one or more lines are too long
118
src/components/CompactSummary.tsx
Normal file
118
src/components/CompactSummary.tsx
Normal file
File diff suppressed because one or more lines are too long
57
src/components/ConfigurableShortcutHint.tsx
Normal file
57
src/components/ConfigurableShortcutHint.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import type { KeybindingAction, KeybindingContextName } from '../keybindings/types.js';
|
||||
import { useShortcutDisplay } from '../keybindings/useShortcutDisplay.js';
|
||||
import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js';
|
||||
type Props = {
|
||||
/** The keybinding action (e.g., 'app:toggleTranscript') */
|
||||
action: KeybindingAction;
|
||||
/** The keybinding context (e.g., 'Global') */
|
||||
context: KeybindingContextName;
|
||||
/** Default shortcut if keybinding not configured */
|
||||
fallback: string;
|
||||
/** The action description text (e.g., 'expand') */
|
||||
description: string;
|
||||
/** Whether to wrap in parentheses */
|
||||
parens?: boolean;
|
||||
/** Whether to show in bold */
|
||||
bold?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* KeyboardShortcutHint that displays the user-configured shortcut.
|
||||
* Falls back to default if keybinding context is not available.
|
||||
*
|
||||
* @example
|
||||
* <ConfigurableShortcutHint
|
||||
* action="app:toggleTranscript"
|
||||
* context="Global"
|
||||
* fallback="ctrl+o"
|
||||
* description="expand"
|
||||
* />
|
||||
*/
|
||||
export function ConfigurableShortcutHint(t0) {
|
||||
const $ = _c(5);
|
||||
const {
|
||||
action,
|
||||
context,
|
||||
fallback,
|
||||
description,
|
||||
parens,
|
||||
bold
|
||||
} = t0;
|
||||
const shortcut = useShortcutDisplay(action, context, fallback);
|
||||
let t1;
|
||||
if ($[0] !== bold || $[1] !== description || $[2] !== parens || $[3] !== shortcut) {
|
||||
t1 = <KeyboardShortcutHint shortcut={shortcut} action={description} parens={parens} bold={bold} />;
|
||||
$[0] = bold;
|
||||
$[1] = description;
|
||||
$[2] = parens;
|
||||
$[3] = shortcut;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIktleWJpbmRpbmdBY3Rpb24iLCJLZXliaW5kaW5nQ29udGV4dE5hbWUiLCJ1c2VTaG9ydGN1dERpc3BsYXkiLCJLZXlib2FyZFNob3J0Y3V0SGludCIsIlByb3BzIiwiYWN0aW9uIiwiY29udGV4dCIsImZhbGxiYWNrIiwiZGVzY3JpcHRpb24iLCJwYXJlbnMiLCJib2xkIiwiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IiwidDAiLCIkIiwiX2MiLCJzaG9ydGN1dCIsInQxIl0sInNvdXJjZXMiOlsiQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB0eXBlIHtcbiAgS2V5YmluZGluZ0FjdGlvbixcbiAgS2V5YmluZGluZ0NvbnRleHROYW1lLFxufSBmcm9tICcuLi9rZXliaW5kaW5ncy90eXBlcy5qcydcbmltcG9ydCB7IHVzZVNob3J0Y3V0RGlzcGxheSB9IGZyb20gJy4uL2tleWJpbmRpbmdzL3VzZVNob3J0Y3V0RGlzcGxheS5qcydcbmltcG9ydCB7IEtleWJvYXJkU2hvcnRjdXRIaW50IH0gZnJvbSAnLi9kZXNpZ24tc3lzdGVtL0tleWJvYXJkU2hvcnRjdXRIaW50LmpzJ1xuXG50eXBlIFByb3BzID0ge1xuICAvKiogVGhlIGtleWJpbmRpbmcgYWN0aW9uIChlLmcuLCAnYXBwOnRvZ2dsZVRyYW5zY3JpcHQnKSAqL1xuICBhY3Rpb246IEtleWJpbmRpbmdBY3Rpb25cbiAgLyoqIFRoZSBrZXliaW5kaW5nIGNvbnRleHQgKGUuZy4sICdHbG9iYWwnKSAqL1xuICBjb250ZXh0OiBLZXliaW5kaW5nQ29udGV4dE5hbWVcbiAgLyoqIERlZmF1bHQgc2hvcnRjdXQgaWYga2V5YmluZGluZyBub3QgY29uZmlndXJlZCAqL1xuICBmYWxsYmFjazogc3RyaW5nXG4gIC8qKiBUaGUgYWN0aW9uIGRlc2NyaXB0aW9uIHRleHQgKGUuZy4sICdleHBhbmQnKSAqL1xuICBkZXNjcmlwdGlvbjogc3RyaW5nXG4gIC8qKiBXaGV0aGVyIHRvIHdyYXAgaW4gcGFyZW50aGVzZXMgKi9cbiAgcGFyZW5zPzogYm9vbGVhblxuICAvKiogV2hldGhlciB0byBzaG93IGluIGJvbGQgKi9cbiAgYm9sZD86IGJvb2xlYW5cbn1cblxuLyoqXG4gKiBLZXlib2FyZFNob3J0Y3V0SGludCB0aGF0IGRpc3BsYXlzIHRoZSB1c2VyLWNvbmZpZ3VyZWQgc2hvcnRjdXQuXG4gKiBGYWxscyBiYWNrIHRvIGRlZmF1bHQgaWYga2V5YmluZGluZyBjb250ZXh0IGlzIG5vdCBhdmFpbGFibGUuXG4gKlxuICogQGV4YW1wbGVcbiAqIDxDb25maWd1cmFibGVTaG9ydGN1dEhpbnRcbiAqICAgYWN0aW9uPVwiYXBwOnRvZ2dsZVRyYW5zY3JpcHRcIlxuICogICBjb250ZXh0PVwiR2xvYmFsXCJcbiAqICAgZmFsbGJhY2s9XCJjdHJsK29cIlxuICogICBkZXNjcmlwdGlvbj1cImV4cGFuZFwiXG4gKiAvPlxuICovXG5leHBvcnQgZnVuY3Rpb24gQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50KHtcbiAgYWN0aW9uLFxuICBjb250ZXh0LFxuICBmYWxsYmFjayxcbiAgZGVzY3JpcHRpb24sXG4gIHBhcmVucyxcbiAgYm9sZCxcbn06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3Qgc2hvcnRjdXQgPSB1c2VTaG9ydGN1dERpc3BsYXkoYWN0aW9uLCBjb250ZXh0LCBmYWxsYmFjaylcbiAgcmV0dXJuIChcbiAgICA8S2V5Ym9hcmRTaG9ydGN1dEhpbnRcbiAgICAgIHNob3J0Y3V0PXtzaG9ydGN1dH1cbiAgICAgIGFjdGlvbj17ZGVzY3JpcHRpb259XG4gICAgICBwYXJlbnM9e3BhcmVuc31cbiAgICAgIGJvbGQ9e2JvbGR9XG4gICAgLz5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxLQUFLQSxLQUFLLE1BQU0sT0FBTztBQUM5QixjQUNFQyxnQkFBZ0IsRUFDaEJDLHFCQUFxQixRQUNoQix5QkFBeUI7QUFDaEMsU0FBU0Msa0JBQWtCLFFBQVEsc0NBQXNDO0FBQ3pFLFNBQVNDLG9CQUFvQixRQUFRLHlDQUF5QztBQUU5RSxLQUFLQyxLQUFLLEdBQUc7RUFDWDtFQUNBQyxNQUFNLEVBQUVMLGdCQUFnQjtFQUN4QjtFQUNBTSxPQUFPLEVBQUVMLHFCQUFxQjtFQUM5QjtFQUNBTSxRQUFRLEVBQUUsTUFBTTtFQUNoQjtFQUNBQyxXQUFXLEVBQUUsTUFBTTtFQUNuQjtFQUNBQyxNQUFNLENBQUMsRUFBRSxPQUFPO0VBQ2hCO0VBQ0FDLElBQUksQ0FBQyxFQUFFLE9BQU87QUFDaEIsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPLFNBQUFDLHlCQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQWtDO0lBQUFULE1BQUE7SUFBQUMsT0FBQTtJQUFBQyxRQUFBO0lBQUFDLFdBQUE7SUFBQUMsTUFBQTtJQUFBQztFQUFBLElBQUFFLEVBT2pDO0VBQ04sTUFBQUcsUUFBQSxHQUFpQmIsa0JBQWtCLENBQUNHLE1BQU0sRUFBRUMsT0FBTyxFQUFFQyxRQUFRLENBQUM7RUFBQSxJQUFBUyxFQUFBO0VBQUEsSUFBQUgsQ0FBQSxRQUFBSCxJQUFBLElBQUFHLENBQUEsUUFBQUwsV0FBQSxJQUFBSyxDQUFBLFFBQUFKLE1BQUEsSUFBQUksQ0FBQSxRQUFBRSxRQUFBO0lBRTVEQyxFQUFBLElBQUMsb0JBQW9CLENBQ1RELFFBQVEsQ0FBUkEsU0FBTyxDQUFDLENBQ1ZQLE1BQVcsQ0FBWEEsWUFBVSxDQUFDLENBQ1hDLE1BQU0sQ0FBTkEsT0FBSyxDQUFDLENBQ1JDLElBQUksQ0FBSkEsS0FBRyxDQUFDLEdBQ1Y7SUFBQUcsQ0FBQSxNQUFBSCxJQUFBO0lBQUFHLENBQUEsTUFBQUwsV0FBQTtJQUFBSyxDQUFBLE1BQUFKLE1BQUE7SUFBQUksQ0FBQSxNQUFBRSxRQUFBO0lBQUFGLENBQUEsTUFBQUcsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUgsQ0FBQTtFQUFBO0VBQUEsT0FMRkcsRUFLRTtBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
631
src/components/ConsoleOAuthFlow.tsx
Normal file
631
src/components/ConsoleOAuthFlow.tsx
Normal file
File diff suppressed because one or more lines are too long
47
src/components/ContextSuggestions.tsx
Normal file
47
src/components/ContextSuggestions.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import figures from 'figures';
|
||||
import * as React from 'react';
|
||||
import { Box, Text } from '../ink.js';
|
||||
import type { ContextSuggestion } from '../utils/contextSuggestions.js';
|
||||
import { formatTokens } from '../utils/format.js';
|
||||
import { StatusIcon } from './design-system/StatusIcon.js';
|
||||
type Props = {
|
||||
suggestions: ContextSuggestion[];
|
||||
};
|
||||
export function ContextSuggestions(t0) {
|
||||
const $ = _c(5);
|
||||
const {
|
||||
suggestions
|
||||
} = t0;
|
||||
if (suggestions.length === 0) {
|
||||
return null;
|
||||
}
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <Text bold={true}>Suggestions</Text>;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
let t2;
|
||||
if ($[1] !== suggestions) {
|
||||
t2 = suggestions.map(_temp);
|
||||
$[1] = suggestions;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
let t3;
|
||||
if ($[3] !== t2) {
|
||||
t3 = <Box flexDirection="column" marginTop={1}>{t1}{t2}</Box>;
|
||||
$[3] = t2;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
function _temp(suggestion, i) {
|
||||
return <Box key={i} flexDirection="column" marginTop={i === 0 ? 0 : 1}><Box><StatusIcon status={suggestion.severity} withSpace={true} /><Text bold={true}>{suggestion.title}</Text>{suggestion.savingsTokens ? <Text dimColor={true}>{" "}{figures.arrowRight} save ~{formatTokens(suggestion.savingsTokens)}</Text> : null}</Box><Box marginLeft={2}><Text dimColor={true}>{suggestion.detail}</Text></Box></Box>;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJCb3giLCJUZXh0IiwiQ29udGV4dFN1Z2dlc3Rpb24iLCJmb3JtYXRUb2tlbnMiLCJTdGF0dXNJY29uIiwiUHJvcHMiLCJzdWdnZXN0aW9ucyIsIkNvbnRleHRTdWdnZXN0aW9ucyIsInQwIiwiJCIsIl9jIiwibGVuZ3RoIiwidDEiLCJTeW1ib2wiLCJmb3IiLCJ0MiIsIm1hcCIsIl90ZW1wIiwidDMiLCJzdWdnZXN0aW9uIiwiaSIsInNldmVyaXR5IiwidGl0bGUiLCJzYXZpbmdzVG9rZW5zIiwiYXJyb3dSaWdodCIsImRldGFpbCJdLCJzb3VyY2VzIjpbIkNvbnRleHRTdWdnZXN0aW9ucy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZpZ3VyZXMgZnJvbSAnZmlndXJlcydcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgQm94LCBUZXh0IH0gZnJvbSAnLi4vaW5rLmpzJ1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0U3VnZ2VzdGlvbiB9IGZyb20gJy4uL3V0aWxzL2NvbnRleHRTdWdnZXN0aW9ucy5qcydcbmltcG9ydCB7IGZvcm1hdFRva2VucyB9IGZyb20gJy4uL3V0aWxzL2Zvcm1hdC5qcydcbmltcG9ydCB7IFN0YXR1c0ljb24gfSBmcm9tICcuL2Rlc2lnbi1zeXN0ZW0vU3RhdHVzSWNvbi5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgc3VnZ2VzdGlvbnM6IENvbnRleHRTdWdnZXN0aW9uW11cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENvbnRleHRTdWdnZXN0aW9ucyh7IHN1Z2dlc3Rpb25zIH06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgaWYgKHN1Z2dlc3Rpb25zLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGxcblxuICByZXR1cm4gKFxuICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiIG1hcmdpblRvcD17MX0+XG4gICAgICA8VGV4dCBib2xkPlN1Z2dlc3Rpb25zPC9UZXh0PlxuICAgICAge3N1Z2dlc3Rpb25zLm1hcCgoc3VnZ2VzdGlvbiwgaSkgPT4gKFxuICAgICAgICA8Qm94IGtleT17aX0gZmxleERpcmVjdGlvbj1cImNvbHVtblwiIG1hcmdpblRvcD17aSA9PT0gMCA/IDAgOiAxfT5cbiAgICAgICAgICA8Qm94PlxuICAgICAgICAgICAgPFN0YXR1c0ljb24gc3RhdHVzPXtzdWdnZXN0aW9uLnNldmVyaXR5fSB3aXRoU3BhY2UgLz5cbiAgICAgICAgICAgIDxUZXh0IGJvbGQ+e3N1Z2dlc3Rpb24udGl0bGV9PC9UZXh0PlxuICAgICAgICAgICAge3N1Z2dlc3Rpb24uc2F2aW5nc1Rva2VucyA/IChcbiAgICAgICAgICAgICAgPFRleHQgZGltQ29sb3I+XG4gICAgICAgICAgICAgICAgeycgJ31cbiAgICAgICAgICAgICAgICB7ZmlndXJlcy5hcnJvd1JpZ2h0fSBzYXZlIH5cbiAgICAgICAgICAgICAgICB7Zm9ybWF0VG9rZW5zKHN1Z2dlc3Rpb24uc2F2aW5nc1Rva2Vucyl9XG4gICAgICAgICAgICAgIDwvVGV4dD5cbiAgICAgICAgICAgICkgOiBudWxsfVxuICAgICAgICAgIDwvQm94PlxuICAgICAgICAgIDxCb3ggbWFyZ2luTGVmdD17Mn0+XG4gICAgICAgICAgICA8VGV4dCBkaW1Db2xvcj57c3VnZ2VzdGlvbi5kZXRhaWx9PC9UZXh0PlxuICAgICAgICAgIDwvQm94PlxuICAgICAgICA8L0JveD5cbiAgICAgICkpfVxuICAgIDwvQm94PlxuICApXG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPQSxPQUFPLE1BQU0sU0FBUztBQUM3QixPQUFPLEtBQUtDLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLEdBQUcsRUFBRUMsSUFBSSxRQUFRLFdBQVc7QUFDckMsY0FBY0MsaUJBQWlCLFFBQVEsZ0NBQWdDO0FBQ3ZFLFNBQVNDLFlBQVksUUFBUSxvQkFBb0I7QUFDakQsU0FBU0MsVUFBVSxRQUFRLCtCQUErQjtBQUUxRCxLQUFLQyxLQUFLLEdBQUc7RUFDWEMsV0FBVyxFQUFFSixpQkFBaUIsRUFBRTtBQUNsQyxDQUFDO0FBRUQsT0FBTyxTQUFBSyxtQkFBQUMsRUFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUE0QjtJQUFBSjtFQUFBLElBQUFFLEVBQXNCO0VBQ3ZELElBQUlGLFdBQVcsQ0FBQUssTUFBTyxLQUFLLENBQUM7SUFBQSxPQUFTLElBQUk7RUFBQTtFQUFBLElBQUFDLEVBQUE7RUFBQSxJQUFBSCxDQUFBLFFBQUFJLE1BQUEsQ0FBQUMsR0FBQTtJQUlyQ0YsRUFBQSxJQUFDLElBQUksQ0FBQyxJQUFJLENBQUosS0FBRyxDQUFDLENBQUMsV0FBVyxFQUFyQixJQUFJLENBQXdCO0lBQUFILENBQUEsTUFBQUcsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUgsQ0FBQTtFQUFBO0VBQUEsSUFBQU0sRUFBQTtFQUFBLElBQUFOLENBQUEsUUFBQUgsV0FBQTtJQUM1QlMsRUFBQSxHQUFBVCxXQUFXLENBQUFVLEdBQUksQ0FBQ0MsS0FpQmhCLENBQUM7SUFBQVIsQ0FBQSxNQUFBSCxXQUFBO0lBQUFHLENBQUEsTUFBQU0sRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQU4sQ0FBQTtFQUFBO0VBQUEsSUFBQVMsRUFBQTtFQUFBLElBQUFULENBQUEsUUFBQU0sRUFBQTtJQW5CSkcsRUFBQSxJQUFDLEdBQUcsQ0FBZSxhQUFRLENBQVIsUUFBUSxDQUFZLFNBQUMsQ0FBRCxHQUFDLENBQ3RDLENBQUFOLEVBQTRCLENBQzNCLENBQUFHLEVBaUJBLENBQ0gsRUFwQkMsR0FBRyxDQW9CRTtJQUFBTixDQUFBLE1BQUFNLEVBQUE7SUFBQU4sQ0FBQSxNQUFBUyxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBVCxDQUFBO0VBQUE7RUFBQSxPQXBCTlMsRUFvQk07QUFBQTtBQXhCSCxTQUFBRCxNQUFBRSxVQUFBLEVBQUFDLENBQUE7RUFBQSxPQU9DLENBQUMsR0FBRyxDQUFNQSxHQUFDLENBQURBLEVBQUEsQ0FBQyxDQUFnQixhQUFRLENBQVIsUUFBUSxDQUFZLFNBQWUsQ0FBZixDQUFBQSxDQUFDLEtBQUssQ0FBUyxHQUFmLENBQWUsR0FBZixDQUFjLENBQUMsQ0FDNUQsQ0FBQyxHQUFHLENBQ0YsQ0FBQyxVQUFVLENBQVMsTUFBbUIsQ0FBbkIsQ0FBQUQsVUFBVSxDQUFBRSxRQUFRLENBQUMsQ0FBRSxTQUFTLENBQVQsS0FBUSxDQUFDLEdBQ2xELENBQUMsSUFBSSxDQUFDLElBQUksQ0FBSixLQUFHLENBQUMsQ0FBRSxDQUFBRixVQUFVLENBQUFHLEtBQUssQ0FBRSxFQUE1QixJQUFJLENBQ0osQ0FBQUgsVUFBVSxDQUFBSSxhQU1ILEdBTE4sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFSLEtBQU8sQ0FBQyxDQUNYLElBQUUsQ0FDRixDQUFBekIsT0FBTyxDQUFBMEIsVUFBVSxDQUFFLE9BQ25CLENBQUFyQixZQUFZLENBQUNnQixVQUFVLENBQUFJLGFBQWMsRUFDeEMsRUFKQyxJQUFJLENBS0MsR0FOUCxJQU1NLENBQ1QsRUFWQyxHQUFHLENBV0osQ0FBQyxHQUFHLENBQWEsVUFBQyxDQUFELEdBQUMsQ0FDaEIsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFSLEtBQU8sQ0FBQyxDQUFFLENBQUFKLFVBQVUsQ0FBQU0sTUFBTSxDQUFFLEVBQWpDLElBQUksQ0FDUCxFQUZDLEdBQUcsQ0FHTixFQWZDLEdBQUcsQ0FlRTtBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
489
src/components/ContextVisualization.tsx
Normal file
489
src/components/ContextVisualization.tsx
Normal file
File diff suppressed because one or more lines are too long
273
src/components/CoordinatorAgentStatus.tsx
Normal file
273
src/components/CoordinatorAgentStatus.tsx
Normal file
File diff suppressed because one or more lines are too long
50
src/components/CostThresholdDialog.tsx
Normal file
50
src/components/CostThresholdDialog.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React from 'react';
|
||||
import { Box, Link, Text } from '../ink.js';
|
||||
import { Select } from './CustomSelect/index.js';
|
||||
import { Dialog } from './design-system/Dialog.js';
|
||||
type Props = {
|
||||
onDone: () => void;
|
||||
};
|
||||
export function CostThresholdDialog(t0) {
|
||||
const $ = _c(7);
|
||||
const {
|
||||
onDone
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <Box flexDirection="column"><Text>Learn more about how to monitor your spending:</Text><Link url="https://code.claude.com/docs/en/costs" /></Box>;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
let t2;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = [{
|
||||
value: "ok",
|
||||
label: "Got it, thanks!"
|
||||
}];
|
||||
$[1] = t2;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
}
|
||||
let t3;
|
||||
if ($[2] !== onDone) {
|
||||
t3 = <Select options={t2} onChange={onDone} />;
|
||||
$[2] = onDone;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
let t4;
|
||||
if ($[4] !== onDone || $[5] !== t3) {
|
||||
t4 = <Dialog title="You've spent $5 on the Anthropic API this session." onCancel={onDone}>{t1}{t3}</Dialog>;
|
||||
$[4] = onDone;
|
||||
$[5] = t3;
|
||||
$[6] = t4;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIkxpbmsiLCJUZXh0IiwiU2VsZWN0IiwiRGlhbG9nIiwiUHJvcHMiLCJvbkRvbmUiLCJDb3N0VGhyZXNob2xkRGlhbG9nIiwidDAiLCIkIiwiX2MiLCJ0MSIsIlN5bWJvbCIsImZvciIsInQyIiwidmFsdWUiLCJsYWJlbCIsInQzIiwidDQiXSwic291cmNlcyI6WyJDb3N0VGhyZXNob2xkRGlhbG9nLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBCb3gsIExpbmssIFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5pbXBvcnQgeyBTZWxlY3QgfSBmcm9tICcuL0N1c3RvbVNlbGVjdC9pbmRleC5qcydcbmltcG9ydCB7IERpYWxvZyB9IGZyb20gJy4vZGVzaWduLXN5c3RlbS9EaWFsb2cuanMnXG5cbnR5cGUgUHJvcHMgPSB7XG4gIG9uRG9uZTogKCkgPT4gdm9pZFxufVxuXG5leHBvcnQgZnVuY3Rpb24gQ29zdFRocmVzaG9sZERpYWxvZyh7IG9uRG9uZSB9OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPERpYWxvZ1xuICAgICAgdGl0bGU9XCJZb3UndmUgc3BlbnQgJDUgb24gdGhlIEFudGhyb3BpYyBBUEkgdGhpcyBzZXNzaW9uLlwiXG4gICAgICBvbkNhbmNlbD17b25Eb25lfVxuICAgID5cbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgICA8VGV4dD5MZWFybiBtb3JlIGFib3V0IGhvdyB0byBtb25pdG9yIHlvdXIgc3BlbmRpbmc6PC9UZXh0PlxuICAgICAgICA8TGluayB1cmw9XCJodHRwczovL2NvZGUuY2xhdWRlLmNvbS9kb2NzL2VuL2Nvc3RzXCIgLz5cbiAgICAgIDwvQm94PlxuICAgICAgPFNlbGVjdFxuICAgICAgICBvcHRpb25zPXtbXG4gICAgICAgICAge1xuICAgICAgICAgICAgdmFsdWU6ICdvaycsXG4gICAgICAgICAgICBsYWJlbDogJ0dvdCBpdCwgdGhhbmtzIScsXG4gICAgICAgICAgfSxcbiAgICAgICAgXX1cbiAgICAgICAgb25DaGFuZ2U9e29uRG9uZX1cbiAgICAgIC8+XG4gICAgPC9EaWFsb2c+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU9BLEtBQUssTUFBTSxPQUFPO0FBQ3pCLFNBQVNDLEdBQUcsRUFBRUMsSUFBSSxFQUFFQyxJQUFJLFFBQVEsV0FBVztBQUMzQyxTQUFTQyxNQUFNLFFBQVEseUJBQXlCO0FBQ2hELFNBQVNDLE1BQU0sUUFBUSwyQkFBMkI7QUFFbEQsS0FBS0MsS0FBSyxHQUFHO0VBQ1hDLE1BQU0sRUFBRSxHQUFHLEdBQUcsSUFBSTtBQUNwQixDQUFDO0FBRUQsT0FBTyxTQUFBQyxvQkFBQUMsRUFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUE2QjtJQUFBSjtFQUFBLElBQUFFLEVBQWlCO0VBQUEsSUFBQUcsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO0lBTS9DRixFQUFBLElBQUMsR0FBRyxDQUFlLGFBQVEsQ0FBUixRQUFRLENBQ3pCLENBQUMsSUFBSSxDQUFDLDhDQUE4QyxFQUFuRCxJQUFJLENBQ0wsQ0FBQyxJQUFJLENBQUssR0FBdUMsQ0FBdkMsdUNBQXVDLEdBQ25ELEVBSEMsR0FBRyxDQUdFO0lBQUFGLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBQUEsSUFBQUssRUFBQTtFQUFBLElBQUFMLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO0lBRUtDLEVBQUEsSUFDUDtNQUFBQyxLQUFBLEVBQ1MsSUFBSTtNQUFBQyxLQUFBLEVBQ0o7SUFDVCxDQUFDLENBQ0Y7SUFBQVAsQ0FBQSxNQUFBSyxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBTCxDQUFBO0VBQUE7RUFBQSxJQUFBUSxFQUFBO0VBQUEsSUFBQVIsQ0FBQSxRQUFBSCxNQUFBO0lBTkhXLEVBQUEsSUFBQyxNQUFNLENBQ0ksT0FLUixDQUxRLENBQUFILEVBS1QsQ0FBQyxDQUNTUixRQUFNLENBQU5BLE9BQUssQ0FBQyxHQUNoQjtJQUFBRyxDQUFBLE1BQUFILE1BQUE7SUFBQUcsQ0FBQSxNQUFBUSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBUixDQUFBO0VBQUE7RUFBQSxJQUFBUyxFQUFBO0VBQUEsSUFBQVQsQ0FBQSxRQUFBSCxNQUFBLElBQUFHLENBQUEsUUFBQVEsRUFBQTtJQWhCSkMsRUFBQSxJQUFDLE1BQU0sQ0FDQyxLQUFvRCxDQUFwRCxvREFBb0QsQ0FDaERaLFFBQU0sQ0FBTkEsT0FBSyxDQUFDLENBRWhCLENBQUFLLEVBR0ssQ0FDTCxDQUFBTSxFQVFDLENBQ0gsRUFqQkMsTUFBTSxDQWlCRTtJQUFBUixDQUFBLE1BQUFILE1BQUE7SUFBQUcsQ0FBQSxNQUFBUSxFQUFBO0lBQUFSLENBQUEsTUFBQVMsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQVQsQ0FBQTtFQUFBO0VBQUEsT0FqQlRTLEVBaUJTO0FBQUEiLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
51
src/components/CtrlOToExpand.tsx
Normal file
51
src/components/CtrlOToExpand.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import chalk from 'chalk';
|
||||
import React, { useContext } from 'react';
|
||||
import { Text } from '../ink.js';
|
||||
import { getShortcutDisplay } from '../keybindings/shortcutFormat.js';
|
||||
import { useShortcutDisplay } from '../keybindings/useShortcutDisplay.js';
|
||||
import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js';
|
||||
import { InVirtualListContext } from './messageActions.js';
|
||||
|
||||
// Context to track if we're inside a sub agent
|
||||
// Similar to MessageResponseContext, this helps us avoid showing
|
||||
// too many "(ctrl+o to expand)" hints in sub agent output
|
||||
const SubAgentContext = React.createContext(false);
|
||||
export function SubAgentProvider(t0) {
|
||||
const $ = _c(2);
|
||||
const {
|
||||
children
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== children) {
|
||||
t1 = <SubAgentContext.Provider value={true}>{children}</SubAgentContext.Provider>;
|
||||
$[0] = children;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
export function CtrlOToExpand() {
|
||||
const $ = _c(2);
|
||||
const isInSubAgent = useContext(SubAgentContext);
|
||||
const inVirtualList = useContext(InVirtualListContext);
|
||||
const expandShortcut = useShortcutDisplay("app:toggleTranscript", "Global", "ctrl+o");
|
||||
if (isInSubAgent || inVirtualList) {
|
||||
return null;
|
||||
}
|
||||
let t0;
|
||||
if ($[0] !== expandShortcut) {
|
||||
t0 = <Text dimColor={true}><KeyboardShortcutHint shortcut={expandShortcut} action="expand" parens={true} /></Text>;
|
||||
$[0] = expandShortcut;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
export function ctrlOToExpand(): string {
|
||||
const shortcut = getShortcutDisplay('app:toggleTranscript', 'Global', 'ctrl+o');
|
||||
return chalk.dim(`(${shortcut} to expand)`);
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjaGFsayIsIlJlYWN0IiwidXNlQ29udGV4dCIsIlRleHQiLCJnZXRTaG9ydGN1dERpc3BsYXkiLCJ1c2VTaG9ydGN1dERpc3BsYXkiLCJLZXlib2FyZFNob3J0Y3V0SGludCIsIkluVmlydHVhbExpc3RDb250ZXh0IiwiU3ViQWdlbnRDb250ZXh0IiwiY3JlYXRlQ29udGV4dCIsIlN1YkFnZW50UHJvdmlkZXIiLCJ0MCIsIiQiLCJfYyIsImNoaWxkcmVuIiwidDEiLCJDdHJsT1RvRXhwYW5kIiwiaXNJblN1YkFnZW50IiwiaW5WaXJ0dWFsTGlzdCIsImV4cGFuZFNob3J0Y3V0IiwiY3RybE9Ub0V4cGFuZCIsInNob3J0Y3V0IiwiZGltIl0sInNvdXJjZXMiOlsiQ3RybE9Ub0V4cGFuZC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJ1xuaW1wb3J0IFJlYWN0LCB7IHVzZUNvbnRleHQgfSBmcm9tICdyZWFjdCdcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5pbXBvcnQgeyBnZXRTaG9ydGN1dERpc3BsYXkgfSBmcm9tICcuLi9rZXliaW5kaW5ncy9zaG9ydGN1dEZvcm1hdC5qcydcbmltcG9ydCB7IHVzZVNob3J0Y3V0RGlzcGxheSB9IGZyb20gJy4uL2tleWJpbmRpbmdzL3VzZVNob3J0Y3V0RGlzcGxheS5qcydcbmltcG9ydCB7IEtleWJvYXJkU2hvcnRjdXRIaW50IH0gZnJvbSAnLi9kZXNpZ24tc3lzdGVtL0tleWJvYXJkU2hvcnRjdXRIaW50LmpzJ1xuaW1wb3J0IHsgSW5WaXJ0dWFsTGlzdENvbnRleHQgfSBmcm9tICcuL21lc3NhZ2VBY3Rpb25zLmpzJ1xuXG4vLyBDb250ZXh0IHRvIHRyYWNrIGlmIHdlJ3JlIGluc2lkZSBhIHN1YiBhZ2VudFxuLy8gU2ltaWxhciB0byBNZXNzYWdlUmVzcG9uc2VDb250ZXh0LCB0aGlzIGhlbHBzIHVzIGF2b2lkIHNob3dpbmdcbi8vIHRvbyBtYW55IFwiKGN0cmwrbyB0byBleHBhbmQpXCIgaGludHMgaW4gc3ViIGFnZW50IG91dHB1dFxuY29uc3QgU3ViQWdlbnRDb250ZXh0ID0gUmVhY3QuY3JlYXRlQ29udGV4dChmYWxzZSlcblxuZXhwb3J0IGZ1bmN0aW9uIFN1YkFnZW50UHJvdmlkZXIoe1xuICBjaGlsZHJlbixcbn06IHtcbiAgY2hpbGRyZW46IFJlYWN0LlJlYWN0Tm9kZVxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPFN1YkFnZW50Q29udGV4dC5Qcm92aWRlciB2YWx1ZT17dHJ1ZX0+e2NoaWxkcmVufTwvU3ViQWdlbnRDb250ZXh0LlByb3ZpZGVyPlxuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBDdHJsT1RvRXhwYW5kKCk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IGlzSW5TdWJBZ2VudCA9IHVzZUNvbnRleHQoU3ViQWdlbnRDb250ZXh0KVxuICBjb25zdCBpblZpcnR1YWxMaXN0ID0gdXNlQ29udGV4dChJblZpcnR1YWxMaXN0Q29udGV4dClcbiAgY29uc3QgZXhwYW5kU2hvcnRjdXQgPSB1c2VTaG9ydGN1dERpc3BsYXkoXG4gICAgJ2FwcDp0b2dnbGVUcmFuc2NyaXB0JyxcbiAgICAnR2xvYmFsJyxcbiAgICAnY3RybCtvJyxcbiAgKVxuICBpZiAoaXNJblN1YkFnZW50IHx8IGluVmlydHVhbExpc3QpIHtcbiAgICByZXR1cm4gbnVsbFxuICB9XG4gIHJldHVybiAoXG4gICAgPFRleHQgZGltQ29sb3I+XG4gICAgICA8S2V5Ym9hcmRTaG9ydGN1dEhpbnQgc2hvcnRjdXQ9e2V4cGFuZFNob3J0Y3V0fSBhY3Rpb249XCJleHBhbmRcIiBwYXJlbnMgLz5cbiAgICA8L1RleHQ+XG4gIClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGN0cmxPVG9FeHBhbmQoKTogc3RyaW5nIHtcbiAgY29uc3Qgc2hvcnRjdXQgPSBnZXRTaG9ydGN1dERpc3BsYXkoXG4gICAgJ2FwcDp0b2dnbGVUcmFuc2NyaXB0JyxcbiAgICAnR2xvYmFsJyxcbiAgICAnY3RybCtvJyxcbiAgKVxuICByZXR1cm4gY2hhbGsuZGltKGAoJHtzaG9ydGN1dH0gdG8gZXhwYW5kKWApXG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPQSxLQUFLLE1BQU0sT0FBTztBQUN6QixPQUFPQyxLQUFLLElBQUlDLFVBQVUsUUFBUSxPQUFPO0FBQ3pDLFNBQVNDLElBQUksUUFBUSxXQUFXO0FBQ2hDLFNBQVNDLGtCQUFrQixRQUFRLGtDQUFrQztBQUNyRSxTQUFTQyxrQkFBa0IsUUFBUSxzQ0FBc0M7QUFDekUsU0FBU0Msb0JBQW9CLFFBQVEseUNBQXlDO0FBQzlFLFNBQVNDLG9CQUFvQixRQUFRLHFCQUFxQjs7QUFFMUQ7QUFDQTtBQUNBO0FBQ0EsTUFBTUMsZUFBZSxHQUFHUCxLQUFLLENBQUNRLGFBQWEsQ0FBQyxLQUFLLENBQUM7QUFFbEQsT0FBTyxTQUFBQyxpQkFBQUMsRUFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUEwQjtJQUFBQztFQUFBLElBQUFILEVBSWhDO0VBQUEsSUFBQUksRUFBQTtFQUFBLElBQUFILENBQUEsUUFBQUUsUUFBQTtJQUVHQyxFQUFBLDZCQUFpQyxLQUFJLENBQUosS0FBRyxDQUFDLENBQUdELFNBQU8sQ0FBRSwyQkFBMkI7SUFBQUYsQ0FBQSxNQUFBRSxRQUFBO0lBQUFGLENBQUEsTUFBQUcsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUgsQ0FBQTtFQUFBO0VBQUEsT0FBNUVHLEVBQTRFO0FBQUE7QUFJaEYsT0FBTyxTQUFBQyxjQUFBO0VBQUEsTUFBQUosQ0FBQSxHQUFBQyxFQUFBO0VBQ0wsTUFBQUksWUFBQSxHQUFxQmYsVUFBVSxDQUFDTSxlQUFlLENBQUM7RUFDaEQsTUFBQVUsYUFBQSxHQUFzQmhCLFVBQVUsQ0FBQ0ssb0JBQW9CLENBQUM7RUFDdEQsTUFBQVksY0FBQSxHQUF1QmQsa0JBQWtCLENBQ3ZDLHNCQUFzQixFQUN0QixRQUFRLEVBQ1IsUUFDRixDQUFDO0VBQ0QsSUFBSVksWUFBNkIsSUFBN0JDLGFBQTZCO0lBQUEsT0FDeEIsSUFBSTtFQUFBO0VBQ1osSUFBQVAsRUFBQTtFQUFBLElBQUFDLENBQUEsUUFBQU8sY0FBQTtJQUVDUixFQUFBLElBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBUixLQUFPLENBQUMsQ0FDWixDQUFDLG9CQUFvQixDQUFXUSxRQUFjLENBQWRBLGVBQWEsQ0FBQyxDQUFTLE1BQVEsQ0FBUixRQUFRLENBQUMsTUFBTSxDQUFOLEtBQUssQ0FBQyxHQUN4RSxFQUZDLElBQUksQ0FFRTtJQUFBUCxDQUFBLE1BQUFPLGNBQUE7SUFBQVAsQ0FBQSxNQUFBRCxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBQyxDQUFBO0VBQUE7RUFBQSxPQUZQRCxFQUVPO0FBQUE7QUFJWCxPQUFPLFNBQVNTLGFBQWFBLENBQUEsQ0FBRSxFQUFFLE1BQU0sQ0FBQztFQUN0QyxNQUFNQyxRQUFRLEdBQUdqQixrQkFBa0IsQ0FDakMsc0JBQXNCLEVBQ3RCLFFBQVEsRUFDUixRQUNGLENBQUM7RUFDRCxPQUFPSixLQUFLLENBQUNzQixHQUFHLENBQUMsSUFBSUQsUUFBUSxhQUFhLENBQUM7QUFDN0MiLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
213
src/components/CustomSelect/SelectMulti.tsx
Normal file
213
src/components/CustomSelect/SelectMulti.tsx
Normal file
File diff suppressed because one or more lines are too long
3
src/components/CustomSelect/index.ts
Normal file
3
src/components/CustomSelect/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './SelectMulti.js'
|
||||
export type { OptionWithDescription } from './select.js'
|
||||
export * from './select.js'
|
||||
50
src/components/CustomSelect/option-map.ts
Normal file
50
src/components/CustomSelect/option-map.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import type { OptionWithDescription } from './select.js'
|
||||
|
||||
type OptionMapItem<T> = {
|
||||
label: ReactNode
|
||||
value: T
|
||||
description?: string
|
||||
previous: OptionMapItem<T> | undefined
|
||||
next: OptionMapItem<T> | undefined
|
||||
index: number
|
||||
}
|
||||
|
||||
export default class OptionMap<T> extends Map<T, OptionMapItem<T>> {
|
||||
readonly first: OptionMapItem<T> | undefined
|
||||
readonly last: OptionMapItem<T> | undefined
|
||||
|
||||
constructor(options: OptionWithDescription<T>[]) {
|
||||
const items: Array<[T, OptionMapItem<T>]> = []
|
||||
let firstItem: OptionMapItem<T> | undefined
|
||||
let lastItem: OptionMapItem<T> | undefined
|
||||
let previous: OptionMapItem<T> | undefined
|
||||
let index = 0
|
||||
|
||||
for (const option of options) {
|
||||
const item = {
|
||||
label: option.label,
|
||||
value: option.value,
|
||||
description: option.description,
|
||||
previous,
|
||||
next: undefined,
|
||||
index,
|
||||
}
|
||||
|
||||
if (previous) {
|
||||
previous.next = item
|
||||
}
|
||||
|
||||
firstItem ||= item
|
||||
lastItem = item
|
||||
|
||||
items.push([option.value, item])
|
||||
index++
|
||||
previous = item
|
||||
}
|
||||
|
||||
super(items)
|
||||
this.first = firstItem
|
||||
this.last = lastItem
|
||||
}
|
||||
}
|
||||
488
src/components/CustomSelect/select-input-option.tsx
Normal file
488
src/components/CustomSelect/select-input-option.tsx
Normal file
File diff suppressed because one or more lines are too long
68
src/components/CustomSelect/select-option.tsx
Normal file
68
src/components/CustomSelect/select-option.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React, { type ReactNode } from 'react';
|
||||
import { ListItem } from '../design-system/ListItem.js';
|
||||
export type SelectOptionProps = {
|
||||
/**
|
||||
* Determines if option is focused.
|
||||
*/
|
||||
readonly isFocused: boolean;
|
||||
|
||||
/**
|
||||
* Determines if option is selected.
|
||||
*/
|
||||
readonly isSelected: boolean;
|
||||
|
||||
/**
|
||||
* Option label.
|
||||
*/
|
||||
readonly children: ReactNode;
|
||||
|
||||
/**
|
||||
* Optional description to display below the label.
|
||||
*/
|
||||
readonly description?: string;
|
||||
|
||||
/**
|
||||
* Determines if the down arrow should be shown.
|
||||
*/
|
||||
readonly shouldShowDownArrow?: boolean;
|
||||
|
||||
/**
|
||||
* Determines if the up arrow should be shown.
|
||||
*/
|
||||
readonly shouldShowUpArrow?: boolean;
|
||||
|
||||
/**
|
||||
* Whether ListItem should declare the terminal cursor position.
|
||||
* Set false when a child declares its own cursor (e.g. BaseTextInput).
|
||||
*/
|
||||
readonly declareCursor?: boolean;
|
||||
};
|
||||
export function SelectOption(t0) {
|
||||
const $ = _c(8);
|
||||
const {
|
||||
isFocused,
|
||||
isSelected,
|
||||
children,
|
||||
description,
|
||||
shouldShowDownArrow,
|
||||
shouldShowUpArrow,
|
||||
declareCursor
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== children || $[1] !== declareCursor || $[2] !== description || $[3] !== isFocused || $[4] !== isSelected || $[5] !== shouldShowDownArrow || $[6] !== shouldShowUpArrow) {
|
||||
t1 = <ListItem isFocused={isFocused} isSelected={isSelected} description={description} showScrollDown={shouldShowDownArrow} showScrollUp={shouldShowUpArrow} styled={false} declareCursor={declareCursor}>{children}</ListItem>;
|
||||
$[0] = children;
|
||||
$[1] = declareCursor;
|
||||
$[2] = description;
|
||||
$[3] = isFocused;
|
||||
$[4] = isSelected;
|
||||
$[5] = shouldShowDownArrow;
|
||||
$[6] = shouldShowUpArrow;
|
||||
$[7] = t1;
|
||||
} else {
|
||||
t1 = $[7];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlJlYWN0Tm9kZSIsIkxpc3RJdGVtIiwiU2VsZWN0T3B0aW9uUHJvcHMiLCJpc0ZvY3VzZWQiLCJpc1NlbGVjdGVkIiwiY2hpbGRyZW4iLCJkZXNjcmlwdGlvbiIsInNob3VsZFNob3dEb3duQXJyb3ciLCJzaG91bGRTaG93VXBBcnJvdyIsImRlY2xhcmVDdXJzb3IiLCJTZWxlY3RPcHRpb24iLCJ0MCIsIiQiLCJfYyIsInQxIl0sInNvdXJjZXMiOlsic2VsZWN0LW9wdGlvbi50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0LCB7IHR5cGUgUmVhY3ROb2RlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBMaXN0SXRlbSB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vTGlzdEl0ZW0uanMnXG5cbmV4cG9ydCB0eXBlIFNlbGVjdE9wdGlvblByb3BzID0ge1xuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiBvcHRpb24gaXMgZm9jdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IGlzRm9jdXNlZDogYm9vbGVhblxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIG9wdGlvbiBpcyBzZWxlY3RlZC5cbiAgICovXG4gIHJlYWRvbmx5IGlzU2VsZWN0ZWQ6IGJvb2xlYW5cblxuICAvKipcbiAgICogT3B0aW9uIGxhYmVsLlxuICAgKi9cbiAgcmVhZG9ubHkgY2hpbGRyZW46IFJlYWN0Tm9kZVxuXG4gIC8qKlxuICAgKiBPcHRpb25hbCBkZXNjcmlwdGlvbiB0byBkaXNwbGF5IGJlbG93IHRoZSBsYWJlbC5cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nXG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgaWYgdGhlIGRvd24gYXJyb3cgc2hvdWxkIGJlIHNob3duLlxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkU2hvd0Rvd25BcnJvdz86IGJvb2xlYW5cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiB0aGUgdXAgYXJyb3cgc2hvdWxkIGJlIHNob3duLlxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkU2hvd1VwQXJyb3c/OiBib29sZWFuXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgTGlzdEl0ZW0gc2hvdWxkIGRlY2xhcmUgdGhlIHRlcm1pbmFsIGN1cnNvciBwb3NpdGlvbi5cbiAgICogU2V0IGZhbHNlIHdoZW4gYSBjaGlsZCBkZWNsYXJlcyBpdHMgb3duIGN1cnNvciAoZS5nLiBCYXNlVGV4dElucHV0KS5cbiAgICovXG4gIHJlYWRvbmx5IGRlY2xhcmVDdXJzb3I/OiBib29sZWFuXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBTZWxlY3RPcHRpb24oe1xuICBpc0ZvY3VzZWQsXG4gIGlzU2VsZWN0ZWQsXG4gIGNoaWxkcmVuLFxuICBkZXNjcmlwdGlvbixcbiAgc2hvdWxkU2hvd0Rvd25BcnJvdyxcbiAgc2hvdWxkU2hvd1VwQXJyb3csXG4gIGRlY2xhcmVDdXJzb3IsXG59OiBTZWxlY3RPcHRpb25Qcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPExpc3RJdGVtXG4gICAgICBpc0ZvY3VzZWQ9e2lzRm9jdXNlZH1cbiAgICAgIGlzU2VsZWN0ZWQ9e2lzU2VsZWN0ZWR9XG4gICAgICBkZXNjcmlwdGlvbj17ZGVzY3JpcHRpb259XG4gICAgICBzaG93U2Nyb2xsRG93bj17c2hvdWxkU2hvd0Rvd25BcnJvd31cbiAgICAgIHNob3dTY3JvbGxVcD17c2hvdWxkU2hvd1VwQXJyb3d9XG4gICAgICBzdHlsZWQ9e2ZhbHNlfVxuICAgICAgZGVjbGFyZUN1cnNvcj17ZGVjbGFyZUN1cnNvcn1cbiAgICA+XG4gICAgICB7Y2hpbGRyZW59XG4gICAgPC9MaXN0SXRlbT5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxJQUFJLEtBQUtDLFNBQVMsUUFBUSxPQUFPO0FBQzdDLFNBQVNDLFFBQVEsUUFBUSw4QkFBOEI7QUFFdkQsT0FBTyxLQUFLQyxpQkFBaUIsR0FBRztFQUM5QjtBQUNGO0FBQ0E7RUFDRSxTQUFTQyxTQUFTLEVBQUUsT0FBTzs7RUFFM0I7QUFDRjtBQUNBO0VBQ0UsU0FBU0MsVUFBVSxFQUFFLE9BQU87O0VBRTVCO0FBQ0Y7QUFDQTtFQUNFLFNBQVNDLFFBQVEsRUFBRUwsU0FBUzs7RUFFNUI7QUFDRjtBQUNBO0VBQ0UsU0FBU00sV0FBVyxDQUFDLEVBQUUsTUFBTTs7RUFFN0I7QUFDRjtBQUNBO0VBQ0UsU0FBU0MsbUJBQW1CLENBQUMsRUFBRSxPQUFPOztFQUV0QztBQUNGO0FBQ0E7RUFDRSxTQUFTQyxpQkFBaUIsQ0FBQyxFQUFFLE9BQU87O0VBRXBDO0FBQ0Y7QUFDQTtBQUNBO0VBQ0UsU0FBU0MsYUFBYSxDQUFDLEVBQUUsT0FBTztBQUNsQyxDQUFDO0FBRUQsT0FBTyxTQUFBQyxhQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQXNCO0lBQUFWLFNBQUE7SUFBQUMsVUFBQTtJQUFBQyxRQUFBO0lBQUFDLFdBQUE7SUFBQUMsbUJBQUE7SUFBQUMsaUJBQUE7SUFBQUM7RUFBQSxJQUFBRSxFQVFUO0VBQUEsSUFBQUcsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQVAsUUFBQSxJQUFBTyxDQUFBLFFBQUFILGFBQUEsSUFBQUcsQ0FBQSxRQUFBTixXQUFBLElBQUFNLENBQUEsUUFBQVQsU0FBQSxJQUFBUyxDQUFBLFFBQUFSLFVBQUEsSUFBQVEsQ0FBQSxRQUFBTCxtQkFBQSxJQUFBSyxDQUFBLFFBQUFKLGlCQUFBO0lBRWhCTSxFQUFBLElBQUMsUUFBUSxDQUNJWCxTQUFTLENBQVRBLFVBQVEsQ0FBQyxDQUNSQyxVQUFVLENBQVZBLFdBQVMsQ0FBQyxDQUNURSxXQUFXLENBQVhBLFlBQVUsQ0FBQyxDQUNSQyxjQUFtQixDQUFuQkEsb0JBQWtCLENBQUMsQ0FDckJDLFlBQWlCLENBQWpCQSxrQkFBZ0IsQ0FBQyxDQUN2QixNQUFLLENBQUwsTUFBSSxDQUFDLENBQ0VDLGFBQWEsQ0FBYkEsY0FBWSxDQUFDLENBRTNCSixTQUFPLENBQ1YsRUFWQyxRQUFRLENBVUU7SUFBQU8sQ0FBQSxNQUFBUCxRQUFBO0lBQUFPLENBQUEsTUFBQUgsYUFBQTtJQUFBRyxDQUFBLE1BQUFOLFdBQUE7SUFBQU0sQ0FBQSxNQUFBVCxTQUFBO0lBQUFTLENBQUEsTUFBQVIsVUFBQTtJQUFBUSxDQUFBLE1BQUFMLG1CQUFBO0lBQUFLLENBQUEsTUFBQUosaUJBQUE7SUFBQUksQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxPQVZYRSxFQVVXO0FBQUEiLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
690
src/components/CustomSelect/select.tsx
Normal file
690
src/components/CustomSelect/select.tsx
Normal file
File diff suppressed because one or more lines are too long
414
src/components/CustomSelect/use-multi-select-state.ts
Normal file
414
src/components/CustomSelect/use-multi-select-state.ts
Normal file
@@ -0,0 +1,414 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
import { isDeepStrictEqual } from 'util'
|
||||
import { useRegisterOverlay } from '../../context/overlayContext.js'
|
||||
import type { InputEvent } from '../../ink/events/input-event.js'
|
||||
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- raw space/arrow multiselect input
|
||||
import { useInput } from '../../ink.js'
|
||||
import {
|
||||
normalizeFullWidthDigits,
|
||||
normalizeFullWidthSpace,
|
||||
} from '../../utils/stringUtils.js'
|
||||
import type { OptionWithDescription } from './select.js'
|
||||
import { useSelectNavigation } from './use-select-navigation.js'
|
||||
|
||||
export type UseMultiSelectStateProps<T> = {
|
||||
/**
|
||||
* When disabled, user input is ignored.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
isDisabled?: boolean
|
||||
|
||||
/**
|
||||
* Number of items to display.
|
||||
*
|
||||
* @default 5
|
||||
*/
|
||||
visibleOptionCount?: number
|
||||
|
||||
/**
|
||||
* Options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Initially selected values.
|
||||
*/
|
||||
defaultValue?: T[]
|
||||
|
||||
/**
|
||||
* Callback when selection changes.
|
||||
*/
|
||||
onChange?: (values: T[]) => void
|
||||
|
||||
/**
|
||||
* Callback for canceling the select.
|
||||
*/
|
||||
onCancel: () => void
|
||||
|
||||
/**
|
||||
* Callback for focusing an option.
|
||||
*/
|
||||
onFocus?: (value: T) => void
|
||||
|
||||
/**
|
||||
* Value to focus
|
||||
*/
|
||||
focusValue?: T
|
||||
|
||||
/**
|
||||
* Text for the submit button. When provided, a submit button is shown and
|
||||
* Enter toggles selection (submit only fires when the button is focused).
|
||||
* When omitted, Enter submits directly and Space toggles selection.
|
||||
*/
|
||||
submitButtonText?: string
|
||||
|
||||
/**
|
||||
* Callback when user submits. Receives the currently selected values.
|
||||
*/
|
||||
onSubmit?: (values: T[]) => void
|
||||
|
||||
/**
|
||||
* Callback when user presses down from the last item (submit button).
|
||||
* If provided, navigation will not wrap to the first item.
|
||||
*/
|
||||
onDownFromLastItem?: () => void
|
||||
|
||||
/**
|
||||
* Callback when user presses up from the first item.
|
||||
* If provided, navigation will not wrap to the last item.
|
||||
*/
|
||||
onUpFromFirstItem?: () => void
|
||||
|
||||
/**
|
||||
* Focus the last option initially instead of the first.
|
||||
*/
|
||||
initialFocusLast?: boolean
|
||||
|
||||
/**
|
||||
* When true, numeric keys (1-9) do not toggle options by index.
|
||||
* Mirrors the rendering layer's hideIndexes: if index labels aren't shown,
|
||||
* pressing a number shouldn't silently toggle an invisible mapping.
|
||||
*/
|
||||
hideIndexes?: boolean
|
||||
}
|
||||
|
||||
export type MultiSelectState<T> = {
|
||||
/**
|
||||
* Value of the currently focused option.
|
||||
*/
|
||||
focusedValue: T | undefined
|
||||
|
||||
/**
|
||||
* Index of the first visible option.
|
||||
*/
|
||||
visibleFromIndex: number
|
||||
|
||||
/**
|
||||
* Index of the last visible option.
|
||||
*/
|
||||
visibleToIndex: number
|
||||
|
||||
/**
|
||||
* All options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Visible options.
|
||||
*/
|
||||
visibleOptions: Array<OptionWithDescription<T> & { index: number }>
|
||||
|
||||
/**
|
||||
* Whether the focused option is an input type.
|
||||
*/
|
||||
isInInput: boolean
|
||||
|
||||
/**
|
||||
* Currently selected values.
|
||||
*/
|
||||
selectedValues: T[]
|
||||
|
||||
/**
|
||||
* Current input field values.
|
||||
*/
|
||||
inputValues: Map<T, string>
|
||||
|
||||
/**
|
||||
* Whether the submit button is focused.
|
||||
*/
|
||||
isSubmitFocused: boolean
|
||||
|
||||
/**
|
||||
* Update an input field value.
|
||||
*/
|
||||
updateInputValue: (value: T, inputValue: string) => void
|
||||
|
||||
/**
|
||||
* Callback for canceling the select.
|
||||
*/
|
||||
onCancel: () => void
|
||||
}
|
||||
|
||||
export function useMultiSelectState<T>({
|
||||
isDisabled = false,
|
||||
visibleOptionCount = 5,
|
||||
options,
|
||||
defaultValue = [],
|
||||
onChange,
|
||||
onCancel,
|
||||
onFocus,
|
||||
focusValue,
|
||||
submitButtonText,
|
||||
onSubmit,
|
||||
onDownFromLastItem,
|
||||
onUpFromFirstItem,
|
||||
initialFocusLast,
|
||||
hideIndexes = false,
|
||||
}: UseMultiSelectStateProps<T>): MultiSelectState<T> {
|
||||
const [selectedValues, setSelectedValues] = useState<T[]>(defaultValue)
|
||||
const [isSubmitFocused, setIsSubmitFocused] = useState(false)
|
||||
|
||||
// Reset selectedValues when options change (e.g. async-loaded data changes
|
||||
// defaultValue after mount). Mirrors the reset pattern in use-select-navigation.ts
|
||||
// and the deleted ui/useMultiSelectState.ts — without this, MCPServerDesktopImportDialog
|
||||
// keeps colliding servers checked after getAllMcpConfigs() resolves.
|
||||
const [lastOptions, setLastOptions] = useState(options)
|
||||
if (options !== lastOptions && !isDeepStrictEqual(options, lastOptions)) {
|
||||
setSelectedValues(defaultValue)
|
||||
setLastOptions(options)
|
||||
}
|
||||
|
||||
// State for input type options
|
||||
const [inputValues, setInputValues] = useState<Map<T, string>>(() => {
|
||||
const initialMap = new Map<T, string>()
|
||||
options.forEach(option => {
|
||||
if (option.type === 'input' && option.initialValue) {
|
||||
initialMap.set(option.value, option.initialValue)
|
||||
}
|
||||
})
|
||||
return initialMap
|
||||
})
|
||||
|
||||
const updateSelectedValues = useCallback(
|
||||
(values: T[] | ((prev: T[]) => T[])) => {
|
||||
const newValues =
|
||||
typeof values === 'function' ? values(selectedValues) : values
|
||||
setSelectedValues(newValues)
|
||||
onChange?.(newValues)
|
||||
},
|
||||
[selectedValues, onChange],
|
||||
)
|
||||
|
||||
const navigation = useSelectNavigation<T>({
|
||||
visibleOptionCount,
|
||||
options,
|
||||
initialFocusValue: initialFocusLast
|
||||
? options[options.length - 1]?.value
|
||||
: undefined,
|
||||
onFocus,
|
||||
focusValue,
|
||||
})
|
||||
|
||||
// Automatically register as an overlay.
|
||||
// This ensures CancelRequestHandler won't intercept Escape when the multi-select is active.
|
||||
useRegisterOverlay('multi-select')
|
||||
|
||||
const updateInputValue = useCallback(
|
||||
(value: T, inputValue: string) => {
|
||||
setInputValues(prev => {
|
||||
const next = new Map(prev)
|
||||
next.set(value, inputValue)
|
||||
return next
|
||||
})
|
||||
|
||||
// Find the option and call its onChange
|
||||
const option = options.find(opt => opt.value === value)
|
||||
if (option && option.type === 'input') {
|
||||
option.onChange(inputValue)
|
||||
}
|
||||
|
||||
// Update selected values to include/exclude based on input
|
||||
updateSelectedValues(prev => {
|
||||
if (inputValue) {
|
||||
if (!prev.includes(value)) {
|
||||
return [...prev, value]
|
||||
}
|
||||
return prev
|
||||
} else {
|
||||
return prev.filter(v => v !== value)
|
||||
}
|
||||
})
|
||||
},
|
||||
[options, updateSelectedValues],
|
||||
)
|
||||
|
||||
// Handle all keyboard input
|
||||
useInput(
|
||||
(input, key, event: InputEvent) => {
|
||||
const normalizedInput = normalizeFullWidthDigits(input)
|
||||
const focusedOption = options.find(
|
||||
opt => opt.value === navigation.focusedValue,
|
||||
)
|
||||
const isInInput = focusedOption?.type === 'input'
|
||||
|
||||
// When in input field, only allow navigation keys
|
||||
if (isInInput) {
|
||||
const isAllowedKey =
|
||||
key.upArrow ||
|
||||
key.downArrow ||
|
||||
key.escape ||
|
||||
key.tab ||
|
||||
key.return ||
|
||||
(key.ctrl && (input === 'n' || input === 'p' || key.return))
|
||||
if (!isAllowedKey) return
|
||||
}
|
||||
|
||||
const lastOptionValue = options[options.length - 1]?.value
|
||||
|
||||
// Handle Tab to move forward
|
||||
if (key.tab && !key.shift) {
|
||||
if (
|
||||
submitButtonText &&
|
||||
onSubmit &&
|
||||
navigation.focusedValue === lastOptionValue &&
|
||||
!isSubmitFocused
|
||||
) {
|
||||
setIsSubmitFocused(true)
|
||||
} else if (!isSubmitFocused) {
|
||||
navigation.focusNextOption()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle Shift+Tab to move backward
|
||||
if (key.tab && key.shift) {
|
||||
if (submitButtonText && onSubmit && isSubmitFocused) {
|
||||
setIsSubmitFocused(false)
|
||||
navigation.focusOption(lastOptionValue)
|
||||
} else {
|
||||
navigation.focusPreviousOption()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle arrow down / Ctrl+N / j
|
||||
if (
|
||||
key.downArrow ||
|
||||
(key.ctrl && input === 'n') ||
|
||||
(!key.ctrl && !key.shift && input === 'j')
|
||||
) {
|
||||
if (isSubmitFocused && onDownFromLastItem) {
|
||||
onDownFromLastItem()
|
||||
} else if (
|
||||
submitButtonText &&
|
||||
onSubmit &&
|
||||
navigation.focusedValue === lastOptionValue &&
|
||||
!isSubmitFocused
|
||||
) {
|
||||
setIsSubmitFocused(true)
|
||||
} else if (
|
||||
!submitButtonText &&
|
||||
onDownFromLastItem &&
|
||||
navigation.focusedValue === lastOptionValue
|
||||
) {
|
||||
// No submit button — exit from the last option
|
||||
onDownFromLastItem()
|
||||
} else if (!isSubmitFocused) {
|
||||
navigation.focusNextOption()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle arrow up / Ctrl+P / k
|
||||
if (
|
||||
key.upArrow ||
|
||||
(key.ctrl && input === 'p') ||
|
||||
(!key.ctrl && !key.shift && input === 'k')
|
||||
) {
|
||||
if (submitButtonText && onSubmit && isSubmitFocused) {
|
||||
setIsSubmitFocused(false)
|
||||
navigation.focusOption(lastOptionValue)
|
||||
} else if (
|
||||
onUpFromFirstItem &&
|
||||
navigation.focusedValue === options[0]?.value
|
||||
) {
|
||||
onUpFromFirstItem()
|
||||
} else {
|
||||
navigation.focusPreviousOption()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle page navigation
|
||||
if (key.pageDown) {
|
||||
navigation.focusNextPage()
|
||||
return
|
||||
}
|
||||
|
||||
if (key.pageUp) {
|
||||
navigation.focusPreviousPage()
|
||||
return
|
||||
}
|
||||
|
||||
// Handle Enter or Space for selection/submit
|
||||
if (key.return || normalizeFullWidthSpace(input) === ' ') {
|
||||
// Ctrl+Enter from input field submits
|
||||
if (key.ctrl && key.return && isInInput && onSubmit) {
|
||||
onSubmit(selectedValues)
|
||||
return
|
||||
}
|
||||
|
||||
// Enter on submit button submits
|
||||
if (isSubmitFocused && onSubmit) {
|
||||
onSubmit(selectedValues)
|
||||
return
|
||||
}
|
||||
|
||||
// No submit button: Enter submits directly, Space still toggles
|
||||
if (key.return && !submitButtonText && onSubmit) {
|
||||
onSubmit(selectedValues)
|
||||
return
|
||||
}
|
||||
|
||||
// Enter or Space toggles selection (including for input fields)
|
||||
if (navigation.focusedValue !== undefined) {
|
||||
const newValues = selectedValues.includes(navigation.focusedValue)
|
||||
? selectedValues.filter(v => v !== navigation.focusedValue)
|
||||
: [...selectedValues, navigation.focusedValue]
|
||||
updateSelectedValues(newValues)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle numeric keys (1-9) for direct selection
|
||||
if (!hideIndexes && /^[0-9]+$/.test(normalizedInput)) {
|
||||
const index = parseInt(normalizedInput) - 1
|
||||
if (index >= 0 && index < options.length) {
|
||||
const value = options[index]!.value
|
||||
const newValues = selectedValues.includes(value)
|
||||
? selectedValues.filter(v => v !== value)
|
||||
: [...selectedValues, value]
|
||||
updateSelectedValues(newValues)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle Escape
|
||||
if (key.escape) {
|
||||
onCancel()
|
||||
event.stopImmediatePropagation()
|
||||
}
|
||||
},
|
||||
{ isActive: !isDisabled },
|
||||
)
|
||||
|
||||
return {
|
||||
...navigation,
|
||||
selectedValues,
|
||||
inputValues,
|
||||
isSubmitFocused,
|
||||
updateInputValue,
|
||||
onCancel,
|
||||
}
|
||||
}
|
||||
287
src/components/CustomSelect/use-select-input.ts
Normal file
287
src/components/CustomSelect/use-select-input.ts
Normal file
@@ -0,0 +1,287 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useRegisterOverlay } from '../../context/overlayContext.js'
|
||||
import type { InputEvent } from '../../ink/events/input-event.js'
|
||||
import { useInput } from '../../ink.js'
|
||||
import { useKeybindings } from '../../keybindings/useKeybinding.js'
|
||||
import {
|
||||
normalizeFullWidthDigits,
|
||||
normalizeFullWidthSpace,
|
||||
} from '../../utils/stringUtils.js'
|
||||
import type { OptionWithDescription } from './select.js'
|
||||
import type { SelectState } from './use-select-state.js'
|
||||
|
||||
export type UseSelectProps<T> = {
|
||||
/**
|
||||
* When disabled, user input is ignored.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
isDisabled?: boolean
|
||||
|
||||
/**
|
||||
* When true, prevents selection on Enter or number keys, but allows
|
||||
* scrolling.
|
||||
* When 'numeric', prevents selection on number keys, but allows Enter (and
|
||||
* scrolling).
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly disableSelection?: boolean | 'numeric'
|
||||
|
||||
/**
|
||||
* Select state.
|
||||
*/
|
||||
state: SelectState<T>
|
||||
|
||||
/**
|
||||
* Options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Whether this is a multi-select component.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
isMultiSelect?: boolean
|
||||
|
||||
/**
|
||||
* Callback when user presses up from the first item.
|
||||
* If provided, navigation will not wrap to the last item.
|
||||
*/
|
||||
onUpFromFirstItem?: () => void
|
||||
|
||||
/**
|
||||
* Callback when user presses down from the last item.
|
||||
* If provided, navigation will not wrap to the first item.
|
||||
*/
|
||||
onDownFromLastItem?: () => void
|
||||
|
||||
/**
|
||||
* Callback when input mode should be toggled for an option.
|
||||
* Called when Tab is pressed (to enter or exit input mode).
|
||||
*/
|
||||
onInputModeToggle?: (value: T) => void
|
||||
|
||||
/**
|
||||
* Current input values for input-type options.
|
||||
* Used to determine if number key should submit an empty input option.
|
||||
*/
|
||||
inputValues?: Map<T, string>
|
||||
|
||||
/**
|
||||
* Whether image selection mode is active on the focused input option.
|
||||
* When true, arrow key navigation in useInput is suppressed so that
|
||||
* Attachments keybindings can handle image navigation instead.
|
||||
*/
|
||||
imagesSelected?: boolean
|
||||
|
||||
/**
|
||||
* Callback to attempt entering image selection mode on DOWN arrow.
|
||||
* Returns true if image selection was entered (images exist), false otherwise.
|
||||
*/
|
||||
onEnterImageSelection?: () => boolean
|
||||
}
|
||||
|
||||
export const useSelectInput = <T>({
|
||||
isDisabled = false,
|
||||
disableSelection = false,
|
||||
state,
|
||||
options,
|
||||
isMultiSelect = false,
|
||||
onUpFromFirstItem,
|
||||
onDownFromLastItem,
|
||||
onInputModeToggle,
|
||||
inputValues,
|
||||
imagesSelected = false,
|
||||
onEnterImageSelection,
|
||||
}: UseSelectProps<T>) => {
|
||||
// Automatically register as an overlay when onCancel is provided.
|
||||
// This ensures CancelRequestHandler won't intercept Escape when the select is active.
|
||||
useRegisterOverlay('select', !!state.onCancel)
|
||||
|
||||
// Determine if the focused option is an input type
|
||||
const isInInput = useMemo(() => {
|
||||
const focusedOption = options.find(opt => opt.value === state.focusedValue)
|
||||
return focusedOption?.type === 'input'
|
||||
}, [options, state.focusedValue])
|
||||
|
||||
// Core navigation via keybindings (up/down/enter/escape)
|
||||
// When in input mode, exclude navigation/accept keybindings so that
|
||||
// j/k/enter pass through to the TextInput instead of being intercepted.
|
||||
const keybindingHandlers = useMemo(() => {
|
||||
const handlers: Record<string, () => void> = {}
|
||||
|
||||
if (!isInInput) {
|
||||
handlers['select:next'] = () => {
|
||||
if (onDownFromLastItem) {
|
||||
const lastOption = options[options.length - 1]
|
||||
if (lastOption && state.focusedValue === lastOption.value) {
|
||||
onDownFromLastItem()
|
||||
return
|
||||
}
|
||||
}
|
||||
state.focusNextOption()
|
||||
}
|
||||
handlers['select:previous'] = () => {
|
||||
if (onUpFromFirstItem && state.visibleFromIndex === 0) {
|
||||
const firstOption = options[0]
|
||||
if (firstOption && state.focusedValue === firstOption.value) {
|
||||
onUpFromFirstItem()
|
||||
return
|
||||
}
|
||||
}
|
||||
state.focusPreviousOption()
|
||||
}
|
||||
handlers['select:accept'] = () => {
|
||||
if (disableSelection === true) return
|
||||
if (state.focusedValue === undefined) return
|
||||
|
||||
const focusedOption = options.find(
|
||||
opt => opt.value === state.focusedValue,
|
||||
)
|
||||
if (focusedOption?.disabled === true) return
|
||||
|
||||
state.selectFocusedOption?.()
|
||||
state.onChange?.(state.focusedValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.onCancel) {
|
||||
handlers['select:cancel'] = () => {
|
||||
state.onCancel!()
|
||||
}
|
||||
}
|
||||
|
||||
return handlers
|
||||
}, [
|
||||
options,
|
||||
state,
|
||||
onDownFromLastItem,
|
||||
onUpFromFirstItem,
|
||||
isInInput,
|
||||
disableSelection,
|
||||
])
|
||||
|
||||
useKeybindings(keybindingHandlers, {
|
||||
context: 'Select',
|
||||
isActive: !isDisabled,
|
||||
})
|
||||
|
||||
// Remaining keys that stay as useInput: number keys, pageUp/pageDown, tab, space,
|
||||
// and arrow key navigation when in input mode
|
||||
useInput(
|
||||
(input, key, event: InputEvent) => {
|
||||
const normalizedInput = normalizeFullWidthDigits(input)
|
||||
const focusedOption = options.find(
|
||||
opt => opt.value === state.focusedValue,
|
||||
)
|
||||
const currentIsInInput = focusedOption?.type === 'input'
|
||||
|
||||
// Handle Tab key for input mode toggling
|
||||
if (key.tab && onInputModeToggle && state.focusedValue !== undefined) {
|
||||
onInputModeToggle(state.focusedValue)
|
||||
return
|
||||
}
|
||||
|
||||
if (currentIsInInput) {
|
||||
// When in image selection mode, suppress all input handling so
|
||||
// Attachments keybindings can handle navigation/deletion instead
|
||||
if (imagesSelected) return
|
||||
|
||||
// DOWN arrow enters image selection mode if images exist
|
||||
if (key.downArrow && onEnterImageSelection?.()) {
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
}
|
||||
|
||||
// Arrow keys still navigate the select even while in input mode
|
||||
if (key.downArrow || (key.ctrl && input === 'n')) {
|
||||
if (onDownFromLastItem) {
|
||||
const lastOption = options[options.length - 1]
|
||||
if (lastOption && state.focusedValue === lastOption.value) {
|
||||
onDownFromLastItem()
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
}
|
||||
}
|
||||
state.focusNextOption()
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
}
|
||||
if (key.upArrow || (key.ctrl && input === 'p')) {
|
||||
if (onUpFromFirstItem && state.visibleFromIndex === 0) {
|
||||
const firstOption = options[0]
|
||||
if (firstOption && state.focusedValue === firstOption.value) {
|
||||
onUpFromFirstItem()
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
}
|
||||
}
|
||||
state.focusPreviousOption()
|
||||
event.stopImmediatePropagation()
|
||||
return
|
||||
}
|
||||
|
||||
// All other keys (including digits) pass through to TextInput.
|
||||
// Digits should type literally into the input rather than select
|
||||
// options — the user has focused a text field and expects typing
|
||||
// to insert characters, not jump to a different option.
|
||||
return
|
||||
}
|
||||
|
||||
if (key.pageDown) {
|
||||
state.focusNextPage()
|
||||
}
|
||||
|
||||
if (key.pageUp) {
|
||||
state.focusPreviousPage()
|
||||
}
|
||||
|
||||
if (disableSelection !== true) {
|
||||
// Space for multi-select toggle
|
||||
if (
|
||||
isMultiSelect &&
|
||||
normalizeFullWidthSpace(input) === ' ' &&
|
||||
state.focusedValue !== undefined
|
||||
) {
|
||||
const isFocusedOptionDisabled = focusedOption?.disabled === true
|
||||
if (!isFocusedOptionDisabled) {
|
||||
state.selectFocusedOption?.()
|
||||
state.onChange?.(state.focusedValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
disableSelection !== 'numeric' &&
|
||||
/^[0-9]+$/.test(normalizedInput)
|
||||
) {
|
||||
const index = parseInt(normalizedInput) - 1
|
||||
if (index >= 0 && index < state.options.length) {
|
||||
const selectedOption = state.options[index]!
|
||||
if (selectedOption.disabled === true) {
|
||||
return
|
||||
}
|
||||
if (selectedOption.type === 'input') {
|
||||
const currentValue = inputValues?.get(selectedOption.value) ?? ''
|
||||
if (currentValue.trim()) {
|
||||
// Pre-filled input: auto-submit (user can Tab to edit instead)
|
||||
state.onChange?.(selectedOption.value)
|
||||
return
|
||||
}
|
||||
if (selectedOption.allowEmptySubmitToCancel) {
|
||||
state.onChange?.(selectedOption.value)
|
||||
return
|
||||
}
|
||||
state.focusOption(selectedOption.value)
|
||||
return
|
||||
}
|
||||
state.onChange?.(selectedOption.value)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ isActive: !isDisabled },
|
||||
)
|
||||
}
|
||||
653
src/components/CustomSelect/use-select-navigation.ts
Normal file
653
src/components/CustomSelect/use-select-navigation.ts
Normal file
@@ -0,0 +1,653 @@
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useReducer,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { isDeepStrictEqual } from 'util'
|
||||
import OptionMap from './option-map.js'
|
||||
import type { OptionWithDescription } from './select.js'
|
||||
|
||||
type State<T> = {
|
||||
/**
|
||||
* Map where key is option's value and value is option's index.
|
||||
*/
|
||||
optionMap: OptionMap<T>
|
||||
|
||||
/**
|
||||
* Number of visible options.
|
||||
*/
|
||||
visibleOptionCount: number
|
||||
|
||||
/**
|
||||
* Value of the currently focused option.
|
||||
*/
|
||||
focusedValue: T | undefined
|
||||
|
||||
/**
|
||||
* Index of the first visible option.
|
||||
*/
|
||||
visibleFromIndex: number
|
||||
|
||||
/**
|
||||
* Index of the last visible option.
|
||||
*/
|
||||
visibleToIndex: number
|
||||
}
|
||||
|
||||
type Action<T> =
|
||||
| FocusNextOptionAction
|
||||
| FocusPreviousOptionAction
|
||||
| FocusNextPageAction
|
||||
| FocusPreviousPageAction
|
||||
| SetFocusAction<T>
|
||||
| ResetAction<T>
|
||||
|
||||
type SetFocusAction<T> = {
|
||||
type: 'set-focus'
|
||||
value: T
|
||||
}
|
||||
|
||||
type FocusNextOptionAction = {
|
||||
type: 'focus-next-option'
|
||||
}
|
||||
|
||||
type FocusPreviousOptionAction = {
|
||||
type: 'focus-previous-option'
|
||||
}
|
||||
|
||||
type FocusNextPageAction = {
|
||||
type: 'focus-next-page'
|
||||
}
|
||||
|
||||
type FocusPreviousPageAction = {
|
||||
type: 'focus-previous-page'
|
||||
}
|
||||
|
||||
type ResetAction<T> = {
|
||||
type: 'reset'
|
||||
state: State<T>
|
||||
}
|
||||
|
||||
const reducer = <T>(state: State<T>, action: Action<T>): State<T> => {
|
||||
switch (action.type) {
|
||||
case 'focus-next-option': {
|
||||
if (state.focusedValue === undefined) {
|
||||
return state
|
||||
}
|
||||
|
||||
const item = state.optionMap.get(state.focusedValue)
|
||||
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Wrap to first item if at the end
|
||||
const next = item.next || state.optionMap.first
|
||||
|
||||
if (!next) {
|
||||
return state
|
||||
}
|
||||
|
||||
// When wrapping to first, reset viewport to start
|
||||
if (!item.next && next === state.optionMap.first) {
|
||||
return {
|
||||
...state,
|
||||
focusedValue: next.value,
|
||||
visibleFromIndex: 0,
|
||||
visibleToIndex: state.visibleOptionCount,
|
||||
}
|
||||
}
|
||||
|
||||
const needsToScroll = next.index >= state.visibleToIndex
|
||||
|
||||
if (!needsToScroll) {
|
||||
return {
|
||||
...state,
|
||||
focusedValue: next.value,
|
||||
}
|
||||
}
|
||||
|
||||
const nextVisibleToIndex = Math.min(
|
||||
state.optionMap.size,
|
||||
state.visibleToIndex + 1,
|
||||
)
|
||||
|
||||
const nextVisibleFromIndex = nextVisibleToIndex - state.visibleOptionCount
|
||||
|
||||
return {
|
||||
...state,
|
||||
focusedValue: next.value,
|
||||
visibleFromIndex: nextVisibleFromIndex,
|
||||
visibleToIndex: nextVisibleToIndex,
|
||||
}
|
||||
}
|
||||
|
||||
case 'focus-previous-option': {
|
||||
if (state.focusedValue === undefined) {
|
||||
return state
|
||||
}
|
||||
|
||||
const item = state.optionMap.get(state.focusedValue)
|
||||
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Wrap to last item if at the beginning
|
||||
const previous = item.previous || state.optionMap.last
|
||||
|
||||
if (!previous) {
|
||||
return state
|
||||
}
|
||||
|
||||
// When wrapping to last, reset viewport to end
|
||||
if (!item.previous && previous === state.optionMap.last) {
|
||||
const nextVisibleToIndex = state.optionMap.size
|
||||
const nextVisibleFromIndex = Math.max(
|
||||
0,
|
||||
nextVisibleToIndex - state.visibleOptionCount,
|
||||
)
|
||||
return {
|
||||
...state,
|
||||
focusedValue: previous.value,
|
||||
visibleFromIndex: nextVisibleFromIndex,
|
||||
visibleToIndex: nextVisibleToIndex,
|
||||
}
|
||||
}
|
||||
|
||||
const needsToScroll = previous.index <= state.visibleFromIndex
|
||||
|
||||
if (!needsToScroll) {
|
||||
return {
|
||||
...state,
|
||||
focusedValue: previous.value,
|
||||
}
|
||||
}
|
||||
|
||||
const nextVisibleFromIndex = Math.max(0, state.visibleFromIndex - 1)
|
||||
|
||||
const nextVisibleToIndex = nextVisibleFromIndex + state.visibleOptionCount
|
||||
|
||||
return {
|
||||
...state,
|
||||
focusedValue: previous.value,
|
||||
visibleFromIndex: nextVisibleFromIndex,
|
||||
visibleToIndex: nextVisibleToIndex,
|
||||
}
|
||||
}
|
||||
|
||||
case 'focus-next-page': {
|
||||
if (state.focusedValue === undefined) {
|
||||
return state
|
||||
}
|
||||
|
||||
const item = state.optionMap.get(state.focusedValue)
|
||||
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Move by a full page (visibleOptionCount items)
|
||||
const targetIndex = Math.min(
|
||||
state.optionMap.size - 1,
|
||||
item.index + state.visibleOptionCount,
|
||||
)
|
||||
|
||||
// Find the item at the target index
|
||||
let targetItem = state.optionMap.first
|
||||
while (targetItem && targetItem.index < targetIndex) {
|
||||
if (targetItem.next) {
|
||||
targetItem = targetItem.next
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetItem) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Update the visible range to include the new focused item
|
||||
const nextVisibleToIndex = Math.min(
|
||||
state.optionMap.size,
|
||||
targetItem.index + 1,
|
||||
)
|
||||
const nextVisibleFromIndex = Math.max(
|
||||
0,
|
||||
nextVisibleToIndex - state.visibleOptionCount,
|
||||
)
|
||||
|
||||
return {
|
||||
...state,
|
||||
focusedValue: targetItem.value,
|
||||
visibleFromIndex: nextVisibleFromIndex,
|
||||
visibleToIndex: nextVisibleToIndex,
|
||||
}
|
||||
}
|
||||
|
||||
case 'focus-previous-page': {
|
||||
if (state.focusedValue === undefined) {
|
||||
return state
|
||||
}
|
||||
|
||||
const item = state.optionMap.get(state.focusedValue)
|
||||
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Move by a full page (visibleOptionCount items)
|
||||
const targetIndex = Math.max(0, item.index - state.visibleOptionCount)
|
||||
|
||||
// Find the item at the target index
|
||||
let targetItem = state.optionMap.first
|
||||
while (targetItem && targetItem.index < targetIndex) {
|
||||
if (targetItem.next) {
|
||||
targetItem = targetItem.next
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetItem) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Update the visible range to include the new focused item
|
||||
const nextVisibleFromIndex = Math.max(0, targetItem.index)
|
||||
const nextVisibleToIndex = Math.min(
|
||||
state.optionMap.size,
|
||||
nextVisibleFromIndex + state.visibleOptionCount,
|
||||
)
|
||||
|
||||
return {
|
||||
...state,
|
||||
focusedValue: targetItem.value,
|
||||
visibleFromIndex: nextVisibleFromIndex,
|
||||
visibleToIndex: nextVisibleToIndex,
|
||||
}
|
||||
}
|
||||
|
||||
case 'reset': {
|
||||
return action.state
|
||||
}
|
||||
|
||||
case 'set-focus': {
|
||||
// Early return if already focused on this value
|
||||
if (state.focusedValue === action.value) {
|
||||
return state
|
||||
}
|
||||
|
||||
const item = state.optionMap.get(action.value)
|
||||
if (!item) {
|
||||
return state
|
||||
}
|
||||
|
||||
// Check if the item is already in view
|
||||
if (
|
||||
item.index >= state.visibleFromIndex &&
|
||||
item.index < state.visibleToIndex
|
||||
) {
|
||||
// Already visible, just update focus
|
||||
return {
|
||||
...state,
|
||||
focusedValue: action.value,
|
||||
}
|
||||
}
|
||||
|
||||
// Need to scroll to make the item visible
|
||||
// Scroll as little as possible - put item at edge of viewport
|
||||
let nextVisibleFromIndex: number
|
||||
let nextVisibleToIndex: number
|
||||
|
||||
if (item.index < state.visibleFromIndex) {
|
||||
// Item is above viewport - scroll up to put it at the top
|
||||
nextVisibleFromIndex = item.index
|
||||
nextVisibleToIndex = Math.min(
|
||||
state.optionMap.size,
|
||||
nextVisibleFromIndex + state.visibleOptionCount,
|
||||
)
|
||||
} else {
|
||||
// Item is below viewport - scroll down to put it at the bottom
|
||||
nextVisibleToIndex = Math.min(state.optionMap.size, item.index + 1)
|
||||
nextVisibleFromIndex = Math.max(
|
||||
0,
|
||||
nextVisibleToIndex - state.visibleOptionCount,
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
focusedValue: action.value,
|
||||
visibleFromIndex: nextVisibleFromIndex,
|
||||
visibleToIndex: nextVisibleToIndex,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type UseSelectNavigationProps<T> = {
|
||||
/**
|
||||
* Number of items to display.
|
||||
*
|
||||
* @default 5
|
||||
*/
|
||||
visibleOptionCount?: number
|
||||
|
||||
/**
|
||||
* Options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Initially focused option's value.
|
||||
*/
|
||||
initialFocusValue?: T
|
||||
|
||||
/**
|
||||
* Callback for focusing an option.
|
||||
*/
|
||||
onFocus?: (value: T) => void
|
||||
|
||||
/**
|
||||
* Value to focus
|
||||
*/
|
||||
focusValue?: T
|
||||
}
|
||||
|
||||
export type SelectNavigation<T> = {
|
||||
/**
|
||||
* Value of the currently focused option.
|
||||
*/
|
||||
focusedValue: T | undefined
|
||||
|
||||
/**
|
||||
* 1-based index of the focused option in the full list.
|
||||
* Returns 0 if no option is focused.
|
||||
*/
|
||||
focusedIndex: number
|
||||
|
||||
/**
|
||||
* Index of the first visible option.
|
||||
*/
|
||||
visibleFromIndex: number
|
||||
|
||||
/**
|
||||
* Index of the last visible option.
|
||||
*/
|
||||
visibleToIndex: number
|
||||
|
||||
/**
|
||||
* All options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Visible options.
|
||||
*/
|
||||
visibleOptions: Array<OptionWithDescription<T> & { index: number }>
|
||||
|
||||
/**
|
||||
* Whether the focused option is an input type.
|
||||
*/
|
||||
isInInput: boolean
|
||||
|
||||
/**
|
||||
* Focus next option and scroll the list down, if needed.
|
||||
*/
|
||||
focusNextOption: () => void
|
||||
|
||||
/**
|
||||
* Focus previous option and scroll the list up, if needed.
|
||||
*/
|
||||
focusPreviousOption: () => void
|
||||
|
||||
/**
|
||||
* Focus next page and scroll the list down by a page.
|
||||
*/
|
||||
focusNextPage: () => void
|
||||
|
||||
/**
|
||||
* Focus previous page and scroll the list up by a page.
|
||||
*/
|
||||
focusPreviousPage: () => void
|
||||
|
||||
/**
|
||||
* Focus a specific option by value.
|
||||
*/
|
||||
focusOption: (value: T | undefined) => void
|
||||
}
|
||||
|
||||
const createDefaultState = <T>({
|
||||
visibleOptionCount: customVisibleOptionCount,
|
||||
options,
|
||||
initialFocusValue,
|
||||
currentViewport,
|
||||
}: Pick<UseSelectNavigationProps<T>, 'visibleOptionCount' | 'options'> & {
|
||||
initialFocusValue?: T
|
||||
currentViewport?: { visibleFromIndex: number; visibleToIndex: number }
|
||||
}): State<T> => {
|
||||
const visibleOptionCount =
|
||||
typeof customVisibleOptionCount === 'number'
|
||||
? Math.min(customVisibleOptionCount, options.length)
|
||||
: options.length
|
||||
|
||||
const optionMap = new OptionMap<T>(options)
|
||||
const focusedItem =
|
||||
initialFocusValue !== undefined && optionMap.get(initialFocusValue)
|
||||
const focusedValue = focusedItem ? initialFocusValue : optionMap.first?.value
|
||||
|
||||
let visibleFromIndex = 0
|
||||
let visibleToIndex = visibleOptionCount
|
||||
|
||||
// When there's a valid focused item, adjust viewport to show it
|
||||
if (focusedItem) {
|
||||
const focusedIndex = focusedItem.index
|
||||
|
||||
if (currentViewport) {
|
||||
// If focused item is already in the current viewport range, try to preserve it
|
||||
if (
|
||||
focusedIndex >= currentViewport.visibleFromIndex &&
|
||||
focusedIndex < currentViewport.visibleToIndex
|
||||
) {
|
||||
// Keep the same viewport if it's valid
|
||||
visibleFromIndex = currentViewport.visibleFromIndex
|
||||
visibleToIndex = Math.min(
|
||||
optionMap.size,
|
||||
currentViewport.visibleToIndex,
|
||||
)
|
||||
} else {
|
||||
// Need to adjust viewport to show focused item
|
||||
// Use minimal scrolling - put item at edge of viewport
|
||||
if (focusedIndex < currentViewport.visibleFromIndex) {
|
||||
// Item is above current viewport - scroll up to put it at the top
|
||||
visibleFromIndex = focusedIndex
|
||||
visibleToIndex = Math.min(
|
||||
optionMap.size,
|
||||
visibleFromIndex + visibleOptionCount,
|
||||
)
|
||||
} else {
|
||||
// Item is below current viewport - scroll down to put it at the bottom
|
||||
visibleToIndex = Math.min(optionMap.size, focusedIndex + 1)
|
||||
visibleFromIndex = Math.max(0, visibleToIndex - visibleOptionCount)
|
||||
}
|
||||
}
|
||||
} else if (focusedIndex >= visibleOptionCount) {
|
||||
// No current viewport but focused item is outside default viewport
|
||||
// Scroll to show the focused item at the bottom of the viewport
|
||||
visibleToIndex = Math.min(optionMap.size, focusedIndex + 1)
|
||||
visibleFromIndex = Math.max(0, visibleToIndex - visibleOptionCount)
|
||||
}
|
||||
|
||||
// Ensure viewport bounds are valid
|
||||
visibleFromIndex = Math.max(
|
||||
0,
|
||||
Math.min(visibleFromIndex, optionMap.size - 1),
|
||||
)
|
||||
visibleToIndex = Math.min(
|
||||
optionMap.size,
|
||||
Math.max(visibleOptionCount, visibleToIndex),
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
optionMap,
|
||||
visibleOptionCount,
|
||||
focusedValue,
|
||||
visibleFromIndex,
|
||||
visibleToIndex,
|
||||
}
|
||||
}
|
||||
|
||||
export function useSelectNavigation<T>({
|
||||
visibleOptionCount = 5,
|
||||
options,
|
||||
initialFocusValue,
|
||||
onFocus,
|
||||
focusValue,
|
||||
}: UseSelectNavigationProps<T>): SelectNavigation<T> {
|
||||
const [state, dispatch] = useReducer(
|
||||
reducer<T>,
|
||||
{
|
||||
visibleOptionCount,
|
||||
options,
|
||||
initialFocusValue: focusValue || initialFocusValue,
|
||||
} as Parameters<typeof createDefaultState<T>>[0],
|
||||
createDefaultState<T>,
|
||||
)
|
||||
|
||||
// Store onFocus in a ref to avoid re-running useEffect when callback changes
|
||||
const onFocusRef = useRef(onFocus)
|
||||
onFocusRef.current = onFocus
|
||||
|
||||
const [lastOptions, setLastOptions] = useState(options)
|
||||
|
||||
if (options !== lastOptions && !isDeepStrictEqual(options, lastOptions)) {
|
||||
dispatch({
|
||||
type: 'reset',
|
||||
state: createDefaultState({
|
||||
visibleOptionCount,
|
||||
options,
|
||||
initialFocusValue:
|
||||
focusValue ?? state.focusedValue ?? initialFocusValue,
|
||||
currentViewport: {
|
||||
visibleFromIndex: state.visibleFromIndex,
|
||||
visibleToIndex: state.visibleToIndex,
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
setLastOptions(options)
|
||||
}
|
||||
|
||||
const focusNextOption = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'focus-next-option',
|
||||
})
|
||||
}, [])
|
||||
|
||||
const focusPreviousOption = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'focus-previous-option',
|
||||
})
|
||||
}, [])
|
||||
|
||||
const focusNextPage = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'focus-next-page',
|
||||
})
|
||||
}, [])
|
||||
|
||||
const focusPreviousPage = useCallback(() => {
|
||||
dispatch({
|
||||
type: 'focus-previous-page',
|
||||
})
|
||||
}, [])
|
||||
|
||||
const focusOption = useCallback((value: T | undefined) => {
|
||||
if (value !== undefined) {
|
||||
dispatch({
|
||||
type: 'set-focus',
|
||||
value,
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const visibleOptions = useMemo(() => {
|
||||
return options
|
||||
.map((option, index) => ({
|
||||
...option,
|
||||
index,
|
||||
}))
|
||||
.slice(state.visibleFromIndex, state.visibleToIndex)
|
||||
}, [options, state.visibleFromIndex, state.visibleToIndex])
|
||||
|
||||
// Validate that focusedValue exists in current options.
|
||||
// This handles the case where options change during render but the reset
|
||||
// action hasn't been processed yet - without this, the cursor would disappear
|
||||
// because focusedValue points to an option that no longer exists.
|
||||
const validatedFocusedValue = useMemo(() => {
|
||||
if (state.focusedValue === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const exists = options.some(opt => opt.value === state.focusedValue)
|
||||
if (exists) {
|
||||
return state.focusedValue
|
||||
}
|
||||
// Fall back to first option if focused value doesn't exist
|
||||
return options[0]?.value
|
||||
}, [state.focusedValue, options])
|
||||
|
||||
const isInInput = useMemo(() => {
|
||||
const focusedOption = options.find(
|
||||
opt => opt.value === validatedFocusedValue,
|
||||
)
|
||||
return focusedOption?.type === 'input'
|
||||
}, [validatedFocusedValue, options])
|
||||
|
||||
// Call onFocus with the validated value (what's actually displayed),
|
||||
// not the internal state value which may be stale if options changed.
|
||||
// Use ref to avoid re-running when callback reference changes.
|
||||
useEffect(() => {
|
||||
if (validatedFocusedValue !== undefined) {
|
||||
onFocusRef.current?.(validatedFocusedValue)
|
||||
}
|
||||
}, [validatedFocusedValue])
|
||||
|
||||
// Allow parent to programmatically set focus via focusValue prop
|
||||
useEffect(() => {
|
||||
if (focusValue !== undefined) {
|
||||
dispatch({
|
||||
type: 'set-focus',
|
||||
value: focusValue,
|
||||
})
|
||||
}
|
||||
}, [focusValue])
|
||||
|
||||
// Compute 1-based focused index for scroll position display
|
||||
const focusedIndex = useMemo(() => {
|
||||
if (validatedFocusedValue === undefined) {
|
||||
return 0
|
||||
}
|
||||
const index = options.findIndex(opt => opt.value === validatedFocusedValue)
|
||||
return index >= 0 ? index + 1 : 0
|
||||
}, [validatedFocusedValue, options])
|
||||
|
||||
return {
|
||||
focusedValue: validatedFocusedValue,
|
||||
focusedIndex,
|
||||
visibleFromIndex: state.visibleFromIndex,
|
||||
visibleToIndex: state.visibleToIndex,
|
||||
visibleOptions,
|
||||
isInInput: isInInput ?? false,
|
||||
focusNextOption,
|
||||
focusPreviousOption,
|
||||
focusNextPage,
|
||||
focusPreviousPage,
|
||||
focusOption,
|
||||
options,
|
||||
}
|
||||
}
|
||||
157
src/components/CustomSelect/use-select-state.ts
Normal file
157
src/components/CustomSelect/use-select-state.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
import type { OptionWithDescription } from './select.js'
|
||||
import { useSelectNavigation } from './use-select-navigation.js'
|
||||
|
||||
export type UseSelectStateProps<T> = {
|
||||
/**
|
||||
* Number of items to display.
|
||||
*
|
||||
* @default 5
|
||||
*/
|
||||
visibleOptionCount?: number
|
||||
|
||||
/**
|
||||
* Options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Initially selected option's value.
|
||||
*/
|
||||
defaultValue?: T
|
||||
|
||||
/**
|
||||
* Callback for selecting an option.
|
||||
*/
|
||||
onChange?: (value: T) => void
|
||||
|
||||
/**
|
||||
* Callback for canceling the select.
|
||||
*/
|
||||
onCancel?: () => void
|
||||
|
||||
/**
|
||||
* Callback for focusing an option.
|
||||
*/
|
||||
onFocus?: (value: T) => void
|
||||
|
||||
/**
|
||||
* Value to focus
|
||||
*/
|
||||
focusValue?: T
|
||||
}
|
||||
|
||||
export type SelectState<T> = {
|
||||
/**
|
||||
* Value of the currently focused option.
|
||||
*/
|
||||
focusedValue: T | undefined
|
||||
|
||||
/**
|
||||
* 1-based index of the focused option in the full list.
|
||||
* Returns 0 if no option is focused.
|
||||
*/
|
||||
focusedIndex: number
|
||||
|
||||
/**
|
||||
* Index of the first visible option.
|
||||
*/
|
||||
visibleFromIndex: number
|
||||
|
||||
/**
|
||||
* Index of the last visible option.
|
||||
*/
|
||||
visibleToIndex: number
|
||||
|
||||
/**
|
||||
* Value of the selected option.
|
||||
*/
|
||||
value: T | undefined
|
||||
|
||||
/**
|
||||
* All options.
|
||||
*/
|
||||
options: OptionWithDescription<T>[]
|
||||
|
||||
/**
|
||||
* Visible options.
|
||||
*/
|
||||
visibleOptions: Array<OptionWithDescription<T> & { index: number }>
|
||||
|
||||
/**
|
||||
* Whether the focused option is an input type.
|
||||
*/
|
||||
isInInput: boolean
|
||||
|
||||
/**
|
||||
* Focus next option and scroll the list down, if needed.
|
||||
*/
|
||||
focusNextOption: () => void
|
||||
|
||||
/**
|
||||
* Focus previous option and scroll the list up, if needed.
|
||||
*/
|
||||
focusPreviousOption: () => void
|
||||
|
||||
/**
|
||||
* Focus next page and scroll the list down by a page.
|
||||
*/
|
||||
focusNextPage: () => void
|
||||
|
||||
/**
|
||||
* Focus previous page and scroll the list up by a page.
|
||||
*/
|
||||
focusPreviousPage: () => void
|
||||
|
||||
/**
|
||||
* Focus a specific option by value.
|
||||
*/
|
||||
focusOption: (value: T | undefined) => void
|
||||
|
||||
/**
|
||||
* Select currently focused option.
|
||||
*/
|
||||
selectFocusedOption: () => void
|
||||
|
||||
/**
|
||||
* Callback for selecting an option.
|
||||
*/
|
||||
onChange?: (value: T) => void
|
||||
|
||||
/**
|
||||
* Callback for canceling the select.
|
||||
*/
|
||||
onCancel?: () => void
|
||||
}
|
||||
|
||||
export function useSelectState<T>({
|
||||
visibleOptionCount = 5,
|
||||
options,
|
||||
defaultValue,
|
||||
onChange,
|
||||
onCancel,
|
||||
onFocus,
|
||||
focusValue,
|
||||
}: UseSelectStateProps<T>): SelectState<T> {
|
||||
const [value, setValue] = useState<T | undefined>(defaultValue)
|
||||
|
||||
const navigation = useSelectNavigation<T>({
|
||||
visibleOptionCount,
|
||||
options,
|
||||
initialFocusValue: undefined,
|
||||
onFocus,
|
||||
focusValue,
|
||||
})
|
||||
|
||||
const selectFocusedOption = useCallback(() => {
|
||||
setValue(navigation.focusedValue)
|
||||
}, [navigation.focusedValue])
|
||||
|
||||
return {
|
||||
...navigation,
|
||||
value,
|
||||
selectFocusedOption,
|
||||
onChange,
|
||||
onCancel,
|
||||
}
|
||||
}
|
||||
193
src/components/DesktopHandoff.tsx
Normal file
193
src/components/DesktopHandoff.tsx
Normal file
File diff suppressed because one or more lines are too long
171
src/components/DesktopUpsell/DesktopUpsellStartup.tsx
Normal file
171
src/components/DesktopUpsell/DesktopUpsellStartup.tsx
Normal file
File diff suppressed because one or more lines are too long
49
src/components/DevBar.tsx
Normal file
49
src/components/DevBar.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { getSlowOperations } from '../bootstrap/state.js';
|
||||
import { Text, useInterval } from '../ink.js';
|
||||
|
||||
// Show DevBar for dev builds or all ants
|
||||
function shouldShowDevBar(): boolean {
|
||||
return "production" === 'development' || "external" === 'ant';
|
||||
}
|
||||
export function DevBar() {
|
||||
const $ = _c(5);
|
||||
const [slowOps, setSlowOps] = useState(getSlowOperations);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
setSlowOps(getSlowOperations());
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
useInterval(t0, shouldShowDevBar() ? 500 : null);
|
||||
if (!shouldShowDevBar() || slowOps.length === 0) {
|
||||
return null;
|
||||
}
|
||||
let t1;
|
||||
if ($[1] !== slowOps) {
|
||||
t1 = slowOps.slice(-3).map(_temp).join(" \xB7 ");
|
||||
$[1] = slowOps;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
const recentOps = t1;
|
||||
let t2;
|
||||
if ($[3] !== recentOps) {
|
||||
t2 = <Text wrap="truncate-end" color="warning">[ANT-ONLY] slow sync: {recentOps}</Text>;
|
||||
$[3] = recentOps;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp(op) {
|
||||
return `${op.operation} (${Math.round(op.durationMs)}ms)`;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZVN0YXRlIiwiZ2V0U2xvd09wZXJhdGlvbnMiLCJUZXh0IiwidXNlSW50ZXJ2YWwiLCJzaG91bGRTaG93RGV2QmFyIiwiRGV2QmFyIiwiJCIsIl9jIiwic2xvd09wcyIsInNldFNsb3dPcHMiLCJ0MCIsIlN5bWJvbCIsImZvciIsImxlbmd0aCIsInQxIiwic2xpY2UiLCJtYXAiLCJfdGVtcCIsImpvaW4iLCJyZWNlbnRPcHMiLCJ0MiIsIm9wIiwib3BlcmF0aW9uIiwiTWF0aCIsInJvdW5kIiwiZHVyYXRpb25NcyJdLCJzb3VyY2VzIjpbIkRldkJhci50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgZ2V0U2xvd09wZXJhdGlvbnMgfSBmcm9tICcuLi9ib290c3RyYXAvc3RhdGUuanMnXG5pbXBvcnQgeyBUZXh0LCB1c2VJbnRlcnZhbCB9IGZyb20gJy4uL2luay5qcydcblxuLy8gU2hvdyBEZXZCYXIgZm9yIGRldiBidWlsZHMgb3IgYWxsIGFudHNcbmZ1bmN0aW9uIHNob3VsZFNob3dEZXZCYXIoKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgXCJwcm9kdWN0aW9uXCIgPT09ICdkZXZlbG9wbWVudCcgfHwgXCJleHRlcm5hbFwiID09PSAnYW50J1xuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBEZXZCYXIoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgW3Nsb3dPcHMsIHNldFNsb3dPcHNdID1cbiAgICB1c2VTdGF0ZTxcbiAgICAgIFJlYWRvbmx5QXJyYXk8e1xuICAgICAgICBvcGVyYXRpb246IHN0cmluZ1xuICAgICAgICBkdXJhdGlvbk1zOiBudW1iZXJcbiAgICAgICAgdGltZXN0YW1wOiBudW1iZXJcbiAgICAgIH0+XG4gICAgPihnZXRTbG93T3BlcmF0aW9ucylcblxuICB1c2VJbnRlcnZhbChcbiAgICAoKSA9PiB7XG4gICAgICBzZXRTbG93T3BzKGdldFNsb3dPcGVyYXRpb25zKCkpXG4gICAgfSxcbiAgICBzaG91bGRTaG93RGV2QmFyKCkgPyA1MDAgOiBudWxsLFxuICApXG5cbiAgLy8gT25seSBzaG93IHdoZW4gdGhlcmUncyBzb21ldGhpbmcgdG8gZGlzcGxheVxuICBpZiAoIXNob3VsZFNob3dEZXZCYXIoKSB8fCBzbG93T3BzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvLyBTaW5nbGUtbGluZSBmb3JtYXQgc28gc2hvcnQgdGVybWluYWxzIGRvbid0IGxvc2Ugcm93cyB0byBkZXYgbm9pc2UuXG4gIGNvbnN0IHJlY2VudE9wcyA9IHNsb3dPcHNcbiAgICAuc2xpY2UoLTMpXG4gICAgLm1hcChvcCA9PiBgJHtvcC5vcGVyYXRpb259ICgke01hdGgucm91bmQob3AuZHVyYXRpb25Ncyl9bXMpYClcbiAgICAuam9pbignIMK3ICcpXG5cbiAgcmV0dXJuIChcbiAgICA8VGV4dCB3cmFwPVwidHJ1bmNhdGUtZW5kXCIgY29sb3I9XCJ3YXJuaW5nXCI+XG4gICAgICBbQU5ULU9OTFldIHNsb3cgc3luYzoge3JlY2VudE9wc31cbiAgICA8L1RleHQ+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sS0FBS0EsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsUUFBUSxRQUFRLE9BQU87QUFDaEMsU0FBU0MsaUJBQWlCLFFBQVEsdUJBQXVCO0FBQ3pELFNBQVNDLElBQUksRUFBRUMsV0FBVyxRQUFRLFdBQVc7O0FBRTdDO0FBQ0EsU0FBU0MsZ0JBQWdCQSxDQUFBLENBQUUsRUFBRSxPQUFPLENBQUM7RUFDbkMsT0FDRSxZQUFZLEtBQUssYUFBYSxJQUFJLFVBQVUsS0FBSyxLQUFLO0FBRTFEO0FBRUEsT0FBTyxTQUFBQyxPQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQ0wsT0FBQUMsT0FBQSxFQUFBQyxVQUFBLElBQ0VULFFBQVEsQ0FNTkMsaUJBQWlCLENBQUM7RUFBQSxJQUFBUyxFQUFBO0VBQUEsSUFBQUosQ0FBQSxRQUFBSyxNQUFBLENBQUFDLEdBQUE7SUFHcEJGLEVBQUEsR0FBQUEsQ0FBQTtNQUNFRCxVQUFVLENBQUNSLGlCQUFpQixDQUFDLENBQUMsQ0FBQztJQUFBLENBQ2hDO0lBQUFLLENBQUEsTUFBQUksRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUosQ0FBQTtFQUFBO0VBSEhILFdBQVcsQ0FDVE8sRUFFQyxFQUNETixnQkFBZ0IsQ0FBYyxDQUFDLEdBQS9CLEdBQStCLEdBQS9CLElBQ0YsQ0FBQztFQUdELElBQUksQ0FBQ0EsZ0JBQWdCLENBQUMsQ0FBeUIsSUFBcEJJLE9BQU8sQ0FBQUssTUFBTyxLQUFLLENBQUM7SUFBQSxPQUN0QyxJQUFJO0VBQUE7RUFDWixJQUFBQyxFQUFBO0VBQUEsSUFBQVIsQ0FBQSxRQUFBRSxPQUFBO0lBR2lCTSxFQUFBLEdBQUFOLE9BQU8sQ0FBQU8sS0FDakIsQ0FBQyxFQUFFLENBQUMsQ0FBQUMsR0FDTixDQUFDQyxLQUF3RCxDQUFDLENBQUFDLElBQ3pELENBQUMsUUFBSyxDQUFDO0lBQUFaLENBQUEsTUFBQUUsT0FBQTtJQUFBRixDQUFBLE1BQUFRLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFSLENBQUE7RUFBQTtFQUhkLE1BQUFhLFNBQUEsR0FBa0JMLEVBR0o7RUFBQSxJQUFBTSxFQUFBO0VBQUEsSUFBQWQsQ0FBQSxRQUFBYSxTQUFBO0lBR1pDLEVBQUEsSUFBQyxJQUFJLENBQU0sSUFBYyxDQUFkLGNBQWMsQ0FBTyxLQUFTLENBQVQsU0FBUyxDQUFDLHNCQUNqQkQsVUFBUSxDQUNqQyxFQUZDLElBQUksQ0FFRTtJQUFBYixDQUFBLE1BQUFhLFNBQUE7SUFBQWIsQ0FBQSxNQUFBYyxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBZCxDQUFBO0VBQUE7RUFBQSxPQUZQYyxFQUVPO0FBQUE7QUEvQkosU0FBQUgsTUFBQUksRUFBQTtFQUFBLE9BeUJRLEdBQUdBLEVBQUUsQ0FBQUMsU0FBVSxLQUFLQyxJQUFJLENBQUFDLEtBQU0sQ0FBQ0gsRUFBRSxDQUFBSSxVQUFXLENBQUMsS0FBSztBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
105
src/components/DevChannelsDialog.tsx
Normal file
105
src/components/DevChannelsDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
95
src/components/DiagnosticsDisplay.tsx
Normal file
95
src/components/DiagnosticsDisplay.tsx
Normal file
File diff suppressed because one or more lines are too long
265
src/components/EffortCallout.tsx
Normal file
265
src/components/EffortCallout.tsx
Normal file
File diff suppressed because one or more lines are too long
42
src/components/EffortIndicator.ts
Normal file
42
src/components/EffortIndicator.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
EFFORT_HIGH,
|
||||
EFFORT_LOW,
|
||||
EFFORT_MAX,
|
||||
EFFORT_MEDIUM,
|
||||
} from '../constants/figures.js'
|
||||
import {
|
||||
type EffortLevel,
|
||||
type EffortValue,
|
||||
getDisplayedEffortLevel,
|
||||
modelSupportsEffort,
|
||||
} from '../utils/effort.js'
|
||||
|
||||
/**
|
||||
* Build the text for the effort-changed notification, e.g. "◐ medium · /effort".
|
||||
* Returns undefined if the model doesn't support effort.
|
||||
*/
|
||||
export function getEffortNotificationText(
|
||||
effortValue: EffortValue | undefined,
|
||||
model: string,
|
||||
): string | undefined {
|
||||
if (!modelSupportsEffort(model)) return undefined
|
||||
const level = getDisplayedEffortLevel(model, effortValue)
|
||||
return `${effortLevelToSymbol(level)} ${level} · /effort`
|
||||
}
|
||||
|
||||
export function effortLevelToSymbol(level: EffortLevel): string {
|
||||
switch (level) {
|
||||
case 'low':
|
||||
return EFFORT_LOW
|
||||
case 'medium':
|
||||
return EFFORT_MEDIUM
|
||||
case 'high':
|
||||
return EFFORT_HIGH
|
||||
case 'max':
|
||||
return EFFORT_MAX
|
||||
default:
|
||||
// Defensive: level can originate from remote config. If an unknown
|
||||
// value slips through, render the high symbol rather than undefined.
|
||||
return EFFORT_HIGH
|
||||
}
|
||||
}
|
||||
48
src/components/ExitFlow.tsx
Normal file
48
src/components/ExitFlow.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import sample from 'lodash-es/sample.js';
|
||||
import React from 'react';
|
||||
import { gracefulShutdown } from '../utils/gracefulShutdown.js';
|
||||
import { WorktreeExitDialog } from './WorktreeExitDialog.js';
|
||||
const GOODBYE_MESSAGES = ['Goodbye!', 'See ya!', 'Bye!', 'Catch you later!'];
|
||||
function getRandomGoodbyeMessage(): string {
|
||||
return sample(GOODBYE_MESSAGES) ?? 'Goodbye!';
|
||||
}
|
||||
type Props = {
|
||||
onDone: (message?: string) => void;
|
||||
onCancel?: () => void;
|
||||
showWorktree: boolean;
|
||||
};
|
||||
export function ExitFlow(t0) {
|
||||
const $ = _c(5);
|
||||
const {
|
||||
showWorktree,
|
||||
onDone,
|
||||
onCancel
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== onDone) {
|
||||
t1 = async function onExit(resultMessage) {
|
||||
onDone(resultMessage ?? getRandomGoodbyeMessage());
|
||||
await gracefulShutdown(0, "prompt_input_exit");
|
||||
};
|
||||
$[0] = onDone;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const onExit = t1;
|
||||
if (showWorktree) {
|
||||
let t2;
|
||||
if ($[2] !== onCancel || $[3] !== onExit) {
|
||||
t2 = <WorktreeExitDialog onDone={onExit} onCancel={onCancel} />;
|
||||
$[2] = onCancel;
|
||||
$[3] = onExit;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJzYW1wbGUiLCJSZWFjdCIsImdyYWNlZnVsU2h1dGRvd24iLCJXb3JrdHJlZUV4aXREaWFsb2ciLCJHT09EQllFX01FU1NBR0VTIiwiZ2V0UmFuZG9tR29vZGJ5ZU1lc3NhZ2UiLCJQcm9wcyIsIm9uRG9uZSIsIm1lc3NhZ2UiLCJvbkNhbmNlbCIsInNob3dXb3JrdHJlZSIsIkV4aXRGbG93IiwidDAiLCIkIiwiX2MiLCJ0MSIsIm9uRXhpdCIsInJlc3VsdE1lc3NhZ2UiLCJ0MiJdLCJzb3VyY2VzIjpbIkV4aXRGbG93LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc2FtcGxlIGZyb20gJ2xvZGFzaC1lcy9zYW1wbGUuanMnXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBncmFjZWZ1bFNodXRkb3duIH0gZnJvbSAnLi4vdXRpbHMvZ3JhY2VmdWxTaHV0ZG93bi5qcydcbmltcG9ydCB7IFdvcmt0cmVlRXhpdERpYWxvZyB9IGZyb20gJy4vV29ya3RyZWVFeGl0RGlhbG9nLmpzJ1xuXG5jb25zdCBHT09EQllFX01FU1NBR0VTID0gWydHb29kYnllIScsICdTZWUgeWEhJywgJ0J5ZSEnLCAnQ2F0Y2ggeW91IGxhdGVyISddXG5cbmZ1bmN0aW9uIGdldFJhbmRvbUdvb2RieWVNZXNzYWdlKCk6IHN0cmluZyB7XG4gIHJldHVybiBzYW1wbGUoR09PREJZRV9NRVNTQUdFUykgPz8gJ0dvb2RieWUhJ1xufVxuXG50eXBlIFByb3BzID0ge1xuICBvbkRvbmU6IChtZXNzYWdlPzogc3RyaW5nKSA9PiB2b2lkXG4gIG9uQ2FuY2VsPzogKCkgPT4gdm9pZFxuICBzaG93V29ya3RyZWU6IGJvb2xlYW5cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIEV4aXRGbG93KHtcbiAgc2hvd1dvcmt0cmVlLFxuICBvbkRvbmUsXG4gIG9uQ2FuY2VsLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBhc3luYyBmdW5jdGlvbiBvbkV4aXQocmVzdWx0TWVzc2FnZT86IHN0cmluZykge1xuICAgIG9uRG9uZShyZXN1bHRNZXNzYWdlID8/IGdldFJhbmRvbUdvb2RieWVNZXNzYWdlKCkpXG4gICAgYXdhaXQgZ3JhY2VmdWxTaHV0ZG93bigwLCAncHJvbXB0X2lucHV0X2V4aXQnKVxuICB9XG5cbiAgaWYgKHNob3dXb3JrdHJlZSkge1xuICAgIHJldHVybiA8V29ya3RyZWVFeGl0RGlhbG9nIG9uRG9uZT17b25FeGl0fSBvbkNhbmNlbD17b25DYW5jZWx9IC8+XG4gIH1cblxuICByZXR1cm4gbnVsbFxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsTUFBTSxNQUFNLHFCQUFxQjtBQUN4QyxPQUFPQyxLQUFLLE1BQU0sT0FBTztBQUN6QixTQUFTQyxnQkFBZ0IsUUFBUSw4QkFBOEI7QUFDL0QsU0FBU0Msa0JBQWtCLFFBQVEseUJBQXlCO0FBRTVELE1BQU1DLGdCQUFnQixHQUFHLENBQUMsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsa0JBQWtCLENBQUM7QUFFNUUsU0FBU0MsdUJBQXVCQSxDQUFBLENBQUUsRUFBRSxNQUFNLENBQUM7RUFDekMsT0FBT0wsTUFBTSxDQUFDSSxnQkFBZ0IsQ0FBQyxJQUFJLFVBQVU7QUFDL0M7QUFFQSxLQUFLRSxLQUFLLEdBQUc7RUFDWEMsTUFBTSxFQUFFLENBQUNDLE9BQWdCLENBQVIsRUFBRSxNQUFNLEVBQUUsR0FBRyxJQUFJO0VBQ2xDQyxRQUFRLENBQUMsRUFBRSxHQUFHLEdBQUcsSUFBSTtFQUNyQkMsWUFBWSxFQUFFLE9BQU87QUFDdkIsQ0FBQztBQUVELE9BQU8sU0FBQUMsU0FBQUMsRUFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUFrQjtJQUFBSixZQUFBO0lBQUFILE1BQUE7SUFBQUU7RUFBQSxJQUFBRyxFQUlqQjtFQUFBLElBQUFHLEVBQUE7RUFBQSxJQUFBRixDQUFBLFFBQUFOLE1BQUE7SUFDTlEsRUFBQSxrQkFBQUMsT0FBQUMsYUFBQTtNQUNFVixNQUFNLENBQUNVLGFBQTBDLElBQXpCWix1QkFBdUIsQ0FBQyxDQUFDLENBQUM7TUFDbEQsTUFBTUgsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFLG1CQUFtQixDQUFDO0lBQUEsQ0FDL0M7SUFBQVcsQ0FBQSxNQUFBTixNQUFBO0lBQUFNLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBSEQsTUFBQUcsTUFBQSxHQUFBRCxFQUdDO0VBRUQsSUFBSUwsWUFBWTtJQUFBLElBQUFRLEVBQUE7SUFBQSxJQUFBTCxDQUFBLFFBQUFKLFFBQUEsSUFBQUksQ0FBQSxRQUFBRyxNQUFBO01BQ1BFLEVBQUEsSUFBQyxrQkFBa0IsQ0FBU0YsTUFBTSxDQUFOQSxPQUFLLENBQUMsQ0FBWVAsUUFBUSxDQUFSQSxTQUFPLENBQUMsR0FBSTtNQUFBSSxDQUFBLE1BQUFKLFFBQUE7TUFBQUksQ0FBQSxNQUFBRyxNQUFBO01BQUFILENBQUEsTUFBQUssRUFBQTtJQUFBO01BQUFBLEVBQUEsR0FBQUwsQ0FBQTtJQUFBO0lBQUEsT0FBMURLLEVBQTBEO0VBQUE7RUFDbEUsT0FFTSxJQUFJO0FBQUEiLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
128
src/components/ExportDialog.tsx
Normal file
128
src/components/ExportDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
116
src/components/FallbackToolUseErrorMessage.tsx
Normal file
116
src/components/FallbackToolUseErrorMessage.tsx
Normal file
File diff suppressed because one or more lines are too long
16
src/components/FallbackToolUseRejectedMessage.tsx
Normal file
16
src/components/FallbackToolUseRejectedMessage.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import { InterruptedByUser } from './InterruptedByUser.js';
|
||||
import { MessageResponse } from './MessageResponse.js';
|
||||
export function FallbackToolUseRejectedMessage() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <MessageResponse height={1}><InterruptedByUser /></MessageResponse>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkludGVycnVwdGVkQnlVc2VyIiwiTWVzc2FnZVJlc3BvbnNlIiwiRmFsbGJhY2tUb29sVXNlUmVqZWN0ZWRNZXNzYWdlIiwiJCIsIl9jIiwidDAiLCJTeW1ib2wiLCJmb3IiXSwic291cmNlcyI6WyJGYWxsYmFja1Rvb2xVc2VSZWplY3RlZE1lc3NhZ2UudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgSW50ZXJydXB0ZWRCeVVzZXIgfSBmcm9tICcuL0ludGVycnVwdGVkQnlVc2VyLmpzJ1xuaW1wb3J0IHsgTWVzc2FnZVJlc3BvbnNlIH0gZnJvbSAnLi9NZXNzYWdlUmVzcG9uc2UuanMnXG5cbmV4cG9ydCBmdW5jdGlvbiBGYWxsYmFja1Rvb2xVc2VSZWplY3RlZE1lc3NhZ2UoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgcmV0dXJuIChcbiAgICA8TWVzc2FnZVJlc3BvbnNlIGhlaWdodD17MX0+XG4gICAgICA8SW50ZXJydXB0ZWRCeVVzZXIgLz5cbiAgICA8L01lc3NhZ2VSZXNwb25zZT5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxLQUFLQSxLQUFLLE1BQU0sT0FBTztBQUM5QixTQUFTQyxpQkFBaUIsUUFBUSx3QkFBd0I7QUFDMUQsU0FBU0MsZUFBZSxRQUFRLHNCQUFzQjtBQUV0RCxPQUFPLFNBQUFDLCtCQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQUEsSUFBQUMsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO0lBRUhGLEVBQUEsSUFBQyxlQUFlLENBQVMsTUFBQyxDQUFELEdBQUMsQ0FDeEIsQ0FBQyxpQkFBaUIsR0FDcEIsRUFGQyxlQUFlLENBRUU7SUFBQUYsQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxPQUZsQkUsRUFFa0I7QUFBQSIsImlnbm9yZUxpc3QiOltdfQ==
|
||||
46
src/components/FastIcon.tsx
Normal file
46
src/components/FastIcon.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import chalk from 'chalk';
|
||||
import * as React from 'react';
|
||||
import { LIGHTNING_BOLT } from '../constants/figures.js';
|
||||
import { Text } from '../ink.js';
|
||||
import { getGlobalConfig } from '../utils/config.js';
|
||||
import { resolveThemeSetting } from '../utils/systemTheme.js';
|
||||
import { color } from './design-system/color.js';
|
||||
type Props = {
|
||||
cooldown?: boolean;
|
||||
};
|
||||
export function FastIcon(t0) {
|
||||
const $ = _c(2);
|
||||
const {
|
||||
cooldown
|
||||
} = t0;
|
||||
if (cooldown) {
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <Text color="promptBorder" dimColor={true}>{LIGHTNING_BOLT}</Text>;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <Text color="fastMode">{LIGHTNING_BOLT}</Text>;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
export function getFastIconString(applyColor = true, cooldown = false): string {
|
||||
if (!applyColor) {
|
||||
return LIGHTNING_BOLT;
|
||||
}
|
||||
const themeName = resolveThemeSetting(getGlobalConfig().theme);
|
||||
if (cooldown) {
|
||||
return chalk.dim(color('promptBorder', themeName)(LIGHTNING_BOLT));
|
||||
}
|
||||
return color('fastMode', themeName)(LIGHTNING_BOLT);
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjaGFsayIsIlJlYWN0IiwiTElHSFROSU5HX0JPTFQiLCJUZXh0IiwiZ2V0R2xvYmFsQ29uZmlnIiwicmVzb2x2ZVRoZW1lU2V0dGluZyIsImNvbG9yIiwiUHJvcHMiLCJjb29sZG93biIsIkZhc3RJY29uIiwidDAiLCIkIiwiX2MiLCJ0MSIsIlN5bWJvbCIsImZvciIsImdldEZhc3RJY29uU3RyaW5nIiwiYXBwbHlDb2xvciIsInRoZW1lTmFtZSIsInRoZW1lIiwiZGltIl0sInNvdXJjZXMiOlsiRmFzdEljb24udHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGFsayBmcm9tICdjaGFsaydcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgTElHSFROSU5HX0JPTFQgfSBmcm9tICcuLi9jb25zdGFudHMvZmlndXJlcy5qcydcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5pbXBvcnQgeyBnZXRHbG9iYWxDb25maWcgfSBmcm9tICcuLi91dGlscy9jb25maWcuanMnXG5pbXBvcnQgeyByZXNvbHZlVGhlbWVTZXR0aW5nIH0gZnJvbSAnLi4vdXRpbHMvc3lzdGVtVGhlbWUuanMnXG5pbXBvcnQgeyBjb2xvciB9IGZyb20gJy4vZGVzaWduLXN5c3RlbS9jb2xvci5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgY29vbGRvd24/OiBib29sZWFuXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBGYXN0SWNvbih7IGNvb2xkb3duIH06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgaWYgKGNvb2xkb3duKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxUZXh0IGNvbG9yPVwicHJvbXB0Qm9yZGVyXCIgZGltQ29sb3I+XG4gICAgICAgIHtMSUdIVE5JTkdfQk9MVH1cbiAgICAgIDwvVGV4dD5cbiAgICApXG4gIH1cbiAgcmV0dXJuIDxUZXh0IGNvbG9yPVwiZmFzdE1vZGVcIj57TElHSFROSU5HX0JPTFR9PC9UZXh0PlxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RmFzdEljb25TdHJpbmcoYXBwbHlDb2xvciA9IHRydWUsIGNvb2xkb3duID0gZmFsc2UpOiBzdHJpbmcge1xuICBpZiAoIWFwcGx5Q29sb3IpIHtcbiAgICByZXR1cm4gTElHSFROSU5HX0JPTFRcbiAgfVxuICBjb25zdCB0aGVtZU5hbWUgPSByZXNvbHZlVGhlbWVTZXR0aW5nKGdldEdsb2JhbENvbmZpZygpLnRoZW1lKVxuICBpZiAoY29vbGRvd24pIHtcbiAgICByZXR1cm4gY2hhbGsuZGltKGNvbG9yKCdwcm9tcHRCb3JkZXInLCB0aGVtZU5hbWUpKExJR0hUTklOR19CT0xUKSlcbiAgfVxuICByZXR1cm4gY29sb3IoJ2Zhc3RNb2RlJywgdGhlbWVOYW1lKShMSUdIVE5JTkdfQk9MVClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU9BLEtBQUssTUFBTSxPQUFPO0FBQ3pCLE9BQU8sS0FBS0MsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsY0FBYyxRQUFRLHlCQUF5QjtBQUN4RCxTQUFTQyxJQUFJLFFBQVEsV0FBVztBQUNoQyxTQUFTQyxlQUFlLFFBQVEsb0JBQW9CO0FBQ3BELFNBQVNDLG1CQUFtQixRQUFRLHlCQUF5QjtBQUM3RCxTQUFTQyxLQUFLLFFBQVEsMEJBQTBCO0FBRWhELEtBQUtDLEtBQUssR0FBRztFQUNYQyxRQUFRLENBQUMsRUFBRSxPQUFPO0FBQ3BCLENBQUM7QUFFRCxPQUFPLFNBQUFDLFNBQUFDLEVBQUE7RUFBQSxNQUFBQyxDQUFBLEdBQUFDLEVBQUE7RUFBa0I7SUFBQUo7RUFBQSxJQUFBRSxFQUFtQjtFQUMxQyxJQUFJRixRQUFRO0lBQUEsSUFBQUssRUFBQTtJQUFBLElBQUFGLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO01BRVJGLEVBQUEsSUFBQyxJQUFJLENBQU8sS0FBYyxDQUFkLGNBQWMsQ0FBQyxRQUFRLENBQVIsS0FBTyxDQUFDLENBQ2hDWCxlQUFhLENBQ2hCLEVBRkMsSUFBSSxDQUVFO01BQUFTLENBQUEsTUFBQUUsRUFBQTtJQUFBO01BQUFBLEVBQUEsR0FBQUYsQ0FBQTtJQUFBO0lBQUEsT0FGUEUsRUFFTztFQUFBO0VBRVYsSUFBQUEsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO0lBQ01GLEVBQUEsSUFBQyxJQUFJLENBQU8sS0FBVSxDQUFWLFVBQVUsQ0FBRVgsZUFBYSxDQUFFLEVBQXRDLElBQUksQ0FBeUM7SUFBQVMsQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxPQUE5Q0UsRUFBOEM7QUFBQTtBQUd2RCxPQUFPLFNBQVNHLGlCQUFpQkEsQ0FBQ0MsVUFBVSxHQUFHLElBQUksRUFBRVQsUUFBUSxHQUFHLEtBQUssQ0FBQyxFQUFFLE1BQU0sQ0FBQztFQUM3RSxJQUFJLENBQUNTLFVBQVUsRUFBRTtJQUNmLE9BQU9mLGNBQWM7RUFDdkI7RUFDQSxNQUFNZ0IsU0FBUyxHQUFHYixtQkFBbUIsQ0FBQ0QsZUFBZSxDQUFDLENBQUMsQ0FBQ2UsS0FBSyxDQUFDO0VBQzlELElBQUlYLFFBQVEsRUFBRTtJQUNaLE9BQU9SLEtBQUssQ0FBQ29CLEdBQUcsQ0FBQ2QsS0FBSyxDQUFDLGNBQWMsRUFBRVksU0FBUyxDQUFDLENBQUNoQixjQUFjLENBQUMsQ0FBQztFQUNwRTtFQUNBLE9BQU9JLEtBQUssQ0FBQyxVQUFVLEVBQUVZLFNBQVMsQ0FBQyxDQUFDaEIsY0FBYyxDQUFDO0FBQ3JEIiwiaWdub3JlTGlzdCI6W119
|
||||
592
src/components/Feedback.tsx
Normal file
592
src/components/Feedback.tsx
Normal file
File diff suppressed because one or more lines are too long
174
src/components/FeedbackSurvey/FeedbackSurvey.tsx
Normal file
174
src/components/FeedbackSurvey/FeedbackSurvey.tsx
Normal file
File diff suppressed because one or more lines are too long
108
src/components/FeedbackSurvey/FeedbackSurveyView.tsx
Normal file
108
src/components/FeedbackSurvey/FeedbackSurveyView.tsx
Normal file
File diff suppressed because one or more lines are too long
88
src/components/FeedbackSurvey/TranscriptSharePrompt.tsx
Normal file
88
src/components/FeedbackSurvey/TranscriptSharePrompt.tsx
Normal file
File diff suppressed because one or more lines are too long
112
src/components/FeedbackSurvey/submitTranscriptShare.ts
Normal file
112
src/components/FeedbackSurvey/submitTranscriptShare.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import axios from 'axios'
|
||||
import { readFile, stat } from 'fs/promises'
|
||||
import type { Message } from '../../types/message.js'
|
||||
import { checkAndRefreshOAuthTokenIfNeeded } from '../../utils/auth.js'
|
||||
import { logForDebugging } from '../../utils/debug.js'
|
||||
import { errorMessage } from '../../utils/errors.js'
|
||||
import { getAuthHeaders, getUserAgent } from '../../utils/http.js'
|
||||
import { normalizeMessagesForAPI } from '../../utils/messages.js'
|
||||
import {
|
||||
extractAgentIdsFromMessages,
|
||||
getTranscriptPath,
|
||||
loadSubagentTranscripts,
|
||||
MAX_TRANSCRIPT_READ_BYTES,
|
||||
} from '../../utils/sessionStorage.js'
|
||||
import { jsonStringify } from '../../utils/slowOperations.js'
|
||||
import { redactSensitiveInfo } from '../Feedback.js'
|
||||
|
||||
type TranscriptShareResult = {
|
||||
success: boolean
|
||||
transcriptId?: string
|
||||
}
|
||||
|
||||
export type TranscriptShareTrigger =
|
||||
| 'bad_feedback_survey'
|
||||
| 'good_feedback_survey'
|
||||
| 'frustration'
|
||||
| 'memory_survey'
|
||||
|
||||
export async function submitTranscriptShare(
|
||||
messages: Message[],
|
||||
trigger: TranscriptShareTrigger,
|
||||
appearanceId: string,
|
||||
): Promise<TranscriptShareResult> {
|
||||
try {
|
||||
logForDebugging('Collecting transcript for sharing', { level: 'info' })
|
||||
|
||||
const transcript = normalizeMessagesForAPI(messages)
|
||||
|
||||
// Collect subagent transcripts
|
||||
const agentIds = extractAgentIdsFromMessages(messages)
|
||||
const subagentTranscripts = await loadSubagentTranscripts(agentIds)
|
||||
|
||||
// Read raw JSONL transcript (with size guard to prevent OOM)
|
||||
let rawTranscriptJsonl: string | undefined
|
||||
try {
|
||||
const transcriptPath = getTranscriptPath()
|
||||
const { size } = await stat(transcriptPath)
|
||||
if (size <= MAX_TRANSCRIPT_READ_BYTES) {
|
||||
rawTranscriptJsonl = await readFile(transcriptPath, 'utf-8')
|
||||
} else {
|
||||
logForDebugging(
|
||||
`Skipping raw transcript read: file too large (${size} bytes)`,
|
||||
{ level: 'warn' },
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
// File may not exist
|
||||
}
|
||||
|
||||
const data = {
|
||||
trigger,
|
||||
version: MACRO.VERSION,
|
||||
platform: process.platform,
|
||||
transcript,
|
||||
subagentTranscripts:
|
||||
Object.keys(subagentTranscripts).length > 0
|
||||
? subagentTranscripts
|
||||
: undefined,
|
||||
rawTranscriptJsonl,
|
||||
}
|
||||
|
||||
const content = redactSensitiveInfo(jsonStringify(data))
|
||||
|
||||
await checkAndRefreshOAuthTokenIfNeeded()
|
||||
|
||||
const authResult = getAuthHeaders()
|
||||
if (authResult.error) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': getUserAgent(),
|
||||
...authResult.headers,
|
||||
}
|
||||
|
||||
const response = await axios.post(
|
||||
'https://api.anthropic.com/api/claude_code_shared_session_transcripts',
|
||||
{ content, appearance_id: appearanceId },
|
||||
{
|
||||
headers,
|
||||
timeout: 30000,
|
||||
},
|
||||
)
|
||||
|
||||
if (response.status === 200 || response.status === 201) {
|
||||
const result = response.data
|
||||
logForDebugging('Transcript shared successfully', { level: 'info' })
|
||||
return {
|
||||
success: true,
|
||||
transcriptId: result?.transcript_id,
|
||||
}
|
||||
}
|
||||
|
||||
return { success: false }
|
||||
} catch (err) {
|
||||
logForDebugging(errorMessage(err), {
|
||||
level: 'error',
|
||||
})
|
||||
return { success: false }
|
||||
}
|
||||
}
|
||||
82
src/components/FeedbackSurvey/useDebouncedDigitInput.ts
Normal file
82
src/components/FeedbackSurvey/useDebouncedDigitInput.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { normalizeFullWidthDigits } from '../../utils/stringUtils.js'
|
||||
|
||||
// Delay before accepting a digit as a response, to prevent accidental
|
||||
// submissions when users start messages with numbers (e.g., numbered lists).
|
||||
// Short enough to feel instant for intentional presses, long enough to
|
||||
// cancel when the user types more characters.
|
||||
const DEFAULT_DEBOUNCE_MS = 400
|
||||
|
||||
/**
|
||||
* Detects when the user types a single valid digit into the prompt input,
|
||||
* debounces to avoid accidental submissions (e.g., "1. First item"),
|
||||
* trims the digit from the input, and fires a callback.
|
||||
*
|
||||
* Used by survey components that accept numeric responses typed directly
|
||||
* into the main prompt input.
|
||||
*/
|
||||
export function useDebouncedDigitInput<T extends string = string>({
|
||||
inputValue,
|
||||
setInputValue,
|
||||
isValidDigit,
|
||||
onDigit,
|
||||
enabled = true,
|
||||
once = false,
|
||||
debounceMs = DEFAULT_DEBOUNCE_MS,
|
||||
}: {
|
||||
inputValue: string
|
||||
setInputValue: (value: string) => void
|
||||
isValidDigit: (char: string) => char is T
|
||||
onDigit: (digit: T) => void
|
||||
enabled?: boolean
|
||||
once?: boolean
|
||||
debounceMs?: number
|
||||
}): void {
|
||||
const initialInputValue = useRef(inputValue)
|
||||
const hasTriggeredRef = useRef(false)
|
||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
// Latest-ref pattern so callers can pass inline callbacks without causing
|
||||
// the effect to re-run (which would reset the debounce timer every render).
|
||||
const callbacksRef = useRef({ setInputValue, isValidDigit, onDigit })
|
||||
callbacksRef.current = { setInputValue, isValidDigit, onDigit }
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || (once && hasTriggeredRef.current)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (debounceRef.current !== null) {
|
||||
clearTimeout(debounceRef.current)
|
||||
debounceRef.current = null
|
||||
}
|
||||
|
||||
if (inputValue !== initialInputValue.current) {
|
||||
const lastChar = normalizeFullWidthDigits(inputValue.slice(-1))
|
||||
if (callbacksRef.current.isValidDigit(lastChar)) {
|
||||
const trimmed = inputValue.slice(0, -1)
|
||||
debounceRef.current = setTimeout(
|
||||
(debounceRef, hasTriggeredRef, callbacksRef, trimmed, lastChar) => {
|
||||
debounceRef.current = null
|
||||
hasTriggeredRef.current = true
|
||||
callbacksRef.current.setInputValue(trimmed)
|
||||
callbacksRef.current.onDigit(lastChar)
|
||||
},
|
||||
debounceMs,
|
||||
debounceRef,
|
||||
hasTriggeredRef,
|
||||
callbacksRef,
|
||||
trimmed,
|
||||
lastChar,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (debounceRef.current !== null) {
|
||||
clearTimeout(debounceRef.current)
|
||||
debounceRef.current = null
|
||||
}
|
||||
}
|
||||
}, [inputValue, enabled, once, debounceMs])
|
||||
}
|
||||
296
src/components/FeedbackSurvey/useFeedbackSurvey.tsx
Normal file
296
src/components/FeedbackSurvey/useFeedbackSurvey.tsx
Normal file
File diff suppressed because one or more lines are too long
213
src/components/FeedbackSurvey/useMemorySurvey.tsx
Normal file
213
src/components/FeedbackSurvey/useMemorySurvey.tsx
Normal file
File diff suppressed because one or more lines are too long
206
src/components/FeedbackSurvey/usePostCompactSurvey.tsx
Normal file
206
src/components/FeedbackSurvey/usePostCompactSurvey.tsx
Normal file
File diff suppressed because one or more lines are too long
100
src/components/FeedbackSurvey/useSurveyState.tsx
Normal file
100
src/components/FeedbackSurvey/useSurveyState.tsx
Normal file
File diff suppressed because one or more lines are too long
181
src/components/FileEditToolDiff.tsx
Normal file
181
src/components/FileEditToolDiff.tsx
Normal file
File diff suppressed because one or more lines are too long
124
src/components/FileEditToolUpdatedMessage.tsx
Normal file
124
src/components/FileEditToolUpdatedMessage.tsx
Normal file
File diff suppressed because one or more lines are too long
170
src/components/FileEditToolUseRejectedMessage.tsx
Normal file
170
src/components/FileEditToolUseRejectedMessage.tsx
Normal file
File diff suppressed because one or more lines are too long
43
src/components/FilePathLink.tsx
Normal file
43
src/components/FilePathLink.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React from 'react';
|
||||
import { pathToFileURL } from 'url';
|
||||
import Link from '../ink/components/Link.js';
|
||||
type Props = {
|
||||
/** The absolute file path */
|
||||
filePath: string;
|
||||
/** Optional display text (defaults to filePath) */
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a file path as an OSC 8 hyperlink.
|
||||
* This helps terminals like iTerm correctly identify file paths
|
||||
* even when they appear inside parentheses or other text.
|
||||
*/
|
||||
export function FilePathLink(t0) {
|
||||
const $ = _c(5);
|
||||
const {
|
||||
filePath,
|
||||
children
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== filePath) {
|
||||
t1 = pathToFileURL(filePath);
|
||||
$[0] = filePath;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const t2 = children ?? filePath;
|
||||
let t3;
|
||||
if ($[2] !== t1.href || $[3] !== t2) {
|
||||
t3 = <Link url={t1.href}>{t2}</Link>;
|
||||
$[2] = t1.href;
|
||||
$[3] = t2;
|
||||
$[4] = t3;
|
||||
} else {
|
||||
t3 = $[4];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInBhdGhUb0ZpbGVVUkwiLCJMaW5rIiwiUHJvcHMiLCJmaWxlUGF0aCIsImNoaWxkcmVuIiwiUmVhY3ROb2RlIiwiRmlsZVBhdGhMaW5rIiwidDAiLCIkIiwiX2MiLCJ0MSIsInQyIiwidDMiLCJocmVmIl0sInNvdXJjZXMiOlsiRmlsZVBhdGhMaW5rLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBwYXRoVG9GaWxlVVJMIH0gZnJvbSAndXJsJ1xuaW1wb3J0IExpbmsgZnJvbSAnLi4vaW5rL2NvbXBvbmVudHMvTGluay5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgLyoqIFRoZSBhYnNvbHV0ZSBmaWxlIHBhdGggKi9cbiAgZmlsZVBhdGg6IHN0cmluZ1xuICAvKiogT3B0aW9uYWwgZGlzcGxheSB0ZXh0IChkZWZhdWx0cyB0byBmaWxlUGF0aCkgKi9cbiAgY2hpbGRyZW4/OiBSZWFjdC5SZWFjdE5vZGVcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGEgZmlsZSBwYXRoIGFzIGFuIE9TQyA4IGh5cGVybGluay5cbiAqIFRoaXMgaGVscHMgdGVybWluYWxzIGxpa2UgaVRlcm0gY29ycmVjdGx5IGlkZW50aWZ5IGZpbGUgcGF0aHNcbiAqIGV2ZW4gd2hlbiB0aGV5IGFwcGVhciBpbnNpZGUgcGFyZW50aGVzZXMgb3Igb3RoZXIgdGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEZpbGVQYXRoTGluayh7IGZpbGVQYXRoLCBjaGlsZHJlbiB9OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHJldHVybiA8TGluayB1cmw9e3BhdGhUb0ZpbGVVUkwoZmlsZVBhdGgpLmhyZWZ9PntjaGlsZHJlbiA/PyBmaWxlUGF0aH08L0xpbms+XG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPQSxLQUFLLE1BQU0sT0FBTztBQUN6QixTQUFTQyxhQUFhLFFBQVEsS0FBSztBQUNuQyxPQUFPQyxJQUFJLE1BQU0sMkJBQTJCO0FBRTVDLEtBQUtDLEtBQUssR0FBRztFQUNYO0VBQ0FDLFFBQVEsRUFBRSxNQUFNO0VBQ2hCO0VBQ0FDLFFBQVEsQ0FBQyxFQUFFTCxLQUFLLENBQUNNLFNBQVM7QUFDNUIsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFBQyxhQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQXNCO0lBQUFOLFFBQUE7SUFBQUM7RUFBQSxJQUFBRyxFQUE2QjtFQUFBLElBQUFHLEVBQUE7RUFBQSxJQUFBRixDQUFBLFFBQUFMLFFBQUE7SUFDdENPLEVBQUEsR0FBQVYsYUFBYSxDQUFDRyxRQUFRLENBQUM7SUFBQUssQ0FBQSxNQUFBTCxRQUFBO0lBQUFLLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBQVEsTUFBQUcsRUFBQSxHQUFBUCxRQUFvQixJQUFwQkQsUUFBb0I7RUFBQSxJQUFBUyxFQUFBO0VBQUEsSUFBQUosQ0FBQSxRQUFBRSxFQUFBLENBQUFHLElBQUEsSUFBQUwsQ0FBQSxRQUFBRyxFQUFBO0lBQTlEQyxFQUFBLElBQUMsSUFBSSxDQUFNLEdBQTRCLENBQTVCLENBQUFGLEVBQXVCLENBQUFHLElBQUksQ0FBQyxDQUFHLENBQUFGLEVBQW1CLENBQUUsRUFBOUQsSUFBSSxDQUFpRTtJQUFBSCxDQUFBLE1BQUFFLEVBQUEsQ0FBQUcsSUFBQTtJQUFBTCxDQUFBLE1BQUFHLEVBQUE7SUFBQUgsQ0FBQSxNQUFBSSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBSixDQUFBO0VBQUE7RUFBQSxPQUF0RUksRUFBc0U7QUFBQSIsImlnbm9yZUxpc3QiOltdfQ==
|
||||
637
src/components/FullscreenLayout.tsx
Normal file
637
src/components/FullscreenLayout.tsx
Normal file
File diff suppressed because one or more lines are too long
343
src/components/GlobalSearchDialog.tsx
Normal file
343
src/components/GlobalSearchDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
82
src/components/HelpV2/Commands.tsx
Normal file
82
src/components/HelpV2/Commands.tsx
Normal file
File diff suppressed because one or more lines are too long
23
src/components/HelpV2/General.tsx
Normal file
23
src/components/HelpV2/General.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import { Box, Text } from '../../ink.js';
|
||||
import { PromptInputHelpMenu } from '../PromptInput/PromptInputHelpMenu.js';
|
||||
export function General() {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <Box><Text>Claude understands your codebase, makes edits with your permission, and executes commands — right from your terminal.</Text></Box>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <Box flexDirection="column" paddingY={1} gap={1}>{t0}<Box flexDirection="column"><Box><Text bold={true}>Shortcuts</Text></Box><PromptInputHelpMenu gap={2} fixedWidth={true} /></Box></Box>;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIlRleHQiLCJQcm9tcHRJbnB1dEhlbHBNZW51IiwiR2VuZXJhbCIsIiQiLCJfYyIsInQwIiwiU3ltYm9sIiwiZm9yIiwidDEiXSwic291cmNlcyI6WyJHZW5lcmFsLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IEJveCwgVGV4dCB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB7IFByb21wdElucHV0SGVscE1lbnUgfSBmcm9tICcuLi9Qcm9tcHRJbnB1dC9Qcm9tcHRJbnB1dEhlbHBNZW51LmpzJ1xuXG5leHBvcnQgZnVuY3Rpb24gR2VuZXJhbCgpOiBSZWFjdC5SZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiIHBhZGRpbmdZPXsxfSBnYXA9ezF9PlxuICAgICAgPEJveD5cbiAgICAgICAgPFRleHQ+XG4gICAgICAgICAgQ2xhdWRlIHVuZGVyc3RhbmRzIHlvdXIgY29kZWJhc2UsIG1ha2VzIGVkaXRzIHdpdGggeW91ciBwZXJtaXNzaW9uLFxuICAgICAgICAgIGFuZCBleGVjdXRlcyBjb21tYW5kcyDigJQgcmlnaHQgZnJvbSB5b3VyIHRlcm1pbmFsLlxuICAgICAgICA8L1RleHQ+XG4gICAgICA8L0JveD5cbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgICA8Qm94PlxuICAgICAgICAgIDxUZXh0IGJvbGQ+U2hvcnRjdXRzPC9UZXh0PlxuICAgICAgICA8L0JveD5cbiAgICAgICAgPFByb21wdElucHV0SGVscE1lbnUgZ2FwPXsyfSBmaXhlZFdpZHRoPXt0cnVlfSAvPlxuICAgICAgPC9Cb3g+XG4gICAgPC9Cb3g+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sS0FBS0EsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsR0FBRyxFQUFFQyxJQUFJLFFBQVEsY0FBYztBQUN4QyxTQUFTQyxtQkFBbUIsUUFBUSx1Q0FBdUM7QUFFM0UsT0FBTyxTQUFBQyxRQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQUEsSUFBQUMsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUcsTUFBQSxDQUFBQyxHQUFBO0lBR0RGLEVBQUEsSUFBQyxHQUFHLENBQ0YsQ0FBQyxJQUFJLENBQUMscUhBR04sRUFIQyxJQUFJLENBSVAsRUFMQyxHQUFHLENBS0U7SUFBQUYsQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxJQUFBSyxFQUFBO0VBQUEsSUFBQUwsQ0FBQSxRQUFBRyxNQUFBLENBQUFDLEdBQUE7SUFOUkMsRUFBQSxJQUFDLEdBQUcsQ0FBZSxhQUFRLENBQVIsUUFBUSxDQUFXLFFBQUMsQ0FBRCxHQUFDLENBQU8sR0FBQyxDQUFELEdBQUMsQ0FDN0MsQ0FBQUgsRUFLSyxDQUNMLENBQUMsR0FBRyxDQUFlLGFBQVEsQ0FBUixRQUFRLENBQ3pCLENBQUMsR0FBRyxDQUNGLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBSixLQUFHLENBQUMsQ0FBQyxTQUFTLEVBQW5CLElBQUksQ0FDUCxFQUZDLEdBQUcsQ0FHSixDQUFDLG1CQUFtQixDQUFNLEdBQUMsQ0FBRCxHQUFDLENBQWMsVUFBSSxDQUFKLEtBQUcsQ0FBQyxHQUMvQyxFQUxDLEdBQUcsQ0FNTixFQWJDLEdBQUcsQ0FhRTtJQUFBRixDQUFBLE1BQUFLLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFMLENBQUE7RUFBQTtFQUFBLE9BYk5LLEVBYU07QUFBQSIsImlnbm9yZUxpc3QiOltdfQ==
|
||||
184
src/components/HelpV2/HelpV2.tsx
Normal file
184
src/components/HelpV2/HelpV2.tsx
Normal file
File diff suppressed because one or more lines are too long
190
src/components/HighlightedCode.tsx
Normal file
190
src/components/HighlightedCode.tsx
Normal file
File diff suppressed because one or more lines are too long
193
src/components/HighlightedCode/Fallback.tsx
Normal file
193
src/components/HighlightedCode/Fallback.tsx
Normal file
File diff suppressed because one or more lines are too long
118
src/components/HistorySearchDialog.tsx
Normal file
118
src/components/HistorySearchDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
154
src/components/IdeAutoConnectDialog.tsx
Normal file
154
src/components/IdeAutoConnectDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
167
src/components/IdeOnboardingDialog.tsx
Normal file
167
src/components/IdeOnboardingDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
58
src/components/IdeStatusIndicator.tsx
Normal file
58
src/components/IdeStatusIndicator.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { basename } from 'path';
|
||||
import * as React from 'react';
|
||||
import { useIdeConnectionStatus } from '../hooks/useIdeConnectionStatus.js';
|
||||
import type { IDESelection } from '../hooks/useIdeSelection.js';
|
||||
import { Text } from '../ink.js';
|
||||
import type { MCPServerConnection } from '../services/mcp/types.js';
|
||||
type IdeStatusIndicatorProps = {
|
||||
ideSelection: IDESelection | undefined;
|
||||
mcpClients?: MCPServerConnection[];
|
||||
};
|
||||
export function IdeStatusIndicator(t0) {
|
||||
const $ = _c(7);
|
||||
const {
|
||||
ideSelection,
|
||||
mcpClients
|
||||
} = t0;
|
||||
const {
|
||||
status: ideStatus
|
||||
} = useIdeConnectionStatus(mcpClients);
|
||||
const shouldShowIdeSelection = ideStatus === "connected" && (ideSelection?.filePath || ideSelection?.text && ideSelection.lineCount > 0);
|
||||
if (ideStatus === null || !shouldShowIdeSelection || !ideSelection) {
|
||||
return null;
|
||||
}
|
||||
if (ideSelection.text && ideSelection.lineCount > 0) {
|
||||
const t1 = ideSelection.lineCount === 1 ? "line" : "lines";
|
||||
let t2;
|
||||
if ($[0] !== ideSelection.lineCount || $[1] !== t1) {
|
||||
t2 = <Text color="ide" key="selection-indicator" wrap="truncate">⧉ {ideSelection.lineCount}{" "}{t1} selected</Text>;
|
||||
$[0] = ideSelection.lineCount;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
if (ideSelection.filePath) {
|
||||
let t1;
|
||||
if ($[3] !== ideSelection.filePath) {
|
||||
t1 = basename(ideSelection.filePath);
|
||||
$[3] = ideSelection.filePath;
|
||||
$[4] = t1;
|
||||
} else {
|
||||
t1 = $[4];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== t1) {
|
||||
t2 = <Text color="ide" key="selection-indicator" wrap="truncate">⧉ In {t1}</Text>;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXNlbmFtZSIsIlJlYWN0IiwidXNlSWRlQ29ubmVjdGlvblN0YXR1cyIsIklERVNlbGVjdGlvbiIsIlRleHQiLCJNQ1BTZXJ2ZXJDb25uZWN0aW9uIiwiSWRlU3RhdHVzSW5kaWNhdG9yUHJvcHMiLCJpZGVTZWxlY3Rpb24iLCJtY3BDbGllbnRzIiwiSWRlU3RhdHVzSW5kaWNhdG9yIiwidDAiLCIkIiwiX2MiLCJzdGF0dXMiLCJpZGVTdGF0dXMiLCJzaG91bGRTaG93SWRlU2VsZWN0aW9uIiwiZmlsZVBhdGgiLCJ0ZXh0IiwibGluZUNvdW50IiwidDEiLCJ0MiJdLCJzb3VyY2VzIjpbIklkZVN0YXR1c0luZGljYXRvci50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgYmFzZW5hbWUgfSBmcm9tICdwYXRoJ1xuaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VJZGVDb25uZWN0aW9uU3RhdHVzIH0gZnJvbSAnLi4vaG9va3MvdXNlSWRlQ29ubmVjdGlvblN0YXR1cy5qcydcbmltcG9ydCB0eXBlIHsgSURFU2VsZWN0aW9uIH0gZnJvbSAnLi4vaG9va3MvdXNlSWRlU2VsZWN0aW9uLmpzJ1xuaW1wb3J0IHsgVGV4dCB9IGZyb20gJy4uL2luay5qcydcbmltcG9ydCB0eXBlIHsgTUNQU2VydmVyQ29ubmVjdGlvbiB9IGZyb20gJy4uL3NlcnZpY2VzL21jcC90eXBlcy5qcydcblxudHlwZSBJZGVTdGF0dXNJbmRpY2F0b3JQcm9wcyA9IHtcbiAgaWRlU2VsZWN0aW9uOiBJREVTZWxlY3Rpb24gfCB1bmRlZmluZWRcbiAgbWNwQ2xpZW50cz86IE1DUFNlcnZlckNvbm5lY3Rpb25bXVxufVxuXG5leHBvcnQgZnVuY3Rpb24gSWRlU3RhdHVzSW5kaWNhdG9yKHtcbiAgaWRlU2VsZWN0aW9uLFxuICBtY3BDbGllbnRzLFxufTogSWRlU3RhdHVzSW5kaWNhdG9yUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCB7IHN0YXR1czogaWRlU3RhdHVzIH0gPSB1c2VJZGVDb25uZWN0aW9uU3RhdHVzKG1jcENsaWVudHMpXG5cbiAgLy8gQ2hlY2sgaWYgd2Ugc2hvdWxkIHNob3cgdGhlIElERSBzZWxlY3Rpb24gaW5kaWNhdG9yXG4gIGNvbnN0IHNob3VsZFNob3dJZGVTZWxlY3Rpb24gPVxuICAgIGlkZVN0YXR1cyA9PT0gJ2Nvbm5lY3RlZCcgJiZcbiAgICAoaWRlU2VsZWN0aW9uPy5maWxlUGF0aCB8fFxuICAgICAgKGlkZVNlbGVjdGlvbj8udGV4dCAmJiBpZGVTZWxlY3Rpb24ubGluZUNvdW50ID4gMCkpXG5cbiAgaWYgKGlkZVN0YXR1cyA9PT0gbnVsbCB8fCAhc2hvdWxkU2hvd0lkZVNlbGVjdGlvbiB8fCAhaWRlU2VsZWN0aW9uKSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIGlmIChpZGVTZWxlY3Rpb24udGV4dCAmJiBpZGVTZWxlY3Rpb24ubGluZUNvdW50ID4gMCkge1xuICAgIHJldHVybiAoXG4gICAgICA8VGV4dCBjb2xvcj1cImlkZVwiIGtleT1cInNlbGVjdGlvbi1pbmRpY2F0b3JcIiB3cmFwPVwidHJ1bmNhdGVcIj5cbiAgICAgICAg4qeJIHtpZGVTZWxlY3Rpb24ubGluZUNvdW50fXsnICd9XG4gICAgICAgIHtpZGVTZWxlY3Rpb24ubGluZUNvdW50ID09PSAxID8gJ2xpbmUnIDogJ2xpbmVzJ30gc2VsZWN0ZWRcbiAgICAgIDwvVGV4dD5cbiAgICApXG4gIH1cblxuICBpZiAoaWRlU2VsZWN0aW9uLmZpbGVQYXRoKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxUZXh0IGNvbG9yPVwiaWRlXCIga2V5PVwic2VsZWN0aW9uLWluZGljYXRvclwiIHdyYXA9XCJ0cnVuY2F0ZVwiPlxuICAgICAgICDip4kgSW4ge2Jhc2VuYW1lKGlkZVNlbGVjdGlvbi5maWxlUGF0aCl9XG4gICAgICA8L1RleHQ+XG4gICAgKVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxTQUFTQSxRQUFRLFFBQVEsTUFBTTtBQUMvQixPQUFPLEtBQUtDLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLHNCQUFzQixRQUFRLG9DQUFvQztBQUMzRSxjQUFjQyxZQUFZLFFBQVEsNkJBQTZCO0FBQy9ELFNBQVNDLElBQUksUUFBUSxXQUFXO0FBQ2hDLGNBQWNDLG1CQUFtQixRQUFRLDBCQUEwQjtBQUVuRSxLQUFLQyx1QkFBdUIsR0FBRztFQUM3QkMsWUFBWSxFQUFFSixZQUFZLEdBQUcsU0FBUztFQUN0Q0ssVUFBVSxDQUFDLEVBQUVILG1CQUFtQixFQUFFO0FBQ3BDLENBQUM7QUFFRCxPQUFPLFNBQUFJLG1CQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQTRCO0lBQUFMLFlBQUE7SUFBQUM7RUFBQSxJQUFBRSxFQUdUO0VBQ3hCO0lBQUFHLE1BQUEsRUFBQUM7RUFBQSxJQUE4Qlosc0JBQXNCLENBQUNNLFVBQVUsQ0FBQztFQUdoRSxNQUFBTyxzQkFBQSxHQUNFRCxTQUFTLEtBQUssV0FFdUMsS0FEcERQLFlBQVksRUFBQVMsUUFDdUMsSUFBakRULFlBQVksRUFBQVUsSUFBb0MsSUFBMUJWLFlBQVksQ0FBQVcsU0FBVSxHQUFHLENBQUc7RUFFdkQsSUFBSUosU0FBUyxLQUFLLElBQStCLElBQTdDLENBQXVCQyxzQkFBdUMsSUFBOUQsQ0FBa0RSLFlBQVk7SUFBQSxPQUN6RCxJQUFJO0VBQUE7RUFHYixJQUFJQSxZQUFZLENBQUFVLElBQW1DLElBQTFCVixZQUFZLENBQUFXLFNBQVUsR0FBRyxDQUFDO0lBSTVDLE1BQUFDLEVBQUEsR0FBQVosWUFBWSxDQUFBVyxTQUFVLEtBQUssQ0FBb0IsR0FBL0MsTUFBK0MsR0FBL0MsT0FBK0M7SUFBQSxJQUFBRSxFQUFBO0lBQUEsSUFBQVQsQ0FBQSxRQUFBSixZQUFBLENBQUFXLFNBQUEsSUFBQVAsQ0FBQSxRQUFBUSxFQUFBO01BRmxEQyxFQUFBLElBQUMsSUFBSSxDQUFPLEtBQUssQ0FBTCxLQUFLLENBQUssR0FBcUIsQ0FBckIscUJBQXFCLENBQU0sSUFBVSxDQUFWLFVBQVUsQ0FBQyxFQUN2RCxDQUFBYixZQUFZLENBQUFXLFNBQVMsQ0FBRyxJQUFFLENBQzVCLENBQUFDLEVBQThDLENBQUUsU0FDbkQsRUFIQyxJQUFJLENBR0U7TUFBQVIsQ0FBQSxNQUFBSixZQUFBLENBQUFXLFNBQUE7TUFBQVAsQ0FBQSxNQUFBUSxFQUFBO01BQUFSLENBQUEsTUFBQVMsRUFBQTtJQUFBO01BQUFBLEVBQUEsR0FBQVQsQ0FBQTtJQUFBO0lBQUEsT0FIUFMsRUFHTztFQUFBO0VBSVgsSUFBSWIsWUFBWSxDQUFBUyxRQUFTO0lBQUEsSUFBQUcsRUFBQTtJQUFBLElBQUFSLENBQUEsUUFBQUosWUFBQSxDQUFBUyxRQUFBO01BR2JHLEVBQUEsR0FBQW5CLFFBQVEsQ0FBQ08sWUFBWSxDQUFBUyxRQUFTLENBQUM7TUFBQUwsQ0FBQSxNQUFBSixZQUFBLENBQUFTLFFBQUE7TUFBQUwsQ0FBQSxNQUFBUSxFQUFBO0lBQUE7TUFBQUEsRUFBQSxHQUFBUixDQUFBO0lBQUE7SUFBQSxJQUFBUyxFQUFBO0lBQUEsSUFBQVQsQ0FBQSxRQUFBUSxFQUFBO01BRHZDQyxFQUFBLElBQUMsSUFBSSxDQUFPLEtBQUssQ0FBTCxLQUFLLENBQUssR0FBcUIsQ0FBckIscUJBQXFCLENBQU0sSUFBVSxDQUFWLFVBQVUsQ0FBQyxLQUNwRCxDQUFBRCxFQUE4QixDQUN0QyxFQUZDLElBQUksQ0FFRTtNQUFBUixDQUFBLE1BQUFRLEVBQUE7TUFBQVIsQ0FBQSxNQUFBUyxFQUFBO0lBQUE7TUFBQUEsRUFBQSxHQUFBVCxDQUFBO0lBQUE7SUFBQSxPQUZQUyxFQUVPO0VBQUE7QUFFViIsImlnbm9yZUxpc3QiOltdfQ==
|
||||
118
src/components/IdleReturnDialog.tsx
Normal file
118
src/components/IdleReturnDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
15
src/components/InterruptedByUser.tsx
Normal file
15
src/components/InterruptedByUser.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import { Text } from '../ink.js';
|
||||
export function InterruptedByUser() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <><Text dimColor={true}>Interrupted </Text>{false ? <Text dimColor={true}>· [ANT-ONLY] /issue to report a model issue</Text> : <Text dimColor={true}>· What should Claude do instead?</Text>}</>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlRleHQiLCJJbnRlcnJ1cHRlZEJ5VXNlciIsIiQiLCJfYyIsInQwIiwiU3ltYm9sIiwiZm9yIl0sInNvdXJjZXMiOlsiSW50ZXJydXB0ZWRCeVVzZXIudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgVGV4dCB9IGZyb20gJy4uL2luay5qcydcblxuZXhwb3J0IGZ1bmN0aW9uIEludGVycnVwdGVkQnlVc2VyKCk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIHJldHVybiAoXG4gICAgPD5cbiAgICAgIDxUZXh0IGRpbUNvbG9yPkludGVycnVwdGVkIDwvVGV4dD5cbiAgICAgIHtcImV4dGVybmFsXCIgPT09ICdhbnQnID8gKFxuICAgICAgICA8VGV4dCBkaW1Db2xvcj7CtyBbQU5ULU9OTFldIC9pc3N1ZSB0byByZXBvcnQgYSBtb2RlbCBpc3N1ZTwvVGV4dD5cbiAgICAgICkgOiAoXG4gICAgICAgIDxUZXh0IGRpbUNvbG9yPsK3IFdoYXQgc2hvdWxkIENsYXVkZSBkbyBpbnN0ZWFkPzwvVGV4dD5cbiAgICAgICl9XG4gICAgPC8+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sS0FBS0EsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsSUFBSSxRQUFRLFdBQVc7QUFFaEMsT0FBTyxTQUFBQyxrQkFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUFBLElBQUFDLEVBQUE7RUFBQSxJQUFBRixDQUFBLFFBQUFHLE1BQUEsQ0FBQUMsR0FBQTtJQUVIRixFQUFBLEtBQ0UsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFSLEtBQU8sQ0FBQyxDQUFDLFlBQVksRUFBMUIsSUFBSSxDQUNKLE1BQW9CLEdBQ25CLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBUixLQUFPLENBQUMsQ0FBQywyQ0FBMkMsRUFBekQsSUFBSSxDQUdOLEdBREMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFSLEtBQU8sQ0FBQyxDQUFDLGdDQUFnQyxFQUE5QyxJQUFJLENBQ1AsQ0FBQyxHQUNBO0lBQUFGLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBQUEsT0FQSEUsRUFPRztBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
156
src/components/InvalidConfigDialog.tsx
Normal file
156
src/components/InvalidConfigDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
89
src/components/InvalidSettingsDialog.tsx
Normal file
89
src/components/InvalidSettingsDialog.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React from 'react';
|
||||
import { Text } from '../ink.js';
|
||||
import type { ValidationError } from '../utils/settings/validation.js';
|
||||
import { Select } from './CustomSelect/index.js';
|
||||
import { Dialog } from './design-system/Dialog.js';
|
||||
import { ValidationErrorsList } from './ValidationErrorsList.js';
|
||||
type Props = {
|
||||
settingsErrors: ValidationError[];
|
||||
onContinue: () => void;
|
||||
onExit: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dialog shown when settings files have validation errors.
|
||||
* User must choose to continue (skipping invalid files) or exit to fix them.
|
||||
*/
|
||||
export function InvalidSettingsDialog(t0) {
|
||||
const $ = _c(13);
|
||||
const {
|
||||
settingsErrors,
|
||||
onContinue,
|
||||
onExit
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== onContinue || $[1] !== onExit) {
|
||||
t1 = function handleSelect(value) {
|
||||
if (value === "exit") {
|
||||
onExit();
|
||||
} else {
|
||||
onContinue();
|
||||
}
|
||||
};
|
||||
$[0] = onContinue;
|
||||
$[1] = onExit;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
const handleSelect = t1;
|
||||
let t2;
|
||||
if ($[3] !== settingsErrors) {
|
||||
t2 = <ValidationErrorsList errors={settingsErrors} />;
|
||||
$[3] = settingsErrors;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
let t3;
|
||||
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = <Text dimColor={true}>Files with errors are skipped entirely, not just the invalid settings.</Text>;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
}
|
||||
let t4;
|
||||
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t4 = [{
|
||||
label: "Exit and fix manually",
|
||||
value: "exit"
|
||||
}, {
|
||||
label: "Continue without these settings",
|
||||
value: "continue"
|
||||
}];
|
||||
$[6] = t4;
|
||||
} else {
|
||||
t4 = $[6];
|
||||
}
|
||||
let t5;
|
||||
if ($[7] !== handleSelect) {
|
||||
t5 = <Select options={t4} onChange={handleSelect} />;
|
||||
$[7] = handleSelect;
|
||||
$[8] = t5;
|
||||
} else {
|
||||
t5 = $[8];
|
||||
}
|
||||
let t6;
|
||||
if ($[9] !== onExit || $[10] !== t2 || $[11] !== t5) {
|
||||
t6 = <Dialog title="Settings Error" onCancel={onExit} color="warning">{t2}{t3}{t5}</Dialog>;
|
||||
$[9] = onExit;
|
||||
$[10] = t2;
|
||||
$[11] = t5;
|
||||
$[12] = t6;
|
||||
} else {
|
||||
t6 = $[12];
|
||||
}
|
||||
return t6;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlRleHQiLCJWYWxpZGF0aW9uRXJyb3IiLCJTZWxlY3QiLCJEaWFsb2ciLCJWYWxpZGF0aW9uRXJyb3JzTGlzdCIsIlByb3BzIiwic2V0dGluZ3NFcnJvcnMiLCJvbkNvbnRpbnVlIiwib25FeGl0IiwiSW52YWxpZFNldHRpbmdzRGlhbG9nIiwidDAiLCIkIiwiX2MiLCJ0MSIsImhhbmRsZVNlbGVjdCIsInZhbHVlIiwidDIiLCJ0MyIsIlN5bWJvbCIsImZvciIsInQ0IiwibGFiZWwiLCJ0NSIsInQ2Il0sInNvdXJjZXMiOlsiSW52YWxpZFNldHRpbmdzRGlhbG9nLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBUZXh0IH0gZnJvbSAnLi4vaW5rLmpzJ1xuaW1wb3J0IHR5cGUgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tICcuLi91dGlscy9zZXR0aW5ncy92YWxpZGF0aW9uLmpzJ1xuaW1wb3J0IHsgU2VsZWN0IH0gZnJvbSAnLi9DdXN0b21TZWxlY3QvaW5kZXguanMnXG5pbXBvcnQgeyBEaWFsb2cgfSBmcm9tICcuL2Rlc2lnbi1zeXN0ZW0vRGlhbG9nLmpzJ1xuaW1wb3J0IHsgVmFsaWRhdGlvbkVycm9yc0xpc3QgfSBmcm9tICcuL1ZhbGlkYXRpb25FcnJvcnNMaXN0LmpzJ1xuXG50eXBlIFByb3BzID0ge1xuICBzZXR0aW5nc0Vycm9yczogVmFsaWRhdGlvbkVycm9yW11cbiAgb25Db250aW51ZTogKCkgPT4gdm9pZFxuICBvbkV4aXQ6ICgpID0+IHZvaWRcbn1cblxuLyoqXG4gKiBEaWFsb2cgc2hvd24gd2hlbiBzZXR0aW5ncyBmaWxlcyBoYXZlIHZhbGlkYXRpb24gZXJyb3JzLlxuICogVXNlciBtdXN0IGNob29zZSB0byBjb250aW51ZSAoc2tpcHBpbmcgaW52YWxpZCBmaWxlcykgb3IgZXhpdCB0byBmaXggdGhlbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEludmFsaWRTZXR0aW5nc0RpYWxvZyh7XG4gIHNldHRpbmdzRXJyb3JzLFxuICBvbkNvbnRpbnVlLFxuICBvbkV4aXQsXG59OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGZ1bmN0aW9uIGhhbmRsZVNlbGVjdCh2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlID09PSAnZXhpdCcpIHtcbiAgICAgIG9uRXhpdCgpXG4gICAgfSBlbHNlIHtcbiAgICAgIG9uQ29udGludWUoKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPERpYWxvZyB0aXRsZT1cIlNldHRpbmdzIEVycm9yXCIgb25DYW5jZWw9e29uRXhpdH0gY29sb3I9XCJ3YXJuaW5nXCI+XG4gICAgICA8VmFsaWRhdGlvbkVycm9yc0xpc3QgZXJyb3JzPXtzZXR0aW5nc0Vycm9yc30gLz5cbiAgICAgIDxUZXh0IGRpbUNvbG9yPlxuICAgICAgICBGaWxlcyB3aXRoIGVycm9ycyBhcmUgc2tpcHBlZCBlbnRpcmVseSwgbm90IGp1c3QgdGhlIGludmFsaWQgc2V0dGluZ3MuXG4gICAgICA8L1RleHQ+XG4gICAgICA8U2VsZWN0XG4gICAgICAgIG9wdGlvbnM9e1tcbiAgICAgICAgICB7IGxhYmVsOiAnRXhpdCBhbmQgZml4IG1hbnVhbGx5JywgdmFsdWU6ICdleGl0JyB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGxhYmVsOiAnQ29udGludWUgd2l0aG91dCB0aGVzZSBzZXR0aW5ncycsXG4gICAgICAgICAgICB2YWx1ZTogJ2NvbnRpbnVlJyxcbiAgICAgICAgICB9LFxuICAgICAgICBdfVxuICAgICAgICBvbkNoYW5nZT17aGFuZGxlU2VsZWN0fVxuICAgICAgLz5cbiAgICA8L0RpYWxvZz5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsU0FBU0MsSUFBSSxRQUFRLFdBQVc7QUFDaEMsY0FBY0MsZUFBZSxRQUFRLGlDQUFpQztBQUN0RSxTQUFTQyxNQUFNLFFBQVEseUJBQXlCO0FBQ2hELFNBQVNDLE1BQU0sUUFBUSwyQkFBMkI7QUFDbEQsU0FBU0Msb0JBQW9CLFFBQVEsMkJBQTJCO0FBRWhFLEtBQUtDLEtBQUssR0FBRztFQUNYQyxjQUFjLEVBQUVMLGVBQWUsRUFBRTtFQUNqQ00sVUFBVSxFQUFFLEdBQUcsR0FBRyxJQUFJO0VBQ3RCQyxNQUFNLEVBQUUsR0FBRyxHQUFHLElBQUk7QUFDcEIsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sU0FBQUMsc0JBQUFDLEVBQUE7RUFBQSxNQUFBQyxDQUFBLEdBQUFDLEVBQUE7RUFBK0I7SUFBQU4sY0FBQTtJQUFBQyxVQUFBO0lBQUFDO0VBQUEsSUFBQUUsRUFJOUI7RUFBQSxJQUFBRyxFQUFBO0VBQUEsSUFBQUYsQ0FBQSxRQUFBSixVQUFBLElBQUFJLENBQUEsUUFBQUgsTUFBQTtJQUNOSyxFQUFBLFlBQUFDLGFBQUFDLEtBQUE7TUFDRSxJQUFJQSxLQUFLLEtBQUssTUFBTTtRQUNsQlAsTUFBTSxDQUFDLENBQUM7TUFBQTtRQUVSRCxVQUFVLENBQUMsQ0FBQztNQUFBO0lBQ2IsQ0FDRjtJQUFBSSxDQUFBLE1BQUFKLFVBQUE7SUFBQUksQ0FBQSxNQUFBSCxNQUFBO0lBQUFHLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBTkQsTUFBQUcsWUFBQSxHQUFBRCxFQU1DO0VBQUEsSUFBQUcsRUFBQTtFQUFBLElBQUFMLENBQUEsUUFBQUwsY0FBQTtJQUlHVSxFQUFBLElBQUMsb0JBQW9CLENBQVNWLE1BQWMsQ0FBZEEsZUFBYSxDQUFDLEdBQUk7SUFBQUssQ0FBQSxNQUFBTCxjQUFBO0lBQUFLLENBQUEsTUFBQUssRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUwsQ0FBQTtFQUFBO0VBQUEsSUFBQU0sRUFBQTtFQUFBLElBQUFOLENBQUEsUUFBQU8sTUFBQSxDQUFBQyxHQUFBO0lBQ2hERixFQUFBLElBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBUixLQUFPLENBQUMsQ0FBQyxzRUFFZixFQUZDLElBQUksQ0FFRTtJQUFBTixDQUFBLE1BQUFNLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFOLENBQUE7RUFBQTtFQUFBLElBQUFTLEVBQUE7RUFBQSxJQUFBVCxDQUFBLFFBQUFPLE1BQUEsQ0FBQUMsR0FBQTtJQUVJQyxFQUFBLElBQ1A7TUFBQUMsS0FBQSxFQUFTLHVCQUF1QjtNQUFBTixLQUFBLEVBQVM7SUFBTyxDQUFDLEVBQ2pEO01BQUFNLEtBQUEsRUFDUyxpQ0FBaUM7TUFBQU4sS0FBQSxFQUNqQztJQUNULENBQUMsQ0FDRjtJQUFBSixDQUFBLE1BQUFTLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFULENBQUE7RUFBQTtFQUFBLElBQUFXLEVBQUE7RUFBQSxJQUFBWCxDQUFBLFFBQUFHLFlBQUE7SUFQSFEsRUFBQSxJQUFDLE1BQU0sQ0FDSSxPQU1SLENBTlEsQ0FBQUYsRUFNVCxDQUFDLENBQ1NOLFFBQVksQ0FBWkEsYUFBVyxDQUFDLEdBQ3RCO0lBQUFILENBQUEsTUFBQUcsWUFBQTtJQUFBSCxDQUFBLE1BQUFXLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFYLENBQUE7RUFBQTtFQUFBLElBQUFZLEVBQUE7RUFBQSxJQUFBWixDQUFBLFFBQUFILE1BQUEsSUFBQUcsQ0FBQSxTQUFBSyxFQUFBLElBQUFMLENBQUEsU0FBQVcsRUFBQTtJQWRKQyxFQUFBLElBQUMsTUFBTSxDQUFPLEtBQWdCLENBQWhCLGdCQUFnQixDQUFXZixRQUFNLENBQU5BLE9BQUssQ0FBQyxDQUFRLEtBQVMsQ0FBVCxTQUFTLENBQzlELENBQUFRLEVBQStDLENBQy9DLENBQUFDLEVBRU0sQ0FDTixDQUFBSyxFQVNDLENBQ0gsRUFmQyxNQUFNLENBZUU7SUFBQVgsQ0FBQSxNQUFBSCxNQUFBO0lBQUFHLENBQUEsT0FBQUssRUFBQTtJQUFBTCxDQUFBLE9BQUFXLEVBQUE7SUFBQVgsQ0FBQSxPQUFBWSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBWixDQUFBO0VBQUE7RUFBQSxPQWZUWSxFQWVTO0FBQUEiLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
55
src/components/KeybindingWarnings.tsx
Normal file
55
src/components/KeybindingWarnings.tsx
Normal file
File diff suppressed because one or more lines are too long
86
src/components/LanguagePicker.tsx
Normal file
86
src/components/LanguagePicker.tsx
Normal file
File diff suppressed because one or more lines are too long
1575
src/components/LogSelector.tsx
Normal file
1575
src/components/LogSelector.tsx
Normal file
File diff suppressed because one or more lines are too long
50
src/components/LogoV2/AnimatedAsterisk.tsx
Normal file
50
src/components/LogoV2/AnimatedAsterisk.tsx
Normal file
File diff suppressed because one or more lines are too long
124
src/components/LogoV2/AnimatedClawd.tsx
Normal file
124
src/components/LogoV2/AnimatedClawd.tsx
Normal file
File diff suppressed because one or more lines are too long
266
src/components/LogoV2/ChannelsNotice.tsx
Normal file
266
src/components/LogoV2/ChannelsNotice.tsx
Normal file
File diff suppressed because one or more lines are too long
240
src/components/LogoV2/Clawd.tsx
Normal file
240
src/components/LogoV2/Clawd.tsx
Normal file
File diff suppressed because one or more lines are too long
161
src/components/LogoV2/CondensedLogo.tsx
Normal file
161
src/components/LogoV2/CondensedLogo.tsx
Normal file
File diff suppressed because one or more lines are too long
58
src/components/LogoV2/EmergencyTip.tsx
Normal file
58
src/components/LogoV2/EmergencyTip.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { Box, Text } from 'src/ink.js';
|
||||
import { getDynamicConfig_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js';
|
||||
import { getGlobalConfig, saveGlobalConfig } from 'src/utils/config.js';
|
||||
const CONFIG_NAME = 'tengu-top-of-feed-tip';
|
||||
export function EmergencyTip(): React.ReactNode {
|
||||
const tip = useMemo(getTipOfFeed, []);
|
||||
// Memoize to prevent re-reads after we save - we want the value at mount time
|
||||
const lastShownTip = useMemo(() => getGlobalConfig().lastShownEmergencyTip, []);
|
||||
|
||||
// Only show if this is a new/different tip
|
||||
const shouldShow = tip.tip && tip.tip !== lastShownTip;
|
||||
|
||||
// Save the tip we're showing so we don't show it again
|
||||
useEffect(() => {
|
||||
if (shouldShow) {
|
||||
saveGlobalConfig(current => {
|
||||
if (current.lastShownEmergencyTip === tip.tip) return current;
|
||||
return {
|
||||
...current,
|
||||
lastShownEmergencyTip: tip.tip
|
||||
};
|
||||
});
|
||||
}
|
||||
}, [shouldShow, tip.tip]);
|
||||
if (!shouldShow) {
|
||||
return null;
|
||||
}
|
||||
return <Box paddingLeft={2} flexDirection="column">
|
||||
<Text {...tip.color === 'warning' ? {
|
||||
color: 'warning'
|
||||
} : tip.color === 'error' ? {
|
||||
color: 'error'
|
||||
} : {
|
||||
dimColor: true
|
||||
}}>
|
||||
{tip.tip}
|
||||
</Text>
|
||||
</Box>;
|
||||
}
|
||||
type TipOfFeed = {
|
||||
tip: string;
|
||||
color?: 'dim' | 'warning' | 'error';
|
||||
};
|
||||
const DEFAULT_TIP: TipOfFeed = {
|
||||
tip: '',
|
||||
color: 'dim'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the tip of the feed from dynamic config with caching
|
||||
* Returns cached value immediately, updates in background
|
||||
*/
|
||||
function getTipOfFeed(): TipOfFeed {
|
||||
return getDynamicConfig_CACHED_MAY_BE_STALE<TipOfFeed>(CONFIG_NAME, DEFAULT_TIP);
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZUVmZmVjdCIsInVzZU1lbW8iLCJCb3giLCJUZXh0IiwiZ2V0RHluYW1pY0NvbmZpZ19DQUNIRURfTUFZX0JFX1NUQUxFIiwiZ2V0R2xvYmFsQ29uZmlnIiwic2F2ZUdsb2JhbENvbmZpZyIsIkNPTkZJR19OQU1FIiwiRW1lcmdlbmN5VGlwIiwiUmVhY3ROb2RlIiwidGlwIiwiZ2V0VGlwT2ZGZWVkIiwibGFzdFNob3duVGlwIiwibGFzdFNob3duRW1lcmdlbmN5VGlwIiwic2hvdWxkU2hvdyIsImN1cnJlbnQiLCJjb2xvciIsImRpbUNvbG9yIiwiVGlwT2ZGZWVkIiwiREVGQVVMVF9USVAiXSwic291cmNlcyI6WyJFbWVyZ2VuY3lUaXAudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgdXNlRWZmZWN0LCB1c2VNZW1vIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBCb3gsIFRleHQgfSBmcm9tICdzcmMvaW5rLmpzJ1xuaW1wb3J0IHsgZ2V0RHluYW1pY0NvbmZpZ19DQUNIRURfTUFZX0JFX1NUQUxFIH0gZnJvbSAnc3JjL3NlcnZpY2VzL2FuYWx5dGljcy9ncm93dGhib29rLmpzJ1xuaW1wb3J0IHsgZ2V0R2xvYmFsQ29uZmlnLCBzYXZlR2xvYmFsQ29uZmlnIH0gZnJvbSAnc3JjL3V0aWxzL2NvbmZpZy5qcydcblxuY29uc3QgQ09ORklHX05BTUUgPSAndGVuZ3UtdG9wLW9mLWZlZWQtdGlwJ1xuXG5leHBvcnQgZnVuY3Rpb24gRW1lcmdlbmN5VGlwKCk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IHRpcCA9IHVzZU1lbW8oZ2V0VGlwT2ZGZWVkLCBbXSlcbiAgLy8gTWVtb2l6ZSB0byBwcmV2ZW50IHJlLXJlYWRzIGFmdGVyIHdlIHNhdmUgLSB3ZSB3YW50IHRoZSB2YWx1ZSBhdCBtb3VudCB0aW1lXG4gIGNvbnN0IGxhc3RTaG93blRpcCA9IHVzZU1lbW8oXG4gICAgKCkgPT4gZ2V0R2xvYmFsQ29uZmlnKCkubGFzdFNob3duRW1lcmdlbmN5VGlwLFxuICAgIFtdLFxuICApXG5cbiAgLy8gT25seSBzaG93IGlmIHRoaXMgaXMgYSBuZXcvZGlmZmVyZW50IHRpcFxuICBjb25zdCBzaG91bGRTaG93ID0gdGlwLnRpcCAmJiB0aXAudGlwICE9PSBsYXN0U2hvd25UaXBcblxuICAvLyBTYXZlIHRoZSB0aXAgd2UncmUgc2hvd2luZyBzbyB3ZSBkb24ndCBzaG93IGl0IGFnYWluXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKHNob3VsZFNob3cpIHtcbiAgICAgIHNhdmVHbG9iYWxDb25maWcoY3VycmVudCA9PiB7XG4gICAgICAgIGlmIChjdXJyZW50Lmxhc3RTaG93bkVtZXJnZW5jeVRpcCA9PT0gdGlwLnRpcCkgcmV0dXJuIGN1cnJlbnRcbiAgICAgICAgcmV0dXJuIHsgLi4uY3VycmVudCwgbGFzdFNob3duRW1lcmdlbmN5VGlwOiB0aXAudGlwIH1cbiAgICAgIH0pXG4gICAgfVxuICB9LCBbc2hvdWxkU2hvdywgdGlwLnRpcF0pXG5cbiAgaWYgKCFzaG91bGRTaG93KSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPEJveCBwYWRkaW5nTGVmdD17Mn0gZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgPFRleHRcbiAgICAgICAgey4uLih0aXAuY29sb3IgPT09ICd3YXJuaW5nJ1xuICAgICAgICAgID8geyBjb2xvcjogJ3dhcm5pbmcnIH1cbiAgICAgICAgICA6IHRpcC5jb2xvciA9PT0gJ2Vycm9yJ1xuICAgICAgICAgICAgPyB7IGNvbG9yOiAnZXJyb3InIH1cbiAgICAgICAgICAgIDogeyBkaW1Db2xvcjogdHJ1ZSB9KX1cbiAgICAgID5cbiAgICAgICAge3RpcC50aXB9XG4gICAgICA8L1RleHQ+XG4gICAgPC9Cb3g+XG4gIClcbn1cblxudHlwZSBUaXBPZkZlZWQgPSB7XG4gIHRpcDogc3RyaW5nXG4gIGNvbG9yPzogJ2RpbScgfCAnd2FybmluZycgfCAnZXJyb3InXG59XG5cbmNvbnN0IERFRkFVTFRfVElQOiBUaXBPZkZlZWQgPSB7IHRpcDogJycsIGNvbG9yOiAnZGltJyB9XG5cbi8qKlxuICogR2V0IHRoZSB0aXAgb2YgdGhlIGZlZWQgZnJvbSBkeW5hbWljIGNvbmZpZyB3aXRoIGNhY2hpbmdcbiAqIFJldHVybnMgY2FjaGVkIHZhbHVlIGltbWVkaWF0ZWx5LCB1cGRhdGVzIGluIGJhY2tncm91bmRcbiAqL1xuZnVuY3Rpb24gZ2V0VGlwT2ZGZWVkKCk6IFRpcE9mRmVlZCB7XG4gIHJldHVybiBnZXREeW5hbWljQ29uZmlnX0NBQ0hFRF9NQVlfQkVfU1RBTEU8VGlwT2ZGZWVkPihcbiAgICBDT05GSUdfTkFNRSxcbiAgICBERUZBVUxUX1RJUCxcbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUtBLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLFNBQVMsRUFBRUMsT0FBTyxRQUFRLE9BQU87QUFDMUMsU0FBU0MsR0FBRyxFQUFFQyxJQUFJLFFBQVEsWUFBWTtBQUN0QyxTQUFTQyxvQ0FBb0MsUUFBUSxzQ0FBc0M7QUFDM0YsU0FBU0MsZUFBZSxFQUFFQyxnQkFBZ0IsUUFBUSxxQkFBcUI7QUFFdkUsTUFBTUMsV0FBVyxHQUFHLHVCQUF1QjtBQUUzQyxPQUFPLFNBQVNDLFlBQVlBLENBQUEsQ0FBRSxFQUFFVCxLQUFLLENBQUNVLFNBQVMsQ0FBQztFQUM5QyxNQUFNQyxHQUFHLEdBQUdULE9BQU8sQ0FBQ1UsWUFBWSxFQUFFLEVBQUUsQ0FBQztFQUNyQztFQUNBLE1BQU1DLFlBQVksR0FBR1gsT0FBTyxDQUMxQixNQUFNSSxlQUFlLENBQUMsQ0FBQyxDQUFDUSxxQkFBcUIsRUFDN0MsRUFDRixDQUFDOztFQUVEO0VBQ0EsTUFBTUMsVUFBVSxHQUFHSixHQUFHLENBQUNBLEdBQUcsSUFBSUEsR0FBRyxDQUFDQSxHQUFHLEtBQUtFLFlBQVk7O0VBRXREO0VBQ0FaLFNBQVMsQ0FBQyxNQUFNO0lBQ2QsSUFBSWMsVUFBVSxFQUFFO01BQ2RSLGdCQUFnQixDQUFDUyxPQUFPLElBQUk7UUFDMUIsSUFBSUEsT0FBTyxDQUFDRixxQkFBcUIsS0FBS0gsR0FBRyxDQUFDQSxHQUFHLEVBQUUsT0FBT0ssT0FBTztRQUM3RCxPQUFPO1VBQUUsR0FBR0EsT0FBTztVQUFFRixxQkFBcUIsRUFBRUgsR0FBRyxDQUFDQTtRQUFJLENBQUM7TUFDdkQsQ0FBQyxDQUFDO0lBQ0o7RUFDRixDQUFDLEVBQUUsQ0FBQ0ksVUFBVSxFQUFFSixHQUFHLENBQUNBLEdBQUcsQ0FBQyxDQUFDO0VBRXpCLElBQUksQ0FBQ0ksVUFBVSxFQUFFO0lBQ2YsT0FBTyxJQUFJO0VBQ2I7RUFFQSxPQUNFLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxRQUFRO0FBQy9DLE1BQU0sQ0FBQyxJQUFJLENBQ0gsSUFBS0osR0FBRyxDQUFDTSxLQUFLLEtBQUssU0FBUyxHQUN4QjtNQUFFQSxLQUFLLEVBQUU7SUFBVSxDQUFDLEdBQ3BCTixHQUFHLENBQUNNLEtBQUssS0FBSyxPQUFPLEdBQ25CO01BQUVBLEtBQUssRUFBRTtJQUFRLENBQUMsR0FDbEI7TUFBRUMsUUFBUSxFQUFFO0lBQUssQ0FBRSxDQUFDO0FBRWxDLFFBQVEsQ0FBQ1AsR0FBRyxDQUFDQSxHQUFHO0FBQ2hCLE1BQU0sRUFBRSxJQUFJO0FBQ1osSUFBSSxFQUFFLEdBQUcsQ0FBQztBQUVWO0FBRUEsS0FBS1EsU0FBUyxHQUFHO0VBQ2ZSLEdBQUcsRUFBRSxNQUFNO0VBQ1hNLEtBQUssQ0FBQyxFQUFFLEtBQUssR0FBRyxTQUFTLEdBQUcsT0FBTztBQUNyQyxDQUFDO0FBRUQsTUFBTUcsV0FBVyxFQUFFRCxTQUFTLEdBQUc7RUFBRVIsR0FBRyxFQUFFLEVBQUU7RUFBRU0sS0FBSyxFQUFFO0FBQU0sQ0FBQzs7QUFFeEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTTCxZQUFZQSxDQUFBLENBQUUsRUFBRU8sU0FBUyxDQUFDO0VBQ2pDLE9BQU9kLG9DQUFvQyxDQUFDYyxTQUFTLENBQUMsQ0FDcERYLFdBQVcsRUFDWFksV0FDRixDQUFDO0FBQ0giLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
112
src/components/LogoV2/Feed.tsx
Normal file
112
src/components/LogoV2/Feed.tsx
Normal file
File diff suppressed because one or more lines are too long
59
src/components/LogoV2/FeedColumn.tsx
Normal file
59
src/components/LogoV2/FeedColumn.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import { Box } from '../../ink.js';
|
||||
import { Divider } from '../design-system/Divider.js';
|
||||
import type { FeedConfig } from './Feed.js';
|
||||
import { calculateFeedWidth, Feed } from './Feed.js';
|
||||
type FeedColumnProps = {
|
||||
feeds: FeedConfig[];
|
||||
maxWidth: number;
|
||||
};
|
||||
export function FeedColumn(t0) {
|
||||
const $ = _c(10);
|
||||
const {
|
||||
feeds,
|
||||
maxWidth
|
||||
} = t0;
|
||||
let t1;
|
||||
if ($[0] !== feeds) {
|
||||
const feedWidths = feeds.map(_temp);
|
||||
t1 = Math.max(...feedWidths);
|
||||
$[0] = feeds;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
const maxOfAllFeeds = t1;
|
||||
const actualWidth = Math.min(maxOfAllFeeds, maxWidth);
|
||||
let t2;
|
||||
if ($[2] !== actualWidth || $[3] !== feeds) {
|
||||
let t3;
|
||||
if ($[5] !== actualWidth || $[6] !== feeds.length) {
|
||||
t3 = (feed_0, index) => <React.Fragment key={index}><Feed config={feed_0} actualWidth={actualWidth} />{index < feeds.length - 1 && <Divider color="claude" width={actualWidth} />}</React.Fragment>;
|
||||
$[5] = actualWidth;
|
||||
$[6] = feeds.length;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
}
|
||||
t2 = feeds.map(t3);
|
||||
$[2] = actualWidth;
|
||||
$[3] = feeds;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
let t3;
|
||||
if ($[8] !== t2) {
|
||||
t3 = <Box flexDirection="column">{t2}</Box>;
|
||||
$[8] = t2;
|
||||
$[9] = t3;
|
||||
} else {
|
||||
t3 = $[9];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
function _temp(feed) {
|
||||
return calculateFeedWidth(feed);
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkJveCIsIkRpdmlkZXIiLCJGZWVkQ29uZmlnIiwiY2FsY3VsYXRlRmVlZFdpZHRoIiwiRmVlZCIsIkZlZWRDb2x1bW5Qcm9wcyIsImZlZWRzIiwibWF4V2lkdGgiLCJGZWVkQ29sdW1uIiwidDAiLCIkIiwiX2MiLCJ0MSIsImZlZWRXaWR0aHMiLCJtYXAiLCJfdGVtcCIsIk1hdGgiLCJtYXgiLCJtYXhPZkFsbEZlZWRzIiwiYWN0dWFsV2lkdGgiLCJtaW4iLCJ0MiIsInQzIiwibGVuZ3RoIiwiZmVlZF8wIiwiaW5kZXgiLCJmZWVkIl0sInNvdXJjZXMiOlsiRmVlZENvbHVtbi50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBCb3ggfSBmcm9tICcuLi8uLi9pbmsuanMnXG5pbXBvcnQgeyBEaXZpZGVyIH0gZnJvbSAnLi4vZGVzaWduLXN5c3RlbS9EaXZpZGVyLmpzJ1xuaW1wb3J0IHR5cGUgeyBGZWVkQ29uZmlnIH0gZnJvbSAnLi9GZWVkLmpzJ1xuaW1wb3J0IHsgY2FsY3VsYXRlRmVlZFdpZHRoLCBGZWVkIH0gZnJvbSAnLi9GZWVkLmpzJ1xuXG50eXBlIEZlZWRDb2x1bW5Qcm9wcyA9IHtcbiAgZmVlZHM6IEZlZWRDb25maWdbXVxuICBtYXhXaWR0aDogbnVtYmVyXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBGZWVkQ29sdW1uKHtcbiAgZmVlZHMsXG4gIG1heFdpZHRoLFxufTogRmVlZENvbHVtblByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgZmVlZFdpZHRocyA9IGZlZWRzLm1hcChmZWVkID0+IGNhbGN1bGF0ZUZlZWRXaWR0aChmZWVkKSlcbiAgY29uc3QgbWF4T2ZBbGxGZWVkcyA9IE1hdGgubWF4KC4uLmZlZWRXaWR0aHMpXG4gIGNvbnN0IGFjdHVhbFdpZHRoID0gTWF0aC5taW4obWF4T2ZBbGxGZWVkcywgbWF4V2lkdGgpXG5cbiAgcmV0dXJuIChcbiAgICA8Qm94IGZsZXhEaXJlY3Rpb249XCJjb2x1bW5cIj5cbiAgICAgIHtmZWVkcy5tYXAoKGZlZWQsIGluZGV4KSA9PiAoXG4gICAgICAgIDxSZWFjdC5GcmFnbWVudCBrZXk9e2luZGV4fT5cbiAgICAgICAgICA8RmVlZCBjb25maWc9e2ZlZWR9IGFjdHVhbFdpZHRoPXthY3R1YWxXaWR0aH0gLz5cbiAgICAgICAgICB7aW5kZXggPCBmZWVkcy5sZW5ndGggLSAxICYmIChcbiAgICAgICAgICAgIDxEaXZpZGVyIGNvbG9yPVwiY2xhdWRlXCIgd2lkdGg9e2FjdHVhbFdpZHRofSAvPlxuICAgICAgICAgICl9XG4gICAgICAgIDwvUmVhY3QuRnJhZ21lbnQ+XG4gICAgICApKX1cbiAgICA8L0JveD5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxLQUFLQSxLQUFLLE1BQU0sT0FBTztBQUM5QixTQUFTQyxHQUFHLFFBQVEsY0FBYztBQUNsQyxTQUFTQyxPQUFPLFFBQVEsNkJBQTZCO0FBQ3JELGNBQWNDLFVBQVUsUUFBUSxXQUFXO0FBQzNDLFNBQVNDLGtCQUFrQixFQUFFQyxJQUFJLFFBQVEsV0FBVztBQUVwRCxLQUFLQyxlQUFlLEdBQUc7RUFDckJDLEtBQUssRUFBRUosVUFBVSxFQUFFO0VBQ25CSyxRQUFRLEVBQUUsTUFBTTtBQUNsQixDQUFDO0FBRUQsT0FBTyxTQUFBQyxXQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQW9CO0lBQUFMLEtBQUE7SUFBQUM7RUFBQSxJQUFBRSxFQUdUO0VBQUEsSUFBQUcsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUosS0FBQTtJQUNoQixNQUFBTyxVQUFBLEdBQW1CUCxLQUFLLENBQUFRLEdBQUksQ0FBQ0MsS0FBZ0MsQ0FBQztJQUN4Q0gsRUFBQSxHQUFBSSxJQUFJLENBQUFDLEdBQUksSUFBSUosVUFBVSxDQUFDO0lBQUFILENBQUEsTUFBQUosS0FBQTtJQUFBSSxDQUFBLE1BQUFFLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFGLENBQUE7RUFBQTtFQUE3QyxNQUFBUSxhQUFBLEdBQXNCTixFQUF1QjtFQUM3QyxNQUFBTyxXQUFBLEdBQW9CSCxJQUFJLENBQUFJLEdBQUksQ0FBQ0YsYUFBYSxFQUFFWCxRQUFRLENBQUM7RUFBQSxJQUFBYyxFQUFBO0VBQUEsSUFBQVgsQ0FBQSxRQUFBUyxXQUFBLElBQUFULENBQUEsUUFBQUosS0FBQTtJQUFBLElBQUFnQixFQUFBO0lBQUEsSUFBQVosQ0FBQSxRQUFBUyxXQUFBLElBQUFULENBQUEsUUFBQUosS0FBQSxDQUFBaUIsTUFBQTtNQUl0Q0QsRUFBQSxHQUFBQSxDQUFBRSxNQUFBLEVBQUFDLEtBQUEsS0FDVCxnQkFBcUJBLEdBQUssQ0FBTEEsTUFBSSxDQUFDLENBQ3hCLENBQUMsSUFBSSxDQUFTQyxNQUFJLENBQUpBLE9BQUcsQ0FBQyxDQUFlUCxXQUFXLENBQVhBLFlBQVUsQ0FBQyxHQUMzQyxDQUFBTSxLQUFLLEdBQUduQixLQUFLLENBQUFpQixNQUFPLEdBQUcsQ0FFdkIsSUFEQyxDQUFDLE9BQU8sQ0FBTyxLQUFRLENBQVIsUUFBUSxDQUFRSixLQUFXLENBQVhBLFlBQVUsQ0FBQyxHQUM1QyxDQUNGLGlCQUNEO01BQUFULENBQUEsTUFBQVMsV0FBQTtNQUFBVCxDQUFBLE1BQUFKLEtBQUEsQ0FBQWlCLE1BQUE7TUFBQWIsQ0FBQSxNQUFBWSxFQUFBO0lBQUE7TUFBQUEsRUFBQSxHQUFBWixDQUFBO0lBQUE7SUFQQVcsRUFBQSxHQUFBZixLQUFLLENBQUFRLEdBQUksQ0FBQ1EsRUFPVixDQUFDO0lBQUFaLENBQUEsTUFBQVMsV0FBQTtJQUFBVCxDQUFBLE1BQUFKLEtBQUE7SUFBQUksQ0FBQSxNQUFBVyxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBWCxDQUFBO0VBQUE7RUFBQSxJQUFBWSxFQUFBO0VBQUEsSUFBQVosQ0FBQSxRQUFBVyxFQUFBO0lBUkpDLEVBQUEsSUFBQyxHQUFHLENBQWUsYUFBUSxDQUFSLFFBQVEsQ0FDeEIsQ0FBQUQsRUFPQSxDQUNILEVBVEMsR0FBRyxDQVNFO0lBQUFYLENBQUEsTUFBQVcsRUFBQTtJQUFBWCxDQUFBLE1BQUFZLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFaLENBQUE7RUFBQTtFQUFBLE9BVE5ZLEVBU007QUFBQTtBQWxCSCxTQUFBUCxNQUFBVyxJQUFBO0VBQUEsT0FJZ0N2QixrQkFBa0IsQ0FBQ3VCLElBQUksQ0FBQztBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
70
src/components/LogoV2/GuestPassesUpsell.tsx
Normal file
70
src/components/LogoV2/GuestPassesUpsell.tsx
Normal file
File diff suppressed because one or more lines are too long
543
src/components/LogoV2/LogoV2.tsx
Normal file
543
src/components/LogoV2/LogoV2.tsx
Normal file
File diff suppressed because one or more lines are too long
55
src/components/LogoV2/Opus1mMergeNotice.tsx
Normal file
55
src/components/LogoV2/Opus1mMergeNotice.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { UP_ARROW } from '../../constants/figures.js';
|
||||
import { Box, Text } from '../../ink.js';
|
||||
import { getGlobalConfig, saveGlobalConfig } from '../../utils/config.js';
|
||||
import { isOpus1mMergeEnabled } from '../../utils/model/model.js';
|
||||
import { AnimatedAsterisk } from './AnimatedAsterisk.js';
|
||||
const MAX_SHOW_COUNT = 6;
|
||||
export function shouldShowOpus1mMergeNotice(): boolean {
|
||||
return isOpus1mMergeEnabled() && (getGlobalConfig().opus1mMergeNoticeSeenCount ?? 0) < MAX_SHOW_COUNT;
|
||||
}
|
||||
export function Opus1mMergeNotice() {
|
||||
const $ = _c(4);
|
||||
const [show] = useState(shouldShowOpus1mMergeNotice);
|
||||
let t0;
|
||||
let t1;
|
||||
if ($[0] !== show) {
|
||||
t0 = () => {
|
||||
if (!show) {
|
||||
return;
|
||||
}
|
||||
const newCount = (getGlobalConfig().opus1mMergeNoticeSeenCount ?? 0) + 1;
|
||||
saveGlobalConfig(prev => {
|
||||
if ((prev.opus1mMergeNoticeSeenCount ?? 0) >= newCount) {
|
||||
return prev;
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
opus1mMergeNoticeSeenCount: newCount
|
||||
};
|
||||
});
|
||||
};
|
||||
t1 = [show];
|
||||
$[0] = show;
|
||||
$[1] = t0;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
t1 = $[2];
|
||||
}
|
||||
useEffect(t0, t1);
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
let t2;
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = <Box paddingLeft={2}><AnimatedAsterisk char={UP_ARROW} /><Text dimColor={true}>{" "}Opus now defaults to 1M context · 5x more room, same pricing</Text></Box>;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZUVmZmVjdCIsInVzZVN0YXRlIiwiVVBfQVJST1ciLCJCb3giLCJUZXh0IiwiZ2V0R2xvYmFsQ29uZmlnIiwic2F2ZUdsb2JhbENvbmZpZyIsImlzT3B1czFtTWVyZ2VFbmFibGVkIiwiQW5pbWF0ZWRBc3RlcmlzayIsIk1BWF9TSE9XX0NPVU5UIiwic2hvdWxkU2hvd09wdXMxbU1lcmdlTm90aWNlIiwib3B1czFtTWVyZ2VOb3RpY2VTZWVuQ291bnQiLCJPcHVzMW1NZXJnZU5vdGljZSIsIiQiLCJfYyIsInNob3ciLCJ0MCIsInQxIiwibmV3Q291bnQiLCJwcmV2IiwidDIiLCJTeW1ib2wiLCJmb3IiXSwic291cmNlcyI6WyJPcHVzMW1NZXJnZU5vdGljZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VFZmZlY3QsIHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBVUF9BUlJPVyB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy9maWd1cmVzLmpzJ1xuaW1wb3J0IHsgQm94LCBUZXh0IH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuaW1wb3J0IHsgZ2V0R2xvYmFsQ29uZmlnLCBzYXZlR2xvYmFsQ29uZmlnIH0gZnJvbSAnLi4vLi4vdXRpbHMvY29uZmlnLmpzJ1xuaW1wb3J0IHsgaXNPcHVzMW1NZXJnZUVuYWJsZWQgfSBmcm9tICcuLi8uLi91dGlscy9tb2RlbC9tb2RlbC5qcydcbmltcG9ydCB7IEFuaW1hdGVkQXN0ZXJpc2sgfSBmcm9tICcuL0FuaW1hdGVkQXN0ZXJpc2suanMnXG5cbmNvbnN0IE1BWF9TSE9XX0NPVU5UID0gNlxuXG5leHBvcnQgZnVuY3Rpb24gc2hvdWxkU2hvd09wdXMxbU1lcmdlTm90aWNlKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIGlzT3B1czFtTWVyZ2VFbmFibGVkKCkgJiZcbiAgICAoZ2V0R2xvYmFsQ29uZmlnKCkub3B1czFtTWVyZ2VOb3RpY2VTZWVuQ291bnQgPz8gMCkgPCBNQVhfU0hPV19DT1VOVFxuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBPcHVzMW1NZXJnZU5vdGljZSgpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBbc2hvd10gPSB1c2VTdGF0ZShzaG91bGRTaG93T3B1czFtTWVyZ2VOb3RpY2UpXG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBpZiAoIXNob3cpIHJldHVyblxuICAgIGNvbnN0IG5ld0NvdW50ID0gKGdldEdsb2JhbENvbmZpZygpLm9wdXMxbU1lcmdlTm90aWNlU2VlbkNvdW50ID8/IDApICsgMVxuICAgIHNhdmVHbG9iYWxDb25maWcocHJldiA9PiB7XG4gICAgICBpZiAoKHByZXYub3B1czFtTWVyZ2VOb3RpY2VTZWVuQ291bnQgPz8gMCkgPj0gbmV3Q291bnQpIHJldHVybiBwcmV2XG4gICAgICByZXR1cm4geyAuLi5wcmV2LCBvcHVzMW1NZXJnZU5vdGljZVNlZW5Db3VudDogbmV3Q291bnQgfVxuICAgIH0pXG4gIH0sIFtzaG93XSlcblxuICBpZiAoIXNob3cpIHJldHVybiBudWxsXG5cbiAgcmV0dXJuIChcbiAgICA8Qm94IHBhZGRpbmdMZWZ0PXsyfT5cbiAgICAgIDxBbmltYXRlZEFzdGVyaXNrIGNoYXI9e1VQX0FSUk9XfSAvPlxuICAgICAgPFRleHQgZGltQ29sb3I+XG4gICAgICAgIHsnICd9XG4gICAgICAgIE9wdXMgbm93IGRlZmF1bHRzIHRvIDFNIGNvbnRleHQgwrcgNXggbW9yZSByb29tLCBzYW1lIHByaWNpbmdcbiAgICAgIDwvVGV4dD5cbiAgICA8L0JveD5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxLQUFLQSxLQUFLLE1BQU0sT0FBTztBQUM5QixTQUFTQyxTQUFTLEVBQUVDLFFBQVEsUUFBUSxPQUFPO0FBQzNDLFNBQVNDLFFBQVEsUUFBUSw0QkFBNEI7QUFDckQsU0FBU0MsR0FBRyxFQUFFQyxJQUFJLFFBQVEsY0FBYztBQUN4QyxTQUFTQyxlQUFlLEVBQUVDLGdCQUFnQixRQUFRLHVCQUF1QjtBQUN6RSxTQUFTQyxvQkFBb0IsUUFBUSw0QkFBNEI7QUFDakUsU0FBU0MsZ0JBQWdCLFFBQVEsdUJBQXVCO0FBRXhELE1BQU1DLGNBQWMsR0FBRyxDQUFDO0FBRXhCLE9BQU8sU0FBU0MsMkJBQTJCQSxDQUFBLENBQUUsRUFBRSxPQUFPLENBQUM7RUFDckQsT0FDRUgsb0JBQW9CLENBQUMsQ0FBQyxJQUN0QixDQUFDRixlQUFlLENBQUMsQ0FBQyxDQUFDTSwwQkFBMEIsSUFBSSxDQUFDLElBQUlGLGNBQWM7QUFFeEU7QUFFQSxPQUFPLFNBQUFHLGtCQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQ0wsT0FBQUMsSUFBQSxJQUFlZCxRQUFRLENBQUNTLDJCQUEyQixDQUFDO0VBQUEsSUFBQU0sRUFBQTtFQUFBLElBQUFDLEVBQUE7RUFBQSxJQUFBSixDQUFBLFFBQUFFLElBQUE7SUFFMUNDLEVBQUEsR0FBQUEsQ0FBQTtNQUNSLElBQUksQ0FBQ0QsSUFBSTtRQUFBO01BQUE7TUFDVCxNQUFBRyxRQUFBLEdBQWlCLENBQUNiLGVBQWUsQ0FBQyxDQUFDLENBQUFNLDBCQUFnQyxJQUFqRCxDQUFpRCxJQUFJLENBQUM7TUFDeEVMLGdCQUFnQixDQUFDYSxJQUFBO1FBQ2YsSUFBSSxDQUFDQSxJQUFJLENBQUFSLDBCQUFnQyxJQUFwQyxDQUFvQyxLQUFLTyxRQUFRO1VBQUEsT0FBU0MsSUFBSTtRQUFBO1FBQUEsT0FDNUQ7VUFBQSxHQUFLQSxJQUFJO1VBQUFSLDBCQUFBLEVBQThCTztRQUFTLENBQUM7TUFBQSxDQUN6RCxDQUFDO0lBQUEsQ0FDSDtJQUFFRCxFQUFBLElBQUNGLElBQUksQ0FBQztJQUFBRixDQUFBLE1BQUFFLElBQUE7SUFBQUYsQ0FBQSxNQUFBRyxFQUFBO0lBQUFILENBQUEsTUFBQUksRUFBQTtFQUFBO0lBQUFELEVBQUEsR0FBQUgsQ0FBQTtJQUFBSSxFQUFBLEdBQUFKLENBQUE7RUFBQTtFQVBUYixTQUFTLENBQUNnQixFQU9ULEVBQUVDLEVBQU0sQ0FBQztFQUVWLElBQUksQ0FBQ0YsSUFBSTtJQUFBLE9BQVMsSUFBSTtFQUFBO0VBQUEsSUFBQUssRUFBQTtFQUFBLElBQUFQLENBQUEsUUFBQVEsTUFBQSxDQUFBQyxHQUFBO0lBR3BCRixFQUFBLElBQUMsR0FBRyxDQUFjLFdBQUMsQ0FBRCxHQUFDLENBQ2pCLENBQUMsZ0JBQWdCLENBQU9sQixJQUFRLENBQVJBLFNBQU8sQ0FBQyxHQUNoQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQVIsS0FBTyxDQUFDLENBQ1gsSUFBRSxDQUFFLDREQUVQLEVBSEMsSUFBSSxDQUlQLEVBTkMsR0FBRyxDQU1FO0lBQUFXLENBQUEsTUFBQU8sRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQVAsQ0FBQTtFQUFBO0VBQUEsT0FOTk8sRUFNTTtBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
166
src/components/LogoV2/OverageCreditUpsell.tsx
Normal file
166
src/components/LogoV2/OverageCreditUpsell.tsx
Normal file
File diff suppressed because one or more lines are too long
68
src/components/LogoV2/VoiceModeNotice.tsx
Normal file
68
src/components/LogoV2/VoiceModeNotice.tsx
Normal file
File diff suppressed because one or more lines are too long
433
src/components/LogoV2/WelcomeV2.tsx
Normal file
433
src/components/LogoV2/WelcomeV2.tsx
Normal file
File diff suppressed because one or more lines are too long
92
src/components/LogoV2/feedConfigs.tsx
Normal file
92
src/components/LogoV2/feedConfigs.tsx
Normal file
File diff suppressed because one or more lines are too long
88
src/components/LspRecommendation/LspRecommendationMenu.tsx
Normal file
88
src/components/LspRecommendation/LspRecommendationMenu.tsx
Normal file
File diff suppressed because one or more lines are too long
115
src/components/MCPServerApprovalDialog.tsx
Normal file
115
src/components/MCPServerApprovalDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
203
src/components/MCPServerDesktopImportDialog.tsx
Normal file
203
src/components/MCPServerDesktopImportDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
15
src/components/MCPServerDialogCopy.tsx
Normal file
15
src/components/MCPServerDialogCopy.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import React from 'react';
|
||||
import { Link, Text } from '../ink.js';
|
||||
export function MCPServerDialogCopy() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <Text>MCP servers may execute code or access system resources. All tool calls require approval. Learn more in the{" "}<Link url="https://code.claude.com/docs/en/mcp">MCP documentation</Link>.</Text>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkxpbmsiLCJUZXh0IiwiTUNQU2VydmVyRGlhbG9nQ29weSIsIiQiLCJfYyIsInQwIiwiU3ltYm9sIiwiZm9yIl0sInNvdXJjZXMiOlsiTUNQU2VydmVyRGlhbG9nQ29weS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgTGluaywgVGV4dCB9IGZyb20gJy4uL2luay5qcydcblxuZXhwb3J0IGZ1bmN0aW9uIE1DUFNlcnZlckRpYWxvZ0NvcHkoKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgcmV0dXJuIChcbiAgICA8VGV4dD5cbiAgICAgIE1DUCBzZXJ2ZXJzIG1heSBleGVjdXRlIGNvZGUgb3IgYWNjZXNzIHN5c3RlbSByZXNvdXJjZXMuIEFsbCB0b29sIGNhbGxzXG4gICAgICByZXF1aXJlIGFwcHJvdmFsLiBMZWFybiBtb3JlIGluIHRoZXsnICd9XG4gICAgICA8TGluayB1cmw9XCJodHRwczovL2NvZGUuY2xhdWRlLmNvbS9kb2NzL2VuL21jcFwiPk1DUCBkb2N1bWVudGF0aW9uPC9MaW5rPi5cbiAgICA8L1RleHQ+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU9BLEtBQUssTUFBTSxPQUFPO0FBQ3pCLFNBQVNDLElBQUksRUFBRUMsSUFBSSxRQUFRLFdBQVc7QUFFdEMsT0FBTyxTQUFBQyxvQkFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUFBLElBQUFDLEVBQUE7RUFBQSxJQUFBRixDQUFBLFFBQUFHLE1BQUEsQ0FBQUMsR0FBQTtJQUVIRixFQUFBLElBQUMsSUFBSSxDQUFDLDJHQUVnQyxJQUFFLENBQ3RDLENBQUMsSUFBSSxDQUFLLEdBQXFDLENBQXJDLHFDQUFxQyxDQUFDLGlCQUFpQixFQUFoRSxJQUFJLENBQW1FLENBQzFFLEVBSkMsSUFBSSxDQUlFO0lBQUFGLENBQUEsTUFBQUUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUYsQ0FBQTtFQUFBO0VBQUEsT0FKUEUsRUFJTztBQUFBIiwiaWdub3JlTGlzdCI6W119
|
||||
133
src/components/MCPServerMultiselectDialog.tsx
Normal file
133
src/components/MCPServerMultiselectDialog.tsx
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
144
src/components/ManagedSettingsSecurityDialog/utils.ts
Normal file
144
src/components/ManagedSettingsSecurityDialog/utils.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import {
|
||||
DANGEROUS_SHELL_SETTINGS,
|
||||
SAFE_ENV_VARS,
|
||||
} from '../../utils/managedEnvConstants.js'
|
||||
import type { SettingsJson } from '../../utils/settings/types.js'
|
||||
import { jsonStringify } from '../../utils/slowOperations.js'
|
||||
|
||||
type DangerousShellSetting = (typeof DANGEROUS_SHELL_SETTINGS)[number]
|
||||
|
||||
export type DangerousSettings = {
|
||||
shellSettings: Partial<Record<DangerousShellSetting, string>>
|
||||
envVars: Record<string, string>
|
||||
hasHooks: boolean
|
||||
hooks?: unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract dangerous settings from a settings object.
|
||||
*
|
||||
* Dangerous env vars are determined by checking against SAFE_ENV_VARS -
|
||||
* any env var NOT in SAFE_ENV_VARS is considered dangerous.
|
||||
* See managedEnv.ts for the authoritative list and threat categories.
|
||||
*/
|
||||
export function extractDangerousSettings(
|
||||
settings: SettingsJson | null | undefined,
|
||||
): DangerousSettings {
|
||||
if (!settings) {
|
||||
return {
|
||||
shellSettings: {},
|
||||
envVars: {},
|
||||
hasHooks: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Extract dangerous shell settings
|
||||
const shellSettings: Partial<Record<DangerousShellSetting, string>> = {}
|
||||
for (const key of DANGEROUS_SHELL_SETTINGS) {
|
||||
const value = settings[key]
|
||||
if (typeof value === 'string' && value.length > 0) {
|
||||
shellSettings[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// Extract dangerous env vars - any var NOT in SAFE_ENV_VARS is dangerous
|
||||
const envVars: Record<string, string> = {}
|
||||
if (settings.env && typeof settings.env === 'object') {
|
||||
for (const [key, value] of Object.entries(settings.env)) {
|
||||
if (typeof value === 'string' && value.length > 0) {
|
||||
// Check if this env var is NOT in the safe list
|
||||
if (!SAFE_ENV_VARS.has(key.toUpperCase())) {
|
||||
envVars[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for hooks
|
||||
const hasHooks =
|
||||
settings.hooks !== undefined &&
|
||||
settings.hooks !== null &&
|
||||
typeof settings.hooks === 'object' &&
|
||||
Object.keys(settings.hooks).length > 0
|
||||
|
||||
return {
|
||||
shellSettings,
|
||||
envVars,
|
||||
hasHooks,
|
||||
hooks: hasHooks ? settings.hooks : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if settings contain any dangerous settings
|
||||
*/
|
||||
export function hasDangerousSettings(dangerous: DangerousSettings): boolean {
|
||||
return (
|
||||
Object.keys(dangerous.shellSettings).length > 0 ||
|
||||
Object.keys(dangerous.envVars).length > 0 ||
|
||||
dangerous.hasHooks
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two sets of dangerous settings to see if the new settings
|
||||
* have changed or added dangerous settings compared to the old settings
|
||||
*/
|
||||
export function hasDangerousSettingsChanged(
|
||||
oldSettings: SettingsJson | null | undefined,
|
||||
newSettings: SettingsJson | null | undefined,
|
||||
): boolean {
|
||||
const oldDangerous = extractDangerousSettings(oldSettings)
|
||||
const newDangerous = extractDangerousSettings(newSettings)
|
||||
|
||||
// If new settings don't have any dangerous settings, no prompt needed
|
||||
if (!hasDangerousSettings(newDangerous)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If old settings didn't have dangerous settings but new does, prompt needed
|
||||
if (!hasDangerousSettings(oldDangerous)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Compare the dangerous settings - any change triggers a prompt
|
||||
const oldJson = jsonStringify({
|
||||
shellSettings: oldDangerous.shellSettings,
|
||||
envVars: oldDangerous.envVars,
|
||||
hooks: oldDangerous.hooks,
|
||||
})
|
||||
const newJson = jsonStringify({
|
||||
shellSettings: newDangerous.shellSettings,
|
||||
envVars: newDangerous.envVars,
|
||||
hooks: newDangerous.hooks,
|
||||
})
|
||||
|
||||
return oldJson !== newJson
|
||||
}
|
||||
|
||||
/**
|
||||
* Format dangerous settings as a human-readable list for the UI
|
||||
* Only returns setting names, not values
|
||||
*/
|
||||
export function formatDangerousSettingsList(
|
||||
dangerous: DangerousSettings,
|
||||
): string[] {
|
||||
const items: string[] = []
|
||||
|
||||
// Shell settings (names only)
|
||||
for (const key of Object.keys(dangerous.shellSettings)) {
|
||||
items.push(key)
|
||||
}
|
||||
|
||||
// Env vars (names only)
|
||||
for (const key of Object.keys(dangerous.envVars)) {
|
||||
items.push(key)
|
||||
}
|
||||
|
||||
// Hooks
|
||||
if (dangerous.hasHooks) {
|
||||
items.push('hooks')
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user