@trenchwork/erosolar 1.1.63 → 1.2.0
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/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +4 -48
- package/dist/core/agent.js.map +1 -1
- package/dist/core/contextManager.d.ts.map +1 -1
- package/dist/core/contextManager.js +5 -2
- package/dist/core/contextManager.js.map +1 -1
- package/dist/core/errorClassification.d.ts +44 -0
- package/dist/core/errorClassification.d.ts.map +1 -0
- package/dist/core/errorClassification.js +333 -0
- package/dist/core/errorClassification.js.map +1 -0
- package/dist/core/hitl.d.ts.map +1 -1
- package/dist/core/hitl.js +8 -0
- package/dist/core/hitl.js.map +1 -1
- package/dist/core/hostedAuth.d.ts +33 -0
- package/dist/core/hostedAuth.d.ts.map +1 -1
- package/dist/core/hostedAuth.js +85 -0
- package/dist/core/hostedAuth.js.map +1 -1
- package/dist/core/quota.d.ts +61 -0
- package/dist/core/quota.d.ts.map +1 -0
- package/dist/core/quota.js +104 -0
- package/dist/core/quota.js.map +1 -0
- package/dist/core/quotaErrors.d.ts.map +1 -1
- package/dist/core/quotaErrors.js +3 -5
- package/dist/core/quotaErrors.js.map +1 -1
- package/dist/core/resultVerification.d.ts +3 -2
- package/dist/core/resultVerification.d.ts.map +1 -1
- package/dist/core/resultVerification.js +3 -2
- package/dist/core/resultVerification.js.map +1 -1
- package/dist/core/slashCommands.d.ts.map +1 -1
- package/dist/core/slashCommands.js +3 -0
- package/dist/core/slashCommands.js.map +1 -1
- package/dist/core/updateChecker.d.ts.map +1 -1
- package/dist/core/updateChecker.js +5 -1
- package/dist/core/updateChecker.js.map +1 -1
- package/dist/core/usage.d.ts +28 -0
- package/dist/core/usage.d.ts.map +1 -0
- package/dist/core/usage.js +77 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/headless/interactiveShell.d.ts +2 -0
- package/dist/headless/interactiveShell.d.ts.map +1 -1
- package/dist/headless/interactiveShell.js +99 -9
- package/dist/headless/interactiveShell.js.map +1 -1
- package/dist/plugins/providers/deepseek/index.d.ts.map +1 -1
- package/dist/plugins/providers/deepseek/index.js +8 -5
- package/dist/plugins/providers/deepseek/index.js.map +1 -1
- package/dist/providers/baseProvider.d.ts +5 -13
- package/dist/providers/baseProvider.d.ts.map +1 -1
- package/dist/providers/baseProvider.js +12 -66
- package/dist/providers/baseProvider.js.map +1 -1
- package/dist/providers/openaiChatCompletionsProvider.d.ts.map +1 -1
- package/dist/providers/openaiChatCompletionsProvider.js +27 -76
- package/dist/providers/openaiChatCompletionsProvider.js.map +1 -1
- package/dist/providers/resilientProvider.d.ts +2 -9
- package/dist/providers/resilientProvider.d.ts.map +1 -1
- package/dist/providers/resilientProvider.js +13 -199
- package/dist/providers/resilientProvider.js.map +1 -1
- package/dist/shell/toolPresentation.d.ts.map +1 -1
- package/dist/shell/toolPresentation.js +27 -3
- package/dist/shell/toolPresentation.js.map +1 -1
- package/dist/tools/bashTools.d.ts.map +1 -1
- package/dist/tools/bashTools.js +9 -3
- package/dist/tools/bashTools.js.map +1 -1
- package/dist/tools/grepTools.d.ts.map +1 -1
- package/dist/tools/grepTools.js +10 -1
- package/dist/tools/grepTools.js.map +1 -1
- package/dist/tools/searchTools.d.ts.map +1 -1
- package/dist/tools/searchTools.js +5 -4
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/webTools.d.ts.map +1 -1
- package/dist/tools/webTools.js +3 -1
- package/dist/tools/webTools.js.map +1 -1
- package/dist/ui/ink/ChatStatic.d.ts.map +1 -1
- package/dist/ui/ink/ChatStatic.js +21 -5
- package/dist/ui/ink/ChatStatic.js.map +1 -1
- package/dist/ui/ink/InkPromptController.d.ts +3 -0
- package/dist/ui/ink/InkPromptController.d.ts.map +1 -1
- package/dist/ui/ink/InkPromptController.js +12 -6
- package/dist/ui/ink/InkPromptController.js.map +1 -1
- package/dist/ui/ink/Prompt.d.ts +4 -0
- package/dist/ui/ink/Prompt.d.ts.map +1 -1
- package/dist/ui/ink/Prompt.js +62 -10
- package/dist/ui/ink/Prompt.js.map +1 -1
- package/dist/ui/ink/pasteBuffer.d.ts +44 -0
- package/dist/ui/ink/pasteBuffer.d.ts.map +1 -0
- package/dist/ui/ink/pasteBuffer.js +73 -0
- package/dist/ui/ink/pasteBuffer.js.map +1 -0
- package/package.json +1 -1
- package/dist/core/index.d.ts +0 -7
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -7
- package/dist/core/index.js.map +0 -1
- package/dist/core/providerKeys.d.ts +0 -20
- package/dist/core/providerKeys.d.ts.map +0 -1
- package/dist/core/providerKeys.js +0 -40
- package/dist/core/providerKeys.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -49
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js +0 -104
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts +0 -10
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js +0 -110
- package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js.map +0 -1
- package/dist/plugins/tools/bash/localBashPlugin.d.ts +0 -3
- package/dist/plugins/tools/bash/localBashPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/bash/localBashPlugin.js +0 -14
- package/dist/plugins/tools/bash/localBashPlugin.js.map +0 -1
- package/dist/plugins/tools/edit/editPlugin.d.ts +0 -9
- package/dist/plugins/tools/edit/editPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/edit/editPlugin.js +0 -15
- package/dist/plugins/tools/edit/editPlugin.js.map +0 -1
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts +0 -3
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js +0 -9
- package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js.map +0 -1
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts +0 -3
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js +0 -14
- package/dist/plugins/tools/filesystem/localFilesystemPlugin.js.map +0 -1
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts +0 -3
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js +0 -9
- package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js.map +0 -1
- package/dist/plugins/tools/index.d.ts +0 -3
- package/dist/plugins/tools/index.d.ts.map +0 -1
- package/dist/plugins/tools/index.js +0 -3
- package/dist/plugins/tools/index.js.map +0 -1
- package/dist/plugins/tools/integrity/integrityPlugin.d.ts +0 -3
- package/dist/plugins/tools/integrity/integrityPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/integrity/integrityPlugin.js +0 -31
- package/dist/plugins/tools/integrity/integrityPlugin.js.map +0 -1
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts +0 -3
- package/dist/plugins/tools/mcp/mcpPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/mcp/mcpPlugin.js +0 -27
- package/dist/plugins/tools/mcp/mcpPlugin.js.map +0 -1
- package/dist/plugins/tools/nodeDefaults.d.ts +0 -13
- package/dist/plugins/tools/nodeDefaults.d.ts.map +0 -1
- package/dist/plugins/tools/nodeDefaults.js +0 -33
- package/dist/plugins/tools/nodeDefaults.js.map +0 -1
- package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts +0 -3
- package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/orchestration/orchestrationPlugin.js +0 -340
- package/dist/plugins/tools/orchestration/orchestrationPlugin.js.map +0 -1
- package/dist/plugins/tools/registry.d.ts +0 -22
- package/dist/plugins/tools/registry.d.ts.map +0 -1
- package/dist/plugins/tools/registry.js +0 -58
- package/dist/plugins/tools/registry.js.map +0 -1
- package/dist/plugins/tools/search/localSearchPlugin.d.ts +0 -3
- package/dist/plugins/tools/search/localSearchPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/search/localSearchPlugin.js +0 -14
- package/dist/plugins/tools/search/localSearchPlugin.js.map +0 -1
- package/dist/plugins/tools/skills/skillPlugin.d.ts +0 -3
- package/dist/plugins/tools/skills/skillPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/skills/skillPlugin.js +0 -27
- package/dist/plugins/tools/skills/skillPlugin.js.map +0 -1
- package/dist/plugins/tools/todo/todoPlugin.d.ts +0 -3
- package/dist/plugins/tools/todo/todoPlugin.d.ts.map +0 -1
- package/dist/plugins/tools/todo/todoPlugin.js +0 -10
- package/dist/plugins/tools/todo/todoPlugin.js.map +0 -1
- package/dist/runtime/agentWorkerPool.d.ts +0 -167
- package/dist/runtime/agentWorkerPool.d.ts.map +0 -1
- package/dist/runtime/agentWorkerPool.js +0 -435
- package/dist/runtime/agentWorkerPool.js.map +0 -1
- package/dist/shell/autoExecutor.d.ts +0 -70
- package/dist/shell/autoExecutor.d.ts.map +0 -1
- package/dist/shell/autoExecutor.js +0 -320
- package/dist/shell/autoExecutor.js.map +0 -1
- package/dist/shell/commandRegistry.d.ts +0 -122
- package/dist/shell/commandRegistry.d.ts.map +0 -1
- package/dist/shell/commandRegistry.js +0 -355
- package/dist/shell/commandRegistry.js.map +0 -1
- package/dist/shell/composableMessage.d.ts +0 -178
- package/dist/shell/composableMessage.d.ts.map +0 -1
- package/dist/shell/composableMessage.js +0 -384
- package/dist/shell/composableMessage.js.map +0 -1
- package/dist/shell/vimMode.d.ts +0 -66
- package/dist/shell/vimMode.d.ts.map +0 -1
- package/dist/shell/vimMode.js +0 -435
- package/dist/shell/vimMode.js.map +0 -1
- package/dist/tools/localExplore.d.ts +0 -38
- package/dist/tools/localExplore.d.ts.map +0 -1
- package/dist/tools/localExplore.js +0 -30
- package/dist/tools/localExplore.js.map +0 -1
|
@@ -32,8 +32,9 @@ import { createAgentController } from '../runtime/agentController.js';
|
|
|
32
32
|
import { expandFileMentions, listWorkspaceFiles } from '../core/fileMentions.js';
|
|
33
33
|
import { resolveWorkspaceCaptureOptions, buildWorkspaceContext } from '../workspace.js';
|
|
34
34
|
import { loadAllSecrets, listSecretDefinitions, setSecretValue, getSecretValue, getSecretDefinition, classifyKeyEntry } from '../core/secretStore.js';
|
|
35
|
-
import { resolveKeyMode, keyModeLine, setPreferOwnKeys, clearHostedSession } from '../core/hostedAuth.js';
|
|
35
|
+
import { resolveKeyMode, keyModeLine, setPreferOwnKeys, clearHostedSession, loginViaLoopback } from '../core/hostedAuth.js';
|
|
36
36
|
import { appendMemoryNote } from '../tools/memoryTools.js';
|
|
37
|
+
import { recordDeepSeekUsage, getUsage, TAVILY_MONTHLY_FREE, TAVILY_ONE_TIME_BONUS } from '../core/usage.js';
|
|
37
38
|
import { listSessions, loadSessionById, saveSessionSnapshot } from '../core/sessionStore.js';
|
|
38
39
|
import { relativeTime } from '../core/relativeTime.js';
|
|
39
40
|
import { getModelContextInfo } from '../core/contextWindow.js';
|
|
@@ -148,7 +149,8 @@ function getVersion() {
|
|
|
148
149
|
}
|
|
149
150
|
/** Inner content of the welcome box (plain, no border/colour). */
|
|
150
151
|
function welcomeBodyLines(input) {
|
|
151
|
-
const
|
|
152
|
+
const title = input.version ? `✻ Welcome to Erosolar Coder ${input.version}` : '✻ Welcome to Erosolar Coder';
|
|
153
|
+
const body = [title, ''];
|
|
152
154
|
const mode = input.keyMode ?? (input.hasApiKey ? 'own' : 'none');
|
|
153
155
|
if (mode === 'hosted') {
|
|
154
156
|
// Signed in — running on hosted keys. The mode line names the account so
|
|
@@ -159,7 +161,7 @@ function welcomeBodyLines(input) {
|
|
|
159
161
|
body.push(`${input.model} · ${input.provider}`, `Key: ${input.maskedKey} · /help for commands`);
|
|
160
162
|
}
|
|
161
163
|
else {
|
|
162
|
-
body.push('⚠ No DeepSeek API key configured', '', '
|
|
164
|
+
body.push('⚠ No DeepSeek API key configured', '', '/login Sign in with Google for hosted keys', '', 'Or bring your own:', ' /key sk-… DeepSeek (required) · platform.deepseek.com', ' /key tvly-… Tavily web search (optional) · tavily.com');
|
|
163
165
|
}
|
|
164
166
|
if (input.cwd)
|
|
165
167
|
body.push(`cwd: ${input.cwd}`);
|
|
@@ -283,6 +285,12 @@ class InteractiveShell {
|
|
|
283
285
|
};
|
|
284
286
|
pendingModelSwitch = null;
|
|
285
287
|
currentResponseBuffer = '';
|
|
288
|
+
// The turn's final assistant text, captured BEFORE currentResponseBuffer is
|
|
289
|
+
// cleared on message.complete. The auto-continue refusal/completion/governor
|
|
290
|
+
// reads run in the `finally`, AFTER that clear, so reading the buffer there saw
|
|
291
|
+
// '' and blinded them (completion detection + safety-refusal both need the
|
|
292
|
+
// text). This mirrors the buffer's content but is never cleared mid-turn.
|
|
293
|
+
finalResponseText = '';
|
|
286
294
|
// Store original prompt for auto-continuation
|
|
287
295
|
originalPromptForAutoContinue = null;
|
|
288
296
|
// (Pinned prompt removed per request — field intentionally absent.)
|
|
@@ -368,6 +376,7 @@ class InteractiveShell {
|
|
|
368
376
|
// the spinner's "esc to interrupt" is real. Ctrl+C still works too.
|
|
369
377
|
onEscape: () => this.handleInterrupt(),
|
|
370
378
|
onShowShortcuts: () => this.showKeyboardShortcuts(),
|
|
379
|
+
onDismissPanel: () => this.dismissInlinePanel(),
|
|
371
380
|
});
|
|
372
381
|
// Register cleanup callback for graceful shutdown
|
|
373
382
|
onShutdown(() => {
|
|
@@ -524,6 +533,7 @@ class InteractiveShell {
|
|
|
524
533
|
cwd: this.workingDir,
|
|
525
534
|
keyMode: keyStatus.mode,
|
|
526
535
|
keyModeLine: keyModeLine(keyStatus),
|
|
536
|
+
version: `v${version}`,
|
|
527
537
|
});
|
|
528
538
|
const boxed = roundedBox(body, (cell) => cell.replace('✻', flare('✻')), (s) => wire(s));
|
|
529
539
|
const welcomeContent = ['', ...updateLines, ...boxed, ''].join('\n');
|
|
@@ -857,6 +867,11 @@ class InteractiveShell {
|
|
|
857
867
|
r?.addEvent('system', this.accountStatusText(resolveKeyMode()));
|
|
858
868
|
return true;
|
|
859
869
|
}
|
|
870
|
+
// /login — Google sign-in via ero.solar (loopback OAuth) to unlock hosted keys.
|
|
871
|
+
if (lower === '/login' || lower === '/signin') {
|
|
872
|
+
void this.handleLogin();
|
|
873
|
+
return true;
|
|
874
|
+
}
|
|
860
875
|
// /logout — drop the hosted session (back to your own keys, or none).
|
|
861
876
|
if (lower === '/logout' || lower === '/signout') {
|
|
862
877
|
clearHostedSession();
|
|
@@ -907,6 +922,13 @@ class InteractiveShell {
|
|
|
907
922
|
this.showContext();
|
|
908
923
|
return true;
|
|
909
924
|
}
|
|
925
|
+
// /cost — DeepSeek tokens + Tavily searches consumed (this session + all
|
|
926
|
+
// time), and the hosted free-pool reference. Account-wide remaining is a
|
|
927
|
+
// backend number shown in the ero.solar portal.
|
|
928
|
+
if (lower === '/cost' || lower === '/spend') {
|
|
929
|
+
this.showUsage();
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
910
932
|
// /diff — review the files the agent changed this run, as colored diffs.
|
|
911
933
|
if (lower === '/diff' || lower === '/changes') {
|
|
912
934
|
this.showDiff();
|
|
@@ -1447,6 +1469,29 @@ class InteractiveShell {
|
|
|
1447
1469
|
this.promptController.setInlinePanel(lines);
|
|
1448
1470
|
this.scheduleInlinePanelDismiss();
|
|
1449
1471
|
}
|
|
1472
|
+
/** /cost — DeepSeek tokens + Tavily searches consumed (this install). */
|
|
1473
|
+
showUsage() {
|
|
1474
|
+
if (!this.promptController?.supportsInlinePanel()) {
|
|
1475
|
+
this.promptController?.setStatusMessage('Use /cost in interactive mode');
|
|
1476
|
+
setTimeout(() => this.promptController?.setStatusMessage(null), 3000);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const { session, cumulative } = getUsage();
|
|
1480
|
+
const label = (s) => chalk.hex('#ffb142')(s.padEnd(9));
|
|
1481
|
+
const dim = (s) => chalk.dim(s);
|
|
1482
|
+
const ds = (u) => `${formatTokenCount(u.deepseekInputTokens)} in · ${formatTokenCount(u.deepseekOutputTokens)} out`;
|
|
1483
|
+
const lines = [
|
|
1484
|
+
chalk.bold.hex('#ece6da')('Usage') + dim(' (press any key to dismiss)'),
|
|
1485
|
+
'',
|
|
1486
|
+
label('DeepSeek') + dim(`${ds(cumulative)} · this session ${ds(session)}`),
|
|
1487
|
+
label('Tavily') + dim(`${cumulative.tavilySearches} searches · this session ${session.tavilySearches}`),
|
|
1488
|
+
'',
|
|
1489
|
+
dim(`Hosted free pool: Tavily ${TAVILY_MONTHLY_FREE.toLocaleString('en-US')}/mo + ${TAVILY_ONE_TIME_BONUS.toLocaleString('en-US')} one-time bonus.`),
|
|
1490
|
+
dim('Account-wide totals + remaining show in the ero.solar portal after sign-in.'),
|
|
1491
|
+
];
|
|
1492
|
+
this.promptController.setInlinePanel(lines);
|
|
1493
|
+
this.scheduleInlinePanelDismiss();
|
|
1494
|
+
}
|
|
1450
1495
|
/**
|
|
1451
1496
|
* /diff — review every file the agent changed this run as a colored diff,
|
|
1452
1497
|
* in a dismissable panel. Reads each file's original content from the change
|
|
@@ -1538,10 +1583,45 @@ class InteractiveShell {
|
|
|
1538
1583
|
}
|
|
1539
1584
|
if (s.mode === 'own') {
|
|
1540
1585
|
return chalk.green(`Your own keys · DeepSeek${s.ownTavily ? ' + Tavily' : ''}.`) +
|
|
1541
|
-
chalk.dim(s.signedIn ? ` /account hosted to use hosted keys.` : `
|
|
1586
|
+
chalk.dim(s.signedIn ? ` /account hosted to use hosted keys.` : ` /login to use hosted keys.`);
|
|
1542
1587
|
}
|
|
1543
1588
|
return chalk.yellow('No keys configured.') +
|
|
1544
|
-
chalk.dim('
|
|
1589
|
+
chalk.dim(' /login for hosted keys, or set your own: /key sk-… (and /key tvly-…).');
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* /login — Google sign-in via ero.solar. Opens the browser to the SSO URL and
|
|
1593
|
+
* runs a one-shot 127.0.0.1 loopback server that captures the redirect with
|
|
1594
|
+
* the short-lived token (see core/hostedAuth.ts). On success the CLI is on
|
|
1595
|
+
* hosted keys; no key ever touches this client.
|
|
1596
|
+
*/
|
|
1597
|
+
async handleLogin() {
|
|
1598
|
+
const r = this.promptController?.getRenderer();
|
|
1599
|
+
const status = resolveKeyMode();
|
|
1600
|
+
if (status.signedIn) {
|
|
1601
|
+
r?.addEvent('system', chalk.green(`Already signed in as ${status.email}.`) +
|
|
1602
|
+
chalk.dim(' /logout to sign out · /account to switch key source.'));
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
r?.addEvent('system', chalk.dim('Opening ero.solar sign-in in your browser — finish there, then return here…'));
|
|
1606
|
+
const result = await loginViaLoopback({ open: (url) => this.openInBrowser(url) });
|
|
1607
|
+
if (result.ok && result.session) {
|
|
1608
|
+
r?.addEvent('system', chalk.green(`✓ Signed in as ${result.session.email} — using hosted keys.`));
|
|
1609
|
+
void this.showWelcome();
|
|
1610
|
+
}
|
|
1611
|
+
else {
|
|
1612
|
+
r?.addEvent('system', chalk.yellow(`Sign-in didn't complete: ${result.error ?? 'unknown error'}.`) +
|
|
1613
|
+
chalk.dim(' Retry /login, or use /key sk-… for your own key.'));
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
/** Best-effort open a URL in the OS browser; also prints it as a fallback. */
|
|
1617
|
+
openInBrowser(url) {
|
|
1618
|
+
const opener = process.platform === 'darwin' ? 'open'
|
|
1619
|
+
: process.platform === 'win32' ? 'start ""'
|
|
1620
|
+
: 'xdg-open';
|
|
1621
|
+
// url is built by loginViaLoopback (no user input) and JSON-quoted, so the
|
|
1622
|
+
// `&` in the query string can't break out of the argument.
|
|
1623
|
+
childExec(`${opener} ${JSON.stringify(url)}`, () => { });
|
|
1624
|
+
this.promptController?.getRenderer()?.addEvent('system', chalk.dim(`If the browser didn't open: ${url}`));
|
|
1545
1625
|
}
|
|
1546
1626
|
showHelp() {
|
|
1547
1627
|
if (!this.promptController?.supportsInlinePanel()) {
|
|
@@ -1557,18 +1637,20 @@ class InteractiveShell {
|
|
|
1557
1637
|
const lines = [
|
|
1558
1638
|
chalk.bold.hex('#ece6da')('Erosolar Coder') + dim(' (press any key to dismiss)'),
|
|
1559
1639
|
'',
|
|
1640
|
+
cmd('/login') + dim(' Sign in with Google (ero.solar) to use hosted keys'),
|
|
1560
1641
|
cmd('/key sk-…') + dim(' Set your DeepSeek API key (required)'),
|
|
1561
1642
|
cmd('/key tvly-…') + dim(' Set your Tavily key for web search (optional)'),
|
|
1562
1643
|
cmd('/account') + dim(' Show / switch key source (hosted vs your own)'),
|
|
1563
1644
|
cmd('/update') + dim(' Check npm and upgrade to the latest version'),
|
|
1564
1645
|
cmd('/resume') + dim(' Restore a previous conversation'),
|
|
1565
1646
|
cmd('/context') + dim(' Show context-window usage'),
|
|
1647
|
+
cmd('/cost') + dim(' DeepSeek tokens + Tavily searches consumed'),
|
|
1566
1648
|
cmd('/diff') + dim(' Review changes made this run'),
|
|
1567
1649
|
cmd('/rewind') + dim(' Undo this run\'s file changes'),
|
|
1568
1650
|
'',
|
|
1569
1651
|
dim('Prefixes: ') + cmd('@file') + dim(' attach · ') + cmd('!cmd') + dim(' run shell · ') + cmd('#note') + dim(' save to memory'),
|
|
1570
1652
|
'',
|
|
1571
|
-
dim('Everything else runs automatically
|
|
1653
|
+
dim('Everything else runs automatically —'),
|
|
1572
1654
|
dim('deepseek-v4-pro · max thought · ultracode · adversarial verifier, all on.'),
|
|
1573
1655
|
dim('Shift+Tab cycles permission mode · Ctrl+D exits · ? for shortcuts'),
|
|
1574
1656
|
];
|
|
@@ -1726,6 +1808,7 @@ class InteractiveShell {
|
|
|
1726
1808
|
enterCriticalSection();
|
|
1727
1809
|
this.isProcessing = true;
|
|
1728
1810
|
this.currentResponseBuffer = '';
|
|
1811
|
+
this.finalResponseText = '';
|
|
1729
1812
|
this.promptController?.setStreaming(true);
|
|
1730
1813
|
this.promptController?.setStatusMessage('Analyzing request…');
|
|
1731
1814
|
const renderer = this.promptController?.getRenderer();
|
|
@@ -1794,6 +1877,7 @@ class InteractiveShell {
|
|
|
1794
1877
|
case 'message.start':
|
|
1795
1878
|
// AI has started processing - update status to show activity
|
|
1796
1879
|
this.currentResponseBuffer = '';
|
|
1880
|
+
this.finalResponseText = '';
|
|
1797
1881
|
reasoningBuffer = '';
|
|
1798
1882
|
reasoningOnlyStartTime = null; // Reset on new message
|
|
1799
1883
|
this.promptController?.setStatusMessage('Thinking...');
|
|
@@ -1801,6 +1885,7 @@ class InteractiveShell {
|
|
|
1801
1885
|
case 'message.delta':
|
|
1802
1886
|
// Stream content as it arrives
|
|
1803
1887
|
this.currentResponseBuffer += event.content ?? '';
|
|
1888
|
+
this.finalResponseText += event.content ?? '';
|
|
1804
1889
|
if (renderer) {
|
|
1805
1890
|
renderer.addEvent('stream', event.content);
|
|
1806
1891
|
}
|
|
@@ -1865,6 +1950,9 @@ class InteractiveShell {
|
|
|
1865
1950
|
}
|
|
1866
1951
|
}
|
|
1867
1952
|
renderer.addEvent('response', '\n');
|
|
1953
|
+
// Capture the authoritative final text BEFORE the buffer is cleared
|
|
1954
|
+
// (the finally's auto-continue reads run after this clear).
|
|
1955
|
+
this.finalResponseText = sourceText || this.finalResponseText;
|
|
1868
1956
|
}
|
|
1869
1957
|
this.currentResponseBuffer = '';
|
|
1870
1958
|
break;
|
|
@@ -1943,6 +2031,8 @@ class InteractiveShell {
|
|
|
1943
2031
|
}
|
|
1944
2032
|
break;
|
|
1945
2033
|
case 'usage': {
|
|
2034
|
+
// Meter cumulative DeepSeek consumption for /usage + the portal.
|
|
2035
|
+
recordDeepSeekUsage(event.inputTokens, event.outputTokens);
|
|
1946
2036
|
// inputTokens = exactly what occupies the context window this turn.
|
|
1947
2037
|
// The real model window (not a hardcoded guess) is the denominator
|
|
1948
2038
|
// so "% context left" reflects the actual model.
|
|
@@ -2098,7 +2188,7 @@ class InteractiveShell {
|
|
|
2098
2188
|
// model declines the request, the request is *done* — auto-continue
|
|
2099
2189
|
// would just resubmit "continue" and start a new spinner cycle, which
|
|
2100
2190
|
// is what produced the stuck "Thinking… (4m N s)" timer the user saw.
|
|
2101
|
-
const refusedTurn = isSafetyRefusal(this.
|
|
2191
|
+
const refusedTurn = isSafetyRefusal(this.finalResponseText);
|
|
2102
2192
|
this.isProcessing = false;
|
|
2103
2193
|
this.promptController?.setStreaming(false);
|
|
2104
2194
|
this.promptController?.setStatusMessage(null);
|
|
@@ -2122,7 +2212,7 @@ class InteractiveShell {
|
|
|
2122
2212
|
// Snapshot this turn's full output (tool results + narration) BEFORE the
|
|
2123
2213
|
// buffer is cleared — the auto-continue governor + failure registry need
|
|
2124
2214
|
// the real error text, which the reset below would otherwise wipe.
|
|
2125
|
-
const combinedTurnOutput = (turnToolOutput + '\n' + this.
|
|
2215
|
+
const combinedTurnOutput = (turnToolOutput + '\n' + this.finalResponseText).slice(-16000);
|
|
2126
2216
|
this.currentResponseBuffer = '';
|
|
2127
2217
|
// Autosave the conversation so /resume has something to restore. Each
|
|
2128
2218
|
// turn updates the same snapshot in place (keyed by this.sessionId).
|
|
@@ -2154,7 +2244,7 @@ class InteractiveShell {
|
|
|
2154
2244
|
if (autoMode !== 'off') {
|
|
2155
2245
|
// Check if original user prompt is fully completed
|
|
2156
2246
|
const detector = getTaskCompletionDetector();
|
|
2157
|
-
const analysis = detector.analyzeCompletion(this.
|
|
2247
|
+
const analysis = detector.analyzeCompletion(this.finalResponseText, toolsUsed);
|
|
2158
2248
|
// Record this turn with the governor (bounds the loop + detects a
|
|
2159
2249
|
// stall: the same tools/files/failure repeating with no new progress)
|
|
2160
2250
|
// and the failure registry (catches the same error recurring across
|