scream-code 0.17.9 → 0.18.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/{app-DiPC-zEu.mjs → app-BuWHcggN.mjs} +47 -7
- package/dist/{dispatch-DoaBG--u.mjs → dispatch-CUfxgLwq.mjs} +1 -1
- package/dist/{dispatch-BGYq0dnV.mjs → dispatch-DfHVLpfA.mjs} +636 -53
- package/dist/main.mjs +1 -1
- package/dist/{text-input-dialog-BlSqBYxO.mjs → text-input-dialog-CK6jTftM.mjs} +16 -2
- package/dist/{text-input-dialog-HfsxLcQf.mjs → text-input-dialog-DZoGkbYZ.mjs} +1 -1
- package/package.json +3 -3
|
@@ -5,8 +5,8 @@ const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
import { A as sharedMemoStore } from "./src-C7C9e5Ds.mjs";
|
|
8
|
-
import { $n as encodeWorkDirKey, $t as lerpGradient, A as highlightLines, An as embeddingFailureDetail, At as isTurnElapsedEnabled, B as ActivityGroupComponent, Bn as detectShellEnvironment, Bt as ENABLE_TERMINAL_THEME_REPORTING, Cn as getLlmNotSetMessage, Ct as clearInfoPanelState, D as ToolCallComponent, Dn as sortSlashCommands, Dt as createEditorTheme, E as UserMessageComponent, En as BUILTIN_SLASH_COMMANDS, Et as resolveThemeSync, F as StatusMessageComponent, Fn as PULSE_WAVE_FRAMES, Ft as detectTerminalTheme, G as AgentGroupComponent, Gn as CLI_COMMAND_NAME, Gt as QUERY_TERMINAL_THEME, H as estimateTokens, Hn as getInputHistoryFile, Ht as OSC11_RESPONSE, I as replaceTabs, In as TuiConfigParseError, It as parseOsc11BackgroundTheme, J as getBreathingFrame, Jn as PRODUCT_NAME, Jt as TERMINAL_THEME_DARK, K as WelcomeComponent, Kn as CLI_UI_MODE, Kt as TERMINAL_FOCUS_IN, L as sanitizeShellOutput, Ln as TuiLikePreferencesSchema, Lt as DISABLE_TERMINAL_FOCUS_REPORTING, M as CachedContainer, Mn as hasEmbeddingModelCache, Mt as createThemeStyles, N as ThinkingComponent, Nn as startManualEmbeddingDownload, Nt as contrastTextHex, O as renderDiffLines, On as isExperimentalFlagEnabled, Ot as createMarkdownTheme, P as NoticeMessageComponent, Pn as PIXEL_PULSE_FRAMES, Pt as getColorPalette, Q as refineGoal, Qn as ScreamHarness, Qt as FooterComponent, R as SkillActivationComponent, Rn as loadTuiConfig, Rt as DISABLE_TERMINAL_THEME_REPORTING, S as readJsonlFile, Sn as getCtrlDHint, St as supportsBalance, Tn as buildSkillSlashCommands, U as getSharedSpeedTracker, Un as getLogDir, Ut as OSC11_RESPONSE_PREFIX, V as charsForTokenBudget, Vn as getDataDir, Vt as OSC11_QUERY, W as BackgroundAgentStatusComponent, Wn as detectInstallSource, Wt as OSC11_RESPONSE_PREFIX_NO_ESC, X as CompactionComponent, Xn as fetchCatalog, Xt as isBusy, Y as resetBreathingClock, Yn as DEFAULT_CATALOG_URL, Yt as TERMINAL_THEME_LIGHT, Z as clearGoalState, Zn as saveCatalogCache, Zt as isStreaming, _n as EXIT_CONFIRM_WINDOW_MS, a as syncDiagramCapabilityPrompt, an as printableChar, ar as isRealUserPrompt, at as toTerminalHyperlink, b as readUpdateCache, bn as TIP_ROTATION_INTERVAL_MS, c as disposeChildren, cn as appendStreamingArgsPreview, cr as flushDiagnosticLogs, d as isPlanExpandable, dn as isTodoItemShape, dr as isScreamError, en as SubagentSlots, er as normalizeWorkDir, f as MoonLoader, fn as parseStreamingArgs, fr as isOrphanedToolCallError, ft as handleFusionPlanCommand, gn as EMPTY_SESSION_HINT_URL, hn as truncateErrorMessage, i as buildRoleAdditionalText, it as isInternalMessage, j as langFromPath, jn as getKnowledgeStore, jt as toggleEmptySessionHint, k as renderDiffLinesClustered, kn as setExperimentalFlags, kt as isEmptySessionHintDismissed, l as hasDispose, ln as argsRecord, lr as log, mn as stringValue, mr as SCREAM_ERROR_INFO, mt as handlePlanCommand, n as clearEvalPanelState, nr as readSessionIndex, on as STATUS_BULLET, or as parseRlmMaxDepthArg, ot as changeThinkingLevel, p as formatMemoryMemoForInjection, pn as serializeToolResultOutput, pr as ErrorCodes, q as BREATHE_CYCLE_MS, qn as CLI_USER_AGENT_PRODUCT, qt as TERMINAL_FOCUS_OUT, r as openUrl, rr as removeSessionIndexEntry, sn as appendSessionHeaderHint, sr as resolveScreamHome, st as getModelCycleLevel, t as dispatchInput, tr as appendSessionIndexEntry, u as isExpandable, un as formatErrorMessage, ur as resolveGlobalLogPath, v as selectUpdateTarget, vn as MAIN_AGENT_ID, w as getDaemonInstructions, wn as getNoActiveSessionMessage, x as appendJsonlLine, xn as getCtrlCHint, xt as refreshProviderBalance, y as refreshUpdateCache, yn as SESSION_TIPS, z as AssistantMessageComponent, zn as saveTuiConfig, zt as ENABLE_TERMINAL_FOCUS_REPORTING } from "./dispatch-
|
|
9
|
-
import { a as setLocale, i as getLocale, o as t } from "./text-input-dialog-
|
|
8
|
+
import { $n as encodeWorkDirKey, $t as lerpGradient, A as highlightLines, An as embeddingFailureDetail, At as isTurnElapsedEnabled, B as ActivityGroupComponent, Bn as detectShellEnvironment, Bt as ENABLE_TERMINAL_THEME_REPORTING, Cn as getLlmNotSetMessage, Ct as clearInfoPanelState, D as ToolCallComponent, Dn as sortSlashCommands, Dt as createEditorTheme, E as UserMessageComponent, En as BUILTIN_SLASH_COMMANDS, Et as resolveThemeSync, F as StatusMessageComponent, Fn as PULSE_WAVE_FRAMES, Ft as detectTerminalTheme, G as AgentGroupComponent, Gn as CLI_COMMAND_NAME, Gt as QUERY_TERMINAL_THEME, H as estimateTokens, Hn as getInputHistoryFile, Ht as OSC11_RESPONSE, I as replaceTabs, In as TuiConfigParseError, It as parseOsc11BackgroundTheme, J as getBreathingFrame, Jn as PRODUCT_NAME, Jt as TERMINAL_THEME_DARK, K as WelcomeComponent, Kn as CLI_UI_MODE, Kt as TERMINAL_FOCUS_IN, L as sanitizeShellOutput, Ln as TuiLikePreferencesSchema, Lt as DISABLE_TERMINAL_FOCUS_REPORTING, M as CachedContainer, Mn as hasEmbeddingModelCache, Mt as createThemeStyles, N as ThinkingComponent, Nn as startManualEmbeddingDownload, Nt as contrastTextHex, O as renderDiffLines, On as isExperimentalFlagEnabled, Ot as createMarkdownTheme, P as NoticeMessageComponent, Pn as PIXEL_PULSE_FRAMES, Pt as getColorPalette, Q as refineGoal, Qn as ScreamHarness, Qt as FooterComponent, R as SkillActivationComponent, Rn as loadTuiConfig, Rt as DISABLE_TERMINAL_THEME_REPORTING, S as readJsonlFile, Sn as getCtrlDHint, St as supportsBalance, Tn as buildSkillSlashCommands, U as getSharedSpeedTracker, Un as getLogDir, Ut as OSC11_RESPONSE_PREFIX, V as charsForTokenBudget, Vn as getDataDir, Vt as OSC11_QUERY, W as BackgroundAgentStatusComponent, Wn as detectInstallSource, Wt as OSC11_RESPONSE_PREFIX_NO_ESC, X as CompactionComponent, Xn as fetchCatalog, Xt as isBusy, Y as resetBreathingClock, Yn as DEFAULT_CATALOG_URL, Yt as TERMINAL_THEME_LIGHT, Z as clearGoalState, Zn as saveCatalogCache, Zt as isStreaming, _n as EXIT_CONFIRM_WINDOW_MS, a as syncDiagramCapabilityPrompt, an as printableChar, ar as isRealUserPrompt, at as toTerminalHyperlink, b as readUpdateCache, bn as TIP_ROTATION_INTERVAL_MS, c as disposeChildren, cn as appendStreamingArgsPreview, cr as flushDiagnosticLogs, d as isPlanExpandable, dn as isTodoItemShape, dr as isScreamError, en as SubagentSlots, er as normalizeWorkDir, f as MoonLoader, fn as parseStreamingArgs, fr as isOrphanedToolCallError, ft as handleFusionPlanCommand, gn as EMPTY_SESSION_HINT_URL, hn as truncateErrorMessage, i as buildRoleAdditionalText, it as isInternalMessage, j as langFromPath, jn as getKnowledgeStore, jt as toggleEmptySessionHint, k as renderDiffLinesClustered, kn as setExperimentalFlags, kt as isEmptySessionHintDismissed, l as hasDispose, ln as argsRecord, lr as log, mn as stringValue, mr as SCREAM_ERROR_INFO, mt as handlePlanCommand, n as clearEvalPanelState, nr as readSessionIndex, on as STATUS_BULLET, or as parseRlmMaxDepthArg, ot as changeThinkingLevel, p as formatMemoryMemoForInjection, pn as serializeToolResultOutput, pr as ErrorCodes, q as BREATHE_CYCLE_MS, qn as CLI_USER_AGENT_PRODUCT, qt as TERMINAL_FOCUS_OUT, r as openUrl, rr as removeSessionIndexEntry, sn as appendSessionHeaderHint, sr as resolveScreamHome, st as getModelCycleLevel, t as dispatchInput, tr as appendSessionIndexEntry, u as isExpandable, un as formatErrorMessage, ur as resolveGlobalLogPath, v as selectUpdateTarget, vn as MAIN_AGENT_ID, w as getDaemonInstructions, wn as getNoActiveSessionMessage, x as appendJsonlLine, xn as getCtrlCHint, xt as refreshProviderBalance, y as refreshUpdateCache, yn as SESSION_TIPS, z as AssistantMessageComponent, zn as saveTuiConfig, zt as ENABLE_TERMINAL_FOCUS_REPORTING } from "./dispatch-DfHVLpfA.mjs";
|
|
9
|
+
import { a as setLocale, i as getLocale, o as t } from "./text-input-dialog-CK6jTftM.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
|
|
12
12
|
import { access, appendFile, chmod, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -33,7 +33,7 @@ function optionalBuildString(value) {
|
|
|
33
33
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
34
34
|
}
|
|
35
35
|
const SCREAM_BUILD_INFO = {
|
|
36
|
-
version: optionalBuildString("0.
|
|
36
|
+
version: optionalBuildString("0.18.0"),
|
|
37
37
|
channel: optionalBuildString(""),
|
|
38
38
|
commit: optionalBuildString(""),
|
|
39
39
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -4206,6 +4206,7 @@ var SessionReplayRenderer = class {
|
|
|
4206
4206
|
this.host = host;
|
|
4207
4207
|
}
|
|
4208
4208
|
async hydrateFromReplay(session) {
|
|
4209
|
+
this.host.state.ui.resetTextSelection();
|
|
4209
4210
|
this.host.setAppState({ isReplaying: true });
|
|
4210
4211
|
try {
|
|
4211
4212
|
const main = session.getResumeState()?.agents["main"];
|
|
@@ -6720,6 +6721,7 @@ var TasksBrowserController = class {
|
|
|
6720
6721
|
}
|
|
6721
6722
|
const current = state.tasksBrowser;
|
|
6722
6723
|
if (current === void 0 || current !== browser) return;
|
|
6724
|
+
if (current.viewer !== void 0) return;
|
|
6723
6725
|
const viewer = new TaskOutputViewer({
|
|
6724
6726
|
taskId,
|
|
6725
6727
|
info: this.host.backgroundTasks.get(taskId),
|
|
@@ -6729,7 +6731,7 @@ var TasksBrowserController = class {
|
|
|
6729
6731
|
this.closeOutputViewer();
|
|
6730
6732
|
}
|
|
6731
6733
|
}, state.terminal);
|
|
6732
|
-
const savedBrowserLayout =
|
|
6734
|
+
const savedBrowserLayout = browser.component;
|
|
6733
6735
|
state.ui.setLayoutRoot(viewer);
|
|
6734
6736
|
state.ui.setFocus(viewer);
|
|
6735
6737
|
state.ui.requestRender(true);
|
|
@@ -7211,6 +7213,7 @@ var TranscriptController = class TranscriptController {
|
|
|
7211
7213
|
this.dropLiveComponent(component);
|
|
7212
7214
|
}
|
|
7213
7215
|
this.committedComponent.setCount(this.committedComponent.getCount() + toCommit.length);
|
|
7216
|
+
state.ui.resetTextSelection();
|
|
7214
7217
|
if (process.env["SCREAM_CODE_DEBUG"] === "1") this.host.showStatus(`[debug] committed=${this.committedComponent.getCount()} live=${this.getLiveCount()}`);
|
|
7215
7218
|
container.invalidate();
|
|
7216
7219
|
state.ui.requestRender();
|
|
@@ -7385,6 +7388,7 @@ var TranscriptController = class TranscriptController {
|
|
|
7385
7388
|
}
|
|
7386
7389
|
clearAndRedraw() {
|
|
7387
7390
|
const { state, streamingUI, imageStore } = this.host;
|
|
7391
|
+
state.ui.resetTextSelection();
|
|
7388
7392
|
streamingUI.discardPending();
|
|
7389
7393
|
streamingUI.endActivityGroup();
|
|
7390
7394
|
streamingUI.flushPendingApprovals();
|
|
@@ -7449,12 +7453,17 @@ var TranscriptController = class TranscriptController {
|
|
|
7449
7453
|
const { state } = this.host;
|
|
7450
7454
|
const next = !state.toolOutputExpanded;
|
|
7451
7455
|
const children = state.transcriptContainer.children;
|
|
7456
|
+
let resized = false;
|
|
7452
7457
|
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
7453
7458
|
const child = children[i];
|
|
7454
7459
|
if (child === void 0) continue;
|
|
7455
7460
|
if (child instanceof UserMessageComponent || child instanceof SkillActivationComponent || child instanceof CronMessageComponent || child instanceof CommittedTranscriptComponent) break;
|
|
7456
|
-
if (isExpandable(child))
|
|
7461
|
+
if (isExpandable(child)) {
|
|
7462
|
+
child.setExpanded(next);
|
|
7463
|
+
resized = true;
|
|
7464
|
+
}
|
|
7457
7465
|
}
|
|
7466
|
+
if (resized) state.ui.resetTextSelection();
|
|
7458
7467
|
state.toolOutputExpanded = next;
|
|
7459
7468
|
state.ui.requestRender();
|
|
7460
7469
|
}
|
|
@@ -7464,6 +7473,7 @@ var TranscriptController = class TranscriptController {
|
|
|
7464
7473
|
let toggled = false;
|
|
7465
7474
|
for (const child of state.transcriptContainer.children) if (isPlanExpandable(child) && child.setPlanExpanded(next)) toggled = true;
|
|
7466
7475
|
if (!toggled) return false;
|
|
7476
|
+
state.ui.resetTextSelection();
|
|
7467
7477
|
state.planExpanded = next;
|
|
7468
7478
|
state.ui.requestRender();
|
|
7469
7479
|
return true;
|
|
@@ -10935,6 +10945,7 @@ var CustomEditor = class extends Editor {
|
|
|
10935
10945
|
thinkingLevel: this.thinkingLevel,
|
|
10936
10946
|
toolPriority: this.toolPriority,
|
|
10937
10947
|
paint: this.borderColor ?? ((s) => s),
|
|
10948
|
+
modeHex: getPermissionModeColor(this.permissionMode, this.colors),
|
|
10938
10949
|
borderHex: this.borderHex
|
|
10939
10950
|
});
|
|
10940
10951
|
return lines;
|
|
@@ -11085,6 +11096,15 @@ function injectPromptSymbol(line) {
|
|
|
11085
11096
|
}
|
|
11086
11097
|
const THINK_LABEL_MIN_WIDTH = 14;
|
|
11087
11098
|
const MODE_BADGE_MIN_WIDTH = 10;
|
|
11099
|
+
function getPermissionModeColor(mode, colors) {
|
|
11100
|
+
return {
|
|
11101
|
+
manual: colors.permissionManual,
|
|
11102
|
+
yolo: colors.permissionYolo,
|
|
11103
|
+
auto: colors.permissionAuto,
|
|
11104
|
+
ask: colors.permissionAsk,
|
|
11105
|
+
bot: colors.permissionBot
|
|
11106
|
+
}[mode];
|
|
11107
|
+
}
|
|
11088
11108
|
function isLightBg(hex) {
|
|
11089
11109
|
const r = parseInt(hex.slice(1, 3), 16);
|
|
11090
11110
|
const g = parseInt(hex.slice(3, 5), 16);
|
|
@@ -11115,7 +11135,7 @@ function injectBorderBadges(lines, width, opts) {
|
|
|
11115
11135
|
let right = paint("─");
|
|
11116
11136
|
if (width >= MODE_BADGE_MIN_WIDTH) {
|
|
11117
11137
|
const badgeText = ` ${opts.mode} `;
|
|
11118
|
-
left = paint("──") +
|
|
11138
|
+
left = paint("──") + chalk.hex(opts.modeHex).bold(badgeText);
|
|
11119
11139
|
}
|
|
11120
11140
|
if (opts.thinking && width >= THINK_LABEL_MIN_WIDTH) right = makeBadge(opts.thinkingLevel !== "off" ? ` Think ${opts.thinkingLevel} ` : " Think ", opts.borderHex) + right;
|
|
11121
11141
|
if (opts.toolPriority === "skill" || opts.toolPriority === "mcp") right = makeBadge(` First ${opts.toolPriority} `, opts.borderHex) + paint("─") + right;
|
|
@@ -12693,6 +12713,10 @@ const DEFAULT_KEYBOARD_SHORTCUTS = [
|
|
|
12693
12713
|
keys: "Shift-Tab",
|
|
12694
12714
|
description: t("help.toggle_plan")
|
|
12695
12715
|
},
|
|
12716
|
+
{
|
|
12717
|
+
keys: "Tab",
|
|
12718
|
+
description: t("help.cycle_thinking")
|
|
12719
|
+
},
|
|
12696
12720
|
{
|
|
12697
12721
|
keys: "Ctrl-G",
|
|
12698
12722
|
description: t("help.external_editor")
|
|
@@ -12701,10 +12725,26 @@ const DEFAULT_KEYBOARD_SHORTCUTS = [
|
|
|
12701
12725
|
keys: "Ctrl-O",
|
|
12702
12726
|
description: t("help.toggle_output")
|
|
12703
12727
|
},
|
|
12728
|
+
{
|
|
12729
|
+
keys: "Ctrl-E",
|
|
12730
|
+
description: t("help.toggle_plan_view")
|
|
12731
|
+
},
|
|
12704
12732
|
{
|
|
12705
12733
|
keys: "Ctrl-S",
|
|
12706
12734
|
description: t("help.interrupt")
|
|
12707
12735
|
},
|
|
12736
|
+
{
|
|
12737
|
+
keys: "Ctrl-X",
|
|
12738
|
+
description: t("help.toggle_sidebar")
|
|
12739
|
+
},
|
|
12740
|
+
{
|
|
12741
|
+
keys: "Ctrl-B",
|
|
12742
|
+
description: t("help.toggle_hint")
|
|
12743
|
+
},
|
|
12744
|
+
{
|
|
12745
|
+
keys: "Ctrl-W",
|
|
12746
|
+
description: t("help.cancel_memory")
|
|
12747
|
+
},
|
|
12708
12748
|
{
|
|
12709
12749
|
keys: "Shift-Enter / Ctrl-J",
|
|
12710
12750
|
description: t("help.newline")
|
|
@@ -14930,7 +14970,7 @@ var ScreamTUI = class {
|
|
|
14930
14970
|
const card = new OnboardingCardComponent({
|
|
14931
14971
|
colors: this.state.theme.colors,
|
|
14932
14972
|
onConfigure: () => {
|
|
14933
|
-
import("./dispatch-
|
|
14973
|
+
import("./dispatch-CUfxgLwq.mjs").then(({ handleConnectCommand }) => handleConnectCommand(this, "")).finally(() => {
|
|
14934
14974
|
this.restoreEditor();
|
|
14935
14975
|
onDone?.();
|
|
14936
14976
|
});
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { rn as handleConnectCommand } from "./dispatch-
|
|
6
|
+
import { rn as handleConnectCommand } from "./dispatch-DfHVLpfA.mjs";
|
|
7
7
|
export { handleConnectCommand };
|
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
|
|
7
7
|
import { A as sharedMemoStore, B as buildProjectTagCloud, C as applyConsolidation, D as parseMemoryMemos, E as buildExitExtractionPrompt, F as probeLocalEmbeddingSupport, G as join$1, H as basename$1, I as createMemoryMemo, J as relative$1, K as normalize, L as toSummary, M as clearEmbeddingModelCache, N as createFastEmbedEngine, O as stripMemoryTags, P as hasEmbeddingModelCache$1, R as generateTags, S as DreamTracker, T as EXIT_EXTRACTION_SYSTEM_PROMPT, U as dirname$2, V as rankMemos, W as isAbsolute$1, Y as resolve$2, a as isSupportedFile, b as sharedKnowledgeStoreReady, i as ingestFile, j as classifyEmbeddingFailure, k as MemoryMemoStore, q as parse$7, r as ingestDirectory, t as multiSearch, w as buildConsolidationPlan, y as sharedKnowledgeStore, z as normalizeTags } from "./src-C7C9e5Ds.mjs";
|
|
8
8
|
import { n as require_base64_js, t as XMLParser } from "./XMLParser-DFAnGqkc.mjs";
|
|
9
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-CK6jTftM.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -784,9 +784,28 @@ var APIEmptyResponseError = class extends ChatProviderError {
|
|
|
784
784
|
this.name = "APIEmptyResponseError";
|
|
785
785
|
}
|
|
786
786
|
};
|
|
787
|
+
/**
|
|
788
|
+
* The provider ended its stream with an in-band failure signal instead of
|
|
789
|
+
* throwing (`finish_reason: "error"` — Mistral-style Chat Completions
|
|
790
|
+
* endpoints). Normalized without a typed class this looked like an "unknown"
|
|
791
|
+
* stop and ended the turn silently: no retry, no error surfaced. Typed here so
|
|
792
|
+
* {@link isRetryableGenerateError} classifies it without message sniffing —
|
|
793
|
+
* the upstream generation broke, the request itself is fine, so the step is
|
|
794
|
+
* worth retrying.
|
|
795
|
+
*/
|
|
796
|
+
var APIFinishReasonError = class extends ChatProviderError {
|
|
797
|
+
/** Raw provider finish reason, preserved verbatim (`"error"`). */
|
|
798
|
+
rawFinishReason;
|
|
799
|
+
constructor(message, rawFinishReason) {
|
|
800
|
+
super(message);
|
|
801
|
+
this.name = "APIFinishReasonError";
|
|
802
|
+
this.rawFinishReason = rawFinishReason;
|
|
803
|
+
}
|
|
804
|
+
};
|
|
787
805
|
function isRetryableGenerateError(error) {
|
|
788
806
|
if (error instanceof APIConnectionError$3 || error instanceof APITimeoutError) return true;
|
|
789
807
|
if (error instanceof APIEmptyResponseError) return true;
|
|
808
|
+
if (error instanceof APIFinishReasonError) return true;
|
|
790
809
|
if (error instanceof APIProviderRateLimitError) return true;
|
|
791
810
|
if (error instanceof APIStatusError) return error.statusCode === 429 || error.statusCode === 408 || error.statusCode >= 500 && error.statusCode < 600;
|
|
792
811
|
if (error instanceof ChatProviderError) return isRetryableProviderMessage(error.message);
|
|
@@ -823,7 +842,9 @@ const RETRYABLE_PROVIDER_MESSAGE_PATTERNS = [
|
|
|
823
842
|
/stream ended|ended without/i,
|
|
824
843
|
/you can retry your request/i,
|
|
825
844
|
/try your request again/i,
|
|
826
|
-
/please retry your request/i
|
|
845
|
+
/please retry your request/i,
|
|
846
|
+
/\bserver[\s_-]+busy\b/i,
|
|
847
|
+
/\bservers?\s+(?:are|is)\s+(?:currently\s+)?busy\b/i
|
|
827
848
|
];
|
|
828
849
|
/**
|
|
829
850
|
* Classify a status-less provider error message. Quota/billing-style wording
|
|
@@ -44674,6 +44695,29 @@ function normalizeOpenAIFinishReason(raw) {
|
|
|
44674
44695
|
}
|
|
44675
44696
|
}
|
|
44676
44697
|
/**
|
|
44698
|
+
* Raise a retryable {@link APIFinishReasonError} when a provider signalled an
|
|
44699
|
+
* in-band stream failure through its terminal finish reason instead of
|
|
44700
|
+
* throwing.
|
|
44701
|
+
*
|
|
44702
|
+
* Mistral-style Chat Completions endpoints end a broken generation with
|
|
44703
|
+
* `finish_reason: "error"`. Normalizing that to `'other'` used to end the turn
|
|
44704
|
+
* silently (no retry, no error shown). Throwing here — from the adapter's
|
|
44705
|
+
* finish-reason capture, i.e. while `generate()` drains the stream — routes the
|
|
44706
|
+
* failure out of `provider.generate()`/`generate()` and into the engine's step
|
|
44707
|
+
* retry (`chatWithRetry` → `LLM.isRetryableError` → `isRetryableGenerateError`),
|
|
44708
|
+
* so the step is retried and, once the retry budget is exhausted, fails loudly
|
|
44709
|
+
* instead of ending the turn.
|
|
44710
|
+
*
|
|
44711
|
+
* The raw value is preserved twice: on the thrown error
|
|
44712
|
+
* ({@link APIFinishReasonError.rawFinishReason}) and — because capture happens
|
|
44713
|
+
* before the throw — on the streamed message's `rawFinishReason` for callers
|
|
44714
|
+
* that still hold it.
|
|
44715
|
+
*/
|
|
44716
|
+
function throwIfErrorFinishReason(rawFinishReason, providerLabel) {
|
|
44717
|
+
if (rawFinishReason === null || rawFinishReason.trim().toLowerCase() !== "error") return;
|
|
44718
|
+
throw new APIFinishReasonError(`Provider stream ended with finish_reason "${rawFinishReason}": the provider reported an in-band generation failure instead of a normal stop. Provider: ${providerLabel}. The request itself is unchanged, so retrying it may succeed.`, rawFinishReason);
|
|
44719
|
+
}
|
|
44720
|
+
/**
|
|
44677
44721
|
* Convert tool-role message content according to the chosen strategy.
|
|
44678
44722
|
*/
|
|
44679
44723
|
function convertToolMessageContent(message, conversion) {
|
|
@@ -44959,6 +45003,7 @@ var ScreamStreamedMessage = class {
|
|
|
44959
45003
|
const normalized = normalizeOpenAIFinishReason(raw);
|
|
44960
45004
|
this._finishReason = normalized.finishReason;
|
|
44961
45005
|
this._rawFinishReason = normalized.rawFinishReason;
|
|
45006
|
+
throwIfErrorFinishReason(normalized.rawFinishReason, "ScreamChatProvider");
|
|
44962
45007
|
}
|
|
44963
45008
|
async *_convertNonStreamResponse(response) {
|
|
44964
45009
|
this._id = response.id;
|
|
@@ -45269,6 +45314,7 @@ var OpenAILegacyStreamedMessage = class {
|
|
|
45269
45314
|
const normalized = normalizeOpenAIFinishReason(raw);
|
|
45270
45315
|
this._finishReason = normalized.finishReason;
|
|
45271
45316
|
this._rawFinishReason = normalized.rawFinishReason;
|
|
45317
|
+
throwIfErrorFinishReason(normalized.rawFinishReason, "OpenAILegacyChatProvider");
|
|
45272
45318
|
}
|
|
45273
45319
|
async *_convertNonStreamResponse(response, reasoningKey) {
|
|
45274
45320
|
this._id = response.id;
|
|
@@ -55613,6 +55659,17 @@ const MAX_OUTPUT_BYTES$1 = 1024 * 1024;
|
|
|
55613
55659
|
* finished tasks, FIFO-overflowing so long sessions stay bounded.
|
|
55614
55660
|
*/
|
|
55615
55661
|
const RETIRED_TASK_LIMIT = 20;
|
|
55662
|
+
/**
|
|
55663
|
+
* Pre-cut bytes the bounded window read (`readOutput`) keeps as context for
|
|
55664
|
+
* `tailSlice`'s boundary rules, on top of the last `tail` code units it must
|
|
55665
|
+
* return. The rules inspect the text before the cut (the nearest ESC, a CSI
|
|
55666
|
+
* body run, a string-sequence opener), so a window starting exactly at the cut
|
|
55667
|
+
* would decide differently from the whole-file read in `getOutput`. Control
|
|
55668
|
+
* sequences in task output sit far closer to the cut than this margin; one
|
|
55669
|
+
* opened farther back is invisible to the window and is not worth paging the
|
|
55670
|
+
* rest of a multi-megabyte log for.
|
|
55671
|
+
*/
|
|
55672
|
+
const TAIL_WINDOW_LOOKBACK_BYTES = 4096;
|
|
55616
55673
|
const SIGTERM_GRACE_MS$2 = 5e3;
|
|
55617
55674
|
const EXIT_SETTLE_GRACE_MS = 10;
|
|
55618
55675
|
const _ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
@@ -55947,7 +56004,7 @@ var BackgroundProcessManager = class {
|
|
|
55947
56004
|
const entry = this.processes.get(taskId);
|
|
55948
56005
|
if (entry) {
|
|
55949
56006
|
const full = entry.outputChunks.join("");
|
|
55950
|
-
if (tail !== void 0 && tail < full.length) return full
|
|
56007
|
+
if (tail !== void 0 && tail < full.length) return tailSlice(full, tail);
|
|
55951
56008
|
return full;
|
|
55952
56009
|
}
|
|
55953
56010
|
const retired = this.retiredTasks.get(taskId);
|
|
@@ -55957,7 +56014,7 @@ var BackgroundProcessManager = class {
|
|
|
55957
56014
|
const persisted = readFileSync(taskOutputFile(retired.outputSessionDir, taskId), "utf-8");
|
|
55958
56015
|
if (persisted.length > 0) full = persisted;
|
|
55959
56016
|
} catch {}
|
|
55960
|
-
if (tail !== void 0 && tail < full.length) return full
|
|
56017
|
+
if (tail !== void 0 && tail < full.length) return tailSlice(full, tail);
|
|
55961
56018
|
return full;
|
|
55962
56019
|
}
|
|
55963
56020
|
async readOutput(taskId, tail) {
|
|
@@ -55968,7 +56025,7 @@ var BackgroundProcessManager = class {
|
|
|
55968
56025
|
if (tail !== void 0 && tail > 0) {
|
|
55969
56026
|
const size = await taskOutputSizeBytes(outputSessionDir, taskId);
|
|
55970
56027
|
if (size > 0) {
|
|
55971
|
-
const windowBytes = Math.min(size, tail * 4 + 7);
|
|
56028
|
+
const windowBytes = Math.min(size, tail * 4 + 7 + TAIL_WINDOW_LOOKBACK_BYTES);
|
|
55972
56029
|
const start = size - windowBytes;
|
|
55973
56030
|
let persisted = await readTaskOutputBytes(outputSessionDir, taskId, start, windowBytes);
|
|
55974
56031
|
if (persisted.length > 0) {
|
|
@@ -55977,13 +56034,13 @@ var BackgroundProcessManager = class {
|
|
|
55977
56034
|
while (lead < persisted.length && persisted.codePointAt(lead) === 65533 && lead < 3) lead += 1;
|
|
55978
56035
|
if (lead > 0) persisted = persisted.slice(lead);
|
|
55979
56036
|
}
|
|
55980
|
-
return tail < persisted.length ? persisted
|
|
56037
|
+
return tail < persisted.length ? tailSlice(persisted, tail) : persisted;
|
|
55981
56038
|
}
|
|
55982
56039
|
return this.getOutput(taskId, tail);
|
|
55983
56040
|
}
|
|
55984
56041
|
} else {
|
|
55985
56042
|
const persisted = await readTaskOutput(outputSessionDir, taskId);
|
|
55986
|
-
if (persisted.length > 0) return tail !== void 0 && tail < persisted.length ? persisted
|
|
56043
|
+
if (persisted.length > 0) return tail !== void 0 && tail < persisted.length ? tailSlice(persisted, tail) : persisted;
|
|
55987
56044
|
}
|
|
55988
56045
|
}
|
|
55989
56046
|
return this.getOutput(taskId, tail);
|
|
@@ -56462,6 +56519,243 @@ var BackgroundProcessManager = class {
|
|
|
56462
56519
|
return true;
|
|
56463
56520
|
}
|
|
56464
56521
|
};
|
|
56522
|
+
const ESC$2 = "\x1B";
|
|
56523
|
+
/**
|
|
56524
|
+
* Largest share of a retained tail the boundary rules may discard.
|
|
56525
|
+
*
|
|
56526
|
+
* Both rules trade content for a head that is whole by construction: rule 1
|
|
56527
|
+
* restarts after the next `\n` and drops the torn line, and rule 2 skips the
|
|
56528
|
+
* remainder of a torn sequence. The trade only pays while the tail keeps a
|
|
56529
|
+
* (non-strict) majority — with one 5000-char line ahead, a 100-unit budget
|
|
56530
|
+
* would come back with the few units after it, and the caller asked for the
|
|
56531
|
+
* newest output, not for a tidy head. Past the bound the raw cut keeps the
|
|
56532
|
+
* content: a string payload stays visible, and a torn CSI or two-byte escape
|
|
56533
|
+
* run keeps the fragment it left in view, because skipping that remainder
|
|
56534
|
+
* would cost more than the fragment it hides — unless the introducer ESC sits
|
|
56535
|
+
* immediately before the head *and* the sequence provably closes, where one
|
|
56536
|
+
* unit of look-back keeps the sequence whole and the fragment never surfaces.
|
|
56537
|
+
* An unclosed run keeps the raw cut: with no terminator to hand the sanitizer,
|
|
56538
|
+
* backing onto its ESC would surface a bare ESC the sanitizer cannot strip.
|
|
56539
|
+
*/
|
|
56540
|
+
const MAX_TAIL_DROP_SHARE$1 = .5;
|
|
56541
|
+
/**
|
|
56542
|
+
* `text.slice(-tail)` (clamping exactly like `slice` does for `tail` outside
|
|
56543
|
+
* `(0, text.length)`), with the head moved to a boundary no ANSI escape
|
|
56544
|
+
* sequence spans, so the first bytes a reader sees are never a torn fragment.
|
|
56545
|
+
*/
|
|
56546
|
+
function tailSlice(text, tail) {
|
|
56547
|
+
if (tail <= 0 || tail >= text.length) return text;
|
|
56548
|
+
return text.slice(safeTailStart$1(text, text.length - tail));
|
|
56549
|
+
}
|
|
56550
|
+
/**
|
|
56551
|
+
* Move a tail cut point forward to a boundary no ANSI escape sequence spans.
|
|
56552
|
+
*
|
|
56553
|
+
* A raw `slice(-tail)` can land inside a sequence (`…\u001b[31|m…`), leaving a
|
|
56554
|
+
* fragment (`m`, `0m`, `[31`) whose ESC byte was cut away — the TUI sanitizer
|
|
56555
|
+
* only recognizes complete sequences, so the fragment renders as text. Two
|
|
56556
|
+
* provable rules keep the head clean:
|
|
56557
|
+
*
|
|
56558
|
+
* 1. Line alignment: a CSI sequence cannot contain `\n` (LF is not a
|
|
56559
|
+
* parameter, intermediate or final byte), so a cut that lands mid-line
|
|
56560
|
+
* restarts after the next `\n`. The only loss is the torn partial line,
|
|
56561
|
+
* whose head cannot be trusted; every escape after the newline is whole.
|
|
56562
|
+
* Bounded by `MAX_TAIL_DROP_SHARE`, so one huge line cannot eat the budget.
|
|
56563
|
+
* 2. Torn-sequence skip: when the retained text is one line (no `\n` after
|
|
56564
|
+
* the cut), or an OSC/DCS/PM/APC payload spans the newline the cut aligned
|
|
56565
|
+
* to, the dropped prefix is inspected for a sequence still open at the cut
|
|
56566
|
+
* — a run of CSI body bytes (0x20–0x3F) reaching back to `ESC [`, an `ESC`
|
|
56567
|
+
* whose intermediate bytes were torn (`ESC ( B`), or a string-sequence
|
|
56568
|
+
* opener the cut landed inside. The head then skips exactly the bytes a
|
|
56569
|
+
* terminal would consume for that sequence, so no visible text is dropped —
|
|
56570
|
+
* but only while that skip stays within `MAX_TAIL_DROP_SHARE` of the tail.
|
|
56571
|
+
* A CSI body or escape-intermediate run can be arbitrarily long, so past
|
|
56572
|
+
* the bound the head keeps the newest bytes and the fragment the raw cut
|
|
56573
|
+
* left with them — or one unit earlier, onto an introducer ESC sitting
|
|
56574
|
+
* immediately before the head, so the whole sequence survives and is
|
|
56575
|
+
* stripped (`withinDropShare`) — but only when the skip proved the sequence
|
|
56576
|
+
* closed: an unclosed run keeps the raw cut, because with no terminator to
|
|
56577
|
+
* hand the sanitizer the ESC would surface bare and swallow what follows
|
|
56578
|
+
* it. So does the head for a string that never ends or ended ahead of the
|
|
56579
|
+
* cut. A sliver of the tail is worse than a fragment.
|
|
56580
|
+
*
|
|
56581
|
+
* The result never splits a surrogate pair, and a non-empty input never comes
|
|
56582
|
+
* back empty: the head is never below `cut` (a tail never grows) except in two
|
|
56583
|
+
* cases — the cut splits a trailing pair, where dropping the orphan half would
|
|
56584
|
+
* empty the tail, so the head backs onto the pair's first half and the last
|
|
56585
|
+
* character survives; and a torn sequence's introducer ESC sits immediately
|
|
56586
|
+
* before the head *and* the sequence's skip proved it closes, where backing
|
|
56587
|
+
* one unit onto it keeps the sequence whole and the fragment is stripped
|
|
56588
|
+
* instead of surfaced. An unclosed skip takes the raw cut.
|
|
56589
|
+
*/
|
|
56590
|
+
function safeTailStart$1(text, cut) {
|
|
56591
|
+
if (cut <= 0 || cut >= text.length) return cut;
|
|
56592
|
+
const tail = text.length - cut;
|
|
56593
|
+
let start = cut;
|
|
56594
|
+
if (text[start - 1] !== "\n") {
|
|
56595
|
+
const newline = text.indexOf("\n", start);
|
|
56596
|
+
if (newline !== -1 && newline + 1 - cut <= tail * MAX_TAIL_DROP_SHARE$1) start = newline + 1;
|
|
56597
|
+
}
|
|
56598
|
+
start = skipOpenEscape$1(text, start);
|
|
56599
|
+
const head = text.codePointAt(start);
|
|
56600
|
+
if (head !== void 0 && head >= 56320 && head <= 57343) return start + 1 < text.length ? start + 1 : start - 1;
|
|
56601
|
+
return start;
|
|
56602
|
+
}
|
|
56603
|
+
/** CSI parameter (0x30–0x3F) / intermediate (0x20–0x2F) bytes — everything before the final byte. */
|
|
56604
|
+
function isCsiBody$1(code) {
|
|
56605
|
+
return code !== void 0 && code >= 32 && code <= 63;
|
|
56606
|
+
}
|
|
56607
|
+
/** CSI final byte (0x40–0x7E) — the sequence ends here. */
|
|
56608
|
+
function isCsiFinal$1(code) {
|
|
56609
|
+
return code !== void 0 && code >= 64 && code <= 126;
|
|
56610
|
+
}
|
|
56611
|
+
/** OSC / DCS / PM / APC introducers — string sequences ended by BEL or ST. */
|
|
56612
|
+
function isStringIntro$1(intro) {
|
|
56613
|
+
return intro === "]" || intro === "P" || intro === "^" || intro === "_";
|
|
56614
|
+
}
|
|
56615
|
+
/** ESC-intermediate byte (0x20–0x2F) of a two-byte escape sequence. */
|
|
56616
|
+
function isEscapeIntermediate$1(code) {
|
|
56617
|
+
return code !== void 0 && code >= 32 && code <= 47;
|
|
56618
|
+
}
|
|
56619
|
+
/** Final byte (0x30–0x7E) that closes a two-byte escape sequence. */
|
|
56620
|
+
function isEscapeFinal$1(code) {
|
|
56621
|
+
return code !== void 0 && code >= 48 && code <= 126;
|
|
56622
|
+
}
|
|
56623
|
+
/** True when every code point in the half-open range `[from, to)` is an ESC intermediate (0x20–0x2F). */
|
|
56624
|
+
function allEscapeIntermediates$1(text, from, to) {
|
|
56625
|
+
for (let i = from; i < to; i += 1) if (!isEscapeIntermediate$1(text.codePointAt(i))) return false;
|
|
56626
|
+
return true;
|
|
56627
|
+
}
|
|
56628
|
+
/**
|
|
56629
|
+
* When the dropped prefix proves an escape sequence is still open at `cut`,
|
|
56630
|
+
* return the index after its remainder; otherwise return `cut` unchanged.
|
|
56631
|
+
*/
|
|
56632
|
+
function skipOpenEscape$1(text, cut) {
|
|
56633
|
+
let run = cut;
|
|
56634
|
+
while (run > 0 && isCsiBody$1(text.codePointAt(run - 1))) run -= 1;
|
|
56635
|
+
if (run >= 2 && text[run - 1] === "[" && text[run - 2] === ESC$2) {
|
|
56636
|
+
const skip = skipCsiRest$1(text, cut);
|
|
56637
|
+
return withinDropShare$1(text, cut, skip.end, skip.closed);
|
|
56638
|
+
}
|
|
56639
|
+
if (text[run - 1] === ESC$2 && allEscapeIntermediates$1(text, run, cut)) return skipEscapeRest$1(text, cut);
|
|
56640
|
+
const open = text.lastIndexOf(ESC$2, cut - 1);
|
|
56641
|
+
if (open !== -1 && isStringIntro$1(text[open + 1])) return stringSequenceHead$1(text, open, cut);
|
|
56642
|
+
return cut;
|
|
56643
|
+
}
|
|
56644
|
+
/**
|
|
56645
|
+
* Keep a provable skip only while it stays within `MAX_TAIL_DROP_SHARE` of the
|
|
56646
|
+
* tail that starts at `from`: the skipped bytes are exactly what the reader
|
|
56647
|
+
* loses from the tail it asked for. A CSI body or escape-intermediate run can
|
|
56648
|
+
* be arbitrarily long, so past the bound the raw cut is worth more than the
|
|
56649
|
+
* clean head — except when the sequence's introducer ESC sits immediately
|
|
56650
|
+
* before the head (`…\u001b|[31m…`) *and* `closed` says the skip found the
|
|
56651
|
+
* sequence's terminator, where one unit of look-back keeps the sequence whole
|
|
56652
|
+
* instead: the sanitizer strips it and the visible text is the skip's, for
|
|
56653
|
+
* that one unit rather than a sliver of the tail. An unclosed run must keep
|
|
56654
|
+
* the raw cut even with that ESC one unit ahead: nothing terminates it, so
|
|
56655
|
+
* look-back would hand the reader a bare ESC whose sequence run a terminal
|
|
56656
|
+
* swallows along with the bytes behind it.
|
|
56657
|
+
*/
|
|
56658
|
+
function withinDropShare$1(text, from, target, closed) {
|
|
56659
|
+
if (target - from <= (text.length - from) * MAX_TAIL_DROP_SHARE$1) return target;
|
|
56660
|
+
return closed && from > 0 && text[from - 1] === ESC$2 ? from - 1 : from;
|
|
56661
|
+
}
|
|
56662
|
+
/**
|
|
56663
|
+
* The rest of a CSI sequence whose body was torn at `cut`, with the closure
|
|
56664
|
+
* its skip proved: `closed` holds only when a final byte (0x40–0x7E) was
|
|
56665
|
+
* actually found, so a parameter run that reaches the end of `text` — or stops
|
|
56666
|
+
* on a byte no CSI can end with — reports the sequence as open.
|
|
56667
|
+
*/
|
|
56668
|
+
function skipCsiRest$1(text, cut) {
|
|
56669
|
+
let end = cut;
|
|
56670
|
+
while (end < text.length && isCsiBody$1(text.codePointAt(end))) end += 1;
|
|
56671
|
+
const closed = end < text.length && isCsiFinal$1(text.codePointAt(end));
|
|
56672
|
+
return {
|
|
56673
|
+
end: closed ? end + 1 : end,
|
|
56674
|
+
closed
|
|
56675
|
+
};
|
|
56676
|
+
}
|
|
56677
|
+
/** Index after the escape sequence whose introducer ESC sits at `cut - 1`. */
|
|
56678
|
+
function skipEscapeRest$1(text, cut) {
|
|
56679
|
+
const intro = text[cut];
|
|
56680
|
+
if (intro === "[") {
|
|
56681
|
+
const skip = skipCsiRest$1(text, cut + 1);
|
|
56682
|
+
return withinDropShare$1(text, cut, skip.end, skip.closed);
|
|
56683
|
+
}
|
|
56684
|
+
if (isStringIntro$1(intro)) return stringSequenceHead$1(text, cut - 1, cut + 1);
|
|
56685
|
+
let end = cut;
|
|
56686
|
+
while (end < text.length && isEscapeIntermediate$1(text.codePointAt(end))) end += 1;
|
|
56687
|
+
const closed = end < text.length && isEscapeFinal$1(text.codePointAt(end));
|
|
56688
|
+
return withinDropShare$1(text, cut, closed ? end + 1 : end, closed);
|
|
56689
|
+
}
|
|
56690
|
+
/**
|
|
56691
|
+
* Head index for a cut that lands inside the string sequence opened at `open`.
|
|
56692
|
+
*
|
|
56693
|
+
* `stringEnd` gives the byte a terminal stops at; skipping to it hides the
|
|
56694
|
+
* payload's remainder, which is what a terminal shows — but only while that
|
|
56695
|
+
* costs at most `MAX_TAIL_DROP_SHARE` of the tail. A long OSC 8 URL, or any
|
|
56696
|
+
* payload longer than the budget, would otherwise hand the caller a sliver of
|
|
56697
|
+
* the tail it asked for; a payload whose extent exceeds the budget stays
|
|
56698
|
+
* visible instead. A cut the string already ended ahead of needs no skip, and
|
|
56699
|
+
* an unterminated one must not swallow the tail (`stringPayloadHead`).
|
|
56700
|
+
*/
|
|
56701
|
+
function stringSequenceHead$1(text, open, cut) {
|
|
56702
|
+
const drop = stringEnd$1(text, open + 2) - cut;
|
|
56703
|
+
if (drop >= 0 && drop <= (text.length - cut) * MAX_TAIL_DROP_SHARE$1) return cut + drop;
|
|
56704
|
+
return stringPayloadHead$1(text, open, cut);
|
|
56705
|
+
}
|
|
56706
|
+
/**
|
|
56707
|
+
* Head index that keeps a string sequence's payload visible, moving the cut
|
|
56708
|
+
* only past the opener's own bytes when the cut landed inside them.
|
|
56709
|
+
*
|
|
56710
|
+
* A terminal swallows an unterminated payload, but a viewer must never render
|
|
56711
|
+
* a blank body: `tailSlice` backs the tasks-browser tail read, and a log that
|
|
56712
|
+
* opens with an unterminated OSC — a run killed mid-title, a truncated write —
|
|
56713
|
+
* would otherwise come back empty. The head stays at `cut` unless the cut
|
|
56714
|
+
* landed inside the opener (`\u001b]0;` would leave `0;` in front of the
|
|
56715
|
+
* payload), and never reaches `text.length` — the clamp to the last unit steps
|
|
56716
|
+
* back onto the pair's first half when that unit is a trailing surrogate
|
|
56717
|
+
* pair's low half — so the tail is empty only for empty input.
|
|
56718
|
+
*/
|
|
56719
|
+
function stringPayloadHead$1(text, open, cut) {
|
|
56720
|
+
const head = Math.min(Math.max(cut, stringPayloadStart$1(text, open)), text.length - 1);
|
|
56721
|
+
const code = text.codePointAt(head);
|
|
56722
|
+
return head > 0 && code !== void 0 && code >= 56320 && code <= 57343 ? head - 1 : head;
|
|
56723
|
+
}
|
|
56724
|
+
/**
|
|
56725
|
+
* Index after the byte that ends the string sequence whose payload starts at
|
|
56726
|
+
* `from` — its BEL or `ESC \` terminator, or a CAN (0x18) / SUB (0x1A), which
|
|
56727
|
+
* a terminal reads as "string over, resume normal parsing". `-1` when the
|
|
56728
|
+
* string never ends.
|
|
56729
|
+
*/
|
|
56730
|
+
function stringEnd$1(text, from) {
|
|
56731
|
+
for (let i = from; i < text.length; i += 1) {
|
|
56732
|
+
const code = text.codePointAt(i);
|
|
56733
|
+
if (code === 7) return i + 1;
|
|
56734
|
+
if (code === 27 && text[i + 1] === "\\") return i + 2;
|
|
56735
|
+
if (code === 24 || code === 26) return i + 1;
|
|
56736
|
+
}
|
|
56737
|
+
return -1;
|
|
56738
|
+
}
|
|
56739
|
+
/**
|
|
56740
|
+
* Index where the payload of the string sequence opened at `open` starts: for
|
|
56741
|
+
* OSC after `ESC ] Ps ;`, for DCS/PM/APC after their parameter and
|
|
56742
|
+
* intermediate bytes and the final byte that opens the payload.
|
|
56743
|
+
*/
|
|
56744
|
+
function stringPayloadStart$1(text, open) {
|
|
56745
|
+
let i = open + 2;
|
|
56746
|
+
if (text[open + 1] === "]") {
|
|
56747
|
+
while (i < text.length && isOscParam$1(text.codePointAt(i))) i += 1;
|
|
56748
|
+
if (text[i] === ";") i += 1;
|
|
56749
|
+
return i;
|
|
56750
|
+
}
|
|
56751
|
+
while (i < text.length && isCsiBody$1(text.codePointAt(i))) i += 1;
|
|
56752
|
+
const final = text.codePointAt(i);
|
|
56753
|
+
return i < text.length && isCsiFinal$1(final) ? i + 1 : i;
|
|
56754
|
+
}
|
|
56755
|
+
/** OSC numeric parameter byte (0x30–0x39) — the `Ps` before the `;` separator. */
|
|
56756
|
+
function isOscParam$1(code) {
|
|
56757
|
+
return code !== void 0 && code >= 48 && code <= 57;
|
|
56758
|
+
}
|
|
56465
56759
|
/**
|
|
56466
56760
|
* Longest suffix of `text` whose UTF-8 encoding fits in `maxBytes`. Encoding
|
|
56467
56761
|
* through a Buffer keeps lone surrogates accounted as the 3-byte replacement
|
|
@@ -61716,7 +62010,7 @@ var ApiError = class extends Error {
|
|
|
61716
62010
|
this.name = "ApiError";
|
|
61717
62011
|
}
|
|
61718
62012
|
};
|
|
61719
|
-
function isPlaceholder(value) {
|
|
62013
|
+
function isPlaceholder$1(value) {
|
|
61720
62014
|
const trimmed = value.trim();
|
|
61721
62015
|
return trimmed.length === 0 || trimmed.includes("replace-with") || trimmed.startsWith("<") && trimmed.endsWith(">");
|
|
61722
62016
|
}
|
|
@@ -61738,11 +62032,11 @@ async function loadConfig(screamHomeDir) {
|
|
|
61738
62032
|
try {
|
|
61739
62033
|
const text = await readFile(join$1(screamHomeDir, "image-config.json"), "utf8");
|
|
61740
62034
|
const parsed = JSON.parse(text);
|
|
61741
|
-
const legacyUrl = typeof parsed.base_url === "string" && !isPlaceholder(parsed.base_url) ? `${normalizeUrl(parsed.base_url)}${GENERATIONS_SUFFIX}` : "";
|
|
61742
|
-
const urlRaw = typeof parsed.url === "string" && !isPlaceholder(parsed.url) ? parsed.url : legacyUrl;
|
|
61743
|
-
if (urlRaw.length === 0 || typeof parsed.api_key !== "string" || typeof parsed.model !== "string" || isPlaceholder(parsed.api_key)) return;
|
|
61744
|
-
const legacyEdit = typeof parsed.edit_base_url === "string" && !isPlaceholder(parsed.edit_base_url) ? `${normalizeUrl(parsed.edit_base_url)}${EDITS_SUFFIX}` : "";
|
|
61745
|
-
const editUrlRaw = typeof parsed.edit_url === "string" && !isPlaceholder(parsed.edit_url) ? parsed.edit_url : legacyEdit;
|
|
62035
|
+
const legacyUrl = typeof parsed.base_url === "string" && !isPlaceholder$1(parsed.base_url) ? `${normalizeUrl(parsed.base_url)}${GENERATIONS_SUFFIX}` : "";
|
|
62036
|
+
const urlRaw = typeof parsed.url === "string" && !isPlaceholder$1(parsed.url) ? parsed.url : legacyUrl;
|
|
62037
|
+
if (urlRaw.length === 0 || typeof parsed.api_key !== "string" || typeof parsed.model !== "string" || isPlaceholder$1(parsed.api_key)) return;
|
|
62038
|
+
const legacyEdit = typeof parsed.edit_base_url === "string" && !isPlaceholder$1(parsed.edit_base_url) ? `${normalizeUrl(parsed.edit_base_url)}${EDITS_SUFFIX}` : "";
|
|
62039
|
+
const editUrlRaw = typeof parsed.edit_url === "string" && !isPlaceholder$1(parsed.edit_url) ? parsed.edit_url : legacyEdit;
|
|
61746
62040
|
const editModelRaw = typeof parsed.edit_model === "string" ? parsed.edit_model : "";
|
|
61747
62041
|
return {
|
|
61748
62042
|
provider: typeof parsed.provider === "string" ? parsed.provider : "openai-compatible",
|
|
@@ -78334,7 +78628,7 @@ var ScriptTool = class {
|
|
|
78334
78628
|
signal: ctx.signal,
|
|
78335
78629
|
store: this.store.get("scriptStore") ?? {}
|
|
78336
78630
|
});
|
|
78337
|
-
if (!result.ok) return await this.failedResult(result.error, result.output, state);
|
|
78631
|
+
if (!result.ok) return await this.failedResult(result.error, result.output, state, parsed.options);
|
|
78338
78632
|
this.commitStoreWrites(result.storeWrites);
|
|
78339
78633
|
return await this.successResult(result.output, result.value, state, parsed.options);
|
|
78340
78634
|
} finally {
|
|
@@ -78397,7 +78691,7 @@ var ScriptTool = class {
|
|
|
78397
78691
|
async successResult(output, value, state, options) {
|
|
78398
78692
|
const textParts = output.filter((item) => item.type === "text").map((item) => item.text);
|
|
78399
78693
|
if (value !== void 0) textParts.push(valueText(value));
|
|
78400
|
-
const { shown } = await truncateOutput(textParts.join("\n"), (options
|
|
78694
|
+
const { shown } = await truncateOutput(textParts.join("\n"), outputBudgetChars(options));
|
|
78401
78695
|
const parts = [];
|
|
78402
78696
|
if (shown.length > 0) parts.push({
|
|
78403
78697
|
type: "text",
|
|
@@ -78416,11 +78710,11 @@ var ScriptTool = class {
|
|
|
78416
78710
|
...state.records.length > 0 ? { nestedCalls: state.records } : {}
|
|
78417
78711
|
};
|
|
78418
78712
|
}
|
|
78419
|
-
async failedResult(error, output, state) {
|
|
78713
|
+
async failedResult(error, output, state, options) {
|
|
78420
78714
|
const lines = [`Script failed (${error.kind}): ${error.message}`];
|
|
78421
78715
|
const partial = output.filter((item) => item.type === "text").map((item) => item.text).join("\n");
|
|
78422
78716
|
if (partial.length > 0) {
|
|
78423
|
-
const { shown } = await truncateOutput(partial,
|
|
78717
|
+
const { shown } = await truncateOutput(partial, outputBudgetChars(options));
|
|
78424
78718
|
lines.push("", "Partial output before the failure:", shown);
|
|
78425
78719
|
}
|
|
78426
78720
|
if (state.records.length > 0) lines.push(`(${state.records.length} nested call${state.records.length === 1 ? "" : "s"} ran before the failure)`);
|
|
@@ -78452,6 +78746,15 @@ function valueText(value) {
|
|
|
78452
78746
|
}
|
|
78453
78747
|
}
|
|
78454
78748
|
/**
|
|
78749
|
+
* The script's effective output budget in characters: the `@options.max_output_tokens`
|
|
78750
|
+
* annotation when the script carries one, the tool default otherwise. The success path
|
|
78751
|
+
* and the failure path both read this single value, so the annotation cannot apply to
|
|
78752
|
+
* only one of them.
|
|
78753
|
+
*/
|
|
78754
|
+
function outputBudgetChars(options) {
|
|
78755
|
+
return (options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS) * CHARS_PER_TOKEN;
|
|
78756
|
+
}
|
|
78757
|
+
/**
|
|
78455
78758
|
* Truncates to the character budget, keeping half the budget on each side
|
|
78456
78759
|
* (matching the reference implementation). The full text is spilled to a
|
|
78457
78760
|
* temp file and its path reported in the shown output.
|
|
@@ -132529,6 +132832,38 @@ function resolveConnectCatalogRequest(args) {
|
|
|
132529
132832
|
};
|
|
132530
132833
|
}
|
|
132531
132834
|
//#endregion
|
|
132835
|
+
//#region src/tui/utils/image-config.ts
|
|
132836
|
+
function getImageConfigPath() {
|
|
132837
|
+
return join(resolveScreamHome(), "image-config.json");
|
|
132838
|
+
}
|
|
132839
|
+
/** Placeholder rules mirrored from the ImageGenerate tool's `isPlaceholder`. */
|
|
132840
|
+
function isPlaceholder(value) {
|
|
132841
|
+
const trimmed = value.trim();
|
|
132842
|
+
return trimmed.length === 0 || trimmed.includes("replace-with") || trimmed.startsWith("<") && trimmed.endsWith(">");
|
|
132843
|
+
}
|
|
132844
|
+
/**
|
|
132845
|
+
* Best-effort read of an existing image config (never throws, never exposes
|
|
132846
|
+
* the key). The `usable` predicate mirrors the ImageGenerate tool's
|
|
132847
|
+
* `loadConfig` (packages/agent-core/src/tools/builtin/image/image-generate.ts):
|
|
132848
|
+
* a config the tool would reject must never be advertised as "configured".
|
|
132849
|
+
*/
|
|
132850
|
+
async function readExistingImageConfig() {
|
|
132851
|
+
try {
|
|
132852
|
+
const text = await readFile(getImageConfigPath(), "utf8");
|
|
132853
|
+
const parsed = JSON.parse(text);
|
|
132854
|
+
const urlRaw = typeof parsed["url"] === "string" ? parsed["url"] : "";
|
|
132855
|
+
const legacyRaw = typeof parsed["base_url"] === "string" ? parsed["base_url"] : "";
|
|
132856
|
+
const url = !isPlaceholder(urlRaw) ? urlRaw.trim() : !isPlaceholder(legacyRaw) ? `${legacyRaw.trim().replace(/\/+$/, "")}/images/generations` : "";
|
|
132857
|
+
const model = typeof parsed["model"] === "string" ? parsed["model"].trim() : "";
|
|
132858
|
+
const apiKeyRaw = typeof parsed["api_key"] === "string" ? parsed["api_key"] : "";
|
|
132859
|
+
if (url.length > 0 && model.length > 0 && !isPlaceholder(apiKeyRaw)) return {
|
|
132860
|
+
provider: typeof parsed["provider"] === "string" ? parsed["provider"] : "openai-compatible",
|
|
132861
|
+
model,
|
|
132862
|
+
url
|
|
132863
|
+
};
|
|
132864
|
+
} catch {}
|
|
132865
|
+
}
|
|
132866
|
+
//#endregion
|
|
132532
132867
|
//#region src/tui/components/dialogs/api-key-input-dialog.ts
|
|
132533
132868
|
function getFooter() {
|
|
132534
132869
|
return t("apikey.footer");
|
|
@@ -132775,6 +133110,11 @@ var ModelSelectorComponent = class extends Container {
|
|
|
132775
133110
|
lines.push(this.renderVideoControl(selected.model));
|
|
132776
133111
|
lines.push(this.renderAudioControl(selected.model));
|
|
132777
133112
|
}
|
|
133113
|
+
if (this.opts.imageGeneration !== void 0) {
|
|
133114
|
+
const imageGeneration = this.opts.imageGeneration;
|
|
133115
|
+
lines.push("");
|
|
133116
|
+
lines.push(chalk.hex(colors.textMuted)(imageGeneration.configured && imageGeneration.model !== void 0 ? t("model.image_gen_configured", { model: imageGeneration.model }) : t("model.image_gen_missing")));
|
|
133117
|
+
}
|
|
132778
133118
|
lines.push("");
|
|
132779
133119
|
if (view.page.pageCount > 1) lines.push(chalk.hex(colors.textMuted)(` Page ${String(view.page.page + 1)}/${String(view.page.pageCount)}`));
|
|
132780
133120
|
lines.push(chalk.hex(colors.primary)("─".repeat(width)));
|
|
@@ -133309,26 +133649,6 @@ const IMAGE_PROVIDER_PRESETS = [
|
|
|
133309
133649
|
model: "gpt-image-2"
|
|
133310
133650
|
}
|
|
133311
133651
|
];
|
|
133312
|
-
function getImageConfigPath() {
|
|
133313
|
-
return join(resolveScreamHome(), "image-config.json");
|
|
133314
|
-
}
|
|
133315
|
-
/** Best-effort read of an existing image config (never throws, never exposes the key). */
|
|
133316
|
-
async function readExistingImageConfig() {
|
|
133317
|
-
try {
|
|
133318
|
-
const text = await readFile(getImageConfigPath(), "utf8");
|
|
133319
|
-
const parsed = JSON.parse(text);
|
|
133320
|
-
const urlDirect = typeof parsed["url"] === "string" ? parsed["url"].trim() : "";
|
|
133321
|
-
const legacyBase = typeof parsed["base_url"] === "string" ? parsed["base_url"].trim() : "";
|
|
133322
|
-
const url = urlDirect.length > 0 ? urlDirect : legacyBase.length > 0 ? `${legacyBase.replace(/\/+$/, "")}/images/generations` : "";
|
|
133323
|
-
const model = typeof parsed["model"] === "string" ? parsed["model"].trim() : "";
|
|
133324
|
-
const apiKey = typeof parsed["api_key"] === "string" ? parsed["api_key"].trim() : "";
|
|
133325
|
-
if (url.length > 0 && !url.includes("replace-with") && !(url.startsWith("<") && url.endsWith(">")) && model.length > 0 && apiKey.length > 0 && !apiKey.includes("replace-with") && !(apiKey.startsWith("<") && apiKey.endsWith(">"))) return {
|
|
133326
|
-
provider: typeof parsed["provider"] === "string" ? parsed["provider"] : "openai-compatible",
|
|
133327
|
-
model,
|
|
133328
|
-
url
|
|
133329
|
-
};
|
|
133330
|
-
} catch {}
|
|
133331
|
-
}
|
|
133332
133652
|
/**
|
|
133333
133653
|
* Normalize the URL exactly as the user typed it: trim whitespace and
|
|
133334
133654
|
* trailing slashes only. Nothing is ever appended or completed — the full
|
|
@@ -135889,6 +136209,10 @@ function parseColorFgBg(value) {
|
|
|
135889
136209
|
*/
|
|
135890
136210
|
const dark = {
|
|
135891
136211
|
yellowGreen: "#79eb00",
|
|
136212
|
+
gold: "#FFD700",
|
|
136213
|
+
coral: "#FF7043",
|
|
136214
|
+
skyBlue: "#9CDCFE",
|
|
136215
|
+
violet: "#C084FC",
|
|
135892
136216
|
pink400: "#FF6B9D",
|
|
135893
136217
|
cyan400: "#56D4DD",
|
|
135894
136218
|
amber400: "#E8A838",
|
|
@@ -135905,6 +136229,10 @@ const dark = {
|
|
|
135905
136229
|
};
|
|
135906
136230
|
const light = {
|
|
135907
136231
|
yellowGreen700: "#4B7A06",
|
|
136232
|
+
gold: "#A16207",
|
|
136233
|
+
orange: "#C2410C",
|
|
136234
|
+
blue: "#1565C0",
|
|
136235
|
+
violet: "#7C3AED",
|
|
135908
136236
|
pink700: "#C2185B",
|
|
135909
136237
|
cyan800: "#006978",
|
|
135910
136238
|
gray900: "#1A1A1A",
|
|
@@ -135921,14 +136249,19 @@ const darkColors = {
|
|
|
135921
136249
|
accent: dark.pink400,
|
|
135922
136250
|
planMode: dark.cyan400,
|
|
135923
136251
|
fusionPlanMode: dark.amber500,
|
|
135924
|
-
wolfpackMode:
|
|
135925
|
-
rlmMode:
|
|
136252
|
+
wolfpackMode: dark.violet,
|
|
136253
|
+
rlmMode: dark.gold,
|
|
136254
|
+
permissionManual: dark.yellowGreen,
|
|
136255
|
+
permissionYolo: dark.gold,
|
|
136256
|
+
permissionAuto: dark.coral,
|
|
136257
|
+
permissionAsk: dark.skyBlue,
|
|
136258
|
+
permissionBot: dark.violet,
|
|
135926
136259
|
text: dark.gray100,
|
|
135927
136260
|
textStrong: dark.gray50,
|
|
135928
136261
|
textDim: dark.gray500,
|
|
135929
136262
|
textMuted: dark.gray600,
|
|
135930
136263
|
mdLink: "#56B6C2",
|
|
135931
|
-
mdCodeBlock:
|
|
136264
|
+
mdCodeBlock: dark.skyBlue,
|
|
135932
136265
|
mdCodeBlockBorder: "#5C6370",
|
|
135933
136266
|
mdCodeBlockBg: "#16191f",
|
|
135934
136267
|
mdQuote: "#7F848E",
|
|
@@ -135956,14 +136289,19 @@ const lightColors = {
|
|
|
135956
136289
|
accent: light.pink700,
|
|
135957
136290
|
planMode: light.cyan800,
|
|
135958
136291
|
fusionPlanMode: light.amber700,
|
|
135959
|
-
wolfpackMode:
|
|
135960
|
-
rlmMode:
|
|
136292
|
+
wolfpackMode: light.violet,
|
|
136293
|
+
rlmMode: light.gold,
|
|
136294
|
+
permissionManual: light.yellowGreen700,
|
|
136295
|
+
permissionYolo: light.gold,
|
|
136296
|
+
permissionAuto: light.orange,
|
|
136297
|
+
permissionAsk: light.blue,
|
|
136298
|
+
permissionBot: light.violet,
|
|
135961
136299
|
text: light.gray900,
|
|
135962
136300
|
textStrong: light.gray900,
|
|
135963
136301
|
textDim: light.gray700,
|
|
135964
136302
|
textMuted: light.gray600,
|
|
135965
136303
|
mdLink: "#007A8A",
|
|
135966
|
-
mdCodeBlock:
|
|
136304
|
+
mdCodeBlock: light.blue,
|
|
135967
136305
|
mdCodeBlockBorder: "#848484",
|
|
135968
136306
|
mdCodeBlockBg: "#f7f9fb",
|
|
135969
136307
|
mdQuote: "#616161",
|
|
@@ -137282,14 +137620,14 @@ async function handleModelCommand(host, args) {
|
|
|
137282
137620
|
const alias = trimmed;
|
|
137283
137621
|
if (alias.length === 0) {
|
|
137284
137622
|
await refreshModelsForPicker(host);
|
|
137285
|
-
showModelPicker(host);
|
|
137623
|
+
await showModelPicker(host);
|
|
137286
137624
|
return;
|
|
137287
137625
|
}
|
|
137288
137626
|
if (host.state.appState.availableModels[alias] === void 0) {
|
|
137289
137627
|
host.showError(`Unknown model alias: ${alias}`);
|
|
137290
137628
|
return;
|
|
137291
137629
|
}
|
|
137292
|
-
showModelPicker(host, alias);
|
|
137630
|
+
await showModelPicker(host, alias);
|
|
137293
137631
|
}
|
|
137294
137632
|
/**
|
|
137295
137633
|
* Reload provider/model config before showing the model picker so models
|
|
@@ -137349,11 +137687,12 @@ async function applyEditorChoice(host, value) {
|
|
|
137349
137687
|
host.setAppState({ editorCommand });
|
|
137350
137688
|
host.showStatus(value.length > 0 ? `Editor set to "${value}".` : "编辑器设置为自动检测 ($VISUAL / $EDITOR)。");
|
|
137351
137689
|
}
|
|
137352
|
-
function showModelPicker(host, selectedValue = host.state.appState.model) {
|
|
137690
|
+
async function showModelPicker(host, selectedValue = host.state.appState.model) {
|
|
137353
137691
|
if (Object.entries(host.state.appState.availableModels).length === 0) {
|
|
137354
137692
|
host.showNotice("未配置模型", "运行 /config 自定义模型配置。");
|
|
137355
137693
|
return;
|
|
137356
137694
|
}
|
|
137695
|
+
const imageConfig = await readExistingImageConfig();
|
|
137357
137696
|
host.mountEditorReplacement(new ModelSelectorComponent({
|
|
137358
137697
|
models: host.state.appState.availableModels,
|
|
137359
137698
|
currentValue: host.state.appState.model,
|
|
@@ -137361,6 +137700,10 @@ function showModelPicker(host, selectedValue = host.state.appState.model) {
|
|
|
137361
137700
|
currentThinkingLevel: host.state.appState.thinkingLevel,
|
|
137362
137701
|
colors: host.state.theme.colors,
|
|
137363
137702
|
searchable: true,
|
|
137703
|
+
imageGeneration: imageConfig === void 0 ? { configured: false } : {
|
|
137704
|
+
configured: true,
|
|
137705
|
+
model: imageConfig.model
|
|
137706
|
+
},
|
|
137364
137707
|
onSelect: ({ alias, thinkingLevel }) => {
|
|
137365
137708
|
host.restoreEditor();
|
|
137366
137709
|
performModelSwitch(host, alias, thinkingLevel);
|
|
@@ -138410,7 +138753,7 @@ async function guidedGoalSetup(host) {
|
|
|
138410
138753
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
138411
138754
|
return;
|
|
138412
138755
|
}
|
|
138413
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
138756
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DZoGkbYZ.mjs");
|
|
138414
138757
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
138415
138758
|
title: t("goal.setup_title_initial"),
|
|
138416
138759
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -138431,7 +138774,7 @@ async function guidedGoalSetup(host) {
|
|
|
138431
138774
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
138432
138775
|
}
|
|
138433
138776
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
138434
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
138777
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DZoGkbYZ.mjs");
|
|
138435
138778
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
138436
138779
|
title: t("goal.wizard_title", { objective }),
|
|
138437
138780
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -141621,24 +141964,259 @@ function trimTrailingEmptyLines(lines) {
|
|
|
141621
141964
|
return lines.slice(0, end);
|
|
141622
141965
|
}
|
|
141623
141966
|
/**
|
|
141624
|
-
* Returns the tail of `text` whose UTF-8 byte length is at most `maxBytes
|
|
141967
|
+
* Returns the tail of `text` whose UTF-8 byte length is at most `maxBytes`
|
|
141968
|
+
* (plus one byte when a torn sequence's introducer ESC sits immediately before
|
|
141969
|
+
* the cut and the sequence's remainder provably closes — keeping the ESC makes
|
|
141970
|
+
* the sequence whole and hides its fragment), with the head aligned to a
|
|
141971
|
+
* boundary no ANSI escape sequence spans.
|
|
141625
141972
|
* Iterates by Unicode code points so multi-byte characters and surrogate
|
|
141626
|
-
* pairs are never split
|
|
141973
|
+
* pairs are never split, then hands the cut to `safeTailStart`: success output
|
|
141974
|
+
* keeps its ANSI codes (only error output is stripped), and a raw byte cut
|
|
141975
|
+
* could land inside a sequence, leaving a fragment (`m`, `0m`, `[31`) that
|
|
141976
|
+
* `sanitizeShellOutput` cannot recognize because its ESC byte was cut away.
|
|
141627
141977
|
*/
|
|
141628
141978
|
function truncateTailBytes(text, maxBytes) {
|
|
141629
141979
|
if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
|
|
141630
141980
|
const chars = Array.from(text);
|
|
141631
|
-
let start = chars.length;
|
|
141632
141981
|
let bytes = 0;
|
|
141982
|
+
let units = 0;
|
|
141633
141983
|
for (let i = chars.length - 1; i >= 0; i--) {
|
|
141634
141984
|
const char = chars[i];
|
|
141635
141985
|
if (char === void 0) continue;
|
|
141636
141986
|
const charBytes = Buffer.byteLength(char, "utf8");
|
|
141637
141987
|
if (bytes + charBytes > maxBytes) break;
|
|
141638
141988
|
bytes += charBytes;
|
|
141639
|
-
|
|
141989
|
+
units += char.length;
|
|
141990
|
+
}
|
|
141991
|
+
return text.slice(safeTailStart(text, text.length - units));
|
|
141992
|
+
}
|
|
141993
|
+
const ESC = "\x1B";
|
|
141994
|
+
/**
|
|
141995
|
+
* Largest share of a retained tail the boundary rules may discard.
|
|
141996
|
+
*
|
|
141997
|
+
* Both rules trade content for a head that is whole by construction: rule 1
|
|
141998
|
+
* restarts after the next `\n` and drops the torn line, and rule 2 skips the
|
|
141999
|
+
* remainder of a torn sequence. The trade only pays while the tail keeps a
|
|
142000
|
+
* (non-strict) majority — with one 5000-char line ahead, a 100-byte budget
|
|
142001
|
+
* would come back with the few bytes after it, and the reader asked for the
|
|
142002
|
+
* newest output, not for a tidy head. Past the bound the raw cut keeps the
|
|
142003
|
+
* content: a string payload stays visible, and a torn CSI or two-byte escape
|
|
142004
|
+
* run keeps the fragment it left in view, because skipping that remainder
|
|
142005
|
+
* would cost more than the fragment it hides — unless the introducer ESC sits
|
|
142006
|
+
* immediately before the head *and* the sequence provably closes, where one
|
|
142007
|
+
* unit of look-back keeps the sequence whole and the fragment never surfaces.
|
|
142008
|
+
* An unclosed run keeps the raw cut: with no terminator to hand the sanitizer,
|
|
142009
|
+
* backing onto its ESC would surface a bare ESC the sanitizer cannot strip.
|
|
142010
|
+
*/
|
|
142011
|
+
const MAX_TAIL_DROP_SHARE = .5;
|
|
142012
|
+
/**
|
|
142013
|
+
* Move a tail cut point forward to a boundary no ANSI escape sequence spans.
|
|
142014
|
+
*
|
|
142015
|
+
* A raw `slice(-tail)` can land inside a sequence (`…\u001b[31|m…`), leaving a
|
|
142016
|
+
* fragment (`m`, `0m`, `[31`) whose ESC byte was cut away —
|
|
142017
|
+
* `sanitizeShellOutput` only recognizes complete sequences, so the fragment
|
|
142018
|
+
* renders as text. Two provable rules keep the head clean:
|
|
142019
|
+
*
|
|
142020
|
+
* 1. Line alignment: a CSI sequence cannot contain `\n` (LF is not a
|
|
142021
|
+
* parameter, intermediate or final byte), so a cut that lands mid-line
|
|
142022
|
+
* restarts after the next `\n`. The only loss is the torn partial line,
|
|
142023
|
+
* whose head cannot be trusted; every escape after the newline is whole.
|
|
142024
|
+
* Bounded by `MAX_TAIL_DROP_SHARE`, so one huge line cannot eat the budget.
|
|
142025
|
+
* 2. Torn-sequence skip: when the retained text is one line (no `\n` after
|
|
142026
|
+
* the cut), or an OSC/DCS/PM/APC payload spans the newline the cut aligned
|
|
142027
|
+
* to, the dropped prefix is inspected for a sequence still open at the cut
|
|
142028
|
+
* — a run of CSI body bytes (0x20–0x3F) reaching back to `ESC [`, an `ESC`
|
|
142029
|
+
* whose intermediate bytes were torn (`ESC ( B`), or a string-sequence
|
|
142030
|
+
* opener the cut landed inside. The head then skips exactly the bytes a
|
|
142031
|
+
* terminal would consume for that sequence, so no visible text is dropped —
|
|
142032
|
+
* but only while that skip stays within `MAX_TAIL_DROP_SHARE` of the tail.
|
|
142033
|
+
* A CSI body or escape-intermediate run can be arbitrarily long, so past
|
|
142034
|
+
* the bound the head keeps the newest bytes and the fragment the raw cut
|
|
142035
|
+
* left with them — or one unit earlier, onto an introducer ESC sitting
|
|
142036
|
+
* immediately before the head, so the whole sequence survives and is
|
|
142037
|
+
* stripped (`withinDropShare`) — but only when the skip proved the sequence
|
|
142038
|
+
* closed: an unclosed run keeps the raw cut, because with no terminator to
|
|
142039
|
+
* hand the sanitizer the ESC would surface bare and swallow what follows
|
|
142040
|
+
* it. So does the head for a string that never ends or ended ahead of the
|
|
142041
|
+
* cut. A sliver of the tail is worse than a fragment.
|
|
142042
|
+
*
|
|
142043
|
+
* `cut` is always a code-point boundary here (the byte loop above works in
|
|
142044
|
+
* code points), so unlike its manager-side twin there is no surrogate half to
|
|
142045
|
+
* drop, and `stringPayloadHead`'s clamp steps back onto a code point as well;
|
|
142046
|
+
* the one-unit look-back onto an introducer ESC (`withinDropShare`) — taken
|
|
142047
|
+
* only for a skip that proved its sequence closed — is a code point boundary
|
|
142048
|
+
* too. Mirrors `safeTailStart` in
|
|
142049
|
+
* `packages/agent-core/src/tools/background/manager.ts` — app code cannot
|
|
142050
|
+
* import agent-core directly, so the rule lives in both places.
|
|
142051
|
+
*/
|
|
142052
|
+
function safeTailStart(text, cut) {
|
|
142053
|
+
if (cut <= 0 || cut >= text.length) return cut;
|
|
142054
|
+
const tail = text.length - cut;
|
|
142055
|
+
let start = cut;
|
|
142056
|
+
if (text[start - 1] !== "\n") {
|
|
142057
|
+
const newline = text.indexOf("\n", start);
|
|
142058
|
+
if (newline !== -1 && newline + 1 - cut <= tail * MAX_TAIL_DROP_SHARE) start = newline + 1;
|
|
142059
|
+
}
|
|
142060
|
+
return skipOpenEscape(text, start);
|
|
142061
|
+
}
|
|
142062
|
+
/** CSI parameter (0x30–0x3F) / intermediate (0x20–0x2F) bytes — everything before the final byte. */
|
|
142063
|
+
function isCsiBody(code) {
|
|
142064
|
+
return code !== void 0 && code >= 32 && code <= 63;
|
|
142065
|
+
}
|
|
142066
|
+
/** CSI final byte (0x40–0x7E) — the sequence ends here. */
|
|
142067
|
+
function isCsiFinal(code) {
|
|
142068
|
+
return code !== void 0 && code >= 64 && code <= 126;
|
|
142069
|
+
}
|
|
142070
|
+
/** OSC / DCS / PM / APC introducers — string sequences ended by BEL or ST. */
|
|
142071
|
+
function isStringIntro(intro) {
|
|
142072
|
+
return intro === "]" || intro === "P" || intro === "^" || intro === "_";
|
|
142073
|
+
}
|
|
142074
|
+
/** ESC-intermediate byte (0x20–0x2F) of a two-byte escape sequence. */
|
|
142075
|
+
function isEscapeIntermediate(code) {
|
|
142076
|
+
return code !== void 0 && code >= 32 && code <= 47;
|
|
142077
|
+
}
|
|
142078
|
+
/** Final byte (0x30–0x7E) that closes a two-byte escape sequence. */
|
|
142079
|
+
function isEscapeFinal(code) {
|
|
142080
|
+
return code !== void 0 && code >= 48 && code <= 126;
|
|
142081
|
+
}
|
|
142082
|
+
/** True when every code point in the half-open range `[from, to)` is an ESC intermediate (0x20–0x2F). */
|
|
142083
|
+
function allEscapeIntermediates(text, from, to) {
|
|
142084
|
+
for (let i = from; i < to; i += 1) if (!isEscapeIntermediate(text.codePointAt(i))) return false;
|
|
142085
|
+
return true;
|
|
142086
|
+
}
|
|
142087
|
+
/**
|
|
142088
|
+
* When the dropped prefix proves an escape sequence is still open at `cut`,
|
|
142089
|
+
* return the index after its remainder; otherwise return `cut` unchanged.
|
|
142090
|
+
*/
|
|
142091
|
+
function skipOpenEscape(text, cut) {
|
|
142092
|
+
let run = cut;
|
|
142093
|
+
while (run > 0 && isCsiBody(text.codePointAt(run - 1))) run -= 1;
|
|
142094
|
+
if (run >= 2 && text[run - 1] === "[" && text[run - 2] === ESC) {
|
|
142095
|
+
const skip = skipCsiRest(text, cut);
|
|
142096
|
+
return withinDropShare(text, cut, skip.end, skip.closed);
|
|
142097
|
+
}
|
|
142098
|
+
if (text[run - 1] === ESC && allEscapeIntermediates(text, run, cut)) return skipEscapeRest(text, cut);
|
|
142099
|
+
const open = text.lastIndexOf(ESC, cut - 1);
|
|
142100
|
+
if (open !== -1 && isStringIntro(text[open + 1])) return stringSequenceHead(text, open, cut);
|
|
142101
|
+
return cut;
|
|
142102
|
+
}
|
|
142103
|
+
/**
|
|
142104
|
+
* Keep a provable skip only while it stays within `MAX_TAIL_DROP_SHARE` of the
|
|
142105
|
+
* tail that starts at `from`: the skipped bytes are exactly what the reader
|
|
142106
|
+
* loses from the tail it asked for. A CSI body or escape-intermediate run can
|
|
142107
|
+
* be arbitrarily long, so past the bound the raw cut is worth more than the
|
|
142108
|
+
* clean head — except when the sequence's introducer ESC sits immediately
|
|
142109
|
+
* before the head (`…\u001b|[31m…`) *and* `closed` says the skip found the
|
|
142110
|
+
* sequence's terminator, where one unit of look-back keeps the sequence whole
|
|
142111
|
+
* instead: the sanitizer strips it and the visible text is the skip's, for
|
|
142112
|
+
* that one unit rather than a sliver of the tail. An unclosed run must keep
|
|
142113
|
+
* the raw cut even with that ESC one unit ahead: nothing terminates it, so
|
|
142114
|
+
* look-back would hand the reader a bare ESC whose sequence run a terminal
|
|
142115
|
+
* swallows along with the bytes behind it.
|
|
142116
|
+
*/
|
|
142117
|
+
function withinDropShare(text, from, target, closed) {
|
|
142118
|
+
if (target - from <= (text.length - from) * MAX_TAIL_DROP_SHARE) return target;
|
|
142119
|
+
return closed && from > 0 && text[from - 1] === ESC ? from - 1 : from;
|
|
142120
|
+
}
|
|
142121
|
+
/**
|
|
142122
|
+
* The rest of a CSI sequence whose body was torn at `cut`, with the closure
|
|
142123
|
+
* its skip proved: `closed` holds only when a final byte (0x40–0x7E) was
|
|
142124
|
+
* actually found, so a parameter run that reaches the end of `text` — or stops
|
|
142125
|
+
* on a byte no CSI can end with — reports the sequence as open.
|
|
142126
|
+
*/
|
|
142127
|
+
function skipCsiRest(text, cut) {
|
|
142128
|
+
let end = cut;
|
|
142129
|
+
while (end < text.length && isCsiBody(text.codePointAt(end))) end += 1;
|
|
142130
|
+
const closed = end < text.length && isCsiFinal(text.codePointAt(end));
|
|
142131
|
+
return {
|
|
142132
|
+
end: closed ? end + 1 : end,
|
|
142133
|
+
closed
|
|
142134
|
+
};
|
|
142135
|
+
}
|
|
142136
|
+
/** Index after the escape sequence whose introducer ESC sits at `cut - 1`. */
|
|
142137
|
+
function skipEscapeRest(text, cut) {
|
|
142138
|
+
const intro = text[cut];
|
|
142139
|
+
if (intro === "[") {
|
|
142140
|
+
const skip = skipCsiRest(text, cut + 1);
|
|
142141
|
+
return withinDropShare(text, cut, skip.end, skip.closed);
|
|
142142
|
+
}
|
|
142143
|
+
if (isStringIntro(intro)) return stringSequenceHead(text, cut - 1, cut + 1);
|
|
142144
|
+
let end = cut;
|
|
142145
|
+
while (end < text.length && isEscapeIntermediate(text.codePointAt(end))) end += 1;
|
|
142146
|
+
const closed = end < text.length && isEscapeFinal(text.codePointAt(end));
|
|
142147
|
+
return withinDropShare(text, cut, closed ? end + 1 : end, closed);
|
|
142148
|
+
}
|
|
142149
|
+
/**
|
|
142150
|
+
* Head index for a cut that lands inside the string sequence opened at `open`.
|
|
142151
|
+
*
|
|
142152
|
+
* `stringEnd` gives the byte a terminal stops at; skipping to it hides the
|
|
142153
|
+
* payload's remainder, which is what a terminal shows — but only while that
|
|
142154
|
+
* costs at most `MAX_TAIL_DROP_SHARE` of the tail. A long OSC 8 URL, or any
|
|
142155
|
+
* payload longer than the budget, would otherwise hand the reader a sliver of
|
|
142156
|
+
* the tail it asked for; a payload whose extent exceeds the budget stays
|
|
142157
|
+
* visible instead. A cut the string already ended ahead of needs no skip, and
|
|
142158
|
+
* an unterminated one must not swallow the tail (`stringPayloadHead`).
|
|
142159
|
+
*/
|
|
142160
|
+
function stringSequenceHead(text, open, cut) {
|
|
142161
|
+
const drop = stringEnd(text, open + 2) - cut;
|
|
142162
|
+
if (drop >= 0 && drop <= (text.length - cut) * MAX_TAIL_DROP_SHARE) return cut + drop;
|
|
142163
|
+
return stringPayloadHead(text, open, cut);
|
|
142164
|
+
}
|
|
142165
|
+
/**
|
|
142166
|
+
* Head index that keeps a string sequence's payload visible, moving the cut
|
|
142167
|
+
* only past the opener's own bytes when the cut landed inside them.
|
|
142168
|
+
*
|
|
142169
|
+
* A terminal swallows an unterminated payload, but a viewer must never render
|
|
142170
|
+
* a blank body: a shell card whose output opens with an unterminated OSC — a
|
|
142171
|
+
* command killed mid-title, a truncated write — would otherwise show nothing
|
|
142172
|
+
* at all. The head stays at `cut` unless the cut landed inside the opener
|
|
142173
|
+
* (`\u001b]0;` would leave `0;` in front of the payload), and never reaches
|
|
142174
|
+
* `text.length` — the clamp to the last unit steps back onto the pair's first
|
|
142175
|
+
* half when that unit is a trailing surrogate pair's low half (defensive here:
|
|
142176
|
+
* `truncateTailBytes` cuts on a code point boundary, so the clamp cannot land
|
|
142177
|
+
* between a pair's halves in practice) — so this rule never empties the tail;
|
|
142178
|
+
* the tail comes back empty only when the byte budget fits none of the last
|
|
142179
|
+
* character.
|
|
142180
|
+
*/
|
|
142181
|
+
function stringPayloadHead(text, open, cut) {
|
|
142182
|
+
const head = Math.min(Math.max(cut, stringPayloadStart(text, open)), text.length - 1);
|
|
142183
|
+
const code = text.codePointAt(head);
|
|
142184
|
+
return head > 0 && code !== void 0 && code >= 56320 && code <= 57343 ? head - 1 : head;
|
|
142185
|
+
}
|
|
142186
|
+
/**
|
|
142187
|
+
* Index after the byte that ends the string sequence whose payload starts at
|
|
142188
|
+
* `from` — its BEL or `ESC \` terminator, or a CAN (0x18) / SUB (0x1A), which
|
|
142189
|
+
* a terminal reads as "string over, resume normal parsing". `-1` when the
|
|
142190
|
+
* string never ends.
|
|
142191
|
+
*/
|
|
142192
|
+
function stringEnd(text, from) {
|
|
142193
|
+
for (let i = from; i < text.length; i += 1) {
|
|
142194
|
+
const code = text.codePointAt(i);
|
|
142195
|
+
if (code === 7) return i + 1;
|
|
142196
|
+
if (code === 27 && text[i + 1] === "\\") return i + 2;
|
|
142197
|
+
if (code === 24 || code === 26) return i + 1;
|
|
141640
142198
|
}
|
|
141641
|
-
return
|
|
142199
|
+
return -1;
|
|
142200
|
+
}
|
|
142201
|
+
/**
|
|
142202
|
+
* Index where the payload of the string sequence opened at `open` starts: for
|
|
142203
|
+
* OSC after `ESC ] Ps ;`, for DCS/PM/APC after their parameter and
|
|
142204
|
+
* intermediate bytes and the final byte that opens the payload.
|
|
142205
|
+
*/
|
|
142206
|
+
function stringPayloadStart(text, open) {
|
|
142207
|
+
let i = open + 2;
|
|
142208
|
+
if (text[open + 1] === "]") {
|
|
142209
|
+
while (i < text.length && isOscParam(text.codePointAt(i))) i += 1;
|
|
142210
|
+
if (text[i] === ";") i += 1;
|
|
142211
|
+
return i;
|
|
142212
|
+
}
|
|
142213
|
+
while (i < text.length && isCsiBody(text.codePointAt(i))) i += 1;
|
|
142214
|
+
const final = text.codePointAt(i);
|
|
142215
|
+
return i < text.length && isCsiFinal(final) ? i + 1 : i;
|
|
142216
|
+
}
|
|
142217
|
+
/** OSC numeric parameter byte (0x30–0x39) — the `Ps` before the `;` separator. */
|
|
142218
|
+
function isOscParam(code) {
|
|
142219
|
+
return code !== void 0 && code >= 48 && code <= 57;
|
|
141642
142220
|
}
|
|
141643
142221
|
/**
|
|
141644
142222
|
* Component that renders tool output with wrap-aware line truncation.
|
|
@@ -143863,6 +144441,7 @@ async function handleRevokeCommand(host, args = "") {
|
|
|
143863
144441
|
const preservedEntries = entries.slice(lastUserIndex).filter((entry) => !isRevokeContextEntry(entry));
|
|
143864
144442
|
entries.splice(lastUserIndex, entries.length - lastUserIndex, ...preservedEntries);
|
|
143865
144443
|
if (entries.length === 0) renderWelcome(host);
|
|
144444
|
+
host.state.ui.resetTextSelection();
|
|
143866
144445
|
host.state.ui.requestRender();
|
|
143867
144446
|
}
|
|
143868
144447
|
function parseRevokeCount(args) {
|
|
@@ -146547,12 +147126,14 @@ function showValuePicker(host, key) {
|
|
|
146547
147126
|
onSelect: (value) => {
|
|
146548
147127
|
const parsed = Number(value);
|
|
146549
147128
|
if (!Number.isFinite(parsed)) return;
|
|
147129
|
+
const resized = parsed !== getActivityLineValue(key);
|
|
146550
147130
|
setActivityLineValue(key, parsed);
|
|
146551
147131
|
host.restoreEditor();
|
|
146552
147132
|
host.showStatus(t("blockrows.saved", {
|
|
146553
147133
|
label: t(setting.label),
|
|
146554
147134
|
value: String(parsed)
|
|
146555
147135
|
}), host.state.theme.colors.success);
|
|
147136
|
+
if (resized) host.state.ui.resetTextSelection();
|
|
146556
147137
|
repaintTranscript(host);
|
|
146557
147138
|
},
|
|
146558
147139
|
onCancel: () => {
|
|
@@ -147135,8 +147716,10 @@ function buildOptions() {
|
|
|
147135
147716
|
}
|
|
147136
147717
|
/** Apply a choice: redraw what is already on screen, restate the capability. */
|
|
147137
147718
|
async function applyDisplay(host, value) {
|
|
147719
|
+
const previous = getMermaidDisplay();
|
|
147138
147720
|
setMermaidDisplay(value);
|
|
147139
147721
|
host.showStatus(t("mermaid.applied", { mode: optionLabel(value) }), value === "off" ? host.state.theme.colors.textDim : host.state.theme.colors.success);
|
|
147722
|
+
if (previous !== value && (previous === "off" || value === "off")) host.state.ui.resetTextSelection();
|
|
147140
147723
|
repaintTranscript(host);
|
|
147141
147724
|
await syncDiagramCapabilityPrompt(host.session);
|
|
147142
147725
|
}
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-BuWHcggN.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|
|
@@ -602,8 +602,15 @@ const dictionaries = {
|
|
|
602
602
|
"model.not_supported": "✗ 不支持",
|
|
603
603
|
"model.video": "视频",
|
|
604
604
|
"model.audio": "音频",
|
|
605
|
+
"model.image_gen_configured": " 生图模型:{model} · 已配置(/config image 修改)",
|
|
606
|
+
"model.image_gen_missing": " 生图模型:未配置 · /config image 设置",
|
|
605
607
|
"help.toggle_plan": "切换计划模式",
|
|
606
608
|
"help.toggle_output": "切换工具输出展开",
|
|
609
|
+
"help.cycle_thinking": "空输入时循环思考档位",
|
|
610
|
+
"help.toggle_plan_view": "展开/收起计划",
|
|
611
|
+
"help.toggle_sidebar": "开关侧边面板",
|
|
612
|
+
"help.toggle_hint": "隐藏/显示空会话提示",
|
|
613
|
+
"help.cancel_memory": "取消挂起的记忆提取",
|
|
607
614
|
"help.interrupt": "中途干预 — 在流式传输中插入后续提示",
|
|
608
615
|
"help.newline": "插入换行",
|
|
609
616
|
"help.external_editor": "在外部编辑器中编辑 ($VISUAL / $EDITOR)",
|
|
@@ -615,7 +622,7 @@ const dictionaries = {
|
|
|
615
622
|
"help.title": " 帮助 ",
|
|
616
623
|
"help.close_hint": "Esc / Enter / q 关闭 · ↑↓ 滚动",
|
|
617
624
|
"help.welcome_msg": "Scream 已准备好帮助您!发送消息即可开始。",
|
|
618
|
-
"help.hidden_commands": "/config diy 自定义模型服务商 /model diy 多代理编排配置",
|
|
625
|
+
"help.hidden_commands": "/config diy 自定义模型服务商 /config image 生图配置 /model diy 多代理编排配置",
|
|
619
626
|
"help.shortcuts": "键盘快捷键",
|
|
620
627
|
"help.slash_commands": "斜杠命令",
|
|
621
628
|
"help.showing_range": "显示 {start}-{end} / {total}",
|
|
@@ -1930,8 +1937,15 @@ const dictionaries = {
|
|
|
1930
1937
|
"model.not_supported": "✗ Not supported",
|
|
1931
1938
|
"model.video": "Video",
|
|
1932
1939
|
"model.audio": "Audio",
|
|
1940
|
+
"model.image_gen_configured": " Image model: {model} · configured (/config image to change)",
|
|
1941
|
+
"model.image_gen_missing": " Image model: not configured · set it with /config image",
|
|
1933
1942
|
"help.toggle_plan": "Toggle plan mode",
|
|
1934
1943
|
"help.toggle_output": "Toggle tool output expansion",
|
|
1944
|
+
"help.cycle_thinking": "Cycle thinking effort (empty input)",
|
|
1945
|
+
"help.toggle_plan_view": "Expand / collapse the plan",
|
|
1946
|
+
"help.toggle_sidebar": "Toggle the sidebar panel",
|
|
1947
|
+
"help.toggle_hint": "Toggle the empty-session hint",
|
|
1948
|
+
"help.cancel_memory": "Cancel the pending memory extraction",
|
|
1935
1949
|
"help.interrupt": "Interrupt — insert follow-up prompt during streaming",
|
|
1936
1950
|
"help.newline": "Insert newline",
|
|
1937
1951
|
"help.external_editor": "Edit in external editor ($VISUAL / $EDITOR)",
|
|
@@ -1943,7 +1957,7 @@ const dictionaries = {
|
|
|
1943
1957
|
"help.title": " Help ",
|
|
1944
1958
|
"help.close_hint": "Esc / Enter / q Close · ↑↓ Scroll",
|
|
1945
1959
|
"help.welcome_msg": "Scream is ready to help! Send a message to get started.",
|
|
1946
|
-
"help.hidden_commands": "/config diy Custom model provider /model diy Multi-agent orchestration",
|
|
1960
|
+
"help.hidden_commands": "/config diy Custom model provider /config image Image generation /model diy Multi-agent orchestration",
|
|
1947
1961
|
"help.shortcuts": "Keyboard Shortcuts",
|
|
1948
1962
|
"help.slash_commands": "Slash Commands",
|
|
1949
1963
|
"help.showing_range": "Showing {start}-{end} / {total}",
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { t as TextInputDialogComponent } from "./text-input-dialog-
|
|
6
|
+
import { t as TextInputDialogComponent } from "./text-input-dialog-CK6jTftM.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scream-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "A terminal-native AI agent for builders",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ScreamCli",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"bench:startup": "node scripts/startup-bench.mjs"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@earendil-works/pi-codemode": "^1.0
|
|
60
|
+
"@earendil-works/pi-codemode": "^1.1.0",
|
|
61
61
|
"@fontsource-variable/inter": "^5.3.0",
|
|
62
62
|
"@fontsource-variable/jetbrains-mono": "^5.3.0",
|
|
63
|
-
"@liutod-scream/pi-tui": "^1.0
|
|
63
|
+
"@liutod-scream/pi-tui": "^1.1.0",
|
|
64
64
|
"@mariozechner/clipboard": "^0.3.2",
|
|
65
65
|
"chalk": "^5.4.1",
|
|
66
66
|
"cli-highlight": "^2.1.11",
|