scream-code 0.18.7 → 0.18.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/{app-IU7G9gs0.mjs → app-Db7f8Kja.mjs} +249 -193
- package/dist/{dispatch-7Mas_Tvb.mjs → dispatch-BPfUTccZ.mjs} +378 -20
- package/dist/{dispatch-BqBnrIMj.mjs → dispatch-zsFzFFoY.mjs} +1 -1
- package/dist/main.mjs +1 -1
- package/dist/{src-CQwXASmd.mjs → src-ClB_Hzp9.mjs} +280 -107
- package/dist/{src-ChTWl9Cn.mjs → src-DA34cXSv.mjs} +1 -1
- package/dist/{text-input-dialog-D7dm6kak.mjs → text-input-dialog-CFRUSCi6.mjs} +1 -1
- package/dist/{text-input-dialog-gDr3i7xz.mjs → text-input-dialog-DHDsHCqR.mjs} +58 -4
- package/package.json +3 -4
|
@@ -4,9 +4,9 @@ import { dirname as __cjsShimDirname } from 'node:path';
|
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
|
|
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
|
|
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 createEmbeddingEngine, 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-ClB_Hzp9.mjs";
|
|
8
8
|
import { n as require_base64_js, t as XMLParser } from "./XMLParser-DFAnGqkc.mjs";
|
|
9
|
-
import { a as assertScreamHostIdentity, i as t, n as getLocale, o as createScreamDefaultHeaders, r as setLocale, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as assertScreamHostIdentity, i as t, n as getLocale, o as createScreamDefaultHeaders, r as setLocale, t as TextInputDialogComponent } from "./text-input-dialog-DHDsHCqR.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";
|
|
@@ -62231,7 +62231,7 @@ var KnowledgeLookupTool = class {
|
|
|
62231
62231
|
const llm = { generate: async (systemPrompt, userPrompt) => {
|
|
62232
62232
|
return this.agent.generateText(systemPrompt, userPrompt);
|
|
62233
62233
|
} };
|
|
62234
|
-
const { multiSearchWithTrace } = await import("./src-
|
|
62234
|
+
const { multiSearchWithTrace } = await import("./src-DA34cXSv.mjs");
|
|
62235
62235
|
const { results, trace } = await multiSearchWithTrace(store, llm, query, {
|
|
62236
62236
|
topK,
|
|
62237
62237
|
skipLlm: args.deep !== true
|
|
@@ -70622,6 +70622,37 @@ var FsScanCache = class {
|
|
|
70622
70622
|
*/
|
|
70623
70623
|
const scanCache = new FsScanCache();
|
|
70624
70624
|
//#endregion
|
|
70625
|
+
//#region ../../packages/agent-core/src/tools/builtin/file/mutation-queue.ts
|
|
70626
|
+
/**
|
|
70627
|
+
* Per-path serialization for file mutations.
|
|
70628
|
+
*
|
|
70629
|
+
* Within one turn a tool batch runs concurrently (`runToolCallBatch` settles
|
|
70630
|
+
* it with `Promise.allSettled`), and sub-agents share this process. Two writes
|
|
70631
|
+
* to the same file can therefore interleave their read→modify→write steps and
|
|
70632
|
+
* lose an update — most visibly two edits whose `old_string` windows overlap.
|
|
70633
|
+
* Mutations against the same resolved path run one after another; different
|
|
70634
|
+
* paths still run in parallel, so throughput is unchanged in the common case.
|
|
70635
|
+
*
|
|
70636
|
+
* Scope: structured write tools only (`Write`, `Edit`). Shell commands that
|
|
70637
|
+
* write files themselves (redirection, scripts) are outside the reach of an
|
|
70638
|
+
* in-process queue, exactly like every other file-tool guarantee.
|
|
70639
|
+
*
|
|
70640
|
+
* Keys are `path.resolve`d so relative and absolute spellings of the same
|
|
70641
|
+
* target share one chain. Symlinked aliases of one target are not merged; the
|
|
70642
|
+
* tools resolve access paths before calling this anyway.
|
|
70643
|
+
*/
|
|
70644
|
+
const tails = /* @__PURE__ */ new Map();
|
|
70645
|
+
function withFileMutationLock(filePath, task) {
|
|
70646
|
+
const key = path$8.resolve(filePath);
|
|
70647
|
+
const result = (tails.get(key) ?? Promise.resolve()).then(task, task);
|
|
70648
|
+
const tail = result.then(() => void 0, () => void 0);
|
|
70649
|
+
tails.set(key, tail);
|
|
70650
|
+
tail.then(() => {
|
|
70651
|
+
if (tails.get(key) === tail) tails.delete(key);
|
|
70652
|
+
});
|
|
70653
|
+
return result;
|
|
70654
|
+
}
|
|
70655
|
+
//#endregion
|
|
70625
70656
|
//#region ../../packages/agent-core/src/tools/builtin/file/conflict-detect.ts
|
|
70626
70657
|
/**
|
|
70627
70658
|
* Detect unresolved git merge conflict markers in read output.
|
|
@@ -70953,7 +70984,7 @@ var EditTool = class {
|
|
|
70953
70984
|
pathClass: this.jian.pathClass(),
|
|
70954
70985
|
homeDir: this.jian.gethome()
|
|
70955
70986
|
}),
|
|
70956
|
-
execute: ({ signal }) => this.execution(args, path, signal)
|
|
70987
|
+
execute: ({ signal }) => withFileMutationLock(path, () => this.execution(args, path, signal))
|
|
70957
70988
|
};
|
|
70958
70989
|
}
|
|
70959
70990
|
async execution(args, safePath, signal) {
|
|
@@ -76914,7 +76945,7 @@ var WriteTool = class {
|
|
|
76914
76945
|
pathClass: this.jian.pathClass(),
|
|
76915
76946
|
homeDir: this.jian.gethome()
|
|
76916
76947
|
}),
|
|
76917
|
-
execute: ({ signal }) => this.execution(args, path, signal)
|
|
76948
|
+
execute: ({ signal }) => withFileMutationLock(path, () => this.execution(args, path, signal))
|
|
76918
76949
|
};
|
|
76919
76950
|
}
|
|
76920
76951
|
async execution(args, safePath, signal) {
|
|
@@ -107549,7 +107580,7 @@ var Agent = class {
|
|
|
107549
107580
|
this.eventBus = new EventSubscriptionBus();
|
|
107550
107581
|
const embedCacheDir = options.screamHomeDir !== void 0 ? join$1(options.screamHomeDir, "cache", "fastembed") : void 0;
|
|
107551
107582
|
this.embeddingCacheDir = embedCacheDir;
|
|
107552
|
-
this.sharedEmbeddingEngine =
|
|
107583
|
+
this.sharedEmbeddingEngine = createEmbeddingEngine(embedCacheDir);
|
|
107553
107584
|
this.log = options.log ?? log;
|
|
107554
107585
|
this.blobStore = options.homedir ? new BlobStore({ blobsDir: join$1(options.homedir, "blobs") }) : void 0;
|
|
107555
107586
|
this.records = new AgentRecords(this, options.persistence ?? (options.homedir ? new FileSystemAgentRecordPersistence(join$1(options.homedir, "wire.jsonl"), {
|
|
@@ -133525,12 +133556,12 @@ function getEmbeddingCacheDir() {
|
|
|
133525
133556
|
return dir;
|
|
133526
133557
|
}
|
|
133527
133558
|
/**
|
|
133528
|
-
* Any usable cache: the
|
|
133559
|
+
* Any usable cache: every file the embedding runtime needs is on disk.
|
|
133529
133560
|
*
|
|
133530
|
-
*
|
|
133531
|
-
* the
|
|
133532
|
-
*
|
|
133533
|
-
*
|
|
133561
|
+
* Loading then never downloads. A cache that only looks installed (weights
|
|
133562
|
+
* without the tokenizer, for instance) is deliberately *not* counted as ready:
|
|
133563
|
+
* the setup flow repairs it through one clean re-download instead of failing
|
|
133564
|
+
* halfway through a load, and reporting it as present would block that repair.
|
|
133534
133565
|
* The existence check itself lives in @scream-code/memory next to the cache
|
|
133535
133566
|
* layout it inspects.
|
|
133536
133567
|
*/
|
|
@@ -133575,15 +133606,21 @@ function getEmbeddingStatus() {
|
|
|
133575
133606
|
* Concurrent calls join the in-flight download and share its result instead
|
|
133576
133607
|
* of failing — the startup warm-up and a user-initiated download must never
|
|
133577
133608
|
* race into a spurious "download already in progress" error.
|
|
133609
|
+
*
|
|
133610
|
+
* `onProgress` observes the attempt (byte progress, then verify/load phases)
|
|
133611
|
+
* so the caller can keep a spinner honest; it is detached when the attempt
|
|
133612
|
+
* settles either way.
|
|
133578
133613
|
*/
|
|
133579
|
-
async function startManualEmbeddingDownload() {
|
|
133614
|
+
async function startManualEmbeddingDownload(onProgress) {
|
|
133580
133615
|
if (embeddingEngineInstance === void 0) return failureResult("embedding engine not initialized");
|
|
133581
133616
|
if (embeddingEngineInstance.available) return {
|
|
133582
133617
|
ok: true,
|
|
133583
133618
|
alreadyReady: true
|
|
133584
133619
|
};
|
|
133585
133620
|
if (downloadPromise !== void 0) return downloadPromise;
|
|
133621
|
+
embeddingEngineInstance.setProgressListener?.(onProgress);
|
|
133586
133622
|
downloadPromise = performDownload().finally(() => {
|
|
133623
|
+
embeddingEngineInstance?.setProgressListener?.(void 0);
|
|
133587
133624
|
downloadPromise = void 0;
|
|
133588
133625
|
});
|
|
133589
133626
|
return downloadPromise;
|
|
@@ -133610,7 +133647,7 @@ async function performDownload() {
|
|
|
133610
133647
|
let ok = await embeddingEngineInstance.ensureReady();
|
|
133611
133648
|
let error = ok ? void 0 : embeddingEngineInstance.lastError;
|
|
133612
133649
|
if (!ok) {
|
|
133613
|
-
if (classifyEmbeddingFailure(error)
|
|
133650
|
+
if (classifyEmbeddingFailure(error) === "archive") {
|
|
133614
133651
|
clearEmbeddingModelCache(getEmbeddingCacheDir());
|
|
133615
133652
|
ok = await embeddingEngineInstance.ensureReady();
|
|
133616
133653
|
error = ok ? void 0 : embeddingEngineInstance.lastError;
|
|
@@ -133636,7 +133673,7 @@ async function performDownload() {
|
|
|
133636
133673
|
*/
|
|
133637
133674
|
function embeddingFailureHint(kind) {
|
|
133638
133675
|
switch (kind) {
|
|
133639
|
-
case "
|
|
133676
|
+
case "install": return t("knowledge.embedding_install_hint");
|
|
133640
133677
|
case "archive": return t("knowledge.embedding_cache_corrupt_hint");
|
|
133641
133678
|
case "network": return t("knowledge.embedding_network_hint");
|
|
133642
133679
|
default: return t("knowledge.embedding_unknown_hint");
|
|
@@ -133654,6 +133691,27 @@ function embeddingFailureDetail(kind, error) {
|
|
|
133654
133691
|
return [embeddingFailureHint(kind), error?.split("\n")[0]].filter(Boolean).join("\n");
|
|
133655
133692
|
}
|
|
133656
133693
|
//#endregion
|
|
133694
|
+
//#region src/tui/utils/embedding-progress-label.ts
|
|
133695
|
+
/**
|
|
133696
|
+
* Spinner label for an in-flight model load: byte progress while downloading
|
|
133697
|
+
* ("12.3 MB / 52.9 MB (23%)"), then the verify and load phases.
|
|
133698
|
+
*
|
|
133699
|
+
* Without a content-length the byte count is still reported, so the number
|
|
133700
|
+
* visibly moves on a slow link instead of looking frozen — the failure mode
|
|
133701
|
+
* that used to leave users staring at a generic spinner.
|
|
133702
|
+
*/
|
|
133703
|
+
function embeddingProgressLabel(progress) {
|
|
133704
|
+
if (progress.phase === "verify") return t("kw.embedding_verifying");
|
|
133705
|
+
if (progress.phase === "load") return t("kw.embedding_loading");
|
|
133706
|
+
const done = `${(progress.received / 1048576).toFixed(1)} MB`;
|
|
133707
|
+
if (progress.total === void 0) return t("kw.embedding_progress_unknown", { done });
|
|
133708
|
+
return t("kw.embedding_progress", {
|
|
133709
|
+
done,
|
|
133710
|
+
total: `${(progress.total / 1048576).toFixed(1)} MB`,
|
|
133711
|
+
percent: `${Math.min(100, Math.floor(progress.received / progress.total * 100))}`
|
|
133712
|
+
});
|
|
133713
|
+
}
|
|
133714
|
+
//#endregion
|
|
133657
133715
|
//#region src/tui/commands/experimental-flags.ts
|
|
133658
133716
|
let snapshot = {};
|
|
133659
133717
|
/** Replace the cached flag snapshot. Call once after fetching via `harness.getExperimentalFlags()`. */
|
|
@@ -133917,6 +133975,20 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
133917
133975
|
priority: 198,
|
|
133918
133976
|
availability: "always"
|
|
133919
133977
|
},
|
|
133978
|
+
{
|
|
133979
|
+
name: "hotkeys",
|
|
133980
|
+
aliases: ["keys"],
|
|
133981
|
+
description: "registry.hotkeys_desc",
|
|
133982
|
+
priority: 197,
|
|
133983
|
+
availability: "always"
|
|
133984
|
+
},
|
|
133985
|
+
{
|
|
133986
|
+
name: "copy",
|
|
133987
|
+
aliases: ["yank"],
|
|
133988
|
+
description: "registry.copy_desc",
|
|
133989
|
+
priority: 196,
|
|
133990
|
+
availability: "always"
|
|
133991
|
+
},
|
|
133920
133992
|
{
|
|
133921
133993
|
name: "make-skill",
|
|
133922
133994
|
aliases: ["makeskill", "craftskill"],
|
|
@@ -134555,6 +134627,10 @@ var ChoicePickerComponent = class extends Container {
|
|
|
134555
134627
|
searchable: opts.searchable === true
|
|
134556
134628
|
});
|
|
134557
134629
|
}
|
|
134630
|
+
/** Panel replaced by another one before a choice was made. */
|
|
134631
|
+
dispose() {
|
|
134632
|
+
this.opts.onDispose?.();
|
|
134633
|
+
}
|
|
134558
134634
|
handleInput(data) {
|
|
134559
134635
|
if (matchesKey(data, Key.escape)) {
|
|
134560
134636
|
if (this.list.clearQuery()) return;
|
|
@@ -134632,9 +134708,10 @@ function optionLabelStyle(option, selected, colors) {
|
|
|
134632
134708
|
//#region src/tui/utils/connect-catalog.ts
|
|
134633
134709
|
/**
|
|
134634
134710
|
* Resolve the catalog request for /config.
|
|
134635
|
-
* - /config → remote-first catalog browser
|
|
134636
134711
|
* - /config diy → hidden manual provider setup (not shown in help)
|
|
134637
134712
|
* - /config image → hidden image-generation API setup (not shown in help)
|
|
134713
|
+
* - anything else → the caller must ask first: a bare `/config` opens the
|
|
134714
|
+
* entry menu (shortcut directory / DIY / image) before any flow starts.
|
|
134638
134715
|
*/
|
|
134639
134716
|
function resolveConnectCatalogRequest(args) {
|
|
134640
134717
|
const trimmed = args.trim().toLowerCase();
|
|
@@ -135257,6 +135334,71 @@ async function handleConnectCommand(host, args) {
|
|
|
135257
135334
|
await handleDiyConfig(host);
|
|
135258
135335
|
return;
|
|
135259
135336
|
}
|
|
135337
|
+
const target = await promptConfigEntry(host);
|
|
135338
|
+
if (target === void 0) return;
|
|
135339
|
+
if (target === "diy") {
|
|
135340
|
+
await handleDiyConfig(host);
|
|
135341
|
+
return;
|
|
135342
|
+
}
|
|
135343
|
+
if (target === "image") {
|
|
135344
|
+
await handleImageConfig(host);
|
|
135345
|
+
return;
|
|
135346
|
+
}
|
|
135347
|
+
await runCatalogConnectFlow(host, url);
|
|
135348
|
+
}
|
|
135349
|
+
/**
|
|
135350
|
+
* Entry menu for a bare `/config`. Mirrors `promptImageProviderPreset`: mount
|
|
135351
|
+
* the picker, resolve on select/cancel, and hand the editor back in both cases.
|
|
135352
|
+
*/
|
|
135353
|
+
function promptConfigEntry(host) {
|
|
135354
|
+
return new Promise((resolve) => {
|
|
135355
|
+
let settled = false;
|
|
135356
|
+
const settle = (value) => {
|
|
135357
|
+
if (settled) return;
|
|
135358
|
+
settled = true;
|
|
135359
|
+
resolve(value);
|
|
135360
|
+
};
|
|
135361
|
+
const picker = new ChoicePickerComponent({
|
|
135362
|
+
title: t("config.entry_title"),
|
|
135363
|
+
hint: t("config.entry_hint"),
|
|
135364
|
+
colors: host.state.theme.colors,
|
|
135365
|
+
options: [
|
|
135366
|
+
{
|
|
135367
|
+
value: "catalog",
|
|
135368
|
+
label: t("config.entry_quick"),
|
|
135369
|
+
description: t("config.entry_quick_desc")
|
|
135370
|
+
},
|
|
135371
|
+
{
|
|
135372
|
+
value: "diy",
|
|
135373
|
+
label: t("config.entry_diy"),
|
|
135374
|
+
description: t("config.entry_diy_desc")
|
|
135375
|
+
},
|
|
135376
|
+
{
|
|
135377
|
+
value: "image",
|
|
135378
|
+
label: t("config.entry_image"),
|
|
135379
|
+
description: t("config.entry_image_desc")
|
|
135380
|
+
}
|
|
135381
|
+
],
|
|
135382
|
+
onSelect: (value) => {
|
|
135383
|
+
settle(value);
|
|
135384
|
+
host.restoreEditor();
|
|
135385
|
+
},
|
|
135386
|
+
onCancel: () => {
|
|
135387
|
+
settle(void 0);
|
|
135388
|
+
host.restoreEditor();
|
|
135389
|
+
},
|
|
135390
|
+
onDispose: () => {
|
|
135391
|
+
settle(void 0);
|
|
135392
|
+
}
|
|
135393
|
+
});
|
|
135394
|
+
host.mountEditorReplacement(picker);
|
|
135395
|
+
});
|
|
135396
|
+
}
|
|
135397
|
+
/**
|
|
135398
|
+
* The shortcut flow: remote catalog (with cache and built-in fallbacks) →
|
|
135399
|
+
* provider → model → API key → apply, then refresh the running config.
|
|
135400
|
+
*/
|
|
135401
|
+
async function runCatalogConnectFlow(host, url) {
|
|
135260
135402
|
let catalog;
|
|
135261
135403
|
const controller = new AbortController();
|
|
135262
135404
|
const cancel = () => {
|
|
@@ -140610,7 +140752,7 @@ async function guidedGoalSetup(host) {
|
|
|
140610
140752
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
140611
140753
|
return;
|
|
140612
140754
|
}
|
|
140613
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
140755
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-CFRUSCi6.mjs");
|
|
140614
140756
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
140615
140757
|
title: t("goal.setup_title_initial"),
|
|
140616
140758
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -140631,7 +140773,7 @@ async function guidedGoalSetup(host) {
|
|
|
140631
140773
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
140632
140774
|
}
|
|
140633
140775
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
140634
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
140776
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-CFRUSCi6.mjs");
|
|
140635
140777
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
140636
140778
|
title: t("goal.wizard_title", { objective }),
|
|
140637
140779
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -147461,6 +147603,7 @@ function buildRows(servers) {
|
|
|
147461
147603
|
const capLabels = getCapabilityLabels();
|
|
147462
147604
|
const capInfo = (s.capabilities ?? []).map((c) => capLabels[c] ?? c).join(" ");
|
|
147463
147605
|
const errorInfo = s.error ? ` — ${sanitizeDesc(s.error)}` : "";
|
|
147606
|
+
const pluginInfo = pluginIdFromMcpRuntimeName(s.name) !== void 0 ? t("mcp.plugin_owned") : "";
|
|
147464
147607
|
rows.push({
|
|
147465
147608
|
kind: "installed",
|
|
147466
147609
|
name: s.name,
|
|
@@ -147472,6 +147615,7 @@ function buildRows(servers) {
|
|
|
147472
147615
|
statusLabel,
|
|
147473
147616
|
toolInfo,
|
|
147474
147617
|
capInfo,
|
|
147618
|
+
pluginInfo,
|
|
147475
147619
|
errorInfo
|
|
147476
147620
|
].filter(Boolean).join(" ")
|
|
147477
147621
|
});
|
|
@@ -147515,6 +147659,14 @@ async function handleEnter(host, row) {
|
|
|
147515
147659
|
}
|
|
147516
147660
|
async function handleDelete$1(host, row) {
|
|
147517
147661
|
if (row.kind !== "installed" || !row.status || row.status === "__section" || row.status === "__empty") return;
|
|
147662
|
+
const pluginId = pluginIdFromMcpRuntimeName(row.name);
|
|
147663
|
+
if (pluginId !== void 0) {
|
|
147664
|
+
host.showError(t("mcp.uninstall_plugin_blocked", {
|
|
147665
|
+
name: row.label,
|
|
147666
|
+
plugin: pluginId
|
|
147667
|
+
}));
|
|
147668
|
+
return;
|
|
147669
|
+
}
|
|
147518
147670
|
if (!await confirmAction(host, t("mcp.uninstall_confirm", { name: row.label }))) return;
|
|
147519
147671
|
await uninstallMcp(host, row.name);
|
|
147520
147672
|
}
|
|
@@ -147613,7 +147765,8 @@ async function disableMcp(host, name) {
|
|
|
147613
147765
|
if (!session) return;
|
|
147614
147766
|
try {
|
|
147615
147767
|
await session.stopMcpServer(name);
|
|
147616
|
-
|
|
147768
|
+
const note = pluginIdFromMcpRuntimeName(name) !== void 0 ? ` ${t("mcp.plugin_owned_stop_note")}` : "";
|
|
147769
|
+
host.showStatus(t("mcp.disabled_done", { name }) + note);
|
|
147617
147770
|
} catch (error) {
|
|
147618
147771
|
host.showError(t("mcp.disable_failed", { msg: error instanceof Error ? error.message : String(error) }));
|
|
147619
147772
|
}
|
|
@@ -147628,12 +147781,68 @@ async function enableMcp(host, name) {
|
|
|
147628
147781
|
host.showError(t("mcp.start_failed", { msg: error instanceof Error ? error.message : String(error) }));
|
|
147629
147782
|
}
|
|
147630
147783
|
}
|
|
147784
|
+
/**
|
|
147785
|
+
* Project-level mcp.json files (cwd + parent chain) that declare `name`.
|
|
147786
|
+
*
|
|
147787
|
+
* The runtime list cannot tell where a server came from, but a server declared
|
|
147788
|
+
* by a project config is re-loaded on every start no matter what we delete from
|
|
147789
|
+
* the user-level file — removing it there is the same silent lie as removing a
|
|
147790
|
+
* plugin-owned server. Paths come from the core's own resolver so the rule that
|
|
147791
|
+
* decides "which files count" cannot drift.
|
|
147792
|
+
*/
|
|
147793
|
+
function projectConfigFilesDeclaring(name) {
|
|
147794
|
+
let parents;
|
|
147795
|
+
let project;
|
|
147796
|
+
try {
|
|
147797
|
+
const resolved = resolveMcpJsonPaths({
|
|
147798
|
+
cwd: process.cwd(),
|
|
147799
|
+
homeDir: getDataDir()
|
|
147800
|
+
});
|
|
147801
|
+
parents = resolved.parents;
|
|
147802
|
+
project = resolved.project;
|
|
147803
|
+
} catch {
|
|
147804
|
+
return [];
|
|
147805
|
+
}
|
|
147806
|
+
return [...parents, project].filter((file) => {
|
|
147807
|
+
if (!existsSync(file)) return false;
|
|
147808
|
+
try {
|
|
147809
|
+
const parsed = JSON.parse(readFileSync(file, "utf-8"));
|
|
147810
|
+
return parsed !== null && typeof parsed === "object" && parsed.mcpServers !== void 0 && Object.hasOwn(parsed.mcpServers, name);
|
|
147811
|
+
} catch {
|
|
147812
|
+
return false;
|
|
147813
|
+
}
|
|
147814
|
+
});
|
|
147815
|
+
}
|
|
147631
147816
|
async function uninstallMcp(host, name) {
|
|
147632
147817
|
const session = host.session;
|
|
147633
147818
|
if (!session) return;
|
|
147819
|
+
const pluginId = pluginIdFromMcpRuntimeName(name);
|
|
147820
|
+
if (pluginId !== void 0) {
|
|
147821
|
+
host.showError(t("mcp.uninstall_plugin_blocked", {
|
|
147822
|
+
name,
|
|
147823
|
+
plugin: pluginId
|
|
147824
|
+
}));
|
|
147825
|
+
return;
|
|
147826
|
+
}
|
|
147827
|
+
const projectFiles = projectConfigFilesDeclaring(name);
|
|
147828
|
+
if (projectFiles.length > 0) {
|
|
147829
|
+
host.showError(t("mcp.uninstall_project_owned", {
|
|
147830
|
+
name,
|
|
147831
|
+
files: projectFiles.join(", ")
|
|
147832
|
+
}));
|
|
147833
|
+
return;
|
|
147834
|
+
}
|
|
147634
147835
|
try {
|
|
147635
147836
|
await session.removeMcpServer(name);
|
|
147636
147837
|
await removeMcpConfig(host, name);
|
|
147838
|
+
let stillListed = false;
|
|
147839
|
+
try {
|
|
147840
|
+
stillListed = (await session.listMcpServers()).some((server) => server.name === name);
|
|
147841
|
+
} catch {}
|
|
147842
|
+
if (stillListed) {
|
|
147843
|
+
host.showError(t("mcp.uninstall_verify_failed", { name }));
|
|
147844
|
+
return;
|
|
147845
|
+
}
|
|
147637
147846
|
host.showStatus(t("mcp.uninstalled", { name }));
|
|
147638
147847
|
} catch (error) {
|
|
147639
147848
|
host.showError(t("mcp.uninstall_failed", { msg: error instanceof Error ? error.message : String(error) }));
|
|
@@ -149675,6 +149884,147 @@ async function handleMermaidCommand(host, args) {
|
|
|
149675
149884
|
}));
|
|
149676
149885
|
}
|
|
149677
149886
|
//#endregion
|
|
149887
|
+
//#region src/utils/clipboard/clipboard-text.ts
|
|
149888
|
+
/**
|
|
149889
|
+
* Write plain text to the system clipboard with platform-specific commands.
|
|
149890
|
+
*
|
|
149891
|
+
* scream-core's clipboard layer is read-only (clipboard-native / clipboard-image),
|
|
149892
|
+
* so the TUI's "copy selected text" needs its own writer. Used to back the
|
|
149893
|
+
* pi-tui `copySelection` hook — return true/false so the TUI can flash
|
|
149894
|
+
* "Copied!" or "Copy failed".
|
|
149895
|
+
*
|
|
149896
|
+
* Platform mapping:
|
|
149897
|
+
* macOS -> pbcopy
|
|
149898
|
+
* Windows-> powershell Set-Clipboard (base64 payload, avoids quoting issues)
|
|
149899
|
+
* Linux -> wl-copy (Wayland) / xclip or xsel (X11), tried in a candidate
|
|
149900
|
+
* chain so a missing tool (Ubuntu ships neither by default)
|
|
149901
|
+
* falls through to the next one instead of failing outright.
|
|
149902
|
+
*/
|
|
149903
|
+
var ClipboardTextError = class extends Error {
|
|
149904
|
+
constructor(message) {
|
|
149905
|
+
super(message);
|
|
149906
|
+
this.name = "ClipboardTextError";
|
|
149907
|
+
}
|
|
149908
|
+
};
|
|
149909
|
+
const defaultRunCommand = (command, args, input) => {
|
|
149910
|
+
const result = spawnSync(command, args, {
|
|
149911
|
+
input,
|
|
149912
|
+
encoding: "utf8",
|
|
149913
|
+
timeout: 3e3
|
|
149914
|
+
});
|
|
149915
|
+
if (result.status === 0) return { ok: true };
|
|
149916
|
+
return {
|
|
149917
|
+
ok: false,
|
|
149918
|
+
error: result.error?.message ?? result.stderr?.toString() ?? `exit ${result.status}`
|
|
149919
|
+
};
|
|
149920
|
+
};
|
|
149921
|
+
function detectPlatform() {
|
|
149922
|
+
if (process.platform === "darwin") return "macos";
|
|
149923
|
+
if (process.platform === "win32") return "windows";
|
|
149924
|
+
if (process.platform === "linux") return process.env["WAYLAND_DISPLAY"] ? "linux-wayland" : "linux-x11";
|
|
149925
|
+
return "unsupported";
|
|
149926
|
+
}
|
|
149927
|
+
function linuxCandidates(platform) {
|
|
149928
|
+
const wl = {
|
|
149929
|
+
command: "wl-copy",
|
|
149930
|
+
args: []
|
|
149931
|
+
};
|
|
149932
|
+
const xclip = {
|
|
149933
|
+
command: "xclip",
|
|
149934
|
+
args: [
|
|
149935
|
+
"-selection",
|
|
149936
|
+
"clipboard",
|
|
149937
|
+
"-i"
|
|
149938
|
+
]
|
|
149939
|
+
};
|
|
149940
|
+
const xsel = {
|
|
149941
|
+
command: "xsel",
|
|
149942
|
+
args: ["--clipboard", "--input"]
|
|
149943
|
+
};
|
|
149944
|
+
return platform === "linux-wayland" ? [
|
|
149945
|
+
wl,
|
|
149946
|
+
xclip,
|
|
149947
|
+
xsel
|
|
149948
|
+
] : [
|
|
149949
|
+
xclip,
|
|
149950
|
+
xsel,
|
|
149951
|
+
wl
|
|
149952
|
+
];
|
|
149953
|
+
}
|
|
149954
|
+
/**
|
|
149955
|
+
* Write `text` to the system clipboard. Throws ClipboardTextError when the
|
|
149956
|
+
* platform is unsupported or every candidate command fails, so callers can
|
|
149957
|
+
* surface a "Copy failed" indicator.
|
|
149958
|
+
*/
|
|
149959
|
+
async function writeTextClipboard(text, runCommand = defaultRunCommand) {
|
|
149960
|
+
const platform = detectPlatform();
|
|
149961
|
+
let command;
|
|
149962
|
+
let args;
|
|
149963
|
+
let input;
|
|
149964
|
+
switch (platform) {
|
|
149965
|
+
case "macos":
|
|
149966
|
+
command = "pbcopy";
|
|
149967
|
+
args = [];
|
|
149968
|
+
input = text;
|
|
149969
|
+
break;
|
|
149970
|
+
case "windows": {
|
|
149971
|
+
const base64 = Buffer.from(text, "utf8").toString("base64");
|
|
149972
|
+
command = "powershell";
|
|
149973
|
+
args = [
|
|
149974
|
+
"-NoProfile",
|
|
149975
|
+
"-Command",
|
|
149976
|
+
`[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${base64}')) | Set-Clipboard`
|
|
149977
|
+
];
|
|
149978
|
+
input = "";
|
|
149979
|
+
break;
|
|
149980
|
+
}
|
|
149981
|
+
case "linux-wayland":
|
|
149982
|
+
case "linux-x11": {
|
|
149983
|
+
const failures = [];
|
|
149984
|
+
for (const candidate of linuxCandidates(platform)) {
|
|
149985
|
+
const result = runCommand(candidate.command, candidate.args, text);
|
|
149986
|
+
if (result.ok) return;
|
|
149987
|
+
failures.push(`${candidate.command}: ${result.error ?? "unknown error"}`);
|
|
149988
|
+
}
|
|
149989
|
+
throw new ClipboardTextError(`failed to copy to clipboard (${failures.join(" | ")}). Install wl-clipboard (Wayland: sudo apt install wl-clipboard) or xclip/xsel (X11: sudo apt install xclip xsel)`);
|
|
149990
|
+
}
|
|
149991
|
+
default: throw new ClipboardTextError(`unsupported clipboard platform: ${process.platform}`);
|
|
149992
|
+
}
|
|
149993
|
+
const result = runCommand(command, args, input);
|
|
149994
|
+
if (!result.ok) throw new ClipboardTextError(`failed to copy to clipboard: ${command} ${result.error ?? "unknown error"}`);
|
|
149995
|
+
}
|
|
149996
|
+
//#endregion
|
|
149997
|
+
//#region src/tui/commands/copy.ts
|
|
149998
|
+
/**
|
|
149999
|
+
* `/copy` — put the most recent assistant reply on the system clipboard.
|
|
150000
|
+
*
|
|
150001
|
+
* Only `assistant` transcript entries are considered: tool output and notices
|
|
150002
|
+
* are not "the reply", and an empty/whitespace entry (a cancelled turn) would
|
|
150003
|
+
* otherwise count as copyable. Clipboard failures are reported, never swallowed:
|
|
150004
|
+
* the user asked for a side effect and must know whether it landed.
|
|
150005
|
+
*/
|
|
150006
|
+
async function handleCopyCommand(host) {
|
|
150007
|
+
const entries = host.state.transcriptEntries;
|
|
150008
|
+
let latest;
|
|
150009
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
150010
|
+
const entry = entries[index];
|
|
150011
|
+
if (entry.kind !== "assistant") continue;
|
|
150012
|
+
if (entry.content.trim().length === 0) continue;
|
|
150013
|
+
latest = entry.content;
|
|
150014
|
+
break;
|
|
150015
|
+
}
|
|
150016
|
+
if (latest === void 0) {
|
|
150017
|
+
host.showStatus(t("tui.copy_empty"));
|
|
150018
|
+
return;
|
|
150019
|
+
}
|
|
150020
|
+
try {
|
|
150021
|
+
await writeTextClipboard(latest);
|
|
150022
|
+
host.showStatus(t("tui.copy_done"));
|
|
150023
|
+
} catch (error) {
|
|
150024
|
+
host.showError(t("tui.copy_failed", { msg: error instanceof Error ? error.message : String(error) }));
|
|
150025
|
+
}
|
|
150026
|
+
}
|
|
150027
|
+
//#endregion
|
|
149678
150028
|
//#region src/tui/commands/like.ts
|
|
149679
150029
|
function promptTextInput$1(host, title, opts) {
|
|
149680
150030
|
const { promise, resolve } = Promise.withResolvers();
|
|
@@ -151666,7 +152016,9 @@ async function ensureEmbeddingReadyInteractive(host) {
|
|
|
151666
152016
|
return false;
|
|
151667
152017
|
}
|
|
151668
152018
|
const spinner = host.showProgressSpinner(t("knowledge.loading_model"));
|
|
151669
|
-
const { ok, error, failureKind } = await startManualEmbeddingDownload()
|
|
152019
|
+
const { ok, error, failureKind } = await startManualEmbeddingDownload((progress) => {
|
|
152020
|
+
spinner.setLabel(embeddingProgressLabel(progress));
|
|
152021
|
+
});
|
|
151670
152022
|
spinner.stop({
|
|
151671
152023
|
ok,
|
|
151672
152024
|
label: ok ? t("kw.embedding_ready") : t("kw.embedding_failed")
|
|
@@ -152589,6 +152941,12 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
152589
152941
|
case "help":
|
|
152590
152942
|
host.showHelpPanel();
|
|
152591
152943
|
return;
|
|
152944
|
+
case "hotkeys":
|
|
152945
|
+
host.showHotkeysPanel();
|
|
152946
|
+
return;
|
|
152947
|
+
case "copy":
|
|
152948
|
+
await handleCopyCommand(host);
|
|
152949
|
+
return;
|
|
152592
152950
|
case "version":
|
|
152593
152951
|
host.showStatus(`Scream Code v${host.state.appState.version}`);
|
|
152594
152952
|
return;
|
|
@@ -152766,4 +153124,4 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
152766
153124
|
}
|
|
152767
153125
|
}
|
|
152768
153126
|
//#endregion
|
|
152769
|
-
export {
|
|
153127
|
+
export { clearGoalState as $, fetchCatalog as $n, isStreaming as $t, renderDiffLines as A, isExperimentalFlagEnabled as An, createMarkdownTheme as At, SkillActivationComponent as B, TuiLikePreferencesSchema as Bn, DISABLE_TERMINAL_THEME_REPORTING as Bt, appendJsonlLine as C, getCtrlCHint as Cn, refreshProviderBalance as Ct, handleRevokeCommand as D, buildSkillSlashCommands as Dn, showUsage as Dt, getDaemonInstructions as E, getNoActiveSessionMessage as En, showStatusReport as Et, ThinkingComponent as F, hasEmbeddingModelCache as Fn, contrastTextHex as Ft, getSharedSpeedTracker as G, getInputHistoryFile as Gn, OSC11_RESPONSE_PREFIX as Gt, ActivityGroupComponent as H, saveTuiConfig as Hn, ENABLE_TERMINAL_THEME_REPORTING as Ht, NoticeMessageComponent as I, startManualEmbeddingDownload as In, getColorPalette as It, WelcomeComponent as J, CLI_COMMAND_NAME as Jn, TERMINAL_FOCUS_IN as Jt, BackgroundAgentStatusComponent as K, getLogDir as Kn, OSC11_RESPONSE_PREFIX_NO_ESC as Kt, StatusMessageComponent as L, PIXEL_PULSE_FRAMES as Ln, detectTerminalTheme as Lt, highlightLines as M, embeddingProgressLabel as Mn, isTurnElapsedEnabled as Mt, langFromPath as N, embeddingFailureDetail as Nn, toggleEmptySessionHint as Nt, UserMessageComponent as O, BUILTIN_SLASH_COMMANDS as On, resolveThemeSync as Ot, CachedContainer as P, getKnowledgeStore as Pn, createThemeStyles as Pt, CompactionComponent as Q, DEFAULT_CATALOG_URL as Qn, isBusy as Qt, replaceTabs as R, PULSE_WAVE_FRAMES as Rn, parseOsc11BackgroundTheme as Rt, readUpdateCache as S, TIP_ROTATION_INTERVAL_MS as Sn, showSettingsSelector as St, handleCcCommand as T, getLlmNotSetMessage as Tn, clearInfoPanelState as Tt, charsForTokenBudget as U, detectShellEnvironment as Un, OSC11_QUERY as Ut, AssistantMessageComponent as V, loadTuiConfig as Vn, ENABLE_TERMINAL_FOCUS_REPORTING as Vt, estimateTokens as W, getDataDir as Wn, OSC11_RESPONSE as Wt, getBreathingFrame as X, CLI_USER_AGENT_PRODUCT as Xn, TERMINAL_THEME_DARK as Xt, BREATHE_CYCLE_MS as Y, CLI_UI_MODE as Yn, TERMINAL_FOCUS_OUT as Yt, resetBreathingClock as Z, PRODUCT_NAME as Zn, TERMINAL_THEME_LIGHT as Zt, handleChannelCommand as _, truncateErrorMessage as _n, SCREAM_ERROR_INFO as _r, handleThemeCommand as _t, buildRoleAdditionalText as a, handleConnectCommand as an, readSessionIndex as ar, handleTitleCommand as at, selectUpdateTarget as b, MAIN_AGENT_ID$1 as bn, showModelPicker as bt, handleExtensionCommand as c, STATUS_BULLET as cn, isRealUserPrompt as cr, changeThinkingLevel as ct, hasDispose as d, argsRecord as dn, flushDiagnosticLogs as dr, handleBotCommand as dt, FooterComponent as en, saveCatalogCache as er, refineGoal as et, isExpandable as f, formatErrorMessage as fn, log as fr, handleCompactCommand as ft, handleMemoryCommand as g, stringValue as gn, ErrorCodes as gr, handlePlanCommand as gt, formatMemoryMemoForInjection as h, serializeToolResultOutput as hn, isOrphanedToolCallError as hr, handleModelCommand as ht, openUrl as i, handleSearchCommand as in, appendSessionIndexEntry as ir, handleInitCommand as it, renderDiffLinesClustered as j, setExperimentalFlags as jn, isEmptySessionHintDismissed as jt, ToolCallComponent as k, sortSlashCommands as kn, createEditorTheme as kt, handleSkillCommand as l, appendSessionHeaderHint as ln, parseRlmMaxDepthArg as lr, getModelCycleLevel as lt, MoonLoader as m, parseStreamingArgs as mn, isScreamError as mr, handleFusionPlanCommand as mt, clearEvalPanelState as n, SubagentSlots as nn, encodeWorkDirKey as nr, handleExportMdCommand as nt, writeTextClipboard as o, handleLogoutCommand as on, removeSessionIndexEntry as or, isInternalMessage as ot, isPlanExpandable as p, isTodoItemShape as pn, resolveGlobalLogPath as pr, handleEditorCommand as pt, AgentGroupComponent as q, detectInstallSource as qn, QUERY_TERMINAL_THEME as qt, handleGrantsCommand as r, handleTraceCommand as rn, normalizeWorkDir as rr, handleForkCommand as rt, syncDiagramCapabilityPrompt as s, printableChar as sn, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE as sr, toTerminalHyperlink as st, dispatchInput as t, lerpGradient as tn, ScreamHarness as tr, handleExportDebugZipCommand as tt, disposeChildren as u, appendStreamingArgsPreview as un, resolveScreamHome as ur, handleAutoCommand as ut, handleMcpCommand as v, EMPTY_SESSION_HINT_URL as vn, handleWolfpackCommand as vt, readJsonlFile as w, getCtrlDHint as wn, supportsBalance as wt, refreshUpdateCache as x, SESSION_TIPS as xn, showPermissionPicker as xt, handleUpdateCommand as y, EXIT_CONFIRM_WINDOW_MS as yn, handleYoloCommand as yt, sanitizeShellOutput as z, TuiConfigParseError as zn, DISABLE_TERMINAL_FOCUS_REPORTING as zt };
|
|
@@ -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 {
|
|
6
|
+
import { an as handleConnectCommand } from "./dispatch-BPfUTccZ.mjs";
|
|
7
7
|
export { handleConnectCommand };
|
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-Db7f8Kja.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);
|