scream-code 0.7.7 → 0.7.9
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-AVBOJrWs.mjs → app-DxQ8R4AP.mjs} +166 -16
- package/dist/main.mjs +1 -1
- package/package.json +22 -22
|
@@ -121994,7 +121994,7 @@ function optionalBuildString(value) {
|
|
|
121994
121994
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
121995
121995
|
}
|
|
121996
121996
|
const SCREAM_BUILD_INFO = {
|
|
121997
|
-
version: optionalBuildString("0.7.
|
|
121997
|
+
version: optionalBuildString("0.7.9"),
|
|
121998
121998
|
channel: optionalBuildString(""),
|
|
121999
121999
|
commit: optionalBuildString(""),
|
|
122000
122000
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -123815,11 +123815,16 @@ function effectiveThinkingLevel(model, thinkingDraft) {
|
|
|
123815
123815
|
if (levels.includes(thinkingDraft)) return thinkingDraft;
|
|
123816
123816
|
return levels[0] ?? "off";
|
|
123817
123817
|
}
|
|
123818
|
+
function modelHasImageIn(model) {
|
|
123819
|
+
return model.capabilities?.includes("image_in") === true;
|
|
123820
|
+
}
|
|
123818
123821
|
var ModelSelectorComponent = class extends Container {
|
|
123819
123822
|
focused = false;
|
|
123820
123823
|
opts;
|
|
123821
123824
|
list;
|
|
123822
123825
|
thinkingDraft;
|
|
123826
|
+
imageDraft;
|
|
123827
|
+
lastSelectedAlias;
|
|
123823
123828
|
constructor(opts) {
|
|
123824
123829
|
super();
|
|
123825
123830
|
this.opts = opts;
|
|
@@ -123835,6 +123840,8 @@ var ModelSelectorComponent = class extends Container {
|
|
|
123835
123840
|
});
|
|
123836
123841
|
const initialChoice = choices[selectedIdx];
|
|
123837
123842
|
this.thinkingDraft = initialChoice !== void 0 ? effectiveThinkingLevel(initialChoice.model, opts.currentThinkingLevel) : opts.currentThinkingLevel;
|
|
123843
|
+
this.imageDraft = initialChoice !== void 0 ? modelHasImageIn(initialChoice.model) : false;
|
|
123844
|
+
this.lastSelectedAlias = initialChoice?.alias;
|
|
123838
123845
|
}
|
|
123839
123846
|
handleInput(data) {
|
|
123840
123847
|
if (matchesKey(data, Key.escape)) {
|
|
@@ -123843,6 +123850,10 @@ var ModelSelectorComponent = class extends Container {
|
|
|
123843
123850
|
return;
|
|
123844
123851
|
}
|
|
123845
123852
|
const selected = this.list.selected();
|
|
123853
|
+
if (selected !== void 0 && selected.alias !== this.lastSelectedAlias) {
|
|
123854
|
+
this.imageDraft = modelHasImageIn(selected.model);
|
|
123855
|
+
this.lastSelectedAlias = selected.alias;
|
|
123856
|
+
}
|
|
123846
123857
|
if (selected !== void 0 && thinkingAvailability(selected.model) !== "unsupported") {
|
|
123847
123858
|
const levels = getThinkingLevels(selected.model);
|
|
123848
123859
|
const idx = levels.indexOf(this.thinkingDraft);
|
|
@@ -123857,11 +123868,16 @@ var ModelSelectorComponent = class extends Container {
|
|
|
123857
123868
|
return;
|
|
123858
123869
|
}
|
|
123859
123870
|
}
|
|
123871
|
+
if (selected !== void 0 && !modelHasImageIn(selected.model) && matchesKey(data, Key.space)) {
|
|
123872
|
+
this.imageDraft = !this.imageDraft;
|
|
123873
|
+
return;
|
|
123874
|
+
}
|
|
123860
123875
|
if (matchesKey(data, Key.enter)) {
|
|
123861
123876
|
if (selected === void 0) return;
|
|
123862
123877
|
this.opts.onSelect({
|
|
123863
123878
|
alias: selected.alias,
|
|
123864
|
-
thinkingLevel: effectiveThinkingLevel(selected.model, this.thinkingDraft)
|
|
123879
|
+
thinkingLevel: effectiveThinkingLevel(selected.model, this.thinkingDraft),
|
|
123880
|
+
imageEnabled: this.imageDraft
|
|
123865
123881
|
});
|
|
123866
123882
|
return;
|
|
123867
123883
|
}
|
|
@@ -123872,7 +123888,11 @@ var ModelSelectorComponent = class extends Container {
|
|
|
123872
123888
|
const searchable = this.opts.searchable === true;
|
|
123873
123889
|
const view = this.list.view();
|
|
123874
123890
|
const choices = view.items;
|
|
123875
|
-
const navParts = [
|
|
123891
|
+
const navParts = [
|
|
123892
|
+
"↑↓ 模型",
|
|
123893
|
+
"←→ 思考等级",
|
|
123894
|
+
"Space(空格) vision识图"
|
|
123895
|
+
];
|
|
123876
123896
|
if (view.page.pageCount > 1) navParts.push("PgUp/PgDn 翻页");
|
|
123877
123897
|
navParts.push("Enter 应用", "Esc 取消");
|
|
123878
123898
|
const titleSuffix = searchable && view.query.length === 0 ? chalk.hex(colors.textMuted)(" (输入搜索)") : "";
|
|
@@ -123897,6 +123917,9 @@ var ModelSelectorComponent = class extends Container {
|
|
|
123897
123917
|
const selected = choices[view.selectedIndex];
|
|
123898
123918
|
if (selected !== void 0) lines.push(this.renderThinkingControl(selected.model));
|
|
123899
123919
|
lines.push("");
|
|
123920
|
+
lines.push(chalk.hex(colors.textMuted)(" Vision 识图"));
|
|
123921
|
+
if (selected !== void 0) lines.push(this.renderImageControl(selected.model));
|
|
123922
|
+
lines.push("");
|
|
123900
123923
|
if (view.page.pageCount > 1) lines.push(chalk.hex(colors.textMuted)(` Page ${String(view.page.page + 1)}/${String(view.page.pageCount)}`));
|
|
123901
123924
|
lines.push(chalk.hex(colors.primary)("─".repeat(width)));
|
|
123902
123925
|
return lines.map((line) => truncateToWidth(line, width));
|
|
@@ -123912,6 +123935,11 @@ var ModelSelectorComponent = class extends Container {
|
|
|
123912
123935
|
if (availability === "unsupported") return `${line} ${chalk.hex(colors.textMuted)("unsupported")}`;
|
|
123913
123936
|
return line;
|
|
123914
123937
|
}
|
|
123938
|
+
renderImageControl(model) {
|
|
123939
|
+
const { colors } = this.opts;
|
|
123940
|
+
if (modelHasImageIn(model)) return ` ${chalk.hex(colors.success).bold("✓ 默认开启")}${chalk.hex(colors.textMuted)(" (catalog)")}`;
|
|
123941
|
+
return ` ${this.imageDraft ? chalk.hex(colors.success).bold("✓ 开启") : chalk.hex(colors.textDim)("✗ 关闭")}${this.imageDraft ? chalk.hex(colors.textMuted)(" (手动开启)") : ""}`;
|
|
123942
|
+
}
|
|
123915
123943
|
};
|
|
123916
123944
|
//#endregion
|
|
123917
123945
|
//#region src/tui/components/dialogs/text-input-dialog.ts
|
|
@@ -125625,23 +125653,24 @@ function showModelPicker(host, selectedValue = host.state.appState.model) {
|
|
|
125625
125653
|
currentThinkingLevel: host.state.appState.thinkingLevel,
|
|
125626
125654
|
colors: host.state.theme.colors,
|
|
125627
125655
|
searchable: true,
|
|
125628
|
-
onSelect: ({ alias, thinkingLevel }) => {
|
|
125656
|
+
onSelect: ({ alias, thinkingLevel, imageEnabled }) => {
|
|
125629
125657
|
host.restoreEditor();
|
|
125630
|
-
performModelSwitch(host, alias, thinkingLevel);
|
|
125658
|
+
performModelSwitch(host, alias, thinkingLevel, imageEnabled);
|
|
125631
125659
|
},
|
|
125632
125660
|
onCancel: () => {
|
|
125633
125661
|
host.restoreEditor();
|
|
125634
125662
|
}
|
|
125635
125663
|
}));
|
|
125636
125664
|
}
|
|
125637
|
-
async function performModelSwitch(host, alias, thinkingLevel) {
|
|
125665
|
+
async function performModelSwitch(host, alias, thinkingLevel, imageEnabled) {
|
|
125638
125666
|
if (isBusy(host.state.appState)) {
|
|
125639
125667
|
host.showError("Cannot switch models while streaming — press Esc or Ctrl-C first.");
|
|
125640
125668
|
return;
|
|
125641
125669
|
}
|
|
125642
125670
|
const prevModel = host.state.appState.model;
|
|
125643
125671
|
const prevThinkingLevel = host.state.appState.thinkingLevel;
|
|
125644
|
-
const
|
|
125672
|
+
const prevImageEnabled = host.state.appState.availableModels[alias]?.capabilities?.includes("image_in") === true;
|
|
125673
|
+
const runtimeChanged = alias !== prevModel || thinkingLevel !== prevThinkingLevel || imageEnabled !== prevImageEnabled;
|
|
125645
125674
|
const overflow = alias !== prevModel ? contextOverflowForModel(host.state.appState, alias) : null;
|
|
125646
125675
|
if (overflow !== null) {
|
|
125647
125676
|
host.showNotice("Storm Breaker(风暴守护者)", `无法切换到模型「${alias}」:当前会话上下文 ${formatTokenCount$1(overflow.currentTokens)} 已超出该模型上限 ${formatTokenCount$1(overflow.maxContextTokens)}。建议先执行 /compact 压缩上下文,或选择上下文窗口更大的模型。`);
|
|
@@ -125665,21 +125694,38 @@ async function performModelSwitch(host, alias, thinkingLevel) {
|
|
|
125665
125694
|
});
|
|
125666
125695
|
let persisted = false;
|
|
125667
125696
|
try {
|
|
125668
|
-
persisted = await persistModelSelection(host, alias, thinkingLevel);
|
|
125697
|
+
persisted = await persistModelSelection(host, alias, thinkingLevel, imageEnabled);
|
|
125669
125698
|
} catch (error) {
|
|
125670
125699
|
const msg = formatErrorMessage(error);
|
|
125671
125700
|
host.showError(`Switched to ${alias}, but failed to save default: ${msg}`);
|
|
125672
125701
|
return;
|
|
125673
125702
|
}
|
|
125703
|
+
if (persisted) {
|
|
125704
|
+
const prevAlias = host.state.appState.availableModels[alias];
|
|
125705
|
+
if (prevAlias !== void 0) {
|
|
125706
|
+
const nextCaps = computeCapabilities(prevAlias.capabilities, imageEnabled);
|
|
125707
|
+
host.setAppState({ availableModels: {
|
|
125708
|
+
...host.state.appState.availableModels,
|
|
125709
|
+
[alias]: {
|
|
125710
|
+
...prevAlias,
|
|
125711
|
+
capabilities: nextCaps
|
|
125712
|
+
}
|
|
125713
|
+
} });
|
|
125714
|
+
}
|
|
125715
|
+
}
|
|
125674
125716
|
const status = runtimeChanged ? `Switched to ${alias} with thinking ${thinkingLevel}.` : persisted ? `Saved ${alias} with thinking ${thinkingLevel} as default.` : `Already using ${alias} with thinking ${thinkingLevel}.`;
|
|
125675
125717
|
host.showStatus(status, host.state.theme.colors.success);
|
|
125676
125718
|
}
|
|
125677
|
-
async function persistModelSelection(host, alias, thinkingLevel) {
|
|
125719
|
+
async function persistModelSelection(host, alias, thinkingLevel, imageEnabled) {
|
|
125678
125720
|
const config = await host.harness.getConfig({ reload: true });
|
|
125679
125721
|
const effectiveThinking = thinkingLevel !== "off";
|
|
125680
125722
|
const existingEffort = config.thinking?.effort;
|
|
125681
125723
|
const newEffort = effectiveThinking ? thinkingLevel : existingEffort;
|
|
125682
|
-
|
|
125724
|
+
const aliasCfg = config.models?.[alias];
|
|
125725
|
+
const prevCaps = aliasCfg?.capabilities;
|
|
125726
|
+
const nextCaps = computeCapabilities(prevCaps, imageEnabled);
|
|
125727
|
+
const capsChanged = prevCaps?.includes("image_in") === true !== imageEnabled;
|
|
125728
|
+
if (config.defaultModel === alias && config.defaultThinking === effectiveThinking && existingEffort === newEffort && !capsChanged) return false;
|
|
125683
125729
|
await host.harness.setConfig({
|
|
125684
125730
|
defaultModel: alias,
|
|
125685
125731
|
defaultThinking: effectiveThinking,
|
|
@@ -125687,10 +125733,28 @@ async function persistModelSelection(host, alias, thinkingLevel) {
|
|
|
125687
125733
|
...config.thinking,
|
|
125688
125734
|
mode: effectiveThinking ? "on" : "off",
|
|
125689
125735
|
effort: newEffort
|
|
125690
|
-
}
|
|
125736
|
+
},
|
|
125737
|
+
models: capsChanged && aliasCfg !== void 0 ? { [alias]: {
|
|
125738
|
+
...aliasCfg,
|
|
125739
|
+
capabilities: nextCaps
|
|
125740
|
+
} } : void 0
|
|
125691
125741
|
});
|
|
125692
125742
|
return true;
|
|
125693
125743
|
}
|
|
125744
|
+
/**
|
|
125745
|
+
* Returns the new capabilities array after toggling 'image_in'. Returns
|
|
125746
|
+
* `undefined` when the result would be empty, so legacy aliases without a
|
|
125747
|
+
* capabilities declaration stay clean (no `capabilities = []` in toml).
|
|
125748
|
+
*/
|
|
125749
|
+
function computeCapabilities(prev, imageEnabled) {
|
|
125750
|
+
if (imageEnabled) {
|
|
125751
|
+
if (prev === void 0) return ["image_in"];
|
|
125752
|
+
return prev.includes("image_in") ? [...prev] : [...prev, "image_in"];
|
|
125753
|
+
}
|
|
125754
|
+
if (prev === void 0) return void 0;
|
|
125755
|
+
const filtered = prev.filter((c) => c !== "image_in");
|
|
125756
|
+
return filtered.length === 0 ? void 0 : filtered;
|
|
125757
|
+
}
|
|
125694
125758
|
function showThemePicker(host) {
|
|
125695
125759
|
host.mountEditorReplacement(new ThemeSelectorComponent({
|
|
125696
125760
|
currentValue: host.state.appState.theme,
|
|
@@ -133020,6 +133084,15 @@ function readImagePath(path) {
|
|
|
133020
133084
|
mimeType: meta.mime
|
|
133021
133085
|
};
|
|
133022
133086
|
}
|
|
133087
|
+
/**
|
|
133088
|
+
* Read an image file from disk into a ClipboardImage. Used when the user
|
|
133089
|
+
* pastes a file URL that the terminal has translated into a text path —
|
|
133090
|
+
* the path points at a real image file, so we load it directly rather
|
|
133091
|
+
* than going through the clipboard native binding.
|
|
133092
|
+
*/
|
|
133093
|
+
function readImageFromPath(path) {
|
|
133094
|
+
return readImagePath(path);
|
|
133095
|
+
}
|
|
133023
133096
|
function readVideoPath(path) {
|
|
133024
133097
|
const mimeType = videoMimeFromPath(path);
|
|
133025
133098
|
if (mimeType === null) return null;
|
|
@@ -133471,6 +133544,16 @@ var EditorKeyboardController = class {
|
|
|
133471
133544
|
return false;
|
|
133472
133545
|
};
|
|
133473
133546
|
editor.onPasteImage = async () => this.handleClipboardImagePaste();
|
|
133547
|
+
editor.onPasteImagePath = async (path) => this.handleImagePathPaste(path);
|
|
133548
|
+
}
|
|
133549
|
+
async handleImagePathPaste(path) {
|
|
133550
|
+
const media = readImageFromPath(path);
|
|
133551
|
+
if (media === null) return;
|
|
133552
|
+
const meta = parseImageMeta(media.bytes);
|
|
133553
|
+
if (meta === null) return;
|
|
133554
|
+
const attachment = this.imageStore.addImage(media.bytes, meta.mime, meta.width, meta.height);
|
|
133555
|
+
this.host.state.editor.insertTextAtCursor?.(`${attachment.placeholder} `);
|
|
133556
|
+
this.host.state.ui.requestRender();
|
|
133474
133557
|
}
|
|
133475
133558
|
clearPendingExit() {
|
|
133476
133559
|
if (!this.pendingExit) return;
|
|
@@ -134413,8 +134496,6 @@ var SessionEventHandler = class {
|
|
|
134413
134496
|
if (event.maxContextTokens !== void 0) patch.maxContextTokens = event.maxContextTokens;
|
|
134414
134497
|
if (event.planMode !== void 0) patch.planMode = event.planMode ? event.planStrategy === "fusion" ? "fusionplan" : this.host.state.appState.planMode === "fusionplan" ? "fusionplan" : "plan" : "off";
|
|
134415
134498
|
if (event.permission !== void 0) patch.permissionMode = event.permission;
|
|
134416
|
-
if (event.model !== void 0) patch.model = event.model;
|
|
134417
|
-
if (event.thinkingLevel !== void 0) patch.thinkingLevel = event.thinkingLevel;
|
|
134418
134499
|
if (Object.keys(patch).length > 0) this.host.setAppState(patch);
|
|
134419
134500
|
}
|
|
134420
134501
|
handleSessionMetaChanged(event) {
|
|
@@ -140734,11 +140815,62 @@ function styleTitle(title, status, colors) {
|
|
|
140734
140815
|
/**
|
|
140735
140816
|
* Custom editor extending pi-tui Editor with app-level keybindings.
|
|
140736
140817
|
*/
|
|
140737
|
-
const ANSI_SGR =
|
|
140818
|
+
const ANSI_SGR = /\[[0-9;]*m/g;
|
|
140738
140819
|
const PASTE_MARKER_RE = /\[paste #(\d+)(?: (?:\+\d+ lines|\d+ chars))?\]/g;
|
|
140739
140820
|
const BRACKET_PASTE_START = "\x1B[200~";
|
|
140740
140821
|
const BRACKET_PASTE_END = "\x1B[201~";
|
|
140741
|
-
const
|
|
140822
|
+
const BRACKETED_IMAGE_PATH_REGEX = /\.(?:png|jpe?g|gif|webp)$/i;
|
|
140823
|
+
const BRACKETED_IMAGE_PATH_BOUNDARY_REGEX = /\.(?:png|jpe?g|gif|webp)(?=$|["']?\s)/gi;
|
|
140824
|
+
const SHELL_ESCAPED_PATH_CHAR_REGEX = /\\([\\\s'"()[\]{}&;<>|?*!$`])/g;
|
|
140825
|
+
function isPastedPathSeparator(char) {
|
|
140826
|
+
return char === void 0 || char === " " || char === " " || char === "\r" || char === "\n";
|
|
140827
|
+
}
|
|
140828
|
+
function imagePathBoundaryEnd(payload, segmentStart, extensionEnd) {
|
|
140829
|
+
const quote = payload[segmentStart];
|
|
140830
|
+
const afterExtension = payload[extensionEnd];
|
|
140831
|
+
if (quote === "\"" || quote === "'") return afterExtension === quote && isPastedPathSeparator(payload[extensionEnd + 1]) ? extensionEnd + 1 : void 0;
|
|
140832
|
+
if (isPastedPathSeparator(afterExtension)) return extensionEnd;
|
|
140833
|
+
}
|
|
140834
|
+
function normalizePastedImagePath(path) {
|
|
140835
|
+
const trimmed = path.trim();
|
|
140836
|
+
const first = trimmed[0];
|
|
140837
|
+
const last = trimmed[trimmed.length - 1];
|
|
140838
|
+
return (trimmed.length > 1 && (first === "\"" || first === "'") && last === first ? trimmed.slice(1, -1) : trimmed).replace(SHELL_ESCAPED_PATH_CHAR_REGEX, "$1");
|
|
140839
|
+
}
|
|
140840
|
+
/**
|
|
140841
|
+
* If a bracketed paste contains only image file paths (one or more,
|
|
140842
|
+
* space/quote separated, all with image extensions), return them. Returns
|
|
140843
|
+
* `undefined` when the paste is mixed text + paths or contains non-image
|
|
140844
|
+
* content — in that case the caller should fall through to normal text
|
|
140845
|
+
* paste. Mirrors oh-my-pi's approach so pasting a Finder-copied image
|
|
140846
|
+
* file becomes a multimodal image attachment instead of a text path the
|
|
140847
|
+
* agent would have to Read manually.
|
|
140848
|
+
*/
|
|
140849
|
+
function extractBracketedImagePastePaths(data) {
|
|
140850
|
+
if (!data.includes(BRACKET_PASTE_START)) return void 0;
|
|
140851
|
+
const startIndex = data.indexOf(BRACKET_PASTE_START);
|
|
140852
|
+
const endIndex = data.indexOf(BRACKET_PASTE_END, startIndex + 6);
|
|
140853
|
+
if (endIndex === -1) return void 0;
|
|
140854
|
+
const pasted = data.slice(startIndex + 6, endIndex).trim();
|
|
140855
|
+
if (pasted.length === 0) return void 0;
|
|
140856
|
+
const paths = [];
|
|
140857
|
+
let segmentStart = 0;
|
|
140858
|
+
BRACKETED_IMAGE_PATH_BOUNDARY_REGEX.lastIndex = 0;
|
|
140859
|
+
for (let match = BRACKETED_IMAGE_PATH_BOUNDARY_REGEX.exec(pasted); match !== null; match = BRACKETED_IMAGE_PATH_BOUNDARY_REGEX.exec(pasted)) {
|
|
140860
|
+
const extensionEnd = match.index + match[0].length;
|
|
140861
|
+
const boundaryEnd = imagePathBoundaryEnd(pasted, segmentStart, extensionEnd);
|
|
140862
|
+
if (boundaryEnd === void 0) continue;
|
|
140863
|
+
const path = normalizePastedImagePath(pasted.slice(segmentStart, boundaryEnd));
|
|
140864
|
+
if (path.length === 0 || !BRACKETED_IMAGE_PATH_REGEX.test(path)) return void 0;
|
|
140865
|
+
paths.push(path);
|
|
140866
|
+
segmentStart = boundaryEnd;
|
|
140867
|
+
while (segmentStart < pasted.length && isPastedPathSeparator(pasted[segmentStart])) segmentStart += 1;
|
|
140868
|
+
BRACKETED_IMAGE_PATH_BOUNDARY_REGEX.lastIndex = segmentStart;
|
|
140869
|
+
}
|
|
140870
|
+
if (paths.length === 0 || segmentStart !== pasted.length) return void 0;
|
|
140871
|
+
return paths;
|
|
140872
|
+
}
|
|
140873
|
+
const KITTY_CSI_U = /^\[(\d+);(\d+)((?::\d+)*)u$/;
|
|
140742
140874
|
const CAPS_LOCK_BIT = 64;
|
|
140743
140875
|
const CTRL_BIT = 4;
|
|
140744
140876
|
const SHIFT_BIT = 1;
|
|
@@ -140770,7 +140902,7 @@ function normalizeCapsLockedCtrl(data) {
|
|
|
140770
140902
|
if (codepoint < 65 || codepoint > 90) return data;
|
|
140771
140903
|
const loweredCodepoint = codepoint + 32;
|
|
140772
140904
|
const strippedModifier = (modifier & -65) + 1;
|
|
140773
|
-
return
|
|
140905
|
+
return `[${String(loweredCodepoint)};${String(strippedModifier)}${tail}u`;
|
|
140774
140906
|
}
|
|
140775
140907
|
/** Convert a visible-char index (ANSI-stripped) back to an index into the raw ANSI-bearing string. */
|
|
140776
140908
|
function mapVisibleIdxToRaw(line, visibleIdx) {
|
|
@@ -140821,6 +140953,15 @@ var CustomEditor = class extends Editor {
|
|
|
140821
140953
|
* the next keystroke.
|
|
140822
140954
|
*/
|
|
140823
140955
|
onPasteImage;
|
|
140956
|
+
/**
|
|
140957
|
+
* Called when a bracketed paste contains only image file paths (e.g.
|
|
140958
|
+
* the user copied an image file in Finder and pasted — the terminal
|
|
140959
|
+
* translates the file URL into a text path). The host loads each path
|
|
140960
|
+
* from disk and registers it as an image attachment, so the paste
|
|
140961
|
+
* becomes a multimodal image input instead of a text path the agent
|
|
140962
|
+
* would have to Read manually.
|
|
140963
|
+
*/
|
|
140964
|
+
onPasteImagePath;
|
|
140824
140965
|
/** Fires exactly once when the user first types anything into the editor. */
|
|
140825
140966
|
onFirstInput;
|
|
140826
140967
|
firstInputFired = false;
|
|
@@ -140912,6 +141053,15 @@ var CustomEditor = class extends Editor {
|
|
|
140912
141053
|
if (!normalized.includes(BRACKET_PASTE_END)) this.consumingPaste = true;
|
|
140913
141054
|
return;
|
|
140914
141055
|
}
|
|
141056
|
+
const pastedImagePaths = extractBracketedImagePastePaths(normalized);
|
|
141057
|
+
if (pastedImagePaths !== void 0 && this.onPasteImagePath !== void 0) {
|
|
141058
|
+
const handler = this.onPasteImagePath;
|
|
141059
|
+
(async () => {
|
|
141060
|
+
for (const path of pastedImagePaths) await handler(path);
|
|
141061
|
+
})();
|
|
141062
|
+
if (!normalized.includes(BRACKET_PASTE_END)) this.consumingPaste = true;
|
|
141063
|
+
return;
|
|
141064
|
+
}
|
|
140915
141065
|
if (matchesKey(normalized, process.platform === "win32" ? "alt+v" : Key.ctrl("v"))) {
|
|
140916
141066
|
if (this.expandPasteMarkerAtCursor()) return;
|
|
140917
141067
|
if (this.onPasteImage !== void 0) {
|
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-DxQ8R4AP.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);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scream-code",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
4
4
|
"description": "A terminal-native AI agent for builders",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ScreamCli",
|
|
@@ -41,20 +41,6 @@
|
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
|
-
"scripts": {
|
|
45
|
-
"build": "tsdown",
|
|
46
|
-
"dev": "node scripts/dev.mjs",
|
|
47
|
-
"dev:cli-only": "tsx --import ../../build/register-raw-text-loader.mjs ./src/main.ts",
|
|
48
|
-
"dev:prod": "node dist/main.mjs",
|
|
49
|
-
"clean": "rm -rf dist",
|
|
50
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
51
|
-
"test": "pnpm -w run build:packages && vitest run",
|
|
52
|
-
"e2e": "pnpm -w run build:packages && SCREAM_E2E=1 vitest run test/e2e",
|
|
53
|
-
"e2e:real": "pnpm -w run build:packages && SCREAM_E2E_REAL=1 vitest run test/e2e/real-llm-smoke.e2e.test.ts",
|
|
54
|
-
"preinstall": "node -e \"console.log('\\n📦 正在安装 scream-code,请稍候...\\n')\"",
|
|
55
|
-
"postinstall": "node scripts/postinstall.mjs",
|
|
56
|
-
"smoke": "node dist/main.mjs --version"
|
|
57
|
-
},
|
|
58
44
|
"dependencies": {
|
|
59
45
|
"@earendil-works/pi-tui": "^0.80.2",
|
|
60
46
|
"@mariozechner/clipboard": "^0.3.2",
|
|
@@ -68,15 +54,29 @@
|
|
|
68
54
|
},
|
|
69
55
|
"devDependencies": {
|
|
70
56
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
71
|
-
"@scream-code/agent-core": "workspace:^",
|
|
72
|
-
"@scream-code/config": "workspace:^",
|
|
73
|
-
"@scream-code/memory": "workspace:*",
|
|
74
|
-
"@scream-code/migration-legacy": "workspace:^",
|
|
75
|
-
"@scream-code/scream-code-sdk": "workspace:^",
|
|
76
57
|
"@types/semver": "^7.7.0",
|
|
77
|
-
"tsx": "^4.21.0"
|
|
58
|
+
"tsx": "^4.21.0",
|
|
59
|
+
"@scream-code/agent-core": "^0.7.0",
|
|
60
|
+
"@scream-code/config": "^0.7.0",
|
|
61
|
+
"@scream-code/memory": "0.7.0",
|
|
62
|
+
"@scream-code/migration-legacy": "^0.7.0",
|
|
63
|
+
"@scream-code/scream-code-sdk": "^0.7.0"
|
|
78
64
|
},
|
|
79
65
|
"engines": {
|
|
80
66
|
"node": ">=22.19.0"
|
|
67
|
+
},
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "tsdown",
|
|
70
|
+
"dev": "node scripts/dev.mjs",
|
|
71
|
+
"dev:cli-only": "tsx --import ../../build/register-raw-text-loader.mjs ./src/main.ts",
|
|
72
|
+
"dev:prod": "node dist/main.mjs",
|
|
73
|
+
"clean": "rm -rf dist",
|
|
74
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
75
|
+
"test": "pnpm -w run build:packages && vitest run",
|
|
76
|
+
"e2e": "pnpm -w run build:packages && SCREAM_E2E=1 vitest run test/e2e",
|
|
77
|
+
"e2e:real": "pnpm -w run build:packages && SCREAM_E2E_REAL=1 vitest run test/e2e/real-llm-smoke.e2e.test.ts",
|
|
78
|
+
"preinstall": "node -e \"console.log('\\n📦 正在安装 scream-code,请稍候...\\n')\"",
|
|
79
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
80
|
+
"smoke": "node dist/main.mjs --version"
|
|
81
81
|
}
|
|
82
|
-
}
|
|
82
|
+
}
|