feat: build

This commit is contained in:
claude-code-best committed 2026-03-31 19:22:47 +08:00
commit f90eee85d8
1906 files changed
+514339

No files matched your search

File diff suppressed because it is too large. Load diff
+137
View File
@@ -0,0 +1,137 @@
import { c as _c } from "react/compiler-runtime";
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
import * as React from 'react';
import { Suspense, useState } from 'react';
import { useKeybinding } from '../../keybindings/useKeybinding.js';
import { useExitOnCtrlCDWithKeybindings } from '../../hooks/useExitOnCtrlCDWithKeybindings.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import { useIsInsideModal, useModalOrTerminalSize } from '../../context/modalContext.js';
import { Pane } from '../design-system/Pane.js';
import { Tabs, Tab } from '../design-system/Tabs.js';
import { Status, buildDiagnostics } from './Status.js';
import { Config } from './Config.js';
import { Usage } from './Usage.js';
import type { LocalJSXCommandContext, CommandResultDisplay } from '../../commands.js';
type Props = {
onClose: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
context: LocalJSXCommandContext;
defaultTab: 'Status' | 'Config' | 'Usage' | 'Gates';
};
export function Settings(t0) {
const $ = _c(25);
const {
onClose,
context,
defaultTab
} = t0;
const [selectedTab, setSelectedTab] = useState(defaultTab);
const [tabsHidden, setTabsHidden] = useState(false);
const [configOwnsEsc, setConfigOwnsEsc] = useState(false);
const [gatesOwnsEsc, setGatesOwnsEsc] = useState(false);
const insideModal = useIsInsideModal();
const {
rows
} = useModalOrTerminalSize(useTerminalSize());
const contentHeight = insideModal ? rows + 1 : Math.max(15, Math.min(Math.floor(rows * 0.8), 30));
const [diagnosticsPromise] = useState(_temp2);
useExitOnCtrlCDWithKeybindings();
let t1;
if ($[0] !== onClose || $[1] !== tabsHidden) {
t1 = () => {
if (tabsHidden) {
return;
}
onClose("Status dialog dismissed", {
display: "system"
});
};
$[0] = onClose;
$[1] = tabsHidden;
$[2] = t1;
} else {
t1 = $[2];
}
const handleEscape = t1;
const t2 = !tabsHidden && !(selectedTab === "Config" && configOwnsEsc) && !(selectedTab === "Gates" && gatesOwnsEsc);
let t3;
if ($[3] !== t2) {
t3 = {
context: "Settings",
isActive: t2
};
$[3] = t2;
$[4] = t3;
} else {
t3 = $[4];
}
useKeybinding("confirm:no", handleEscape, t3);
let t4;
if ($[5] !== context || $[6] !== diagnosticsPromise) {
t4 = <Tab key="status" title="Status"><Status context={context} diagnosticsPromise={diagnosticsPromise} /></Tab>;
$[5] = context;
$[6] = diagnosticsPromise;
$[7] = t4;
} else {
t4 = $[7];
}
let t5;
if ($[8] !== contentHeight || $[9] !== context || $[10] !== onClose) {
t5 = <Tab key="config" title="Config"><Suspense fallback={null}><Config context={context} onClose={onClose} setTabsHidden={setTabsHidden} onIsSearchModeChange={setConfigOwnsEsc} contentHeight={contentHeight} /></Suspense></Tab>;
$[8] = contentHeight;
$[9] = context;
$[10] = onClose;
$[11] = t5;
} else {
t5 = $[11];
}
let t6;
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
t6 = <Tab key="usage" title="Usage"><Usage /></Tab>;
$[12] = t6;
} else {
t6 = $[12];
}
let t7;
if ($[13] !== contentHeight) {
t7 = false ? [<Tab key="gates" title="Gates"><Gates onOwnsEscChange={setGatesOwnsEsc} contentHeight={contentHeight} /></Tab>] : [];
$[13] = contentHeight;
$[14] = t7;
} else {
t7 = $[14];
}
let t8;
if ($[15] !== t4 || $[16] !== t5 || $[17] !== t7) {
t8 = [t4, t5, t6, ...t7];
$[15] = t4;
$[16] = t5;
$[17] = t7;
$[18] = t8;
} else {
t8 = $[18];
}
const tabs = t8;
const t9 = defaultTab !== "Config" && defaultTab !== "Gates";
const t10 = tabsHidden || insideModal ? undefined : contentHeight;
let t11;
if ($[19] !== selectedTab || $[20] !== t10 || $[21] !== t9 || $[22] !== tabs || $[23] !== tabsHidden) {
t11 = <Pane color="permission"><Tabs color="permission" selectedTab={selectedTab} onTabChange={setSelectedTab} hidden={tabsHidden} initialHeaderFocused={t9} contentHeight={t10}>{tabs}</Tabs></Pane>;
$[19] = selectedTab;
$[20] = t10;
$[21] = t9;
$[22] = tabs;
$[23] = tabsHidden;
$[24] = t11;
} else {
t11 = $[24];
}
return t11;
}
function _temp2() {
return buildDiagnostics().catch(_temp);
}
function _temp() {
return [];
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlN1c3BlbnNlIiwidXNlU3RhdGUiLCJ1c2VLZXliaW5kaW5nIiwidXNlRXhpdE9uQ3RybENEV2l0aEtleWJpbmRpbmdzIiwidXNlVGVybWluYWxTaXplIiwidXNlSXNJbnNpZGVNb2RhbCIsInVzZU1vZGFsT3JUZXJtaW5hbFNpemUiLCJQYW5lIiwiVGFicyIsIlRhYiIsIlN0YXR1cyIsImJ1aWxkRGlhZ25vc3RpY3MiLCJDb25maWciLCJVc2FnZSIsIkxvY2FsSlNYQ29tbWFuZENvbnRleHQiLCJDb21tYW5kUmVzdWx0RGlzcGxheSIsIlByb3BzIiwib25DbG9zZSIsInJlc3VsdCIsIm9wdGlvbnMiLCJkaXNwbGF5IiwiY29udGV4dCIsImRlZmF1bHRUYWIiLCJTZXR0aW5ncyIsInQwIiwiJCIsIl9jIiwic2VsZWN0ZWRUYWIiLCJzZXRTZWxlY3RlZFRhYiIsInRhYnNIaWRkZW4iLCJzZXRUYWJzSGlkZGVuIiwiY29uZmlnT3duc0VzYyIsInNldENvbmZpZ093bnNFc2MiLCJnYXRlc093bnNFc2MiLCJzZXRHYXRlc093bnNFc2MiLCJpbnNpZGVNb2RhbCIsInJvd3MiLCJjb250ZW50SGVpZ2h0IiwiTWF0aCIsIm1heCIsIm1pbiIsImZsb29yIiwiZGlhZ25vc3RpY3NQcm9taXNlIiwiX3RlbXAyIiwidDEiLCJoYW5kbGVFc2NhcGUiLCJ0MiIsInQzIiwiaXNBY3RpdmUiLCJ0NCIsInQ1IiwidDYiLCJTeW1ib2wiLCJmb3IiLCJ0NyIsInQ4IiwidGFicyIsInQ5IiwidDEwIiwidW5kZWZpbmVkIiwidDExIiwiY2F0Y2giLCJfdGVtcCJdLCJzb3VyY2VzIjpbIlNldHRpbmdzLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBiaW9tZS1pZ25vcmUtYWxsIGFzc2lzdC9zb3VyY2Uvb3JnYW5pemVJbXBvcnRzOiBBTlQtT05MWSBpbXBvcnQgbWFya2VycyBtdXN0IG5vdCBiZSByZW9yZGVyZWRcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgU3VzcGVuc2UsIHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VLZXliaW5kaW5nIH0gZnJvbSAnLi4vLi4va2V5YmluZGluZ3MvdXNlS2V5YmluZGluZy5qcydcbmltcG9ydCB7IHVzZUV4aXRPbkN0cmxDRFdpdGhLZXliaW5kaW5ncyB9IGZyb20gJy4uLy4uL2hvb2tzL3VzZUV4aXRPbkN0cmxDRFdpdGhLZXliaW5kaW5ncy5qcydcbmltcG9ydCB7IHVzZVRlcm1pbmFsU2l6ZSB9IGZyb20gJy4uLy4uL2hvb2tzL3VzZVRlcm1pbmFsU2l6ZS5qcydcbmltcG9ydCB7XG4gIHVzZUlzSW5zaWRlTW9kYWwsXG4gIHVzZU1vZGFsT3JUZXJtaW5hbFNpemUsXG59IGZyb20gJy4uLy4uL2NvbnRleHQvbW9kYWxDb250ZXh0LmpzJ1xuaW1wb3J0IHsgUGFuZSB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vUGFuZS5qcydcbmltcG9ydCB7IFRhYnMsIFRhYiB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vVGFicy5qcydcbmltcG9ydCB7IFN0YXR1cywgYnVpbGREaWFnbm9zdGljcyB9IGZyb20gJy4vU3RhdHVzLmpzJ1xuaW1wb3J0IHsgQ29uZmlnIH0gZnJvbSAnLi9Db25maWcuanMnXG5pbXBvcnQgeyBVc2FnZSB9IGZyb20gJy4vVXNhZ2UuanMnXG5pbXBvcnQgdHlwZSB7XG4gIExvY2FsSlNYQ29tbWFuZENvbnRleHQsXG4gIENvbW1hbmRSZXN1bHREaXNwbGF5LFxufSBmcm9tICcuLi8uLi9jb21tYW5kcy5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgb25DbG9zZTogKFxuICAgIHJlc3VsdD86IHN0cmluZyxcbiAgICBvcHRpb25zPzogeyBkaXNwbGF5PzogQ29tbWFuZFJlc3VsdERpc3BsYXkgfSxcbiAgKSA9PiB2b2lkXG4gIGNvbnRleHQ6IExvY2FsSlNYQ29tbWFuZENvbnRleHRcbiAgZGVmYXVsdFRhYjogJ1N0YXR1cycgfCAnQ29uZmlnJyB8ICdVc2FnZScgfCAnR2F0ZXMnXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBTZXR0aW5ncyh7XG4gIG9uQ2xvc2UsXG4gIGNvbnRleHQsXG4gIGRlZmF1bHRUYWIsXG59OiBQcm9wcyk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IFtzZWxlY3RlZFRhYiwgc2V0U2VsZWN0ZWRUYWJdID0gdXNlU3RhdGU8c3RyaW5nPihkZWZhdWx0VGFiKVxuICBjb25zdCBbdGFic0hpZGRlbiwgc2V0VGFic0hpZGRlbl0gPSB1c2VTdGF0ZShmYWxzZSlcbiAgLy8gVHJ1ZSB3aGlsZSBDb25maWcncyBvd24gRXNjIGhhbmRsZXIgaXMgYWN0aXZlIChzZWFyY2ggbW9kZSB3aXRoIGNvbnRlbnRcbiAgLy8gZm9jdXNlZCkuIFNldHRpbmdzIG11c3QgY2VkZSBFc2Mgc28gc2VhcmNoIGNhbiBjbGVhci9leGl0IGZpcnN0LlxuICBjb25zdCBbY29uZmlnT3duc0VzYywgc2V0Q29uZmlnT3duc0VzY10gPSB1c2VTdGF0ZShmYWxzZSlcbiAgY29uc3QgW2dhdGVzT3duc0VzYywgc2V0R2F0ZXNPd25zRXNjXSA9IHVzZVN0YXRlKGZhbHNlKVxuICAvLyBGaXhlZCBjb250ZW50IGhlaWdodCBzbyBzd2l0Y2hpbmcgdGFicyBkb2Vzbid0IHNoaWZ0IHRoZSBwYW5lIGhlaWdodC5cbiAgLy8gT3V0c2lkZSBtb2RhbHMgY2FwIGF0IG1pbig4MCUgdmlld3BvcnQsIDMwKS4gSW5zaWRlIGEgTW9kYWwgdGhlIG1vZGFsJ3NcbiAgLy8gaW5uZXJTaXplLnJvd3MgSVMgdGhlIFNjcm9sbEJveCB2aWV3cG9ydCDigJQgdGhlIDAuOCBtdWx0aXBsaWVyIG92ZXItXG4gIC8vIHNocmlua3MsIGxlYXZpbmcgZW1wdHkgcm93cyB3aGlsZSBDb25maWcgc2hvd3MgXCLihpMgTiBtb3JlIGJlbG93XCIuXG4gIC8vXG4gIC8vIEluc2lkZS1tb2RhbCBtYXRoOiBDb25maWcncyBwYW5lQ2FwLTEwIGNocm9tZSBlc3RpbWF0ZSB3YXMgdHVuZWQgZm9yXG4gIC8vIG1hcmdpblk9ezF9ICgyIHJvd3MpIHdoaWNoIGlzIHN0cmlwcGVkIGluc2lkZSBtb2RhbHMg4oaSICsyIHRvIHJlY292ZXIuXG4gIC8vIFRoZW4gLTIgZm9yIFRhYnMnIGhlYWRlciByb3cgKyBpdHMgbWFyZ2luVG9wPTEuIFBsdXMgKzEgb2JzZXJ2ZWQgZ2FwXG4gIC8vIGZyb20gdGhlIHBhbmVDYXAtMTAgZXN0aW1hdGUgYmVpbmcgc2xpZ2h0bHkgZ2VuZXJvdXMuIE5ldDogcm93cyArIDEuXG4gIGNvbnN0IGluc2lkZU1vZGFsID0gdXNlSXNJbnNpZGVNb2RhbCgpXG4gIGNvbnN0IHsgcm93cyB9ID0gdXNlTW9kYWxPclRlcm1pbmFsU2l6ZSh1c2VUZXJtaW5hbFNpemUoKSlcbiAgY29uc3QgY29udGVudEhlaWdodCA9IGluc2lkZU1vZGFsXG4gICAgPyByb3dzICsgMVxuICAgIDogTWF0aC5tYXgoMTUsIE1hdGgubWluKE1hdGguZmxvb3Iocm93cyAqIDAuOCksIDMwKSlcbiAgLy8gS2ljayBvZmYgZGlhZ25vc3RpY3Mgb25jZSB3aGVuIHRoZSBwYW5lIG9wZW5zLiBTdGF0dXMgdXNlKClzIHRoaXMgc29cbiAgLy8gaXQgcmVzb2x2ZXMgb25jZSBwZXIgL2NvbmZpZyBpbnZvY2F0aW9uIOKAlCBubyByZS1mZXRjaCBmbGFzaCB3aGVuXG4gIC8vIHRhYmJpbmcgYmFjayB0byBTdGF0dXMgKFRhYiB1bm1vdW50cyBjaGlsZHJlbiB3aGVuIG5vdCBzZWxlY3RlZCkuXG4gIGNvbnN0IFtkaWFnbm9zdGljc1Byb21pc2VdID0gdXNlU3RhdGUoKCkgPT5cbiAgICBidWlsZERpYWdub3N0aWNzKCkuY2F0Y2goKCkgPT4gW10pLFxuICApXG5cbiAgdXNlRXhpdE9uQ3RybENEV2l0aEtleWJpbmRpbmdzKClcblxuICAvLyBIYW5kbGUgZXNjYXBlIHZpYSBrZXliaW5kaW5nIC0gb25seSB3aGVuIG5vdCBpbiBzdWJtZW51XG4gIGNvbnN0IGhhbmRsZUVzY2FwZSA9ICgpID0+IHtcbiAgICAvLyBEb24ndCBoYW5kbGUgZXNjYXBlIHdoZW4gYSBzdWJtZW51IGlzIHNob3dpbmcgKHRhYnNIaWRkZW4gbWVhbnMgc3VibWVudSBpcyBvcGVuKVxuICAgIC8vIExldCB0aGUgc3VibWVudSBoYW5kbGU Line truncated
+241
View File
@@ -0,0 +1,241 @@
import { c as _c } from "react/compiler-runtime";
import figures from 'figures';
import * as React from 'react';
import { Suspense, use } from 'react';
import { getSessionId } from '../../bootstrap/state.js';
import type { LocalJSXCommandContext } from '../../commands.js';
import { useIsInsideModal } from '../../context/modalContext.js';
import { Box, Text, useTheme } from '../../ink.js';
import { type AppState, useAppState } from '../../state/AppState.js';
import { getCwd } from '../../utils/cwd.js';
import { getCurrentSessionTitle } from '../../utils/sessionStorage.js';
import { buildAccountProperties, buildAPIProviderProperties, buildIDEProperties, buildInstallationDiagnostics, buildInstallationHealthDiagnostics, buildMcpProperties, buildMemoryDiagnostics, buildSandboxProperties, buildSettingSourcesProperties, type Diagnostic, getModelDisplayLabel, type Property } from '../../utils/status.js';
import type { ThemeName } from '../../utils/theme.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
type Props = {
context: LocalJSXCommandContext;
diagnosticsPromise: Promise<Diagnostic[]>;
};
function buildPrimarySection(): Property[] {
const sessionId = getSessionId();
const customTitle = getCurrentSessionTitle(sessionId);
const nameValue = customTitle ?? <Text dimColor>/rename to add a name</Text>;
return [{
label: 'Version',
value: MACRO.VERSION
}, {
label: 'Session name',
value: nameValue
}, {
label: 'Session ID',
value: sessionId
}, {
label: 'cwd',
value: getCwd()
}, ...buildAccountProperties(), ...buildAPIProviderProperties()];
}
function buildSecondarySection({
mainLoopModel,
mcp,
theme,
context
}: {
mainLoopModel: AppState['mainLoopModel'];
mcp: AppState['mcp'];
theme: ThemeName;
context: LocalJSXCommandContext;
}): Property[] {
const modelLabel = getModelDisplayLabel(mainLoopModel);
return [{
label: 'Model',
value: modelLabel
}, ...buildIDEProperties(mcp.clients, context.options.ideInstallationStatus, theme), ...buildMcpProperties(mcp.clients, theme), ...buildSandboxProperties(), ...buildSettingSourcesProperties()];
}
export async function buildDiagnostics(): Promise<Diagnostic[]> {
return [...(await buildInstallationDiagnostics()), ...(await buildInstallationHealthDiagnostics()), ...(await buildMemoryDiagnostics())];
}
function PropertyValue(t0) {
const $ = _c(8);
const {
value
} = t0;
if (Array.isArray(value)) {
let t1;
if ($[0] !== value) {
let t2;
if ($[2] !== value.length) {
t2 = (item, i) => <Text key={i}>{item}{i < value.length - 1 ? "," : ""}</Text>;
$[2] = value.length;
$[3] = t2;
} else {
t2 = $[3];
}
t1 = value.map(t2);
$[0] = value;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[4] !== t1) {
t2 = <Box flexWrap="wrap" columnGap={1} flexShrink={99}>{t1}</Box>;
$[4] = t1;
$[5] = t2;
} else {
t2 = $[5];
}
return t2;
}
if (typeof value === "string") {
let t1;
if ($[6] !== value) {
t1 = <Text>{value}</Text>;
$[6] = value;
$[7] = t1;
} else {
t1 = $[7];
}
return t1;
}
return value;
}
export function Status(t0) {
const $ = _c(20);
const {
context,
diagnosticsPromise
} = t0;
const mainLoopModel = useAppState(_temp);
const mcp = useAppState(_temp2);
const [theme] = useTheme();
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = buildPrimarySection();
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== context || $[2] !== mainLoopModel || $[3] !== mcp || $[4] !== theme) {
t2 = buildSecondarySection({
mainLoopModel,
mcp,
theme,
context
});
$[1] = context;
$[2] = mainLoopModel;
$[3] = mcp;
$[4] = theme;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== t2) {
t3 = [t1, t2];
$[6] = t2;
$[7] = t3;
} else {
t3 = $[7];
}
const sections = t3;
const grow = useIsInsideModal() ? 1 : undefined;
let t4;
if ($[8] !== sections) {
t4 = sections.map(_temp4);
$[8] = sections;
$[9] = t4;
} else {
t4 = $[9];
}
let t5;
if ($[10] !== diagnosticsPromise) {
t5 = <Suspense fallback={null}><Diagnostics promise={diagnosticsPromise} /></Suspense>;
$[10] = diagnosticsPromise;
$[11] = t5;
} else {
t5 = $[11];
}
let t6;
if ($[12] !== grow || $[13] !== t4 || $[14] !== t5) {
t6 = <Box flexDirection="column" gap={1} flexGrow={grow}>{t4}{t5}</Box>;
$[12] = grow;
$[13] = t4;
$[14] = t5;
$[15] = t6;
} else {
t6 = $[15];
}
let t7;
if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
t7 = <Text dimColor={true}><ConfigurableShortcutHint action="confirm:no" context="Settings" fallback="Esc" description="cancel" /></Text>;
$[16] = t7;
} else {
t7 = $[16];
}
let t8;
if ($[17] !== grow || $[18] !== t6) {
t8 = <Box flexDirection="column" flexGrow={grow}>{t6}{t7}</Box>;
$[17] = grow;
$[18] = t6;
$[19] = t8;
} else {
t8 = $[19];
}
return t8;
}
function _temp4(properties, i) {
return properties.length > 0 && <Box key={i} flexDirection="column">{properties.map(_temp3)}</Box>;
}
function _temp3(t0, j) {
const {
label,
value
} = t0;
return <Box key={j} flexDirection="row" gap={1} flexShrink={0}>{label !== undefined && <Text bold={true}>{label}:</Text>}<PropertyValue value={value} /></Box>;
}
function _temp2(s_0) {
return s_0.mcp;
}
function _temp(s) {
return s.mainLoopModel;
}
function Diagnostics(t0) {
const $ = _c(5);
const {
promise
} = t0;
const diagnostics = use(promise);
if (diagnostics.length === 0) {
return null;
}
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Text bold={true}>System Diagnostics</Text>;
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== diagnostics) {
t2 = diagnostics.map(_temp5);
$[1] = diagnostics;
$[2] = t2;
} else {
t2 = $[2];
}
let t3;
if ($[3] !== t2) {
t3 = <Box flexDirection="column" paddingBottom={1}>{t1}{t2}</Box>;
$[3] = t2;
$[4] = t3;
} else {
t3 = $[4];
}
return t3;
}
function _temp5(diagnostic, i) {
return <Box key={i} flexDirection="row" gap={1} paddingX={1}><Text color="error">{figures.warning}</Text>{typeof diagnostic === "string" ? <Text wrap="wrap">{diagnostic}</Text> : diagnostic}</Box>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiUmVhY3QiLCJTdXNwZW5zZSIsInVzZSIsImdldFNlc3Npb25JZCIsIkxvY2FsSlNYQ29tbWFuZENvbnRleHQiLCJ1c2VJc0luc2lkZU1vZGFsIiwiQm94IiwiVGV4dCIsInVzZVRoZW1lIiwiQXBwU3RhdGUiLCJ1c2VBcHBTdGF0ZSIsImdldEN3ZCIsImdldEN1cnJlbnRTZXNzaW9uVGl0bGUiLCJidWlsZEFjY291bnRQcm9wZXJ0aWVzIiwiYnVpbGRBUElQcm92aWRlclByb3BlcnRpZXMiLCJidWlsZElERVByb3BlcnRpZXMiLCJidWlsZEluc3RhbGxhdGlvbkRpYWdub3N0aWNzIiwiYnVpbGRJbnN0YWxsYXRpb25IZWFsdGhEaWFnbm9zdGljcyIsImJ1aWxkTWNwUHJvcGVydGllcyIsImJ1aWxkTWVtb3J5RGlhZ25vc3RpY3MiLCJidWlsZFNhbmRib3hQcm9wZXJ0aWVzIiwiYnVpbGRTZXR0aW5nU291cmNlc1Byb3BlcnRpZXMiLCJEaWFnbm9zdGljIiwiZ2V0TW9kZWxEaXNwbGF5TGFiZWwiLCJQcm9wZXJ0eSIsIlRoZW1lTmFtZSIsIkNvbmZpZ3VyYWJsZVNob3J0Y3V0SGludCIsIlByb3BzIiwiY29udGV4dCIsImRpYWdub3N0aWNzUHJvbWlzZSIsIlByb21pc2UiLCJidWlsZFByaW1hcnlTZWN0aW9uIiwic2Vzc2lvbklkIiwiY3VzdG9tVGl0bGUiLCJuYW1lVmFsdWUiLCJsYWJlbCIsInZhbHVlIiwiTUFDUk8iLCJWRVJTSU9OIiwiYnVpbGRTZWNvbmRhcnlTZWN0aW9uIiwibWFpbkxvb3BNb2RlbCIsIm1jcCIsInRoZW1lIiwibW9kZWxMYWJlbCIsImNsaWVudHMiLCJvcHRpb25zIiwiaWRlSW5zdGFsbGF0aW9uU3RhdHVzIiwiYnVpbGREaWFnbm9zdGljcyIsIlByb3BlcnR5VmFsdWUiLCJ0MCIsIiQiLCJfYyIsIkFycmF5IiwiaXNBcnJheSIsInQxIiwidDIiLCJsZW5ndGgiLCJpdGVtIiwiaSIsIm1hcCIsIlN0YXR1cyIsIl90ZW1wIiwiX3RlbXAyIiwiU3ltYm9sIiwiZm9yIiwidDMiLCJzZWN0aW9ucyIsImdyb3ciLCJ1bmRlZmluZWQiLCJ0NCIsIl90ZW1wNCIsInQ1IiwidDYiLCJ0NyIsInQ4IiwicHJvcGVydGllcyIsIl90ZW1wMyIsImoiLCJzXzAiLCJzIiwiRGlhZ25vc3RpY3MiLCJwcm9taXNlIiwiZGlhZ25vc3RpY3MiLCJfdGVtcDUiLCJkaWFnbm9zdGljIiwid2FybmluZyJdLCJzb3VyY2VzIjpbIlN0YXR1cy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZpZ3VyZXMgZnJvbSAnZmlndXJlcydcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgU3VzcGVuc2UsIHVzZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgZ2V0U2Vzc2lvbklkIH0gZnJvbSAnLi4vLi4vYm9vdHN0cmFwL3N0YXRlLmpzJ1xuaW1wb3J0IHR5cGUgeyBMb2NhbEpTWENvbW1hbmRDb250ZXh0IH0gZnJvbSAnLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgeyB1c2VJc0luc2lkZU1vZGFsIH0gZnJvbSAnLi4vLi4vY29udGV4dC9tb2RhbENvbnRleHQuanMnXG5pbXBvcnQgeyBCb3gsIFRleHQsIHVzZVRoZW1lIH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuaW1wb3J0IHsgdHlwZSBBcHBTdGF0ZSwgdXNlQXBwU3RhdGUgfSBmcm9tICcuLi8uLi9zdGF0ZS9BcHBTdGF0ZS5qcydcbmltcG9ydCB7IGdldEN3ZCB9IGZyb20gJy4uLy4uL3V0aWxzL2N3ZC5qcydcbmltcG9ydCB7IGdldEN1cnJlbnRTZXNzaW9uVGl0bGUgfSBmcm9tICcuLi8uLi91dGlscy9zZXNzaW9uU3RvcmFnZS5qcydcbmltcG9ydCB7XG4gIGJ1aWxkQWNjb3VudFByb3BlcnRpZXMsXG4gIGJ1aWxkQVBJUHJvdmlkZXJQcm9wZXJ0aWVzLFxuICBidWlsZElERVByb3BlcnRpZXMsXG4gIGJ1aWxkSW5zdGFsbGF0aW9uRGlhZ25vc3RpY3MsXG4gIGJ1aWxkSW5zdGFsbGF0aW9uSGVhbHRoRGlhZ25vc3RpY3MsXG4gIGJ1aWxkTWNwUHJvcGVydGllcyxcbiAgYnVpbGRNZW1vcnlEaWFnbm9zdGljcyxcbiAgYnVpbGRTYW5kYm94UHJvcGVydGllcyxcbiAgYnVpbGRTZXR0aW5nU291cmNlc1Byb3BlcnRpZXMsXG4gIHR5cGUgRGlhZ25vc3RpYyxcbiAgZ2V0TW9kZWxEaXNwbGF5TGFiZWwsXG4gIHR5cGUgUHJvcGVydHksXG59IGZyb20gJy4uLy4uL3V0aWxzL3N0YXR1cy5qcydcbmltcG9ydCB0eXBlIHsgVGhlbWVOYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMvdGhlbWUuanMnXG5pbXBvcnQgeyBDb25maWd1cmFibGVTaG9ydGN1dEhpbnQgfSBmcm9tICcuLi9Db25maWd1cmFibGVTaG9ydGN1dEhpbnQuanMnXG5cbnR5cGUgUHJvcHMgPSB7XG4gIGNvbnRleHQ6IExvY2FsSlNYQ29tbWFuZENvbnRleHRcbiAgZGlhZ25vc3RpY3NQcm9taXNlOiBQcm9taXNlPERpYWdub3N0aWNbXT5cbn1cblxuZnVuY3Rpb24gYnVpbGRQcmltYXJ5U2VjdGlvbigpOiBQcm9wZXJ0eVtdIHtcbiAgY29uc3Qgc2Vzc2lvbklkID0gZ2V0U2Vzc2lvbklkKClcbiAgY29uc3QgY3VzdG9tVGl0bGUgPSBnZXRDdXJyZW50U2Vzc2lvblRpdGxlKHNlc3Npb25JZClcbiAgY29uc3QgbmFtZVZhbHVlID0gY3VzdG9tVGl0bGUgPz8gPFRleHQgZGltQ29sb3I+L3JlbmFtZSB0byBhZGQgYSBuYW1lPC9UZXh0PlxuXG4gIHJldHVybiBbXG4gICAgeyBsYWJlbDogJ1ZlcnNpb24nLCB2YWx1ZTogTUFDUk8uVkVSU0lPTiB9LFxuICAgIHsgbGFiZWw6ICdTZXNzaW9uIG5hbWUnLCB2YWx1ZTogbmFtZVZhbHVlIH0sXG4gICAgeyBsYWJlbDogJ1Nlc3Npb24gSUQnLCB2YWx1ZTogc2Vzc2lvbklkIH0sXG4gICAgeyBsYWJlbDogJ2N3ZCcsIHZhbHVlOiBnZXRDd2QoKSB9LFxuICAgIC4uLmJ1aWxkQWNjb3VudFByb3BlcnRpZXMoKSxcbiAgICAuLi5idWlsZEFQSVByb3ZpZGVyUHJvcGVydGllcygpLFxuICBdXG59XG5cbmZ1bmN0aW9uIGJ1aWxkU2Vjb25kYXJ5U2VjdGlvbih7XG4gIG1haW5Mb29wTW9kZWwsXG4gIG1jcCxcbiAgdGhlbWUsXG4gIGNvbnRleHQsXG59OiB7XG4gIG1haW5Mb29wTW9kZWw6IEFwcFN0YXRlWydtYWluTG9vcE1vZGVsJ11cbiAgbWNwOiBBcHBTdGF0ZVsnbWNwJ11cbiAgdGhlbWU6IFRoZW1lTmFtZVxuICBjb250ZXh0OiBMb2NhbEpTWENvbW1hbmRDb250ZXh0XG59KTogUHJvcGVydHlbXSB7XG4gIGNvbnN0IG1vZGVsTGFiZWwgPSBnZXRNb2RlbERpc3BsYXlMYWJlbChtYWluTG9vcE1vZGVsKVxuXG4gIHJldHVybiBbXG4gICAgeyBsYWJlbDogJ01vZGVsJywgdmFsdWU6IG1vZGVsTGFiZWwgfSxcbiAgICAuLi5idWlsZElERVByb3BlcnRpZXMoXG4gICAgICBtY3AuY2xpZW50cyxcbiAgICAgIGNvbnRleHQub3B0aW9ucy5pZGVJbnN0YWxsYXRpb25TdGF0dXMsXG4gICAgICB0aGVtZSxcbiAgICApLFxuICAgIC4uLmJ1aWxkTWNwUHJvcGVydGllcyhtY3AuY2xpZW50cywgdGhlbWUpLFxuICAgIC4uLmJ1aWxkU2FuZGJveFByb3BlcnRpZXMoKSxcbiAgICAuLi5idWlsZFNldHRpbmdTb3VyY2VzUHJvcGVydGllcygpLFxuICBdXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBidWlsZERpYWdub3N0aWNzKCk6IFByb21pc2U8RGlhZ25vc3RpY1tdPiB7XG4gIHJldHVybiBbXG4gICAgLi4uKGF3YWl0IGJ1aWxkSW5zdGFsbGF0aW9uRGlhZ25vc3RpY3MoKSksXG4gICAgLi4uKGF3YWl0IGJ1aWxkSW5zdGFsbGF0aW9uSGVhbHRoRGlhZ25vc3RpY3MoKSksXG4gICAgLi4uKGF3YWl0IGJ1aWxkTWVtb3J5RGlhZ25vc3RpY3MoKSksXG4gIF1cbn1cblxuZnVuY3Rpb24gUHJvcGVydHlWYWx1ZSh7XG4gIHZhbHVlLFxufToge1xuICB2YWx1ZTogUHJvcGVydHlbJ3ZhbHVlJ11cbn0pOiBSZWFjdC5SZWFjdE5vZGUge1x Line truncated
+377
View File
@@ -0,0 +1,377 @@
import { c as _c } from "react/compiler-runtime";
import * as React from 'react';
import { useEffect, useState } from 'react';
import { extraUsage as extraUsageCommand } from 'src/commands/extra-usage/index.js';
import { formatCost } from 'src/cost-tracker.js';
import { getSubscriptionType } from 'src/utils/auth.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import { Box, Text } from '../../ink.js';
import { useKeybinding } from '../../keybindings/useKeybinding.js';
import { type ExtraUsage, fetchUtilization, type RateLimit, type Utilization } from '../../services/api/usage.js';
import { formatResetText } from '../../utils/format.js';
import { logError } from '../../utils/log.js';
import { jsonStringify } from '../../utils/slowOperations.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Byline } from '../design-system/Byline.js';
import { ProgressBar } from '../design-system/ProgressBar.js';
import { isEligibleForOverageCreditGrant, OverageCreditUpsell } from '../LogoV2/OverageCreditUpsell.js';
type LimitBarProps = {
title: string;
limit: RateLimit;
maxWidth: number;
showTimeInReset?: boolean;
extraSubtext?: string;
};
function LimitBar(t0) {
const $ = _c(34);
const {
title,
limit,
maxWidth,
showTimeInReset: t1,
extraSubtext
} = t0;
const showTimeInReset = t1 === undefined ? true : t1;
const {
utilization,
resets_at
} = limit;
if (utilization === null) {
return null;
}
const usedText = `${Math.floor(utilization)}% used`;
let subtext;
if (resets_at) {
let t2;
if ($[0] !== resets_at || $[1] !== showTimeInReset) {
t2 = formatResetText(resets_at, true, showTimeInReset);
$[0] = resets_at;
$[1] = showTimeInReset;
$[2] = t2;
} else {
t2 = $[2];
}
subtext = `Resets ${t2}`;
}
if (extraSubtext) {
if (subtext) {
subtext = `${extraSubtext} · ${subtext}`;
} else {
subtext = extraSubtext;
}
}
if (maxWidth >= 62) {
let t2;
if ($[3] !== title) {
t2 = <Text bold={true}>{title}</Text>;
$[3] = title;
$[4] = t2;
} else {
t2 = $[4];
}
const t3 = utilization / 100;
let t4;
if ($[5] !== t3) {
t4 = <ProgressBar ratio={t3} width={50} fillColor="rate_limit_fill" emptyColor="rate_limit_empty" />;
$[5] = t3;
$[6] = t4;
} else {
t4 = $[6];
}
let t5;
if ($[7] !== usedText) {
t5 = <Text>{usedText}</Text>;
$[7] = usedText;
$[8] = t5;
} else {
t5 = $[8];
}
let t6;
if ($[9] !== t4 || $[10] !== t5) {
t6 = <Box flexDirection="row" gap={1}>{t4}{t5}</Box>;
$[9] = t4;
$[10] = t5;
$[11] = t6;
} else {
t6 = $[11];
}
let t7;
if ($[12] !== subtext) {
t7 = subtext && <Text dimColor={true}>{subtext}</Text>;
$[12] = subtext;
$[13] = t7;
} else {
t7 = $[13];
}
let t8;
if ($[14] !== t2 || $[15] !== t6 || $[16] !== t7) {
t8 = <Box flexDirection="column">{t2}{t6}{t7}</Box>;
$[14] = t2;
$[15] = t6;
$[16] = t7;
$[17] = t8;
} else {
t8 = $[17];
}
return t8;
} else {
let t2;
if ($[18] !== title) {
t2 = <Text bold={true}>{title}</Text>;
$[18] = title;
$[19] = t2;
} else {
t2 = $[19];
}
let t3;
if ($[20] !== subtext) {
t3 = subtext && <><Text> </Text><Text dimColor={true}>· {subtext}</Text></>;
$[20] = subtext;
$[21] = t3;
} else {
t3 = $[21];
}
let t4;
if ($[22] !== t2 || $[23] !== t3) {
t4 = <Text>{t2}{t3}</Text>;
$[22] = t2;
$[23] = t3;
$[24] = t4;
} else {
t4 = $[24];
}
const t5 = utilization / 100;
let t6;
if ($[25] !== maxWidth || $[26] !== t5) {
t6 = <ProgressBar ratio={t5} width={maxWidth} fillColor="rate_limit_fill" emptyColor="rate_limit_empty" />;
$[25] = maxWidth;
$[26] = t5;
$[27] = t6;
} else {
t6 = $[27];
}
let t7;
if ($[28] !== usedText) {
t7 = <Text>{usedText}</Text>;
$[28] = usedText;
$[29] = t7;
} else {
t7 = $[29];
}
let t8;
if ($[30] !== t4 || $[31] !== t6 || $[32] !== t7) {
t8 = <Box flexDirection="column">{t4}{t6}{t7}</Box>;
$[30] = t4;
$[31] = t6;
$[32] = t7;
$[33] = t8;
} else {
t8 = $[33];
}
return t8;
}
}
export function Usage(): React.ReactNode {
const [utilization, setUtilization] = useState<Utilization | null>(null);
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const {
columns
} = useTerminalSize();
const availableWidth = columns - 2; // 2 for screen padding
const maxWidth = Math.min(availableWidth, 80);
const loadUtilization = React.useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const data = await fetchUtilization();
setUtilization(data);
} catch (err) {
logError(err as Error);
const axiosError = err as {
response?: {
data?: unknown;
};
};
const responseBody = axiosError.response?.data ? jsonStringify(axiosError.response.data) : undefined;
setError(responseBody ? `Failed to load usage data: ${responseBody}` : 'Failed to load usage data');
} finally {
setIsLoading(false);
}
}, []);
useEffect(() => {
void loadUtilization();
}, [loadUtilization]);
useKeybinding('settings:retry', () => {
void loadUtilization();
}, {
context: 'Settings',
isActive: !!error && !isLoading
});
if (error) {
return <Box flexDirection="column" gap={1}>
<Text color="error">Error: {error}</Text>
<Text dimColor>
<Byline>
<ConfigurableShortcutHint action="settings:retry" context="Settings" fallback="r" description="retry" />
<ConfigurableShortcutHint action="confirm:no" context="Settings" fallback="Esc" description="cancel" />
</Byline>
</Text>
</Box>;
}
if (!utilization) {
return <Box flexDirection="column" gap={1}>
<Text dimColor>Loading usage data…</Text>
<Text dimColor>
<ConfigurableShortcutHint action="confirm:no" context="Settings" fallback="Esc" description="cancel" />
</Text>
</Box>;
}
// Only Max and Team plans have a Sonnet limit that differs from the weekly
// limit (see rateLimitMessages.ts). For other plans the bar is redundant.
// Show for null (unknown plan) to stay consistent with rateLimitMessages.ts,
// which labels it "Sonnet limit" in that case.
const subscriptionType = getSubscriptionType();
const showSonnetBar = subscriptionType === 'max' || subscriptionType === 'team' || subscriptionType === null;
const limits = [{
title: 'Current session',
limit: utilization.five_hour
}, {
title: 'Current week (all models)',
limit: utilization.seven_day
}, ...(showSonnetBar ? [{
title: 'Current week (Sonnet only)',
limit: utilization.seven_day_sonnet
}] : [])];
return <Box flexDirection="column" gap={1} width="100%">
{limits.some(({
limit
}) => limit) || <Text dimColor>/usage is only available for subscription plans.</Text>}
{limits.map(({
title,
limit: limit_0
}) => limit_0 && <LimitBar key={title} title={title} limit={limit_0} maxWidth={maxWidth} />)}
{utilization.extra_usage && <ExtraUsageSection extraUsage={utilization.extra_usage} maxWidth={maxWidth} />}
{isEligibleForOverageCreditGrant() && <OverageCreditUpsell maxWidth={maxWidth} />}
<Text dimColor>
<ConfigurableShortcutHint action="confirm:no" context="Settings" fallback="Esc" description="cancel" />
</Text>
</Box>;
}
type ExtraUsageSectionProps = {
extraUsage: ExtraUsage;
maxWidth: number;
};
const EXTRA_USAGE_SECTION_TITLE = 'Extra usage';
function ExtraUsageSection(t0) {
const $ = _c(20);
const {
extraUsage,
maxWidth
} = t0;
const subscriptionType = getSubscriptionType();
const isProOrMax = subscriptionType === "pro" || subscriptionType === "max";
if (!isProOrMax) {
return false;
}
if (!extraUsage.is_enabled) {
if (extraUsageCommand.isEnabled()) {
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Box flexDirection="column"><Text bold={true}>{EXTRA_USAGE_SECTION_TITLE}</Text><Text dimColor={true}>Extra usage not enabled · /extra-usage to enable</Text></Box>;
$[0] = t1;
} else {
t1 = $[0];
}
return t1;
}
return null;
}
if (extraUsage.monthly_limit === null) {
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Box flexDirection="column"><Text bold={true}>{EXTRA_USAGE_SECTION_TITLE}</Text><Text dimColor={true}>Unlimited</Text></Box>;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
if (typeof extraUsage.used_credits !== "number" || typeof extraUsage.utilization !== "number") {
return null;
}
const t1 = extraUsage.used_credits / 100;
let t2;
if ($[2] !== t1) {
t2 = formatCost(t1, 2);
$[2] = t1;
$[3] = t2;
} else {
t2 = $[3];
}
const formattedUsedCredits = t2;
const t3 = extraUsage.monthly_limit / 100;
let t4;
if ($[4] !== t3) {
t4 = formatCost(t3, 2);
$[4] = t3;
$[5] = t4;
} else {
t4 = $[5];
}
const formattedMonthlyLimit = t4;
let T0;
let t5;
let t6;
let t7;
if ($[6] !== extraUsage.utilization) {
const now = new Date();
const oneMonthReset = new Date(now.getFullYear(), now.getMonth() + 1, 1);
T0 = LimitBar;
t7 = EXTRA_USAGE_SECTION_TITLE;
t5 = extraUsage.utilization;
t6 = oneMonthReset.toISOString();
$[6] = extraUsage.utilization;
$[7] = T0;
$[8] = t5;
$[9] = t6;
$[10] = t7;
} else {
T0 = $[7];
t5 = $[8];
t6 = $[9];
t7 = $[10];
}
let t8;
if ($[11] !== t5 || $[12] !== t6) {
t8 = {
utilization: t5,
resets_at: t6
};
$[11] = t5;
$[12] = t6;
$[13] = t8;
} else {
t8 = $[13];
}
const t9 = `${formattedUsedCredits} / ${formattedMonthlyLimit} spent`;
let t10;
if ($[14] !== T0 || $[15] !== maxWidth || $[16] !== t7 || $[17] !== t8 || $[18] !== t9) {
t10 = <T0 title={t7} limit={t8} showTimeInReset={false} extraSubtext={t9} maxWidth={maxWidth} />;
$[14] = T0;
$[15] = maxWidth;
$[16] = t7;
$[17] = t8;
$[18] = t9;
$[19] = t10;
} else {
t10 = $[19];
}
return t10;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZUVmZmVjdCIsInVzZVN0YXRlIiwiZXh0cmFVc2FnZSIsImV4dHJhVXNhZ2VDb21tYW5kIiwiZm9ybWF0Q29zdCIsImdldFN1YnNjcmlwdGlvblR5cGUiLCJ1c2VUZXJtaW5hbFNpemUiLCJCb3giLCJUZXh0IiwidXNlS2V5YmluZGluZyIsIkV4dHJhVXNhZ2UiLCJmZXRjaFV0aWxpemF0aW9uIiwiUmF0ZUxpbWl0IiwiVXRpbGl6YXRpb24iLCJmb3JtYXRSZXNldFRleHQiLCJsb2dFcnJvciIsImpzb25TdHJpbmdpZnkiLCJDb25maWd1cmFibGVTaG9ydGN1dEhpbnQiLCJCeWxpbmUiLCJQcm9ncmVzc0JhciIsImlzRWxpZ2libGVGb3JPdmVyYWdlQ3JlZGl0R3JhbnQiLCJPdmVyYWdlQ3JlZGl0VXBzZWxsIiwiTGltaXRCYXJQcm9wcyIsInRpdGxlIiwibGltaXQiLCJtYXhXaWR0aCIsInNob3dUaW1lSW5SZXNldCIsImV4dHJhU3VidGV4dCIsIkxpbWl0QmFyIiwidDAiLCIkIiwiX2MiLCJ0MSIsInVuZGVmaW5lZCIsInV0aWxpemF0aW9uIiwicmVzZXRzX2F0IiwidXNlZFRleHQiLCJNYXRoIiwiZmxvb3IiLCJzdWJ0ZXh0IiwidDIiLCJ0MyIsInQ0IiwibWF4QmFyV2lkdGgiLCJ0NSIsInQ2IiwidDciLCJ0OCIsIlVzYWdlIiwiUmVhY3ROb2RlIiwic2V0VXRpbGl6YXRpb24iLCJlcnJvciIsInNldEVycm9yIiwiaXNMb2FkaW5nIiwic2V0SXNMb2FkaW5nIiwiY29sdW1ucyIsImF2YWlsYWJsZVdpZHRoIiwibWluIiwibG9hZFV0aWxpemF0aW9uIiwidXNlQ2FsbGJhY2siLCJkYXRhIiwiZXJyIiwiRXJyb3IiLCJheGlvc0Vycm9yIiwicmVzcG9uc2UiLCJyZXNwb25zZUJvZHkiLCJjb250ZXh0IiwiaXNBY3RpdmUiLCJzdWJzY3JpcHRpb25UeXBlIiwic2hvd1Nvbm5ldEJhciIsImxpbWl0cyIsImZpdmVfaG91ciIsInNldmVuX2RheSIsInNldmVuX2RheV9zb25uZXQiLCJzb21lIiwibWFwIiwiZXh0cmFfdXNhZ2UiLCJFeHRyYVVzYWdlU2VjdGlvblByb3BzIiwiRVhUUkFfVVNBR0VfU0VDVElPTl9USVRMRSIsIkV4dHJhVXNhZ2VTZWN0aW9uIiwiaXNQcm9Pck1heCIsImlzX2VuYWJsZWQiLCJpc0VuYWJsZWQiLCJTeW1ib2wiLCJmb3IiLCJtb250aGx5X2xpbWl0IiwidXNlZF9jcmVkaXRzIiwiZm9ybWF0dGVkVXNlZENyZWRpdHMiLCJmb3JtYXR0ZWRNb250aGx5TGltaXQiLCJUMCIsIm5vdyIsIkRhdGUiLCJvbmVNb250aFJlc2V0IiwiZ2V0RnVsbFllYXIiLCJnZXRNb250aCIsInRvSVNPU3RyaW5nIiwidDkiLCJ0MTAiXSwic291cmNlcyI6WyJVc2FnZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyB1c2VFZmZlY3QsIHVzZVN0YXRlIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBleHRyYVVzYWdlIGFzIGV4dHJhVXNhZ2VDb21tYW5kIH0gZnJvbSAnc3JjL2NvbW1hbmRzL2V4dHJhLXVzYWdlL2luZGV4LmpzJ1xuaW1wb3J0IHsgZm9ybWF0Q29zdCB9IGZyb20gJ3NyYy9jb3N0LXRyYWNrZXIuanMnXG5pbXBvcnQgeyBnZXRTdWJzY3JpcHRpb25UeXBlIH0gZnJvbSAnc3JjL3V0aWxzL2F1dGguanMnXG5pbXBvcnQgeyB1c2VUZXJtaW5hbFNpemUgfSBmcm9tICcuLi8uLi9ob29rcy91c2VUZXJtaW5hbFNpemUuanMnXG5pbXBvcnQgeyBCb3gsIFRleHQgfSBmcm9tICcuLi8uLi9pbmsuanMnXG5pbXBvcnQgeyB1c2VLZXliaW5kaW5nIH0gZnJvbSAnLi4vLi4va2V5YmluZGluZ3MvdXNlS2V5YmluZGluZy5qcydcbmltcG9ydCB7XG4gIHR5cGUgRXh0cmFVc2FnZSxcbiAgZmV0Y2hVdGlsaXphdGlvbixcbiAgdHlwZSBSYXRlTGltaXQsXG4gIHR5cGUgVXRpbGl6YXRpb24sXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FwaS91c2FnZS5qcydcbmltcG9ydCB7IGZvcm1hdFJlc2V0VGV4dCB9IGZyb20gJy4uLy4uL3V0aWxzL2Zvcm1hdC5qcydcbmltcG9ydCB7IGxvZ0Vycm9yIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nLmpzJ1xuaW1wb3J0IHsganNvblN0cmluZ2lmeSB9IGZyb20gJy4uLy4uL3V0aWxzL3Nsb3dPcGVyYXRpb25zLmpzJ1xuaW1wb3J0IHsgQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50IH0gZnJvbSAnLi4vQ29uZmlndXJhYmxlU2hvcnRjdXRIaW50LmpzJ1xuaW1wb3J0IHsgQnlsaW5lIH0gZnJvbSAnLi4vZGVzaWduLXN5c3RlbS9CeWxpbmUuanMnXG5pbXBvcnQgeyBQcm9ncmVzc0JhciB9IGZyb20gJy4uL2Rlc2lnbi1zeXN0ZW0vUHJvZ3Jlc3NCYXIuanMnXG5pbXBvcnQge1xuICBpc0VsaWdpYmxlRm9yT3ZlcmFnZUNyZWRpdEdyYW50LFxuICBPdmVyYWdlQ3JlZGl0VXBzZWxsLFxufSBmcm9tICcuLi9Mb2dvVjIvT3ZlcmFnZUNyZWRpdFVwc2VsbC5qcydcblxudHlwZSBMaW1pdEJhclByb3BzID0ge1xuICB0aXRsZTogc3RyaW5nXG4gIGxpbWl0OiBSYXRlTGltaXRcbiAgbWF4V2lkdGg6IG51bWJlclxuICBzaG93VGltZUluUmVzZXQ/OiBib29sZWFuXG4gIGV4dHJhU3VidGV4dD86IHN0cmluZ1xufVxuXG5mdW5jdGlvbiBMaW1pdEJhcih7XG4gIHRpdGxlLFxuICBsaW1pdCxcbiAgbWF4V2lkdGgsXG4gIHNob3dUaW1lSW5SZXNldCA9IHRydWUsXG4gIGV4dHJhU3VidGV4dCxcbn06IExpbWl0QmFyUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCB7IHV0aWxpemF0aW9uLCByZXNldHNfYXQgfSA9IGxpbWl0XG4gIGlmICh1dGlsaXphdGlvbiA9PT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvLyBDYWxjdWxhdGUgdXNhZ2UgcGVyY2VudGFnZVxuICBjb25zdCB1c2VkVGV4dCA9IGAke01hdGguZmxvb3IodXRpbGl6YXRpb24pfSUgdXNlZGBcblxuICBsZXQgc3VidGV4dDogc3RyaW5nIHwgdW5kZWZpbmVkXG4gIGlmIChyZXNldHNfYXQpIHtcbiAgICBzdWJ0ZXh0ID0gYFJlc2V0cyAke2Zvcm1hdFJlc2V0VGV4dChyZXNldHNfYXQsIHRydWUsIHNob3dUaW1lSW5SZXNldCl9YFxuICB9XG5cbiAgaWYgKGV4dHJhU3VidGV4dCkge1xuICAgIGlmIChzdWJ0ZXh0KSB7XG4gICAgICBzdWJ0ZXh0ID0gYCR7ZXh0cmFTdWJ0ZXh0fSDCtyAke3N1YnRleHR9YFxuICAgIH0gZWxzZSB7XG4gICAgICBzdWJ0ZXh0ID0gZXh0cmFTdWJ0ZXh0XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbWF4QmFyV2lkdGggPSA1MFxuICBjb25zdCB1c2VkTGFiZWxTcGFjZSA9IDEyXG4gIGlmIChtYXhXaWR0aCA+PSBtYXhCYXJXaWR0aCArIHVzZWRMYWJlbFNwYWNlKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgICA8VGV4dCBib2xkPnt0aXRsZX08L1RleHQ+XG4gICAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cInJvd1wiIGdhcD17MX0+XG4gICAgICAgICAgPFByb2dyZXNzQmFyXG4gICAgICAgICAgICByYXRpbz17dXRpbGl6YXRpb24gLyAxMDB9XG4gICAgICAgICAgICB3aWR0aD17bWF4QmFyV2lkdGh9XG4gICAgICAgICAgICBmaWxsQ29sb3I9XCJyYXRlX2xpbWl0X2ZpbGxcIlxuICAgICAgICAgICAgZW1wdHlDb2xvcj1cInJhdGVfbGltaXRfZW1wdHlcIlxuICAgICAgICAgIC8+XG4gICAgICAgICAgPFRleHQ+e3VzZWRUZXh0fTwvVGV4dD5cbiAgICAgICAgPC9Cb3g+XG4gICAgICAgIHtzdWJ0ZXh0ICYmIDxUZXh0IGRpbUNvbG9yPntzdWJ0ZXh0fTwvVGV4dD59XG4gICAgICA8L0JveD5cbiAgICApXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHV Line truncated