scream-code 0.10.0 → 0.10.2
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 +1 -1
- package/dist/{app-Bda9iKUb.mjs → app-VZDNiLvJ.mjs} +637 -574
- package/dist/main.mjs +1 -1
- package/dist/{src-DA9VZFf3.mjs → src-B2kaYK-M.mjs} +1 -1
- package/dist/{src-1LHYB0xM.mjs → src-oeUnRY3N.mjs} +62 -7
- package/dist/{text-input-dialog-Yyssn7t3.mjs → text-input-dialog-C8_8qYYi.mjs} +1 -1
- package/dist/{text-input-dialog-os5jWxGT.mjs → text-input-dialog-Cj7OClhs.mjs} +4 -20
- package/package.json +2 -2
|
@@ -5,8 +5,8 @@ const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import { a as __toESM, i as __require, r as __exportAll, t as __commonJSMin } from "./chunk-apG1qJts.mjs";
|
|
7
7
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
8
|
-
import { C as join$1, D as resolve$1, E as relative$1, S as isAbsolute$1, T as parse$7, a as isSupportedFile, b as basename$1, i as ingestFile, r as ingestDirectory, t as multiSearch, w as normalize, x as dirname$2, y as KnowledgeStore } from "./src-
|
|
9
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
8
|
+
import { C as join$1, D as resolve$1, E as relative$1, S as isAbsolute$1, T as parse$7, a as isSupportedFile, b as basename$1, i as ingestFile, r as ingestDirectory, t as multiSearch, w as normalize, x as dirname$2, y as KnowledgeStore } from "./src-oeUnRY3N.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-Cj7OClhs.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import Jn, { access, appendFile, chmod, copyFile, cp, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, rmdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -22,7 +22,7 @@ import { finished, pipeline as pipeline$1 } from "node:stream/promises";
|
|
|
22
22
|
import * as vs from "zlib";
|
|
23
23
|
import Qr from "zlib";
|
|
24
24
|
import * as fs$9 from "node:fs";
|
|
25
|
-
import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
25
|
+
import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
26
26
|
import * as path$8 from "node:path";
|
|
27
27
|
import path, { basename, dirname as dirname$1, extname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
|
|
28
28
|
import { z } from "zod";
|
|
@@ -9190,7 +9190,7 @@ var AnthropicChatProvider = class {
|
|
|
9190
9190
|
const kwargs = {
|
|
9191
9191
|
thinking: {
|
|
9192
9192
|
type: "enabled",
|
|
9193
|
-
budget_tokens: budgetTokensForEffort(effectiveEffort)
|
|
9193
|
+
budget_tokens: budgetTokensForEffort(effectiveEffort === "xhigh" || effectiveEffort === "max" ? "high" : effectiveEffort)
|
|
9194
9194
|
},
|
|
9195
9195
|
betaFeatures: newBetas
|
|
9196
9196
|
};
|
|
@@ -37877,6 +37877,7 @@ function messagesToGoogleGenAIContents(messages) {
|
|
|
37877
37877
|
toolMessages.push(toolMsg);
|
|
37878
37878
|
j += 1;
|
|
37879
37879
|
}
|
|
37880
|
+
if (toolMessages.length === 0) throw new ChatProviderError(`Missing tool responses for ids: ${expectedToolCallIds.join(", ")}`);
|
|
37880
37881
|
if (toolMessages.length > 0) {
|
|
37881
37882
|
const toolMsgById = /* @__PURE__ */ new Map();
|
|
37882
37883
|
const seenToolCallIds = /* @__PURE__ */ new Set();
|
|
@@ -48773,6 +48774,7 @@ var OpenAILegacyChatProvider = class {
|
|
|
48773
48774
|
_defaultHeaders;
|
|
48774
48775
|
_reasoningKey;
|
|
48775
48776
|
_reasoningEffort;
|
|
48777
|
+
_thinkingExplicitlyOff = false;
|
|
48776
48778
|
_generationKwargs;
|
|
48777
48779
|
_toolMessageConversion;
|
|
48778
48780
|
_client;
|
|
@@ -48821,7 +48823,7 @@ var OpenAILegacyChatProvider = class {
|
|
|
48821
48823
|
for (const msg of normalizedHistory) messages.push(convertMessage$1(msg, this._reasoningKey, this._toolMessageConversion));
|
|
48822
48824
|
const kwargs = { ...this._generationKwargs };
|
|
48823
48825
|
let reasoningEffort = this._reasoningEffort;
|
|
48824
|
-
if (reasoningEffort === void 0 && kwargs["reasoning_effort"] === void 0) {
|
|
48826
|
+
if (!this._thinkingExplicitlyOff && reasoningEffort === void 0 && kwargs["reasoning_effort"] === void 0) {
|
|
48825
48827
|
if (history.some((message) => message.content.some((part) => part.type === "think"))) reasoningEffort = "medium";
|
|
48826
48828
|
}
|
|
48827
48829
|
for (const key of Object.keys(kwargs)) if (kwargs[key] === void 0) delete kwargs[key];
|
|
@@ -48844,6 +48846,7 @@ var OpenAILegacyChatProvider = class {
|
|
|
48844
48846
|
const reasoningEffort = thinkingEffortToReasoningEffort(effort);
|
|
48845
48847
|
const clone = this._clone();
|
|
48846
48848
|
clone._reasoningEffort = reasoningEffort;
|
|
48849
|
+
clone._thinkingExplicitlyOff = effort === "off";
|
|
48847
48850
|
return clone;
|
|
48848
48851
|
}
|
|
48849
48852
|
withGenerationKwargs(kwargs) {
|
|
@@ -56837,7 +56840,10 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56837
56840
|
initPromise = null;
|
|
56838
56841
|
async init() {
|
|
56839
56842
|
if (this.initPromise) return this.initPromise;
|
|
56840
|
-
this.initPromise = this._doInit()
|
|
56843
|
+
this.initPromise = this._doInit().catch((error) => {
|
|
56844
|
+
this.initPromise = null;
|
|
56845
|
+
throw error;
|
|
56846
|
+
});
|
|
56841
56847
|
return this.initPromise;
|
|
56842
56848
|
}
|
|
56843
56849
|
async _doInit() {
|
|
@@ -56853,6 +56859,11 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
56853
56859
|
}
|
|
56854
56860
|
/** Close the database handle and checkpoint WAL. */
|
|
56855
56861
|
close() {
|
|
56862
|
+
if (this.embeddingTimer !== void 0) {
|
|
56863
|
+
clearTimeout(this.embeddingTimer);
|
|
56864
|
+
this.embeddingTimer = void 0;
|
|
56865
|
+
}
|
|
56866
|
+
this.embeddingQueue.clear();
|
|
56856
56867
|
if (this.db !== void 0) {
|
|
56857
56868
|
this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
56858
56869
|
this.db.close();
|
|
@@ -57126,6 +57137,7 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
57126
57137
|
try {
|
|
57127
57138
|
for (const memo of memos) {
|
|
57128
57139
|
const row = insert.get(memo.id, memo.sourceSessionId, memo.sourceSessionTitle ?? null, memo.userNeed, memo.approach, memo.outcome, memo.whatFailed, memo.whatWorked, memo.extractionSource, memo.recordedAt, memo.projectDir ?? "", JSON.stringify(memo.tags ?? []));
|
|
57140
|
+
if (row === void 0) continue;
|
|
57129
57141
|
insertFts.run(row.rowid, toFtsText(memo.userNeed), toFtsText(memo.approach), toFtsText(memo.whatFailed), toFtsText(memo.whatWorked), toFtsText(memo.sourceSessionTitle ?? ""));
|
|
57130
57142
|
}
|
|
57131
57143
|
this.db.exec("COMMIT");
|
|
@@ -57188,6 +57200,7 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
57188
57200
|
const updateFts = this.db.prepare(`INSERT INTO memos_fts(rowid, user_need, approach, what_failed, what_worked, source_session_title)
|
|
57189
57201
|
VALUES (?, ?, ?, ?, ?, ?)`);
|
|
57190
57202
|
const deleteFts = this.db.prepare("INSERT INTO memos_fts(memos_fts, rowid) VALUES ('delete', ?)");
|
|
57203
|
+
const deleteEmbedding = this.db.prepare("DELETE FROM memory_embeddings WHERE memory_id = ?");
|
|
57191
57204
|
this.db.exec("BEGIN TRANSACTION");
|
|
57192
57205
|
try {
|
|
57193
57206
|
const oldRow = selectRow.get(id);
|
|
@@ -57202,7 +57215,9 @@ var MemoryMemoStore = class MemoryMemoStore {
|
|
|
57202
57215
|
}
|
|
57203
57216
|
deleteFts.run(oldRow.rowid);
|
|
57204
57217
|
updateFts.run(row.rowid, toFtsText(updated.userNeed), toFtsText(updated.approach), toFtsText(updated.whatFailed), toFtsText(updated.whatWorked), toFtsText(updated.sourceSessionTitle ?? ""));
|
|
57218
|
+
deleteEmbedding.run(id);
|
|
57205
57219
|
this.db.exec("COMMIT");
|
|
57220
|
+
this.scheduleEmbedding(updated);
|
|
57206
57221
|
return true;
|
|
57207
57222
|
} catch {
|
|
57208
57223
|
this.db.exec("ROLLBACK");
|
|
@@ -57613,6 +57628,7 @@ async function applyConsolidation(store, plan) {
|
|
|
57613
57628
|
whatWorked: worked || "none",
|
|
57614
57629
|
whatFailed: failed || "none",
|
|
57615
57630
|
tags: normalizeTags(plan.resolved.flatMap((m) => m.tags ?? [])),
|
|
57631
|
+
projectDir: plan.resolved[0].projectDir,
|
|
57616
57632
|
extractionSource: "compaction"
|
|
57617
57633
|
});
|
|
57618
57634
|
await store.append(archive);
|
|
@@ -57631,6 +57647,7 @@ async function applyConsolidation(store, plan) {
|
|
|
57631
57647
|
whatWorked: worked || "none",
|
|
57632
57648
|
whatFailed: failed || "none",
|
|
57633
57649
|
tags: normalizeTags(plan.stale.flatMap((m) => m.tags ?? [])),
|
|
57650
|
+
projectDir: plan.stale[0].projectDir,
|
|
57634
57651
|
extractionSource: "compaction"
|
|
57635
57652
|
});
|
|
57636
57653
|
await store.append(archive);
|
|
@@ -57649,6 +57666,7 @@ async function applyConsolidation(store, plan) {
|
|
|
57649
57666
|
whatFailed: group.merged.whatFailed,
|
|
57650
57667
|
whatWorked: group.merged.whatWorked,
|
|
57651
57668
|
tags: group.merged.tags ?? mergedTags,
|
|
57669
|
+
projectDir: newest.projectDir,
|
|
57652
57670
|
extractionSource: "compaction"
|
|
57653
57671
|
});
|
|
57654
57672
|
await store.append(merged);
|
|
@@ -58334,7 +58352,7 @@ var KnowledgeLookupTool = class {
|
|
|
58334
58352
|
const llm = { generate: async (systemPrompt, userPrompt) => {
|
|
58335
58353
|
return this.agent.generateText(systemPrompt, userPrompt);
|
|
58336
58354
|
} };
|
|
58337
|
-
const { multiSearchWithTrace } = await import("./src-
|
|
58355
|
+
const { multiSearchWithTrace } = await import("./src-B2kaYK-M.mjs");
|
|
58338
58356
|
const { results, trace } = await multiSearchWithTrace(store, llm, query, { topK });
|
|
58339
58357
|
if (results.length === 0) return {
|
|
58340
58358
|
isError: false,
|
|
@@ -62525,8 +62543,8 @@ function parseSkillText(options) {
|
|
|
62525
62543
|
if (!isRecord$6(frontmatter)) throw new SkillParseError(`Frontmatter in ${options.skillMdPath} must be a mapping at the top level`);
|
|
62526
62544
|
const metadata = normalizeMetadata(frontmatter);
|
|
62527
62545
|
if (!isSupportedSkillType(metadata.type)) throw new UnsupportedSkillTypeError(metadata.type ?? String(frontmatter["type"]));
|
|
62528
|
-
const name = nonEmptyString$
|
|
62529
|
-
const description = nonEmptyString$
|
|
62546
|
+
const name = nonEmptyString$1(metadata.name);
|
|
62547
|
+
const description = nonEmptyString$1(metadata.description);
|
|
62530
62548
|
if (isDirectorySkill && (name === void 0 || description === void 0)) throw new SkillParseError(`Missing required frontmatter field ${name === void 0 ? "\"name\"" : "\"description\""} in ${options.skillMdPath}`);
|
|
62531
62549
|
const skillPath = resolve$1(options.skillMdPath);
|
|
62532
62550
|
const content = parsed.body.trim();
|
|
@@ -62586,11 +62604,11 @@ function normalizeMetadata(raw) {
|
|
|
62586
62604
|
const key = METADATA_ALIASES[rawKey] ?? rawKey;
|
|
62587
62605
|
out[key] = value;
|
|
62588
62606
|
}
|
|
62589
|
-
const type = nonEmptyString$
|
|
62607
|
+
const type = nonEmptyString$1(out["type"]);
|
|
62590
62608
|
if (type !== void 0) out["type"] = type;
|
|
62591
|
-
const name = nonEmptyString$
|
|
62609
|
+
const name = nonEmptyString$1(out["name"]);
|
|
62592
62610
|
if (name !== void 0) out["name"] = name;
|
|
62593
|
-
const description = nonEmptyString$
|
|
62611
|
+
const description = nonEmptyString$1(out["description"]);
|
|
62594
62612
|
if (description !== void 0) out["description"] = description;
|
|
62595
62613
|
return out;
|
|
62596
62614
|
}
|
|
@@ -62632,7 +62650,7 @@ function tokenizeArgs(raw) {
|
|
|
62632
62650
|
if (hasContent) out.push(current);
|
|
62633
62651
|
return out;
|
|
62634
62652
|
}
|
|
62635
|
-
function nonEmptyString$
|
|
62653
|
+
function nonEmptyString$1(value) {
|
|
62636
62654
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
62637
62655
|
}
|
|
62638
62656
|
function isRecord$6(value) {
|
|
@@ -69634,17 +69652,13 @@ const HookDefSchema = z.object({
|
|
|
69634
69652
|
command: z.string().min(1),
|
|
69635
69653
|
timeout: z.number().int().min(1).max(600).optional()
|
|
69636
69654
|
}).strict();
|
|
69637
|
-
const ScreamCliServiceConfigSchema = z.object({
|
|
69638
|
-
baseUrl: z.string().optional(),
|
|
69639
|
-
apiKey: z.string().optional(),
|
|
69640
|
-
oauth: OAuthRefSchema.optional(),
|
|
69641
|
-
customHeaders: StringRecordSchema.optional()
|
|
69642
|
-
});
|
|
69643
69655
|
const DuckDuckGoConfigSchema = z.object({ enabled: z.boolean().default(true) });
|
|
69656
|
+
const DomesticSearchConfigSchema = z.object({ enabled: z.boolean().default(true) });
|
|
69644
69657
|
const ServicesConfigSchema = z.object({
|
|
69645
|
-
|
|
69646
|
-
|
|
69647
|
-
|
|
69658
|
+
duckduckgo: DuckDuckGoConfigSchema.optional(),
|
|
69659
|
+
sogou: DomesticSearchConfigSchema.optional(),
|
|
69660
|
+
so360: DomesticSearchConfigSchema.optional(),
|
|
69661
|
+
baidu: DomesticSearchConfigSchema.optional()
|
|
69648
69662
|
});
|
|
69649
69663
|
const McpServerCommonFields = {
|
|
69650
69664
|
enabled: z.boolean().optional(),
|
|
@@ -69718,12 +69732,13 @@ const ThinkingConfigPatchSchema = ThinkingConfigSchema.partial();
|
|
|
69718
69732
|
const PermissionConfigPatchSchema = PermissionConfigSchema.partial();
|
|
69719
69733
|
const LoopControlPatchSchema = LoopControlSchema.partial();
|
|
69720
69734
|
const BackgroundConfigPatchSchema = BackgroundConfigSchema.partial();
|
|
69721
|
-
const ScreamCliServiceConfigPatchSchema = ScreamCliServiceConfigSchema.partial();
|
|
69722
69735
|
const DuckDuckGoConfigPatchSchema = DuckDuckGoConfigSchema.partial();
|
|
69736
|
+
const DomesticSearchConfigPatchSchema = DomesticSearchConfigSchema.partial();
|
|
69723
69737
|
const ServicesConfigPatchSchema = z.object({
|
|
69724
|
-
|
|
69725
|
-
|
|
69726
|
-
|
|
69738
|
+
duckduckgo: DuckDuckGoConfigPatchSchema.optional(),
|
|
69739
|
+
sogou: DomesticSearchConfigPatchSchema.optional(),
|
|
69740
|
+
so360: DomesticSearchConfigPatchSchema.optional(),
|
|
69741
|
+
baidu: DomesticSearchConfigPatchSchema.optional()
|
|
69727
69742
|
});
|
|
69728
69743
|
const ScreamConfigPatchSchema = z.object({
|
|
69729
69744
|
providers: z.record(z.string(), ProviderConfigPatchSchema).optional(),
|
|
@@ -76673,7 +76688,8 @@ var ReadTool = class {
|
|
|
76673
76688
|
hasLf: false,
|
|
76674
76689
|
hasLoneCr: false
|
|
76675
76690
|
};
|
|
76676
|
-
const
|
|
76691
|
+
const rawHash = createHash("sha256");
|
|
76692
|
+
const normalizedHash = createHash("sha256");
|
|
76677
76693
|
let currentLineNo = 0;
|
|
76678
76694
|
let maxLinesReached = false;
|
|
76679
76695
|
let collectionClosed = false;
|
|
@@ -76684,7 +76700,8 @@ var ReadTool = class {
|
|
|
76684
76700
|
};
|
|
76685
76701
|
currentLineNo += 1;
|
|
76686
76702
|
updateLineEndingFlags(flags, rawLine);
|
|
76687
|
-
|
|
76703
|
+
rawHash.update(rawLine);
|
|
76704
|
+
normalizedHash.update(rawLine.replaceAll("\r\n", "\n"));
|
|
76688
76705
|
if (collectionClosed) {
|
|
76689
76706
|
if (effectiveLimit >= 1e3 && currentLineNo >= lineOffset) maxLinesReached = true;
|
|
76690
76707
|
continue;
|
|
@@ -76702,7 +76719,7 @@ var ReadTool = class {
|
|
|
76702
76719
|
if (selectedEntries.length >= effectiveLimit) collectionClosed = true;
|
|
76703
76720
|
}
|
|
76704
76721
|
const lineEndingStyle = lineEndingStyleFromFlags(flags);
|
|
76705
|
-
const anchor =
|
|
76722
|
+
const anchor = (lineEndingStyle === "crlf" ? normalizedHash : rawHash).digest("hex").slice(0, 8);
|
|
76706
76723
|
const renderedLines = [];
|
|
76707
76724
|
const truncatedLineNumbers = [];
|
|
76708
76725
|
let bytes = 0;
|
|
@@ -76742,7 +76759,8 @@ var ReadTool = class {
|
|
|
76742
76759
|
hasLf: false,
|
|
76743
76760
|
hasLoneCr: false
|
|
76744
76761
|
};
|
|
76745
|
-
const
|
|
76762
|
+
const rawHash = createHash("sha256");
|
|
76763
|
+
const normalizedHash = createHash("sha256");
|
|
76746
76764
|
let currentLineNo = 0;
|
|
76747
76765
|
for await (const rawLine of this.jian.readLines(safePath, { errors: "strict" })) {
|
|
76748
76766
|
if (containsNulByte(rawLine)) return {
|
|
@@ -76751,7 +76769,8 @@ var ReadTool = class {
|
|
|
76751
76769
|
};
|
|
76752
76770
|
currentLineNo += 1;
|
|
76753
76771
|
updateLineEndingFlags(flags, rawLine);
|
|
76754
|
-
|
|
76772
|
+
rawHash.update(rawLine);
|
|
76773
|
+
normalizedHash.update(rawLine.replaceAll("\r\n", "\n"));
|
|
76755
76774
|
entries.push({
|
|
76756
76775
|
lineNo: currentLineNo,
|
|
76757
76776
|
rawContent: stripTrailingLf(rawLine)
|
|
@@ -76759,7 +76778,7 @@ var ReadTool = class {
|
|
|
76759
76778
|
if (entries.length > tailCount) entries.shift();
|
|
76760
76779
|
}
|
|
76761
76780
|
const lineEndingStyle = lineEndingStyleFromFlags(flags);
|
|
76762
|
-
const anchor =
|
|
76781
|
+
const anchor = (lineEndingStyle === "crlf" ? normalizedHash : rawHash).digest("hex").slice(0, 8);
|
|
76763
76782
|
let renderedCandidates = entries.slice(0, effectiveLimit).map((entry) => {
|
|
76764
76783
|
return {
|
|
76765
76784
|
entry,
|
|
@@ -78086,7 +78105,7 @@ var BashTool = class {
|
|
|
78086
78105
|
const info = backgroundManager.getTask(taskId);
|
|
78087
78106
|
if (info && info.status === "running") backgroundManager.stop(taskId, "Timed out");
|
|
78088
78107
|
})();
|
|
78089
|
-
}, timeoutMs);
|
|
78108
|
+
}, timeoutMs).unref();
|
|
78090
78109
|
const status = backgroundManager.getTask(taskId).status;
|
|
78091
78110
|
const builder = new ToolResultBuilder();
|
|
78092
78111
|
builder.write(`task_id: ${taskId}\npid: ${String(proc.pid)}\ndescription: ${args.description.trim()}\nstatus: ${status}\nautomatic_notification: true\nnext_step: You will be automatically notified when it completes.
|
|
@@ -78330,9 +78349,12 @@ var WebSearchTool = class {
|
|
|
78330
78349
|
execute: (ctx) => this.execution(args, ctx)
|
|
78331
78350
|
};
|
|
78332
78351
|
}
|
|
78333
|
-
async execution(args, { toolCallId }) {
|
|
78352
|
+
async execution(args, { signal, toolCallId }) {
|
|
78334
78353
|
try {
|
|
78335
|
-
const opts = {
|
|
78354
|
+
const opts = {
|
|
78355
|
+
signal,
|
|
78356
|
+
toolCallId
|
|
78357
|
+
};
|
|
78336
78358
|
if (args.limit !== void 0) opts.limit = args.limit;
|
|
78337
78359
|
if (args.include_content !== void 0) opts.includeContent = args.include_content;
|
|
78338
78360
|
const results = await this.provider.search(args.query, opts);
|
|
@@ -79152,7 +79174,10 @@ var FullCompaction = class {
|
|
|
79152
79174
|
if (this.compactionCountInTurn > this.strategy.maxCompactionPerTurn) return;
|
|
79153
79175
|
if (this.agent.records.restoring) return;
|
|
79154
79176
|
const compactedCount = this.strategy.computeCompactCount(this.agent.context.history, data.source);
|
|
79155
|
-
if (compactedCount === 0)
|
|
79177
|
+
if (compactedCount === 0) {
|
|
79178
|
+
if (data.source === "manual") throw new ScreamError(ErrorCodes.COMPACTION_UNABLE, "No prefix that can be compacted in current history.");
|
|
79179
|
+
return;
|
|
79180
|
+
}
|
|
79156
79181
|
this.agent.records.logRecord({
|
|
79157
79182
|
type: "full_compaction.begin",
|
|
79158
79183
|
...data
|
|
@@ -80881,7 +80906,8 @@ var ContextMemory = class {
|
|
|
80881
80906
|
toolCalls: [],
|
|
80882
80907
|
origin: { kind: "compaction_summary" }
|
|
80883
80908
|
}, ...this._history.slice(summary.compactedCount)];
|
|
80884
|
-
this.
|
|
80909
|
+
const survivingMessages = new Set(this._history);
|
|
80910
|
+
for (const [uuid, message] of this.openSteps) if (!survivingMessages.has(message)) this.openSteps.delete(uuid);
|
|
80885
80911
|
this.flushDeferredMessagesIfToolExchangeClosed();
|
|
80886
80912
|
this._tokenCount = summary.tokensAfter;
|
|
80887
80913
|
this.tokenCountCoveredMessageCount = this._history.length;
|
|
@@ -92274,8 +92300,7 @@ function parseToolCallArguments(raw) {
|
|
|
92274
92300
|
*/
|
|
92275
92301
|
function repairTruncatedJson(raw) {
|
|
92276
92302
|
let repaired = raw.trimEnd();
|
|
92277
|
-
|
|
92278
|
-
let bracketOpen = 0;
|
|
92303
|
+
const openStack = [];
|
|
92279
92304
|
let inString = false;
|
|
92280
92305
|
let stringHasEscape = false;
|
|
92281
92306
|
let lastNonWhitespace = "";
|
|
@@ -92293,24 +92318,16 @@ function repairTruncatedJson(raw) {
|
|
|
92293
92318
|
}
|
|
92294
92319
|
stringHasEscape = false;
|
|
92295
92320
|
if (inString) continue;
|
|
92296
|
-
if (ch === "{")
|
|
92297
|
-
if (ch === "
|
|
92298
|
-
if (ch === "
|
|
92299
|
-
|
|
92321
|
+
if (ch === "{") openStack.push("}");
|
|
92322
|
+
else if (ch === "[") openStack.push("]");
|
|
92323
|
+
else if (ch === "}" || ch === "]") {
|
|
92324
|
+
if (openStack.length > 0 && openStack[openStack.length - 1] === ch) openStack.pop();
|
|
92325
|
+
}
|
|
92300
92326
|
if (!/\s/.test(ch)) lastNonWhitespace = ch;
|
|
92301
92327
|
}
|
|
92302
92328
|
if (inString) repaired += "\"";
|
|
92303
92329
|
if (lastNonWhitespace === ",") repaired += "null";
|
|
92304
|
-
|
|
92305
|
-
while (bracketOpen > 0) {
|
|
92306
|
-
closers.push("]");
|
|
92307
|
-
bracketOpen--;
|
|
92308
|
-
}
|
|
92309
|
-
while (braceOpen > 0) {
|
|
92310
|
-
closers.push("}");
|
|
92311
|
-
braceOpen--;
|
|
92312
|
-
}
|
|
92313
|
-
if (closers.length > 0) repaired += closers.join("");
|
|
92330
|
+
for (let i = openStack.length - 1; i >= 0; i--) repaired += openStack[i];
|
|
92314
92331
|
return repaired;
|
|
92315
92332
|
}
|
|
92316
92333
|
function validateExecutableToolArgs(tool, args) {
|
|
@@ -97920,7 +97937,7 @@ var TurnFlow = class {
|
|
|
97920
97937
|
});
|
|
97921
97938
|
return null;
|
|
97922
97939
|
}
|
|
97923
|
-
if (this.turnId === -1) this.agent.dreamTracker.init().then(() => this.agent.dreamTracker.recordNewSession());
|
|
97940
|
+
if (this.turnId === -1) this.agent.dreamTracker.init().then(() => this.agent.dreamTracker.recordNewSession()).catch(() => {});
|
|
97924
97941
|
const turnId = this.allocateTurnId();
|
|
97925
97942
|
const controller = new AbortController();
|
|
97926
97943
|
const promise = this.turnWorker(turnId, input, origin, controller.signal);
|
|
@@ -99951,17 +99968,18 @@ function permissionRuleToToml(rule) {
|
|
|
99951
99968
|
}
|
|
99952
99969
|
function servicesToToml(services, rawServices) {
|
|
99953
99970
|
const out = cloneRecord(rawServices);
|
|
99954
|
-
|
|
99955
|
-
|
|
99956
|
-
|
|
99957
|
-
|
|
99958
|
-
|
|
99959
|
-
|
|
99960
|
-
|
|
99961
|
-
|
|
99962
|
-
|
|
99963
|
-
|
|
99964
|
-
|
|
99971
|
+
for (const key of [
|
|
99972
|
+
"duckduckgo",
|
|
99973
|
+
"sogou",
|
|
99974
|
+
"so360",
|
|
99975
|
+
"baidu"
|
|
99976
|
+
]) {
|
|
99977
|
+
const toggle = services[key];
|
|
99978
|
+
if (toggle?.enabled !== void 0) out[key] = {
|
|
99979
|
+
...isPlainObject$1(out[key]) ? out[key] : {},
|
|
99980
|
+
enabled: toggle.enabled
|
|
99981
|
+
};
|
|
99982
|
+
}
|
|
99965
99983
|
return out;
|
|
99966
99984
|
}
|
|
99967
99985
|
function loopControlToToml(loopControl, rawLoopControl) {
|
|
@@ -104227,7 +104245,7 @@ var Session$1 = class {
|
|
|
104227
104245
|
});
|
|
104228
104246
|
await this.options.jian.writeText(this.metadataPath, text);
|
|
104229
104247
|
};
|
|
104230
|
-
this.writeMetadataPromise = this.writeMetadataPromise.then(() => write());
|
|
104248
|
+
this.writeMetadataPromise = this.writeMetadataPromise.then(() => write(), () => write());
|
|
104231
104249
|
return this.writeMetadataPromise;
|
|
104232
104250
|
}
|
|
104233
104251
|
async readMetadata() {
|
|
@@ -117201,6 +117219,7 @@ setPrototypeOf(Document, Document$1).prototype = Document$1.prototype;
|
|
|
117201
117219
|
*/
|
|
117202
117220
|
const DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
|
|
117203
117221
|
const DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
|
|
117222
|
+
const FETCH_TIMEOUT_MS = 3e4;
|
|
117204
117223
|
const parseHTML = parseHTML$1;
|
|
117205
117224
|
/**
|
|
117206
117225
|
* SSRF guard — reject non-http(s) schemes and (by default) any hostname
|
|
@@ -117263,7 +117282,7 @@ function isPrivateIp(ip) {
|
|
|
117263
117282
|
}
|
|
117264
117283
|
return lower === "::1" || lower === "::" || lower.startsWith("fe80:") || lower.startsWith("fc") || lower.startsWith("fd");
|
|
117265
117284
|
}
|
|
117266
|
-
function cacheKey
|
|
117285
|
+
function cacheKey(url, allowPrivate, maxBytes, userAgent) {
|
|
117267
117286
|
return `local:${url}:${String(allowPrivate)}:${String(maxBytes)}:${userAgent}`;
|
|
117268
117287
|
}
|
|
117269
117288
|
const defaultDnsLookup = async (hostname) => {
|
|
@@ -117285,7 +117304,7 @@ var LocalFetchURLProvider = class {
|
|
|
117285
117304
|
this.dnsLookup = options.dnsLookup ?? defaultDnsLookup;
|
|
117286
117305
|
}
|
|
117287
117306
|
async fetch(url, _options) {
|
|
117288
|
-
const key = cacheKey
|
|
117307
|
+
const key = cacheKey(url, this.allowPrivateAddresses, this.maxBytes, this.userAgent);
|
|
117289
117308
|
const cached = this.cache.get(key);
|
|
117290
117309
|
if (cached !== void 0) return cached;
|
|
117291
117310
|
await assertSafeFetchTarget(url, this.allowPrivateAddresses, this.dnsLookup);
|
|
@@ -117296,7 +117315,8 @@ var LocalFetchURLProvider = class {
|
|
|
117296
117315
|
async fetchFresh(url) {
|
|
117297
117316
|
const response = await this.fetchImpl(url, {
|
|
117298
117317
|
method: "GET",
|
|
117299
|
-
headers: { "User-Agent": this.userAgent }
|
|
117318
|
+
headers: { "User-Agent": this.userAgent },
|
|
117319
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
117300
117320
|
});
|
|
117301
117321
|
if (response.status >= 400) {
|
|
117302
117322
|
await response.body?.cancel().catch(() => {});
|
|
@@ -117305,7 +117325,10 @@ var LocalFetchURLProvider = class {
|
|
|
117305
117325
|
const contentLengthRaw = response.headers.get("content-length");
|
|
117306
117326
|
if (contentLengthRaw !== null) {
|
|
117307
117327
|
const cl = Number(contentLengthRaw);
|
|
117308
|
-
if (Number.isFinite(cl) && cl > this.maxBytes)
|
|
117328
|
+
if (Number.isFinite(cl) && cl > this.maxBytes) {
|
|
117329
|
+
await response.body?.cancel().catch(() => {});
|
|
117330
|
+
throw new Error(`Response body too large: ${String(cl)} bytes exceeds maxBytes (${String(this.maxBytes)}).`);
|
|
117331
|
+
}
|
|
117309
117332
|
}
|
|
117310
117333
|
const body = await response.text();
|
|
117311
117334
|
const actualBytes = Buffer.byteLength(body, "utf8");
|
|
@@ -117340,268 +117363,220 @@ var LocalFetchURLProvider = class {
|
|
|
117340
117363
|
}
|
|
117341
117364
|
};
|
|
117342
117365
|
//#endregion
|
|
117343
|
-
//#region ../../packages/agent-core/src/tools/providers/
|
|
117366
|
+
//#region ../../packages/agent-core/src/tools/providers/search-timeout.ts
|
|
117344
117367
|
/**
|
|
117345
|
-
*
|
|
117368
|
+
* Hard timeout for outbound web-search requests (omp pattern).
|
|
117346
117369
|
*
|
|
117347
|
-
*
|
|
117348
|
-
*
|
|
117349
|
-
*
|
|
117350
|
-
*
|
|
117351
|
-
|
|
117352
|
-
|
|
117353
|
-
|
|
117354
|
-
|
|
117355
|
-
|
|
117356
|
-
|
|
117357
|
-
*/
|
|
117358
|
-
function cacheKey(baseUrl, url) {
|
|
117359
|
-
return `cli:${baseUrl}:${url}`;
|
|
117360
|
-
}
|
|
117361
|
-
var ScreamCliFetchURLProvider = class {
|
|
117362
|
-
tokenProvider;
|
|
117363
|
-
apiKey;
|
|
117364
|
-
baseUrl;
|
|
117365
|
-
defaultHeaders;
|
|
117366
|
-
customHeaders;
|
|
117367
|
-
localFallback;
|
|
117368
|
-
fetchImpl;
|
|
117369
|
-
cache;
|
|
117370
|
-
constructor(options) {
|
|
117371
|
-
this.tokenProvider = options.tokenProvider;
|
|
117372
|
-
this.apiKey = options.apiKey;
|
|
117373
|
-
this.baseUrl = options.baseUrl;
|
|
117374
|
-
this.defaultHeaders = options.defaultHeaders ?? {};
|
|
117375
|
-
this.customHeaders = options.customHeaders ?? {};
|
|
117376
|
-
this.localFallback = options.localFallback;
|
|
117377
|
-
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
117378
|
-
this.cache = options.cache ?? new FetchCache();
|
|
117379
|
-
}
|
|
117380
|
-
async fetch(url, options) {
|
|
117381
|
-
const key = cacheKey(this.baseUrl, url);
|
|
117382
|
-
const cached = this.cache.get(key);
|
|
117383
|
-
if (cached !== void 0) return cached;
|
|
117384
|
-
const result = await this.fetchFresh(url, options?.toolCallId);
|
|
117385
|
-
this.cache.set(key, result);
|
|
117386
|
-
return result;
|
|
117387
|
-
}
|
|
117388
|
-
async fetchFresh(url, toolCallId) {
|
|
117389
|
-
try {
|
|
117390
|
-
return {
|
|
117391
|
-
content: await this.fetchViaScreamCli(url, toolCallId),
|
|
117392
|
-
kind: "extracted"
|
|
117393
|
-
};
|
|
117394
|
-
} catch {
|
|
117395
|
-
return this.localFallback.fetch(url, { toolCallId });
|
|
117396
|
-
}
|
|
117397
|
-
}
|
|
117398
|
-
async fetchViaScreamCli(url, toolCallId) {
|
|
117399
|
-
const bodyJson = JSON.stringify({ url });
|
|
117400
|
-
const response = await this.post(bodyJson, toolCallId);
|
|
117401
|
-
if (response.status !== 200) {
|
|
117402
|
-
let detail = "";
|
|
117403
|
-
try {
|
|
117404
|
-
detail = await response.text();
|
|
117405
|
-
} catch {}
|
|
117406
|
-
throw new HttpFetchError(response.status, `ScreamCli fetch request failed: HTTP ${String(response.status)}. ${detail}`.trim());
|
|
117407
|
-
}
|
|
117408
|
-
return response.text();
|
|
117409
|
-
}
|
|
117410
|
-
async post(bodyJson, toolCallId) {
|
|
117411
|
-
const accessToken = await this.resolveApiKey();
|
|
117412
|
-
return this.fetchImpl(this.baseUrl, {
|
|
117413
|
-
method: "POST",
|
|
117414
|
-
headers: {
|
|
117415
|
-
...this.defaultHeaders,
|
|
117416
|
-
Authorization: `Bearer ${accessToken}`,
|
|
117417
|
-
Accept: "text/markdown",
|
|
117418
|
-
"Content-Type": "application/json",
|
|
117419
|
-
...toolCallId !== void 0 && toolCallId.length > 0 ? { "X-Msh-Tool-Call-Id": toolCallId } : {},
|
|
117420
|
-
...this.customHeaders
|
|
117421
|
-
},
|
|
117422
|
-
body: bodyJson
|
|
117423
|
-
});
|
|
117424
|
-
}
|
|
117425
|
-
async resolveApiKey() {
|
|
117426
|
-
if (this.tokenProvider !== void 0) try {
|
|
117427
|
-
const token = await this.tokenProvider.getAccessToken();
|
|
117428
|
-
if (token.trim().length > 0) return token;
|
|
117429
|
-
if (this.apiKey !== void 0 && this.apiKey.length > 0) return this.apiKey;
|
|
117430
|
-
} catch (error) {
|
|
117431
|
-
if (this.apiKey !== void 0 && this.apiKey.length > 0) return this.apiKey;
|
|
117432
|
-
throw error;
|
|
117433
|
-
}
|
|
117434
|
-
if (this.apiKey !== void 0 && this.apiKey.length > 0) return this.apiKey;
|
|
117435
|
-
throw new Error("ScreamCli fetch service is not configured: missing API key or token provider.");
|
|
117436
|
-
}
|
|
117437
|
-
};
|
|
117370
|
+
* A stalled TCP/TLS connection can keep an undici fetch pending for minutes;
|
|
117371
|
+
* composing the caller's signal with a fixed ceiling guarantees the request
|
|
117372
|
+
* settles. Fires as a `TimeoutError` DOMException, which the tool layer maps
|
|
117373
|
+
* to "Search timed out".
|
|
117374
|
+
*/
|
|
117375
|
+
const SEARCH_HARD_TIMEOUT_MS = 6e4;
|
|
117376
|
+
function withHardTimeout(signal, ms = SEARCH_HARD_TIMEOUT_MS) {
|
|
117377
|
+
const timeout = AbortSignal.timeout(ms);
|
|
117378
|
+
return signal !== void 0 ? AbortSignal.any([signal, timeout]) : timeout;
|
|
117379
|
+
}
|
|
117438
117380
|
//#endregion
|
|
117439
117381
|
//#region ../../packages/agent-core/src/tools/providers/duckduckgo-search.ts
|
|
117382
|
+
const DUCKDUCKGO_HTML_URL = "https://html.duckduckgo.com/html/";
|
|
117383
|
+
/**
|
|
117384
|
+
* Browser-like UA so DDG serves the standard results page instead of the
|
|
117385
|
+
* mobile/noscript variants, and is less likely to trip bot detection.
|
|
117386
|
+
* DDG answers automation it suspects with HTTP 202 plus an anomaly modal;
|
|
117387
|
+
* the body check (not the status) is the reliable signal.
|
|
117388
|
+
*/
|
|
117389
|
+
const BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36";
|
|
117440
117390
|
var DuckDuckGoSearchProvider = class {
|
|
117391
|
+
name = "duckduckgo";
|
|
117441
117392
|
fetchImpl;
|
|
117442
117393
|
constructor(options = {}) {
|
|
117443
117394
|
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
117444
117395
|
}
|
|
117445
117396
|
async search(query, options) {
|
|
117446
117397
|
const limit = options?.limit ?? 5;
|
|
117447
|
-
|
|
117448
|
-
|
|
117449
|
-
|
|
117450
|
-
|
|
117451
|
-
|
|
117452
|
-
|
|
117453
|
-
|
|
117454
|
-
|
|
117455
|
-
|
|
117456
|
-
|
|
117457
|
-
|
|
117458
|
-
|
|
117459
|
-
|
|
117460
|
-
|
|
117461
|
-
|
|
117462
|
-
|
|
117463
|
-
|
|
117464
|
-
|
|
117465
|
-
|
|
117466
|
-
if (response.status !==
|
|
117467
|
-
|
|
117468
|
-
|
|
117469
|
-
}
|
|
117470
|
-
let json;
|
|
117471
|
-
try {
|
|
117472
|
-
json = await response.json();
|
|
117473
|
-
} catch {
|
|
117474
|
-
return [];
|
|
117475
|
-
}
|
|
117476
|
-
return this.buildApiResults(json, limit);
|
|
117477
|
-
}
|
|
117478
|
-
buildApiResults(json, limit) {
|
|
117479
|
-
const results = [];
|
|
117480
|
-
if (json.AbstractText && json.AbstractURL && json.AbstractText.trim().length > 0) results.push({
|
|
117481
|
-
title: json.Heading && json.Heading.trim().length > 0 ? json.Heading : json.AbstractSource ?? "DuckDuckGo",
|
|
117482
|
-
url: json.AbstractURL,
|
|
117483
|
-
snippet: json.AbstractText
|
|
117484
|
-
});
|
|
117485
|
-
if (json.RelatedTopics && json.RelatedTopics.length > 0) {
|
|
117486
|
-
const flattened = flattenRelatedTopics(json.RelatedTopics);
|
|
117487
|
-
for (const topic of flattened) {
|
|
117488
|
-
if (results.length >= limit) break;
|
|
117489
|
-
const url = topic.FirstURL ?? "";
|
|
117490
|
-
const text = topic.Text ?? "";
|
|
117491
|
-
if (url === "" || text === "") continue;
|
|
117492
|
-
results.push({
|
|
117493
|
-
title: text,
|
|
117494
|
-
url,
|
|
117495
|
-
snippet: text
|
|
117496
|
-
});
|
|
117497
|
-
}
|
|
117498
|
-
}
|
|
117499
|
-
return results.slice(0, limit);
|
|
117500
|
-
}
|
|
117501
|
-
/**
|
|
117502
|
-
* Scrape DuckDuckGo Lite search results.
|
|
117503
|
-
*
|
|
117504
|
-
* Lite is a minimal HTML table with no JavaScript, designed for basic
|
|
117505
|
-
* browsers. It may return a CAPTCHA page from datacenter IPs — in that
|
|
117506
|
-
* case we return `[]` so the caller can fall through.
|
|
117507
|
-
*/
|
|
117508
|
-
async searchViaLite(query, limit) {
|
|
117509
|
-
const url = `https://lite.duckduckgo.com/lite/?q=${encodeURIComponent(query)}`;
|
|
117510
|
-
let response;
|
|
117511
|
-
try {
|
|
117512
|
-
response = await this.fetchImpl(url);
|
|
117513
|
-
} catch {
|
|
117514
|
-
return [];
|
|
117515
|
-
}
|
|
117516
|
-
if (response.status !== 200) {
|
|
117517
|
-
await drainBody(response);
|
|
117518
|
-
return [];
|
|
117519
|
-
}
|
|
117520
|
-
let html;
|
|
117521
|
-
try {
|
|
117522
|
-
html = await response.text();
|
|
117523
|
-
} catch {
|
|
117524
|
-
return [];
|
|
117525
|
-
}
|
|
117526
|
-
if (isCaptchaPage(html)) return [];
|
|
117527
|
-
return parseLiteResults(html, limit);
|
|
117398
|
+
const form = new URLSearchParams({
|
|
117399
|
+
q: query,
|
|
117400
|
+
kl: "us-en"
|
|
117401
|
+
});
|
|
117402
|
+
form.set("b", "");
|
|
117403
|
+
const response = await this.fetchImpl(DUCKDUCKGO_HTML_URL, {
|
|
117404
|
+
method: "POST",
|
|
117405
|
+
body: form.toString(),
|
|
117406
|
+
headers: {
|
|
117407
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
|
117408
|
+
"Accept-Language": "en,en-US;q=0.9",
|
|
117409
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
117410
|
+
Referer: "https://html.duckduckgo.com/",
|
|
117411
|
+
"Upgrade-Insecure-Requests": "1",
|
|
117412
|
+
"User-Agent": BROWSER_USER_AGENT
|
|
117413
|
+
},
|
|
117414
|
+
signal: withHardTimeout(options?.signal)
|
|
117415
|
+
});
|
|
117416
|
+
const html = await response.text();
|
|
117417
|
+
if (!response.ok && response.status !== 202) throw new Error(`DuckDuckGo request failed: HTTP ${String(response.status)}`);
|
|
117418
|
+
if (isAnomalyResponse(html)) throw new Error("DuckDuckGo blocked the request with a bot-detection challenge (common from datacenter/shared-egress IPs)");
|
|
117419
|
+
return parseHtmlResults(html).slice(0, limit);
|
|
117528
117420
|
}
|
|
117529
117421
|
};
|
|
117530
|
-
/**
|
|
117531
|
-
|
|
117532
|
-
|
|
117533
|
-
* The API nests topics in two ways:
|
|
117534
|
-
* - A direct topic has `FirstURL` + `Text` (may lack `Topics`).
|
|
117535
|
-
* - A category group has a `Name` and nested `Topics[]`.
|
|
117536
|
-
* We walk both shapes, returning a flat list of leaf topics.
|
|
117537
|
-
*/
|
|
117538
|
-
function flattenRelatedTopics(topics) {
|
|
117539
|
-
const out = [];
|
|
117540
|
-
for (const topic of topics) if (topic.Topics && topic.Topics.length > 0) out.push(...flattenRelatedTopics(topic.Topics));
|
|
117541
|
-
else if (topic.FirstURL) out.push(topic);
|
|
117542
|
-
return out;
|
|
117422
|
+
/** `true` when DDG returned the bot-challenge modal instead of results. */
|
|
117423
|
+
function isAnomalyResponse(html) {
|
|
117424
|
+
return html.includes("anomaly-modal") || html.includes("anomaly.js");
|
|
117543
117425
|
}
|
|
117544
117426
|
/**
|
|
117545
|
-
*
|
|
117427
|
+
* Each result lives in a `<div class="result …">` container with
|
|
117428
|
+
* `<a class="result__a">` for the title link and an optional
|
|
117429
|
+
* `<a|div|span class="result__snippet">` sibling for the preview text.
|
|
117430
|
+
* Sponsored rows, missing snippets, and the pagination row are tolerated.
|
|
117546
117431
|
*/
|
|
117547
|
-
|
|
117548
|
-
|
|
117432
|
+
const RESULT_BLOCK_RE = /<div\b[^>]*\bclass="[^"]*\bresult\b[^"]*"[^>]*>([\s\S]*?)(?=<div\b[^>]*\bclass="[^"]*\bresult\b|<div\b[^>]*\bclass="[^"]*\bnav-link\b|$)/g;
|
|
117433
|
+
const RESULT_TITLE_RE = /<a\b[^>]*\bclass="[^"]*\bresult__a\b[^"]*"[^>]*\bhref="([^"]+)"[^>]*>([\s\S]*?)<\/a>/;
|
|
117434
|
+
const RESULT_SNIPPET_RE = /<(?:a|div|span)\b[^>]*\bclass="[^"]*\bresult__snippet\b[^"]*"[^>]*>([\s\S]*?)<\/(?:a|div|span)>/;
|
|
117435
|
+
/** Strip inline tags (DDG wraps query terms in `<b>`) and decode entities. */
|
|
117436
|
+
function decodeHtmlText$1(value) {
|
|
117437
|
+
return value.replace(/<[^>]*>/g, " ").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code))).replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCharCode(Number.parseInt(code, 16))).replace(/ /gi, " ").replace(/&/gi, "&").replace(/</gi, "<").replace(/>/gi, ">").replace(/"/gi, "\"").replace(/'|'/gi, "'").replace(/\s+/g, " ").trim();
|
|
117549
117438
|
}
|
|
117550
117439
|
/**
|
|
117551
|
-
*
|
|
117552
|
-
*
|
|
117553
|
-
*
|
|
117554
|
-
*
|
|
117555
|
-
* The Lite markup is intentionally minimal (no JS, no CSS classes beyond a
|
|
117556
|
-
* handful of utility names), so a DOM parser is unnecessary overhead.
|
|
117440
|
+
* Resolve a DDG result href to the underlying target URL. DDG routes
|
|
117441
|
+
* outbound clicks through `//duckduckgo.com/l/?uddg=<encoded>`; handles
|
|
117442
|
+
* redirect wrappers, protocol-relative links, and plain absolute URLs.
|
|
117557
117443
|
*/
|
|
117558
|
-
|
|
117559
|
-
|
|
117560
|
-
|
|
117561
|
-
|
|
117562
|
-
|
|
117563
|
-
|
|
117564
|
-
/** Unwrap a DuckDuckGo redirect URL to the real target if possible. */
|
|
117565
|
-
function unwrapDdgRedirect(url) {
|
|
117566
|
-
const uddgMatch = url.match(/[?&]uddg=([^&]+)/);
|
|
117567
|
-
if (uddgMatch?.[1]) try {
|
|
117568
|
-
return decodeURIComponent(uddgMatch[1]);
|
|
117444
|
+
function unwrapResultUrl(href) {
|
|
117445
|
+
if (href === "") return void 0;
|
|
117446
|
+
const decoded = href.replace(/&/gi, "&");
|
|
117447
|
+
const wrapMatch = decoded.match(/[?&]uddg=([^&]+)/);
|
|
117448
|
+
if (wrapMatch?.[1] !== void 0) try {
|
|
117449
|
+
return decodeURIComponent(wrapMatch[1]);
|
|
117569
117450
|
} catch {
|
|
117570
|
-
return
|
|
117451
|
+
return;
|
|
117571
117452
|
}
|
|
117572
|
-
return
|
|
117453
|
+
if (decoded.startsWith("//")) return `https:${decoded}`;
|
|
117454
|
+
if (decoded.startsWith("http://") || decoded.startsWith("https://")) return decoded;
|
|
117573
117455
|
}
|
|
117574
|
-
function
|
|
117456
|
+
function parseHtmlResults(html) {
|
|
117575
117457
|
const results = [];
|
|
117576
|
-
const
|
|
117577
|
-
for (const match of
|
|
117578
|
-
|
|
117579
|
-
const
|
|
117580
|
-
|
|
117581
|
-
|
|
117458
|
+
const seen = /* @__PURE__ */ new Set();
|
|
117459
|
+
for (const match of html.matchAll(RESULT_BLOCK_RE)) {
|
|
117460
|
+
const block = match[1] ?? "";
|
|
117461
|
+
const title = RESULT_TITLE_RE.exec(block);
|
|
117462
|
+
if (title === null) continue;
|
|
117463
|
+
const url = unwrapResultUrl(title[1] ?? "");
|
|
117464
|
+
if (url === void 0 || seen.has(url)) continue;
|
|
117465
|
+
const titleText = decodeHtmlText$1(title[2] ?? "");
|
|
117466
|
+
if (titleText === "") continue;
|
|
117467
|
+
seen.add(url);
|
|
117468
|
+
const snippet = RESULT_SNIPPET_RE.exec(block);
|
|
117469
|
+
const snippetText = snippet !== null ? decodeHtmlText$1(snippet[1] ?? "") : "";
|
|
117582
117470
|
results.push({
|
|
117583
|
-
title,
|
|
117584
|
-
url
|
|
117585
|
-
snippet:
|
|
117471
|
+
title: titleText,
|
|
117472
|
+
url,
|
|
117473
|
+
snippet: snippetText !== "" ? snippetText : titleText
|
|
117586
117474
|
});
|
|
117587
117475
|
}
|
|
117588
|
-
const snippetMatches = html.matchAll(LITE_SNIPPET_RE);
|
|
117589
|
-
let snippetIndex = 0;
|
|
117590
|
-
for (const match of snippetMatches) {
|
|
117591
|
-
if (snippetIndex >= results.length) break;
|
|
117592
|
-
const snippet = stripHtmlAndDecode(match[1] ?? "");
|
|
117593
|
-
const entry = results[snippetIndex];
|
|
117594
|
-
if (entry && snippet.length > 0) entry.snippet = snippet;
|
|
117595
|
-
snippetIndex++;
|
|
117596
|
-
}
|
|
117597
117476
|
return results;
|
|
117598
117477
|
}
|
|
117599
|
-
|
|
117600
|
-
|
|
117601
|
-
|
|
117602
|
-
|
|
117603
|
-
|
|
117478
|
+
//#endregion
|
|
117479
|
+
//#region ../../packages/agent-core/src/tools/providers/domestic-search.ts
|
|
117480
|
+
const BROWSER_HEADERS = {
|
|
117481
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
|
117482
|
+
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
|
117483
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"
|
|
117484
|
+
};
|
|
117485
|
+
/** Strip inline tags and decode the common named/numeric entities. */
|
|
117486
|
+
function decodeHtmlText(value) {
|
|
117487
|
+
return value.replace(/<[^>]*>/g, " ").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code))).replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCharCode(Number.parseInt(code, 16))).replace(/ /gi, " ").replace(/&/gi, "&").replace(/</gi, "<").replace(/>/gi, ">").replace(/"/gi, "\"").replace(/'|'/gi, "'").replace(/\s+/g, " ").trim();
|
|
117604
117488
|
}
|
|
117489
|
+
async function searchEngine(spec, fetchImpl, query, options) {
|
|
117490
|
+
const limit = options?.limit ?? 5;
|
|
117491
|
+
const response = await fetchImpl(spec.url(query), {
|
|
117492
|
+
headers: BROWSER_HEADERS,
|
|
117493
|
+
signal: withHardTimeout(options?.signal)
|
|
117494
|
+
});
|
|
117495
|
+
const html = await response.text();
|
|
117496
|
+
if (!response.ok) throw new Error(`${spec.label} request failed: HTTP ${String(response.status)}`);
|
|
117497
|
+
if (spec.botMarkers.some((m) => html.includes(m))) throw new Error(`${spec.label} blocked the request with an anti-bot challenge`);
|
|
117498
|
+
const results = [];
|
|
117499
|
+
const seen = /* @__PURE__ */ new Set();
|
|
117500
|
+
for (const match of html.matchAll(spec.blockRe)) {
|
|
117501
|
+
if (results.length >= limit) break;
|
|
117502
|
+
const block = match[1] ?? "";
|
|
117503
|
+
const title = spec.titleRe.exec(block);
|
|
117504
|
+
if (title === null) continue;
|
|
117505
|
+
const rawHref = (title[1] ?? "").replace(/&/gi, "&");
|
|
117506
|
+
const url = spec.normalizeUrl !== void 0 ? spec.normalizeUrl(rawHref) : rawHref;
|
|
117507
|
+
if (url === void 0 || url === "" || seen.has(url)) continue;
|
|
117508
|
+
const titleText = decodeHtmlText(title[2] ?? "");
|
|
117509
|
+
if (titleText === "") continue;
|
|
117510
|
+
seen.add(url);
|
|
117511
|
+
const snippetMatch = spec.snippetRe === void 0 ? null : spec.snippetRe.exec(block);
|
|
117512
|
+
const snippetText = snippetMatch !== null ? decodeHtmlText(snippetMatch[1] ?? "") : "";
|
|
117513
|
+
results.push({
|
|
117514
|
+
title: titleText,
|
|
117515
|
+
url,
|
|
117516
|
+
snippet: snippetText !== "" ? snippetText : titleText
|
|
117517
|
+
});
|
|
117518
|
+
}
|
|
117519
|
+
return results;
|
|
117520
|
+
}
|
|
117521
|
+
const SOGOU = {
|
|
117522
|
+
label: "Sogou",
|
|
117523
|
+
url: (q) => `https://www.sogou.com/web?query=${encodeURIComponent(q)}`,
|
|
117524
|
+
blockRe: /<div\b[^>]*\bclass="[^"]*\b(?:vrwrap|rb)\b[^"]*"[^>]*>([\s\S]*?)(?=<div\b[^>]*\bclass="[^"]*\b(?:vrwrap|rb)\b|$)/g,
|
|
117525
|
+
titleRe: /<h3[^>]*>[\s\S]*?<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/,
|
|
117526
|
+
snippetRe: /<(?:p|div)\b[^>]*\bclass="[^"]*\b(?:str-text|str_info|text-layout)\b[^"]*"[^>]*>([\s\S]*?)<\/(?:p|div)>/,
|
|
117527
|
+
normalizeUrl: (href) => {
|
|
117528
|
+
if (href.startsWith("/link?")) return `https://www.sogou.com${href}`;
|
|
117529
|
+
if (href.includes("sogou.com/sogou?")) return void 0;
|
|
117530
|
+
if (href.startsWith("http://") || href.startsWith("https://")) return href;
|
|
117531
|
+
},
|
|
117532
|
+
botMarkers: ["antispider", "异常访问请求"]
|
|
117533
|
+
};
|
|
117534
|
+
var SogouSearchProvider = class {
|
|
117535
|
+
name = "sogou";
|
|
117536
|
+
fetchImpl;
|
|
117537
|
+
constructor(options = {}) {
|
|
117538
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
117539
|
+
}
|
|
117540
|
+
search(query, options) {
|
|
117541
|
+
return searchEngine(SOGOU, this.fetchImpl, query, options);
|
|
117542
|
+
}
|
|
117543
|
+
};
|
|
117544
|
+
const SO360 = {
|
|
117545
|
+
label: "360 Search",
|
|
117546
|
+
url: (q) => `https://www.so.com/s?q=${encodeURIComponent(q)}`,
|
|
117547
|
+
blockRe: /<li\b[^>]*\bclass="[^"]*\bres-list\b[^"]*"[^>]*>([\s\S]*?)(?=<li\b[^>]*\bclass="[^"]*\bres-list\b|$)/g,
|
|
117548
|
+
titleRe: /<h3[^>]*class="[^"]*\bres-title\b[^"]*"[^>]*>[\s\S]*?<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/,
|
|
117549
|
+
snippetRe: /<p\b[^>]*\bclass="[^"]*\bres-desc\b[^"]*"[^>]*>([\s\S]*?)<\/p>/,
|
|
117550
|
+
botMarkers: ["安全验证"]
|
|
117551
|
+
};
|
|
117552
|
+
var So360SearchProvider = class {
|
|
117553
|
+
name = "360";
|
|
117554
|
+
fetchImpl;
|
|
117555
|
+
constructor(options = {}) {
|
|
117556
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
117557
|
+
}
|
|
117558
|
+
search(query, options) {
|
|
117559
|
+
return searchEngine(SO360, this.fetchImpl, query, options);
|
|
117560
|
+
}
|
|
117561
|
+
};
|
|
117562
|
+
const BAIDU = {
|
|
117563
|
+
label: "Baidu",
|
|
117564
|
+
url: (q) => `https://www.baidu.com/s?wd=${encodeURIComponent(q)}`,
|
|
117565
|
+
blockRe: /<div\b[^>]*\bclass="[^"]*\bc-container\b[^"]*"[^>]*>([\s\S]*?)(?=<div\b[^>]*\bclass="[^"]*\bc-container\b|$)/g,
|
|
117566
|
+
titleRe: /<h3[^>]*class="[^"]*\bt\b[^"]*"[^>]*>[\s\S]*?<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/,
|
|
117567
|
+
snippetRe: /<(?:span|div)\b[^>]*\bclass="[^"]*\b(?:c-abstract|content-right)[^"]*\b[^"]*"[^>]*>([\s\S]*?)<\/(?:span|div)>/,
|
|
117568
|
+
botMarkers: ["百度安全验证", "wappass.baidu.com"]
|
|
117569
|
+
};
|
|
117570
|
+
var BaiduSearchProvider = class {
|
|
117571
|
+
name = "baidu";
|
|
117572
|
+
fetchImpl;
|
|
117573
|
+
constructor(options = {}) {
|
|
117574
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
117575
|
+
}
|
|
117576
|
+
search(query, options) {
|
|
117577
|
+
return searchEngine(BAIDU, this.fetchImpl, query, options);
|
|
117578
|
+
}
|
|
117579
|
+
};
|
|
117605
117580
|
//#endregion
|
|
117606
117581
|
//#region ../../packages/agent-core/src/tools/providers/fallback-search.ts
|
|
117607
117582
|
var FallbackSearchProvider = class {
|
|
@@ -117611,94 +117586,31 @@ var FallbackSearchProvider = class {
|
|
|
117611
117586
|
this.providers = providers;
|
|
117612
117587
|
}
|
|
117613
117588
|
async search(query, options) {
|
|
117614
|
-
|
|
117615
|
-
|
|
117616
|
-
|
|
117617
|
-
|
|
117618
|
-
|
|
117619
|
-
|
|
117620
|
-
|
|
117621
|
-
|
|
117622
|
-
|
|
117623
|
-
|
|
117624
|
-
|
|
117625
|
-
|
|
117626
|
-
|
|
117627
|
-
|
|
117628
|
-
|
|
117629
|
-
|
|
117630
|
-
|
|
117631
|
-
fetchImpl;
|
|
117632
|
-
constructor(options) {
|
|
117633
|
-
this.tokenProvider = options.tokenProvider;
|
|
117634
|
-
this.apiKey = options.apiKey;
|
|
117635
|
-
this.baseUrl = options.baseUrl;
|
|
117636
|
-
this.defaultHeaders = options.defaultHeaders ?? {};
|
|
117637
|
-
this.customHeaders = options.customHeaders ?? {};
|
|
117638
|
-
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
117639
|
-
}
|
|
117640
|
-
async search(query, options) {
|
|
117641
|
-
const body = {
|
|
117642
|
-
text_query: query,
|
|
117643
|
-
limit: options?.limit ?? 5,
|
|
117644
|
-
enable_page_crawling: options?.includeContent ?? false,
|
|
117645
|
-
timeout_seconds: 30
|
|
117646
|
-
};
|
|
117647
|
-
const bodyJson = JSON.stringify(body);
|
|
117648
|
-
const toolCallId = options?.toolCallId;
|
|
117649
|
-
const response = await this.post(bodyJson, toolCallId);
|
|
117650
|
-
if (response.status === 401) {
|
|
117651
|
-
const detail = await safeReadText(response);
|
|
117652
|
-
throw new Error(`ScreamCli search request failed: HTTP 401 (auth/unauthorized). ${detail}`.trim());
|
|
117653
|
-
}
|
|
117654
|
-
if (response.status !== 200) {
|
|
117655
|
-
const detail = await safeReadText(response);
|
|
117656
|
-
throw new Error(`ScreamCli search request failed: HTTP ${String(response.status)}. ${detail}`.trim());
|
|
117657
|
-
}
|
|
117658
|
-
const json = await response.json();
|
|
117659
|
-
return (Array.isArray(json.search_results) ? json.search_results : []).map((r) => {
|
|
117660
|
-
const out = {
|
|
117661
|
-
title: r.title ?? "",
|
|
117662
|
-
url: r.url ?? "",
|
|
117663
|
-
snippet: r.snippet ?? ""
|
|
117664
|
-
};
|
|
117665
|
-
if (typeof r.date === "string" && r.date.length > 0) out.date = r.date;
|
|
117666
|
-
if (typeof r.content === "string" && r.content.length > 0) out.content = r.content;
|
|
117667
|
-
return out;
|
|
117668
|
-
});
|
|
117669
|
-
}
|
|
117670
|
-
async post(bodyJson, toolCallId) {
|
|
117671
|
-
const accessToken = await this.resolveApiKey();
|
|
117672
|
-
return this.fetchImpl(this.baseUrl, {
|
|
117673
|
-
method: "POST",
|
|
117674
|
-
headers: {
|
|
117675
|
-
...this.defaultHeaders,
|
|
117676
|
-
Authorization: `Bearer ${accessToken}`,
|
|
117677
|
-
"Content-Type": "application/json",
|
|
117678
|
-
...toolCallId !== void 0 && toolCallId.length > 0 ? { "X-Msh-Tool-Call-Id": toolCallId } : {},
|
|
117679
|
-
...this.customHeaders
|
|
117680
|
-
},
|
|
117681
|
-
body: bodyJson
|
|
117682
|
-
});
|
|
117683
|
-
}
|
|
117684
|
-
async resolveApiKey() {
|
|
117685
|
-
if (this.tokenProvider !== void 0) try {
|
|
117686
|
-
return await this.tokenProvider.getAccessToken();
|
|
117687
|
-
} catch (error) {
|
|
117688
|
-
if (this.apiKey !== void 0 && this.apiKey.length > 0) return this.apiKey;
|
|
117689
|
-
throw error;
|
|
117589
|
+
const failures = [];
|
|
117590
|
+
for (const [index, provider] of this.providers.entries()) {
|
|
117591
|
+
options?.signal?.throwIfAborted();
|
|
117592
|
+
try {
|
|
117593
|
+
const results = await provider.search(query, options);
|
|
117594
|
+
if (results.length > 0) return results;
|
|
117595
|
+
failures.push({
|
|
117596
|
+
provider: provider.name ?? `provider ${String(index + 1)}`,
|
|
117597
|
+
reason: "no results"
|
|
117598
|
+
});
|
|
117599
|
+
} catch (error) {
|
|
117600
|
+
options?.signal?.throwIfAborted();
|
|
117601
|
+
failures.push({
|
|
117602
|
+
provider: provider.name ?? `provider ${String(index + 1)}`,
|
|
117603
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
117604
|
+
});
|
|
117605
|
+
}
|
|
117690
117606
|
}
|
|
117691
|
-
if (
|
|
117692
|
-
|
|
117607
|
+
if (failures.every((f) => f.reason === "no results")) return [];
|
|
117608
|
+
const last = failures[failures.length - 1];
|
|
117609
|
+
if (this.providers.length === 1 && last !== void 0) throw new Error(last.reason);
|
|
117610
|
+
const summary = failures.map((f) => `${f.provider}: ${f.reason}`).join("; ");
|
|
117611
|
+
throw new Error(`All web search providers failed — ${summary}`);
|
|
117693
117612
|
}
|
|
117694
117613
|
};
|
|
117695
|
-
async function safeReadText(response) {
|
|
117696
|
-
try {
|
|
117697
|
-
return await response.text();
|
|
117698
|
-
} catch {
|
|
117699
|
-
return "";
|
|
117700
|
-
}
|
|
117701
|
-
}
|
|
117702
117614
|
//#endregion
|
|
117703
117615
|
//#region ../../packages/agent-core/src/session/export/manifest.ts
|
|
117704
117616
|
const WIRE_PROTOCOL_VERSION = "1.3";
|
|
@@ -118888,7 +118800,7 @@ function providerApiKey(provider) {
|
|
|
118888
118800
|
case "openai_responses": return providerValue(provider.apiKey, provider.env, "OPENAI_API_KEY");
|
|
118889
118801
|
case "scream": return providerValue(provider.apiKey, provider.env, "SCREAM_API_KEY");
|
|
118890
118802
|
case "google-genai": return providerValue(provider.apiKey, provider.env, "GOOGLE_API_KEY");
|
|
118891
|
-
case "vertexai": return nonEmptyString
|
|
118803
|
+
case "vertexai": return nonEmptyString(provider.apiKey) ?? envValue(provider.env, "VERTEXAI_API_KEY") ?? envValue(provider.env, "GOOGLE_API_KEY");
|
|
118892
118804
|
default: {
|
|
118893
118805
|
const exhaustive = provider.type;
|
|
118894
118806
|
throw new ScreamError(ErrorCodes.MODEL_CONFIG_INVALID, `Unsupported provider type: ${String(exhaustive)}`);
|
|
@@ -118905,21 +118817,21 @@ function vertexAILocation(provider) {
|
|
|
118905
118817
|
return envValue(provider.env, "GOOGLE_CLOUD_LOCATION") ?? locationFromVertexAIBaseUrl(provider.baseUrl);
|
|
118906
118818
|
}
|
|
118907
118819
|
function providerValue(configured, env, envKey) {
|
|
118908
|
-
return nonEmptyString
|
|
118820
|
+
return nonEmptyString(configured) ?? envValue(env, envKey);
|
|
118909
118821
|
}
|
|
118910
118822
|
function envValue(env, key) {
|
|
118911
|
-
return nonEmptyString
|
|
118823
|
+
return nonEmptyString(env?.[key]);
|
|
118912
118824
|
}
|
|
118913
|
-
function nonEmptyString
|
|
118825
|
+
function nonEmptyString(value) {
|
|
118914
118826
|
const trimmed = value?.trim();
|
|
118915
118827
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
118916
118828
|
}
|
|
118917
118829
|
function locationFromVertexAIBaseUrl(baseUrl) {
|
|
118918
|
-
const url = nonEmptyString
|
|
118830
|
+
const url = nonEmptyString(baseUrl);
|
|
118919
118831
|
if (url === void 0) return void 0;
|
|
118920
118832
|
try {
|
|
118921
118833
|
const host = new URL(url).hostname;
|
|
118922
|
-
return host.endsWith("-aiplatform.googleapis.com") ? nonEmptyString
|
|
118834
|
+
return host.endsWith("-aiplatform.googleapis.com") ? nonEmptyString(host.slice(0, -26)) : void 0;
|
|
118923
118835
|
} catch {
|
|
118924
118836
|
return;
|
|
118925
118837
|
}
|
|
@@ -120464,7 +120376,6 @@ function waitForSpawn(child) {
|
|
|
120464
120376
|
new AsyncLocalStorage();
|
|
120465
120377
|
//#endregion
|
|
120466
120378
|
//#region ../../packages/agent-core/src/rpc/core-impl.ts
|
|
120467
|
-
const SCREAM_CODE_PROVIDER_NAME = "managed:scream-code";
|
|
120468
120379
|
var ScreamCore = class {
|
|
120469
120380
|
rpcClient;
|
|
120470
120381
|
sdk;
|
|
@@ -120945,11 +120856,7 @@ var ScreamCore = class {
|
|
|
120945
120856
|
}
|
|
120946
120857
|
async resolveRuntime(config) {
|
|
120947
120858
|
if (this.runtime !== void 0) return this.runtime;
|
|
120948
|
-
const runtime = await createRuntimeConfig({
|
|
120949
|
-
config,
|
|
120950
|
-
screamRequestHeaders: this.screamRequestHeaders,
|
|
120951
|
-
resolveOAuthTokenProvider: this.resolveOAuthTokenProvider
|
|
120952
|
-
});
|
|
120859
|
+
const runtime = await createRuntimeConfig({ config });
|
|
120953
120860
|
this.runtime = runtime;
|
|
120954
120861
|
return runtime;
|
|
120955
120862
|
}
|
|
@@ -121006,42 +120913,20 @@ var ScreamCore = class {
|
|
|
121006
120913
|
}
|
|
121007
120914
|
};
|
|
121008
120915
|
async function createRuntimeConfig(input) {
|
|
121009
|
-
const fetchCache = new FetchCache();
|
|
121010
|
-
const localFetcher = new LocalFetchURLProvider({ cache: fetchCache });
|
|
121011
|
-
const fetchService = input.config.services?.screamCliFetch;
|
|
121012
120916
|
return {
|
|
121013
|
-
urlFetcher:
|
|
121014
|
-
baseUrl: fetchService.baseUrl,
|
|
121015
|
-
localFallback: localFetcher,
|
|
121016
|
-
defaultHeaders: input.screamRequestHeaders,
|
|
121017
|
-
cache: fetchCache,
|
|
121018
|
-
...serviceCredentials(fetchService, input.resolveOAuthTokenProvider)
|
|
121019
|
-
}),
|
|
120917
|
+
urlFetcher: new LocalFetchURLProvider({ cache: new FetchCache() }),
|
|
121020
120918
|
webSearcher: buildWebSearcher(input)
|
|
121021
120919
|
};
|
|
121022
120920
|
}
|
|
121023
120921
|
function buildWebSearcher(input) {
|
|
121024
|
-
const
|
|
121025
|
-
const
|
|
121026
|
-
|
|
121027
|
-
|
|
121028
|
-
|
|
121029
|
-
|
|
121030
|
-
|
|
121031
|
-
|
|
121032
|
-
if (screamProvider && ddgProvider) return new FallbackSearchProvider([screamProvider, ddgProvider]);
|
|
121033
|
-
return screamProvider ?? ddgProvider;
|
|
121034
|
-
}
|
|
121035
|
-
function serviceCredentials(service, resolveOAuthTokenProvider) {
|
|
121036
|
-
return {
|
|
121037
|
-
apiKey: nonEmptyString(service.apiKey),
|
|
121038
|
-
tokenProvider: service.oauth !== void 0 ? resolveOAuthTokenProvider?.(SCREAM_CODE_PROVIDER_NAME, service.oauth) : void 0,
|
|
121039
|
-
customHeaders: service.customHeaders
|
|
121040
|
-
};
|
|
121041
|
-
}
|
|
121042
|
-
function nonEmptyString(value) {
|
|
121043
|
-
const trimmed = value?.trim();
|
|
121044
|
-
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
120922
|
+
const services = input.config.services;
|
|
120923
|
+
const providers = [];
|
|
120924
|
+
if (services?.duckduckgo?.enabled !== false) providers.push(new DuckDuckGoSearchProvider());
|
|
120925
|
+
if (services?.sogou?.enabled !== false) providers.push(new SogouSearchProvider());
|
|
120926
|
+
if (services?.so360?.enabled !== false) providers.push(new So360SearchProvider());
|
|
120927
|
+
if (services?.baidu?.enabled !== false) providers.push(new BaiduSearchProvider());
|
|
120928
|
+
if (providers.length === 0) return void 0;
|
|
120929
|
+
return providers.length === 1 ? providers[0] : new FallbackSearchProvider(providers);
|
|
121045
120930
|
}
|
|
121046
120931
|
function requiredWorkDir(operation, value) {
|
|
121047
120932
|
if (typeof value !== "string" || value.trim() === "") throw new ScreamError(ErrorCodes.REQUEST_WORK_DIR_REQUIRED, `${operation} requires workDir`);
|
|
@@ -122505,7 +122390,7 @@ function optionalBuildString(value) {
|
|
|
122505
122390
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
122506
122391
|
}
|
|
122507
122392
|
const SCREAM_BUILD_INFO = {
|
|
122508
|
-
version: optionalBuildString("0.10.
|
|
122393
|
+
version: optionalBuildString("0.10.2"),
|
|
122509
122394
|
channel: optionalBuildString(""),
|
|
122510
122395
|
commit: optionalBuildString(""),
|
|
122511
122396
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -122991,7 +122876,7 @@ async function resolvePromptSession(harness, opts, workDir, defaultModel, stderr
|
|
|
122991
122876
|
workDir
|
|
122992
122877
|
}))[0];
|
|
122993
122878
|
if (target === void 0) throw new Error(`未找到会话 "${opts.session}"。`);
|
|
122994
|
-
if (target.workDir
|
|
122879
|
+
if (!sameWorkDir(target.workDir, workDir)) {
|
|
122995
122880
|
stderr.write(`${chalk.yellow(`会话 "${opts.session}" 是在其他目录下创建的。\n cd "${target.workDir}" && scream -r ${opts.session}`)}\n\n`);
|
|
122996
122881
|
throw new Error(`会话 "${opts.session}" 是在其他目录下创建的。`);
|
|
122997
122882
|
}
|
|
@@ -123380,6 +123265,23 @@ function formatTurnEndedFailure(event) {
|
|
|
123380
123265
|
if (event.error !== void 0) return `${event.error.code}: ${event.error.message}`;
|
|
123381
123266
|
return `提示回合结束,原因:${event.reason}`;
|
|
123382
123267
|
}
|
|
123268
|
+
/**
|
|
123269
|
+
* Compare two working directories tolerating symlink aliases (/tmp vs
|
|
123270
|
+
* /private/tmp on macOS), trailing separators, and Windows case
|
|
123271
|
+
* differences. Falls back to resolved-string compare when either path
|
|
123272
|
+
* doesn't exist on disk.
|
|
123273
|
+
*/
|
|
123274
|
+
function sameWorkDir(a, b) {
|
|
123275
|
+
const normalize = (p) => {
|
|
123276
|
+
let out = resolve(p);
|
|
123277
|
+
try {
|
|
123278
|
+
out = realpathSync(out);
|
|
123279
|
+
} catch {}
|
|
123280
|
+
out = out.replace(/[/\\]+$/, "");
|
|
123281
|
+
return process.platform === "win32" ? out.toLowerCase() : out;
|
|
123282
|
+
};
|
|
123283
|
+
return normalize(a) === normalize(b);
|
|
123284
|
+
}
|
|
123383
123285
|
//#endregion
|
|
123384
123286
|
//#region src/tui/constant/rendering.ts
|
|
123385
123287
|
const MAX_SHELL_OUTPUT_BYTES = 128 * 1024;
|
|
@@ -123838,12 +123740,13 @@ function isManagedUsageProvider(providerKey) {
|
|
|
123838
123740
|
//#region src/tui/constant/streaming.ts
|
|
123839
123741
|
const STREAMING_ARGS_FIELD_RE = /"(path|file_path|command|pattern|query|url|description|title|name)"\s*:\s*"((?:\\.|[^"\\])*)"/g;
|
|
123840
123742
|
const STREAMING_ARGS_PREVIEW_MAX_CHARS = 8 * 1024;
|
|
123743
|
+
const STREAMING_ARGS_BUFFER_MAX_CHARS = 1024 * 1024;
|
|
123841
123744
|
//#endregion
|
|
123842
123745
|
//#region src/tui/utils/event-payload.ts
|
|
123843
123746
|
function appendStreamingArgsPreview(current, next) {
|
|
123844
|
-
const existing = (current ?? "").slice(0,
|
|
123747
|
+
const existing = (current ?? "").slice(0, STREAMING_ARGS_BUFFER_MAX_CHARS);
|
|
123845
123748
|
if (next === null || next === void 0 || next.length === 0) return existing;
|
|
123846
|
-
const remaining =
|
|
123749
|
+
const remaining = STREAMING_ARGS_BUFFER_MAX_CHARS - existing.length;
|
|
123847
123750
|
if (remaining <= 0) return existing;
|
|
123848
123751
|
return `${existing}${next.slice(0, remaining)}`;
|
|
123849
123752
|
}
|
|
@@ -125769,7 +125672,7 @@ var FooterComponent = class {
|
|
|
125769
125672
|
gitCache;
|
|
125770
125673
|
gitCacheWorkDir;
|
|
125771
125674
|
transientHint = null;
|
|
125772
|
-
|
|
125675
|
+
statusTimer = null;
|
|
125773
125676
|
/**
|
|
125774
125677
|
* Non-terminal background-task counts split by kind so the footer can
|
|
125775
125678
|
* render two distinct badges. `bashTasks` covers `bash-*` BPM tasks
|
|
@@ -125788,15 +125691,13 @@ var FooterComponent = class {
|
|
|
125788
125691
|
this.gitCache = createGitStatusCache(state.workDir, { onChange: this.onGitStatusChange });
|
|
125789
125692
|
}
|
|
125790
125693
|
setState(state) {
|
|
125791
|
-
const
|
|
125694
|
+
const prevPhase = this.state?.streamingPhase;
|
|
125792
125695
|
if (state.workDir !== this.gitCacheWorkDir) {
|
|
125793
125696
|
this.gitCacheWorkDir = state.workDir;
|
|
125794
125697
|
this.gitCache = createGitStatusCache(state.workDir, { onChange: this.onGitStatusChange });
|
|
125795
125698
|
}
|
|
125796
125699
|
this.state = state;
|
|
125797
|
-
|
|
125798
|
-
if (isThinking && !wasThinking) this.#startShimmer();
|
|
125799
|
-
else if (!isThinking && wasThinking) this.#stopShimmer();
|
|
125700
|
+
if (state.streamingPhase !== prevPhase) this.#restartStatusTimer(state.streamingPhase);
|
|
125800
125701
|
}
|
|
125801
125702
|
setColors(colors) {
|
|
125802
125703
|
this.colors = colors;
|
|
@@ -125821,29 +125722,29 @@ var FooterComponent = class {
|
|
|
125821
125722
|
}
|
|
125822
125723
|
invalidate() {}
|
|
125823
125724
|
/**
|
|
125824
|
-
* Stop the
|
|
125725
|
+
* Stop the status timer. Idempotent — safe to call even when
|
|
125825
125726
|
* the timer isn't running. Call this when the component is disposed.
|
|
125826
125727
|
*/
|
|
125827
125728
|
dispose() {
|
|
125828
|
-
this.#
|
|
125729
|
+
this.#stopStatusTimer();
|
|
125829
125730
|
}
|
|
125830
|
-
#
|
|
125831
|
-
|
|
125832
|
-
|
|
125833
|
-
|
|
125834
|
-
|
|
125731
|
+
#restartStatusTimer(phase) {
|
|
125732
|
+
this.#stopStatusTimer();
|
|
125733
|
+
if (phase === "idle") return;
|
|
125734
|
+
const intervalMs = phase === "thinking" ? 1e3 / 30 : SPINNER_TICK_MS;
|
|
125735
|
+
this.statusTimer = setInterval(() => {
|
|
125736
|
+
this.ui.requestComponentRender(this);
|
|
125737
|
+
}, intervalMs);
|
|
125835
125738
|
}
|
|
125836
|
-
#
|
|
125837
|
-
if (!this.
|
|
125838
|
-
clearInterval(this.
|
|
125839
|
-
this.
|
|
125739
|
+
#stopStatusTimer() {
|
|
125740
|
+
if (!this.statusTimer) return;
|
|
125741
|
+
clearInterval(this.statusTimer);
|
|
125742
|
+
this.statusTimer = null;
|
|
125840
125743
|
}
|
|
125841
125744
|
render(width) {
|
|
125842
125745
|
const colors = this.colors;
|
|
125843
125746
|
const state = this.state;
|
|
125844
125747
|
const left = [];
|
|
125845
|
-
if (state.permissionMode === "auto") left.push(chalk.hex(colors.warning).bold(t("badge.auto")));
|
|
125846
|
-
if (state.permissionMode === "yolo") left.push(chalk.hex(colors.warning).bold(t("badge.yes")));
|
|
125847
125748
|
if (state.planMode !== "off") {
|
|
125848
125749
|
const isFusion = state.planMode === "fusionplan";
|
|
125849
125750
|
left.push(chalk.hex(isFusion ? colors.fusionPlanMode : colors.planMode).bold(isFusion ? t("badge.fusion") : t("badge.plan")));
|
|
@@ -126727,7 +126628,6 @@ async function handleYoloCommand(host, args) {
|
|
|
126727
126628
|
}
|
|
126728
126629
|
await session.setPermission("yolo");
|
|
126729
126630
|
host.setAppState({ permissionMode: "yolo" });
|
|
126730
|
-
host.showNotice(t("config.yolo_on"), t("config.yolo_on_desc"));
|
|
126731
126631
|
return;
|
|
126732
126632
|
}
|
|
126733
126633
|
if (subcmd === "off") {
|
|
@@ -126737,17 +126637,14 @@ async function handleYoloCommand(host, args) {
|
|
|
126737
126637
|
}
|
|
126738
126638
|
await session.setPermission("manual");
|
|
126739
126639
|
host.setAppState({ permissionMode: "manual" });
|
|
126740
|
-
host.showNotice(t("config.yolo_off"));
|
|
126741
126640
|
return;
|
|
126742
126641
|
}
|
|
126743
126642
|
if (currentMode === "yolo") {
|
|
126744
126643
|
await session.setPermission("manual");
|
|
126745
126644
|
host.setAppState({ permissionMode: "manual" });
|
|
126746
|
-
host.showNotice(t("config.yolo_off"));
|
|
126747
126645
|
} else {
|
|
126748
126646
|
await session.setPermission("yolo");
|
|
126749
126647
|
host.setAppState({ permissionMode: "yolo" });
|
|
126750
|
-
host.showNotice(t("config.yolo_toggle_on"), t("config.yolo_toggle_on_desc"));
|
|
126751
126648
|
}
|
|
126752
126649
|
}
|
|
126753
126650
|
async function handleAutoCommand(host, args) {
|
|
@@ -126765,7 +126662,6 @@ async function handleAutoCommand(host, args) {
|
|
|
126765
126662
|
}
|
|
126766
126663
|
await session.setPermission("auto");
|
|
126767
126664
|
host.setAppState({ permissionMode: "auto" });
|
|
126768
|
-
host.showNotice(t("config.auto_on"), t("config.auto_on_desc"));
|
|
126769
126665
|
return;
|
|
126770
126666
|
}
|
|
126771
126667
|
if (subcmd === "off") {
|
|
@@ -126775,17 +126671,14 @@ async function handleAutoCommand(host, args) {
|
|
|
126775
126671
|
}
|
|
126776
126672
|
await session.setPermission("manual");
|
|
126777
126673
|
host.setAppState({ permissionMode: "manual" });
|
|
126778
|
-
host.showNotice(t("config.auto_off"));
|
|
126779
126674
|
return;
|
|
126780
126675
|
}
|
|
126781
126676
|
if (currentMode === "auto") {
|
|
126782
126677
|
await session.setPermission("manual");
|
|
126783
126678
|
host.setAppState({ permissionMode: "manual" });
|
|
126784
|
-
host.showNotice(t("config.auto_off"));
|
|
126785
126679
|
} else {
|
|
126786
126680
|
await session.setPermission("auto");
|
|
126787
126681
|
host.setAppState({ permissionMode: "auto" });
|
|
126788
|
-
host.showNotice(t("config.auto_toggle_on"), t("config.auto_toggle_on_desc"));
|
|
126789
126682
|
}
|
|
126790
126683
|
}
|
|
126791
126684
|
async function handleWolfpackCommand(host, args) {
|
|
@@ -127788,7 +127681,7 @@ async function createGoal(host, parsed) {
|
|
|
127788
127681
|
await showGoalConfigWizard(host, session, parsed.objective, parsed.replace);
|
|
127789
127682
|
}
|
|
127790
127683
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
127791
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
127684
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-C8_8qYYi.mjs");
|
|
127792
127685
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
127793
127686
|
title: t("goal.wizard_title", { objective }),
|
|
127794
127687
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -128537,7 +128430,7 @@ var AssistantMessageComponent = class {
|
|
|
128537
128430
|
const age = Date.now() - (this.fadeStartMs ?? 0);
|
|
128538
128431
|
this.cachedWidth = void 0;
|
|
128539
128432
|
this.cachedLines = void 0;
|
|
128540
|
-
this.ui?.
|
|
128433
|
+
this.ui?.requestComponentRender(this);
|
|
128541
128434
|
if (age >= 1200) this.stopFade();
|
|
128542
128435
|
}, FADE_TICK_MS);
|
|
128543
128436
|
this.ui.requestRender();
|
|
@@ -129018,7 +128911,7 @@ var ThinkingComponent = class {
|
|
|
129018
128911
|
if (this.ui === void 0 || this.spinnerInterval !== void 0) return;
|
|
129019
128912
|
this.spinnerInterval = setInterval(() => {
|
|
129020
128913
|
this.spinnerFrame = (this.spinnerFrame + 1) % BRAILLE_SPINNER_FRAMES.length;
|
|
129021
|
-
this.ui?.
|
|
128914
|
+
this.ui?.requestComponentRender(this);
|
|
129022
128915
|
}, 80);
|
|
129023
128916
|
}
|
|
129024
128917
|
stopSpinner() {
|
|
@@ -130205,23 +130098,20 @@ function unescapeJsonString(s) {
|
|
|
130205
130098
|
});
|
|
130206
130099
|
}
|
|
130207
130100
|
/**
|
|
130208
|
-
*
|
|
130209
|
-
*
|
|
130210
|
-
*
|
|
130211
|
-
*
|
|
130212
|
-
*
|
|
130101
|
+
* Scan a JSON string value starting at `start` (just after the opening
|
|
130102
|
+
* quote), unescaping into plain text. Stops at the closing quote or at
|
|
130103
|
+
* `end`, tolerating truncation (an incomplete escape at the boundary
|
|
130104
|
+
* simply ends the scan). Shared by the partial-args extractor and the
|
|
130105
|
+
* Write streaming tail preview.
|
|
130213
130106
|
*/
|
|
130214
|
-
function
|
|
130215
|
-
const match = new RegExp(`"${key}"\\s*:\\s*"`).exec(text);
|
|
130216
|
-
if (match === null) return void 0;
|
|
130217
|
-
const start = match.index + match[0].length;
|
|
130107
|
+
function unescapeJsonStringValue(text, start, end = text.length) {
|
|
130218
130108
|
let out = "";
|
|
130219
130109
|
let i = start;
|
|
130220
|
-
while (i <
|
|
130110
|
+
while (i < end) {
|
|
130221
130111
|
const ch = text[i];
|
|
130222
130112
|
if (ch === "\\") {
|
|
130223
130113
|
const next = text[i + 1];
|
|
130224
|
-
if (next === void 0) return out;
|
|
130114
|
+
if (next === void 0 || i + 1 >= end) return out;
|
|
130225
130115
|
switch (next) {
|
|
130226
130116
|
case "n":
|
|
130227
130117
|
out += "\n";
|
|
@@ -130248,7 +130138,7 @@ function extractPartialStringField(text, key) {
|
|
|
130248
130138
|
out += "/";
|
|
130249
130139
|
break;
|
|
130250
130140
|
case "u": {
|
|
130251
|
-
if (i + 5 >=
|
|
130141
|
+
if (i + 5 >= end) return out;
|
|
130252
130142
|
const hex = text.slice(i + 2, i + 6);
|
|
130253
130143
|
const code = Number.parseInt(hex, 16);
|
|
130254
130144
|
if (Number.isNaN(code)) return out;
|
|
@@ -130267,6 +130157,16 @@ function extractPartialStringField(text, key) {
|
|
|
130267
130157
|
}
|
|
130268
130158
|
return out;
|
|
130269
130159
|
}
|
|
130160
|
+
/**
|
|
130161
|
+
* Pull the live value of a JSON string field out of partially-streamed
|
|
130162
|
+
* arguments, even if the closing quote hasn't arrived yet. Returns
|
|
130163
|
+
* `undefined` if the field hasn't started streaming yet.
|
|
130164
|
+
*/
|
|
130165
|
+
function extractPartialStringField(text, key) {
|
|
130166
|
+
const match = new RegExp(`"${key}"\\s*:\\s*"`).exec(text);
|
|
130167
|
+
if (match === null) return void 0;
|
|
130168
|
+
return unescapeJsonStringValue(text, match.index + match[0].length);
|
|
130169
|
+
}
|
|
130270
130170
|
function parseArgsPreview(value) {
|
|
130271
130171
|
const previewText = value.slice(0, STREAMING_ARGS_PREVIEW_MAX_CHARS);
|
|
130272
130172
|
if (previewText.trim().length === 0) return {};
|
|
@@ -130409,6 +130309,11 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
130409
130309
|
subagentEndedAtMs;
|
|
130410
130310
|
progressLines = [];
|
|
130411
130311
|
static MAX_PROGRESS_LINES = 24;
|
|
130312
|
+
writeStreamContentStart = -1;
|
|
130313
|
+
writeStreamNlScanOffset = 0;
|
|
130314
|
+
writeStreamNlCount = 0;
|
|
130315
|
+
writeStreamLang;
|
|
130316
|
+
static WRITE_STREAM_TAIL_RAW_CHARS = 4096;
|
|
130412
130317
|
/**
|
|
130413
130318
|
* Registered by a group container (`AgentGroupComponent` or
|
|
130414
130319
|
* `ReadGroupComponent`) when this component is borrowed as a hidden state
|
|
@@ -131178,21 +131083,12 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
131178
131083
|
const name = this.toolCall.name;
|
|
131179
131084
|
const previewText = streamText.slice(0, STREAMING_ARGS_PREVIEW_MAX_CHARS);
|
|
131180
131085
|
if (name === "Write") {
|
|
131181
|
-
|
|
131182
|
-
if (content === void 0 || content.length === 0) return;
|
|
131183
|
-
const allLines = highlightLines(content, langFromPath(extractPartialStringField(previewText, "file_path") ?? extractPartialStringField(previewText, "path") ?? ""));
|
|
131184
|
-
const maxLines = 10;
|
|
131185
|
-
const scrollLines = allLines.length > maxLines ? allLines.slice(allLines.length - maxLines) : allLines;
|
|
131186
|
-
for (const [i, line] of scrollLines.entries()) {
|
|
131187
|
-
const originalLineNumber = allLines.length > maxLines ? allLines.length - maxLines + i : i;
|
|
131188
|
-
const lineNum = chalk.dim(String(originalLineNumber + 1).padStart(4) + " ");
|
|
131189
|
-
this.addChild(new Text(lineNum + line, 2, 0));
|
|
131190
|
-
}
|
|
131086
|
+
this.buildWriteStreamingPreview(streamText);
|
|
131191
131087
|
return;
|
|
131192
131088
|
}
|
|
131193
131089
|
if (name === "Edit") {
|
|
131194
131090
|
const filePath = extractPartialStringField(previewText, "file_path") ?? extractPartialStringField(previewText, "path") ?? "";
|
|
131195
|
-
const bytes = Buffer.byteLength(
|
|
131091
|
+
const bytes = Buffer.byteLength(streamText, "utf8");
|
|
131196
131092
|
const startedAtMs = this.toolCall.streamingStartedAtMs;
|
|
131197
131093
|
const elapsedSeconds = startedAtMs === void 0 ? 0 : Math.max(0, Math.floor((Date.now() - startedAtMs) / 1e3));
|
|
131198
131094
|
const progress = t("toolcall.preparing_changes", {
|
|
@@ -131214,6 +131110,54 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
131214
131110
|
}));
|
|
131215
131111
|
}
|
|
131216
131112
|
}
|
|
131113
|
+
/**
|
|
131114
|
+
* Live Write preview: renders the last COMMAND_PREVIEW_LINES lines of the
|
|
131115
|
+
* file being written, reading from the TAIL of the accumulating args JSON
|
|
131116
|
+
* so the window keeps scrolling for arbitrarily large files (the old
|
|
131117
|
+
* head-bounded preview visibly froze once args passed 8KB). Line numbers
|
|
131118
|
+
* stay exact via an incremental newline counter. Per-frame cost is
|
|
131119
|
+
* O(delta + tail), independent of total file size.
|
|
131120
|
+
*/
|
|
131121
|
+
buildWriteStreamingPreview(streamText) {
|
|
131122
|
+
if (streamText.length < this.writeStreamNlScanOffset) {
|
|
131123
|
+
this.writeStreamContentStart = -1;
|
|
131124
|
+
this.writeStreamLang = void 0;
|
|
131125
|
+
}
|
|
131126
|
+
if (this.writeStreamContentStart < 0) {
|
|
131127
|
+
const opener = /"content"\s*:\s*"/.exec(streamText);
|
|
131128
|
+
if (opener === null) return;
|
|
131129
|
+
this.writeStreamContentStart = opener.index + opener[0].length;
|
|
131130
|
+
this.writeStreamNlScanOffset = this.writeStreamContentStart;
|
|
131131
|
+
this.writeStreamNlCount = 0;
|
|
131132
|
+
const filePath = extractPartialStringField(streamText, "file_path") ?? extractPartialStringField(streamText, "path") ?? "";
|
|
131133
|
+
this.writeStreamLang = langFromPath(filePath);
|
|
131134
|
+
}
|
|
131135
|
+
const contentStart = this.writeStreamContentStart;
|
|
131136
|
+
const tailStart = Math.max(contentStart, streamText.length - ToolCallComponent.WRITE_STREAM_TAIL_RAW_CHARS);
|
|
131137
|
+
while (this.writeStreamNlScanOffset < tailStart) {
|
|
131138
|
+
const idx = streamText.indexOf("\\n", this.writeStreamNlScanOffset);
|
|
131139
|
+
if (idx === -1 || idx >= tailStart) break;
|
|
131140
|
+
this.writeStreamNlCount++;
|
|
131141
|
+
this.writeStreamNlScanOffset = idx + 2;
|
|
131142
|
+
}
|
|
131143
|
+
let fragmentStart = tailStart;
|
|
131144
|
+
if (tailStart > contentStart) {
|
|
131145
|
+
const firstNl = streamText.indexOf("\\n", tailStart);
|
|
131146
|
+
if (firstNl === -1) return;
|
|
131147
|
+
fragmentStart = firstNl + 2;
|
|
131148
|
+
}
|
|
131149
|
+
const fragmentEnd = Math.min(streamText.length, fragmentStart + ToolCallComponent.WRITE_STREAM_TAIL_RAW_CHARS);
|
|
131150
|
+
const fragment = unescapeJsonStringValue(streamText, fragmentStart, fragmentEnd);
|
|
131151
|
+
if (fragment.length === 0) return;
|
|
131152
|
+
const lines = highlightLines(fragment, this.writeStreamLang);
|
|
131153
|
+
const displayLines = lines.slice(-10);
|
|
131154
|
+
const firstFragmentLineNo = this.writeStreamNlCount + (tailStart > contentStart ? 2 : 1);
|
|
131155
|
+
const skipped = lines.length - displayLines.length;
|
|
131156
|
+
for (const [i, line] of displayLines.entries()) {
|
|
131157
|
+
const lineNum = chalk.dim(String(firstFragmentLineNo + skipped + i).padStart(4) + " ");
|
|
131158
|
+
this.addChild(new Text(lineNum + line, 2, 0));
|
|
131159
|
+
}
|
|
131160
|
+
}
|
|
131217
131161
|
buildPlanPreview() {
|
|
131218
131162
|
const plan = this.resolvePlanForPreview();
|
|
131219
131163
|
if (plan.length === 0) return;
|
|
@@ -132341,35 +132285,39 @@ async function handleUpdateCommand(host) {
|
|
|
132341
132285
|
* /mcp — MCP 服务器管理面板。
|
|
132342
132286
|
*
|
|
132343
132287
|
* 查看已安装的 MCP 服务器状态,一键安装推荐服务器。 */
|
|
132344
|
-
|
|
132345
|
-
|
|
132346
|
-
|
|
132347
|
-
|
|
132348
|
-
|
|
132349
|
-
|
|
132350
|
-
|
|
132351
|
-
|
|
132352
|
-
|
|
132353
|
-
|
|
132354
|
-
|
|
132355
|
-
|
|
132356
|
-
|
|
132357
|
-
|
|
132358
|
-
|
|
132359
|
-
|
|
132360
|
-
|
|
132361
|
-
|
|
132362
|
-
|
|
132363
|
-
|
|
132364
|
-
|
|
132365
|
-
|
|
132366
|
-
|
|
132367
|
-
|
|
132368
|
-
|
|
132369
|
-
|
|
132370
|
-
|
|
132371
|
-
|
|
132372
|
-
|
|
132288
|
+
function getRecommended() {
|
|
132289
|
+
return [{
|
|
132290
|
+
name: "peekaboo",
|
|
132291
|
+
displayName: "Peekaboo",
|
|
132292
|
+
description: t("mcp.desktop_desc"),
|
|
132293
|
+
command: "npx",
|
|
132294
|
+
args: [
|
|
132295
|
+
"-y",
|
|
132296
|
+
"@steipete/peekaboo",
|
|
132297
|
+
"mcp"
|
|
132298
|
+
],
|
|
132299
|
+
macOnly: true
|
|
132300
|
+
}, {
|
|
132301
|
+
name: "chrome-devtools",
|
|
132302
|
+
displayName: "Chrome DevTools",
|
|
132303
|
+
description: t("mcp.browser_desc"),
|
|
132304
|
+
command: "npx",
|
|
132305
|
+
args: [
|
|
132306
|
+
"-y",
|
|
132307
|
+
"chrome-devtools-mcp@latest",
|
|
132308
|
+
"--no-usage-statistics"
|
|
132309
|
+
]
|
|
132310
|
+
}];
|
|
132311
|
+
}
|
|
132312
|
+
function getStatusLabels() {
|
|
132313
|
+
return {
|
|
132314
|
+
pending: t("mcp.connecting"),
|
|
132315
|
+
connected: t("mcp.connected"),
|
|
132316
|
+
failed: t("mcp.failed"),
|
|
132317
|
+
disabled: t("mcp.disabled"),
|
|
132318
|
+
"needs-auth": t("mcp.auth_required")
|
|
132319
|
+
};
|
|
132320
|
+
}
|
|
132373
132321
|
async function handleMcpCommand(host, _args) {
|
|
132374
132322
|
if (!host.session) {
|
|
132375
132323
|
host.showError(t("mcp.no_session"));
|
|
@@ -132438,7 +132386,7 @@ function buildRows(servers) {
|
|
|
132438
132386
|
status: "__section"
|
|
132439
132387
|
});
|
|
132440
132388
|
for (const s of servers) {
|
|
132441
|
-
const statusLabel =
|
|
132389
|
+
const statusLabel = getStatusLabels()[s.status] ?? s.status;
|
|
132442
132390
|
const toolInfo = s.status === "connected" ? `${s.toolCount} tools` : "";
|
|
132443
132391
|
const errorInfo = s.error ? ` — ${sanitizeDesc(s.error)}` : "";
|
|
132444
132392
|
rows.push({
|
|
@@ -132467,7 +132415,7 @@ function buildRows(servers) {
|
|
|
132467
132415
|
label: "── " + t("mcp.recommended") + " ──",
|
|
132468
132416
|
status: "__section"
|
|
132469
132417
|
});
|
|
132470
|
-
for (const rec of
|
|
132418
|
+
for (const rec of getRecommended()) {
|
|
132471
132419
|
const alreadyInstalled = installedNames.has(rec.name);
|
|
132472
132420
|
const platformUnavailable = rec.macOnly && process.platform !== "darwin";
|
|
132473
132421
|
rows.push({
|
|
@@ -132486,7 +132434,7 @@ async function handleEnter(host, row) {
|
|
|
132486
132434
|
host.showStatus(t("mcp.already_installed", { name: row.label }));
|
|
132487
132435
|
return;
|
|
132488
132436
|
}
|
|
132489
|
-
const rec =
|
|
132437
|
+
const rec = getRecommended().find((r) => r.name === row.name);
|
|
132490
132438
|
if (!rec) return;
|
|
132491
132439
|
await installMcp(host, rec);
|
|
132492
132440
|
} else if (row.kind === "installed" && row.status && row.status !== "__section" && row.status !== "__empty") if (row.status === "connected") await disableMcp(host, row.name);
|
|
@@ -133189,7 +133137,7 @@ var MoonLoader = class extends Text {
|
|
|
133189
133137
|
const frame = this.frames[this.currentFrame];
|
|
133190
133138
|
const coloredFrame = this.colorFn ? this.colorFn(frame) : frame;
|
|
133191
133139
|
this.setText(this.label ? `${coloredFrame} ${this.label}` : coloredFrame);
|
|
133192
|
-
this.ui.
|
|
133140
|
+
this.ui.requestComponentRender(this);
|
|
133193
133141
|
}
|
|
133194
133142
|
};
|
|
133195
133143
|
//#endregion
|
|
@@ -136492,6 +136440,9 @@ out.join('\n');
|
|
|
136492
136440
|
function isWaylandSession(env) {
|
|
136493
136441
|
return Boolean(env["WAYLAND_DISPLAY"]) || env["XDG_SESSION_TYPE"] === "wayland";
|
|
136494
136442
|
}
|
|
136443
|
+
function isX11Session(env) {
|
|
136444
|
+
return Boolean(env["DISPLAY"]);
|
|
136445
|
+
}
|
|
136495
136446
|
function isWSL(env) {
|
|
136496
136447
|
if (env["WSL_DISTRO_NAME"] !== void 0 || env["WSLENV"] !== void 0) return true;
|
|
136497
136448
|
try {
|
|
@@ -136829,7 +136780,7 @@ async function readClipboardMedia(options) {
|
|
|
136829
136780
|
if (platform === "linux") {
|
|
136830
136781
|
const wayland = isWaylandSession(env);
|
|
136831
136782
|
const wsl = isWSL(env);
|
|
136832
|
-
if (wayland || wsl) {
|
|
136783
|
+
if (wayland || wsl || isX11Session(env)) {
|
|
136833
136784
|
const fileMedia = readClipboardFileMediaViaWlPaste() ?? readClipboardFileMediaViaXclip();
|
|
136834
136785
|
if (fileMedia !== null) return fileMedia;
|
|
136835
136786
|
image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();
|
|
@@ -138122,9 +138073,9 @@ var SessionEventHandler = class {
|
|
|
138122
138073
|
const { streamingUI } = this.host;
|
|
138123
138074
|
const backgroundMeta = this.backgroundAgentMetadata.get(event.subagentId);
|
|
138124
138075
|
if (backgroundMeta !== void 0) {
|
|
138076
|
+
const taskId = this.findAgentTaskId(event.subagentId);
|
|
138125
138077
|
this.backgroundAgentMetadata.delete(event.subagentId);
|
|
138126
138078
|
this.syncBackgroundAgentBadge();
|
|
138127
|
-
const taskId = this.findAgentTaskId(event.subagentId);
|
|
138128
138079
|
if (taskId !== void 0 && this.backgroundTaskTranscriptedTerminal.has(taskId)) return;
|
|
138129
138080
|
if (taskId !== void 0) this.backgroundTaskTranscriptedTerminal.add(taskId);
|
|
138130
138081
|
const extras = event.resultSummary === void 0 ? void 0 : { resultSummary: event.resultSummary };
|
|
@@ -138145,6 +138096,7 @@ var SessionEventHandler = class {
|
|
|
138145
138096
|
const { streamingUI } = this.host;
|
|
138146
138097
|
const backgroundMeta = this.backgroundAgentMetadata.get(event.subagentId);
|
|
138147
138098
|
if (backgroundMeta !== void 0) {
|
|
138099
|
+
const taskId = this.findAgentTaskId(event.subagentId);
|
|
138148
138100
|
this.backgroundAgentMetadata.delete(event.subagentId);
|
|
138149
138101
|
this.syncBackgroundAgentBadge();
|
|
138150
138102
|
streamingUI.applyBackgroundTaskTerminalStatus({
|
|
@@ -138153,7 +138105,6 @@ var SessionEventHandler = class {
|
|
|
138153
138105
|
status: "failed",
|
|
138154
138106
|
errorText: event.error
|
|
138155
138107
|
});
|
|
138156
|
-
const taskId = this.findAgentTaskId(event.subagentId);
|
|
138157
138108
|
if (taskId !== void 0 && this.backgroundTaskTranscriptedTerminal.has(taskId)) return;
|
|
138158
138109
|
if (taskId !== void 0) this.backgroundTaskTranscriptedTerminal.add(taskId);
|
|
138159
138110
|
this.appendBackgroundAgentEntry("failed", backgroundMeta, { error: event.error });
|
|
@@ -138297,18 +138248,21 @@ var SessionEventHandler = class {
|
|
|
138297
138248
|
};
|
|
138298
138249
|
//#endregion
|
|
138299
138250
|
//#region src/tui/utils/media-url.ts
|
|
138300
|
-
|
|
138301
|
-
|
|
138302
|
-
|
|
138303
|
-
|
|
138304
|
-
|
|
138251
|
+
function getMediaKindLabels() {
|
|
138252
|
+
return {
|
|
138253
|
+
audio: t("mediaurl.audio"),
|
|
138254
|
+
image: t("mediaurl.image"),
|
|
138255
|
+
video: t("mediaurl.video")
|
|
138256
|
+
};
|
|
138257
|
+
}
|
|
138305
138258
|
function mediaUrlPartToText(kind, url) {
|
|
138259
|
+
const labels = getMediaKindLabels();
|
|
138306
138260
|
const summary = summarizeDataUrl(url);
|
|
138307
138261
|
if (summary !== void 0) {
|
|
138308
138262
|
const size = summary.bytes !== void 0 ? `, ${formatByteSize(summary.bytes)}` : "";
|
|
138309
|
-
return `[${
|
|
138263
|
+
return `[${labels[kind]} ${summary.mime}${size}]`;
|
|
138310
138264
|
}
|
|
138311
|
-
return `<${
|
|
138265
|
+
return `<${labels[kind]} url="${escapeAttribute$1(url)}">`;
|
|
138312
138266
|
}
|
|
138313
138267
|
function summarizeDataUrl(url) {
|
|
138314
138268
|
if (!url.startsWith("data:")) return void 0;
|
|
@@ -141457,7 +141411,7 @@ var PulseWaveLoader = class extends Text {
|
|
|
141457
141411
|
2
|
|
141458
141412
|
].map((idx) => this.renderCell(idx, step.active, step.forward));
|
|
141459
141413
|
this.setText(cells.join(" "));
|
|
141460
|
-
this.ui.
|
|
141414
|
+
this.ui.requestComponentRender(this);
|
|
141461
141415
|
}
|
|
141462
141416
|
renderCell(index, active, forward) {
|
|
141463
141417
|
const distance = forward ? active - index : index - active;
|
|
@@ -142194,7 +142148,7 @@ function hslToHex(h, s, l) {
|
|
|
142194
142148
|
const toHex = (v) => Math.round((v + m) * 255).toString(16).padStart(2, "0");
|
|
142195
142149
|
return `#${toHex(rf)}${toHex(gf)}${toHex(bf)}`;
|
|
142196
142150
|
}
|
|
142197
|
-
var InputController = class {
|
|
142151
|
+
var InputController = class InputController {
|
|
142198
142152
|
host;
|
|
142199
142153
|
lastHistoryContent;
|
|
142200
142154
|
breatheTimer = null;
|
|
@@ -142215,12 +142169,38 @@ var InputController = class {
|
|
|
142215
142169
|
};
|
|
142216
142170
|
if (this.host.state.appState.planMode === "off") this.#startBreathing();
|
|
142217
142171
|
}
|
|
142172
|
+
pendingLargeInput = null;
|
|
142173
|
+
static LARGE_INPUT_THRESHOLD = 5e3;
|
|
142218
142174
|
handleInput(text) {
|
|
142175
|
+
if (this.pendingLargeInput !== null) {
|
|
142176
|
+
const answer = text.trim().toLowerCase();
|
|
142177
|
+
if (answer === "y" || answer === "yes") {
|
|
142178
|
+
const pending = this.pendingLargeInput;
|
|
142179
|
+
this.pendingLargeInput = null;
|
|
142180
|
+
this.persistInputHistory(pending);
|
|
142181
|
+
dispatchInput(this.host, pending);
|
|
142182
|
+
this.host.stopMemoryIdleTimer();
|
|
142183
|
+
} else {
|
|
142184
|
+
const pending = this.pendingLargeInput;
|
|
142185
|
+
this.pendingLargeInput = null;
|
|
142186
|
+
this.host.showStatus(t("input.large_cancelled"), this.host.state.theme.colors.textDim);
|
|
142187
|
+
if (answer !== "n" && answer !== "no" && text.trim().length > 0) {
|
|
142188
|
+
this.host.state.editor.setText(pending);
|
|
142189
|
+
this.handleInput(text);
|
|
142190
|
+
} else this.host.state.editor.setText(pending);
|
|
142191
|
+
}
|
|
142192
|
+
return;
|
|
142193
|
+
}
|
|
142219
142194
|
if (text.trim().length === 0) return;
|
|
142220
142195
|
if (this.host.state.appState.isReplaying) {
|
|
142221
142196
|
this.host.showError(t("input.replay_blocked"));
|
|
142222
142197
|
return;
|
|
142223
142198
|
}
|
|
142199
|
+
if (text.length > InputController.LARGE_INPUT_THRESHOLD) {
|
|
142200
|
+
this.pendingLargeInput = text;
|
|
142201
|
+
this.host.showStatus(t("input.large_confirm", { count: text.length }), this.host.state.theme.colors.warning);
|
|
142202
|
+
return;
|
|
142203
|
+
}
|
|
142224
142204
|
this.persistInputHistory(text);
|
|
142225
142205
|
dispatchInput(this.host, text);
|
|
142226
142206
|
this.host.stopMemoryIdleTimer();
|
|
@@ -143030,6 +143010,8 @@ var CustomEditor = class extends Editor {
|
|
|
143030
143010
|
thinking = false;
|
|
143031
143011
|
/** Current thinking effort level (e.g. low, medium, high). Used to annotate the think label. */
|
|
143032
143012
|
thinkingLevel = "off";
|
|
143013
|
+
/** Current permission mode — always shown as a badge at the top-left of the input box border. */
|
|
143014
|
+
permissionMode = "manual";
|
|
143033
143015
|
/** Current border colour hex — kept in sync with borderColor by the host. */
|
|
143034
143016
|
borderHex = "";
|
|
143035
143017
|
consumingPaste = false;
|
|
@@ -143090,7 +143072,13 @@ var CustomEditor = class extends Editor {
|
|
|
143090
143072
|
const withPrompt = injectPromptSymbol(firstContent);
|
|
143091
143073
|
if (withPrompt !== void 0) lines[firstContentIdx] = withPrompt;
|
|
143092
143074
|
}
|
|
143093
|
-
|
|
143075
|
+
injectBorderBadges(lines, width, {
|
|
143076
|
+
mode: this.permissionMode,
|
|
143077
|
+
thinking: this.thinking,
|
|
143078
|
+
thinkingLevel: this.thinkingLevel,
|
|
143079
|
+
paint: this.borderColor ?? ((s) => s),
|
|
143080
|
+
borderHex: this.borderHex
|
|
143081
|
+
});
|
|
143094
143082
|
return lines;
|
|
143095
143083
|
}
|
|
143096
143084
|
handleInput(data) {
|
|
@@ -143223,34 +143211,47 @@ function injectPromptSymbol(line) {
|
|
|
143223
143211
|
return "> " + line.slice(2);
|
|
143224
143212
|
}
|
|
143225
143213
|
const THINK_LABEL_MIN_WIDTH = 14;
|
|
143214
|
+
const MODE_BADGE_MIN_WIDTH = 10;
|
|
143226
143215
|
function isLightBg(hex) {
|
|
143227
143216
|
const r = parseInt(hex.slice(1, 3), 16);
|
|
143228
143217
|
const g = parseInt(hex.slice(3, 5), 16);
|
|
143229
143218
|
const b = parseInt(hex.slice(5, 7), 16);
|
|
143230
143219
|
return (.299 * r + .587 * g + .114 * b) / 255 > .5;
|
|
143231
143220
|
}
|
|
143221
|
+
function makeBadge(label, bgHex) {
|
|
143222
|
+
return bgHex ? chalk.bgHex(bgHex).hex(isLightBg(bgHex) ? "#000000" : "#FFFFFF")(label) : chalk.bgBlack.white(label);
|
|
143223
|
+
}
|
|
143232
143224
|
/**
|
|
143233
|
-
*
|
|
143234
|
-
*
|
|
143235
|
-
*
|
|
143236
|
-
*
|
|
143237
|
-
*
|
|
143238
|
-
*
|
|
143239
|
-
*
|
|
143225
|
+
* Compose the editor's top border line with up to two badges: the
|
|
143226
|
+
* permission mode badge at the left (always shown) and the think badge at
|
|
143227
|
+
* the right (only when thinking is enabled). Each badge is a solid colour
|
|
143228
|
+
* block with black/white text picked by background luminance. When the
|
|
143229
|
+
* editor is scrolled, pi-tui's `↑ N more` indicator keeps the line — it
|
|
143230
|
+
* signals hidden content, which matters more than the badges. On narrow
|
|
143231
|
+
* terminals the think badge drops first, then the mode badge.
|
|
143240
143232
|
*/
|
|
143241
|
-
function
|
|
143242
|
-
if (width < THINK_LABEL_MIN_WIDTH) return;
|
|
143233
|
+
function injectBorderBadges(lines, width, opts) {
|
|
143243
143234
|
const topIdx = lines.findIndex((line) => {
|
|
143244
143235
|
const plain = stripSgr(line);
|
|
143245
143236
|
return plain.length > 0 && plain[0] === "─";
|
|
143246
143237
|
});
|
|
143247
143238
|
if (topIdx === -1) return;
|
|
143248
|
-
|
|
143249
|
-
const
|
|
143250
|
-
|
|
143251
|
-
|
|
143252
|
-
if (
|
|
143253
|
-
|
|
143239
|
+
if (stripSgr(lines[topIdx]).includes("↑")) return;
|
|
143240
|
+
const { paint } = opts;
|
|
143241
|
+
let left = "";
|
|
143242
|
+
let right = paint("─");
|
|
143243
|
+
if (width >= MODE_BADGE_MIN_WIDTH) {
|
|
143244
|
+
const badgeText = ` ${opts.mode} `;
|
|
143245
|
+
left = paint("──") + (opts.borderHex ? chalk.hex(opts.borderHex).bold(badgeText) : paint(badgeText));
|
|
143246
|
+
}
|
|
143247
|
+
if (opts.thinking && width >= THINK_LABEL_MIN_WIDTH) right = makeBadge(opts.thinkingLevel !== "off" ? ` Think ${opts.thinkingLevel} ` : " Think ", opts.borderHex) + paint("─");
|
|
143248
|
+
const fill = width - visibleWidth(left) - visibleWidth(right);
|
|
143249
|
+
if (fill < 0) {
|
|
143250
|
+
const modeOnlyFill = width - visibleWidth(left) - 1;
|
|
143251
|
+
lines[topIdx] = modeOnlyFill >= 0 ? left + paint("─".repeat(modeOnlyFill)) + paint("─") : paint("─".repeat(width));
|
|
143252
|
+
return;
|
|
143253
|
+
}
|
|
143254
|
+
lines[topIdx] = left + paint("─".repeat(fill)) + right;
|
|
143254
143255
|
}
|
|
143255
143256
|
//#endregion
|
|
143256
143257
|
//#region src/tui/utils/terminal-state.ts
|
|
@@ -143491,6 +143492,7 @@ function createTUIState(options) {
|
|
|
143491
143492
|
const editor = new CustomEditor(ui, theme.colors);
|
|
143492
143493
|
editor.thinking = initialAppState.thinkingLevel !== "off";
|
|
143493
143494
|
editor.thinkingLevel = initialAppState.thinkingLevel;
|
|
143495
|
+
editor.permissionMode = initialAppState.permissionMode ?? "manual";
|
|
143494
143496
|
return {
|
|
143495
143497
|
ui,
|
|
143496
143498
|
terminal,
|
|
@@ -144110,11 +144112,17 @@ var SessionManager = class {
|
|
|
144110
144112
|
}
|
|
144111
144113
|
if (isBusy(this.host.state.appState)) {
|
|
144112
144114
|
this.host.showError(t("session.switch_streaming"));
|
|
144113
|
-
return {
|
|
144115
|
+
return {
|
|
144116
|
+
switched: false,
|
|
144117
|
+
blocked: true
|
|
144118
|
+
};
|
|
144114
144119
|
}
|
|
144115
144120
|
if (this.host.state.appState.isReplaying) {
|
|
144116
144121
|
this.host.showError(t("session.switch_replaying"));
|
|
144117
|
-
return {
|
|
144122
|
+
return {
|
|
144123
|
+
switched: false,
|
|
144124
|
+
blocked: true
|
|
144125
|
+
};
|
|
144118
144126
|
}
|
|
144119
144127
|
let session;
|
|
144120
144128
|
try {
|
|
@@ -146025,12 +146033,12 @@ var DialogManager = class {
|
|
|
146025
146033
|
const row = this.host.getSessions().find((s) => s.id === pickerId);
|
|
146026
146034
|
const isCc = row?.metadata?.["source"] === "cc-connect";
|
|
146027
146035
|
const realId = isCc ? row.metadata["agentSessionId"] : pickerId;
|
|
146028
|
-
this.host.resumeSession(realId).then(async (switched) => {
|
|
146036
|
+
this.host.resumeSession(realId).then(async ({ switched, blocked }) => {
|
|
146029
146037
|
if (switched) {
|
|
146030
146038
|
this.hideSessionPicker();
|
|
146031
146039
|
return;
|
|
146032
146040
|
}
|
|
146033
|
-
if (isCc) try {
|
|
146041
|
+
if (isCc && blocked !== true) try {
|
|
146034
146042
|
const session = await this.host.harness.createSession({
|
|
146035
146043
|
id: realId,
|
|
146036
146044
|
workDir: this.host.getCurrentWorkDir(),
|
|
@@ -146044,6 +146052,8 @@ var DialogManager = class {
|
|
|
146044
146052
|
} catch {
|
|
146045
146053
|
this.host.showError(t("dialog.create_session_failed"));
|
|
146046
146054
|
}
|
|
146055
|
+
}).catch((error) => {
|
|
146056
|
+
this.host.showError(error instanceof Error ? error.message : String(error));
|
|
146047
146057
|
});
|
|
146048
146058
|
},
|
|
146049
146059
|
onCancel,
|
|
@@ -146056,6 +146066,8 @@ var DialogManager = class {
|
|
|
146056
146066
|
await this.host.fetchSessions();
|
|
146057
146067
|
if (this.host.getSessions().length === 0) this.hideSessionPicker();
|
|
146058
146068
|
else if (this.host.state.activeDialog === "session-picker") this.mountSessionPicker(onCancel);
|
|
146069
|
+
}).catch((error) => {
|
|
146070
|
+
this.host.showError(error instanceof Error ? error.message : String(error));
|
|
146059
146071
|
});
|
|
146060
146072
|
}
|
|
146061
146073
|
}));
|
|
@@ -146576,6 +146588,7 @@ var ScreamTUI = class {
|
|
|
146576
146588
|
this.state.editor.thinking = patch.thinkingLevel !== "off";
|
|
146577
146589
|
this.state.editor.thinkingLevel = patch.thinkingLevel ?? "off";
|
|
146578
146590
|
}
|
|
146591
|
+
if ("permissionMode" in patch) this.state.editor.permissionMode = patch.permissionMode ?? "manual";
|
|
146579
146592
|
if ("streamingPhase" in patch && patch.streamingPhase !== "idle") {
|
|
146580
146593
|
this.transcriptController.stopWelcomeBreathing();
|
|
146581
146594
|
this.inputController.stopBreathingForStreaming();
|
|
@@ -146630,7 +146643,11 @@ var ScreamTUI = class {
|
|
|
146630
146643
|
this.sessionManager.resetSessionRuntime();
|
|
146631
146644
|
}
|
|
146632
146645
|
async resumeSession(targetSessionId) {
|
|
146633
|
-
|
|
146646
|
+
const result = await this.sessionManager.resumeSession(targetSessionId);
|
|
146647
|
+
return {
|
|
146648
|
+
switched: result.switched,
|
|
146649
|
+
blocked: result.blocked
|
|
146650
|
+
};
|
|
146634
146651
|
}
|
|
146635
146652
|
async switchToSession(session, statusMessage) {
|
|
146636
146653
|
await this.sessionManager.switchToSession(session, statusMessage);
|
|
@@ -146775,6 +146792,8 @@ const SHADOW_CHARS = new Set([
|
|
|
146775
146792
|
const SHEEN_STEP = 4;
|
|
146776
146793
|
const SHEEN_INTERVAL_MS = 60;
|
|
146777
146794
|
const LOADING_DURATION_MS = 1500;
|
|
146795
|
+
const FULL_LOGO_MIN_COLS = 87;
|
|
146796
|
+
const COMPACT_LOGO = ["██▄▄▄██", "▐█▄▀▄█▌"];
|
|
146778
146797
|
const THEME_PRIMARY = {
|
|
146779
146798
|
dark: [
|
|
146780
146799
|
204,
|
|
@@ -146963,7 +146982,9 @@ function supportsAnsi() {
|
|
|
146963
146982
|
}
|
|
146964
146983
|
function runLoadingAnimation(theme = "dark") {
|
|
146965
146984
|
if (!supportsAnsi()) {
|
|
146966
|
-
|
|
146985
|
+
const { cols } = getTerminalSize();
|
|
146986
|
+
if (cols >= FULL_LOGO_MIN_COLS) for (const line of LOGO) stdout.write(`${fg(...LOGO_RGB)}${line}${RESET}\n`);
|
|
146987
|
+
else for (const line of COMPACT_LOGO) stdout.write(`${fg(...BLOCK_RGB)}${line}${RESET}\n`);
|
|
146967
146988
|
stdout.write(`${BOLD}${fg(...THEME_PRIMARY[theme])}${t("loading.waking")}${RESET}\n`);
|
|
146968
146989
|
return Promise.resolve();
|
|
146969
146990
|
}
|
|
@@ -146981,15 +147002,20 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
146981
147002
|
function render() {
|
|
146982
147003
|
const { cols, rows } = getTerminalSize();
|
|
146983
147004
|
const lines = [];
|
|
146984
|
-
const
|
|
147005
|
+
const useFullLogo = cols >= FULL_LOGO_MIN_COLS;
|
|
147006
|
+
const contentHeight = useFullLogo ? LOGO.length + 5 : COMPACT_LOGO.length + 5;
|
|
146985
147007
|
const topPad = Math.max(0, Math.floor((rows - contentHeight) / 2));
|
|
146986
147008
|
for (let i = 0; i < topPad; i++) lines.push("");
|
|
146987
147009
|
const breatheColor = breathePalette[breatheFrame] ?? primary;
|
|
146988
|
-
for (const line of LOGO) {
|
|
147010
|
+
if (useFullLogo) for (const line of LOGO) {
|
|
146989
147011
|
let colored = "";
|
|
146990
147012
|
for (let ci = 0; ci < line.length; ci++) colored += renderSheen(line[ci], ci, sheenPos, isReversing, breatheColor);
|
|
146991
147013
|
lines.push(centerPad(colored, cols));
|
|
146992
147014
|
}
|
|
147015
|
+
else for (const line of COMPACT_LOGO) {
|
|
147016
|
+
const colored = `${fg(...BLOCK_RGB)}${line}${RESET}`;
|
|
147017
|
+
lines.push(centerPad(colored, cols));
|
|
147018
|
+
}
|
|
146993
147019
|
lines.push("");
|
|
146994
147020
|
if (phase === "loading") lines.push(centerPad(renderShimmer(shimmerPulse, breatheColor), cols));
|
|
146995
147021
|
else lines.push(centerPad(`${BOLD}${fg(...breatheColor)}${t("loading.press_enter")}${RESET}`, cols));
|
|
@@ -147046,7 +147072,9 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
147046
147072
|
process$1.off("SIGTERM", interrupt);
|
|
147047
147073
|
stdout.write("\x1B[?25h");
|
|
147048
147074
|
if (process$1.platform !== "win32") stdout.write("\x1B[?1049l");
|
|
147049
|
-
|
|
147075
|
+
const { cols: fallbackCols } = getTerminalSize();
|
|
147076
|
+
if (fallbackCols >= FULL_LOGO_MIN_COLS) for (const line of LOGO) stdout.write(`${fg(...LOGO_RGB)}${line}${RESET}\n`);
|
|
147077
|
+
else for (const line of COMPACT_LOGO) stdout.write(`${fg(...BLOCK_RGB)}${line}${RESET}\n`);
|
|
147050
147078
|
stdout.write(`${BOLD}${fg(...primary)}${t("loading.waking")}${RESET}\n`);
|
|
147051
147079
|
resolve();
|
|
147052
147080
|
return;
|
|
@@ -147700,6 +147728,27 @@ async function runStreamJson(opts) {
|
|
|
147700
147728
|
hasAppendPrompt: appendPrompt.length > 0
|
|
147701
147729
|
});
|
|
147702
147730
|
}
|
|
147731
|
+
let cleaned = false;
|
|
147732
|
+
const runCleanup = async () => {
|
|
147733
|
+
if (cleaned) return;
|
|
147734
|
+
cleaned = true;
|
|
147735
|
+
for (const [, pending] of pendingApprovals) pending.resolve({
|
|
147736
|
+
decision: "rejected",
|
|
147737
|
+
feedback: "会话已结束"
|
|
147738
|
+
});
|
|
147739
|
+
pendingApprovals.clear();
|
|
147740
|
+
if (currentSessionId) writer.emitResumeHint(sessionKey);
|
|
147741
|
+
try {
|
|
147742
|
+
if (session) await session.close();
|
|
147743
|
+
await harness.close();
|
|
147744
|
+
} catch {}
|
|
147745
|
+
if (injectedAgentsMd) try {
|
|
147746
|
+
if (originalAgentsMd === void 0) {
|
|
147747
|
+
if (existsSync(agentsMdPath)) unlinkSync(agentsMdPath);
|
|
147748
|
+
} else writeFileSync(agentsMdPath, originalAgentsMd, "utf-8");
|
|
147749
|
+
} catch {}
|
|
147750
|
+
};
|
|
147751
|
+
const uninstallTerminationHandlers = installStreamJsonTerminationHandlers(runCleanup);
|
|
147703
147752
|
try {
|
|
147704
147753
|
await harness.ensureConfigFile();
|
|
147705
147754
|
const config = await harness.getConfig();
|
|
@@ -147934,7 +147983,7 @@ async function runStreamJson(opts) {
|
|
|
147934
147983
|
});
|
|
147935
147984
|
session.prompt(userText).catch((error) => {
|
|
147936
147985
|
const msg = error instanceof Error ? error.message : String(error);
|
|
147937
|
-
if (msg.includes("insufficient tool messages") || msg.includes("tool_calls")) {
|
|
147986
|
+
if (msg.includes("insufficient tool messages") || msg.includes("tool_calls") && msg.includes("followed by tool messages")) {
|
|
147938
147987
|
log.warn("stream-json: resetting session after tool call mismatch", {
|
|
147939
147988
|
sessionId: session?.id,
|
|
147940
147989
|
error: msg
|
|
@@ -147952,7 +148001,9 @@ async function runStreamJson(opts) {
|
|
|
147952
148001
|
}
|
|
147953
148002
|
finish(error instanceof Error ? error : new Error(msg));
|
|
147954
148003
|
});
|
|
147955
|
-
|
|
148004
|
+
try {
|
|
148005
|
+
await turnPromise;
|
|
148006
|
+
} catch {}
|
|
147956
148007
|
}
|
|
147957
148008
|
} catch (error) {
|
|
147958
148009
|
if (process.exitCode === void 0) {
|
|
@@ -147961,23 +148012,35 @@ async function runStreamJson(opts) {
|
|
|
147961
148012
|
process.exitCode = 1;
|
|
147962
148013
|
} else log.error("stream-json: turn error (exitCode already set)", { error });
|
|
147963
148014
|
} finally {
|
|
147964
|
-
|
|
147965
|
-
|
|
147966
|
-
feedback: "会话已结束"
|
|
147967
|
-
});
|
|
147968
|
-
pendingApprovals.clear();
|
|
147969
|
-
if (currentSessionId) writer.emitResumeHint(sessionKey);
|
|
147970
|
-
try {
|
|
147971
|
-
if (session) await session.close();
|
|
147972
|
-
await harness.close();
|
|
147973
|
-
} catch {}
|
|
147974
|
-
if (injectedAgentsMd) try {
|
|
147975
|
-
if (originalAgentsMd === void 0) {
|
|
147976
|
-
if (existsSync(agentsMdPath)) unlinkSync(agentsMdPath);
|
|
147977
|
-
} else writeFileSync(agentsMdPath, originalAgentsMd, "utf-8");
|
|
147978
|
-
} catch {}
|
|
148015
|
+
uninstallTerminationHandlers();
|
|
148016
|
+
await runCleanup();
|
|
147979
148017
|
}
|
|
147980
148018
|
}
|
|
148019
|
+
/** Install termination handlers so we can clean up on SIGINT / SIGTERM. */
|
|
148020
|
+
function installStreamJsonTerminationHandlers(cleanup) {
|
|
148021
|
+
let terminating = false;
|
|
148022
|
+
const handler = async (signal) => {
|
|
148023
|
+
if (terminating) return;
|
|
148024
|
+
terminating = true;
|
|
148025
|
+
try {
|
|
148026
|
+
await cleanup();
|
|
148027
|
+
} finally {
|
|
148028
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
148029
|
+
}
|
|
148030
|
+
};
|
|
148031
|
+
const onSigint = () => {
|
|
148032
|
+
handler("SIGINT");
|
|
148033
|
+
};
|
|
148034
|
+
const onSigterm = () => {
|
|
148035
|
+
handler("SIGTERM");
|
|
148036
|
+
};
|
|
148037
|
+
process.once("SIGINT", onSigint);
|
|
148038
|
+
process.once("SIGTERM", onSigterm);
|
|
148039
|
+
return () => {
|
|
148040
|
+
process.off("SIGINT", onSigint);
|
|
148041
|
+
process.off("SIGTERM", onSigterm);
|
|
148042
|
+
};
|
|
148043
|
+
}
|
|
147981
148044
|
//#endregion
|
|
147982
148045
|
//#region src/cli/startup-error.ts
|
|
147983
148046
|
function formatUnknownErrorMessage(error) {
|