init claude-code

This commit is contained in:
2026-04-01 17:32:37 +02:00
commit 73b208c009
1902 changed files with 513237 additions and 0 deletions
File diff suppressed because one or more lines are too long
+56
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+56
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+57
View 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
File diff suppressed because one or more lines are too long
+47
View 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+XG4gICAgICAgICAgICA8VGV4dCBkaW1Db2xvcj57c3VnZ2VzdGlvbi5kZXRhaWx9PC9UZXh0PlxuICAgICAgICAgIDwvQm94PlxuICAgICAgICA8L0JveD5cbiAgICAgICkpfVxuICAgIDwvQm94PlxuICApXG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPQSxPQUFPLE1BQU0sU0FBUztBQUM3QixPQUFPLEtBQUtDLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLEdBQUcsRUFBRUMsSUFBSSxRQUFRLFdBQVc7QUFDckMsY0FBY0MsaUJBQWlCLFFBQVEsZ0NBQWdDO0FBQ3ZFLFNBQVNDLFlBQVksUUFBUSxvQkFBb0I7QUFDakQsU0FBU0MsVUFBVSxRQUFRLCtCQUErQjtBQUUxRCxLQUFLQyxLQUFL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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+50
View 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
View 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=
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
export * from './SelectMulti.js'
export type { OptionWithDescription } from './select.js'
export * from './select.js'
+50
View 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
}
}
File diff suppressed because one or more lines are too long
+68
View 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=
File diff suppressed because one or more lines are too long
@@ -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
View 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 },
)
}
@@ -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
View 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,
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+49
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+42
View 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
View 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=
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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 }
}
}
@@ -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])
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+43
View 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==
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+23
View 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==
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+58
View 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+XG4gICAgKVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7QUFBQSxTQUFTQSxRQUFRLFFBQVEs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
File diff suppressed because one or more lines are too long
+15
View 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
File diff suppressed because one or more lines are too long
+89
View 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+XG4gICAgICA8U2VsZWN0XG4gICAgICAgIG9wdGlvbnM9e1tcbiAgICAgICAgICB7IGxhYmVsOiAnRXhpdCBhbmQgZml4IG1hbnVhbGx5JywgdmFsdWU6ICdleGl0JyB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGxhYmVsOiAnQ29udGludWUgd2l0aG91dCB0aGVzZSBzZXR0aW5ncycsXG4gICAgICAgICAgICB2YWx1ZTogJ2NvbnRpbnVlJyxcbiAgICAgICAgICB9LFxuICAgICAgICBdfVxuICAgICAgICBvbkNoYW5nZT17aGFuZGxlU2VsZWN0fVxuICAgICAgLz5cbiAgICA8L0RpYWxvZz5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsU0FBU0MsSUFBSSxRQUFRLFdBQVc7QUFDaEMsY0FBY0MsZUFBZSxRQUFRLGlDQUFpQztBQUN0RSxTQUFTQyxNQUFNLFFB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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+58
View 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=
File diff suppressed because one or more lines are too long
+59
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+55
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+15
View 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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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