dsh-ssh-tui 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +29 -17
- package/README.md +17 -8
- package/lib/index.js +58 -8
- package/lib/index.js.map +1 -1
- package/lib/route-memory.js +23 -4
- package/lib/route-memory.js.map +1 -1
- package/lib/subagent-model.js +37 -12
- package/lib/subagent-model.js.map +1 -1
- package/lib/supergrok-token.js +128 -0
- package/lib/supergrok-token.js.map +1 -0
- package/lib/tui.js +187 -71
- package/lib/tui.js.map +1 -1
- package/lib/types/route-memory.d.ts +10 -0
- package/lib/types/subagent-model.d.ts +4 -2
- package/lib/types/supergrok-token.d.ts +22 -0
- package/lib/types/tui.d.ts +10 -1
- package/package.json +1 -1
package/lib/tui.js
CHANGED
|
@@ -25,7 +25,9 @@ import { formatSessionTime, listResumableSessions } from './session-list.js';
|
|
|
25
25
|
import { defaultReasoningEffort } from './reasoning.js';
|
|
26
26
|
import { checkForPluginUpdate } from './update-check.js';
|
|
27
27
|
import { ROUTE_MEMORY_NAMESPACE, parseRouteMemory, rememberedRouteFor, upsertRememberedRoute, } from './route-memory.js';
|
|
28
|
+
import { AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE } from '@deepseek-ai/dsh-agent-default-model';
|
|
28
29
|
import { DEFAULT_SUBAGENT_MODEL, SUBAGENT_SETTINGS_NAMESPACE, defaultSubagentModelForProvider, subagentModelMatchesProvider, subagentSettingsValue, } from './subagent-model.js';
|
|
30
|
+
import { resolveFreshSuperGrokToken } from './supergrok-token.js';
|
|
29
31
|
import { UserQuestionError, } from '@deepseek-ai/dsh-user-questions';
|
|
30
32
|
function discoverProviderModels(llm, request, signal) {
|
|
31
33
|
return llm.discoverModels(settingsNamespace('llm-pi-ai'), { ...request, signal }, signal);
|
|
@@ -703,6 +705,62 @@ function wrap(text, width) {
|
|
|
703
705
|
}
|
|
704
706
|
return lines;
|
|
705
707
|
}
|
|
708
|
+
/** Wrap plain text and report each output line's char range in the source. */
|
|
709
|
+
function wrapTracked(text, width) {
|
|
710
|
+
const limit = Math.max(1, width);
|
|
711
|
+
const out = [];
|
|
712
|
+
let base = 0;
|
|
713
|
+
for (const sourceLine of text.split('\n')) {
|
|
714
|
+
if (sourceLine === '') {
|
|
715
|
+
out.push({ line: '', start: base, end: base });
|
|
716
|
+
base += 1;
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
let rest = sourceLine;
|
|
720
|
+
let cursor = base;
|
|
721
|
+
while (displayWidth(rest) > limit) {
|
|
722
|
+
let cut = 0;
|
|
723
|
+
let used = 0;
|
|
724
|
+
for (const char of rest) {
|
|
725
|
+
const charWidth = displayWidth(char);
|
|
726
|
+
if (charWidth > 0 && used + charWidth > limit)
|
|
727
|
+
break;
|
|
728
|
+
used += charWidth;
|
|
729
|
+
cut += char.length;
|
|
730
|
+
}
|
|
731
|
+
if (cut === 0)
|
|
732
|
+
cut = firstCodePointLength(rest);
|
|
733
|
+
out.push({ line: rest.slice(0, cut), start: cursor, end: cursor + cut });
|
|
734
|
+
rest = rest.slice(cut);
|
|
735
|
+
cursor += cut;
|
|
736
|
+
}
|
|
737
|
+
out.push({ line: rest, start: cursor, end: cursor + rest.length });
|
|
738
|
+
base += sourceLine.length + 1;
|
|
739
|
+
}
|
|
740
|
+
return out;
|
|
741
|
+
}
|
|
742
|
+
/** Paint one already-wrapped output line by the segments overlapping its range. */
|
|
743
|
+
function paintSegmentedLine(line, start, end, segments) {
|
|
744
|
+
if (segments.length === 0)
|
|
745
|
+
return line;
|
|
746
|
+
let out = '';
|
|
747
|
+
for (const seg of segments) {
|
|
748
|
+
if (seg.end <= start)
|
|
749
|
+
continue;
|
|
750
|
+
if (seg.start >= end)
|
|
751
|
+
break;
|
|
752
|
+
const from = Math.max(seg.start, start);
|
|
753
|
+
const to = Math.min(seg.end, end);
|
|
754
|
+
if (to <= from)
|
|
755
|
+
continue;
|
|
756
|
+
out += `\x1b[${seg.sgr}m${line.slice(from - start, to - start)}\x1b[0m`;
|
|
757
|
+
}
|
|
758
|
+
return out === '' ? line : out;
|
|
759
|
+
}
|
|
760
|
+
/** Wrap `text` and color each output line by overlapping `segments`. */
|
|
761
|
+
function wrapSegmented(text, width, segments) {
|
|
762
|
+
return wrapTracked(text, width).map(({ line, start, end }) => paintSegmentedLine(line, start, end, segments));
|
|
763
|
+
}
|
|
706
764
|
function truncate(text, maxLines) {
|
|
707
765
|
const lines = text.split('\n');
|
|
708
766
|
if (maxLines <= 0)
|
|
@@ -1616,6 +1674,24 @@ function friendlyArgsSummary(name, args) {
|
|
|
1616
1674
|
const SHELL_TOOL_NAMES = new Set(['bash', 'pwsh']);
|
|
1617
1675
|
const DIFF_TOOL_NAMES = new Set(['edit', 'write', 'str_replace_editor']);
|
|
1618
1676
|
const SUBAGENT_TOOL_NAMES = new Set(['subagent', 'subagent_fork', 'task']);
|
|
1677
|
+
/** Localized card titles for tool names without a dedicated branch. */
|
|
1678
|
+
const TOOL_TITLE_MAP = {
|
|
1679
|
+
edit: '编辑',
|
|
1680
|
+
write: '写入',
|
|
1681
|
+
str_replace_editor: '替换',
|
|
1682
|
+
fetch: '抓取网页',
|
|
1683
|
+
list_files: '列出文件',
|
|
1684
|
+
list: '列出文件',
|
|
1685
|
+
ls: '列出文件',
|
|
1686
|
+
find: '搜索文件',
|
|
1687
|
+
search: '网页搜索',
|
|
1688
|
+
delete: '删除文件',
|
|
1689
|
+
rm: '删除文件',
|
|
1690
|
+
rename: '重命名文件',
|
|
1691
|
+
mv: '重命名文件',
|
|
1692
|
+
mkdir: '创建目录',
|
|
1693
|
+
skills: '技能',
|
|
1694
|
+
};
|
|
1619
1695
|
const MAX_SUBAGENT_LOGS = 80;
|
|
1620
1696
|
const TODO_STATUS_MARK = {
|
|
1621
1697
|
pending: '○',
|
|
@@ -1954,7 +2030,7 @@ export function presentToolCall(name, args) {
|
|
|
1954
2030
|
const diff = diffHunksFromArgs(name, args);
|
|
1955
2031
|
const path = diff?.[0]?.path;
|
|
1956
2032
|
return {
|
|
1957
|
-
title: name,
|
|
2033
|
+
title: TOOL_TITLE_MAP[name] ?? name,
|
|
1958
2034
|
summary: path ?? friendlyArgsSummary(name, args),
|
|
1959
2035
|
...diff === null || diff === undefined ? {} : { diff },
|
|
1960
2036
|
};
|
|
@@ -2002,7 +2078,7 @@ export function presentToolCall(name, args) {
|
|
|
2002
2078
|
const url = typeof parsed?.url === 'string' ? parsed.url : '';
|
|
2003
2079
|
return { title: '抓取网页', summary: url || friendlyArgsSummary(name, args) };
|
|
2004
2080
|
}
|
|
2005
|
-
return { title: name, summary: friendlyArgsSummary(name, args) };
|
|
2081
|
+
return { title: TOOL_TITLE_MAP[name] ?? name, summary: friendlyArgsSummary(name, args) };
|
|
2006
2082
|
}
|
|
2007
2083
|
/** Validate a tool/result meta payload's structured diff, mirroring the web card. */
|
|
2008
2084
|
export function diffMetaDiffs(meta) {
|
|
@@ -3097,22 +3173,11 @@ export class SshTui {
|
|
|
3097
3173
|
if (row.kind === 'tool') {
|
|
3098
3174
|
const running = row.status === undefined || row.status === 'running';
|
|
3099
3175
|
const ok = row.status === 'ok';
|
|
3100
|
-
//
|
|
3101
|
-
//
|
|
3102
|
-
|
|
3103
|
-
const dotColor = !this.color ? undefined : running ? '33' : ok ? '32' : '31';
|
|
3104
|
-
const styleToolHeader = (line) => {
|
|
3105
|
-
const safe = sanitizeTerminalText(line);
|
|
3106
|
-
if (!this.color)
|
|
3107
|
-
return safe;
|
|
3108
|
-
const dotIndex = safe.indexOf('●');
|
|
3109
|
-
if (dotColor === undefined || dotIndex === -1)
|
|
3110
|
-
return this.styleLine('tool', safe);
|
|
3111
|
-
return `\x1b[33m${safe.slice(0, dotIndex)}\x1b[${dotColor}m●\x1b[33m${safe.slice(dotIndex + 1)}\x1b[0m`;
|
|
3112
|
-
};
|
|
3176
|
+
// Header text follows the execution state; the shell command itself
|
|
3177
|
+
// stays dim so it reads like a command, not a status.
|
|
3178
|
+
const stateCode = !this.color ? undefined : running ? '33' : ok ? '32' : '31';
|
|
3113
3179
|
const spinner = running ? ` ${this.spinnerFrame()}` : '';
|
|
3114
3180
|
const state = running ? 'running…' : ok ? 'ok' : 'error';
|
|
3115
|
-
const summary = row.summary === '' ? '' : ` ${row.summary}`;
|
|
3116
3181
|
const exit = !running && row.command !== undefined
|
|
3117
3182
|
? row.signal !== undefined
|
|
3118
3183
|
? ` [信号 ${row.signal}]`
|
|
@@ -3122,22 +3187,49 @@ export class SshTui {
|
|
|
3122
3187
|
: '';
|
|
3123
3188
|
const focused = this.focusedRow === row;
|
|
3124
3189
|
const marker = row.expanded ? '▾' : '▸';
|
|
3125
|
-
const
|
|
3190
|
+
const lead = `${focused ? '▶ ' : ' '}${marker} ● ${row.title}`;
|
|
3191
|
+
// Summary carries the operand (command / path / pattern), not a status:
|
|
3192
|
+
// keep it dim so the title stays the colored, readable part.
|
|
3193
|
+
const summaryText = row.summary === '' ? '' : ` ${row.summary}`;
|
|
3194
|
+
const tail = ` [${state}]${exit}${spinner}`;
|
|
3195
|
+
const plainHeader = `${lead}${summaryText}${tail}`;
|
|
3196
|
+
const headerSegments = stateCode === undefined
|
|
3197
|
+
? []
|
|
3198
|
+
: [
|
|
3199
|
+
{ start: 0, end: lead.length, sgr: stateCode },
|
|
3200
|
+
{ start: lead.length, end: lead.length + summaryText.length, sgr: '90' },
|
|
3201
|
+
{ start: lead.length + summaryText.length, end: plainHeader.length, sgr: stateCode },
|
|
3202
|
+
];
|
|
3126
3203
|
if (!row.expanded) {
|
|
3127
|
-
const collapsed = truncateToWidth(
|
|
3128
|
-
const styled =
|
|
3204
|
+
const collapsed = truncateToWidth(plainHeader, Math.max(1, width - 2));
|
|
3205
|
+
const styled = stateCode === undefined
|
|
3206
|
+
? collapsed
|
|
3207
|
+
: paintSegmentedLine(collapsed, 0, collapsed.length, headerSegments);
|
|
3129
3208
|
addDisplay(focused && this.color ? `\x1b[7m${styled}\x1b[27m` : styled, row);
|
|
3130
3209
|
continue;
|
|
3131
3210
|
}
|
|
3132
|
-
|
|
3133
|
-
|
|
3211
|
+
const expandedHeaderLines = headerSegments.length === 0
|
|
3212
|
+
? wrap(plainHeader, width)
|
|
3213
|
+
: wrapSegmented(plainHeader, Math.max(1, width), headerSegments);
|
|
3214
|
+
for (const wrapped of expandedHeaderLines) {
|
|
3215
|
+
addDisplay(wrapped, row);
|
|
3134
3216
|
}
|
|
3217
|
+
const bodyCode = !this.color ? undefined : running ? '33' : ok ? '32' : '31';
|
|
3135
3218
|
for (const line of toolBodyLines(row, this.maxToolOutputLines)) {
|
|
3136
3219
|
const inner = Math.max(1, width - 2);
|
|
3137
3220
|
const fillRow = line.kind === 'diff-add' || line.kind === 'diff-del';
|
|
3138
3221
|
for (const wrapped of wrap(line.text, inner)) {
|
|
3139
3222
|
const body = fillRow ? padToWidth(` ${wrapped}`, width) : ` ${wrapped}`;
|
|
3140
|
-
|
|
3223
|
+
// Diffs and todo marks keep their dedicated colors; ordinary
|
|
3224
|
+
// results follow the tool's execution state (yellow running /
|
|
3225
|
+
// green ok / red error).
|
|
3226
|
+
const kind = line.kind;
|
|
3227
|
+
const style = kind === 'diff-add' || kind === 'diff-del' || kind === 'diff-path'
|
|
3228
|
+
? this.styleLine(kind, body)
|
|
3229
|
+
: kind === 'todo-done' || kind === 'todo-active' || kind === 'todo-pending'
|
|
3230
|
+
? this.styleLine(kind, body)
|
|
3231
|
+
: this.styleStatusText(bodyCode ?? (kind === 'error' ? '31' : '37'), body);
|
|
3232
|
+
addDisplay(style, row);
|
|
3141
3233
|
}
|
|
3142
3234
|
}
|
|
3143
3235
|
continue;
|
|
@@ -3791,6 +3883,13 @@ export class SshTui {
|
|
|
3791
3883
|
this.dirty = false;
|
|
3792
3884
|
this.paint();
|
|
3793
3885
|
};
|
|
3886
|
+
/** Color one line with an explicit SGR code (tool state colors, etc.). */
|
|
3887
|
+
styleStatusText(code, text) {
|
|
3888
|
+
const safe = sanitizeTerminalText(text);
|
|
3889
|
+
if (!this.color)
|
|
3890
|
+
return safe;
|
|
3891
|
+
return `\x1b[${code}m${safe}\x1b[0m`;
|
|
3892
|
+
}
|
|
3794
3893
|
styleLine(kind, text) {
|
|
3795
3894
|
const safe = sanitizeTerminalText(text);
|
|
3796
3895
|
if (!this.color)
|
|
@@ -3828,7 +3927,7 @@ export class SshTui {
|
|
|
3828
3927
|
const provider = selection.provider ?? parentProvider;
|
|
3829
3928
|
const model = subagentModelMatchesProvider(provider, selection.model)
|
|
3830
3929
|
? selection.model
|
|
3831
|
-
: defaultSubagentModelForProvider(provider);
|
|
3930
|
+
: defaultSubagentModelForProvider(provider, [], this.selectionRef?.current?.model);
|
|
3832
3931
|
return {
|
|
3833
3932
|
...resolved,
|
|
3834
3933
|
provider,
|
|
@@ -5051,7 +5150,7 @@ export class SshTui {
|
|
|
5051
5150
|
if (this.selectionRef !== undefined)
|
|
5052
5151
|
this.selectionRef.current = next;
|
|
5053
5152
|
this.onSelectionChanged?.(next);
|
|
5054
|
-
await this.
|
|
5153
|
+
await this.persistDefaultSelection(next);
|
|
5055
5154
|
await this.rememberRoute(next);
|
|
5056
5155
|
const kind = describeProviderRoute(provider);
|
|
5057
5156
|
this.pushRow({
|
|
@@ -5062,7 +5161,6 @@ export class SshTui {
|
|
|
5062
5161
|
const previousProvider = current?.provider ?? this.agent.options.provider ?? this.providerName;
|
|
5063
5162
|
if (previousProvider !== provider) {
|
|
5064
5163
|
await this.syncSubagentToProvider(provider, listedIds, true);
|
|
5065
|
-
await this.promptSubagentAfterProviderSwitch(provider);
|
|
5066
5164
|
this.clearQuotaForProvider(provider);
|
|
5067
5165
|
void this.refreshQuota({ reason: 'command', announce: false }).catch(() => { });
|
|
5068
5166
|
}
|
|
@@ -5071,6 +5169,47 @@ export class SshTui {
|
|
|
5071
5169
|
}
|
|
5072
5170
|
this.markDirty();
|
|
5073
5171
|
}
|
|
5172
|
+
/**
|
|
5173
|
+
* Persist the default provider/model selection. `agentDefaultModel` may be
|
|
5174
|
+
* unavailable or its settings namespace may not be registered in this
|
|
5175
|
+
* process, so a failed `saveSelection` falls back to writing the
|
|
5176
|
+
* `agent-default-model` settings section directly and surfaces a warning
|
|
5177
|
+
* when neither path sticks.
|
|
5178
|
+
*/
|
|
5179
|
+
async persistDefaultSelection(next) {
|
|
5180
|
+
const settings = this.ctx.get('settings');
|
|
5181
|
+
const defaultModel = this.ctx.get('agentDefaultModel');
|
|
5182
|
+
if (defaultModel !== undefined) {
|
|
5183
|
+
try {
|
|
5184
|
+
await defaultModel.saveSelection(next);
|
|
5185
|
+
return true;
|
|
5186
|
+
}
|
|
5187
|
+
catch {
|
|
5188
|
+
// Fall through to the direct settings write.
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
if (settings !== undefined) {
|
|
5192
|
+
try {
|
|
5193
|
+
await settings.replace(AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE, {
|
|
5194
|
+
provider: next.provider,
|
|
5195
|
+
model: next.model,
|
|
5196
|
+
...(next.reasoningEffort === undefined ? {} : { reasoningEffort: String(next.reasoningEffort) }),
|
|
5197
|
+
});
|
|
5198
|
+
return true;
|
|
5199
|
+
}
|
|
5200
|
+
catch (error) {
|
|
5201
|
+
this.pushRow({
|
|
5202
|
+
kind: 'error',
|
|
5203
|
+
text: `默认选择未能固化:agentDefaultModel 不可用且 settings 写入失败(${errorChain(error)})。本次切换仅当前会话生效,重启会回退到保存过的提供商。`,
|
|
5204
|
+
});
|
|
5205
|
+
this.markDirty();
|
|
5206
|
+
return false;
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
this.pushRow({ kind: 'error', text: '默认选择未能固化:settings 服务不可用。本次切换仅当前会话生效。' });
|
|
5210
|
+
this.markDirty();
|
|
5211
|
+
return false;
|
|
5212
|
+
}
|
|
5074
5213
|
/** Provider route the next subagent request should use. */
|
|
5075
5214
|
effectiveSubagentProvider() {
|
|
5076
5215
|
return this.subagentSelection.current.provider
|
|
@@ -5099,7 +5238,8 @@ export class SshTui {
|
|
|
5099
5238
|
catalog = [];
|
|
5100
5239
|
}
|
|
5101
5240
|
}
|
|
5102
|
-
const
|
|
5241
|
+
const parentModel = this.selectionRef?.current?.model ?? this.agent.options.model;
|
|
5242
|
+
const nextModel = defaultSubagentModelForProvider(provider, catalog, parentModel);
|
|
5103
5243
|
if (!force && nextModel === current.model && current.provider === undefined)
|
|
5104
5244
|
return;
|
|
5105
5245
|
const persisted = await this.saveSubagentSelection({
|
|
@@ -5111,35 +5251,6 @@ export class SshTui {
|
|
|
5111
5251
|
text: `子代理已跟随提供商 ${provider},模型改为 ${nextModel}${persisted ? '' : '(仅当前会话)'}。`,
|
|
5112
5252
|
});
|
|
5113
5253
|
}
|
|
5114
|
-
async promptSubagentAfterProviderSwitch(provider) {
|
|
5115
|
-
const current = this.subagentSelection.current;
|
|
5116
|
-
try {
|
|
5117
|
-
const { options, source } = await this.subagentModelOptions(provider);
|
|
5118
|
-
const listed = options.length === 0
|
|
5119
|
-
? [{ id: current.model, label: current.model }]
|
|
5120
|
-
: options;
|
|
5121
|
-
if (!listed.some(option => option.id === current.model)) {
|
|
5122
|
-
listed.unshift({ id: current.model, label: current.model });
|
|
5123
|
-
}
|
|
5124
|
-
const selected = await this.pickModelOption(listed, provider, source, current.model);
|
|
5125
|
-
if (selected === undefined || selected.id === current.model)
|
|
5126
|
-
return;
|
|
5127
|
-
if (!(await this.ensureProviderModelConfigured(provider, selected.id)))
|
|
5128
|
-
return;
|
|
5129
|
-
const persisted = await this.saveSubagentSelection({ model: selected.id });
|
|
5130
|
-
this.pushRow({
|
|
5131
|
-
kind: 'system',
|
|
5132
|
-
text: `子代理模型已设为 ${selected.id}(提供方跟随 ${provider})${persisted ? '' : '(仅当前会话)'}。`,
|
|
5133
|
-
});
|
|
5134
|
-
}
|
|
5135
|
-
catch (error) {
|
|
5136
|
-
if (error instanceof UserQuestionError) {
|
|
5137
|
-
this.pushRow({ kind: 'system', text: `子代理沿用 ${current.model}。之后可用 /submodel 再改。` });
|
|
5138
|
-
return;
|
|
5139
|
-
}
|
|
5140
|
-
this.pushRow({ kind: 'error', text: `选择子代理模型失败:${errorChain(error)}` });
|
|
5141
|
-
}
|
|
5142
|
-
}
|
|
5143
5254
|
clearQuotaForProvider(provider) {
|
|
5144
5255
|
if (this.quotaSnapshot !== undefined && this.quotaSnapshot.provider === provider)
|
|
5145
5256
|
return;
|
|
@@ -5573,13 +5684,29 @@ export class SshTui {
|
|
|
5573
5684
|
const token = await this.resolveSuperGrokToken();
|
|
5574
5685
|
if (token === undefined)
|
|
5575
5686
|
throw new Error('未找到 SuperGrok OAuth token(~/.grok-bridge/auth.json)');
|
|
5576
|
-
const
|
|
5687
|
+
const headers = {
|
|
5577
5688
|
authorization: `Bearer ${token}`,
|
|
5578
5689
|
accept: 'application/json',
|
|
5579
5690
|
'x-grok-client-mode': 'cli',
|
|
5580
5691
|
'x-grok-client-version': '1.0.0',
|
|
5581
|
-
}
|
|
5582
|
-
|
|
5692
|
+
};
|
|
5693
|
+
try {
|
|
5694
|
+
const payload = await this.fetchJson(SUPERGROK_BILLING_URL, headers, 'SuperGrok');
|
|
5695
|
+
return parseSuperGrokBilling(payload);
|
|
5696
|
+
}
|
|
5697
|
+
catch (error) {
|
|
5698
|
+
const message = errorChain(error);
|
|
5699
|
+
if (!message.includes('HTTP 401') && !message.includes('HTTP 403'))
|
|
5700
|
+
throw error;
|
|
5701
|
+
const retried = await this.resolveSuperGrokToken({ force: true });
|
|
5702
|
+
if (retried === undefined || retried === token)
|
|
5703
|
+
throw error;
|
|
5704
|
+
const payload = await this.fetchJson(SUPERGROK_BILLING_URL, {
|
|
5705
|
+
...headers,
|
|
5706
|
+
authorization: `Bearer ${retried}`,
|
|
5707
|
+
}, 'SuperGrok');
|
|
5708
|
+
return parseSuperGrokBilling(payload);
|
|
5709
|
+
}
|
|
5583
5710
|
}
|
|
5584
5711
|
const llmPiAi = this.ctx.get('settings')?.get(settingsNamespace('llm-pi-ai'));
|
|
5585
5712
|
const source = openCodeSourceFor(provider, llmPiAi);
|
|
@@ -5591,19 +5718,8 @@ export class SshTui {
|
|
|
5591
5718
|
const payload = await this.fetchOpenCodeGoUsage(apiKey);
|
|
5592
5719
|
return parseOpenCodeGoQuota(payload, source.provider);
|
|
5593
5720
|
}
|
|
5594
|
-
async resolveSuperGrokToken() {
|
|
5595
|
-
|
|
5596
|
-
try {
|
|
5597
|
-
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
5598
|
-
const token = typeof parsed.access_token === 'string' ? parsed.access_token : parsed.accessToken;
|
|
5599
|
-
return typeof token === 'string' && token.trim() !== '' ? token.trim() : undefined;
|
|
5600
|
-
}
|
|
5601
|
-
catch {
|
|
5602
|
-
return undefined;
|
|
5603
|
-
}
|
|
5604
|
-
};
|
|
5605
|
-
return await fromFile(join(homedir(), '.grok-bridge', 'auth.json'))
|
|
5606
|
-
?? await fromFile(join(homedir(), '.grok', 'auth.json'));
|
|
5721
|
+
async resolveSuperGrokToken(options = {}) {
|
|
5722
|
+
return resolveFreshSuperGrokToken(options);
|
|
5607
5723
|
}
|
|
5608
5724
|
async fetchJson(url, headers, label) {
|
|
5609
5725
|
let response;
|